Test Failed
Push — master ( 9f3342...e85998 )
by Devin
08:35
created

Give_Donate_Form   F

Complexity

Total Complexity 90

Size/Duplication

Total Lines 1212
Duplicated Lines 15.84 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 192
loc 1212
rs 0.8
c 0
b 0
f 0
wmc 90
lcom 1
cbo 2

31 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A setup_donation_form() 0 18 4
A __get() 0 10 2
A create() 0 36 2
A get_ID() 0 3 1
A get_name() 0 3 1
A get_price() 28 28 3
A get_minimum_price() 0 19 4
A get_maximum_price() 12 12 3
A get_prices() 0 19 2
A get_level_info() 0 19 5
B get_goal() 0 23 6
A is_single_price_mode() 20 20 3
A is_custom_price_mode() 0 20 2
A is_custom_price() 0 28 5
A has_variable_prices() 18 18 2
A get_type() 15 15 3
A get_form_classes() 0 19 2
A get_form_wrap_classes() 0 32 5
A is_set_type_donation_form() 0 5 2
A is_multi_type_donation_form() 0 6 2
A get_sales() 20 20 4
A increase_sales() 0 16 2
A decrease_sales() 0 23 3
A get_earnings() 20 20 4
A increase_earnings() 28 28 2
A decrease_earnings() 31 31 3
A is_close_donation_form() 0 22 2
A has_goal() 0 9 1
A update_meta() 0 16 3
B bc_210_is_close_donation_form() 0 38 6

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 Give_Donate_Form 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 Give_Donate_Form, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * Donate Form
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Donate_Form
7
 * @copyright   Copyright (c) 2015, GiveWP
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_Donate_Form Class.
19
 *
20
 * This class handles donation forms.
21
 *
22
 * @since 1.0
23
 *
24
 * @property $price
25
 * @property $minimum_price
26
 * @property $maximum_price
27
 * @property $prices
28
 * @property $goal
29
 * @property $sales
30
 * @property $earnings
31
 * @property $post_type
32
 */
