Current File : //var/www/prestashop/vendor/symfony/polyfill-intl-icu/NumberFormatter.php
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Polyfill\Intl\Icu;

use Symfony\Polyfill\Intl\Icu\Exception\MethodArgumentNotImplementedException;
use Symfony\Polyfill\Intl\Icu\Exception\MethodArgumentValueNotImplementedException;
use Symfony\Polyfill\Intl\Icu\Exception\MethodNotImplementedException;
use Symfony\Polyfill\Intl\Icu\Exception\NotImplementedException;

/**
 * Replacement for PHP's native {@link \NumberFormatter} class.
 *
 * The only methods currently supported in this class are:
 *
 *  - {@link __construct}
 *  - {@link create}
 *  - {@link formatCurrency}
 *  - {@link format}
 *  - {@link getAttribute}
 *  - {@link getErrorCode}
 *  - {@link getErrorMessage}
 *  - {@link getLocale}
 *  - {@link parse}
 *  - {@link setAttribute}
 *
 * @author Eriksen Costa <eriksen.costa@infranology.com.br>
 * @author Bernhard Schussek <bschussek@gmail.com>
 *
 * @internal
 */
abstract class NumberFormatter
{
    /* Format style constants */
    public const PATTERN_DECIMAL = 0;
    public const DECIMAL = 1;
    public const CURRENCY = 2;
    public const PERCENT = 3;
    public const SCIENTIFIC = 4;
    public const SPELLOUT = 5;
    public const ORDINAL = 6;
    public const DURATION = 7;
    public const PATTERN_RULEBASED = 9;
    public const IGNORE = 0;
    public const DEFAULT_STYLE = 1;

    /* Format type constants */
    public const TYPE_DEFAULT = 0;
    public const TYPE_INT32 = 1;
    public const TYPE_INT64 = 2;
    public const TYPE_DOUBLE = 3;
    public const TYPE_CURRENCY = 4;

    /* Numeric attribute constants */
    public const PARSE_INT_ONLY = 0;
    public const GROUPING_USED = 1;
    public const DECIMAL_ALWAYS_SHOWN = 2;
    public const MAX_INTEGER_DIGITS = 3;
    public const MIN_INTEGER_DIGITS = 4;
    public const INTEGER_DIGITS = 5;
    public const MAX_FRACTION_DIGITS = 6;
    public const MIN_FRACTION_DIGITS = 7;
    public const FRACTION_DIGITS = 8;
    public const MULTIPLIER = 9;
    public const GROUPING_SIZE = 10;
    public const ROUNDING_MODE = 11;
    public const ROUNDING_INCREMENT = 12;
    public const FORMAT_WIDTH = 13;
    public const PADDING_POSITION = 14;
    public const SECONDARY_GROUPING_SIZE = 15;
    public const SIGNIFICANT_DIGITS_USED = 16;
    public const MIN_SIGNIFICANT_DIGITS = 17;
    public const MAX_SIGNIFICANT_DIGITS = 18;
    public const LENIENT_PARSE = 19;

    /* Text attribute constants */
    public const POSITIVE_PREFIX = 0;
    public const POSITIVE_SUFFIX = 1;
    public const NEGATIVE_PREFIX = 2;
    public const NEGATIVE_SUFFIX = 3;
    public const PADDING_CHARACTER = 4;
    public const CURRENCY_CODE = 5;
    public const DEFAULT_RULESET = 6;
    public const PUBLIC_RULESETS = 7;

    /* Format symbol constants */
    public const DECIMAL_SEPARATOR_SYMBOL = 0;
    public const GROUPING_SEPARATOR_SYMBOL = 1;
    public const PATTERN_SEPARATOR_SYMBOL = 2;
    public const PERCENT_SYMBOL = 3;
    public const ZERO_DIGIT_SYMBOL = 4;
    public const DIGIT_SYMBOL = 5;
    public const MINUS_SIGN_SYMBOL = 6;
    public const PLUS_SIGN_SYMBOL = 7;
    public const CURRENCY_SYMBOL = 8;
    public const INTL_CURRENCY_SYMBOL = 9;
    public const MONETARY_SEPARATOR_SYMBOL = 10;
    public const EXPONENTIAL_SYMBOL = 11;
    public const PERMILL_SYMBOL = 12;
    public const PAD_ESCAPE_SYMBOL = 13;
    public const INFINITY_SYMBOL = 14;
    public const NAN_SYMBOL = 15;
    public const SIGNIFICANT_DIGIT_SYMBOL = 16;
    public const MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;

