[Intl][Validator] Handle alias locales/timezones
This commit is contained in:
parent
58d03ea0cc
commit
0a9be0df6e
@ -44,7 +44,7 @@ final class Locales extends ResourceBundle
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (MissingResourceException $e) {
|
} catch (MissingResourceException $e) {
|
||||||
return false;
|
return \in_array($locale, self::getAliases(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +53,15 @@ final class Locales extends ResourceBundle
|
|||||||
*/
|
*/
|
||||||
public static function getName(string $locale, string $displayLocale = null): string
|
public static function getName(string $locale, string $displayLocale = null): string
|
||||||
{
|
{
|
||||||
return self::readEntry(['Names', $locale], $displayLocale);
|
try {
|
||||||
|
return self::readEntry(['Names', $locale], $displayLocale);
|
||||||
|
} catch (MissingResourceException $e) {
|
||||||
|
if (false === $aliased = array_search($locale, self::getAliases(), true)) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::readEntry(['Names', $aliased], $displayLocale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,9 +93,16 @@ class LocalesTest extends ResourceBundleTestCase
|
|||||||
Locales::getName('foo');
|
Locales::getName('foo');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testGetNameWithAliasLocale()
|
||||||
|
{
|
||||||
|
$this->assertSame(Locales::getName('tl_PH'), Locales::getName('fil_PH'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testExists()
|
public function testExists()
|
||||||
{
|
{
|
||||||
$this->assertTrue(Locales::exists('nl_NL'));
|
$this->assertTrue(Locales::exists('nl_NL'));
|
||||||
|
$this->assertTrue(Locales::exists('tl_PH'));
|
||||||
|
$this->assertTrue(Locales::exists('fil_PH')); // alias for "tl_PH"
|
||||||
$this->assertFalse(Locales::exists('zxx_ZZ'));
|
$this->assertFalse(Locales::exists('zxx_ZZ'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,14 +530,23 @@ class TimezonesTest extends ResourceBundleTestCase
|
|||||||
/**
|
/**
|
||||||
* @expectedException \Symfony\Component\Intl\Exception\MissingResourceException
|
* @expectedException \Symfony\Component\Intl\Exception\MissingResourceException
|
||||||
*/
|
*/
|
||||||
public function testGetNameWithInvalidTimezoneId()
|
public function testGetNameWithInvalidTimezone()
|
||||||
{
|
{
|
||||||
Timezones::getName('foo');
|
Timezones::getName('foo');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\Intl\Exception\MissingResourceException
|
||||||
|
*/
|
||||||
|
public function testGetNameWithAliasTimezone()
|
||||||
|
{
|
||||||
|
Timezones::getName('US/Pacific'); // alias in icu (not compiled), name unavailable in php
|
||||||
|
}
|
||||||
|
|
||||||
public function testExists()
|
public function testExists()
|
||||||
{
|
{
|
||||||
$this->assertTrue(Timezones::exists('Europe/Amsterdam'));
|
$this->assertTrue(Timezones::exists('Europe/Amsterdam'));
|
||||||
|
$this->assertTrue(Timezones::exists('US/Pacific')); // alias in icu (not compiled), identifier available in php
|
||||||
$this->assertFalse(Timezones::exists('Etc/Unknown'));
|
$this->assertFalse(Timezones::exists('Etc/Unknown'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,6 +556,9 @@ class TimezonesTest extends ResourceBundleTestCase
|
|||||||
$this->assertSame(0, Timezones::getRawOffset('Etc/UTC'));
|
$this->assertSame(0, Timezones::getRawOffset('Etc/UTC'));
|
||||||
$this->assertSame(-10800, Timezones::getRawOffset('America/Buenos_Aires'));
|
$this->assertSame(-10800, Timezones::getRawOffset('America/Buenos_Aires'));
|
||||||
$this->assertSame(20700, Timezones::getRawOffset('Asia/Katmandu'));
|
$this->assertSame(20700, Timezones::getRawOffset('Asia/Katmandu'));
|
||||||
|
|
||||||
|
// ensure we support identifiers available in php (not compiled from icu)
|
||||||
|
Timezones::getRawOffset('US/Pacific');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,12 +36,18 @@ final class Timezones extends ResourceBundle
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (MissingResourceException $e) {
|
} catch (MissingResourceException $e) {
|
||||||
return false;
|
try {
|
||||||
|
new \DateTimeZone($timezone);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws MissingResourceException if the timezone identifier does not exists
|
* @throws MissingResourceException if the timezone identifier does not exist or is an alias
|
||||||
*/
|
*/
|
||||||
public static function getName(string $timezone, string $displayLocale = null): string
|
public static function getName(string $timezone, string $displayLocale = null): string
|
||||||
{
|
{
|
||||||
@ -57,7 +63,7 @@ final class Timezones extends ResourceBundle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws \Exception if the timezone identifier does not exists
|
* @throws \Exception if the timezone identifier does not exist
|
||||||
* @throws RuntimeException if there's no timezone DST transition information available
|
* @throws RuntimeException if there's no timezone DST transition information available
|
||||||
*/
|
*/
|
||||||
public static function getRawOffset(string $timezone, int $timestamp = null): int
|
public static function getRawOffset(string $timezone, int $timestamp = null): int
|
||||||
@ -92,7 +98,7 @@ final class Timezones extends ResourceBundle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws MissingResourceException if the country code does not exists
|
* @throws MissingResourceException if the country code does not exist
|
||||||
*/
|
*/
|
||||||
public static function forCountryCode(string $country): array
|
public static function forCountryCode(string $country): array
|
||||||
{
|
{
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
|
|
||||||
namespace Symfony\Component\Validator\Constraints;
|
namespace Symfony\Component\Validator\Constraints;
|
||||||
|
|
||||||
use Symfony\Component\Intl\Intl;
|
|
||||||
use Symfony\Component\Intl\Locales;
|
use Symfony\Component\Intl\Locales;
|
||||||
use Symfony\Component\Validator\Constraint;
|
use Symfony\Component\Validator\Constraint;
|
||||||
use Symfony\Component\Validator\ConstraintValidator;
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
use Symfony\Component\Validator\Exception\LogicException;
|
||||||
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
|
||||||
use Symfony\Component\Validator\Exception\UnexpectedValueException;
|
use Symfony\Component\Validator\Exception\UnexpectedValueException;
|
||||||
|
|
||||||
@ -42,13 +42,17 @@ class LocaleValidator extends ConstraintValidator
|
|||||||
throw new UnexpectedValueException($value, 'string');
|
throw new UnexpectedValueException($value, 'string');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!class_exists(Locales::class)) {
|
||||||
|
throw new LogicException('The "symfony/intl" component is required to use the Locale constraint.');
|
||||||
|
}
|
||||||
|
|
||||||
$inputValue = (string) $value;
|
$inputValue = (string) $value;
|
||||||
$value = $inputValue;
|
$value = $inputValue;
|
||||||
if ($constraint->canonicalize) {
|
if ($constraint->canonicalize) {
|
||||||
$value = \Locale::canonicalize($value);
|
$value = \Locale::canonicalize($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Locales::exists($value) && !\in_array($value, Locales::getAliases(), true)) {
|
if (!Locales::exists($value)) {
|
||||||
$this->context->buildViolation($constraint->message)
|
$this->context->buildViolation($constraint->message)
|
||||||
->setParameter('{{ value }}', $this->formatValue($inputValue))
|
->setParameter('{{ value }}', $this->formatValue($inputValue))
|
||||||
->setCode(Locale::NO_SUCH_LOCALE_ERROR)
|
->setCode(Locale::NO_SUCH_LOCALE_ERROR)
|
||||||
|
@ -54,19 +54,10 @@ class TimezoneValidator extends ConstraintValidator
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($constraint->countryCode) {
|
if (
|
||||||
$phpTimezoneIds = @\DateTimeZone::listIdentifiers($constraint->zone, $constraint->countryCode) ?: [];
|
\in_array($value, self::getPhpTimezones($constraint->zone, $constraint->countryCode), true) ||
|
||||||
try {
|
\in_array($value, self::getIntlTimezones($constraint->zone, $constraint->countryCode), true)
|
||||||
$intlTimezoneIds = Timezones::forCountryCode($constraint->countryCode);
|
) {
|
||||||
} catch (MissingResourceException $e) {
|
|
||||||
$intlTimezoneIds = [];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$phpTimezoneIds = \DateTimeZone::listIdentifiers($constraint->zone);
|
|
||||||
$intlTimezoneIds = self::getIntlTimezones($constraint->zone);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\in_array($value, $phpTimezoneIds, true) || \in_array($value, $intlTimezoneIds, true)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,8 +97,29 @@ class TimezoneValidator extends ConstraintValidator
|
|||||||
return array_search($value, (new \ReflectionClass(\DateTimeZone::class))->getConstants(), true) ?: $value;
|
return array_search($value, (new \ReflectionClass(\DateTimeZone::class))->getConstants(), true) ?: $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function getIntlTimezones(int $zone): array
|
private static function getPhpTimezones(int $zone, string $countryCode = null): array
|
||||||
{
|
{
|
||||||
|
if (null !== $countryCode) {
|
||||||
|
return @\DateTimeZone::listIdentifiers($zone, $countryCode) ?: [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return \DateTimeZone::listIdentifiers($zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getIntlTimezones(int $zone, string $countryCode = null): array
|
||||||
|
{
|
||||||
|
if (!class_exists(Timezones::class)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null !== $countryCode) {
|
||||||
|
try {
|
||||||
|
return Timezones::forCountryCode($countryCode);
|
||||||
|
} catch (MissingResourceException $e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$timezones = Timezones::getIds();
|
$timezones = Timezones::getIds();
|
||||||
|
|
||||||
if (\DateTimeZone::ALL === (\DateTimeZone::ALL & $zone)) {
|
if (\DateTimeZone::ALL === (\DateTimeZone::ALL & $zone)) {
|
||||||
|
@ -111,7 +111,8 @@ class LocaleValidatorTest extends ConstraintValidatorTestCase
|
|||||||
['pt', ['canonicalize' => true]],
|
['pt', ['canonicalize' => true]],
|
||||||
['pt_PT', ['canonicalize' => true]],
|
['pt_PT', ['canonicalize' => true]],
|
||||||
['zh_Hans', ['canonicalize' => true]],
|
['zh_Hans', ['canonicalize' => true]],
|
||||||
['fil_PH', ['canonicalize' => true]],
|
['tl_PH', ['canonicalize' => true]],
|
||||||
|
['fil_PH', ['canonicalize' => true]], // alias for "tl_PH"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user