1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace EngineWorks\DBAL\Internal; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* This class parses a string expression as a number or as in plain english (as need to put inside a sql statement) |
9
|
|
|
* |
10
|
|
|
* @internal |
11
|
|
|
*/ |
12
|
|
|
class NumericParser |
13
|
|
|
{ |
14
|
|
|
use ConvertObjectToStringMethod; |
|
|
|
|
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Contains the running locale information |
18
|
|
|
* @var array{decimal_point: string, thousands_sep: string, currency_symbol: string}|null |
19
|
|
|
*/ |
20
|
|
|
private $localeConv = null; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @param mixed $value |
24
|
|
|
* @param bool $asInteger |
25
|
|
|
* @return int|float |
26
|
|
|
*/ |
27
|
317 |
|
public function parse($value, bool $asInteger) |
28
|
|
|
{ |
29
|
|
|
// return simple numeric data |
30
|
317 |
|
if (is_bool($value) || is_int($value) || is_float($value)) { |
31
|
|
|
return ($asInteger) ? intval($value) : floatval($value); |
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
// is object, convert to string |
35
|
317 |
|
if (is_object($value)) { |
36
|
|
|
$value = $this->convertObjectToString($value); |
37
|
|
|
} |
38
|
|
|
// is not string, early exit with 0 |
39
|
317 |
|
if (! is_string($value)) { |
40
|
|
|
return 0; |
41
|
|
|
} |
42
|
317 |
|
$value = $this->parseToEnglish(trim($value)); |
43
|
317 |
|
return ($asInteger) ? intval($value) : floatval($value); |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* @param mixed $value |
48
|
|
|
* @param bool $asInteger |
49
|
|
|
* @return string |
50
|
|
|
*/ |
51
|
317 |
|
public function parseAsEnglish($value, bool $asInteger): string |
52
|
|
|
{ |
53
|
317 |
|
return $this->numberToEnglish((string) $this->parse($value, $asInteger)); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
/** |
57
|
|
|
* @return array{decimal_point: string, thousands_sep: string, currency_symbol: string} |
58
|
|
|
*/ |
59
|
317 |
|
protected function getLocaleInfo(): array |
60
|
|
|
{ |
61
|
317 |
|
if (null === $this->localeConv) { |
62
|
317 |
|
$this->localeConv = $this->obtainLocaleInfo(); |
63
|
|
|
} |
64
|
317 |
|
return $this->localeConv; |
65
|
|
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @return array{decimal_point: string, thousands_sep: string, currency_symbol: string} |
69
|
|
|
*/ |
70
|
317 |
|
protected function obtainLocaleInfo(): array |
71
|
|
|
{ |
72
|
317 |
|
if ('C' === setlocale(LC_NUMERIC, '0')) { |
73
|
|
|
// override to us_EN |
74
|
|
|
return ['decimal_point' => '.', 'thousands_sep' => ',', 'currency_symbol' => '$']; |
75
|
|
|
} |
76
|
|
|
|
77
|
317 |
|
$locale = localeconv(); |
78
|
317 |
|
return [ |
79
|
317 |
|
'decimal_point' => strval($locale['decimal_point'] ?? '.'), |
80
|
317 |
|
'thousands_sep' => strval($locale['thousands_sep'] ?? ','), |
81
|
317 |
|
'currency_symbol' => strval($locale['currency_symbol'] ?? '$'), |
82
|
317 |
|
]; |
83
|
|
|
} |
84
|
|
|
|
85
|
|
|
/** |
86
|
|
|
* Remove the thousand separator, currency symbol and white spaces. |
87
|
|
|
* Returns the resulting string if is numeric, otherwise returns '0' |
88
|
|
|
* |
89
|
|
|
* @param string $value |
90
|
|
|
* @return string |
91
|
|
|
*/ |
92
|
317 |
|
protected function parseToEnglish(string $value): string |
93
|
|
|
{ |
94
|
317 |
|
if (ctype_digit($value)) { |
95
|
317 |
|
return $value; |
96
|
|
|
} |
97
|
297 |
|
$localeConv = $this->getLocaleInfo(); |
98
|
297 |
|
$replacements = [$localeConv['thousands_sep'], $localeConv['currency_symbol'], ' ', "\t"]; |
99
|
297 |
|
$value = $this->numberToEnglish(str_replace($replacements, '', $value)); |
100
|
297 |
|
return (! is_numeric($value)) ? '0' : $value; |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
/** |
104
|
|
|
* Change decimal point to a real point |
105
|
|
|
* @param string $value |
106
|
|
|
* @return string |
107
|
|
|
*/ |
108
|
317 |
|
protected function numberToEnglish(string $value): string |
109
|
|
|
{ |
110
|
317 |
|
if ('.' !== $this->getDecimalPoint()) { |
111
|
8 |
|
return str_replace($this->getDecimalPoint(), '.', $value); |
112
|
|
|
} |
113
|
317 |
|
return $value; |
114
|
|
|
} |
115
|
|
|
|
116
|
317 |
|
protected function getDecimalPoint(): string |
117
|
|
|
{ |
118
|
317 |
|
return $this->getLocaleInfo()['decimal_point']; |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
|