    /* Rounding mode values used by NumberFormatter::setAttribute() with NumberFormatter::ROUNDING_MODE attribute */
    public const ROUND_CEILING = 0;
    public const ROUND_FLOOR = 1;
    public const ROUND_DOWN = 2;
    public const ROUND_UP = 3;
    public const ROUND_HALFEVEN = 4;
    public const ROUND_HALFDOWN = 5;
    public const ROUND_HALFUP = 6;

    /* Pad position values used by NumberFormatter::setAttribute() with NumberFormatter::PADDING_POSITION attribute */
    public const PAD_BEFORE_PREFIX = 0;
    public const PAD_AFTER_PREFIX = 1;
    public const PAD_BEFORE_SUFFIX = 2;
    public const PAD_AFTER_SUFFIX = 3;

    /**
     * The error code from the last operation.
     *
     * @var int
     */
    protected $errorCode = Icu::U_ZERO_ERROR;

    /**
     * The error message from the last operation.
     *
     * @var string
     */
    protected $errorMessage = 'U_ZERO_ERROR';

    /**
     * @var int
     */
    private $style;

    /**
     * Default values for the en locale.
     */
    private $attributes = [
        self::FRACTION_DIGITS => 0,
        self::GROUPING_USED => 1,
        self::ROUNDING_MODE => self::ROUND_HALFEVEN,
    ];

    /**
     * Holds the initialized attributes code.
     */
    private $initializedAttributes = [];

    /**
     * The supported styles to the constructor $styles argument.
     */
    private static $supportedStyles = [
        'CURRENCY' => self::CURRENCY,
        'DECIMAL' => self::DECIMAL,
    ];

    /**
     * Supported attributes to the setAttribute() $attr argument.
     */
    private static $supportedAttributes = [
        'FRACTION_DIGITS' => self::FRACTION_DIGITS,
        'GROUPING_USED' => self::GROUPING_USED,
        'ROUNDING_MODE' => self::ROUNDING_MODE,
    ];

    /**
     * The available rounding modes for setAttribute() usage with
     * NumberFormatter::ROUNDING_MODE. NumberFormatter::ROUND_DOWN
     * and NumberFormatter::ROUND_UP does not have a PHP only equivalent.
     */
    private static $roundingModes = [
        'ROUND_HALFEVEN' => self::ROUND_HALFEVEN,
        'ROUND_HALFDOWN' => self::ROUND_HALFDOWN,
        'ROUND_HALFUP' => self::ROUND_HALFUP,
        'ROUND_CEILING' => self::ROUND_CEILING,
        'ROUND_FLOOR' => self::ROUND_FLOOR,
        'ROUND_DOWN' => self::ROUND_DOWN,
        'ROUND_UP' => self::ROUND_UP,
    ];

    /**
     * The mapping between NumberFormatter rounding modes to the available
     * modes in PHP's round() function.
     *
     * @see https://php.net/round
     */
    private static $phpRoundingMap = [
        self::ROUND_HALFDOWN => \PHP_ROUND_HALF_DOWN,
        self::ROUND_HALFEVEN => \PHP_ROUND_HALF_EVEN,
        self::ROUND_HALFUP => \PHP_ROUND_HALF_UP,
    ];

    /**
     * The list of supported rounding modes which aren't available modes in
     * PHP's round() function, but there's an equivalent. Keys are rounding
     * modes, values does not matter.
     */
    private static $customRoundingList = [
        self::ROUND_CEILING => true,
        self::ROUND_FLOOR => true,
        self::ROUND_DOWN => true,
        self::ROUND_UP => true,
    ];

    /**
     * The maximum value of the integer type in 32 bit platforms.
     */
    private static $int32Max = 2147483647;

    /**
     * The maximum value of the integer type in 64 bit platforms.
     *
     * @var int|float
     */
    private static $int64Max = 9223372036854775807;

    private static $enSymbols = [
        self::DECIMAL => ['.', ',', ';', '%', '0', '#', '-', '+', '¤', '¤¤', '.', 'E', '‰', '*', '∞', 'NaN', '@', ','],
        self::CURRENCY => ['.', ',', ';', '%', '0', '#', '-', '+', '¤', '¤¤', '.', 'E', '‰', '*', '∞', 'NaN', '@', ','],
    ];

