Completed
Branch BUG/11288/fix-datepicker (d15367)
by
unknown
108:07 queued 94:31
created

EEH_Money::format_currency()   B

Complexity

Conditions 7
Paths 9

Size

Total Lines 64
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 41
nc 9
nop 6
dl 0
loc 64
rs 7.2058
c 0
b 0
f 0

How to fix   Long Method   

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
2
3
use EventEspresso\core\exceptions\InvalidDataTypeException;
4
use EventEspresso\core\exceptions\InvalidInterfaceException;
5
6
defined('EVENT_ESPRESSO_VERSION') || exit('NO direct script access allowed');
7
8
9
10
/**
11
 * Money helper class.
12
 * This class has helper methods that help with money related conversions and calculations.
13
 *
14
 * @package        Event Espresso
15
 * @subpackage     helpers
16
 * @author         Darren Ethier
17
 * ------------------------------------------------------------------------
18
 */
19
class EEH_Money extends EEH_Base
20
{
21
22
    /**
23
     * This removes all localized money formatting from the incoming value
24
     * Note: uses this site's currency settings for deciding what is considered a
25
     * "thousands separator" (usually the character "," )
26
     * and what is a "decimal mark" (usually the character ".")
27
     *
28
     * @param int|float|string $money_value
29
     * @param string           $CNT_ISO
30
     * @return float
31
     * @throws EE_Error
32
     * @throws InvalidArgumentException
33
     * @throws ReflectionException
34
     * @throws InvalidDataTypeException
35
     * @throws InvalidInterfaceException
36
     */
37
    public static function strip_localized_money_formatting($money_value, $CNT_ISO = '')
38
    {
39
        $currency_config = EEH_Money::get_currency_config($CNT_ISO);
40
        $money_value     = str_replace(
41
            array(
42
                $currency_config->thsnds,
43
                $currency_config->dec_mrk,
44
            ),
45
            array(
46
                '', // remove thousands separator
47
                '.', // convert decimal mark to what PHP expects
48
            ),
49
            $money_value
50
        );
51
        $money_value     = filter_var(
52
            $money_value,
53
            FILTER_SANITIZE_NUMBER_FLOAT,
54
            FILTER_FLAG_ALLOW_FRACTION
55
        );
56
        return $money_value;
57
    }
58
59
60
    /**
61
     * This converts an incoming localized money value into a standard float item (to three decimal places)
62
     * Only use this if you know the $money_value follows your currency configuration's
63
     * settings. Note: this uses this site's currency settings for deciding what is considered a
64
     * "thousands separator" (usually the character "," )
65
     * and what is a "decimal mark" (usually the character ".")
66
     *
67
     * @param int|string $money_value
68
     * @return float
69
     * @throws EE_Error
70
     * @throws InvalidArgumentException
71
     * @throws ReflectionException
72
     * @throws InvalidDataTypeException
73
     * @throws InvalidInterfaceException
74
     */
75
    public static function convert_to_float_from_localized_money($money_value)
76
    {
77
        //float it! and round to three decimal places
78
        return round((float) EEH_Money::strip_localized_money_formatting($money_value), 3);
79
    }
80
81
82
    /**
83
     * For comparing floats. Default operator is '=', but see the $operator below for all options.
84
     * This should be used to compare floats instead of normal '==' because floats
85
     * are inherently imprecise, and so you can sometimes have two floats that appear to be identical
86
     * but actually differ by 0.00000001.
87
     *
88
     * @see http://biostall.com/php-function-to-compare-floating-point-numbers
89
     * @param float  $float1
90
     * @param float  $float2
91
     * @param string $operator The operator. Valid options are =, <=, <, >=, >, <>, eq, lt, lte, gt, gte, ne
92
     * @return bool whether the equation is true or false
93
     * @throws EE_Error
94
     */
95
    public static function compare_floats($float1, $float2, $operator = '=')
96
    {
97
        // Check numbers to 5 digits of precision
98
        $epsilon = 0.00001;
99
        $float1  = (float) $float1;
100
        $float2  = (float) $float2;
101
        switch ($operator) {
102
            // equal
103
            case '=':
104
            case '==':
105
            case '===':
106
            case 'eq':
107
                if (abs($float1 - $float2) < $epsilon) {
108
                    return true;
109
                }
110
                break;
111
            // less than
112
            case '<':
113 View Code Duplication
            case 'lt':
114
                if (abs($float1 - $float2) < $epsilon) {
115
                    return false;
116
                }
117
                if ($float1 < $float2) {
118
                    return true;
119
                }
120
                break;
121
            // less than or equal
122
            case '<=':
123 View Code Duplication
            case 'lte':
124
                if (
125
                    self::compare_floats($float1, $float2, '<')
126
                    || self::compare_floats($float1, $float2)
127
                ) {
128
                    return true;
129
                }
130
                break;
131
            // greater than
132
            case '>':
133 View Code Duplication
            case 'gt':
134
                if (abs($float1 - $float2) < $epsilon) {
135
                    return false;
136
                }
137
                if ($float1 > $float2) {
138
                    return true;
139
                }
140
                break;
141
            // greater than or equal
142
            case '>=':
143 View Code Duplication
            case 'gte':
144
                if (
145
                    self::compare_floats($float1, $float2, '>')
146
                    || self::compare_floats($float1, $float2)
147
                ) {
148
                    return true;
149
                }
150
                break;
151
            case '<>':
152
            case '!=':
153
            case 'ne':
154
                if (abs($float1 - $float2) > $epsilon) {
155
                    return true;
156
                }
157
                break;
158
            default:
159
                throw new EE_Error(
160
                    esc_html__(
161
                        "Unknown operator '" . $operator . "' in EEH_Money::compare_floats()",
162
                        'event_espresso'
163
                    )
164
                );
165
        }
166
        return false;
167
    }
168
169
170
    /**
171
     * This returns a localized format string suitable for jqPlot.
172
     *
173
     * @param string $CNT_ISO  If this is provided, then will attempt to get the currency settings for the country.
174
     *                         Otherwise will use currency settings for current active country on site.
175
     * @return string
176
     * @throws EE_Error
177
     * @throws InvalidArgumentException
178
     * @throws ReflectionException
179
     * @throws InvalidDataTypeException
180
     * @throws InvalidInterfaceException
181
     */
182
    public static function get_format_for_jqplot($CNT_ISO = '')
183
    {
184
        //default format
185
        $format          = 'f';
186
        $currency_config = $currency_config = EEH_Money::get_currency_config($CNT_ISO);
187
        //first get the decimal place and number of places
188
        $format = "%'." . $currency_config->dec_plc . $format;
189
        //currency symbol on right side.
190
        $format = $currency_config->sign_b4 ? $currency_config->sign . $format : $format . $currency_config->sign;
191
        return $format;
192
    }
193
194
195
    /**
196
     * This returns a localized format string suitable for usage with the Google Charts API format param.
197
     *
198
     * @param string $CNT_ISO  If this is provided, then will attempt to get the currency settings for the country.
199
     *                         Otherwise will use currency settings for current active country on site.
200
     *                         Note: GoogleCharts uses ICU pattern set
201
     *                         (@see http://icu-project.org/apiref/icu4c/classDecimalFormat.html#_details)
202
     * @return array
203
     * @throws EE_Error
204
     * @throws InvalidArgumentException
205
     * @throws ReflectionException
206
     * @throws InvalidDataTypeException
207
     * @throws InvalidInterfaceException
208
     */
209
    public static function get_format_for_google_charts($CNT_ISO = '')
210
    {
211
        $currency_config            = EEH_Money::get_currency_config($CNT_ISO);
212
        $decimal_places_placeholder = str_pad('', $currency_config->dec_plc, '0');
213
        //first get the decimal place and number of places
214
        $format = '#,##0.' . $decimal_places_placeholder;
215
        //currency symbol on right side.
216
        $format          = $currency_config->sign_b4
217
            ? $currency_config->sign . $format
218
            : $format
219
              . $currency_config->sign;
220
        $formatterObject = array(
221
            'decimalSymbol'  => $currency_config->dec_mrk,
222
            'groupingSymbol' => $currency_config->thsnds,
223
            'fractionDigits' => $currency_config->dec_plc,
224
        );
225
        if ($currency_config->sign_b4) {
226
            $formatterObject['prefix'] = $currency_config->sign;
227
        } else {
228
            $formatterObject['suffix'] = $currency_config->sign;
229
        }
230
        return array(
231
            'format'          => $format,
232
            'formatterObject' => $formatterObject,
233
        );
234
    }
235
236
237
    /**
238
     * @param string $CNT_ISO
239
     * @param bool   $from_db whether to fetch currency data from the admin editable DB, or the immutable JSON file
240
     * @return EE_Currency_Config
241
     * @throws EE_Error
242
     * @throws InvalidArgumentException
243
     * @throws ReflectionException
244
     * @throws InvalidDataTypeException
245
     * @throws InvalidInterfaceException
246
     */
247
    public static function get_currency_config($CNT_ISO = '', $from_db = true)
248
    {
249
        //if CNT_ISO passed lets try to get currency settings for it.
250
        $currency_config = $CNT_ISO !== ''
251
            ? new EE_Currency_Config($CNT_ISO)
252
            : null;
253
        if ($from_db) {
254
            $country = EEM_Country::instance()->get_one_by_ID($CNT_ISO);
255
            if ($country instanceof EE_Country) {
256
                $currency_config->setFromCountry($country);
257
            }
258
        }
259
        //default currency settings for site if not set
260
        if (! $currency_config instanceof EE_Currency_Config) {
261
            $currency_config = EE_Registry::instance()->CFG->currency instanceof EE_Currency_Config
262
                ? EE_Registry::instance()->CFG->currency
263
                : new EE_Currency_Config();
264
        }
265
        return $currency_config;
266
    }
267
268
269
    /**
270
     * replacement for EEH_Template::format_currency
271
     * This helper takes a raw float value and formats it according to the default config country currency settings, or
272
     * the country currency settings from the supplied country ISO code
273
     *
274
     * @param  float   $amount       raw money value
275
     * @param  boolean $return_raw   whether to return the formatted float value only with no currency sign or code
276
     * @param  boolean $display_code whether to display the country code (USD). Default = TRUE
277
     * @param string   $CNT_ISO      2 letter ISO code for a country
278
     * @param string   $cur_code_span_class
279
     * @param boolean  $from_db whether to fetch configuration data from the database (which a site admin can change)
280
     *                          or from our JSON file, which admins can't change. Setting to true is usually better
281
     *                          if the value will be displayed to a user; but if communicating with another server,
282
     *                          setting to false will return more reliable formatting.
283
     * @since $VID:$
284
     * @return string        the html output for the formatted money value
285
     * @throws EE_Error
286
     * @throws InvalidArgumentException
287
     * @throws ReflectionException
288
     * @throws InvalidDataTypeException
289
     * @throws InvalidInterfaceException
290
     */
291
    public static function format_currency(
292
        $amount = null,
293
        $return_raw = false,
294
        $display_code = true,
295
        $CNT_ISO = '',
296
        $cur_code_span_class = 'currency-code',
297
        $from_db = true
298
    ) {
299
        // ensure amount was received
300
        if ($amount === null) {
301
            $msg = esc_html__('In order to format currency, an amount needs to be passed.', 'event_espresso');
302
            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
303
            return '';
304
        }
305
        //ensure amount is float
306
        $amount  = (float)filter_var(
307
            apply_filters('FHEE__EEH_Template__format_currency__raw_amount', $amount),
308
            FILTER_SANITIZE_NUMBER_FLOAT,
309
            FILTER_FLAG_ALLOW_FRACTION
310
        );
311
        $CNT_ISO = (string) apply_filters('FHEE__EEH_Template__format_currency__CNT_ISO', $CNT_ISO, $amount);
312
        // filter raw amount (allows 0.00 to be changed to "free" for example)
313
        $amount_formatted = apply_filters('FHEE__EEH_Template__format_currency__amount', $amount, $return_raw);
314
        // still a number or was amount converted to a string like "free" ?
315
        if (is_float($amount_formatted)) {
316
            // get currency config object for that country
317
            $mny = EEH_Money::get_currency_config($CNT_ISO, $from_db);
318
            // format float
319
            $amount_formatted = number_format($amount, $mny->dec_plc, $mny->dec_mrk, $mny->thsnds);
320
            // add formatting ?
321
            if (! $return_raw) {
322
                // add currency sign
323
                if ($mny->sign_b4) {
324
                    if ($amount >= 0) {
325
                        $amount_formatted = $mny->sign . $amount_formatted;
326
                    } else {
327
                        $amount_formatted = '-' . $mny->sign . str_replace('-', '', $amount_formatted);
328
                    }
329
                } else {
330
                    $amount_formatted .= $mny->sign;
331
                }
332
                // filter to allow global setting of display_code
333
                $display_code = filter_var(
334
                    apply_filters('FHEE__EEH_Template__format_currency__display_code', $display_code),
335
                    FILTER_VALIDATE_BOOLEAN
336
                );
337
                // add currency code ?
338
                $amount_formatted = $display_code
339
                    ? $amount_formatted . ' <span class="' . $cur_code_span_class . '">(' . $mny->code . ')</span>'
340
                    : $amount_formatted;
341
            }
342
            // filter results
343
            $amount_formatted = (string) apply_filters(
344
                'FHEE__EEH_Template__format_currency__amount_formatted',
345
                $amount_formatted,
346
                $mny,
347
                $return_raw
348
            );
349
        }
350
        // clean up vars
351
        unset($mny);
352
        // return formatted currency amount
353
        return $amount_formatted;
354
    }
355
}
356