diff --git a/src/Symfony/Component/Intl/Locales.php b/src/Symfony/Component/Intl/Locales.php index c5def031cf47..1f434ee2672c 100644 --- a/src/Symfony/Component/Intl/Locales.php +++ b/src/Symfony/Component/Intl/Locales.php @@ -44,7 +44,7 @@ public static function exists(string $locale): bool return true; } catch (MissingResourceException $e) { - return false; + return \in_array($locale, self::getAliases(), true); } } @@ -53,7 +53,15 @@ public static function exists(string $locale): bool */ 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); + } } /** diff --git a/src/Symfony/Component/Intl/Tests/LocalesTest.php b/src/Symfony/Component/Intl/Tests/LocalesTest.php index ae419eaa67e5..5ccff4923f4e 100644 --- a/src/Symfony/Component/Intl/Tests/LocalesTest.php +++ b/src/Symfony/Component/Intl/Tests/LocalesTest.php @@ -92,9 +92,16 @@ public function testGetNameWithInvalidLocale() Locales::getName('foo'); } + public function testGetNameWithAliasLocale() + { + $this->assertSame(Locales::getName('tl_PH'), Locales::getName('fil_PH')); + } + public function testExists() { $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')); } } diff --git a/src/Symfony/Component/Intl/Tests/TimezonesTest.php b/src/Symfony/Component/Intl/Tests/TimezonesTest.php index 58a9a3600190..cc000c148270 100644 --- a/src/Symfony/Component/Intl/Tests/TimezonesTest.php +++ b/src/Symfony/Component/Intl/Tests/TimezonesTest.php @@ -530,14 +530,23 @@ public function testGetNameDefaultLocale() /** * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException */ - public function testGetNameWithInvalidTimezoneId() + public function testGetNameWithInvalidTimezone() { 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() { $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')); } @@ -547,6 +556,9 @@ public function testGetRawOffset() $this->assertSame(0, Timezones::getRawOffset('Etc/UTC')); $this->assertSame(-10800, Timezones::getRawOffset('America/Buenos_Aires')); $this->assertSame(20700, Timezones::getRawOffset('Asia/Katmandu')); + + // ensure we support identifiers available in php (not compiled from icu) + Timezones::getRawOffset('US/Pacific'); } /** diff --git a/src/Symfony/Component/Intl/Timezones.php b/src/Symfony/Component/Intl/Timezones.php index 08f81b830548..1058a0978be5 100644 --- a/src/Symfony/Component/Intl/Timezones.php +++ b/src/Symfony/Component/Intl/Timezones.php @@ -36,12 +36,18 @@ public static function exists(string $timezone): bool return true; } 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 { @@ -57,7 +63,7 @@ public static function getNames(string $displayLocale = null): array } /** - * @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 */ public static function getRawOffset(string $timezone, int $timestamp = null): int @@ -92,7 +98,7 @@ public static function getCountryCode(string $timezone): string } /** - * @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 { diff --git a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php index 244d0f554ba0..2a48c0f5ef12 100644 --- a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php @@ -11,10 +11,10 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Locales; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\LogicException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; @@ -42,13 +42,17 @@ public function validate($value, Constraint $constraint) 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; $value = $inputValue; if ($constraint->canonicalize) { $value = \Locale::canonicalize($value); } - if (!Locales::exists($value) && !\in_array($value, Locales::getAliases(), true)) { + if (!Locales::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($inputValue)) ->setCode(Locale::NO_SUCH_LOCALE_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php b/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php index ac0d751a4532..d4261ff376c5 100644 --- a/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php +++ b/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php @@ -54,19 +54,10 @@ public function validate($value, Constraint $constraint) return; } - if ($constraint->countryCode) { - $phpTimezoneIds = @\DateTimeZone::listIdentifiers($constraint->zone, $constraint->countryCode) ?: []; - try { - $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)) { + if ( + \in_array($value, self::getPhpTimezones($constraint->zone, $constraint->countryCode), true) || + \in_array($value, self::getIntlTimezones($constraint->zone, $constraint->countryCode), true) + ) { return; } @@ -106,8 +97,29 @@ protected function formatValue($value, $format = 0) 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(); if (\DateTimeZone::ALL === (\DateTimeZone::ALL & $zone)) { diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LocaleValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LocaleValidatorTest.php index 381d690bb84e..8dfeb48464f2 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LocaleValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LocaleValidatorTest.php @@ -111,7 +111,8 @@ public function getValidLocales() ['pt', ['canonicalize' => true]], ['pt_PT', ['canonicalize' => true]], ['zh_Hans', ['canonicalize' => true]], - ['fil_PH', ['canonicalize' => true]], + ['tl_PH', ['canonicalize' => true]], + ['fil_PH', ['canonicalize' => true]], // alias for "tl_PH" ]; }