    private static $enTextAttributes = [
        self::DECIMAL => ['', '', '-', '', ' ', 'XXX', ''],
        self::CURRENCY => ['¤', '', '-¤', '', ' ', 'XXX'],
    ];

    /**
     * @param string|null $locale  The locale code. The only currently supported locale is "en" (or null using the default locale, i.e. "en")
     * @param int         $style   Style of the formatting, one of the format style constants.
     *                             The only supported styles are NumberFormatter::DECIMAL
     *                             and NumberFormatter::CURRENCY.
     * @param string      $pattern Not supported. A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
     *                             NumberFormat::PATTERN_RULEBASED. It must conform to  the syntax
     *                             described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
     *
     * @see https://php.net/numberformatter.create
     * @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1DecimalFormat.html#details
     * @see https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classicu_1_1RuleBasedNumberFormat.html#details
     *
     * @throws MethodArgumentValueNotImplementedException When $locale different than "en" or null is passed
     * @throws MethodArgumentValueNotImplementedException When the $style is not supported
     * @throws MethodArgumentNotImplementedException      When the pattern value is different than null
     */
    public function __construct(?string $locale = 'en', int $style = null, string $pattern = null)
    {
        if ('en' !== $locale && null !== $locale) {
            throw new MethodArgumentValueNotImplementedException(__METHOD__, 'locale', $locale, 'Only the locale "en" is supported');
        }

        if (!\in_array($style, self::$supportedStyles)) {
            $message = sprintf('The available styles are: %s.', implode(', ', array_keys(self::$supportedStyles)));
            throw new MethodArgumentValueNotImplementedException(__METHOD__, 'style', $style, $message);
        }

        if (null !== $pattern) {
            throw new MethodArgumentNotImplementedException(__METHOD__, 'pattern');
        }

        $this->style = $style;
    }

    /**
     * Static constructor.
     *
     * @param string|null $locale  The locale code. The only supported locale is "en" (or null using the default locale, i.e. "en")
     * @param int         $style   Style of the formatting, one of the format style constants.
     *                             The only currently supported styles are NumberFormatter::DECIMAL
     *                             and NumberFormatter::CURRENCY.
     * @param string      $pattern Not supported. A pattern string in case $style is NumberFormat::PATTERN_DECIMAL or
     *                             NumberFormat::PATTERN_RULEBASED. It must conform to  the syntax
     *                             described in the ICU DecimalFormat or ICU RuleBasedNumberFormat documentation
     *
     * @return static
     *
     * @see https://php.net/numberformatter.create
     * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
     * @see http://www.icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html#_details
     *
     * @throws MethodArgumentValueNotImplementedException When $locale different than "en" or null is passed
     * @throws MethodArgumentValueNotImplementedException When the $style is not supported
     * @throws MethodArgumentNotImplementedException      When the pattern value is different than null
     */
    public static function create(?string $locale = 'en', int $style = null, string $pattern = null)
    {
        return new static($locale, $style, $pattern);
    }

    /**
     * Format a currency value.
     *
     * @return string The formatted currency value
     *
     * @see https://php.net/numberformatter.formatcurrency
     * @see https://en.wikipedia.org/wiki/ISO_4217#Active_codes
     */
    public function formatCurrency(float $amount, string $currency)
    {
        if (self::DECIMAL === $this->style) {
            return $this->format($amount);
        }

        if (null === $symbol = Currencies::getSymbol($currency)) {
            return false;
        }
        $fractionDigits = Currencies::getFractionDigits($currency);

        $amount = $this->roundCurrency($amount, $currency);

        $negative = false;
        if (0 > $amount) {
            $negative = true;
            $amount *= -1;
        }

        $amount = $this->formatNumber($amount, $fractionDigits);

        // There's a non-breaking space after the currency code (i.e. CRC 100), but not if the currency has a symbol (i.e. £100).
        $ret = $symbol.(mb_strlen($symbol, 'UTF-8') > 2 ? "\xc2\xa0" : '').$amount;

        return $negative ? '-'.$ret : $ret;
    }

