. */ namespace Intl; use DateTime; use NumberFormatter; /** * Classe per gestire la formattazione di date e numeri in convenzioni differenti. * * @since 2.3 */ class Formatter { protected static $standards = [ 'timestamp' => 'Y-m-d H:i:s', 'date' => 'Y-m-d', 'time' => 'H:i:s', 'number' => [ 'decimals' => '.', 'thousands' => '', ], ]; /** @var NumberFormatter|array Oggetto dedicato alla formattazione dei numeri */ protected $numberFormatter; protected $precision; /** @var string Pattern per i timestamp */ protected $timestampPattern; /** @var string Pattern per le date */ protected $datePattern; /** @var string Pattern per gli orari */ protected $timePattern; /** @var array Pattern per SQL */ protected $sql = []; public function __construct($locale, $timestamp = null, $date = null, $time = null, $number = []) { if (class_exists('NumberFormatter')) { $this->numberFormatter = new NumberFormatter($locale, NumberFormatter::DECIMAL); $this->numberFormatter->setAttribute(NumberFormatter::ROUNDING_MODE, NumberFormatter::ROUND_HALFUP); } else { $this->numberFormatter = $number; } $this->setTimestampPattern($timestamp); $this->setDatePattern($date); $this->setTimePattern($time); } /** * Restituisce gli elementi di separazione secondo la formattazione in utilizzo. * * @return array */ public static function getStandardFormats() { return static::$standards; } /** * Restituisce gli elementi di separazione secondo la formattazione in utilizzo. * * @return mixed */ public function format($value) { if (!empty($value)) { if ($this->isStandardDate($value)) { $value = $this->formatDate($value); } elseif ($this->isStandardTime($value)) { $value = $this->formatTime($value); } elseif ($this->isStandardTimestamp($value)) { $value = $this->formatTimestamp($value); } elseif ($this->isStandardNumber($value)) { $value = $this->formatNumber($value); } } return $value; } /** * Restituisce gli elementi di separazione secondo la formattazione in utilizzo. * * @return mixed */ public function parse($value) { if (!empty($value)) { if ($this->isFormattedDate($value)) { $value = $this->parseDate($value); } elseif ($this->isFormattedTime($value)) { $value = $this->parseTime($value); } elseif ($this->isFormattedTimestamp($value)) { $value = $this->parseTimestamp($value); } elseif ($this->isFormattedNumber($value)) { $value = $this->parseNumber($value); } } return $value; } // Gestione della conversione dei numeri /** * Converte un numero da una formattazione all'altra. * * @param string $value * @param int $decimals * * @return string|bool */ public function formatNumber($value, $decimals = null) { $value = trim($value); $value = floatval($value); if (isset($decimals)) { $original = $this->getPrecision(); $this->setPrecision($decimals); } if (is_object($this->numberFormatter)) { $result = $this->numberFormatter->format($value); } else { $number = number_format($value, $this->getPrecision(), self::getStandardFormats()['number']['decimals'], self::getStandardFormats()['number']['thousands']); $result = $this->customNumber($number, self::getStandardFormats()['number'], $this->getNumberSeparators()); } if (isset($decimals)) { $this->setPrecision($original); } return is_numeric($value) ? $result : false; } /** * Converte un numero da una formattazione all'altra. * * @param string $value * * @return float|bool */ public function parseNumber($value) { // Controllo sull'effettiva natura del numero $sign = null; if ($value[0] == '+' || $value[0] == '-') { $sign = $value[0]; $value = substr($value, 1); } $number = str_replace(array_values($this->getNumberSeparators()), '', $value); $pieces = explode($this->getNumberSeparators()['decimals'], $value); $integer = str_replace(array_values($this->getNumberSeparators()), '', $pieces[0]); if (!ctype_digit($number) || (strlen($integer) != strlen((int) $integer)) || is_numeric($value)) { return false; } $value = $sign.$value; if (is_object($this->numberFormatter)) { $result = $this->numberFormatter->parse($value); } else { $result = $this->customNumber($value, $this->getNumberSeparators(), self::getStandardFormats()['number']); } $result = is_numeric($result) ? floatval($result) : false; return $result; } /** * Controlla se l'elemento indicato è un numero. * * @param string $value * * @return bool */ public function isStandardNumber($value) { $result = $this->formatNumber($value); return !is_bool($result); } /** * Controlla se l'elemento indicato è un numero. * * @param string $value * * @return bool */ public function isFormattedNumber($value) { $result = $this->parseNumber($value); return !is_bool($result); } /** * Imposta la precisione di default per i numeri da formattare. * * @param int $decimals */ public function setPrecision($decimals) { if (is_object($this->numberFormatter)) { $this->numberFormatter->setAttribute(NumberFormatter::FRACTION_DIGITS, $decimals); } else { $this->precision = $decimals; } } /** * Restituisce la precisione di default per i numeri da formattare. * * @return int */ public function getPrecision() { return is_object($this->numberFormatter) ? $this->numberFormatter->getAttribute(NumberFormatter::FRACTION_DIGITS) : $this->precision; } /** * Restituisce gli elementi di separazione secondo la formattazione in utilizzo. * * @return array */ public function getNumberSeparators() { return [ '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 string|bool */ 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 && string_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 /** * Converte un timestamp da una formattazione all'altra. * * @param string $value * * @return string|bool */ public function formatTimestamp($value) { $object = DateTime::createFromFormat(static::$standards['timestamp'], $value); $result = is_object($object) ? $object->format($this->getTimestampPattern()) : false; return $result; } /** * Converte un timestamp da una formattazione all'altra. * * @param string $value * * @return string|bool */ public function parseTimestamp($value) { $object = DateTime::createFromFormat($this->getTimestampPattern(), $value); $result = is_object($object) ? $object->format(static::$standards['timestamp']) : false; return $result; } /** * Controlla se l'elemento indicato è un timestamp. * * @param string $value * * @return bool */ public function isStandardTimestamp($value) { $result = $this->formatTimestamp($value); return !is_bool($result); } /** * Controlla se l'elemento indicato è un timestamp. * * @param string $value * * @return bool */ public function isFormattedTimestamp($value) { $result = $this->parseTimestamp($value); return !is_bool($result); } /** * Restituisce il formato del timestamp. * * @return string */ public function getTimestampPattern($type = null) { return $this->timestampPattern; } /** * Imposta il formato del timestamp. * * @return string */ public function setTimestampPattern($pattern) { return $this->timestampPattern = $pattern; } // Gestione della conversione delle date /** * Converte una data da una formattazione all'altra. * * @param string $value * * @return string|bool */ public function formatDate($value) { if (!empty($value)){ $object = DateTime::createFromFormat(static::$standards['date'], $value); // Fallback per la gestione dei timestamp $object = !is_object($object) ? DateTime::createFromFormat(static::$standards['timestamp'], $value) : $object; $result = is_object($object) ? $object->format($this->getDatePattern()) : false; return $result; }else{ return true; } } /** * Converte una data da una formattazione all'altra. * * @param string $value * * @return string|bool */ public function parseDate($value) { $object = DateTime::createFromFormat($this->getDatePattern(), $value); $result = is_object($object) ? $object->format(static::$standards['date']) : false; return $result; } /** * Controlla se l'elemento indicato è una data. * * @param string $value * * @return bool */ public function isStandardDate($value) { $result = $this->formatDate($value); return !is_bool($result); } /** * Controlla se l'elemento indicato è una data. * * @param string $value * * @return bool */ public function isFormattedDate($value) { $result = $this->parseDate($value); return !is_bool($result); } /** * Restituisce il formato del timestamp. * * @return string */ public function getDatePattern() { return $this->datePattern; } /** * Imposta il formato del timestamp. * * @return string */ public function setDatePattern($pattern) { return $this->datePattern = $pattern; } // Gestione della conversione degli orarii /** * Converte un orario da una formattazione all'altra. * * @param string $value * * @return string|bool */ public function formatTime($value) { $object = DateTime::createFromFormat(static::$standards['time'], $value); // Fallback per la gestione dei timestamp $object = !is_object($object) ? DateTime::createFromFormat(static::$standards['timestamp'], $value) : $object; $result = is_object($object) ? $object->format($this->getTimePattern()) : false; return $result; } /** * Converte un orario da una formattazione all'altra. * * @param string $value * * @return string|bool */ public function parseTime($value) { $object = DateTime::createFromFormat($this->getTimePattern(), $value); $result = is_object($object) ? $object->format(static::$standards['time']) : false; return $result; } /** * Controlla se l'elemento indicato è un orario. * * @param string $value * * @return bool */ public function isStandardTime($value) { $result = $this->formatTime($value); return !is_bool($result); } /** * Controlla se l'elemento indicato è un orario. * * @param string $value * * @return bool */ public function isFormattedTime($value) { $result = $this->parseTime($value); return !is_bool($result); } /** * Restituisce il formato del orario. * * @return string */ public function getTimePattern($type = null) { return $this->timePattern; } /** * Imposta il formato del orario. * * @return string */ public function setTimePattern($pattern) { return $this->timePattern = $pattern; } public function getSQLPatterns() { if (empty($this->sql)) { $formats = [ 'd' => '%d', 'm' => '%m', 'Y' => '%Y', 'H' => '%H', 'i' => '%i', ]; $result = [ 'timestamp' => $this->getTimestampPattern(), 'date' => $this->getDatePattern(), 'time' => $this->getTimePattern(), ]; foreach ($result as $key => $value) { $result[$key] = replace($value, $formats); } $this->sql = $result; } return $this->sql; } }