From e654dba5e384b108c0f58ee0ba70c0fca078e566 Mon Sep 17 00:00:00 2001 From: Thomas Zilio Date: Wed, 20 Sep 2017 12:14:33 +0200 Subject: [PATCH] Migliorato supporto nativo delle conversione numeriche Aggiunto sistema basilare per le conversioni numeriche nel caso non sia presente l'estensione intl di PHP. --- config.example.php | 10 ++- include/configuration.php | 3 +- src/Intl/Formatter.php | 127 +++++++++++++++++++++++++++++++++----- src/Translator.php | 6 +- 4 files changed, 129 insertions(+), 17 deletions(-) diff --git a/config.example.php b/config.example.php index ff646471c..f6f95ccd8 100644 --- a/config.example.php +++ b/config.example.php @@ -27,4 +27,12 @@ $HTMLManagers = []; // Lingua del progetto (per la traduzione e la conversione numerica) $lang = 'it'; // Personalizzazione della formattazione di timestamp, date e orari -$formatter = []; +$formatter = [ + 'timestamp' => 'd/m/Y H:i', + 'date' => 'd/m/Y', + 'time' => 'H:i', + 'number' => [ + 'decimals' => ',', + 'thousands' => '.', + ], +]; diff --git a/include/configuration.php b/include/configuration.php index 5dfa575b1..7e5da1780 100644 --- a/include/configuration.php +++ b/include/configuration.php @@ -294,7 +294,8 @@ if (empty($creation) && (!file_exists('config.inc.php') || !$valid_config)) { $extensions = [ 'zip' => tr("Necessario per l'utilizzo delle funzioni di aggiornamento automatico e backup, oltre che per eventuali moduli aggiuntivi"), 'pdo_mysql' => tr('Necessario per la connessione al database'), - 'openssl' => tr('Utile per la generazione di chiavi complesse (non obbligatorio)'), + 'openssl' => tr('Utile per la generazione di chiavi complesse (facoltativo)'), + 'intl' => tr('Utile per la gestione automatizzata della conversione numerica (facoltativo)'), ]; foreach ($extensions as $key => $value) { $check = extension_loaded($key); diff --git a/src/Intl/Formatter.php b/src/Intl/Formatter.php index b17c44418..0723bee90 100644 --- a/src/Intl/Formatter.php +++ b/src/Intl/Formatter.php @@ -16,10 +16,15 @@ class Formatter 'timestamp' => 'Y-m-d H:i:s', 'date' => 'Y-m-d', 'time' => 'H:i:s', + 'number' => [ + 'decimals' => '.', + 'thousands' => '', + ], ]; - /** @var NumberFormatter Oggetto dedicato alla formattazione dei numeri */ + /** @var NumberFormatter|array Oggetto dedicato alla formattazione dei numeri */ protected $numberFormatter; + protected $precision; /** @var string Pattern per i timestamp */ protected $timestampPattern; @@ -28,9 +33,13 @@ class Formatter /** @var string Pattern per gli orari */ protected $timePattern; - public function __construct($locale, $timestamp = null, $date = null, $time = null) + public function __construct($locale, $timestamp = null, $date = null, $time = null, $number = []) { - $this->numberFormatter = new NumberFormatter($locale, NumberFormatter::DECIMAL); + if (class_exists('NumberFormatter')) { + $this->numberFormatter = new NumberFormatter($locale, NumberFormatter::DECIMAL); + } else { + $this->numberFormatter = $number; + } $this->setTimestampPattern($timestamp); @@ -62,15 +71,23 @@ class Formatter { $value = trim($value); - if (!empty($decimals)) { - $original = $this->numberFormatter->getAttribute(NumberFormatter::FRACTION_DIGITS); - $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $decimals); - } + if (is_object($this->numberFormatter)) { + if (!empty($decimals)) { + $original = $this->numberFormatter->getAttribute(NumberFormatter::FRACTION_DIGITS); + $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $decimals); + } - $result = $this->numberFormatter->format($value); + $result = $this->numberFormatter->format($value); - if (!empty($decimals)) { - $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $original); + if (!empty($decimals)) { + $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $original); + } + } else { + $decimals = !empty($decimals) ? $decimals : $this->precision; + + $number = number_format($value, $decimals, $this->getStandardFormats()['number']['decimals'], $this->getStandardFormats()['number']['thousands']); + + $result = $this->customNumber($number, $this->getStandardFormats()['number'], $this->getNumberSeparators()); } return is_numeric($value) ? $result : false; @@ -85,7 +102,17 @@ class Formatter */ public function parseNumber($value) { - return ctype_digit(str_replace(array_values($this->getNumberSeparators()), '', $value)) ? $this->numberFormatter->parse($value) : false; + if (!ctype_digit(str_replace(array_values($this->getNumberSeparators()), '', $value))) { + return false; + } + + if (is_object($this->numberFormatter)) { + $result = $this->numberFormatter->parse($value); + } else { + $result = $this->customNumber($value, $this->getNumberSeparators(), $this->getStandardFormats()['number']); + } + + return $result; } /** @@ -123,7 +150,11 @@ class Formatter */ public function setPrecision($decimals) { - $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $decimals); + if (is_object($this->numberFormatter)) { + $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $decimals); + } else { + $this->precision = $decimals; + } } /** @@ -134,11 +165,79 @@ class Formatter public function getNumberSeparators() { return [ - 'decimals' => $this->numberFormatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL), - 'thousands' => $this->numberFormatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL), + 'decimals' => is_object($this->numberFormatter) ? $this->numberFormatter->getSymbol(NumberFormatter::DECIMAL_SEPARATOR_SYMBOL) : $this->numberFormatter['decimals'], + 'thousands' => is_object($this->numberFormatter) ? $this->numberFormatter->getSymbol(NumberFormatter::GROUPING_SEPARATOR_SYMBOL) : $this->numberFormatter['thousands'], ]; } + /** + * Converte l'elemento in una rappresentazione numerica. + * + * @param string $value + * + * @return array + */ + public function customNumber($value, $current, $format) + { + $value = trim($value); + + if (strlen($value) == 0) { + return false; + } + + $sign = null; + if ($value[0] == '+' || $value[0] == '-') { + $sign = $value[0]; + $value = trim(substr($value, 1)); + } elseif (!is_numeric($value[0])) { + return false; + } + + if (strlen($value) == 0) { + return false; + } + + $pieces = explode($current['decimals'], $value); + if (count($pieces) > 2) { + return false; + } + $integer = $pieces[0]; + $decimal = (isset($pieces[1])) ? $pieces[1] : null; + + if (!empty($current['thousands'])) { + $error = true; + if (floor(strlen($integer) / 4) == substr_count($integer, $current['thousands'])) { + $values = str_split(strrev($integer), 4); + + foreach ($values as $key => $value) { + if (strlen($value) == 4 && ends_with($value, $current['thousands'])) { + $values[$key] = substr($value, 0, -1); + } + } + + $integer = strrev(implode($values)); + + $error = substr_count($integer, $current['thousands']); + } + + if (!empty($error)) { + return false; + } + } + + if (!ctype_digit($integer) || (strlen($integer) != strlen((int) $integer)) || (isset($decimal) && !ctype_digit($decimal))) { + return false; + } + + $result = $sign.number_format($integer, 0, '', $format['thousands']); + + if (isset($decimal)) { + $result .= $format['decimals'].$decimal; + } + + return $result; + } + // Gestione della conversione dei timestamp /** diff --git a/src/Translator.php b/src/Translator.php index 084ec0ac1..b1878dad5 100644 --- a/src/Translator.php +++ b/src/Translator.php @@ -120,7 +120,11 @@ class Translator extends Util\Singleton $this->locale, empty($formatter['timestamp']) ? 'd/m/Y H:i' : $formatter['timestamp'], empty($formatter['date']) ? 'd/m/Y' : $formatter['date'], - empty($formatter['time']) ? 'H:i' : $formatter['time'] + empty($formatter['time']) ? 'H:i' : $formatter['time'], + empty($formatter['number']) ? [ + 'decimals' => ',', + 'thousands' => '.', + ] : $formatter['number'] ); self::$formatter->setPrecision(Settings::get('Cifre decimali per importi'));