Completed
Push — master ( be9b7b...7c61e9 )
by Mike
10:50
created

WC_Shipping_Legacy_Flat_Rate::calculate_shipping()   D

Complexity

Conditions 11
Paths 136

Size

Total Lines 79
Code Lines 34

Duplication

Lines 28
Ratio 35.44 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 28
loc 79
rs 4.9999
cc 11
eloc 34
nc 136
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

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

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

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

Loading history...
2
if ( ! defined( 'ABSPATH' ) ) {
3
	exit;
4
}
5
6
/**
7
 * Flat Rate Shipping Method.
8
 *
9
 * This class is here for backwards commpatility for methods existing before zones existed.
10
 *
11
 * @deprecated  2.6.0
12
 * @version		2.4.0
13
 * @package		WooCommerce/Classes/Shipping
14
 * @author 		WooThemes
15
 */
16
class WC_Shipping_Legacy_Flat_Rate extends WC_Shipping_Method {
17
18
	/** @var string cost passed to [fee] shortcode */
19
	protected $fee_cost = '';
20
21
	/**
22
	 * Constructor.
23
	 */
24
	public function __construct() {
25
		$this->id                 = 'legacy_flat_rate';
26
		$this->method_title       = __( 'Flat Rate (Legacy)', 'woocommerce' );
27
		$this->method_description = sprintf( __( '<strong>This method is deprecated in 2.6.0 and will be removed in future versions - we recommend disabling it and instead setting up a new rate within your <a href="%s">Shipping Zones</a>.</strong>', 'woocommerce' ), admin_url( 'admin.php?page=wc-settings&tab=shipping' ) );
28
		$this->init();
29
30
		add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
31
		add_action( 'woocommerce_flat_rate_shipping_add_rate', array( $this, 'calculate_extra_shipping' ), 10, 3 );
32
	}
33
34
	/**
35
	 * Return the name of the option in the WP DB.
36
	 * @since 2.6.0
37
	 * @return string
38
	 */
39
	public function get_option_key() {
40
		return $this->plugin_id . 'flat_rate' . '_settings';
41
	}
42
43
	/**
44
	 * init function.
45
	 */
46
	public function init() {
47
		// Load the settings.
48
		$this->init_form_fields();
49
		$this->init_settings();
50
51
		// Define user set variables
52
		$this->title        = $this->get_option( 'title' );
53
		$this->availability = $this->get_option( 'availability' );
0 ignored issues
show
Deprecated Code introduced by
The property WC_Shipping_Method::$availability has been deprecated with message: 2.6.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
54
		$this->countries    = $this->get_option( 'countries' );
0 ignored issues
show
Deprecated Code introduced by
The property WC_Shipping_Method::$countries has been deprecated with message: 2.6.0

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
Documentation Bug introduced by
It seems like $this->get_option('countries') of type * is incompatible with the declared type array of property $countries.

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...
55
		$this->tax_status   = $this->get_option( 'tax_status' );
56
		$this->cost         = $this->get_option( 'cost' );
57
		$this->type         = $this->get_option( 'type', 'class' );
58
		$this->options      = $this->get_option( 'options', false ); // @deprecated in 2.4.0
59
	}
60
61
	/**
62
	 * Initialise Settings Form Fields.
63
	 */
64
	public function init_form_fields() {
65
		$this->form_fields = include( 'includes/settings-flat-rate.php' );
66
	}
67
68
	/**
69
	 * Evaluate a cost from a sum/string.
70
	 * @param  string $sum
71
	 * @param  array  $args
72
	 * @return string
73
	 */
74
	protected function evaluate_cost( $sum, $args = array() ) {
75
		include_once( 'includes/class-wc-eval-math.php' );
76
77
		$locale   = localeconv();
78
		$decimals = array( wc_get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );
79
80
		$this->fee_cost = $args['cost'];
81
82
		// Expand shortcodes
83
		add_shortcode( 'fee', array( $this, 'fee' ) );
84
85
		$sum = do_shortcode( str_replace(
86
			array(
87
				'[qty]',
88
				'[cost]'
89
			),
90
			array(
91
				$args['qty'],
92
				$args['cost']
93
			),
94
			$sum
95
		) );
96
97
		remove_shortcode( 'fee', array( $this, 'fee' ) );
98
99
		// Remove whitespace from string
100
		$sum = preg_replace( '/\s+/', '', $sum );
101
102
		// Remove locale from string
103
		$sum = str_replace( $decimals, '.', $sum );
104
105
		// Trim invalid start/end characters
106
		$sum = rtrim( ltrim( $sum, "\t\n\r\0\x0B+*/" ), "\t\n\r\0\x0B+-*/" );
107
108
		// Do the math
109
		return $sum ? WC_Eval_Math::evaluate( $sum ) : 0;
110
	}
111
112
	/**
113
	 * Work out fee (shortcode).
114
	 * @param  array $atts
115
	 * @return string
116
	 */
117 View Code Duplication
	public function fee( $atts ) {
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...
118
		$atts = shortcode_atts( array(
119
			'percent' => '',
120
			'min_fee' => ''
121
		), $atts );
122
123
		$calculated_fee = 0;
124
125
		if ( $atts['percent'] ) {
126
			$calculated_fee = $this->fee_cost * ( floatval( $atts['percent'] ) / 100 );
127
		}
128
129
		if ( $atts['min_fee'] && $calculated_fee < $atts['min_fee'] ) {
130
			$calculated_fee = $atts['min_fee'];
131
		}
132
133
		return $calculated_fee;
134
	}
135
136
	/**
137
	 * calculate_shipping function.
138
	 *
139
	 * @param array $package (default: array())
140
	 */
141
	public function calculate_shipping( $package = array() ) {
142
		$rate = array(
143
			'id'      => $this->id,
144
			'label'   => $this->title,
145
			'cost'    => 0,
146
			'package' => $package,
147
		);
148
149
		// Calculate the costs
150
		$has_costs = false; // True when a cost is set. False if all costs are blank strings.
151
		$cost      = $this->get_option( 'cost' );
152
153 View Code Duplication
		if ( $cost !== '' ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
154
			$has_costs    = true;
155
			$rate['cost'] = $this->evaluate_cost( $cost, array(
156
				'qty'  => $this->get_package_item_qty( $package ),
157
				'cost' => $package['contents_cost']
158
			) );
159
		}
160
161
		// Add shipping class costs
162
		$found_shipping_classes = $this->find_shipping_classes( $package );
163
		$highest_class_cost     = 0;
164
165 View Code Duplication
		foreach ( $found_shipping_classes as $shipping_class => $products ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
166
			// Also handles BW compatibility when slugs were used instead of ids
167
			$shipping_class_term = get_term_by( 'slug', $shipping_class, 'product_shipping_class' );
168
			$class_cost_string   = $shipping_class_term && $shipping_class_term->term_id ? $this->get_option( 'class_cost_' . $shipping_class_term->term_id, $this->get_option( 'class_cost_' . $shipping_class, '' ) ) : $this->get_option( 'no_class_cost', '' );
169
170
			if ( $class_cost_string === '' ) {
171
				continue;
172
			}
173
174
			$has_costs  = true;
175
			$class_cost = $this->evaluate_cost( $class_cost_string, array(
176
				'qty'  => array_sum( wp_list_pluck( $products, 'quantity' ) ),
177
				'cost' => array_sum( wp_list_pluck( $products, 'line_total' ) )
178
			) );
179
180
			if ( $this->type === 'class' ) {
181
				$rate['cost'] += $class_cost;
182
			} else {
183
				$highest_class_cost = $class_cost > $highest_class_cost ? $class_cost : $highest_class_cost;
184
			}
185
		}
186
187
		if ( $this->type === 'order' && $highest_class_cost ) {
188
			$rate['cost'] += $highest_class_cost;
189
		}
190
191
		$rate['package'] = $package;
192
193
		// Add the rate
194
		if ( $has_costs ) {
195
			$this->add_rate( $rate );
196
		}
197
198
		/**
199
		 * Developers can add additional flat rates based on this one via this action since @version 2.4.
200
		 *
201
		 * Previously there were (overly complex) options to add additional rates however this was not user.
202
		 * friendly and goes against what Flat Rate Shipping was originally intended for.
203
		 *
204
		 * This example shows how you can add an extra rate based on this flat rate via custom function:
205
		 *
206
		 * 		add_action( 'woocommerce_flat_rate_shipping_add_rate', 'add_another_custom_flat_rate', 10, 2 );
207
		 *
208
		 * 		function add_another_custom_flat_rate( $method, $rate ) {
209
		 * 			$new_rate          = $rate;
210
		 * 			$new_rate['id']    .= ':' . 'custom_rate_name'; // Append a custom ID.
211
		 * 			$new_rate['label'] = 'Rushed Shipping'; // Rename to 'Rushed Shipping'.
212
		 * 			$new_rate['cost']  += 2; // Add $2 to the cost.
213
		 *
214
		 * 			// Add it to WC.
215
		 * 			$method->add_rate( $new_rate );
216
		 * 		}.
217
		 */
218
		do_action( 'woocommerce_flat_rate_shipping_add_rate', $this, $rate );
219
	}
220
221
	/**
222
	 * Get items in package.
223
	 * @param  array $package
224
	 * @return int
225
	 */
226 View Code Duplication
	public function get_package_item_qty( $package ) {
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...
227
		$total_quantity = 0;
228
		foreach ( $package['contents'] as $item_id => $values ) {
229
			if ( $values['quantity'] > 0 && $values['data']->needs_shipping() ) {
230
				$total_quantity += $values['quantity'];
231
			}
232
		}
233
		return $total_quantity;
234
	}
235
236
	/**
237
	 * Finds and returns shipping classes and the products with said class.
238
	 * @param mixed $package
239
	 * @return array
240
	 */
241 View Code Duplication
	public function find_shipping_classes( $package ) {
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...
242
		$found_shipping_classes = array();
243
244
		foreach ( $package['contents'] as $item_id => $values ) {
245
			if ( $values['data']->needs_shipping() ) {
246
				$found_class = $values['data']->get_shipping_class();
247
248
				if ( ! isset( $found_shipping_classes[ $found_class ] ) ) {
249
					$found_shipping_classes[ $found_class ] = array();
250
				}
251
252
				$found_shipping_classes[ $found_class ][ $item_id ] = $values;
253
			}
254
		}
255
256
		return $found_shipping_classes;
257
	}
258
259
	/**
260
	 * Adds extra calculated flat rates.
261
	 *
262
	 * @deprecated 2.4.0
263
	 *
264
	 * Additonal rates defined like this:
265
	 * 	Option Name | Additional Cost [+- Percents%] | Per Cost Type (order, class, or item).
266
	 */
267
	public function calculate_extra_shipping( $method, $rate, $package ) {
268
		if ( $this->options ) {
269
			$options = array_filter( (array) explode( "\n", $this->options ) );
270
271
			foreach ( $options as $option ) {
272
				$this_option = array_map( 'trim', explode( WC_DELIMITER, $option ) );
273
				if ( sizeof( $this_option ) !== 3 ) {
274
					continue;
275
				}
276
				$extra_rate          = $rate;
277
				$extra_rate['id']    = $this->id . ':' . urldecode( sanitize_title( $this_option[0] ) );
278
				$extra_rate['label'] = $this_option[0];
279
				$extra_cost          = $this->get_extra_cost( $this_option[1], $this_option[2], $package );
0 ignored issues
show
Deprecated Code introduced by
The method WC_Shipping_Legacy_Flat_Rate::get_extra_cost() has been deprecated with message: 2.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
280
				if ( is_array( $extra_rate['cost'] ) ) {
281
					$extra_rate['cost']['order'] = $extra_rate['cost']['order'] + $extra_cost;
282
				} else {
283
					$extra_rate['cost'] += $extra_cost;
284
				}
285
286
				$rate['package'] = $package;
287
288
				$this->add_rate( $extra_rate );
289
			}
290
		}
291
	}
292
293
	/**
294
	 * Calculate the percentage adjustment for each shipping rate.
295
	 *
296
	 * @deprecated 2.4.0
297
	 * @param  float  $cost
298
	 * @param  float  $percent_adjustment
299
	 * @param  string $percent_operator
300
	 * @param  float  $base_price
301
	 * @return float
302
	 */
303
	public function calc_percentage_adjustment( $cost, $percent_adjustment, $percent_operator, $base_price ) {
304
		if ( '+' == $percent_operator ) {
305
			$cost += $percent_adjustment * $base_price;
306
		} else {
307
			$cost -= $percent_adjustment * $base_price;
308
		}
309
		return $cost;
310
	}
311
312
	/**
313
	 * Get extra cost.
314
	 *
315
	 * @deprecated 2.4.0
316
	 * @param  string $cost_string
317
	 * @param  string $type
318
	 * @param  array $package
319
	 * @return float
320
	 */
321
	public function get_extra_cost( $cost_string, $type, $package ) {
322
		$cost         = $cost_string;
323
		$cost_percent = false;
324
		$pattern      =
325
			'/' .           // start regex
326
			'(\d+\.?\d*)' . // capture digits, optionally capture a `.` and more digits
327
			'\s*' .         // match whitespace
328
			'(\+|-)' .      // capture the operand
329
			'\s*'.          // match whitespace
330
			'(\d+\.?\d*)'.  // capture digits, optionally capture a `.` and more digits
331
			'\%/';          // match the percent sign & end regex
332
		if ( preg_match( $pattern, $cost_string, $this_cost_matches ) ) {
333
			$cost_operator = $this_cost_matches[2];
334
			$cost_percent  = $this_cost_matches[3] / 100;
335
			$cost          = $this_cost_matches[1];
336
		}
337
		switch ( $type ) {
338
			case 'class' :
339
				$cost = $cost * sizeof( $this->find_shipping_classes( $package ) );
340
			break;
341
			case 'item' :
342
				$cost = $cost * $this->get_package_item_qty( $package );
343
			break;
344
		}
345
		if ( $cost_percent ) {
346
			switch ( $type ) {
347
				case 'class' :
348
					$shipping_classes = $this->find_shipping_classes( $package );
349
					foreach ( $shipping_classes as $shipping_class => $items ){
350
						foreach ( $items as $item_id => $values ) {
351
							$cost = $this->calc_percentage_adjustment( $cost, $cost_percent, $cost_operator, $values['line_total'] );
0 ignored issues
show
Deprecated Code introduced by
The method WC_Shipping_Legacy_Flat_...percentage_adjustment() has been deprecated with message: 2.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
352
						}
353
					}
354
				break;
355
				case 'item' :
356
					foreach ( $package['contents'] as $item_id => $values ) {
357
						if ( $values['data']->needs_shipping() ) {
358
							$cost = $this->calc_percentage_adjustment( $cost, $cost_percent, $cost_operator, $values['line_total'] );
0 ignored issues
show
Deprecated Code introduced by
The method WC_Shipping_Legacy_Flat_...percentage_adjustment() has been deprecated with message: 2.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
359
						}
360
					}
361
				break;
362
				case  'order' :
363
					$cost = $this->calc_percentage_adjustment( $cost, $cost_percent, $cost_operator, $package['contents_cost'] );
0 ignored issues
show
Deprecated Code introduced by
The method WC_Shipping_Legacy_Flat_...percentage_adjustment() has been deprecated with message: 2.4.0

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
364
				break;
365
			}
366
		}
367
		return $cost;
368
	}
369
}
370