Completed
Pull Request — master (#664)
by Devin
19:01
created

Give_Donate_Form   C

Complexity

Total Complexity 63

Size/Duplication

Total Lines 653
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 56.74%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 653
rs 5.4614
ccs 80
cts 141
cp 0.5674
wmc 63
lcom 1
cbo 0

21 Methods

Rating   Name   Duplication   Size   Complexity  
A get_ID() 0 5 1
A get_type() 0 15 3
A __construct() 0 7 1
B setup_donation_form() 0 29 5
A __get() 0 13 2
B create() 0 36 2
A get_name() 0 3 1
B get_price() 0 28 3
A get_minimum_price() 0 21 4
A get_prices() 0 19 2
A get_goal() 0 21 3
A is_single_price_mode() 0 20 3
A has_variable_prices() 0 18 2
A get_sales() 0 20 4
A get_earnings() 0 20 4
A increase_earnings() 0 16 2
A decrease_earnings() 0 22 3
B is_free() 0 18 7
A increase_sales() 0 16 2
A decrease_sales() 0 23 3
B update_meta() 0 29 6

How to fix   Complexity   

Complex Class

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 Object
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Forms
7
 * @copyright   Copyright (c) 2015, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.0
10
 */
11
12
/**
13
 * Give_Donate_Form Class
14
 *
15
 * @since 1.0
16
 */
17
class Give_Donate_Form {
18
19
	/**
20
	 * The donation ID
21
	 *
22
	 * @since 1.0
23
	 */
24
	public $ID = 0;
25
26
	/**
27
	 * The donation price
28
	 *
29
	 * @since 1.0
30
	 */
31
	private $price;
32
33
	/**
34
	 * The minimum donation price
35
	 *
36
	 * @since 1.3.6
37
	 */
38
	private $minimum_price;
39
40
	/**
41
	 * The donation goal
42
	 *
43
	 * @since 1.0
44
	 */
45
	private $goal;
46
47
	/**
48
	 * The donation prices, if Price Levels are enabled
49
	 *
50
	 * @since 1.0
51
	 */
52
	private $prices;
53
54
	/**
55
	 * The form's sale count
56
	 *
57
	 * @since 1.0
58
	 */
59
	private $sales;
60
61
	/**
62
	 * The form's total earnings
63
	 *
64
	 * @since 1.0
65
	 */
66
	private $earnings;
67
68
	/**
69
	 * Declare the default properties in WP_Post as we can't extend it
70
	 * Anything we've declared above has been removed.
71
	 */
72
	public $post_author = 0;
73
	public $post_date = '0000-00-00 00:00:00';
74
	public $post_date_gmt = '0000-00-00 00:00:00';
75
	public $post_content = '';
76 40
	public $post_title = '';
77
	public $post_excerpt = '';
78 40
	public $post_status = 'publish';
79
	public $comment_status = 'open';
80
	public $ping_status = 'open';
81
	public $post_password = '';
82
	public $post_name = '';
83
	public $to_ping = '';
84
	public $pinged = '';
85
	public $post_modified = '0000-00-00 00:00:00';
86
	public $post_modified_gmt = '0000-00-00 00:00:00';
87
	public $post_content_filtered = '';
88
	public $post_parent = 0;
89
	public $guid = '';
90
	public $menu_order = 0;
91
	public $post_mime_type = '';
92 40
	public $comment_count = 0;
93
	public $filter;
94 40
95
	/**
96
	 * Give_Donate_Form constructor.
97
	 *
98 40
	 * @since 1.0
99
	 *
100
	 * @param bool $_id
101
	 * @param array $_args
102 40
	 */
103
	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...
104
105
106 40
		$donation_form = WP_Post::get_instance( $_id );
107
108 40
		return $this->setup_donation_form( $donation_form );
109
	}
110 40
111
	/**
112 40
	 * Given the donation form data, let's set the variables
113
	 *
114
	 * @since  1.5
115
	 *
116
	 * @param  object $donation_form The Donation Form Object
117
	 *
118
	 * @return bool             If the setup was successful or not
119
	 */
120
	private function setup_donation_form( $donation_form ) {
121
122
		if ( ! is_object( $donation_form ) ) {
123
			return false;
124 11
		}
125
126 11
		if ( ! is_a( $donation_form, 'WP_Post' ) ) {
127
			return false;
128 11
		}
129
130
		if ( 'give_forms' !== $donation_form->post_type ) {
131
			return false;
132
		}
133
134
		foreach ( $donation_form as $key => $value ) {
135
136
			switch ( $key ) {
137
138
				default:
0 ignored issues
show
Unused Code introduced by
default: $this->{$key} = $value; break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
139
					$this->$key = $value;
140
					break;
141
142
			}
143
144 1
		}
145
146 1
		return true;
147
148
	}
149
150
	/**
151
	 * Magic __get function to dispatch a call to retrieve a private property
152
	 *
153
	 * @since 1.0
154
	 *
155
	 * @param $key
156 11
	 *
157
	 * @return mixed
158 11
	 * @throws Exception
159
	 */
160 11
	public function __get( $key ) {
161
162 11
		if ( method_exists( $this, 'get_' . $key ) ) {
163
164 1
			return call_user_func( array( $this, 'get_' . $key ) );
165
166 1
		} else {
167
168 10
			return new WP_Error( 'give-form-invalid-property', sprintf( __( 'Can\'t get property %s', 'give' ), $key ) );
169
170
		}
171
172 11
	}
173
174 11
175
	/**
176
	 * Creates a donation form
177
	 *
178
	 * @since  1.5
179
	 *
180
	 * @param  array $data Array of attributes for a donation form
181
	 *
182
	 * @return mixed  false if data isn't passed and class not instantiated for creation, or New Form ID
183 2
	 */
184
	public function create( $data = array() ) {
185 2
186
		if ( $this->id != 0 ) {
0 ignored issues
show
Documentation introduced by
The property id does not exist on object<Give_Donate_Form>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
187 2
			return false;
188 2
		}
189
190 2
		$defaults = array(
191
			'post_type'   => 'give_forms',
192 1
			'post_status' => 'draft',
193
			'post_title'  => __( 'New Donation Form', 'give' )
194 1
		);
195
196 1
		$args = wp_parse_args( $data, $defaults );
197
198
		/**
199
		 * Fired before a donation form is created
200 2
		 *
201
		 * @param array $args The post object arguments used for creation.
202 2
		 */
203
		do_action( 'give_form_pre_create', $args );
204
205
		$id = wp_insert_post( $args, true );
206
207
		$donation_form = WP_Post::get_instance( $id );
208
209
		/**
210
		 * Fired after a donation form is created
211 12
		 *
212
		 * @param int $id The post ID of the created item.
213 12
		 * @param array $args The post object arguments used for creation.
214
		 */
215 12
		do_action( 'give_form_post_create', $id, $args );
216
217 12
		return $this->setup_donation_form( $donation_form );
218
219 12
	}
220
221
	/**
222
	 * Retrieve the ID
223
	 *
224
	 * @since 1.0
225
	 * @return int
226
	 */
227
	public function get_ID() {
228
229 2
		return $this->ID;
230
231 2
	}
232
233 2
	/**
234
	 * Retrieve the donation form name
235 2
	 *
236
	 * @since 1.5
237 1
	 * @return string Name of the donation form
238
	 */
239 1
	public function get_name() {
240
		return get_the_title( $this->ID );
241 2
	}
242
243
	/**
244
	 * Retrieve the price
245 2
	 *
246
	 * @since 1.0
247 2
	 * @return float
248
	 */
249
	public function get_price() {
250
251
		if ( ! isset( $this->price ) ) {
252
253
			$this->price = get_post_meta( $this->ID, '_give_set_price', true );
254
255
			if ( $this->price ) {
256
257 2
				$this->price = give_sanitize_amount( $this->price );
258
259 2
			} else {
260 2
261
				$this->price = 0;
262 2
263 1
			}
264 1
265
		}
266 2
267
		/**
268
		 * Override the donation form set price.
269
		 *
270
		 * @since 1.0
271
		 *
272
		 * @param string $price The donation form price.
273
		 * @param string|int $id The form ID.
274
		 */
275
		return apply_filters( 'give_get_set_price', $this->price, $this->ID );
276
	}
277
278 37
	/**
279
	 * Retrieve the minimum price
280 37
	 *
281 37
	 * @since 1.3.6
282
	 * @return float
283 37
	 */
284 36
	public function get_minimum_price() {
285 36
286
		if ( ! isset( $this->minimum_price ) ) {
287 37
288
			$allow_custom_amount = get_post_meta( $this->ID, '_give_custom_amount', true );
289
			$this->minimum_price = get_post_meta( $this->ID, '_give_custom_amount_minimum', true );
290
291
			if ( $allow_custom_amount != 'no' && $this->minimum_price ) {
292
293
				$this->minimum_price = give_sanitize_amount( $this->minimum_price );
294
295
			} else {
296
297
				$this->minimum_price = 0;
298 10
299
			}
300 10
301
		}
302 10
303 10
		return apply_filters( 'give_get_set_minimum_price', $this->minimum_price, $this->ID );
304 10
	}
305
306 10
	/**
307
	 * Retrieve the variable prices
308 10
	 *
309
	 * @since 1.0
310
	 * @return array
311
	 */
312
	public function get_prices() {
313 10
314
		if ( ! isset( $this->prices ) ) {
315 10
316
			$this->prices = get_post_meta( $this->ID, '_give_donation_levels', true );
317
318
		}
319
320
		/**
321
		 * Override multi-level prices
322
		 *
323
		 * @since 1.0
324
		 *
325
		 * @param array $prices The array of mulit-level prices.
326
		 * @param int|string The ID of the form.
327
		 */
328
		return apply_filters( 'give_get_donation_levels', $this->prices, $this->ID );
329
330
	}
331
332
	/**
333
	 * Retrieve the goal
334
	 *
335
	 * @since 1.0
336
	 * @return float
337
	 */
338
	public function get_goal() {
339
340
		if ( ! isset( $this->goal ) ) {
341
342
			$this->goal = get_post_meta( $this->ID, '_give_set_goal', true );
343
344
			if ( $this->goal ) {
345
346
				$this->goal = give_sanitize_amount( $this->goal );
347
348
			} else {
349
350
				$this->goal = 0;
351
352
			}
353
354
		}
355
356
		return apply_filters( 'give_get_set_goal', $this->goal, $this->ID );
357
358
	}
359
360
	/**
361
	 * Determine if single price mode is enabled or disabled
362
	 *
363
	 * @since 1.0
364
	 * @return bool
365
	 */
366
	public function is_single_price_mode() {
367
368
		$option = get_post_meta( $this->ID, '_give_price_options_mode', true );
369 11
		$ret    = 0;
370
371 11
		if ( empty( $option ) || $option === 'set' ) {
372
			$ret = 1;
373 11
		}
374 11
		
375 11
		/**
376
		 * Override the price mode for a donation when checking if is in single price mode.
377 11
		 *
378
		 * @since 1.0
379 11
		 *
380
		 * @param bool $ret Is donation form in single price mode?
381
		 * @param int|string The ID of the donation form.
382
		 */
383
		return (bool) apply_filters( 'give_single_price_option_mode', $ret, $this->ID );
384 11
385
	}
386 11
387
	/**
388
	 * Has Variable Prices
389
	 *
390
	 * @description Determine if the donation form has variable prices enabled
391
	 *
392
	 * @since       1.0
393
	 * @return bool
394
	 */
395
	public function has_variable_prices() {
396
397
		$option = get_post_meta( $this->ID, '_give_price_option', true );
398
		$ret    = 0;
399
400
		if ( $option === 'multi' ) {
401
			$ret = 1;
402
		}
403
404
		/**
405
		 * Filter: Override whether the donation form has variables prices.
406
		 *
407
		 * @param bool $ret Does donation form have variable prices?
408
		 * @param int|string The ID of the donation form.
409
		 */
410
		return (bool) apply_filters( 'give_has_variable_prices', $ret, $this->ID );
411
412
	}
413
414
	/**
415
	 * Retrieve the donation form type, set or multi-level
416
	 *
417
	 * @since 1.5
418
	 * @return string Type of donation form, either 'set' or 'multi'
419
	 */
420
	public function get_type() {
421
422
		if ( ! isset( $this->type ) ) {
423
424
			$this->type = get_post_meta( $this->ID, '_give_price_option', true );
0 ignored issues
show
Bug introduced by
The property type does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
425
426
			if ( empty( $this->type ) ) {
427
				$this->type = 'set';
428
			}
429
430
		}
431
432
		return apply_filters( 'give_get_form_type', $this->type, $this->ID );
433
434
	}
435
436
	/**
437
	 * Retrieve the sale count for the donation form
438
	 *
439
	 * @since 1.0
440
	 * @return int
441
	 */
442
	public function get_sales() {
443
444
		if ( ! isset( $this->sales ) ) {
445
446
			if ( '' == get_post_meta( $this->ID, '_give_form_sales', true ) ) {
447
				add_post_meta( $this->ID, '_give_form_sales', 0 );
448
			} // End if
449
450
			$this->sales = get_post_meta( $this->ID, '_give_form_sales', true );
451
452
			if ( $this->sales < 0 ) {
453
				// Never let sales be less than zero
454
				$this->sales = 0;
455
			}
456
457
		}
458
459
		return $this->sales;
460
461
	}
462
463
	/**
464
	 * Increment the sale count by one
465
	 *
466
	 * @since 1.0
467
	 *
468
	 * @param int $quantity The quantity to increase the donations by
469
	 *
470
	 * @return int|false  New number of total sales
471
	 */
472
	public function increase_sales( $quantity = 1 ) {
473
474
		$sales       = give_get_form_sales_stats( $this->ID );
475
		$quantity    = absint( $quantity );
476
		$total_sales = $sales + $quantity;
477
478
		if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
479
480
			$this->sales = $total_sales;
481
482
			return $this->sales;
483
484
		}
485
486
		return false;
487
	}
