Completed
Push — develop ( bb1f31...d4a8c8 )
by Remco
08:57 queued 05:35
created

Money   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 323
Duplicated Lines 5.57 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 81.32%

Importance

Changes 0
Metric Value
dl 18
loc 323
ccs 74
cts 91
cp 0.8132
rs 10
c 0
b 0
f 0
wmc 30
lcom 1
cbo 2

18 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A get_default_format() 0 8 1
A format_i18n() 0 31 5
A format_i18n_non_trailing_zeros() 0 9 2
A format() 0 18 3
A get_value() 0 3 1
A get_amount() 0 5 1
A get_cents() 0 3 1
A get_minor_units() 0 7 1
A set_value() 0 3 1
A set_amount() 0 5 1
A get_currency() 0 3 1
A set_currency() 0 9 2
A __toString() 0 3 1
A add() 9 9 1
A subtract() 9 9 1
A initialize_calculator() 0 15 4
A get_calculator() 0 7 2

How to fix   Duplicated Code   

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:

1
<?php
2
/**
3
 * Money
4
 *
5
 * @author    Pronamic <[email protected]>
6
 * @copyright 2005-2019 Pronamic
7
 * @license   GPL-3.0-or-later
8
 * @package   Pronamic\WordPress\Money
9
 */
10
11
namespace Pronamic\WordPress\Money;
12
13
use Pronamic\WordPress\Money\Calculator\BcMathCalculator;
14
use Pronamic\WordPress\Money\Calculator\PhpCalculator;
15
16
/**
17
 * Money
18
 *
19
 * @author Remco Tolsma
20
 * @version 1.2.1
21
 * @since   1.0.0
22
 */
