Completed
Push — master ( 79000f...ecfa5f )
by Sébastien
02:41
created

CurrencyFormatter::initWhitespaceSeparator()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 9
cts 9
cp 1
rs 9.7666
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 3
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * soluble-flexstore library
7
 *
8
 * @author    Vanvelthem Sébastien
9
 * @link      https://github.com/belgattitude/soluble-flexstore
10
 * @copyright Copyright (c) 2016-2017 Vanvelthem Sébastien
11
 * @license   MIT License https://github.com/belgattitude/soluble-flexstore/blob/master/LICENSE.md
12
 *
13
 */
14
15
namespace Soluble\FlexStore\Formatter;
16
17
use Soluble\FlexStore\Exception;
18
use ArrayObject;
19
use NumberFormatter as IntlNumberFormatter;
20
21
/**
22
 * columns
23
 *  - price:
24
 *    - formatter:
25
 *          - money
26
 *              - currency_code
27
 *              - locale.
28
 */
29
class CurrencyFormatter extends NumberFormatter
30
{
31
    /**
32
     * @var string|null
33
     */
34
    protected $currency_column;
35
36
    /**
37
     * @var array
38
     */
39
    protected $default_params = [
40
        'decimals' => 2,
41
        'locale' => null,
42
        'pattern' => null,
43
        'currency_code' => null,
44
        'disableUseOfNonBreakingSpaces' => false
45
    ];
46
47
    /**
48
     * @throws Exception\ExtensionNotLoadedException if ext/intl is not present
49
     */
50 12
    public function __construct(array $params = [])
51
    {
52 12
        parent::__construct($params);
53 12
    }
54
55 6
    protected function loadFormatterId(string $formatterId): void
56
    {
57 6
        $locale = $this->params['locale'];
58 6
        $formatter = new IntlNumberFormatter(
59 6
            $locale,
60 6
            IntlNumberFormatter::CURRENCY
61
        );
62 6
        $formatter->setAttribute(IntlNumberFormatter::FRACTION_DIGITS, $this->params['decimals']);
63 6
        if ($this->params['pattern'] !== null) {
64
            $formatter->setPattern($this->params['pattern']);
65
        }
66 6
        $this->initWhitespaceSeparator($formatter);
67 6
        $this->formatters[$formatterId] = $formatter;
68 6
    }
69
70
    /**
71
     * Currency format a number.
72
     *
73
     * @throws Exception\RuntimeException
74
     *
75
     * @param float|string|int $number
76
     *
77
     * @return string
78
     */
79 6
    public function format($number, ArrayObject $row = null): string
80
    {
81 6
        $locale = $this->params['locale'];
82
83
        //$formatterId = md5($locale);
84 6
        $formatterId = $locale . (string) $this->params['pattern'];
85
86 6
        if (!array_key_exists($formatterId, $this->formatters)) {
87 6
            $this->loadFormatterId($formatterId);
88
        }
89
90 6
        if ($this->currency_column !== null) {
91 1
            if (!isset($row[$this->currency_column])) {
92
                throw new Exception\RuntimeException(__METHOD__ . " Cannot determine currency code based on column '{$this->currency_column}'.");
93
            }
94 1
            $value = $this->formatters[$formatterId]->formatCurrency(
95 1
                (float) $number,
96 1
                $row[$this->currency_column]
97
            );
98
        } else {
99 5
            if ($this->params['currency_code'] == '') {
100 3
                throw new Exception\RuntimeException(__METHOD__ . ' Currency code must be set prior to use the currency formatter');
101
            }
102
103 2
            $value = $this->formatters[$formatterId]->formatCurrency(
104 2
                (float) $number,
105 2
                $this->params['currency_code']
106
            );
107
        }
108
109 3
        if (intl_is_failure($this->formatters[$formatterId]->getErrorCode())) {
110
            $this->throwNumberFormatterException($this->formatters[$formatterId], $number);
111
        }
112
113 3
        return $value;
114
    }
115
116
    /**
117
     * Parse a.
118
     *
119
     * @param string $value
120
     *
121
     * @return array|null
122
     */
123 1
    public function parse($value)
124
    {
125 1
        $locale = $this->params['locale'];
126
        //$formatterId = md5($locale);
127 1
        $formatterId = $locale;
128 1
        if (!array_key_exists($formatterId, $this->formatters)) {
129
            $this->loadFormatterId($formatterId);
130
        }
131
        // Currency will be passed as reference
132
        // setting it to null prevent eventual warning
133 1
        $currency = null;
134 1
        $result = $this->formatters[$formatterId]->parseCurrency($value, $currency);
135
136 1
        if ($result === false) {
137
            return null;
138
        }
139
140 1
        return ['value' => $result, 'currency' => $currency];
141
    }
142
143
    /**
144
     * The 3-letter ISO 4217 currency code indicating the currency to use.
145
     *
146
     * @throws Exception\InvalidArgumentException
147
     *
148
     * @param string|RowColumn $currencyCode
149
     */
150 4
    public function setCurrencyCode($currencyCode): self
151
    {
152 4
        if ($currencyCode instanceof RowColumn) {
153 2
            $this->currency_column = $currencyCode->getColumnName();
154 3
        } elseif (!is_string($currencyCode) || trim($currencyCode) === '') {
155
            throw new Exception\InvalidArgumentException(__METHOD__ . ' Currency code must be an non empty string (or a RowColumn object)');
156
        }
157 4
        $this->params['currency_code'] = $currencyCode;
158
159 4
        return $this;
160
    }
161
162 6
    protected function initWhitespaceSeparator(IntlNumberFormatter $formatter): void
163
    {
164 6
        parent::initWhitespaceSeparator($formatter);
165 6
        if ($this->params['disableUseOfNonBreakingSpaces'] === true
166 1
            && in_array(bin2hex($formatter->getSymbol(IntlNumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL)), [
167 1
                self::NARROW_NO_BREAK_SPACE_HEX,
168 1
                self::NO_BREAK_SPACE_HEX
169 6
            ], true)) {
0 ignored issues
show
Coding Style introduced by
Blank line found at start of control structure
Loading history...
170
171 1
            $formatter->setSymbol(IntlNumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL, ' ');
172
            // This does not work on php 7.3 (bug) !
173
            //$formatter->setSymbol(IntlNumberFormatter::MONETARY_SEPARATOR_SYMBOL, ' ');
174
0 ignored issues
show
Coding Style introduced by
Blank line found at end of control structure
Loading history...
175
        }
176 6
    }
177
178
    /**
179
     * Get the 3-letter ISO 4217 currency code indicating the currency to use.
180
     *
181
     * @return string|RowColumn
182
     */
183 1
    public function getCurrencyCode()
184
    {
185 1
        return $this->params['currency_code'];
186
    }
187
}
188