Failed Conditions
Pull Request — master (#4127)
by Owen
10:47
created

CurrencyBase::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 18
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 8
dl 0
loc 18
rs 10
c 1
b 0
f 0
cc 1
nc 1
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Style\NumberFormat\Wizard;
4
5
use NumberFormatter;
6
use PhpOffice\PhpSpreadsheet\Exception;
7
8
class CurrencyBase extends Number
9
{
10
    public const LEADING_SYMBOL = true;
11
12
    public const TRAILING_SYMBOL = false;
13
14
    public const SYMBOL_WITH_SPACING = true;
15
16
    public const SYMBOL_WITHOUT_SPACING = false;
17
18
    protected string $currencyCode = '$';
19
20
    protected bool $currencySymbolPosition = self::LEADING_SYMBOL;
21
22
    protected bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING;
23
24
    protected const DEFAULT_STRIP_LEADING_RLM = false;
25
26
    protected bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM;
27
28
    public const DEFAULT_NEGATIVE = CurrencyNegative::minus;
29
30
    protected CurrencyNegative $negative = CurrencyNegative::minus;
31
32
    protected ?bool $overrideSpacing = null;
33
34
    protected ?CurrencyNegative $overrideNegative = null;
35
36
    // Not sure why original code uses nbsp
37
    private string $spaceOrNbsp = ' '; // or "\u{a0}"
38
39
    /**
40
     * @param string $currencyCode the currency symbol or code to display for this mask
41
     * @param int $decimals number of decimal places to display, in the range 0-30
42
     * @param bool $thousandsSeparator indicator whether the thousands separator should be used, or not
43
     * @param bool $currencySymbolPosition indicates whether the currency symbol comes before or after the value
44
     *              Possible values are Currency::LEADING_SYMBOL and Currency::TRAILING_SYMBOL
45
     * @param bool $currencySymbolSpacing indicates whether there is spacing between the currency symbol and the value
46
     *              Possible values are Currency::SYMBOL_WITH_SPACING and Currency::SYMBOL_WITHOUT_SPACING
47
     *              However, Currency always uses WITHOUT and Accounting always uses WITH
48
     * @param ?string $locale Set the locale for the currency format; or leave as the default null.
49
     *          If provided, Locale values must be a valid formatted locale string (e.g. 'en-GB', 'fr', uz-Arab-AF).
50
     *          Note that setting a locale will override any other settings defined in this class
51
     *          other than the currency code; or decimals (unless the decimals value is set to 0).
52
     * @param bool $stripLeadingRLM remove leading RLM added with
53
     *          ICU 72.1+.
54
     * @param CurrencyNegative $negative How to display negative numbers.
55
     *                         Always use parentheses for Accounting.
56
     *                         4 options for Currency.
57
     *
58
     * @throws Exception If a provided locale code is not a valid format
59
     */
60
    public function __construct(
61
        string $currencyCode = '$',
62
        int $decimals = 2,
63
        bool $thousandsSeparator = true,
64
        bool $currencySymbolPosition = self::LEADING_SYMBOL,
65
        bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING,
66
        ?string $locale = null,
67
        bool $stripLeadingRLM = self::DEFAULT_STRIP_LEADING_RLM,
68
        CurrencyNegative $negative = CurrencyNegative::minus
69
    ) {
70
        $this->setCurrencyCode($currencyCode);
71
        $this->setThousandsSeparator($thousandsSeparator);
72
        $this->setDecimals($decimals);
73
        $this->setCurrencySymbolPosition($currencySymbolPosition);
74
        $this->setCurrencySymbolSpacing($currencySymbolSpacing);
75
        $this->setLocale($locale);
76
        $this->stripLeadingRLM = $stripLeadingRLM;
77
        $this->negative = $negative;
78
    }
79
80
    public function setCurrencyCode(string $currencyCode): void
81
    {
82
        $this->currencyCode = $currencyCode;
83
    }
84
85
    public function setCurrencySymbolPosition(bool $currencySymbolPosition = self::LEADING_SYMBOL): void
86
    {
87
        $this->currencySymbolPosition = $currencySymbolPosition;
88
    }
89
90
    public function setCurrencySymbolSpacing(bool $currencySymbolSpacing = self::SYMBOL_WITHOUT_SPACING): void
91
    {
92
        $this->currencySymbolSpacing = $currencySymbolSpacing;
93
    }
94
95
    public function setStripLeadingRLM(bool $stripLeadingRLM): void
96
    {
97
        $this->stripLeadingRLM = $stripLeadingRLM;
98
    }
99
100
    public function setNegative(CurrencyNegative $negative): void
101
    {
102
        $this->negative = $negative;
103
    }
104
105
    protected function getLocaleFormat(): string
106
    {
107
        $formatter = new Locale($this->fullLocale, NumberFormatter::CURRENCY);
108
        $mask = $formatter->format($this->stripLeadingRLM);
109
        if ($this->decimals === 0) {
110
            $mask = (string) preg_replace('/\.0+/miu', '', $mask);
111
        }
112
113
        return str_replace('¤', $this->formatCurrencyCode(), $mask);
114
    }
115
116
    private function formatCurrencyCode(): string
117
    {
118
        if ($this->locale === null) {
119
            return $this->currencyCode;
120
        }
121
122
        return "[\${$this->currencyCode}-{$this->locale}]";
123
    }
124
125
    public function format(): string
126
    {
127
        if ($this->localeFormat !== null) {
128
            return $this->localeFormat;
129
        }
130
        $symbolWithSpacing = $this->overrideSpacing ?? ($this->currencySymbolSpacing === self::SYMBOL_WITH_SPACING);
131
        $negative = $this->overrideNegative ?? $this->negative;
132
133
        // format if positive
134
        $format = '_(';
135
        if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
136
            $format .= '"' . $this->currencyCode . '"';
137
            if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
138
                $format .= $this->spaceOrNbsp;
139
            }
140
            if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
141
                $format .= $this->spaceOrNbsp;
142
            }
143
            if ($symbolWithSpacing) {
144
                $format .= '*' . $this->spaceOrNbsp;
145
            }
146
        }
