Completed
Pull Request — master (#984)
by Devin
28:24
created

formatting.php ➔ give_format_amount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 10
nc 2
nop 2
dl 0
loc 17
ccs 6
cts 6
cp 1
crap 2
rs 9.4285
c 1
b 0
f 0
1
<?php
0 ignored issues
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 25 and the first side effect is on line 14.

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
/**
3
 * Formatting functions for taking care of proper number formats and such
4
 *
5
 * @package     Give
6
 * @subpackage  Functions/Formatting
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.0
10
 */
11
12
// Exit if accessed directly
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
18
/**
19
 * Get decimal count
20
 *
21
 * @since 1.6
22
 *
23
 * @return mixed
24
 */
25
function give_get_price_decimals() {
26
    return apply_filters( 'give_sanitize_amount_decimals', give_get_option( 'number_decimals', 0 ) );
27
}
28
29 52
/**
30 52
 * Get thousand separator
31 52
 *
32
 * @since 1.6
33
 *
34 52
 * @return mixed
35
 */
36
function give_get_price_thousand_separator() {
37
    return give_get_option( 'thousands_separator', ',' );
38
}
39
40
/**
41
 * Get decimal separator
42 52
 *
43
 * @since 1.6
44
 *
45
 * @return mixed
46 52
 */
47
function give_get_price_decimal_separator() {
48
    return give_get_option( 'decimal_separator', '.' );
49
}
50 52
51 52
/**
52 52
 * Sanitize Amount
53
 *
54 52
 * Returns a sanitized amount by stripping out thousands separators.
55
 *
56
 * @since      1.0
57
 *
58 52
 * @param  int|float|string $number     Expects either a float or a string with a decimal separator only (no thousands)
59
 * @param  int|bool     $dp         Number of decimals
60
 * @param  bool         $trim_zeros From end of string
61
 *
62
 *
63
 * @return string $amount Newly sanitized amount
64
 */
65
function give_sanitize_amount( $number, $dp = false, $trim_zeros = false ) {
66
67
    // Bailout.
68
    if( empty( $number ) ) {
69
        return $number;
70
    }
71
72
	// Remove slash from amount.
73 43
	// If thousand or decimal separator is set to ' then in $_POST or $_GET param we will get an escaped number.
74 43
	// To prevent notices and warning remove slash from amount/number.
75
	$number = wp_unslash( $number );
76
77 43
    $thousand_separator = give_get_price_thousand_separator();
78
79
    $locale   = localeconv();
80
    $decimals = array( give_get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );
81
82
    // Remove locale from string
83
    if ( ! is_float( $number ) ) {
84 43
        $number = str_replace( $decimals, '.', $number );
85
    }
86
87
    // Remove thousand amount formatting if amount has.
88
    // This condition use to add backward compatibility to version before 1.6, because before version 1.6 we were saving formatted amount to db.
89 43
    // Do not replace thousand separator from price if it is same as decimal separator, because it will be already replace by above code.
90
    if(  ! in_array( $thousand_separator, $decimals ) && ( false !== strpos( $number, $thousand_separator ) ) ) {
91
        $number = str_replace( $thousand_separator, '', $number );
92
    } elseif ( in_array( $thousand_separator, $decimals ) ) {
93
		$number = preg_replace( '/\.(?=.*\.)/', '', $number );
94
	}
95
96
    // Remove non numeric entity before decimal separator.
97
    $number     = preg_replace( '/[^0-9\.]/', '', $number );
98
    $default_dp = give_get_price_decimals();
99 43
100
    // Format number of decimals in number.
101
    if( false !== $dp ) {
102
        $dp     = intval(  empty( $dp ) ? $default_dp : $dp );
103 43
        $dp     = apply_filters( 'give_sanitize_amount_decimals', $dp, $number );
104 2
        $number = number_format( floatval( $number ), $dp, '.', '' );
105 2
    }
106
107 43
    // Reset negative amount to zero.
108
	if ( 0 > $number ) {
109 43
		$number = number_format( 0, $default_dp, '.' );
110
	}
111 43
112
    // If number does not have decimal then add number of decimals to it.
113
    if(
114
        false === strpos( $number, '.' )
115
        || ( $default_dp > strlen( substr( $number, strpos( $number , '.' ) + 1 ) ) )
116
    ) {
117
        $number = number_format( $number, $default_dp, '.', '' );
118
    }
119
120
    // Trim zeros.
121
    if ( $trim_zeros && strstr( $number, '.' ) ) {
122
        $number = rtrim( rtrim( $number, '0' ), '.' );
123
    }
124
125
    return apply_filters( 'give_sanitize_amount', $number );
126
}
127
128
/**
129
 * Returns a nicely formatted amount.
130
 *
131
 * @since 1.0
132
 *
133
 * @param string      $amount   Price amount to format
134
 * @param bool|string $decimals Whether or not to use decimals. Useful when set to false for non-currency numbers.
135
 *
136
 * @return string $amount Newly formatted amount or Price Not Available
137
 */
138
function give_format_amount( $amount, $decimals = true ) {
0 ignored issues
show
Unused Code introduced by
The parameter $decimals 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...
139
	$thousands_sep = give_get_option( 'thousands_separator', ',' );
140
	$decimal_sep   = give_get_option( 'decimal_separator', '.' );
141
142
	if ( empty( $amount ) ) {
143
		$amount = 0;
144
	} else {
145
		// Sanitize amount before formatting.
146 45
		$amount = give_sanitize_amount( $amount );
147 45
	}
148 45
149
	$decimals = give_get_price_decimals();
150 45
151
	$formatted = number_format( $amount, $decimals, $decimal_sep, $thousands_sep );
152 45
153
	return apply_filters( 'give_format_amount', $formatted, $amount, $decimals, $decimal_sep, $thousands_sep );
154 45
}
155
156
157
/**
158 45
 * Get human readable amount.
159
 *
160 45
 * Note: This function only support large number formatting from million to trillion
161
 *
162 45
 * @since 1.6
163 45
 *
164 45
 * @use  give_get_price_thousand_separator Get thousand separator.
165 45
 *
166 45
 * @param string $amount formatted amount number.
167 45
 * @return float|string  formatted amount number with large number names.
168 45
 */
169 45
function give_human_format_large_amount( $amount ) {
170 45
171 45
    // Get thousand separator.
172 45
    $thousands_sep = give_get_price_thousand_separator();
173 45
174 45
    // Sanitize amount.
175 45
    $sanitize_amount = give_sanitize_amount( $amount );
176 45
177 45
    // Explode amount to calculate name of large numbers.
178 45
	$amount_array = explode( $thousands_sep, $amount );
179 45
180 45
    // Calculate amount parts count.
181 45
    $amount_count_parts = count( $amount_array );
182 45
183 45
	// Human format amount (default).
184 45
	$human_format_amount = $amount;
185 45
186 45
    // Calculate large number formatted amount.
187 45
    if ( 4 < $amount_count_parts ){
188 45
        $human_format_amount =  sprintf( esc_html__( '%s trillion', 'give' ), round( ( $sanitize_amount / 1000000000000 ), 2 ) );
189 45
    } elseif ( 3 < $amount_count_parts ){
190 45
        $human_format_amount =  sprintf( esc_html__( '%s billion', 'give' ), round( ( $sanitize_amount / 1000000000 ), 2 ));
191 45
    } elseif ( 2 < $amount_count_parts  ) {
192
        $human_format_amount =  sprintf( esc_html__( '%s million', 'give' ), round( ( $sanitize_amount / 1000000), 2 ) );
193
    }
194
195
    return apply_filters( 'give_human_format_large_amount', $human_format_amount, $amount, $sanitize_amount );
196
}
197
198
/**
199 45
 * Returns a nicely formatted amount with custom decimal separator.
200 45
 *
201
 * @since 1.0
202
 *
203
 * @param int|float|string      $amount   Formatted or sanitized price
204
 * @param int|bool    $dp       number of decimals
205
 *
206
 * @return string $amount Newly formatted amount or Price Not Available
207
 */
208
function give_format_decimal( $amount, $dp = false ){
209
    $decimal_separator = give_get_price_decimal_separator();
210
    $formatted_amount  = give_sanitize_amount( $amount, $dp );
211
212
    if( false !== strpos( $formatted_amount, '.' ) ) {
213
        $formatted_amount = str_replace( '.', $decimal_separator, $formatted_amount );
214
    }
215
216
    return apply_filters( 'give_format_decimal', $formatted_amount, $amount, $decimal_separator );
217
}
218
219
220
/**
221
 * Format Multi-level Amount
222
 *
223
 * Loops through CMB2 repeater field and updates amount field using give_format_amount()
224
 *
225
 * @param $field_args
226
 * @param $field
227
 *
228
 * @return bool
229
 */
230
function give_format_admin_multilevel_amount( $field_args, $field ) {
0 ignored issues
show
Unused Code introduced by
The parameter $field_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...
231
232
	if ( empty( $field->value ) ) {
233
		return false;
234
	}
235
236
	$field->value = give_format_decimal( $field->value );
237
}
238 45
239
/**
240
 * Formats the currency display
241
 *
242
 * @since 1.0
243 45
 *
244
 * @param string $price
245
 * @param string $currency
246
 *
247
 * @return mixed|string|void
248
 */
249
function give_currency_filter( $price = '', $currency = '' ) {
250
251
	if ( empty( $currency ) ) {
252
		$currency = give_get_currency();
253
	}
254
255
	$position = give_get_option( 'currency_position', 'before' );
256
257 55
	$negative = $price < 0;
258
259
	if ( $negative ) {
260 55
        // Remove proceeding "-".
261 55
		$price = substr( $price, 1 );
262 55
	}
263 55
264
	$symbol = give_currency_symbol( $currency );
265
266
    switch ( $currency ):
267
        case 'GBP' :
268
        case 'BRL' :
269 55
        case 'EUR' :
270
        case 'USD' :
271
        case 'AUD' :
272
        case 'CAD' :
273
        case 'HKD' :
274
        case 'MXN' :
275
        case 'NZD' :
276
        case 'SGD' :
277
        case 'JPY' :
278
        case 'THB' :
279
        case 'INR' :
280
        case 'RIAL' :
281
        case 'TRY' :
282
        case 'RUB' :
283
        case 'SEK' :
284
        case 'PLN' :
285
        case 'PHP' :
286
        case 'TWD' :
287
        case 'MYR' :
288
        case 'CZK' :
289
        case 'DKK' :
290
        case 'HUF' :
291
        case 'ILS' :
292
        case 'MAD' :
293
        case 'KRW' :
294
        case 'ZAR' :
295
            $formatted = ( 'before' === $position ? $symbol . $price : $price . $symbol );
296
            break;
297
        case 'NOK' :
298
            $formatted = ( 'before' === $position ? $symbol . ' ' . $price : $price . ' ' . $symbol );
299
            break;
300
        default :
301
            $formatted = ( 'before' === $position ? $currency . ' ' . $price : $price . ' ' . $currency );
302
            break;
303
    endswitch;
304
305
    /**
306
     * Filter formatted amount with currency
307
     *
308
     * Filter name depends upon current value of currency and currency position.
309
     * For example :
310
     *           if currency is USD and currency position is before then
311
     *           filter name will be give_usd_currency_filter_before
312
     *
313
     *           and if currency is USD and currency position is after then
314
     *           filter name will be give_usd_currency_filter_after
315
     *
316
     */
317
    $formatted = apply_filters( 'give_' . strtolower( $currency ) . "_currency_filter_{$position}", $formatted, $currency, $price );
318
319
    if ( $negative ) {
320
		// Prepend the minus sign before the currency sign.
321
		$formatted = '-' . $formatted;
322
	}
323
324
	return $formatted;
325
}
326
327
/**
328
 * Set the number of decimal places per currency
329
 *
330
 * @since 1.0
331
 * @since 1.6 $decimals parameter removed from function params
332
 **
333
 * @return int $decimals
334
 */
335
function give_currency_decimal_filter() {
336
337
    remove_filter( 'give_sanitize_amount_decimals', 'give_currency_decimal_filter' );
338
339
    // Set default number of decimals.
340
    $decimals = give_get_price_decimals();
341
342
    add_filter( 'give_sanitize_amount_decimals', 'give_currency_decimal_filter' );
343
344
345
    // Get number of decimals with backward compatibility ( version < 1.6 )
346
    if( 1 <= func_num_args() ){
347
        $decimals = ( false === func_get_arg( 0 ) ? $decimals : absint( func_get_arg( 0 ) ) );
348
    }
349
350
	$currency = give_get_currency();
351
352
	switch ( $currency ) {
353
		case 'RIAL' :
354
		case 'JPY' :
355
		case 'TWD' :
356
		case 'HUF' :
357
358
			$decimals = 0;
359
			break;
360
	}
361
362
	return apply_filters( 'give_currency_decimal_count', $decimals, $currency );
363
}
364
365
add_filter( 'give_sanitize_amount_decimals', 'give_currency_decimal_filter' );
366
add_filter( 'give_format_amount_decimals', 'give_currency_decimal_filter' );
367
368
/**
369
 * Sanitize thousand separator
370
 *
371
 * @since 1.6
372
 *
373
 * @param string $value
374
 * @param array  $field_args
375
 * @param object $field
376
 *
377
 * @return mixed
378
 */
379
function give_sanitize_thousand_separator( $value, $field_args, $field ){
0 ignored issues
show
Unused Code introduced by
The parameter $field_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...
Unused Code introduced by
The parameter $field 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...
380
    return stripslashes( $value );
381
}
382
383
384
/**
385
 * Sanitize number of decimals
386
 *
387
 * @since 1.6
388
 *
389
 * @param string $value
390
 * @param array  $field_args
391
 * @param object $field
392
 *
393
 * @return mixed
394
 */
395
function give_sanitize_number_decimals( $value, $field_args, $field ){
0 ignored issues
show
Unused Code introduced by
The parameter $field_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...
Unused Code introduced by
The parameter $field 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...
396
	return absint($value);
397
}
398
399
/**
400
 * Sanitize price file value
401
 *
402
 * @since 1.6
403
 *
404
 * @param string $value
405
 * @param array  $field_args
406
 * @param object $field
407
 *
408
 * @return mixed
409
 */
410
function give_sanitize_price_field_value( $value, $field_args, $field ){
0 ignored issues
show
Unused Code introduced by
The parameter $field_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...
Unused Code introduced by
The parameter $field 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...
411
    return give_sanitize_amount( $value );
412
}
413
414
415
/**
416
 * Manually render amount field.
417
 *
418
 * @since  1.7
419
 *
420
 * @param  array      $field_args Array of field arguments.
421
 * @param  CMB2_Field $field      The field object
422
 *
423
 * @return void
424
 */
425
function give_cmb_amount_field_render_row_cb( $field_args, $field ) {
0 ignored issues
show
Unused Code introduced by
The parameter $field_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...
426
427
	// Get args.
428
	$id          = $field->args('id');
429
	$label       = $field->args( 'name' );
430
	$name        = $field->args( '_name' );
431
	$description = $field->args( 'description' );
432
	$attributes  = $field->args( 'attributes' );
433
	$attributes_string  = '';
434
	$row_class          = $field->row_classes();
435
436
	// Get attributes.
437
	if( ! empty( $attributes ) ) {
438
		foreach ( $attributes as $attribute_name => $attribute_val ) {
439
			$attributes_string[] = "$attribute_name=\"$attribute_val\"";
440
		}
441
442
		$attributes_string = implode( ' ', $attributes_string );
443
	}
444
445
	// Get row class.
446
	if( ! empty( $row_class ) && is_array( $row_class ) ) {
447
		$row_class = implode( ' ', $row_class );
448
	}
449
	?>
450
	<div class="cmb-row <?php echo $row_class; ?>">
451
		<div class="cmb-th">
452
			<label for="<?php echo $id; ?>"><?php echo $label; ?></label>
453
		</div>
454
		<div class="cmb-td">
455
			<?php echo ( give_get_option( 'currency_position' ) == 'before' ? '<span class="give-money-symbol give-money-symbol-before">' . give_currency_symbol() . '</span>' : '' ); ?>
456
			<input id="<?php echo $id; ?>" type="text" name="<?php echo $name; ?>" <?php echo $attributes_string?>/>
457
			<?php echo ( give_get_option( 'currency_position' ) == 'after' ? '<span class="give-money-symbol give-money-symbol-after">' . give_currency_symbol() . '</span>' : '' ); ?>
458
459
			<span class="cmb2-metabox-description"><?php echo $description; ?></span>
460
		</div>
461
	</div>
462
	<?php
463
}