23
class Money {
24
	/**
25
	 * Amount value.
26
	 *
27
	 * @var float
28
	 */
29
	private $value;
30
31
	/**
32
	 * Currency.
33
	 *
34
	 * @var Currency
35
	 */
36
	private $currency;
37
38
	/**
39
	 * Calculator.
40
	 *
41
	 * @var Calculator|null
42
	 */
43
	private static $calculator;
44
45
	/**
46
	 * Calculators.
47
	 *
48
	 * @var array
49
	 */
50
	private static $calculators = [
51
		BcMathCalculator::class,
52
		PhpCalculator::class,
53
	];
54
55
	/**
56
	 * Construct and initialize money object.
57
	 *
58
	 * @param string|int|float $value    Amount value.
59
	 * @param Currency|string  $currency Currency.
60
	 */
61 74
	public function __construct( $value = 0, $currency = 'EUR' ) {
62 74
		$this->set_value( $value );
63 74
		$this->set_currency( $currency );
64 74
	}
65
66
	/**
67
	 * Get default format.
68
	 *
69
	 * @return string
70
	 */
71 17
	public static function get_default_format() {
72
		/* translators: 1: currency symbol, 2: amount value, 3: currency code, note: use non-breaking space! */
73 17
		$format = _x( '%1$s%2$s %3$s', 'money format', 'pronamic-money' );
74
		// Note:               ↳ Non-breaking space.
75 17
		$format = apply_filters( 'pronamic_money_default_format', $format );
76
77 17
		return $format;
78
	}
79
80
	/**
81
	 * Format i18n.
82
	 *
83
	 * @param string|null $format Format.
84
	 *
85
	 * @return string
86
	 */
87 14
	public function format_i18n( $format = null ) {
88 14
		if ( is_null( $format ) ) {
89 7
			$format = self::get_default_format();
90
		}
91
92 14
		$alphabetic_code = $this->currency->get_alphabetic_code();
93
94 14
		if ( ! empty( $alphabetic_code ) ) {
95 14
			$number_decimals = $this->currency->get_number_decimals();
96
97
			// Handle non trailing zero formatter.
98 14
			if ( false !== strpos( $format, '%2$NTZ' ) ) {
99 7
				$decimals = substr( $this->format(), ( - 1 * $number_decimals ), $number_decimals );
100
101 7
				if ( 0 === (int) $decimals ) {
102 5
					$number_decimals = 0;
103
				}
104
105 7
				$format = str_replace( '%2$NTZ', '%2$s', $format );
106
			}
107
108 14
			return sprintf(
109 14
				$format,
110 14
				strval( $this->currency->get_symbol() ),
111 14
				number_format_i18n( $this->get_value(), $number_decimals ),
112 14
				strval( $this->currency->get_alphabetic_code() )
113
			);
114
		}
115
116
		return number_format_i18n( $this->get_value(), 2 );
117
	}
118
119
	/**
120
	 * Format i18n without trailing zeros.
121
	 *
122
	 * @param string|null $format Format.
123
	 *
124
	 * @return string
125
	 */
126 7
	public function format_i18n_non_trailing_zeros( $format = null ) {
127 7
		if ( is_null( $format ) ) {
128 7
			$format = self::get_default_format();
129
		}
130
131 7
		$format = str_replace( '%2$s', '%2$NTZ', $format );
132
133 7
		return $this->format_i18n( $format );
134
	}
135
136
	/**
137
	 * Format.
138
	 *
139
	 * @param string|null $format Format.
140
	 *
141
	 * @return string
142
	 */
143 7
	public function format( $format = null ) {
144 7
		if ( is_null( $format ) ) {
145 7
			$format = '%2$s';
146
		}
147
148 7
		$alphabetic_code = $this->currency->get_alphabetic_code();
149
150 7
		if ( ! empty( $alphabetic_code ) ) {
151 7
			return sprintf(
152 7
				$format,
153 7
				strvaL( $this->currency->get_symbol() ),
154 7
				number_format( $this->get_value(), $this->get_currency()->get_number_decimals(), '.', '' ),
155 7
				strval( $this->currency->get_alphabetic_code() )
156
			);
157
		}
158
159
		return number_format( $this->get_value(), 2, '.', '' );
160
	}
161
162
	/**
163
	 * Get value.
164
	 *
165
	 * @return float Amount value.
166
	 */
167 74
	public function get_value() {
168 74
		return $this->value;
169
	}
170
171
	/**
172
	 * Get amount.
173
	 *
174
	 * @deprecated 1.2.0
175
	 * @return float Amount value.
176
	 */
177
	public function get_amount() {
178
		_deprecated_function( __METHOD__, '1.2.0', 'Money::get_value()' );
179
180
		return $this->get_value();
181
	}
182
183
	/**
184
	 * Get cents.
185
	 *
186
	 * @return float
187
	 *
188
	 * @deprecated 1.2.2 Use `Money::get_minor_units()` instead.
189
	 */
190 1
	public function get_cents() {
191 1
		return (float) $this->get_minor_units();
192
	}
193
194
	/**
195
	 * Get amount in minor units.
196
	 *
197
	 * Examples for value 10:
198
	 *   JPY 0 decimals: 10
199
	 *   EUR 2 decimals: 1000
200
	 *   BHD 3 decimals: 10000
201
	 *   NLG 4 decimals: 100000
202
	 *
203
	 * @since 1.2.1
204
	 *
205
	 * @return int
206
	 */
207 21
	public function get_minor_units() {
208 21
		$calculator = $this->get_calculator();
209
210 21
		$minor_units = $calculator->multiply( strval( $this->get_value() ), pow( 10, $this->currency->get_number_decimals() ) );
211
212 21
		return (int) $minor_units;
213
	}
214
215
	/**
216
	 * Set value.
217
	 *
218
	 * @param mixed $value Amount value.
219
	 * @return void
220
	 */
221 74
	public function set_value( $value ) {
222 74
		$this->value = floatval( $value );
223 74
	}
224
225
	/**
226
	 * Set amount.
227
	 *
228
	 * @deprecated 1.2.0
229
	 * @param mixed $value Amount value.
230
	 * @return void
231
	 */
232
	public function set_amount( $value ) {
233
		_deprecated_function( __METHOD__, '1.2.0', 'Money::set_value()' );
234
235
		$this->set_value( $value );
236
	}
237
238
	/**
239
	 * Get currency.
240
	 *
241
	 * @return Currency
242
	 */
243 8
	public function get_currency() {
244 8
		return $this->currency;
245
	}
246
247
	/**
248
	 * Set currency.
249
	 *
250
	 * @param string|Currency $currency Currency.
251
	 * @return void
252
	 */
253 74
	public function set_currency( $currency ) {
254 74
		if ( $currency instanceof Currency ) {
255 1
			$this->currency = $currency;
256
257 1
			return;
258
		}
259
260 74
		$this->currency = Currency::get_instance( $currency );
261 74
	}
262
263
	/**
264
	 * Create a string representation of this money object.
265
	 *
266
	 * @return string
267
	 */
268
	public function __toString() {
269
		return $this->format_i18n();
270
	}
271
272
	/**
273
	 * Returns a new Money object that represents
274
	 * the sum of this and an other Money object.
275
	 *
276
	 * @param Money $addend Addend.
277
	 *
278
	 * @return Money
279
	 */
280 1 View Code Duplication
	public function add( Money $addend ) {
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...
281 1
		$value = $this->get_value();
282
283 1
		$calculator = $this->get_calculator();
284
285 1
		$value = $calculator->add( strval( $value ), strval( $addend->get_value() ) );
286
287 1
		return new self( $value, $this->get_currency() );
288
	}
289
290
	/**
291
	 * Returns a new Money object that represents
292
	 * the difference of this and an other Money object.
293
	 *
294
	 * @link https://github.com/moneyphp/money/blob/v3.2.1/src/Money.php#L235-L255
295
	 *
296
	 * @param Money $subtrahend Subtrahend.
297
	 *
298
	 * @return Money
299
	 */
300 View Code Duplication
	public function subtract( Money $subtrahend ) {
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...
301
		$value = $this->get_value();
302
303
		$calculator = $this->get_calculator();
304
305
		$value = $calculator->subtract( strval( $value ), strval( $subtrahend->get_value() ) );
306
307
		return new self( $value, $this->get_currency() );
308
	}
309
310
	/**
311
	 * Initialize calculator.
312
	 *
313
	 * @return Calculator
314
	 *
315
	 * @throws \RuntimeException If cannot find calculator for money calculations.
316
	 */
317 1
	private static function initialize_calculator() {
318 1
		$calculator_classes = self::$calculators;
319
320 1
		foreach ( $calculator_classes as $calculator_class ) {
321 1
			if ( $calculator_class::supported() ) {
322 1
				$calculator = new $calculator_class();
323
324 1
				if ( $calculator instanceof Calculator ) {
325 1
					return $calculator;
326
				}
327
			}
328
		}
329
330
		throw new \RuntimeException( 'Cannot find calculator for money calculations' );
331
	}
332
333
	/**
334
	 * Get calculator.
335
	 *
336
	 * @return Calculator
337
	 */
338 22
	protected function get_calculator() {
339 22
		if ( null === self::$calculator ) {
340 1
			self::$calculator = self::initialize_calculator();
341
		}
342
343 22
		return self::$calculator;
344
	}
345
}
346