147
        $format .= $this->thousandsSeparator ? '#,##0' : '0';
148
        if ($this->decimals > 0) {
149
            $format .= '.' . str_repeat('0', $this->decimals);
150
        }
151
        if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
152
            if ($symbolWithSpacing) {
153
                $format .= $this->spaceOrNbsp;
154
            } elseif (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
155
                $format .= $this->spaceOrNbsp;
156
            }
157
            $format .= '[$' . $this->currencyCode . ']';
158
        }
159
        $format .= '_)';
160
161
        // format if negative
162
        $format .= ';_(';
163
        $format .= $negative->color();
164
        $negativeStart = $negative->start();
165
        if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
166
            if ($negativeStart === '-' && !$symbolWithSpacing) {
167
                $format .= $negativeStart;
168
            }
169
            $format .= '"' . $this->currencyCode . '"';
170
            if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
171
                $format .= $this->spaceOrNbsp;
172
            }
173
            if ($symbolWithSpacing) {
174
                $format .= '*' . $this->spaceOrNbsp;
175
            }
176
            if ($negativeStart === '\\(' || ($symbolWithSpacing && $negativeStart === '-')) {
177
                $format .= $negativeStart;
178
            }
179
        } else {
180
            $format .= $negative->start();
181
        }
182
        $format .= $this->thousandsSeparator ? '#,##0' : '0';
183
        if ($this->decimals > 0) {
184
            $format .= '.' . str_repeat('0', $this->decimals);
185
        }
186
        $format .= $negative->end();
187
        if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
188
            if ($symbolWithSpacing) {
189
                // Do nothing - I can't figure out how to get
190
                // everything to align if I put any kind of space here.
191
                //$format .= "\u{2009}";
192
            } elseif (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
193
                $format .= $this->spaceOrNbsp;
194
            }
195
            $format .= '[$' . $this->currencyCode . ']';
196
        }
197
        if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
198
            $format .= '_)';
199
        } elseif ($symbolWithSpacing && $negativeStart === '-') {
200
            $format .= ' ';
201
        }
202
        // format if zero
203
        $format .= ';_(';
204
        if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
205
            $format .= '"' . $this->currencyCode . '"';
206
        }
207
        if ($symbolWithSpacing) {
208
            if ($this->currencySymbolPosition === self::LEADING_SYMBOL) {
209
                $format .= '*' . $this->spaceOrNbsp;
210
            }
211
            $format .= '"-"';
212
            if ($this->decimals > 0) {
213
                $format .= str_repeat('?', $this->decimals);
214
            }
215
        } else {
216
            if (preg_match('/^[A-Z]{3}$/i', $this->currencyCode) === 1) {
217
                $format .= $this->spaceOrNbsp;
218
            }
219
            $format .= '0';
220
            if ($this->decimals > 0) {
221
                $format .= '.' . str_repeat('0', $this->decimals);
222
            }
223
        }
224
        if ($this->currencySymbolPosition === self::TRAILING_SYMBOL) {
225
            if ($symbolWithSpacing) {
226
                $format .= $this->spaceOrNbsp;
227
            }
228
            $format .= '[$' . $this->currencyCode . ']';
229
        }
230
        $format .= '_)';
231
        // format if text
232
        $format .= ';_(@_)';
233
234
        return $format;
235
    }
236
}
237