33
class Give_Donate_Form {
34
35
	/**
36
	 * The donation ID.
37
	 *
38
	 * @since  1.0
39
	 * @access public
40
	 *
41
	 * @var    int
42
	 */
43
	public $ID = 0;
44
45
	/**
46
	 * The donation price.
47
	 *
48
	 * @since  1.0
49
	 * @access private
50
	 *
51
	 * @var    float
52
	 */
53
	private $price;
54
55
	/**
56
	 * The minimum donation price.
57
	 *
58
	 * @since  1.3.6
59
	 * @access private
60
	 *
61
	 * @var    float
62
	 */
63
	private $minimum_price;
64
65
	/**
66
	 * The maximum donation price.
67
	 *
68
	 * @since  2.0
69
	 * @access private
70
	 *
71
	 * @var    float
72
	 */
73
	private $maximum_price;
74
75
	/**
76
	 * The donation prices, if Price Levels are enabled.
77
	 *
78
	 * @since  1.0
79
	 * @access private
80
	 *
81
	 * @var    array
82
	 */
83
	private $prices;
84
85
	/**
86
	 * The donation goal.
87
	 *
88
	 * @since  1.0
89
	 * @access private
90
	 *
91
	 * @var    float
92
	 */
93
	private $goal;
94
95
	/**
96
	 * The form's sale count.
97
	 *
98
	 * @since  1.0
99
	 * @access private
100
	 *
101
	 * @var    int
102
	 */
103
	private $sales;
104
105
	/**
106
	 * The form's total earnings
107
	 *
108
	 * @since  1.0
109
	 * @access private
110
	 *
111
	 * @var    float
112
	 */
113
	private $earnings;
114
115
	/**
116
	 * Declare the default properties in WP_Post as we can't extend it
117
	 * Anything we've declared above has been removed.
118
	 */
119
120
	/**
121
	 * The post author
122
	 *
123
	 * @since  1.0
124
	 * @access public
125
	 *
126
	 * @var    int
127
	 */
128
	public $post_author = 0;
129
130
	/**
131
	 * The post date
132
	 *
133
	 * @since  1.0
134
	 * @access public
135
	 *
136
	 * @var    string
137
	 */
138
	public $post_date = '0000-00-00 00:00:00';
139
140
	/**
141
	 * The post GTM date
142
	 *
143
	 * @since  1.0
144
	 * @access public
145
	 *
146
	 * @var    string
147
	 */
148
	public $post_date_gmt = '0000-00-00 00:00:00';
149
150
	/**
151
	 * The post content
152
	 *
153
	 * @since  1.0
154
	 * @access public
155
	 *
156
	 * @var    string
157
	 */
158
	public $post_content = '';
159
160
	/**
161
	 * The post title
162
	 *
163
	 * @since  1.0
164
	 * @access public
165
	 *
166
	 * @var    string
167
	 */
168
	public $post_title = '';
169
170
	/**
171
	 * The post excerpt
172
	 *
173
	 * @since  1.0
174
	 * @access public
175
	 *
176
	 * @var    string
177
	 */
178
	public $post_excerpt = '';
179
180
	/**
181
	 * The post status
182
	 *
183
	 * @since  1.0
184
	 * @access public
185
	 *
186
	 * @var    string
187
	 */
188
	public $post_status = 'publish';
189
190
	/**
191
	 * The comment status
192
	 *
193
	 * @since  1.0
194
	 * @access public
195
	 *
196
	 * @var    string
197
	 */
198
	public $comment_status = 'open';
199
200
	/**
201
	 * The ping status
202
	 *
203
	 * @since  1.0
204
	 * @access public
205
	 *
206
	 * @var    string
207
	 */
208
	public $ping_status = 'open';
209
210
	/**
211
	 * The post password
212
	 *
213
	 * @since  1.0
214
	 * @access public
215
	 *
216
	 * @var    string
217
	 */
218
	public $post_password = '';
219
220
	/**
221
	 * The post name
222
	 *
223
	 * @since  1.0
224
	 * @access public
225
	 *
226
	 * @var    string
227
	 */
228
	public $post_name = '';
229
230
	/**
231
	 * Ping
232
	 *
233
	 * @since  1.0
234
	 * @access public
235
	 *
236
	 * @var    string
237
	 */
238
	public $to_ping = '';
239
240
	/**
241
	 * Pinged
242
	 *
243
	 * @since  1.0
244
	 * @access public
245
	 *
246
	 * @var    string
247
	 */
248
	public $pinged = '';
249
250
	/**
251
	 * The post modified date
252
	 *
253
	 * @since  1.0
254
	 * @access public
255
	 *
256
	 * @var    string
257
	 */
258
	public $post_modified = '0000-00-00 00:00:00';
259
260
	/**
261
	 * The post modified GTM date
262
	 *
263
	 * @since  1.0
264
	 * @access public
265
	 *
266
	 * @var    string
267
	 */
268
	public $post_modified_gmt = '0000-00-00 00:00:00';
269
270
	/**
271
	 * The post filtered content
272
	 *
273
	 * @since  1.0
274
	 * @access public
275
	 *
276
	 * @var    string
277
	 */
278
	public $post_content_filtered = '';
279
280
	/**
281
	 * The post parent
282
	 *
283
	 * @since  1.0
284
	 * @access public
285
	 *
286
	 * @var    int
287
	 */
288
	public $post_parent = 0;
289
290
	/**
291
	 * The post GUID
292
	 *
293
	 * @since  1.0
294
	 * @access public
295
	 *
296
	 * @var    string
297
	 */
298
	public $guid = '';
299
300
	/**
301
	 * The menu order
302
	 *
303
	 * @since  1.0
304
	 * @access public
305
	 *
306
	 * @var    int
307
	 */
308
	public $menu_order = 0;
309
310
	/**
311
	 * The mime type0
312
	 *
313
	 * @since  1.0
314
	 * @access public
315
	 *
316
	 * @var    string
317
	 */
318
	public $post_mime_type = '';
319
320
	/**
321
	 * The comment count
322
	 *
323
	 * @since  1.0
324
	 * @access public
325
	 *
326
	 * @var    int
327
	 */
328
	public $comment_count = 0;
329
330
	/**
331
	 * Filtered
332
	 *
333
	 * @since  1.0
334
	 * @access public
335
	 *
336
	 * @var    string
337
	 */
338
	public $filter;
339
340
	/**
341
	 * Class Constructor
342
	 *
343
	 * Set up the Give Donate Form Class.
344
	 *
345
	 * @since  1.0
346
	 * @access public
347
	 *
348
	 * @param  int|bool $_id   Post id. Default is false.
349
	 * @param  array    $_args Arguments passed.
350
	 */
351
	public function __construct( $_id = false, $_args = array() ) {
0 ignored issues
show
Unused Code introduced by
The parameter $_args is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
352
353
		$donation_form = WP_Post::get_instance( $_id );
354
355
		$this->setup_donation_form( $donation_form );
356
	}
357
358
	/**
359
	 * Given the donation form data, let's set the variables
360
	 *
361
	 * @since  1.5
362
	 * @access private
363
	 *
364
	 * @param  WP_Post $donation_form WP_Post Object for the donation form.
365
	 *
366
	 * @return bool                   If the setup was successful or not.
367
	 */
368
	private function setup_donation_form( $donation_form ) {
369
370
		// Bailout.
371
		if (
372
			! ( $donation_form instanceof WP_Post )
0 ignored issues
show
Bug introduced by
The class WP_Post does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
373
			|| 'give_forms' !== $donation_form->post_type
374
		) {
375
			return false;
376
		}
377
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
378
379
		foreach ( $donation_form as $key => $value ) {
380
			$this->$key = $value;
381
		}
382
383
		return true;
384
385
	}
386
387
	/**
388
	 * Magic __get function to dispatch a call to retrieve a private property
389
	 *
390
	 * @since  1.0
391
	 * @access public
392
	 *
393
	 * @param  string $key
394
	 *
395
	 * @return mixed
396
	 */
397
	public function __get( $key ) {
398
399
		if ( method_exists( $this, "get_{$key}" ) ) {
400
			return $this->{"get_{$key}"}();
401
		}
402
403
		/* translators: %s: property key */
404
		return new WP_Error( 'give-form-invalid-property', sprintf( esc_html__( 'Can\'t get property %s.', 'give' ), $key ) );
405
406
	}
407
408
	/**
409
	 * Creates a donation form
410
	 *
411
	 * @since  1.5
412
	 * @access public
413
	 *
414
	 * @param  array $data Array of attributes for a donation form.
415
	 *
416
	 * @return bool|int    False if data isn't passed and class not instantiated for creation, or New Form ID.
417
	 */
418
	public function create( $data = array() ) {
419
420
		if ( $this->id != 0 ) {
0 ignored issues
show
introduced by
Found "!= 0". Use Yoda Condition checks, you must
Loading history...
421
			return false;
422
		}
423
424
		$defaults = array(
425
			'post_type'   => 'give_forms',
426
			'post_status' => 'draft',
427
			'post_title'  => __( 'New Donation Form', 'give' ),
428
		);
429
430
		$args = wp_parse_args( $data, $defaults );
431
432
		/**
433
		 * Fired before a donation form is created
434
		 *
435
		 * @param array $args The post object arguments used for creation.
436
		 */
437
		do_action( 'give_form_pre_create', $args );
438
439
		$id = wp_insert_post( $args, true );
440
441
		$donation_form = WP_Post::get_instance( $id );
442
443
		/**
444
		 * Fired after a donation form is created
445
		 *
446
		 * @param int   $id   The post ID of the created item.
447
		 * @param array $args The post object arguments used for creation.
448
		 */
449
		do_action( 'give_form_post_create', $id, $args );
450
451
		return $this->setup_donation_form( $donation_form );
452
453
	}
454
455
	/**
456
	 * Retrieve the ID
457
	 *
458
	 * @since  1.0
459
	 * @access public
460
	 *
461
	 * @return int    Donation form ID.
462
	 */
463
	public function get_ID() {
0 ignored issues
show
Coding Style introduced by
The function name get_ID is in camel caps, but expected get_i_d instead as per the coding standard.
Loading history...
464
		return $this->ID;
465
	}
466
467
	/**
468
	 * Retrieve the donation form name
469
	 *
470
	 * @since  1.5
471
	 * @access public
472
	 *
473
	 * @return string Donation form name.
474
	 */
475
	public function get_name() {
476
		return get_the_title( $this->ID );
477
	}
478
479
	/**
480
	 * Retrieve the price
481
	 *
482
	 * @since  1.0
483
	 * @access public
484
	 *
485
	 * @return float  Price.
486
	 */
487 View Code Duplication
	public function get_price() {
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...
488
489
		if ( ! isset( $this->price ) ) {
490
491
			$this->price = give_maybe_sanitize_amount(
0 ignored issues
show
Documentation Bug introduced by
It seems like give_maybe_sanitize_amou...give_set_price', true)) can also be of type integer or string. However, the property $price is declared as type double. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
492
				give_get_meta(
493
					$this->ID,
494
					'_give_set_price',
495
					true
496
				)
497
			);
498
499
			if ( ! $this->price ) {
500
				$this->price = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $price was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
501
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
502
503
		}
504
505
		/**
506
		 * Override the donation form set price.
507
		 *
508
		 * @since 1.0
509
		 *
510
		 * @param string     $price The donation form price.
511
		 * @param string|int $id    The form ID.
512
		 */
513
		return apply_filters( 'give_get_set_price', $this->price, $this->ID );
514
	}
515
516
	/**
517
	 * Retrieve the minimum price.
518
	 *
519
	 * @since  1.3.6
520
	 * @access public
521
	 *
522
	 * @return float  Minimum price.
523
	 */
524
	public function get_minimum_price() {
525
526
		if ( ! isset( $this->minimum_price ) ) {
527
528
			$this->minimum_price = give_get_meta( $this->ID, '_give_custom_amount_range_minimum', true );
529
530
			// Give backward < 2.1
531
			if ( empty( $this->minimum_price ) ) {
532
				$this->minimum_price = give_get_meta( $this->ID, '_give_custom_amount_minimum', true );
533
			}
534
535
			if ( ! $this->is_custom_price_mode() ) {
536
				$this->minimum_price = give_get_lowest_price_option( $this->ID );
537
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
538
539
		}
540
541
		return apply_filters( 'give_get_set_minimum_price', $this->minimum_price, $this->ID );
542
	}
543
544
	/**
545
	 * Retrieve the maximum price.
546
	 *
547
	 * @since  2.1
548
	 * @access public
549
	 *
550
	 * @return float  Maximum price.
551
	 */
552 View Code Duplication
	public function get_maximum_price() {
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...
553
554
		if ( ! isset( $this->maximum_price ) ) {
555
			$this->maximum_price = give_get_meta( $this->ID, '_give_custom_amount_range_maximum', true, 999999.99 );
0 ignored issues
show
Documentation introduced by
999999.99 is of type double, but the function expects a boolean.

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...
556
557
			if ( ! $this->is_custom_price_mode() ) {
558
				$this->maximum_price = give_get_highest_price_option( $this->ID );
559
			}
560
		}
561
562
		return apply_filters( 'give_get_set_maximum_price', $this->maximum_price, $this->ID );
563
	}
564
565
	/**
566
	 * Retrieve the variable prices
567
	 *
568
	 * @since  1.0
569
	 * @access public
570
	 *
571
	 * @return array  Variable prices.
572
	 */
573
	public function get_prices() {
574
575
		if ( ! isset( $this->prices ) ) {
576
577
			$this->prices = give_get_meta( $this->ID, '_give_donation_levels', true );
0 ignored issues
show
Documentation Bug introduced by
It seems like give_get_meta($this->ID,...donation_levels', true) of type * is incompatible with the declared type array of property $prices.

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...
578
579
		}
580
581
		/**
582
		 * Override multi-level prices
583
		 *
584
		 * @since 1.0
585
		 *
586
		 * @param array      $prices The array of mulit-level prices.
587
		 * @param int|string $ID     The ID of the form.
588
		 */
589
		return apply_filters( 'give_get_donation_levels', $this->prices, $this->ID );
590
591
	}
592
593
	/**
594
	 * Get donation form level info
595
	 *
596
	 * @since  2.0.6
597
	 * @access public
598
	 *
599
	 * @param $price_id
600
	 *
601
	 * @return array|null
602
	 */
603
	public function get_level_info( $price_id ) {
604
		$level_info = array();
605
606
		// Bailout.
607
		if ( 'multi' !== $this->get_type() ) {
608
			return null;
609
		} elseif ( ! ( $levels = $this->get_prices() ) ) {
610
			return $level_info;
611
		}
612
613
		foreach ( $levels as $level ) {
614
			if ( $price_id === $level['_give_id']['level_id'] ) {
615
				$level_info = $level;
616
				break;
617
			}
618
		}
619
620
		return $level_info;
621
	}
622
623
624
	/**
625
	 * Retrieve the goal
626
	 *
627
	 * @since  1.0
628
	 * @access public
629
	 *
630
	 * @return float  Goal.
631
	 */
632
	public function get_goal() {
633
634
		if ( ! isset( $this->goal ) ) {
635
636
			$goal_format = give_get_form_goal_format( $this->ID );
637
638
			if( ! $this->has_goal() ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
639
				$this->goal = '';
0 ignored issues
show
Documentation Bug introduced by
The property $goal was declared of type double, but '' is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
640
641
			} elseif ( 'donation' === $goal_format ) {
642
				$this->goal = give_get_meta( $this->ID, '_give_number_of_donation_goal', true );
643
644
			} elseif ( 'donors' === $goal_format ) {
645
				$this->goal = give_get_meta( $this->ID, '_give_number_of_donor_goal', true );
646
647
			} elseif( 'amount' === $goal_format ) {
0 ignored issues
show
introduced by
Space after opening control structure is required
Loading history...
introduced by
No space before opening parenthesis is prohibited
Loading history...
648
				$this->goal = give_get_meta( $this->ID, '_give_set_goal', true );
649
			}
650
		}
651
652
		return apply_filters( 'give_get_set_goal', $this->goal, $this->ID );
653
654
	}
655
656
	/**
657
	 * Determine if single price mode is enabled or disabled
658
	 *
659
	 * @since  1.0
660
	 * @access public
661
	 *
662
	 * @return bool
663
	 */
664 View Code Duplication
	public function is_single_price_mode() {
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...
665
666
		$option = give_get_meta( $this->ID, '_give_price_option', true );
667
		$ret    = 0;
668
669
		if ( empty( $option ) || $option === 'set' ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
670
			$ret = 1;
671
		}
672
673
		/**
674
		 * Override the price mode for a donation when checking if is in single price mode.
675
		 *
676
		 * @since 1.0
677
		 *
678
		 * @param bool       $ret Is donation form in single price mode?
679
		 * @param int|string $ID  The ID of the donation form.
680
		 */
681
		return (bool) apply_filters( 'give_single_price_option_mode', $ret, $this->ID );
682
683
	}
684
685
	/**
686
	 * Determine if custom price mode is enabled or disabled
687
	 *
688
	 * @since  1.6
689
	 * @access public
690
	 *
691
	 * @return bool
692
	 */
693
	public function is_custom_price_mode() {
694
695
		$option = give_get_meta( $this->ID, '_give_custom_amount', true );
696
		$ret    = 0;
697
698
		if ( give_is_setting_enabled( $option ) ) {
699
			$ret = 1;
700
		}
701
702
		/**
703
		 * Override the price mode for a donation when checking if is in custom price mode.
704
		 *
705
		 * @since 1.6
706
		 *
707
		 * @param bool       $ret Is donation form in custom price mode?
708
		 * @param int|string $ID  The ID of the donation form.
709
		 */
710
		return (bool) apply_filters( 'give_custom_price_option_mode', $ret, $this->ID );
711
712
	}
713
714
	/**
715
	 * Determine if custom price mode is enabled or disabled
716
	 *
717
	 * @since  1.8.18
718
	 * @access public
719
	 *
720
	 * @param string|float $amount Donation Amount.
721
	 *
722
	 * @return bool
723
	 */
724
	public function is_custom_price( $amount ) {
725
		$result = false;
726
		$amount = give_maybe_sanitize_amount( $amount );
727
728
		if ( $this->is_custom_price_mode() ) {
729
730
			if ( 'set' === $this->get_type() ) {
731
				if ( $amount !== $this->get_price() ) {
732
					$result = true;
733
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
734
735
			} elseif ( 'multi' === $this->get_type() ) {
736
				$level_amounts = array_map( 'give_maybe_sanitize_amount', wp_list_pluck( $this->get_prices(), '_give_amount' ) );
737
				$result        = ! in_array( $amount, $level_amounts );
738
			}
739
		}
740
741
		/**
742
		 * Filter to reset whether it is custom price or not.
743
		 *
744
		 * @param bool         $result True/False.
745
		 * @param string|float $amount Donation Amount.
746
		 * @param int          $this   ->ID Form ID.
747
		 *
748
		 * @since 1.8.18
749
		 */
750
		return (bool) apply_filters( 'give_is_custom_price', $result, $amount, $this->ID );
751
	}
752
753
	/**
754
	 * Has Variable Prices
755
	 *
756
	 * Determine if the donation form has variable prices enabled
757
	 *
758
	 * @since  1.0
759
	 * @access public
760
	 *
761
	 * @return bool
762
	 */
763 View Code Duplication
	public function has_variable_prices() {
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...
764
765
		$option = give_get_meta( $this->ID, '_give_price_option', true );
766
		$ret    = 0;
767
768
		if ( $option === 'multi' ) {
0 ignored issues
show
introduced by
Found "=== '". Use Yoda Condition checks, you must
Loading history...
769
			$ret = 1;
770
		}
771
772
		/**
773
		 * Filter: Override whether the donation form has variables prices.
774
		 *
775
		 * @param bool       $ret Does donation form have variable prices?
776
		 * @param int|string $ID  The ID of the donation form.
777
		 */
778
		return (bool) apply_filters( 'give_has_variable_prices', $ret, $this->ID );
779
780
	}
781
782
	/**
783
	 * Retrieve the donation form type, set or multi-level
784
	 *
785
	 * @since  1.5
786
	 * @access public
787
	 *
788
	 * @return string Type of donation form, either 'set' or 'multi'.
789
	 */
790 View Code Duplication
	public function get_type() {
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...
791
792
		if ( ! isset( $this->type ) ) {
793
794
			$this->type = give_get_meta( $this->ID, '_give_price_option', true );
795
796
			if ( empty( $this->type ) ) {
797
				$this->type = 'set';
798
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
799
800
		}
801
802
		return apply_filters( 'give_get_form_type', $this->type, $this->ID );
803
804
	}
805
806
	/**
807
	 * Get form tag classes.
808
	 *
809
	 * Provides the classes for the donation <form> html tag and filters for customization.
810
	 *
811
	 * @since  1.6
812
	 * @access public
813
	 *
814
	 * @param  $args
815
	 *
816
	 * @return string
817
	 */
818
	public function get_form_classes( $args ) {
819
820
		$float_labels_option = give_is_float_labels_enabled( $args )
821
			? 'float-labels-enabled'
822
			: '';
823
824
		$form_classes_array = apply_filters( 'give_form_classes', array(
825
			'give-form',
826
			'give-form-' . $this->ID,
827
			'give-form-type-' . $this->get_type(),
828
			$float_labels_option,
829
		), $this->ID, $args );
830
831
		// Remove empty class names.
832
		$form_classes_array = array_filter( $form_classes_array );
833
834
		return implode( ' ', $form_classes_array );
835
836
	}
837
838
	/**
839
	 * Get form wrap Classes.
840
	 *
841
	 * Provides the classes for the donation form div wrapper and filters for customization.
842
	 *
843
	 * @access public
844
	 *
845
	 * @param  $args
846
	 *
847
	 * @return string
848
	 */
849
	public function get_form_wrap_classes( $args ) {
850
		$custom_class = array(
851
			'give-form-wrap',
852
		);
853
854
		if ( $this->is_close_donation_form() ) {
855
			$custom_class[] = 'give-form-closed';
856
		} else {
857
			$display_option = ( isset( $args['display_style'] ) && ! empty( $args['display_style'] ) )
858
				? $args['display_style']
859
				: give_get_meta( $this->ID, '_give_payment_display', true );
860
861
			$custom_class[] = "give-display-{$display_option}";
862
863
			// If admin want to show only button for form then user inbuilt modal functionality.
864
			if ( 'button' === $display_option ) {
865
				$custom_class[] = 'give-display-button-only';
866
			}
867
		}
868
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
869
870
		/**
871
		 * Filter the donation form classes.
872
		 *
873
		 * @since 1.0
874
		 */
875
		$form_wrap_classes_array = (array) apply_filters( 'give_form_wrap_classes', $custom_class, $this->ID, $args );
876
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
877
878
		return implode( ' ', $form_wrap_classes_array );
879
880
	}
881
882
	/**
883
	 * Get if form type set or not.
884
	 *
885
	 * @since  1.6
886
	 * @access public
887
	 *
888
	 * @return bool
889
	 */
890
	public function is_set_type_donation_form() {
891
		$form_type = $this->get_type();
892
893
		return ( 'set' === $form_type ? true : false );
894
	}
895
896
	/**
897
	 * Get if form type multi or not.
898
	 *
899
	 * @since  1.6
900
	 * @access public
901
	 *
902
	 * @return bool True if form type is 'multi' and false otherwise.
903
	 */
904
	public function is_multi_type_donation_form() {
905
		$form_type = $this->get_type();
906
907
		return ( 'multi' === $form_type ? true : false );
908
909
	}
910
911
	/**
912
	 * Retrieve the sale count for the donation form
913
	 *
914
	 * @since  1.0
915
	 * @access public
916
	 *
917
	 * @return int    Donation form sale count.
918
	 */
919 View Code Duplication
	public function get_sales() {
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...
920
921
		if ( ! isset( $this->sales ) ) {
922
923
			if ( '' == give_get_meta( $this->ID, '_give_form_sales', true ) ) {
924
				add_post_meta( $this->ID, '_give_form_sales', 0 );
925
			} // End if
926
927
			$this->sales = give_get_meta( $this->ID, '_give_form_sales', true );
928
929
			if ( $this->sales < 0 ) {
930
				// Never let sales be less than zero.
931
				$this->sales = 0;
932
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
933
934
		}
935
936
		return $this->sales;
937
938
	}
939
940
	/**
941
	 * Increment the sale count by one
942
	 *
943
	 * @since  1.0
944
	 * @access public
945
	 *
946
	 * @param  int $quantity The quantity to increase the donations by. Default is 1.
947
	 *
948
	 * @return int|false     New number of total sales.
949
	 */
950
	public function increase_sales( $quantity = 1 ) {
951
952
		$sales       = give_get_form_sales_stats( $this->ID );
953
		$quantity    = absint( $quantity );
954
		$total_sales = $sales + $quantity;
955
956
		if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
957
958
			$this->sales = $total_sales;
959
960
			return $this->sales;
961
962
		}
963
964
		return false;
965
	}
966
967
	/**
968
	 * Decrement the sale count by one
969
	 *
970
	 * @since  1.0
971
	 * @access public
972
	 *
973
	 * @param  int $quantity The quantity to decrease by. Default is 1.
974
	 *
975
	 * @return int|false     New number of total sales.
976
	 */
977
	public function decrease_sales( $quantity = 1 ) {
978
979
		$sales = give_get_form_sales_stats( $this->ID );
980
981
		// Only decrease if not already zero
982
		if ( $sales > 0 ) {
983
984
			$quantity    = absint( $quantity );
985
			$total_sales = $sales - $quantity;
986
987
			if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
988
989
				$this->sales = $sales;
0 ignored issues
show
Documentation Bug introduced by
It seems like $sales can also be of type double. However, the property $sales is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
990
991
				return $sales;
992
993
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
994
995
		}
996
997
		return false;
998
999
	}
1000
1001
	/**
1002
	 * Retrieve the total earnings for the form
1003
	 *
1004
	 * @since  1.0
1005
	 * @access public
1006
	 *
1007
	 * @return float  Donation form total earnings.
1008
	 */
1009 View Code Duplication
	public function get_earnings() {
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...
1010
1011
		if ( ! isset( $this->earnings ) ) {
1012
1013
			if ( '' == give_get_meta( $this->ID, '_give_form_earnings', true ) ) {
1014
				add_post_meta( $this->ID, '_give_form_earnings', 0 );
1015
			}
1016
1017
			$this->earnings = give_get_meta( $this->ID, '_give_form_earnings', true );
1018
1019
			if ( $this->earnings < 0 ) {
1020
				// Never let earnings be less than zero
1021
				$this->earnings = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $earnings was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1022
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
1023
1024
		}
1025
1026
		return $this->earnings;
1027
1028
	}
1029
1030
	/**
1031
	 * Increase the earnings by the given amount
1032
	 *
1033
	 * @since  1.0
1034
	 * @since  2.1 Pass the donation ID.
1035
	 *
1036
	 * @access public
1037
	 *
1038
	 * @param  int $amount     Amount of donation. Default is 0.
1039
	 * @param int  $payment_id Donation ID.
1040
	 *
1041
	 * @return float|false
1042
	 */
1043 View Code Duplication
	public function increase_earnings( $amount = 0, $payment_id = 0 ) {
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...
1044
1045
		$earnings   = give_get_form_earnings_stats( $this->ID );
1046
1047
		/**
1048
		 * Modify the earning amount when increasing.
1049
		 *
1050
		 * @since 2.1
1051
		 *
1052
		 * @param float $amount     Earning amount.
1053
		 * @param int   $form_id    Donation form ID.
1054
		 * @param int   $payment_id Donation ID.
1055
		 */
1056
		$amount = apply_filters( 'give_increase_form_earnings_amount', $amount, $this->ID, $payment_id );
1057
1058
		$new_amount = $earnings + (float) $amount;
1059
1060
		if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
1061
1062
			$this->earnings = $new_amount;
1063
1064
			return $this->earnings;
1065
1066
		}
1067
1068
		return false;
1069
1070
	}
1071
1072
	/**
1073
	 * Decrease the earnings by the given amount
1074
	 *
1075
	 * @since  1.0
1076
	 * @access public
1077
	 *
1078
	 * @param  int $amount     Amount of donation.
1079
	 * @param int  $payment_id Donation ID.
1080
	 *
1081
	 * @return float|false
1082
	 */
1083 View Code Duplication
	public function decrease_earnings( $amount, $payment_id = 0 ) {
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...
1084
1085
		$earnings = give_get_form_earnings_stats( $this->ID );
1086
1087
		if ( $earnings > 0 ) {
1088
1089
			/**
1090
			 * Modify the earning value when decreasing it.
1091
			 *
1092
			 * @since 2.1
1093
			 *
1094
			 * @param float $amount     Earning amount.
1095
			 * @param int   $form_id    Donation Form ID.
1096
			 * @param int   $payment_id Donation ID.
1097
			 */
1098
			$amount = apply_filters( 'give_decrease_form_earnings_amount', $amount, $this->ID, $payment_id );
1099
1100
			// Only decrease if greater than zero
1101
			$new_amount = $earnings - (float) $amount;
1102
1103
			if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
1104
				$this->earnings = $new_amount;
1105
1106
				return $this->earnings;
1107
			}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
1108
1109
		}
1110
1111
		return false;
1112
1113
	}
1114
1115
	/**
1116
	 * Determine if donation form closed or not
1117
	 *
1118
	 * Form will be close if:
1119
	 *  a. form has fixed goal
1120
	 *  b. close form when goal achieved cmb2 setting is set to 'Yes'
1121
	 *  c. goal has been achieved
1122
	 *
1123
	 * @since  1.4.5
1124
	 * @access public
1125
	 *
1126
	 * @return bool
1127
	 */
1128
	public function is_close_donation_form() {
1129
		$is_closed = ( 'closed' === give_get_meta( $this->ID, '_give_form_status', true, 'open' ) );
0 ignored issues
show
Documentation introduced by
'open' is of type string, but the function expects a boolean.

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...
1130
1131
		// If manual upgrade not completed, proceed with backward compatible code.
1132
		if ( ! give_has_upgrade_completed( 'v210_verify_form_status_upgrades' ) ) {
1133
1134
			// Check for backward compatibility.
1135
			$is_closed = $this->bc_210_is_close_donation_form();
1136
		}
1137
1138
		/**
1139
		 * Filter the close form result.
1140
		 *
1141
		 * @since 1.8
1142
		 */
1143
		return apply_filters(
1144
			'give_is_close_donation_form',
1145
			$is_closed,
1146
			$this
1147
		);
1148
1149
	}
1150
1151
1152
	/**
1153
	 * Check whether donation form has goal or not
1154
	 *
1155
	 * @since  2.4.2
1156
	 * @access public
1157
	 *
1158
	 * @return bool
1159
	 */
1160
	public function has_goal() {
1161
		return give_is_setting_enabled(
1162
			Give()->form_meta->get_meta(
1163
				$this->ID,
1164
				'_give_goal_option',
1165
				true
1166
			)
1167
		);
1168
	}
1169
1170
	/**
1171
	 * Updates a single meta entry for the donation form
1172
	 *
1173
	 * @since  1.5
1174
	 * @access private
1175
	 *
1176
	 * @param  string              $meta_key   The meta_key to update.
1177
	 * @param  string|array|object $meta_value The value to put into the meta.
1178
	 *
1179
	 * @return bool                            The result of the update query.
1180
	 */
1181
	private function update_meta( $meta_key = '', $meta_value = '' ) {
1182
1183
		/* @var WPDB $wpdb */
1184
		global $wpdb;
1185
1186
		// Bailout.
1187
		if ( empty( $meta_key ) ) {
1188
			return false;
1189
		}
1190
1191
		if ( give_update_meta( $this->ID, $meta_key, $meta_value ) ) {
1192
			return true;
1193
		}
1194
1195
		return false;
1196
	}
1197
1198
	/**
1199
	 * Backward Compatible function for is_close_donation_form()
1200
	 *
1201
	 * @since 2.1.0
1202
	 *
1203
	 * @return bool
1204
	 */
1205
	private function bc_210_is_close_donation_form() {
1206
1207
		$close_form      = false;
1208
		$is_goal_enabled = give_is_setting_enabled( give_get_meta( $this->ID, '_give_goal_option', true, 'disabled' ) );
0 ignored issues
show
Documentation introduced by
'disabled' is of type string, but the function expects a boolean.

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...
1209
1210
		// Proceed, if the form goal is enabled.
1211
		if ( $is_goal_enabled ) {
1212
1213
			$close_form_when_goal_achieved = give_is_setting_enabled( give_get_meta( $this->ID, '_give_close_form_when_goal_achieved', true, 'disabled' ) );
0 ignored issues
show
Documentation introduced by
'disabled' is of type string, but the function expects a boolean.

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...
1214
1215
			// Proceed, if close form when goal achieved option is enabled.
1216
			if ( $close_form_when_goal_achieved ) {
1217
1218
				$form        = new Give_Donate_Form( $this->ID );
1219
				$goal_format = give_get_form_goal_format( $this->ID );
1220
1221
				// Verify whether the form is closed or not after processing data based on goal format.
1222
				switch ( $goal_format ) {
1223
					case 'donation':
1224
						$closed = $form->get_goal() <= $form->get_sales();
1225
						break;
1226
					case 'donors':
1227
						$closed = $form->get_goal() <= give_get_form_donor_count( $this->ID );
1228
						break;
1229
					default :
1230
						$closed = $form->get_goal() <= $form->get_earnings();
1231
						break;
1232
				}
1233
1234
				if ( $closed ) {
1235
					$close_form = true;
1236
				}
0 ignored issues
show
introduced by
Blank line found after control structure
Loading history...
1237
1238
			}
1239
		}
1240
1241
		return $close_form;
1242
	}
1243
1244
}
1245