488
489
	/**
490
	 * Decrement the sale count by one
491
	 *
492
	 * @since 1.0
493
	 *
494
	 * @param int $quantity The quantity to decrease by
495
	 *
496
	 * @return int|false  New number of total sales
497
	 */
498
	public function decrease_sales( $quantity = 1 ) {
499
500
		$sales = give_get_form_sales_stats( $this->ID );
501
502
		// Only decrease if not already zero
503
		if ( $sales > 0 ) {
504
505
			$quantity    = absint( $quantity );
506
			$total_sales = $sales - $quantity;
507
508
			if ( $this->update_meta( '_give_form_sales', $total_sales ) ) {
509
510
				$this->sales = $sales;
511
512
				return $sales;
513
514
			}
515
516
		}
517
518
		return false;
519
520
	}
521
522
	/**
523
	 * Retrieve the total earnings for the form
524
	 *
525
	 * @since 1.0
526
	 * @return float
527
	 */
528
	public function get_earnings() {
529
530
		if ( ! isset( $this->earnings ) ) {
531
532
			if ( '' == get_post_meta( $this->ID, '_give_form_earnings', true ) ) {
533
				add_post_meta( $this->ID, '_give_form_earnings', 0 );
534
			}
535
536
			$this->earnings = get_post_meta( $this->ID, '_give_form_earnings', true );
537
538
			if ( $this->earnings < 0 ) {
539
				// Never let earnings be less than zero
540
				$this->earnings = 0;
541
			}
542
543
		}
544
545
		return $this->earnings;
546
547
	}
