Passed
Pull Request — master (#257)
by
unknown
06:36
created

WPInv_Discount::has_started()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * Contains Discount calculation class
4
 *
5
 * @since   1.0.14
6
 */
7
8
defined( 'ABSPATH' ) || exit;
9
10
/**
11
 * Discount class.
12
 * 
13
 * @since 1.0.14
14
 *
15
 */
16
class WPInv_Discount {
17
	
18
	/**
19
	 * Discount ID.
20
	 *
21
	 * @since 1.0.14
22
	 * @var array
23
	 */
24
	public $ID = null;
25
26
	/**
27
	 * Old discount status.
28
	 *
29
	 * @since 1.0.14
30
	 * @var string
31
	 */
32
	public $old_status = 'draft';
33
	
34
	/**
35
	 * Data array, with defaults.
36
	 *
37
	 * @since 1.0.14
38
	 * @var array
39
	 */
40
	protected $data = array();
41
42
	/**
43
	 * Discount constructor.
44
	 *
45
	 * @param int|array|string|WPInv_Discount $discount discount data, object, ID or code.
46
	 * @since 1.0.14
47
	 */
48
	public function __construct( $discount = array() ) {
49
        
50
        // If the discount is an instance of this class...
51
		if ( $discount instanceof WPInv_Discount ) {
52
			$this->init( $discount->data );
53
			return;
54
        }
55
        
56
        // If the discount is an array of discount details...
57
        if ( is_array( $discount ) ) {
58
			$this->init( $discount );
59
			return;
60
		}
61
		
62
		// Try fetching the discount by its post id.
63
		$data = false;
64
		
65
		if ( ! empty( $discount ) && is_numeric( $discount ) ) {
66
			$discount = absint( $discount );
67
			$data = self::get_data_by( 'id', $discount );
68
		}
69
70
		if ( $data ) {
71
			$this->init( $data );
72
			return;
73
		}
74
		
75
		// Try fetching the discount by its discount code.
76
		if ( ! empty( $discount ) && is_string( $discount ) ) {
77
			$data = self::get_data_by( 'discount_code', $discount );
78
		}
79
80
		if ( $data ) {
81
			$this->init( $data );
82
			return;
83
		} 
84
		
85
		// If we are here then the discount does not exist.
86
		$this->init( array() );
87
	}
88
	
89
	/**
90
	 * Sets up object properties
91
	 *
92
	 * @since 1.0.14
93
	 * @param array $data An array containing the discount's data
94
	 */
95
	public function init( $data ) {
96
		$data       	  = self::sanitize_discount_data( $data );
97
		$this->data 	  = $data;
98
		$this->old_status = $data['status'];
99
		$this->ID   	  = $data['ID'];
100
	}
101
	
102
	/**
103
	 * Fetch a discount from the db/cache
104
	 *
105
	 *
106
	 * @static
107
	 *
108
	 *
109
	 * @param string $field The field to query against: 'ID', 'discount_code'
110
	 * @param string|int $value The field value
111
	 * @since 1.0.14
112
	 * @return array|false array of discount details on success. False otherwise.
113
	 */
114
	public static function get_data_by( $field, $value ) {
115
116
		// 'ID' is an alias of 'id'.
117
		if ( 'ID' === $field ) {
118
			$field = 'id';
119
		}
120
121
		if ( 'id' == $field ) {
122
			// Make sure the value is numeric to avoid casting objects, for example,
123
			// to int 1.
124
			if ( ! is_numeric( $value ) )
125
				return false;
126
			$value = intval( $value );
127
			if ( $value < 1 )
128
				return false;
129
		} else {
130
			$value = trim( $value );
131
		}
132
133
		if ( !$value || ! is_string( $field ) )
134
			return false;
135
136
		// prepare query args
137
		switch ( strtolower( $field ) ) {
138
			case 'id':
139
				$discount_id = $value;
140
				$args		 = array( 'include' => array( $value ) );
141
				break;
142
			case 'discount_code':
143
			case 'code':
144
				$discount_id = wp_cache_get( $value, 'WPInv_Discount_Codes' );
145
				$args		 = array( 'meta_key' => '_wpi_discount_code', 'meta_value' => $value );
146
				break;
147
			case 'name':
148
				$discount_id = 0;
149
				$args		 = array( 'name' => $value );
150
				break;
151
			default:
152
				return false;
153
		}
154
155
		// Check if there is a cached value.
156
		if ( false !== $discount_id && $discount = wp_cache_get( $discount_id, 'WPInv_Discounts' ) ) {
0 ignored issues
show
Bug introduced by
It seems like $discount_id can also be of type true; however, parameter $key of wp_cache_get() does only seem to accept integer|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

156
		if ( false !== $discount_id && $discount = wp_cache_get( /** @scrutinizer ignore-type */ $discount_id, 'WPInv_Discounts' ) ) {
Loading history...
157
			return $discount;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $discount also could return the type true which is incompatible with the documented return type array|false.
Loading history...
158
		}
159
160
		$args = wp_parse_args(
161
			$args,
0 ignored issues
show
Security Variable Injection introduced by
$args can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST, and wpinv_store_discount() is called
    in includes/admin/admin-meta-boxes.php on line 379
  2. Enters via parameter $data
    in includes/wpinv-discount-functions.php on line 252
  3. Data is passed through wp_parse_args(), and wp_parse_args($data, $existing_data) is assigned to $data
    in includes/wpinv-discount-functions.php on line 261
  4. wpinv_get_discount_obj() is called
    in includes/wpinv-discount-functions.php on line 262
  5. Enters via parameter $discount
    in includes/wpinv-discount-functions.php on line 215
  6. WPInv_Discount::__construct() is called
    in includes/wpinv-discount-functions.php on line 216
  7. Enters via parameter $discount
    in includes/class-wpinv-discount.php on line 48
  8. WPInv_Discount::get_data_by() is called
    in includes/class-wpinv-discount.php on line 77
  9. Enters via parameter $value
    in includes/class-wpinv-discount.php on line 114
  10. Data is passed through trim(), and trim($value) is assigned to $value
    in includes/class-wpinv-discount.php on line 130
  11. array('include' => array($value)) is assigned to $args
    in includes/class-wpinv-discount.php on line 140

Used in variable context

  1. wp_parse_args() is called
    in includes/class-wpinv-discount.php on line 161
  2. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4294
  3. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4300
  4. Enters via parameter $string
    in wordpress/wp-includes/formatting.php on line 4865
  5. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 4866

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
162
			array(
163
				'post_type'      => 'wpi_discount',
164
				'posts_per_page' => 1,
165
				'post_status'    => array( 'publish', 'pending', 'draft', 'expired' )
166
			)
167
		);
168
169
		$discount = get_posts( $args );
0 ignored issues
show
Security Variable Injection introduced by
$args can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST, and wpinv_store_discount() is called
    in includes/admin/admin-meta-boxes.php on line 379
  2. Enters via parameter $data
    in includes/wpinv-discount-functions.php on line 252
  3. Data is passed through wp_parse_args(), and wp_parse_args($data, $existing_data) is assigned to $data
    in includes/wpinv-discount-functions.php on line 261
  4. wpinv_get_discount_obj() is called
    in includes/wpinv-discount-functions.php on line 262
  5. Enters via parameter $discount
    in includes/wpinv-discount-functions.php on line 215
  6. WPInv_Discount::__construct() is called
    in includes/wpinv-discount-functions.php on line 216
  7. Enters via parameter $discount
    in includes/class-wpinv-discount.php on line 48
  8. WPInv_Discount::get_data_by() is called
    in includes/class-wpinv-discount.php on line 77
  9. Enters via parameter $value
    in includes/class-wpinv-discount.php on line 114
  10. Data is passed through trim(), and trim($value) is assigned to $value
    in includes/class-wpinv-discount.php on line 130
  11. array('include' => array($value)) is assigned to $args
    in includes/class-wpinv-discount.php on line 140
  12. Data is passed through wp_parse_args(), and wp_parse_args($args, array('post_type' => 'wpi_discount', 'posts_per_page' => 1, 'post_status' => array('publish', 'pending', 'draft', 'expired'))) is assigned to $args
    in includes/class-wpinv-discount.php on line 160

Used in variable context

  1. get_posts() is called
    in includes/class-wpinv-discount.php on line 169
  2. Enters via parameter $args
    in wordpress/wp-includes/post.php on line 2009
  3. wp_parse_args() is called
    in wordpress/wp-includes/post.php on line 2023
  4. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4294
  5. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4300
  6. Enters via parameter $string
    in wordpress/wp-includes/formatting.php on line 4865
  7. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 4866

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
170
				
171
		if( empty( $discount ) ) {
172
			return false;
173
		}
174
175
		$discount = $discount[0];
176
		
177
		// Prepare the return data.
178
		$return = array(
179
            'ID'                          => $discount->ID,
180
            'code'                        => get_post_meta( $discount->ID, '_wpi_discount_code', true ),
181
            'amount'                      => get_post_meta( $discount->ID, '_wpi_discount_amount', true ),
182
            'date_created'                => $discount->post_date,
183
			'date_modified'               => $discount->post_modified,
184
			'status'               		  => $discount->post_status,
185
			'start'                  	  => get_post_meta( $discount->ID, '_wpi_discount_start', true ),
186
            'expiration'                  => get_post_meta( $discount->ID, '_wpi_discount_expiration', true ),
187
            'type'               		  => get_post_meta( $discount->ID, '_wpi_discount_type', true ),
188
            'description'                 => $discount->post_excerpt,
189
            'uses'                 		  => get_post_meta( $discount->ID, '_wpi_discount_uses', true ),
190
            'is_single_use'               => get_post_meta( $discount->ID, '_wpi_discount_is_single_use', true ),
191
            'items'              	      => get_post_meta( $discount->ID, '_wpi_discount_items', true ),
192
            'excluded_items'              => get_post_meta( $discount->ID, '_wpi_discount_excluded_items', true ),
193
            'max_uses'                    => get_post_meta( $discount->ID, '_wpi_discount_max_uses', true ),
194
            'is_recurring'                => get_post_meta( $discount->ID, '_wpi_discount_is_recurring', true ),
195
            'min_total'                   => get_post_meta( $discount->ID, '_wpi_discount_min_total', true ),
196
            'max_total'                   => get_post_meta( $discount->ID, '_wpi_discount_max_total', true ),
197
        );
198
		
199
		$return = self::sanitize_discount_data( $return );
200
		$return = apply_filters( 'wpinv_discount_properties', $return );
201
202
		// Update the cache with our data
203
		wp_cache_add( $discount->ID, $return, 'WPInv_Discounts' );
204
		wp_cache_add( $discount['code'], $discount->ID, 'WPInv_Discount_Codes' );
205
206
		return $return  ;
207
	}
208
	
209
	/**
210
	 * Sanitizes discount data
211
	 *
212
	 * @static
213
	 * @since 1.0.14
214
	 * @access public
215
	 *
216
	 * @return array the sanitized data
217
	 */
218
	public static function sanitize_discount_data( $data ) {
219
		
220
		$allowed_discount_types = array_keys( wpinv_get_discount_types() );
221
		
222
		$return = array(
223
            'ID'                          => null,
224
            'code'                        => '',
225
            'amount'                      => 0,
226
            'date_created'                => current_time('mysql'),
227
            'date_modified'               => current_time('mysql'),
228
			'expiration'                  => null,
229
			'start'                  	  => current_time('mysql'),
230
			'status'                  	  => 'draft',
231
            'type'               		  => 'percent',
232
            'description'                 => '',
233
            'uses'                        => 0,
234
            'is_single_use'               => false,
235
            'items'              		  => array(),
236
            'excluded_items'              => array(),
237
            'max_uses'                    => 0,
238
            'is_recurring'                => false,
239
            'min_total'                   => '',
240
			'max_total'              	  => '',
241
		);
242
		
243
				
244
		// Arrays only please.
245
		if (! is_array( $data ) ) {
246
            return $return;
247
        }
248
249
		// If an id is provided, ensure it is a valid discount.
250
        if (! empty( $data['ID'] ) && is_numeric( $data['ID'] ) && 'wpi_discount' !== get_post_type( $data['ID'] ) ) {
251
            return $return;
252
		} else {
253
			unset( $data['ID'] );
254
		}
255
256
        $return = wp_parse_args( $data, $return );
0 ignored issues
show
Security Variable Injection introduced by
$data can contain request data and is used in variable name context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_POST, and wpinv_store_discount() is called
    in includes/admin/admin-meta-boxes.php on line 379
  2. Enters via parameter $data
    in includes/wpinv-discount-functions.php on line 252
  3. Data is passed through wp_parse_args(), and wp_parse_args($data, $existing_data) is assigned to $data
    in includes/wpinv-discount-functions.php on line 261
  4. wpinv_get_discount_obj() is called
    in includes/wpinv-discount-functions.php on line 262
  5. Enters via parameter $discount
    in includes/wpinv-discount-functions.php on line 215
  6. WPInv_Discount::__construct() is called
    in includes/wpinv-discount-functions.php on line 216
  7. Enters via parameter $discount
    in includes/class-wpinv-discount.php on line 48
  8. WPInv_Discount::init() is called
    in includes/class-wpinv-discount.php on line 58
  9. Enters via parameter $data
    in includes/class-wpinv-discount.php on line 95
  10. WPInv_Discount::sanitize_discount_data() is called
    in includes/class-wpinv-discount.php on line 96
  11. Enters via parameter $data
    in includes/class-wpinv-discount.php on line 218

Used in variable context

  1. wp_parse_args() is called
    in includes/class-wpinv-discount.php on line 256
  2. Enters via parameter $args
    in wordpress/wp-includes/functions.php on line 4294
  3. wp_parse_str() is called
    in wordpress/wp-includes/functions.php on line 4300
  4. Enters via parameter $string
    in wordpress/wp-includes/formatting.php on line 4865
  5. parse_str() is called
    in wordpress/wp-includes/formatting.php on line 4866

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
257
258
        // Sanitize some keys.
259
        $return['amount']         = wpinv_sanitize_amount( $return['amount'] );
260
		$return['is_single_use']  = (bool) $return['single_use'];
261
		$return['is_recurring']   = (bool) $return['recurring'];
262
		$return['uses']	          = (int) $return['uses'];
263
		$return['max_uses']	      = (int) $return['max_uses'];
264
		$return['min_total'] 	  = wpinv_sanitize_amount( $return['min_total'] );
265
        $return['max_total'] 	  = wpinv_sanitize_amount( $return['max_total'] );
266
267
		// Trim all values.
268
		$return = wpinv_clean( $return );
269
		
270
		// Ensure the discount type is supported.
271
        if ( ! in_array( $return['discount_type'], $allowed_discount_types, true ) ) {
272
            $return['discount_type'] = 'percent';
273
		}
274
		$return['discount_type_name'] = wpinv_get_discount_type_name( $return['discount_type'] );
275
		
276
		// Do not offer more than a 100% discount.
277
		if ( $return['discount_type'] == 'percent' && (float) $return['amount'] > 100 ) {
278
			$return['amount'] = 100;
279
		}
280
281
		// Format dates.
282
		foreach( wpinv_parse_list( 'date_created date_modified expiration start') as $prop ) {
283
			if( ! empty( $return[$prop] ) ) {
284
				$return[$prop]      = date_i18n( 'Y-m-d H:i:s', strtotime( $return[$prop] ) );
285
			}
286
		}
287
288
		// Formart items.
289
		foreach( wpinv_parse_list( 'excluded_items items') as $prop ) {
290
291
			if( ! empty( $return[$prop] ) ) {
292
				// Ensure that the property is an array of non-empty integers.
293
				$return[$prop]      = array_filter( array_map( 'intval', wpinv_parse_list( $return[$prop] ) ) );
294
			} else {
295
				$return[$prop]      = array();
296
			}
297
298
		}
299
		
300
		return apply_filters( 'sanitize_discount_data', $return, $data );
301
	}
302
	
303
	/**
304
	 * Magic method for checking the existence of a certain custom field.
305
	 *
306
	 * @since 1.0.14
307
	 * @access public
308
	 *
309
	 * @return bool Whether the given discount field is set.
310
	 */
311
	public function __isset( $key ){
312
		return isset( $this->data[$key] );
313
	}
314
	
315
	/**
316
	 * Magic method for accessing discount properties.
317
	 *
318
	 * @since 1.0.14
319
	 * @access public
320
	 *
321
	 * @param string $key Discount data to retrieve
322
	 * @return mixed Value of the given discount property (if set).
323
	 */
324
	public function __get( $key ) {
325
		
326
		if ( $key == 'id' ) {
327
			$key = 'ID';
328
		}
329
		
330
		if( method_exists( $this, "get_$key") ) {
331
			$value 	= call_user_func( array( $this, "get_$key" ) );
332
		} else if( isset( $this->data[$key] ) ) {
333
			$value 	= $this->data[$key];
334
		} else {
335
			$value = null;
336
		}
337
		
338
		return apply_filters( "wpinv_get_discount_{$key}", $value, $this->ID, $this, $this->code, $this->data );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
339
340
	}
341
	
342
	/**
343
	 * Magic method for setting discount fields.
344
	 *
345
	 * This method does not update custom fields in the database.
346
	 *
347
	 * @since 1.0.14
348
	 * @access public
349
	 *
350
	 */
351
	public function __set( $key, $value ) {
352
		
353
		if ( 'id' == strtolower( $key ) ) {
354
			
355
			$this->ID = $value;
356
			$this->data['ID'] = $value;
357
			return;
358
			
359
		}
360
		
361
		$value = apply_filters( "wpinv_set_discount_{$key}", $value, $this->ID, $this, $this->code, $this->data );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
362
		$this->data[$key] = $value;
363
		
364
	}
365
	
366
	/**
367
	 * Saves (or updates) a discount to the database
368
	 *
369
	 * @since 1.0.14
370
	 * @access public
371
	 * @return bool
372
	 *
373
	 */
374
	public function save(){
375
		
376
		$data = self::sanitize_discount_data( $this->data );
377
378
		// Should we create a new post?
379
		if(! $data[ 'ID' ] ) {
380
381
			$id = wp_insert_post( array(
382
				'post_status'           => $data['status'],
383
				'post_type'             => 'wpi_discount',
384
				'post_excerpt'          => $data['description'],
385
			) );
386
387
			if( empty( $id ) ) {
388
				return false;
389
			}
390
391
			$data[ 'ID' ] = $id;
392
			$this->ID = $id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $id of type WP_Error or integer is incompatible with the declared type array of property $ID.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
393
			$this->data['ID'] = $id;
394
395
		} else {
396
			$this->update_status( $data['post_status'] );
397
		}
398
399
		$meta = apply_filters( 'wpinv_update_discount', $data, $this->ID, $this );
400
401
		do_action( 'wpinv_pre_update_discount', $meta, $this->ID, $this );
402
403
		foreach( wpinv_parse_list( 'ID date_created date_modified status description discount_type_name' ) as $prop ) {
404
			unset( $meta[$prop] );
405
		}
406
407
		if( empty( $meta['uses'] ) ) {
408
			unset( $meta['uses'] );
409
		}
410
411
		// Save the metadata
412
		foreach( $meta as $key => $value ) {
413
			update_post_meta( $this->ID, "_wpi_discount_$key", $value );
414
		}
415
		
416
		// Empty the cache for this discount.
417
		wp_cache_delete( $this->ID, 'WPInv_Discounts' );
418
		wp_cache_delete( $data['code'], 'WPInv_Discount_Codes' );
419
420
		do_action( 'wpinv_post_update_discount', $meta, $this->ID, $this );
421
422
		$data = self::get_data_by( 'id', $this->ID );
423
		$this->init( $data );
0 ignored issues
show
Bug introduced by
It seems like $data can also be of type false; however, parameter $data of WPInv_Discount::init() 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

423
		$this->init( /** @scrutinizer ignore-type */ $data );
Loading history...
424
425
		return true;		
426
	}
427
428
	/**
429
	 * Saves (or updates) a discount to the database
430
	 *
431
	 * @since 1.0.14
432
	 * @access public
433
	 * @return bool
434
	 *
435
	 */
436
	public function update_status( $status = 'publish' ){
437
438
439
		if( $this->exists() && $this->old_status != $status ) {
440
441
			do_action( 'wpinv_pre_update_discount_status', $this->ID, $this->old_status, $status );
442
        	$updated = wp_update_post( array( 'ID' => $this->ID, 'post_status' => $status ) );
443
			do_action( 'wpinv_post_update_discount_status', $this->ID, $this->old_status, $status );
444
445
			wp_cache_delete( $this->ID, 'WPInv_Discounts' );
0 ignored issues
show
Bug introduced by
$this->ID of type array is incompatible with the type integer|string expected by parameter $key of wp_cache_delete(). ( Ignorable by Annotation )

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

445
			wp_cache_delete( /** @scrutinizer ignore-type */ $this->ID, 'WPInv_Discounts' );
Loading history...
446
			wp_cache_delete( $this->code, 'WPInv_Discount_Codes' );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
447
448
			return $updated !== 0;
449
			
450
		}
451
452
		return false;		
453
	}
454
	
455
	
456
	/**
457
	 * Checks whether a discount exists in the database or not
458
	 * 
459
	 * @since 1.0.14
460
	 */
461
	public function exists(){
462
		return ! empty( $this->ID );
463
	}
464
	
465
	// Boolean methods
466
	
467
	/**
468
	 * Checks the discount type.
469
	 * 
470
	 * 
471
	 * @param  string $type the discount type to check against
472
	 * @since 1.0.14
473
	 * @return bool
474
	 */
475
	public function is_type( $type ) {
476
		return $this->type == $type;
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
477
	}
478
	
479
	/**
480
	 * Checks whether the discount is published or not
481
	 * 
482
	 * @since 1.0.14
483
	 * @return bool
484
	 */
485
	public function is_active() {
486
		return $this->post_status == 'publish';
0 ignored issues
show
Bug Best Practice introduced by
The property post_status does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
487
	}
488
	
489
	/**
490
	 * Checks whether the discount is has exided the usage limit or not
491
	 * 
492
	 * @since 1.0.14
493
	 * @return bool
494
	 */
495
	public function has_exceeded_limit() {
496
		if( empty( $this->max_uses ) || empty( $this->uses ) ) { 
0 ignored issues
show
Bug Best Practice introduced by
The property max_uses does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
497
			return false ;
498
		}
499
		
500
		$exceeded =  $this->uses >= $this->max_uses;
501
		return apply_filters( 'wpinv_is_discount_maxed_out', $exceeded, $this->ID, $this, $this->code );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
502
	}
503
	
504
	/**
505
	 * Checks if the discount is expired
506
	 * 
507
	 * @since 1.0.14
508
	 * @return bool
509
	 */
510
	public function is_expired() {
511
		$expired = empty ( $this->expires ) ? false : current_time( 'timestamp' ) > strtotime( $this->expires );
0 ignored issues
show
Bug Best Practice introduced by
The property expires does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
512
		return apply_filters( 'wpinv_is_discount_expired', $expired, $this->ID, $this, $this->code );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
513
	}
514
515
	/**
516
	 * Checks the discount start date.
517
	 * 
518
	 * @since 1.0.14
519
	 * @return bool
520
	 */
521
	public function has_started() {
522
		$started = empty ( $this->start ) ? true : current_time( 'timestamp' ) > strtotime( $this->start );
0 ignored issues
show
Bug Best Practice introduced by
The property start does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
523
		return apply_filters( 'wpinv_is_discount_started', $started, $this->ID, $this, $this->code );		
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
524
	}
525
	
526
	/**
527
	 * Check if a discount is valid for a given item id.
528
	 *
529
	 * @param  int|array  $item_ids
530
	 * @since 1.0.14
531
	 * @return boolean
532
	 */
533
	public function is_valid_for_items( $item_ids ) {
534
		 
535
		$item_ids = wpinv_parse_list( $item_ids );
536
		$included = array_intersect( $item_ids, $this->items );
0 ignored issues
show
Bug Best Practice introduced by
The property items does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
537
		$excluded = array_intersect( $item_ids, $this->excluded_items );
0 ignored issues
show
Bug Best Practice introduced by
The property excluded_items does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
538
539
		if( ! empty( $this->excluded_items ) && ! empty( $excluded ) ) {
540
			return false;
541
		}
542
543
		if( ! empty( $this->included_items ) && empty( $included ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The property included_items does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
544
			return false;
545
		}
546
		return true;
547
	}
548
	
549
	/**
550
	 * Check if a discount is valid for the given amount
551
	 *
552
	 * @param  float  $amount The amount to check against
553
	 * @since 1.0.14
554
	 * @return boolean
555
	 */
556
	public function is_valid_for_amount( $amount ) {
557
		
558
		// Amount passed is not valid;
559
		if(! is_numeric ( $amount ) ) {
0 ignored issues
show
introduced by
The condition is_numeric($amount) is always true.
Loading history...
560
			return false;
561
		}
562
563
		$amount = floatval( $amount );
564
565
		// check if it meets the minimum amount valid.
566
		if( $this->min_total > 0 && $amount < $this->min_total ) {
0 ignored issues
show
Bug Best Practice introduced by
The property min_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
567
			return false;
568
		}
569
570
		// check if it meets the maximum amount valid.
571
		if( $this->max_total > 0 && $amount > $this->max_total ) {
0 ignored issues
show
Bug Best Practice introduced by
The property max_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
572
			return false;
573
		}
574
575
		return true;
576
	}
577
578
	/**
579
	 * Checks if the minimum amount is met
580
	 *
581
	 * @param  float  $amount The amount to check against
582
	 * @since 1.0.14
583
	 * @return boolean
584
	 */
585
	public function is_minimum_amount_met( $amount ) {
586
		
587
		// Amount passed is not valid;
588
		if(! is_numeric ( $amount ) ) {
0 ignored issues
show
introduced by
The condition is_numeric($amount) is always true.
Loading history...
589
			return false;
590
		}
591
592
		$amount = floatval( $amount );
593
		$min_met= ! ( $this->min_total > 0 && $amount < $this->min_total );
0 ignored issues
show
Bug Best Practice introduced by
The property min_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
594
		return apply_filters( 'wpinv_is_discount_min_met', $min_met, $this->ID, $this, $this->code, $amount );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
595
	}
596
597
	/**
598
	 * Checks if the maximum amount is met
599
	 *
600
	 * @param  float  $amount The amount to check against
601
	 * @since 1.0.14
602
	 * @return boolean
603
	 */
604
	public function is_maximum_amount_met( $amount ) {
605
		
606
		// Amount passed is not valid;
607
		if(! is_numeric ( $amount ) ) {
0 ignored issues
show
introduced by
The condition is_numeric($amount) is always true.
Loading history...
608
			return false;
609
		}
610
611
		$amount = floatval( $amount );
612
		$max_met= ! ( $this->max_total > 0 && $amount > $this->max_total );
0 ignored issues
show
Bug Best Practice introduced by
The property max_total does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
613
		return apply_filters( 'wpinv_is_discount_max_met', $max_met, $this->ID, $this, $this->code, $amount );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
614
	}
615
616
	/**
617
	 * Check if a discount is valid for the given user
618
	 *
619
	 * @param  int|string  $user
620
	 * @since 1.0.14
621
	 * @return boolean
622
	 */
623
	public function is_valid_for_user( $user ) {
624
		global $wpi_checkout_id;
625
626
		if( empty( $user ) || empty( $this->single_use ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The property single_use does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
627
			return true;
628
		}
629
630
		$user_id = 0;
631
        if ( is_int( $user ) ) {
632
            $user_id = absint( $user );
633
        } else if ( is_email( $user ) && $user_data = get_user_by( 'email', $user ) ) {
634
            $user_id = $user_data->ID;
635
        } else if ( $user_data = get_user_by( 'login', $user ) ) {
636
            $user_id = $user_data->ID;
637
        } else if ( absint( $user ) > 0 ) {
638
            $user_id = absint( $user );
639
		}
640
641
		if( empty( $user_id ) ) {
642
			return true;
643
		}
644
		
645
		// Get all payments with matching user id
646
        $payments = wpinv_get_invoices( array( 'user' => $user_id, 'limit' => false ) ); 
647
		$code     = strtolower( $this->code );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
648
649
		foreach ( $payments as $payment ) {
650
651
			// Don't count discount used for current invoice checkout.
652
			if ( !empty( $wpi_checkout_id ) && $wpi_checkout_id == $payment->ID ) {
653
				continue;
654
			}
655
			
656
			if ( $payment->has_status( array( 'wpi-cancelled', 'wpi-failed' ) ) ) {
657
				continue;
658
			}
659
660
			$discounts = $payment->get_discounts( true );
661
			if ( empty( $discounts ) ) {
662
				continue;
663
			}
664
665
			$discounts = array_map( 'strtolower', wpinv_parse_list( $discounts ) );
666
			if ( ! empty( $discounts ) && in_array( $code, $discounts ) ) {
667
				return false;
668
			}
669
		}
670
671
		return true;
672
	}
673
674
	/**
675
	 * Deletes the discount from the database
676
	 *
677
	 * @since 1.0.14
678
	 * @return boolean
679
	 */
680
	public function remove() {
681
682
		if( empty( $this->ID ) ) {
683
			return true;
684
		}
685
686
		do_action( 'wpinv_pre_delete_discount', $this->ID );
687
		wp_cache_delete( $this->ID, 'WPInv_Discounts' );
0 ignored issues
show
Bug introduced by
$this->ID of type array is incompatible with the type integer|string expected by parameter $key of wp_cache_delete(). ( Ignorable by Annotation )

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

687
		wp_cache_delete( /** @scrutinizer ignore-type */ $this->ID, 'WPInv_Discounts' );
Loading history...
688
    	wp_delete_post( $this->ID, true );
0 ignored issues
show
Bug introduced by
$this->ID of type array is incompatible with the type integer expected by parameter $postid of wp_delete_post(). ( Ignorable by Annotation )

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

688
    	wp_delete_post( /** @scrutinizer ignore-type */ $this->ID, true );
Loading history...
689
		wp_cache_delete( $this->code, 'WPInv_Discount_Codes' );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
690
    	do_action( 'wpinv_post_delete_discount', $this->ID );
691
692
		$this->ID = null;
693
		$this->data['id'] = null;
694
		return true;
695
	}
696
697
	/**
698
	 * Increases a discount's usage.
699
	 *
700
	 * @since 1.0.14
701
	 * @param int $by The number of usages to increas by.
702
	 * @return bool
703
	 */
704
	public function increase_usage( $by = 1 ) {
705
706
		$this->uses = $this->uses + $by;
0 ignored issues
show
Bug Best Practice introduced by
The property uses does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
707
708
		if( $this->uses  < 0 ) {
709
			$this->uses = 0;
710
		}
711
712
		$this->save();
713
714
		if( $by > 0 ) {
715
			do_action( 'wpinv_discount_increase_use_count', $this->uses, $this->ID, $this->code, $by );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
716
		} else {
717
			do_action( 'wpinv_discount_decrease_use_count', $this->uses, $this->ID, $this->code, absint( $by ) );
718
		}
719
		
720
		return $this->uses;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->uses returns the type integer which is incompatible with the documented return type boolean.
Loading history...
721
	}
722
723
	/**
724
	 * Retrieves discount data
725
	 *
726
	 * @since 1.0.14
727
	 * @return array
728
	 */
729
	public function get_data() {
730
		$return = array();
731
		foreach( array_keys( $this->data ) as $key ) {
732
			$return[ $key ] = $this->$key;
733
		}
734
		return $return;
735
	}
736
737
	/**
738
	 * Retrieves discount data as json
739
	 *
740
	 * @since 1.0.14
741
	 * @return string
742
	 */
743
	public function get_data_as_json() {
744
		return wp_json_encode( $this->get_data() );
0 ignored issues
show
Bug Best Practice introduced by
The expression return wp_json_encode($this->get_data()) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
745
	}
746
747
	/**
748
	 * Checks if a discount can only be used once per user.
749
	 *
750
	 * @since 1.0.14
751
	 * @return bool
752
	 */
753
	public function get_is_single_use() {
754
		return (bool) apply_filters( 'wpinv_is_discount_single_use', $this->data['single_use'], $this->ID, $this, $this->code );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
755
	}
756
757
	/**
758
	 * Checks if a discount is recurring.
759
	 *
760
	 * @since 1.0.14
761
	 * @return bool
762
	 */
763
	public function get_is_recurring() {
764
		return (bool) apply_filters( 'wpinv_is_discount_recurring', $this->data['is_recurring'], $this->ID, $this->code, $this );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
765
	}
766
767
	/**
768
	 * Returns a discount's included items.
769
	 *
770
	 * @since 1.0.14
771
	 * @return array
772
	 */
773
	public function get_items() {
774
		return wpinv_parse_list( apply_filters( 'wpinv_get_discount_item_reqs', $this->data['items'], $this->ID, $this, $this->code ) );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
775
	}
776
777
	/**
778
	 * Returns a discount's discounted amount.
779
	 *
780
	 * @since 1.0.14
781
	 * @return float
782
	 */
783
	public function get_discounted_amount( $amount ) {
784
785
		if ( $this->type == 'flat' ) {
0 ignored issues
show
Bug Best Practice introduced by
The property type does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
786
            $amount = $amount - $this->amount;
0 ignored issues
show
Bug Best Practice introduced by
The property amount does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
787
		} else {
788
            $amount = $amount - ( $amount * ( $this->amount / 100 ) );
789
		}
790
791
		if ( $amount < 0 ) {
792
			$amount = 0;
793
		}
794
795
		return apply_filters( 'wpinv_discounted_amount', $amount, $this->ID, $this, $this->code, $this->amount );
0 ignored issues
show
Bug Best Practice introduced by
The property code does not exist on WPInv_Discount. Since you implemented __get, consider adding a @property annotation.
Loading history...
796
	}
797
	
798
}
799