    /**
     * Format a number.
     *
     * @param int|float $num  The value to format
     * @param int       $type Type of the formatting, one of the format type constants.
     *                        Only type NumberFormatter::TYPE_DEFAULT is currently supported.
     *
     * @return bool|string The formatted value or false on error
     *
     * @see https://php.net/numberformatter.format
     *
     * @throws NotImplementedException                    If the method is called with the class $style 'CURRENCY'
     * @throws MethodArgumentValueNotImplementedException If the $type is different than TYPE_DEFAULT
     */
    public function format($num, int $type = self::TYPE_DEFAULT)
    {
        // The original NumberFormatter does not support this format type
        if (self::TYPE_CURRENCY === $type) {
            if (\PHP_VERSION_ID >= 80000) {
                throw new \ValueError(sprintf('The format type must be a NumberFormatter::TYPE_* constant (%s given).', $type));
            }

            trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);

            return false;
        }

        if (self::CURRENCY === $this->style) {
            throw new NotImplementedException(sprintf('"%s()" method does not support the formatting of currencies (instance with CURRENCY style). "%s".', __METHOD__, NotImplementedException::INTL_INSTALL_MESSAGE));
        }

        // Only the default type is supported.
        if (self::TYPE_DEFAULT !== $type) {
            throw new MethodArgumentValueNotImplementedException(__METHOD__, 'type', $type, 'Only TYPE_DEFAULT is supported');
        }

        $fractionDigits = $this->getAttribute(self::FRACTION_DIGITS);

        $num = $this->round($num, $fractionDigits);
        $num = $this->formatNumber($num, $fractionDigits);

        // behave like the intl extension
        $this->resetError();

