Completed
Pull Request — master (#859)
by Devin
19:40
created

formatting.php ➔ give_format_decimal()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 6
c 1
b 0
f 0
nc 2
nop 2
dl 0
loc 10
rs 9.4285
ccs 0
cts 10
cp 0
crap 6
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
    $thousand_separator = give_get_price_thousand_separator();
73 43
74 43
    $locale   = localeconv();
75
    $decimals = array( give_get_price_decimal_separator(), $locale['decimal_point'], $locale['mon_decimal_point'] );
76
77 43
    // Remove locale from string
78
    if ( ! is_float( $number ) ) {
79
        $number = str_replace( $decimals, '.', $number );
80
    }
81
82
    // Remove thousand amount formatting if amount has.
83
    // This condition use to add backward compatibility to version before 1.6, because before version 1.6 we were saving formatted amount to db.
84 43
    // Do not replace thousand separator from price if it is same as decimal separator, because it will be already replace by above code.
85
    if(  ! in_array( $thousand_separator, $decimals ) && ( false !== strpos( $number, $thousand_separator ) ) ) {
86
        $number = str_replace( $thousand_separator, '', $number );
87
    }
88
89 43
    // Remove non numeric entity before decimal separator.
90
    $number     = preg_replace( '/[^0-9\.]/', '', $number );
91
    $default_dp = give_get_price_decimals();
92
93
    // Format number of decimals in number.
94
    if( false !== $dp ) {
95
        $dp     = intval(  empty( $dp ) ? $default_dp : $dp );
96
        $dp     = apply_filters( 'give_sanitize_amount_decimals', $dp, $number );
97
        $number = number_format( floatval( $number ), $dp, '.', '' );
98
    }
99 43
100
    // Reset negative amount to zero.
101
	if ( 0 > $number ) {
102
		$number = number_format( 0, $default_dp, '.' );
103 43
	}
104 2
105 2
    // If number does not have decimal then add number of decimals to it.
106
    if(
107 43
        false === strpos( $number, '.' )
108
        || ( $default_dp > strlen( substr( $number, strpos( $number , '.' ) + 1 ) ) )
109 43
    ) {
110
        $number = number_format( $number, $default_dp, '.', '' );
111 43
    }
112
113
    // Trim zeros.
114
    if ( $trim_zeros && strstr( $number, '.' ) ) {
115
        $number = rtrim( rtrim( $number, '0' ), '.' );
116
    }
117
118
    return apply_filters( 'give_sanitize_amount', $number );
119
}
120
121
/**
122
 * Returns a nicely formatted amount.
123
 *
124
 * @since 1.0
125
 *
126
 * @param string      $amount   Price amount to format
127
 * @param bool|string $decimals Whether or not to use decimals. Useful when set to false for non-currency numbers.
128
 *
129
 * @return string $amount Newly formatted amount or Price Not Available
130
 */
131
function give_format_amount( $amount, $decimals = true ) {
132
133
	$thousands_sep = give_get_option( 'thousands_separator', ',' );
134
	$decimal_sep   = give_get_option( 'decimal_separator', '.' );
135
136
	// Format the amount
137
	if ( $decimal_sep == ',' && false !== ( $sep_found = strpos( $amount, $decimal_sep ) ) ) {
138
		$whole  = substr( $amount, 0, $sep_found );
139
		$part   = substr( $amount, $sep_found + 1, ( strlen( $amount ) - 1 ) );
140
		$amount = $whole . '.' . $part;
141
	}
142
143
	// Strip , from the amount (if set as the thousands separator)
144
	if ( $thousands_sep == ',' && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
145
		$amount = str_replace( ',', '', $amount );
146 45
	}
147 45
148 45
	// Strip . from the amount (if set as the thousands separator) AND , set to decimal separator
149
	if ( $thousands_sep == '.' && $decimal_sep == ',' && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
150 45
		$amount      = explode( '.', $amount );
151
		$array_count = count( $amount );
152 45
		if ( $decimals == true ) {
153
			unset( $amount[ $array_count - 1 ] );
154 45
		}
155
		$amount = implode( '', $amount );
156
	}
157
158 45
	// Strip ' ' from the amount (if set as the thousands separator)
159
	if ( $thousands_sep == ' ' && false !== ( $found = strpos( $amount, $thousands_sep ) ) ) {
160 45
		$amount = str_replace( ' ', '', $amount );
161
	}
162 45
163 45
	if ( empty( $amount ) ) {
164 45
		$amount = 0;
165 45
	}
166 45
167 45
	$decimals = give_get_price_decimals();
168 45
169 45
	$formatted = number_format( $amount, $decimals, $decimal_sep, $thousands_sep );
170 45
171 45
	return apply_filters( 'give_format_amount', $formatted, $amount, $decimals, $decimal_sep, $thousands_sep );
172 45
}
173 45
174 45
175 45
/**
176 45
 * Get human readable amount.
177 45
 *
178 45
 * Note: This function only support large number formatting from million to trillion
179 45
 *
180 45
 * @since 1.6
181 45
 *
182 45
 * @use  give_get_price_thousand_separator Get thousand separator.
183 45
 *
184 45
 * @param string $amount formatted amount number.
185 45
 * @return float|string  formatted amount number with large number names.
186 45
 */