548
549
	/**
550
	 * Increase the earnings by the given amount
551
	 *
552
	 * @since 1.0
553
	 * @return float|false
554
	 */
555
	public function increase_earnings( $amount = 0 ) {
556
557
		$earnings   = give_get_form_earnings_stats( $this->ID );
558
		$new_amount = $earnings + (float) $amount;
559
560
		if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
561
562
			$this->earnings = $new_amount;
563
564
			return $this->earnings;
565
566
		}
567
568
		return false;
569
570
	}
571
572
	/**
573
	 * Decrease the earnings by the given amount
574
	 *
575
	 * @since 1.0
576
	 * @return float|false
577
	 */
578
	public function decrease_earnings( $amount ) {
579
580
		$earnings = give_get_form_earnings_stats( $this->ID );
581
582
		if ( $earnings > 0 ) {
583
			// Only decrease if greater than zero
584
			$new_amount = $earnings - (float) $amount;
585
586
587
			if ( $this->update_meta( '_give_form_earnings', $new_amount ) ) {
588
589
				$this->earnings = $new_amount;
590
591
				return $this->earnings;
592
593
			}
594
595
		}
596
597
		return false;
598
599
	}
600
601
	/**
602
	 * Determine if the donation is free or if the given price ID is free
603
	 *
604
	 * @since 1.0
605
	 * @return bool
606
	 */