        return $num;
    }

    /**
     * Returns an attribute value.
     *
     * @return int|false The attribute value on success or false on error
     *
     * @see https://php.net/numberformatter.getattribute
     */
    public function getAttribute(int $attribute)
    {
        return $this->attributes[$attribute] ?? null;
    }

    /**
     * Returns formatter's last error code. Always returns the U_ZERO_ERROR class constant value.
     *
     * @return int The error code from last formatter call
     *
     * @see https://php.net/numberformatter.geterrorcode
     */
    public function getErrorCode()
    {
        return $this->errorCode;
    }

    /**
     * Returns formatter's last error message. Always returns the U_ZERO_ERROR_MESSAGE class constant value.
     *
     * @return string The error message from last formatter call
     *
     * @see https://php.net/numberformatter.geterrormessage
     */
    public function getErrorMessage()
    {
        return $this->errorMessage;
    }

    /**
     * Returns the formatter's locale.
     *
     * The parameter $type is currently ignored.
     *
     * @param int $type Not supported. The locale name type to return (Locale::VALID_LOCALE or Locale::ACTUAL_LOCALE)
     *
     * @return string The locale used to create the formatter. Currently always
     *                returns "en".
     *
     * @see https://php.net/numberformatter.getlocale
     */
    public function getLocale(int $type = Locale::ACTUAL_LOCALE)
    {
        return 'en';
    }

    /**
     * Not supported. Returns the formatter's pattern.
     *
     * @return string|false The pattern string used by the formatter or false on error
     *
     * @see https://php.net/numberformatter.getpattern
     *
     * @throws MethodNotImplementedException
     */
    public function getPattern()
    {
        throw new MethodNotImplementedException(__METHOD__);
    }

    /**
     * Not supported. Returns a formatter symbol value.
     *
     * @return string|false The symbol value or false on error
     *
     * @see https://php.net/numberformatter.getsymbol
     */
    public function getSymbol(int $symbol)
    {
        return \array_key_exists($this->style, self::$enSymbols) && \array_key_exists($symbol, self::$enSymbols[$this->style]) ? self::$enSymbols[$this->style][$symbol] : false;
    }

    /**
     * Not supported. Returns a formatter text attribute value.
     *
     * @return string|false The attribute value or false on error
     *
     * @see https://php.net/numberformatter.gettextattribute
     */
    public function getTextAttribute(int $attribute)
    {
        return \array_key_exists($this->style, self::$enTextAttributes) && \array_key_exists($attribute, self::$enTextAttributes[$this->style]) ? self::$enTextAttributes[$this->style][$attribute] : false;
    }

    /**
     * Not supported. Parse a currency number.
     *
     * @return float|false The parsed numeric value or false on error
     *
     * @see https://php.net/numberformatter.parsecurrency
     *
     * @throws MethodNotImplementedException
     */
    public function parseCurrency(string $string, &$currency, &$offset = null)
    {
        throw new MethodNotImplementedException(__METHOD__);
    }

    /**
     * Parse a number.
     *
     * @return int|float|false The parsed value or false on error
     *
     * @see https://php.net/numberformatter.parse
     */
    public function parse(string $string, int $type = self::TYPE_DOUBLE, &$offset = null)
    {
        if (self::TYPE_DEFAULT === $type || self::TYPE_CURRENCY === $type) {
            if (\PHP_VERSION_ID >= 80000) {
                throw new \ValueError(sprintf('The format type must be a NumberFormatter::TYPE_* constant (%d given).', $type));
            }

            trigger_error(__METHOD__.'(): Unsupported format type '.$type, \E_USER_WARNING);

            return false;
        }

        // Any invalid number at the end of the string is removed.
        // Only numbers and the fraction separator is expected in the string.
        // If grouping is used, grouping separator also becomes a valid character.
        $groupingMatch = $this->getAttribute(self::GROUPING_USED) ? '|(?P<grouping>\d++(,{1}\d+)++(\.\d*+)?)' : '';
        if (preg_match("/^-?(?:\.\d++{$groupingMatch}|\d++(\.\d*+)?)/", $string, $matches)) {
            $string = $matches[0];
            $offset = \strlen($string);
            // value is not valid if grouping is used, but digits are not grouped in groups of three
            if ($error = isset($matches['grouping']) && !preg_match('/^-?(?:\d{1,3}+)?(?:(?:,\d{3})++|\d*+)(?:\.\d*+)?$/', $string)) {
                // the position on error is 0 for positive and 1 for negative numbers
                $offset = 0 === strpos($string, '-') ? 1 : 0;
            }
        } else {
            $error = true;
            $offset = 0;
        }

        if ($error) {
            Icu::setError(Icu::U_PARSE_ERROR, 'Number parsing failed');
            $this->errorCode = Icu::getErrorCode();
            $this->errorMessage = Icu::getErrorMessage();

            return false;
        }

        $string = str_replace(',', '', $string);
        $string = $this->convertValueDataType($string, $type);

        // behave like the intl extension
        $this->resetError();

        return $string;
    }

    /**
     * Set an attribute.
     *
     * @param int|float $value
     *
     * @return bool true on success or false on failure
     *
     * @see https://php.net/numberformatter.setattribute
     *
     * @throws MethodArgumentValueNotImplementedException When the $attribute is not supported
     * @throws MethodArgumentValueNotImplementedException When the $value is not supported
     */
    public function setAttribute(int $attribute, $value)
    {
        if (!\in_array($attribute, self::$supportedAttributes)) {
            $message = sprintf(
                'The available attributes are: %s',
                implode(', ', array_keys(self::$supportedAttributes))
            );

            throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attribute', $value, $message);
        }

        if (self::$supportedAttributes['ROUNDING_MODE'] === $attribute && $this->isInvalidRoundingMode($value)) {
            $message = sprintf(
                'The supported values for ROUNDING_MODE are: %s',
                implode(', ', array_keys(self::$roundingModes))
            );

            throw new MethodArgumentValueNotImplementedException(__METHOD__, 'attribute', $value, $message);
        }

        if (self::$supportedAttributes['GROUPING_USED'] === $attribute) {
            $value = $this->normalizeGroupingUsedValue($value);
        }

        if (self::$supportedAttributes['FRACTION_DIGITS'] === $attribute) {
            $value = $this->normalizeFractionDigitsValue($value);
            if ($value < 0) {
                // ignore negative values but do not raise an error
                return true;
            }
        }

        $this->attributes[$attribute] = $value;
        $this->initializedAttributes[$attribute] = true;

        return true;
    }

    /**
     * Not supported. Set the formatter's pattern.
     *
     * @return bool true on success or false on failure
     *
     * @see https://php.net/numberformatter.setpattern
     * @see http://www.icu-project.org/apiref/icu4c/classDecimalFormat.html#_details
     *
     * @throws MethodNotImplementedException
     */
    public function setPattern(string $pattern)
    {
        throw new MethodNotImplementedException(__METHOD__);
    }

    /**
     * Not supported. Set the formatter's symbol.
     *
     * @return bool true on success or false on failure
     *
     * @see https://php.net/numberformatter.setsymbol
     *
     * @throws MethodNotImplementedException
     */
    public function setSymbol(int $symbol, string $value)
    {
        throw new MethodNotImplementedException(__METHOD__);
    }

    /**
     * Not supported. Set a text attribute.
     *
     * @return bool true on success or false on failure
     *
     * @see https://php.net/numberformatter.settextattribute
     *
     * @throws MethodNotImplementedException
     */
    public function setTextAttribute(int $attribute, string $value)
    {
        throw new MethodNotImplementedException(__METHOD__);
    }

    /**
     * Set the error to the default U_ZERO_ERROR.
     */
    protected function resetError()
    {
        Icu::setError(Icu::U_ZERO_ERROR);
        $this->errorCode = Icu::getErrorCode();
        $this->errorMessage = Icu::getErrorMessage();
    }

    /**
     * Rounds a currency value, applying increment rounding if applicable.
     *
     * When a currency have a rounding increment, an extra round is made after the first one. The rounding factor is
     * determined in the ICU data and is explained as of:
     *
     * "the rounding increment is given in units of 10^(-fraction_digits)"
     *
     * The only actual rounding data as of this writing, is CHF.
     *
     * @see http://en.wikipedia.org/wiki/Swedish_rounding
     * @see http://www.docjar.com/html/api/com/ibm/icu/util/Currency.java.html#1007
     */
    private function roundCurrency(float $value, string $currency): float
    {
        $fractionDigits = Currencies::getFractionDigits($currency);
        $roundingIncrement = Currencies::getRoundingIncrement($currency);

        // Round with the formatter rounding mode
        $value = $this->round($value, $fractionDigits);

        // Swiss rounding
        if (0 < $roundingIncrement && 0 < $fractionDigits) {
            $roundingFactor = $roundingIncrement / 10 ** $fractionDigits;
            $value = round($value / $roundingFactor) * $roundingFactor;
        }

        return $value;
    }

    /**
     * Rounds a value.
     *
     * @param int|float $value The value to round
     *
     * @return int|float The rounded value
     */
    private function round($value, int $precision)
    {
        $precision = $this->getUninitializedPrecision($value, $precision);

        $roundingModeAttribute = $this->getAttribute(self::ROUNDING_MODE);
        if (isset(self::$phpRoundingMap[$roundingModeAttribute])) {
            $value = round($value, $precision, self::$phpRoundingMap[$roundingModeAttribute]);
        } elseif (isset(self::$customRoundingList[$roundingModeAttribute])) {
            $roundingCoef = 10 ** $precision;
            $value *= $roundingCoef;
            $value = (float) (string) $value;

            switch ($roundingModeAttribute) {
                case self::ROUND_CEILING:
                    $value = ceil($value);
                    break;
                case self::ROUND_FLOOR:
                    $value = floor($value);
                    break;
                case self::ROUND_UP:
                    $value = $value > 0 ? ceil($value) : floor($value);
                    break;
                case self::ROUND_DOWN:
                    $value = $value > 0 ? floor($value) : ceil($value);
                    break;
            }

            $value /= $roundingCoef;
        }

        return $value;
    }

    /**
     * Formats a number.
     *
     * @param int|float $value The numeric value to format
     */
    private function formatNumber($value, int $precision): string
    {
        $precision = $this->getUninitializedPrecision($value, $precision);

        return number_format($value, $precision, '.', $this->getAttribute(self::GROUPING_USED) ? ',' : '');
    }

    /**
     * Returns the precision value if the DECIMAL style is being used and the FRACTION_DIGITS attribute is uninitialized.
     *
     * @param int|float $value The value to get the precision from if the FRACTION_DIGITS attribute is uninitialized
     */
    private function getUninitializedPrecision($value, int $precision): int
    {
        if (self::CURRENCY === $this->style) {
            return $precision;
        }

        if (!$this->isInitializedAttribute(self::FRACTION_DIGITS)) {
            preg_match('/.*\.(.*)/', (string) $value, $digits);
            if (isset($digits[1])) {
                $precision = \strlen($digits[1]);
            }
        }

        return $precision;
    }

    /**
     * Check if the attribute is initialized (value set by client code).
     */
    private function isInitializedAttribute(string $attr): bool
    {
        return isset($this->initializedAttributes[$attr]);
    }

    /**
     * Returns the numeric value using the $type to convert to the right data type.
     *
     * @param mixed $value The value to be converted
     *
     * @return int|float|false The converted value
     */
    private function convertValueDataType($value, int $type)
    {
        if (self::TYPE_DOUBLE === $type) {
            $value = (float) $value;
        } elseif (self::TYPE_INT32 === $type) {
            $value = $this->getInt32Value($value);
        } elseif (self::TYPE_INT64 === $type) {
            $value = $this->getInt64Value($value);
        }

        return $value;
    }

    /**
     * Convert the value data type to int or returns false if the value is out of the integer value range.
     *
     * @return int|false The converted value
     */
    private function getInt32Value($value)
    {
        if ($value > self::$int32Max || $value < -self::$int32Max - 1) {
            return false;
        }

        return (int) $value;
    }

    /**
     * Convert the value data type to int or returns false if the value is out of the integer value range.
     *
     * @return int|float|false The converted value
     */
    private function getInt64Value($value)
    {
        if ($value > self::$int64Max || $value < -self::$int64Max - 1) {
            return false;
        }

        if (\PHP_INT_SIZE !== 8 && ($value > self::$int32Max || $value < -self::$int32Max - 1)) {
            return (float) $value;
        }

        return (int) $value;
    }

    /**
     * Check if the rounding mode is invalid.
     */
    private function isInvalidRoundingMode(int $value): bool
    {
        if (\in_array($value, self::$roundingModes, true)) {
            return false;
        }

        return true;
    }

    /**
     * Returns the normalized value for the GROUPING_USED attribute. Any value that can be converted to int will be
     * cast to Boolean and then to int again. This way, negative values are converted to 1 and string values to 0.
     */
    private function normalizeGroupingUsedValue($value): int
    {
        return (int) (bool) (int) $value;
    }

    /**
     * Returns the normalized value for the FRACTION_DIGITS attribute.
     */
    private function normalizeFractionDigitsValue($value): int
    {
        return (int) $value;
    }
}
¿Qué es la limpieza dental de perros? - Clínica veterinaria