187 45
function give_human_format_large_amount( $amount ) {
188 45
189 45
    // Get thousand separator.
190 45
    $thousands_sep = give_get_price_thousand_separator();
191 45
192
    // Sanitize amount.
193
    $sanitize_amount = give_sanitize_amount( $amount );
194
195
    // Explode amount to calculate name of large numbers.
196
	$amount_array = explode( $thousands_sep, $amount );
197
198
    // Calculate amount parts count.
199 45
    $amount_count_parts = count( $amount_array );
200 45
201
    // Calculate large number formatted amount.
202
    if ( 4 < $amount_count_parts ){
203
        $sanitize_amount =  sprintf( esc_html__( '%s trillion', 'give' ), round( ( $sanitize_amount / 1000000000000 ), 2 ) );
204
    } elseif ( 3 < $amount_count_parts ){
205
        $sanitize_amount =  sprintf( esc_html__( '%s billion', 'give' ), round( ( $sanitize_amount / 1000000000 ), 2 ));
206
    } elseif ( 2 < $amount_count_parts  ) {
207
        $sanitize_amount =  sprintf( esc_html__( '%s million', 'give' ), round( ( $sanitize_amount / 1000000), 2 ) );
208
    } else{
209
        $sanitize_amount = give_format_amount( $amount );
210
    }
211
212
    return apply_filters( 'give_human_format_large_amount', $sanitize_amount, $amount );
213
}
214
215
/**
216
 * Returns a nicely formatted amount with custom decimal separator.
217
 *
218
 * @since 1.0
219
 *
220
 * @param int|float|string      $amount   Formatted or sanitized price
221
 * @param int|bool    $dp       number of decimals
222
 *
223
 * @return string $amount Newly formatted amount or Price Not Available
224
 */
225
function give_format_decimal( $amount, $dp = false ){
226
    $decimal_separator = give_get_price_decimal_separator();
227
    $formatted_amount  = give_sanitize_amount( $amount, $dp );
228
229
    if( false !== strpos( $formatted_amount, '.' ) ) {
230
        $formatted_amount = str_replace( '.', $decimal_separator, $formatted_amount );
231
    }
232
233
    return apply_filters( 'give_format_decimal', $formatted_amount, $amount, $decimal_separator );
234
}
235
236
237
/**
238 45
 * Format Multi-level Amount
239
 *
240
 * Loops through CMB2 repeater field and updates amount field using give_format_amount()
241
 *
242
 * @param $field_args
243 45
 * @param $field
244
 *
245
 * @return bool
246
 */
247
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...
248
249
	if ( empty( $field->value ) ) {
250
		return false;
251
	}
252
253
	$field->value = give_format_decimal( $field->value );
254
}
255
256
/**
257 55
 * Formats the currency display
258
 *
259
 * @since 1.0
260 55
 *
261 55
 * @param string $price
262 55
 * @param string $currency
263 55
 *
264
 * @return mixed|string|void
265
 */
