@ -210,7 +210,7 @@ class Formatter extends Component
*/
public $calendar;
/**
* @var string the character displayed as the decimal point when formatting a number.
* @var string|null the character displayed as the decimal point when formatting a number.
* If not set, the decimal separator corresponding to [[locale]] will be used.
* If [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value is '.'.
*/
@ -223,7 +223,7 @@ class Formatter extends Component
*/
public $currencyDecimalSeparator;
/**
* @var string the character displayed as the thousands separator (also called grouping separator) character when formatting a number.
* @var string|null the character displayed as the thousands separator (also called grouping separator) character when formatting a number.
* If not set, the thousand separator corresponding to [[locale]] will be used.
* If [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value is ','.
*/
@ -286,7 +286,7 @@ class Formatter extends Component
*/
public $numberFormatterSymbols = [];
/**
* @var string the 3-letter ISO 4217 currency code indicating the default currency to use for [[asCurrency]].
* @var string|null the 3-letter ISO 4217 currency code indicating the default currency to use for [[asCurrency]].
* If not set, the currency code corresponding to [[locale]] will be used.
* Note that in this case the [[locale]] has to be specified with a country code, e.g. `en-US` otherwise it
* is not possible to determine the default currency.
@ -443,8 +443,9 @@ class Formatter extends Component
public function format($value, $format)
{
if ($format instanceof Closure) {
return call_user_func($format, $value, $this);
} elseif (is_array($format)) {
return $format($value, $this);
}
if (is_array($format)) {
if (!isset($format[0])) {
throw new InvalidArgumentException('The $format array must contain at least one element.');
}
@ -463,10 +464,8 @@ class Formatter extends Component
throw new InvalidArgumentException("Unknown format type: $format");
}
// simple formats
/**
* Formats the value as is without any formatting.
* This method simply returns back the parameter without any format.
@ -578,16 +577,30 @@ class Formatter extends Component
* Formats the value as a hyperlink.
* @param mixed $value the value to be formatted.
* @param array $options the tag options in terms of name-value pairs. See [[Html::a()]].
* @param bool|string $scheme the URI scheme to use in the formatted hyperlink (available since 2.0.43):
*
* - `false (default)`: adding non-secure protocol scheme if there is none added already
* - `true`: adding secure protocol scheme if there is none added already
* - string: adding the specified scheme (either `http`, `https` or empty string
* for protocol-relative URL) if there is none added already
*
* @return string the formatted result.
*/
public function asUrl($value, $options = [])
public function asUrl($value, $options = [], $scheme = false )
{
if ($value === null) {
return $this->nullDisplay;
}
$url = $value;
if (strpos($url, '://') === false) {
if ($scheme === false || $scheme === 'http') {
$url = 'http://' . $url;
} elseif ($scheme === true || $scheme === 'https') {
$url = 'https://' . $url;
} elseif ($scheme === '') {
$url = '//' . $url;
}
}
return Html::a(Html::encode($value), $url, $options);
@ -608,10 +621,8 @@ class Formatter extends Component
return $value ? $this->booleanFormat[1] : $this->booleanFormat[0];
}
// date and time formats
/**
* Formats the value as a date.
* @param int|string|DateTime|DateTimeInterface $value the value to be formatted. The following
@ -754,7 +765,7 @@ class Formatter extends Component
// avoid time zone conversion for date-only and time-only values
if ($type === 'date' || $type === 'time') {
list($timestamp, $hasTimeInfo, $hasDateInfo) = $this->normalizeDatetimeValue($value, true);
if ($type === 'date' & & !$hasTimeInfo || $type === 'time' & & !$hasDateInfo) {
if (( $type === 'date' & & !$hasTimeInfo) || ( $type === 'time' & & !$hasDateInfo) ) {
$timeZone = $this->defaultTimeZone;
}
} else {
@ -772,18 +783,41 @@ class Formatter extends Component
}
if (isset($this->_dateFormats[$format])) {
if ($type === 'date') {
$formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], IntlDateFormatter::NONE, $timeZone, $this->calendar);
$formatter = new IntlDateFormatter(
$this->locale,
$this->_dateFormats[$format],
IntlDateFormatter::NONE,
$timeZone,
$this->calendar
);
} elseif ($type === 'time') {
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, $this->_dateFormats[$format], $timeZone, $this->calendar);
$formatter = new IntlDateFormatter(
$this->locale,
IntlDateFormatter::NONE,
$this->_dateFormats[$format],
$timeZone,
$this->calendar
);
} else {
$formatter = new IntlDateFormatter($this->locale, $this->_dateFormats[$format], $this->_dateFormats[$format], $timeZone, $this->calendar);
$formatter = new IntlDateFormatter(
$this->locale,
$this->_dateFormats[$format],
$this->_dateFormats[$format],
$timeZone,
$this->calendar
);
}
} else {
$formatter = new IntlDateFormatter($this->locale, IntlDateFormatter::NONE, IntlDateFormatter::NONE, $timeZone, $this->calendar, $format);
}
if ($formatter === null) {
throw new InvalidConfigException(intl_get_error_message());
$formatter = new IntlDateFormatter(
$this->locale,
IntlDateFormatter::NONE,
IntlDateFormatter::NONE,
$timeZone,
$this->calendar,
$format
);
}
// make IntlDateFormatter work with DateTimeImmutable
if ($timestamp instanceof \DateTimeImmutable) {
$timestamp = new DateTime($timestamp->format(DateTime::ISO8601), $timestamp->getTimezone());
@ -824,7 +858,7 @@ class Formatter extends Component
* timestamp, the second a boolean indicating whether the timestamp has time information and third a boolean indicating
* whether the timestamp has date information.
* This parameter is available since version 2.0.1.
* @return DateTime|array the normalized datetime value.
* @return DateTime|array the normalized datetime value
* Since version 2.0.1 this may also return an array if `$checkDateTimeInfo` is true.
* The first element of the array is the normalized timestamp and the second is a boolean indicating whether
* the timestamp has time information or it is just a date value.
@ -846,9 +880,23 @@ class Formatter extends Component
if (is_numeric($value)) { // process as unix timestamp, which is always in UTC
$timestamp = new DateTime('@' . (int) $value, new DateTimeZone('UTC'));
return $checkDateTimeInfo ? [$timestamp, true, true] : $timestamp;
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d|', $value, new DateTimeZone($this->defaultTimeZone))) !== false) { // try Y-m-d format (support invalid dates like 2012-13-01)
}
if (
($timestamp = DateTime::createFromFormat(
'Y-m-d|',
$value,
new DateTimeZone($this->defaultTimeZone))
) !== false
) { // try Y-m-d format (support invalid dates like 2012-13-01)
return $checkDateTimeInfo ? [$timestamp, false, true] : $timestamp;
} elseif (($timestamp = DateTime::createFromFormat('Y-m-d H:i:s', $value, new DateTimeZone($this->defaultTimeZone))) !== false) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12)
}
if (
($timestamp = DateTime::createFromFormat(
'Y-m-d H:i:s',
$value,
new DateTimeZone($this->defaultTimeZone))
) !== false
) { // try Y-m-d H:i:s format (support invalid dates like 2012-13-01 12:63:12)
return $checkDateTimeInfo ? [$timestamp, true, true] : $timestamp;
}
// finally try to create a DateTime object with the value
@ -923,17 +971,6 @@ class Formatter extends Component
$interval = $value;
} else {
$timestamp = $this->normalizeDatetimeValue($value);
if ($timestamp === false) {
// $value is not a valid date/time value, so we try
// to create a DateInterval with it
try {
$interval = new DateInterval($value);
} catch (\Exception $e) {
// invalid date/time and invalid interval
return $this->nullDisplay;
}
} else {
$timeZone = new DateTimeZone($this->timeZone);
if ($referenceTime === null) {
@ -944,10 +981,8 @@ class Formatter extends Component
}
$dateThen = $timestamp->setTimezone($timeZone);
$interval = $dateThen->diff($dateNow);
}
}
if ($interval->invert) {
if ($interval->y >= 1) {
@ -1213,7 +1248,8 @@ class Formatter extends Component
* If not given, the number of digits depends in the input value and is determined based on
* `NumberFormatter::MIN_FRACTION_DIGITS` and `NumberFormatter::MAX_FRACTION_DIGITS`, which can be configured
* using [[$numberFormatterOptions]].
* If the [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value depends on your PHP configuration.
* If the [PHP intl extension](https://secure.php.net/manual/en/book.intl.php) is not available, the default value
* depends on your PHP configuration.
* If you want consistent behavior between environments where intl is available and not, you should explicitly
* specify a value here.
* @param array $options optional configuration for the number formatter. This parameter will be merged with [[numberFormatterOptions]].
@ -1497,7 +1533,7 @@ class Formatter extends Component
*/
public function asLength($value, $decimals = null, $numberOptions = [], $textOptions = [])
{
return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_LONG, $value, null, null, $decimals, $numberOptions, $textOptions);
return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_LONG, $value, $decimals, $numberOptions, $textOptions);
}
/**
@ -1520,7 +1556,7 @@ class Formatter extends Component
*/
public function asShortLength($value, $decimals = null, $options = [], $textOptions = [])
{
return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_SHORT, $value, null, null, $decimals, $options, $textOptions);
return $this->formatUnit(self::UNIT_LENGTH, self::FORMAT_WIDTH_SHORT, $value, $decimals, $options, $textOptions);
}
/**
@ -1540,7 +1576,7 @@ class Formatter extends Component
*/
public function asWeight($value, $decimals = null, $options = [], $textOptions = [])
{
return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_LONG, $value, null, null, $decimals, $options, $textOptions);
return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_LONG, $value, $decimals, $options, $textOptions);
}
/**
@ -1562,38 +1598,29 @@ class Formatter extends Component
*/
public function asShortWeight($value, $decimals = null, $options = [], $textOptions = [])
{
return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_SHORT, $value, null, null, $decimals, $options, $textOptions);
return $this->formatUnit(self::UNIT_WEIGHT, self::FORMAT_WIDTH_SHORT, $value, $decimals, $options, $textOptions);
}
/**
* @param string $unitType one of [[UNIT_WEIGHT]], [[UNIT_LENGTH]]
* @param string $unitFormat one of [[FORMAT_WIDTH_SHORT]], [[FORMAT_WIDTH_LONG]]
* @param float|int|null $value to be formatted
* @param float $baseUnit unit of value as the multiplier of the smallest unit. When `null`, property [[baseUnits]]
* will be used to determine base unit using $unitType and $unitSystem.
* @param string $unitSystem either [[UNIT_SYSTEM_METRIC]] or [[UNIT_SYSTEM_IMPERIAL]]. When `null`, property [[systemOfUnits]] will be used.
* @param int $decimals the number of digits after the decimal point.
* @param int|null $decimals the number of digits after the decimal point.
* @param array $options optional configuration for the number formatter. This parameter will be merged with [[numberFormatterOptions]].
* @param array $textOptions optional configuration for the number formatter. This parameter will be merged with [[numberFormatterTextOptions]].
* @return string
* @throws InvalidConfigException when INTL is not installed or does not contain required information
*/
private function formatUnit($unitType, $unitFormat, $value, $baseUnit, $unitSystem, $ decimals, $options, $textOptions)
private function formatUnit($unitType, $unitFormat, $value, $decimals, $options, $textOptions)
{
if ($value === null) {
return $this->nullDisplay;
}
if ($unitSystem === null) {
$unitSystem = $this->systemOfUnits;
}
if ($baseUnit === null) {
$baseUnit = $this->baseUnits[$unitType][$unitSystem];
}
$multipliers = array_values($this->measureUnits[$unitType][$unitSystem ]);
$multipliers = array_values($this->measureUnits[$unitType][$this->systemOfUnits]);
list($params, $position) = $this->formatNumber(
$this->normalizeNumericValue($value) * $baseUnit,
$this->normalizeNumericValue($value) * $this->baseUnits[$unitType][$this->systemOfUnits],
$decimals,
null,
$multipliers,
@ -1601,7 +1628,7 @@ class Formatter extends Component
$textOptions
);
$message = $this->getUnitMessage($unitType, $unitFormat, $unitSystem , $position);
$message = $this->getUnitMessage($unitType, $unitFormat, $this->systemOfUnits , $position);
return (new \MessageFormatter($this->locale, $message))->format([
'0' => $params['nFormatted'],
@ -1638,7 +1665,10 @@ class Formatter extends Component
$unitBundle = $this->_resourceBundle[$bundleKey][$unitType][$unitNames[$position]];
if ($unitBundle === null) {
throw new InvalidConfigException('Current ICU data version does not contain information about unit type "' . $unitType . '" and unit measure "' . $unitNames[$position] . '". Check system requirements.');
throw new InvalidConfigException(
'Current ICU data version does not contain information about unit type "' . $unitType
. '" and unit measure "' . $unitNames[$position] . '". Check system requirements.'
);
}
$message = [];
@ -1656,7 +1686,7 @@ class Formatter extends Component
* Given the value in bytes formats number part of the human readable form.
*
* @param string|int|float $value value in bytes to be formatted.
* @param int $decimals the number of digits after the decimal point
* @param int|null $decimals the number of digits after the decimal point
* @param int $maxPosition maximum internal position of size unit, ignored if $formatBase is an array
* @param array|int $formatBase the base at which each next unit is calculated, either 1000 or 1024, or an array
* @param array $options optional configuration for the number formatter. This parameter will be merged with [[numberFormatterOptions]].
@ -1881,7 +1911,7 @@ class Formatter extends Component
* to the defined decimal digits.
*
* @param string|int|float $value the value to be formatted.
* @param int $decimals the number of digits after the decimal point. The default value is `2`.
* @param int|null $decimals the number of digits after the decimal point. The default value is `2`.
* @return string the formatted result.
* @see decimalSeparator
* @see thousandSeparator