Es la eliminación del sarro y la placa adherida a la superficie de los dientes mediante un equipo de ultrasonidos que garantiza la integridad de las piezas dentales a la vez que elimina en profundidad cualquier resto de suciedad.

A continuación se procede al pulido de los dientes mediante una fresa especial que elimina la placa bacteriana y devuelve a los dientes el aspecto sano que deben tener.

Una vez terminado todo el proceso, se mantiene al perro en observación hasta que se despierta de la anestesia, bajo la atenta supervisión de un veterinario.

¿Cada cuánto tiempo tengo que hacerle una limpieza dental a mi perro?

A partir de cierta edad, los perros pueden necesitar una limpieza dental anual o bianual. Depende de cada caso. En líneas generales, puede decirse que los perros de razas pequeñas suelen acumular más sarro y suelen necesitar una atención mayor en cuanto a higiene dental.


Riesgos de una mala higiene


Los riesgos más evidentes de una mala higiene dental en los perros son los siguientes:

  • Cuando la acumulación de sarro no se trata, se puede producir una inflamación y retracción de las encías que puede descalzar el diente y provocar caídas.
  • Mal aliento (halitosis).
  • Sarro perros
  • Puede ir a más
  • Las bacterias de la placa pueden trasladarse a través del torrente circulatorio a órganos vitales como el corazón ocasionando problemas de endocarditis en las válvulas. Las bacterias pueden incluso acantonarse en huesos (La osteomielitis es la infección ósea, tanto cortical como medular) provocando mucho dolor y una artritis séptica).