266
function give_currency_filter( $price = '', $currency = '' ) {
267
268
	if ( empty( $currency ) ) {
269 55
		$currency = give_get_currency();
270
	}
271
272
	$position = give_get_option( 'currency_position', 'before' );
273
274
	$negative = $price < 0;
275
276
	if ( $negative ) {
277
        // Remove proceeding "-".
278
		$price = substr( $price, 1 );
279
	}
280
281
	$symbol = give_currency_symbol( $currency );
282
283
    switch ( $currency ):
284
        case 'GBP' :
285
        case 'BRL' :
286
        case 'EUR' :
287
        case 'USD' :
288
        case 'AUD' :
289
        case 'CAD' :
290
        case 'HKD' :
291
        case 'MXN' :
292
        case 'NZD' :
293
        case 'SGD' :
294
        case 'JPY' :
295
        case 'THB' :
296
        case 'INR' :
297
        case 'RIAL' :
298
        case 'TRY' :
299
        case 'RUB' :
300
        case 'SEK' :
301
        case 'PLN' :
302
        case 'PHP' :
303
        case 'TWD' :
304
        case 'MYR' :
305
        case 'CZK' :
306
        case 'DKK' :
307
        case 'HUF' :
308
        case 'ILS' :
309
        case 'MAD' :
310
        case 'KRW' :
311
        case 'ZAR' :
312
            $formatted = ( 'before' === $position ? $symbol . $price : $price . $symbol );
313
            break;
314
        case 'NOK' :
315
            $formatted = ( 'before' === $position ? $symbol . ' ' . $price : $price . ' ' . $symbol );
316
            break;
317
        default :
318
            $formatted = ( 'before' === $position ? $currency . ' ' . $price : $price . ' ' . $currency );
319
            break;
320
    endswitch;
321
322
    /**
323
     * Filter formatted amount with currency
324
     *
325
     * Filter name depends upon current value of currency and currency position.
326
     * For example :
327
     *           if currency is USD and currency position is before then
328
     *           filter name will be give_usd_currency_filter_before
329
     *
330
     *           and if currency is USD and currency position is after then
331
     *           filter name will be give_usd_currency_filter_after
332
     *
333
     */
334
    $formatted = apply_filters( 'give_' . strtolower( $currency ) . "_currency_filter_{$position}", $formatted, $currency, $price );
335
336
    if ( $negative ) {
337
		// Prepend the minus sign before the currency sign.
338
		$formatted = '-' . $formatted;
339
	}
340
341
	return $formatted;
342
}
343
344
/**
345
 * Set the number of decimal places per currency
346
 *
347
 * @since 1.0
348
 * @since 1.6 $decimals parameter removed from function params
349
 **
350
 * @return int $decimals
351
 */
352
function give_currency_decimal_filter() {
353
354
    remove_filter( 'give_sanitize_amount_decimals', 'give_currency_decimal_filter' );
355
356
    // Set default number of decimals.
357
    $decimals = give_get_price_decimals();
358
359
    add_filter( 'give_sanitize_amount_decimals', 'give_currency_decimal_filter' );
360
361
362
    // Get number of decimals with backward compatibility ( version < 1.6 )
363
    if( 1 <= func_num_args() ){
364
        $decimals = ( false === func_get_arg( 0 ) ? $decimals : absint( func_get_arg( 0 ) ) );
365
    }
366
367
	$currency = give_get_currency();
368
369
	switch ( $currency ) {
370
		case 'RIAL' :
371
		case 'JPY' :
372
		case 'TWD' :
373
		case 'HUF' :
374
375
			$decimals = 0;
376
			break;
377
	}
378
379
	return apply_filters( 'give_currency_decimal_count', $decimals, $currency );
380
}
381
382
add_filter( 'give_sanitize_amount_decimals', 'give_currency_decimal_filter' );
383
add_filter( 'give_format_amount_decimals', 'give_currency_decimal_filter' );
384
385
/**
386
 * Sanitize thousand separator
387
 *
388
 * @since 1.6
389
 *
390
 * @param string $value
391
 * @param array  $field_args
392
 * @param object $field
393
 *
394
 * @return mixed
395
 */
396
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...
397
    return $value;
398
}
399
400
401
/**
402
 * Sanitize number of decimals
403
 *
404
 * @since 1.6
405
 *
406
 * @param string $value
407
 * @param array  $field_args
408
 * @param object $field
409
 *
410
 * @return mixed
411
 */
412
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...
413
	return absint($value);
414
}
415
416
/**
417
 * Sanitize price file value
418
 *
419
 * @since 1.6
420
 *
421
 * @param string $value
422
 * @param array  $field_args
423
 * @param object $field
424
 *
425
 * @return mixed
426
 */
427
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...
428
    return give_sanitize_amount( $value );
429
}