607
	public function is_free( $price_id = false ) {
608
609
		$is_free          = false;
610
		$variable_pricing = give_has_variable_prices( $this->ID );
611
612
		if ( $variable_pricing && ! is_null( $price_id ) && $price_id !== false ) {
613
			$price = give_get_price_option_amount( $this->ID, $price_id );
614
		} elseif ( ! $variable_pricing ) {
615
			$price = get_post_meta( $this->ID, '_give_set_price', true );
616
		}
617
618
		if ( isset( $price ) && (float) $price == 0 ) {
619
			$is_free = true;
620
		}
621
622
		return (bool) apply_filters( 'give_is_free_donation', $is_free, $this->ID, $price_id );
623
624
	}
625
626
627
	/**
628
	 * Updates a single meta entry for the donation form
629
	 *
630
	 * @since  1.5
631
	 * @access private
632
	 *
633
	 * @param  string $meta_key The meta_key to update
634
	 * @param  string|array|object $meta_value The value to put into the meta
635
	 *
636
	 * @return bool             The result of the update query
637
	 */
638
	private function update_meta( $meta_key = '', $meta_value = '' ) {
639
640
		global $wpdb;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
641
642
		if ( empty( $meta_key ) || empty( $meta_value ) ) {
643
			return false;
644
		}
645
646
		// Make sure if it needs to be serialized, we do
647
		$meta_value = maybe_serialize( $meta_value );
648
649
		if ( is_numeric( $meta_value ) ) {
650
			$value_type = is_float( $meta_value ) ? '%f' : '%d';
651
		} else {
652
			$value_type = "'%s'";
653
		}
654
655
		$sql = $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = $value_type WHERE post_id = $this->ID AND meta_key = '%s'", $meta_value, $meta_key );
656
657
		if ( $wpdb->query( $sql ) ) {
658
659
			clean_post_cache( $this->ID );
660
661
			return true;
662
663
		}
664
665
		return false;
666
	}
667
668
669
}
670