¿Cómo se forma el sarro?

El sarro es la calcificación de la placa dental. Los restos de alimentos, junto con las bacterias presentes en la boca, van a formar la placa bacteriana o placa dental. Si la placa no se retira, al mezclarse con la saliva y los minerales presentes en ella, reaccionará formando una costra. La placa se calcifica y se forma el sarro.

El sarro, cuando se forma, es de color blanquecino pero a medida que pasa el tiempo se va poniendo amarillo y luego marrón.

Síntomas de una pobre higiene dental
La señal más obvia de una mala salud dental canina es el mal aliento.

Sin embargo, a veces no es tan fácil de detectar
Y hay perros que no se dejan abrir la boca por su dueño. Por ejemplo…

Recientemente nos trajeron a la clínica a un perro que parpadeaba de un ojo y decía su dueño que le picaba un lado de la cara. Tenía molestias y dificultad para comer, lo que había llevado a sus dueños a comprarle comida blanda (que suele ser un poco más cara y llevar más contenido en grasa) durante medio año. Después de una exploración oftalmológica, nos dimos cuenta de que el ojo tenía una úlcera en la córnea probablemente de rascarse . Además, el canto lateral del ojo estaba inflamado. Tenía lo que en humanos llamamos flemón pero como era un perro de pelo largo, no se le notaba a simple vista. Al abrirle la boca nos llamó la atención el ver una muela llena de sarro. Le realizamos una radiografía y encontramos una fístula que llegaba hasta la parte inferior del ojo.

Le tuvimos que extraer la muela. Tras esto, el ojo se curó completamente con unos colirios y una lentilla protectora de úlcera. Afortunadamente, la úlcera no profundizó y no perforó el ojo. Ahora el perro come perfectamente a pesar de haber perdido una muela.

¿Cómo mantener la higiene dental de tu perro?
Hay varias maneras de prevenir problemas derivados de la salud dental de tu perro.

Limpiezas de dientes en casa
Es recomendable limpiar los dientes de tu perro semanal o diariamente si se puede. Existe una gran variedad de productos que se pueden utilizar:

Pastas de dientes.
Cepillos de dientes o dedales para el dedo índice, que hacen más fácil la limpieza.
Colutorios para echar en agua de bebida o directamente sobre el diente en líquido o en spray.

En la Clínica Tus Veterinarios enseñamos a nuestros clientes a tomar el hábito de limpiar los dientes de sus perros desde que son cachorros. Esto responde a nuestro compromiso con la prevención de enfermedades caninas.

Hoy en día tenemos muchos clientes que limpian los dientes todos los días a su mascota, y como resultado, se ahorran el dinero de hacer limpiezas dentales profesionales y consiguen una mejor salud de su perro.


Limpiezas dentales profesionales de perros y gatos

Recomendamos hacer una limpieza dental especializada anualmente. La realizamos con un aparato de ultrasonidos que utiliza agua para quitar el sarro. Después, procedemos a pulir los dientes con un cepillo de alta velocidad y una pasta especial. Hacemos esto para proteger el esmalte.

La frecuencia de limpiezas dentales necesaria varía mucho entre razas. En general, las razas grandes tienen buena calidad de esmalte, por lo que no necesitan hacerlo tan a menudo e incluso pueden pasarse la vida sin requerir una limpieza. Sin embargo, razas pequeñas como el Yorkshire o el Maltés, deben hacérselas todos los años desde cachorros si se quiere conservar sus piezas dentales.

Otro factor fundamental es la calidad del pienso. Algunas marcas han diseñado croquetas que limpian la superficie del diente y de la muela al masticarse.

Ultrasonido para perros

¿Se necesita anestesia para las limpiezas dentales de perros y gatos?

La limpieza dental en perros no es una técnica que pueda practicarse sin anestesia general , aunque hay veces que los propietarios no quieren anestesiar y si tiene poco sarro y el perro es muy bueno se puede intentar…… , pero no se va a poder pulir ni acceder a todas la zona de la boca …. Además los limpiadores dentales van a irrigar agua y hay riesgo de aspiración a vías respiratorias si no se realiza una anestesia correcta con intubación traqueal . En resumen , sin anestesia no se va hacer una correcta limpieza dental.

Tampoco sirve la sedación ya que necesitamos que el animal esté totalmente quieto, y el veterinario tenga un acceso completo a todas sus piezas dentales y encías.

Alimentos para la limpieza dental

Hay que tener cierto cuidado a la hora de comprar determinados alimentos porque no todos son saludables. Algunos tienen demasiado contenido graso, que en exceso puede causar problemas cardiovasculares y obesidad.

Los mejores alimentos para los dientes son aquellos que están elaborados por empresas farmacéuticas y llevan componentes químicos con tratamientos específicos para el diente del perro. Esto implica no solo limpieza a través de la acción mecánica de morder sino también un tratamiento antibacteriano para prevenir el sarro.

Conclusión

Si eres como la mayoría de dueños, por falta de tiempo , es probable que no estés prestando la suficiente atención a la limpieza dental de tu perro. Por eso te animamos a que comiences a limpiar los dientes de tu perro y consideres atender a su higiene bucal con frecuencia.

Estas simples medidas pueden conllevar a que tu perro tenga una vida más larga y mucho más saludable.

Si te resulta imposible introducir un cepillo de dientes a tu perro en la boca, pásate con él por clínica Tus Veterinarios y te explicamos cómo hacerlo.

Necesitas hacer una limpieza dental profesional a tu mascota?
Llámanos al 622575274 o contacta con nosotros

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

¡Hola!