From 06920a79c483c427fec7d85f08bf842bf313bf79 Mon Sep 17 00:00:00 2001 From: Michael Babker Date: Wed, 11 Apr 2018 12:33:35 -0500 Subject: [PATCH 001/495] Support pluralization in the inflector --- src/Symfony/Component/Inflector/Inflector.php | 271 +++++++++++++++++- .../Inflector/Tests/InflectorTest.php | 139 +++++++++ 2 files changed, 407 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Inflector/Inflector.php b/src/Symfony/Component/Inflector/Inflector.php index cf685159a7f41..48538751d19d3 100644 --- a/src/Symfony/Component/Inflector/Inflector.php +++ b/src/Symfony/Component/Inflector/Inflector.php @@ -82,9 +82,6 @@ final class Inflector // news (news) array('swen', 4, true, true, 'news'), - // series (series) - array('seires', 6, true, true, 'series'), - // babies (baby) array('sei', 3, false, true, 'y'), @@ -139,6 +136,179 @@ final class Inflector array('elpoep', 6, true, true, 'person'), ); + /** + * Map English singular to plural suffixes. + * + * @var array + * + * @see http://english-zone.com/spelling/plurals.html + */ + private static $singularMap = array( + // First entry: singular suffix, reversed + // Second entry: length of singular suffix + // Third entry: Whether the suffix may succeed a vocal + // Fourth entry: Whether the suffix may succeed a consonant + // Fifth entry: plural suffix, normal + + // criterion (criteria) + array('airetirc', 8, false, false, 'criterion'), + + // nebulae (nebula) + array('aluben', 6, false, false, 'nebulae'), + + // children (child) + array('dlihc', 5, true, true, 'children'), + + // prices (price) + array('eci', 3, false, true, 'ices'), + + // services (service) + array('ecivres', 7, true, true, 'services'), + + // lives (life), wives (wife) + array('efi', 3, false, true, 'ives'), + + // selfies (selfie) + array('eifles', 6, true, true, 'selfies'), + + // movies (movie) + array('eivom', 5, true, true, 'movies'), + + // lice (louse) + array('esuol', 5, false, true, 'lice'), + + // mice (mouse) + array('esuom', 5, false, true, 'mice'), + + // geese (goose) + array('esoo', 4, false, true, 'eese'), + + // houses (house), bases (base) + array('es', 2, true, true, 'ses'), + + // geese (goose) + array('esoog', 5, true, true, 'geese'), + + // caves (cave) + array('ev', 2, true, true, 'ves'), + + // drives (drive) + array('evird', 5, false, true, 'drives'), + + // objectives (objective), alternative (alternatives) + array('evit', 4, true, true, 'tives'), + + // moves (move) + array('evom', 4, true, true, 'moves'), + + // staves (staff) + array('ffats', 5, true, true, 'staves'), + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + array('ff', 2, true, true, 'ffs'), + + // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) + array('f', 1, true, true, array('fs', 'ves')), + + // arches (arch) + array('hc', 2, true, true, 'ches'), + + // bushes (bush) + array('hs', 2, true, true, 'shes'), + + // teeth (tooth) + array('htoot', 5, true, true, 'teeth'), + + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + array('mu', 2, true, true, 'a'), + + // echoes (echo) + array('ohce', 4, true, true, 'echoes'), + + // men (man), women (woman) + array('nam', 3, true, true, 'men'), + + // people (person) + array('nosrep', 6, true, true, array('persons', 'people')), + + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + array('noi', 3, true, true, 'ions'), + + // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + array('no', 2, true, true, 'a'), + + // atlases (atlas) + array('salta', 5, true, true, 'atlases'), + + // irises (iris) + array('siri', 4, true, true, 'irises'), + + // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) + // theses (thesis), emphases (emphasis), oases (oasis), + // crises (crisis) + array('sis', 3, true, true, 'ses'), + + // accesses (access), addresses (address), kisses (kiss) + array('ss', 2, true, false, 'sses'), + + // syllabi (syllabus) + array('suballys', 8, true, true, 'syllabi'), + + // buses (bus) + array('sub', 3, true, true, 'buses'), + + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) + array('su', 2, true, true, 'i'), + + // news (news) + array('swen', 4, true, true, 'news'), + + // feet (foot) + array('toof', 4, true, true, 'feet'), + + // chateaux (chateau), bureaus (bureau) + array('uae', 3, false, true, array('eaus', 'eaux')), + + // oxen (ox) + array('xo', 2, false, false, 'oxen'), + + // hoaxes (hoax) + array('xaoh', 4, true, false, 'hoaxes'), + + // indices (index) + array('xedni', 5, false, true, array('indicies', 'indexes')), + + // indexes (index), matrixes (matrix) + array('x', 1, true, false, array('cies', 'xes')), + + // appendices (appendix) + array('xi', 2, false, true, 'ices'), + + // babies (baby) + array('y', 1, false, true, 'ies'), + + // quizzes (quiz) + array('ziuq', 4, true, false, 'quizzes'), + + // waltzes (waltz) + array('z', 1, true, false, 'zes'), + ); + + /** + * A list of words which should not be inflected + * + * @var array + */ + private static $uninflected = array( + 'data', + 'deer', + 'feedback', + 'fish', + 'moose', + 'series', + 'sheep', + ); + /** * This class should not be instantiated. */ @@ -165,6 +335,11 @@ public static function singularize(string $plural) $lowerPluralRev = strtolower($pluralRev); $pluralLength = strlen($lowerPluralRev); + // Check if the word is one which is not inflected, return early if so + if (in_array(strtolower($plural), self::$uninflected, true)) { + return $plural; + } + // The outer loop iterates over the entries of the plural table // The inner loop $j iterates over the characters of the plural suffix // in the plural table to compare them with the characters of the actual @@ -229,4 +404,94 @@ public static function singularize(string $plural) // Assume that plural and singular is identical return $plural; } + + /** + * Returns the plural form of a word. + * + * If the method can't determine the form with certainty, an array of the + * possible plurals is returned. + * + * @param string $singular A word in plural form + * + * @return string|array The plural form or an array of possible plural + * forms + * + * @internal + */ + public static function pluralize(string $singular) + { + $singularRev = strrev($singular); + $lowerSingularRev = strtolower($singularRev); + $singularLength = strlen($lowerSingularRev); + + // Check if the word is one which is not inflected, return early if so + if (in_array(strtolower($singular), self::$uninflected, true)) { + return $singular; + } + + // The outer loop iterates over the entries of the singular table + // The inner loop $j iterates over the characters of the singular suffix + // in the singular table to compare them with the characters of the actual + // given singular suffix + foreach (self::$singularMap as $map) { + $suffix = $map[0]; + $suffixLength = $map[1]; + $j = 0; + + // Compare characters in the singular table and of the suffix of the + // given plural one by one + + while ($suffix[$j] === $lowerSingularRev[$j]) { + // Let $j point to the next character + ++$j; + + // Successfully compared the last character + // Add an entry with the plural suffix to the plural array + if ($j === $suffixLength) { + // Is there any character preceding the suffix in the plural string? + if ($j < $singularLength) { + $nextIsVocal = false !== strpos('aeiou', $lowerSingularRev[$j]); + + if (!$map[2] && $nextIsVocal) { + // suffix may not succeed a vocal but next char is one + break; + } + + if (!$map[3] && !$nextIsVocal) { + // suffix may not succeed a consonant but next char is one + break; + } + } + + $newBase = substr($singular, 0, $singularLength - $suffixLength); + $newSuffix = $map[4]; + + // Check whether the first character in the singular suffix + // is uppercased. If yes, uppercase the first character in + // the singular suffix too + $firstUpper = ctype_upper($singularRev[$j - 1]); + + if (is_array($newSuffix)) { + $plurals = array(); + + foreach ($newSuffix as $newSuffixEntry) { + $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); + } + + return $plurals; + } + + return $newBase.($firstUpper ? ucfirst($newSuffix) : $newSuffix); + } + + // Suffix is longer than word + if ($j === $singularLength) { + break; + } + } + } + + // Assume that plural is singular with a trailing `s` + return $singular.'s'; + } } diff --git a/src/Symfony/Component/Inflector/Tests/InflectorTest.php b/src/Symfony/Component/Inflector/Tests/InflectorTest.php index be7836736f8ba..b0a68944d944a 100644 --- a/src/Symfony/Component/Inflector/Tests/InflectorTest.php +++ b/src/Symfony/Component/Inflector/Tests/InflectorTest.php @@ -155,6 +155,130 @@ public function singularizeProvider() ); } + public function pluralizeProvider() + { + // see http://english-zone.com/spelling/plurals.html + // see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English + return array( + array('access', 'accesses'), + array('address', 'addresses'), + array('agenda', 'agendas'), + array('alumnus', 'alumni'), + array('analysis', 'analyses'), + array('antenna', 'antennas'), //antennae + array('appendix', array('appendicies', 'appendixes')), + array('arch', 'arches'), + array('atlas', 'atlases'), + array('axe', 'axes'), + array('baby', 'babies'), + array('bacterium', 'bacteria'), + array('base', 'bases'), + array('batch', 'batches'), + array('beau', array('beaus', 'beaux')), + array('bee', 'bees'), + array('box', array('bocies', 'boxes')), + array('boy', 'boys'), + array('bureau', array('bureaus', 'bureaux')), + array('bus', 'buses'), + array('bush', 'bushes'), + array('calf', array('calfs', 'calves')), + array('car', 'cars'), + array('cassette', 'cassettes'), + array('cave', 'caves'), + array('chateau', array('chateaus', 'chateaux')), + array('cheese', 'cheeses'), + array('child', 'children'), + array('circus', 'circuses'), + array('cliff', 'cliffs'), + array('committee', 'committees'), + array('crisis', 'crises'), + array('criteria', 'criterion'), + array('cup', 'cups'), + array('data', 'data'), + array('day', 'days'), + array('disco', 'discos'), + array('device', 'devices'), + array('drive', 'drives'), + array('driver', 'drivers'), + array('dwarf', array('dwarfs', 'dwarves')), + array('echo', 'echoes'), + array('elf', array('elfs', 'elves')), + array('emphasis', 'emphases'), + array('fax', array('facies', 'faxes')), + array('feedback', 'feedback'), + array('focus', 'foci'), + array('foot', 'feet'), + array('formula', 'formulas'), //formulae + array('fungus', 'fungi'), + array('garage', 'garages'), + array('goose', 'geese'), + array('half', array('halfs', 'halves')), + array('hat', 'hats'), + array('hero', 'heroes'), + array('hippopotamus', 'hippopotami'), //hippopotamuses + array('hoax', 'hoaxes'), + array('hoof', array('hoofs', 'hooves')), + array('house', 'houses'), + array('index', array('indicies', 'indexes')), + array('ion', 'ions'), + array('iris', 'irises'), + array('kiss', 'kisses'), + array('knife', 'knives'), + array('lamp', 'lamps'), + array('leaf', array('leafs', 'leaves')), + array('life', 'lives'), + array('louse', 'lice'), + array('man', 'men'), + array('matrix', array('matricies', 'matrixes')), + array('mouse', 'mice'), + array('move', 'moves'), + array('movie', 'movies'), + array('nebula', 'nebulae'), + array('neurosis', 'neuroses'), + array('news', 'news'), + array('oasis', 'oases'), + array('objective', 'objectives'), + array('ox', 'oxen'), + array('party', 'parties'), + array('person', array('persons', 'people')), + array('phenomenon', 'phenomena'), + array('photo', 'photos'), + array('piano', 'pianos'), + array('plateau', array('plateaus', 'plateaux')), + array('poppy', 'poppies'), + array('price', 'prices'), + array('quiz', 'quizzes'), + array('radius', 'radii'), + array('roof', array('roofs', 'rooves')), + array('rose', 'roses'), + array('sandwich', 'sandwiches'), + array('scarf', array('scarfs', 'scarves')), + array('schema', 'schemas'), //schemata + array('selfie', 'selfies'), + array('series', 'series'), + array('service', 'services'), + array('sheriff', 'sheriffs'), + array('shoe', 'shoes'), + array('spy', 'spies'), + array('staff', 'staves'), + array('story', 'stories'), + array('stratum', 'strata'), + array('suitcase', 'suitcases'), + array('syllabus', 'syllabi'), + array('tag', 'tags'), + array('thief', array('thiefs', 'thieves')), + array('tooth', 'teeth'), + array('tree', 'trees'), + array('waltz', 'waltzes'), + array('wife', 'wives'), + + // test casing: if the first letter was uppercase, it should remain so + array('Man', 'Men'), + array('GrandChild', 'GrandChildren'), + array('SubTree', 'SubTrees'), + ); + } + /** * @dataProvider singularizeProvider */ @@ -169,4 +293,19 @@ public function testSingularize($plural, $singular) $this->assertEquals($singular, $single); } + + /** + * @dataProvider pluralizeProvider + */ + public function testPluralize($plural, $singular) + { + $single = Inflector::pluralize($plural); + if (is_string($singular) && is_array($single)) { + $this->fail("--- Expected\n`string`: ".$singular."\n+++ Actual\n`array`: ".implode(', ', $single)); + } elseif (is_array($singular) && is_string($single)) { + $this->fail("--- Expected\n`array`: ".implode(', ', $singular)."\n+++ Actual\n`string`: ".$single); + } + + $this->assertEquals($singular, $single); + } } From 2a4e2e614b9ee6a5e243721ed004d5b3c9a21f56 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 22 Oct 2018 20:26:40 +0200 Subject: [PATCH 002/495] [Debug] Mark the ErrorHandler and ExceptionHandler classes as final --- src/Symfony/Component/Debug/CHANGELOG.md | 5 +++++ src/Symfony/Component/Debug/ErrorHandler.php | 2 ++ src/Symfony/Component/Debug/ExceptionHandler.php | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/Symfony/Component/Debug/CHANGELOG.md b/src/Symfony/Component/Debug/CHANGELOG.md index 122af73174bf4..2b7bfc8ba30ed 100644 --- a/src/Symfony/Component/Debug/CHANGELOG.md +++ b/src/Symfony/Component/Debug/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + +* made the `ErrorHandler` and `ExceptionHandler` classes final + 4.0.0 ----- diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 912839bc472e2..972fc3a29772f 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -45,6 +45,8 @@ * * @author Nicolas Grekas * @author Grégoire Pineau + * + * @final since Symfony 4.3 */ class ErrorHandler { diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index ea666b1ac3863..259fb548939d1 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -26,6 +26,8 @@ * * @author Fabien Potencier * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ class ExceptionHandler { From bb6be1534a4c627b202e9e0afc5358245c3e711c Mon Sep 17 00:00:00 2001 From: Sylvain Fabre Date: Mon, 22 Oct 2018 17:19:12 +0200 Subject: [PATCH 003/495] [Validator] Checking a BIC along with an IBAN Fix #28166 --- src/Symfony/Component/Validator/CHANGELOG.md | 5 + .../Component/Validator/Constraints/Bic.php | 14 ++ .../Validator/Constraints/BicValidator.php | 45 ++++++ .../Resources/translations/validators.en.xlf | 4 + .../Resources/translations/validators.fr.xlf | 4 + .../Tests/Constraints/BicValidatorTest.php | 128 ++++++++++++++++++ 6 files changed, 200 insertions(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 3863b5717a1fe..e2dfc921e40b7 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added options `iban` and `ibanPropertyPath` to Bic constraint + 4.2.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Bic.php b/src/Symfony/Component/Validator/Constraints/Bic.php index 9af23c8ddb89f..2e1fa68df1238 100644 --- a/src/Symfony/Component/Validator/Constraints/Bic.php +++ b/src/Symfony/Component/Validator/Constraints/Bic.php @@ -12,7 +12,9 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Intl\Intl; +use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Exception\LogicException; /** @@ -28,6 +30,7 @@ class Bic extends Constraint const INVALID_BANK_CODE_ERROR = '00559357-6170-4f29-aebd-d19330aa19cf'; const INVALID_COUNTRY_CODE_ERROR = '1ce76f8d-3c1f-451c-9e62-fe9c3ed486ae'; const INVALID_CASE_ERROR = '11884038-3312-4ae5-9d04-699f782130c7'; + const INVALID_IBAN_COUNTRY_CODE_ERROR = '29a2c3bb-587b-4996-b6f5-53081364cea5'; protected static $errorNames = array( self::INVALID_LENGTH_ERROR => 'INVALID_LENGTH_ERROR', @@ -38,6 +41,9 @@ class Bic extends Constraint ); public $message = 'This is not a valid Business Identifier Code (BIC).'; + public $ibanMessage = 'This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.'; + public $iban; + public $ibanPropertyPath; public function __construct($options = null) { @@ -46,6 +52,14 @@ public function __construct($options = null) @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } + if (isset($options['iban']) && isset($options['ibanPropertyPath'])) { + throw new ConstraintDefinitionException(sprintf('The "iban" and "ibanPropertyPath" options of the Iban constraint cannot be used at the same time.', self::class)); + } + + if (isset($options['ibanPropertyPath']) && !class_exists(PropertyAccess::class)) { + throw new LogicException(sprintf('The "symfony/property-access" component is required to use the "%s" constraint with the "ibanPropertyPath" option.', self::class)); + } + parent::__construct($options); } } diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index 7daf9a9c250d8..6d077b6d0920b 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -12,8 +12,12 @@ namespace Symfony\Component\Validator\Constraints; use Symfony\Component\Intl\Intl; +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessor; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Exception\LogicException; use Symfony\Component\Validator\Exception\UnexpectedValueException; @@ -24,6 +28,13 @@ */ class BicValidator extends ConstraintValidator { + private $propertyAccessor; + + public function __construct(PropertyAccessor $propertyAccessor = null) + { + $this->propertyAccessor = $propertyAccessor; + } + /** * {@inheritdoc} */ @@ -95,5 +106,39 @@ public function validate($value, Constraint $constraint) return; } + + // check against an IBAN + $iban = $constraint->iban; + $path = $constraint->ibanPropertyPath; + if ($path && null !== $object = $this->context->getObject()) { + try { + $iban = $this->getPropertyAccessor()->getValue($object, $path); + } catch (NoSuchPropertyException $e) { + throw new ConstraintDefinitionException(sprintf('Invalid property path "%s" provided to "%s" constraint: %s', $path, \get_class($constraint), $e->getMessage()), 0, $e); + } + } + if (!$iban) { + return; + } + $ibanCountryCode = substr($iban, 0, 2); + if (ctype_alpha($ibanCountryCode) && substr($canonicalize, 4, 2) !== $ibanCountryCode) { + $this->context->buildViolation($constraint->ibanMessage) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ iban }}', $iban) + ->setCode(Bic::INVALID_IBAN_COUNTRY_CODE_ERROR) + ->addViolation(); + } + } + + private function getPropertyAccessor(): PropertyAccessor + { + if (null === $this->propertyAccessor) { + if (!class_exists(PropertyAccess::class)) { + throw new LogicException('Unable to use property path as the Symfony PropertyAccess component is not installed.'); + } + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); + } + + return $this->propertyAccessor; } } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 4bb2760b418e3..30e6804c7b83e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -326,6 +326,10 @@ This value should be a multiple of {{ compared_value }}. This value should be a multiple of {{ compared_value }}. + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index c7ee2795b553e..67441127cda1a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -326,6 +326,10 @@ This value should be a multiple of {{ compared_value }}. Cette valeur doit être un multiple de {{ compared_value }}. + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Ce BIC n'est pas associé à l'IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php index 231843a792d41..2d57ab0ec3c83 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraints\Bic; use Symfony\Component\Validator\Constraints\BicValidator; +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; class BicValidatorTest extends ConstraintValidatorTestCase @@ -36,6 +37,113 @@ public function testEmptyStringIsValid() $this->assertNoViolation(); } + public function testValidComparisonToPropertyPath() + { + $constraint = new Bic(array('ibanPropertyPath' => 'value')); + + $object = new BicComparisonTestClass('FR14 2004 1010 0505 0001 3M02 606'); + + $this->setObject($object); + + $this->validator->validate('SOGEFRPP', $constraint); + + $this->assertNoViolation(); + } + + public function testValidComparisonToPropertyPathOnArray() + { + $constraint = new Bic(array('ibanPropertyPath' => '[root][value]')); + + $this->setObject(array('root' => array('value' => 'FR14 2004 1010 0505 0001 3M02 606'))); + + $this->validator->validate('SOGEFRPP', $constraint); + + $this->assertNoViolation(); + } + + public function testInvalidComparisonToPropertyPath() + { + $constraint = new Bic(array('ibanPropertyPath' => 'value')); + $constraint->ibanMessage = 'Constraint Message'; + + $object = new BicComparisonTestClass('FR14 2004 1010 0505 0001 3M02 606'); + + $this->setObject($object); + + $this->validator->validate('UNCRIT2B912', $constraint); + + $this->buildViolation('Constraint Message') + ->setParameter('{{ value }}', '"UNCRIT2B912"') + ->setParameter('{{ iban }}', 'FR14 2004 1010 0505 0001 3M02 606') + ->setCode(Bic::INVALID_IBAN_COUNTRY_CODE_ERROR) + ->assertRaised(); + } + + public function testValidComparisonToValue() + { + $constraint = new Bic(array('iban' => 'FR14 2004 1010 0505 0001 3M02 606')); + $constraint->ibanMessage = 'Constraint Message'; + + $this->validator->validate('SOGEFRPP', $constraint); + + $this->assertNoViolation(); + } + + public function testInvalidComparisonToValue() + { + $constraint = new Bic(array('iban' => 'FR14 2004 1010 0505 0001 3M02 606')); + $constraint->ibanMessage = 'Constraint Message'; + + $this->validator->validate('UNCRIT2B912', $constraint); + + $this->buildViolation('Constraint Message') + ->setParameter('{{ value }}', '"UNCRIT2B912"') + ->setParameter('{{ iban }}', 'FR14 2004 1010 0505 0001 3M02 606') + ->setCode(Bic::INVALID_IBAN_COUNTRY_CODE_ERROR) + ->assertRaised(); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $constraint = new Bic(array('ibanPropertyPath' => 'propertyPath')); + + $this->setObject(null); + + $this->validator->validate('UNCRIT2B912', $constraint); + + $this->assertNoViolation(); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "iban" and "ibanPropertyPath" options of the Iban constraint cannot be used at the same time + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + new Bic(array( + 'iban' => 'value', + 'ibanPropertyPath' => 'propertyPath', + )); + } + + public function testInvalidValuePath() + { + $constraint = new Bic(array('ibanPropertyPath' => 'foo')); + + if (method_exists($this, 'expectException')) { + $this->expectException(ConstraintDefinitionException::class); + $this->expectExceptionMessage(sprintf('Invalid property path "foo" provided to "%s" constraint', \get_class($constraint))); + } else { + $this->setExpectedException(ConstraintDefinitionException::class, sprintf('Invalid property path "foo" provided to "%s" constraint', \get_class($constraint))); + } + + $object = new BicComparisonTestClass(5); + + $this->setObject($object); + + $this->validator->validate('UNCRIT2B912', $constraint); + } + /** * @expectedException \Symfony\Component\Validator\Exception\UnexpectedValueException */ @@ -114,3 +222,23 @@ public function getInvalidBics() ); } } + +class BicComparisonTestClass +{ + protected $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function __toString() + { + return (string) $this->value; + } + + public function getValue() + { + return $this->value; + } +} From 3b3a1bd3cce9eddcf42f95e2a5a3872ee1253927 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 6 Nov 2018 15:59:24 +0100 Subject: [PATCH 004/495] [DI] compute autowiring error messages lazily --- .../TestServiceContainerWeakRefPass.php | 4 +- .../Compiler/AutowirePass.php | 61 ++++++++++--------- .../Compiler/DefinitionErrorExceptionPass.php | 2 +- .../Compiler/InlineServiceDefinitionsPass.php | 2 +- .../Compiler/ResolveChildDefinitionsPass.php | 5 +- .../DependencyInjection/ContainerBuilder.php | 2 +- .../DependencyInjection/Definition.php | 21 ++++++- .../DependencyInjection/Dumper/PhpDumper.php | 8 +-- .../Exception/AutowiringFailedException.php | 36 ++++++++++- .../Tests/Compiler/AutowirePassTest.php | 7 +-- .../Tests/DefinitionTest.php | 2 +- 11 files changed, 98 insertions(+), 52 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php index a7d6986fa9d61..4912a001ec4de 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php @@ -31,7 +31,7 @@ public function process(ContainerBuilder $container) $definitions = $container->getDefinitions(); foreach ($definitions as $id => $definition) { - if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate()) && !$definition->getErrors() && !$definition->isAbstract()) { + if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate()) && !$definition->hasErrors() && !$definition->isAbstract()) { $privateServices[$id] = new Reference($id, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE); } } @@ -43,7 +43,7 @@ public function process(ContainerBuilder $container) while (isset($aliases[$target = (string) $alias])) { $alias = $aliases[$target]; } - if (isset($definitions[$target]) && !$definitions[$target]->getErrors() && !$definitions[$target]->isAbstract()) { + if (isset($definitions[$target]) && !$definitions[$target]->hasErrors() && !$definitions[$target]->isAbstract()) { $privateServices[$id] = new Reference($target, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE); } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 4aa6fbf6dcc96..d8269e13b8a48 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -74,7 +74,7 @@ protected function processValue($value, $isRoot = false) throw $e; } - $this->container->getDefinition($this->currentId)->addError($e->getMessage()); + $this->container->getDefinition($this->currentId)->addError($e->getMessageCallback() ?? $e->getMessage()); return parent::processValue($value, $isRoot); } @@ -86,16 +86,15 @@ private function doProcessValue($value, $isRoot = false) if ($ref = $this->getAutowiredReference($value)) { return $ref; } - $message = $this->createTypeNotFoundMessage($value, 'it'); - if (ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) { + $message = $this->createTypeNotFoundMessageCallback($value, 'it'); + // since the error message varies by referenced id and $this->currentId, so should the id of the dummy errored definition $this->container->register($id = sprintf('.errored.%s.%s', $this->currentId, (string) $value), $value->getType()) ->addError($message); return new TypedReference($id, $value->getType(), $value->getInvalidBehavior(), $value->getName()); } - $this->container->log($this, $message); } $value = parent::processValue($value, $isRoot); @@ -222,14 +221,13 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a $getValue = function () use ($type, $parameter, $class, $method) { if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $parameter->name))) { - $failureMessage = $this->createTypeNotFoundMessage($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); + $failureMessage = $this->createTypeNotFoundMessageCallback($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); if ($parameter->isDefaultValueAvailable()) { $value = $parameter->getDefaultValue(); } elseif (!$parameter->allowsNull()) { throw new AutowiringFailedException($this->currentId, $failureMessage); } - $this->container->log($this, $failureMessage); } return $value; @@ -307,27 +305,27 @@ private function getAutowiredReference(TypedReference $reference) /** * Populates the list of available types. */ - private function populateAvailableTypes() + private function populateAvailableTypes(ContainerBuilder $container) { $this->types = array(); $this->ambiguousServiceTypes = array(); - foreach ($this->container->getDefinitions() as $id => $definition) { - $this->populateAvailableType($id, $definition); + foreach ($container->getDefinitions() as $id => $definition) { + $this->populateAvailableType($container, $id, $definition); } } /** * Populates the list of available types for a given definition. */ - private function populateAvailableType(string $id, Definition $definition) + private function populateAvailableType(ContainerBuilder $container, string $id, Definition $definition) { // Never use abstract services if ($definition->isAbstract()) { return; } - if ('' === $id || '.' === $id[0] || $definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), false)) { + if ('' === $id || '.' === $id[0] || $definition->isDeprecated() || !$reflectionClass = $container->getReflectionClass($definition->getClass(), false)) { return; } @@ -367,19 +365,21 @@ private function set(string $type, string $id) $this->ambiguousServiceTypes[$type][] = $id; } - private function createTypeNotFoundMessage(TypedReference $reference, $label) + private function createTypeNotFoundMessageCallback(TypedReference $reference, $label) { - $trackResources = $this->container->isTrackingResources(); - $this->container->setResourceTracking(false); - try { - if ($r = $this->container->getReflectionClass($type = $reference->getType(), false)) { - $alternatives = $this->createTypeAlternatives($reference); - } - } finally { - $this->container->setResourceTracking($trackResources); - } + $container = new ContainerBuilder($this->container->getParameterBag()); + $container->setAliases($this->container->getAliases()); + $container->setDefinitions($this->container->getDefinitions()); + $container->setResourceTracking(false); + + return function () use ($container, $reference, $label) { + return $this->createTypeNotFoundMessage($container, $reference, $label); + }; + } - if (!$r) { + private function createTypeNotFoundMessage(ContainerBuilder $container, TypedReference $reference, $label) + { + if (!$r = $container->getReflectionClass($type = $reference->getType(), false)) { // either $type does not exist or a parent class does not exist try { $resource = new ClassExistenceResource($type, false); @@ -392,7 +392,8 @@ private function createTypeNotFoundMessage(TypedReference $reference, $label) $message = sprintf('has type "%s" but this class %s.', $type, $parentMsg ? sprintf('is missing a parent class (%s)', $parentMsg) : 'was not found'); } else { - $message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists'; + $alternatives = $this->createTypeAlternatives($container, $reference); + $message = $container->has($type) ? 'this service is abstract' : 'no such service exists'; $message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $alternatives); if ($r->isInterface() && !$alternatives) { @@ -410,18 +411,18 @@ private function createTypeNotFoundMessage(TypedReference $reference, $label) return $message; } - private function createTypeAlternatives(TypedReference $reference) + private function createTypeAlternatives(ContainerBuilder $container, TypedReference $reference) { // try suggesting available aliases first - if ($message = $this->getAliasesSuggestionForType($type = $reference->getType())) { + if ($message = $this->getAliasesSuggestionForType($container, $type = $reference->getType())) { return ' '.$message; } if (null === $this->ambiguousServiceTypes) { - $this->populateAvailableTypes(); + $this->populateAvailableTypes($container); } - $servicesAndAliases = $this->container->getServiceIds(); - if (!$this->container->has($type) && false !== $key = array_search(strtolower($type), array_map('strtolower', $servicesAndAliases))) { + $servicesAndAliases = $container->getServiceIds(); + if (!$container->has($type) && false !== $key = array_search(strtolower($type), array_map('strtolower', $servicesAndAliases))) { return sprintf(' Did you mean "%s"?', $servicesAndAliases[$key]); } elseif (isset($this->ambiguousServiceTypes[$type])) { $message = sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type])); @@ -434,11 +435,11 @@ private function createTypeAlternatives(TypedReference $reference) return sprintf(' You should maybe alias this %s to %s.', class_exists($type, false) ? 'class' : 'interface', $message); } - private function getAliasesSuggestionForType($type, $extraContext = null) + private function getAliasesSuggestionForType(ContainerBuilder $container, $type, $extraContext = null) { $aliases = array(); foreach (class_parents($type) + class_implements($type) as $parent) { - if ($this->container->has($parent) && !$this->container->findDefinition($parent)->isAbstract()) { + if ($container->has($parent) && !$container->findDefinition($parent)->isAbstract()) { $aliases[] = $parent; } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php index 509011247c1c2..5ee0ff1f491cc 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php @@ -28,7 +28,7 @@ class DefinitionErrorExceptionPass extends AbstractRecursivePass */ protected function processValue($value, $isRoot = false) { - if (!$value instanceof Definition || empty($value->getErrors())) { + if (!$value instanceof Definition || !$value->hasErrors()) { return parent::processValue($value, $isRoot); } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php index eb89a2a40d2d2..7f17eedeea6c0 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php @@ -157,7 +157,7 @@ protected function processValue($value, $isRoot = false) */ private function isInlineableDefinition($id, Definition $definition) { - if ($definition->getErrors() || $definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic()) { + if ($definition->hasErrors() || $definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic()) { return false; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php index ac6687c36a109..f5ec06eb1af14 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveChildDefinitionsPass.php @@ -176,9 +176,8 @@ private function doResolveDefinition(ChildDefinition $definition) $def->setMethodCalls(array_merge($def->getMethodCalls(), $calls)); } - foreach (array_merge($parentDef->getErrors(), $definition->getErrors()) as $v) { - $def->addError($v); - } + $def->addError($parentDef); + $def->addError($definition); // these attributes are always taken from the child $def->setAbstract($definition->isAbstract()); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index f49288ccf6d0d..8ec1c62e4381c 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -592,7 +592,7 @@ private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_ throw $e; } - if ($e = $definition->getErrors()) { + if ($definition->hasErrors() && $e = $definition->getErrors()) { throw new RuntimeException(reset($e)); } diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index ceff4b899d27a..5480fe7ddb857 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -876,13 +876,17 @@ public function setBindings(array $bindings) /** * Add an error that occurred when building this Definition. * - * @param string $error + * @param string|\Closure|self $error * * @return $this */ public function addError($error) { - $this->errors[] = $error; + if ($error instanceof self) { + $this->errors = array_merge($this->errors, $error->errors); + } else { + $this->errors[] = $error; + } return $this; } @@ -894,6 +898,19 @@ public function addError($error) */ public function getErrors() { + foreach ($this->errors as $i => $error) { + if ($error instanceof \Closure) { + $this->errors[$i] = (string) $error(); + } elseif (!\is_string($error)) { + $this->errors[$i] = (string) $error; + } + } + return $this->errors; } + + public function hasErrors(): bool + { + return (bool) $this->errors; + } } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 3649ef780cdc9..eec9742f02e2f 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -492,7 +492,7 @@ private function addServiceInstance(string $id, Definition $definition, bool $is private function isTrivialInstance(Definition $definition): bool { - if ($definition->getErrors()) { + if ($definition->hasErrors()) { return true; } if ($definition->isSynthetic() || $definition->getFile() || $definition->getMethodCalls() || $definition->getProperties() || $definition->getConfigurator()) { @@ -1465,7 +1465,7 @@ private function dumpValue($value, bool $interpolate = true): string continue; } $definition = $this->container->findDefinition($id = (string) $v); - $load = !($e = $definition->getErrors()) ? $this->asFiles && !$this->isHotPath($definition) : reset($e); + $load = !($definition->hasErrors() && $e = $definition->getErrors()) ? $this->asFiles && !$this->isHotPath($definition) : reset($e); $serviceMap .= sprintf("\n %s => array(%s, %s, %s, %s),", $this->export($k), $this->export($definition->isShared() ? ($definition->isPublic() ? 'services' : 'privates') : false), @@ -1483,7 +1483,7 @@ private function dumpValue($value, bool $interpolate = true): string list($this->definitionVariables, $this->referenceVariables) = $scope; } } elseif ($value instanceof Definition) { - if ($e = $value->getErrors()) { + if ($value->hasErrors() && $e = $value->getErrors()) { $this->addThrow = true; return sprintf('$this->throw(%s)', $this->export(reset($e))); @@ -1592,7 +1592,7 @@ private function getServiceCall(string $id, Reference $reference = null): string return $code; } } elseif ($this->isTrivialInstance($definition)) { - if ($e = $definition->getErrors()) { + if ($definition->hasErrors() && $e = $definition->getErrors()) { $this->addThrow = true; return sprintf('$this->throw(%s)', $this->export(reset($e))); diff --git a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php index f198cd2800289..05f134a942faa 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php @@ -17,12 +17,44 @@ class AutowiringFailedException extends RuntimeException { private $serviceId; + private $messageCallback; - public function __construct(string $serviceId, string $message = '', int $code = 0, \Exception $previous = null) + public function __construct(string $serviceId, $message = '', int $code = 0, \Exception $previous = null) { $this->serviceId = $serviceId; - parent::__construct($message, $code, $previous); + if (!$message instanceof \Closure) { + parent::__construct($message, $code, $previous); + + return; + } + + $this->messageCallback = $message; + parent::__construct('', $code, $previous); + + $this->message = new class($this->message, $this->messageCallback) { + private $message; + private $messageCallback; + + public function __construct(&$message, &$messageCallback) + { + $this->message = &$message; + $this->messageCallback = &$messageCallback; + } + + public function __toString(): string + { + $messageCallback = $this->messageCallback; + $this->messageCallback = null; + + return $this->message = $messageCallback(); + } + }; + } + + public function getMessageCallback(): ?\Closure + { + return $this->messageCallback; } public function getServiceId() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 110c7edd8a71b..d22148fdac690 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -20,7 +20,6 @@ use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass; use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; @@ -620,7 +619,7 @@ public function testSetterInjectionCollisionThrowsException() } $this->assertNotNull($e); - $this->assertSame('Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2".', $e->getMessage()); + $this->assertSame('Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2".', (string) $e->getMessage()); } /** @@ -903,9 +902,7 @@ public function testErroredServiceLocator() (new AutowirePass())->process($container); - $erroredDefinition = new Definition(MissingClass::class); - - $this->assertEquals($erroredDefinition->addError('Cannot autowire service "some_locator": it has type "Symfony\Component\DependencyInjection\Tests\Compiler\MissingClass" but this class was not found.'), $container->getDefinition('.errored.some_locator.'.MissingClass::class)); + $this->assertSame(array('Cannot autowire service "some_locator": it has type "Symfony\Component\DependencyInjection\Tests\Compiler\MissingClass" but this class was not found.'), $container->getDefinition('.errored.some_locator.'.MissingClass::class)->getErrors()); } public function testNamedArgumentAliasResolveCollisions() diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index 0ed135915e491..b0c1e63d0c018 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -375,7 +375,7 @@ public function testShouldAutoconfigure() public function testAddError() { $def = new Definition('stdClass'); - $this->assertEmpty($def->getErrors()); + $this->assertFalse($def->hasErrors()); $def->addError('First error'); $def->addError('Second error'); $this->assertSame(array('First error', 'Second error'), $def->getErrors()); From 388840fd99d59ab3d5ae7f61ab5a0da96499e317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 8 Nov 2018 16:47:13 +0100 Subject: [PATCH 005/495] [Workflow] Trigger `entered` event for subject entering in the Workflow for the first time --- src/Symfony/Component/Workflow/CHANGELOG.md | 5 +++++ src/Symfony/Component/Workflow/Event/Event.php | 2 +- src/Symfony/Component/Workflow/Tests/WorkflowTest.php | 2 ++ src/Symfony/Component/Workflow/Workflow.php | 10 +++++++--- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 5d0f6a6abb241..4668f2f68af17 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * Trigger `entered` event for subject entering in the Workflow for the first time + 4.1.0 ----- diff --git a/src/Symfony/Component/Workflow/Event/Event.php b/src/Symfony/Component/Workflow/Event/Event.php index 395f2fd97bfe1..79ba18d6a5306 100644 --- a/src/Symfony/Component/Workflow/Event/Event.php +++ b/src/Symfony/Component/Workflow/Event/Event.php @@ -35,7 +35,7 @@ class Event extends BaseEvent * @param Transition $transition * @param WorkflowInterface $workflow */ - public function __construct($subject, Marking $marking, Transition $transition, $workflow = null) + public function __construct($subject, Marking $marking, Transition $transition = null, $workflow = null) { $this->subject = $subject; $this->marking = $marking; diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 87f48002487d7..e83162b74775f 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -373,6 +373,8 @@ public function testApplyWithEventDispatcher() $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); $eventNameExpected = array( + 'workflow.entered', + 'workflow.workflow_name.entered', 'workflow.guard', 'workflow.workflow_name.guard', 'workflow.workflow_name.guard.t1', diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 21676e0fc89ae..936c19f948148 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -61,6 +61,8 @@ public function getMarking($subject) // update the subject with the new marking $this->markingStore->setMarking($subject, $marking); + + $this->entered($subject, null, $marking); } // check that the subject has a known place @@ -323,7 +325,7 @@ private function enter($subject, Transition $transition, Marking $marking): void } } - private function entered($subject, Transition $transition, Marking $marking): void + private function entered($subject, Transition $transition = null, Marking $marking): void { if (null === $this->dispatcher) { return; @@ -334,8 +336,10 @@ private function entered($subject, Transition $transition, Marking $marking): vo $this->dispatcher->dispatch('workflow.entered', $event); $this->dispatcher->dispatch(sprintf('workflow.%s.entered', $this->name), $event); - foreach ($transition->getTos() as $place) { - $this->dispatcher->dispatch(sprintf('workflow.%s.entered.%s', $this->name, $place), $event); + if ($transition) { + foreach ($transition->getTos() as $place) { + $this->dispatcher->dispatch(sprintf('workflow.%s.entered.%s', $this->name, $place), $event); + } } } From e7cd44f5b2765d8fe4775b50cfcde46de4519b5d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 15 Nov 2018 20:20:02 +0100 Subject: [PATCH 006/495] [VarDumper] add support for links in CliDumper --- .../DependencyInjection/DebugExtension.php | 9 +++++ .../DataCollector/DumpDataCollector.php | 6 +++ .../Component/VarDumper/Dumper/CliDumper.php | 39 ++++++++++++++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php index aa124a8c03b26..317f2fba4e093 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Extension\Extension; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\VarDumper\Dumper\CliDumper; /** * DebugExtension. @@ -69,6 +70,14 @@ public function load(array $configs, ContainerBuilder $container) ->setClass(ServerDumpPlaceholderCommand::class) ; } + + if (method_exists(CliDumper::class, 'setDisplayOptions')) { + $container->getDefinition('var_dumper.cli_dumper') + ->addMethodCall('setDisplayOptions', array(array( + 'fileLinkFormat' => new Reference('debug.file_link_formatter', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), + ))) + ; + } } /** diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index 13694f5a5937f..051c3dd2cfb0d 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -113,6 +113,9 @@ public function collect(Request $request, Response $response, \Exception $except $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); } else { $dumper = new CliDumper('php://output', $this->charset); + if (method_exists($dumper, 'setDisplayOptions')) { + $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + } } foreach ($this->data as $dump) { @@ -215,6 +218,9 @@ public function __destruct() $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); } else { $dumper = new CliDumper('php://output', $this->charset); + if (method_exists($dumper, 'setDisplayOptions')) { + $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + } } foreach ($this->data as $i => $dump) { diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index 9fcd6c412666f..a6341709a48fa 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -55,6 +55,10 @@ class CliDumper extends AbstractDumper protected $collapseNextHash = false; protected $expandNextHash = false; + private $displayOptions = array( + 'fileLinkFormat' => null, + ); + /** * {@inheritdoc} */ @@ -76,6 +80,8 @@ public function __construct($output = null, string $charset = null, int $flags = 'index' => '34', )); } + + $this->displayOptions['fileLinkFormat'] = ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f'; } /** @@ -108,6 +114,16 @@ public function setStyles(array $styles) $this->styles = $styles + $this->styles; } + /** + * Configures display options. + * + * @param array $displayOptions A map of display options to customize the behavior + */ + public function setDisplayOptions(array $displayOptions) + { + $this->displayOptions = $displayOptions + $this->displayOptions; + } + /** * {@inheritdoc} */ @@ -427,7 +443,9 @@ protected function style($style, $value, $attr = array()) $value = substr($value, -$attr['ellipsis']); } - return $this->style('default', $prefix).$this->style($style, $value); + $value = $this->style('default', $prefix).$this->style($style, $value); + + goto href; } $style = $this->styles[$style]; @@ -458,6 +476,16 @@ protected function style($style, $value, $attr = array()) } } + href: + if ($this->colors) { + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], isset($attr['line']) ? $attr['line'] : 0)) { + $attr['href'] = $href; + } + if (isset($attr['href'])) { + $value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\"; + } + } + return $value; } @@ -594,4 +622,13 @@ private function isWindowsTrueColor() return $result; } + + private function getSourceLink($file, $line) + { + if ($fmt = $this->displayOptions['fileLinkFormat']) { + return \is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line); + } + + return false; + } } From 9ae2bb45b2c0d2afc4dd846c59b5b8f2c80ab65c Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Thu, 22 Nov 2018 19:37:19 +0100 Subject: [PATCH 007/495] [WebProfilerBundle] Enable translation filters --- .../TwigBundle/Resources/views/exception.css.twig | 2 +- .../Resources/views/Collector/translation.html.twig | 10 ++++++---- .../Resources/views/Profiler/profiler.css.twig | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig index 4556749de8688..c717b70d696eb 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig @@ -126,7 +126,7 @@ thead.sf-toggle-content.sf-toggle-visible, tbody.sf-toggle-content.sf-toggle-vis .filter-list-level li.active { cursor: n-resize; } .filter-list-level li.last-active { cursor: default; } .filter-list-level li.last-active:before { content: '\2714\00a0'; } -.filter-list-choice li:before { content: '\2714\00a0'; color: var(--tab-background); } +.filter-list-choice li:before { content: '\2714\00a0'; color: transparent; } .filter-list-choice li.active:before { color: unset; } .container { max-width: 1024px; margin: 0 auto; padding: 0 15px; } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig index cd9f5971c412d..06c27b4716a51 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig @@ -179,16 +179,18 @@ + + {% endblock messages %} {% endblock %} {% macro render_table(messages) %} - +
- - + + @@ -196,7 +198,7 @@ {% for message in messages %} - + diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 5f6582ed38677..dd5b970148e68 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -957,7 +957,7 @@ tr.status-warning td { .filter-list-level li.active { cursor: n-resize; } .filter-list-level li.last-active { cursor: default; } .filter-list-level li.last-active:before { content: '\2714\00a0'; } -.filter-list-choice li:before { content: '\2714\00a0'; color: var(--tab-background); } +.filter-list-choice li:before { content: '\2714\00a0'; color: transparent; } .filter-list-choice li.active:before { color: unset; } {# Twig panel From 1a8c844f0e0f2c03a3456c388c836c8efdaf6474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 16 Oct 2017 16:11:13 +0200 Subject: [PATCH 008/495] [FrameworkBundle] Added `ControllerTrait::isFormValid` --- .../Bundle/FrameworkBundle/CHANGELOG.md | 15 ++- .../Controller/ControllerTrait.php | 22 ++++ .../Tests/Controller/ControllerTraitTest.php | 112 ++++++++++++++++++ 3 files changed, 144 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 6bb39e9f0e411..b2096087bc3ec 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * Added `ControllerTrait::isFormValid()` + 4.2.0 ----- @@ -12,7 +17,7 @@ CHANGELOG * Deprecated the `Symfony\Bundle\FrameworkBundle\Controller\Controller` class in favor of `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`. * Enabled autoconfiguration for `Psr\Log\LoggerAwareInterface` * Added new "auto" mode for `framework.session.cookie_secure` to turn it on when HTTPS is used - * Removed the `framework.messenger.encoder` and `framework.messenger.decoder` options. Use the `framework.messenger.serializer.id` option to replace the Messenger serializer. + * Removed the `framework.messenger.encoder` and `framework.messenger.decoder` options. Use the `framework.messenger.serializer.id` option to replace the Messenger serializer. * Deprecated the `ContainerAwareCommand` class in favor of `Symfony\Component\Console\Command\Command` * Made `debug:container` and `debug:autowiring` ignore backslashes in service ids * Deprecated the `Templating\Helper\TranslatorHelper::transChoice()` method, use the `trans()` one instead with a `%count%` parameter @@ -83,17 +88,17 @@ CHANGELOG * Deprecated the `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()` methods. * Deprecated `AddCacheClearerPass`, use tagged iterator arguments instead. * Deprecated `AddCacheWarmerPass`, use tagged iterator arguments instead. - * Deprecated `TranslationDumperPass`, use + * Deprecated `TranslationDumperPass`, use `Symfony\Component\Translation\DependencyInjection\TranslationDumperPass` instead - * Deprecated `TranslationExtractorPass`, use + * Deprecated `TranslationExtractorPass`, use `Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass` instead - * Deprecated `TranslatorPass`, use + * Deprecated `TranslatorPass`, use `Symfony\Component\Translation\DependencyInjection\TranslatorPass` instead * Added `command` attribute to the `console.command` tag which takes the command name as value, using it makes the command lazy * Added `cache:pool:prune` command to allow manual stale cache item pruning of supported PSR-6 and PSR-16 cache pool implementations - * Deprecated `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`, use + * Deprecated `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`, use `Symfony\Component\Translation\Reader\TranslationReader` instead * Deprecated `translation.loader` service, use `translation.reader` instead * `AssetsInstallCommand::__construct()` now takes an instance of diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index 451b83931a843..51bc264a6e6fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -326,6 +326,28 @@ protected function createFormBuilder($data = null, array $options = array()): Fo return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options); } + /** + * Handles request and check form validity. + * + * @final + */ + protected function isFormValid(FormInterface $form, Request $request = null): bool + { + if ($form->isSubmitted()) { + throw new \LogicException('The form is already submitted, use $form->isValid() directly.'); + } + + if (!$request) { + $request = $this->container->get('request_stack')->getCurrentRequest(); + } + + if (!$request) { + throw new \LogicException('You must pass a request as second argument because the request stack is empty.'); + } + + return $form->handleRequest($request)->isSubmitted() && $form->isValid(); + } + /** * Shortcut to return the Doctrine Registry service. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php index 41d463f57381d..0dcbc0e5db06d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php @@ -517,6 +517,117 @@ public function testCreateFormBuilder() $this->assertEquals($formBuilder, $controller->createFormBuilder('foo')); } + /** + * @expectedException \LogicException + * @expectedExceptionMessage The form is already submitted, use $form->isValid() directly. + */ + public function testIsFormValidWhenAlreadySubmitted() + { + $requestStack = new RequestStack(); + $requestStack->push($request = new Request()); + + $container = new Container(); + $container->set('request_stack', $requestStack); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + $form + ->expects($this->once()) + ->method('isSubmitted') + ->willReturn(true) + ; + + $controller->isFormValid($form); + } + + public function testIsFormValidWhenInvalid() + { + $requestStack = new RequestStack(); + $requestStack->push($request = new Request()); + + $container = new Container(); + $container->set('request_stack', $requestStack); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + $form + ->expects($this->at(0)) + ->method('isSubmitted') + ->willReturn(false) + ; + $form + ->expects($this->once()) + ->method('handleRequest') + ->with($request) + ->willReturn($form) + ; + $form + ->expects($this->at(2)) + ->method('isSubmitted') + ->willReturn(false) + ; + + $this->assertFalse($controller->isFormValid($form)); + } + + public function testIsFormValidWhenValid() + { + $requestStack = new RequestStack(); + $requestStack->push($request = new Request()); + + $container = new Container(); + $container->set('request_stack', $requestStack); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + $form + ->expects($this->at(0)) + ->method('isSubmitted') + ->willReturn(false) + ; + $form + ->expects($this->once()) + ->method('handleRequest') + ->with($request) + ->willReturn($form) + ; + $form + ->expects($this->at(2)) + ->method('isSubmitted') + ->willReturn(true) + ; + $form + ->expects($this->once()) + ->method('isValid') + ->willReturn(true) + ; + + $this->assertTrue($controller->isFormValid($form)); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You must pass a request as second argument because the request stack is empty. + */ + public function testIsFormValidWhenRequestStackIsEmpty() + { + $container = new Container(); + $container->set('request_stack', new RequestStack()); + + $controller = $this->createController(); + $controller->setContainer($container); + + $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); + + $this->assertTrue($controller->isFormValid($form)); + } + public function testGetDoctrine() { $doctrine = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); @@ -569,5 +680,6 @@ trait TestControllerTrait createFormBuilder as public; getDoctrine as public; addLink as public; + isFormValid as public; } } From 534b83f08056129e3043589849dab564830c5d9a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 17:19:01 +0100 Subject: [PATCH 009/495] updated version to 4.3 --- composer.json | 2 +- src/Symfony/Bridge/Doctrine/composer.json | 2 +- src/Symfony/Bridge/Monolog/composer.json | 2 +- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- src/Symfony/Bridge/ProxyManager/composer.json | 2 +- src/Symfony/Bridge/Twig/composer.json | 2 +- src/Symfony/Bundle/DebugBundle/composer.json | 2 +- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- src/Symfony/Bundle/TwigBundle/composer.json | 2 +- src/Symfony/Bundle/WebProfilerBundle/composer.json | 2 +- src/Symfony/Bundle/WebServerBundle/composer.json | 2 +- src/Symfony/Component/Asset/composer.json | 2 +- src/Symfony/Component/BrowserKit/composer.json | 2 +- src/Symfony/Component/Cache/composer.json | 2 +- src/Symfony/Component/Config/composer.json | 2 +- src/Symfony/Component/Console/composer.json | 2 +- src/Symfony/Component/CssSelector/composer.json | 2 +- src/Symfony/Component/Debug/composer.json | 2 +- .../Component/DependencyInjection/composer.json | 2 +- src/Symfony/Component/DomCrawler/composer.json | 2 +- src/Symfony/Component/Dotenv/composer.json | 2 +- src/Symfony/Component/EventDispatcher/composer.json | 2 +- src/Symfony/Component/ExpressionLanguage/composer.json | 2 +- src/Symfony/Component/Filesystem/composer.json | 2 +- src/Symfony/Component/Finder/composer.json | 2 +- src/Symfony/Component/Form/composer.json | 2 +- src/Symfony/Component/HttpFoundation/composer.json | 2 +- src/Symfony/Component/HttpKernel/Kernel.php | 10 +++++----- src/Symfony/Component/HttpKernel/composer.json | 2 +- src/Symfony/Component/Inflector/composer.json | 2 +- src/Symfony/Component/Intl/composer.json | 2 +- src/Symfony/Component/Ldap/composer.json | 2 +- src/Symfony/Component/Lock/composer.json | 2 +- src/Symfony/Component/Messenger/composer.json | 2 +- src/Symfony/Component/OptionsResolver/composer.json | 2 +- src/Symfony/Component/Process/composer.json | 2 +- src/Symfony/Component/PropertyAccess/composer.json | 2 +- src/Symfony/Component/PropertyInfo/composer.json | 2 +- src/Symfony/Component/Routing/composer.json | 2 +- src/Symfony/Component/Security/Core/composer.json | 2 +- src/Symfony/Component/Security/Csrf/composer.json | 2 +- src/Symfony/Component/Security/Guard/composer.json | 2 +- src/Symfony/Component/Security/Http/composer.json | 2 +- src/Symfony/Component/Security/composer.json | 2 +- src/Symfony/Component/Serializer/composer.json | 2 +- src/Symfony/Component/Stopwatch/composer.json | 2 +- src/Symfony/Component/Templating/composer.json | 2 +- src/Symfony/Component/Translation/composer.json | 2 +- src/Symfony/Component/Validator/composer.json | 2 +- src/Symfony/Component/VarDumper/composer.json | 2 +- src/Symfony/Component/VarExporter/composer.json | 2 +- src/Symfony/Component/WebLink/composer.json | 2 +- src/Symfony/Component/Workflow/composer.json | 2 +- src/Symfony/Component/Yaml/composer.json | 2 +- 55 files changed, 59 insertions(+), 59 deletions(-) diff --git a/composer.json b/composer.json index 839e21780b88d..8eeac423c69df 100644 --- a/composer.json +++ b/composer.json @@ -147,7 +147,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index bc828b43e21b6..181df055b12ce 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -65,7 +65,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index ce7fee470b247..2cb3654013d30 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -46,7 +46,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 4d72603eb452f..0c2f6d80492e9 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -40,7 +40,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" }, "thanks": { "name": "phpunit/phpunit", diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json index 648bf8990fb64..d5ce7a3e3989f 100644 --- a/src/Symfony/Bridge/ProxyManager/composer.json +++ b/src/Symfony/Bridge/ProxyManager/composer.json @@ -35,7 +35,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 2441cbf9faa3d..a559ce366a993 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -70,7 +70,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bundle/DebugBundle/composer.json b/src/Symfony/Bundle/DebugBundle/composer.json index 535d0edfa8050..76f7a86f96a23 100644 --- a/src/Symfony/Bundle/DebugBundle/composer.json +++ b/src/Symfony/Bundle/DebugBundle/composer.json @@ -44,7 +44,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index f2b85c5f0c84a..13ba0434d9b25 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -97,7 +97,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 5a03f8f7fa846..23b40ea144635 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -64,7 +64,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index d9526cf7d5411..5376f90e126a1 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -54,7 +54,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index 0f4d40879d22d..fc8ee7cfd7389 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -43,7 +43,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Bundle/WebServerBundle/composer.json b/src/Symfony/Bundle/WebServerBundle/composer.json index 4a981ea93e419..bf2e67a8368ba 100644 --- a/src/Symfony/Bundle/WebServerBundle/composer.json +++ b/src/Symfony/Bundle/WebServerBundle/composer.json @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Asset/composer.json b/src/Symfony/Component/Asset/composer.json index bcf70fc18318f..cfdd49546f5e2 100644 --- a/src/Symfony/Component/Asset/composer.json +++ b/src/Symfony/Component/Asset/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/BrowserKit/composer.json b/src/Symfony/Component/BrowserKit/composer.json index 0607378c4d367..4c0567b5da9ef 100644 --- a/src/Symfony/Component/BrowserKit/composer.json +++ b/src/Symfony/Component/BrowserKit/composer.json @@ -35,7 +35,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 1abdb562a9bee..6356939b465ff 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -51,7 +51,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index 35fbffdb69a41..aa87fe4f38898 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -41,7 +41,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index ca1a9269f3096..64f63aeb23e93 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -47,7 +47,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/CssSelector/composer.json b/src/Symfony/Component/CssSelector/composer.json index ebe7d0d5c1eea..91e64f27d9b2b 100644 --- a/src/Symfony/Component/CssSelector/composer.json +++ b/src/Symfony/Component/CssSelector/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Debug/composer.json b/src/Symfony/Component/Debug/composer.json index 45799e2e60f67..7fd5ff9c93ab8 100644 --- a/src/Symfony/Component/Debug/composer.json +++ b/src/Symfony/Component/Debug/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index 32f52797e4345..164b3594c7fbe 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -51,7 +51,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/DomCrawler/composer.json b/src/Symfony/Component/DomCrawler/composer.json index 167d0fdfe50c9..b3173484c1e7d 100644 --- a/src/Symfony/Component/DomCrawler/composer.json +++ b/src/Symfony/Component/DomCrawler/composer.json @@ -35,7 +35,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Dotenv/composer.json b/src/Symfony/Component/Dotenv/composer.json index 6590da03e5169..872ff3a4c5be8 100644 --- a/src/Symfony/Component/Dotenv/composer.json +++ b/src/Symfony/Component/Dotenv/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/EventDispatcher/composer.json b/src/Symfony/Component/EventDispatcher/composer.json index 6c75dfbb0052b..6cdc762bc301b 100644 --- a/src/Symfony/Component/EventDispatcher/composer.json +++ b/src/Symfony/Component/EventDispatcher/composer.json @@ -42,7 +42,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/ExpressionLanguage/composer.json b/src/Symfony/Component/ExpressionLanguage/composer.json index 2e699629e8eb0..66581371f907f 100644 --- a/src/Symfony/Component/ExpressionLanguage/composer.json +++ b/src/Symfony/Component/ExpressionLanguage/composer.json @@ -29,7 +29,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Filesystem/composer.json b/src/Symfony/Component/Filesystem/composer.json index ee8a319a7d1c5..d13397b42410d 100644 --- a/src/Symfony/Component/Filesystem/composer.json +++ b/src/Symfony/Component/Filesystem/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Finder/composer.json b/src/Symfony/Component/Finder/composer.json index 37d34a5e51d76..05d5d1bb9e9f7 100644 --- a/src/Symfony/Component/Finder/composer.json +++ b/src/Symfony/Component/Finder/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 49448badc8db0..4f72f19e8e5b4 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -60,7 +60,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/HttpFoundation/composer.json b/src/Symfony/Component/HttpFoundation/composer.json index 76381a7c46a05..49ab5c64275c6 100644 --- a/src/Symfony/Component/HttpFoundation/composer.json +++ b/src/Symfony/Component/HttpFoundation/composer.json @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7116b7015c465..c5aea60154b1a 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,15 +73,15 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.2.0-DEV'; - const VERSION_ID = 40200; + const VERSION = '4.3.0-DEV'; + const VERSION_ID = 40300; const MAJOR_VERSION = 4; - const MINOR_VERSION = 2; + const MINOR_VERSION = 3; const RELEASE_VERSION = 0; const EXTRA_VERSION = 'DEV'; - const END_OF_MAINTENANCE = '07/2019'; - const END_OF_LIFE = '01/2020'; + const END_OF_MAINTENANCE = '01/2020'; + const END_OF_LIFE = '07/2020'; public function __construct(string $environment, bool $debug) { diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 8228377e0419b..6bacac83a21a5 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -67,7 +67,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Inflector/composer.json b/src/Symfony/Component/Inflector/composer.json index b4312cd037dfe..2a4e29695d85f 100644 --- a/src/Symfony/Component/Inflector/composer.json +++ b/src/Symfony/Component/Inflector/composer.json @@ -35,7 +35,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Intl/composer.json b/src/Symfony/Component/Intl/composer.json index b0f3e3b6d53c7..64a2ebf1a64d7 100644 --- a/src/Symfony/Component/Intl/composer.json +++ b/src/Symfony/Component/Intl/composer.json @@ -43,7 +43,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Ldap/composer.json b/src/Symfony/Component/Ldap/composer.json index 77c3d773ce5d2..e8fb2720f4d12 100644 --- a/src/Symfony/Component/Ldap/composer.json +++ b/src/Symfony/Component/Ldap/composer.json @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index 22704c6e5c361..7c5fa0acd599d 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index 077a5feb08080..f828b64451943 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -42,7 +42,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/OptionsResolver/composer.json b/src/Symfony/Component/OptionsResolver/composer.json index 1c819495bf89d..6753856f56b02 100644 --- a/src/Symfony/Component/OptionsResolver/composer.json +++ b/src/Symfony/Component/OptionsResolver/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Process/composer.json b/src/Symfony/Component/Process/composer.json index 44bad06b597b9..d3efd0238207a 100644 --- a/src/Symfony/Component/Process/composer.json +++ b/src/Symfony/Component/Process/composer.json @@ -27,7 +27,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/PropertyAccess/composer.json b/src/Symfony/Component/PropertyAccess/composer.json index 33f9b188d0d1c..bd81e5c260cc2 100644 --- a/src/Symfony/Component/PropertyAccess/composer.json +++ b/src/Symfony/Component/PropertyAccess/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json index 357b05da93694..bfa0fd3eccac1 100644 --- a/src/Symfony/Component/PropertyInfo/composer.json +++ b/src/Symfony/Component/PropertyInfo/composer.json @@ -53,7 +53,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json index be489ee983262..11fd7ee68cda5 100644 --- a/src/Symfony/Component/Routing/composer.json +++ b/src/Symfony/Component/Routing/composer.json @@ -49,7 +49,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Security/Core/composer.json b/src/Symfony/Component/Security/Core/composer.json index 4df719003045d..f4128c65c2bc6 100644 --- a/src/Symfony/Component/Security/Core/composer.json +++ b/src/Symfony/Component/Security/Core/composer.json @@ -45,7 +45,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Security/Csrf/composer.json b/src/Symfony/Component/Security/Csrf/composer.json index cdc19ade22f15..716951f95bdf0 100644 --- a/src/Symfony/Component/Security/Csrf/composer.json +++ b/src/Symfony/Component/Security/Csrf/composer.json @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Security/Guard/composer.json b/src/Symfony/Component/Security/Guard/composer.json index 982b16f012a32..44adaa6e11e83 100644 --- a/src/Symfony/Component/Security/Guard/composer.json +++ b/src/Symfony/Component/Security/Guard/composer.json @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index ef81706f2a5fa..7047eba06e9e8 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -44,7 +44,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index 6cf567f2b01fc..80e62d923a565 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -59,7 +59,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index 52961bb7c0528..9e86c07e73c34 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -58,7 +58,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Stopwatch/composer.json b/src/Symfony/Component/Stopwatch/composer.json index 356b1fec17d4d..2ac6e03e29c2c 100644 --- a/src/Symfony/Component/Stopwatch/composer.json +++ b/src/Symfony/Component/Stopwatch/composer.json @@ -28,7 +28,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Templating/composer.json b/src/Symfony/Component/Templating/composer.json index 9e56b0247cc88..f6474495d5687 100644 --- a/src/Symfony/Component/Templating/composer.json +++ b/src/Symfony/Component/Templating/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Translation/composer.json b/src/Symfony/Component/Translation/composer.json index 29ba62ab15eab..6cb801b895c40 100644 --- a/src/Symfony/Component/Translation/composer.json +++ b/src/Symfony/Component/Translation/composer.json @@ -51,7 +51,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 442d7c67b4411..e91e8e4a706cd 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -67,7 +67,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/VarDumper/composer.json b/src/Symfony/Component/VarDumper/composer.json index 5cf48475a78e1..5c31550976c78 100644 --- a/src/Symfony/Component/VarDumper/composer.json +++ b/src/Symfony/Component/VarDumper/composer.json @@ -47,7 +47,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/VarExporter/composer.json b/src/Symfony/Component/VarExporter/composer.json index b982d3bfd7443..3d543df671a54 100644 --- a/src/Symfony/Component/VarExporter/composer.json +++ b/src/Symfony/Component/VarExporter/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/WebLink/composer.json b/src/Symfony/Component/WebLink/composer.json index 2c09787390037..57f96c1a6c2f7 100644 --- a/src/Symfony/Component/WebLink/composer.json +++ b/src/Symfony/Component/WebLink/composer.json @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Workflow/composer.json b/src/Symfony/Component/Workflow/composer.json index 645c550c67b99..40dc178e16fe5 100644 --- a/src/Symfony/Component/Workflow/composer.json +++ b/src/Symfony/Component/Workflow/composer.json @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/src/Symfony/Component/Yaml/composer.json b/src/Symfony/Component/Yaml/composer.json index c8b7123f239d4..2338728efecfc 100644 --- a/src/Symfony/Component/Yaml/composer.json +++ b/src/Symfony/Component/Yaml/composer.json @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } From 79162c1eb5ba7be211005c5debe4d017f5d9a63e Mon Sep 17 00:00:00 2001 From: Andrey Helldar Date: Wed, 7 Nov 2018 17:41:49 +0300 Subject: [PATCH 010/495] [DomCrawler] Added return of element name in `extract()` method --- src/Symfony/Component/DomCrawler/CHANGELOG.md | 5 +++++ src/Symfony/Component/DomCrawler/Crawler.php | 2 ++ src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/Symfony/Component/DomCrawler/CHANGELOG.md b/src/Symfony/Component/DomCrawler/CHANGELOG.md index dc773be06d65b..3accde4bf5738 100644 --- a/src/Symfony/Component/DomCrawler/CHANGELOG.md +++ b/src/Symfony/Component/DomCrawler/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + +* Added return of element name (`_name`) in `extract()` method. + 4.2.0 ----- diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 455e030955eaa..a70c6466e0686 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -658,6 +658,8 @@ public function extract($attributes) foreach ($attributes as $attribute) { if ('_text' === $attribute) { $elements[] = $node->nodeValue; + } elseif ('_name' === $attribute) { + $elements[] = $node->nodeName; } else { $elements[] = $node->getAttribute($attribute); } diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index 9e73eaae1d9c2..254b1ba7f3206 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -416,6 +416,8 @@ public function testExtract() $this->assertEquals(array(array(), array(), array()), $crawler->extract(array()), '->extract() returns empty arrays if the attribute list is empty'); $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty'); + + $this->assertEquals(array(array('One', 'li'), array('Two', 'li'), array('Three', 'li')), $crawler->extract(array('_text', '_name')), '->extract() returns an array of extracted data from the node list'); } public function testFilterXpathComplexQueries() From aee4e33cdb493e7c1cbdca715e6d014dcceee06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 25 Oct 2018 09:05:21 +0200 Subject: [PATCH 011/495] =?UTF-8?q?[DI]=C2=A0Add=20a=20\"default\"=20EnvPr?= =?UTF-8?q?ocessor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DependencyInjection/CHANGELOG.md | 5 + .../DependencyInjection/EnvVarProcessor.php | 31 ++++- .../Exception/EnvNotFoundException.php | 4 - .../RegisterEnvVarProcessorsPassTest.php | 1 + .../Tests/Dumper/PhpDumperTest.php | 22 +++ .../Tests/EnvVarProcessorTest.php | 4 +- .../Fixtures/php/services_default_env.php | 130 ++++++++++++++++++ 7 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 2cc1a49725930..470331d9b7cec 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added `%env(default:...)%` processor to fallback to a default value + 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 67a0687c24586..912091b217188 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -44,6 +44,7 @@ public static function getProvidedTypes() 'json' => 'array', 'key' => 'bool|int|float|string|array', 'resolve' => 'string', + 'default' => 'bool|int|float|string|array', 'string' => 'string', ); } @@ -57,7 +58,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) if ('key' === $prefix) { if (false === $i) { - throw new RuntimeException(sprintf('Invalid configuration: env var "key:%s" does not contain a key specifier.', $name)); + throw new RuntimeException(sprintf('Invalid env "key:%s": a key specifier should be provided.', $name)); } $next = substr($name, $i + 1); @@ -67,19 +68,39 @@ public function getEnv($prefix, $name, \Closure $getEnv) if (!\is_array($array)) { throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.', $next)); } - if (!array_key_exists($key, $array)) { - throw new RuntimeException(sprintf('Key "%s" not found in "%s" (resolved from "%s")', $key, json_encode($array), $next)); + + if (!isset($array[$key]) && !array_key_exists($key, $array)) { + throw new EnvNotFoundException(sprintf('Key "%s" not found in "%s" (resolved from "%s").', $key, json_encode($array), $next)); } return $array[$key]; } + if ('default' === $prefix) { + if (false === $i) { + throw new RuntimeException(sprintf('Invalid env "default:%s": a fallback parameter should be provided.', $name)); + } + + $next = substr($name, $i + 1); + $default = substr($name, 0, $i); + + if (!$this->container->hasParameter($default)) { + throw new RuntimeException(sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.', $name, $default)); + } + + try { + return $getEnv($next); + } catch (EnvNotFoundException $e) { + return $this->container->getParameter($default); + } + } + if ('file' === $prefix) { if (!is_scalar($file = $getEnv($name))) { throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.', $name)); } if (!file_exists($file)) { - throw new RuntimeException(sprintf('Env "file:%s" not found: %s does not exist.', $name, $file)); + throw new EnvNotFoundException(sprintf('File "%s" not found (resolved from "%s").', $file, $name)); } return file_get_contents($file); @@ -95,7 +116,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) $env = $_SERVER[$name]; } elseif (false === ($env = getenv($name)) || null === $env) { // null is a possible value because of thread safety issues if (!$this->container->hasParameter("env($name)")) { - throw new EnvNotFoundException($name); + throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name)); } if (null === $env = $this->container->getParameter("env($name)")) { diff --git a/src/Symfony/Component/DependencyInjection/Exception/EnvNotFoundException.php b/src/Symfony/Component/DependencyInjection/Exception/EnvNotFoundException.php index 6ed18e06807f5..04ac84800abc1 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/EnvNotFoundException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/EnvNotFoundException.php @@ -18,8 +18,4 @@ */ class EnvNotFoundException extends InvalidArgumentException { - public function __construct(string $name) - { - parent::__construct(sprintf('Environment variable not found: "%s".', $name)); - } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php index 4681092ca7849..93d3c16ff94dc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php @@ -40,6 +40,7 @@ public function testSimpleProcessor() 'json' => array('array'), 'key' => array('bool', 'int', 'float', 'string', 'array'), 'resolve' => array('string'), + 'default' => array('bool', 'int', 'float', 'string', 'array'), 'string' => array('string'), ); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 941404c4107e3..4f138b9fe6b18 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -439,6 +439,28 @@ public function testDumpedCsvEnvParameters() $this->assertSame(array('foo', 'bar'), $container->getParameter('hello')); } + public function testDumpedDefaultEnvParameters() + { + $container = new ContainerBuilder(); + $container->setParameter('fallback_param', 'baz'); + $container->setParameter('fallback_env', '%env(foobar)%'); + $container->setParameter('env(foobar)', 'foobaz'); + $container->setParameter('env(foo)', '{"foo": "bar"}'); + $container->setParameter('hello', '%env(default:fallback_param:bar)%'); + $container->setParameter('hello-bar', '%env(default:fallback_env:key:baz:json:foo)%'); + $container->compile(); + + $dumper = new PhpDumper($container); + $dumper->dump(); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_default_env.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_DefaultParameters'))); + + require self::$fixturesPath.'/php/services_default_env.php'; + $container = new \Symfony_DI_PhpDumper_Test_DefaultParameters(); + $this->assertSame('baz', $container->getParameter('hello')); + $this->assertSame('foobaz', $container->getParameter('hello-bar')); + } + public function testDumpedJsonEnvParameters() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index 5cd3a68b21baa..b244537354e43 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -317,7 +317,7 @@ public function testGetEnvUnknown() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Invalid configuration: env var "key:foo" does not contain a key specifier. + * @expectedExceptionMessage Invalid env "key:foo": a key specifier should be provided. */ public function testGetEnvKeyInvalidKey() { @@ -355,7 +355,7 @@ public function noArrayValues() } /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException * @expectedExceptionMessage Key "index" not found in * @dataProvider invalidArrayValues */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php new file mode 100644 index 0000000000000..f0a82838481be --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php @@ -0,0 +1,130 @@ +parameters = $this->getDefaultParameters(); + + $this->services = $this->privates = array(); + + $this->aliases = array(); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function getParameter($name) + { + $name = (string) $name; + + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + if (isset($this->loadedDynamicParameters[$name])) { + return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + + return $this->parameters[$name]; + } + + public function hasParameter($name) + { + $name = (string) $name; + + return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); + } + + public function setParameter($name, $value) + { + throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + public function getParameterBag() + { + if (null === $this->parameterBag) { + $parameters = $this->parameters; + foreach ($this->loadedDynamicParameters as $name => $loaded) { + $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); + } + $this->parameterBag = new FrozenParameterBag($parameters); + } + + return $this->parameterBag; + } + + private $loadedDynamicParameters = array( + 'fallback_env' => false, + 'hello' => false, + 'hello-bar' => false, + ); + private $dynamicParameters = array(); + + /** + * Computes a dynamic parameter. + * + * @param string The name of the dynamic parameter to load + * + * @return mixed The value of the dynamic parameter + * + * @throws InvalidArgumentException When the dynamic parameter does not exist + */ + private function getDynamicParameter($name) + { + switch ($name) { + case 'fallback_env': $value = $this->getEnv('foobar'); break; + case 'hello': $value = $this->getEnv('default:fallback_param:bar'); break; + case 'hello-bar': $value = $this->getEnv('default:fallback_env:key:baz:json:foo'); break; + default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); + } + $this->loadedDynamicParameters[$name] = true; + + return $this->dynamicParameters[$name] = $value; + } + + /** + * Gets the default parameters. + * + * @return array An array of the default parameters + */ + protected function getDefaultParameters() + { + return array( + 'fallback_param' => 'baz', + 'env(foobar)' => 'foobaz', + 'env(foo)' => '{"foo": "bar"}', + ); + } +} From 397c19ee5fe02bd9073f87c19fa70f38cbd7cbe0 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sun, 14 Oct 2018 14:18:54 +0200 Subject: [PATCH 012/495] [DI] Deprecated using env vars with cannotBeEmpty() --- UPGRADE-4.2.md | 1 + UPGRADE-5.0.md | 1 + src/Symfony/Component/Config/CHANGELOG.md | 1 + .../Config/Definition/ScalarNode.php | 2 + .../Config/Definition/VariableNode.php | 15 +++++++ .../ValidateEnvPlaceholdersPassTest.php | 40 +++++++++++++++++++ 6 files changed, 60 insertions(+) diff --git a/UPGRADE-4.2.md b/UPGRADE-4.2.md index f04124d9bc4ce..d838b7c2b24ea 100644 --- a/UPGRADE-4.2.md +++ b/UPGRADE-4.2.md @@ -16,6 +16,7 @@ Config * Deprecated constructing a `TreeBuilder` without passing root node information. * Deprecated `FileLoaderLoadException`, use `LoaderLoadException` instead. + * Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` Console ------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 80403f038d623..81709247cae8d 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -18,6 +18,7 @@ Config * Added the `getChildNodeDefinitions()` method to `ParentNodeDefinitionInterface`. * The `Processor` class has been made final * Removed `FileLoaderLoadException`, use `LoaderLoadException` instead. + * Using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` will throw an exception. Console ------- diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index fea35f9e47be6..a2c1a2076a476 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * deprecated constructing a `TreeBuilder` without passing root node information * renamed `FileLoaderLoadException` to `LoaderLoadException` + * deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` 4.1.0 ----- diff --git a/src/Symfony/Component/Config/Definition/ScalarNode.php b/src/Symfony/Component/Config/Definition/ScalarNode.php index ee870b6a85ea9..77503bfd6e1ff 100644 --- a/src/Symfony/Component/Config/Definition/ScalarNode.php +++ b/src/Symfony/Component/Config/Definition/ScalarNode.php @@ -48,6 +48,8 @@ protected function validateType($value) */ protected function isValueEmpty($value) { + // assume environment variables are never empty (which in practice is likely to be true during runtime) + // not doing so breaks many configs that are valid today if ($this->isHandlingPlaceholder()) { return false; } diff --git a/src/Symfony/Component/Config/Definition/VariableNode.php b/src/Symfony/Component/Config/Definition/VariableNode.php index 1a3442d9613db..93576870cf3ec 100644 --- a/src/Symfony/Component/Config/Definition/VariableNode.php +++ b/src/Symfony/Component/Config/Definition/VariableNode.php @@ -81,6 +81,19 @@ protected function validateType($value) */ protected function finalizeValue($value) { + // deny environment variables only when using custom validators + // this avoids ever passing an empty value to final validation closures + if (!$this->allowEmptyValue && $this->isHandlingPlaceholder() && $this->finalValidationClosures) { + @trigger_error(sprintf('Setting path "%s" to an environment variable is deprecated since Symfony 4.2. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead.', $this->getPath()), E_USER_DEPRECATED); +// $e = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath(), json_encode($value))); +// if ($hint = $this->getInfo()) { +// $e->addHint($hint); +// } +// $e->setPath($this->getPath()); +// +// throw $e; + } + if (!$this->allowEmptyValue && $this->isValueEmpty($value)) { $ex = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value))); if ($hint = $this->getInfo()) { @@ -120,6 +133,8 @@ protected function mergeValues($leftSide, $rightSide) * @param mixed $value * * @return bool + * + * @see finalizeValue() */ protected function isValueEmpty($value) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php index 32a5bb1ab6de7..4121a84131ee3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php @@ -210,6 +210,38 @@ public function testEmptyEnvWhichCannotBeEmptyForScalarNode(): void $this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig())); } + /** + * NOT LEGACY (test exception in 5.0). + * + * @group legacy + * @expectedDeprecation Setting path "env_extension.scalar_node_not_empty_validated" to an environment variable is deprecated since Symfony 4.2. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead. + */ + public function testEmptyEnvWhichCannotBeEmptyForScalarNodeWithValidation(): void + { + $container = new ContainerBuilder(); + $container->registerExtension($ext = new EnvExtension()); + $container->prependExtensionConfig('env_extension', $expected = array( + 'scalar_node_not_empty_validated' => '%env(SOME)%', + )); + + $this->doProcess($container); + + $this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig())); + } + + public function testPartialEnvWhichCannotBeEmptyForScalarNode(): void + { + $container = new ContainerBuilder(); + $container->registerExtension($ext = new EnvExtension()); + $container->prependExtensionConfig('env_extension', $expected = array( + 'scalar_node_not_empty_validated' => 'foo %env(SOME)% bar', + )); + + $this->doProcess($container); + + $this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig())); + } + public function testEnvWithVariableNode(): void { $container = new ContainerBuilder(); @@ -281,6 +313,14 @@ public function getConfigTreeBuilder() ->children() ->scalarNode('scalar_node')->end() ->scalarNode('scalar_node_not_empty')->cannotBeEmpty()->end() + ->scalarNode('scalar_node_not_empty_validated') + ->cannotBeEmpty() + ->validate() + ->always(function ($value) { + return $value; + }) + ->end() + ->end() ->integerNode('int_node')->end() ->floatNode('float_node')->end() ->booleanNode('bool_node')->end() From ce6ecaf862465740f9d48b0f8e329083ef239656 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sat, 1 Dec 2018 10:28:10 +0100 Subject: [PATCH 013/495] Add upgrade from 4.2 to 4.3 --- UPGRADE-4.2.md | 1 - UPGRADE-4.3.md | 7 +++++++ src/Symfony/Component/Config/CHANGELOG.md | 6 +++++- src/Symfony/Component/Config/Definition/VariableNode.php | 2 +- .../Tests/Compiler/ValidateEnvPlaceholdersPassTest.php | 2 +- 5 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 UPGRADE-4.3.md diff --git a/UPGRADE-4.2.md b/UPGRADE-4.2.md index 7556a91eeda5f..8d69d2c526252 100644 --- a/UPGRADE-4.2.md +++ b/UPGRADE-4.2.md @@ -29,7 +29,6 @@ Config ``` * Deprecated `FileLoaderLoadException`, use `LoaderLoadException` instead. - * Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` Console ------- diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md new file mode 100644 index 0000000000000..c88642f610ca7 --- /dev/null +++ b/UPGRADE-4.3.md @@ -0,0 +1,7 @@ +UPGRADE FROM 4.2 to 4.3 +======================= + +Config +------ + + * Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index a2c1a2076a476..5b4f60a2722a0 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -1,12 +1,16 @@ CHANGELOG ========= +4.3.0 +----- + + * deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` + 4.2.0 ----- * deprecated constructing a `TreeBuilder` without passing root node information * renamed `FileLoaderLoadException` to `LoaderLoadException` - * deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` 4.1.0 ----- diff --git a/src/Symfony/Component/Config/Definition/VariableNode.php b/src/Symfony/Component/Config/Definition/VariableNode.php index 93576870cf3ec..0d722c6bd28a8 100644 --- a/src/Symfony/Component/Config/Definition/VariableNode.php +++ b/src/Symfony/Component/Config/Definition/VariableNode.php @@ -84,7 +84,7 @@ protected function finalizeValue($value) // deny environment variables only when using custom validators // this avoids ever passing an empty value to final validation closures if (!$this->allowEmptyValue && $this->isHandlingPlaceholder() && $this->finalValidationClosures) { - @trigger_error(sprintf('Setting path "%s" to an environment variable is deprecated since Symfony 4.2. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead.', $this->getPath()), E_USER_DEPRECATED); + @trigger_error(sprintf('Setting path "%s" to an environment variable is deprecated since Symfony 4.3. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead.', $this->getPath()), E_USER_DEPRECATED); // $e = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath(), json_encode($value))); // if ($hint = $this->getInfo()) { // $e->addHint($hint); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php index 90417f44d212e..c544015d90166 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php @@ -215,7 +215,7 @@ public function testEmptyEnvWhichCannotBeEmptyForScalarNode(): void * NOT LEGACY (test exception in 5.0). * * @group legacy - * @expectedDeprecation Setting path "env_extension.scalar_node_not_empty_validated" to an environment variable is deprecated since Symfony 4.2. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead. + * @expectedDeprecation Setting path "env_extension.scalar_node_not_empty_validated" to an environment variable is deprecated since Symfony 4.3. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead. */ public function testEmptyEnvWhichCannotBeEmptyForScalarNodeWithValidation(): void { From d6a594bf426527a61bb404fdbbf5125d9ef0c9a5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 17 Nov 2018 10:06:42 +0100 Subject: [PATCH 014/495] [EventDispatcher][VarDumper] optimize perf by leveraging Closure::fromCallable() --- .../EventDispatcher/Debug/WrappedListener.php | 6 +- .../EventDispatcher/EventDispatcher.php | 69 ++- .../Tests/AbstractEventDispatcherTest.php | 442 ----------------- .../Tests/ChildEventDispatcherTest.php | 26 + .../Tests/EventDispatcherTest.php | 451 +++++++++++++++++- .../VarDumper/Cloner/AbstractCloner.php | 5 +- 6 files changed, 535 insertions(+), 464 deletions(-) delete mode 100644 src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php create mode 100644 src/Symfony/Component/EventDispatcher/Tests/ChildEventDispatcherTest.php diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index d49f69de72502..6f89c64bdec4d 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -22,6 +22,7 @@ class WrappedListener { private $listener; + private $optimizedListener; private $name; private $called; private $stoppedPropagation; @@ -31,9 +32,10 @@ class WrappedListener private $stub; private static $hasClassStub; - public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) + public function __construct(callable $listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) { $this->listener = $listener; + $this->optimizedListener = $listener instanceof \Closure ? $listener : \Closure::fromCallable($listener); $this->stopwatch = $stopwatch; $this->dispatcher = $dispatcher; $this->called = false; @@ -108,7 +110,7 @@ public function __invoke(Event $event, $eventName, EventDispatcherInterface $dis $e = $this->stopwatch->start($this->name, 'event_listener'); - \call_user_func($this->listener, $event, $eventName, $this->dispatcher ?: $dispatcher); + \call_user_func($this->optimizedListener, $event, $eventName, $this->dispatcher ?: $dispatcher); if ($e->isStarted()) { $e->stop(); diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 4e75c63e4fafb..1d7b2322bcb1e 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -30,6 +30,14 @@ class EventDispatcher implements EventDispatcherInterface { private $listeners = array(); private $sorted = array(); + private $optimized; + + public function __construct() + { + if (__CLASS__ === \get_class($this)) { + $this->optimized = array(); + } + } /** * {@inheritdoc} @@ -40,7 +48,13 @@ public function dispatch($eventName, Event $event = null) $event = new Event(); } - if ($listeners = $this->getListeners($eventName)) { + if (null !== $this->optimized && null !== $eventName) { + $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? array() : $this->optimizeListeners($eventName)); + } else { + $listeners = $this->getListeners($eventName); + } + + if ($listeners) { $this->doDispatch($listeners, $eventName, $event); } @@ -86,11 +100,10 @@ public function getListenerPriority($eventName, $listener) $listener[0] = $listener[0](); } - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $v) { + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as &$v) { if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { $v[0] = $v[0](); - $this->listeners[$eventName][$priority][$k] = $v; } if ($v === $listener) { return $priority; @@ -123,7 +136,7 @@ public function hasListeners($eventName = null) public function addListener($eventName, $listener, $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; - unset($this->sorted[$eventName]); + unset($this->sorted[$eventName], $this->optimized[$eventName]); } /** @@ -139,21 +152,17 @@ public function removeListener($eventName, $listener) $listener[0] = $listener[0](); } - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $v) { + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as $k => &$v) { if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { $v[0] = $v[0](); } if ($v === $listener) { - unset($listeners[$k], $this->sorted[$eventName]); - } else { - $listeners[$k] = $v; + unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); } } - if ($listeners) { - $this->listeners[$eventName][$priority] = $listeners; - } else { + if (!$listeners) { unset($this->listeners[$eventName][$priority]); } } @@ -215,22 +224,46 @@ protected function doDispatch($listeners, $eventName, Event $event) /** * Sorts the internal list of listeners for the given event by priority. - * - * @param string $eventName The name of the event */ - private function sortListeners($eventName) + private function sortListeners(string $eventName) { krsort($this->listeners[$eventName]); $this->sorted[$eventName] = array(); - foreach ($this->listeners[$eventName] as $priority => $listeners) { + foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as $k => $listener) { if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { $listener[0] = $listener[0](); - $this->listeners[$eventName][$priority][$k] = $listener; } $this->sorted[$eventName][] = $listener; } } } + + /** + * Optimizes the internal list of listeners for the given event by priority. + */ + private function optimizeListeners(string $eventName): array + { + krsort($this->listeners[$eventName]); + $this->optimized[$eventName] = array(); + + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as &$listener) { + $closure = &$this->optimized[$eventName][]; + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + $closure = static function (...$args) use (&$listener, &$closure) { + if ($listener[0] instanceof \Closure) { + $listener[0] = $listener[0](); + } + ($closure = \Closure::fromCallable($listener))(...$args); + }; + } else { + $closure = $listener instanceof \Closure ? $listener : \Closure::fromCallable($listener); + } + } + } + + return $this->optimized[$eventName]; + } } diff --git a/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php deleted file mode 100644 index 6d377d11fe30f..0000000000000 --- a/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php +++ /dev/null @@ -1,442 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -abstract class AbstractEventDispatcherTest extends TestCase -{ - /* Some pseudo events */ - const preFoo = 'pre.foo'; - const postFoo = 'post.foo'; - const preBar = 'pre.bar'; - const postBar = 'post.bar'; - - /** - * @var EventDispatcher - */ - private $dispatcher; - - private $listener; - - protected function setUp() - { - $this->dispatcher = $this->createEventDispatcher(); - $this->listener = new TestEventListener(); - } - - protected function tearDown() - { - $this->dispatcher = null; - $this->listener = null; - } - - abstract protected function createEventDispatcher(); - - public function testInitialState() - { - $this->assertEquals(array(), $this->dispatcher->getListeners()); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); - } - - public function testAddListener() - { - $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); - $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); - $this->assertTrue($this->dispatcher->hasListeners()); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); - $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); - $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); - $this->assertCount(2, $this->dispatcher->getListeners()); - } - - public function testGetListenersSortsByPriority() - { - $listener1 = new TestEventListener(); - $listener2 = new TestEventListener(); - $listener3 = new TestEventListener(); - $listener1->name = '1'; - $listener2->name = '2'; - $listener3->name = '3'; - - $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); - $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); - $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); - - $expected = array( - array($listener2, 'preFoo'), - array($listener3, 'preFoo'), - array($listener1, 'preFoo'), - ); - - $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); - } - - public function testGetAllListenersSortsByPriority() - { - $listener1 = new TestEventListener(); - $listener2 = new TestEventListener(); - $listener3 = new TestEventListener(); - $listener4 = new TestEventListener(); - $listener5 = new TestEventListener(); - $listener6 = new TestEventListener(); - - $this->dispatcher->addListener('pre.foo', $listener1, -10); - $this->dispatcher->addListener('pre.foo', $listener2); - $this->dispatcher->addListener('pre.foo', $listener3, 10); - $this->dispatcher->addListener('post.foo', $listener4, -10); - $this->dispatcher->addListener('post.foo', $listener5); - $this->dispatcher->addListener('post.foo', $listener6, 10); - - $expected = array( - 'pre.foo' => array($listener3, $listener2, $listener1), - 'post.foo' => array($listener6, $listener5, $listener4), - ); - - $this->assertSame($expected, $this->dispatcher->getListeners()); - } - - public function testGetListenerPriority() - { - $listener1 = new TestEventListener(); - $listener2 = new TestEventListener(); - - $this->dispatcher->addListener('pre.foo', $listener1, -10); - $this->dispatcher->addListener('pre.foo', $listener2); - - $this->assertSame(-10, $this->dispatcher->getListenerPriority('pre.foo', $listener1)); - $this->assertSame(0, $this->dispatcher->getListenerPriority('pre.foo', $listener2)); - $this->assertNull($this->dispatcher->getListenerPriority('pre.bar', $listener2)); - $this->assertNull($this->dispatcher->getListenerPriority('pre.foo', function () {})); - } - - public function testDispatch() - { - $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); - $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); - $this->dispatcher->dispatch(self::preFoo); - $this->assertTrue($this->listener->preFooInvoked); - $this->assertFalse($this->listener->postFooInvoked); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); - $event = new Event(); - $return = $this->dispatcher->dispatch(self::preFoo, $event); - $this->assertSame($event, $return); - } - - public function testDispatchForClosure() - { - $invoked = 0; - $listener = function () use (&$invoked) { - ++$invoked; - }; - $this->dispatcher->addListener('pre.foo', $listener); - $this->dispatcher->addListener('post.foo', $listener); - $this->dispatcher->dispatch(self::preFoo); - $this->assertEquals(1, $invoked); - } - - public function testStopEventPropagation() - { - $otherListener = new TestEventListener(); - - // postFoo() stops the propagation, so only one listener should - // be executed - // Manually set priority to enforce $this->listener to be called first - $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); - $this->dispatcher->addListener('post.foo', array($otherListener, 'postFoo')); - $this->dispatcher->dispatch(self::postFoo); - $this->assertTrue($this->listener->postFooInvoked); - $this->assertFalse($otherListener->postFooInvoked); - } - - public function testDispatchByPriority() - { - $invoked = array(); - $listener1 = function () use (&$invoked) { - $invoked[] = '1'; - }; - $listener2 = function () use (&$invoked) { - $invoked[] = '2'; - }; - $listener3 = function () use (&$invoked) { - $invoked[] = '3'; - }; - $this->dispatcher->addListener('pre.foo', $listener1, -10); - $this->dispatcher->addListener('pre.foo', $listener2); - $this->dispatcher->addListener('pre.foo', $listener3, 10); - $this->dispatcher->dispatch(self::preFoo); - $this->assertEquals(array('3', '2', '1'), $invoked); - } - - public function testRemoveListener() - { - $this->dispatcher->addListener('pre.bar', $this->listener); - $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); - $this->dispatcher->removeListener('pre.bar', $this->listener); - $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); - $this->dispatcher->removeListener('notExists', $this->listener); - } - - public function testAddSubscriber() - { - $eventSubscriber = new TestEventSubscriber(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); - } - - public function testAddSubscriberWithPriorities() - { - $eventSubscriber = new TestEventSubscriber(); - $this->dispatcher->addSubscriber($eventSubscriber); - - $eventSubscriber = new TestEventSubscriberWithPriorities(); - $this->dispatcher->addSubscriber($eventSubscriber); - - $listeners = $this->dispatcher->getListeners('pre.foo'); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertCount(2, $listeners); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); - } - - public function testAddSubscriberWithMultipleListeners() - { - $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); - $this->dispatcher->addSubscriber($eventSubscriber); - - $listeners = $this->dispatcher->getListeners('pre.foo'); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertCount(2, $listeners); - $this->assertEquals('preFoo2', $listeners[0][1]); - } - - public function testRemoveSubscriber() - { - $eventSubscriber = new TestEventSubscriber(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); - $this->dispatcher->removeSubscriber($eventSubscriber); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); - } - - public function testRemoveSubscriberWithPriorities() - { - $eventSubscriber = new TestEventSubscriberWithPriorities(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->dispatcher->removeSubscriber($eventSubscriber); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - } - - public function testRemoveSubscriberWithMultipleListeners() - { - $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); - $this->dispatcher->removeSubscriber($eventSubscriber); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - } - - public function testEventReceivesTheDispatcherInstanceAsArgument() - { - $listener = new TestWithDispatcher(); - $this->dispatcher->addListener('test', array($listener, 'foo')); - $this->assertNull($listener->name); - $this->assertNull($listener->dispatcher); - $this->dispatcher->dispatch('test'); - $this->assertEquals('test', $listener->name); - $this->assertSame($this->dispatcher, $listener->dispatcher); - } - - /** - * @see https://bugs.php.net/bug.php?id=62976 - * - * This bug affects: - * - The PHP 5.3 branch for versions < 5.3.18 - * - The PHP 5.4 branch for versions < 5.4.8 - * - The PHP 5.5 branch is not affected - */ - public function testWorkaroundForPhpBug62976() - { - $dispatcher = $this->createEventDispatcher(); - $dispatcher->addListener('bug.62976', new CallableClass()); - $dispatcher->removeListener('bug.62976', function () {}); - $this->assertTrue($dispatcher->hasListeners('bug.62976')); - } - - public function testHasListenersWhenAddedCallbackListenerIsRemoved() - { - $listener = function () {}; - $this->dispatcher->addListener('foo', $listener); - $this->dispatcher->removeListener('foo', $listener); - $this->assertFalse($this->dispatcher->hasListeners()); - } - - public function testGetListenersWhenAddedCallbackListenerIsRemoved() - { - $listener = function () {}; - $this->dispatcher->addListener('foo', $listener); - $this->dispatcher->removeListener('foo', $listener); - $this->assertSame(array(), $this->dispatcher->getListeners()); - } - - public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() - { - $this->assertFalse($this->dispatcher->hasListeners('foo')); - $this->assertFalse($this->dispatcher->hasListeners()); - } - - public function testHasListenersIsLazy() - { - $called = 0; - $listener = array(function () use (&$called) { ++$called; }, 'onFoo'); - $this->dispatcher->addListener('foo', $listener); - $this->assertTrue($this->dispatcher->hasListeners()); - $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->assertSame(0, $called); - } - - public function testDispatchLazyListener() - { - $called = 0; - $factory = function () use (&$called) { - ++$called; - - return new TestWithDispatcher(); - }; - $this->dispatcher->addListener('foo', array($factory, 'foo')); - $this->assertSame(0, $called); - $this->dispatcher->dispatch('foo', new Event()); - $this->dispatcher->dispatch('foo', new Event()); - $this->assertSame(1, $called); - } - - public function testRemoveFindsLazyListeners() - { - $test = new TestWithDispatcher(); - $factory = function () use ($test) { return $test; }; - - $this->dispatcher->addListener('foo', array($factory, 'foo')); - $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->dispatcher->removeListener('foo', array($test, 'foo')); - $this->assertFalse($this->dispatcher->hasListeners('foo')); - - $this->dispatcher->addListener('foo', array($test, 'foo')); - $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->dispatcher->removeListener('foo', array($factory, 'foo')); - $this->assertFalse($this->dispatcher->hasListeners('foo')); - } - - public function testPriorityFindsLazyListeners() - { - $test = new TestWithDispatcher(); - $factory = function () use ($test) { return $test; }; - - $this->dispatcher->addListener('foo', array($factory, 'foo'), 3); - $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', array($test, 'foo'))); - $this->dispatcher->removeListener('foo', array($factory, 'foo')); - - $this->dispatcher->addListener('foo', array($test, 'foo'), 5); - $this->assertSame(5, $this->dispatcher->getListenerPriority('foo', array($factory, 'foo'))); - } - - public function testGetLazyListeners() - { - $test = new TestWithDispatcher(); - $factory = function () use ($test) { return $test; }; - - $this->dispatcher->addListener('foo', array($factory, 'foo'), 3); - $this->assertSame(array(array($test, 'foo')), $this->dispatcher->getListeners('foo')); - - $this->dispatcher->removeListener('foo', array($test, 'foo')); - $this->dispatcher->addListener('bar', array($factory, 'foo'), 3); - $this->assertSame(array('bar' => array(array($test, 'foo'))), $this->dispatcher->getListeners()); - } -} - -class CallableClass -{ - public function __invoke() - { - } -} - -class TestEventListener -{ - public $preFooInvoked = false; - public $postFooInvoked = false; - - /* Listener methods */ - - public function preFoo(Event $e) - { - $this->preFooInvoked = true; - } - - public function postFoo(Event $e) - { - $this->postFooInvoked = true; - - $e->stopPropagation(); - } -} - -class TestWithDispatcher -{ - public $name; - public $dispatcher; - - public function foo(Event $e, $name, $dispatcher) - { - $this->name = $name; - $this->dispatcher = $dispatcher; - } -} - -class TestEventSubscriber implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); - } -} - -class TestEventSubscriberWithPriorities implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return array( - 'pre.foo' => array('preFoo', 10), - 'post.foo' => array('postFoo'), - ); - } -} - -class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return array('pre.foo' => array( - array('preFoo1'), - array('preFoo2', 10), - )); - } -} diff --git a/src/Symfony/Component/EventDispatcher/Tests/ChildEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/ChildEventDispatcherTest.php new file mode 100644 index 0000000000000..442b88fbb39e1 --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/Tests/ChildEventDispatcherTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\Tests; + +use Symfony\Component\EventDispatcher\EventDispatcher; + +class ChildEventDispatcherTest extends EventDispatcherTest +{ + protected function createEventDispatcher() + { + return new ChildEventDispatcher(); + } +} + +class ChildEventDispatcher extends EventDispatcher +{ +} diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index 5faa5c8be876a..4a533dfa56664 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -11,12 +11,461 @@ namespace Symfony\Component\EventDispatcher\Tests; +use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class EventDispatcherTest extends AbstractEventDispatcherTest +class EventDispatcherTest extends TestCase { + /* Some pseudo events */ + const preFoo = 'pre.foo'; + const postFoo = 'post.foo'; + const preBar = 'pre.bar'; + const postBar = 'post.bar'; + + /** + * @var EventDispatcher + */ + private $dispatcher; + + private $listener; + + protected function setUp() + { + $this->dispatcher = $this->createEventDispatcher(); + $this->listener = new TestEventListener(); + } + + protected function tearDown() + { + $this->dispatcher = null; + $this->listener = null; + } + protected function createEventDispatcher() { return new EventDispatcher(); } + + public function testInitialState() + { + $this->assertEquals(array(), $this->dispatcher->getListeners()); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testAddListener() + { + $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->assertTrue($this->dispatcher->hasListeners()); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); + $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); + $this->assertCount(2, $this->dispatcher->getListeners()); + } + + public function testGetListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener1->name = '1'; + $listener2->name = '2'; + $listener3->name = '3'; + + $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); + $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); + $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); + + $expected = array( + array($listener2, 'preFoo'), + array($listener3, 'preFoo'), + array($listener1, 'preFoo'), + ); + + $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); + } + + public function testGetAllListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener4 = new TestEventListener(); + $listener5 = new TestEventListener(); + $listener6 = new TestEventListener(); + + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + $this->dispatcher->addListener('pre.foo', $listener3, 10); + $this->dispatcher->addListener('post.foo', $listener4, -10); + $this->dispatcher->addListener('post.foo', $listener5); + $this->dispatcher->addListener('post.foo', $listener6, 10); + + $expected = array( + 'pre.foo' => array($listener3, $listener2, $listener1), + 'post.foo' => array($listener6, $listener5, $listener4), + ); + + $this->assertSame($expected, $this->dispatcher->getListeners()); + } + + public function testGetListenerPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + + $this->assertSame(-10, $this->dispatcher->getListenerPriority('pre.foo', $listener1)); + $this->assertSame(0, $this->dispatcher->getListenerPriority('pre.foo', $listener2)); + $this->assertNull($this->dispatcher->getListenerPriority('pre.bar', $listener2)); + $this->assertNull($this->dispatcher->getListenerPriority('pre.foo', function () {})); + } + + public function testDispatch() + { + $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->dispatcher->dispatch(self::preFoo); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); + $event = new Event(); + $return = $this->dispatcher->dispatch(self::preFoo, $event); + $this->assertSame($event, $return); + } + + public function testDispatchForClosure() + { + $invoked = 0; + $listener = function () use (&$invoked) { + ++$invoked; + }; + $this->dispatcher->addListener('pre.foo', $listener); + $this->dispatcher->addListener('post.foo', $listener); + $this->dispatcher->dispatch(self::preFoo); + $this->assertEquals(1, $invoked); + } + + public function testStopEventPropagation() + { + $otherListener = new TestEventListener(); + + // postFoo() stops the propagation, so only one listener should + // be executed + // Manually set priority to enforce $this->listener to be called first + $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); + $this->dispatcher->addListener('post.foo', array($otherListener, 'postFoo')); + $this->dispatcher->dispatch(self::postFoo); + $this->assertTrue($this->listener->postFooInvoked); + $this->assertFalse($otherListener->postFooInvoked); + } + + public function testDispatchByPriority() + { + $invoked = array(); + $listener1 = function () use (&$invoked) { + $invoked[] = '1'; + }; + $listener2 = function () use (&$invoked) { + $invoked[] = '2'; + }; + $listener3 = function () use (&$invoked) { + $invoked[] = '3'; + }; + $this->dispatcher->addListener('pre.foo', $listener1, -10); + $this->dispatcher->addListener('pre.foo', $listener2); + $this->dispatcher->addListener('pre.foo', $listener3, 10); + $this->dispatcher->dispatch(self::preFoo); + $this->assertEquals(array('3', '2', '1'), $invoked); + } + + public function testRemoveListener() + { + $this->dispatcher->addListener('pre.bar', $this->listener); + $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); + $this->dispatcher->removeListener('pre.bar', $this->listener); + $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); + $this->dispatcher->removeListener('notExists', $this->listener); + } + + public function testAddSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testAddSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $listeners = $this->dispatcher->getListeners('pre.foo'); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); + } + + public function testAddSubscriberWithMultipleListeners() + { + $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); + $this->dispatcher->addSubscriber($eventSubscriber); + + $listeners = $this->dispatcher->getListeners('pre.foo'); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertEquals('preFoo2', $listeners[0][1]); + } + + public function testRemoveSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); + } + + public function testRemoveSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + } + + public function testRemoveSubscriberWithMultipleListeners() + { + $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); + $this->dispatcher->addSubscriber($eventSubscriber); + $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); + $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); + $this->dispatcher->removeSubscriber($eventSubscriber); + $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); + } + + public function testEventReceivesTheDispatcherInstanceAsArgument() + { + $listener = new TestWithDispatcher(); + $this->dispatcher->addListener('test', array($listener, 'foo')); + $this->assertNull($listener->name); + $this->assertNull($listener->dispatcher); + $this->dispatcher->dispatch('test'); + $this->assertEquals('test', $listener->name); + $this->assertSame($this->dispatcher, $listener->dispatcher); + } + + /** + * @see https://bugs.php.net/bug.php?id=62976 + * + * This bug affects: + * - The PHP 5.3 branch for versions < 5.3.18 + * - The PHP 5.4 branch for versions < 5.4.8 + * - The PHP 5.5 branch is not affected + */ + public function testWorkaroundForPhpBug62976() + { + $dispatcher = $this->createEventDispatcher(); + $dispatcher->addListener('bug.62976', new CallableClass()); + $dispatcher->removeListener('bug.62976', function () {}); + $this->assertTrue($dispatcher->hasListeners('bug.62976')); + } + + public function testHasListenersWhenAddedCallbackListenerIsRemoved() + { + $listener = function () {}; + $this->dispatcher->addListener('foo', $listener); + $this->dispatcher->removeListener('foo', $listener); + $this->assertFalse($this->dispatcher->hasListeners()); + } + + public function testGetListenersWhenAddedCallbackListenerIsRemoved() + { + $listener = function () {}; + $this->dispatcher->addListener('foo', $listener); + $this->dispatcher->removeListener('foo', $listener); + $this->assertSame(array(), $this->dispatcher->getListeners()); + } + + public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() + { + $this->assertFalse($this->dispatcher->hasListeners('foo')); + $this->assertFalse($this->dispatcher->hasListeners()); + } + + public function testHasListenersIsLazy() + { + $called = 0; + $listener = array(function () use (&$called) { ++$called; }, 'onFoo'); + $this->dispatcher->addListener('foo', $listener); + $this->assertTrue($this->dispatcher->hasListeners()); + $this->assertTrue($this->dispatcher->hasListeners('foo')); + $this->assertSame(0, $called); + } + + public function testDispatchLazyListener() + { + $called = 0; + $factory = function () use (&$called) { + ++$called; + + return new TestWithDispatcher(); + }; + $this->dispatcher->addListener('foo', array($factory, 'foo')); + $this->assertSame(0, $called); + $this->dispatcher->dispatch('foo', new Event()); + $this->dispatcher->dispatch('foo', new Event()); + $this->assertSame(1, $called); + } + + public function testRemoveFindsLazyListeners() + { + $test = new TestWithDispatcher(); + $factory = function () use ($test) { return $test; }; + + $this->dispatcher->addListener('foo', array($factory, 'foo')); + $this->assertTrue($this->dispatcher->hasListeners('foo')); + $this->dispatcher->removeListener('foo', array($test, 'foo')); + $this->assertFalse($this->dispatcher->hasListeners('foo')); + + $this->dispatcher->addListener('foo', array($test, 'foo')); + $this->assertTrue($this->dispatcher->hasListeners('foo')); + $this->dispatcher->removeListener('foo', array($factory, 'foo')); + $this->assertFalse($this->dispatcher->hasListeners('foo')); + } + + public function testPriorityFindsLazyListeners() + { + $test = new TestWithDispatcher(); + $factory = function () use ($test) { return $test; }; + + $this->dispatcher->addListener('foo', array($factory, 'foo'), 3); + $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', array($test, 'foo'))); + $this->dispatcher->removeListener('foo', array($factory, 'foo')); + + $this->dispatcher->addListener('foo', array($test, 'foo'), 5); + $this->assertSame(5, $this->dispatcher->getListenerPriority('foo', array($factory, 'foo'))); + } + + public function testGetLazyListeners() + { + $test = new TestWithDispatcher(); + $factory = function () use ($test) { return $test; }; + + $this->dispatcher->addListener('foo', array($factory, 'foo'), 3); + $this->assertSame(array(array($test, 'foo')), $this->dispatcher->getListeners('foo')); + + $this->dispatcher->removeListener('foo', array($test, 'foo')); + $this->dispatcher->addListener('bar', array($factory, 'foo'), 3); + $this->assertSame(array('bar' => array(array($test, 'foo'))), $this->dispatcher->getListeners()); + } + + public function testMutatingWhilePropagationIsStopped() + { + $testLoaded = false; + $test = new TestEventListener(); + $this->dispatcher->addListener('foo', array($test, 'postFoo')); + $this->dispatcher->addListener('foo', array(function () use ($test, &$testLoaded) { + $testLoaded = true; + + return $test; + }, 'preFoo')); + + $this->dispatcher->dispatch('foo'); + + $this->assertTrue($test->postFooInvoked); + $this->assertFalse($test->preFooInvoked); + + $this->assertsame(0, $this->dispatcher->getListenerPriority('foo', array($test, 'preFoo'))); + + $test->preFoo(new Event()); + $this->dispatcher->dispatch('foo'); + + $this->assertTrue($testLoaded); + } +} + +class CallableClass +{ + public function __invoke() + { + } +} + +class TestEventListener +{ + public $preFooInvoked = false; + public $postFooInvoked = false; + + /* Listener methods */ + + public function preFoo(Event $e) + { + $this->preFooInvoked = true; + } + + public function postFoo(Event $e) + { + $this->postFooInvoked = true; + + if (!$this->preFooInvoked) { + $e->stopPropagation(); + } + } +} + +class TestWithDispatcher +{ + public $name; + public $dispatcher; + + public function foo(Event $e, $name, $dispatcher) + { + $this->name = $name; + $this->dispatcher = $dispatcher; + } +} + +class TestEventSubscriber implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); + } +} + +class TestEventSubscriberWithPriorities implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array( + 'pre.foo' => array('preFoo', 10), + 'post.foo' => array('postFoo'), + ); + } +} + +class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface +{ + public static function getSubscribedEvents() + { + return array('pre.foo' => array( + array('preFoo1'), + array('preFoo2', 10), + )); + } } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 38891f1d80e57..00519ab4ac616 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -176,7 +176,10 @@ public function __construct(array $casters = null) public function addCasters(array $casters) { foreach ($casters as $type => $callback) { - $this->casters[strtolower($type)][] = \is_string($callback) && false !== strpos($callback, '::') ? explode('::', $callback, 2) : $callback; + $closure = &$this->casters[strtolower($type)][]; + $closure = $callback instanceof \Closure ? $callback : static function (...$args) use ($callback, &$closure) { + return ($closure = \Closure::fromCallable($callback))(...$args); + }; } } From d63b3e3ee022109c573bc202c6767ec3c8e9a583 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 1 Dec 2018 10:47:14 +0100 Subject: [PATCH 015/495] fix merge --- .../Tests/Fixtures/php/services_default_env.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php index f0a82838481be..c9bdb62d75f14 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_default_env.php @@ -95,7 +95,7 @@ public function getParameterBag() /** * Computes a dynamic parameter. * - * @param string The name of the dynamic parameter to load + * @param string $name The name of the dynamic parameter to load * * @return mixed The value of the dynamic parameter * From e0d95029c3452a7f7e28081d7885e7b4a25a34d7 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sat, 1 Dec 2018 11:11:46 +0100 Subject: [PATCH 016/495] [DI] Fix deps=low --- src/Symfony/Component/DependencyInjection/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index 164b3594c7fbe..4acf55465075f 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -22,7 +22,7 @@ }, "require-dev": { "symfony/yaml": "~3.4|~4.0", - "symfony/config": "~4.2", + "symfony/config": "^4.3", "symfony/expression-language": "~3.4|~4.0" }, "suggest": { @@ -33,7 +33,7 @@ "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them" }, "conflict": { - "symfony/config": "<4.2", + "symfony/config": "<4.3", "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" From 11e0df4f55ce19d64c232cb6b60955eff375524c Mon Sep 17 00:00:00 2001 From: Raul Fraile Date: Sat, 8 Dec 2018 10:21:14 +0100 Subject: [PATCH 017/495] [Validator] Add tests in regex validator for objects with __toString method --- .../Tests/Constraints/RegexValidatorTest.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php index 777fa26693f56..1587392b608e4 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php @@ -62,6 +62,12 @@ public function getValidValues() array('0'), array('090909'), array(90909), + array(new class() { + public function __toString() + { + return '090909'; + } + }), ); } @@ -88,6 +94,12 @@ public function getInvalidValues() return array( array('abcd'), array('090foo'), + array(new class() { + public function __toString() + { + return 'abcd'; + } + }), ); } } From 30609bfa70504ea7fc12e3367b8ccdaabb49b715 Mon Sep 17 00:00:00 2001 From: Vlad Gregurco Date: Wed, 5 Dec 2018 10:02:19 +0200 Subject: [PATCH 018/495] [PhpUnitBridge] install PHPUnit 7 on PHP 7.1 and fix require for PHPUnit 6 --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index c94fa31abd937..6ccd5d33ceb9b 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -45,14 +45,16 @@ $getEnvVar = function ($name, $default = false) { return $default; }; -if (PHP_VERSION_ID >= 70200) { - // PHPUnit 6 is required for PHP 7.2+ +if (PHP_VERSION_ID >= 70100) { + // PHPUnit 7 requires PHP 7.1+ + $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '7.4'); +} elseif (PHP_VERSION_ID >= 70000) { + // PHPUnit 6 requires PHP 7.0+ $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '6.5'); } elseif (PHP_VERSION_ID >= 50600) { - // PHPUnit 4 does not support PHP 7 + // PHPUnit 5 requires PHP 5.6+ $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '5.7'); } else { - // PHPUnit 5.1 requires PHP 5.6+ $PHPUNIT_VERSION = '4.8'; } From a28e3b61f61c4c0bb9a2c8fd765ce2898104eb48 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Tue, 4 Dec 2018 11:46:34 +0100 Subject: [PATCH 019/495] [Form] Shortcut debug:form for partial type name --- src/Symfony/Component/Form/Command/DebugCommand.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Symfony/Component/Form/Command/DebugCommand.php b/src/Symfony/Component/Form/Command/DebugCommand.php index 6daaf793b7e1f..87924092ed803 100644 --- a/src/Symfony/Component/Form/Command/DebugCommand.php +++ b/src/Symfony/Component/Form/Command/DebugCommand.php @@ -158,6 +158,12 @@ private function getFqcnTypeClass(InputInterface $input, SymfonyStyle $io, $shor foreach ($this->namespaces as $namespace) { if (class_exists($fqcn = $namespace.'\\'.$shortClassName)) { $classes[] = $fqcn; + } elseif (class_exists($fqcn = $namespace.'\\'.ucfirst($shortClassName))) { + $classes[] = $fqcn; + } elseif (class_exists($fqcn = $namespace.'\\'.ucfirst($shortClassName).'Type')) { + $classes[] = $fqcn; + } elseif ('type' === substr($shortClassName, -4) && class_exists($fqcn = $namespace.'\\'.ucfirst(substr($shortClassName, 0, -4).'Type'))) { + $classes[] = $fqcn; } } From 97e15fe1b514e4aca130f68f48b75b31a22395aa Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 9 Dec 2018 20:16:27 +0100 Subject: [PATCH 020/495] [FrameworkBundle] Stop calling Kernel::boot() twice in cli --- src/Symfony/Bundle/FrameworkBundle/Console/Application.php | 6 ++---- .../FrameworkBundle/Tests/Console/ApplicationTest.php | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php index 04258131b539a..51cc1940b3a6a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php @@ -62,16 +62,14 @@ public function getKernel() */ public function doRun(InputInterface $input, OutputInterface $output) { - $this->kernel->boot(); - - $this->setDispatcher($this->kernel->getContainer()->get('event_dispatcher')); - $this->registerCommands(); if ($this->registrationErrors) { $this->renderRegistrationErrors($input, $output); } + $this->setDispatcher($this->kernel->getContainer()->get('event_dispatcher')); + return parent::doRun($input, $output); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php index 6ac413a226fd3..fe171ed6238c0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php @@ -204,6 +204,7 @@ public function testRunOnlyWarnsOnUnregistrableCommandAtTheEnd() $container->setParameter('console.command.ids', array(ThrowingCommand::class => ThrowingCommand::class)); $kernel = $this->getMockBuilder(KernelInterface::class)->getMock(); + $kernel->expects($this->once())->method('boot'); $kernel ->method('getBundles') ->willReturn(array($this->createBundleMock( @@ -256,6 +257,7 @@ private function getKernel(array $bundles, $useDispatcher = false) ; $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock(); + $kernel->expects($this->once())->method('boot'); $kernel ->expects($this->any()) ->method('getBundles') From db750ed8ae80de9417e7964c532ab4bc44b4f9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Sat, 10 Nov 2018 20:58:44 +0100 Subject: [PATCH 021/495] [Console] Add hyperlinks support --- src/Symfony/Component/Console/CHANGELOG.md | 5 ++ .../Console/Formatter/OutputFormatter.php | 4 +- .../Formatter/OutputFormatterStyle.php | 19 +++++-- .../Tests/Formatter/OutputFormatterTest.php | 51 +++++++------------ 4 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index b9175109c434a..017decf63b98f 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added support for hyperlinks + 4.2.0 ----- diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index fd3bbd12d30be..600cf76f50180 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -141,7 +141,7 @@ public function formatAndWrap(string $message, int $width) { $offset = 0; $output = ''; - $tagRegex = '[a-z][a-z0-9,_=;-]*+'; + $tagRegex = '[a-z][^<>]*+'; $currentLineLength = 0; preg_match_all("#<(($tagRegex) | /($tagRegex)?)>#ix", $message, $matches, PREG_OFFSET_CAPTURE); foreach ($matches[0] as $i => $match) { @@ -215,6 +215,8 @@ private function createStyleFromString(string $string) $style->setForeground($match[1]); } elseif ('bg' == $match[0]) { $style->setBackground($match[1]); + } elseif ('href' === $match[0]) { + $style->setHref($match[1]); } elseif ('options' === $match[0]) { preg_match_all('([^,;]+)', $match[1], $options); $options = array_shift($options); diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php index 906021f6f94ab..445de6a200b7e 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php @@ -52,6 +52,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface private $foreground; private $background; + private $href; private $options = array(); /** @@ -118,6 +119,11 @@ public function setBackground($color = null) $this->background = static::$availableBackgroundColors[$color]; } + public function setHref(string $url): void + { + $this->href = $url; + } + /** * Sets some specific style option. * @@ -187,11 +193,14 @@ public function apply($text) $setCodes[] = $this->background['set']; $unsetCodes[] = $this->background['unset']; } - if (\count($this->options)) { - foreach ($this->options as $option) { - $setCodes[] = $option['set']; - $unsetCodes[] = $option['unset']; - } + + foreach ($this->options as $option) { + $setCodes[] = $option['set']; + $unsetCodes[] = $option['unset']; + } + + if (null !== $this->href) { + $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\"; } if (0 === \count($setCodes)) { diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index b51668cfa7e20..2639b94043c97 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -228,7 +228,7 @@ public function testFormatToStringObject() ); } - public function testNotDecoratedFormatter() + public function testFormatterHasStyles() { $formatter = new OutputFormatter(false); @@ -236,39 +236,26 @@ public function testNotDecoratedFormatter() $this->assertTrue($formatter->hasStyle('info')); $this->assertTrue($formatter->hasStyle('comment')); $this->assertTrue($formatter->hasStyle('question')); + } - $this->assertEquals( - 'some error', $formatter->format('some error') - ); - $this->assertEquals( - 'some info', $formatter->format('some info') - ); - $this->assertEquals( - 'some comment', $formatter->format('some comment') - ); - $this->assertEquals( - 'some question', $formatter->format('some question') - ); - $this->assertEquals( - 'some text with inline style', $formatter->format('some text with inline style') - ); - - $formatter->setDecorated(true); + /** + * @dataProvider provideDecoratedAndNonDecoratedOutput + */ + public function testNotDecoratedFormatter(string $input, string $expectedNonDecoratedOutput, string $expectedDecoratedOutput) + { + $this->assertEquals($expectedDecoratedOutput, (new OutputFormatter(true))->format($input)); + $this->assertEquals($expectedNonDecoratedOutput, (new OutputFormatter(false))->format($input)); + } - $this->assertEquals( - "\033[37;41msome error\033[39;49m", $formatter->format('some error') - ); - $this->assertEquals( - "\033[32msome info\033[39m", $formatter->format('some info') - ); - $this->assertEquals( - "\033[33msome comment\033[39m", $formatter->format('some comment') - ); - $this->assertEquals( - "\033[30;46msome question\033[39;49m", $formatter->format('some question') - ); - $this->assertEquals( - "\033[31msome text with inline style\033[39m", $formatter->format('some text with inline style') + public function provideDecoratedAndNonDecoratedOutput() + { + return array( + array('some error', 'some error', "\033[37;41msome error\033[39;49m"), + array('some info', 'some info', "\033[32msome info\033[39m"), + array('some comment', 'some comment', "\033[33msome comment\033[39m"), + array('some question', 'some question', "\033[30;46msome question\033[39;49m"), + array('some text with inline style', 'some text with inline style', "\033[31msome text with inline style\033[39m"), + array('some URL', 'some URL', "\033]8;;idea://open/?file=/path/somefile.php&line=12\033\\some URL\033]8;;\033\\"), ); } From 2446a1763d75e8c26058caa7cbad1340fd698533 Mon Sep 17 00:00:00 2001 From: Raul Fraile Date: Fri, 7 Dec 2018 19:30:58 +0100 Subject: [PATCH 022/495] [Validator] Add support for UATP card validation --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Component/Validator/Constraints/CardSchemeValidator.php | 4 ++++ .../Validator/Tests/Constraints/CardSchemeValidatorTest.php | 2 ++ 3 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index e2dfc921e40b7..45e00e00a90cf 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * added options `iban` and `ibanPropertyPath` to Bic constraint + * added UATP cards support to `CardSchemeValidator` 4.2.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index dae3412cd7178..0a3c06c1454bc 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -78,6 +78,10 @@ class CardSchemeValidator extends ConstraintValidator '/^5[1-5][0-9]{14}$/', '/^2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12})$/', ), + // All UATP card numbers start with a 1 and have a length of 15 digits. + 'UATP' => array( + '/^1[0-9]{14}$/', + ), // All Visa card numbers start with a 4 and have a length of 13, 16, or 19 digits. 'VISA' => array( '/^4([0-9]{12}|[0-9]{15}|[0-9]{18})$/', diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index b0280713d5285..fccee9e0abc1a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -103,6 +103,7 @@ public function getValidNumbers() array('MASTERCARD', '2699999999999999'), array('MASTERCARD', '2709999999999999'), array('MASTERCARD', '2720995105105100'), + array('UATP', '110165309696173'), array('VISA', '4111111111111111'), array('VISA', '4012888888881881'), array('VISA', '4222222222222'), @@ -133,6 +134,7 @@ public function getInvalidNumbers() array('DISCOVER', '1117', CardScheme::INVALID_FORMAT_ERROR), // only last 4 digits array('MASTERCARD', '2721001234567890', CardScheme::INVALID_FORMAT_ERROR), // Not assigned yet array('MASTERCARD', '2220991234567890', CardScheme::INVALID_FORMAT_ERROR), // Not assigned yet + array('UATP', '11016530969617', CardScheme::INVALID_FORMAT_ERROR), // invalid length ); } } From 62caec1a7947b64059d9e21685afc534835fed25 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sat, 20 Oct 2018 12:45:50 +0200 Subject: [PATCH 023/495] [PhpUnitBridge] Added ClassExistsMock --- src/Symfony/Bridge/PhpUnit/CHANGELOG.md | 5 + .../Bridge/PhpUnit/ClassExistsMock.php | 75 +++++++++++ .../PhpUnit/Tests/ClassExistsMockTest.php | 119 ++++++++++++++++++ 3 files changed, 199 insertions(+) create mode 100644 src/Symfony/Bridge/PhpUnit/ClassExistsMock.php create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/ClassExistsMockTest.php diff --git a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md index 9c5ef00f1992a..888f03d5a8117 100644 --- a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md +++ b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added `ClassExistsMock` + 4.1.0 ----- diff --git a/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php b/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php new file mode 100644 index 0000000000000..23869c033d7da --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit; + +/** + * @author Roland Franssen + */ +class ClassExistsMock +{ + private static $classes = array(); + + /** + * Configures the classes to be checked upon existence. + * + * @param array $classes Mocked class names as keys (case sensitive, without leading root namespace slash) and booleans as values + */ + public static function withMockedClasses(array $classes) + { + self::$classes = $classes; + } + + public static function class_exists($name, $autoload = true) + { + return (bool) (self::$classes[ltrim($name, '\\')] ?? \class_exists($name, $autoload)); + } + + public static function interface_exists($name, $autoload = true) + { + return (bool) (self::$classes[ltrim($name, '\\')] ?? \interface_exists($name, $autoload)); + } + + public static function trait_exists($name, $autoload = true) + { + return (bool) (self::$classes[ltrim($name, '\\')] ?? \trait_exists($name, $autoload)); + } + + public static function register($class) + { + $self = \get_called_class(); + + $mockedNs = array(substr($class, 0, strrpos($class, '\\'))); + if (0 < strpos($class, '\\Tests\\')) { + $ns = str_replace('\\Tests\\', '\\', $class); + $mockedNs[] = substr($ns, 0, strrpos($ns, '\\')); + } elseif (0 === strpos($class, 'Tests\\')) { + $mockedNs[] = substr($class, 6, strrpos($class, '\\') - 6); + } + foreach ($mockedNs as $ns) { + foreach (array('class', 'interface', 'trait') as $type) { + if (\function_exists($ns.'\\'.$type.'_exists')) { + continue; + } + eval(<< + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ClassExistsMock; + +class ClassExistsMockTest extends TestCase +{ + public static function setUpBeforeClass() + { + ClassExistsMock::register(__CLASS__); + } + + protected function setUp() + { + ClassExistsMock::withMockedClasses(array( + ExistingClass::class => false, + 'NonExistingClass' => true, + ExistingInterface::class => false, + 'NonExistingInterface' => true, + ExistingTrait::class => false, + 'NonExistingTrait' => true, + )); + } + + public function testClassExists() + { + $this->assertFalse(class_exists(ExistingClass::class)); + $this->assertFalse(class_exists(ExistingClass::class, false)); + $this->assertFalse(class_exists('\\'.ExistingClass::class)); + $this->assertFalse(class_exists('\\'.ExistingClass::class, false)); + $this->assertTrue(class_exists('NonExistingClass')); + $this->assertTrue(class_exists('NonExistingClass', false)); + $this->assertTrue(class_exists('\\NonExistingClass')); + $this->assertTrue(class_exists('\\NonExistingClass', false)); + $this->assertTrue(class_exists(ExistingClassReal::class)); + $this->assertTrue(class_exists(ExistingClassReal::class, false)); + $this->assertTrue(class_exists('\\'.ExistingClassReal::class)); + $this->assertTrue(class_exists('\\'.ExistingClassReal::class, false)); + $this->assertFalse(class_exists('NonExistingClassReal')); + $this->assertFalse(class_exists('NonExistingClassReal', false)); + $this->assertFalse(class_exists('\\NonExistingClassReal')); + $this->assertFalse(class_exists('\\NonExistingClassReal', false)); + } + + public function testInterfaceExists() + { + $this->assertFalse(interface_exists(ExistingInterface::class)); + $this->assertFalse(interface_exists(ExistingInterface::class, false)); + $this->assertFalse(interface_exists('\\'.ExistingInterface::class)); + $this->assertFalse(interface_exists('\\'.ExistingInterface::class, false)); + $this->assertTrue(interface_exists('NonExistingInterface')); + $this->assertTrue(interface_exists('NonExistingInterface', false)); + $this->assertTrue(interface_exists('\\NonExistingInterface')); + $this->assertTrue(interface_exists('\\NonExistingInterface', false)); + $this->assertTrue(interface_exists(ExistingInterfaceReal::class)); + $this->assertTrue(interface_exists(ExistingInterfaceReal::class, false)); + $this->assertTrue(interface_exists('\\'.ExistingInterfaceReal::class)); + $this->assertTrue(interface_exists('\\'.ExistingInterfaceReal::class, false)); + $this->assertFalse(interface_exists('NonExistingClassReal')); + $this->assertFalse(interface_exists('NonExistingClassReal', false)); + $this->assertFalse(interface_exists('\\NonExistingInterfaceReal')); + $this->assertFalse(interface_exists('\\NonExistingInterfaceReal', false)); + } + + public function testTraitExists() + { + $this->assertFalse(trait_exists(ExistingTrait::class)); + $this->assertFalse(trait_exists(ExistingTrait::class, false)); + $this->assertFalse(trait_exists('\\'.ExistingTrait::class)); + $this->assertFalse(trait_exists('\\'.ExistingTrait::class, false)); + $this->assertTrue(trait_exists('NonExistingTrait')); + $this->assertTrue(trait_exists('NonExistingTrait', false)); + $this->assertTrue(trait_exists('\\NonExistingTrait')); + $this->assertTrue(trait_exists('\\NonExistingTrait', false)); + $this->assertTrue(trait_exists(ExistingTraitReal::class)); + $this->assertTrue(trait_exists(ExistingTraitReal::class, false)); + $this->assertTrue(trait_exists('\\'.ExistingTraitReal::class)); + $this->assertTrue(trait_exists('\\'.ExistingTraitReal::class, false)); + $this->assertFalse(trait_exists('NonExistingClassReal')); + $this->assertFalse(trait_exists('NonExistingClassReal', false)); + $this->assertFalse(trait_exists('\\NonExistingTraitReal')); + $this->assertFalse(trait_exists('\\NonExistingTraitReal', false)); + } +} + +class ExistingClass +{ +} + +class ExistingClassReal +{ +} + +interface ExistingInterface +{ +} + +interface ExistingInterfaceReal +{ +} + +trait ExistingTrait +{ +} + +trait ExistingTraitReal +{ +} From 4399dabfd48ca0c7b9ea500cd69c7402346ee123 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Mon, 10 Dec 2018 19:42:44 +0100 Subject: [PATCH 024/495] [WebProfilerBundle] Fix php extension badges --- .../Resources/views/Collector/config.html.twig | 10 +++++----- .../WebProfilerBundle/Resources/views/Icon/no-gray.svg | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no-gray.svg diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig index aa0e452375055..33fdbad0572b0 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig @@ -64,9 +64,9 @@
PHP Extensions - xdebug - APCu - OPcache + xdebug {{ collector.hasxdebug ? '✓' : '✗' }} + APCu {{ collector.hasapcu ? '✓' : '✗' }} + OPcache {{ collector.haszendopcache ? '✓' : '✗' }}
@@ -187,12 +187,12 @@
- {{ include('@WebProfiler/Icon/' ~ (collector.hasapcu ? 'yes' : 'no') ~ '.svg') }} + {{ include('@WebProfiler/Icon/' ~ (collector.hasapcu ? 'yes' : 'no-gray') ~ '.svg') }} APCu
- {{ include('@WebProfiler/Icon/' ~ (collector.hasxdebug ? 'yes' : 'no') ~ '.svg') }} + {{ include('@WebProfiler/Icon/' ~ (collector.hasxdebug ? 'yes' : 'no-gray') ~ '.svg') }} Xdebug
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no-gray.svg b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no-gray.svg new file mode 100644 index 0000000000000..85b8305addb50 --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Icon/no-gray.svg @@ -0,0 +1,5 @@ + + + From 02c9f352d99d277c82ba368e3e45c65036d53fe5 Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Thu, 13 Dec 2018 10:16:14 +0000 Subject: [PATCH 025/495] Set the default locale early --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 5 +++++ .../EventListener/LocaleListener.php | 14 +++++++++--- .../EventListener/LocaleListenerTest.php | 22 +++++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index b96b4aefa1f21..3b40d8ae71514 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * made `Symfony\Component\HttpKernel\EventListenerLocaleListener` set the default locale early + 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 1067e8a0a51d9..2c8e7744afc4c 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\RequestContextAwareInterface; @@ -42,10 +43,14 @@ public function __construct(RequestStack $requestStack, string $defaultLocale = $this->router = $router; } + public function setDefaultLocale(KernelEvent $event) + { + $event->getRequest()->setDefaultLocale($this->defaultLocale); + } + public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); - $request->setDefaultLocale($this->defaultLocale); $this->setLocale($request); $this->setRouterContext($request); @@ -75,8 +80,11 @@ private function setRouterContext(Request $request) public static function getSubscribedEvents() { return array( - // must be registered after the Router to have access to the _locale - KernelEvents::REQUEST => array(array('onKernelRequest', 16)), + KernelEvents::REQUEST => array( + array('setDefaultLocale', 100), + // must be registered after the Router to have access to the _locale + array('onKernelRequest', 16), + ), KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)), ); } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index f442235ad048d..20282766a87ae 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -12,10 +12,12 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\EventListener\LocaleListener; use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; class LocaleListenerTest extends TestCase { @@ -26,12 +28,28 @@ protected function setUp() $this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->disableOriginalConstructor()->getMock(); } - public function testDefaultLocaleWithoutSession() + public function testIsAnEventSubscriber() + { + $this->assertInstanceOf(EventSubscriberInterface::class, new LocaleListener($this->requestStack)); + } + + public function testRegisteredEvent() + { + $this->assertEquals( + array( + KernelEvents::REQUEST => array(array('setDefaultLocale', 100), array('onKernelRequest', 16)), + KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)), + ), + LocaleListener::getSubscribedEvents() + ); + } + + public function testDefaultLocale() { $listener = new LocaleListener($this->requestStack, 'fr'); $event = $this->getEvent($request = Request::create('/')); - $listener->onKernelRequest($event); + $listener->setDefaultLocale($event); $this->assertEquals('fr', $request->getLocale()); } From 9bf313660d6d638586aefd5def2a8d1b4bcf9301 Mon Sep 17 00:00:00 2001 From: Chris Wilkinson Date: Thu, 13 Dec 2018 10:20:24 +0000 Subject: [PATCH 026/495] Increase priority of AddRequestFormatsListener --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 5 +++++ .../HttpKernel/EventListener/AddRequestFormatsListener.php | 2 +- .../Tests/EventListener/AddRequestFormatsListenerTest.php | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index b96b4aefa1f21..e6dda15045c93 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` + 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php b/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php index 5ec528417c987..e14a1aaf2d53a 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php @@ -45,6 +45,6 @@ public function onKernelRequest(GetResponseEvent $event) */ public static function getSubscribedEvents() { - return array(KernelEvents::REQUEST => array('onKernelRequest', 1)); + return array(KernelEvents::REQUEST => array('onKernelRequest', 100)); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php index 3ffb9f3d632e4..4c5cdf0e709d4 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php @@ -46,7 +46,7 @@ public function testIsAnEventSubscriber() public function testRegisteredEvent() { $this->assertEquals( - array(KernelEvents::REQUEST => array('onKernelRequest', 1)), + array(KernelEvents::REQUEST => array('onKernelRequest', 100)), AddRequestFormatsListener::getSubscribedEvents() ); } From 2f0e948bf084fa9bdc539501ecd4ae0e9a749ba2 Mon Sep 17 00:00:00 2001 From: karser Date: Sat, 8 Dec 2018 14:27:41 +0200 Subject: [PATCH 027/495] [Hackday][Messenger] Add an alias for transport.symfony_serializer so SerializerInterface can be autowired --- .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 2 ++ .../Bundle/FrameworkBundle/Resources/config/messenger.xml | 1 + 2 files changed, 3 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index faaebada1592d..9d0988a833653 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -70,6 +70,7 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportFactoryInterface; use Symfony\Component\Messenger\Transport\TransportInterface; use Symfony\Component\PropertyAccess\PropertyAccessor; @@ -1530,6 +1531,7 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $container->setAlias('messenger.transport.serializer', $config['serializer']['id']); } else { $container->removeDefinition('messenger.transport.amqp.factory'); + $container->removeDefinition(SerializerInterface::class); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index ef4ae3051a727..9d8a0ff74dd42 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -22,6 +22,7 @@ + From 1e0165ba94223fbf8646170f79483eb202e19983 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 13 Dec 2018 14:01:35 +0100 Subject: [PATCH 028/495] Fix deps=low --- .../Compiler/TestServiceContainerWeakRefPass.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php index 4912a001ec4de..f264ba44dde4e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php @@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; /** @@ -29,9 +30,10 @@ public function process(ContainerBuilder $container) $privateServices = array(); $definitions = $container->getDefinitions(); + $hasErrors = method_exists(Definition::class, 'hasErrors') ? 'hasErrors' : 'getErrors'; foreach ($definitions as $id => $definition) { - if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate()) && !$definition->hasErrors() && !$definition->isAbstract()) { + if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate()) && !$definition->$hasErrors() && !$definition->isAbstract()) { $privateServices[$id] = new Reference($id, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE); } } @@ -43,7 +45,7 @@ public function process(ContainerBuilder $container) while (isset($aliases[$target = (string) $alias])) { $alias = $aliases[$target]; } - if (isset($definitions[$target]) && !$definitions[$target]->hasErrors() && !$definitions[$target]->isAbstract()) { + if (isset($definitions[$target]) && !$definitions[$target]->$hasErrors() && !$definitions[$target]->isAbstract()) { $privateServices[$id] = new Reference($target, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE); } } From e54e21933a15d1222126dc8a5ec2a3e073548c8d Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Fri, 14 Dec 2018 16:36:24 +0100 Subject: [PATCH 029/495] [VarDumper] Use hyperlinks in CliDescriptor --- .../VarDumper/Command/Descriptor/CliDescriptor.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php b/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php index 1422960ce1187..74c1bc8b4c96c 100644 --- a/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php +++ b/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper\Command\Descriptor; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; @@ -28,10 +29,12 @@ class CliDescriptor implements DumpDescriptorInterface { private $dumper; private $lastIdentifier; + private $supportsHref; public function __construct(CliDumper $dumper) { $this->dumper = $dumper; + $this->supportsHref = method_exists(OutputFormatterStyle::class, 'setHref'); } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void @@ -62,15 +65,19 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['source'])) { $source = $context['source']; - $rows[] = array('source', sprintf('%s on line %d', $source['name'], $source['line'])); + $sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']); + $fileLink = $source['file_link'] ?? null; + if ($this->supportsHref && $fileLink) { + $sourceInfo = sprintf('%s', $fileLink, $sourceInfo); + } + $rows[] = array('source', $sourceInfo); $file = $source['file_relative'] ?? $source['file']; $rows[] = array('file', $file); - $fileLink = $source['file_link'] ?? null; } $io->table(array(), $rows); - if (isset($fileLink)) { + if (!$this->supportsHref && isset($fileLink)) { $io->writeln(array('Open source in your IDE/browser:', $fileLink)); $io->newLine(); } From 2b55d1504eb09894a0c8c83f165e67acc796c3d5 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Sat, 15 Dec 2018 11:33:10 +0100 Subject: [PATCH 030/495] [Console] Test href case conservation --- .../Component/Console/Tests/Formatter/OutputFormatterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 2639b94043c97..e1d8cff47a65f 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -255,7 +255,7 @@ public function provideDecoratedAndNonDecoratedOutput() array('some comment', 'some comment', "\033[33msome comment\033[39m"), array('some question', 'some question', "\033[30;46msome question\033[39;49m"), array('some text with inline style', 'some text with inline style', "\033[31msome text with inline style\033[39m"), - array('some URL', 'some URL', "\033]8;;idea://open/?file=/path/somefile.php&line=12\033\\some URL\033]8;;\033\\"), + array('some URL', 'some URL', "\033]8;;idea://open/?file=/path/SomeFile.php&line=12\033\\some URL\033]8;;\033\\"), ); } From 6a4ce386fef2f0013af694cc46e077cb41a3d46e Mon Sep 17 00:00:00 2001 From: Roberto Espinoza Date: Mon, 24 Sep 2018 20:20:15 +0900 Subject: [PATCH 031/495] [DomCrawler] Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. --- src/Symfony/Component/DomCrawler/CHANGELOG.md | 1 + src/Symfony/Component/DomCrawler/Crawler.php | 16 ++++++++++++++-- .../Component/DomCrawler/Tests/CrawlerTest.php | 4 ++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DomCrawler/CHANGELOG.md b/src/Symfony/Component/DomCrawler/CHANGELOG.md index 3accde4bf5738..fae5bd3f1d915 100644 --- a/src/Symfony/Component/DomCrawler/CHANGELOG.md +++ b/src/Symfony/Component/DomCrawler/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * Added return of element name (`_name`) in `extract()` method. +* Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. 4.2.0 ----- diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index a70c6466e0686..3526a1ebc6111 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -570,13 +570,19 @@ public function nodeName() /** * Returns the node value of the first node of the list. * + * @param mixed $default When provided and the current node is empty, this value is returned and no exception is thrown + * * @return string The node value * * @throws \InvalidArgumentException When current node is empty */ - public function text() + public function text(/* $default = null */) { if (!$this->nodes) { + if (0 < \func_num_args()) { + return \func_get_arg(0); + } + throw new \InvalidArgumentException('The current node list is empty.'); } @@ -586,13 +592,19 @@ public function text() /** * Returns the first node of the list as HTML. * + * @param mixed $default When provided and the current node is empty, this value is returned and no exception is thrown + * * @return string The node html * * @throws \InvalidArgumentException When current node is empty */ - public function html() + public function html(/* $default = null */) { if (!$this->nodes) { + if (0 < \func_num_args()) { + return \func_get_arg(0); + } + throw new \InvalidArgumentException('The current node list is empty.'); } diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index 254b1ba7f3206..fe2cf669b445d 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -392,6 +392,8 @@ public function testText() } catch (\InvalidArgumentException $e) { $this->assertTrue(true, '->text() throws an \InvalidArgumentException if the node list is empty'); } + + $this->assertSame('my value', $this->createTestCrawler(null)->filterXPath('//ol')->text('my value')); } public function testHtml() @@ -405,6 +407,8 @@ public function testHtml() } catch (\InvalidArgumentException $e) { $this->assertTrue(true, '->html() throws an \InvalidArgumentException if the node list is empty'); } + + $this->assertSame('my value', $this->createTestCrawler(null)->filterXPath('//ol')->html('my value')); } public function testExtract() From 9fab3d62ecd1f8c338bbcc1b1a800999723a0402 Mon Sep 17 00:00:00 2001 From: Vladimir Luchaninov Date: Fri, 14 Dec 2018 01:52:56 +0200 Subject: [PATCH 032/495] [Routing] Allow force-generation of trailing parameters using eg \"/exports/news.{!_format}\" --- .../Routing/Generator/UrlGenerator.php | 15 ++++++++----- .../Component/Routing/RouteCompiler.php | 9 +++++++- .../Tests/Generator/UrlGeneratorTest.php | 21 +++++++++++++++++++ .../Routing/Tests/Matcher/UrlMatcherTest.php | 9 ++++++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 91794423234fe..fbb5cca0b0a0f 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -156,21 +156,26 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $message = 'Parameter "{parameter}" for route "{route}" must match "{expected}" ("{given}" given) to generate a corresponding URL.'; foreach ($tokens as $token) { if ('variable' === $token[0]) { - if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) { + $varName = $token[3]; + if ($important = ('!' === $varName[0])) { + $varName = substr($varName, 1); + } + + if (!$optional || $important || !array_key_exists($varName, $defaults) || (null !== $mergedParams[$varName] && (string) $mergedParams[$varName] !== (string) $defaults[$varName])) { // check requirement - if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) { + if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$varName])) { if ($this->strictRequirements) { - throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]]))); + throw new InvalidParameterException(strtr($message, array('{parameter}' => $varName, '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$varName]))); } if ($this->logger) { - $this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]])); + $this->logger->error($message, array('parameter' => $varName, 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$varName])); } return; } - $url = $token[1].$mergedParams[$token[3]].$url; + $url = $token[1].$mergedParams[$varName].$url; $optional = false; } } else { diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index 66b291b831adc..abab86be7a95b 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -111,7 +111,7 @@ private static function compilePattern(Route $route, $pattern, $isHost) // Match all variables enclosed in "{}" and iterate over them. But we only want to match the innermost variable // in case of nested "{}", e.g. {foo{bar}}. This in ensured because \w does not match "{" or "}" itself. - preg_match_all('#\{\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); + preg_match_all('#\{!?\w+\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); foreach ($matches as $match) { $varName = substr($match[0][0], 1, -1); // get all static text preceding the current variable @@ -184,6 +184,9 @@ private static function compilePattern(Route $route, $pattern, $isHost) } $tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName); + if ('!' === $varName[0]) { + $varName = substr($varName, 1); + } $variables[] = $varName; } @@ -283,6 +286,10 @@ private static function computeRegexp(array $tokens, int $index, int $firstOptio // Text tokens return preg_quote($token[1], self::REGEX_DELIMITER); } else { + if ('variable' === $token[0] && '!' === $token[3][0]) { + $token[3] = substr($token[3], 1); + } + // Variable tokens if (0 === $index && 0 === $firstOptional) { // When the only token is an optional variable token, the separator is required diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index d4bf18ccac929..bb248d0fcd997 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -397,6 +397,27 @@ public function testDefaultRequirementOfVariable() $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html'))); } + public function testImportantVariable() + { + $routes = $this->getRoutes('test', (new Route('/{page}.{!_format}'))->addDefaults(array('_format' => 'mobile.html'))); + $generator = $this->getGenerator($routes); + + $this->assertSame('/app.php/index.xml', $generator->generate('test', array('page' => 'index', '_format' => 'xml'))); + $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html'))); + $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index'))); + } + + /** + * @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException + */ + public function testImportantVariableWithNoDefault() + { + $routes = $this->getRoutes('test', new Route('/{page}.{!_format}')); + $generator = $this->getGenerator($routes); + + $generator->generate('test', array('page' => 'index')); + } + /** * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException */ diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index bcaf3dee7218a..ecf6c5926bc5c 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -177,6 +177,15 @@ public function testMatchSpecialRouteName() $this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar')); } + public function testMatchImportantVariable() + { + $collection = new RouteCollection(); + $collection->add('index', new Route('/index.{!_format}', array('_format' => 'xml'))); + + $matcher = $this->getUrlMatcher($collection); + $this->assertEquals(array('_route' => 'index', '_format' => 'xml'), $matcher->match('/index.xml')); + } + /** * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException */ From 1fe2fc2697b09372a5428716b97638d2a9ce8c10 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 24 Dec 2018 11:20:31 +0100 Subject: [PATCH 033/495] fix merge --- .../VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php index 46032b7b7425d..10a8d9a512877 100644 --- a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php @@ -88,9 +88,6 @@ public function provideContext() source CliDescriptorTest.php on line 30 file src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php -------- -------------------------------------------------------------------------------- - -Open source in your IDE/browser: -phpstorm://open?file=/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php&line=30 TXT ); From 66928dd09d0bc24c56dd7051369630a5dd59b459 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Mon, 24 Dec 2018 11:44:29 +0100 Subject: [PATCH 034/495] fix merge (bis) --- .../Command/Descriptor/CliDescriptorTest.php | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php index 10a8d9a512877..cc4f46752688f 100644 --- a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\VarDumper\Tests\Command\Descriptor; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor; @@ -35,9 +36,10 @@ public static function tearDownAfterClass() /** * @dataProvider provideContext */ - public function testDescribe(array $context, string $expectedOutput) + public function testDescribe(array $context, string $expectedOutput, bool $decorated = false) { $output = new BufferedOutput(); + $output->setDecorated($decorated); $descriptor = new CliDescriptor(new CliDumper(function ($s) { return $s; })); @@ -79,7 +81,8 @@ public function provideContext() 'file_link' => 'phpstorm://open?file=/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php&line=30', ), ), - << array( + array( + 'source' => array( + 'name' => 'CliDescriptorTest.php', + 'line' => 30, + 'file_relative' => 'src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php', + 'file_link' => 'phpstorm://open?file=/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php&line=30', + ) + ), + << array( array( 'cli' => array( From 32a53bfc1346cac0d906b0f9c43498539e417576 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Mon, 24 Dec 2018 14:39:10 +0100 Subject: [PATCH 035/495] fix cs --- .../VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php index cc4f46752688f..eee402f2eafdb 100644 --- a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php @@ -117,14 +117,14 @@ public function provideContext() 'line' => 30, 'file_relative' => 'src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php', 'file_link' => 'phpstorm://open?file=/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php&line=30', - ) + ), ), << Date: Sat, 15 Dec 2018 11:33:10 +0100 Subject: [PATCH 036/495] [Console][VarDumper] Ignore href for PhpStorm terminal emulator --- .../Console/Formatter/OutputFormatterStyle.php | 7 ++++++- .../Tests/Formatter/OutputFormatterStyleTest.php | 15 +++++++++++++++ .../Tests/Formatter/OutputFormatterTest.php | 14 +++++++++++--- .../Component/VarDumper/Dumper/CliDumper.php | 8 +++++++- .../Command/Descriptor/CliDescriptorTest.php | 5 +++++ 5 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php index 445de6a200b7e..4c9265599816b 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php @@ -54,6 +54,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface private $background; private $href; private $options = array(); + private $handlesHrefGracefully; /** * Initializes output formatter style. @@ -185,6 +186,10 @@ public function apply($text) $setCodes = array(); $unsetCodes = array(); + if (null === $this->handlesHrefGracefully) { + $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR'); + } + if (null !== $this->foreground) { $setCodes[] = $this->foreground['set']; $unsetCodes[] = $this->foreground['unset']; @@ -199,7 +204,7 @@ public function apply($text) $unsetCodes[] = $option['unset']; } - if (null !== $this->href) { + if (null !== $this->href && $this->handlesHrefGracefully) { $text = "\033]8;;$this->href\033\\$text\033]8;;\033\\"; } diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php index ddf77902c90e9..6b675784460b4 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php @@ -97,4 +97,19 @@ public function testOptions() $this->assertContains('Invalid option specified: "foo"', $e->getMessage(), '->unsetOption() throws an \InvalidArgumentException when the option does not exist in the available options'); } } + + public function testHref() + { + $prevTerminalEmulator = getenv('TERMINAL_EMULATOR'); + putenv('TERMINAL_EMULATOR'); + + $style = new OutputFormatterStyle(); + + try { + $style->setHref('idea://open/?file=/path/SomeFile.php&line=12'); + $this->assertSame("\e]8;;idea://open/?file=/path/SomeFile.php&line=12\e\\some URL\e]8;;\e\\", $style->apply('some URL')); + } finally { + putenv('TERMINAL_EMULATOR'.($prevTerminalEmulator ? "=$prevTerminalEmulator" : '')); + } + } } diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index e1d8cff47a65f..030c9c1fabc18 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -241,10 +241,17 @@ public function testFormatterHasStyles() /** * @dataProvider provideDecoratedAndNonDecoratedOutput */ - public function testNotDecoratedFormatter(string $input, string $expectedNonDecoratedOutput, string $expectedDecoratedOutput) + public function testNotDecoratedFormatter(string $input, string $expectedNonDecoratedOutput, string $expectedDecoratedOutput, string $terminalEmulator = 'foo') { - $this->assertEquals($expectedDecoratedOutput, (new OutputFormatter(true))->format($input)); - $this->assertEquals($expectedNonDecoratedOutput, (new OutputFormatter(false))->format($input)); + $prevTerminalEmulator = getenv('TERMINAL_EMULATOR'); + putenv('TERMINAL_EMULATOR='.$terminalEmulator); + + try { + $this->assertEquals($expectedDecoratedOutput, (new OutputFormatter(true))->format($input)); + $this->assertEquals($expectedNonDecoratedOutput, (new OutputFormatter(false))->format($input)); + } finally { + putenv('TERMINAL_EMULATOR'.($prevTerminalEmulator ? "=$prevTerminalEmulator" : '')); + } } public function provideDecoratedAndNonDecoratedOutput() @@ -256,6 +263,7 @@ public function provideDecoratedAndNonDecoratedOutput() array('some question', 'some question', "\033[30;46msome question\033[39;49m"), array('some text with inline style', 'some text with inline style', "\033[31msome text with inline style\033[39m"), array('some URL', 'some URL', "\033]8;;idea://open/?file=/path/SomeFile.php&line=12\033\\some URL\033]8;;\033\\"), + array('some URL', 'some URL', 'some URL', 'JetBrains-JediTerm'), ); } diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index a6341709a48fa..65adfdecf89a9 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -59,6 +59,8 @@ class CliDumper extends AbstractDumper 'fileLinkFormat' => null, ); + private $handlesHrefGracefully; + /** * {@inheritdoc} */ @@ -431,6 +433,10 @@ protected function style($style, $value, $attr = array()) $this->colors = $this->supportsColors(); } + if (null === $this->handlesHrefGracefully) { + $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR'); + } + if (isset($attr['ellipsis'], $attr['ellipsis-type'])) { $prefix = substr($value, 0, -$attr['ellipsis']); if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && 0 === strpos($prefix, $_SERVER[$pwd])) { @@ -477,7 +483,7 @@ protected function style($style, $value, $attr = array()) } href: - if ($this->colors) { + if ($this->colors && $this->handlesHrefGracefully) { if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], isset($attr['line']) ? $attr['line'] : 0)) { $attr['href'] = $href; } diff --git a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php index eee402f2eafdb..473bd63dac7cb 100644 --- a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php @@ -21,16 +21,21 @@ class CliDescriptorTest extends TestCase { private static $timezone; + private static $prevTerminalEmulator; public static function setUpBeforeClass() { self::$timezone = date_default_timezone_get(); date_default_timezone_set('UTC'); + + self::$prevTerminalEmulator = getenv('TERMINAL_EMULATOR'); + putenv('TERMINAL_EMULATOR'); } public static function tearDownAfterClass() { date_default_timezone_set(self::$timezone); + putenv('TERMINAL_EMULATOR'.(self::$prevTerminalEmulator ? '='.self::$prevTerminalEmulator : '')); } /** From 71dfa35a215a01b39bca646b2df473f62f5beb29 Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Thu, 20 Dec 2018 18:23:49 +0100 Subject: [PATCH 037/495] add new `choices` wildcard in message --- .../Component/Validator/Constraints/ChoiceValidator.php | 2 ++ .../Validator/Tests/Constraints/ChoiceValidatorTest.php | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php index a2635309f057b..c97d8a6880e55 100644 --- a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php @@ -68,6 +68,7 @@ public function validate($value, Constraint $constraint) if (!\in_array($_value, $choices, true)) { $this->context->buildViolation($constraint->multipleMessage) ->setParameter('{{ value }}', $this->formatValue($_value)) + ->setParameter('{{ choices }}', $this->formatValues($choices)) ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->setInvalidValue($_value) ->addViolation(); @@ -100,6 +101,7 @@ public function validate($value, Constraint $constraint) } elseif (!\in_array($value, $choices, true)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ choices }}', $this->formatValues($choices)) ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->addViolation(); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php index f9db12200e6d5..0235408af07c7 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ChoiceValidatorTest.php @@ -169,6 +169,7 @@ public function testInvalidChoice() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"baz"') + ->setParameter('{{ choices }}', '"foo", "bar"') ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } @@ -186,6 +187,7 @@ public function testInvalidChoiceEmptyChoices() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"baz"') + ->setParameter('{{ choices }}', '') ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } @@ -202,6 +204,7 @@ public function testInvalidChoiceMultiple() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"baz"') + ->setParameter('{{ choices }}', '"foo", "bar"') ->setInvalidValue('baz') ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); @@ -275,6 +278,7 @@ public function testStrictDisallowsDifferentType() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"2"') + ->setParameter('{{ choices }}', '1, 2') ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); } @@ -291,6 +295,7 @@ public function testStrictWithMultipleChoices() $this->buildViolation('myMessage') ->setParameter('{{ value }}', '"3"') + ->setParameter('{{ choices }}', '1, 2, 3') ->setInvalidValue('3') ->setCode(Choice::NO_SUCH_CHOICE_ERROR) ->assertRaised(); From 59313095d3596466b9ed5340a9a3a1089a7f121e Mon Sep 17 00:00:00 2001 From: George Mponos Date: Fri, 28 Dec 2018 20:02:12 +0200 Subject: [PATCH 038/495] [PHPUnit bridge] Bump php version of PHPUnit-bridge --- src/Symfony/Bridge/PhpUnit/CHANGELOG.md | 1 + src/Symfony/Bridge/PhpUnit/composer.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md index 888f03d5a8117..6dfb949754968 100644 --- a/src/Symfony/Bridge/PhpUnit/CHANGELOG.md +++ b/src/Symfony/Bridge/PhpUnit/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * added `ClassExistsMock` + * bumped PHP version from 5.3.3 to 5.5.9 4.1.0 ----- diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 0c2f6d80492e9..289d92ee5095b 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -16,9 +16,9 @@ } ], "require": { - "php": ">=5.3.3 EVEN ON LATEST SYMFONY VERSIONS TO ALLOW USING", + "php": ">=5.5.9 EVEN ON LATEST SYMFONY VERSIONS TO ALLOW USING", "php": "THIS BRIDGE WHEN TESTING LOWEST SYMFONY VERSIONS.", - "php": ">=5.3.3" + "php": ">=5.5.9" }, "suggest": { "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader", From 0e63c61190f706e8a8723433ad44980ab0d9e5e2 Mon Sep 17 00:00:00 2001 From: Mihai Nica Date: Thu, 22 Nov 2018 15:34:35 +0200 Subject: [PATCH 039/495] [Serializer] CsvEncoder no header option (encode / decode) --- .../Serializer/Encoder/CsvEncoder.php | 25 +++++++++++++------ .../Tests/Encoder/CsvEncoderTest.php | 24 ++++++++++++++++++ 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php index c453120fc6a0d..d751e21046871 100644 --- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php @@ -29,6 +29,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface const HEADERS_KEY = 'csv_headers'; const ESCAPE_FORMULAS_KEY = 'csv_escape_formulas'; const AS_COLLECTION_KEY = 'as_collection'; + const NO_HEADERS_KEY = 'no_headers'; private $formulasStartCharacters = array('=', '-', '+', '@'); private $defaultContext = array( @@ -38,6 +39,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface self::ESCAPE_FORMULAS_KEY => false, self::HEADERS_KEY => array(), self::KEY_SEPARATOR_KEY => '.', + self::NO_HEADERS_KEY => false, ); /** @@ -95,7 +97,9 @@ public function encode($data, $format, array $context = array()) $headers = array_merge(array_values($headers), array_diff($this->extractHeaders($data), $headers)); - fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar); + if (!($context[self::NO_HEADERS_KEY] ?? false)) { + fputcsv($handle, $headers, $delimiter, $enclosure, $escapeChar); + } $headers = array_fill_keys($headers, ''); foreach ($data as $row) { @@ -139,13 +143,20 @@ public function decode($data, $format, array $context = array()) if (null === $headers) { $nbHeaders = $nbCols; - foreach ($cols as $col) { - $header = explode($keySeparator, $col); - $headers[] = $header; - $headerCount[] = \count($header); - } + if ($context[self::NO_HEADERS_KEY] ?? false) { + for ($i = 0; $i < $nbCols; ++$i) { + $headers[] = array($i); + } + $headerCount = array_fill(0, $nbCols, 1); + } else { + foreach ($cols as $col) { + $header = explode($keySeparator, $col); + $headers[] = $header; + $headerCount[] = \count($header); + } - continue; + continue; + } } $item = array(); diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index 65ced222a9760..86ea75b9ea77a 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -309,6 +309,18 @@ public function testEncodeFormulasWithSettingsPassedInContext() ))); } + public function testEncodeWithoutHeader() + { + $this->assertSame(<<<'CSV' +a,b +c,d + +CSV + , $this->encoder->encode(array(array('a', 'b'), array('c', 'd')), 'csv', array( + CsvEncoder::NO_HEADERS_KEY => true, + ))); + } + public function testSupportsDecoding() { $this->assertTrue($this->encoder->supportsDecoding('csv')); @@ -480,4 +492,16 @@ public function testDecodeEmptyArray() { $this->assertEquals(array(), $this->encoder->decode('', 'csv')); } + + public function testDecodeWithoutHeader() + { + $this->assertEquals(array(array('a', 'b'), array('c', 'd')), $this->encoder->decode(<<<'CSV' +a,b +c,d + +CSV + , 'csv', array( + CsvEncoder::NO_HEADERS_KEY => true, + ))); + } } From bd50ac44fc733d0f531051bcb06328a8e77a1fe4 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 24 Dec 2018 19:01:37 -0500 Subject: [PATCH 040/495] Add block_prefix option for an easy form theming --- src/Symfony/Component/Form/CHANGELOG.md | 5 +++++ .../Component/Form/Extension/Core/Type/BaseType.php | 5 +++++ .../Form/Tests/Extension/Core/Type/FormTypeTest.php | 12 ++++++++++++ .../Fixtures/Descriptor/resolved_form_type_1.json | 1 + .../Fixtures/Descriptor/resolved_form_type_1.txt | 11 ++++++----- .../Fixtures/Descriptor/resolved_form_type_2.json | 1 + .../Fixtures/Descriptor/resolved_form_type_2.txt | 1 + 7 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index f1cbf0ba4f875..45e085d488671 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added `block_prefix` option to `BaseType`. + 4.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php index d68337e3bc8c1..91c6d8615c7cc 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php @@ -79,6 +79,9 @@ public function buildView(FormView $view, FormInterface $form, array $options) for ($type = $form->getConfig()->getType(); null !== $type; $type = $type->getParent()) { array_unshift($blockPrefixes, $type->getBlockPrefix()); } + if (null !== $options['block_prefix']) { + $blockPrefixes[] = $options['block_prefix']; + } $blockPrefixes[] = $uniqueBlockPrefix; $view->vars = array_replace($view->vars, array( @@ -111,6 +114,7 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'block_name' => null, + 'block_prefix' => null, 'disabled' => false, 'label' => null, 'label_format' => null, @@ -119,6 +123,7 @@ public function configureOptions(OptionsResolver $resolver) 'auto_initialize' => true, )); + $resolver->setAllowedTypes('block_prefix', array('null', 'string')); $resolver->setAllowedTypes('attr', 'array'); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 68f30ef16bc05..2f08dd6ad4830 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -639,4 +639,16 @@ public function testSubmitNull($expected = null, $norm = null, $view = null) { parent::testSubmitNull(array(), array(), array()); } + + public function testPassBlockPrefixToViewWithParent() + { + $view = $this->factory->createNamedBuilder('parent', static::TESTED_TYPE) + ->add('child', $this->getTestedType(), array( + 'block_prefix' => 'child', + )) + ->getForm() + ->createView(); + + $this->assertSame(array('form', 'child', '_parent_child'), $view['child']->vars['block_prefixes']); + } } diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json index eb7f21af962e4..e274979eb8815 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json @@ -32,6 +32,7 @@ "attr", "auto_initialize", "block_name", + "block_prefix", "by_reference", "data", "disabled", diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt index 500a6e0dd2b2f..7de8dce90e385 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt @@ -12,11 +12,12 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice") choice_translation_domain empty_data attr csrf_protection choice_value error_bubbling auto_initialize csrf_token_id choices trim block_name csrf_token_manager - expanded by_reference - group_by data - multiple disabled - placeholder help - preferred_choices help_attr + expanded block_prefix + group_by by_reference + multiple data + placeholder disabled + preferred_choices help + help_attr inherit_data label label_attr diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json index eb93423adf651..e36dadf31fefb 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json @@ -8,6 +8,7 @@ "attr", "auto_initialize", "block_name", + "block_prefix", "by_reference", "compound", "data", diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt index 5b97c854c7b06..560d9c25d78c2 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt @@ -10,6 +10,7 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form") attr auto_initialize block_name + block_prefix by_reference compound data From 91e8057d9ae5cb7bcd9158758071a4a2a3c3dc6c Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Sat, 8 Dec 2018 14:17:19 +0000 Subject: [PATCH 041/495] [DebugBundle] Added 'theme' option to change the color of dump() when rendered inside templates --- .../DependencyInjection/Configuration.php | 18 ++++++++++++++++-- .../DependencyInjection/DebugExtension.php | 6 ++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php index 436a95c50b6f7..5f98efab0d9a8 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php @@ -13,6 +13,7 @@ use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; /** * DebugExtension configuration structure. @@ -28,8 +29,8 @@ public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder('debug'); - $treeBuilder->getRootNode() - ->children() + $rootNode = $treeBuilder->getRootNode(); + $rootNode->children() ->integerNode('max_items') ->info('Max number of displayed items past the first level, -1 means no limit') ->min(-1) @@ -53,6 +54,19 @@ public function getConfigTreeBuilder() ->end() ; + if (method_exists(HtmlDumper::class, 'setTheme')) { + $rootNode + ->children() + ->enumNode('theme') + ->info('Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light"') + ->example('dark') + ->values(array('dark', 'light')) + ->defaultValue('dark') + ->end() + ->end() + ; + } + return $treeBuilder; } } diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php index 317f2fba4e093..968fa81f75f9f 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; /** * DebugExtension. @@ -42,6 +43,11 @@ public function load(array $configs, ContainerBuilder $container) ->addMethodCall('setMinDepth', array($config['min_depth'])) ->addMethodCall('setMaxString', array($config['max_string_length'])); + if (method_exists(HtmlDumper::class, 'setTheme') && 'dark' !== $config['theme']) { + $container->getDefinition('var_dumper.html_dumper') + ->addMethodCall('setTheme', array($config['theme'])); + } + if (null === $config['dump_destination']) { $container->getDefinition('var_dumper.command.server_dump') ->setClass(ServerDumpPlaceholderCommand::class) From 88a1696a647db7a1b3f080b123cc8aaa582cd195 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Jan 2019 11:00:42 +0100 Subject: [PATCH 042/495] Improved BIC + IBAN validator for some special cases --- .../Validator/Constraints/BicValidator.php | 26 +++++++++++++- .../Tests/Constraints/BicValidatorTest.php | 35 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index 23c33c812e42c..a8e9d07ba6cff 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -29,6 +29,25 @@ */ class BicValidator extends ConstraintValidator { + private const BIC_COUNTRY_TO_IBAN_COUNTRY_MAP = array( + // Reference: https://www.ecbs.org/iban/france-bank-account-number.html + 'GF' => 'FR', // French Guiana + 'PF' => 'FR', // French Polynesia + 'TF' => 'FR', // French Southern Territories + 'GP' => 'FR', // Guadeloupe + 'MQ' => 'FR', // Martinique + 'YT' => 'FR', // Mayotte + 'NC' => 'FR', // New Caledonia + 'RE' => 'FR', // Reunion + 'PM' => 'FR', // Saint Pierre and Miquelon + 'WF' => 'FR', // Wallis and Futuna Islands + // Reference: https://www.ecbs.org/iban/united-kingdom-uk-bank-account-number.html + 'JE' => 'GB', // Jersey + 'IM' => 'GB', // Isle of Man + 'GG' => 'GB', // Guernsey + 'VG' => 'GB', // British Virgin Islands + ); + private $propertyAccessor; public function __construct(PropertyAccessor $propertyAccessor = null) @@ -126,7 +145,7 @@ public function validate($value, Constraint $constraint) return; } $ibanCountryCode = substr($iban, 0, 2); - if (ctype_alpha($ibanCountryCode) && substr($canonicalize, 4, 2) !== $ibanCountryCode) { + if (ctype_alpha($ibanCountryCode) && !$this->bicAndIbanCountriesMatch(substr($canonicalize, 4, 2), $ibanCountryCode)) { $this->context->buildViolation($constraint->ibanMessage) ->setParameter('{{ value }}', $this->formatValue($value)) ->setParameter('{{ iban }}', $iban) @@ -146,4 +165,9 @@ private function getPropertyAccessor(): PropertyAccessor return $this->propertyAccessor; } + + private function bicAndIbanCountriesMatch(string $bicCountryCode, string $ibanCountryCode): bool + { + return $ibanCountryCode === $bicCountryCode || $ibanCountryCode === (self::BIC_COUNTRY_TO_IBAN_COUNTRY_MAP[$bicCountryCode] ?? null); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php index 2d57ab0ec3c83..e0d7e0db631da 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php @@ -221,6 +221,41 @@ public function getInvalidBics() array('DEUTAT2lxxx', Bic::INVALID_CASE_ERROR), ); } + + /** + * @dataProvider getValidBicSpecialCases + * + * Some territories have their own ISO country code but can use another country code + * for IBAN accounts. Example: "French Guiana" (country code "GF") can use FR too. + */ + public function testValidBicSpecialCases(string $bic, string $iban) + { + $constraint = new Bic(array('iban' => $iban)); + $this->validator->validate($bic, $constraint); + + $this->assertNoViolation(); + } + + public function getValidBicSpecialCases() + { + // FR related special cases + yield array('BNPAGFGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAPFGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPATFGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAGPGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAMQGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAYTGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPANCGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAREGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAPMGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield array('BNPAWFGX', 'FR14 2004 1010 0505 0001 3M02 606'); + + // GB related special cases + yield array('BARCJESA', 'GB12 CPBK 0892 9965 0449 911'); + yield array('BARCIMSA', 'GB12 CPBK 0892 9965 0449 911'); + yield array('BARCGGSA', 'GB12 CPBK 0892 9965 0449 911'); + yield array('BARCVGSA', 'GB12 CPBK 0892 9965 0449 911'); + } } class BicComparisonTestClass From d80bfad54ef8e6167c6d5d978cd2297ce3d19fee Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Fri, 4 Jan 2019 18:02:37 +0100 Subject: [PATCH 043/495] [Profiler] Still show locale and fallback locale even if no trans used --- .../views/Collector/translation.html.twig | 183 ++++++++---------- 1 file changed, 80 insertions(+), 103 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig index 06c27b4716a51..b37da94681167 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/translation.html.twig @@ -56,38 +56,9 @@ {% endblock %} {% block panel %} - {% if collector.messages is empty %} -

Translations

-
-

No translations have been called.

-
- {% else %} - {{ block('panelContent') }} - {% endif %} -{% endblock %} - -{% block panelContent %} -

Translation

-
- {{ collector.countDefines }} - Defined messages -
- -
- {{ collector.countFallbacks }} - Fallback messages -
- -
- {{ collector.countMissings }} - Missing messages -
- -
-
{{ collector.locale|default('-') }} Locale @@ -100,88 +71,94 @@

Messages

- {% block messages %} - - {# sort translation messages in groups #} - {% set messages_defined, messages_missing, messages_fallback = [], [], [] %} - {% for message in collector.messages %} - {% if message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_DEFINED') %} - {% set messages_defined = messages_defined|merge([message]) %} - {% elseif message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_MISSING') %} - {% set messages_missing = messages_missing|merge([message]) %} - {% elseif message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK') %} - {% set messages_fallback = messages_fallback|merge([message]) %} - {% endif %} - {% endfor %} - -
-
-

Defined {{ collector.countDefines }}

- -
-

- These messages are correctly translated into the given locale. -

- - {% if messages_defined is empty %} -
-

None of the used translation messages are defined for the given locale.

-
- {% else %} - {% block defined_messages %} - {{ helper.render_table(messages_defined) }} - {% endblock %} - {% endif %} -
+ {% if collector.messages is empty %} +
+

No translations have been called.

+ {% else %} + {% block messages %} + + {# sort translation messages in groups #} + {% set messages_defined, messages_missing, messages_fallback = [], [], [] %} + {% for message in collector.messages %} + {% if message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_DEFINED') %} + {% set messages_defined = messages_defined|merge([message]) %} + {% elseif message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_MISSING') %} + {% set messages_missing = messages_missing|merge([message]) %} + {% elseif message.state == constant('Symfony\\Component\\Translation\\DataCollectorTranslator::MESSAGE_EQUALS_FALLBACK') %} + {% set messages_fallback = messages_fallback|merge([message]) %} + {% endif %} + {% endfor %} + +
+
+

Defined {{ collector.countDefines }}

+ +
+

+ These messages are correctly translated into the given locale. +

-
-

Fallback {{ collector.countFallbacks }}

- -
-

- These messages are not available for the given locale - but Symfony found them in the fallback locale catalog. -

- - {% if messages_fallback is empty %} -
-

No fallback translation messages were used.

-
- {% else %} - {% block fallback_messages %} - {{ helper.render_table(messages_fallback) }} - {% endblock %} - {% endif %} + {% if messages_defined is empty %} +
+

None of the used translation messages are defined for the given locale.

+
+ {% else %} + {% block defined_messages %} + {{ helper.render_table(messages_defined) }} + {% endblock %} + {% endif %} +
-
-
-

Missing {{ collector.countMissings }}

- -
-

- These messages are not available for the given locale and cannot - be found in the fallback locales. Add them to the translation - catalogue to avoid Symfony outputting untranslated contents. -

- - {% if messages_missing is empty %} -
-

There are no messages of this category.

-
- {% else %} - {% block missing_messages %} - {{ helper.render_table(messages_missing) }} - {% endblock %} - {% endif %} +
+

Fallback {{ collector.countFallbacks }}

+ +
+

+ These messages are not available for the given locale + but Symfony found them in the fallback locale catalog. +

+ + {% if messages_fallback is empty %} +
+

No fallback translation messages were used.

+
+ {% else %} + {% block fallback_messages %} + {{ helper.render_table(messages_fallback) }} + {% endblock %} + {% endif %} +
+
+ +
+

Missing {{ collector.countMissings }}

+ +
+

+ These messages are not available for the given locale and cannot + be found in the fallback locales. Add them to the translation + catalogue to avoid Symfony outputting untranslated contents. +

+ + {% if messages_missing is empty %} +
+

There are no messages of this category.

+
+ {% else %} + {% block missing_messages %} + {{ helper.render_table(messages_missing) }} + {% endblock %} + {% endif %} +
-
- + - {% endblock messages %} + {% endblock messages %} + {% endif %} {% endblock %} From 38877c32acfafdc7146331c46f64349444b51be9 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Wed, 17 Oct 2018 11:28:44 +0200 Subject: [PATCH 044/495] [Debug] Detect virtual methods using @method --- .../Component/Debug/DebugClassLoader.php | 41 ++++++++++++ .../Debug/Tests/DebugClassLoaderTest.php | 66 +++++++++++++++++++ .../Debug/Tests/Fixtures/VirtualClass.php | 11 ++++ .../Tests/Fixtures/VirtualClassMagicCall.php | 18 +++++ .../Debug/Tests/Fixtures/VirtualInterface.php | 34 ++++++++++ .../Tests/Fixtures/VirtualSubInterface.php | 10 +++ .../Debug/Tests/Fixtures/VirtualTrait.php | 10 +++ 7 files changed, 190 insertions(+) create mode 100644 src/Symfony/Component/Debug/Tests/Fixtures/VirtualClass.php create mode 100644 src/Symfony/Component/Debug/Tests/Fixtures/VirtualClassMagicCall.php create mode 100644 src/Symfony/Component/Debug/Tests/Fixtures/VirtualInterface.php create mode 100644 src/Symfony/Component/Debug/Tests/Fixtures/VirtualSubInterface.php create mode 100644 src/Symfony/Component/Debug/Tests/Fixtures/VirtualTrait.php diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index 5c2be6b3b4331..f0916bb66fae2 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -39,6 +39,7 @@ class DebugClassLoader private static $internalMethods = array(); private static $annotatedParameters = array(); private static $darwinCache = array('/' => array('/', array())); + private static $method = array(); public function __construct(callable $classLoader) { @@ -228,6 +229,24 @@ public function checkAnnotations(\ReflectionClass $refl, $class) self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; } } + + if ($refl->isInterface() && false !== \strpos($doc, 'method') && preg_match_all('#\n \* @method\s+(static\s+)?+(?:[\w\|&\[\]\\\]+\s+)?(\w+(?:\s*\([^\)]*\))?)+(.+?([[:punct:]]\s*)?)?(?=\r?\n \*(?: @|/$|\r?\n))#', $doc, $notice, PREG_SET_ORDER)) { + foreach ($notice as $method) { + $static = '' !== $method[1]; + $name = $method[2]; + $description = $method[3] ?? null; + if (false === strpos($name, '(')) { + $name .= '()'; + } + if (null !== $description) { + $description = trim($description); + if (!isset($method[4])) { + $description .= '.'; + } + } + self::$method[$class][] = array($class, $name, $static, $description); + } + } } $parent = \get_parent_class($class); @@ -258,6 +277,28 @@ public function checkAnnotations(\ReflectionClass $refl, $class) if (isset(self::$internal[$use]) && \strncmp($ns, $use, $len)) { $deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class); } + if (isset(self::$method[$use])) { + if ($refl->isAbstract()) { + if (isset(self::$method[$class])) { + self::$method[$class] = array_merge(self::$method[$class], self::$method[$use]); + } else { + self::$method[$class] = self::$method[$use]; + } + } elseif (!$refl->isInterface()) { + $hasCall = $refl->hasMethod('__call'); + $hasStaticCall = $refl->hasMethod('__callStatic'); + foreach (self::$method[$use] as $method) { + list($interface, $name, $static, $description) = $method; + if ($static ? $hasStaticCall : $hasCall) { + continue; + } + $realName = substr($name, 0, strpos($name, '(')); + if (!$refl->hasMethod($realName) || !($methodRefl = $refl->getMethod($realName))->isPublic() || ($static && !$methodRefl->isStatic()) || (!$static && $methodRefl->isStatic())) { + $deprecations[] = sprintf('Class "%s" should implement method "%s::%s"%s', $class, ($static ? 'static ' : '').$interface, $name, null == $description ? '.' : ': '.$description); + } + } + } + } } if (\trait_exists($class)) { diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php index c7e03fbef84ec..b5582f15fc5dc 100644 --- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php +++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php @@ -304,6 +304,46 @@ class_exists('Test\\'.__NAMESPACE__.'\\UseTraitWithInternalMethod', true); $this->assertSame(array(), $deprecations); } + + public function testVirtualUse() + { + $deprecations = array(); + set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); + $e = error_reporting(E_USER_DEPRECATED); + + class_exists('Test\\'.__NAMESPACE__.'\\ExtendsVirtual', true); + + error_reporting($e); + restore_error_handler(); + + $this->assertSame(array( + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::sameLineInterfaceMethodNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::newLineInterfaceMethod()": Some description!', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::newLineInterfaceMethodNoBraces()": Description.', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::invalidInterfaceMethod()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::invalidInterfaceMethodNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::complexInterfaceMethod($arg, ...$args)".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::complexInterfaceMethodTyped($arg, int ...$args)": Description ...', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodTyped(int $arg)": Description.', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodTypedNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtual" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualSubInterface::subInterfaceMethod()".', + ), $deprecations); + } + + public function testVirtualUseWithMagicCall() + { + $deprecations = array(); + set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); + $e = error_reporting(E_USER_DEPRECATED); + + class_exists('Test\\'.__NAMESPACE__.'\\ExtendsVirtualMagicCall', true); + + error_reporting($e); + restore_error_handler(); + + $this->assertSame(array(), $deprecations); + } } class ClassLoader @@ -359,6 +399,32 @@ public function internalMethod() { } eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }'); } elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtual' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtual extends ExtendsVirtualParent implements \\'.__NAMESPACE__.'\Fixtures\VirtualSubInterface { + public function ownClassMethod() { } + public function classMethod() { } + public function sameLineInterfaceMethodNoBraces() { } + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualParent' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualParent extends ExtendsVirtualAbstract { + public function ownParentMethod() { } + public function traitMethod() { } + public function sameLineInterfaceMethod() { } + public function staticMethodNoBraces() { } // should be static + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualAbstract' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; abstract class ExtendsVirtualAbstract extends ExtendsVirtualAbstractBase { + public static function staticMethod() { } + public function ownAbstractMethod() { } + public function interfaceMethod() { } + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualAbstractBase' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; abstract class ExtendsVirtualAbstractBase extends \\'.__NAMESPACE__.'\Fixtures\VirtualClass implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface { + public function ownAbstractBaseMethod() { } + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualMagicCall' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualMagicCall extends \\'.__NAMESPACE__.'\Fixtures\VirtualClassMagicCall implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface { + }'); } } } diff --git a/src/Symfony/Component/Debug/Tests/Fixtures/VirtualClass.php b/src/Symfony/Component/Debug/Tests/Fixtures/VirtualClass.php new file mode 100644 index 0000000000000..25712519a5fb6 --- /dev/null +++ b/src/Symfony/Component/Debug/Tests/Fixtures/VirtualClass.php @@ -0,0 +1,11 @@ + Date: Fri, 4 Jan 2019 18:50:27 +0100 Subject: [PATCH 045/495] [DI] Add trim env processor --- .../Component/DependencyInjection/CHANGELOG.md | 1 + .../DependencyInjection/EnvVarProcessor.php | 5 +++++ .../Compiler/RegisterEnvVarProcessorsPassTest.php | 1 + .../Tests/EnvVarProcessorTest.php | 13 +++++++++++++ 4 files changed, 20 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 470331d9b7cec..7afa4a21b89a0 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added `%env(trim:...)%` processor to trim a string value * added `%env(default:...)%` processor to fallback to a default value 4.2.0 diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index abf2d0c192ce5..fb9894912b635 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -45,6 +45,7 @@ public static function getProvidedTypes() 'resolve' => 'string', 'default' => 'bool|int|float|string|array', 'string' => 'string', + 'trim' => 'string', ); } @@ -195,6 +196,10 @@ public function getEnv($prefix, $name, \Closure $getEnv) return str_getcsv($env); } + if ('trim' === $prefix) { + return trim($env); + } + throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix)); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php index 93d3c16ff94dc..bdc05146e4eb3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php @@ -42,6 +42,7 @@ public function testSimpleProcessor() 'resolve' => array('string'), 'default' => array('bool', 'int', 'float', 'string', 'array'), 'string' => array('string'), + 'trim' => array('string'), ); $this->assertSame($expected, $container->getParameterBag()->getProvidedTypes()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index b244537354e43..e9bb0fe47aa86 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -233,6 +233,19 @@ public function testGetEnvBase64() $this->assertSame('hello', $result); } + public function testGetEnvTrim() + { + $processor = new EnvVarProcessor(new Container()); + + $result = $processor->getEnv('trim', 'foo', function ($name) { + $this->assertSame('foo', $name); + + return " hello\n"; + }); + + $this->assertSame('hello', $result); + } + /** * @dataProvider validJson */ From 3b8d6d19ec3f0655bf400bdc7c0e82b10165147c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Jan 2019 15:55:15 +0100 Subject: [PATCH 046/495] Improved performance of LoggerDataCollector --- .../HttpKernel/DataCollector/LoggerDataCollector.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php index 3081ac7fb5b36..d862ad7306410 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php @@ -66,7 +66,9 @@ public function lateCollect() if (null !== $this->logger) { $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); - $this->data['compiler_logs'] = $this->getContainerCompilerLogs(); + // get compiler logs later (only when they are needed) to improve performance + $this->data['compiler_logs'] = array(); + $this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log'; $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs)); $this->data = $this->cloneVar($this->data); } @@ -110,7 +112,7 @@ public function countScreams() public function getCompilerLogs() { - return isset($this->data['compiler_logs']) ? $this->data['compiler_logs'] : array(); + return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null)); } /** @@ -143,14 +145,14 @@ private function getContainerDeprecationLogs() return $logs; } - private function getContainerCompilerLogs() + private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): array { - if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Compiler.log')) { + if (!file_exists($compilerLogsFilepath)) { return array(); } $logs = array(); - foreach (file($file, FILE_IGNORE_NEW_LINES) as $log) { + foreach (file($compilerLogsFilepath, FILE_IGNORE_NEW_LINES) as $log) { $log = explode(': ', $log, 2); if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) { $log = array('Unknown Compiler Pass', implode(': ', $log)); From 5e88dc63e2e746ced52c37578d452d8d47fa0092 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Jan 2019 17:39:20 +0100 Subject: [PATCH 047/495] [VarDumper] add caster for OpenSSL X.509 resources --- .../Component/VarDumper/Caster/ConstStub.php | 4 +-- .../VarDumper/Caster/ResourceCaster.php | 26 +++++++++++++++++++ .../VarDumper/Cloner/AbstractCloner.php | 3 ++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ConstStub.php b/src/Symfony/Component/VarDumper/Caster/ConstStub.php index 250a250a9f7c4..15868b0934219 100644 --- a/src/Symfony/Component/VarDumper/Caster/ConstStub.php +++ b/src/Symfony/Component/VarDumper/Caster/ConstStub.php @@ -20,10 +20,10 @@ */ class ConstStub extends Stub { - public function __construct(string $name, $value) + public function __construct(string $name, $value = null) { $this->class = $name; - $this->value = $value; + $this->value = 1 < \func_num_args() ? $value : $name; } public function __toString() diff --git a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php index 3cdb27c30879b..85de5b59674ac 100644 --- a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php @@ -69,4 +69,30 @@ public static function castMysqlLink($h, array $a, Stub $stub, $isNested) return $a; } + + public static function castOpensslX509($h, array $a, Stub $stub, $isNested) + { + $stub->cut = -1; + $info = openssl_x509_parse($h, false); + + $pin = openssl_pkey_get_public($h); + $pin = openssl_pkey_get_details($pin)['key']; + $pin = \array_slice(explode("\n", $pin), 1, -2); + $pin = base64_decode(implode('', $pin)); + $pin = base64_encode(hash('sha256', $pin, true)); + + $a += array( + 'subject' => new EnumStub(array_intersect_key($info['subject'], array('organizationName' => true, 'commonName' => true))), + 'issuer' => new EnumStub(array_intersect_key($info['issuer'], array('organizationName' => true, 'commonName' => true))), + 'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), + 'fingerprint' => new EnumStub(array( + 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), + 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), + 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), + 'pin-sha256' => new ConstStub($pin), + )), + ); + + return $a; + } } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 88691609e1906..f55b2a1c67c00 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -136,6 +136,7 @@ abstract class AbstractCloner implements ClonerInterface ':pgsql result' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'), ':process' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'), ':stream' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'), + ':OpenSSL X.509' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'), ':persistent stream' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'), ':stream-context' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'), ':xml' => array('Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'), @@ -176,7 +177,7 @@ public function __construct(array $casters = null) public function addCasters(array $casters) { foreach ($casters as $type => $callback) { - $closure = &$this->casters[strtolower($type)][]; + $closure = &$this->casters['' === $type || ':' === $type[0] ? $type : strtolower($type)][]; $closure = $callback instanceof \Closure ? $callback : static function (...$args) use ($callback, &$closure) { return ($closure = \Closure::fromCallable($callback))(...$args); }; From b373d4206b926c1c4375228f29a811bf8acf1f1e Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 2 Jan 2019 17:21:45 +0100 Subject: [PATCH 048/495] pass project dir into the assets install command --- UPGRADE-4.3.md | 6 ++++++ UPGRADE-5.0.md | 2 ++ src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md | 2 ++ .../FrameworkBundle/Command/AssetsInstallCommand.php | 12 +++++++++--- .../FrameworkBundle/Resources/config/console.xml | 1 + 5 files changed, 20 insertions(+), 3 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index c88642f610ca7..d6a7f00203526 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -5,3 +5,9 @@ Config ------ * Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` + +FrameworkBundle +--------------- + + * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will + be mandatory in 5.0. diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 7a845414bd869..cf677c478a5dd 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -127,6 +127,8 @@ Form FrameworkBundle --------------- + * The project dir argument of the constructor of `AssetsInstallCommand` is required. + * Removed support for `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method` instead where `serviceOrFqcn` is either the service ID when using controllers as services or the FQCN of the controller. diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index b2096087bc3ec..cc001ff6180ed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will + be mandatory in 5.0. * Added `ControllerTrait::isFormValid()` 4.2.0 diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php index 957d85bf392bd..8a6f7290a9e5b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AssetsInstallCommand.php @@ -42,12 +42,18 @@ class AssetsInstallCommand extends Command protected static $defaultName = 'assets:install'; private $filesystem; + private $projectDir; - public function __construct(Filesystem $filesystem) + public function __construct(Filesystem $filesystem, string $projectDir = null) { parent::__construct(); + if (null === $projectDir) { + @trigger_error(sprintf('Not passing the project directory to the constructor of %s is deprecated since Symfony 4.3 and will not be supported in 5.0.', __CLASS__), E_USER_DEPRECATED); + } + $this->filesystem = $filesystem; + $this->projectDir = $projectDir; } /** @@ -260,11 +266,11 @@ private function getPublicDirectory(ContainerInterface $container) { $defaultPublicDir = 'public'; - if (!$container->hasParameter('kernel.project_dir')) { + if (null === $this->projectDir && !$container->hasParameter('kernel.project_dir')) { return $defaultPublicDir; } - $composerFilePath = $container->getParameter('kernel.project_dir').'/composer.json'; + $composerFilePath = ($this->projectDir ?? $container->getParameter('kernel.project_dir')).'/composer.json'; if (!file_exists($composerFilePath)) { return $defaultPublicDir; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 9553d4d60d7ce..9c5da8e177a0c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -19,6 +19,7 @@ + %kernel.project_dir% From 4073319d0f6757c98a53b70a3fe85bd8a9eef591 Mon Sep 17 00:00:00 2001 From: Pablo Borowicz Date: Thu, 8 Nov 2018 18:05:28 -0300 Subject: [PATCH 049/495] Load original file metadata when loading Xliff 1.2 files --- .../Component/Translation/CHANGELOG.md | 5 ++ .../Translation/Loader/XliffFileLoader.php | 60 +++++++++------ .../Tests/Loader/XliffFileLoaderTest.php | 73 ++++++++++++++++++- .../Tests/fixtures/resources-multi-files.xlf | 27 +++++++ 4 files changed, 137 insertions(+), 28 deletions(-) create mode 100644 src/Symfony/Component/Translation/Tests/fixtures/resources-multi-files.xlf diff --git a/src/Symfony/Component/Translation/CHANGELOG.md b/src/Symfony/Component/Translation/CHANGELOG.md index 87eb2fa4a3775..42ae7789fa192 100644 --- a/src/Symfony/Component/Translation/CHANGELOG.md +++ b/src/Symfony/Component/Translation/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * Improved Xliff 1.2 loader to load the original file's metadata + 4.2.0 ----- diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index 1106ec65f0e2c..33599400c5db8 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -82,38 +82,50 @@ private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, s $xml = simplexml_import_dom($dom); $encoding = strtoupper($dom->encoding); - $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2'); - foreach ($xml->xpath('//xliff:trans-unit') as $translation) { - $attributes = $translation->attributes(); + $namespace = 'urn:oasis:names:tc:xliff:document:1.2'; + $xml->registerXPathNamespace('xliff', $namespace); - if (!(isset($attributes['resname']) || isset($translation->source))) { - continue; - } + foreach ($xml->xpath('//xliff:file') as $file) { + $fileAttributes = $file->attributes(); - $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; - // If the xlf file has another encoding specified, try to convert it because - // simple_xml will always return utf-8 encoded values - $target = $this->utf8ToCharset((string) (isset($translation->target) ? $translation->target : $translation->source), $encoding); + $file->registerXPathNamespace('xliff', $namespace); - $catalogue->set((string) $source, $target, $domain); + foreach ($file->xpath('.//xliff:trans-unit') as $translation) { + $attributes = $translation->attributes(); - $metadata = array(); - if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { - $metadata['notes'] = $notes; - } + if (!(isset($attributes['resname']) || isset($translation->source))) { + continue; + } - if (isset($translation->target) && $translation->target->attributes()) { - $metadata['target-attributes'] = array(); - foreach ($translation->target->attributes() as $key => $value) { - $metadata['target-attributes'][$key] = (string) $value; + $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; + // If the xlf file has another encoding specified, try to convert it because + // simple_xml will always return utf-8 encoded values + $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding); + + $catalogue->set((string) $source, $target, $domain); + + $metadata = array( + 'file' => array( + 'original' => (string) $fileAttributes['original'], + ), + ); + if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { + $metadata['notes'] = $notes; } - } - if (isset($attributes['id'])) { - $metadata['id'] = (string) $attributes['id']; - } + if (isset($translation->target) && $translation->target->attributes()) { + $metadata['target-attributes'] = array(); + foreach ($translation->target->attributes() as $key => $value) { + $metadata['target-attributes'][$key] = (string) $value; + } + } - $catalogue->setMetadata((string) $source, $metadata, $domain); + if (isset($attributes['id'])) { + $metadata['id'] = (string) $attributes['id']; + } + + $catalogue->setMetadata((string) $source, $metadata, $domain); + } } } diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index c6958486c1206..cf21c8227f7e4 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -84,7 +84,16 @@ public function testEncoding() $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1')); $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1')); - $this->assertEquals(array('notes' => array(array('content' => utf8_decode('bäz'))), 'id' => '1'), $catalogue->getMetadata('foo', 'domain1')); + $this->assertEquals( + array( + 'notes' => array(array('content' => utf8_decode('bäz'))), + 'id' => '1', + 'file' => array( + 'original' => 'file.ext', + ), + ), + $catalogue->getMetadata('foo', 'domain1') + ); } public function testTargetAttributesAreStoredCorrectly() @@ -164,11 +173,41 @@ public function testLoadNotes() $loader = new XliffFileLoader(); $catalogue = $loader->load(__DIR__.'/../fixtures/withnote.xlf', 'en', 'domain1'); - $this->assertEquals(array('notes' => array(array('priority' => 1, 'content' => 'foo')), 'id' => '1'), $catalogue->getMetadata('foo', 'domain1')); + $this->assertEquals( + array( + 'notes' => array(array('priority' => 1, 'content' => 'foo')), + 'id' => '1', + 'file' => array( + 'original' => 'file.ext', + ), + ), + $catalogue->getMetadata('foo', 'domain1') + ); // message without target - $this->assertEquals(array('notes' => array(array('content' => 'bar', 'from' => 'foo')), 'id' => '2'), $catalogue->getMetadata('extra', 'domain1')); + $this->assertEquals( + array( + 'notes' => array(array('content' => 'bar', 'from' => 'foo')), + 'id' => '2', + 'file' => array( + 'original' => 'file.ext', + ), + ), + $catalogue->getMetadata('extra', 'domain1') + ); // message with empty target - $this->assertEquals(array('notes' => array(array('content' => 'baz'), array('priority' => 2, 'from' => 'bar', 'content' => 'qux')), 'id' => '123'), $catalogue->getMetadata('key', 'domain1')); + $this->assertEquals( + array( + 'notes' => array( + array('content' => 'baz'), + array('priority' => 2, 'from' => 'bar', 'content' => 'qux'), + ), + 'id' => '123', + 'file' => array( + 'original' => 'file.ext', + ), + ), + $catalogue->getMetadata('key', 'domain1') + ); } public function testLoadVersion2() @@ -257,4 +296,30 @@ public function testLoadVersion2WithMultiSegmentUnit() $this->assertSame('processed', $metadata['notes'][0]['category']); $this->assertSame('true', $metadata['notes'][0]['content']); } + + public function testLoadWithMultipleFileNodes() + { + $loader = new XliffFileLoader(); + $catalogue = $loader->load(__DIR__.'/../fixtures/resources-multi-files.xlf', 'en', 'domain1'); + + $this->assertEquals( + array( + 'id' => '1', + 'file' => array( + 'original' => 'file.ext', + ), + ), + $catalogue->getMetadata('foo', 'domain1') + ); + $this->assertEquals( + array( + 'notes' => array(array('content' => 'note')), + 'id' => '4', + 'file' => array( + 'original' => 'otherfile.ext', + ), + ), + $catalogue->getMetadata('test', 'domain1') + ); + } } diff --git a/src/Symfony/Component/Translation/Tests/fixtures/resources-multi-files.xlf b/src/Symfony/Component/Translation/Tests/fixtures/resources-multi-files.xlf new file mode 100644 index 0000000000000..5f451508bc8d8 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/fixtures/resources-multi-files.xlf @@ -0,0 +1,27 @@ + + + + + + foo + bar + + + + + + + extra + + + key + + + + test + with + note + + + + From 34dac7c8fd17a2757390710c7c8979b107dcb4b0 Mon Sep 17 00:00:00 2001 From: Stas Soroka Date: Sun, 6 Jan 2019 03:17:55 +0200 Subject: [PATCH 050/495] [Dotenv] improved code coverage and removed unreachable code --- src/Symfony/Component/Dotenv/Dotenv.php | 3 --- src/Symfony/Component/Dotenv/Tests/DotenvTest.php | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 2460f8617d213..619cc8be8a691 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -271,9 +271,6 @@ private function lexValue() throw $this->createFormatException('Missing quote to end the value'); } } - if ("\n" === $this->data[$this->cursor]) { - throw $this->createFormatException('Missing quote to end the value'); - } ++$this->cursor; $value = str_replace(array('\\"', '\r', '\n'), array('"', "\r", "\n"), $value); $resolvedValue = $value; diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 834f97ff650c6..a4e317d3cedf0 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -40,8 +40,14 @@ public function getEnvDataWithFormatErrors() array('FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"), array('FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"), array('FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"), + array('FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 8"), array('export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"), array('FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"), + array('FOO= BAR', "Whitespace are not supported before the value in \".env\" at line 1.\n...FOO= BAR...\n ^ line 1 offset 4"), + array('Стасян', "Invalid character in variable name in \".env\" at line 1.\n...Стасян...\n ^ line 1 offset 0"), + array('FOO!', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO!...\n ^ line 1 offset 3"), + array('FOO=$(echo foo', "Missing closing parenthesis. in \".env\" at line 1.\n...FOO=$(echo foo...\n ^ line 1 offset 14"), + array('FOO=$(echo foo'."\n", "Missing closing parenthesis. in \".env\" at line 1.\n...FOO=$(echo foo\\n...\n ^ line 1 offset 14"), ); if ('\\' !== \DIRECTORY_SEPARATOR) { @@ -64,6 +70,7 @@ public function getEnvData() { putenv('LOCAL=local'); $_ENV['REMOTE'] = 'remote'; + $_SERVER['SERVERVAR'] = 'servervar'; $tests = array( // backslashes @@ -150,6 +157,7 @@ public function getEnvData() array('FOO=" $ "', array('FOO' => ' $ ')), array('BAR=$LOCAL', array('BAR' => 'local')), array('BAR=$REMOTE', array('BAR' => 'remote')), + array('BAR=$SERVERVAR', array('BAR' => 'servervar')), array('FOO=$NOTDEFINED', array('FOO' => '')), ); @@ -222,6 +230,7 @@ public function testLoadEnv() // .env.local + $_SERVER['TEST_APP_ENV'] = 'local'; file_put_contents("$path.local", 'FOO=localBAR'); (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('localBAR', getenv('FOO')); From 2be1987ad1dca580a0dfc03e407c8a6343dd47cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 8 Jan 2019 10:39:57 +0100 Subject: [PATCH 051/495] [FrameworkBundle] Remove ControllerTrait::isFormValid() --- .../Bundle/FrameworkBundle/CHANGELOG.md | 5 - .../Controller/ControllerTrait.php | 46 ++----- .../Tests/Controller/ControllerTraitTest.php | 125 +----------------- 3 files changed, 19 insertions(+), 157 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index b2096087bc3ec..88623174b9b16 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -1,11 +1,6 @@ CHANGELOG ========= -4.3.0 ------ - - * Added `ControllerTrait::isFormValid()` - 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index 51bc264a6e6fa..0650fea5cac7f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -73,7 +73,7 @@ protected function get(string $id) * * @final */ - protected function generateUrl(string $route, array $parameters = array(), int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string + protected function generateUrl(string $route, array $parameters = [], int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string { return $this->container->get('router')->generate($route, $parameters, $referenceType); } @@ -85,7 +85,7 @@ protected function generateUrl(string $route, array $parameters = array(), int $ * * @final */ - protected function forward(string $controller, array $path = array(), array $query = array()): Response + protected function forward(string $controller, array $path = [], array $query = []): Response { $request = $this->container->get('request_stack')->getCurrentRequest(); $path['_controller'] = $controller; @@ -109,7 +109,7 @@ protected function redirect(string $url, int $status = 302): RedirectResponse * * @final */ - protected function redirectToRoute(string $route, array $parameters = array(), int $status = 302): RedirectResponse + protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse { return $this->redirect($this->generateUrl($route, $parameters), $status); } @@ -119,12 +119,12 @@ protected function redirectToRoute(string $route, array $parameters = array(), i * * @final */ - protected function json($data, int $status = 200, array $headers = array(), array $context = array()): JsonResponse + protected function json($data, int $status = 200, array $headers = [], array $context = []): JsonResponse { if ($this->container->has('serializer')) { - $json = $this->container->get('serializer')->serialize($data, 'json', array_merge(array( + $json = $this->container->get('serializer')->serialize($data, 'json', array_merge([ 'json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS, - ), $context)); + ], $context)); return new JsonResponse($json, $status, $headers, true); } @@ -203,7 +203,7 @@ protected function denyAccessUnlessGranted($attributes, $subject = null, string * * @final */ - protected function renderView(string $view, array $parameters = array()): string + protected function renderView(string $view, array $parameters = []): string { if ($this->container->has('templating')) { return $this->container->get('templating')->render($view, $parameters); @@ -221,7 +221,7 @@ protected function renderView(string $view, array $parameters = array()): string * * @final */ - protected function render(string $view, array $parameters = array(), Response $response = null): Response + protected function render(string $view, array $parameters = [], Response $response = null): Response { if ($this->container->has('templating')) { $content = $this->container->get('templating')->render($view, $parameters); @@ -245,7 +245,7 @@ protected function render(string $view, array $parameters = array(), Response $r * * @final */ - protected function stream(string $view, array $parameters = array(), StreamedResponse $response = null): StreamedResponse + protected function stream(string $view, array $parameters = [], StreamedResponse $response = null): StreamedResponse { if ($this->container->has('templating')) { $templating = $this->container->get('templating'); @@ -311,7 +311,7 @@ protected function createAccessDeniedException(string $message = 'Access Denied. * * @final */ - protected function createForm(string $type, $data = null, array $options = array()): FormInterface + protected function createForm(string $type, $data = null, array $options = []): FormInterface { return $this->container->get('form.factory')->create($type, $data, $options); } @@ -321,33 +321,11 @@ protected function createForm(string $type, $data = null, array $options = array * * @final */ - protected function createFormBuilder($data = null, array $options = array()): FormBuilderInterface + protected function createFormBuilder($data = null, array $options = []): FormBuilderInterface { return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options); } - /** - * Handles request and check form validity. - * - * @final - */ - protected function isFormValid(FormInterface $form, Request $request = null): bool - { - if ($form->isSubmitted()) { - throw new \LogicException('The form is already submitted, use $form->isValid() directly.'); - } - - if (!$request) { - $request = $this->container->get('request_stack')->getCurrentRequest(); - } - - if (!$request) { - throw new \LogicException('You must pass a request as second argument because the request stack is empty.'); - } - - return $form->handleRequest($request)->isSubmitted() && $form->isValid(); - } - /** * Shortcut to return the Doctrine Registry service. * @@ -441,7 +419,7 @@ protected function addLink(Request $request, Link $link) } if (null === $linkProvider = $request->attributes->get('_links')) { - $request->attributes->set('_links', new GenericLinkProvider(array($link))); + $request->attributes->set('_links', new GenericLinkProvider([$link])); return; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php index 0dcbc0e5db06d..ff6dba6252769 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php @@ -60,7 +60,7 @@ public function testForward() public function testGetUser() { $user = new User('user', 'pass'); - $token = new UsernamePasswordToken($user, 'pass', 'default', array('ROLE_USER')); + $token = new UsernamePasswordToken($user, 'pass', 'default', ['ROLE_USER']); $controller = $this->createController(); $controller->setContainer($this->getContainerWithTokenStorage($token)); @@ -122,7 +122,7 @@ public function testJson() $controller = $this->createController(); $controller->setContainer(new Container()); - $response = $controller->json(array()); + $response = $controller->json([]); $this->assertInstanceOf(JsonResponse::class, $response); $this->assertEquals('[]', $response->getContent()); } @@ -135,7 +135,7 @@ public function testJsonWithSerializer() $serializer ->expects($this->once()) ->method('serialize') - ->with(array(), 'json', array('json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS)) + ->with([], 'json', ['json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS]) ->will($this->returnValue('[]')); $container->set('serializer', $serializer); @@ -143,7 +143,7 @@ public function testJsonWithSerializer() $controller = $this->createController(); $controller->setContainer($container); - $response = $controller->json(array()); + $response = $controller->json([]); $this->assertInstanceOf(JsonResponse::class, $response); $this->assertEquals('[]', $response->getContent()); } @@ -156,7 +156,7 @@ public function testJsonWithSerializerContextOverride() $serializer ->expects($this->once()) ->method('serialize') - ->with(array(), 'json', array('json_encode_options' => 0, 'other' => 'context')) + ->with([], 'json', ['json_encode_options' => 0, 'other' => 'context']) ->will($this->returnValue('[]')); $container->set('serializer', $serializer); @@ -164,7 +164,7 @@ public function testJsonWithSerializerContextOverride() $controller = $this->createController(); $controller->setContainer($container); - $response = $controller->json(array(), 200, array(), array('json_encode_options' => 0, 'other' => 'context')); + $response = $controller->json([], 200, [], ['json_encode_options' => 0, 'other' => 'context']); $this->assertInstanceOf(JsonResponse::class, $response); $this->assertEquals('[]', $response->getContent()); $response->setEncodingOptions(JSON_FORCE_OBJECT); @@ -389,7 +389,7 @@ public function testAddFlash() $controller->setContainer($container); $controller->addFlash('foo', 'bar'); - $this->assertSame(array('bar'), $flashBag->get('foo')); + $this->assertSame(['bar'], $flashBag->get('foo')); } public function testCreateAccessDeniedException() @@ -517,117 +517,6 @@ public function testCreateFormBuilder() $this->assertEquals($formBuilder, $controller->createFormBuilder('foo')); } - /** - * @expectedException \LogicException - * @expectedExceptionMessage The form is already submitted, use $form->isValid() directly. - */ - public function testIsFormValidWhenAlreadySubmitted() - { - $requestStack = new RequestStack(); - $requestStack->push($request = new Request()); - - $container = new Container(); - $container->set('request_stack', $requestStack); - - $controller = $this->createController(); - $controller->setContainer($container); - - $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); - $form - ->expects($this->once()) - ->method('isSubmitted') - ->willReturn(true) - ; - - $controller->isFormValid($form); - } - - public function testIsFormValidWhenInvalid() - { - $requestStack = new RequestStack(); - $requestStack->push($request = new Request()); - - $container = new Container(); - $container->set('request_stack', $requestStack); - - $controller = $this->createController(); - $controller->setContainer($container); - - $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); - $form - ->expects($this->at(0)) - ->method('isSubmitted') - ->willReturn(false) - ; - $form - ->expects($this->once()) - ->method('handleRequest') - ->with($request) - ->willReturn($form) - ; - $form - ->expects($this->at(2)) - ->method('isSubmitted') - ->willReturn(false) - ; - - $this->assertFalse($controller->isFormValid($form)); - } - - public function testIsFormValidWhenValid() - { - $requestStack = new RequestStack(); - $requestStack->push($request = new Request()); - - $container = new Container(); - $container->set('request_stack', $requestStack); - - $controller = $this->createController(); - $controller->setContainer($container); - - $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); - $form - ->expects($this->at(0)) - ->method('isSubmitted') - ->willReturn(false) - ; - $form - ->expects($this->once()) - ->method('handleRequest') - ->with($request) - ->willReturn($form) - ; - $form - ->expects($this->at(2)) - ->method('isSubmitted') - ->willReturn(true) - ; - $form - ->expects($this->once()) - ->method('isValid') - ->willReturn(true) - ; - - $this->assertTrue($controller->isFormValid($form)); - } - - /** - * @expectedException \LogicException - * @expectedExceptionMessage You must pass a request as second argument because the request stack is empty. - */ - public function testIsFormValidWhenRequestStackIsEmpty() - { - $container = new Container(); - $container->set('request_stack', new RequestStack()); - - $controller = $this->createController(); - $controller->setContainer($container); - - $form = $this->getMockBuilder('Symfony\Component\Form\FormInterface')->getMock(); - - $this->assertTrue($controller->isFormValid($form)); - } - public function testGetDoctrine() { $doctrine = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); From 53d26e5a880c9bec3ec31ecc8c3cf59e248883a3 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 14 Jan 2019 08:47:52 -0500 Subject: [PATCH 052/495] Removing isFormValid remnants --- .../FrameworkBundle/Tests/Controller/ControllerTraitTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php index ff6dba6252769..5ba1526f38490 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php @@ -569,6 +569,5 @@ trait TestControllerTrait createFormBuilder as public; getDoctrine as public; addLink as public; - isFormValid as public; } } From e8e52355d49f208df9a9b9ceac043da5b0594ece Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 14 Jan 2019 15:19:12 +0100 Subject: [PATCH 053/495] [BrowserKit] deprecated Response::getStatus() in favor of Response::getStatusCode() --- UPGRADE-4.3.md | 5 +++++ UPGRADE-5.0.md | 1 + src/Symfony/Component/BrowserKit/CHANGELOG.md | 5 +++++ src/Symfony/Component/BrowserKit/Client.php | 4 ++-- src/Symfony/Component/BrowserKit/Response.php | 9 +++++++++ src/Symfony/Component/BrowserKit/Tests/ClientTest.php | 2 +- src/Symfony/Component/BrowserKit/Tests/ResponseTest.php | 9 +++++++++ 7 files changed, 32 insertions(+), 3 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index d6a7f00203526..a6a1f73afb94a 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -1,6 +1,11 @@ UPGRADE FROM 4.2 to 4.3 ======================= +BrowserKit +---------- + + * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead + Config ------ diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index cf677c478a5dd..ad9e6535a8bb0 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.x to 5.0 BrowserKit ---------- + * Removed `Response::getStatus()`, use `Response::getStatusCode()` instead * The `Client::submit()` method has a new `$serverParameters` argument. Cache diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index 51d8fbf48c1dd..55a8d7d518388 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead + 4.2.0 ----- diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index d483dbcb070c0..0d1382a5f08f5 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -409,7 +409,7 @@ public function request(string $method, string $uri, array $parameters = array() $this->cookieJar->updateFromResponse($this->internalResponse, $uri); - $status = $this->internalResponse->getStatus(); + $status = $this->internalResponse->getStatusCode(); if ($status >= 300 && $status < 400) { $this->redirect = $this->internalResponse->getHeader('Location'); @@ -599,7 +599,7 @@ public function followRedirect() $request = $this->internalRequest; - if (\in_array($this->internalResponse->getStatus(), array(301, 302, 303))) { + if (\in_array($this->internalResponse->getStatusCode(), array(301, 302, 303))) { $method = 'GET'; $files = array(); $content = null; diff --git a/src/Symfony/Component/BrowserKit/Response.php b/src/Symfony/Component/BrowserKit/Response.php index 6c50aeee43361..711e4d1aacf97 100644 --- a/src/Symfony/Component/BrowserKit/Response.php +++ b/src/Symfony/Component/BrowserKit/Response.php @@ -83,8 +83,17 @@ public function getContent() * Gets the response status code. * * @return int The response status code + * + * @deprecated since Symfony 4.3, use getStatusCode() instead */ public function getStatus() + { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.3, use getStatusCode() instead.', __METHOD__), E_USER_DEPRECATED); + + return $this->status; + } + + public function getStatusCode(): int { return $this->status; } diff --git a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php index 1a34c623bcb91..e4cec8b393a38 100644 --- a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php @@ -52,7 +52,7 @@ protected function doRequest($request) protected function filterResponse($response) { if ($response instanceof SpecialResponse) { - return new Response($response->getContent(), $response->getStatus(), $response->getHeaders()); + return new Response($response->getContent(), $response->getStatusCode(), $response->getHeaders()); } return $response; diff --git a/src/Symfony/Component/BrowserKit/Tests/ResponseTest.php b/src/Symfony/Component/BrowserKit/Tests/ResponseTest.php index 0ba4e3b3a71d9..8afebe454cc8b 100644 --- a/src/Symfony/Component/BrowserKit/Tests/ResponseTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/ResponseTest.php @@ -22,12 +22,21 @@ public function testGetUri() $this->assertEquals('foo', $response->getContent(), '->getContent() returns the content of the response'); } + /** + * @group legacy + */ public function testGetStatus() { $response = new Response('foo', 304); $this->assertEquals('304', $response->getStatus(), '->getStatus() returns the status of the response'); } + public function testGetStatusCode() + { + $response = new Response('foo', 304); + $this->assertEquals('304', $response->getStatusCode(), '->getStatusCode() returns the status of the response'); + } + public function testGetHeaders() { $response = new Response('foo', 200, array('foo' => 'bar')); From 0abff982e04296e7a77abd803e968f59d1e3825e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 14 Jan 2019 15:23:01 +0100 Subject: [PATCH 054/495] [BrowserKit] deprecated Response::buildHeader() --- UPGRADE-4.3.md | 1 + UPGRADE-5.0.md | 1 + src/Symfony/Component/BrowserKit/CHANGELOG.md | 1 + src/Symfony/Component/BrowserKit/Response.php | 8 ++++++-- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index a6a1f73afb94a..2e6c64b2b9b79 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.2 to 4.3 BrowserKit ---------- + * Deprecated `Response::buildHeader()` * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead Config diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index ad9e6535a8bb0..f1acd19efff1d 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.x to 5.0 BrowserKit ---------- + * Removed `Response::buildHeader()` * Removed `Response::getStatus()`, use `Response::getStatusCode()` instead * The `Client::submit()` method has a new `$serverParameters` argument. diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index 55a8d7d518388..37a724261a583 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Deprecated `Response::buildHeader()` * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead 4.2.0 diff --git a/src/Symfony/Component/BrowserKit/Response.php b/src/Symfony/Component/BrowserKit/Response.php index 711e4d1aacf97..9045da567312c 100644 --- a/src/Symfony/Component/BrowserKit/Response.php +++ b/src/Symfony/Component/BrowserKit/Response.php @@ -45,10 +45,10 @@ public function __toString() $headers = ''; foreach ($this->headers as $name => $value) { if (\is_string($value)) { - $headers .= $this->buildHeader($name, $value); + $headers .= sprintf("%s: %s\n", $name, $value); } else { foreach ($value as $headerValue) { - $headers .= $this->buildHeader($name, $headerValue); + $headers .= sprintf("%s: %s\n", $name, $headerValue); } } } @@ -63,9 +63,13 @@ public function __toString() * @param string $value The header value * * @return string The built header line + * + * @deprecated since Symfony 4.3 */ protected function buildHeader($name, $value) { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); + return sprintf("%s: %s\n", $name, $value); } From 9045a4e580d3ff1316831ac8cb78d3bfb1dce87d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 14 Jan 2019 15:42:11 +0100 Subject: [PATCH 055/495] [BrowserKit] marked Response as @final --- UPGRADE-4.3.md | 1 + UPGRADE-5.0.md | 1 + src/Symfony/Component/BrowserKit/CHANGELOG.md | 1 + src/Symfony/Component/BrowserKit/Response.php | 5 +++++ 4 files changed, 8 insertions(+) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 2e6c64b2b9b79..4eb383d46710b 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.2 to 4.3 BrowserKit ---------- + * Marked `Response` final. * Deprecated `Response::buildHeader()` * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index f1acd19efff1d..f446a7c15a378 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.x to 5.0 BrowserKit ---------- + * Removed the possibility to extend `Response` by making it final. * Removed `Response::buildHeader()` * Removed `Response::getStatus()`, use `Response::getStatusCode()` instead * The `Client::submit()` method has a new `$serverParameters` argument. diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index 37a724261a583..5ff92bb02477c 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Marked `Response` final. * Deprecated `Response::buildHeader()` * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead diff --git a/src/Symfony/Component/BrowserKit/Response.php b/src/Symfony/Component/BrowserKit/Response.php index 9045da567312c..845be10b686cf 100644 --- a/src/Symfony/Component/BrowserKit/Response.php +++ b/src/Symfony/Component/BrowserKit/Response.php @@ -13,11 +13,16 @@ /** * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class Response { + /** @internal */ protected $content; + /** @internal */ protected $status; + /** @internal */ protected $headers; /** From eb75781ccd0549aca241128aaa1ee58984c2ade8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 16 Jan 2019 07:59:14 +0100 Subject: [PATCH 056/495] simplified PHPUnit exception expectations --- .../Security/User/EntityUserProviderTest.php | 4 ++-- .../Component/BrowserKit/Tests/CookieTest.php | 4 ++-- .../Console/Tests/Command/CommandTest.php | 2 +- .../Formatter/OutputFormatterStyleTest.php | 4 ++-- .../CssSelector/Tests/Parser/ParserTest.php | 2 +- .../Tests/Parser/TokenStreamTest.php | 4 ++-- .../Tests/ContainerBuilderTest.php | 2 +- .../EventDispatcher/Tests/GenericEventTest.php | 2 +- .../DateIntervalToArrayTransformerTest.php | 4 ++-- .../DateIntervalToStringTransformerTest.php | 8 ++++---- ...ateTimeToLocalizedStringTransformerTest.php | 2 +- .../DateTimeToStringTransformerTest.php | 8 ++++---- .../DateTimeToTimestampTransformerTest.php | 4 ++-- .../MoneyToLocalizedStringTransformerTest.php | 4 ++-- ...PercentToLocalizedStringTransformerTest.php | 4 ++-- .../Extension/Core/Type/CollectionTypeTest.php | 2 +- .../Component/Form/Tests/FormBuilderTest.php | 4 ++-- .../HttpFoundation/Tests/File/FileTest.php | 2 +- .../Tests/File/MimeType/MimeTypeTest.php | 6 +++--- .../Tests/File/UploadedFileTest.php | 2 +- .../Tests/Config/FileLocatorTest.php | 2 +- .../AbstractNumberFormatterTest.php | 6 +++--- .../Ldap/Tests/Adapter/ExtLdap/AdapterTest.php | 2 +- .../Tests/Adapter/ExtLdap/LdapManagerTest.php | 18 +++++++++--------- src/Symfony/Component/Ldap/Tests/LdapTest.php | 2 +- .../Tests/Generator/UrlGeneratorTest.php | 2 +- .../Routing/Tests/Matcher/UrlMatcherTest.php | 6 +++--- .../Templating/Tests/PhpEngineTest.php | 2 +- .../Tests/Catalogue/AbstractOperationTest.php | 2 +- .../Validator/Tests/ConstraintTest.php | 10 +++++----- .../Tests/Mapping/ClassMetadataTest.php | 4 ++-- .../Tests/Mapping/GetterMetadataTest.php | 2 +- .../Tests/Mapping/Loader/XmlFileLoaderTest.php | 4 ++-- .../Mapping/Loader/YamlFileLoaderTest.php | 2 +- .../Tests/Mapping/MemberMetadataTest.php | 2 +- .../Tests/Mapping/PropertyMetadataTest.php | 4 ++-- 36 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php index 9d0f79948ba6e..aa09feecdac7f 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php @@ -105,7 +105,7 @@ public function testRefreshUserRequiresId() $user1 = new User(null, null, 'user1'); $provider = new EntityUserProvider($this->getManager($em), 'Symfony\Bridge\Doctrine\Tests\Fixtures\User', 'name'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}( + $this->expectException( 'InvalidArgumentException', 'You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine' ); @@ -125,7 +125,7 @@ public function testRefreshInvalidUser() $provider = new EntityUserProvider($this->getManager($em), 'Symfony\Bridge\Doctrine\Tests\Fixtures\User', 'name'); $user2 = new User(1, 2, 'user2'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}( + $this->expectException( 'Symfony\Component\Security\Core\Exception\UsernameNotFoundException', 'User with id {"id1":1,"id2":2} not found' ); diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php index 41628b70144a7..838da8ef145b7 100644 --- a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php @@ -103,7 +103,7 @@ public function testFromStringWithUrl() public function testFromStringThrowsAnExceptionIfCookieIsNotValid() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); Cookie::fromString('foo'); } @@ -116,7 +116,7 @@ public function testFromStringIgnoresInvalidExpiresDate() public function testFromStringThrowsAnExceptionIfUrlIsNotValid() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); Cookie::fromString('foo=bar', 'foobar'); } diff --git a/src/Symfony/Component/Console/Tests/Command/CommandTest.php b/src/Symfony/Component/Console/Tests/Command/CommandTest.php index 41df51b3e17dc..2ee16423b64fb 100644 --- a/src/Symfony/Component/Console/Tests/Command/CommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/CommandTest.php @@ -188,7 +188,7 @@ public function testGetSetAliases() public function testSetAliasesNull() { $command = new \TestCommand(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $command->setAliases(null); } diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php index 6b675784460b4..4f2c73415d691 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterStyleTest.php @@ -41,7 +41,7 @@ public function testForeground() $style->setForeground('default'); $this->assertEquals("\033[39mfoo\033[39m", $style->apply('foo')); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $style->setForeground('undefined-color'); } @@ -58,7 +58,7 @@ public function testBackground() $style->setBackground('default'); $this->assertEquals("\033[49mfoo\033[49m", $style->apply('foo')); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $style->setBackground('undefined-color'); } diff --git a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php index 024be8101eab5..66403d4f49067 100644 --- a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php +++ b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php @@ -89,7 +89,7 @@ public function testParseSeriesException($series) /** @var FunctionNode $function */ $function = $selectors[0]->getTree(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\CssSelector\Exception\SyntaxErrorException'); + $this->expectException('Symfony\Component\CssSelector\Exception\SyntaxErrorException'); Parser::parseSeries($function->getArguments()); } diff --git a/src/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php b/src/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php index 44c751ac865d2..fb47625a89ac5 100644 --- a/src/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php +++ b/src/Symfony/Component/CssSelector/Tests/Parser/TokenStreamTest.php @@ -53,7 +53,7 @@ public function testGetNextIdentifier() public function testFailToGetNextIdentifier() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\CssSelector\Exception\SyntaxErrorException'); + $this->expectException('Symfony\Component\CssSelector\Exception\SyntaxErrorException'); $stream = new TokenStream(); $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2)); @@ -73,7 +73,7 @@ public function testGetNextIdentifierOrStar() public function testFailToGetNextIdentifierOrStar() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\CssSelector\Exception\SyntaxErrorException'); + $this->expectException('Symfony\Component\CssSelector\Exception\SyntaxErrorException'); $stream = new TokenStream(); $stream->push(new Token(Token::TYPE_DELIMITER, '.', 2)); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index d8a671b5830ea..b09da4621b9c1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -1008,7 +1008,7 @@ public function testExtension() $container->registerExtension($extension = new \ProjectExtension()); $this->assertSame($container->getExtension('project'), $extension, '->registerExtension() registers an extension'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException'); + $this->expectException('LogicException'); $container->getExtension('no_registered'); } diff --git a/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php b/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php index b63f69df1456f..44485c9930e62 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/GenericEventTest.php @@ -92,7 +92,7 @@ public function testOffsetGet() $this->assertEquals('Event', $this->event['name']); // test getting invalid arg - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $this->assertFalse($this->event['nameNotExist']); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php index a75fe1145c57e..f05f321da7f75 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php @@ -176,7 +176,7 @@ public function testReverseTransformRequiresDateTime() { $transformer = new DateIntervalToArrayTransformer(); $this->assertNull($transformer->reverseTransform(null)); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(UnexpectedTypeException::class); + $this->expectException(UnexpectedTypeException::class); $transformer->reverseTransform('12345'); } @@ -184,7 +184,7 @@ public function testReverseTransformWithUnsetFields() { $transformer = new DateIntervalToArrayTransformer(); $input = array('years' => '1'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(TransformationFailedException::class); + $this->expectException(TransformationFailedException::class); $transformer->reverseTransform($input); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php index 389e0c161d04a..0029e2fda7bf9 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToStringTransformerTest.php @@ -75,7 +75,7 @@ public function testTransformEmpty() public function testTransformExpectsDateTime() { $transformer = new DateIntervalToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(UnexpectedTypeException::class); + $this->expectException(UnexpectedTypeException::class); $transformer->transform('1234'); } @@ -96,7 +96,7 @@ public function testReverseTransformDateString($format, $input, $output) { $reverseTransformer = new DateIntervalToStringTransformer($format, true); $interval = new \DateInterval($output); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(TransformationFailedException::class); + $this->expectException(TransformationFailedException::class); $this->assertDateIntervalEquals($interval, $reverseTransformer->reverseTransform($input)); } @@ -109,14 +109,14 @@ public function testReverseTransformEmpty() public function testReverseTransformExpectsString() { $reverseTransformer = new DateIntervalToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(UnexpectedTypeException::class); + $this->expectException(UnexpectedTypeException::class); $reverseTransformer->reverseTransform(1234); } public function testReverseTransformExpectsValidIntervalString() { $reverseTransformer = new DateIntervalToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(TransformationFailedException::class); + $this->expectException(TransformationFailedException::class); $reverseTransformer->reverseTransform('10Y'); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 5653efabd8ee9..ea25c7320e87b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -196,7 +196,7 @@ public function testTransformWrapsIntlErrors() // HOW TO REPRODUCE? - //$this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Extension\Core\DataTransformer\TransformationFailedException'); + //$this->expectException('Symfony\Component\Form\Extension\Core\DataTransformer\TransformationFailedException'); //$transformer->transform(1.5); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php index c4d04e0e0f5f5..cc2681b3053f2 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php @@ -111,7 +111,7 @@ public function testTransformExpectsDateTime() { $transformer = new DateTimeToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $transformer->transform('1234'); } @@ -150,7 +150,7 @@ public function testReverseTransformExpectsString() { $reverseTransformer = new DateTimeToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $reverseTransformer->reverseTransform(1234); } @@ -159,7 +159,7 @@ public function testReverseTransformExpectsValidDateString() { $reverseTransformer = new DateTimeToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $reverseTransformer->reverseTransform('2010-2010-2010'); } @@ -168,7 +168,7 @@ public function testReverseTransformWithNonExistingDate() { $reverseTransformer = new DateTimeToStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $reverseTransformer->reverseTransform('2010-04-31'); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php index ecd5b70b97de6..4462108cf8d1a 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php @@ -72,7 +72,7 @@ public function testTransformExpectsDateTime() { $transformer = new DateTimeToTimestampTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $transformer->transform('1234'); } @@ -109,7 +109,7 @@ public function testReverseTransformExpectsValidTimestamp() { $reverseTransformer = new DateTimeToTimestampTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $reverseTransformer->reverseTransform('2010-2010-2010'); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php index d9fafdff13a35..0fbf8af6c20fc 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php @@ -33,7 +33,7 @@ public function testTransformExpectsNumeric() { $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $transformer->transform('abcd'); } @@ -61,7 +61,7 @@ public function testReverseTransformExpectsString() { $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $transformer->reverseTransform(12345); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index 3467e891c9bdd..4d7909d3a6f39 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -106,7 +106,7 @@ public function testTransformExpectsNumeric() { $transformer = new PercentToLocalizedStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $transformer->transform('foo'); } @@ -115,7 +115,7 @@ public function testReverseTransformExpectsString() { $transformer = new PercentToLocalizedStringTransformer(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\TransformationFailedException'); + $this->expectException('Symfony\Component\Form\Exception\TransformationFailedException'); $transformer->reverseTransform(1); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php index 9393c99dc0fd8..56ae48ce70fd8 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -61,7 +61,7 @@ public function testThrowsExceptionIfObjectIsNotTraversable() $form = $this->factory->create(static::TESTED_TYPE, null, array( 'entry_type' => TextTypeTest::TESTED_TYPE, )); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\UnexpectedTypeException'); + $this->expectException('Symfony\Component\Form\Exception\UnexpectedTypeException'); $form->setData(new \stdClass()); } diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index 0326f545af39e..d0adfb5508b99 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -51,13 +51,13 @@ public function testNoSetName() public function testAddNameNoStringAndNoInteger() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\UnexpectedTypeException'); + $this->expectException('Symfony\Component\Form\Exception\UnexpectedTypeException'); $this->builder->add(true); } public function testAddTypeNoString() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Form\Exception\UnexpectedTypeException'); + $this->expectException('Symfony\Component\Form\Exception\UnexpectedTypeException'); $this->builder->add('foo', 1234); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php index dbd9c44bd802c..8935a4310cfe0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php @@ -64,7 +64,7 @@ public function testGuessExtensionWithReset() public function testConstructWhenFileNotExists() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); new File(__DIR__.'/Fixtures/not_here'); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index bb88807ab0519..3960988a6a654 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -29,7 +29,7 @@ public function testGuessImageWithoutExtension() public function testGuessImageWithDirectory() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/directory'); } @@ -53,7 +53,7 @@ public function testGuessFileWithUnknownExtension() public function testGuessWithIncorrectPath() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/not_here'); } @@ -72,7 +72,7 @@ public function testGuessWithNonReadablePath() @chmod($path, 0333); if ('0333' == substr(sprintf('%o', fileperms($path)), -4)) { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException'); MimeTypeGuesser::getInstance()->guess($path); } else { $this->markTestSkipped('Can not verify chmod operations, change of file permissions failed'); diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php index 6a0b550d791d3..89eb359dbcc7e 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php @@ -33,7 +33,7 @@ protected function setUp() public function testConstructWhenFileNotExists() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); new UploadedFile( __DIR__.'/Fixtures/not_here', diff --git a/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php b/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php index 6265f0275560a..ca1b3191bd552 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Config/FileLocatorTest.php @@ -30,7 +30,7 @@ public function testLocate() $kernel ->expects($this->never()) ->method('locateResource'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException'); + $this->expectException('LogicException'); $locator->locate('/some/path'); } diff --git a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php index 89be79574de97..560306df7805c 100644 --- a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php @@ -329,7 +329,7 @@ public function testFormatTypeCurrency($formatter, $value) $exceptionCode = 'PHPUnit_Framework_Error_Warning'; } - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}($exceptionCode); + $this->expectException($exceptionCode); $formatter->format($value, NumberFormatter::TYPE_CURRENCY); } @@ -712,7 +712,7 @@ public function testParseTypeDefault() $exceptionCode = 'PHPUnit_Framework_Error_Warning'; } - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}($exceptionCode); + $this->expectException($exceptionCode); $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL); $formatter->parse('1', NumberFormatter::TYPE_DEFAULT); @@ -838,7 +838,7 @@ public function testParseTypeCurrency() $exceptionCode = 'PHPUnit_Framework_Error_Warning'; } - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}($exceptionCode); + $this->expectException($exceptionCode); $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL); $formatter->parse('1', NumberFormatter::TYPE_CURRENCY); diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php index f238361879425..fbd49359dd2f6 100644 --- a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php @@ -74,7 +74,7 @@ public function testLdapQueryIterator() public function testLdapQueryWithoutBind() { $ldap = new Adapter($this->getLdapConfig()); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(NotBoundException::class); + $this->expectException(NotBoundException::class); $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', array()); $query->execute(); } diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php index 94acb3e3494bc..2ce82b219f620 100644 --- a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php @@ -61,7 +61,7 @@ public function testLdapAddAndRemove() */ public function testLdapAddInvalidEntry() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(LdapException::class); + $this->expectException(LdapException::class); $this->executeSearchQuery(1); // The entry is missing a subject name @@ -107,7 +107,7 @@ public function testLdapUpdate() public function testLdapUnboundAdd() { $this->adapter = new Adapter($this->getLdapConfig()); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(NotBoundException::class); + $this->expectException(NotBoundException::class); $em = $this->adapter->getEntryManager(); $em->add(new Entry('')); } @@ -118,7 +118,7 @@ public function testLdapUnboundAdd() public function testLdapUnboundRemove() { $this->adapter = new Adapter($this->getLdapConfig()); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(NotBoundException::class); + $this->expectException(NotBoundException::class); $em = $this->adapter->getEntryManager(); $em->remove(new Entry('')); } @@ -129,7 +129,7 @@ public function testLdapUnboundRemove() public function testLdapUnboundUpdate() { $this->adapter = new Adapter($this->getLdapConfig()); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(NotBoundException::class); + $this->expectException(NotBoundException::class); $em = $this->adapter->getEntryManager(); $em->update(new Entry('')); } @@ -224,7 +224,7 @@ public function testLdapRemoveAttributeValuesError() $result = $this->executeSearchQuery(1); $entry = $result[0]; - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(LdapException::class); + $this->expectException(LdapException::class); $entryManager->removeAttributeValues($entry, 'mail', array('fabpot@example.org')); } @@ -236,7 +236,7 @@ public function testLdapAddAttributeValuesError() $result = $this->executeSearchQuery(1); $entry = $result[0]; - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(LdapException::class); + $this->expectException(LdapException::class); $entryManager->addAttributeValues($entry, 'mail', $entry->getAttribute('mail')); } @@ -248,7 +248,7 @@ public function testLdapApplyOperationsRemoveAllWithArrayError() $result = $this->executeSearchQuery(1); $entry = $result[0]; - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(UpdateOperationException::class); + $this->expectException(UpdateOperationException::class); $entryManager->applyOperations($entry->getDn(), array(new UpdateOperation(LDAP_MODIFY_BATCH_REMOVE_ALL, 'mail', array()))); } @@ -260,7 +260,7 @@ public function testLdapApplyOperationsWithWrongConstantError() $result = $this->executeSearchQuery(1); $entry = $result[0]; - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(UpdateOperationException::class); + $this->expectException(UpdateOperationException::class); $entryManager->applyOperations($entry->getDn(), array(new UpdateOperation(512, 'mail', array()))); } @@ -337,7 +337,7 @@ public function testUpdateOperationsThrowsExceptionWhenAddedDuplicatedValue() $result = $this->executeSearchQuery(1); $entry = $result[0]; - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(UpdateOperationException::class); + $this->expectException(UpdateOperationException::class); $entryManager->applyOperations($entry->getDn(), $duplicateIterator); } diff --git a/src/Symfony/Component/Ldap/Tests/LdapTest.php b/src/Symfony/Component/Ldap/Tests/LdapTest.php index 17184323f41cc..139bb6952e414 100644 --- a/src/Symfony/Component/Ldap/Tests/LdapTest.php +++ b/src/Symfony/Component/Ldap/Tests/LdapTest.php @@ -78,7 +78,7 @@ public function testLdapCreate() public function testCreateWithInvalidAdapterName() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(DriverNotFoundException::class); + $this->expectException(DriverNotFoundException::class); Ldap::create('foo'); } } diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index bb248d0fcd997..44edbe78285fb 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -368,7 +368,7 @@ public function testAdjacentVariables() // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything // and following optional variables like _format could never match. - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\InvalidParameterException'); + $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml')); } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 791fb5ecb3c23..dbb9b85b83907 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -231,7 +231,7 @@ public function testMatchOverriddenRoute() $matcher = $this->getUrlMatcher($collection); $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1')); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\ResourceNotFoundException'); + $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $this->assertEquals(array(), $matcher->match('/foo')); } @@ -300,7 +300,7 @@ public function testAdjacentVariables() // z and _format are optional. $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z', '_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxy')); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\ResourceNotFoundException'); + $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $matcher->match('/wxy.html'); } @@ -315,7 +315,7 @@ public function testOptionalVariableWithNoRealSeparator() // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match. // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it. - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\ResourceNotFoundException'); + $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $matcher->match('/ge'); } diff --git a/src/Symfony/Component/Templating/Tests/PhpEngineTest.php b/src/Symfony/Component/Templating/Tests/PhpEngineTest.php index f677c3028d031..0102f85af54e3 100644 --- a/src/Symfony/Component/Templating/Tests/PhpEngineTest.php +++ b/src/Symfony/Component/Templating/Tests/PhpEngineTest.php @@ -86,7 +86,7 @@ public function testUnsetHelper() $foo = new \Symfony\Component\Templating\Tests\Fixtures\SimpleHelper('foo'); $engine->set($foo); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('\LogicException'); + $this->expectException('\LogicException'); unset($engine['foo']); } diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php b/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php index 90cf4a5dc381e..cc098881d3914 100644 --- a/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php +++ b/src/Symfony/Component/Translation/Tests/Catalogue/AbstractOperationTest.php @@ -41,7 +41,7 @@ public function testGetMergedDomains() public function testGetMessagesFromUnknownDomain() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $this->createOperation( new MessageCatalogue('en'), new MessageCatalogue('en') diff --git a/src/Symfony/Component/Validator/Tests/ConstraintTest.php b/src/Symfony/Component/Validator/Tests/ConstraintTest.php index a05741490fdde..7c21d601ae8aa 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintTest.php @@ -35,7 +35,7 @@ public function testSetProperties() public function testSetNotExistingPropertyThrowsException() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\InvalidOptionsException'); + $this->expectException('Symfony\Component\Validator\Exception\InvalidOptionsException'); new ConstraintA(array( 'foo' => 'bar', @@ -46,14 +46,14 @@ public function testMagicPropertiesAreNotAllowed() { $constraint = new ConstraintA(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\InvalidOptionsException'); + $this->expectException('Symfony\Component\Validator\Exception\InvalidOptionsException'); $constraint->foo = 'bar'; } public function testInvalidAndRequiredOptionsPassed() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\InvalidOptionsException'); + $this->expectException('Symfony\Component\Validator\Exception\InvalidOptionsException'); new ConstraintC(array( 'option1' => 'default', @@ -101,14 +101,14 @@ public function testDontSetDefaultPropertyIfValuePropertyExists() public function testSetUndefinedDefaultProperty() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); + $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); new ConstraintB('foo'); } public function testRequiredOptionsMustBeDefined() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\MissingOptionsException'); + $this->expectException('Symfony\Component\Validator\Exception\MissingOptionsException'); new ConstraintC(); } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php index a3f8a8c1ec8a3..361899b9f5ac9 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php @@ -40,14 +40,14 @@ protected function tearDown() public function testAddConstraintDoesNotAcceptValid() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); + $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); $this->metadata->addConstraint(new Valid()); } public function testAddConstraintRequiresClassConstraints() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); + $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); $this->metadata->addConstraint(new PropertyConstraint()); } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php index 05aef47e84aaf..ac4ea5668a6db 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php @@ -21,7 +21,7 @@ class GetterMetadataTest extends TestCase public function testInvalidPropertyName() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ValidatorException'); + $this->expectException('Symfony\Component\Validator\Exception\ValidatorException'); new GetterMetadata(self::CLASSNAME, 'foobar'); } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php index 100e4fa062fc1..affdaf3c37fac 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/XmlFileLoaderTest.php @@ -114,7 +114,7 @@ public function testThrowExceptionIfDocTypeIsSet() $loader = new XmlFileLoader(__DIR__.'/withdoctype.xml'); $metadata = new ClassMetadata('Symfony\Component\Validator\Tests\Fixtures\Entity'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('\Symfony\Component\Validator\Exception\MappingException'); + $this->expectException('\Symfony\Component\Validator\Exception\MappingException'); $loader->loadClassMetadata($metadata); } @@ -129,7 +129,7 @@ public function testDoNotModifyStateIfExceptionIsThrown() try { $loader->loadClassMetadata($metadata); } catch (MappingException $e) { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('\Symfony\Component\Validator\Exception\MappingException'); + $this->expectException('\Symfony\Component\Validator\Exception\MappingException'); $loader->loadClassMetadata($metadata); } } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/YamlFileLoaderTest.php index 9920fb0737ae9..4b2bbcb62f9e7 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/YamlFileLoaderTest.php @@ -69,7 +69,7 @@ public function testDoNotModifyStateIfExceptionIsThrown() $loader->loadClassMetadata($metadata); } catch (\InvalidArgumentException $e) { // Call again. Again an exception should be thrown - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('\InvalidArgumentException'); + $this->expectException('\InvalidArgumentException'); $loader->loadClassMetadata($metadata); } } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/MemberMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/MemberMetadataTest.php index 593f90faa66b6..d7736de3407c4 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/MemberMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/MemberMetadataTest.php @@ -38,7 +38,7 @@ protected function tearDown() public function testAddConstraintRequiresClassConstraints() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); + $this->expectException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); $this->metadata->addConstraint(new ClassConstraint()); } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php index 9fea435dff279..7902625219ba9 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/PropertyMetadataTest.php @@ -22,7 +22,7 @@ class PropertyMetadataTest extends TestCase public function testInvalidPropertyName() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ValidatorException'); + $this->expectException('Symfony\Component\Validator\Exception\ValidatorException'); new PropertyMetadata(self::CLASSNAME, 'foobar'); } @@ -50,7 +50,7 @@ public function testGetPropertyValueFromRemovedProperty() $metadata = new PropertyMetadata(self::CLASSNAME, 'internal'); $metadata->name = 'test'; - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Validator\Exception\ValidatorException'); + $this->expectException('Symfony\Component\Validator\Exception\ValidatorException'); $metadata->getPropertyValue($entity); } } From 02bd6893a53ccc09295162bc8d06be93bbbc727c Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sat, 12 Jan 2019 17:21:48 +0100 Subject: [PATCH 057/495] Add block prefix to csrf token field --- .../Extension/Csrf/Type/FormTypeCsrfExtension.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php index 4a39b1d999a91..5e5f26ff74790 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -90,9 +90,10 @@ public function finishView(FormView $view, FormInterface $form, array $options) $tokenId = $options['csrf_token_id'] ?: ($form->getName() ?: \get_class($form->getConfig()->getType()->getInnerType())); $data = (string) $options['csrf_token_manager']->getToken($tokenId); - $csrfForm = $factory->createNamed($options['csrf_field_name'], 'Symfony\Component\Form\Extension\Core\Type\HiddenType', $data, array( + $csrfForm = $factory->createNamed($options['csrf_field_name'], 'Symfony\Component\Form\Extension\Core\Type\HiddenType', $data, [ + 'block_prefix' => 'csrf_token', 'mapped' => false, - )); + ]); $view->children[$options['csrf_field_name']] = $csrfForm->createView($view); } @@ -103,13 +104,13 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setDefaults(array( + $resolver->setDefaults([ 'csrf_protection' => $this->defaultEnabled, 'csrf_field_name' => $this->defaultFieldName, 'csrf_message' => 'The CSRF token is invalid. Please try to resubmit the form.', 'csrf_token_manager' => $this->defaultTokenManager, 'csrf_token_id' => null, - )); + ]); } /** @@ -117,6 +118,6 @@ public function configureOptions(OptionsResolver $resolver) */ public static function getExtendedTypes(): iterable { - return array(FormType::class); + return [FormType::class]; } } From 18b9e45f4a8cbb69b89b1af187be30a6f804eda4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 16 Jan 2019 22:53:45 +0100 Subject: [PATCH 058/495] fixed CS --- .../Bridge/PhpUnit/ClassExistsMock.php | 6 +- .../PhpUnit/Tests/ClassExistsMockTest.php | 4 +- .../DependencyInjection/Configuration.php | 2 +- .../DependencyInjection/DebugExtension.php | 6 +- src/Symfony/Component/BrowserKit/Client.php | 32 +- .../Formatter/OutputFormatterStyle.php | 68 ++-- .../Tests/Formatter/OutputFormatterTest.php | 18 +- .../Component/Debug/DebugClassLoader.php | 48 +-- .../DependencyInjection/Dumper/PhpDumper.php | 116 +++--- .../DependencyInjection/EnvVarProcessor.php | 4 +- .../Tests/Compiler/AutowirePassTest.php | 2 +- .../RegisterEnvVarProcessorsPassTest.php | 36 +- .../ValidateEnvPlaceholdersPassTest.php | 8 +- .../Tests/Dumper/PhpDumperTest.php | 2 +- .../DomCrawler/Tests/CrawlerTest.php | 62 ++-- .../Component/Dotenv/Tests/DotenvTest.php | 200 +++++------ .../EventDispatcher/EventDispatcher.php | 24 +- .../Tests/EventDispatcherTest.php | 104 +++--- .../Form/Extension/Core/Type/BaseType.php | 2 +- .../DateIntervalToArrayTransformerTest.php | 96 ++--- .../Core/Type/CollectionTypeTest.php | 204 +++++------ .../Extension/Core/Type/FormTypeTest.php | 6 +- .../DataCollector/DumpDataCollector.php | 4 +- .../DataCollector/LoggerDataCollector.php | 48 +-- .../AddRequestFormatsListener.php | 2 +- .../EventListener/LocaleListener.php | 14 +- .../AddRequestFormatsListenerTest.php | 6 +- .../EventListener/LocaleListenerTest.php | 8 +- .../Tests/Adapter/ExtLdap/AdapterTest.php | 26 +- .../Routing/Generator/UrlGenerator.php | 22 +- .../Component/Routing/RouteCompiler.php | 24 +- .../Tests/Generator/UrlGeneratorTest.php | 334 +++++++++--------- .../Routing/Tests/Matcher/UrlMatcherTest.php | 212 +++++------ .../Serializer/Encoder/CsvEncoder.php | 42 +-- .../Tests/Encoder/CsvEncoderTest.php | 10 +- .../Translation/Loader/XliffFileLoader.php | 22 +- .../Tests/Loader/XliffFileLoaderTest.php | 92 ++--- .../Validator/Constraints/BicValidator.php | 4 +- .../Constraints/CardSchemeValidator.php | 48 +-- .../Tests/Constraints/BicValidatorTest.php | 50 +-- .../Constraints/CardSchemeValidatorTest.php | 142 ++++---- .../Tests/Constraints/RegexValidatorTest.php | 40 +-- .../VarDumper/Caster/ResourceCaster.php | 12 +- .../VarDumper/Cloner/AbstractCloner.php | 256 +++++++------- .../Command/Descriptor/CliDescriptor.php | 14 +- .../Component/VarDumper/Dumper/CliDumper.php | 6 +- .../Command/Descriptor/CliDescriptorTest.php | 64 ++-- .../Component/Workflow/Tests/WorkflowTest.php | 62 ++-- 48 files changed, 1307 insertions(+), 1307 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php b/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php index 23869c033d7da..e8ca4ac9402a8 100644 --- a/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php +++ b/src/Symfony/Bridge/PhpUnit/ClassExistsMock.php @@ -16,7 +16,7 @@ */ class ClassExistsMock { - private static $classes = array(); + private static $classes = []; /** * Configures the classes to be checked upon existence. @@ -47,7 +47,7 @@ public static function register($class) { $self = \get_called_class(); - $mockedNs = array(substr($class, 0, strrpos($class, '\\'))); + $mockedNs = [substr($class, 0, strrpos($class, '\\'))]; if (0 < strpos($class, '\\Tests\\')) { $ns = str_replace('\\Tests\\', '\\', $class); $mockedNs[] = substr($ns, 0, strrpos($ns, '\\')); @@ -55,7 +55,7 @@ public static function register($class) $mockedNs[] = substr($class, 6, strrpos($class, '\\') - 6); } foreach ($mockedNs as $ns) { - foreach (array('class', 'interface', 'trait') as $type) { + foreach (['class', 'interface', 'trait'] as $type) { if (\function_exists($ns.'\\'.$type.'_exists')) { continue; } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ClassExistsMockTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ClassExistsMockTest.php index 30d8edf95f630..002d313a6fa01 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/ClassExistsMockTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/ClassExistsMockTest.php @@ -23,14 +23,14 @@ public static function setUpBeforeClass() protected function setUp() { - ClassExistsMock::withMockedClasses(array( + ClassExistsMock::withMockedClasses([ ExistingClass::class => false, 'NonExistingClass' => true, ExistingInterface::class => false, 'NonExistingInterface' => true, ExistingTrait::class => false, 'NonExistingTrait' => true, - )); + ]); } public function testClassExists() diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php index 5f98efab0d9a8..e3a724cd2448a 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Configuration.php @@ -60,7 +60,7 @@ public function getConfigTreeBuilder() ->enumNode('theme') ->info('Changes the color of the dump() output when rendered directly on the templating. "dark" (default) or "light"') ->example('dark') - ->values(array('dark', 'light')) + ->values(['dark', 'light']) ->defaultValue('dark') ->end() ->end() diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php index da07d970510b6..9c098a09962b0 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php @@ -45,7 +45,7 @@ public function load(array $configs, ContainerBuilder $container) if (method_exists(HtmlDumper::class, 'setTheme') && 'dark' !== $config['theme']) { $container->getDefinition('var_dumper.html_dumper') - ->addMethodCall('setTheme', array($config['theme'])); + ->addMethodCall('setTheme', [$config['theme']]); } if (null === $config['dump_destination']) { @@ -79,9 +79,9 @@ public function load(array $configs, ContainerBuilder $container) if (method_exists(CliDumper::class, 'setDisplayOptions')) { $container->getDefinition('var_dumper.cli_dumper') - ->addMethodCall('setDisplayOptions', array(array( + ->addMethodCall('setDisplayOptions', [[ 'fileLinkFormat' => new Reference('debug.file_link_formatter', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), - ))) + ]]) ; } } diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index 0d1382a5f08f5..461f5f5e54778 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -31,7 +31,7 @@ abstract class Client { protected $history; protected $cookieJar; - protected $server = array(); + protected $server = []; protected $internalRequest; protected $request; protected $internalResponse; @@ -44,7 +44,7 @@ abstract class Client private $maxRedirects = -1; private $redirectCount = 0; - private $redirects = array(); + private $redirects = []; private $isMainRequest = true; /** @@ -52,7 +52,7 @@ abstract class Client * @param History $history A History instance to store the browser history * @param CookieJar $cookieJar A CookieJar instance to store the cookies */ - public function __construct(array $server = array(), History $history = null, CookieJar $cookieJar = null) + public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) { $this->setServerParameters($server); $this->history = $history ?: new History(); @@ -131,9 +131,9 @@ public function insulate($insulated = true) */ public function setServerParameters(array $server) { - $this->server = array_merge(array( + $this->server = array_merge([ 'HTTP_USER_AGENT' => 'Symfony BrowserKit', - ), $server); + ], $server); } /** @@ -160,7 +160,7 @@ public function getServerParameter($key, $default = '') return isset($this->server[$key]) ? $this->server[$key] : $default; } - public function xmlHttpRequest(string $method, string $uri, array $parameters = array(), array $files = array(), array $server = array(), string $content = null, bool $changeHistory = true): Crawler + public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler { $this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest'); @@ -313,14 +313,14 @@ public function clickLink(string $linkText): Crawler * * @return Crawler */ - public function submit(Form $form, array $values = array()/*, array $serverParameters = array()*/) + public function submit(Form $form, array $values = []/*, array $serverParameters = array()*/) { if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { @trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = array()" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); } $form->setValues($values); - $serverParameters = 2 < \func_num_args() ? func_get_arg(2) : array(); + $serverParameters = 2 < \func_num_args() ? func_get_arg(2) : []; return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles(), $serverParameters); } @@ -334,7 +334,7 @@ public function submit(Form $form, array $values = array()/*, array $serverParam * @param string $method The HTTP method used to submit the form * @param array $serverParameters These values override the ones stored in $_SERVER (HTTP headers must include a HTTP_ prefix as PHP does) */ - public function submitForm(string $button, array $fieldValues = array(), string $method = 'POST', array $serverParameters = array()): Crawler + public function submitForm(string $button, array $fieldValues = [], string $method = 'POST', array $serverParameters = []): Crawler { if (null === $this->crawler) { throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); @@ -343,7 +343,7 @@ public function submitForm(string $button, array $fieldValues = array(), string $buttonNode = $this->crawler->selectButton($button); $form = $buttonNode->form($fieldValues, $method); - return $this->submit($form, array(), $serverParameters); + return $this->submit($form, [], $serverParameters); } /** @@ -359,7 +359,7 @@ public function submitForm(string $button, array $fieldValues = array(), string * * @return Crawler */ - public function request(string $method, string $uri, array $parameters = array(), array $files = array(), array $server = array(), string $content = null, bool $changeHistory = true) + public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true) { if ($this->isMainRequest) { $this->redirectCount = 0; @@ -455,7 +455,7 @@ protected function doRequestInProcess($request) if (file_exists($deprecationsFile)) { $deprecations = file_get_contents($deprecationsFile); unlink($deprecationsFile); - foreach ($deprecations ? unserialize($deprecations) : array() as $deprecation) { + foreach ($deprecations ? unserialize($deprecations) : [] as $deprecation) { if ($deprecation[0]) { @trigger_error($deprecation[1], E_USER_DEPRECATED); } else { @@ -599,9 +599,9 @@ public function followRedirect() $request = $this->internalRequest; - if (\in_array($this->internalResponse->getStatusCode(), array(301, 302, 303))) { + if (\in_array($this->internalResponse->getStatusCode(), [301, 302, 303])) { $method = 'GET'; - $files = array(); + $files = []; $content = null; } else { $method = $request->getMethod(); @@ -611,7 +611,7 @@ public function followRedirect() if ('GET' === strtoupper($method)) { // Don't forward parameters for GET request as it should reach the redirection URI - $parameters = array(); + $parameters = []; } else { $parameters = $request->getParameters(); } @@ -634,7 +634,7 @@ public function followRedirect() private function getMetaRefreshUrl(): ?string { $metaRefresh = $this->getCrawler()->filter('head meta[http-equiv="refresh"]'); - foreach ($metaRefresh->extract(array('content')) as $content) { + foreach ($metaRefresh->extract(['content']) as $content) { if (preg_match('/^\s*0\s*;\s*URL\s*=\s*(?|\'([^\']++)|"([^"]++)|([^\'"].*))/i', $content, $m)) { return str_replace("\t\r\n", '', rtrim($m[1])); } diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php index 4c9265599816b..6a181f8ff6751 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatterStyle.php @@ -20,40 +20,40 @@ */ class OutputFormatterStyle implements OutputFormatterStyleInterface { - private static $availableForegroundColors = array( - 'black' => array('set' => 30, 'unset' => 39), - 'red' => array('set' => 31, 'unset' => 39), - 'green' => array('set' => 32, 'unset' => 39), - 'yellow' => array('set' => 33, 'unset' => 39), - 'blue' => array('set' => 34, 'unset' => 39), - 'magenta' => array('set' => 35, 'unset' => 39), - 'cyan' => array('set' => 36, 'unset' => 39), - 'white' => array('set' => 37, 'unset' => 39), - 'default' => array('set' => 39, 'unset' => 39), - ); - private static $availableBackgroundColors = array( - 'black' => array('set' => 40, 'unset' => 49), - 'red' => array('set' => 41, 'unset' => 49), - 'green' => array('set' => 42, 'unset' => 49), - 'yellow' => array('set' => 43, 'unset' => 49), - 'blue' => array('set' => 44, 'unset' => 49), - 'magenta' => array('set' => 45, 'unset' => 49), - 'cyan' => array('set' => 46, 'unset' => 49), - 'white' => array('set' => 47, 'unset' => 49), - 'default' => array('set' => 49, 'unset' => 49), - ); - private static $availableOptions = array( - 'bold' => array('set' => 1, 'unset' => 22), - 'underscore' => array('set' => 4, 'unset' => 24), - 'blink' => array('set' => 5, 'unset' => 25), - 'reverse' => array('set' => 7, 'unset' => 27), - 'conceal' => array('set' => 8, 'unset' => 28), - ); + private static $availableForegroundColors = [ + 'black' => ['set' => 30, 'unset' => 39], + 'red' => ['set' => 31, 'unset' => 39], + 'green' => ['set' => 32, 'unset' => 39], + 'yellow' => ['set' => 33, 'unset' => 39], + 'blue' => ['set' => 34, 'unset' => 39], + 'magenta' => ['set' => 35, 'unset' => 39], + 'cyan' => ['set' => 36, 'unset' => 39], + 'white' => ['set' => 37, 'unset' => 39], + 'default' => ['set' => 39, 'unset' => 39], + ]; + private static $availableBackgroundColors = [ + 'black' => ['set' => 40, 'unset' => 49], + 'red' => ['set' => 41, 'unset' => 49], + 'green' => ['set' => 42, 'unset' => 49], + 'yellow' => ['set' => 43, 'unset' => 49], + 'blue' => ['set' => 44, 'unset' => 49], + 'magenta' => ['set' => 45, 'unset' => 49], + 'cyan' => ['set' => 46, 'unset' => 49], + 'white' => ['set' => 47, 'unset' => 49], + 'default' => ['set' => 49, 'unset' => 49], + ]; + private static $availableOptions = [ + 'bold' => ['set' => 1, 'unset' => 22], + 'underscore' => ['set' => 4, 'unset' => 24], + 'blink' => ['set' => 5, 'unset' => 25], + 'reverse' => ['set' => 7, 'unset' => 27], + 'conceal' => ['set' => 8, 'unset' => 28], + ]; private $foreground; private $background; private $href; - private $options = array(); + private $options = []; private $handlesHrefGracefully; /** @@ -63,7 +63,7 @@ class OutputFormatterStyle implements OutputFormatterStyleInterface * @param string|null $background The style background color name * @param array $options The style options */ - public function __construct(string $foreground = null, string $background = null, array $options = array()) + public function __construct(string $foreground = null, string $background = null, array $options = []) { if (null !== $foreground) { $this->setForeground($foreground); @@ -167,7 +167,7 @@ public function unsetOption($option) */ public function setOptions(array $options) { - $this->options = array(); + $this->options = []; foreach ($options as $option) { $this->setOption($option); @@ -183,8 +183,8 @@ public function setOptions(array $options) */ public function apply($text) { - $setCodes = array(); - $unsetCodes = array(); + $setCodes = []; + $unsetCodes = []; if (null === $this->handlesHrefGracefully) { $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR'); diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index 0d81207392faa..ced7634186787 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -256,15 +256,15 @@ public function testNotDecoratedFormatter(string $input, string $expectedNonDeco public function provideDecoratedAndNonDecoratedOutput() { - return array( - array('some error', 'some error', "\033[37;41msome error\033[39;49m"), - array('some info', 'some info', "\033[32msome info\033[39m"), - array('some comment', 'some comment', "\033[33msome comment\033[39m"), - array('some question', 'some question', "\033[30;46msome question\033[39;49m"), - array('some text with inline style', 'some text with inline style', "\033[31msome text with inline style\033[39m"), - array('some URL', 'some URL', "\033]8;;idea://open/?file=/path/SomeFile.php&line=12\033\\some URL\033]8;;\033\\"), - array('some URL', 'some URL', 'some URL', 'JetBrains-JediTerm'), - ); + return [ + ['some error', 'some error', "\033[37;41msome error\033[39;49m"], + ['some info', 'some info', "\033[32msome info\033[39m"], + ['some comment', 'some comment', "\033[33msome comment\033[39m"], + ['some question', 'some question', "\033[30;46msome question\033[39;49m"], + ['some text with inline style', 'some text with inline style', "\033[31msome text with inline style\033[39m"], + ['some URL', 'some URL', "\033]8;;idea://open/?file=/path/SomeFile.php&line=12\033\\some URL\033]8;;\033\\"], + ['some URL', 'some URL', 'some URL', 'JetBrains-JediTerm'], + ]; } public function testContentWithLineBreaks() diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index 492f085985a6e..efc52a2fd6610 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -29,17 +29,17 @@ class DebugClassLoader { private $classLoader; private $isFinder; - private $loaded = array(); + private $loaded = []; private static $caseCheck; - private static $checkedClasses = array(); - private static $final = array(); - private static $finalMethods = array(); - private static $deprecated = array(); - private static $internal = array(); - private static $internalMethods = array(); - private static $annotatedParameters = array(); - private static $darwinCache = array('/' => array('/', array())); - private static $method = array(); + private static $checkedClasses = []; + private static $final = []; + private static $finalMethods = []; + private static $deprecated = []; + private static $internal = []; + private static $internalMethods = []; + private static $annotatedParameters = []; + private static $darwinCache = ['/' => ['/', []]]; + private static $method = []; public function __construct(callable $classLoader) { @@ -99,7 +99,7 @@ class_exists('Psr\Log\LogLevel'); foreach ($functions as $function) { if (!\is_array($function) || !$function[0] instanceof self) { - $function = array(new static($function), 'loadClass'); + $function = [new static($function), 'loadClass']; } spl_autoload_register($function); @@ -220,7 +220,7 @@ private function checkClass($class, $file = null) public function checkAnnotations(\ReflectionClass $refl, $class) { - $deprecations = array(); + $deprecations = []; // Don't trigger deprecations for classes in the same vendor if (2 > $len = 1 + (\strpos($class, '\\') ?: \strpos($class, '_'))) { @@ -232,7 +232,7 @@ public function checkAnnotations(\ReflectionClass $refl, $class) // Detect annotations on the class if (false !== $doc = $refl->getDocComment()) { - foreach (array('final', 'deprecated', 'internal') as $annotation) { + foreach (['final', 'deprecated', 'internal'] as $annotation) { if (false !== \strpos($doc, $annotation) && preg_match('#\n \* @'.$annotation.'(?:( .+?)\.?)?\r?\n \*(?: @|/$)#s', $doc, $notice)) { self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; } @@ -252,7 +252,7 @@ public function checkAnnotations(\ReflectionClass $refl, $class) $description .= '.'; } } - self::$method[$class][] = array($class, $name, $static, $description); + self::$method[$class][] = [$class, $name, $static, $description]; } } } @@ -314,11 +314,11 @@ public function checkAnnotations(\ReflectionClass $refl, $class) } // Inherit @final, @internal and @param annotations for methods - self::$finalMethods[$class] = array(); - self::$internalMethods[$class] = array(); - self::$annotatedParameters[$class] = array(); + self::$finalMethods[$class] = []; + self::$internalMethods[$class] = []; + self::$annotatedParameters[$class] = []; foreach ($parentAndOwnInterfaces as $use) { - foreach (array('finalMethods', 'internalMethods', 'annotatedParameters') as $property) { + foreach (['finalMethods', 'internalMethods', 'annotatedParameters'] as $property) { if (isset(self::${$property}[$use])) { self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use]; } @@ -346,7 +346,7 @@ public function checkAnnotations(\ReflectionClass $refl, $class) $doc = $method->getDocComment(); if (isset(self::$annotatedParameters[$class][$method->name])) { - $definedParameters = array(); + $definedParameters = []; foreach ($method->getParameters() as $parameter) { $definedParameters[$parameter->name] = true; } @@ -364,10 +364,10 @@ public function checkAnnotations(\ReflectionClass $refl, $class) $finalOrInternal = false; - foreach (array('final', 'internal') as $annotation) { + foreach (['final', 'internal'] as $annotation) { if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) { $message = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; - self::${$annotation.'Methods'}[$class][$method->name] = array($class, $message); + self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message]; $finalOrInternal = true; } } @@ -379,7 +379,7 @@ public function checkAnnotations(\ReflectionClass $refl, $class) continue; } if (!isset(self::$annotatedParameters[$class][$method->name])) { - $definedParameters = array(); + $definedParameters = []; foreach ($method->getParameters() as $parameter) { $definedParameters[$parameter->name] = true; } @@ -425,7 +425,7 @@ public function checkCase(\ReflectionClass $refl, $file, $class) if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true) && 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false) ) { - return array(substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)); + return [substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)]; } } @@ -455,7 +455,7 @@ private function darwinRealpath($real) $k = $kDir; $i = \strlen($dir) - 1; while (!isset(self::$darwinCache[$k])) { - self::$darwinCache[$k] = array($dir, array()); + self::$darwinCache[$k] = [$dir, []]; self::$darwinCache[$dir] = &self::$darwinCache[$k]; while ('/' !== $dir[--$i]) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index bccb74538ede2..e01f5bf088229 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -62,7 +62,7 @@ class PhpDumper extends Dumper private $variableCount; private $inlinedDefinitions; private $serviceCalls; - private $reservedVariables = array('instance', 'class', 'this'); + private $reservedVariables = ['instance', 'class', 'this']; private $expressionLanguage; private $targetDirRegex; private $targetDirMaxMatches; @@ -73,14 +73,14 @@ class PhpDumper extends Dumper private $asFiles; private $hotPathTag; private $inlineRequires; - private $inlinedRequires = array(); - private $circularReferences = array(); - private $singleUsePrivateIds = array(); + private $inlinedRequires = []; + private $circularReferences = []; + private $singleUsePrivateIds = []; private $addThrow = false; private $addGetService = false; - private $locatedIds = array(); + private $locatedIds = []; private $serviceLocatorTag; - private $exportedVariables = array(); + private $exportedVariables = []; /** * @var ProxyDumper @@ -121,13 +121,13 @@ public function setProxyDumper(ProxyDumper $proxyDumper) * * @throws EnvParameterException When an env var exists but has not been dumped */ - public function dump(array $options = array()) + public function dump(array $options = []) { - $this->locatedIds = array(); + $this->locatedIds = []; $this->targetDirRegex = null; - $this->inlinedRequires = array(); - $this->exportedVariables = array(); - $options = array_merge(array( + $this->inlinedRequires = []; + $this->exportedVariables = []; + $options = array_merge([ 'class' => 'ProjectServiceContainer', 'base_class' => 'Container', 'namespace' => '', @@ -137,7 +137,7 @@ public function dump(array $options = array()) 'inline_class_loader_parameter' => 'container.dumper.inline_class_loader', 'service_locator_tag' => 'container.service_locator', 'build_time' => time(), - ), $options); + ], $options); $this->addThrow = $this->addGetService = false; $this->namespace = $options['namespace']; @@ -171,9 +171,9 @@ public function dump(array $options = array()) } (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container); - $checkedNodes = array(); - $this->circularReferences = array(); - $this->singleUsePrivateIds = array(); + $checkedNodes = []; + $this->circularReferences = []; + $this->singleUsePrivateIds = []; foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { if (!$node->getValue() instanceof Definition) { continue; @@ -186,7 +186,7 @@ public function dump(array $options = array()) } } $this->container->getCompiler()->getServiceReferenceGraph()->clear(); - $checkedNodes = array(); + $checkedNodes = []; $this->docStar = $options['debug'] ? '*' : ''; @@ -240,7 +240,7 @@ public function dump(array $options = array()) // This file has been auto-generated by the Symfony Dependency Injection Component for internal use. EOF; - $files = array(); + $files = []; $ids = $this->container->getRemovedIds(); foreach ($this->container->getDefinitions() as $id => $definition) { @@ -265,7 +265,7 @@ public function dump(array $options = array()) } $files[$options['class'].'.php'] = $code.$this->endClass(); $hash = ucfirst(strtr(ContainerBuilder::hash($files), '._', 'xx')); - $code = array(); + $code = []; foreach ($files as $file => $c) { $code["Container{$hash}/{$file}"] = $c; @@ -308,12 +308,12 @@ public function dump(array $options = array()) } $this->targetDirRegex = null; - $this->inlinedRequires = array(); - $this->circularReferences = array(); - $this->locatedIds = array(); - $this->exportedVariables = array(); + $this->inlinedRequires = []; + $this->circularReferences = []; + $this->locatedIds = []; + $this->exportedVariables = []; - $unusedEnvs = array(); + $unusedEnvs = []; foreach ($this->container->getEnvCounters() as $env => $use) { if (!$use) { $unusedEnvs[] = $env; @@ -338,7 +338,7 @@ private function getProxyDumper(): ProxyDumper return $this->proxyDumper; } - private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = array()) + private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = []) { $checkedNodes[$sourceId] = true; $currentPath[$sourceId] = $sourceId; @@ -367,7 +367,7 @@ private function analyzeCircularReferences($sourceId, array $edges, &$checkedNod unset($currentPath[$sourceId]); } - private function connectCircularReferences($sourceId, &$currentPath, &$subPath = array()) + private function connectCircularReferences($sourceId, &$currentPath, &$subPath = []) { $subPath[$sourceId] = $sourceId; $currentPath[$sourceId] = $sourceId; @@ -423,7 +423,7 @@ private function collectLineage($class, array &$lineage) private function generateProxyClasses() { - $alreadyGenerated = array(); + $alreadyGenerated = []; $definitions = $this->container->getDefinitions(); $strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments'); $proxyDumper = $this->getProxyDumper(); @@ -454,7 +454,7 @@ private function addServiceInclude(string $cId, Definition $definition): string $code = ''; if ($this->inlineRequires && !$this->isHotPath($definition)) { - $lineage = array(); + $lineage = []; foreach ($this->inlinedDefinitions as $def) { if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { $this->collectLineage($class, $lineage); @@ -566,7 +566,7 @@ private function addServiceMethodCalls(Definition $definition, string $variableN { $calls = ''; foreach ($definition->getMethodCalls() as $call) { - $arguments = array(); + $arguments = []; foreach ($call[1] as $value) { $arguments[] = $this->dumpValue($value); } @@ -619,11 +619,11 @@ private function addServiceConfigurator(Definition $definition, string $variable private function addService(string $id, Definition $definition): array { $this->definitionVariables = new \SplObjectStorage(); - $this->referenceVariables = array(); + $this->referenceVariables = []; $this->variableCount = 0; $this->referenceVariables[$id] = new Variable('instance'); - $return = array(); + $return = []; if ($class = $definition->getClass()) { $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class); @@ -680,8 +680,8 @@ protected function {$methodName}($lazyInitialization) EOF; } - $this->serviceCalls = array(); - $this->inlinedDefinitions = $this->getDefinitionsFromArguments(array($definition), null, $this->serviceCalls); + $this->serviceCalls = []; + $this->inlinedDefinitions = $this->getDefinitionsFromArguments([$definition], null, $this->serviceCalls); $code .= $this->addServiceInclude($id, $definition); @@ -705,7 +705,7 @@ protected function {$methodName}($lazyInitialization) $this->definitionVariables = $this->inlinedDefinitions = null; $this->referenceVariables = $this->serviceCalls = null; - return array($file, $code); + return [$file, $code]; } private function addInlineVariables(string $id, Definition $definition, array $arguments, bool $forConstructor): string @@ -782,11 +782,11 @@ private function addInlineService(string $id, Definition $definition, Definition return ''; } - $arguments = array($inlineDef->getArguments(), $inlineDef->getFactory()); + $arguments = [$inlineDef->getArguments(), $inlineDef->getFactory()]; $code = $this->addInlineVariables($id, $definition, $arguments, $forConstructor); - if ($arguments = array_filter(array($inlineDef->getProperties(), $inlineDef->getMethodCalls(), $inlineDef->getConfigurator()))) { + if ($arguments = array_filter([$inlineDef->getProperties(), $inlineDef->getMethodCalls(), $inlineDef->getConfigurator()])) { $isSimpleInstance = false; } elseif ($definition !== $inlineDef && 2 > $this->inlinedDefinitions[$inlineDef]) { return $code; @@ -855,9 +855,9 @@ private function generateServiceFiles(array $services) if (!$definition->isShared()) { $i = strpos($code, "\n\ninclude_once "); if (false !== $i && false !== $i = strpos($code, "\n\n", 2 + $i)) { - $code = array(substr($code, 0, 2 + $i), substr($code, 2 + $i)); + $code = [substr($code, 0, 2 + $i), substr($code, 2 + $i)]; } else { - $code = array("\n", $code); + $code = ["\n", $code]; } $code[1] = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code[1]))); $factory = sprintf('$this->factories%s[\'%s\']', $definition->isPublic() ? '' : "['service_container']", $id); @@ -875,7 +875,7 @@ private function addNewInstance(Definition $definition, string $return = '', str $tail = $return ? ";\n" : ''; if (BaseServiceLocator::class === $definition->getClass() && $definition->hasTag($this->serviceLocatorTag)) { - $arguments = array(); + $arguments = []; foreach ($definition->getArgument(0) as $k => $argument) { $arguments[$k] = $argument->getValues()[0]; } @@ -883,7 +883,7 @@ private function addNewInstance(Definition $definition, string $return = '', str return $return.$this->dumpValue(new ServiceLocatorArgument($arguments)).$tail; } - $arguments = array(); + $arguments = []; foreach ($definition->getArguments() as $value) { $arguments[] = $this->dumpValue($value); } @@ -1157,11 +1157,11 @@ private function addInlineRequires(): string return ''; } - $lineage = array(); + $lineage = []; foreach ($this->container->findTaggedServiceIds($this->hotPathTag) as $id => $tags) { $definition = $this->container->getDefinition($id); - $inlinedDefinitions = $this->getDefinitionsFromArguments(array($definition)); + $inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]); foreach ($inlinedDefinitions as $def) { if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { @@ -1188,14 +1188,14 @@ private function addDefaultParametersMethod(): string return ''; } - $php = array(); - $dynamicPhp = array(); + $php = []; + $dynamicPhp = []; foreach ($this->container->getParameterBag()->all() as $key => $value) { if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) { throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: %s.', $resolvedKey)); } - $export = $this->exportParameters(array($value)); + $export = $this->exportParameters([$value]); $export = explode('0 => ', substr(rtrim($export, " )\n"), 7, -1), 2); if (preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDirs\[\d++\])/", $export[1])) { @@ -1317,7 +1317,7 @@ protected function getDefaultParameters() */ private function exportParameters(array $parameters, string $path = '', int $indent = 12): string { - $php = array(); + $php = []; foreach ($parameters as $key => $value) { if (\is_array($value)) { $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4); @@ -1375,7 +1375,7 @@ private function wrapServiceConditionals($value, string $code): string private function getServiceConditionals($value): string { - $conditions = array(); + $conditions = []; foreach (ContainerBuilder::getInitializedConditionals($value) as $service) { if (!$this->container->hasDefinition($service)) { return 'false'; @@ -1397,7 +1397,7 @@ private function getServiceConditionals($value): string return implode(' && ', $conditions); } - private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = array()): \SplObjectStorage + private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = []): \SplObjectStorage { if (null === $definitions) { $definitions = new \SplObjectStorage(); @@ -1410,7 +1410,7 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $id = (string) $argument; if (!isset($calls[$id])) { - $calls[$id] = array(0, $argument->getInvalidBehavior()); + $calls[$id] = [0, $argument->getInvalidBehavior()]; } else { $calls[$id][1] = min($calls[$id][1], $argument->getInvalidBehavior()); } @@ -1422,7 +1422,7 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions[$argument] = 1 + $definitions[$argument]; } else { $definitions[$argument] = 1; - $arguments = array($argument->getArguments(), $argument->getFactory(), $argument->getProperties(), $argument->getMethodCalls(), $argument->getConfigurator()); + $arguments = [$argument->getArguments(), $argument->getFactory(), $argument->getProperties(), $argument->getMethodCalls(), $argument->getConfigurator()]; $this->getDefinitionsFromArguments($arguments, $definitions, $calls); } } @@ -1439,14 +1439,14 @@ private function dumpValue($value, bool $interpolate = true): string if ($value && $interpolate && false !== $param = array_search($value, $this->container->getParameterBag()->all(), true)) { return $this->dumpValue("%$param%"); } - $code = array(); + $code = []; foreach ($value as $k => $v) { $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate)); } return sprintf('array(%s)', implode(', ', $code)); } elseif ($value instanceof ArgumentInterface) { - $scope = array($this->definitionVariables, $this->referenceVariables); + $scope = [$this->definitionVariables, $this->referenceVariables]; $this->definitionVariables = $this->referenceVariables = null; try { @@ -1465,14 +1465,14 @@ private function dumpValue($value, bool $interpolate = true): string } if ($value instanceof IteratorArgument) { - $operands = array(0); - $code = array(); + $operands = [0]; + $code = []; $code[] = 'new RewindableGenerator(function () {'; if (!$values = $value->getValues()) { $code[] = ' return new \EmptyIterator();'; } else { - $countCode = array(); + $countCode = []; $countCode[] = 'function () {'; foreach ($values as $k => $v) { @@ -1548,7 +1548,7 @@ private function dumpValue($value, bool $interpolate = true): string return $this->getServiceCall($id, $value); } elseif ($value instanceof Expression) { - return $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container')); + return $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']); } elseif ($value instanceof Parameter) { return $this->dumpParameter($value); } elseif (true === $interpolate && \is_string($value)) { @@ -1670,8 +1670,8 @@ private function getServiceCall(string $id, Reference $reference = null): string */ private function initializeMethodNamesMap(string $class) { - $this->serviceIdToMethodNameMap = array(); - $this->usedMethodNames = array(); + $this->serviceIdToMethodNameMap = []; + $this->usedMethodNames = []; if ($reflectionClass = $this->container->getReflectionClass($class)) { foreach ($reflectionClass->getMethods() as $method) { @@ -1776,7 +1776,7 @@ private function isSingleUsePrivateNode(ServiceReferenceGraphNode $node): bool if ($node->getValue()->isPublic()) { return false; } - $ids = array(); + $ids = []; foreach ($node->getInEdges() as $edge) { if (!$value = $edge->getSourceNode()->getValue()) { continue; diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index fea1ffe8c967e..1b71924d8a719 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -31,7 +31,7 @@ public function __construct(ContainerInterface $container) */ public static function getProvidedTypes() { - return array( + return [ 'base64' => 'string', 'bool' => 'bool', 'const' => 'bool|int|float|string|array', @@ -45,7 +45,7 @@ public static function getProvidedTypes() 'default' => 'bool|int|float|string|array', 'string' => 'string', 'trim' => 'string', - ); + ]; } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index d7da25a60235e..c6c71f7c2617d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -902,7 +902,7 @@ public function testErroredServiceLocator() (new AutowirePass())->process($container); - $this->assertSame(array('Cannot autowire service "some_locator": it has type "Symfony\Component\DependencyInjection\Tests\Compiler\MissingClass" but this class was not found.'), $container->getDefinition('.errored.some_locator.'.MissingClass::class)->getErrors()); + $this->assertSame(['Cannot autowire service "some_locator": it has type "Symfony\Component\DependencyInjection\Tests\Compiler\MissingClass" but this class was not found.'], $container->getDefinition('.errored.some_locator.'.MissingClass::class)->getErrors()); } public function testNamedArgumentAliasResolveCollisions() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php index bdc05146e4eb3..f376165dfc0a1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php @@ -28,22 +28,22 @@ public function testSimpleProcessor() $this->assertTrue($container->has('container.env_var_processors_locator')); $this->assertInstanceOf(SimpleProcessor::class, $container->get('container.env_var_processors_locator')->get('foo')); - $expected = array( - 'foo' => array('string'), - 'base64' => array('string'), - 'bool' => array('bool'), - 'const' => array('bool', 'int', 'float', 'string', 'array'), - 'csv' => array('array'), - 'file' => array('string'), - 'float' => array('float'), - 'int' => array('int'), - 'json' => array('array'), - 'key' => array('bool', 'int', 'float', 'string', 'array'), - 'resolve' => array('string'), - 'default' => array('bool', 'int', 'float', 'string', 'array'), - 'string' => array('string'), - 'trim' => array('string'), - ); + $expected = [ + 'foo' => ['string'], + 'base64' => ['string'], + 'bool' => ['bool'], + 'const' => ['bool', 'int', 'float', 'string', 'array'], + 'csv' => ['array'], + 'file' => ['string'], + 'float' => ['float'], + 'int' => ['int'], + 'json' => ['array'], + 'key' => ['bool', 'int', 'float', 'string', 'array'], + 'resolve' => ['string'], + 'default' => ['bool', 'int', 'float', 'string', 'array'], + 'string' => ['string'], + 'trim' => ['string'], + ]; $this->assertSame($expected, $container->getParameterBag()->getProvidedTypes()); } @@ -79,7 +79,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) public static function getProvidedTypes() { - return array('foo' => 'string'); + return ['foo' => 'string']; } } @@ -87,6 +87,6 @@ class BadProcessor extends SimpleProcessor { public static function getProvidedTypes() { - return array('foo' => 'string|foo'); + return ['foo' => 'string|foo']; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php index a3ebb1b3dd45b..22950f34550a5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php @@ -221,9 +221,9 @@ public function testEmptyEnvWhichCannotBeEmptyForScalarNodeWithValidation(): voi { $container = new ContainerBuilder(); $container->registerExtension($ext = new EnvExtension()); - $container->prependExtensionConfig('env_extension', $expected = array( + $container->prependExtensionConfig('env_extension', $expected = [ 'scalar_node_not_empty_validated' => '%env(SOME)%', - )); + ]); $this->doProcess($container); @@ -234,9 +234,9 @@ public function testPartialEnvWhichCannotBeEmptyForScalarNode(): void { $container = new ContainerBuilder(); $container->registerExtension($ext = new EnvExtension()); - $container->prependExtensionConfig('env_extension', $expected = array( + $container->prependExtensionConfig('env_extension', $expected = [ 'scalar_node_not_empty_validated' => 'foo %env(SOME)% bar', - )); + ]); $this->doProcess($container); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index a296f8cde942f..6f1fb76719cce 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -453,7 +453,7 @@ public function testDumpedDefaultEnvParameters() $dumper = new PhpDumper($container); $dumper->dump(); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_default_env.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_DefaultParameters'))); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_default_env.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_DefaultParameters'])); require self::$fixturesPath.'/php/services_default_env.php'; $container = new \Symfony_DI_PhpDumper_Test_DefaultParameters(); diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index fe2cf669b445d..dac52ff5624ce 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -52,7 +52,7 @@ public function testAdd() $crawler->add($this->createNodeList()); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMNodeList'); - $list = array(); + $list = []; foreach ($this->createNodeList() as $node) { $list[] = $node; } @@ -269,7 +269,7 @@ public function testAddNodeList() public function testAddNodes() { - $list = array(); + $list = []; foreach ($this->createNodeList() as $node) { $list[] = $node; } @@ -314,7 +314,7 @@ public function testEach() return $i.'-'.$node->text(); }); - $this->assertEquals(array('0-One', '1-Two', '2-Three'), $data, '->each() executes an anonymous function on each node of the list'); + $this->assertEquals(['0-One', '1-Two', '2-Three'], $data, '->each() executes an anonymous function on each node of the list'); } public function testIteration() @@ -415,13 +415,13 @@ public function testExtract() { $crawler = $this->createTestCrawler()->filterXPath('//ul[1]/li'); - $this->assertEquals(array('One', 'Two', 'Three'), $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list'); - $this->assertEquals(array(array('One', 'first'), array('Two', ''), array('Three', '')), $crawler->extract(array('_text', 'class')), '->extract() returns an array of extracted data from the node list'); - $this->assertEquals(array(array(), array(), array()), $crawler->extract(array()), '->extract() returns empty arrays if the attribute list is empty'); + $this->assertEquals(['One', 'Two', 'Three'], $crawler->extract('_text'), '->extract() returns an array of extracted data from the node list'); + $this->assertEquals([['One', 'first'], ['Two', ''], ['Three', '']], $crawler->extract(['_text', 'class']), '->extract() returns an array of extracted data from the node list'); + $this->assertEquals([[], [], []], $crawler->extract([]), '->extract() returns empty arrays if the attribute list is empty'); - $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty'); + $this->assertEquals([], $this->createTestCrawler()->filterXPath('//ol')->extract('_text'), '->extract() returns an empty array if the node list is empty'); - $this->assertEquals(array(array('One', 'li'), array('Two', 'li'), array('Three', 'li')), $crawler->extract(array('_text', '_name')), '->extract() returns an array of extracted data from the node list'); + $this->assertEquals([['One', 'li'], ['Two', 'li'], ['Three', 'li']], $crawler->extract(['_text', '_name']), '->extract() returns an array of extracted data from the node list'); } public function testFilterXpathComplexQueries() @@ -855,7 +855,7 @@ public function testLinks() $links = $crawler->links(); $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Link', $links[0], '->links() returns an array of Link instances'); - $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty'); + $this->assertEquals([], $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty'); } public function testImages() @@ -867,7 +867,7 @@ public function testImages() $images = $crawler->images(); $this->assertInstanceOf('Symfony\\Component\\DomCrawler\\Image', $images[0], '->images() returns an array of Image instances'); - $this->assertEquals(array(), $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty'); + $this->assertEquals([], $this->createTestCrawler()->filterXPath('//ol')->links(), '->links() returns an empty array if the node selection is empty'); } public function testForm() @@ -880,9 +880,9 @@ public function testForm() $this->assertEquals($crawler->form()->getFormNode()->getAttribute('id'), $crawler2->form()->getFormNode()->getAttribute('id'), '->form() works on elements with form attribute'); - $this->assertEquals(array('FooName' => 'FooBar', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form(array('FooName' => 'FooBar'))->getValues(), '->form() takes an array of values to submit as its first argument'); - $this->assertEquals(array('FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler->form()->getValues(), '->getValues() returns correct form values'); - $this->assertEquals(array('FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'), $crawler2->form()->getValues(), '->getValues() returns correct form values'); + $this->assertEquals(['FooName' => 'FooBar', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'], $crawler->form(['FooName' => 'FooBar'])->getValues(), '->form() takes an array of values to submit as its first argument'); + $this->assertEquals(['FooName' => 'FooValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'], $crawler->form()->getValues(), '->getValues() returns correct form values'); + $this->assertEquals(['FooBarName' => 'FooBarValue', 'TextName' => 'TextValue', 'FooTextName' => 'FooTextValue'], $crawler2->form()->getValues(), '->getValues() returns correct form values'); try { $this->createTestCrawler()->filterXPath('//ol')->form(); @@ -1072,13 +1072,13 @@ public function testBaseTag($baseValue, $linkValue, $expectedUri, $currentUri = public function getBaseTagData() { - return array( - array('http://base.com', 'link', 'http://base.com/link'), - array('//base.com', 'link', 'https://base.com/link', 'https://domain.com', ' tag can use a schema-less URL'), - array('path/', 'link', 'https://domain.com/path/link', 'https://domain.com', ' tag can set a path'), - array('http://base.com', '#', 'http://base.com#', 'http://domain.com/path/link', ' tag does work with links to an anchor'), - array('http://base.com', '', 'http://base.com', 'http://domain.com/path/link', ' tag does work with empty links'), - ); + return [ + ['http://base.com', 'link', 'http://base.com/link'], + ['//base.com', 'link', 'https://base.com/link', 'https://domain.com', ' tag can use a schema-less URL'], + ['path/', 'link', 'https://domain.com/path/link', 'https://domain.com', ' tag can set a path'], + ['http://base.com', '#', 'http://base.com#', 'http://domain.com/path/link', ' tag does work with links to an anchor'], + ['http://base.com', '', 'http://base.com', 'http://domain.com/path/link', ' tag does work with empty links'], + ]; } /** @@ -1092,14 +1092,14 @@ public function testBaseTagWithForm($baseValue, $actionValue, $expectedUri, $cur public function getBaseTagWithFormData() { - return array( - array('https://base.com/', 'link/', 'https://base.com/link/', 'https://base.com/link/', ' tag does work with a path and relative form action'), - array('/basepath', '/registration', 'http://domain.com/registration', 'http://domain.com/registration', ' tag does work with a path and form action'), - array('/basepath', '', 'http://domain.com/registration', 'http://domain.com/registration', ' tag does work with a path and empty form action'), - array('http://base.com/', '/registration', 'http://base.com/registration', 'http://domain.com/registration', ' tag does work with a URL and form action'), - array('http://base.com', '', 'http://domain.com/path/form', 'http://domain.com/path/form', ' tag does work with a URL and an empty form action'), - array('http://base.com/path', '/registration', 'http://base.com/registration', 'http://domain.com/path/form', ' tag does work with a URL and form action'), - ); + return [ + ['https://base.com/', 'link/', 'https://base.com/link/', 'https://base.com/link/', ' tag does work with a path and relative form action'], + ['/basepath', '/registration', 'http://domain.com/registration', 'http://domain.com/registration', ' tag does work with a path and form action'], + ['/basepath', '', 'http://domain.com/registration', 'http://domain.com/registration', ' tag does work with a path and empty form action'], + ['http://base.com/', '/registration', 'http://base.com/registration', 'http://domain.com/registration', ' tag does work with a URL and form action'], + ['http://base.com', '', 'http://domain.com/path/form', 'http://domain.com/path/form', ' tag does work with a URL and an empty form action'], + ['http://base.com/path', '/registration', 'http://base.com/registration', 'http://domain.com/path/form', ' tag does work with a URL and form action'], + ]; } public function testCountOfNestedElements() @@ -1115,7 +1115,7 @@ public function testEvaluateReturnsTypedResultOfXPathExpressionOnADocumentSubset $result = $crawler->filterXPath('//form/input')->evaluate('substring-before(@name, "Name")'); - $this->assertSame(array('Text', 'Foo', 'Bar'), $result); + $this->assertSame(['Text', 'Foo', 'Bar'], $result); } public function testEvaluateReturnsTypedResultOfNamespacedXPathExpressionOnADocumentSubset() @@ -1124,7 +1124,7 @@ public function testEvaluateReturnsTypedResultOfNamespacedXPathExpressionOnADocu $result = $crawler->filterXPath('//yt:accessControl/@action')->evaluate('string(.)'); - $this->assertSame(array('comment', 'videoRespond'), $result); + $this->assertSame(['comment', 'videoRespond'], $result); } public function testEvaluateReturnsTypedResultOfNamespacedXPathExpression() @@ -1134,7 +1134,7 @@ public function testEvaluateReturnsTypedResultOfNamespacedXPathExpression() $result = $crawler->evaluate('string(//youtube:accessControl/@action)'); - $this->assertSame(array('comment'), $result); + $this->assertSame(['comment'], $result); } public function testEvaluateReturnsACrawlerIfXPathExpressionEvaluatesToANode() diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index a4e317d3cedf0..75c87c1b0b2a6 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -34,24 +34,24 @@ public function testParseWithFormatError($data, $error) public function getEnvDataWithFormatErrors() { - $tests = array( - array('FOO=BAR BAZ', "A value containing spaces must be surrounded by quotes in \".env\" at line 1.\n...FOO=BAR BAZ...\n ^ line 1 offset 11"), - array('FOO BAR=BAR', "Whitespace are not supported after the variable name in \".env\" at line 1.\n...FOO BAR=BAR...\n ^ line 1 offset 3"), - array('FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"), - array('FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"), - array('FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"), - array('FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 8"), - array('export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"), - array('FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"), - array('FOO= BAR', "Whitespace are not supported before the value in \".env\" at line 1.\n...FOO= BAR...\n ^ line 1 offset 4"), - array('Стасян', "Invalid character in variable name in \".env\" at line 1.\n...Стасян...\n ^ line 1 offset 0"), - array('FOO!', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO!...\n ^ line 1 offset 3"), - array('FOO=$(echo foo', "Missing closing parenthesis. in \".env\" at line 1.\n...FOO=$(echo foo...\n ^ line 1 offset 14"), - array('FOO=$(echo foo'."\n", "Missing closing parenthesis. in \".env\" at line 1.\n...FOO=$(echo foo\\n...\n ^ line 1 offset 14"), - ); + $tests = [ + ['FOO=BAR BAZ', "A value containing spaces must be surrounded by quotes in \".env\" at line 1.\n...FOO=BAR BAZ...\n ^ line 1 offset 11"], + ['FOO BAR=BAR', "Whitespace are not supported after the variable name in \".env\" at line 1.\n...FOO BAR=BAR...\n ^ line 1 offset 3"], + ['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"], + ['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"], + ['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"], + ['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 8"], + ['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"], + ['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"], + ['FOO= BAR', "Whitespace are not supported before the value in \".env\" at line 1.\n...FOO= BAR...\n ^ line 1 offset 4"], + ['Стасян', "Invalid character in variable name in \".env\" at line 1.\n...Стасян...\n ^ line 1 offset 0"], + ['FOO!', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO!...\n ^ line 1 offset 3"], + ['FOO=$(echo foo', "Missing closing parenthesis. in \".env\" at line 1.\n...FOO=$(echo foo...\n ^ line 1 offset 14"], + ['FOO=$(echo foo'."\n", "Missing closing parenthesis. in \".env\" at line 1.\n...FOO=$(echo foo\\n...\n ^ line 1 offset 14"], + ]; if ('\\' !== \DIRECTORY_SEPARATOR) { - $tests[] = array('FOO=$((1dd2))', "Issue expanding a command (%s\n) in \".env\" at line 1.\n...FOO=$((1dd2))...\n ^ line 1 offset 13"); + $tests[] = ['FOO=$((1dd2))', "Issue expanding a command (%s\n) in \".env\" at line 1.\n...FOO=$((1dd2))...\n ^ line 1 offset 13"]; } return $tests; @@ -72,105 +72,105 @@ public function getEnvData() $_ENV['REMOTE'] = 'remote'; $_SERVER['SERVERVAR'] = 'servervar'; - $tests = array( + $tests = [ // backslashes - array('FOO=foo\\\\bar', array('FOO' => 'foo\\bar')), - array("FOO='foo\\\\bar'", array('FOO' => 'foo\\\\bar')), - array('FOO="foo\\\\bar"', array('FOO' => 'foo\\bar')), + ['FOO=foo\\\\bar', ['FOO' => 'foo\\bar']], + ["FOO='foo\\\\bar'", ['FOO' => 'foo\\\\bar']], + ['FOO="foo\\\\bar"', ['FOO' => 'foo\\bar']], // escaped backslash in front of variable - array("BAR=bar\nFOO=foo\\\\\$BAR", array('BAR' => 'bar', 'FOO' => 'foo\\bar')), - array("BAR=bar\nFOO='foo\\\\\$BAR'", array('BAR' => 'bar', 'FOO' => 'foo\\\\$BAR')), - array("BAR=bar\nFOO=\"foo\\\\\$BAR\"", array('BAR' => 'bar', 'FOO' => 'foo\\bar')), + ["BAR=bar\nFOO=foo\\\\\$BAR", ['BAR' => 'bar', 'FOO' => 'foo\\bar']], + ["BAR=bar\nFOO='foo\\\\\$BAR'", ['BAR' => 'bar', 'FOO' => 'foo\\\\$BAR']], + ["BAR=bar\nFOO=\"foo\\\\\$BAR\"", ['BAR' => 'bar', 'FOO' => 'foo\\bar']], - array('FOO=foo\\\\\\$BAR', array('FOO' => 'foo\\$BAR')), - array('FOO=\'foo\\\\\\$BAR\'', array('FOO' => 'foo\\\\\\$BAR')), - array('FOO="foo\\\\\\$BAR"', array('FOO' => 'foo\\$BAR')), + ['FOO=foo\\\\\\$BAR', ['FOO' => 'foo\\$BAR']], + ['FOO=\'foo\\\\\\$BAR\'', ['FOO' => 'foo\\\\\\$BAR']], + ['FOO="foo\\\\\\$BAR"', ['FOO' => 'foo\\$BAR']], // spaces - array('FOO=bar', array('FOO' => 'bar')), - array(' FOO=bar ', array('FOO' => 'bar')), - array('FOO=', array('FOO' => '')), - array("FOO=\n\n\nBAR=bar", array('FOO' => '', 'BAR' => 'bar')), - array('FOO= ', array('FOO' => '')), - array("FOO=\nBAR=bar", array('FOO' => '', 'BAR' => 'bar')), + ['FOO=bar', ['FOO' => 'bar']], + [' FOO=bar ', ['FOO' => 'bar']], + ['FOO=', ['FOO' => '']], + ["FOO=\n\n\nBAR=bar", ['FOO' => '', 'BAR' => 'bar']], + ['FOO= ', ['FOO' => '']], + ["FOO=\nBAR=bar", ['FOO' => '', 'BAR' => 'bar']], // newlines - array("\n\nFOO=bar\r\n\n", array('FOO' => 'bar')), - array("FOO=bar\r\nBAR=foo", array('FOO' => 'bar', 'BAR' => 'foo')), - array("FOO=bar\rBAR=foo", array('FOO' => 'bar', 'BAR' => 'foo')), - array("FOO=bar\nBAR=foo", array('FOO' => 'bar', 'BAR' => 'foo')), + ["\n\nFOO=bar\r\n\n", ['FOO' => 'bar']], + ["FOO=bar\r\nBAR=foo", ['FOO' => 'bar', 'BAR' => 'foo']], + ["FOO=bar\rBAR=foo", ['FOO' => 'bar', 'BAR' => 'foo']], + ["FOO=bar\nBAR=foo", ['FOO' => 'bar', 'BAR' => 'foo']], // quotes - array("FOO=\"bar\"\n", array('FOO' => 'bar')), - array("FOO=\"bar'foo\"\n", array('FOO' => 'bar\'foo')), - array("FOO='bar'\n", array('FOO' => 'bar')), - array("FOO='bar\"foo'\n", array('FOO' => 'bar"foo')), - array("FOO=\"bar\\\"foo\"\n", array('FOO' => 'bar"foo')), - array('FOO="bar\nfoo"', array('FOO' => "bar\nfoo")), - array('FOO="bar\rfoo"', array('FOO' => "bar\rfoo")), - array('FOO=\'bar\nfoo\'', array('FOO' => 'bar\nfoo')), - array('FOO=\'bar\rfoo\'', array('FOO' => 'bar\rfoo')), - array('FOO=" FOO "', array('FOO' => ' FOO ')), - array('FOO=" "', array('FOO' => ' ')), - array('PATH="c:\\\\"', array('PATH' => 'c:\\')), - array("FOO=\"bar\nfoo\"", array('FOO' => "bar\nfoo")), - array('FOO=BAR\\"', array('FOO' => 'BAR"')), - array("FOO=BAR\\'BAZ", array('FOO' => "BAR'BAZ")), - array('FOO=\\"BAR', array('FOO' => '"BAR')), + ["FOO=\"bar\"\n", ['FOO' => 'bar']], + ["FOO=\"bar'foo\"\n", ['FOO' => 'bar\'foo']], + ["FOO='bar'\n", ['FOO' => 'bar']], + ["FOO='bar\"foo'\n", ['FOO' => 'bar"foo']], + ["FOO=\"bar\\\"foo\"\n", ['FOO' => 'bar"foo']], + ['FOO="bar\nfoo"', ['FOO' => "bar\nfoo"]], + ['FOO="bar\rfoo"', ['FOO' => "bar\rfoo"]], + ['FOO=\'bar\nfoo\'', ['FOO' => 'bar\nfoo']], + ['FOO=\'bar\rfoo\'', ['FOO' => 'bar\rfoo']], + ['FOO=" FOO "', ['FOO' => ' FOO ']], + ['FOO=" "', ['FOO' => ' ']], + ['PATH="c:\\\\"', ['PATH' => 'c:\\']], + ["FOO=\"bar\nfoo\"", ['FOO' => "bar\nfoo"]], + ['FOO=BAR\\"', ['FOO' => 'BAR"']], + ["FOO=BAR\\'BAZ", ['FOO' => "BAR'BAZ"]], + ['FOO=\\"BAR', ['FOO' => '"BAR']], // concatenated values - array("FOO='bar''foo'\n", array('FOO' => 'barfoo')), - array("FOO='bar '' baz'", array('FOO' => 'bar baz')), - array("FOO=bar\nBAR='baz'\"\$FOO\"", array('FOO' => 'bar', 'BAR' => 'bazbar')), - array("FOO='bar '\\'' baz'", array('FOO' => "bar ' baz")), + ["FOO='bar''foo'\n", ['FOO' => 'barfoo']], + ["FOO='bar '' baz'", ['FOO' => 'bar baz']], + ["FOO=bar\nBAR='baz'\"\$FOO\"", ['FOO' => 'bar', 'BAR' => 'bazbar']], + ["FOO='bar '\\'' baz'", ['FOO' => "bar ' baz"]], // comments - array("#FOO=bar\nBAR=foo", array('BAR' => 'foo')), - array("#FOO=bar # Comment\nBAR=foo", array('BAR' => 'foo')), - array("FOO='bar foo' # Comment", array('FOO' => 'bar foo')), - array("FOO='bar#foo' # Comment", array('FOO' => 'bar#foo')), - array("# Comment\r\nFOO=bar\n# Comment\nBAR=foo", array('FOO' => 'bar', 'BAR' => 'foo')), - array("FOO=bar # Another comment\nBAR=foo", array('FOO' => 'bar', 'BAR' => 'foo')), - array("FOO=\n\n# comment\nBAR=bar", array('FOO' => '', 'BAR' => 'bar')), - array('FOO=NOT#COMMENT', array('FOO' => 'NOT#COMMENT')), - array('FOO= # Comment', array('FOO' => '')), + ["#FOO=bar\nBAR=foo", ['BAR' => 'foo']], + ["#FOO=bar # Comment\nBAR=foo", ['BAR' => 'foo']], + ["FOO='bar foo' # Comment", ['FOO' => 'bar foo']], + ["FOO='bar#foo' # Comment", ['FOO' => 'bar#foo']], + ["# Comment\r\nFOO=bar\n# Comment\nBAR=foo", ['FOO' => 'bar', 'BAR' => 'foo']], + ["FOO=bar # Another comment\nBAR=foo", ['FOO' => 'bar', 'BAR' => 'foo']], + ["FOO=\n\n# comment\nBAR=bar", ['FOO' => '', 'BAR' => 'bar']], + ['FOO=NOT#COMMENT', ['FOO' => 'NOT#COMMENT']], + ['FOO= # Comment', ['FOO' => '']], // edge cases (no conversions, only strings as values) - array('FOO=0', array('FOO' => '0')), - array('FOO=false', array('FOO' => 'false')), - array('FOO=null', array('FOO' => 'null')), + ['FOO=0', ['FOO' => '0']], + ['FOO=false', ['FOO' => 'false']], + ['FOO=null', ['FOO' => 'null']], // export - array('export FOO=bar', array('FOO' => 'bar')), - array(' export FOO=bar', array('FOO' => 'bar')), + ['export FOO=bar', ['FOO' => 'bar']], + [' export FOO=bar', ['FOO' => 'bar']], // variable expansion - array("FOO=BAR\nBAR=\$FOO", array('FOO' => 'BAR', 'BAR' => 'BAR')), - array("FOO=BAR\nBAR=\"\$FOO\"", array('FOO' => 'BAR', 'BAR' => 'BAR')), - array("FOO=BAR\nBAR='\$FOO'", array('FOO' => 'BAR', 'BAR' => '$FOO')), - array("FOO_BAR9=BAR\nBAR=\$FOO_BAR9", array('FOO_BAR9' => 'BAR', 'BAR' => 'BAR')), - array("FOO=BAR\nBAR=\${FOO}Z", array('FOO' => 'BAR', 'BAR' => 'BARZ')), - array("FOO=BAR\nBAR=\$FOO}", array('FOO' => 'BAR', 'BAR' => 'BAR}')), - array("FOO=BAR\nBAR=\\\$FOO", array('FOO' => 'BAR', 'BAR' => '$FOO')), - array('FOO=" \\$ "', array('FOO' => ' $ ')), - array('FOO=" $ "', array('FOO' => ' $ ')), - array('BAR=$LOCAL', array('BAR' => 'local')), - array('BAR=$REMOTE', array('BAR' => 'remote')), - array('BAR=$SERVERVAR', array('BAR' => 'servervar')), - array('FOO=$NOTDEFINED', array('FOO' => '')), - ); + ["FOO=BAR\nBAR=\$FOO", ['FOO' => 'BAR', 'BAR' => 'BAR']], + ["FOO=BAR\nBAR=\"\$FOO\"", ['FOO' => 'BAR', 'BAR' => 'BAR']], + ["FOO=BAR\nBAR='\$FOO'", ['FOO' => 'BAR', 'BAR' => '$FOO']], + ["FOO_BAR9=BAR\nBAR=\$FOO_BAR9", ['FOO_BAR9' => 'BAR', 'BAR' => 'BAR']], + ["FOO=BAR\nBAR=\${FOO}Z", ['FOO' => 'BAR', 'BAR' => 'BARZ']], + ["FOO=BAR\nBAR=\$FOO}", ['FOO' => 'BAR', 'BAR' => 'BAR}']], + ["FOO=BAR\nBAR=\\\$FOO", ['FOO' => 'BAR', 'BAR' => '$FOO']], + ['FOO=" \\$ "', ['FOO' => ' $ ']], + ['FOO=" $ "', ['FOO' => ' $ ']], + ['BAR=$LOCAL', ['BAR' => 'local']], + ['BAR=$REMOTE', ['BAR' => 'remote']], + ['BAR=$SERVERVAR', ['BAR' => 'servervar']], + ['FOO=$NOTDEFINED', ['FOO' => '']], + ]; if ('\\' !== \DIRECTORY_SEPARATOR) { - $tests = array_merge($tests, array( + $tests = array_merge($tests, [ // command expansion - array('FOO=$(echo foo)', array('FOO' => 'foo')), - array('FOO=$((1+2))', array('FOO' => '3')), - array('FOO=FOO$((1+2))BAR', array('FOO' => 'FOO3BAR')), - array('FOO=$(echo "$(echo "$(echo "$(echo foo)")")")', array('FOO' => 'foo')), - array("FOO=$(echo \"Quotes won't be a problem\")", array('FOO' => 'Quotes won\'t be a problem')), - array("FOO=bar\nBAR=$(echo \"FOO is \$FOO\")", array('FOO' => 'bar', 'BAR' => 'FOO is bar')), - )); + ['FOO=$(echo foo)', ['FOO' => 'foo']], + ['FOO=$((1+2))', ['FOO' => '3']], + ['FOO=FOO$((1+2))BAR', ['FOO' => 'FOO3BAR']], + ['FOO=$(echo "$(echo "$(echo "$(echo foo)")")")', ['FOO' => 'foo']], + ["FOO=$(echo \"Quotes won't be a problem\")", ['FOO' => 'Quotes won\'t be a problem']], + ["FOO=bar\nBAR=$(echo \"FOO is \$FOO\")", ['FOO' => 'bar', 'BAR' => 'FOO is bar']], + ]); } return $tests; @@ -319,7 +319,7 @@ public function testServerSuperglobalIsNotOverriden() $originalValue = $_SERVER['argc']; $dotenv = new Dotenv(); - $dotenv->populate(array('argc' => 'new_value')); + $dotenv->populate(['argc' => 'new_value']); $this->assertSame($originalValue, $_SERVER['argc']); } @@ -330,7 +330,7 @@ public function testEnvVarIsNotOverriden() $_SERVER['TEST_ENV_VAR'] = 'original_value'; $dotenv = new Dotenv(); - $dotenv->populate(array('TEST_ENV_VAR' => 'new_value')); + $dotenv->populate(['TEST_ENV_VAR' => 'new_value']); $this->assertSame('original_value', getenv('TEST_ENV_VAR')); } @@ -340,7 +340,7 @@ public function testHttpVarIsPartiallyOverriden() $_SERVER['HTTP_TEST_ENV_VAR'] = 'http_value'; $dotenv = new Dotenv(); - $dotenv->populate(array('HTTP_TEST_ENV_VAR' => 'env_value')); + $dotenv->populate(['HTTP_TEST_ENV_VAR' => 'env_value']); $this->assertSame('env_value', getenv('HTTP_TEST_ENV_VAR')); $this->assertSame('env_value', $_ENV['HTTP_TEST_ENV_VAR']); @@ -352,7 +352,7 @@ public function testEnvVarIsOverriden() putenv('TEST_ENV_VAR_OVERRIDEN=original_value'); $dotenv = new Dotenv(); - $dotenv->populate(array('TEST_ENV_VAR_OVERRIDEN' => 'new_value'), true); + $dotenv->populate(['TEST_ENV_VAR_OVERRIDEN' => 'new_value'], true); $this->assertSame('new_value', getenv('TEST_ENV_VAR_OVERRIDEN')); $this->assertSame('new_value', $_ENV['TEST_ENV_VAR_OVERRIDEN']); @@ -374,7 +374,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() putenv('DATABASE_URL'); $dotenv = new Dotenv(); - $dotenv->populate(array('APP_DEBUG' => '1', 'DATABASE_URL' => 'mysql://root@localhost/db')); + $dotenv->populate(['APP_DEBUG' => '1', 'DATABASE_URL' => 'mysql://root@localhost/db']); $this->assertSame('APP_DEBUG,DATABASE_URL', getenv('SYMFONY_DOTENV_VARS')); @@ -391,8 +391,8 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() putenv('DATABASE_URL'); $dotenv = new Dotenv(); - $dotenv->populate(array('APP_DEBUG' => '0', 'DATABASE_URL' => 'mysql://root@localhost/db')); - $dotenv->populate(array('DATABASE_URL' => 'sqlite:///somedb.sqlite')); + $dotenv->populate(['APP_DEBUG' => '0', 'DATABASE_URL' => 'mysql://root@localhost/db']); + $dotenv->populate(['DATABASE_URL' => 'sqlite:///somedb.sqlite']); $this->assertSame('APP_ENV,DATABASE_URL', getenv('SYMFONY_DOTENV_VARS')); } @@ -407,7 +407,7 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() putenv('DOCUMENT_ROOT=/var/www'); $dotenv = new Dotenv(); - $dotenv->populate(array('FOO' => 'foo1', 'BAR' => 'bar1', 'BAZ' => 'baz1', 'DOCUMENT_ROOT' => '/boot')); + $dotenv->populate(['FOO' => 'foo1', 'BAR' => 'bar1', 'BAZ' => 'baz1', 'DOCUMENT_ROOT' => '/boot']); $this->assertSame('foo1', getenv('FOO')); $this->assertSame('bar1', getenv('BAR')); diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 50c5fd5fa4fc7..6962c5facfdf6 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -28,14 +28,14 @@ */ class EventDispatcher implements EventDispatcherInterface { - private $listeners = array(); - private $sorted = array(); + private $listeners = []; + private $sorted = []; private $optimized; public function __construct() { if (__CLASS__ === \get_class($this)) { - $this->optimized = array(); + $this->optimized = []; } } @@ -49,7 +49,7 @@ public function dispatch($eventName, Event $event = null) } if (null !== $this->optimized && null !== $eventName) { - $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? array() : $this->optimizeListeners($eventName)); + $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName)); } else { $listeners = $this->getListeners($eventName); } @@ -68,7 +68,7 @@ public function getListeners($eventName = null) { if (null !== $eventName) { if (empty($this->listeners[$eventName])) { - return array(); + return []; } if (!isset($this->sorted[$eventName])) { @@ -175,12 +175,12 @@ public function addSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (\is_string($params)) { - $this->addListener($eventName, array($subscriber, $params)); + $this->addListener($eventName, [$subscriber, $params]); } elseif (\is_string($params[0])) { - $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0); + $this->addListener($eventName, [$subscriber, $params[0]], isset($params[1]) ? $params[1] : 0); } else { foreach ($params as $listener) { - $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0); + $this->addListener($eventName, [$subscriber, $listener[0]], isset($listener[1]) ? $listener[1] : 0); } } } @@ -194,10 +194,10 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (\is_array($params) && \is_array($params[0])) { foreach ($params as $listener) { - $this->removeListener($eventName, array($subscriber, $listener[0])); + $this->removeListener($eventName, [$subscriber, $listener[0]]); } } else { - $this->removeListener($eventName, array($subscriber, \is_string($params) ? $params : $params[0])); + $this->removeListener($eventName, [$subscriber, \is_string($params) ? $params : $params[0]]); } } } @@ -228,7 +228,7 @@ protected function doDispatch($listeners, $eventName, Event $event) private function sortListeners(string $eventName) { krsort($this->listeners[$eventName]); - $this->sorted[$eventName] = array(); + $this->sorted[$eventName] = []; foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as $k => $listener) { @@ -246,7 +246,7 @@ private function sortListeners(string $eventName) private function optimizeListeners(string $eventName): array { krsort($this->listeners[$eventName]); - $this->optimized[$eventName] = array(); + $this->optimized[$eventName] = []; foreach ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as &$listener) { diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index 4a533dfa56664..98fd027a6a736 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -50,15 +50,15 @@ protected function createEventDispatcher() public function testInitialState() { - $this->assertEquals(array(), $this->dispatcher->getListeners()); + $this->assertEquals([], $this->dispatcher->getListeners()); $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); } public function testAddListener() { - $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); - $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); + $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); $this->assertTrue($this->dispatcher->hasListeners()); $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); @@ -76,15 +76,15 @@ public function testGetListenersSortsByPriority() $listener2->name = '2'; $listener3->name = '3'; - $this->dispatcher->addListener('pre.foo', array($listener1, 'preFoo'), -10); - $this->dispatcher->addListener('pre.foo', array($listener2, 'preFoo'), 10); - $this->dispatcher->addListener('pre.foo', array($listener3, 'preFoo')); + $this->dispatcher->addListener('pre.foo', [$listener1, 'preFoo'], -10); + $this->dispatcher->addListener('pre.foo', [$listener2, 'preFoo'], 10); + $this->dispatcher->addListener('pre.foo', [$listener3, 'preFoo']); - $expected = array( - array($listener2, 'preFoo'), - array($listener3, 'preFoo'), - array($listener1, 'preFoo'), - ); + $expected = [ + [$listener2, 'preFoo'], + [$listener3, 'preFoo'], + [$listener1, 'preFoo'], + ]; $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); } @@ -105,10 +105,10 @@ public function testGetAllListenersSortsByPriority() $this->dispatcher->addListener('post.foo', $listener5); $this->dispatcher->addListener('post.foo', $listener6, 10); - $expected = array( - 'pre.foo' => array($listener3, $listener2, $listener1), - 'post.foo' => array($listener6, $listener5, $listener4), - ); + $expected = [ + 'pre.foo' => [$listener3, $listener2, $listener1], + 'post.foo' => [$listener6, $listener5, $listener4], + ]; $this->assertSame($expected, $this->dispatcher->getListeners()); } @@ -129,8 +129,8 @@ public function testGetListenerPriority() public function testDispatch() { - $this->dispatcher->addListener('pre.foo', array($this->listener, 'preFoo')); - $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo')); + $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); + $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); $this->dispatcher->dispatch(self::preFoo); $this->assertTrue($this->listener->preFooInvoked); $this->assertFalse($this->listener->postFooInvoked); @@ -160,8 +160,8 @@ public function testStopEventPropagation() // postFoo() stops the propagation, so only one listener should // be executed // Manually set priority to enforce $this->listener to be called first - $this->dispatcher->addListener('post.foo', array($this->listener, 'postFoo'), 10); - $this->dispatcher->addListener('post.foo', array($otherListener, 'postFoo')); + $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo'], 10); + $this->dispatcher->addListener('post.foo', [$otherListener, 'postFoo']); $this->dispatcher->dispatch(self::postFoo); $this->assertTrue($this->listener->postFooInvoked); $this->assertFalse($otherListener->postFooInvoked); @@ -169,7 +169,7 @@ public function testStopEventPropagation() public function testDispatchByPriority() { - $invoked = array(); + $invoked = []; $listener1 = function () use (&$invoked) { $invoked[] = '1'; }; @@ -183,7 +183,7 @@ public function testDispatchByPriority() $this->dispatcher->addListener('pre.foo', $listener2); $this->dispatcher->addListener('pre.foo', $listener3, 10); $this->dispatcher->dispatch(self::preFoo); - $this->assertEquals(array('3', '2', '1'), $invoked); + $this->assertEquals(['3', '2', '1'], $invoked); } public function testRemoveListener() @@ -261,7 +261,7 @@ public function testRemoveSubscriberWithMultipleListeners() public function testEventReceivesTheDispatcherInstanceAsArgument() { $listener = new TestWithDispatcher(); - $this->dispatcher->addListener('test', array($listener, 'foo')); + $this->dispatcher->addListener('test', [$listener, 'foo']); $this->assertNull($listener->name); $this->assertNull($listener->dispatcher); $this->dispatcher->dispatch('test'); @@ -298,7 +298,7 @@ public function testGetListenersWhenAddedCallbackListenerIsRemoved() $listener = function () {}; $this->dispatcher->addListener('foo', $listener); $this->dispatcher->removeListener('foo', $listener); - $this->assertSame(array(), $this->dispatcher->getListeners()); + $this->assertSame([], $this->dispatcher->getListeners()); } public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() @@ -310,7 +310,7 @@ public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEv public function testHasListenersIsLazy() { $called = 0; - $listener = array(function () use (&$called) { ++$called; }, 'onFoo'); + $listener = [function () use (&$called) { ++$called; }, 'onFoo']; $this->dispatcher->addListener('foo', $listener); $this->assertTrue($this->dispatcher->hasListeners()); $this->assertTrue($this->dispatcher->hasListeners('foo')); @@ -325,7 +325,7 @@ public function testDispatchLazyListener() return new TestWithDispatcher(); }; - $this->dispatcher->addListener('foo', array($factory, 'foo')); + $this->dispatcher->addListener('foo', [$factory, 'foo']); $this->assertSame(0, $called); $this->dispatcher->dispatch('foo', new Event()); $this->dispatcher->dispatch('foo', new Event()); @@ -337,14 +337,14 @@ public function testRemoveFindsLazyListeners() $test = new TestWithDispatcher(); $factory = function () use ($test) { return $test; }; - $this->dispatcher->addListener('foo', array($factory, 'foo')); + $this->dispatcher->addListener('foo', [$factory, 'foo']); $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->dispatcher->removeListener('foo', array($test, 'foo')); + $this->dispatcher->removeListener('foo', [$test, 'foo']); $this->assertFalse($this->dispatcher->hasListeners('foo')); - $this->dispatcher->addListener('foo', array($test, 'foo')); + $this->dispatcher->addListener('foo', [$test, 'foo']); $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->dispatcher->removeListener('foo', array($factory, 'foo')); + $this->dispatcher->removeListener('foo', [$factory, 'foo']); $this->assertFalse($this->dispatcher->hasListeners('foo')); } @@ -353,12 +353,12 @@ public function testPriorityFindsLazyListeners() $test = new TestWithDispatcher(); $factory = function () use ($test) { return $test; }; - $this->dispatcher->addListener('foo', array($factory, 'foo'), 3); - $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', array($test, 'foo'))); - $this->dispatcher->removeListener('foo', array($factory, 'foo')); + $this->dispatcher->addListener('foo', [$factory, 'foo'], 3); + $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', [$test, 'foo'])); + $this->dispatcher->removeListener('foo', [$factory, 'foo']); - $this->dispatcher->addListener('foo', array($test, 'foo'), 5); - $this->assertSame(5, $this->dispatcher->getListenerPriority('foo', array($factory, 'foo'))); + $this->dispatcher->addListener('foo', [$test, 'foo'], 5); + $this->assertSame(5, $this->dispatcher->getListenerPriority('foo', [$factory, 'foo'])); } public function testGetLazyListeners() @@ -366,31 +366,31 @@ public function testGetLazyListeners() $test = new TestWithDispatcher(); $factory = function () use ($test) { return $test; }; - $this->dispatcher->addListener('foo', array($factory, 'foo'), 3); - $this->assertSame(array(array($test, 'foo')), $this->dispatcher->getListeners('foo')); + $this->dispatcher->addListener('foo', [$factory, 'foo'], 3); + $this->assertSame([[$test, 'foo']], $this->dispatcher->getListeners('foo')); - $this->dispatcher->removeListener('foo', array($test, 'foo')); - $this->dispatcher->addListener('bar', array($factory, 'foo'), 3); - $this->assertSame(array('bar' => array(array($test, 'foo'))), $this->dispatcher->getListeners()); + $this->dispatcher->removeListener('foo', [$test, 'foo']); + $this->dispatcher->addListener('bar', [$factory, 'foo'], 3); + $this->assertSame(['bar' => [[$test, 'foo']]], $this->dispatcher->getListeners()); } public function testMutatingWhilePropagationIsStopped() { $testLoaded = false; $test = new TestEventListener(); - $this->dispatcher->addListener('foo', array($test, 'postFoo')); - $this->dispatcher->addListener('foo', array(function () use ($test, &$testLoaded) { + $this->dispatcher->addListener('foo', [$test, 'postFoo']); + $this->dispatcher->addListener('foo', [function () use ($test, &$testLoaded) { $testLoaded = true; return $test; - }, 'preFoo')); + }, 'preFoo']); $this->dispatcher->dispatch('foo'); $this->assertTrue($test->postFooInvoked); $this->assertFalse($test->preFooInvoked); - $this->assertsame(0, $this->dispatcher->getListenerPriority('foo', array($test, 'preFoo'))); + $this->assertsame(0, $this->dispatcher->getListenerPriority('foo', [$test, 'preFoo'])); $test->preFoo(new Event()); $this->dispatcher->dispatch('foo'); @@ -444,7 +444,7 @@ class TestEventSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { - return array('pre.foo' => 'preFoo', 'post.foo' => 'postFoo'); + return ['pre.foo' => 'preFoo', 'post.foo' => 'postFoo']; } } @@ -452,10 +452,10 @@ class TestEventSubscriberWithPriorities implements EventSubscriberInterface { public static function getSubscribedEvents() { - return array( - 'pre.foo' => array('preFoo', 10), - 'post.foo' => array('postFoo'), - ); + return [ + 'pre.foo' => ['preFoo', 10], + 'post.foo' => ['postFoo'], + ]; } } @@ -463,9 +463,9 @@ class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterfa { public static function getSubscribedEvents() { - return array('pre.foo' => array( - array('preFoo1'), - array('preFoo2', 10), - )); + return ['pre.foo' => [ + ['preFoo1'], + ['preFoo2', 10], + ]]; } } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php index 8badd0817b494..cac3ae2311ec1 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php @@ -123,7 +123,7 @@ public function configureOptions(OptionsResolver $resolver) 'auto_initialize' => true, ]); - $resolver->setAllowedTypes('block_prefix', array('null', 'string')); + $resolver->setAllowedTypes('block_prefix', ['null', 'string']); $resolver->setAllowedTypes('attr', 'array'); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php index f05f321da7f75..b6fe373d7b90b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateIntervalToArrayTransformerTest.php @@ -24,7 +24,7 @@ public function testTransform() { $transformer = new DateIntervalToArrayTransformer(); $input = new \DateInterval('P1Y2M3DT4H5M6S'); - $output = array( + $output = [ 'years' => '1', 'months' => '2', 'days' => '3', @@ -32,14 +32,14 @@ public function testTransform() 'minutes' => '5', 'seconds' => '6', 'invert' => false, - ); + ]; $this->assertSame($output, $transformer->transform($input)); } public function testTransformEmpty() { $transformer = new DateIntervalToArrayTransformer(); - $output = array( + $output = [ 'years' => '', 'months' => '', 'days' => '', @@ -47,43 +47,43 @@ public function testTransformEmpty() 'minutes' => '', 'seconds' => '', 'invert' => false, - ); + ]; $this->assertSame($output, $transformer->transform(null)); } public function testTransformEmptyWithFields() { - $transformer = new DateIntervalToArrayTransformer(array('years', 'weeks', 'minutes', 'seconds')); - $output = array( + $transformer = new DateIntervalToArrayTransformer(['years', 'weeks', 'minutes', 'seconds']); + $output = [ 'years' => '', 'weeks' => '', 'minutes' => '', 'seconds' => '', - ); + ]; $this->assertSame($output, $transformer->transform(null)); } public function testTransformWithFields() { - $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds')); + $transformer = new DateIntervalToArrayTransformer(['years', 'minutes', 'seconds']); $input = new \DateInterval('P1Y2M3DT4H5M6S'); - $output = array( + $output = [ 'years' => '1', 'minutes' => '5', 'seconds' => '6', - ); + ]; $this->assertSame($output, $transformer->transform($input)); } public function testTransformWithWeek() { - $transformer = new DateIntervalToArrayTransformer(array('weeks', 'minutes', 'seconds')); + $transformer = new DateIntervalToArrayTransformer(['weeks', 'minutes', 'seconds']); $input = new \DateInterval('P1Y2M3WT4H5M6S'); - $output = array( + $output = [ 'weeks' => '3', 'minutes' => '5', 'seconds' => '6', - ); + ]; $input = $transformer->transform($input); ksort($input); ksort($output); @@ -92,13 +92,13 @@ public function testTransformWithWeek() public function testTransformWithZeroWeek() { - $transformer = new DateIntervalToArrayTransformer(array('weeks', 'minutes', 'seconds')); + $transformer = new DateIntervalToArrayTransformer(['weeks', 'minutes', 'seconds']); $input = new \DateInterval('P1Y2M0WT4H5M6S'); - $output = array( + $output = [ 'weeks' => '0', 'minutes' => '5', 'seconds' => '6', - ); + ]; $input = $transformer->transform($input); ksort($input); ksort($output); @@ -107,13 +107,13 @@ public function testTransformWithZeroWeek() public function testTransformDaysToWeeks() { - $transformer = new DateIntervalToArrayTransformer(array('weeks', 'minutes', 'seconds')); + $transformer = new DateIntervalToArrayTransformer(['weeks', 'minutes', 'seconds']); $input = new \DateInterval('P1Y2M23DT4H5M6S'); - $output = array( + $output = [ 'weeks' => '3', 'minutes' => '5', 'seconds' => '6', - ); + ]; $input = $transformer->transform($input); ksort($input); ksort($output); @@ -122,25 +122,25 @@ public function testTransformDaysToWeeks() public function testTransformDaysNotOverflowingToWeeks() { - $transformer = new DateIntervalToArrayTransformer(array('days', 'minutes', 'seconds')); + $transformer = new DateIntervalToArrayTransformer(['days', 'minutes', 'seconds']); $input = new \DateInterval('P1Y2M23DT4H5M6S'); - $output = array( + $output = [ 'days' => '23', 'minutes' => '5', 'seconds' => '6', - ); + ]; $this->assertSame($output, $transformer->transform($input)); } public function testTransformWithInvert() { - $transformer = new DateIntervalToArrayTransformer(array('years', 'invert')); + $transformer = new DateIntervalToArrayTransformer(['years', 'invert']); $input = new \DateInterval('P1Y'); $input->invert = 1; - $output = array( + $output = [ 'years' => '1', 'invert' => true, - ); + ]; $this->assertSame($output, $transformer->transform($input)); } @@ -148,7 +148,7 @@ public function testTransformWithPadding() { $transformer = new DateIntervalToArrayTransformer(null, true); $input = new \DateInterval('P1Y2M3DT4H5M6S'); - $output = array( + $output = [ 'years' => '01', 'months' => '02', 'days' => '03', @@ -156,19 +156,19 @@ public function testTransformWithPadding() 'minutes' => '05', 'seconds' => '06', 'invert' => false, - ); + ]; $this->assertSame($output, $transformer->transform($input)); } public function testTransformWithFieldsAndPadding() { - $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds'), true); + $transformer = new DateIntervalToArrayTransformer(['years', 'minutes', 'seconds'], true); $input = new \DateInterval('P1Y2M3DT4H5M6S'); - $output = array( + $output = [ 'years' => '01', 'minutes' => '05', 'seconds' => '06', - ); + ]; $this->assertSame($output, $transformer->transform($input)); } @@ -183,19 +183,19 @@ public function testReverseTransformRequiresDateTime() public function testReverseTransformWithUnsetFields() { $transformer = new DateIntervalToArrayTransformer(); - $input = array('years' => '1'); + $input = ['years' => '1']; $this->expectException(TransformationFailedException::class); $transformer->reverseTransform($input); } public function testReverseTransformWithEmptyFields() { - $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds')); - $input = array( + $transformer = new DateIntervalToArrayTransformer(['years', 'minutes', 'seconds']); + $input = [ 'years' => '1', 'minutes' => '', 'seconds' => '6', - ); + ]; if (method_exists($this, 'expectException')) { $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('This amount of "minutes" is invalid'); @@ -207,10 +207,10 @@ public function testReverseTransformWithEmptyFields() public function testReverseTransformWithWrongInvertType() { - $transformer = new DateIntervalToArrayTransformer(array('invert')); - $input = array( + $transformer = new DateIntervalToArrayTransformer(['invert']); + $input = [ 'invert' => '1', - ); + ]; if (method_exists($this, 'expectException')) { $this->expectException(TransformationFailedException::class); $this->expectExceptionMessage('The value of "invert" must be boolean'); @@ -223,7 +223,7 @@ public function testReverseTransformWithWrongInvertType() public function testReverseTransform() { $transformer = new DateIntervalToArrayTransformer(); - $input = array( + $input = [ 'years' => '1', 'months' => '2', 'days' => '3', @@ -231,7 +231,7 @@ public function testReverseTransform() 'minutes' => '5', 'seconds' => '6', 'invert' => false, - ); + ]; $output = new \DateInterval('P01Y02M03DT04H05M06S'); $this->assertDateIntervalEquals($output, $transformer->reverseTransform($input)); } @@ -239,28 +239,28 @@ public function testReverseTransform() public function testReverseTransformWithWeek() { $transformer = new DateIntervalToArrayTransformer( - array('years', 'months', 'weeks', 'hours', 'minutes', 'seconds') + ['years', 'months', 'weeks', 'hours', 'minutes', 'seconds'] ); - $input = array( + $input = [ 'years' => '1', 'months' => '2', 'weeks' => '3', 'hours' => '4', 'minutes' => '5', 'seconds' => '6', - ); + ]; $output = new \DateInterval('P1Y2M21DT4H5M6S'); $this->assertDateIntervalEquals($output, $transformer->reverseTransform($input)); } public function testReverseTransformWithFields() { - $transformer = new DateIntervalToArrayTransformer(array('years', 'minutes', 'seconds')); - $input = array( + $transformer = new DateIntervalToArrayTransformer(['years', 'minutes', 'seconds']); + $input = [ 'years' => '1', 'minutes' => '5', 'seconds' => '6', - ); + ]; $output = new \DateInterval('P1Y0M0DT0H5M6S'); $this->assertDateIntervalEquals($output, $transformer->reverseTransform($input)); } @@ -268,17 +268,17 @@ public function testReverseTransformWithFields() public function testBothTransformsWithWeek() { $transformer = new DateIntervalToArrayTransformer( - array('years', 'months', 'weeks', 'hours', 'minutes', 'seconds') + ['years', 'months', 'weeks', 'hours', 'minutes', 'seconds'] ); $interval = new \DateInterval('P1Y2M21DT4H5M6S'); - $array = array( + $array = [ 'years' => '1', 'months' => '2', 'weeks' => '3', 'hours' => '4', 'minutes' => '5', 'seconds' => '6', - ); + ]; $input = $transformer->transform($interval); ksort($input); ksort($array); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php index 56ae48ce70fd8..583a7c4f8b1c0 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -20,22 +20,22 @@ class CollectionTypeTest extends BaseTypeTest public function testContainsNoChildByDefault() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, - )); + ]); $this->assertCount(0, $form); } public function testSetDataAdjustsSize() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, - 'entry_options' => array( - 'attr' => array('maxlength' => 20), - ), - )); - $form->setData(array('foo@foo.com', 'foo@bar.com')); + 'entry_options' => [ + 'attr' => ['maxlength' => 20], + ], + ]); + $form->setData(['foo@foo.com', 'foo@bar.com']); $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]); $this->assertInstanceOf('Symfony\Component\Form\Form', $form[1]); @@ -47,7 +47,7 @@ public function testSetDataAdjustsSize() $this->assertEquals(20, $formAttrs0['maxlength']); $this->assertEquals(20, $formAttrs1['maxlength']); - $form->setData(array('foo@baz.com')); + $form->setData(['foo@baz.com']); $this->assertInstanceOf('Symfony\Component\Form\Form', $form[0]); $this->assertArrayNotHasKey(1, $form); $this->assertCount(1, $form); @@ -58,20 +58,20 @@ public function testSetDataAdjustsSize() public function testThrowsExceptionIfObjectIsNotTraversable() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, - )); + ]); $this->expectException('Symfony\Component\Form\Exception\UnexpectedTypeException'); $form->setData(new \stdClass()); } public function testNotResizedIfSubmittedWithMissingData() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, - )); - $form->setData(array('foo@foo.com', 'bar@bar.com')); - $form->submit(array('foo@bar.com')); + ]); + $form->setData(['foo@foo.com', 'bar@bar.com']); + $form->submit(['foo@bar.com']); $this->assertTrue($form->has('0')); $this->assertTrue($form->has('1')); @@ -81,106 +81,106 @@ public function testNotResizedIfSubmittedWithMissingData() public function testResizedDownIfSubmittedWithMissingDataAndAllowDelete() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, 'allow_delete' => true, - )); - $form->setData(array('foo@foo.com', 'bar@bar.com')); - $form->submit(array('foo@foo.com')); + ]); + $form->setData(['foo@foo.com', 'bar@bar.com']); + $form->submit(['foo@foo.com']); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); $this->assertEquals('foo@foo.com', $form[0]->getData()); - $this->assertEquals(array('foo@foo.com'), $form->getData()); + $this->assertEquals(['foo@foo.com'], $form->getData()); } public function testResizedDownIfSubmittedWithEmptyDataAndDeleteEmpty() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, 'allow_delete' => true, 'delete_empty' => true, - )); + ]); - $form->setData(array('foo@foo.com', 'bar@bar.com')); - $form->submit(array('foo@foo.com', '')); + $form->setData(['foo@foo.com', 'bar@bar.com']); + $form->submit(['foo@foo.com', '']); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); $this->assertEquals('foo@foo.com', $form[0]->getData()); - $this->assertEquals(array('foo@foo.com'), $form->getData()); + $this->assertEquals(['foo@foo.com'], $form->getData()); } public function testResizedDownWithDeleteEmptyCallable() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => AuthorType::class, 'allow_delete' => true, 'delete_empty' => function (Author $obj = null) { return null === $obj || empty($obj->firstName); }, - )); + ]); - $form->setData(array(new Author('Bob'), new Author('Alice'))); - $form->submit(array(array('firstName' => 'Bob'), array('firstName' => ''))); + $form->setData([new Author('Bob'), new Author('Alice')]); + $form->submit([['firstName' => 'Bob'], ['firstName' => '']]); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); $this->assertEquals(new Author('Bob'), $form[0]->getData()); - $this->assertEquals(array(new Author('Bob')), $form->getData()); + $this->assertEquals([new Author('Bob')], $form->getData()); } public function testResizedDownIfSubmittedWithCompoundEmptyDataDeleteEmptyAndNoDataClass() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => AuthorType::class, // If the field is not required, no new Author will be created if the // form is completely empty - 'entry_options' => array('data_class' => null), + 'entry_options' => ['data_class' => null], 'allow_add' => true, 'allow_delete' => true, 'delete_empty' => function ($author) { return empty($author['firstName']); }, - )); - $form->setData(array(array('firstName' => 'first', 'lastName' => 'last'))); - $form->submit(array( - array('firstName' => 's_first', 'lastName' => 's_last'), - array('firstName' => '', 'lastName' => ''), - )); + ]); + $form->setData([['firstName' => 'first', 'lastName' => 'last']]); + $form->submit([ + ['firstName' => 's_first', 'lastName' => 's_last'], + ['firstName' => '', 'lastName' => ''], + ]); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); - $this->assertEquals(array('firstName' => 's_first', 'lastName' => 's_last'), $form[0]->getData()); - $this->assertEquals(array(array('firstName' => 's_first', 'lastName' => 's_last')), $form->getData()); + $this->assertEquals(['firstName' => 's_first', 'lastName' => 's_last'], $form[0]->getData()); + $this->assertEquals([['firstName' => 's_first', 'lastName' => 's_last']], $form->getData()); } public function testDontAddEmptyDataIfDeleteEmpty() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, 'allow_add' => true, 'delete_empty' => true, - )); + ]); - $form->setData(array('foo@foo.com')); - $form->submit(array('foo@foo.com', '')); + $form->setData(['foo@foo.com']); + $form->submit(['foo@foo.com', '']); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); $this->assertEquals('foo@foo.com', $form[0]->getData()); - $this->assertEquals(array('foo@foo.com'), $form->getData()); + $this->assertEquals(['foo@foo.com'], $form->getData()); } public function testNoDeleteEmptyIfDeleteNotAllowed() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, 'allow_delete' => false, 'delete_empty' => true, - )); + ]); - $form->setData(array('foo@foo.com')); - $form->submit(array('')); + $form->setData(['foo@foo.com']); + $form->submit(['']); $this->assertTrue($form->has('0')); $this->assertEquals('', $form[0]->getData()); @@ -188,34 +188,34 @@ public function testNoDeleteEmptyIfDeleteNotAllowed() public function testResizedDownIfSubmittedWithCompoundEmptyDataAndDeleteEmpty() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => 'Symfony\Component\Form\Tests\Fixtures\AuthorType', // If the field is not required, no new Author will be created if the // form is completely empty - 'entry_options' => array('required' => false), + 'entry_options' => ['required' => false], 'allow_add' => true, 'delete_empty' => true, - )); + ]); - $form->setData(array(new Author('first', 'last'))); - $form->submit(array( - array('firstName' => 's_first', 'lastName' => 's_last'), - array('firstName' => '', 'lastName' => ''), - )); + $form->setData([new Author('first', 'last')]); + $form->submit([ + ['firstName' => 's_first', 'lastName' => 's_last'], + ['firstName' => '', 'lastName' => ''], + ]); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); $this->assertEquals(new Author('s_first', 's_last'), $form[0]->getData()); - $this->assertEquals(array(new Author('s_first', 's_last')), $form->getData()); + $this->assertEquals([new Author('s_first', 's_last')], $form->getData()); } public function testNotResizedIfSubmittedWithExtraData() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, - )); - $form->setData(array('foo@bar.com')); - $form->submit(array('foo@foo.com', 'bar@bar.com')); + ]); + $form->setData(['foo@bar.com']); + $form->submit(['foo@foo.com', 'bar@bar.com']); $this->assertTrue($form->has('0')); $this->assertFalse($form->has('1')); @@ -224,27 +224,27 @@ public function testNotResizedIfSubmittedWithExtraData() public function testResizedUpIfSubmittedWithExtraDataAndAllowAdd() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => TextTypeTest::TESTED_TYPE, 'allow_add' => true, - )); - $form->setData(array('foo@bar.com')); - $form->submit(array('foo@bar.com', 'bar@bar.com')); + ]); + $form->setData(['foo@bar.com']); + $form->submit(['foo@bar.com', 'bar@bar.com']); $this->assertTrue($form->has('0')); $this->assertTrue($form->has('1')); $this->assertEquals('foo@bar.com', $form[0]->getData()); $this->assertEquals('bar@bar.com', $form[1]->getData()); - $this->assertEquals(array('foo@bar.com', 'bar@bar.com'), $form->getData()); + $this->assertEquals(['foo@bar.com', 'bar@bar.com'], $form->getData()); } public function testAllowAddButNoPrototype() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => FormTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => false, - )); + ]); $this->assertFalse($form->has('__name__')); } @@ -252,11 +252,11 @@ public function testAllowAddButNoPrototype() public function testPrototypeMultipartPropagation() { $form = $this->factory - ->create(static::TESTED_TYPE, null, array( + ->create(static::TESTED_TYPE, null, [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, - )) + ]) ; $this->assertTrue($form->createView()->vars['multipart']); @@ -264,11 +264,11 @@ public function testPrototypeMultipartPropagation() public function testGetDataDoesNotContainsPrototypeNameBeforeDataAreSet() { - $form = $this->factory->create(static::TESTED_TYPE, array(), array( + $form = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'prototype' => true, 'allow_add' => true, - )); + ]); $data = $form->getData(); $this->assertArrayNotHasKey('__name__', $data); @@ -276,61 +276,61 @@ public function testGetDataDoesNotContainsPrototypeNameBeforeDataAreSet() public function testGetDataDoesNotContainsPrototypeNameAfterDataAreSet() { - $form = $this->factory->create(static::TESTED_TYPE, array(), array( + $form = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, - )); + ]); - $form->setData(array('foobar.png')); + $form->setData(['foobar.png']); $data = $form->getData(); $this->assertArrayNotHasKey('__name__', $data); } public function testPrototypeNameOption() { - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => FormTypeTest::TESTED_TYPE, 'prototype' => true, 'allow_add' => true, - )); + ]); $this->assertSame('__name__', $form->getConfig()->getAttribute('prototype')->getName(), '__name__ is the default'); - $form = $this->factory->create(static::TESTED_TYPE, null, array( + $form = $this->factory->create(static::TESTED_TYPE, null, [ 'entry_type' => FormTypeTest::TESTED_TYPE, 'prototype' => true, 'allow_add' => true, 'prototype_name' => '__test__', - )); + ]); $this->assertSame('__test__', $form->getConfig()->getAttribute('prototype')->getName()); } public function testPrototypeDefaultLabel() { - $form = $this->factory->create(static::TESTED_TYPE, array(), array( + $form = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', - )); + ]); $this->assertSame('__test__label__', $form->createView()->vars['prototype']->vars['label']); } public function testPrototypeData() { - $form = $this->factory->create(static::TESTED_TYPE, array(), array( + $form = $this->factory->create(static::TESTED_TYPE, [], [ 'allow_add' => true, 'prototype' => true, 'prototype_data' => 'foo', 'entry_type' => TextTypeTest::TESTED_TYPE, - 'entry_options' => array( + 'entry_options' => [ 'data' => 'bar', 'label' => false, - ), - )); + ], + ]); $this->assertSame('foo', $form->createView()->vars['prototype']->vars['value']); $this->assertFalse($form->createView()->vars['prototype']->vars['label']); @@ -338,25 +338,25 @@ public function testPrototypeData() public function testPrototypeDefaultRequired() { - $form = $this->factory->create(static::TESTED_TYPE, array(), array( + $form = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', - )); + ]); $this->assertTrue($form->createView()->vars['prototype']->vars['required']); } public function testPrototypeSetNotRequired() { - $form = $this->factory->create(static::TESTED_TYPE, array(), array( + $form = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', 'required' => false, - )); + ]); $this->assertFalse($form->createView()->vars['required'], 'collection is not required'); $this->assertFalse($form->createView()->vars['prototype']->vars['required'], '"prototype" should not be required'); @@ -364,16 +364,16 @@ public function testPrototypeSetNotRequired() public function testPrototypeSetNotRequiredIfParentNotRequired() { - $child = $this->factory->create(static::TESTED_TYPE, array(), array( + $child = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', - )); + ]); - $parent = $this->factory->create(FormTypeTest::TESTED_TYPE, array(), array( + $parent = $this->factory->create(FormTypeTest::TESTED_TYPE, [], [ 'required' => false, - )); + ]); $child->setParent($parent); $this->assertFalse($parent->createView()->vars['required'], 'Parent is not required'); @@ -383,19 +383,19 @@ public function testPrototypeSetNotRequiredIfParentNotRequired() public function testPrototypeNotOverrideRequiredByEntryOptionsInFavorOfParent() { - $child = $this->factory->create(static::TESTED_TYPE, array(), array( + $child = $this->factory->create(static::TESTED_TYPE, [], [ 'entry_type' => FileTypeTest::TESTED_TYPE, 'allow_add' => true, 'prototype' => true, 'prototype_name' => '__test__', - 'entry_options' => array( + 'entry_options' => [ 'required' => true, - ), - )); + ], + ]); - $parent = $this->factory->create(FormTypeTest::TESTED_TYPE, array(), array( + $parent = $this->factory->create(FormTypeTest::TESTED_TYPE, [], [ 'required' => false, - )); + ]); $child->setParent($parent); @@ -406,10 +406,10 @@ public function testPrototypeNotOverrideRequiredByEntryOptionsInFavorOfParent() public function testSubmitNull($expected = null, $norm = null, $view = null) { - parent::testSubmitNull(array(), array(), array()); + parent::testSubmitNull([], [], []); } - public function testSubmitNullUsesDefaultEmptyData($emptyData = array(), $expectedData = array()) + public function testSubmitNullUsesDefaultEmptyData($emptyData = [], $expectedData = []) { // resize form listener always set an empty array parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 5e0bb9e90f549..47e7ae66beb9b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -643,12 +643,12 @@ public function testSubmitNull($expected = null, $norm = null, $view = null) public function testPassBlockPrefixToViewWithParent() { $view = $this->factory->createNamedBuilder('parent', static::TESTED_TYPE) - ->add('child', $this->getTestedType(), array( + ->add('child', $this->getTestedType(), [ 'block_prefix' => 'child', - )) + ]) ->getForm() ->createView(); - $this->assertSame(array('form', 'child', '_parent_child'), $view['child']->vars['block_prefixes']); + $this->assertSame(['form', 'child', '_parent_child'], $view['child']->vars['block_prefixes']); } } diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index 1df46ef28f049..17c5f2624d57f 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -114,7 +114,7 @@ public function collect(Request $request, Response $response, \Exception $except } else { $dumper = new CliDumper('php://output', $this->charset); if (method_exists($dumper, 'setDisplayOptions')) { - $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } } @@ -219,7 +219,7 @@ public function __destruct() } else { $dumper = new CliDumper('php://output', $this->charset); if (method_exists($dumper, 'setDisplayOptions')) { - $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } } diff --git a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php index d862ad7306410..9f5bb7a2afd31 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.php @@ -55,7 +55,7 @@ public function reset() if ($this->logger instanceof DebugLoggerInterface) { $this->logger->clear(); } - $this->data = array(); + $this->data = []; } /** @@ -67,7 +67,7 @@ public function lateCollect() $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); // get compiler logs later (only when they are needed) to improve performance - $this->data['compiler_logs'] = array(); + $this->data['compiler_logs'] = []; $this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log'; $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs)); $this->data = $this->cloneVar($this->data); @@ -82,12 +82,12 @@ public function lateCollect() */ public function getLogs() { - return isset($this->data['logs']) ? $this->data['logs'] : array(); + return isset($this->data['logs']) ? $this->data['logs'] : []; } public function getPriorities() { - return isset($this->data['priorities']) ? $this->data['priorities'] : array(); + return isset($this->data['priorities']) ? $this->data['priorities'] : []; } public function countErrors() @@ -126,13 +126,13 @@ public function getName() private function getContainerDeprecationLogs() { if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) { - return array(); + return []; } $bootTime = filemtime($file); - $logs = array(); + $logs = []; foreach (unserialize(file_get_contents($file)) as $log) { - $log['context'] = array('exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])); + $log['context'] = ['exception' => new SilencedErrorContext($log['type'], $log['file'], $log['line'], $log['trace'], $log['count'])]; $log['timestamp'] = $bootTime; $log['priority'] = 100; $log['priorityName'] = 'DEBUG'; @@ -148,17 +148,17 @@ private function getContainerDeprecationLogs() private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): array { if (!file_exists($compilerLogsFilepath)) { - return array(); + return []; } - $logs = array(); + $logs = []; foreach (file($compilerLogsFilepath, FILE_IGNORE_NEW_LINES) as $log) { $log = explode(': ', $log, 2); if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) { - $log = array('Unknown Compiler Pass', implode(': ', $log)); + $log = ['Unknown Compiler Pass', implode(': ', $log)]; } - $logs[$log[0]][] = array('message' => $log[1]); + $logs[$log[0]][] = ['message' => $log[1]]; } return $logs; @@ -166,8 +166,8 @@ private function getContainerCompilerLogs(?string $compilerLogsFilepath = null): private function sanitizeLogs($logs) { - $sanitizedLogs = array(); - $silencedLogs = array(); + $sanitizedLogs = []; + $silencedLogs = []; foreach ($logs as $log) { if (!$this->isSilencedOrDeprecationErrorLog($log)) { @@ -186,10 +186,10 @@ private function sanitizeLogs($logs) $silencedLogs[$h] = true; if (!isset($sanitizedLogs[$message])) { - $sanitizedLogs[$message] = $log + array( + $sanitizedLogs[$message] = $log + [ 'errorCount' => 0, 'scream' => true, - ); + ]; } $sanitizedLogs[$message]['errorCount'] += $exception->count; @@ -201,10 +201,10 @@ private function sanitizeLogs($logs) if (isset($sanitizedLogs[$errorId])) { ++$sanitizedLogs[$errorId]['errorCount']; } else { - $log += array( + $log += [ 'errorCount' => 1, 'scream' => false, - ); + ]; $sanitizedLogs[$errorId] = $log; } @@ -225,7 +225,7 @@ private function isSilencedOrDeprecationErrorLog(array $log) return true; } - if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), array(E_DEPRECATED, E_USER_DEPRECATED), true)) { + if ($exception instanceof \ErrorException && \in_array($exception->getSeverity(), [E_DEPRECATED, E_USER_DEPRECATED], true)) { return true; } @@ -234,23 +234,23 @@ private function isSilencedOrDeprecationErrorLog(array $log) private function computeErrorsCount(array $containerDeprecationLogs) { - $silencedLogs = array(); - $count = array( + $silencedLogs = []; + $count = [ 'error_count' => $this->logger->countErrors($this->currentRequest), 'deprecation_count' => 0, 'warning_count' => 0, 'scream_count' => 0, - 'priorities' => array(), - ); + 'priorities' => [], + ]; foreach ($this->logger->getLogs($this->currentRequest) as $log) { if (isset($count['priorities'][$log['priority']])) { ++$count['priorities'][$log['priority']]['count']; } else { - $count['priorities'][$log['priority']] = array( + $count['priorities'][$log['priority']] = [ 'count' => 1, 'name' => $log['priorityName'], - ); + ]; } if ('WARNING' === $log['priorityName']) { ++$count['warning_count']; diff --git a/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php b/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php index e14a1aaf2d53a..2372575517a1b 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php @@ -45,6 +45,6 @@ public function onKernelRequest(GetResponseEvent $event) */ public static function getSubscribedEvents() { - return array(KernelEvents::REQUEST => array('onKernelRequest', 100)); + return [KernelEvents::REQUEST => ['onKernelRequest', 100]]; } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index 2c8e7744afc4c..0c21d74020aa3 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -79,13 +79,13 @@ private function setRouterContext(Request $request) public static function getSubscribedEvents() { - return array( - KernelEvents::REQUEST => array( - array('setDefaultLocale', 100), + return [ + KernelEvents::REQUEST => [ + ['setDefaultLocale', 100], // must be registered after the Router to have access to the _locale - array('onKernelRequest', 16), - ), - KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)), - ); + ['onKernelRequest', 16], + ], + KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], + ]; } } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php index 4c5cdf0e709d4..b4f92f97c13d1 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php @@ -30,7 +30,7 @@ class AddRequestFormatsListenerTest extends TestCase protected function setUp() { - $this->listener = new AddRequestFormatsListener(array('csv' => array('text/csv', 'text/plain'))); + $this->listener = new AddRequestFormatsListener(['csv' => ['text/csv', 'text/plain']]); } protected function tearDown() @@ -46,7 +46,7 @@ public function testIsAnEventSubscriber() public function testRegisteredEvent() { $this->assertEquals( - array(KernelEvents::REQUEST => array('onKernelRequest', 100)), + [KernelEvents::REQUEST => ['onKernelRequest', 100]], AddRequestFormatsListener::getSubscribedEvents() ); } @@ -58,7 +58,7 @@ public function testSetAdditionalFormats() $request->expects($this->once()) ->method('setFormat') - ->with('csv', array('text/csv', 'text/plain')); + ->with('csv', ['text/csv', 'text/plain']); $this->listener->onKernelRequest($event); } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index 2ad903f4b1a9a..5462fec978f4a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -36,10 +36,10 @@ public function testIsAnEventSubscriber() public function testRegisteredEvent() { $this->assertEquals( - array( - KernelEvents::REQUEST => array(array('setDefaultLocale', 100), array('onKernelRequest', 16)), - KernelEvents::FINISH_REQUEST => array(array('onKernelFinishRequest', 0)), - ), + [ + KernelEvents::REQUEST => [['setDefaultLocale', 100], ['onKernelRequest', 16]], + KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], + ], LocaleListener::getSubscribedEvents() ); } diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php index fbd49359dd2f6..f5c856f9d520a 100644 --- a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php @@ -38,7 +38,7 @@ public function testLdapQuery() $ldap = new Adapter($this->getLdapConfig()); $ldap->getConnection()->bind('cn=admin,dc=symfony,dc=com', 'symfony'); - $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', array()); + $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', []); $result = $query->execute(); $this->assertInstanceOf(Collection::class, $result); @@ -46,8 +46,8 @@ public function testLdapQuery() $entry = $result[0]; $this->assertInstanceOf(Entry::class, $entry); - $this->assertEquals(array('Fabien Potencier'), $entry->getAttribute('cn')); - $this->assertEquals(array('fabpot@symfony.com', 'fabien@potencier.com'), $entry->getAttribute('mail')); + $this->assertEquals(['Fabien Potencier'], $entry->getAttribute('cn')); + $this->assertEquals(['fabpot@symfony.com', 'fabien@potencier.com'], $entry->getAttribute('mail')); } /** @@ -58,14 +58,14 @@ public function testLdapQueryIterator() $ldap = new Adapter($this->getLdapConfig()); $ldap->getConnection()->bind('cn=admin,dc=symfony,dc=com', 'symfony'); - $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', array()); + $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', []); $result = $query->execute(); $iterator = $result->getIterator(); $iterator->rewind(); $entry = $iterator->current(); $this->assertInstanceOf(Entry::class, $entry); - $this->assertEquals(array('Fabien Potencier'), $entry->getAttribute('cn')); - $this->assertEquals(array('fabpot@symfony.com', 'fabien@potencier.com'), $entry->getAttribute('mail')); + $this->assertEquals(['Fabien Potencier'], $entry->getAttribute('cn')); + $this->assertEquals(['fabpot@symfony.com', 'fabien@potencier.com'], $entry->getAttribute('mail')); } /** @@ -75,7 +75,7 @@ public function testLdapQueryWithoutBind() { $ldap = new Adapter($this->getLdapConfig()); $this->expectException(NotBoundException::class); - $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', array()); + $query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectclass=person)(ou=Maintainers))', []); $query->execute(); } @@ -85,14 +85,14 @@ public function testLdapQueryScopeBase() $ldap->getConnection()->bind('cn=admin,dc=symfony,dc=com', 'symfony'); - $query = $ldap->createQuery('cn=Fabien Potencier,dc=symfony,dc=com', '(objectclass=*)', array( + $query = $ldap->createQuery('cn=Fabien Potencier,dc=symfony,dc=com', '(objectclass=*)', [ 'scope' => Query::SCOPE_BASE, - )); + ]); $result = $query->execute(); $entry = $result[0]; $this->assertEquals($result->count(), 1); - $this->assertEquals(array('Fabien Potencier'), $entry->getAttribute('cn')); + $this->assertEquals(['Fabien Potencier'], $entry->getAttribute('cn')); } public function testLdapQueryScopeOneLevel() @@ -101,14 +101,14 @@ public function testLdapQueryScopeOneLevel() $ldap->getConnection()->bind('cn=admin,dc=symfony,dc=com', 'symfony'); - $one_level_result = $ldap->createQuery('ou=Components,dc=symfony,dc=com', '(objectclass=*)', array( + $one_level_result = $ldap->createQuery('ou=Components,dc=symfony,dc=com', '(objectclass=*)', [ 'scope' => Query::SCOPE_ONE, - ))->execute(); + ])->execute(); $subtree_count = $ldap->createQuery('ou=Components,dc=symfony,dc=com', '(objectclass=*)')->execute()->count(); $this->assertNotEquals($one_level_result->count(), $subtree_count); $this->assertEquals($one_level_result->count(), 1); - $this->assertEquals($one_level_result[0]->getAttribute('ou'), array('Ldap')); + $this->assertEquals($one_level_result[0]->getAttribute('ou'), ['Ldap']); } } diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index fbb5cca0b0a0f..92be7daa49c90 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -47,7 +47,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt * "?" and "#" (would be interpreted wrongly as query and fragment identifier), * "'" and """ (are used as delimiters in HTML). */ - protected $decodedChars = array( + protected $decodedChars = [ // the slash can be used to designate a hierarchical structure and we want allow using it with this meaning // some webservers don't allow the slash in encoded form in the path for security reasons anyway // see http://stackoverflow.com/questions/4069002/http-400-if-2f-part-of-get-url-in-jboss @@ -65,7 +65,7 @@ class UrlGenerator implements UrlGeneratorInterface, ConfigurableRequirementsInt '%21' => '!', '%2A' => '*', '%7C' => '|', - ); + ]; public function __construct(RouteCollection $routes, RequestContext $context, LoggerInterface $logger = null, string $defaultLocale = null) { @@ -110,7 +110,7 @@ public function isStrictRequirements() /** * {@inheritdoc} */ - public function generate($name, $parameters = array(), $referenceType = self::ABSOLUTE_PATH) + public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH) { $route = null; $locale = $parameters['_locale'] @@ -141,7 +141,7 @@ public function generate($name, $parameters = array(), $referenceType = self::AB * @throws InvalidParameterException When a parameter value for a placeholder is not correct because * it does not match the requirement */ - protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = array()) + protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = []) { $variables = array_flip($variables); $mergedParams = array_replace($defaults, $this->context->getParameters(), $parameters); @@ -165,11 +165,11 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa // check requirement if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$varName])) { if ($this->strictRequirements) { - throw new InvalidParameterException(strtr($message, array('{parameter}' => $varName, '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$varName]))); + throw new InvalidParameterException(strtr($message, ['{parameter}' => $varName, '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$varName]])); } if ($this->logger) { - $this->logger->error($message, array('parameter' => $varName, 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$varName])); + $this->logger->error($message, ['parameter' => $varName, 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$varName]]); } return; @@ -195,7 +195,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa // the path segments "." and ".." are interpreted as relative reference when resolving a URI; see http://tools.ietf.org/html/rfc3986#section-3.3 // so we need to encode them as they are not used for this purpose here // otherwise we would generate a URI that, when followed by a user agent (e.g. browser), does not match this route - $url = strtr($url, array('/../' => '/%2E%2E/', '/./' => '/%2E/')); + $url = strtr($url, ['/../' => '/%2E%2E/', '/./' => '/%2E/']); if ('/..' === substr($url, -3)) { $url = substr($url, 0, -2).'%2E%2E'; } elseif ('/.' === substr($url, -2)) { @@ -219,11 +219,11 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa if ('variable' === $token[0]) { if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#i'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) { if ($this->strictRequirements) { - throw new InvalidParameterException(strtr($message, array('{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]]))); + throw new InvalidParameterException(strtr($message, ['{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]]])); } if ($this->logger) { - $this->logger->error($message, array('parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]])); + $this->logger->error($message, ['parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]]]); } return; @@ -277,11 +277,11 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa if ($extra && $query = http_build_query($extra, '', '&', PHP_QUERY_RFC3986)) { // "/" and "?" can be left decoded for better user experience, see // http://tools.ietf.org/html/rfc3986#section-3.4 - $url .= '?'.strtr($query, array('%2F' => '/')); + $url .= '?'.strtr($query, ['%2F' => '/']); } if ('' !== $fragment) { - $url .= '#'.strtr(rawurlencode($fragment), array('%2F' => '/', '%3F' => '?')); + $url .= '#'.strtr(rawurlencode($fragment), ['%2F' => '/', '%3F' => '?']); } return $url; diff --git a/src/Symfony/Component/Routing/RouteCompiler.php b/src/Symfony/Component/Routing/RouteCompiler.php index abab86be7a95b..adf3cef8e1c20 100644 --- a/src/Symfony/Component/Routing/RouteCompiler.php +++ b/src/Symfony/Component/Routing/RouteCompiler.php @@ -46,10 +46,10 @@ class RouteCompiler implements RouteCompilerInterface */ public static function compile(Route $route) { - $hostVariables = array(); - $variables = array(); + $hostVariables = []; + $variables = []; $hostRegex = null; - $hostTokens = array(); + $hostTokens = []; if ('' !== $host = $route->getHost()) { $result = self::compilePattern($route, $host, true); @@ -94,9 +94,9 @@ public static function compile(Route $route) private static function compilePattern(Route $route, $pattern, $isHost) { - $tokens = array(); - $variables = array(); - $matches = array(); + $tokens = []; + $variables = []; + $matches = []; $pos = 0; $defaultSeparator = $isHost ? '.' : '/'; $useUtf8 = preg_match('//u', $pattern); @@ -142,9 +142,9 @@ private static function compilePattern(Route $route, $pattern, $isHost) } if ($isSeparator && $precedingText !== $precedingChar) { - $tokens[] = array('text', substr($precedingText, 0, -\strlen($precedingChar))); + $tokens[] = ['text', substr($precedingText, 0, -\strlen($precedingChar))]; } elseif (!$isSeparator && \strlen($precedingText) > 0) { - $tokens[] = array('text', $precedingText); + $tokens[] = ['text', $precedingText]; } $regexp = $route->getRequirement($varName); @@ -183,7 +183,7 @@ private static function compilePattern(Route $route, $pattern, $isHost) $regexp = self::transformCapturingGroupsToNonCapturings($regexp); } - $tokens[] = array('variable', $isSeparator ? $precedingChar : '', $regexp, $varName); + $tokens[] = ['variable', $isSeparator ? $precedingChar : '', $regexp, $varName]; if ('!' === $varName[0]) { $varName = substr($varName, 1); } @@ -191,7 +191,7 @@ private static function compilePattern(Route $route, $pattern, $isHost) } if ($pos < \strlen($pattern)) { - $tokens[] = array('text', substr($pattern, $pos)); + $tokens[] = ['text', substr($pattern, $pos)]; } // find the first optional token @@ -224,12 +224,12 @@ private static function compilePattern(Route $route, $pattern, $isHost) } } - return array( + return [ 'staticPrefix' => self::determineStaticPrefix($route, $tokens), 'regex' => $regexp, 'tokens' => array_reverse($tokens), 'variables' => $variables, - ); + ]; } /** diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index 44edbe78285fb..6a79609917444 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -23,7 +23,7 @@ class UrlGeneratorTest extends TestCase public function testAbsoluteUrlWithPort80() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost/app.php/testing', $url); } @@ -31,7 +31,7 @@ public function testAbsoluteUrlWithPort80() public function testAbsoluteSecureUrlWithPort443() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $url = $this->getGenerator($routes, ['scheme' => 'https'])->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('https://localhost/app.php/testing', $url); } @@ -39,7 +39,7 @@ public function testAbsoluteSecureUrlWithPort443() public function testAbsoluteUrlWithNonStandardPort() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes, array('httpPort' => 8080))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $url = $this->getGenerator($routes, ['httpPort' => 8080])->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost:8080/app.php/testing', $url); } @@ -47,7 +47,7 @@ public function testAbsoluteUrlWithNonStandardPort() public function testAbsoluteSecureUrlWithNonStandardPort() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes, array('httpsPort' => 8080, 'scheme' => 'https'))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $url = $this->getGenerator($routes, ['httpsPort' => 8080, 'scheme' => 'https'])->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('https://localhost:8080/app.php/testing', $url); } @@ -55,7 +55,7 @@ public function testAbsoluteSecureUrlWithNonStandardPort() public function testRelativeUrlWithoutParameters() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing', $url); } @@ -63,15 +63,15 @@ public function testRelativeUrlWithoutParameters() public function testRelativeUrlWithParameter() { $routes = $this->getRoutes('test', new Route('/testing/{foo}')); - $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing/bar', $url); } public function testRelativeUrlWithNullParameter() { - $routes = $this->getRoutes('test', new Route('/testing.{format}', array('format' => null))); - $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH); + $routes = $this->getRoutes('test', new Route('/testing.{format}', ['format' => null])); + $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing', $url); } @@ -81,31 +81,31 @@ public function testRelativeUrlWithNullParameter() */ public function testRelativeUrlWithNullParameterButNotOptional() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', array('foo' => null))); + $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', ['foo' => null])); // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params. // Generating path "/testing//bar" would be wrong as matching this route would fail. - $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH); + $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); } public function testRelativeUrlWithOptionalZeroParameter() { $routes = $this->getRoutes('test', new Route('/testing/{page}')); - $url = $this->getGenerator($routes)->generate('test', array('page' => 0), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', ['page' => 0], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing/0', $url); } public function testNotPassedOptionalParameterInBetween() { - $routes = $this->getRoutes('test', new Route('/{slug}/{page}', array('slug' => 'index', 'page' => 0))); - $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', array('page' => 1))); + $routes = $this->getRoutes('test', new Route('/{slug}/{page}', ['slug' => 'index', 'page' => 0])); + $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', ['page' => 1])); $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test')); } public function testRelativeUrlWithExtraParameters() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing?foo=bar', $url); } @@ -113,7 +113,7 @@ public function testRelativeUrlWithExtraParameters() public function testAbsoluteUrlWithExtraParameters() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL); + $url = $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url); } @@ -121,7 +121,7 @@ public function testAbsoluteUrlWithExtraParameters() public function testUrlWithNullExtraParameters() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array('foo' => null), UrlGeneratorInterface::ABSOLUTE_URL); + $url = $this->getGenerator($routes)->generate('test', ['foo' => null], UrlGeneratorInterface::ABSOLUTE_URL); $this->assertEquals('http://localhost/app.php/testing', $url); } @@ -133,7 +133,7 @@ public function testUrlWithExtraParametersFromGlobals() $context = new RequestContext('/app.php'); $context->setParameter('bar', 'bar'); $generator->setContext($context); - $url = $generator->generate('test', array('foo' => 'bar')); + $url = $generator->generate('test', ['foo' => 'bar']); $this->assertEquals('/app.php/testing?foo=bar', $url); } @@ -145,19 +145,19 @@ public function testUrlWithGlobalParameter() $context = new RequestContext('/app.php'); $context->setParameter('foo', 'bar'); $generator->setContext($context); - $url = $generator->generate('test', array()); + $url = $generator->generate('test', []); $this->assertEquals('/app.php/testing/bar', $url); } public function testGlobalParameterHasHigherPriorityThanDefault() { - $routes = $this->getRoutes('test', new Route('/{_locale}', array('_locale' => 'en'))); + $routes = $this->getRoutes('test', new Route('/{_locale}', ['_locale' => 'en'])); $generator = $this->getGenerator($routes); $context = new RequestContext('/app.php'); $context->setParameter('_locale', 'de'); $generator->setContext($context); - $url = $generator->generate('test', array()); + $url = $generator->generate('test', []); $this->assertSame('/app.php/de', $url); } @@ -168,7 +168,7 @@ public function testGlobalParameterHasHigherPriorityThanDefault() public function testGenerateWithoutRoutes() { $routes = $this->getRoutes('foo', new Route('/testing/{foo}')); - $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); } /** @@ -177,7 +177,7 @@ public function testGenerateWithoutRoutes() public function testGenerateForRouteWithoutMandatoryParameter() { $routes = $this->getRoutes('test', new Route('/testing/{foo}')); - $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL); + $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL); } /** @@ -185,8 +185,8 @@ public function testGenerateForRouteWithoutMandatoryParameter() */ public function testGenerateForRouteWithInvalidOptionalParameter() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+'))); - $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); + $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); } /** @@ -194,35 +194,35 @@ public function testGenerateForRouteWithInvalidOptionalParameter() */ public function testGenerateForRouteWithInvalidParameter() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '1|2'))); - $this->getGenerator($routes)->generate('test', array('foo' => '0'), UrlGeneratorInterface::ABSOLUTE_URL); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', [], ['foo' => '1|2'])); + $this->getGenerator($routes)->generate('test', ['foo' => '0'], UrlGeneratorInterface::ABSOLUTE_URL); } public function testGenerateForRouteWithInvalidOptionalParameterNonStrict() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+'))); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(false); - $this->assertNull($generator->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertNull($generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+'))); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); $logger->expects($this->once()) ->method('error'); - $generator = $this->getGenerator($routes, array(), $logger); + $generator = $this->getGenerator($routes, [], $logger); $generator->setStrictRequirements(false); - $this->assertNull($generator->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertNull($generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+'))); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(null); - $this->assertSame('/app.php/testing/bar', $generator->generate('test', array('foo' => 'bar'))); + $this->assertSame('/app.php/testing/bar', $generator->generate('test', ['foo' => 'bar'])); } /** @@ -230,8 +230,8 @@ public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsC */ public function testGenerateForRouteWithInvalidMandatoryParameter() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => 'd+'))); - $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', [], ['foo' => 'd+'])); + $this->getGenerator($routes)->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL); } /** @@ -239,8 +239,8 @@ public function testGenerateForRouteWithInvalidMandatoryParameter() */ public function testGenerateForRouteWithInvalidUtf8Parameter() { - $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '\pL+'), array('utf8' => true))); - $this->getGenerator($routes)->generate('test', array('foo' => 'abc123'), UrlGeneratorInterface::ABSOLUTE_URL); + $routes = $this->getRoutes('test', new Route('/testing/{foo}', [], ['foo' => '\pL+'], ['utf8' => true])); + $this->getGenerator($routes)->generate('test', ['foo' => 'abc123'], UrlGeneratorInterface::ABSOLUTE_URL); } /** @@ -248,31 +248,31 @@ public function testGenerateForRouteWithInvalidUtf8Parameter() */ public function testRequiredParamAndEmptyPassed() { - $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+'))); - $this->getGenerator($routes)->generate('test', array('slug' => '')); + $routes = $this->getRoutes('test', new Route('/{slug}', [], ['slug' => '.+'])); + $this->getGenerator($routes)->generate('test', ['slug' => '']); } public function testSchemeRequirementDoesNothingIfSameCurrentScheme() { - $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http'))); + $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['http'])); $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test')); - $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https'))); - $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test')); + $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['https'])); + $this->assertEquals('/app.php/', $this->getGenerator($routes, ['scheme' => 'https'])->generate('test')); } public function testSchemeRequirementForcesAbsoluteUrl() { - $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https'))); + $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['https'])); $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test')); - $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http'))); - $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test')); + $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['http'])); + $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, ['scheme' => 'https'])->generate('test')); } public function testSchemeRequirementCreatesUrlForFirstRequiredScheme() { - $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('Ftp', 'https'))); + $routes = $this->getRoutes('test', new Route('/', [], [], [], '', ['Ftp', 'https'])); $this->assertEquals('ftp://localhost/app.php/', $this->getGenerator($routes)->generate('test')); } @@ -281,48 +281,48 @@ public function testPathWithTwoStartingSlashes() $routes = $this->getRoutes('test', new Route('//path-and-not-domain')); // this must not generate '//path-and-not-domain' because that would be a network path - $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test')); + $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, ['BaseUrl' => ''])->generate('test')); } public function testNoTrailingSlashForMultipleOptionalParameters() { - $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null))); + $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', ['slug2' => null, 'slug3' => null])); - $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo'))); + $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', ['slug1' => 'foo'])); } public function testWithAnIntegerAsADefaultValue() { - $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0))); + $routes = $this->getRoutes('test', new Route('/{default}', ['default' => 0])); - $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo'))); + $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', ['default' => 'foo'])); } public function testNullForOptionalParameterIsIgnored() { - $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0))); + $routes = $this->getRoutes('test', new Route('/test/{default}', ['default' => 0])); - $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null))); + $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', ['default' => null])); } public function testQueryParamSameAsDefault() { - $routes = $this->getRoutes('test', new Route('/test', array('page' => 1))); + $routes = $this->getRoutes('test', new Route('/test', ['page' => 1])); - $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', array('page' => 2))); - $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => 1))); - $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => '1'))); + $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', ['page' => 2])); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['page' => 1])); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['page' => '1'])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test')); } public function testArrayQueryParamSameAsDefault() { - $routes = $this->getRoutes('test', new Route('/test', array('array' => array('foo', 'bar')))); + $routes = $this->getRoutes('test', new Route('/test', ['array' => ['foo', 'bar']])); - $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', array('array' => array('bar', 'foo')))); - $this->assertSame('/app.php/test?array%5Ba%5D=foo&array%5Bb%5D=bar', $this->getGenerator($routes)->generate('test', array('array' => array('a' => 'foo', 'b' => 'bar')))); - $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array('foo', 'bar')))); - $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array(1 => 'bar', 0 => 'foo')))); + $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', ['array' => ['bar', 'foo']])); + $this->assertSame('/app.php/test?array%5Ba%5D=foo&array%5Bb%5D=bar', $this->getGenerator($routes)->generate('test', ['array' => ['a' => 'foo', 'b' => 'bar']])); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['array' => ['foo', 'bar']])); + $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', ['array' => [1 => 'bar', 0 => 'foo']])); $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test')); } @@ -342,11 +342,11 @@ public function testUrlEncoding() // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986) // and other special ASCII chars. These chars are tested as static text path, variable path and query param. $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id'; - $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+'))); - $this->assertSame($expectedPath, $this->getGenerator($routes)->generate('test', array( + $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", [], ['varpath' => '.+'])); + $this->assertSame($expectedPath, $this->getGenerator($routes)->generate('test', [ 'varpath' => $chars, 'query' => $chars, - ))); + ])); } public function testEncodingOfRelativePathSegments() @@ -361,24 +361,24 @@ public function testEncodingOfRelativePathSegments() public function testAdjacentVariables() { - $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+'))); + $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', ['z' => 'default-z', '_format' => 'html'], ['y' => '\d+'])); $generator = $this->getGenerator($routes); - $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123'))); - $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml'))); + $this->assertSame('/app.php/foo123', $generator->generate('test', ['x' => 'foo', 'y' => '123'])); + $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', ['x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml'])); // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything // and following optional variables like _format could never match. $this->expectException('Symfony\Component\Routing\Exception\InvalidParameterException'); - $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml')); + $generator->generate('test', ['x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml']); } public function testOptionalVariableWithNoRealSeparator() { - $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All'))); + $routes = $this->getRoutes('test', new Route('/get{what}', ['what' => 'All'])); $generator = $this->getGenerator($routes); $this->assertSame('/app.php/get', $generator->generate('test')); - $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites'))); + $this->assertSame('/app.php/getSites', $generator->generate('test', ['what' => 'Sites'])); } public function testRequiredVariableWithNoRealSeparator() @@ -386,7 +386,7 @@ public function testRequiredVariableWithNoRealSeparator() $routes = $this->getRoutes('test', new Route('/get{what}Suffix')); $generator = $this->getGenerator($routes); - $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites'))); + $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', ['what' => 'Sites'])); } public function testDefaultRequirementOfVariable() @@ -394,17 +394,17 @@ public function testDefaultRequirementOfVariable() $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); $generator = $this->getGenerator($routes); - $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html'))); + $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', ['page' => 'index', '_format' => 'mobile.html'])); } public function testImportantVariable() { - $routes = $this->getRoutes('test', (new Route('/{page}.{!_format}'))->addDefaults(array('_format' => 'mobile.html'))); + $routes = $this->getRoutes('test', (new Route('/{page}.{!_format}'))->addDefaults(['_format' => 'mobile.html'])); $generator = $this->getGenerator($routes); - $this->assertSame('/app.php/index.xml', $generator->generate('test', array('page' => 'index', '_format' => 'xml'))); - $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html'))); - $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index'))); + $this->assertSame('/app.php/index.xml', $generator->generate('test', ['page' => 'index', '_format' => 'xml'])); + $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', ['page' => 'index', '_format' => 'mobile.html'])); + $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', ['page' => 'index'])); } /** @@ -415,7 +415,7 @@ public function testImportantVariableWithNoDefault() $routes = $this->getRoutes('test', new Route('/{page}.{!_format}')); $generator = $this->getGenerator($routes); - $generator->generate('test', array('page' => 'index')); + $generator->generate('test', ['page' => 'index']); } /** @@ -424,7 +424,7 @@ public function testImportantVariableWithNoDefault() public function testDefaultRequirementOfVariableDisallowsSlash() { $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); - $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash')); + $this->getGenerator($routes)->generate('test', ['page' => 'index', '_format' => 'sl/ash']); } /** @@ -433,28 +433,28 @@ public function testDefaultRequirementOfVariableDisallowsSlash() public function testDefaultRequirementOfVariableDisallowsNextSeparator() { $routes = $this->getRoutes('test', new Route('/{page}.{_format}')); - $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html')); + $this->getGenerator($routes)->generate('test', ['page' => 'do.t', '_format' => 'html']); } public function testWithHostDifferentFromContext() { - $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com')); + $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com')); - $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' => 'Fabien', 'locale' => 'fr'))); + $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', ['name' => 'Fabien', 'locale' => 'fr'])); } public function testWithHostSameAsContext() { - $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com')); + $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com')); - $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr'))); + $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, ['host' => 'fr.example.com'])->generate('test', ['name' => 'Fabien', 'locale' => 'fr'])); } public function testWithHostSameAsContextAndAbsolute() { - $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com')); + $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com')); - $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, ['host' => 'fr.example.com'])->generate('test', ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::ABSOLUTE_URL)); } /** @@ -462,8 +462,8 @@ public function testWithHostSameAsContextAndAbsolute() */ public function testUrlWithInvalidParameterInHost() { - $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com')); - $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH); + $routes = $this->getRoutes('test', new Route('/', [], ['foo' => 'bar'], [], '{foo}.example.com')); + $this->getGenerator($routes)->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH); } /** @@ -471,8 +471,8 @@ public function testUrlWithInvalidParameterInHost() */ public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue() { - $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com')); - $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH); + $routes = $this->getRoutes('test', new Route('/', ['foo' => 'bar'], ['foo' => 'bar'], [], '{foo}.example.com')); + $this->getGenerator($routes)->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH); } /** @@ -480,72 +480,72 @@ public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue() */ public function testUrlWithInvalidParameterEqualsDefaultValueInHost() { - $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com')); - $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH); + $routes = $this->getRoutes('test', new Route('/', ['foo' => 'baz'], ['foo' => 'bar'], [], '{foo}.example.com')); + $this->getGenerator($routes)->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH); } public function testUrlWithInvalidParameterInHostInNonStrictMode() { - $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com')); + $routes = $this->getRoutes('test', new Route('/', [], ['foo' => 'bar'], [], '{foo}.example.com')); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(false); - $this->assertNull($generator->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH)); + $this->assertNull($generator->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH)); } public function testHostIsCaseInsensitive() { - $routes = $this->getRoutes('test', new Route('/', array(), array('locale' => 'en|de|fr'), array(), '{locale}.FooBar.com')); + $routes = $this->getRoutes('test', new Route('/', [], ['locale' => 'en|de|fr'], [], '{locale}.FooBar.com')); $generator = $this->getGenerator($routes); - $this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', array('locale' => 'EN'), UrlGeneratorInterface::NETWORK_PATH)); + $this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', ['locale' => 'EN'], UrlGeneratorInterface::NETWORK_PATH)); } public function testDefaultHostIsUsedWhenContextHostIsEmpty() { - $routes = $this->getRoutes('test', new Route('/route', array('domain' => 'my.fallback.host'), array('domain' => '.+'), array(), '{domain}', array('http'))); + $routes = $this->getRoutes('test', new Route('/route', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}', ['http'])); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); - $this->assertSame('http://my.fallback.host/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertSame('http://my.fallback.host/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testDefaultHostIsUsedWhenContextHostIsEmptyAndSchemeIsNot() { - $routes = $this->getRoutes('test', new Route('/route', array('domain' => 'my.fallback.host'), array('domain' => '.+'), array(), '{domain}', array('http', 'https'))); + $routes = $this->getRoutes('test', new Route('/route', ['domain' => 'my.fallback.host'], ['domain' => '.+'], [], '{domain}', ['http', 'https'])); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); $generator->getContext()->setScheme('https'); - $this->assertSame('https://my.fallback.host/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertSame('https://my.fallback.host/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testAbsoluteUrlFallbackToRelativeIfHostIsEmptyAndSchemeIsNot() { - $routes = $this->getRoutes('test', new Route('/route', array(), array(), array(), '', array('http', 'https'))); + $routes = $this->getRoutes('test', new Route('/route', [], [], [], '', ['http', 'https'])); $generator = $this->getGenerator($routes); $generator->getContext()->setHost(''); $generator->getContext()->setScheme('https'); - $this->assertSame('/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertSame('/app.php/route', $generator->generate('test', [], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateNetworkPath() { - $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com', array('http'))); + $routes = $this->getRoutes('test', new Route('/{name}', [], [], [], '{locale}.example.com', ['http'])); $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', - array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host' + ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::NETWORK_PATH), 'network path with different host' ); - $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', - array('name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context' + $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, ['host' => 'fr.example.com'])->generate('test', + ['name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'], UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context' ); - $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', - array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context' + $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, ['scheme' => 'https'])->generate('test', + ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context' ); $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', - array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested' + ['name' => 'Fabien', 'locale' => 'fr'], UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested' ); } @@ -554,32 +554,32 @@ public function testGenerateRelativePath() $routes = new RouteCollection(); $routes->add('article', new Route('/{author}/{article}/')); $routes->add('comments', new Route('/{author}/{article}/comments')); - $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com')); - $routes->add('scheme', new Route('/{author}/blog', array(), array(), array(), '', array('https'))); + $routes->add('host', new Route('/{article}', [], [], [], '{author}.example.com')); + $routes->add('scheme', new Route('/{author}/blog', [], [], [], '', ['https'])); $routes->add('unrelated', new Route('/about')); - $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/')); + $generator = $this->getGenerator($routes, ['host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/']); $this->assertSame('comments', $generator->generate('comments', - array('author' => 'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH) + ['author' => 'fabien', 'article' => 'symfony-is-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('comments?page=2', $generator->generate('comments', - array('author' => 'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH) + ['author' => 'fabien', 'article' => 'symfony-is-great', 'page' => 2], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('../twig-is-great/', $generator->generate('article', - array('author' => 'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH) + ['author' => 'fabien', 'article' => 'twig-is-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article', - array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH) + ['author' => 'bernhard', 'article' => 'forms-are-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host', - array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH) + ['author' => 'bernhard', 'article' => 'forms-are-great'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('https://example.com/app.php/bernhard/blog', $generator->generate('scheme', - array('author' => 'bernhard'), UrlGeneratorInterface::RELATIVE_PATH) + ['author' => 'bernhard'], UrlGeneratorInterface::RELATIVE_PATH) ); $this->assertSame('../../about', $generator->generate('unrelated', - array(), UrlGeneratorInterface::RELATIVE_PATH) + [], UrlGeneratorInterface::RELATIVE_PATH) ); } @@ -593,138 +593,138 @@ public function testGetRelativePath($sourcePath, $targetPath, $expectedPath) public function provideRelativePaths() { - return array( - array( + return [ + [ '/same/dir/', '/same/dir/', '', - ), - array( + ], + [ '/same/file', '/same/file', '', - ), - array( + ], + [ '/', '/file', 'file', - ), - array( + ], + [ '/', '/dir/file', 'dir/file', - ), - array( + ], + [ '/dir/file.html', '/dir/different-file.html', 'different-file.html', - ), - array( + ], + [ '/same/dir/extra-file', '/same/dir/', './', - ), - array( + ], + [ '/parent/dir/', '/parent/', '../', - ), - array( + ], + [ '/parent/dir/extra-file', '/parent/', '../', - ), - array( + ], + [ '/a/b/', '/x/y/z/', '../../x/y/z/', - ), - array( + ], + [ '/a/b/c/d/e', '/a/c/d', '../../../c/d', - ), - array( + ], + [ '/a/b/c//', '/a/b/c/', '../', - ), - array( + ], + [ '/a/b/c/', '/a/b/c//', './/', - ), - array( + ], + [ '/root/a/b/c/', '/root/x/b/c/', '../../../x/b/c/', - ), - array( + ], + [ '/a/b/c/d/', '/a', '../../../../a', - ), - array( + ], + [ '/special-chars/sp%20ce/1€/mäh/e=mc²', '/special-chars/sp%20ce/1€/<µ>/e=mc²', '../<µ>/e=mc²', - ), - array( + ], + [ 'not-rooted', 'dir/file', 'dir/file', - ), - array( + ], + [ '//dir/', '', '../../', - ), - array( + ], + [ '/dir/', '/dir/file:with-colon', './file:with-colon', - ), - array( + ], + [ '/dir/', '/dir/subdir/file:with-colon', 'subdir/file:with-colon', - ), - array( + ], + [ '/dir/', '/dir/:subdir/', './:subdir/', - ), - ); + ], + ]; } public function testFragmentsCanBeAppendedToUrls() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array('_fragment' => 'frag ment'), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', ['_fragment' => 'frag ment'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#frag%20ment', $url); - $url = $this->getGenerator($routes)->generate('test', array('_fragment' => '0'), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', ['_fragment' => '0'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#0', $url); } public function testFragmentsDoNotEscapeValidCharacters() { $routes = $this->getRoutes('test', new Route('/testing')); - $url = $this->getGenerator($routes)->generate('test', array('_fragment' => '?/'), UrlGeneratorInterface::ABSOLUTE_PATH); + $url = $this->getGenerator($routes)->generate('test', ['_fragment' => '?/'], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#?/', $url); } public function testFragmentsCanBeDefinedAsDefaults() { - $routes = $this->getRoutes('test', new Route('/testing', array('_fragment' => 'fragment'))); - $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH); + $routes = $this->getRoutes('test', new Route('/testing', ['_fragment' => 'fragment'])); + $url = $this->getGenerator($routes)->generate('test', [], UrlGeneratorInterface::ABSOLUTE_PATH); $this->assertEquals('/app.php/testing#fragment', $url); } - protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null) + protected function getGenerator(RouteCollection $routes, array $parameters = [], $logger = null) { $context = new RequestContext('/app.php'); foreach ($parameters as $key => $value) { diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index dbb9b85b83907..6eaacc78a5d1f 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -33,7 +33,7 @@ public function testNoMethodSoAllowed() public function testMethodNotAllowed() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/foo', array(), array(), array(), '', array(), array('post'))); + $coll->add('foo', new Route('/foo', [], [], [], '', [], ['post'])); $matcher = $this->getUrlMatcher($coll); @@ -41,14 +41,14 @@ public function testMethodNotAllowed() $matcher->match('/foo'); $this->fail(); } catch (MethodNotAllowedException $e) { - $this->assertEquals(array('POST'), $e->getAllowedMethods()); + $this->assertEquals(['POST'], $e->getAllowedMethods()); } } public function testMethodNotAllowedOnRoot() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/', array(), array(), array(), '', array(), array('GET'))); + $coll->add('foo', new Route('/', [], [], [], '', [], ['GET'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'POST')); @@ -56,14 +56,14 @@ public function testMethodNotAllowedOnRoot() $matcher->match('/'); $this->fail(); } catch (MethodNotAllowedException $e) { - $this->assertEquals(array('GET'), $e->getAllowedMethods()); + $this->assertEquals(['GET'], $e->getAllowedMethods()); } } public function testHeadAllowedWhenRequirementContainsGet() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/foo', array(), array(), array(), '', array(), array('get'))); + $coll->add('foo', new Route('/foo', [], [], [], '', [], ['get'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'head')); $this->assertInternalType('array', $matcher->match('/foo')); @@ -72,8 +72,8 @@ public function testHeadAllowedWhenRequirementContainsGet() public function testMethodNotAllowedAggregatesAllowedMethods() { $coll = new RouteCollection(); - $coll->add('foo1', new Route('/foo', array(), array(), array(), '', array(), array('post'))); - $coll->add('foo2', new Route('/foo', array(), array(), array(), '', array(), array('put', 'delete'))); + $coll->add('foo1', new Route('/foo', [], [], [], '', [], ['post'])); + $coll->add('foo2', new Route('/foo', [], [], [], '', [], ['put', 'delete'])); $matcher = $this->getUrlMatcher($coll); @@ -81,7 +81,7 @@ public function testMethodNotAllowedAggregatesAllowedMethods() $matcher->match('/foo'); $this->fail(); } catch (MethodNotAllowedException $e) { - $this->assertEquals(array('POST', 'PUT', 'DELETE'), $e->getAllowedMethods()); + $this->assertEquals(['POST', 'PUT', 'DELETE'], $e->getAllowedMethods()); } } @@ -96,17 +96,17 @@ public function testMatch() $this->fail(); } catch (ResourceNotFoundException $e) { } - $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz'), $matcher->match('/foo/baz')); + $this->assertEquals(['_route' => 'foo', 'bar' => 'baz'], $matcher->match('/foo/baz')); // test that defaults are merged $collection = new RouteCollection(); - $collection->add('foo', new Route('/foo/{bar}', array('def' => 'test'))); + $collection->add('foo', new Route('/foo/{bar}', ['def' => 'test'])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'def' => 'test'), $matcher->match('/foo/baz')); + $this->assertEquals(['_route' => 'foo', 'bar' => 'baz', 'def' => 'test'], $matcher->match('/foo/baz')); // test that route "method" is ignored if no method is given in the context $collection = new RouteCollection(); - $collection->add('foo', new Route('/foo', array(), array(), array(), '', array(), array('get', 'head'))); + $collection->add('foo', new Route('/foo', [], [], [], '', [], ['get', 'head'])); $matcher = $this->getUrlMatcher($collection); $this->assertInternalType('array', $matcher->match('/foo')); @@ -126,24 +126,24 @@ public function testMatch() // route with an optional variable as the first segment $collection = new RouteCollection(); - $collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar'))); + $collection->add('bar', new Route('/{bar}/foo', ['bar' => 'bar'], ['bar' => 'foo|bar'])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo')); - $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo')); + $this->assertEquals(['_route' => 'bar', 'bar' => 'bar'], $matcher->match('/bar/foo')); + $this->assertEquals(['_route' => 'bar', 'bar' => 'foo'], $matcher->match('/foo/foo')); $collection = new RouteCollection(); - $collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar'))); + $collection->add('bar', new Route('/{bar}', ['bar' => 'bar'], ['bar' => 'foo|bar'])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo')); - $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/')); + $this->assertEquals(['_route' => 'bar', 'bar' => 'foo'], $matcher->match('/foo')); + $this->assertEquals(['_route' => 'bar', 'bar' => 'bar'], $matcher->match('/')); // route with only optional variables $collection = new RouteCollection(); - $collection->add('bar', new Route('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar'), array())); + $collection->add('bar', new Route('/{foo}/{bar}', ['foo' => 'foo', 'bar' => 'bar'], [])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'), $matcher->match('/')); - $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'), $matcher->match('/a')); - $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'b'), $matcher->match('/a/b')); + $this->assertEquals(['_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'], $matcher->match('/')); + $this->assertEquals(['_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'], $matcher->match('/a')); + $this->assertEquals(['_route' => 'bar', 'foo' => 'a', 'bar' => 'b'], $matcher->match('/a/b')); } public function testMatchWithPrefixes() @@ -154,7 +154,7 @@ public function testMatchWithPrefixes() $collection->addPrefix('/a'); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'foo', 'foo' => 'foo'), $matcher->match('/a/b/foo')); + $this->assertEquals(['_route' => 'foo', 'foo' => 'foo'], $matcher->match('/a/b/foo')); } public function testMatchWithDynamicPrefix() @@ -165,7 +165,7 @@ public function testMatchWithDynamicPrefix() $collection->addPrefix('/{_locale}'); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'), $matcher->match('/fr/b/foo')); + $this->assertEquals(['_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'], $matcher->match('/fr/b/foo')); } public function testMatchSpecialRouteName() @@ -174,16 +174,16 @@ public function testMatchSpecialRouteName() $collection->add('$péß^a|', new Route('/bar')); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar')); + $this->assertEquals(['_route' => '$péß^a|'], $matcher->match('/bar')); } public function testMatchImportantVariable() { $collection = new RouteCollection(); - $collection->add('index', new Route('/index.{!_format}', array('_format' => 'xml'))); + $collection->add('index', new Route('/index.{!_format}', ['_format' => 'xml'])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'index', '_format' => 'xml'), $matcher->match('/index.xml')); + $this->assertEquals(['_route' => 'index', '_format' => 'xml'], $matcher->match('/index.xml')); } /** @@ -202,20 +202,20 @@ public function testMatchNonAlpha() { $collection = new RouteCollection(); $chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-'; - $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+'), array('utf8' => true))); + $collection->add('foo', new Route('/{foo}/bar', [], ['foo' => '['.preg_quote($chars).']+'], ['utf8' => true])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.rawurlencode($chars).'/bar')); - $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.strtr($chars, array('%' => '%25')).'/bar')); + $this->assertEquals(['_route' => 'foo', 'foo' => $chars], $matcher->match('/'.rawurlencode($chars).'/bar')); + $this->assertEquals(['_route' => 'foo', 'foo' => $chars], $matcher->match('/'.strtr($chars, ['%' => '%25']).'/bar')); } public function testMatchWithDotMetacharacterInRequirements() { $collection = new RouteCollection(); - $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '.+'))); + $collection->add('foo', new Route('/{foo}/bar', [], ['foo' => '.+'])); $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'foo', 'foo' => "\n"), $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched'); + $this->assertEquals(['_route' => 'foo', 'foo' => "\n"], $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched'); } public function testMatchOverriddenRoute() @@ -230,9 +230,9 @@ public function testMatchOverriddenRoute() $matcher = $this->getUrlMatcher($collection); - $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1')); + $this->assertEquals(['_route' => 'foo'], $matcher->match('/foo1')); $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); - $this->assertEquals(array(), $matcher->match('/foo')); + $this->assertEquals([], $matcher->match('/foo')); } public function testMatchRegression() @@ -242,7 +242,7 @@ public function testMatchRegression() $coll->add('bar', new Route('/foo/bar/{foo}')); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar')); + $this->assertEquals(['foo' => 'bar', '_route' => 'bar'], $matcher->match('/foo/bar/bar')); $collection = new RouteCollection(); $collection->add('foo', new Route('/{bar}')); @@ -269,36 +269,36 @@ public function testMultipleParams() public function testDefaultRequirementForOptionalVariables() { $coll = new RouteCollection(); - $coll->add('test', new Route('/{page}.{_format}', array('page' => 'index', '_format' => 'html'))); + $coll->add('test', new Route('/{page}.{_format}', ['page' => 'index', '_format' => 'html'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('page' => 'my-page', '_format' => 'xml', '_route' => 'test'), $matcher->match('/my-page.xml')); + $this->assertEquals(['page' => 'my-page', '_format' => 'xml', '_route' => 'test'], $matcher->match('/my-page.xml')); } public function testMatchingIsEager() { $coll = new RouteCollection(); - $coll->add('test', new Route('/{foo}-{bar}-', array(), array('foo' => '.+', 'bar' => '.+'))); + $coll->add('test', new Route('/{foo}-{bar}-', [], ['foo' => '.+', 'bar' => '.+'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'), $matcher->match('/text1-text2-text3-text4-')); + $this->assertEquals(['foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'], $matcher->match('/text1-text2-text3-text4-')); } public function testAdjacentVariables() { $coll = new RouteCollection(); - $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => 'y|Y'))); + $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', ['z' => 'default-z', '_format' => 'html'], ['y' => 'y|Y'])); $matcher = $this->getUrlMatcher($coll); // 'w' eagerly matches as much as possible and the other variables match the remaining chars. // This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement. // Otherwise they would also consume '.xml' and _format would never match as it's an optional variable. - $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z', '_format' => 'xml', '_route' => 'test'), $matcher->match('/wwwwwxYZ.xml')); + $this->assertEquals(['w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z', '_format' => 'xml', '_route' => 'test'], $matcher->match('/wwwwwxYZ.xml')); // As 'y' has custom requirement and can only be of value 'y|Y', it will leave 'ZZZ' to variable z. // So with carefully chosen requirements adjacent variables, can be useful. - $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ', '_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxyZZZ')); + $this->assertEquals(['w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ', '_format' => 'html', '_route' => 'test'], $matcher->match('/wwwwwxyZZZ')); // z and _format are optional. - $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z', '_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxy')); + $this->assertEquals(['w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z', '_format' => 'html', '_route' => 'test'], $matcher->match('/wwwwwxy')); $this->expectException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); $matcher->match('/wxy.html'); @@ -307,11 +307,11 @@ public function testAdjacentVariables() public function testOptionalVariableWithNoRealSeparator() { $coll = new RouteCollection(); - $coll->add('test', new Route('/get{what}', array('what' => 'All'))); + $coll->add('test', new Route('/get{what}', ['what' => 'All'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('what' => 'All', '_route' => 'test'), $matcher->match('/get')); - $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSites')); + $this->assertEquals(['what' => 'All', '_route' => 'test'], $matcher->match('/get')); + $this->assertEquals(['what' => 'Sites', '_route' => 'test'], $matcher->match('/getSites')); // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match. // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it. @@ -325,7 +325,7 @@ public function testRequiredVariableWithNoRealSeparator() $coll->add('test', new Route('/get{what}Suffix')); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSitesSuffix')); + $this->assertEquals(['what' => 'Sites', '_route' => 'test'], $matcher->match('/getSitesSuffix')); } public function testDefaultRequirementOfVariable() @@ -334,7 +334,7 @@ public function testDefaultRequirementOfVariable() $coll->add('test', new Route('/{page}.{_format}')); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('page' => 'index', '_format' => 'mobile.html', '_route' => 'test'), $matcher->match('/index.mobile.html')); + $this->assertEquals(['page' => 'index', '_format' => 'mobile.html', '_route' => 'test'], $matcher->match('/index.mobile.html')); } /** @@ -355,7 +355,7 @@ public function testDefaultRequirementOfVariableDisallowsSlash() public function testDefaultRequirementOfVariableDisallowsNextSeparator() { $coll = new RouteCollection(); - $coll->add('test', new Route('/{page}.{_format}', array(), array('_format' => 'html|xml'))); + $coll->add('test', new Route('/{page}.{_format}', [], ['_format' => 'html|xml'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/do.t.html'); @@ -419,7 +419,7 @@ public function testExtraTrailingSlashForNonSafeMethod() public function testSchemeRequirement() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/foo', array(), array(), array(), '', array('https'))); + $coll->add('foo', new Route('/foo', [], [], [], '', ['https'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/foo'); } @@ -430,7 +430,7 @@ public function testSchemeRequirement() public function testSchemeRequirementForNonSafeMethod() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/foo', array(), array(), array(), '', array('https'))); + $coll->add('foo', new Route('/foo', [], [], [], '', ['https'])); $context = new RequestContext(); $context->setMethod('POST'); @@ -441,10 +441,10 @@ public function testSchemeRequirementForNonSafeMethod() public function testSamePathWithDifferentScheme() { $coll = new RouteCollection(); - $coll->add('https_route', new Route('/', array(), array(), array(), '', array('https'))); - $coll->add('http_route', new Route('/', array(), array(), array(), '', array('http'))); + $coll->add('https_route', new Route('/', [], [], [], '', ['https'])); + $coll->add('http_route', new Route('/', [], [], [], '', ['http'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'http_route'), $matcher->match('/')); + $this->assertEquals(['_route' => 'http_route'], $matcher->match('/')); } /** @@ -470,7 +470,7 @@ public function testRequestCondition() $route->setCondition('request.getBaseUrl() == "/sub/front.php" and request.getPathInfo() == "/foo/bar"'); $coll->add('foo', $route); $matcher = $this->getUrlMatcher($coll, new RequestContext('/sub/front.php')); - $this->assertEquals(array('bar' => 'bar', '_route' => 'foo'), $matcher->match('/foo/bar')); + $this->assertEquals(['bar' => 'bar', '_route' => 'foo'], $matcher->match('/foo/bar')); } public function testDecodeOnce() @@ -479,7 +479,7 @@ public function testDecodeOnce() $coll->add('foo', new Route('/foo/{foo}')); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('foo' => 'bar%23', '_route' => 'foo'), $matcher->match('/foo/bar%2523')); + $this->assertEquals(['foo' => 'bar%23', '_route' => 'foo'], $matcher->match('/foo/bar%2523')); } public function testCannotRelyOnPrefix() @@ -495,30 +495,30 @@ public function testCannotRelyOnPrefix() $coll->addCollection($subColl); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'bar'), $matcher->match('/new')); + $this->assertEquals(['_route' => 'bar'], $matcher->match('/new')); } public function testWithHost() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com')); + $coll->add('foo', new Route('/foo/{foo}', [], [], [], '{locale}.example.com')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); - $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar')); + $this->assertEquals(['foo' => 'bar', '_route' => 'foo', 'locale' => 'en'], $matcher->match('/foo/bar')); } public function testWithHostOnRouteCollection() { $coll = new RouteCollection(); $coll->add('foo', new Route('/foo/{foo}')); - $coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net')); + $coll->add('bar', new Route('/bar/{foo}', [], [], [], '{locale}.example.net')); $coll->setHost('{locale}.example.com'); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); - $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar')); + $this->assertEquals(['foo' => 'bar', '_route' => 'foo', 'locale' => 'en'], $matcher->match('/foo/bar')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); - $this->assertEquals(array('foo' => 'bar', '_route' => 'bar', 'locale' => 'en'), $matcher->match('/bar/bar')); + $this->assertEquals(['foo' => 'bar', '_route' => 'bar', 'locale' => 'en'], $matcher->match('/bar/bar')); } /** @@ -527,7 +527,7 @@ public function testWithHostOnRouteCollection() public function testWithOutHostHostDoesNotMatch() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com')); + $coll->add('foo', new Route('/foo/{foo}', [], [], [], '{locale}.example.com')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'example.com')); $matcher->match('/foo/bar'); @@ -539,7 +539,7 @@ public function testWithOutHostHostDoesNotMatch() public function testPathIsCaseSensitive() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/locale', array(), array('locale' => 'EN|FR|DE'))); + $coll->add('foo', new Route('/locale', [], ['locale' => 'EN|FR|DE'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/en'); @@ -548,10 +548,10 @@ public function testPathIsCaseSensitive() public function testHostIsCaseInsensitive() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/', array(), array('locale' => 'EN|FR|DE'), array(), '{locale}.example.com')); + $coll->add('foo', new Route('/', [], ['locale' => 'EN|FR|DE'], [], '{locale}.example.com')); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); - $this->assertEquals(array('_route' => 'foo', 'locale' => 'en'), $matcher->match('/')); + $this->assertEquals(['_route' => 'foo', 'locale' => 'en'], $matcher->match('/')); } /** @@ -584,9 +584,9 @@ public function testNestedCollections() $coll->addCollection($subColl); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'a'), $matcher->match('/p/a')); - $this->assertEquals(array('_route' => 'baz', 'baz' => 'p'), $matcher->match('/p')); - $this->assertEquals(array('_route' => 'buz'), $matcher->match('/prefix/buz')); + $this->assertEquals(['_route' => 'a'], $matcher->match('/p/a')); + $this->assertEquals(['_route' => 'baz', 'baz' => 'p'], $matcher->match('/p')); + $this->assertEquals(['_route' => 'buz'], $matcher->match('/prefix/buz')); } /** @@ -595,7 +595,7 @@ public function testNestedCollections() public function testSchemeAndMethodMismatch() { $coll = new RouteCollection(); - $coll->add('foo', new Route('/', array(), array(), array(), null, array('https'), array('POST'))); + $coll->add('foo', new Route('/', [], [], [], null, ['https'], ['POST'])); $matcher = $this->getUrlMatcher($coll); $matcher->match('/'); @@ -609,54 +609,54 @@ public function testSiblingRoutes() $coll->add('c', new Route('/a{a}')); $coll->add('d', (new Route('/b{a}'))->setCondition('false')); $coll->add('e', (new Route('/{b}{a}'))->setCondition('false')); - $coll->add('f', (new Route('/{b}{a}'))->setRequirements(array('b' => 'b'))); + $coll->add('f', (new Route('/{b}{a}'))->setRequirements(['b' => 'b'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'c', 'a' => 'a'), $matcher->match('/aa')); - $this->assertEquals(array('_route' => 'f', 'b' => 'b', 'a' => 'a'), $matcher->match('/ba')); + $this->assertEquals(['_route' => 'c', 'a' => 'a'], $matcher->match('/aa')); + $this->assertEquals(['_route' => 'f', 'b' => 'b', 'a' => 'a'], $matcher->match('/ba')); } public function testUnicodeRoute() { $coll = new RouteCollection(); - $coll->add('a', new Route('/{a}', array(), array('a' => '.'), array('utf8' => false))); - $coll->add('b', new Route('/{a}', array(), array('a' => '.'), array('utf8' => true))); + $coll->add('a', new Route('/{a}', [], ['a' => '.'], ['utf8' => false])); + $coll->add('b', new Route('/{a}', [], ['a' => '.'], ['utf8' => true])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'b', 'a' => 'é'), $matcher->match('/é')); + $this->assertEquals(['_route' => 'b', 'a' => 'é'], $matcher->match('/é')); } public function testRequirementWithCapturingGroup() { $coll = new RouteCollection(); - $coll->add('a', new Route('/{a}/{b}', array(), array('a' => '(a|b)'))); + $coll->add('a', new Route('/{a}/{b}', [], ['a' => '(a|b)'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'a', 'a' => 'a', 'b' => 'b'), $matcher->match('/a/b')); + $this->assertEquals(['_route' => 'a', 'a' => 'a', 'b' => 'b'], $matcher->match('/a/b')); } public function testDotAllWithCatchAll() { $coll = new RouteCollection(); - $coll->add('a', new Route('/{id}.html', array(), array('id' => '.+'))); - $coll->add('b', new Route('/{all}', array(), array('all' => '.+'))); + $coll->add('a', new Route('/{id}.html', [], ['id' => '.+'])); + $coll->add('b', new Route('/{all}', [], ['all' => '.+'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'a', 'id' => 'foo/bar'), $matcher->match('/foo/bar.html')); + $this->assertEquals(['_route' => 'a', 'id' => 'foo/bar'], $matcher->match('/foo/bar.html')); } public function testHostPattern() { $coll = new RouteCollection(); - $coll->add('a', new Route('/{app}/{action}/{unused}', array(), array(), array(), '{host}')); + $coll->add('a', new Route('/{app}/{action}/{unused}', [], [], [], '{host}')); - $expected = array( + $expected = [ '_route' => 'a', 'app' => 'an_app', 'action' => 'an_action', 'unused' => 'unused', 'host' => 'foo', - ); + ]; $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'GET', 'foo')); $this->assertEquals($expected, $matcher->match('/an_app/an_action/unused')); } @@ -664,8 +664,8 @@ public function testHostPattern() public function testUtf8Prefix() { $coll = new RouteCollection(); - $coll->add('a', new Route('/é{foo}', array(), array(), array('utf8' => true))); - $coll->add('b', new Route('/è{bar}', array(), array(), array('utf8' => true))); + $coll->add('a', new Route('/é{foo}', [], [], ['utf8' => true])); + $coll->add('b', new Route('/è{bar}', [], [], ['utf8' => true])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals('a', $matcher->match('/éo')['_route']); @@ -674,9 +674,9 @@ public function testUtf8Prefix() public function testUtf8AndMethodMatching() { $coll = new RouteCollection(); - $coll->add('a', new Route('/admin/api/list/{shortClassName}/{id}.{_format}', array(), array(), array('utf8' => true), '', array(), array('PUT'))); - $coll->add('b', new Route('/admin/api/package.{_format}', array(), array(), array(), '', array(), array('POST'))); - $coll->add('c', new Route('/admin/api/package.{_format}', array('_format' => 'json'), array(), array(), '', array(), array('GET'))); + $coll->add('a', new Route('/admin/api/list/{shortClassName}/{id}.{_format}', [], [], ['utf8' => true], '', [], ['PUT'])); + $coll->add('b', new Route('/admin/api/package.{_format}', [], [], [], '', [], ['POST'])); + $coll->add('c', new Route('/admin/api/package.{_format}', ['_format' => 'json'], [], [], '', [], ['GET'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals('c', $matcher->match('/admin/api/package.json')['_route']); @@ -685,7 +685,7 @@ public function testUtf8AndMethodMatching() public function testHostWithDot() { $coll = new RouteCollection(); - $coll->add('a', new Route('/foo', array(), array(), array(), 'foo.example.com')); + $coll->add('a', new Route('/foo', [], [], [], 'foo.example.com')); $coll->add('b', new Route('/bar/{baz}')); $matcher = $this->getUrlMatcher($coll); @@ -695,7 +695,7 @@ public function testHostWithDot() public function testSlashVariant() { $coll = new RouteCollection(); - $coll->add('a', new Route('/foo/{bar}', array(), array('bar' => '.*'))); + $coll->add('a', new Route('/foo/{bar}', [], ['bar' => '.*'])); $matcher = $this->getUrlMatcher($coll); $this->assertEquals('a', $matcher->match('/foo/')['_route']); @@ -704,54 +704,54 @@ public function testSlashVariant() public function testSlashVariant2() { $coll = new RouteCollection(); - $coll->add('a', new Route('/foo/{bar}/', array(), array('bar' => '.*'))); + $coll->add('a', new Route('/foo/{bar}/', [], ['bar' => '.*'])); $matcher = $this->getUrlMatcher($coll); - $this->assertEquals(array('_route' => 'a', 'bar' => 'bar'), $matcher->match('/foo/bar/')); + $this->assertEquals(['_route' => 'a', 'bar' => 'bar'], $matcher->match('/foo/bar/')); } public function testSlashWithVerb() { $coll = new RouteCollection(); - $coll->add('a', new Route('/{foo}', array(), array(), array(), '', array(), array('put', 'delete'))); + $coll->add('a', new Route('/{foo}', [], [], [], '', [], ['put', 'delete'])); $coll->add('b', new Route('/bar/')); $matcher = $this->getUrlMatcher($coll); - $this->assertSame(array('_route' => 'b'), $matcher->match('/bar/')); + $this->assertSame(['_route' => 'b'], $matcher->match('/bar/')); $coll = new RouteCollection(); - $coll->add('a', new Route('/dav/{foo<.*>?}', array(), array(), array(), '', array(), array('GET', 'OPTIONS'))); + $coll->add('a', new Route('/dav/{foo<.*>?}', [], [], [], '', [], ['GET', 'OPTIONS'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'OPTIONS')); - $expected = array( + $expected = [ '_route' => 'a', 'foo' => 'files/bar', - ); + ]; $this->assertEquals($expected, $matcher->match('/dav/files/bar/')); } public function testSlashAndVerbPrecedence() { $coll = new RouteCollection(); - $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', array(), array(), array(), '', array(), array('post'))); - $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', array(), array(), array(), '', array(), array('get'))); + $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', [], [], [], '', [], ['post'])); + $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', [], [], [], '', [], ['get'])); $matcher = $this->getUrlMatcher($coll); - $expected = array( + $expected = [ '_route' => 'b', 'customerId' => '123', - ); + ]; $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); $coll = new RouteCollection(); - $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', array(), array(), array(), '', array(), array('get'))); - $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', array(), array(), array(), '', array(), array('post'))); + $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', [], [], [], '', [], ['get'])); + $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', [], [], [], '', [], ['post'])); $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'POST')); - $expected = array( + $expected = [ '_route' => 'b', 'customerId' => '123', - ); + ]; $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); } diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php index d751e21046871..123ecf7dd14ad 100644 --- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php @@ -31,32 +31,32 @@ class CsvEncoder implements EncoderInterface, DecoderInterface const AS_COLLECTION_KEY = 'as_collection'; const NO_HEADERS_KEY = 'no_headers'; - private $formulasStartCharacters = array('=', '-', '+', '@'); - private $defaultContext = array( + private $formulasStartCharacters = ['=', '-', '+', '@']; + private $defaultContext = [ self::DELIMITER_KEY => ',', self::ENCLOSURE_KEY => '"', self::ESCAPE_CHAR_KEY => '\\', self::ESCAPE_FORMULAS_KEY => false, - self::HEADERS_KEY => array(), + self::HEADERS_KEY => [], self::KEY_SEPARATOR_KEY => '.', self::NO_HEADERS_KEY => false, - ); + ]; /** * @param array $defaultContext */ - public function __construct($defaultContext = array(), string $enclosure = '"', string $escapeChar = '\\', string $keySeparator = '.', bool $escapeFormulas = false) + public function __construct($defaultContext = [], string $enclosure = '"', string $escapeChar = '\\', string $keySeparator = '.', bool $escapeFormulas = false) { if (!\is_array($defaultContext)) { @trigger_error('Passing configuration options directly to the constructor is deprecated since Symfony 4.2, use the default context instead.', E_USER_DEPRECATED); - $defaultContext = array( + $defaultContext = [ self::DELIMITER_KEY => (string) $defaultContext, self::ENCLOSURE_KEY => $enclosure, self::ESCAPE_CHAR_KEY => $escapeChar, self::KEY_SEPARATOR_KEY => $keySeparator, self::ESCAPE_FORMULAS_KEY => $escapeFormulas, - ); + ]; } $this->defaultContext = array_merge($this->defaultContext, $defaultContext); @@ -65,20 +65,20 @@ public function __construct($defaultContext = array(), string $enclosure = '"', /** * {@inheritdoc} */ - public function encode($data, $format, array $context = array()) + public function encode($data, $format, array $context = []) { $handle = fopen('php://temp,', 'w+'); if (!\is_array($data)) { - $data = array(array($data)); + $data = [[$data]]; } elseif (empty($data)) { - $data = array(array()); + $data = [[]]; } else { // Sequential arrays of arrays are considered as collections $i = 0; foreach ($data as $key => $value) { if ($i !== $key || !\is_array($value)) { - $data = array($data); + $data = [$data]; break; } @@ -89,7 +89,7 @@ public function encode($data, $format, array $context = array()) list($delimiter, $enclosure, $escapeChar, $keySeparator, $headers, $escapeFormulas) = $this->getCsvOptions($context); foreach ($data as &$value) { - $flattened = array(); + $flattened = []; $this->flatten($value, $flattened, $keySeparator, '', $escapeFormulas); $value = $flattened; } @@ -124,7 +124,7 @@ public function supportsEncoding($format) /** * {@inheritdoc} */ - public function decode($data, $format, array $context = array()) + public function decode($data, $format, array $context = []) { $handle = fopen('php://temp', 'r+'); fwrite($handle, $data); @@ -132,8 +132,8 @@ public function decode($data, $format, array $context = array()) $headers = null; $nbHeaders = 0; - $headerCount = array(); - $result = array(); + $headerCount = []; + $result = []; list($delimiter, $enclosure, $escapeChar, $keySeparator) = $this->getCsvOptions($context); @@ -145,7 +145,7 @@ public function decode($data, $format, array $context = array()) if ($context[self::NO_HEADERS_KEY] ?? false) { for ($i = 0; $i < $nbCols; ++$i) { - $headers[] = array($i); + $headers[] = [$i]; } $headerCount = array_fill(0, $nbCols, 1); } else { @@ -159,7 +159,7 @@ public function decode($data, $format, array $context = array()) } } - $item = array(); + $item = []; for ($i = 0; ($i < $nbCols) && ($i < $nbHeaders); ++$i) { $depth = $headerCount[$i]; $arr = &$item; @@ -172,7 +172,7 @@ public function decode($data, $format, array $context = array()) } if (!isset($arr[$headers[$i][$j]])) { - $arr[$headers[$i][$j]] = array(); + $arr[$headers[$i][$j]] = []; } $arr = &$arr[$headers[$i][$j]]; @@ -238,7 +238,7 @@ private function getCsvOptions(array $context): array throw new InvalidArgumentException(sprintf('The "%s" context variable must be an array or null, given "%s".', self::HEADERS_KEY, \gettype($headers))); } - return array($delimiter, $enclosure, $escapeChar, $keySeparator, $headers, $escapeFormulas); + return [$delimiter, $enclosure, $escapeChar, $keySeparator, $headers, $escapeFormulas]; } /** @@ -246,8 +246,8 @@ private function getCsvOptions(array $context): array */ private function extractHeaders(array $data) { - $headers = array(); - $flippedHeaders = array(); + $headers = []; + $flippedHeaders = []; foreach ($data as $row) { $previousHeader = null; diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index 04d98c5833e12..74235c46c1d16 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -316,9 +316,9 @@ public function testEncodeWithoutHeader() c,d CSV - , $this->encoder->encode(array(array('a', 'b'), array('c', 'd')), 'csv', array( + , $this->encoder->encode([['a', 'b'], ['c', 'd']], 'csv', [ CsvEncoder::NO_HEADERS_KEY => true, - ))); + ])); } public function testSupportsDecoding() @@ -495,13 +495,13 @@ public function testDecodeEmptyArray() public function testDecodeWithoutHeader() { - $this->assertEquals(array(array('a', 'b'), array('c', 'd')), $this->encoder->decode(<<<'CSV' + $this->assertEquals([['a', 'b'], ['c', 'd']], $this->encoder->decode(<<<'CSV' a,b c,d CSV - , 'csv', array( + , 'csv', [ CsvEncoder::NO_HEADERS_KEY => true, - ))); + ])); } } diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index 33599400c5db8..78c3fe93813e5 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -104,17 +104,17 @@ private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, s $catalogue->set((string) $source, $target, $domain); - $metadata = array( - 'file' => array( + $metadata = [ + 'file' => [ 'original' => (string) $fileAttributes['original'], - ), - ); + ], + ]; if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { $metadata['notes'] = $notes; } if (isset($translation->target) && $translation->target->attributes()) { - $metadata['target-attributes'] = array(); + $metadata['target-attributes'] = []; foreach ($translation->target->attributes() as $key => $value) { $metadata['target-attributes'][$key] = (string) $value; } @@ -146,18 +146,18 @@ private function extractXliff2(\DOMDocument $dom, MessageCatalogue $catalogue, s $catalogue->set((string) $source, $target, $domain); - $metadata = array(); + $metadata = []; if (isset($segment->target) && $segment->target->attributes()) { - $metadata['target-attributes'] = array(); + $metadata['target-attributes'] = []; foreach ($segment->target->attributes() as $key => $value) { $metadata['target-attributes'][$key] = (string) $value; } } if (isset($unit->notes)) { - $metadata['notes'] = array(); + $metadata['notes'] = []; foreach ($unit->notes->note as $noteNode) { - $note = array(); + $note = []; foreach ($noteNode->attributes() as $key => $value) { $note[$key] = (string) $value; } @@ -185,7 +185,7 @@ private function utf8ToCharset(string $content, string $encoding = null): string private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, string $encoding = null): array { - $notes = array(); + $notes = []; if (null === $noteElement) { return $notes; @@ -194,7 +194,7 @@ private function parseNotesMetadata(\SimpleXMLElement $noteElement = null, strin /** @var \SimpleXMLElement $xmlNote */ foreach ($noteElement as $xmlNote) { $noteAttributes = $xmlNote->attributes(); - $note = array('content' => $this->utf8ToCharset((string) $xmlNote, $encoding)); + $note = ['content' => $this->utf8ToCharset((string) $xmlNote, $encoding)]; if (isset($noteAttributes['priority'])) { $note['priority'] = (int) $noteAttributes['priority']; } diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index cf21c8227f7e4..f475c065b2aae 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -24,8 +24,8 @@ public function testLoad() $catalogue = $loader->load($resource, 'en', 'domain1'); $this->assertEquals('en', $catalogue->getLocale()); - $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); - $this->assertSame(array(), libxml_get_errors()); + $this->assertEquals([new FileResource($resource)], $catalogue->getResources()); + $this->assertSame([], libxml_get_errors()); $this->assertContainsOnly('string', $catalogue->all('domain1')); } @@ -33,15 +33,15 @@ public function testLoadWithInternalErrorsEnabled() { $internalErrors = libxml_use_internal_errors(true); - $this->assertSame(array(), libxml_get_errors()); + $this->assertSame([], libxml_get_errors()); $loader = new XliffFileLoader(); $resource = __DIR__.'/../fixtures/resources.xlf'; $catalogue = $loader->load($resource, 'en', 'domain1'); $this->assertEquals('en', $catalogue->getLocale()); - $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); - $this->assertSame(array(), libxml_get_errors()); + $this->assertEquals([new FileResource($resource)], $catalogue->getResources()); + $this->assertSame([], libxml_get_errors()); libxml_clear_errors(); libxml_use_internal_errors($internalErrors); @@ -58,7 +58,7 @@ public function testLoadWithExternalEntitiesDisabled() libxml_disable_entity_loader($disableEntities); $this->assertEquals('en', $catalogue->getLocale()); - $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); + $this->assertEquals([new FileResource($resource)], $catalogue->getResources()); } public function testLoadWithResname() @@ -66,7 +66,7 @@ public function testLoadWithResname() $loader = new XliffFileLoader(); $catalogue = $loader->load(__DIR__.'/../fixtures/resname.xlf', 'en', 'domain1'); - $this->assertEquals(array('foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo', 'qux' => 'qux source'), $catalogue->all('domain1')); + $this->assertEquals(['foo' => 'bar', 'bar' => 'baz', 'baz' => 'foo', 'qux' => 'qux source'], $catalogue->all('domain1')); } public function testIncompleteResource() @@ -74,7 +74,7 @@ public function testIncompleteResource() $loader = new XliffFileLoader(); $catalogue = $loader->load(__DIR__.'/../fixtures/resources.xlf', 'en', 'domain1'); - $this->assertEquals(array('foo' => 'bar', 'extra' => 'extra', 'key' => '', 'test' => 'with'), $catalogue->all('domain1')); + $this->assertEquals(['foo' => 'bar', 'extra' => 'extra', 'key' => '', 'test' => 'with'], $catalogue->all('domain1')); } public function testEncoding() @@ -85,13 +85,13 @@ public function testEncoding() $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1')); $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1')); $this->assertEquals( - array( - 'notes' => array(array('content' => utf8_decode('bäz'))), + [ + 'notes' => [['content' => utf8_decode('bäz')]], 'id' => '1', - 'file' => array( + 'file' => [ 'original' => 'file.ext', - ), - ), + ], + ], $catalogue->getMetadata('foo', 'domain1') ); } @@ -174,38 +174,38 @@ public function testLoadNotes() $catalogue = $loader->load(__DIR__.'/../fixtures/withnote.xlf', 'en', 'domain1'); $this->assertEquals( - array( - 'notes' => array(array('priority' => 1, 'content' => 'foo')), + [ + 'notes' => [['priority' => 1, 'content' => 'foo']], 'id' => '1', - 'file' => array( + 'file' => [ 'original' => 'file.ext', - ), - ), + ], + ], $catalogue->getMetadata('foo', 'domain1') ); // message without target $this->assertEquals( - array( - 'notes' => array(array('content' => 'bar', 'from' => 'foo')), + [ + 'notes' => [['content' => 'bar', 'from' => 'foo']], 'id' => '2', - 'file' => array( + 'file' => [ 'original' => 'file.ext', - ), - ), + ], + ], $catalogue->getMetadata('extra', 'domain1') ); // message with empty target $this->assertEquals( - array( - 'notes' => array( - array('content' => 'baz'), - array('priority' => 2, 'from' => 'bar', 'content' => 'qux'), - ), + [ + 'notes' => [ + ['content' => 'baz'], + ['priority' => 2, 'from' => 'bar', 'content' => 'qux'], + ], 'id' => '123', - 'file' => array( + 'file' => [ 'original' => 'file.ext', - ), - ), + ], + ], $catalogue->getMetadata('key', 'domain1') ); } @@ -217,15 +217,15 @@ public function testLoadVersion2() $catalogue = $loader->load($resource, 'en', 'domain1'); $this->assertEquals('en', $catalogue->getLocale()); - $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); - $this->assertSame(array(), libxml_get_errors()); + $this->assertEquals([new FileResource($resource)], $catalogue->getResources()); + $this->assertSame([], libxml_get_errors()); $domains = $catalogue->all(); $this->assertCount(3, $domains['domain1']); $this->assertContainsOnly('string', $catalogue->all('domain1')); // target attributes - $this->assertEquals(array('target-attributes' => array('order' => 1)), $catalogue->getMetadata('bar', 'domain1')); + $this->assertEquals(['target-attributes' => ['order' => 1]], $catalogue->getMetadata('bar', 'domain1')); } public function testLoadVersion2WithNoteMeta() @@ -235,8 +235,8 @@ public function testLoadVersion2WithNoteMeta() $catalogue = $loader->load($resource, 'en', 'domain1'); $this->assertEquals('en', $catalogue->getLocale()); - $this->assertEquals(array(new FileResource($resource)), $catalogue->getResources()); - $this->assertSame(array(), libxml_get_errors()); + $this->assertEquals([new FileResource($resource)], $catalogue->getResources()); + $this->assertSame([], libxml_get_errors()); // test for "foo" metadata $this->assertTrue($catalogue->defines('foo', 'domain1')); @@ -275,7 +275,7 @@ public function testLoadVersion2WithMultiSegmentUnit() $catalog = $loader->load($resource, 'en', 'domain1'); $this->assertSame('en', $catalog->getLocale()); - $this->assertEquals(array(new FileResource($resource)), $catalog->getResources()); + $this->assertEquals([new FileResource($resource)], $catalog->getResources()); $this->assertFalse(libxml_get_last_error()); // test for "foo" metadata @@ -303,22 +303,22 @@ public function testLoadWithMultipleFileNodes() $catalogue = $loader->load(__DIR__.'/../fixtures/resources-multi-files.xlf', 'en', 'domain1'); $this->assertEquals( - array( + [ 'id' => '1', - 'file' => array( + 'file' => [ 'original' => 'file.ext', - ), - ), + ], + ], $catalogue->getMetadata('foo', 'domain1') ); $this->assertEquals( - array( - 'notes' => array(array('content' => 'note')), + [ + 'notes' => [['content' => 'note']], 'id' => '4', - 'file' => array( + 'file' => [ 'original' => 'otherfile.ext', - ), - ), + ], + ], $catalogue->getMetadata('test', 'domain1') ); } diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index c58f8ac7ded6d..3036d200e0668 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -29,7 +29,7 @@ */ class BicValidator extends ConstraintValidator { - private const BIC_COUNTRY_TO_IBAN_COUNTRY_MAP = array( + private const BIC_COUNTRY_TO_IBAN_COUNTRY_MAP = [ // Reference: https://www.ecbs.org/iban/france-bank-account-number.html 'GF' => 'FR', // French Guiana 'PF' => 'FR', // French Polynesia @@ -46,7 +46,7 @@ class BicValidator extends ConstraintValidator 'IM' => 'GB', // Isle of Man 'GG' => 'GB', // Guernsey 'VG' => 'GB', // British Virgin Islands - ); + ]; private $propertyAccessor; diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index 0a3c06c1454bc..dcc5ad0cb80b2 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -27,66 +27,66 @@ */ class CardSchemeValidator extends ConstraintValidator { - protected $schemes = array( + protected $schemes = [ // American Express card numbers start with 34 or 37 and have 15 digits. - 'AMEX' => array( + 'AMEX' => [ '/^3[47][0-9]{13}$/', - ), + ], // China UnionPay cards start with 62 and have between 16 and 19 digits. // Please note that these cards do not follow Luhn Algorithm as a checksum. - 'CHINA_UNIONPAY' => array( + 'CHINA_UNIONPAY' => [ '/^62[0-9]{14,17}$/', - ), + ], // Diners Club card numbers begin with 300 through 305, 36 or 38. All have 14 digits. // There are Diners Club cards that begin with 5 and have 16 digits. // These are a joint venture between Diners Club and MasterCard, and should be processed like a MasterCard. - 'DINERS' => array( + 'DINERS' => [ '/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/', - ), + ], // Discover card numbers begin with 6011, 622126 through 622925, 644 through 649 or 65. // All have 16 digits. - 'DISCOVER' => array( + 'DISCOVER' => [ '/^6011[0-9]{12}$/', '/^64[4-9][0-9]{13}$/', '/^65[0-9]{14}$/', '/^622(12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|91[0-9]|92[0-5])[0-9]{10}$/', - ), + ], // InstaPayment cards begin with 637 through 639 and have 16 digits. - 'INSTAPAYMENT' => array( + 'INSTAPAYMENT' => [ '/^63[7-9][0-9]{13}$/', - ), + ], // JCB cards beginning with 2131 or 1800 have 15 digits. // JCB cards beginning with 35 have 16 digits. - 'JCB' => array( + 'JCB' => [ '/^(?:2131|1800|35[0-9]{3})[0-9]{11}$/', - ), + ], // Laser cards begin with either 6304, 6706, 6709 or 6771 and have between 16 and 19 digits. - 'LASER' => array( + 'LASER' => [ '/^(6304|670[69]|6771)[0-9]{12,15}$/', - ), + ], // Maestro international cards begin with 675900..675999 and have between 12 and 19 digits. // Maestro UK cards begin with either 500000..509999 or 560000..699999 and have between 12 and 19 digits. - 'MAESTRO' => array( + 'MAESTRO' => [ '/^(6759[0-9]{2})[0-9]{6,13}$/', '/^(50[0-9]{4})[0-9]{6,13}$/', '/^5[6-9][0-9]{10,17}$/', '/^6[0-9]{11,18}$/', - ), + ], // All MasterCard numbers start with the numbers 51 through 55. All have 16 digits. // October 2016 MasterCard numbers can also start with 222100 through 272099. - 'MASTERCARD' => array( + 'MASTERCARD' => [ '/^5[1-5][0-9]{14}$/', '/^2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12})$/', - ), + ], // All UATP card numbers start with a 1 and have a length of 15 digits. - 'UATP' => array( + 'UATP' => [ '/^1[0-9]{14}$/', - ), + ], // All Visa card numbers start with a 4 and have a length of 13, 16, or 19 digits. - 'VISA' => array( + 'VISA' => [ '/^4([0-9]{12}|[0-9]{15}|[0-9]{18})$/', - ), - ); + ], + ]; /** * Validates a creditcard belongs to a specified scheme. diff --git a/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php index d7dc469479382..174bbb2863437 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/BicValidatorTest.php @@ -39,7 +39,7 @@ public function testEmptyStringIsValid() public function testValidComparisonToPropertyPath() { - $constraint = new Bic(array('ibanPropertyPath' => 'value')); + $constraint = new Bic(['ibanPropertyPath' => 'value']); $object = new BicComparisonTestClass('FR14 2004 1010 0505 0001 3M02 606'); @@ -52,9 +52,9 @@ public function testValidComparisonToPropertyPath() public function testValidComparisonToPropertyPathOnArray() { - $constraint = new Bic(array('ibanPropertyPath' => '[root][value]')); + $constraint = new Bic(['ibanPropertyPath' => '[root][value]']); - $this->setObject(array('root' => array('value' => 'FR14 2004 1010 0505 0001 3M02 606'))); + $this->setObject(['root' => ['value' => 'FR14 2004 1010 0505 0001 3M02 606']]); $this->validator->validate('SOGEFRPP', $constraint); @@ -63,7 +63,7 @@ public function testValidComparisonToPropertyPathOnArray() public function testInvalidComparisonToPropertyPath() { - $constraint = new Bic(array('ibanPropertyPath' => 'value')); + $constraint = new Bic(['ibanPropertyPath' => 'value']); $constraint->ibanMessage = 'Constraint Message'; $object = new BicComparisonTestClass('FR14 2004 1010 0505 0001 3M02 606'); @@ -81,7 +81,7 @@ public function testInvalidComparisonToPropertyPath() public function testValidComparisonToValue() { - $constraint = new Bic(array('iban' => 'FR14 2004 1010 0505 0001 3M02 606')); + $constraint = new Bic(['iban' => 'FR14 2004 1010 0505 0001 3M02 606']); $constraint->ibanMessage = 'Constraint Message'; $this->validator->validate('SOGEFRPP', $constraint); @@ -91,7 +91,7 @@ public function testValidComparisonToValue() public function testInvalidComparisonToValue() { - $constraint = new Bic(array('iban' => 'FR14 2004 1010 0505 0001 3M02 606')); + $constraint = new Bic(['iban' => 'FR14 2004 1010 0505 0001 3M02 606']); $constraint->ibanMessage = 'Constraint Message'; $this->validator->validate('UNCRIT2B912', $constraint); @@ -105,7 +105,7 @@ public function testInvalidComparisonToValue() public function testNoViolationOnNullObjectWithPropertyPath() { - $constraint = new Bic(array('ibanPropertyPath' => 'propertyPath')); + $constraint = new Bic(['ibanPropertyPath' => 'propertyPath']); $this->setObject(null); @@ -120,15 +120,15 @@ public function testNoViolationOnNullObjectWithPropertyPath() */ public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() { - new Bic(array( + new Bic([ 'iban' => 'value', 'ibanPropertyPath' => 'propertyPath', - )); + ]); } public function testInvalidValuePath() { - $constraint = new Bic(array('ibanPropertyPath' => 'foo')); + $constraint = new Bic(['ibanPropertyPath' => 'foo']); if (method_exists($this, 'expectException')) { $this->expectException(ConstraintDefinitionException::class); @@ -230,7 +230,7 @@ public function getInvalidBics() */ public function testValidBicSpecialCases(string $bic, string $iban) { - $constraint = new Bic(array('iban' => $iban)); + $constraint = new Bic(['iban' => $iban]); $this->validator->validate($bic, $constraint); $this->assertNoViolation(); @@ -239,22 +239,22 @@ public function testValidBicSpecialCases(string $bic, string $iban) public function getValidBicSpecialCases() { // FR related special cases - yield array('BNPAGFGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAPFGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPATFGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAGPGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAMQGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAYTGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPANCGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAREGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAPMGX', 'FR14 2004 1010 0505 0001 3M02 606'); - yield array('BNPAWFGX', 'FR14 2004 1010 0505 0001 3M02 606'); + yield ['BNPAGFGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAPFGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPATFGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAGPGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAMQGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAYTGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPANCGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAREGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAPMGX', 'FR14 2004 1010 0505 0001 3M02 606']; + yield ['BNPAWFGX', 'FR14 2004 1010 0505 0001 3M02 606']; // GB related special cases - yield array('BARCJESA', 'GB12 CPBK 0892 9965 0449 911'); - yield array('BARCIMSA', 'GB12 CPBK 0892 9965 0449 911'); - yield array('BARCGGSA', 'GB12 CPBK 0892 9965 0449 911'); - yield array('BARCVGSA', 'GB12 CPBK 0892 9965 0449 911'); + yield ['BARCJESA', 'GB12 CPBK 0892 9965 0449 911']; + yield ['BARCIMSA', 'GB12 CPBK 0892 9965 0449 911']; + yield ['BARCGGSA', 'GB12 CPBK 0892 9965 0449 911']; + yield ['BARCVGSA', 'GB12 CPBK 0892 9965 0449 911']; } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index fccee9e0abc1a..24c23109f4615 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -24,14 +24,14 @@ protected function createValidator() public function testNullIsValid() { - $this->validator->validate(null, new CardScheme(array('schemes' => array()))); + $this->validator->validate(null, new CardScheme(['schemes' => []])); $this->assertNoViolation(); } public function testEmptyStringIsValid() { - $this->validator->validate('', new CardScheme(array('schemes' => array()))); + $this->validator->validate('', new CardScheme(['schemes' => []])); $this->assertNoViolation(); } @@ -41,7 +41,7 @@ public function testEmptyStringIsValid() */ public function testValidNumbers($scheme, $number) { - $this->validator->validate($number, new CardScheme(array('schemes' => $scheme))); + $this->validator->validate($number, new CardScheme(['schemes' => $scheme])); $this->assertNoViolation(); } @@ -51,10 +51,10 @@ public function testValidNumbers($scheme, $number) */ public function testInvalidNumbers($scheme, $number, $code) { - $constraint = new CardScheme(array( + $constraint = new CardScheme([ 'schemes' => $scheme, 'message' => 'myMessage', - )); + ]); $this->validator->validate($number, $constraint); @@ -66,75 +66,75 @@ public function testInvalidNumbers($scheme, $number, $code) public function getValidNumbers() { - return array( - array('AMEX', '378282246310005'), - array('AMEX', '371449635398431'), - array('AMEX', '378734493671000'), - array('AMEX', '347298508610146'), - array('CHINA_UNIONPAY', '6228888888888888'), - array('CHINA_UNIONPAY', '62288888888888888'), - array('CHINA_UNIONPAY', '622888888888888888'), - array('CHINA_UNIONPAY', '6228888888888888888'), - array('DINERS', '30569309025904'), - array('DINERS', '36088894118515'), - array('DINERS', '38520000023237'), - array('DISCOVER', '6011111111111117'), - array('DISCOVER', '6011000990139424'), - array('INSTAPAYMENT', '6372476031350068'), - array('INSTAPAYMENT', '6385537775789749'), - array('INSTAPAYMENT', '6393440808445746'), - array('JCB', '3530111333300000'), - array('JCB', '3566002020360505'), - array('JCB', '213112345678901'), - array('JCB', '180012345678901'), - array('LASER', '6304678107004080'), - array('LASER', '6706440607428128629'), - array('LASER', '6771656738314582216'), - array('MAESTRO', '6759744069209'), - array('MAESTRO', '5020507657408074712'), - array('MAESTRO', '5612559223580173965'), - array('MAESTRO', '6759744069209'), - array('MAESTRO', '6594371785970435599'), - array('MASTERCARD', '5555555555554444'), - array('MASTERCARD', '5105105105105100'), - array('MASTERCARD', '2221005555554444'), - array('MASTERCARD', '2230000000000000'), - array('MASTERCARD', '2300000000000000'), - array('MASTERCARD', '2699999999999999'), - array('MASTERCARD', '2709999999999999'), - array('MASTERCARD', '2720995105105100'), - array('UATP', '110165309696173'), - array('VISA', '4111111111111111'), - array('VISA', '4012888888881881'), - array('VISA', '4222222222222'), - array('VISA', '4917610000000000003'), - array(array('AMEX', 'VISA'), '4111111111111111'), - array(array('AMEX', 'VISA'), '378282246310005'), - array(array('JCB', 'MASTERCARD'), '5105105105105100'), - array(array('VISA', 'MASTERCARD'), '5105105105105100'), - ); + return [ + ['AMEX', '378282246310005'], + ['AMEX', '371449635398431'], + ['AMEX', '378734493671000'], + ['AMEX', '347298508610146'], + ['CHINA_UNIONPAY', '6228888888888888'], + ['CHINA_UNIONPAY', '62288888888888888'], + ['CHINA_UNIONPAY', '622888888888888888'], + ['CHINA_UNIONPAY', '6228888888888888888'], + ['DINERS', '30569309025904'], + ['DINERS', '36088894118515'], + ['DINERS', '38520000023237'], + ['DISCOVER', '6011111111111117'], + ['DISCOVER', '6011000990139424'], + ['INSTAPAYMENT', '6372476031350068'], + ['INSTAPAYMENT', '6385537775789749'], + ['INSTAPAYMENT', '6393440808445746'], + ['JCB', '3530111333300000'], + ['JCB', '3566002020360505'], + ['JCB', '213112345678901'], + ['JCB', '180012345678901'], + ['LASER', '6304678107004080'], + ['LASER', '6706440607428128629'], + ['LASER', '6771656738314582216'], + ['MAESTRO', '6759744069209'], + ['MAESTRO', '5020507657408074712'], + ['MAESTRO', '5612559223580173965'], + ['MAESTRO', '6759744069209'], + ['MAESTRO', '6594371785970435599'], + ['MASTERCARD', '5555555555554444'], + ['MASTERCARD', '5105105105105100'], + ['MASTERCARD', '2221005555554444'], + ['MASTERCARD', '2230000000000000'], + ['MASTERCARD', '2300000000000000'], + ['MASTERCARD', '2699999999999999'], + ['MASTERCARD', '2709999999999999'], + ['MASTERCARD', '2720995105105100'], + ['UATP', '110165309696173'], + ['VISA', '4111111111111111'], + ['VISA', '4012888888881881'], + ['VISA', '4222222222222'], + ['VISA', '4917610000000000003'], + [['AMEX', 'VISA'], '4111111111111111'], + [['AMEX', 'VISA'], '378282246310005'], + [['JCB', 'MASTERCARD'], '5105105105105100'], + [['VISA', 'MASTERCARD'], '5105105105105100'], + ]; } public function getInvalidNumbers() { - return array( - array('VISA', '42424242424242424242', CardScheme::INVALID_FORMAT_ERROR), - array('AMEX', '357298508610146', CardScheme::INVALID_FORMAT_ERROR), - array('DINERS', '31569309025904', CardScheme::INVALID_FORMAT_ERROR), - array('DINERS', '37088894118515', CardScheme::INVALID_FORMAT_ERROR), - array('INSTAPAYMENT', '6313440808445746', CardScheme::INVALID_FORMAT_ERROR), - array('CHINA_UNIONPAY', '622888888888888', CardScheme::INVALID_FORMAT_ERROR), - array('CHINA_UNIONPAY', '62288888888888888888', CardScheme::INVALID_FORMAT_ERROR), - array('AMEX', '30569309025904', CardScheme::INVALID_FORMAT_ERROR), // DINERS number - array('AMEX', 'invalid', CardScheme::NOT_NUMERIC_ERROR), // A string - array('AMEX', 0, CardScheme::INVALID_FORMAT_ERROR), // a lone number - array('AMEX', '0', CardScheme::INVALID_FORMAT_ERROR), // a lone number - array('AMEX', '000000000000', CardScheme::INVALID_FORMAT_ERROR), // a lone number - array('DINERS', '3056930', CardScheme::INVALID_FORMAT_ERROR), // only first part of the number - array('DISCOVER', '1117', CardScheme::INVALID_FORMAT_ERROR), // only last 4 digits - array('MASTERCARD', '2721001234567890', CardScheme::INVALID_FORMAT_ERROR), // Not assigned yet - array('MASTERCARD', '2220991234567890', CardScheme::INVALID_FORMAT_ERROR), // Not assigned yet - array('UATP', '11016530969617', CardScheme::INVALID_FORMAT_ERROR), // invalid length - ); + return [ + ['VISA', '42424242424242424242', CardScheme::INVALID_FORMAT_ERROR], + ['AMEX', '357298508610146', CardScheme::INVALID_FORMAT_ERROR], + ['DINERS', '31569309025904', CardScheme::INVALID_FORMAT_ERROR], + ['DINERS', '37088894118515', CardScheme::INVALID_FORMAT_ERROR], + ['INSTAPAYMENT', '6313440808445746', CardScheme::INVALID_FORMAT_ERROR], + ['CHINA_UNIONPAY', '622888888888888', CardScheme::INVALID_FORMAT_ERROR], + ['CHINA_UNIONPAY', '62288888888888888888', CardScheme::INVALID_FORMAT_ERROR], + ['AMEX', '30569309025904', CardScheme::INVALID_FORMAT_ERROR], // DINERS number + ['AMEX', 'invalid', CardScheme::NOT_NUMERIC_ERROR], // A string + ['AMEX', 0, CardScheme::INVALID_FORMAT_ERROR], // a lone number + ['AMEX', '0', CardScheme::INVALID_FORMAT_ERROR], // a lone number + ['AMEX', '000000000000', CardScheme::INVALID_FORMAT_ERROR], // a lone number + ['DINERS', '3056930', CardScheme::INVALID_FORMAT_ERROR], // only first part of the number + ['DISCOVER', '1117', CardScheme::INVALID_FORMAT_ERROR], // only last 4 digits + ['MASTERCARD', '2721001234567890', CardScheme::INVALID_FORMAT_ERROR], // Not assigned yet + ['MASTERCARD', '2220991234567890', CardScheme::INVALID_FORMAT_ERROR], // Not assigned yet + ['UATP', '11016530969617', CardScheme::INVALID_FORMAT_ERROR], // invalid length + ]; } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php index 1587392b608e4..b67846f878047 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/RegexValidatorTest.php @@ -24,14 +24,14 @@ protected function createValidator() public function testNullIsValid() { - $this->validator->validate(null, new Regex(array('pattern' => '/^[0-9]+$/'))); + $this->validator->validate(null, new Regex(['pattern' => '/^[0-9]+$/'])); $this->assertNoViolation(); } public function testEmptyStringIsValid() { - $this->validator->validate('', new Regex(array('pattern' => '/^[0-9]+$/'))); + $this->validator->validate('', new Regex(['pattern' => '/^[0-9]+$/'])); $this->assertNoViolation(); } @@ -41,7 +41,7 @@ public function testEmptyStringIsValid() */ public function testExpectsStringCompatibleType() { - $this->validator->validate(new \stdClass(), new Regex(array('pattern' => '/^[0-9]+$/'))); + $this->validator->validate(new \stdClass(), new Regex(['pattern' => '/^[0-9]+$/'])); } /** @@ -49,7 +49,7 @@ public function testExpectsStringCompatibleType() */ public function testValidValues($value) { - $constraint = new Regex(array('pattern' => '/^[0-9]+$/')); + $constraint = new Regex(['pattern' => '/^[0-9]+$/']); $this->validator->validate($value, $constraint); $this->assertNoViolation(); @@ -57,18 +57,18 @@ public function testValidValues($value) public function getValidValues() { - return array( - array(0), - array('0'), - array('090909'), - array(90909), - array(new class() { + return [ + [0], + ['0'], + ['090909'], + [90909], + [new class() { public function __toString() { return '090909'; } - }), - ); + }], + ]; } /** @@ -76,10 +76,10 @@ public function __toString() */ public function testInvalidValues($value) { - $constraint = new Regex(array( + $constraint = new Regex([ 'pattern' => '/^[0-9]+$/', 'message' => 'myMessage', - )); + ]); $this->validator->validate($value, $constraint); @@ -91,15 +91,15 @@ public function testInvalidValues($value) public function getInvalidValues() { - return array( - array('abcd'), - array('090foo'), - array(new class() { + return [ + ['abcd'], + ['090foo'], + [new class() { public function __toString() { return 'abcd'; } - }), - ); + }], + ]; } } diff --git a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php index 85de5b59674ac..5d9b80de2a51f 100644 --- a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php @@ -81,17 +81,17 @@ public static function castOpensslX509($h, array $a, Stub $stub, $isNested) $pin = base64_decode(implode('', $pin)); $pin = base64_encode(hash('sha256', $pin, true)); - $a += array( - 'subject' => new EnumStub(array_intersect_key($info['subject'], array('organizationName' => true, 'commonName' => true))), - 'issuer' => new EnumStub(array_intersect_key($info['issuer'], array('organizationName' => true, 'commonName' => true))), + $a += [ + 'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), + 'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), 'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), - 'fingerprint' => new EnumStub(array( + 'fingerprint' => new EnumStub([ 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), 'pin-sha256' => new ConstStub($pin), - )), - ); + ]), + ]; return $a; } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index f55b2a1c67c00..8d0525062b2ad 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -21,134 +21,134 @@ */ abstract class AbstractCloner implements ClonerInterface { - public static $defaultCasters = array( - '__PHP_Incomplete_Class' => array('Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'), - - 'Symfony\Component\VarDumper\Caster\CutStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'), - 'Symfony\Component\VarDumper\Caster\CutArrayStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'), - 'Symfony\Component\VarDumper\Caster\ConstStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'), - 'Symfony\Component\VarDumper\Caster\EnumStub' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'), - - 'Closure' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'), - 'Generator' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'), - 'ReflectionType' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'), - 'ReflectionGenerator' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'), - 'ReflectionClass' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'), - 'ReflectionFunctionAbstract' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'), - 'ReflectionMethod' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'), - 'ReflectionParameter' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'), - 'ReflectionProperty' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'), - 'ReflectionExtension' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'), - 'ReflectionZendExtension' => array('Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'), - - 'Doctrine\Common\Persistence\ObjectManager' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'), - 'Doctrine\Common\Proxy\Proxy' => array('Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'), - 'Doctrine\ORM\Proxy\Proxy' => array('Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'), - 'Doctrine\ORM\PersistentCollection' => array('Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'), - - 'DOMException' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'), - 'DOMStringList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'), - 'DOMNameList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'), - 'DOMImplementation' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'), - 'DOMImplementationList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'), - 'DOMNode' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'), - 'DOMNameSpaceNode' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'), - 'DOMDocument' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'), - 'DOMNodeList' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'), - 'DOMNamedNodeMap' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'), - 'DOMCharacterData' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'), - 'DOMAttr' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'), - 'DOMElement' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'), - 'DOMText' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'), - 'DOMTypeinfo' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'), - 'DOMDomError' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'), - 'DOMLocator' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'), - 'DOMDocumentType' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'), - 'DOMNotation' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'), - 'DOMEntity' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'), - 'DOMProcessingInstruction' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'), - 'DOMXPath' => array('Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'), - - 'XmlReader' => array('Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'), - - 'ErrorException' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'), - 'Exception' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'), - 'Error' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'), - 'Symfony\Component\DependencyInjection\ContainerInterface' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'), - 'Symfony\Component\HttpFoundation\Request' => array('Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'), - 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'), - 'Symfony\Component\VarDumper\Caster\TraceStub' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'), - 'Symfony\Component\VarDumper\Caster\FrameStub' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'), - 'Symfony\Component\Debug\Exception\SilencedErrorContext' => array('Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'), - - 'ProxyManager\Proxy\ProxyInterface' => array('Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'), - 'PHPUnit_Framework_MockObject_MockObject' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'), - 'Prophecy\Prophecy\ProphecySubjectInterface' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'), - 'Mockery\MockInterface' => array('Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'), - - 'PDO' => array('Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'), - 'PDOStatement' => array('Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'), - - 'AMQPConnection' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'), - 'AMQPChannel' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'), - 'AMQPQueue' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'), - 'AMQPExchange' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'), - 'AMQPEnvelope' => array('Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'), - - 'ArrayObject' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'), - 'ArrayIterator' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'), - 'SplDoublyLinkedList' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'), - 'SplFileInfo' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'), - 'SplFileObject' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'), - 'SplFixedArray' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castFixedArray'), - 'SplHeap' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'), - 'SplObjectStorage' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'), - 'SplPriorityQueue' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'), - 'OuterIterator' => array('Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'), - - 'Redis' => array('Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'), - 'RedisArray' => array('Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'), - 'RedisCluster' => array('Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'), - - 'DateTimeInterface' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'), - 'DateInterval' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'), - 'DateTimeZone' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'), - 'DatePeriod' => array('Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'), - - 'GMP' => array('Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'), - - 'MessageFormatter' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'), - 'NumberFormatter' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'), - 'IntlTimeZone' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'), - 'IntlCalendar' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'), - 'IntlDateFormatter' => array('Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'), - - 'Memcached' => array('Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'), - - ':curl' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'), - ':dba' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'), - ':dba persistent' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'), - ':gd' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'), - ':mysql link' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'), - ':pgsql large object' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'), - ':pgsql link' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'), - ':pgsql link persistent' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'), - ':pgsql result' => array('Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'), - ':process' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'), - ':stream' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'), - ':OpenSSL X.509' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'), - ':persistent stream' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'), - ':stream-context' => array('Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'), - ':xml' => array('Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'), - ); + public static $defaultCasters = [ + '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], + + 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], + 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], + 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], + 'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'], + + 'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'], + 'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'], + 'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'], + 'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'], + 'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'], + 'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'], + 'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'], + 'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'], + 'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'], + 'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'], + 'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'], + + 'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'], + 'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'], + 'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'], + + 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], + 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], + 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], + 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], + 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], + 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], + 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], + 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], + 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], + 'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'], + 'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'], + 'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'], + 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], + 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], + 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], + 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], + 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], + + 'XmlReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], + + 'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'], + 'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'], + 'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'], + 'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], + 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'], + 'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'], + 'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'], + 'Symfony\Component\Debug\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'], + + 'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'], + 'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + + 'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'], + 'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'], + + 'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'], + 'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'], + 'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'], + 'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'], + 'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'], + + 'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'], + 'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'], + 'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'], + 'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'], + 'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'], + 'SplFixedArray' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFixedArray'], + 'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], + 'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'], + 'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], + 'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'], + + 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], + 'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'], + 'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'], + + 'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'], + 'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'], + 'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'], + 'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'], + + 'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'], + + 'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'], + 'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'], + 'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'], + 'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'], + 'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'], + + 'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'], + + ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], + ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], + ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], + ':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'], + ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], + ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], + ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'], + ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], + ':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], + ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'], + ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], + ]; protected $maxItems = 2500; protected $maxString = -1; protected $minDepth = 1; - private $casters = array(); + private $casters = []; private $prevErrorHandler; - private $classInfo = array(); + private $classInfo = []; private $filter = 0; /** @@ -225,7 +225,7 @@ public function setMinDepth($minDepth) */ public function cloneVar($var, $filter = 0) { - $this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) { + $this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) { if (E_RECOVERABLE_ERROR === $type || E_USER_ERROR === $type) { // Cloner never dies throw new \ErrorException($msg, 0, $type, $file, $line); @@ -282,7 +282,7 @@ protected function castObject(Stub $stub, $isNested) list($i, $parents, $hasDebugInfo) = $this->classInfo[$class]; } else { $i = 2; - $parents = array(strtolower($class)); + $parents = [strtolower($class)]; $hasDebugInfo = method_exists($class, '__debugInfo'); foreach (class_parents($class) as $p) { @@ -295,7 +295,7 @@ protected function castObject(Stub $stub, $isNested) } $parents[] = '*'; - $this->classInfo[$class] = array($i, $parents, $hasDebugInfo); + $this->classInfo[$class] = [$i, $parents, $hasDebugInfo]; } $a = Caster::castObject($obj, $class, $hasDebugInfo); @@ -309,7 +309,7 @@ protected function castObject(Stub $stub, $isNested) } } } catch (\Exception $e) { - $a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a; + $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; } return $a; @@ -325,7 +325,7 @@ protected function castObject(Stub $stub, $isNested) */ protected function castResource(Stub $stub, $isNested) { - $a = array(); + $a = []; $res = $stub->value; $type = $stub->class; @@ -336,7 +336,7 @@ protected function castResource(Stub $stub, $isNested) } } } catch (\Exception $e) { - $a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a; + $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; } return $a; diff --git a/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php b/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php index 74c1bc8b4c96c..dc77d03ecd80c 100644 --- a/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php +++ b/src/Symfony/Component/VarDumper/Command/Descriptor/CliDescriptor.php @@ -39,10 +39,10 @@ public function __construct(CliDumper $dumper) public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void { - $io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput(array()), $output); + $io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output); $this->dumper->setColors($output->isDecorated()); - $rows = array(array('date', date('r', $context['timestamp']))); + $rows = [['date', date('r', $context['timestamp'])]]; $lastIdentifier = $this->lastIdentifier; $this->lastIdentifier = $clientId; @@ -52,7 +52,7 @@ public function describe(OutputInterface $output, Data $data, array $context, in $this->lastIdentifier = $request['identifier']; $section = sprintf('%s %s', $request['method'], $request['uri']); if ($controller = $request['controller']) { - $rows[] = array('controller', rtrim($this->dumper->dump($controller, true), "\n")); + $rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")]; } } elseif (isset($context['cli'])) { $this->lastIdentifier = $context['cli']['identifier']; @@ -70,15 +70,15 @@ public function describe(OutputInterface $output, Data $data, array $context, in if ($this->supportsHref && $fileLink) { $sourceInfo = sprintf('%s', $fileLink, $sourceInfo); } - $rows[] = array('source', $sourceInfo); + $rows[] = ['source', $sourceInfo]; $file = $source['file_relative'] ?? $source['file']; - $rows[] = array('file', $file); + $rows[] = ['file', $file]; } - $io->table(array(), $rows); + $io->table([], $rows); if (!$this->supportsHref && isset($fileLink)) { - $io->writeln(array('Open source in your IDE/browser:', $fileLink)); + $io->writeln(['Open source in your IDE/browser:', $fileLink]); $io->newLine(); } diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index 418f0448183d9..3fb7ac619e55d 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -55,9 +55,9 @@ class CliDumper extends AbstractDumper protected $collapseNextHash = false; protected $expandNextHash = false; - private $displayOptions = array( + private $displayOptions = [ 'fileLinkFormat' => null, - ); + ]; private $handlesHrefGracefully; @@ -632,7 +632,7 @@ private function isWindowsTrueColor() private function getSourceLink($file, $line) { if ($fmt = $this->displayOptions['fileLinkFormat']) { - return \is_string($fmt) ? strtr($fmt, array('%f' => $file, '%l' => $line)) : $fmt->format($file, $line); + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line); } return false; diff --git a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php index 473bd63dac7cb..fef5dcd127630 100644 --- a/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php @@ -49,21 +49,21 @@ public function testDescribe(array $context, string $expectedOutput, bool $decor return $s; })); - $descriptor->describe($output, new Data(array(array(123))), $context + array('timestamp' => 1544804268.3668), 1); + $descriptor->describe($output, new Data([[123]]), $context + ['timestamp' => 1544804268.3668], 1); $this->assertStringMatchesFormat(trim($expectedOutput), str_replace(PHP_EOL, "\n", trim($output->fetch()))); } public function provideContext() { - yield 'source' => array( - array( - 'source' => array( + yield 'source' => [ + [ + 'source' => [ 'name' => 'CliDescriptorTest.php', 'line' => 30, 'file' => '/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php', - ), - ), + ], + ], << array( - array( - 'source' => array( + yield 'source full' => [ + [ + 'source' => [ 'name' => 'CliDescriptorTest.php', 'line' => 30, 'file_relative' => 'src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php', 'file' => '/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php', 'file_link' => 'phpstorm://open?file=/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php&line=30', - ), - ), + ], + ], method_exists(OutputFormatterStyle::class, 'setHref') ? << array( - array( - 'source' => array( + yield 'source with hyperlink' => [ + [ + 'source' => [ 'name' => 'CliDescriptorTest.php', 'line' => 30, 'file_relative' => 'src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php', 'file_link' => 'phpstorm://open?file=/Users/ogi/symfony/src/Symfony/Component/VarDumper/Tests/Command/Descriptor/CliDescriptorTest.php&line=30', - ), - ), + ], + ], << array( - array( - 'cli' => array( + yield 'cli' => [ + [ + 'cli' => [ 'identifier' => 'd8bece1c', 'command_line' => 'bin/phpunit', - ), - ), + ], + ], << array( - array( - 'request' => array( + yield 'request' => [ + [ + 'request' => [ 'identifier' => 'd8bece1c', - 'controller' => new Data(array(array('FooController.php'))), + 'controller' => new Data([['FooController.php']]), 'method' => 'GET', 'uri' => 'http://localhost/foo', - ), - ), + ], + ], <<marking = null; - $workflow = new Workflow(new Definition(array(), array()), $this->getMockBuilder(MarkingStoreInterface::class)->getMock()); + $workflow = new Workflow(new Definition([], []), $this->getMockBuilder(MarkingStoreInterface::class)->getMock()); $workflow->getMarking($subject); } @@ -40,7 +40,7 @@ public function testGetMarkingWithEmptyDefinition() { $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow(new Definition(array(), array()), new MultipleStateMarkingStore()); + $workflow = new Workflow(new Definition([], []), new MultipleStateMarkingStore()); $workflow->getMarking($subject); } @@ -52,8 +52,8 @@ public function testGetMarkingWithEmptyDefinition() public function testGetMarkingWithImpossiblePlace() { $subject = new \stdClass(); - $subject->marking = array('nope' => 1); - $workflow = new Workflow(new Definition(array(), array()), new MultipleStateMarkingStore()); + $subject->marking = ['nope' => 1]; + $workflow = new Workflow(new Definition([], []), new MultipleStateMarkingStore()); $workflow->getMarking($subject); } @@ -69,7 +69,7 @@ public function testGetMarkingWithEmptyInitialMarking() $this->assertInstanceOf(Marking::class, $marking); $this->assertTrue($marking->has('a')); - $this->assertSame(array('a' => 1), $subject->marking); + $this->assertSame(['a' => 1], $subject->marking); } public function testGetMarkingWithExistingMarking() @@ -77,7 +77,7 @@ public function testGetMarkingWithExistingMarking() $definition = $this->createComplexWorkflowDefinition(); $subject = new \stdClass(); $subject->marking = null; - $subject->marking = array('b' => 1, 'c' => 1); + $subject->marking = ['b' => 1, 'c' => 1]; $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->getMarking($subject); @@ -107,19 +107,19 @@ public function testCan() $this->assertTrue($workflow->can($subject, 't1')); $this->assertFalse($workflow->can($subject, 't2')); - $subject->marking = array('b' => 1); + $subject->marking = ['b' => 1]; $this->assertFalse($workflow->can($subject, 't1')); // In a workflow net, all "from" places should contain a token to enable // the transition. $this->assertFalse($workflow->can($subject, 't2')); - $subject->marking = array('b' => 1, 'c' => 1); + $subject->marking = ['b' => 1, 'c' => 1]; $this->assertFalse($workflow->can($subject, 't1')); $this->assertTrue($workflow->can($subject, 't2')); - $subject->marking = array('f' => 1); + $subject->marking = ['f' => 1]; $this->assertFalse($workflow->can($subject, 't5')); $this->assertTrue($workflow->can($subject, 't6')); @@ -145,7 +145,7 @@ public function testCanDoesNotTriggerGuardEventsForNotEnabledTransitions() $subject = new \stdClass(); $subject->marking = null; - $dispatchedEvents = array(); + $dispatchedEvents = []; $eventDispatcher = new EventDispatcher(); $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); @@ -161,7 +161,7 @@ public function testCanDoesNotTriggerGuardEventsForNotEnabledTransitions() $workflow->can($subject, 't3'); - $this->assertSame(array('workflow_name.guard.t3'), $dispatchedEvents); + $this->assertSame(['workflow_name.guard.t3'], $dispatchedEvents); } public function testCanWithSameNameTransition() @@ -175,7 +175,7 @@ public function testCanWithSameNameTransition() $this->assertFalse($workflow->can($subject, 'b_to_c')); $this->assertFalse($workflow->can($subject, 'to_a')); - $subject->marking = array('b' => 1); + $subject->marking = ['b' => 1]; $this->assertFalse($workflow->can($subject, 'a_to_bc')); $this->assertTrue($workflow->can($subject, 'b_to_c')); $this->assertTrue($workflow->can($subject, 'to_a')); @@ -205,17 +205,17 @@ public function testBuildTransitionBlockerList() $this->assertTrue($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty()); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty()); - $subject->marking = array('b' => 1); + $subject->marking = ['b' => 1]; $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty()); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty()); - $subject->marking = array('b' => 1, 'c' => 1); + $subject->marking = ['b' => 1, 'c' => 1]; $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty()); $this->assertTrue($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty()); - $subject->marking = array('f' => 1); + $subject->marking = ['f' => 1]; $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't5')->isEmpty()); $this->assertTrue($workflow->buildTransitionBlockerList($subject, 't6')->isEmpty()); @@ -354,10 +354,10 @@ public function testApplyWithSameNameTransition() public function testApplyWithSameNameTransition2() { $subject = new \stdClass(); - $subject->marking = array('a' => 1, 'b' => 1); + $subject->marking = ['a' => 1, 'b' => 1]; $places = range('a', 'd'); - $transitions = array(); + $transitions = []; $transitions[] = new Transition('t', 'a', 'c'); $transitions[] = new Transition('t', 'b', 'd'); $definition = new Definition($places, $transitions); @@ -374,10 +374,10 @@ public function testApplyWithSameNameTransition2() public function testApplyWithSameNameTransition3() { $subject = new \stdClass(); - $subject->marking = array('a' => 1); + $subject->marking = ['a' => 1]; $places = range('a', 'd'); - $transitions = array(); + $transitions = []; $transitions[] = new Transition('t', 'a', 'b'); $transitions[] = new Transition('t', 'b', 'c'); $transitions[] = new Transition('t', 'c', 'd'); @@ -398,7 +398,7 @@ public function testApplyWithEventDispatcher() $eventDispatcher = new EventDispatcherMock(); $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); - $eventNameExpected = array( + $eventNameExpected = [ 'workflow.entered', 'workflow.workflow_name.entered', 'workflow.guard', @@ -428,7 +428,7 @@ public function testApplyWithEventDispatcher() 'workflow.workflow_name.guard', 'workflow.workflow_name.guard.t2', 'workflow.workflow_name.announce.t2', - ); + ]; $marking = $workflow->apply($subject, 't1'); @@ -448,14 +448,14 @@ public function testEventName() $this->assertEquals($name, $event->getWorkflowName()); }; - $eventNames = array( + $eventNames = [ 'workflow.guard', 'workflow.leave', 'workflow.transition', 'workflow.enter', 'workflow.entered', 'workflow.announce', - ); + ]; foreach ($eventNames as $eventName) { $dispatcher->addListener($eventName, $assertWorkflowName); @@ -466,20 +466,20 @@ public function testEventName() public function testMarkingStateOnApplyWithEventDispatcher() { - $definition = new Definition(range('a', 'f'), array(new Transition('t', range('a', 'c'), range('d', 'f')))); + $definition = new Definition(range('a', 'f'), [new Transition('t', range('a', 'c'), range('d', 'f'))]); $subject = new \stdClass(); - $subject->marking = array('a' => 1, 'b' => 1, 'c' => 1); + $subject->marking = ['a' => 1, 'b' => 1, 'c' => 1]; $dispatcher = new EventDispatcher(); $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $dispatcher, 'test'); $assertInitialState = function (Event $event) { - $this->assertEquals(new Marking(array('a' => 1, 'b' => 1, 'c' => 1)), $event->getMarking()); + $this->assertEquals(new Marking(['a' => 1, 'b' => 1, 'c' => 1]), $event->getMarking()); }; $assertTransitionState = function (Event $event) { - $this->assertEquals(new Marking(array()), $event->getMarking()); + $this->assertEquals(new Marking([]), $event->getMarking()); }; $dispatcher->addListener('workflow.leave', $assertInitialState); @@ -512,13 +512,13 @@ public function testGetEnabledTransitions() $this->assertEmpty($workflow->getEnabledTransitions($subject)); - $subject->marking = array('d' => 1); + $subject->marking = ['d' => 1]; $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(2, $transitions); $this->assertSame('t3', $transitions[0]->getName()); $this->assertSame('t4', $transitions[1]->getName()); - $subject->marking = array('c' => 1, 'e' => 1); + $subject->marking = ['c' => 1, 'e' => 1]; $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(1, $transitions); $this->assertSame('t5', $transitions[0]->getName()); @@ -535,7 +535,7 @@ public function testGetEnabledTransitionsWithSameNameTransition() $this->assertCount(1, $transitions); $this->assertSame('a_to_bc', $transitions[0]->getName()); - $subject->marking = array('b' => 1, 'c' => 1); + $subject->marking = ['b' => 1, 'c' => 1]; $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(3, $transitions); $this->assertSame('b_to_c', $transitions[0]->getName()); @@ -546,7 +546,7 @@ public function testGetEnabledTransitionsWithSameNameTransition() class EventDispatcherMock implements \Symfony\Component\EventDispatcher\EventDispatcherInterface { - public $dispatchedEvents = array(); + public $dispatchedEvents = []; public function dispatch($eventName, \Symfony\Component\EventDispatcher\Event $event = null) { From 5aa0967f9f0ab803ededefb040d48a0ebc7a27a6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 16 Jan 2019 23:13:51 +0100 Subject: [PATCH 059/495] fixed CS --- src/Symfony/Component/BrowserKit/Client.php | 6 +-- .../Debug/Tests/DebugClassLoaderTest.php | 10 ++-- .../DependencyInjection/Dumper/PhpDumper.php | 46 +++++++++---------- .../Fixtures/php/services_default_env.php | 20 ++++---- .../Component/Routing/RouteCompiler.php | 2 +- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index 461f5f5e54778..307c3b02520dc 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -313,10 +313,10 @@ public function clickLink(string $linkText): Crawler * * @return Crawler */ - public function submit(Form $form, array $values = []/*, array $serverParameters = array()*/) + public function submit(Form $form, array $values = []/*, array $serverParameters = []*/) { if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { - @trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = array()" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + @trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); } $form->setValues($values); @@ -330,7 +330,7 @@ public function submit(Form $form, array $values = []/*, array $serverParameters * uses it to submit the given form field values. * * @param string $button The text content, id, value or name of the form
LocaleDomainLocaleDomain Times used Message ID Message Preview
{{ message.locale }} {{ message.domain }} {{ message.count }}
+ diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index e18919c31ff9d..b5b4ce8d94986 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -136,6 +136,10 @@ var row = document.createElement('tr'); request.DOMNode = row; + var requestNumberCell = document.createElement('td'); + requestNumberCell.textContent = index + 1; + row.appendChild(requestNumberCell); + var profilerCell = document.createElement('td'); profilerCell.textContent = 'n/a'; row.appendChild(profilerCell); From 36c5df4589cfce22ab7dead0303a7eb1b146ff6d Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 8 Feb 2019 09:29:15 +0100 Subject: [PATCH 106/495] [SecurityBundle] Deprecate the normalization of the cookie names --- UPGRADE-5.0.md | 9 ++++++-- .../Bundle/SecurityBundle/CHANGELOG.md | 14 +++++++++--- .../DependencyInjection/MainConfiguration.php | 17 ++++++++++++++ .../CompleteConfigurationTest.php | 14 ++++++++++++ .../Fixtures/php/logout_delete_cookies.php | 21 ++++++++++++++++++ .../Fixtures/xml/logout_delete_cookies.xml | 22 +++++++++++++++++++ .../Fixtures/yml/logout_delete_cookies.yml | 15 +++++++++++++ 7 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 58bb2035bc550..f576c87890532 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -192,7 +192,7 @@ HttpKernel * The `Kernel::getRootDir()` and the `kernel.root_dir` parameter have been removed * The `KernelInterface::getName()` and the `kernel.name` parameter have been removed * Removed the first and second constructor argument of `ConfigDataCollector` - * Removed `ConfigDataCollector::getApplicationName()` + * Removed `ConfigDataCollector::getApplicationName()` * Removed `ConfigDataCollector::getApplicationVersion()` Monolog @@ -278,6 +278,11 @@ SecurityBundle use Guard instead. * The `SimpleFormFactory` and `SimplePreAuthenticationFactory` classes have been removed, use Guard instead. + * The names of the cookies configured in the `logout.delete_cookies` option are + no longer normalized. If any of your cookie names has dashes they won't be + changed to underscores. + Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore). + After: `my-cookie` deletes the `my-cookie` cookie (with a dash). Serializer ---------- @@ -326,5 +331,5 @@ Workflow Yaml ---- - * The parser is now stricter and will throw a `ParseException` when a + * The parser is now stricter and will throw a `ParseException` when a mapping is found inside a multi-line string. diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 812c22eab65eb..84219a99f08d1 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -1,10 +1,18 @@ CHANGELOG ========= +4.3.0 +----- + + * The normalization of the cookie names configured in the `logout.delete_cookies` + option is deprecated and will be disabled in Symfony 5.0. This affects to cookies + with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie` + name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore). + 4.2.0 ----- - * Using the `security.authentication.trust_resolver.anonymous_class` and + * Using the `security.authentication.trust_resolver.anonymous_class` and `security.authentication.trust_resolver.rememberme_class` parameters to define the token classes is deprecated. To use custom tokens extend the existing `Symfony\Component\Security\Core\Authentication\Token\AnonymousToken`. @@ -17,7 +25,7 @@ CHANGELOG * Deprecated the `SimpleFormFactory` and `SimplePreAuthenticationFactory` classes, use Guard instead. * Added `port` in access_control * Added individual voter decisions to the profiler - + 4.1.0 ----- @@ -50,7 +58,7 @@ CHANGELOG * Tagging voters with the `security.voter` tag without implementing the `VoterInterface` on the class is now deprecated and will be removed in 4.0. * [BC BREAK] `FirewallContext::getListeners()` now returns `\Traversable|array` - * added info about called security listeners in profiler + * added info about called security listeners in profiler * Added `logout_on_user_change` to the firewall options. This config item will trigger a logout when the user has changed. Should be set to true to avoid deprecations in the configuration. diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index c8334313a5c61..6b3ba9e8fdbfb 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -218,10 +218,27 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto ->fixXmlConfig('delete_cookie') ->children() ->arrayNode('delete_cookies') + ->normalizeKeys(false) ->beforeNormalization() ->ifTrue(function ($v) { return \is_array($v) && \is_int(key($v)); }) ->then(function ($v) { return array_map(function ($v) { return ['name' => $v]; }, $v); }) ->end() + ->beforeNormalization() + ->ifArray()->then(function ($v) { + foreach ($v as $originalName => $cookieConfig) { + if (false !== strpos($originalName, '-')) { + $normalizedName = str_replace('-', '_', $originalName); + @trigger_error(sprintf('Normalization of cookie names is deprecated since Symfony 4.3. Starting from Symfony 5.0, the "%s" cookie configured in "logout.delete_cookies" will delete the "%s" cookie instead of the "%s" cookie.', $originalName, $originalName, $normalizedName), E_USER_DEPRECATED); + + // normalize cookie names manually for BC reasons. Remove it in Symfony 5.0. + $v[$normalizedName] = $cookieConfig; + unset($v[$originalName]); + } + } + + return $v; + }) + ->end() ->useAttributeAsKey('name') ->prototype('array') ->children() diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index c2511ff280d5f..f9102edfb07bf 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -506,6 +506,20 @@ public function testSimpleAuth() ]], $listeners); } + /** + * @group legacy + * @expectedDeprecation Normalization of cookie names is deprecated since Symfony 4.3. Starting from Symfony 5.0, the "cookie1-name" cookie configured in "logout.delete_cookies" will delete the "cookie1-name" cookie instead of the "cookie1_name" cookie. + * @expectedDeprecation Normalization of cookie names is deprecated since Symfony 4.3. Starting from Symfony 5.0, the "cookie3-long_name" cookie configured in "logout.delete_cookies" will delete the "cookie3-long_name" cookie instead of the "cookie3_long_name" cookie. + */ + public function testLogoutDeleteCookieNamesNormalization() + { + $container = $this->getContainer('logout_delete_cookies'); + $cookiesToDelete = $container->getDefinition('security.logout.handler.cookie_clearing.main')->getArgument(0); + $expectedCookieNames = ['cookie2_name', 'cookie1_name', 'cookie3_long_name']; + + $this->assertSame($expectedCookieNames, array_keys($cookiesToDelete)); + } + protected function getContainer($file) { $file .= '.'.$this->getFileExtension(); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php new file mode 100644 index 0000000000000..8ffe12e3eb929 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/logout_delete_cookies.php @@ -0,0 +1,21 @@ +loadFromExtension('security', [ + 'providers' => [ + 'default' => ['id' => 'foo'], + ], + + 'firewalls' => [ + 'main' => [ + 'provider' => 'default', + 'form_login' => true, + 'logout' => [ + 'delete_cookies' => [ + 'cookie1-name' => true, + 'cookie2_name' => true, + 'cookie3-long_name' => ['path' => '/'], + ], + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml new file mode 100644 index 0000000000000..3243650c3294a --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml new file mode 100644 index 0000000000000..09bea8c13ab37 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/logout_delete_cookies.yml @@ -0,0 +1,15 @@ +security: + providers: + default: + id: foo + + firewalls: + main: + provider: default + form_login: true + logout: + delete_cookies: + cookie1-name: ~ + cookie2_name: ~ + cookie3-long_name: + path: '/' From b3f3c5361f2b07100624fa9ce5b8816449d410af Mon Sep 17 00:00:00 2001 From: Webnet team Date: Fri, 29 Jun 2018 15:37:37 +0200 Subject: [PATCH 107/495] [Form] Add label_translation_parameters, help_translation_parameters and attr_translation_parameters options to base form type --- .../Tests/Form/Type/EntityTypeTest.php | 174 ++++++++++++++++++ src/Symfony/Bridge/Doctrine/composer.json | 3 +- .../views/Form/bootstrap_3_layout.html.twig | 4 +- .../views/Form/bootstrap_4_layout.html.twig | 6 +- .../views/Form/form_div_layout.html.twig | 10 +- .../Extension/Fixtures/StubTranslator.php | 2 +- .../templates/form/custom_widgets.html.twig | 4 +- .../Resources/views/Form/attributes.html.php | 2 +- .../views/Form/button_widget.html.php | 2 +- .../Resources/views/Form/form_help.html.php | 2 +- .../Resources/views/Form/form_label.html.php | 2 +- .../Helper/Fixtures/StubTranslator.php | 2 +- src/Symfony/Component/Form/CHANGELOG.md | 24 +++ .../Form/Extension/Core/Type/BaseType.php | 9 + .../Form/Extension/Core/Type/FormType.php | 5 + .../Form/Tests/AbstractLayoutTest.php | 76 ++++++++ .../Extension/Core/Type/BaseTypeTest.php | 96 ++++++++++ .../Extension/Core/Type/FormTypeTest.php | 48 +++++ .../Descriptor/resolved_form_type_1.json | 3 + .../Descriptor/resolved_form_type_1.txt | 61 +++--- .../Descriptor/resolved_form_type_2.json | 3 + .../Descriptor/resolved_form_type_2.txt | 67 +++---- 22 files changed, 525 insertions(+), 80 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 2869c2b804c4c..42e210400e4d6 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -1366,6 +1366,180 @@ public function testDefaultTranslationDomain() $this->assertNull($view['child']->vars['translation_domain']); } + public function testPassLabelTranslationParametersToView() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'label_translation_parameters' => ['%param%' => 'value'], + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->createView(); + + $this->assertSame(['%param%' => 'value'], $view->vars['label_translation_parameters']); + } + + public function testPassHelpTranslationParametersToView() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'help_translation_parameters' => ['%param%' => 'value'], + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->createView(); + + $this->assertSame(['%param%' => 'value'], $view->vars['help_translation_parameters']); + } + + public function testPassAttrTranslationParametersToView() + { + $view = $this->factory->create(static::TESTED_TYPE, null, [ + 'attr_translation_parameters' => ['%param%' => 'value'], + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->createView(); + + $this->assertSame(['%param%' => 'value'], $view->vars['attr_translation_parameters']); + } + + public function testInheritLabelTranslationParametersFromParent() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'label_translation_parameters' => ['%param%' => 'value'], + ]) + ->add('child', static::TESTED_TYPE, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%param%' => 'value'], $view['child']->vars['label_translation_parameters']); + } + + public function testInheritHelpTranslationParametersFromParent() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'help_translation_parameters' => ['%param%' => 'value'], + ]) + ->add('child', static::TESTED_TYPE, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%param%' => 'value'], $view['child']->vars['help_translation_parameters']); + } + + public function testInheritAttrTranslationParametersFromParent() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'attr_translation_parameters' => ['%param%' => 'value'], + ]) + ->add('child', static::TESTED_TYPE, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%param%' => 'value'], $view['child']->vars['attr_translation_parameters']); + } + + public function testPreferOwnLabelTranslationParameters() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'label_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], + ]) + ->add('child', static::TESTED_TYPE, [ + 'label_translation_parameters' => ['%override_param%' => 'child_value'], + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['label_translation_parameters']); + } + + public function testPreferOwnHelpTranslationParameters() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'help_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], + ]) + ->add('child', static::TESTED_TYPE, [ + 'help_translation_parameters' => ['%override_param%' => 'child_value'], + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['help_translation_parameters']); + } + + public function testPreferOwnAttrTranslationParameters() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'attr_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], + ]) + ->add('child', static::TESTED_TYPE, [ + 'attr_translation_parameters' => ['%override_param%' => 'child_value'], + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['attr_translation_parameters']); + } + + public function testDefaultLabelTranslationParameters() + { + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) + ->add('child', static::TESTED_TYPE, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals([], $view['child']->vars['label_translation_parameters']); + } + + public function testDefaultHelpTranslationParameters() + { + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) + ->add('child', static::TESTED_TYPE, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals([], $view['child']->vars['help_translation_parameters']); + } + + public function testDefaultAttrTranslationParameters() + { + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) + ->add('child', static::TESTED_TYPE, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + ]) + ->getForm() + ->createView(); + + $this->assertEquals([], $view['child']->vars['attr_translation_parameters']); + } + public function testPassLabelToView() { $view = $this->factory->createNamed('__test___field', static::TESTED_TYPE, null, [ diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 7c0bed953db84..849d2069adb98 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -27,7 +27,7 @@ "require-dev": { "symfony/stopwatch": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", - "symfony/form": "~3.4|~4.0", + "symfony/form": "~4.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/messenger": "~4.2", "symfony/property-access": "~3.4|~4.0", @@ -47,6 +47,7 @@ "conflict": { "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/dependency-injection": "<3.4", + "symfony/form": "<4.3", "symfony/messenger": "<4.2" }, "suggest": { diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig index eaa61a7cfedfc..95f371b567edd 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig @@ -187,9 +187,9 @@ {%- endif -%} {%- else -%} {%- if help_html is same as(false) -%} - {{- help|trans({}, translation_domain) -}} + {{- help|trans(help_translation_parameters, translation_domain) -}} {%- else -%} - {{- help|trans({}, translation_domain)|raw -}} + {{- help|trans(help_translation_parameters, translation_domain)|raw -}} {%- endif -%} {%- endif -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig index 1b79dbcac349b..0b301b42cc4ad 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig @@ -219,7 +219,7 @@ {% set label = name|humanize %} {%- endif -%} {%- endif -%} - <{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>{{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }}{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %} + <{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}>{{ translation_domain is same as(false) ? label : label|trans(label_translation_parameters, translation_domain) }}{% block form_label_errors %}{{- form_errors(form) -}}{% endblock form_label_errors %} {%- else -%} {%- if errors|length > 0 -%}
@@ -312,9 +312,9 @@ {%- endif -%} {%- else -%} {%- if help_html is same as(false) -%} - {{- help|trans({}, translation_domain) -}} + {{- help|trans(help_translation_parameters, translation_domain) -}} {%- else -%} - {{- help|trans({}, translation_domain)|raw -}} + {{- help|trans(help_translation_parameters, translation_domain)|raw -}} {%- endif -%} {%- endif -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 4013e0021a54b..234faab533d61 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -232,7 +232,7 @@ {% set label = name|humanize %} {%- endif -%} {%- endif -%} - + {%- endblock button_widget -%} {%- block submit_widget -%} @@ -279,7 +279,7 @@ {%- if translation_domain is same as(false) -%} {{- label -}} {%- else -%} - {{- label|trans({}, translation_domain) -}} + {{- label|trans(label_translation_parameters, translation_domain) -}} {%- endif -%} {%- endif -%} @@ -301,9 +301,9 @@ {%- endif -%} {%- else -%} {%- if help_html is same as(false) -%} - {{- help|trans({}, translation_domain) -}} + {{- help|trans(help_translation_parameters, translation_domain) -}} {%- else -%} - {{- help|trans({}, translation_domain)|raw -}} + {{- help|trans(help_translation_parameters, translation_domain)|raw -}} {%- endif -%} {%- endif -%}

@@ -433,7 +433,7 @@ {%- for attrname, attrvalue in attr -%} {{- " " -}} {%- if attrname in ['placeholder', 'title'] -%} - {{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans({}, translation_domain) }}" + {{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans(attr_translation_parameters, translation_domain) }}" {%- elseif attrvalue is same as(true) -%} {{- attrname }}="{{ attrname }}" {%- elseif attrvalue is not same as(false) -%} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php b/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php index 55c0dfa18a1e6..9abd707b40e0e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/StubTranslator.php @@ -17,6 +17,6 @@ class StubTranslator implements TranslatorInterface { public function trans($id, array $parameters = [], $domain = null, $locale = null) { - return '[trans]'.$id.'[/trans]'; + return '[trans]'.strtr($id, $parameters).'[/trans]'; } } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/templates/form/custom_widgets.html.twig b/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/templates/form/custom_widgets.html.twig index 4eda8d76d3736..9375051e47fbb 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/templates/form/custom_widgets.html.twig +++ b/src/Symfony/Bridge/Twig/Tests/Extension/Fixtures/templates/form/custom_widgets.html.twig @@ -11,7 +11,7 @@ {% if label is empty %} {% set label = name|humanize %} {% endif %} - + {% endspaceless %} {% endblock _names_entry_label %} @@ -20,6 +20,6 @@ {% if label is empty %} {% set label = name|humanize %} {% endif %} - + {% endspaceless %} {% endblock _name_c_entry_label %} diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/attributes.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/attributes.html.php index dbed8eff722ee..047d342a8d5c3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/attributes.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/attributes.html.php @@ -1,6 +1,6 @@ $v): ?> -escape($k), $view->escape(false !== $translation_domain ? $view['translator']->trans($v, [], $translation_domain) : $v)) ?> +escape($k), $view->escape(false !== $translation_domain ? $view['translator']->trans($v, $attr_translation_parameters, $translation_domain) : $v)) ?> escape($k), $view->escape($k)) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php index 2a10aa0f415b0..42a7c5db02d8f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/button_widget.html.php @@ -1,4 +1,4 @@ $name, '%id%' => $id]) : $view['form']->humanize($name); } ?> - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_help.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_help.html.php index fc4b24726cf27..9e3ed9b6c6e44 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_help.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_help.html.php @@ -1,6 +1,6 @@ - trans($help, [], $translation_domain) : $help; ?> + trans($help, $help_translation_parameters, $translation_domain) : $help; ?> escape($help) : $help ?>

block($form, 'attributes', ['attr' => $help_attr]); ?>>

diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php index 8e8e5b94983bb..b3465042efddd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/form_label.html.php @@ -4,5 +4,5 @@ $name, '%id%' => $id]) : $view['form']->humanize($name); } ?> -block($form, 'attributes', ['attr' => $label_attr]); } ?>>escape(false !== $translation_domain ? $view['translator']->trans($label, [], $translation_domain) : $label) ?> +block($form, 'attributes', ['attr' => $label_attr]); } ?>>escape(false !== $translation_domain ? $view['translator']->trans($label, $label_translation_parameters, $translation_domain) : $label) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Fixtures/StubTranslator.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Fixtures/StubTranslator.php index 9175b371156f5..402b3a886c74b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Fixtures/StubTranslator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Fixtures/StubTranslator.php @@ -17,6 +17,6 @@ class StubTranslator implements TranslatorInterface { public function trans($id, array $parameters = [], $domain = null, $locale = null) { - return '[trans]'.$id.'[/trans]'; + return '[trans]'.strtr($id, $parameters).'[/trans]'; } } diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index b6d83d613b01e..142a1d92fa85e 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -8,6 +8,30 @@ CHANGELOG option is set to `single_text` * added `block_prefix` option to `BaseType`. * added `help_html` option to display the `help` text as HTML. + * added `label_translation_parameters`, `attr_translation_parameters`, `help_translation_parameters` options + to `FormType` to pass translation parameters to form labels, attributes (`placeholder` and `title`) and help text respectively. + The passed parameters will replace placeholders in translation messages. + + ```php + class OrderType extends AbstractType + { + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add('comment', TextType::class, [ + 'label' => 'Comment to the order to %company%', + 'label_translation_parameters' => [ + '%company%' => 'Acme', + ], + 'help' => 'The address of the %company% is %address%', + 'help_translation_parameters' => [ + '%company%' => 'Acme Ltd.', + '%address%' => '4 Form street, Symfonyville', + ], + ]) + } + } + ``` + 4.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php index cac3ae2311ec1..f6c222a1be376 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php @@ -44,6 +44,8 @@ public function buildView(FormView $view, FormInterface $form, array $options) $name = $form->getName(); $blockName = $options['block_name'] ?: $form->getName(); $translationDomain = $options['translation_domain']; + $labelTranslationParameters = $options['label_translation_parameters']; + $attrTranslationParameters = $options['attr_translation_parameters']; $labelFormat = $options['label_format']; if ($view->parent) { @@ -61,6 +63,9 @@ public function buildView(FormView $view, FormInterface $form, array $options) $translationDomain = $view->parent->vars['translation_domain']; } + $labelTranslationParameters = array_merge($view->parent->vars['label_translation_parameters'], $labelTranslationParameters); + $attrTranslationParameters = array_merge($view->parent->vars['attr_translation_parameters'], $attrTranslationParameters); + if (!$labelFormat) { $labelFormat = $view->parent->vars['label_format']; } @@ -97,6 +102,8 @@ public function buildView(FormView $view, FormInterface $form, array $options) 'block_prefixes' => $blockPrefixes, 'unique_block_prefix' => $uniqueBlockPrefix, 'translation_domain' => $translationDomain, + 'label_translation_parameters' => $labelTranslationParameters, + 'attr_translation_parameters' => $attrTranslationParameters, // Using the block name here speeds up performance in collection // forms, where each entry has the same full block name. // Including the type is important too, because if rows of a @@ -118,6 +125,8 @@ public function configureOptions(OptionsResolver $resolver) 'disabled' => false, 'label' => null, 'label_format' => null, + 'label_translation_parameters' => [], + 'attr_translation_parameters' => [], 'attr' => [], 'translation_domain' => null, 'auto_initialize' => true, diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 3934416ff6dbf..208d44f5fac0c 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -68,6 +68,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) parent::buildView($view, $form, $options); $name = $form->getName(); + $helpTranslationParameters = $options['help_translation_parameters']; if ($view->parent) { if ('' === $name) { @@ -78,6 +79,8 @@ public function buildView(FormView $view, FormInterface $form, array $options) if (!isset($view->vars['attr']['readonly']) && isset($view->parent->vars['attr']['readonly']) && false !== $view->parent->vars['attr']['readonly']) { $view->vars['attr']['readonly'] = true; } + + $helpTranslationParameters = array_merge($view->parent->vars['help_translation_parameters'], $helpTranslationParameters); } $formConfig = $form->getConfig(); @@ -92,6 +95,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) 'help' => $options['help'], 'help_attr' => $options['help_attr'], 'help_html' => $options['help_html'], + 'help_translation_parameters' => $helpTranslationParameters, 'compound' => $formConfig->getCompound(), 'method' => $formConfig->getMethod(), 'action' => $formConfig->getAction(), @@ -185,6 +189,7 @@ public function configureOptions(OptionsResolver $resolver) 'help' => null, 'help_attr' => [], 'help_html' => false, + 'help_translation_parameters' => [], ]); $resolver->setAllowedTypes('label_attr', 'array'); diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 24d8dbcf94baf..43ff2ded12868 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -2572,6 +2572,82 @@ public function testColor() [@type="color"] [@name="name"] [@value="#0000ff"] +' + ); + } + + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] ' ); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php index 92eff38669ff2..5bd97257a6427 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php @@ -119,6 +119,102 @@ public function testDefaultTranslationDomain() $this->assertNull($view['child']->vars['translation_domain']); } + public function testPassLabelTranslationParametersToView() + { + $view = $this->factory->create($this->getTestedType(), null, [ + 'label_translation_parameters' => ['%param%' => 'value'], + ]) + ->createView(); + + $this->assertSame(['%param%' => 'value'], $view->vars['label_translation_parameters']); + } + + public function testPassAttrTranslationParametersToView() + { + $view = $this->factory->create($this->getTestedType(), null, [ + 'attr_translation_parameters' => ['%param%' => 'value'], + ]) + ->createView(); + + $this->assertSame(['%param%' => 'value'], $view->vars['attr_translation_parameters']); + } + + public function testInheritLabelTranslationParametersFromParent() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'label_translation_parameters' => ['%param%' => 'value'], + ]) + ->add('child', $this->getTestedType()) + ->getForm() + ->createView(); + + $this->assertEquals(['%param%' => 'value'], $view['child']->vars['label_translation_parameters']); + } + + public function testInheritAttrTranslationParametersFromParent() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'attr_translation_parameters' => ['%param%' => 'value'], + ]) + ->add('child', $this->getTestedType()) + ->getForm() + ->createView(); + + $this->assertEquals(['%param%' => 'value'], $view['child']->vars['attr_translation_parameters']); + } + + public function testPreferOwnLabelTranslationParameters() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'label_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], + ]) + ->add('child', $this->getTestedType(), [ + 'label_translation_parameters' => ['%override_param%' => 'child_value'], + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['label_translation_parameters']); + } + + public function testPreferOwnAttrTranslationParameters() + { + $view = $this->factory + ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ + 'attr_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], + ]) + ->add('child', $this->getTestedType(), [ + 'attr_translation_parameters' => ['%override_param%' => 'child_value'], + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['attr_translation_parameters']); + } + + public function testDefaultLabelTranslationParameters() + { + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) + ->add('child', $this->getTestedType()) + ->getForm() + ->createView(); + + $this->assertEquals([], $view['child']->vars['label_translation_parameters']); + } + + public function testDefaultAttrTranslationParameters() + { + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) + ->add('child', $this->getTestedType()) + ->getForm() + ->createView(); + + $this->assertEquals([], $view['child']->vars['attr_translation_parameters']); + } + public function testPassLabelToView() { $view = $this->factory->createNamed('__test___field', $this->getTestedType(), null, ['label' => 'My label']) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 47e7ae66beb9b..0c7f97dc1e744 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -651,4 +651,52 @@ public function testPassBlockPrefixToViewWithParent() $this->assertSame(['form', 'child', '_parent_child'], $view['child']->vars['block_prefixes']); } + + public function testDefaultHelpTranslationParameters() + { + $view = $this->factory->createNamedBuilder('parent', self::TESTED_TYPE) + ->add('child', $this->getTestedType()) + ->getForm() + ->createView(); + + $this->assertEquals([], $view['child']->vars['help_translation_parameters']); + } + + public function testPassHelpTranslationParametersToView() + { + $view = $this->factory->create($this->getTestedType(), null, [ + 'help_translation_parameters' => ['%param%' => 'value'], + ]) + ->createView(); + + $this->assertSame(['%param%' => 'value'], $view->vars['help_translation_parameters']); + } + + public function testInheritHelpTranslationParametersFromParent() + { + $view = $this->factory + ->createNamedBuilder('parent', self::TESTED_TYPE, null, [ + 'help_translation_parameters' => ['%param%' => 'value'], + ]) + ->add('child', $this->getTestedType()) + ->getForm() + ->createView(); + + $this->assertEquals(['%param%' => 'value'], $view['child']->vars['help_translation_parameters']); + } + + public function testPreferOwnHelpTranslationParameters() + { + $view = $this->factory + ->createNamedBuilder('parent', self::TESTED_TYPE, null, [ + 'help_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], + ]) + ->add('child', $this->getTestedType(), [ + 'help_translation_parameters' => ['%override_param%' => 'child_value'], + ]) + ->getForm() + ->createView(); + + $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['help_translation_parameters']); + } } diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json index c0f335f27ea20..36d74742a7994 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.json @@ -30,6 +30,7 @@ "action", "allow_file_upload", "attr", + "attr_translation_parameters", "auto_initialize", "block_name", "block_prefix", @@ -39,10 +40,12 @@ "help", "help_attr", "help_html", + "help_translation_parameters", "inherit_data", "label", "label_attr", "label_format", + "label_translation_parameters", "mapped", "method", "post_max_size_message", diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt index 49fba719da4ca..ed393b7e7f98e 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_1.txt @@ -2,35 +2,38 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (Block prefix: "choice") ============================================================================== - --------------------------- -------------------- ------------------------- ----------------------- - Options Overridden options Parent options Extension options - --------------------------- -------------------- ------------------------- ----------------------- - choice_attr FormType FormType FormTypeCsrfExtension - choice_label -------------------- ------------------------- ----------------------- - choice_loader compound action csrf_field_name - choice_name data_class allow_file_upload csrf_message - choice_translation_domain empty_data attr csrf_protection - choice_value error_bubbling auto_initialize csrf_token_id - choices trim block_name csrf_token_manager - expanded block_prefix - group_by by_reference - multiple data - placeholder disabled - preferred_choices help - help_attr - help_html - inherit_data - label - label_attr - label_format - mapped - method - post_max_size_message - property_path - required - translation_domain - upload_max_size_message - --------------------------- -------------------- ------------------------- ----------------------- + --------------------------- -------------------- ------------------------------ ----------------------- + Options Overridden options Parent options Extension options + --------------------------- -------------------- ------------------------------ ----------------------- + choice_attr FormType FormType FormTypeCsrfExtension + choice_label -------------------- ------------------------------ ----------------------- + choice_loader compound action csrf_field_name + choice_name data_class allow_file_upload csrf_message + choice_translation_domain empty_data attr csrf_protection + choice_value error_bubbling attr_translation_parameters csrf_token_id + choices trim auto_initialize csrf_token_manager + expanded block_name + group_by block_prefix + multiple by_reference + placeholder data + preferred_choices disabled + help + help_attr + help_html + help_translation_parameters + inherit_data + label + label_attr + label_format + label_translation_parameters + mapped + method + post_max_size_message + property_path + required + translation_domain + upload_max_size_message + --------------------------- -------------------- ------------------------------ ----------------------- Parent types ------------ diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json index 49fcd8bd1335e..149e73da13709 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.json @@ -6,6 +6,7 @@ "action", "allow_file_upload", "attr", + "attr_translation_parameters", "auto_initialize", "block_name", "block_prefix", @@ -19,10 +20,12 @@ "help", "help_attr", "help_html", + "help_translation_parameters", "inherit_data", "label", "label_attr", "label_format", + "label_translation_parameters", "mapped", "method", "post_max_size_message", diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt index 732c0d2f7c413..79a97f23d3515 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/resolved_form_type_2.txt @@ -2,36 +2,39 @@ Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form") ========================================================================== - ------------------------- - Options - ------------------------- - action - allow_file_upload - attr - auto_initialize - block_name - block_prefix - by_reference - compound - data - data_class - disabled - empty_data - error_bubbling - help - help_attr - help_html - inherit_data - label - label_attr - label_format - mapped - method - post_max_size_message - property_path - required - translation_domain - trim - upload_max_size_message - ------------------------- + ------------------------------ + Options + ------------------------------ + action + allow_file_upload + attr + attr_translation_parameters + auto_initialize + block_name + block_prefix + by_reference + compound + data + data_class + disabled + empty_data + error_bubbling + help + help_attr + help_html + help_translation_parameters + inherit_data + label + label_attr + label_format + label_translation_parameters + mapped + method + post_max_size_message + property_path + required + translation_domain + trim + upload_max_size_message + ------------------------------ From 131febc7be8392d408a1afb8798d40e52877308b Mon Sep 17 00:00:00 2001 From: zairig imad Date: Sun, 16 Sep 2018 01:09:38 +0200 Subject: [PATCH 108/495] [Validator] Add new json Validator --- src/Symfony/Component/Validator/CHANGELOG.md | 3 +- .../Component/Validator/Constraints/Json.php | 31 ++++++++ .../Validator/Constraints/JsonValidator.php | 51 ++++++++++++ .../Resources/translations/validators.en.xlf | 4 + .../Resources/translations/validators.fr.xlf | 4 + .../Tests/Constraints/JsonValidatorTest.php | 77 +++++++++++++++++++ 6 files changed, 169 insertions(+), 1 deletion(-) create mode 100755 src/Symfony/Component/Validator/Constraints/Json.php create mode 100755 src/Symfony/Component/Validator/Constraints/JsonValidator.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 43ead5b182ba7..509f3317672b6 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -7,7 +7,8 @@ CHANGELOG * added options `iban` and `ibanPropertyPath` to Bic constraint * added UATP cards support to `CardSchemeValidator` * added option `allowNull` to NotBlank constraint - + * added `Json` constraint + 4.2.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Json.php b/src/Symfony/Component/Validator/Constraints/Json.php new file mode 100755 index 0000000000000..74d55f775d7a2 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Json.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Imad ZAIRIG + */ +class Json extends Constraint +{ + const INVALID_JSON_ERROR = '0789c8ad-2d2b-49a4-8356-e2ce63998504'; + + protected static $errorNames = [ + self::INVALID_JSON_ERROR => 'INVALID_JSON_ERROR', + ]; + + public $message = 'This value should be valid JSON.'; +} diff --git a/src/Symfony/Component/Validator/Constraints/JsonValidator.php b/src/Symfony/Component/Validator/Constraints/JsonValidator.php new file mode 100755 index 0000000000000..850bbfbcbf908 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/JsonValidator.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; + +/** + * @author Imad ZAIRIG + */ +class JsonValidator extends ConstraintValidator +{ + /** + * {@inheritdoc} + */ + public function validate($value, Constraint $constraint) + { + if (!$constraint instanceof Json) { + throw new UnexpectedTypeException($constraint, Json::class); + } + + if (null === $value || '' === $value) { + return; + } + + if (!is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { + throw new UnexpectedTypeException($value, 'string'); + } + + $value = (string) $value; + + json_decode($value); + + if (JSON_ERROR_NONE !== json_last_error()) { + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Json::INVALID_JSON_ERROR) + ->addViolation(); + } + } +} diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 30e6804c7b83e..bb997332aecb6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -330,6 +330,10 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + + This value should be valid JSON. + This value should be valid JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index 67441127cda1a..bdee03a0004c2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -330,6 +330,10 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Ce BIC n'est pas associé à l'IBAN {{ iban }}. + + This value should be valid JSON. + Cette valeur doit être un JSON valide. + diff --git a/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php new file mode 100644 index 0000000000000..6c94c1d8df6cc --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/JsonValidatorTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Json; +use Symfony\Component\Validator\Constraints\JsonValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; + +class JsonValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator() + { + return new JsonValidator(); + } + + /** + * @dataProvider getValidValues + */ + public function testJsonIsValid($value) + { + $this->validator->validate($value, new Json()); + + $this->assertNoViolation(); + } + + /** + * @dataProvider getInvalidValues + */ + public function testInvalidValues($value) + { + $constraint = new Json([ + 'message' => 'myMessageTest', + ]); + + $this->validator->validate($value, $constraint); + + $this->buildViolation('myMessageTest') + ->setParameter('{{ value }}', '"'.$value.'"') + ->setCode(Json::INVALID_JSON_ERROR) + ->assertRaised(); + } + + public function getValidValues() + { + return [ + ['{"planet":"earth", "country": "Morocco","city": "Rabat" ,"postcode" : 10160, "is_great": true, + "img" : null, "area": 118.5, "foo": 15 }'], + [null], + [''], + ['"null"'], + ['null'], + ['"string"'], + ['1'], + ['true'], + [1], + ]; + } + + public function getInvalidValues() + { + return [ + ['{"foo": 3 "bar": 4}'], + ['{"foo": 3 ,"bar": 4'], + ['{foo": 3, "bar": 4}'], + ['foo'], + ]; + } +} From 21b8efc44cab711db7a16b63bbc9c2ce5bcf6b52 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 13 Feb 2019 08:36:40 +0100 Subject: [PATCH 109/495] fixed typo --- .../Validator/Resources/translations/validators.en.xlf | 2 +- .../Validator/Resources/translations/validators.fr.xlf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index bb997332aecb6..465ad220d8790 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -330,7 +330,7 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. - + This value should be valid JSON. This value should be valid JSON. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index 6960a9d55ef49..7b1799d53315c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -330,7 +330,7 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Ce code d'identification d'entreprise (BIC) n'est pas associé à l'IBAN {{ iban }}. - + This value should be valid JSON. Cette valeur doit être un JSON valide. From 6f9fdaf7e4a218a88095a102e603bfc3cfd7d52d Mon Sep 17 00:00:00 2001 From: "fedor.f" Date: Wed, 13 Feb 2019 11:30:45 +0200 Subject: [PATCH 110/495] publish message with custom queue options : flags | attributes --- .../Tests/Transport/AmqpExt/ConnectionTest.php | 18 ++++++++++++++++++ .../Messenger/Transport/AmqpExt/Connection.php | 5 ++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index b7d1be4453629..b459c163315fe 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -233,6 +233,24 @@ public function testItCanDisableTheSetup() $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key&auto-setup=false', [], true, $factory); $connection->publish('body'); } + + public function testPublishWithQueueOptions() + { + $factory = new TestAmqpFactory( + $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), + $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), + $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), + $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + ); + $headers = [ + 'type' => '*', + ]; + $amqpExchange->expects($this->once())->method('publish') + ->with('body', null, 1, ['delivery_mode' => 2, 'headers' => $headers]); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[attributes][delivery_mode]=2&queue[flags]=1', [], true, $factory); + $connection->publish('body', $headers); + } } class TestAmqpFactory extends AmqpFactory diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index cffc49df29c78..d56b105a2b103 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -133,7 +133,10 @@ public function publish(string $body, array $headers = []): void $this->setup(); } - $this->exchange()->publish($body, $this->queueConfiguration['routing_key'] ?? null, AMQP_NOPARAM, ['headers' => $headers]); + $flags = $this->queueConfiguration['flags'] ?? AMQP_NOPARAM; + $attributes = array_merge_recursive($this->queueConfiguration['attributes'] ?? [], ['headers' => $headers]); + + $this->exchange()->publish($body, $this->queueConfiguration['routing_key'] ?? null, $flags, $attributes); } /** From 4532319520e6e73b7933d8eab3cf8fa5623c6603 Mon Sep 17 00:00:00 2001 From: "fedor.f" Date: Wed, 13 Feb 2019 14:53:10 +0200 Subject: [PATCH 111/495] publish message with custom queue options : update ConnectionTest --- .../Messenger/Tests/Transport/AmqpExt/ConnectionTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index b459c163315fe..d3b11c7a35c3d 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -237,10 +237,10 @@ public function testItCanDisableTheSetup() public function testPublishWithQueueOptions() { $factory = new TestAmqpFactory( - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), - $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), - $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) ); $headers = [ 'type' => '*', From 1a983d07dbd5ef44f262f2ce6263ce2dbd6c9d1d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 13 Feb 2019 19:21:50 +0100 Subject: [PATCH 112/495] undeprecate date formats in single_text widgets --- .../Form/Extension/Core/Type/DateTimeType.php | 6 +++--- .../Tests/Extension/Core/Type/DateTimeTypeTest.php | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php index 4c0bdf203f064..4109c1d7c0111 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php @@ -294,9 +294,9 @@ public function configureOptions(OptionsResolver $resolver) ]); $resolver->setDeprecated('date_format', function (Options $options, $dateFormat) { - if (null !== $dateFormat && 'single_text' === $options['widget']) { - return sprintf('Using the "date_format" option of %s when the "widget" option is set to "single_text" is deprecated since Symfony 4.3 and will lead to an exception in 5.0.', self::class); - //throw new LogicException(sprintf('Cannot use the "date_format" option of the %s when the "widget" option is set to "single_text".', self::class)); + if (null !== $dateFormat && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) { + return sprintf('Using the "date_format" option of %s with an HTML5 date widget is deprecated since Symfony 4.3 and will lead to an exception in 5.0.', self::class); + //throw new LogicException(sprintf('Cannot use the "date_format" option of the %s with an HTML5 date.', self::class)); } return ''; diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php index 4f4966c5f8d2f..ac04761a81555 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php @@ -491,6 +491,18 @@ public function testDontPassHtml5TypeIfNotSingleText() $this->assertArrayNotHasKey('type', $view->vars); } + public function testSingleTextWidgetWithCustomNonHtml5Format() + { + $form = $this->factory->create(static::TESTED_TYPE, new \DateTime('2019-02-13 19:12:13'), [ + 'widget' => 'single_text', + 'date_format' => \IntlDateFormatter::SHORT, + 'format' => null, + ]); + $view = $form->createView(); + + $this->assertSame('2/13/19, 7:12:13 PM', $view->vars['value']); + } + public function testDateTypeChoiceErrorsBubbleUp() { $error = new FormError('Invalid!'); From 1fe359995bb56b14b31df0b2d172a199f47e2b6f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 13 Feb 2019 22:52:06 +0100 Subject: [PATCH 113/495] fix tests --- .../AbstractBootstrap3LayoutTest.php | 76 +++++++++++++++++++ .../Form/Tests/AbstractDivLayoutTest.php | 76 +++++++++++++++++++ .../Form/Tests/AbstractLayoutTest.php | 76 ------------------- .../Form/Tests/AbstractTableLayoutTest.php | 76 +++++++++++++++++++ 4 files changed, 228 insertions(+), 76 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 2d9c79b64132f..0ad7ea34a62ce 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -2670,6 +2670,82 @@ public function testColor() [@name="name"] [@class="my&class form-control"] [@value="#0000ff"] +' + ); + } + + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] ' ); } diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php index ab8444974959d..a95f430de6617 100644 --- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php @@ -931,4 +931,80 @@ public function testWidgetContainerAttributeNameRepeatedIfTrue() // foo="foo" $this->assertContains('
', $html); } + + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] +' + ); + } } diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 7f8d82faae421..de27ee9ef0030 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -2587,82 +2587,6 @@ public function testColor() [@type="color"] [@name="name"] [@value="#0000ff"] -' - ); - } - - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] ' ); } diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php index 6c09ba8ead456..ca96c179b9b83 100644 --- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php @@ -533,4 +533,80 @@ public function testWidgetContainerAttributeNameRepeatedIfTrue() // foo="foo" $this->assertContains('
# Profile Method Type
', $html); } + + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] +' + ); + } } From 9f9b82883289c15ad40cd5db47106548ce7eee52 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Fri, 8 Feb 2019 12:17:48 -0500 Subject: [PATCH 114/495] Added support for PHP files with translation in translation commands --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Command/TranslationDebugCommand.php | 2 +- .../Command/TranslationUpdateCommand.php | 2 +- .../FrameworkBundle/FrameworkBundle.php | 2 + .../TestBundle/Controller/TransController.php | 22 +++ .../TransDebug/TransConstructArgService.php | 29 ++++ .../TransDebug/TransMethodCallsService.php | 29 ++++ .../TransDebug/TransPropertyService.php | 25 +++ .../TransDebug/TransSubscriberService.php | 36 +++++ .../TranslationDebugCommandTest.php | 9 +- .../Functional/app/TransDebug/config.yml | 1 + .../Functional/app/TransDebug/services.yml | 21 +++ .../Component/Translation/CHANGELOG.md | 1 + .../TranslatorPathsPass.php | 144 ++++++++++++++++++ .../TranslationPathsPassTest.php | 89 +++++++++++ .../fixtures/ControllerArguments.php | 16 ++ .../fixtures/ServiceArguments.php | 12 ++ .../fixtures/ServiceMethodCalls.php | 12 ++ .../fixtures/ServiceProperties.php | 8 + .../fixtures/ServiceSubscriber.php | 19 +++ 20 files changed, 476 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/TransController.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransConstructArgService.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransMethodCallsService.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransPropertyService.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransSubscriberService.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/services.yml create mode 100644 src/Symfony/Component/Translation/DependencyInjection/TranslatorPathsPass.php create mode 100644 src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPathsPassTest.php create mode 100644 src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ControllerArguments.php create mode 100644 src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ServiceArguments.php create mode 100644 src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ServiceMethodCalls.php create mode 100644 src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ServiceProperties.php create mode 100644 src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ServiceSubscriber.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 434305545cc1e..4c91ff11bef31 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -16,6 +16,7 @@ CHANGELOG * Added php ini session options `sid_length` and `sid_bits_per_character` to the `session` section of the configuration * Added support for Translator paths, Twig paths in translation commands. + * Added support for PHP files with translations in translation commands. 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php index 57e364d8ffffd..555db678e1a24 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php @@ -346,7 +346,7 @@ private function extractMessages(string $locale, array $transPaths): MessageCata { $extractedCatalogue = new MessageCatalogue($locale); foreach ($transPaths as $path) { - if (is_dir($path)) { + if (is_dir($path) || is_file($path)) { $this->extractor->extract($path, $extractedCatalogue); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 8045176fcc01b..ded71fd60e4bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -207,7 +207,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $errorIo->comment('Parsing templates...'); $this->extractor->setPrefix($input->getOption('prefix')); foreach ($viewsPaths as $path) { - if (is_dir($path)) { + if (is_dir($path) || is_file($path)) { $this->extractor->extract($path, $extractedCatalogue); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 2a561bc19be43..debbc69a676ad 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -51,6 +51,7 @@ use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass; use Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass; use Symfony\Component\Translation\DependencyInjection\TranslatorPass; +use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass; use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass; use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass; use Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass; @@ -103,6 +104,7 @@ public function build(ContainerBuilder $container) // must be registered as late as possible to get access to all Twig paths registered in // twig.template_iterator definition $this->addCompilerPassIfExists($container, TranslatorPass::class, PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); + $this->addCompilerPassIfExists($container, TranslatorPathsPass::class, PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new LoggingTranslatorPass()); $container->addCompilerPass(new AddExpressionLanguageProvidersPass(false)); $this->addCompilerPassIfExists($container, TranslationExtractorPass::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/TransController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/TransController.php new file mode 100644 index 0000000000000..e4127bc17bf37 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/TransController.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class TransController +{ + public function index(TranslatorInterface $translator) + { + $translator->trans('hello_from_controller'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransConstructArgService.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransConstructArgService.php new file mode 100644 index 0000000000000..c4b985e8ee80d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransConstructArgService.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class TransConstructArgService +{ + private $translator; + + public function __construct(TranslatorInterface $translator) + { + $this->translator = $translator; + } + + public function hello(): string + { + return $this->translator->trans('hello_from_construct_arg_service'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransMethodCallsService.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransMethodCallsService.php new file mode 100644 index 0000000000000..66247e56c6175 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransMethodCallsService.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class TransMethodCallsService +{ + private $translator; + + public function setTranslator(TranslatorInterface $translator): void + { + $this->translator = $translator; + } + + public function hello(): string + { + return $this->translator->trans('hello_from_method_calls_service'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransPropertyService.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransPropertyService.php new file mode 100644 index 0000000000000..6bd17bdfd034a --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransPropertyService.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class TransPropertyService +{ + /** @var TranslatorInterface */ + public $translator; + + public function hello(): string + { + return $this->translator->trans('hello_from_property_service'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransSubscriberService.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransSubscriberService.php new file mode 100644 index 0000000000000..449b35f5e9450 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TransDebug/TransSubscriberService.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +class TransSubscriberService implements ServiceSubscriberInterface +{ + private $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + public static function getSubscribedServices() + { + return ['translator' => TranslatorInterface::class]; + } + + public function hello(): string + { + return $this->container->get('translator')->trans('hello_from_subscriber_service'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php index ebc485fa3a86e..1da49ce79c8f6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/TranslationDebugCommandTest.php @@ -33,8 +33,13 @@ public function testDumpAllTrans() $ret = $tester->execute(['locale' => 'en']); $this->assertSame(0, $ret, 'Returns 0 in case of success'); - $this->assertContains('unused validators This value should be blank.', $tester->getDisplay()); - $this->assertContains('unused security Invalid CSRF token.', $tester->getDisplay()); + $this->assertContains('missing messages hello_from_construct_arg_service', $tester->getDisplay()); + $this->assertContains('missing messages hello_from_subscriber_service', $tester->getDisplay()); + $this->assertContains('missing messages hello_from_property_service', $tester->getDisplay()); + $this->assertContains('missing messages hello_from_method_calls_service', $tester->getDisplay()); + $this->assertContains('missing messages hello_from_controller', $tester->getDisplay()); + $this->assertContains('unused validators This value should be blank.', $tester->getDisplay()); + $this->assertContains('unused security Invalid CSRF token.', $tester->getDisplay()); } private function createCommandTester(): CommandTester diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml index 6f52f7404ff20..7f8815b2942fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/config.yml @@ -1,5 +1,6 @@ imports: - { resource: ../config/default.yml } + - { resource: services.yml } framework: secret: '%secret%' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/services.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/services.yml new file mode 100644 index 0000000000000..cfb810144ca91 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/TransDebug/services.yml @@ -0,0 +1,21 @@ +services: + _defaults: + public: true + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\TransController: + tags: ['controller.service_arguments'] + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug\TransConstructArgService: + arguments: ['@translator'] + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug\TransSubscriberService: + arguments: ['@Psr\Container\ContainerInterface'] + tags: ['container.service_subscriber'] + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug\TransPropertyService: + properties: + $translator: '@translator' + + Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TransDebug\TransMethodCallsService: + calls: + - [ setTranslator, ['@translator'] ] diff --git a/src/Symfony/Component/Translation/CHANGELOG.md b/src/Symfony/Component/Translation/CHANGELOG.md index 42ae7789fa192..c80716838b4b6 100644 --- a/src/Symfony/Component/Translation/CHANGELOG.md +++ b/src/Symfony/Component/Translation/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * Improved Xliff 1.2 loader to load the original file's metadata + * Added `TranslatorPathsPass` 4.2.0 ----- diff --git a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPathsPass.php b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPathsPass.php new file mode 100644 index 0000000000000..d9fc71911fedb --- /dev/null +++ b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPathsPass.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; + +/** + * @author Yonel Ceruto + */ +class TranslatorPathsPass extends AbstractRecursivePass +{ + private $translatorServiceId; + private $debugCommandServiceId; + private $updateCommandServiceId; + private $resolverServiceId; + private $level = 0; + private $paths = []; + private $definitions = []; + private $controllers = []; + + public function __construct(string $translatorServiceId = 'translator', string $debugCommandServiceId = 'console.command.translation_debug', string $updateCommandServiceId = 'console.command.translation_update', string $resolverServiceId = 'argument_resolver.service') + { + $this->translatorServiceId = $translatorServiceId; + $this->debugCommandServiceId = $debugCommandServiceId; + $this->updateCommandServiceId = $updateCommandServiceId; + $this->resolverServiceId = $resolverServiceId; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->translatorServiceId)) { + return; + } + + foreach ($this->findControllerArguments($container) as $controller => $argument) { + $id = \substr($controller, 0, \strpos($controller, ':') ?: \strlen($controller)); + if ($container->hasDefinition($id)) { + list($locatorRef) = $argument->getValues(); + $this->controllers[(string) $locatorRef][$container->getDefinition($id)->getClass()] = true; + } + } + + try { + parent::process($container); + + $paths = []; + foreach ($this->paths as $class => $_) { + if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) { + $paths[] = $r->getFileName(); + } + } + if ($paths) { + if ($container->hasDefinition($this->debugCommandServiceId)) { + $definition = $container->getDefinition($this->debugCommandServiceId); + $definition->replaceArgument(6, array_merge($definition->getArgument(6), $paths)); + } + if ($container->hasDefinition($this->updateCommandServiceId)) { + $definition = $container->getDefinition($this->updateCommandServiceId); + $definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths)); + } + } + } finally { + $this->level = 0; + $this->paths = []; + $this->definitions = []; + } + } + + protected function processValue($value, $isRoot = false) + { + if ($value instanceof Reference) { + if ((string) $value === $this->translatorServiceId) { + for ($i = $this->level - 1; $i >= 0; --$i) { + $class = $this->definitions[$i]->getClass(); + + if (ServiceLocator::class === $class) { + if (!isset($this->controllers[$this->currentId])) { + continue; + } + foreach ($this->controllers[$this->currentId] as $class => $_) { + $this->paths[$class] = true; + } + } else { + $this->paths[$class] = true; + } + + break; + } + } + + return $value; + } + + if ($value instanceof Definition) { + $this->definitions[$this->level++] = $value; + $value = parent::processValue($value, $isRoot); + unset($this->definitions[--$this->level]); + + return $value; + } + + return parent::processValue($value, $isRoot); + } + + private function findControllerArguments(ContainerBuilder $container): array + { + if ($container->hasDefinition($this->resolverServiceId)) { + $argument = $container->getDefinition($this->resolverServiceId)->getArgument(0); + if ($argument instanceof Reference) { + $argument = $container->getDefinition($argument); + } + + return $argument->getArgument(0); + } + + if ($container->hasDefinition('debug.'.$this->resolverServiceId)) { + $argument = $container->getDefinition('debug.'.$this->resolverServiceId)->getArgument(0); + if ($argument instanceof Reference) { + $argument = $container->getDefinition($argument); + } + $argument = $argument->getArgument(0); + if ($argument instanceof Reference) { + $argument = $container->getDefinition($argument); + } + + return $argument->getArgument(0); + } + + return []; + } +} diff --git a/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPathsPassTest.php b/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPathsPassTest.php new file mode 100644 index 0000000000000..42ab398dffe7b --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPathsPassTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ControllerArguments; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceArguments; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceMethodCalls; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceProperties; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceSubscriber; + +class TranslationPathsPassTest extends TestCase +{ + public function testProcess() + { + $container = new ContainerBuilder(); + $container->register('translator'); + $debugCommand = $container->register('console.command.translation_debug') + ->setArguments([null, null, null, null, null, [], []]) + ; + $updateCommand = $container->register('console.command.translation_update') + ->setArguments([null, null, null, null, null, null, [], []]) + ; + $container->register(ControllerArguments::class, ControllerArguments::class) + ->setTags(['controller.service_arguments']) + ; + $container->register(ServiceArguments::class, ServiceArguments::class) + ->setArguments([new Reference('translator')]) + ; + $container->register(ServiceProperties::class, ServiceProperties::class) + ->setProperties([new Reference('translator')]) + ; + $container->register(ServiceMethodCalls::class, ServiceMethodCalls::class) + ->setMethodCalls([['setTranslator', [new Reference('translator')]]]) + ; + $container->register('service_rc') + ->setArguments([new Definition(), new Reference(ServiceMethodCalls::class)]) + ; + $serviceLocator1 = $container->register('.service_locator.foo', ServiceLocator::class) + ->setArguments([new ServiceClosureArgument(new Reference('translator'))]) + ; + $serviceLocator2 = (new Definition(ServiceLocator::class)) + ->setArguments([ServiceSubscriber::class, new Reference('service_container')]) + ->setFactory([$serviceLocator1, 'withContext']) + ; + $container->register('service_subscriber', ServiceSubscriber::class) + ->setArguments([$serviceLocator2]) + ; + $container->register('.service_locator.bar', ServiceLocator::class) + ->setArguments([[ + ControllerArguments::class.'::index' => new ServiceClosureArgument(new Reference('.service_locator.foo')), + ControllerArguments::class.'::__invoke' => new ServiceClosureArgument(new Reference('.service_locator.foo')), + ControllerArguments::class => new ServiceClosureArgument(new Reference('.service_locator.foo')), + ]]) + ; + $container->register('argument_resolver.service') + ->setArguments([new Reference('.service_locator.bar')]) + ; + + $pass = new TranslatorPathsPass('translator', 'console.command.translation_debug', 'console.command.translation_update', 'argument_resolver.service'); + $pass->process($container); + + $expectedPaths = [ + $container->getReflectionClass(ServiceArguments::class)->getFileName(), + $container->getReflectionClass(ServiceProperties::class)->getFileName(), + $container->getReflectionClass(ServiceMethodCalls::class)->getFileName(), + $container->getReflectionClass(ControllerArguments::class)->getFileName(), + $container->getReflectionClass(ServiceSubscriber::class)->getFileName(), + ]; + + $this->assertSame($expectedPaths, $debugCommand->getArgument(6)); + $this->assertSame($expectedPaths, $updateCommand->getArgument(7)); + } +} diff --git a/src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ControllerArguments.php b/src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ControllerArguments.php new file mode 100644 index 0000000000000..97a53fa76bcd8 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/DependencyInjection/fixtures/ControllerArguments.php @@ -0,0 +1,16 @@ + TranslatorInterface::class]; + } +} From 37dbab263e2cc0be480e3dd6be63189d988037e8 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 14 Feb 2019 04:47:16 +0100 Subject: [PATCH 115/495] [Routing] fix changelog typos Fix small typos from #28865 --- src/Symfony/Component/Routing/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 5e8a998cd74ff..f9755971044db 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -6,7 +6,7 @@ CHANGELOG * added `CompiledUrlMatcher` and `CompiledUrlMatcherDumper` * added `CompiledUrlGenerator` and `CompiledUrlGeneratorDumper` - * deprecated `PhpUrlGeneratorDumped` and `PhpMatcherDumper` + * deprecated `PhpGeneratorDumper` and `PhpMatcherDumper` 4.2.0 ----- From c8d6dd7c8fc716f1e7773022eac4fb2fe48a9429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bogusz?= Date: Thu, 14 Feb 2019 09:56:06 +0100 Subject: [PATCH 116/495] Add element to ghost in Exception --- src/Symfony/Component/Debug/ExceptionHandler.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index 1bf4accef168c..c99c5943960ad 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -31,6 +31,10 @@ */ class ExceptionHandler { + private const GHOST_ADDONS = [ + '02-14' => '', + ]; + private $debug; private $charset; private $handler; @@ -438,6 +442,11 @@ private function escapeHtml($str) private function getSymfonyGhostAsSvg() { - return ''; + return ''.$this->addElementToGhost().''; + } + + private function addElementToGhost() + { + return self::GHOST_ADDONS[\date('m-d')] ?? ''; } } From 6bfc5f09019aa723abcf8496981d8fb37da7c8ea Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 14 Feb 2019 10:40:15 +0100 Subject: [PATCH 117/495] properly move test methods --- .../Extension/FormExtensionDivLayoutTest.php | 76 +++++++++++++++++++ .../FormExtensionTableLayoutTest.php | 76 +++++++++++++++++++ .../Helper/FormHelperDivLayoutTest.php | 76 +++++++++++++++++++ .../Helper/FormHelperTableLayoutTest.php | 76 +++++++++++++++++++ .../Form/Tests/AbstractDivLayoutTest.php | 76 ------------------- .../Form/Tests/AbstractTableLayoutTest.php | 76 ------------------- 6 files changed, 304 insertions(+), 152 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 49778e7f85c7e..6107660ec64cf 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -293,6 +293,82 @@ public function testHelpHtmlIsTrue() ); } + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] +' + ); + } + protected function renderForm(FormView $view, array $vars = []) { return (string) $this->renderer->renderBlock($view, 'form', $vars); diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php index a1cefcb577d5b..d519dd33c0bfd 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -179,6 +179,82 @@ public function testHelpHtmlIsTrue() ); } + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] +' + ); + } + protected function renderForm(FormView $view, array $vars = []) { return (string) $this->renderer->renderBlock($view, 'form', $vars); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php index 8d0449cd03b6b..7f670911f7707 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @@ -193,6 +193,82 @@ public function testHelpHtmlIsTrue() ); } + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] +' + ); + } + protected function renderForm(FormView $view, array $vars = []) { return (string) $this->engine->get('form')->form($view, $vars); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php index 8b1bf4cbdd81a..2371b343a1961 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @@ -71,6 +71,82 @@ public function testHelpAttr() ); } + public function testLabelWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] +' + ); + } + protected function getExtensions() { // should be moved to the Form component once absolute file paths are supported diff --git a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php index a95f430de6617..ab8444974959d 100644 --- a/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractDivLayoutTest.php @@ -931,80 +931,4 @@ public function testWidgetContainerAttributeNameRepeatedIfTrue() // foo="foo" $this->assertContains('
', $html); } - - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] -' - ); - } } diff --git a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php index ca96c179b9b83..6c09ba8ead456 100644 --- a/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractTableLayoutTest.php @@ -533,80 +533,4 @@ public function testWidgetContainerAttributeNameRepeatedIfTrue() // foo="foo" $this->assertContains('
', $html); } - - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] -' - ); - } } From d42e054d2c825cbbdd049967d6736fca49ae4162 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 14 Feb 2019 16:46:28 +0100 Subject: [PATCH 118/495] (finally) fix version dependent Form tests --- .../AbstractBootstrap3LayoutTest.php | 78 +---------------- .../Extension/FormExtensionDivLayoutTest.php | 78 +---------------- .../FormExtensionTableLayoutTest.php | 78 +---------------- .../Helper/FormHelperDivLayoutTest.php | 78 +---------------- .../Helper/FormHelperTableLayoutTest.php | 78 +---------------- .../Form/Tests/AbstractLayoutTest.php | 84 +++++++++++++++++++ .../Extension/Core/Type/BaseTypeTest.php | 16 ++++ 7 files changed, 105 insertions(+), 385 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index dbe12ee979734..160c18cce3cd3 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -16,7 +16,7 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest { - protected static $supportedFeatureSetVersion = 304; + protected static $supportedFeatureSetVersion = 403; public function testLabelOnForm() { @@ -2672,82 +2672,6 @@ public function testColor() [@name="name"] [@class="my&class form-control"] [@value="#0000ff"] -' - ); - } - - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] ' ); } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index eab8328b2d85c..e40e57505a0a5 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -31,7 +31,7 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest */ private $renderer; - protected static $supportedFeatureSetVersion = 304; + protected static $supportedFeatureSetVersion = 403; protected function setUp() { @@ -295,82 +295,6 @@ public function testHelpHtmlIsTrue() ); } - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] -' - ); - } - protected function renderForm(FormView $view, array $vars = []) { return (string) $this->renderer->renderBlock($view, 'form', $vars); diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php index 49efa7f67aaea..9570e03e523c7 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -30,7 +30,7 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest */ private $renderer; - protected static $supportedFeatureSetVersion = 304; + protected static $supportedFeatureSetVersion = 403; protected function setUp() { @@ -181,82 +181,6 @@ public function testHelpHtmlIsTrue() ); } - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] -' - ); - } - protected function renderForm(FormView $view, array $vars = []) { return (string) $this->renderer->renderBlock($view, 'form', $vars); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php index 5ef8f3d17b0bc..35dbc03f3433b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @@ -27,7 +27,7 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest */ protected $engine; - protected static $supportedFeatureSetVersion = 304; + protected static $supportedFeatureSetVersion = 403; protected function getExtensions() { @@ -195,82 +195,6 @@ public function testHelpHtmlIsTrue() ); } - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] -' - ); - } - protected function renderForm(FormView $view, array $vars = []) { return (string) $this->engine->get('form')->form($view, $vars); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php index 853dc7af6f296..262421bf34bb9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @@ -27,7 +27,7 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest */ protected $engine; - protected static $supportedFeatureSetVersion = 304; + protected static $supportedFeatureSetVersion = 403; public function testStartTagHasNoActionAttributeWhenActionIsEmpty() { @@ -73,82 +73,6 @@ public function testHelpAttr() ); } - public function testLabelWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $html = $this->renderLabel($form->createView(), 'Address is %address%', [ - 'label_translation_parameters' => [ - '%address%' => 'Paris, rue de la Paix', - ], - ]); - - $this->assertMatchesXpath($html, - '/label - [@for="name"] - [.="[trans]Address is Paris, rue de la Paix[/trans]"] -' - ); - } - - public function testHelpWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'help' => 'for company %company%', - 'help_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderHelp($form->createView()); - - $this->assertMatchesXpath($html, - '/* - [@id="name_help"] - [.="[trans]for company ACME Ltd.[/trans]"] -' - ); - } - - public function testAttributesWithTranslationParameters() - { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'attr' => [ - 'title' => 'Message to %company%', - 'placeholder' => 'Enter a message to %company%', - ], - 'attr_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]); - $html = $this->renderWidget($form->createView()); - - $this->assertMatchesXpath($html, - '/input - [@title="[trans]Message to ACME Ltd.[/trans]"] - [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] -' - ); - } - - public function testButtonWithTranslationParameters() - { - $form = $this->factory->createNamedBuilder('myform') - ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ - 'label' => 'Submit to %company%', - 'label_translation_parameters' => [ - '%company%' => 'ACME Ltd.', - ], - ]) - ->getForm(); - $view = $form->get('mybutton')->createView(); - $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); - - $this->assertMatchesXpath($html, - '/button - [.="[trans]Submit to ACME Ltd.[/trans]"] -' - ); - } - protected function getExtensions() { // should be moved to the Form component once absolute file paths are supported diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 07c027d24297d..b5f0b8f84e04e 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -2589,6 +2589,90 @@ public function testColor() [@type="color"] [@name="name"] [@value="#0000ff"] +' + ); + } + + public function testLabelWithTranslationParameters() + { + $this->requiresFeatureSet(403); + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $html = $this->renderLabel($form->createView(), 'Address is %address%', [ + 'label_translation_parameters' => [ + '%address%' => 'Paris, rue de la Paix', + ], + ]); + + $this->assertMatchesXpath($html, + '/label + [@for="name"] + [.="[trans]Address is Paris, rue de la Paix[/trans]"] +' + ); + } + + public function testHelpWithTranslationParameters() + { + $this->requiresFeatureSet(403); + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'help' => 'for company %company%', + 'help_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderHelp($form->createView()); + + $this->assertMatchesXpath($html, + '/* + [@id="name_help"] + [.="[trans]for company ACME Ltd.[/trans]"] +' + ); + } + + public function testAttributesWithTranslationParameters() + { + $this->requiresFeatureSet(403); + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ + 'attr' => [ + 'title' => 'Message to %company%', + 'placeholder' => 'Enter a message to %company%', + ], + 'attr_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]); + $html = $this->renderWidget($form->createView()); + + $this->assertMatchesXpath($html, + '/input + [@title="[trans]Message to ACME Ltd.[/trans]"] + [@placeholder="[trans]Enter a message to ACME Ltd.[/trans]"] +' + ); + } + + public function testButtonWithTranslationParameters() + { + $this->requiresFeatureSet(403); + + $form = $this->factory->createNamedBuilder('myform') + ->add('mybutton', 'Symfony\Component\Form\Extension\Core\Type\ButtonType', [ + 'label' => 'Submit to %company%', + 'label_translation_parameters' => [ + '%company%' => 'ACME Ltd.', + ], + ]) + ->getForm(); + $view = $form->get('mybutton')->createView(); + $html = $this->renderWidget($view, ['label_format' => 'form.%name%']); + + $this->assertMatchesXpath($html, + '/button + [.="[trans]Submit to ACME Ltd.[/trans]"] ' ); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php index 1a1706378e1a9..20618bba39ee3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php @@ -124,6 +124,8 @@ public function testDefaultTranslationDomain() public function testPassLabelTranslationParametersToView() { + $this->requiresFeatureSet(403); + $view = $this->factory->create($this->getTestedType(), null, [ 'label_translation_parameters' => ['%param%' => 'value'], ]) @@ -134,6 +136,8 @@ public function testPassLabelTranslationParametersToView() public function testPassAttrTranslationParametersToView() { + $this->requiresFeatureSet(403); + $view = $this->factory->create($this->getTestedType(), null, [ 'attr_translation_parameters' => ['%param%' => 'value'], ]) @@ -144,6 +148,8 @@ public function testPassAttrTranslationParametersToView() public function testInheritLabelTranslationParametersFromParent() { + $this->requiresFeatureSet(403); + $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'label_translation_parameters' => ['%param%' => 'value'], @@ -157,6 +163,8 @@ public function testInheritLabelTranslationParametersFromParent() public function testInheritAttrTranslationParametersFromParent() { + $this->requiresFeatureSet(403); + $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'attr_translation_parameters' => ['%param%' => 'value'], @@ -170,6 +178,8 @@ public function testInheritAttrTranslationParametersFromParent() public function testPreferOwnLabelTranslationParameters() { + $this->requiresFeatureSet(403); + $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'label_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], @@ -185,6 +195,8 @@ public function testPreferOwnLabelTranslationParameters() public function testPreferOwnAttrTranslationParameters() { + $this->requiresFeatureSet(403); + $view = $this->factory ->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE, null, [ 'attr_translation_parameters' => ['%parent_param%' => 'parent_value', '%override_param%' => 'parent_override_value'], @@ -200,6 +212,8 @@ public function testPreferOwnAttrTranslationParameters() public function testDefaultLabelTranslationParameters() { + $this->requiresFeatureSet(403); + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) ->add('child', $this->getTestedType()) ->getForm() @@ -210,6 +224,8 @@ public function testDefaultLabelTranslationParameters() public function testDefaultAttrTranslationParameters() { + $this->requiresFeatureSet(403); + $view = $this->factory->createNamedBuilder('parent', FormTypeTest::TESTED_TYPE) ->add('child', $this->getTestedType()) ->getForm() From 592e03f06579178d514113015a681da42bb42027 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 13 Feb 2019 21:37:56 +0100 Subject: [PATCH 119/495] ignore not-existent service definitions --- .../DependencyInjection/FrameworkExtension.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 13d263ea6278e..cd513ec90a9f6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1059,8 +1059,14 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir)); } } - $container->getDefinition('console.command.translation_debug')->replaceArgument(5, $transPaths); - $container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths); + + if ($container->hasDefinition('console.command.translation_debug')) { + $container->getDefinition('console.command.translation_debug')->replaceArgument(5, $transPaths); + } + + if ($container->hasDefinition('console.command.translation_update')) { + $container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths); + } if ($container->fileExists($defaultDir)) { $dirs[] = $defaultDir; From bf4cd6164dbd31861ca4e1c61a052d878ce6eae7 Mon Sep 17 00:00:00 2001 From: Tobias Schultze Date: Thu, 14 Feb 2019 20:11:38 +0100 Subject: [PATCH 120/495] [Routing] deprecate some router options --- .../FrameworkExtension.php | 8 +++-- .../Resources/config/routing.xml | 4 --- src/Symfony/Component/Routing/CHANGELOG.md | 1 + src/Symfony/Component/Routing/Router.php | 35 +++++++++++++------ .../Component/Routing/Tests/RouterTest.php | 30 +++------------- 5 files changed, 34 insertions(+), 44 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cd513ec90a9f6..ee23ac58aac10 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -20,6 +20,7 @@ use Symfony\Bridge\Twig\Extension\CsrfExtension; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader; +use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher; use Symfony\Bundle\FullStack; use Symfony\Component\BrowserKit\Client; use Symfony\Component\Cache\Adapter\AbstractAdapter; @@ -83,6 +84,7 @@ use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\Routing\Generator\Dumper\PhpGeneratorDumper; +use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader; use Symfony\Component\Routing\Loader\AnnotationFileLoader; use Symfony\Component\Routing\Matcher\CompiledUrlMatcher; @@ -750,7 +752,7 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co } $container->setParameter('router.resource', $config['resource']); - $container->setParameter('router.cache_class_prefix', $container->getParameter('kernel.container_class')); + $container->setParameter('router.cache_class_prefix', $container->getParameter('kernel.container_class')); // deprecated $router = $container->findDefinition('router.default'); $argument = $router->getArgument(2); $argument['strict_requirements'] = $config['strict_requirements']; @@ -758,9 +760,9 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co $argument['resource_type'] = $config['type']; } if (!class_exists(CompiledUrlMatcher::class)) { - $argument['matcher_class'] = $argument['matcher_base_class']; + $argument['matcher_class'] = $argument['matcher_base_class'] = $argument['matcher_base_class'] ?? RedirectableUrlMatcher::class; $argument['matcher_dumper_class'] = PhpMatcherDumper::class; - $argument['generator_class'] = $argument['generator_base_class']; + $argument['generator_class'] = $argument['generator_base_class'] = $argument['generator_base_class'] ?? UrlGenerator::class; $argument['generator_dumper_class'] = PhpGeneratorDumper::class; } $router->replaceArgument(2, $argument); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml index bdce1956a3015..a240dd85eb62c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.xml @@ -60,13 +60,9 @@ %kernel.cache_dir% %kernel.debug% Symfony\Component\Routing\Generator\CompiledUrlGenerator - Symfony\Component\Routing\Generator\UrlGenerator Symfony\Component\Routing\Generator\Dumper\CompiledUrlGeneratorDumper - %router.cache_class_prefix%UrlGenerator Symfony\Bundle\FrameworkBundle\Routing\RedirectableCompiledUrlMatcher - Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherDumper - %router.cache_class_prefix%UrlMatcher diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index f9755971044db..d695cd6bd1e91 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -7,6 +7,7 @@ CHANGELOG * added `CompiledUrlMatcher` and `CompiledUrlMatcherDumper` * added `CompiledUrlGenerator` and `CompiledUrlGeneratorDumper` * deprecated `PhpGeneratorDumper` and `PhpMatcherDumper` + * deprecated `generator_base_class`, `generator_cache_class`, `matcher_base_class` and `matcher_cache_class` router options 4.2.0 ----- diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 35c2cf679d21d..34c4d9ce23ba1 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Routing; use Psr\Log\LoggerInterface; +use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher; use Symfony\Component\Config\ConfigCacheFactory; use Symfony\Component\Config\ConfigCacheFactoryInterface; use Symfony\Component\Config\ConfigCacheInterface; @@ -113,13 +114,9 @@ public function __construct(LoaderInterface $loader, $resource, array $options = * * cache_dir: The cache directory (or null to disable caching) * * debug: Whether to enable debugging or not (false by default) * * generator_class: The name of a UrlGeneratorInterface implementation - * * generator_base_class: The base class for the dumped generator class - * * generator_cache_class: The class name for the dumped generator class * * generator_dumper_class: The name of a GeneratorDumperInterface implementation * * matcher_class: The name of a UrlMatcherInterface implementation - * * matcher_base_class: The base class for the dumped matcher class - * * matcher_dumper_class: The class name for the dumped matcher class - * * matcher_cache_class: The name of a MatcherDumperInterface implementation + * * matcher_dumper_class: The name of a MatcherDumperInterface implementation * * resource_type: Type hint for the main resource (optional) * * strict_requirements: Configure strict requirement checking for generators * implementing ConfigurableRequirementsInterface (default is true) @@ -134,13 +131,13 @@ public function setOptions(array $options) 'cache_dir' => null, 'debug' => false, 'generator_class' => CompiledUrlGenerator::class, - 'generator_base_class' => UrlGenerator::class, + 'generator_base_class' => UrlGenerator::class, // deprecated 'generator_dumper_class' => CompiledUrlGeneratorDumper::class, - 'generator_cache_class' => 'UrlGenerator', + 'generator_cache_class' => 'UrlGenerator', // deprecated 'matcher_class' => CompiledUrlMatcher::class, - 'matcher_base_class' => UrlMatcher::class, + 'matcher_base_class' => UrlMatcher::class, // deprecated 'matcher_dumper_class' => CompiledUrlMatcherDumper::class, - 'matcher_cache_class' => 'UrlMatcher', + 'matcher_cache_class' => 'UrlMatcher', // deprecated 'resource_type' => null, 'strict_requirements' => true, ]; @@ -148,6 +145,7 @@ public function setOptions(array $options) // check option names and live merge, if errors are encountered Exception will be thrown $invalid = []; foreach ($options as $key => $value) { + $this->checkDeprecatedOption($key); if (array_key_exists($key, $this->options)) { $this->options[$key] = $value; } else { @@ -174,6 +172,8 @@ public function setOption($key, $value) throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); } + $this->checkDeprecatedOption($key); + $this->options[$key] = $value; } @@ -192,6 +192,8 @@ public function getOption($key) throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); } + $this->checkDeprecatedOption($key); + return $this->options[$key]; } @@ -279,7 +281,7 @@ public function getMatcher() return $this->matcher; } - $compiled = is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true); + $compiled = is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && (UrlMatcher::class === $this->options['matcher_base_class'] || RedirectableUrlMatcher::class === $this->options['matcher_base_class']); if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) { $routes = $this->getRouteCollection(); @@ -336,7 +338,7 @@ public function getGenerator() return $this->generator; } - $compiled = is_a($this->options['generator_class'], CompiledUrlGenerator::class, true); + $compiled = is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && UrlGenerator::class === $this->options['generator_base_class']; if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) { $routes = $this->getRouteCollection(); @@ -411,4 +413,15 @@ private function getConfigCacheFactory() return $this->configCacheFactory; } + + private function checkDeprecatedOption($key) + { + switch ($key) { + case 'generator_base_class': + case 'generator_cache_class': + case 'matcher_base_class': + case 'matcher_cache_class': + @trigger_error(sprintf('Option "%s" given to router %s is deprecated since Symfony 4.3.', $key, static::class), E_USER_DEPRECATED); + } + } } diff --git a/src/Symfony/Component/Routing/Tests/RouterTest.php b/src/Symfony/Component/Routing/Tests/RouterTest.php index 589ce5403ac2b..46a45fef082e1 100644 --- a/src/Symfony/Component/Routing/Tests/RouterTest.php +++ b/src/Symfony/Component/Routing/Tests/RouterTest.php @@ -93,12 +93,9 @@ public function testThatRouteCollectionIsLoaded() $this->assertSame($routeCollection, $this->router->getRouteCollection()); } - /** - * @dataProvider provideMatcherOptionsPreventingCaching - */ - public function testMatcherIsCreatedIfCacheIsNotConfigured($option) + public function testMatcherIsCreatedIfCacheIsNotConfigured() { - $this->router->setOption($option, null); + $this->router->setOption('cache_dir', null); $this->loader->expects($this->once()) ->method('load')->with('routing.yml', null) @@ -107,20 +104,9 @@ public function testMatcherIsCreatedIfCacheIsNotConfigured($option) $this->assertInstanceOf('Symfony\\Component\\Routing\\Matcher\\UrlMatcher', $this->router->getMatcher()); } - public function provideMatcherOptionsPreventingCaching() - { - return [ - ['cache_dir'], - ['matcher_cache_class'], - ]; - } - - /** - * @dataProvider provideGeneratorOptionsPreventingCaching - */ - public function testGeneratorIsCreatedIfCacheIsNotConfigured($option) + public function testGeneratorIsCreatedIfCacheIsNotConfigured() { - $this->router->setOption($option, null); + $this->router->setOption('cache_dir', null); $this->loader->expects($this->once()) ->method('load')->with('routing.yml', null) @@ -129,14 +115,6 @@ public function testGeneratorIsCreatedIfCacheIsNotConfigured($option) $this->assertInstanceOf('Symfony\\Component\\Routing\\Generator\\UrlGenerator', $this->router->getGenerator()); } - public function provideGeneratorOptionsPreventingCaching() - { - return [ - ['cache_dir'], - ['generator_cache_class'], - ]; - } - public function testMatchRequestWithUrlMatcherInterface() { $matcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\UrlMatcherInterface')->getMock(); From 45dde5d00cd773d9acc6d1ce76f3b10f01f344a9 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 15 Feb 2019 17:16:33 +0100 Subject: [PATCH 121/495] restore compatibility with FrameworkBundle 4.2 --- .../DependencyInjection/TranslatorPass.php | 10 ++++- .../TranslationPassTest.php | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php index 655e7ae988073..ed4a840d86127 100644 --- a/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php +++ b/src/Symfony/Component/Translation/DependencyInjection/TranslatorPass.php @@ -72,12 +72,18 @@ public function process(ContainerBuilder $container) if ($container->hasDefinition($this->debugCommandServiceId)) { $definition = $container->getDefinition($this->debugCommandServiceId); $definition->replaceArgument(4, $container->getParameter('twig.default_path')); - $definition->replaceArgument(6, $paths); + + if (\count($definition->getArguments()) > 6) { + $definition->replaceArgument(6, $paths); + } } if ($container->hasDefinition($this->updateCommandServiceId)) { $definition = $container->getDefinition($this->updateCommandServiceId); $definition->replaceArgument(5, $container->getParameter('twig.default_path')); - $definition->replaceArgument(7, $paths); + + if (\count($definition->getArguments()) > 7) { + $definition->replaceArgument(7, $paths); + } } } } diff --git a/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php b/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php index d054152ce6f5c..f62fc85ebc97a 100644 --- a/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php +++ b/src/Symfony/Component/Translation/Tests/DependencyInjection/TranslationPassTest.php @@ -82,4 +82,41 @@ public function testValidCommandsViewPathsArgument() $this->assertSame($expectedViewPaths, $debugCommand->getArgument(6)); $this->assertSame($expectedViewPaths, $updateCommand->getArgument(7)); } + + public function testCommandsViewPathsArgumentsAreIgnoredWithOldServiceDefinitions() + { + $container = new ContainerBuilder(); + $container->register('translator.default') + ->setArguments([null, null, null, null]) + ; + $debugCommand = $container->register('console.command.translation_debug') + ->setArguments([ + new Reference('translator'), + new Reference('translation.reader'), + new Reference('translation.extractor'), + '%translator.default_path%', + null, + ]) + ; + $updateCommand = $container->register('console.command.translation_update') + ->setArguments([ + new Reference('translation.writer'), + new Reference('translation.reader'), + new Reference('translation.extractor'), + '%kernel.default_locale%', + '%translator.default_path%', + null, + ]) + ; + $container->register('twig.template_iterator') + ->setArguments([null, null, ['other/templates' => null, 'tpl' => 'App']]) + ; + $container->setParameter('twig.default_path', 'templates'); + + $pass = new TranslatorPass('translator.default'); + $pass->process($container); + + $this->assertSame('templates', $debugCommand->getArgument(4)); + $this->assertSame('templates', $updateCommand->getArgument(5)); + } } From 6674391dd4988f2d87f392628fe5ca39df1f77cd Mon Sep 17 00:00:00 2001 From: Sergio Date: Thu, 14 Feb 2019 11:13:47 +0100 Subject: [PATCH 122/495] Add missing Romanian translations for validator --- .../Resources/translations/validators.ro.xlf | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 63af47042b199..26b069ab02774 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -278,10 +278,62 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Această valoare nu trebuie să fie identică cu {{ compared_value_type }} {{ compared_value }}. + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Raportul imaginii este prea mare ({{ ratio }}). Raportul maxim permis este {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Raportul imaginii este prea mic ({{ ratio }}). Raportul minim permis este {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Imaginea este un pătrat ({{ width }}x{{ height }}px). Imaginile pătrat nu sunt permise. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Imaginea are orientarea peisaj ({{ width }}x{{ height }}px). Imaginile cu orientare peisaj nu sunt permise. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Imaginea are orientarea portret ({{ width }}x{{ height }}px). Imaginile cu orientare portret nu sunt permise. + + + An empty file is not allowed. + Nu se permite un fișier gol. + + + The host could not be resolved. + Numele host nu a putut fi rezolvat către o adresă IP. + + + This value does not match the expected {{ charset }} charset. + Această valoare nu corespunde setului de caractere {{ charset }} așteptat. + + + This is not a valid Business Identifier Code (BIC). + Codul BIC (Business Identifier Code) nu este valid. + Error Eroare + + This is not a valid UUID. + Identificatorul universal unic (UUID) nu este valid. + + + This value should be a multiple of {{ compared_value }}. + Această valoare trebuie să fie un multiplu de {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Codul BIC (Business Identifier Code) nu este asociat cu codul IBAN {{ iban }}. + + + This value should be valid JSON. + Această valoare trebuie să fie un JSON valid. + From f8bf9738f0cb2ed1b535785699d1d37dc0ea78d7 Mon Sep 17 00:00:00 2001 From: renanbr Date: Thu, 31 Jan 2019 13:39:06 +0100 Subject: [PATCH 123/495] Drop \Serializable --- src/Symfony/Component/Config/CHANGELOG.md | 1 + .../Resource/ClassExistenceResource.php | 16 ++++--------- .../Config/Resource/ComposerResource.php | 20 +++------------- .../Config/Resource/DirectoryResource.php | 20 +++------------- .../Config/Resource/FileExistenceResource.php | 20 +++------------- .../Config/Resource/FileResource.php | 20 +++------------- .../Config/Resource/GlobResource.php | 16 ++++--------- .../Resource/ReflectionClassResource.php | 16 ++++--------- .../Config/ResourceCheckerConfigCache.php | 10 +++++++- .../DependencyInjection/CHANGELOG.md | 1 + .../Config/ContainerParametersResource.php | 20 +++------------- src/Symfony/Component/Form/CHANGELOG.md | 2 +- src/Symfony/Component/Form/FormError.php | 24 +------------------ .../DataCollector/FormDataCollectorTest.php | 2 +- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../HttpKernel/Debug/FileLinkFormatter.php | 16 +++++-------- 16 files changed, 51 insertions(+), 154 deletions(-) diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index 2e3b31e3146d7..122184021c3bf 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` + * made `Resource\*` classes final and not implement `Serializable` anymore 4.2.0 ----- diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index 035b3ce980035..51154cfd6a41f 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -18,8 +18,10 @@ * The resource must be a fully-qualified class name. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ -class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializable +class ClassExistenceResource implements SelfCheckingResourceInterface { private $resource; private $exists; @@ -97,21 +99,13 @@ public function isFresh($timestamp) /** * @internal */ - public function serialize() + public function __sleep(): array { if (null === $this->exists) { $this->isFresh(0); } - return serialize([$this->resource, $this->exists]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->resource, $this->exists) = unserialize($serialized); + return ['resource', 'exists']; } /** diff --git a/src/Symfony/Component/Config/Resource/ComposerResource.php b/src/Symfony/Component/Config/Resource/ComposerResource.php index c826d1bb75127..db6b04c812c57 100644 --- a/src/Symfony/Component/Config/Resource/ComposerResource.php +++ b/src/Symfony/Component/Config/Resource/ComposerResource.php @@ -15,8 +15,10 @@ * ComposerResource tracks the PHP version and Composer dependencies. * * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ -class ComposerResource implements SelfCheckingResourceInterface, \Serializable +class ComposerResource implements SelfCheckingResourceInterface { private $vendors; @@ -51,22 +53,6 @@ public function isFresh($timestamp) return self::$runtimeVendors === $this->vendors; } - /** - * @internal - */ - public function serialize() - { - return serialize($this->vendors); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - $this->vendors = unserialize($serialized); - } - private static function refresh() { self::$runtimeVendors = []; diff --git a/src/Symfony/Component/Config/Resource/DirectoryResource.php b/src/Symfony/Component/Config/Resource/DirectoryResource.php index d657abcbae204..3d703db7f6ebe 100644 --- a/src/Symfony/Component/Config/Resource/DirectoryResource.php +++ b/src/Symfony/Component/Config/Resource/DirectoryResource.php @@ -15,8 +15,10 @@ * DirectoryResource represents a resources stored in a subdirectory tree. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ -class DirectoryResource implements SelfCheckingResourceInterface, \Serializable +class DirectoryResource implements SelfCheckingResourceInterface { private $resource; private $pattern; @@ -103,20 +105,4 @@ public function isFresh($timestamp) return true; } - - /** - * @internal - */ - public function serialize() - { - return serialize([$this->resource, $this->pattern]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->resource, $this->pattern) = unserialize($serialized); - } } diff --git a/src/Symfony/Component/Config/Resource/FileExistenceResource.php b/src/Symfony/Component/Config/Resource/FileExistenceResource.php index 8c65729c45a10..57234161588c7 100644 --- a/src/Symfony/Component/Config/Resource/FileExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/FileExistenceResource.php @@ -18,8 +18,10 @@ * The resource can be a file or a directory. * * @author Charles-Henri Bruyand + * + * @final since Symfony 4.3 */ -class FileExistenceResource implements SelfCheckingResourceInterface, \Serializable +class FileExistenceResource implements SelfCheckingResourceInterface { private $resource; @@ -57,20 +59,4 @@ public function isFresh($timestamp) { return file_exists($this->resource) === $this->exists; } - - /** - * @internal - */ - public function serialize() - { - return serialize([$this->resource, $this->exists]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->resource, $this->exists) = unserialize($serialized); - } } diff --git a/src/Symfony/Component/Config/Resource/FileResource.php b/src/Symfony/Component/Config/Resource/FileResource.php index 94ec2c729a994..95fe8a0bf802c 100644 --- a/src/Symfony/Component/Config/Resource/FileResource.php +++ b/src/Symfony/Component/Config/Resource/FileResource.php @@ -17,8 +17,10 @@ * The resource can be a file or a directory. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ -class FileResource implements SelfCheckingResourceInterface, \Serializable +class FileResource implements SelfCheckingResourceInterface { /** * @var string|false @@ -62,20 +64,4 @@ public function isFresh($timestamp) { return false !== ($filemtime = @filemtime($this->resource)) && $filemtime <= $timestamp; } - - /** - * @internal - */ - public function serialize() - { - return serialize($this->resource); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - $this->resource = unserialize($serialized); - } } diff --git a/src/Symfony/Component/Config/Resource/GlobResource.php b/src/Symfony/Component/Config/Resource/GlobResource.php index 5581e67ecaae9..fce8f6e2062a0 100644 --- a/src/Symfony/Component/Config/Resource/GlobResource.php +++ b/src/Symfony/Component/Config/Resource/GlobResource.php @@ -20,8 +20,10 @@ * Only existence/removal is tracked (not mtimes.) * * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ -class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface, \Serializable +class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface { private $prefix; private $pattern; @@ -80,21 +82,13 @@ public function isFresh($timestamp) /** * @internal */ - public function serialize() + public function __sleep(): array { if (null === $this->hash) { $this->hash = $this->computeHash(); } - return serialize([$this->prefix, $this->pattern, $this->recursive, $this->hash, $this->forExclusion, $this->excludedPrefixes]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->prefix, $this->pattern, $this->recursive, $this->hash, $this->forExclusion, $this->excludedPrefixes) = unserialize($serialized) + [4 => false, []]; + return ['prefix', 'pattern', 'recursive', 'hash', 'forExclusion', 'excludedPrefixes']; } public function getIterator() diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index a7e73becf55f4..16cdb6ac0c379 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -17,8 +17,10 @@ /** * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ -class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable +class ReflectionClassResource implements SelfCheckingResourceInterface { private $files = []; private $className; @@ -61,22 +63,14 @@ public function __toString() /** * @internal */ - public function serialize() + public function __sleep(): array { if (null === $this->hash) { $this->hash = $this->computeHash(); $this->loadFiles($this->classReflector); } - return serialize([$this->files, $this->className, $this->hash]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->files, $this->className, $this->hash) = unserialize($serialized); + return ['files', 'className', 'hash']; } private function loadFiles(\ReflectionClass $class) diff --git a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php index ef18072844eaa..34dc35d5f51f8 100644 --- a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php +++ b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php @@ -158,7 +158,7 @@ private function safelyUnserialize($file) $meta = false; $content = file_get_contents($file); $signalingException = new \UnexpectedValueException(); - $prevUnserializeHandler = ini_set('unserialize_callback_func', ''); + $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { if (__FILE__ === $file) { throw $signalingException; @@ -180,4 +180,12 @@ private function safelyUnserialize($file) return $meta; } + + /** + * @internal + */ + public static function handleUnserializeCallback($class) + { + trigger_error('Class not found: '.$class); + } } diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index d76aeb147ba4c..87739fc9753da 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG * added `%env(default:...)%` processor to fallback to a default value * added `%env(nullable:...)%` processor to allow empty variables to be processed as null values * added support for deprecating aliases + * made `ContainerParametersResource` final and not implement `Serializable` anymore 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Config/ContainerParametersResource.php b/src/Symfony/Component/DependencyInjection/Config/ContainerParametersResource.php index 7560c3356d978..e9a4fffe2ad1c 100644 --- a/src/Symfony/Component/DependencyInjection/Config/ContainerParametersResource.php +++ b/src/Symfony/Component/DependencyInjection/Config/ContainerParametersResource.php @@ -17,8 +17,10 @@ * Tracks container parameters. * * @author Maxime Steinhausser + * + * @final since Symfony 4.3 */ -class ContainerParametersResource implements ResourceInterface, \Serializable +class ContainerParametersResource implements ResourceInterface { private $parameters; @@ -38,22 +40,6 @@ public function __toString() return 'container_parameters_'.md5(serialize($this->parameters)); } - /** - * @internal - */ - public function serialize() - { - return serialize($this->parameters); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - $this->parameters = unserialize($serialized); - } - /** * @return array Tracked parameters */ diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 142a1d92fa85e..127406bcdeddb 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -8,6 +8,7 @@ CHANGELOG option is set to `single_text` * added `block_prefix` option to `BaseType`. * added `help_html` option to display the `help` text as HTML. + * `FormError` doesn't implement `Serializable` anymore * added `label_translation_parameters`, `attr_translation_parameters`, `help_translation_parameters` options to `FormType` to pass translation parameters to form labels, attributes (`placeholder` and `title`) and help text respectively. The passed parameters will replace placeholders in translation messages. @@ -32,7 +33,6 @@ CHANGELOG } ``` - 4.2.0 ----- diff --git a/src/Symfony/Component/Form/FormError.php b/src/Symfony/Component/Form/FormError.php index 6724ddc03c510..4e01a62e419a2 100644 --- a/src/Symfony/Component/Form/FormError.php +++ b/src/Symfony/Component/Form/FormError.php @@ -18,7 +18,7 @@ * * @author Bernhard Schussek */ -class FormError implements \Serializable +class FormError { protected $messageTemplate; protected $messageParameters; @@ -133,26 +133,4 @@ public function getOrigin() { return $this->origin; } - - /** - * @internal - */ - public function serialize() - { - return serialize([ - $this->message, - $this->messageTemplate, - $this->messageParameters, - $this->messagePluralization, - $this->cause, - ]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->message, $this->messageTemplate, $this->messageParameters, $this->messagePluralization, $this->cause) = unserialize($serialized, ['allowed_classes' => false]); - } } diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php index 2ca0f95f3c6e3..0603c38e05cd5 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php @@ -448,7 +448,7 @@ public function testSerializeWithFormAddedMultipleTimes() $this->dataCollector->collectViewVariables($form2View); $this->dataCollector->buildFinalFormTree($form2, $form2View); - $this->dataCollector->serialize(); + serialize($this->dataCollector); } public function testFinalFormReliesOnFormViewStructure() diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 5b974735e2647..2d1cfc4ba1d9e 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` * made `Symfony\Component\HttpKernel\EventListenerLocaleListener` set the default locale early + * made `FileLinkFormatter` final and not implement `Serializable` anymore 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php index 9476d50486f87..d83f7920df055 100644 --- a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php +++ b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php @@ -20,8 +20,10 @@ * Formats debug file links. * * @author Jérémy Romey + * + * @final since Symfony 4.3 */ -class FileLinkFormatter implements \Serializable +class FileLinkFormatter { private $fileLinkFormat; private $requestStack; @@ -64,17 +66,11 @@ public function format($file, $line) /** * @internal */ - public function serialize() + public function __sleep(): array { - return serialize($this->getFileLinkFormat()); - } + $this->getFileLinkFormat(); - /** - * @internal - */ - public function unserialize($serialized) - { - $this->fileLinkFormat = unserialize($serialized, ['allowed_classes' => false]); + return ['fileLinkFormat']; } /** From 5e16053c70c1c91322dc4deb100eed16e1f5a8b4 Mon Sep 17 00:00:00 2001 From: insidestyles Date: Sun, 17 Feb 2019 13:03:29 +0200 Subject: [PATCH 124/495] update test case for custom queue options --- .../Messenger/Tests/Transport/AmqpExt/ConnectionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index d3b11c7a35c3d..b8809368e5b3d 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -246,9 +246,9 @@ public function testPublishWithQueueOptions() 'type' => '*', ]; $amqpExchange->expects($this->once())->method('publish') - ->with('body', null, 1, ['delivery_mode' => 2, 'headers' => $headers]); + ->with('body', null, 1, ['delivery_mode' => 2, 'headers' => ['token' => 'uuid', 'type' => '*']]); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[attributes][delivery_mode]=2&queue[flags]=1', [], true, $factory); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[attributes][delivery_mode]=2&queue[attributes][headers][token]=uuid&queue[flags]=1', [], true, $factory); $connection->publish('body', $headers); } } From c8240a0423ac37a574c5cc883a48eba185d419be Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 14 Jan 2019 21:37:57 +0100 Subject: [PATCH 125/495] [Form] Add input_format option to DateType and DateTimeType --- src/Symfony/Component/Form/CHANGELOG.md | 1 + .../Form/Extension/Core/Type/DateTimeType.php | 5 ++++- .../Form/Extension/Core/Type/DateType.php | 5 ++++- .../Extension/Core/Type/DateTimeTypeTest.php | 15 +++++++++++++++ .../Tests/Extension/Core/Type/DateTypeTest.php | 15 +++++++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 127406bcdeddb..8da8a75255faa 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -32,6 +32,7 @@ CHANGELOG } } ``` + * added new option `input_format` to `DateType` and `DateTimeType` to specify the date format when using the `string` input. 4.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php index 4c0bdf203f064..93439acfc9fe6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php @@ -176,7 +176,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer()); } elseif ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( - new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone']) + new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], $options['input_format']) )); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( @@ -251,6 +251,7 @@ public function configureOptions(OptionsResolver $resolver) 'empty_data' => function (Options $options) { return $options['compound'] ? [] : ''; }, + 'input_format' => 'Y-m-d H:i:s', ]); // Don't add some defaults in order to preserve the defaults @@ -317,6 +318,8 @@ public function configureOptions(OptionsResolver $resolver) return ''; }); + + $resolver->setAllowedTypes('input_format', 'string'); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php index 81a928871dd08..ced29d88e04a2 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -154,7 +154,7 @@ class_exists('IntlTimeZone', false) ? \IntlTimeZone::createDefault() : null, $builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer()); } elseif ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( - new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'Y-m-d') + new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], $options['input_format']) )); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( @@ -283,6 +283,7 @@ public function configureOptions(OptionsResolver $resolver) return $options['compound'] ? [] : ''; }, 'choice_translation_domain' => false, + 'input_format' => 'Y-m-d', ]); $resolver->setNormalizer('placeholder', $placeholderNormalizer); @@ -305,6 +306,8 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('years', 'array'); $resolver->setAllowedTypes('months', 'array'); $resolver->setAllowedTypes('days', 'array'); + + $resolver->setAllowedTypes('input_format', 'string'); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php index 4f4966c5f8d2f..692462a607845 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php @@ -671,4 +671,19 @@ public function provideEmptyData() 'Compound choice field' => ['choice', ['date' => ['year' => '2018', 'month' => '11', 'day' => '11'], 'time' => ['hour' => '21', 'minute' => '23']], $expectedData], ]; } + + public function testSubmitStringWithCustomInputFormat(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'UTC', + 'input' => 'string', + 'widget' => 'single_text', + 'input_format' => 'd/m/Y H:i:s P', + ]); + + $form->submit('2018-01-14T21:29:00'); + + $this->assertSame('14/01/2018 21:29:00 +00:00', $form->getData()); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index 8a627c27e4a91..3ff363f958840 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -1037,4 +1037,19 @@ public function provideEmptyData() 'Compound choice fields' => ['choice', ['year' => '2018', 'month' => '11', 'day' => '11'], $expectedData], ]; } + + public function testSubmitStringWithCustomInputFormat(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'UTC', + 'widget' => 'single_text', + 'input' => 'string', + 'input_format' => 'd/m/Y', + ]); + + $form->submit('2018-01-14'); + + $this->assertSame('14/01/2018', $form->getData()); + } } From f3659b684e7474fe6b3d73c6402d0cf8a3998abb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 18 Feb 2019 19:32:59 +0100 Subject: [PATCH 126/495] [VarDumper] dump Closures' parameters once: in their signatures --- .../Component/VarDumper/Caster/ReflectionCaster.php | 13 +------------ .../VarDumper/Tests/Caster/ReflectionCasterTest.php | 5 +---- .../VarDumper/Tests/Dumper/CliDumperTest.php | 7 ------- .../VarDumper/Tests/Dumper/HtmlDumperTest.php | 7 ------- 4 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index 1ecfa2d2d1918..5290fedfcf044 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -52,18 +52,7 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, return []; } - if (isset($a[$prefix.'parameters'])) { - foreach ($a[$prefix.'parameters']->value as &$v) { - $param = $v; - $v = new EnumStub([]); - foreach (static::castParameter($param, [], $stub, true) as $k => $param) { - if ("\0" === $k[0]) { - $v->value[substr($k, 3)] = $param; - } - } - unset($v->value['position'], $v->value['isVariadic'], $v->value['byReference'], $v); - } - } + unset($a[$prefix.'parameters']); if ($f = $c->getFileName()) { $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index fd8194cca5959..f53f06ab5f43f 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -70,10 +70,7 @@ public function testClosureCaster() $this->assertDumpMatchesFormat( <<<'EOTXT' Closure($x) { -%Aparameters: { - $x: {} - } - use: { +%Ause: { $a: 123 $b: & 123 } diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index 3387dcdb24c14..fc623808ce1d6 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -81,13 +81,6 @@ public function testGet() "closure" => Closure(\$a, PDO &\$b = null) {#%d class: "Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest" this: Symfony\Component\VarDumper\Tests\Dumper\CliDumperTest {#%d …} - parameters: { - \$a: {} - &\$b: { - typeHint: "PDO" - default: null - } - } file: "%s%eTests%eFixtures%edumb-var.php" line: "{$var['line']} to {$var['line']}" } diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/HtmlDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/HtmlDumperTest.php index da8e21dff9c78..ae4ee8e6cc24b 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/HtmlDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/HtmlDumperTest.php @@ -85,13 +85,6 @@ public function testGet() class: "Symfony\Component\VarDumper\Tests\Dumper\HtmlDumperTest" this: HtmlDumperTest {#%d &%s;} - parameters: { - \$a: {} - &\$b: { - typeHint: "PDO" - default: null - } - } file: "%s%eVarDumper%eTests%eFixtures%edumb-var.php" line: "{$var['line']} to {$var['line']}" From 6672ac3f436f55a5a299e0fb67d687bb82d79fd2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 18 Feb 2019 19:48:10 +0100 Subject: [PATCH 127/495] [VarDumper] link paths in stack traces to IDE --- src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index 06cd11e63dd50..54f0ba153033c 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -236,7 +236,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is $ellipsis += 1 + \strlen($f['line']); } } - $srcAttr .= '&separator= '; + $srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); } else { $srcAttr .= '&separator=:'; } From 005e75cbab422ba7e71f309bbe8030cb2b34ff33 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 19 Feb 2019 15:40:04 +0100 Subject: [PATCH 128/495] [Form] Fix describing closures --- .../Component/Form/Console/Descriptor/TextDescriptor.php | 1 - .../Fixtures/Descriptor/default_option_with_normalizer.txt | 1 - .../Descriptor/overridden_option_with_default_closures.txt | 2 -- .../Fixtures/Descriptor/required_option_with_allowed_values.txt | 1 - 4 files changed, 5 deletions(-) diff --git a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php index 4ea8ab6d834e5..70ee44520eab8 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php @@ -188,7 +188,6 @@ private function getDumpFunction() $prefix = Caster::PREFIX_VIRTUAL; return [ - $prefix.'parameters' => isset($a[$prefix.'parameters']) ? \count($a[$prefix.'parameters']->value) : 0, $prefix.'file' => $a[$prefix.'file'], $prefix.'line' => $a[$prefix.'line'], ]; diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt index 391c3e694d974..8ed69a0dbf187 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt @@ -16,7 +16,6 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain Allowed values - %s ---------------- --------------------%s Normalizer Closure%s{%w - parameters: 2 %s file: "%s%eExtension%eCore%eType%eChoiceType.php"%w line: "%s to %s" %s } %s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt index 846d6f384684c..d8b68257fdb66 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt @@ -9,12 +9,10 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data) %s Closure(s): [ %s Closure%s{%w - parameters: 1 %s file: "%s%eExtension%eCore%eType%eFormType.php"%w line: "%s to %s" %s }, %s Closure%s{%w - parameters: 2 %s file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w line: "%s to %s" %s } %s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt index 8cc88a550ab70..5fedbef2e146b 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt @@ -17,7 +17,6 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo) ] %s ---------------- --------------------%s Normalizer Closure%s{%w - parameters: 2 %s file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w line: "%s to %s" %s } %s From 5fcd6b1d4ec5525fbd9276078b74e0b65dce559a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 19 Feb 2019 15:09:31 +0100 Subject: [PATCH 129/495] [VarDumper] add link to source next to class names --- .../DependencyInjection/DebugExtension.php | 5 +++++ .../DataCollector/DataCollector.php | 9 +++++++- .../HttpKernel/Debug/FileLinkFormatter.php | 12 ++++------- .../Tests/Debug/FileLinkFormatterTest.php | 12 ----------- .../VarDumper/Caster/ReflectionCaster.php | 20 +++++++++++++++--- .../VarDumper/Cloner/AbstractCloner.php | 11 ++++++++-- .../Component/VarDumper/Dumper/CliDumper.php | 21 +++++++++++-------- .../RequestContextProvider.php | 2 ++ .../Component/VarDumper/Dumper/HtmlDumper.php | 18 ++++++++++++---- .../Tests/Caster/ReflectionCasterTest.php | 2 +- .../VarDumper/Tests/Cloner/VarClonerTest.php | 2 ++ src/Symfony/Component/VarDumper/VarDumper.php | 2 ++ 12 files changed, 76 insertions(+), 40 deletions(-) diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php index 9c098a09962b0..a183e82cf8501 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php @@ -43,6 +43,11 @@ public function load(array $configs, ContainerBuilder $container) ->addMethodCall('setMinDepth', [$config['min_depth']]) ->addMethodCall('setMaxString', [$config['max_string_length']]); + if (method_exists(ReflectionClass::class, 'unsetClosureFileInfo')) { + $container->getDefinition('var_dumper.cloner') + ->addMethodCall('addCasters', ReflectionClass::UNSET_CLOSURE_FILE_INFO); + } + if (method_exists(HtmlDumper::class, 'setTheme') && 'dark' !== $config['theme']) { $container->getDefinition('var_dumper.html_dumper') ->addMethodCall('setTheme', [$config['theme']]); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php index efe1705179b6d..3b15868ff5c3e 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\VarDumper\Caster\CutStub; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; @@ -79,7 +80,7 @@ protected function cloneVar($var) */ protected function getCasters() { - return [ + $casters = [ '*' => function ($v, array $a, Stub $s, $isNested) { if (!$v instanceof Stub) { foreach ($a as $k => $v) { @@ -92,5 +93,11 @@ protected function getCasters() return $a; }, ]; + + if (method_exists(ReflectionCaster::class, 'unsetClosureFileInfo')) { + $casters += ReflectionCaster::UNSET_CLOSURE_FILE_INFO; + } + + return $casters; } } diff --git a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php index d83f7920df055..54defbf1d1111 100644 --- a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php +++ b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php @@ -87,21 +87,17 @@ public static function generateUrlFormat(UrlGeneratorInterface $router, $routeNa private function getFileLinkFormat() { - if ($this->fileLinkFormat) { - return $this->fileLinkFormat; - } if ($this->requestStack && $this->baseDir && $this->urlFormat) { $request = $this->requestStack->getMasterRequest(); - if ($request instanceof Request) { - if ($this->urlFormat instanceof \Closure && !$this->urlFormat = ($this->urlFormat)()) { - return; - } - return [ + if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) { + $this->fileLinkFormat = [ $request->getSchemeAndHttpHost().$request->getBasePath().$this->urlFormat, $this->baseDir.\DIRECTORY_SEPARATOR, '', ]; } } + + return $this->fileLinkFormat; } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php b/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php index 5c93bd90e3565..1f4d298bf3768 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php @@ -34,18 +34,6 @@ public function testWhenFileLinkFormatAndNoRequest() $this->assertSame("debug://open?url=file://$file&line=3", $sut->format($file, 3)); } - public function testWhenFileLinkFormatAndRequest() - { - $file = __DIR__.\DIRECTORY_SEPARATOR.'file.php'; - $requestStack = new RequestStack(); - $request = new Request(); - $requestStack->push($request); - - $sut = new FileLinkFormatter('debug://open?url=file://%f&line=%l', $requestStack, __DIR__, '/_profiler/open?file=%f&line=%l#line%l'); - - $this->assertSame("debug://open?url=file://$file&line=3", $sut->format($file, 3)); - } - public function testWhenNoFileLinkFormatAndRequest() { $file = __DIR__.\DIRECTORY_SEPARATOR.'file.php'; diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index 5290fedfcf044..c686962dbdd58 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -20,6 +20,8 @@ */ class ReflectionCaster { + const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__.'::unsetClosureFileInfo']; + private static $extraMap = [ 'docComment' => 'getDocComment', 'extension' => 'getExtensionName', @@ -46,15 +48,20 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, $stub->class .= self::getSignature($a); + if ($f = $c->getFileName()) { + $stub->attr['file'] = $f; + $stub->attr['line'] = $c->getStartLine(); + } + + unset($a[$prefix.'parameters']); + if ($filter & Caster::EXCLUDE_VERBOSE) { $stub->cut += ($c->getFileName() ? 2 : 0) + \count($a); return []; } - unset($a[$prefix.'parameters']); - - if ($f = $c->getFileName()) { + if ($f) { $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); $a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine(); } @@ -62,6 +69,13 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested, return $a; } + public static function unsetClosureFileInfo(\Closure $c, array $a) + { + unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); + + return $a; + } + public static function castGenerator(\Generator $c, array $a, Stub $stub, $isNested) { if (!class_exists('ReflectionGenerator', false)) { diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 80b5d548fb0b7..7891edf2a4674 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -279,7 +279,7 @@ protected function castObject(Stub $stub, $isNested) $stub->class = get_parent_class($class).'@anonymous'; } if (isset($this->classInfo[$class])) { - list($i, $parents, $hasDebugInfo) = $this->classInfo[$class]; + list($i, $parents, $hasDebugInfo, $fileInfo) = $this->classInfo[$class]; } else { $i = 2; $parents = [$class]; @@ -295,9 +295,16 @@ protected function castObject(Stub $stub, $isNested) } $parents[] = '*'; - $this->classInfo[$class] = [$i, $parents, $hasDebugInfo]; + $r = new \ReflectionClass($class); + $fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [ + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + + $this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo]; } + $stub->attr += $fileInfo; $a = Caster::castObject($obj, $class, $hasDebugInfo); try { diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index 3fb7ac619e55d..3ca3e33587c41 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -274,6 +274,7 @@ public function dumpString(Cursor $cursor, $str, $bin, $cut) public function enterHash(Cursor $cursor, $type, $class, $hasChild) { $this->dumpKey($cursor); + $attr = $cursor->attr; if ($this->collapseNextHash) { $cursor->skipChildren = true; @@ -282,11 +283,11 @@ public function enterHash(Cursor $cursor, $type, $class, $hasChild) $class = $this->utf8Encode($class); if (Cursor::HASH_OBJECT === $type) { - $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class).' {' : '{'; + $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).' {' : '{'; } elseif (Cursor::HASH_RESOURCE === $type) { - $prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' '); + $prefix = $this->style('note', $class.' resource', $attr).($hasChild ? ' {' : ' '); } else { - $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; + $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class, $attr).' [' : '['; } if ($cursor->softRefCount || 0 < $cursor->softRefHandle) { @@ -454,11 +455,9 @@ protected function style($style, $value, $attr = []) goto href; } - $style = $this->styles[$style]; - $map = static::$controlCharsMap; $startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : ''; - $endCchr = $this->colors ? "\033[m\033[{$style}m" : ''; + $endCchr = $this->colors ? "\033[m\033[{$this->styles[$style]}m" : ''; $value = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $startCchr, $endCchr) { $s = $startCchr; $c = $c[$i = 0]; @@ -473,7 +472,7 @@ protected function style($style, $value, $attr = []) if ($cchrCount && "\033" === $value[0]) { $value = substr($value, \strlen($startCchr)); } else { - $value = "\033[{$style}m".$value; + $value = "\033[{$this->styles[$style]}m".$value; } if ($cchrCount && $endCchr === substr($value, -\strlen($endCchr))) { $value = substr($value, 0, -\strlen($endCchr)); @@ -485,7 +484,11 @@ protected function style($style, $value, $attr = []) href: if ($this->colors && $this->handlesHrefGracefully) { if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], isset($attr['line']) ? $attr['line'] : 0)) { - $attr['href'] = $href; + if ('note' === $style) { + $value .= "\033]8;;{$href}\033\\^\033]8;;\033\\"; + } else { + $attr['href'] = $href; + } } if (isset($attr['href'])) { $value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\"; @@ -632,7 +635,7 @@ private function isWindowsTrueColor() private function getSourceLink($file, $line) { if ($fmt = $this->displayOptions['fileLinkFormat']) { - return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line); + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file); } return false; diff --git a/src/Symfony/Component/VarDumper/Dumper/ContextProvider/RequestContextProvider.php b/src/Symfony/Component/VarDumper/Dumper/ContextProvider/RequestContextProvider.php index bb3cc863fe302..3684a47535cfc 100644 --- a/src/Symfony/Component/VarDumper/Dumper/ContextProvider/RequestContextProvider.php +++ b/src/Symfony/Component/VarDumper/Dumper/ContextProvider/RequestContextProvider.php @@ -12,6 +12,7 @@ namespace Symfony\Component\VarDumper\Dumper\ContextProvider; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\VarCloner; /** @@ -29,6 +30,7 @@ public function __construct(RequestStack $requestStack) $this->requestStack = $requestStack; $this->cloner = new VarCloner(); $this->cloner->setMaxItems(0); + $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); } public function getContext(): ?array diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index 37651816e6629..0acf3b502bae1 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -314,13 +314,17 @@ function resetHighlightedNodes(root) { } function a(e, f) { - addEventListener(root, e, function (e) { + addEventListener(root, e, function (e, n) { if ('A' == e.target.tagName) { f(e.target, e); } else if ('A' == e.target.parentNode.tagName) { f(e.target.parentNode, e); - } else if (e.target.nextElementSibling && 'A' == e.target.nextElementSibling.tagName) { - f(e.target.nextElementSibling, e, true); + } else if ((n = e.target.nextElementSibling) && 'A' == n.tagName) { + if (!/\bsf-dump-toggle\b/.test(n.className)) { + n = n.nextElementSibling; + } + + f(n, e, true); } }); }; @@ -852,7 +856,13 @@ protected function style($style, $value, $attr = []) } elseif ('str' === $style && 1 < $attr['length']) { $style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); } elseif ('note' === $style && false !== $c = strrpos($v, '\\')) { - return sprintf('%s', $v, $style, substr($v, $c + 1)); + if (isset($attr['file']) && $link = $this->getSourceLink($attr['file'], isset($attr['line']) ? $attr['line'] : 0)) { + $link = sprintf('^', esc($this->utf8Encode($link))); + } else { + $link = ''; + } + + return sprintf('%s%s', $v, $style, substr($v, $c + 1), $link); } elseif ('protected' === $style) { $style .= ' title="Protected property"'; } elseif ('meta' === $style && isset($attr['title'])) { diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index f53f06ab5f43f..ebe9ab4b94bda 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -114,7 +114,7 @@ public function testClosureCasterExcludingVerbosity() { $var = function &($a = 5) {}; - $this->assertDumpEquals('Closure&($a = 5) { …6}', $var, Caster::EXCLUDE_VERBOSE); + $this->assertDumpEquals('Closure&($a = 5) { …5}', $var, Caster::EXCLUDE_VERBOSE); } public function testReflectionParameter() diff --git a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php index 3b180af49810d..d3141c6eaf285 100644 --- a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php @@ -411,6 +411,8 @@ public function testCaster() [position] => 1 [attr] => Array ( + [file] => %a%eVarClonerTest.php + [line] => 20 ) ) diff --git a/src/Symfony/Component/VarDumper/VarDumper.php b/src/Symfony/Component/VarDumper/VarDumper.php index 4271e63965d6d..009f662f3bf27 100644 --- a/src/Symfony/Component/VarDumper/VarDumper.php +++ b/src/Symfony/Component/VarDumper/VarDumper.php @@ -11,6 +11,7 @@ namespace Symfony\Component\VarDumper; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Dumper\HtmlDumper; @@ -29,6 +30,7 @@ public static function dump($var) { if (null === self::$handler) { $cloner = new VarCloner(); + $cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); if (isset($_SERVER['VAR_DUMPER_FORMAT'])) { $dumper = 'html' === $_SERVER['VAR_DUMPER_FORMAT'] ? new HtmlDumper() : new CliDumper(); From eab631fc454791dc144f650c780e51c32412c165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1chym=20Tou=C5=A1ek?= Date: Wed, 20 Feb 2019 09:40:26 +0100 Subject: [PATCH 130/495] [VarDumper] Implement DsCaster --- src/Symfony/Component/VarDumper/CHANGELOG.md | 7 ++- .../Component/VarDumper/Caster/DsCaster.php | 50 +++++++++++++++++++ .../VarDumper/Cloner/AbstractCloner.php | 8 +++ 3 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/VarDumper/Caster/DsCaster.php diff --git a/src/Symfony/Component/VarDumper/CHANGELOG.md b/src/Symfony/Component/VarDumper/CHANGELOG.md index 0ef5e85bdbe1e..5f88029c01308 100644 --- a/src/Symfony/Component/VarDumper/CHANGELOG.md +++ b/src/Symfony/Component/VarDumper/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added `DsCaster` to support dumping the contents of data structures from the Ds extension + 4.2.0 ----- @@ -34,4 +39,4 @@ CHANGELOG 2.7.0 ----- - * deprecated Cloner\Data::getLimitedClone(). Use withMaxDepth, withMaxItemsPerDepth or withRefHandles instead. + * deprecated `Cloner\Data::getLimitedClone()`. Use `withMaxDepth`, `withMaxItemsPerDepth` or `withRefHandles` instead. diff --git a/src/Symfony/Component/VarDumper/Caster/DsCaster.php b/src/Symfony/Component/VarDumper/Caster/DsCaster.php new file mode 100644 index 0000000000000..1140b099e732d --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/DsCaster.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Ds\Deque; +use Ds\Map; +use Ds\PriorityQueue; +use Ds\Queue; +use Ds\Set; +use Ds\Stack; +use Ds\Vector; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Ds extension classes to array representation. + * + * @author Jáchym Toušek + */ +class DsCaster +{ + /** + * @param Set|Deque|Vector|Stack|Queue|PriorityQueue $c + */ + public static function castDs($c, array $a, Stub $stub, bool $isNested): array + { + $prefix = Caster::PREFIX_VIRTUAL; + $a = $c->toArray(); + $a[$prefix.'capacity'] = $c->capacity(); + + return $a; + } + + public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array + { + $prefix = Caster::PREFIX_VIRTUAL; + $a = $c->pairs()->toArray(); + $a[$prefix.'capacity'] = $c->capacity(); + + return $a; + } +} diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 80b5d548fb0b7..3b41c6781b4f1 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -125,6 +125,14 @@ abstract class AbstractCloner implements ClonerInterface 'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'], + 'Ds\Set' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\Vector' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\Deque' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\Stack' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\Queue' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\PriorityQueue' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'], + ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], From 51ed942ef5f4a902730c6617ef8e8c1aa9b04e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bogusz?= Date: Thu, 21 Feb 2019 00:39:50 +0100 Subject: [PATCH 131/495] Additional addons for the ghost --- src/Symfony/Component/Debug/ExceptionHandler.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index c99c5943960ad..18d56f3469eb7 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -32,9 +32,15 @@ class ExceptionHandler { private const GHOST_ADDONS = [ - '02-14' => '', + '02-14' => self::GHOST_HEART, + '02-29' => self::GHOST_PLUS, + '10-18' => self::GHOST_GIFT, ]; + private const GHOST_GIFT = 'M124.00534057617188,5.3606138080358505 C124.40059661865234,4.644828304648399 125.1237564086914,3.712414965033531 123.88127899169922,3.487462028861046 C123.53517150878906,3.3097832053899765 123.18894958496094,2.9953975528478622 122.8432846069336,3.345616325736046 C122.07421112060547,3.649444565176964 121.40750122070312,4.074306473135948 122.2164306640625,4.869479164481163 C122.57514953613281,5.3830065578222275 122.90142822265625,6.503447040915489 123.3077621459961,6.626829609274864 C123.55027770996094,6.210384353995323 123.7774658203125,5.785196766257286 124.00534057617188,5.3606138080358505 zM122.30630493164062,7.336987480521202 C121.60028076171875,6.076864704489708 121.03211975097656,4.72498320043087 120.16796875,3.562500938773155 C119.11695098876953,2.44033907353878 117.04605865478516,2.940566048026085 116.57544708251953,4.387995228171349 C115.95028686523438,5.819030746817589 117.2991714477539,7.527640804648399 118.826171875,7.348545059561729 C119.98493194580078,7.367936596274376 121.15027618408203,7.420116886496544 122.30630493164062,7.336987480521202 zM128.1732177734375,7.379541382193565 C129.67486572265625,7.17823551595211 130.53842163085938,5.287807449698448 129.68344116210938,4.032590612769127 C128.92578125,2.693056806921959 126.74605560302734,2.6463639587163925 125.98509216308594,4.007616028189659 C125.32617950439453,5.108129009604454 124.75428009033203,6.258124336600304 124.14962768554688,7.388818249106407 C125.48638916015625,7.465229496359825 126.8357162475586,7.447416767477989 128.1732177734375,7.379541382193565 zM130.6601104736328,8.991325363516808 C131.17202758789062,8.540884003043175 133.1543731689453,8.009847149252892 131.65304565429688,7.582054600119591 C131.2811279296875,7.476506695151329 130.84751892089844,6.99234913289547 130.5132598876953,7.124847874045372 C129.78744506835938,8.02728746831417 128.67140197753906,8.55669592320919 127.50616455078125,8.501235947012901 C127.27806091308594,8.576229080557823 126.11459350585938,8.38720129430294 126.428955078125,8.601900085806847 C127.25099182128906,9.070617660880089 128.0523223876953,9.579657539725304 128.902587890625,9.995706543326378 C129.49813842773438,9.678531631827354 130.0761260986328,9.329126343131065 130.6601104736328,8.991325363516808 zM118.96446990966797,9.246344551444054 C119.4022445678711,8.991325363516808 119.84001922607422,8.736305221915245 120.27779388427734,8.481284126639366 C118.93965911865234,8.414779648184776 117.40827941894531,8.607666000723839 116.39698791503906,7.531384453177452 C116.11186981201172,7.212117180228233 115.83845520019531,6.846597656607628 115.44329071044922,7.248530372977257 C114.96995544433594,7.574637398123741 113.5140609741211,7.908811077475548 114.63501739501953,8.306883797049522 C115.61112976074219,8.883499130606651 116.58037567138672,9.474181160330772 117.58061218261719,10.008124336600304 C118.05723571777344,9.784612640738487 118.50651550292969,9.5052699893713 118.96446990966797,9.246344551444054 zM125.38018035888672,12.091858848929405 C125.9474868774414,11.636047348380089 127.32159423828125,11.201767906546593 127.36749267578125,10.712632164359093 C126.08487701416016,9.974547371268272 124.83960723876953,9.152772888541222 123.49772644042969,8.528907760977745 C123.03594207763672,8.353693947196007 122.66152954101562,8.623294815421104 122.28982543945312,8.857431396842003 C121.19065856933594,9.51122473180294 120.06505584716797,10.12446115911007 119.00167083740234,10.835315689444542 C120.39238739013672,11.69529627263546 121.79983520507812,12.529837593436241 123.22095489501953,13.338589653372765 C123.94580841064453,12.932025894522667 124.66128540039062,12.508862480521202 125.38018035888672,12.091858848929405 zM131.07164001464844,13.514615997672081 C131.66018676757812,13.143282875418663 132.2487335205078,12.771927818655968 132.8372802734375,12.400571808218956 C132.8324737548828,11.156818374991417 132.8523406982422,9.912529930472374 132.81829833984375,8.669195160269737 C131.63046264648438,9.332009300589561 130.45948791503906,10.027913078665733 129.30828857421875,10.752535805106163 C129.182373046875,12.035354599356651 129.24623107910156,13.33940313756466 129.27359008789062,14.628684982657433 C129.88104248046875,14.27079389989376 130.4737548828125,13.888019546866417 131.07164001464844,13.514640793204308 zM117.26847839355469,12.731024727225304 C117.32825469970703,11.67083452641964 117.45709991455078,10.46224020421505 116.17853546142578,10.148179039359093 C115.37110900878906,9.77159021794796 114.25194549560547,8.806716904044151 113.62991333007812,8.81639002263546 C113.61052703857422,10.0110072940588 113.62078857421875,11.20585821568966 113.61869049072266,12.400571808218956 C114.81139373779297,13.144886955618858 115.98292541503906,13.925040230154991 117.20137023925781,14.626662239432335 C117.31951141357422,14.010867103934288 117.24227905273438,13.35805033147335 117.26847839355469,12.731024727225304 zM125.80937957763672,16.836034759879112 C126.51483917236328,16.390663132071495 127.22030639648438,15.945291504263878 127.92576599121094,15.49991987645626 C127.92250061035156,14.215868934988976 127.97560119628906,12.929980263113976 127.91757202148438,11.647302612662315 C127.14225769042969,11.869626984000206 126.25550079345703,12.556857094168663 125.43866729736328,12.983742699027061 C124.82704162597656,13.342005714774132 124.21542358398438,13.700271591544151 123.60379028320312,14.05853746831417 C123.61585235595703,15.429577812552452 123.57081604003906,16.803131088614464 123.64839172363281,18.172149643301964 C124.37957000732422,17.744937881827354 125.09130859375,17.284801468253136 125.80937957763672,16.836034759879112 zM122.8521499633789,16.115344032645226 C122.8521499633789,15.429741844534874 122.8521499633789,14.744139656424522 122.8521499633789,14.05853746831417 C121.43595123291016,13.230924591422081 120.02428436279297,12.395455345511436 118.60256958007812,11.577354416251183 C118.52394104003906,12.888403877615929 118.56887817382812,14.204405769705772 118.55702209472656,15.517732605338097 C119.97289276123047,16.4041957706213 121.37410736083984,17.314891800284386 122.80789947509766,18.172149643301964 C122.86368560791016,17.488990768790245 122.84332275390625,16.800363525748253 122.8521499633789,16.115344032645226 zM131.10684204101562,18.871450409293175 C131.68399047851562,18.48711584508419 132.2611541748047,18.10278509557247 132.8383026123047,17.718475326895714 C132.81423950195312,16.499977096915245 132.89776611328125,15.264989838004112 132.77627563476562,14.05993078649044 C131.5760040283203,14.744719490408897 130.41763305664062,15.524359688162804 129.23875427246094,16.255397781729698 C129.26707458496094,17.516149505972862 129.18060302734375,18.791316971182823 129.3108367919922,20.041303619742393 C129.91973876953125,19.667551025748253 130.51010131835938,19.264152511954308 131.10684204101562,18.871450409293175 zM117.2557373046875,18.188333496451378 C117.25104522705078,17.549470886588097 117.24633026123047,16.91058538854122 117.24163055419922,16.271720871329308 C116.04924774169922,15.525708183646202 114.87187957763672,14.75476549565792 113.66158294677734,14.038097366690636 C113.5858383178711,15.262084946036339 113.62901306152344,16.49083898961544 113.61761474609375,17.717010483145714 C114.82051086425781,18.513254150748253 116.00987243652344,19.330610260367393 117.22888946533203,20.101993545889854 C117.27559661865234,19.466014847159386 117.25241088867188,18.825733169913292 117.2557373046875,18.188333496451378 zM125.8398666381836,22.38675306737423 C126.54049682617188,21.921453461050987 127.24110412597656,21.456151947379112 127.94172668457031,20.99083136022091 C127.94009399414062,19.693386062979698 127.96646118164062,18.395381912589073 127.93160247802734,17.098379120230675 C126.50540924072266,17.97775076329708 125.08877563476562,18.873308166861534 123.68258666992188,19.78428266942501 C123.52366638183594,21.03710363805294 123.626708984375,22.32878302037716 123.62647247314453,23.595300659537315 C124.06291198730469,23.86113165318966 125.1788101196289,22.68297766149044 125.8398666381836,22.38675306737423 zM122.8521499633789,21.83134649693966 C122.76741790771484,20.936696991324425 123.21651458740234,19.67745779454708 122.0794677734375,19.330633148550987 C120.93280029296875,18.604360565543175 119.7907485961914,17.870157226920128 118.62899780273438,17.16818617284298 C118.45966339111328,18.396427139639854 118.63676452636719,19.675991043448448 118.50668334960938,20.919256195425987 C119.89984130859375,21.92635916173458 121.32942199707031,22.88914106786251 122.78502655029297,23.803510650992393 C122.90177917480469,23.1627406924963 122.82917022705078,22.48402212560177 122.8521499633789,21.83134649693966 zM117.9798355102539,21.59483526647091 C116.28416442871094,20.46288488805294 114.58848571777344,19.330957397818565 112.892822265625,18.199007019400597 C112.89473724365234,14.705654129385948 112.84647369384766,11.211485847830772 112.90847778320312,7.718807205557823 C113.7575912475586,7.194885239005089 114.66117858886719,6.765397056937218 115.5350341796875,6.284702762961388 C114.97061157226562,4.668964847922325 115.78496551513672,2.7054970115423203 117.42159271240234,2.1007001250982285 C118.79354095458984,1.537783369421959 120.44731903076172,2.0457767099142075 121.32200622558594,3.23083733022213 C121.95732116699219,2.9050118774175644 122.59264373779297,2.5791852325201035 123.22796630859375,2.253336176276207 C123.86669921875,2.5821153968572617 124.50543975830078,2.9108948558568954 125.1441650390625,3.23967407643795 C126.05941009521484,2.154020771384239 127.62747192382812,1.5344576686620712 128.986328125,2.1429056972265244 C130.61741638183594,2.716217741370201 131.50650024414062,4.675290569663048 130.9215545654297,6.2884936183691025 C131.8018341064453,6.78548763692379 132.7589111328125,7.1738648265600204 133.5660400390625,7.780336365103722 C133.60182189941406,11.252970680594444 133.56637573242188,14.726140961050987 133.5631103515625,18.199007019400597 C130.18914794921875,20.431867584586143 126.86984252929688,22.74994657933712 123.44108581542969,24.897907242178917 C122.44406127929688,24.897628769278526 121.5834732055664,23.815067276358604 120.65831756591797,23.37616156041622 C119.76387023925781,22.784828171133995 118.87168884277344,22.19007681310177 117.9798355102539,21.59483526647091 z'; + private const GHOST_HEART = 'M125.91386369681868,8.305165958366445 C128.95033202169043,-0.40540639102854037 140.8469835342744,8.305165958366445 125.91386369681868,19.504526138305664 C110.98208663272044,8.305165958366445 122.87795231771452,-0.40540639102854037 125.91386369681868,8.305165958366445 z'; + private const GHOST_PLUS = 'M111.36824226379395,8.969108581542969 L118.69175148010254,8.969108581542969 L118.69175148010254,1.6455793380737305 L126.20429420471191,1.6455793380737305 L126.20429420471191,8.969108581542969 L133.52781105041504,8.969108581542969 L133.52781105041504,16.481630325317383 L126.20429420471191,16.481630325317383 L126.20429420471191,23.805158615112305 L118.69175148010254,23.805158615112305 L118.69175148010254,16.481630325317383 L111.36824226379395,16.481630325317383 z'; + private $debug; private $charset; private $handler; @@ -447,6 +453,10 @@ private function getSymfonyGhostAsSvg() private function addElementToGhost() { - return self::GHOST_ADDONS[\date('m-d')] ?? ''; + if (!isset(self::GHOST_ADDONS[\date('m-d')])) { + return; + } + + return ''; } } From 42e8f5e3a240aa2d05e4a79a00df605a969f088b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 16 Feb 2019 11:15:17 +0100 Subject: [PATCH 132/495] add option to render NumberType as type="number" --- .../views/Form/form_div_layout.html.twig | 2 +- .../AbstractBootstrap3LayoutTest.php | 16 +++++++++++ src/Symfony/Component/Form/CHANGELOG.md | 1 + .../NumberToLocalizedStringTransformer.php | 6 +++-- .../Form/Extension/Core/Type/NumberType.php | 27 ++++++++++++++++++- .../Form/Tests/AbstractLayoutTest.php | 17 ++++++++++++ .../Extension/Core/Type/NumberTypeTest.php | 24 +++++++++++++++++ 7 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 234faab533d61..52a639a33365f 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -170,7 +170,7 @@ {%- endblock dateinterval_widget -%} {%- block number_widget -%} - {# type="number" doesn't work with floats #} + {# type="number" doesn't work with floats in localized formats #} {%- set type = type|default('text') -%} {{ block('form_widget_simple') }} {%- endblock number_widget -%} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 160c18cce3cd3..254f9a4d1fc6b 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -2089,6 +2089,22 @@ public function testNumber() ); } + public function testRenderNumberWithHtml5NumberType() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\NumberType', 1234.56, [ + 'html5' => true, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], + '/input + [@type="number"] + [@name="name"] + [@class="my&class form-control"] + [@value="1234.56"] +' + ); + } + public function testPassword() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PasswordType', 'foo&bar'); diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 142a1d92fa85e..302f0ac1b9132 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added `html5` option to `NumberType` that allows to render `type="number"` input fields * deprecated using the `date_format`, `date_widget`, and `time_widget` options of the `DateTimeType` when the `widget` option is set to `single_text` * added `block_prefix` option to `BaseType`. diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index b019fff4a8e72..a93a9bf246f0f 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -77,8 +77,9 @@ class NumberToLocalizedStringTransformer implements DataTransformerInterface protected $roundingMode; private $scale; + private $locale; - public function __construct(int $scale = null, ?bool $grouping = false, ?int $roundingMode = self::ROUND_HALF_UP) + public function __construct(int $scale = null, ?bool $grouping = false, ?int $roundingMode = self::ROUND_HALF_UP, string $locale = null) { if (null === $grouping) { $grouping = false; @@ -91,6 +92,7 @@ public function __construct(int $scale = null, ?bool $grouping = false, ?int $ro $this->scale = $scale; $this->grouping = $grouping; $this->roundingMode = $roundingMode; + $this->locale = $locale; } /** @@ -214,7 +216,7 @@ public function reverseTransform($value) */ protected function getNumberFormatter() { - $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL); + $formatter = new \NumberFormatter($this->locale ?? \Locale::getDefault(), \NumberFormatter::DECIMAL); if (null !== $this->scale) { $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, $this->scale); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php b/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php index 1054b5899bd13..a0257f0269628 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php @@ -12,8 +12,12 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; +use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; class NumberType extends AbstractType @@ -26,10 +30,21 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder->addViewTransformer(new NumberToLocalizedStringTransformer( $options['scale'], $options['grouping'], - $options['rounding_mode'] + $options['rounding_mode'], + $options['html5'] ? 'en' : null )); } + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + if ($options['html5']) { + $view->vars['type'] = 'number'; + } + } + /** * {@inheritdoc} */ @@ -41,6 +56,7 @@ public function configureOptions(OptionsResolver $resolver) 'grouping' => false, 'rounding_mode' => NumberToLocalizedStringTransformer::ROUND_HALF_UP, 'compound' => false, + 'html5' => false, ]); $resolver->setAllowedValues('rounding_mode', [ @@ -54,6 +70,15 @@ public function configureOptions(OptionsResolver $resolver) ]); $resolver->setAllowedTypes('scale', ['null', 'int']); + $resolver->setAllowedTypes('html5', 'bool'); + + $resolver->setNormalizer('grouping', function (Options $options, $value) { + if (true === $value && $options['html5']) { + throw new LogicException('Cannot use the "grouping" option when the "html5" option is enabled.'); + } + + return $value; + }); } /** diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index b5f0b8f84e04e..5b4b84e9e5b99 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -1871,6 +1871,23 @@ public function testNumber() ); } + public function testRenderNumberWithHtml5NumberType() + { + $this->requiresFeatureSet(403); + + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\NumberType', 1234.56, [ + 'html5' => true, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), [], +'/input + [@type="number"] + [@name="name"] + [@value="1234.56"] +' + ); + } + public function testPassword() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PasswordType', 'foo&bar'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php index c19c82b117697..1ab6c8e9fbc76 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php @@ -75,4 +75,28 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = '10', $expectedD $this->assertSame($expectedData, $form->getNormData()); $this->assertSame($expectedData, $form->getData()); } + + public function testIgnoresDefaultLocaleToRenderHtml5NumberWidgets() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'scale' => 2, + 'rounding_mode' => \NumberFormatter::ROUND_UP, + 'html5' => true, + ]); + $form->setData(12345.54321); + + $this->assertSame('12345.55', $form->createView()->vars['value']); + $this->assertSame('12345.55', $form->getViewData()); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\LogicException + */ + public function testGroupingNotAllowedWithHtml5Widget() + { + $this->factory->create(static::TESTED_TYPE, null, [ + 'grouping' => true, + 'html5' => true, + ]); + } } From b70c1b6e0d1b0fccd01a4ae46eb499a2e9007eda Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 4 Oct 2018 13:05:56 +0200 Subject: [PATCH 133/495] deprecate custom formats with HTML5 widgets --- UPGRADE-4.3.md | 1 + UPGRADE-5.0.md | 1 + src/Symfony/Component/Form/CHANGELOG.md | 1 + .../Form/Extension/Core/Type/DateTimeType.php | 14 +++++++++++++- .../Form/Extension/Core/Type/DateType.php | 10 +++++++++- .../Form/Tests/Command/DebugCommandTest.php | 2 +- .../Extension/Core/Type/DateTimeTypeTest.php | 3 +++ .../Tests/Extension/Core/Type/DateTypeTest.php | 15 +++++++++++++++ 8 files changed, 44 insertions(+), 3 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 8050fed2679bc..7a2dca20633fa 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -23,6 +23,7 @@ Config Form ---- + * Using the `format` option of `DateType` and `DateTimeType` when the `html5` option is enabled is deprecated. * Using names for buttons that do not start with a letter, a digit, or an underscore is deprecated and will lead to an exception in 5.0. * Using names for buttons that do not contain only letters, digits, underscores, hyphens, and colons is deprecated and diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 07a21d558bf9b..f61211c1cc15e 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -78,6 +78,7 @@ Finder Form ---- + * Removed support for using the `format` option of `DateType` and `DateTimeType` when the `html5` option is enabled. * Using names for buttons that do not start with a letter, a digit, or an underscore leads to an exception. * Using names for buttons that do not contain only letters, digits, underscores, hyphens, and colons leads to an exception. diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 2304727571255..d25fbc6a4c0bf 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Using the `format` option of `DateType` and `DateTimeType` when the `html5` option is enabled is deprecated. * Using names for buttons that do not start with a letter, a digit, or an underscore is deprecated and will lead to an exception in 5.0. * Using names for buttons that do not contain only letters, digits, underscores, hyphens, and colons is deprecated and diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php index 291d86af6fc14..4e84b71a7c8e4 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php @@ -159,6 +159,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) $dateOptions['input'] = $timeOptions['input'] = 'array'; $dateOptions['error_bubbling'] = $timeOptions['error_bubbling'] = true; + if (isset($dateOptions['format']) && DateType::HTML5_FORMAT !== $dateOptions['format']) { + $dateOptions['html5'] = false; + } + $builder ->addViewTransformer(new DataTransformerChain([ new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts), @@ -294,6 +298,8 @@ public function configureOptions(OptionsResolver $resolver) 'choice', ]); + $resolver->setAllowedTypes('input_format', 'string'); + $resolver->setDeprecated('date_format', function (Options $options, $dateFormat) { if (null !== $dateFormat && 'single_text' === $options['widget'] && self::HTML5_FORMAT === $options['format']) { return sprintf('Using the "date_format" option of %s with an HTML5 date widget is deprecated since Symfony 4.3 and will lead to an exception in 5.0.', self::class); @@ -318,8 +324,14 @@ public function configureOptions(OptionsResolver $resolver) return ''; }); + $resolver->setDeprecated('html5', function (Options $options, $html5) { + if ($html5 && self::HTML5_FORMAT !== $options['format']) { + return sprintf('Using a custom format when the "html5" option of %s is enabled is deprecated since Symfony 4.3 and will lead to an exception in 5.0.', self::class); + //throw new LogicException(sprintf('Cannot use the "format" option of %s when the "html5" option is disabled.', self::class)); + } - $resolver->setAllowedTypes('input_format', 'string'); + return ''; + }); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php index ced29d88e04a2..39002df2b6d24 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -306,8 +306,16 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('years', 'array'); $resolver->setAllowedTypes('months', 'array'); $resolver->setAllowedTypes('days', 'array'); - $resolver->setAllowedTypes('input_format', 'string'); + + $resolver->setDeprecated('html5', function (Options $options, $html5) { + if ($html5 && 'single_text' === $options['widget'] && self::HTML5_FORMAT !== $options['format']) { + return sprintf('Using a custom format when the "html5" option of %s is enabled is deprecated since Symfony 4.3 and will lead to an exception in 5.0.', self::class); + //throw new LogicException(sprintf('Cannot use the "format" option of %s when the "html5" option is disabled.', self::class)); + } + + return ''; + }); } /** diff --git a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php index 99391245da97d..b572daf7b2bbe 100644 --- a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php @@ -45,7 +45,7 @@ public function testDebugDeprecatedDefaults() Built-in form types (Symfony\Component\Form\Extension\Core\Type) ---------------------------------------------------------------- - DateTimeType, IntegerType, TimezoneType + BirthdayType, DateTimeType, DateType, IntegerType, TimezoneType Service form types ------------------ diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php index 20899c15701df..93935157fe9c2 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php @@ -470,6 +470,9 @@ public function testDontPassHtml5TypeIfHtml5NotAllowed() $this->assertArrayNotHasKey('type', $view->vars); } + /** + * @group legacy + */ public function testDontPassHtml5TypeIfNotHtml5Format() { $view = $this->factory->create(static::TESTED_TYPE, null, [ diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index 3ff363f958840..f84547141fc9a 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -76,6 +76,7 @@ public function testSubmitFromSingleTextDateTimeWithCustomFormat() 'widget' => 'single_text', 'input' => 'datetime', 'format' => 'yyyy', + 'html5' => false, ]); $form->submit('2010'); @@ -93,6 +94,7 @@ public function testSubmitFromSingleTextDateTime() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'widget' => 'single_text', @@ -114,6 +116,7 @@ public function testSubmitFromSingleTextDateTimeImmutable() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'widget' => 'single_text', @@ -136,6 +139,7 @@ public function testSubmitFromSingleTextString() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'widget' => 'single_text', @@ -157,6 +161,7 @@ public function testSubmitFromSingleTextTimestamp() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'widget' => 'single_text', @@ -180,6 +185,7 @@ public function testSubmitFromSingleTextRaw() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'widget' => 'single_text', @@ -270,6 +276,7 @@ public function testSubmitFromInputDateTimeDifferentPattern() 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'format' => 'MM*yyyy*dd', + 'html5' => false, 'widget' => 'single_text', 'input' => 'datetime', ]); @@ -286,6 +293,7 @@ public function testSubmitFromInputStringDifferentPattern() 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'format' => 'MM*yyyy*dd', + 'html5' => false, 'widget' => 'single_text', 'input' => 'string', ]); @@ -302,6 +310,7 @@ public function testSubmitFromInputTimestampDifferentPattern() 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'format' => 'MM*yyyy*dd', + 'html5' => false, 'widget' => 'single_text', 'input' => 'timestamp', ]); @@ -320,6 +329,7 @@ public function testSubmitFromInputRawDifferentPattern() 'model_timezone' => 'UTC', 'view_timezone' => 'UTC', 'format' => 'MM*yyyy*dd', + 'html5' => false, 'widget' => 'single_text', 'input' => 'array', ]); @@ -368,6 +378,7 @@ public function testThrowExceptionIfFormatIsNoPattern() { $this->factory->create(static::TESTED_TYPE, null, [ 'format' => '0', + 'html5' => false, 'widget' => 'single_text', 'input' => 'string', ]); @@ -394,6 +405,7 @@ public function testThrowExceptionIfFormatMissesYearMonthAndDayWithSingleTextWid $this->factory->create(static::TESTED_TYPE, null, [ 'widget' => 'single_text', 'format' => 'wrong', + 'html5' => false, ]); } @@ -456,6 +468,7 @@ public function testSetDataWithNegativeTimezoneOffsetStringInput() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'America/New_York', 'input' => 'string', @@ -478,6 +491,7 @@ public function testSetDataWithNegativeTimezoneOffsetDateTimeInput() $form = $this->factory->create(static::TESTED_TYPE, null, [ 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, 'model_timezone' => 'UTC', 'view_timezone' => 'America/New_York', 'input' => 'datetime', @@ -856,6 +870,7 @@ public function testDontPassHtml5TypeIfNotHtml5Format() $view = $this->factory->create(static::TESTED_TYPE, null, [ 'widget' => 'single_text', 'format' => \IntlDateFormatter::MEDIUM, + 'html5' => false, ]) ->createView(); From 423a54f46e68e18220cd1e65959e71d8a2eca9d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bogusz?= Date: Mon, 14 Jan 2019 00:50:28 +0100 Subject: [PATCH 134/495] [Console] Added suggestions for missing packages --- .../SuggestMissingPackageSubscriber.php | 83 +++++++++++++++++++ .../Resources/config/console.xml | 4 + .../Tests/Console/ApplicationTest.php | 31 +++++++ 3 files changed, 118 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/EventListener/SuggestMissingPackageSubscriber.php diff --git a/src/Symfony/Bundle/FrameworkBundle/EventListener/SuggestMissingPackageSubscriber.php b/src/Symfony/Bundle/FrameworkBundle/EventListener/SuggestMissingPackageSubscriber.php new file mode 100644 index 0000000000000..692a878a9d507 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/SuggestMissingPackageSubscriber.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\EventListener; + +use Symfony\Component\Console\ConsoleEvents; +use Symfony\Component\Console\Event\ConsoleErrorEvent; +use Symfony\Component\Console\Exception\CommandNotFoundException; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; + +/** + * Suggests a package, that should be installed (via composer), + * if the package is missing, and the input command namespace can be mapped to a Symfony bundle. + * + * @author Przemysław Bogusz + * + * @internal + */ +final class SuggestMissingPackageSubscriber implements EventSubscriberInterface +{ + private const PACKAGES = [ + 'doctrine' => [ + 'fixtures' => ['DoctrineFixturesBundle', 'doctrine/doctrine-fixtures-bundle --dev'], + 'mongodb' => ['DoctrineMongoDBBundle', 'doctrine/mongodb-odm-bundle'], + '_default' => ['Doctrine ORM', 'symfony/orm-pack'], + ], + 'generate' => [ + '_default' => ['SensioGeneratorBundle', 'sensio/generator-bundle'], + ], + 'make' => [ + '_default' => ['MakerBundle', 'symfony/maker-bundle --dev'], + ], + 'server' => [ + 'dump' => ['VarDumper Component', 'symfony/var-dumper --dev'], + '_default' => ['WebServerBundle', 'symfony/web-server-bundle --dev'], + ], + ]; + + public function onConsoleError(ConsoleErrorEvent $event): void + { + if (!$event->getError() instanceof CommandNotFoundException) { + return; + } + + [$namespace, $command] = explode(':', $event->getInput()->getFirstArgument()) + [1 => '']; + + if (!isset(self::PACKAGES[$namespace])) { + return; + } + + if (isset(self::PACKAGES[$namespace][$command])) { + $suggestion = self::PACKAGES[$namespace][$command]; + $exact = true; + } else { + $suggestion = self::PACKAGES[$namespace]['_default']; + $exact = false; + } + + $error = $event->getError(); + + if ($error->getAlternatives() && !$exact) { + return; + } + + $message = sprintf("%s\n\nYou may be looking for a command provided by the \"%s\" which is currently not installed. Try running \"composer require %s\".", $error->getMessage(), $suggestion[0], $suggestion[1]); + $event->setError(new CommandNotFoundException($message)); + } + + public static function getSubscribedEvents(): array + { + return [ + ConsoleEvents::ERROR => ['onConsoleError', 0], + ]; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 3d9f3a8188275..f98281074062b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -13,6 +13,10 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php index 6662efd4a40a0..5021d56733158 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/ApplicationTest.php @@ -12,8 +12,11 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Console; use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Bundle\FrameworkBundle\EventListener\SuggestMissingPackageSubscriber; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Event\ConsoleErrorEvent; +use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\NullOutput; @@ -226,6 +229,34 @@ public function testRunOnlyWarnsOnUnregistrableCommandAtTheEnd() $this->assertContains(trim('[WARNING] Some commands could not be registered:'), trim($display[1])); } + public function testSuggestingPackagesWithExactMatch() + { + $result = $this->createEventForSuggestingPackages('server:dump', []); + $this->assertRegExp('/You may be looking for a command provided by/', $result); + } + + public function testSuggestingPackagesWithPartialMatchAndNoAlternatives() + { + $result = $this->createEventForSuggestingPackages('server', []); + $this->assertRegExp('/You may be looking for a command provided by/', $result); + } + + public function testSuggestingPackagesWithPartialMatchAndAlternatives() + { + $result = $this->createEventForSuggestingPackages('server', ['server:run']); + $this->assertNotRegExp('/You may be looking for a command provided by/', $result); + } + + private function createEventForSuggestingPackages(string $command, array $alternatives = []): string + { + $error = new CommandNotFoundException('', $alternatives); + $event = new ConsoleErrorEvent(new ArrayInput([$command]), new NullOutput(), $error); + $subscriber = new SuggestMissingPackageSubscriber(); + $subscriber->onConsoleError($event); + + return $event->getError()->getMessage(); + } + private function getKernel(array $bundles, $useDispatcher = false) { $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); From 9f8510315135d5f131f96a0c9f5538c91bda9b5b Mon Sep 17 00:00:00 2001 From: Sam Fleming Date: Fri, 19 Oct 2018 21:49:47 +0100 Subject: [PATCH 135/495] [DX][WebProfilerBundle] Add Pretty Print functionality for Request Content --- .../Resources/views/base_js.html.twig | 4 +- .../views/Collector/request.html.twig | 23 +++++++- .../views/Profiler/base_js.html.twig | 4 +- .../DataCollector/RequestDataCollector.php | 12 +++++ .../RequestDataCollectorTest.php | 54 +++++++++++++++++++ 5 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig index 07feb3856a326..858d44382cc31 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig +++ b/src/Symfony/Bundle/TwigBundle/Resources/views/base_js.html.twig @@ -41,7 +41,7 @@ /* create the tab navigation for each group of tabs */ for (var i = 0; i < tabGroups.length; i++) { - var tabs = tabGroups[i].querySelectorAll('.tab'); + var tabs = tabGroups[i].querySelectorAll(':scope > .tab'); var tabNavigation = document.createElement('ul'); tabNavigation.className = 'tab-navigation'; @@ -67,7 +67,7 @@ /* display the active tab and add the 'click' event listeners */ for (i = 0; i < tabGroups.length; i++) { - tabNavigation = tabGroups[i].querySelectorAll('.tab-navigation li'); + tabNavigation = tabGroups[i].querySelectorAll(':scope >.tab-navigation li'); for (j = 0; j < tabNavigation.length; j++) { tabId = tabNavigation[j].getAttribute('data-tab-id'); diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig index 8e496fe8a458e..02d4fe5097dfd 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/request.html.twig @@ -178,8 +178,27 @@

Request content not available (it was retrieved as a resource).

{% elseif collector.content %} -
-
{{ collector.content }}
+
+ {% set prettyJson = collector.isJsonRequest ? collector.prettyJson : null %} + {% if prettyJson is not null %} +
+

Pretty

+
+
+
{{ prettyJson }}
+
+
+
+ {% endif %} + +
+

Raw

+
+
+
{{ collector.content }}
+
+
+
{% else %}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index ea6177e2e8d68..ddd6eeb0c6215 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -552,7 +552,7 @@ /* create the tab navigation for each group of tabs */ for (var i = 0; i < tabGroups.length; i++) { - var tabs = tabGroups[i].querySelectorAll('.tab'); + var tabs = tabGroups[i].querySelectorAll(':scope > .tab'); var tabNavigation = document.createElement('ul'); tabNavigation.className = 'tab-navigation'; @@ -578,7 +578,7 @@ /* display the active tab and add the 'click' event listeners */ for (i = 0; i < tabGroups.length; i++) { - tabNavigation = tabGroups[i].querySelectorAll('.tab-navigation li'); + tabNavigation = tabGroups[i].querySelectorAll(':scope > .tab-navigation li'); for (j = 0; j < tabNavigation.length; j++) { tabId = tabNavigation[j].getAttribute('data-tab-id'); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php index 32cee4bff7b27..c2507b3bc62db 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php @@ -263,6 +263,18 @@ public function getContent() return $this->data['content']; } + public function isJsonRequest() + { + return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']); + } + + public function getPrettyJson() + { + $decoded = json_decode($this->getContent()); + + return JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, JSON_PRETTY_PRINT) : null; + } + public function getContentType() { return $this->data['content_type']; diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php index 24904f7ccadf1..051525e3cb301 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php @@ -333,4 +333,58 @@ private function getCookieByName(Response $response, $name) throw new \InvalidArgumentException(sprintf('Cookie named "%s" is not in response', $name)); } + + /** + * @dataProvider provideJsonContentTypes + */ + public function testIsJson($contentType, $expected) + { + $response = $this->createResponse(); + $request = $this->createRequest(); + $request->headers->set('Content-Type', $contentType); + + $c = new RequestDataCollector(); + $c->collect($request, $response); + + $this->assertSame($expected, $c->isJsonRequest()); + } + + public function provideJsonContentTypes() + { + return array( + array('text/csv', false), + array('application/json', true), + array('application/JSON', true), + array('application/hal+json', true), + array('application/xml+json', true), + array('application/xml', false), + array('', false), + ); + } + + /** + * @dataProvider providePrettyJson + */ + public function testGetPrettyJsonValidity($content, $expected) + { + $response = $this->createResponse(); + $request = Request::create('/', 'POST', array(), array(), array(), array(), $content); + + $c = new RequestDataCollector(); + $c->collect($request, $response); + + $this->assertSame($expected, $c->getPrettyJson()); + } + + public function providePrettyJson() + { + return array( + array('null', 'null'), + array('{ "foo": "bar" }', '{ + "foo": "bar" +}'), + array('{ "abc" }', null), + array('', null), + ); + } } From f6510cda40193e9e586ca5c801594a286e3854f7 Mon Sep 17 00:00:00 2001 From: tsantos Date: Sat, 9 Jun 2018 20:32:40 -0300 Subject: [PATCH 136/495] [PropertyInfo] Added support for extract type from default value --- .../Component/PropertyInfo/CHANGELOG.md | 5 ++++ .../Extractor/ReflectionExtractor.php | 29 +++++++++++++++++++ .../Extractor/ReflectionExtractorTest.php | 20 +++++++++++++ .../Tests/Fixtures/DefaultValue.php | 26 +++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php diff --git a/src/Symfony/Component/PropertyInfo/CHANGELOG.md b/src/Symfony/Component/PropertyInfo/CHANGELOG.md index a81f3124a67c4..9db346c21787f 100644 --- a/src/Symfony/Component/PropertyInfo/CHANGELOG.md +++ b/src/Symfony/Component/PropertyInfo/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + +* Added the ability to extract property type based on its initial value + 4.2.0 ----- diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 0ed1e4e2afe3d..83f14acb70760 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -42,6 +42,12 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp */ public static $defaultArrayMutatorPrefixes = ['add', 'remove']; + private const MAP_TYPES = [ + 'integer' => Type::BUILTIN_TYPE_INT, + 'boolean' => Type::BUILTIN_TYPE_BOOL, + 'double' => Type::BUILTIN_TYPE_FLOAT, + ]; + private $mutatorPrefixes; private $accessorPrefixes; private $arrayMutatorPrefixes; @@ -117,6 +123,10 @@ public function getTypes($class, $property, array $context = []) ) { return $fromConstructor; } + + if ($fromDefaultValue = $this->extractFromDefaultValue($class, $property)) { + return $fromDefaultValue; + } } /** @@ -258,6 +268,25 @@ private function extractFromConstructor(string $class, string $property): ?array return null; } + private function extractFromDefaultValue(string $class, string $property) + { + try { + $reflectionClass = new \ReflectionClass($class); + } catch (\ReflectionException $e) { + return null; + } + + $defaultValue = $reflectionClass->getDefaultProperties()[$property] ?? null; + + if (null === $defaultValue) { + return null; + } + + $type = \gettype($defaultValue); + + return [new Type(static::MAP_TYPES[$type] ?? $type)]; + } + private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod): Type { $phpTypeOrClass = $reflectionType->getName(); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index e58c70d41d702..7472d6ef21b00 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\AdderRemoverDummy; +use Symfony\Component\PropertyInfo\Tests\Fixtures\DefaultValue; use Symfony\Component\PropertyInfo\Tests\Fixtures\NotInstantiable; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended2; @@ -208,6 +209,25 @@ public function php71TypesProvider() ]; } + /** + * @dataProvider defaultValueProvider + */ + public function testExtractWithDefaultValue($property, $type) + { + $this->assertEquals($type, $this->extractor->getTypes(DefaultValue::class, $property, [])); + } + + public function defaultValueProvider() + { + return [ + ['defaultInt', [new Type(Type::BUILTIN_TYPE_INT, false)]], + ['defaultFloat', [new Type(Type::BUILTIN_TYPE_FLOAT, false)]], + ['defaultString', [new Type(Type::BUILTIN_TYPE_STRING, false)]], + ['defaultArray', [new Type(Type::BUILTIN_TYPE_ARRAY, false)]], + ['defaultNull', null], + ]; + } + /** * @dataProvider getReadableProperties */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php new file mode 100644 index 0000000000000..f7a718e5c7b11 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\Fixtures; + +/** + * @author Tales Santos + */ +class DefaultValue +{ + public $defaultInt = 30; + public $defaultFloat = 30.5; + public $defaultString = 'foo'; + public $defaultArray = []; + public $defaultNull = null; +} From 715cf8db81f926437a500ee3ce7dff3a2afe2124 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 21 Feb 2019 13:15:05 +0100 Subject: [PATCH 137/495] fix lowest supported Routing component version --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 5ed9bc5cc5eca..4f620f3453f6d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -28,7 +28,7 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", - "symfony/routing": "^4.1" + "symfony/routing": "^4.3" }, "require-dev": { "doctrine/cache": "~1.0", From 514a1b506c20ef9641ceb7ec8b73967d51c75980 Mon Sep 17 00:00:00 2001 From: Maximilian Ruta Date: Mon, 15 Oct 2018 16:45:45 +0200 Subject: [PATCH 138/495] [Debug] Mimic __toString php behavior in FlattenException --- src/Symfony/Component/Debug/CHANGELOG.md | 3 ++ .../Debug/Exception/FlattenException.php | 32 +++++++++++++++++ .../Tests/Exception/FlattenExceptionTest.php | 35 +++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/src/Symfony/Component/Debug/CHANGELOG.md b/src/Symfony/Component/Debug/CHANGELOG.md index 2b7bfc8ba30ed..367e834f01e7e 100644 --- a/src/Symfony/Component/Debug/CHANGELOG.md +++ b/src/Symfony/Component/Debug/CHANGELOG.md @@ -5,6 +5,9 @@ CHANGELOG ----- * made the `ErrorHandler` and `ExceptionHandler` classes final +* added `Exception\FlattenException::getAsString` and +`Exception\FlattenException::getTraceAsString` to increase compatibility to php +exception objects 4.0.0 ----- diff --git a/src/Symfony/Component/Debug/Exception/FlattenException.php b/src/Symfony/Component/Debug/Exception/FlattenException.php index d016bb2fb45cc..304df0405c267 100644 --- a/src/Symfony/Component/Debug/Exception/FlattenException.php +++ b/src/Symfony/Component/Debug/Exception/FlattenException.php @@ -27,6 +27,7 @@ class FlattenException private $code; private $previous; private $trace; + private $traceAsString; private $class; private $statusCode; private $headers; @@ -239,6 +240,8 @@ public function setTraceFromException(\Exception $exception) public function setTraceFromThrowable(\Throwable $throwable) { + $this->traceAsString = $throwable->getTraceAsString(); + return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine()); } @@ -324,4 +327,33 @@ private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value) return $array['__PHP_Incomplete_Class_Name']; } + + public function getTraceAsString() + { + return $this->traceAsString; + } + + public function getAsString() + { + $message = ''; + $next = false; + + foreach (array_reverse(array_merge([$this], $this->getAllPrevious())) as $exception) { + if ($next) { + $message .= 'Next '; + } else { + $next = true; + } + $message .= $exception->getClass(); + + if ('' != $exception->getMessage()) { + $message .= ': '.$exception->getMessage(); + } + + $message .= ' in '.$exception->getFile().':'.$exception->getLine(). + "\nStack trace:\n".$exception->getTraceAsString()."\n\n"; + } + + return rtrim($message); + } } diff --git a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php index eb884b51c1017..e86210b903b02 100644 --- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php @@ -346,6 +346,41 @@ public function testAnonymousClass() $this->assertSame('Class "RuntimeException@anonymous" blah.', $flattened->getMessage()); } + public function testToStringEmptyMessage() + { + $exception = new \RuntimeException(); + + $flattened = FlattenException::create($exception); + + $this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString()); + $this->assertSame($exception->__toString(), $flattened->getAsString()); + } + + public function testToString() + { + $test = function ($a, $b, $c, $d) { + return new \RuntimeException('This is a test message'); + }; + + $exception = $test('foo123', 1, null, 1.5); + + $flattened = FlattenException::create($exception); + + $this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString()); + $this->assertSame($exception->__toString(), $flattened->getAsString()); + } + + public function testToStringParent() + { + $exception = new \LogicException('This is message 1'); + $exception = new \RuntimeException('This is messsage 2', 500, $exception); + + $flattened = FlattenException::create($exception); + + $this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString()); + $this->assertSame($exception->__toString(), $flattened->getAsString()); + } + private function createException($foo) { return new \Exception(); From 845d3a681b971f3e99ba434a4700c3c4665d1a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= Date: Thu, 13 Dec 2018 17:18:52 +0100 Subject: [PATCH 139/495] Allow to choose an index for tagged collection --- .../Argument/TaggedIteratorArgument.php | 19 ++++++- .../Compiler/PriorityTaggedServiceTrait.php | 49 +++++++++++++++++-- .../ResolveTaggedIteratorArgumentPass.php | 2 +- .../Configurator/ContainerConfigurator.php | 4 +- .../Loader/YamlFileLoader.php | 12 +++-- 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php index f3b3621d89c68..b6a06f7de7f1d 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php @@ -19,16 +19,33 @@ class TaggedIteratorArgument extends IteratorArgument { private $tag; + private $indexAttribute; + private $defaultIndexMethod; - public function __construct(string $tag) + public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null) { parent::__construct([]); $this->tag = $tag; + $this->indexAttribute = $indexAttribute ?: null; + + if ($indexAttribute) { + $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name'); + } } public function getTag() { return $this->tag; } + + public function getIndexAttribute(): ?string + { + return $this->indexAttribute; + } + + public function getDefaultIndexMethod(): ?string + { + return $this->defaultIndexMethod; + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php index adb99f0d546fd..f9046d3c3283b 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php @@ -11,7 +11,9 @@ namespace Symfony\Component\DependencyInjection\Compiler; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; /** @@ -31,18 +33,59 @@ trait PriorityTaggedServiceTrait * @see https://bugs.php.net/bug.php?id=53710 * @see https://bugs.php.net/bug.php?id=60926 * - * @param string $tagName - * @param ContainerBuilder $container + * @param string|TaggedIteratorArgument $tagName + * @param ContainerBuilder $container * * @return Reference[] */ private function findAndSortTaggedServices($tagName, ContainerBuilder $container) { + $indexAttribute = $defaultIndexMethod = null; + if ($tagName instanceof TaggedIteratorArgument) { + $indexAttribute = $tagName->getIndexAttribute(); + $defaultIndexMethod = $tagName->getDefaultIndexMethod(); + $tagName = $tagName->getTag(); + } $services = []; foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) { $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $services[$priority][] = new Reference($serviceId); + + if (null === $indexAttribute) { + $services[$priority][] = new Reference($serviceId); + + continue; + } + + if (isset($attributes[0][$indexAttribute])) { + $services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId); + + continue; + } + + if (!$r = $container->getReflectionClass($class = $container->getDefinition($serviceId)->getClass())) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId)); + } + + if (!$r->hasMethod($defaultIndexMethod)) { + throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute)); + } + + if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) { + throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be static: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute)); + } + + if (!$rm->isPublic()) { + throw new InvalidArgumentException(sprintf('Method "%s::%s()" should be public: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute)); + } + + $key = $rm->invoke(null); + + if (!\is_string($key)) { + throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($key), $tagName, $serviceId, $indexAttribute)); + } + + $services[$priority][$key] = new Reference($serviceId); } if ($services) { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveTaggedIteratorArgumentPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveTaggedIteratorArgumentPass.php index 009cee9bf5c1d..a4305722f7cb5 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveTaggedIteratorArgumentPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveTaggedIteratorArgumentPass.php @@ -31,7 +31,7 @@ protected function processValue($value, $isRoot = false) return parent::processValue($value, $isRoot); } - $value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container)); + $value->setValues($this->findAndSortTaggedServices($value, $this->container)); return $value; } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index f1593e4f69d84..f75ba1be85790 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -116,9 +116,9 @@ function iterator(array $values): IteratorArgument /** * Creates a lazy iterator by tag name. */ -function tagged(string $tag): TaggedIteratorArgument +function tagged(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null): TaggedIteratorArgument { - return new TaggedIteratorArgument($tag); + return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod); } /** diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index e14d38d49d7f1..700cd79be5a6f 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -710,11 +710,17 @@ private function resolveServices($value, $file, $isParameter = false) } } if ('tagged' === $value->getTag()) { - if (!\is_string($argument) || !$argument) { - throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file)); + if (\is_string($argument) && $argument) { + return new TaggedIteratorArgument($argument); } + if (\is_array($argument) && isset($argument['name']) && $argument['name']) { + if (array_diff(array_keys($argument), ['name', 'index_by', 'default_index_method'])) { + throw new InvalidArgumentException('"!tagged" tag contains unsupported keys. Supported are: "name, index_by, default_index_method".'); + } - return new TaggedIteratorArgument($argument); + return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null); + } + throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file)); } if ('service' === $value->getTag()) { if ($isParameter) { From 5e494db04c24ac7bdbd063fd3d2e99765e1a92cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Fri, 22 Feb 2019 14:32:09 +0100 Subject: [PATCH 140/495] [Monolog] Added a way to configure the ConsoleFormatter from the ConsoleHandler --- src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php b/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php index 997ecc107cce5..1ec91e43f29a2 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ConsoleHandler.php @@ -50,6 +50,7 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe OutputInterface::VERBOSITY_VERY_VERBOSE => Logger::INFO, OutputInterface::VERBOSITY_DEBUG => Logger::DEBUG, ]; + private $consoleFormaterOptions; /** * @param OutputInterface|null $output The console output to use (the handler remains disabled when passing null @@ -58,7 +59,7 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe * @param array $verbosityLevelMap Array that maps the OutputInterface verbosity to a minimum logging * level (leave empty to use the default mapping) */ - public function __construct(OutputInterface $output = null, bool $bubble = true, array $verbosityLevelMap = []) + public function __construct(OutputInterface $output = null, bool $bubble = true, array $verbosityLevelMap = [], array $consoleFormaterOptions = []) { parent::__construct(Logger::DEBUG, $bubble); $this->output = $output; @@ -66,6 +67,8 @@ public function __construct(OutputInterface $output = null, bool $bubble = true, if ($verbosityLevelMap) { $this->verbosityLevelMap = $verbosityLevelMap; } + + $this->consoleFormaterOptions = $consoleFormaterOptions; } /** @@ -155,13 +158,13 @@ protected function getDefaultFormatter() return new LineFormatter(); } if (!$this->output) { - return new ConsoleFormatter(); + return new ConsoleFormatter($this->consoleFormaterOptions); } - return new ConsoleFormatter([ + return new ConsoleFormatter(array_replace([ 'colors' => $this->output->isDecorated(), 'multiline' => OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity(), - ]); + ], $this->consoleFormaterOptions)); } /** From 101bfd79bfc9853e7935f2c87411516eda0a8b2f Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Wed, 13 Feb 2019 17:39:28 +0100 Subject: [PATCH 141/495] [DI] change name to tag + add XMl support + adding yaml/xml tests --- .../Argument/TaggedIteratorArgument.php | 9 +++- .../DependencyInjection/CHANGELOG.md | 1 + .../DependencyInjection/Dumper/XmlDumper.php | 8 +++ .../DependencyInjection/Dumper/YamlDumper.php | 13 +++++ .../Loader/XmlFileLoader.php | 5 +- .../Loader/YamlFileLoader.php | 24 +++++---- .../schema/dic/services/services-1.0.xsd | 2 + .../Tests/Compiler/IntegrationTest.php | 52 +++++++++++++++++++ .../Tests/Dumper/XmlDumperTest.php | 14 +++++ .../Tests/Dumper/YamlDumperTest.php | 11 ++++ .../Tests/Fixtures/BarTagClass.php | 16 ++++++ .../Tests/Fixtures/FooBarTaggedClass.php | 18 +++++++ .../Tests/Fixtures/FooTagClass.php | 11 ++++ .../xml/services_with_tagged_arguments.xml | 14 +++++ .../yaml/services_with_tagged_argument.yml | 19 +++++++ .../Tests/Loader/XmlFileLoaderTest.php | 12 +++++ .../Tests/Loader/YamlFileLoaderTest.php | 12 +++++ 17 files changed, 227 insertions(+), 14 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/BarTagClass.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooBarTaggedClass.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooTagClass.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php index b6a06f7de7f1d..fabfb00451851 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php @@ -22,14 +22,21 @@ class TaggedIteratorArgument extends IteratorArgument private $indexAttribute; private $defaultIndexMethod; + /** + * TaggedIteratorArgument constructor. + * + * @param string $tag The name of the tag identifying the target services + * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection + * @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute + */ public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null) { parent::__construct([]); $this->tag = $tag; - $this->indexAttribute = $indexAttribute ?: null; if ($indexAttribute) { + $this->indexAttribute = $indexAttribute; $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name'); } } diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 87739fc9753da..e5fcd4f768579 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG * added `%env(nullable:...)%` processor to allow empty variables to be processed as null values * added support for deprecating aliases * made `ContainerParametersResource` final and not implement `Serializable` anymore + * added ability to define an index for a tagged collection 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index 704df2af3965e..4b01bd30d3779 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -286,6 +286,14 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent } elseif ($value instanceof TaggedIteratorArgument) { $element->setAttribute('type', 'tagged'); $element->setAttribute('tag', $value->getTag()); + + if (null !== $value->getIndexAttribute()) { + $element->setAttribute('index-by', $value->getIndexAttribute()); + } + + if (null !== $value->getDefaultIndexMethod()) { + $element->setAttribute('default-index-method', $value->getDefaultIndexMethod()); + } } elseif ($value instanceof IteratorArgument) { $element->setAttribute('type', 'iterator'); $this->convertParameters($value->getValues(), $type, $element, 'key'); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index 5b9e747315abd..875ebbc0abc8b 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -233,6 +233,19 @@ private function dumpValue($value) } if ($value instanceof ArgumentInterface) { if ($value instanceof TaggedIteratorArgument) { + if (null !== $value->getIndexAttribute()) { + $taggedValueContent = [ + 'tag' => $value->getTag(), + 'index_by' => $value->getIndexAttribute(), + ]; + + if (null !== $value->getDefaultIndexMethod()) { + $taggedValueContent['default_index_method'] = $value->getDefaultIndexMethod(); + } + + return new TaggedValue('tagged', $taggedValueContent); + } + return new TaggedValue('tagged', $value->getTag()); } if ($value instanceof IteratorArgument) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 16b9b48c2061b..6f672bdc7f6bc 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -353,7 +353,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) continue; } - if (false !== strpos($name, '-') && false === strpos($name, '_') && !array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) { + if (false !== strpos($name, '-') && false === strpos($name, '_') && !\array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) { $parameters[$normalizedName] = XmlUtils::phpize($node->nodeValue); } // keep not normalized key @@ -537,7 +537,8 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = if (!$arg->getAttribute('tag')) { throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file)); } - $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag')); + + $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null); break; case 'binary': if (false === $value = base64_decode($arg->nodeValue)) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 700cd79be5a6f..06fcbb4a91af1 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -203,7 +203,7 @@ private function parseDefinitions(array $content, string $file) throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file)); } - if (array_key_exists('_instanceof', $content['services'])) { + if (\array_key_exists('_instanceof', $content['services'])) { $instanceof = $content['services']['_instanceof']; unset($content['services']['_instanceof']); @@ -235,7 +235,7 @@ private function parseDefinitions(array $content, string $file) */ private function parseDefaults(array &$content, string $file): array { - if (!array_key_exists('_defaults', $content['services'])) { + if (!\array_key_exists('_defaults', $content['services'])) { return []; } $defaults = $content['services']['_defaults']; @@ -342,7 +342,7 @@ private function parseDefinition($id, $service, $file, array $defaults) if (isset($service['alias'])) { $this->container->setAlias($id, $alias = new Alias($service['alias'])); - if (array_key_exists('public', $service)) { + if (\array_key_exists('public', $service)) { $alias->setPublic($service['public']); } elseif (isset($defaults['public'])) { $alias->setPublic($defaults['public']); @@ -430,7 +430,7 @@ private function parseDefinition($id, $service, $file, array $defaults) $definition->setAbstract($service['abstract']); } - if (array_key_exists('deprecated', $service)) { + if (\array_key_exists('deprecated', $service)) { $definition->setDeprecated(true, $service['deprecated']); } @@ -545,11 +545,11 @@ private function parseDefinition($id, $service, $file, array $defaults) } } - if (array_key_exists('namespace', $service) && !array_key_exists('resource', $service)) { + if (\array_key_exists('namespace', $service) && !\array_key_exists('resource', $service)) { throw new InvalidArgumentException(sprintf('A "resource" attribute must be set when the "namespace" attribute is set for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - if (array_key_exists('resource', $service)) { + if (\array_key_exists('resource', $service)) { if (!\is_string($service['resource'])) { throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); } @@ -713,14 +713,16 @@ private function resolveServices($value, $file, $isParameter = false) if (\is_string($argument) && $argument) { return new TaggedIteratorArgument($argument); } - if (\is_array($argument) && isset($argument['name']) && $argument['name']) { - if (array_diff(array_keys($argument), ['name', 'index_by', 'default_index_method'])) { - throw new InvalidArgumentException('"!tagged" tag contains unsupported keys. Supported are: "name, index_by, default_index_method".'); + + if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) { + if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { + throw new InvalidArgumentException(sprintf('"!tagged" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); } - return new TaggedIteratorArgument($argument['name'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null); + return new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null); } - throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts a non empty string or an array with a key "name" in "%s".', $file)); + + throw new InvalidArgumentException(sprintf('"!tagged" tags only accept a non empty string or an array with a key "tag" in "%s".', $file)); } if ('service' === $value->getTag()) { if ($isParameter) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index 25ef73a14eb30..b14ffc8dcd212 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -234,6 +234,8 @@ + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index b9f9d7bf36204..1ba0a53eaa679 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -14,10 +14,14 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; +use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooTagClass; /** * This class tests the integration of the different compiler passes. @@ -234,6 +238,54 @@ public function getYamlCompileTests() $container, ]; } + + public function testTaggedServiceWithIndexAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class, BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar', ['foo' => 'bar']) + ; + $container->register(FooTagClass::class, FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooBarTaggedClass::class, FooBarTaggedClass::class) + ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo')) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + $param = iterator_to_array($s->getParam()->getIterator()); + $this->assertSame(['bar' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $param); + } + + public function testTaggedServiceWithIndexAttributeAndDefaultMethod() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class, BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class, FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar', ['foo' => 'foo']) + ; + $container->register(FooBarTaggedClass::class, FooBarTaggedClass::class) + ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar')) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + $param = iterator_to_array($s->getParam()->getIterator()); + $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param); + } } class ServiceSubscriberStub implements ServiceSubscriberInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index ac274c6f26267..b110cdc5e880d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Dumper\XmlDumper; @@ -200,6 +201,19 @@ public function testDumpLoad() $this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_dump_load.xml', $dumper->dump()); } + public function testTaggedArgument() + { + $container = new ContainerBuilder(); + $container->register('foo', 'Foo')->addTag('foo_tag'); + $container->register('foo_tagged_iterator', 'Bar') + ->setPublic(true) + ->addArgument(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar')) + ; + + $dumper = new XmlDumper($container); + $this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_with_tagged_arguments.xml', $dumper->dump()); + } + public function testDumpAbstractServices() { $container = include self::$fixturesPath.'/containers/container_abstract.php'; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index 49ee8e6f3002e..61a1aec5105dc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; @@ -95,6 +96,16 @@ public function testInlineServices() $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_inline.yml', $dumper->dump()); } + public function testTaggedArgument() + { + $container = new ContainerBuilder(); + $container->register('foo_service', 'Foo')->addTag('foo'); + $container->register('foo_service_tagged', 'Bar')->addArgument(new TaggedIteratorArgument('foo', 'barfoo', 'foobar')); + + $dumper = new YamlDumper($container); + $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_tagged_argument.yml', $dumper->dump()); + } + private function assertEqualYamlStructure($expected, $yaml, $message = '') { $parser = new Parser(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/BarTagClass.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/BarTagClass.php new file mode 100644 index 0000000000000..9e065f6b102a9 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/BarTagClass.php @@ -0,0 +1,16 @@ +param = $param; + } + + public function getParam() + { + return $this->param; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooTagClass.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooTagClass.php new file mode 100644 index 0000000000000..c1279b9a9feeb --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooTagClass.php @@ -0,0 +1,11 @@ + + + + + + + + + + + + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml new file mode 100644 index 0000000000000..bf7cf06930d0c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml @@ -0,0 +1,19 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + foo_service: + class: Foo + tags: + - { name: foo } + foo_service_tagged: + class: Bar + arguments: [!tagged { tag: foo, index_by: barfoo, default_index_method: foobar }] + Psr\Container\ContainerInterface: + alias: service_container + public: false + Symfony\Component\DependencyInjection\ContainerInterface: + alias: service_container + public: false diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 9cb64f39da17f..20c80258e2686 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; @@ -315,6 +316,17 @@ public function testParsesTags() } } + public function testParseTaggedArgumentsWithIndexBy() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('services_with_tagged_arguments.xml'); + + $this->assertCount(1, $container->getDefinition('foo')->getTag('foo_tag')); + $this->assertCount(1, $container->getDefinition('foo_tagged_iterator')->getArguments()); + $this->assertEquals(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'), $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + } + /** * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException */ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 8c9ccaf06ff93..7870a521a9dbe 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; @@ -279,6 +280,17 @@ public function testTagWithoutNameThrowsException() } } + public function testTaggedArgumentsWithIndex() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('services_with_tagged_argument.yml'); + + $this->assertCount(1, $container->getDefinition('foo_service')->getTag('foo')); + $this->assertCount(1, $container->getDefinition('foo_service_tagged')->getArguments()); + $this->assertEquals(new TaggedIteratorArgument('foo', 'barfoo', 'foobar'), $container->getDefinition('foo_service_tagged')->getArgument(0)); + } + public function testNameOnlyTagsAreAllowedAsString() { $container = new ContainerBuilder(); From 45869ac10c659daaa9a1f43e003f78cd8ed49cc5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 22 Feb 2019 20:41:55 +0100 Subject: [PATCH 142/495] [VarDumper] fix dumping Ds maps and pairs --- .../Component/VarDumper/Caster/DsCaster.php | 50 +++++++++++++------ .../Component/VarDumper/Caster/DsPairStub.php | 28 +++++++++++ .../VarDumper/Cloner/AbstractCloner.php | 9 ++-- 3 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 src/Symfony/Component/VarDumper/Caster/DsPairStub.php diff --git a/src/Symfony/Component/VarDumper/Caster/DsCaster.php b/src/Symfony/Component/VarDumper/Caster/DsCaster.php index 1140b099e732d..467aadfd765d8 100644 --- a/src/Symfony/Component/VarDumper/Caster/DsCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DsCaster.php @@ -11,13 +11,9 @@ namespace Symfony\Component\VarDumper\Caster; -use Ds\Deque; +use Ds\Collection; use Ds\Map; -use Ds\PriorityQueue; -use Ds\Queue; -use Ds\Set; -use Ds\Stack; -use Ds\Vector; +use Ds\Pair; use Symfony\Component\VarDumper\Cloner\Stub; /** @@ -27,23 +23,45 @@ */ class DsCaster { - /** - * @param Set|Deque|Vector|Stack|Queue|PriorityQueue $c - */ - public static function castDs($c, array $a, Stub $stub, bool $isNested): array + public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested): array { - $prefix = Caster::PREFIX_VIRTUAL; - $a = $c->toArray(); - $a[$prefix.'capacity'] = $c->capacity(); + $a[Caster::PREFIX_VIRTUAL.'count'] = $c->count(); + $a[Caster::PREFIX_VIRTUAL.'capacity'] = $c->capacity(); + + if (!$c instanceof Map) { + $a += $c->toArray(); + } return $a; } public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array { - $prefix = Caster::PREFIX_VIRTUAL; - $a = $c->pairs()->toArray(); - $a[$prefix.'capacity'] = $c->capacity(); + foreach ($c as $k => $v) { + $a[] = new DsPairStub($k, $v); + } + + return $a; + } + + public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested): array + { + foreach ($c->toArray() as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } + + public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested): array + { + if ($isNested) { + $stub->class = Pair::class; + $stub->value = null; + $stub->handle = 0; + + $a = $c->value; + } return $a; } diff --git a/src/Symfony/Component/VarDumper/Caster/DsPairStub.php b/src/Symfony/Component/VarDumper/Caster/DsPairStub.php new file mode 100644 index 0000000000000..a1dcc156183e9 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Caster/DsPairStub.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + */ +class DsPairStub extends Stub +{ + public function __construct($key, $value) + { + $this->value = [ + Caster::PREFIX_VIRTUAL.'key' => $key, + Caster::PREFIX_VIRTUAL.'value' => $value, + ]; + } +} diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 174ce24c40e68..9836040e34fea 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -125,13 +125,10 @@ abstract class AbstractCloner implements ClonerInterface 'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'], - 'Ds\Set' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], - 'Ds\Vector' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], - 'Ds\Deque' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], - 'Ds\Stack' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], - 'Ds\Queue' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], - 'Ds\PriorityQueue' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castDs'], + 'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'], 'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'], + 'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'], + 'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'], ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], From d7aaa615b98270ff5b5c801e8a6a82ac8f6730d8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 6 Mar 2017 18:12:20 +0100 Subject: [PATCH 143/495] deprecate the Role and SwitchUserRole classes --- UPGRADE-4.3.md | 7 + UPGRADE-5.0.md | 5 + .../Monolog/Processor/TokenProcessor.php | 8 +- .../Tests/Processor/TokenProcessorTest.php | 3 +- .../DataCollector/SecurityDataCollector.php | 32 +++- .../Resources/config/security.xml | 1 + .../SecurityDataCollectorTest.php | 70 ++++---- .../Bundle/SecurityBundle/composer.json | 2 +- src/Symfony/Component/Security/CHANGELOG.md | 7 + .../Provider/UserAuthenticationProvider.php | 10 +- .../Authentication/Token/AbstractToken.php | 23 ++- .../Authentication/Token/AnonymousToken.php | 4 +- .../Token/PreAuthenticatedToken.php | 10 +- .../Token/Storage/TokenStorage.php | 4 + .../Authentication/Token/SwitchUserToken.php | 60 +++++++ .../Authentication/Token/TokenInterface.php | 4 + .../Token/UsernamePasswordToken.php | 10 +- .../Authorization/Voter/ExpressionVoter.php | 26 ++- .../Voter/RoleHierarchyVoter.php | 19 ++- .../Core/Authorization/Voter/RoleVoter.php | 10 +- .../Component/Security/Core/Role/Role.php | 11 ++ .../Security/Core/Role/RoleHierarchy.php | 33 ++++ .../Core/Role/RoleHierarchyInterface.php | 2 + .../Security/Core/Role/SwitchUserRole.php | 17 +- ...uthenticatedAuthenticationProviderTest.php | 2 +- .../RememberMeAuthenticationProviderTest.php | 3 +- .../UserAuthenticationProviderTest.php | 37 ++++- .../Token/AbstractTokenTest.php | 150 +++++++++--------- .../Token/AnonymousTokenTest.php | 3 +- .../Token/PreAuthenticatedTokenTest.php | 3 +- .../Token/RememberMeTokenTest.php | 3 +- .../Token/Storage/TokenStorageTest.php | 3 +- .../Token/SwitchUserTokenTest.php | 41 +++++ .../Token/UsernamePasswordTokenTest.php | 3 +- .../AuthorizationCheckerTest.php | 11 +- .../Voter/ExpressionVoterTest.php | 25 +++ .../Voter/RoleHierarchyVoterTest.php | 33 ++++ .../Authorization/Voter/RoleVoterTest.php | 39 +++++ .../Core/Tests/Role/RoleHierarchyTest.php | 17 ++ .../Security/Core/Tests/Role/RoleTest.php | 3 + .../Core/Tests/Role/SwitchUserRoleTest.php | 3 + .../Token/PostAuthenticationGuardToken.php | 7 +- .../Http/Firewall/ContextListener.php | 13 +- .../Http/Firewall/SwitchUserListener.php | 25 ++- .../Controller/UserValueResolverTest.php | 11 +- .../Tests/Firewall/SwitchUserListenerTest.php | 23 ++- .../Tests/Logout/LogoutUrlGeneratorTest.php | 2 +- .../Component/Security/Http/composer.json | 2 +- .../Workflow/EventListener/GuardListener.php | 18 ++- .../Tests/EventListener/GuardListenerTest.php | 4 +- 50 files changed, 654 insertions(+), 208 deletions(-) create mode 100644 src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php create mode 100644 src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 7a2dca20633fa..a0d5e52b17632 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -53,6 +53,13 @@ HttpFoundation Security -------- + * The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles + instead. + * The `RoleHierarchyInterface` is deprecated and will be removed in 5.0. + * The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0. + Use the `getReachableRoleNames()` method instead. + * The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` + method instead and return roles as strings. * The `AbstractToken::serialize()`, `AbstractToken::unserialize()`, `AuthenticationException::serialize()` and `AuthenticationException::unserialize()` methods are now final, use `getState()` and `setState()` instead. diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index f61211c1cc15e..a959f2d06a179 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -226,6 +226,11 @@ Process Security -------- + * The `Role` and `SwitchUserRole` classes have been removed. + * The `RoleHierarchyInterface` has been removed. + * The `getReachableRoles()` method of the `RoleHierarchy` class has been removed. + * The `getRoles()` method has been removed from the `TokenInterface`. It has been replaced by the new + `getRoleNames()` method. * The `ContextListener::setLogoutOnUserChange()` method has been removed. * The `Symfony\Component\Security\Core\User\AdvancedUserInterface` has been removed. * The `ExpressionVoter::addExpressionLanguageProvider()` method has been removed. diff --git a/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php b/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php index 7bf03a036a257..7613d01361962 100644 --- a/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/TokenProcessor.php @@ -31,10 +31,16 @@ public function __invoke(array $records) { $records['extra']['token'] = null; if (null !== $token = $this->tokenStorage->getToken()) { + if (method_exists($token, 'getRoleNames')) { + $roles = $token->getRoleNames(); + } else { + $roles = array_map(function ($role) { return $role->getRole(); }, $token->getRoles(false)); + } + $records['extra']['token'] = [ 'username' => $token->getUsername(), 'authenticated' => $token->isAuthenticated(), - 'roles' => array_map(function ($role) { return $role->getRole(); }, $token->getRoles()), + 'roles' => $roles, ]; } diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php index 1b01348639b0d..ef3f6cc9f5c6a 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/TokenProcessorTest.php @@ -36,7 +36,6 @@ public function testProcessor() $this->assertArrayHasKey('token', $record['extra']); $this->assertEquals($token->getUsername(), $record['extra']['token']['username']); $this->assertEquals($token->isAuthenticated(), $record['extra']['token']['authenticated']); - $roles = array_map(function ($role) { return $role->getRole(); }, $token->getRoles()); - $this->assertEquals($roles, $record['extra']['token']['roles']); + $this->assertEquals(['ROLE_USER'], $record['extra']['token']['roles']); } } diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index 3e55022f16429..d33d227ff137c 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -18,10 +18,12 @@ use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager; use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter; use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Http\Firewall\SwitchUserListener; @@ -91,18 +93,32 @@ public function collect(Request $request, Response $response, \Exception $except ]; } else { $inheritedRoles = []; - $assignedRoles = $token->getRoles(); + + if (method_exists($token, 'getRoleNames')) { + $assignedRoles = $token->getRoleNames(); + } else { + $assignedRoles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false)); + } $impersonatorUser = null; - foreach ($assignedRoles as $role) { - if ($role instanceof SwitchUserRole) { - $impersonatorUser = $role->getSource()->getUsername(); - break; + if ($token instanceof SwitchUserToken) { + $impersonatorUser = $token->getOriginalToken()->getUsername(); + } else { + foreach ($token->getRoles(false) as $role) { + if ($role instanceof SwitchUserRole) { + $impersonatorUser = $role->getSource()->getUsername(); + break; + } } } if (null !== $this->roleHierarchy) { - $allRoles = $this->roleHierarchy->getReachableRoles($assignedRoles); + if ($this->roleHierarchy instanceof RoleHierarchy) { + $allRoles = $this->roleHierarchy->getReachableRoleNames($assignedRoles); + } else { + $allRoles = array_map(function (Role $role) { return (string) $role; }, $this->roleHierarchy->getReachableRoles($token->getRoles(false))); + } + foreach ($allRoles as $role) { if (!\in_array($role, $assignedRoles, true)) { $inheritedRoles[] = $role; @@ -129,8 +145,8 @@ public function collect(Request $request, Response $response, \Exception $except 'token_class' => $this->hasVarDumper ? new ClassStub(\get_class($token)) : \get_class($token), 'logout_url' => $logoutUrl, 'user' => $token->getUsername(), - 'roles' => array_map(function (Role $role) { return $role->getRole(); }, $assignedRoles), - 'inherited_roles' => array_unique(array_map(function (Role $role) { return $role->getRole(); }, $inheritedRoles)), + 'roles' => $assignedRoles, + 'inherited_roles' => array_unique($inheritedRoles), 'supports_role_hierarchy' => null !== $this->roleHierarchy, ]; } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 9fbdae0bdd46f..08931ac718b98 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -98,6 +98,7 @@ %security.role_hierarchy.roles% + diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php index e95b354d99851..ac264d2937ecc 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php @@ -18,9 +18,12 @@ use Symfony\Bundle\SecurityBundle\Security\FirewallMap; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager; @@ -38,7 +41,7 @@ class SecurityDataCollectorTest extends TestCase public function testCollectWhenSecurityIsDisabled() { $collector = new SecurityDataCollector(); - $collector->collect($this->getRequest(), $this->getResponse()); + $collector->collect(new Request(), new Response()); $this->assertSame('security', $collector->getName()); $this->assertFalse($collector->isEnabled()); @@ -58,7 +61,7 @@ public function testCollectWhenAuthenticationTokenIsNull() { $tokenStorage = new TokenStorage(); $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy()); - $collector->collect($this->getRequest(), $this->getResponse()); + $collector->collect(new Request(), new Response()); $this->assertTrue($collector->isEnabled()); $this->assertFalse($collector->isAuthenticated()); @@ -80,7 +83,7 @@ public function testCollectAuthenticationTokenAndRoles(array $roles, array $norm $tokenStorage->setToken(new UsernamePasswordToken('hhamon', 'P4$$w0rD', 'provider', $roles)); $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy()); - $collector->collect($this->getRequest(), $this->getResponse()); + $collector->collect(new Request(), new Response()); $collector->lateCollect(); $this->assertTrue($collector->isEnabled()); @@ -95,6 +98,9 @@ public function testCollectAuthenticationTokenAndRoles(array $roles, array $norm $this->assertSame('hhamon', $collector->getUser()); } + /** + * @group legacy + */ public function testCollectImpersonatedToken() { $adminToken = new UsernamePasswordToken('yceruto', 'P4$$w0rD', 'provider', ['ROLE_ADMIN']); @@ -108,7 +114,7 @@ public function testCollectImpersonatedToken() $tokenStorage->setToken(new UsernamePasswordToken('hhamon', 'P4$$w0rD', 'provider', $userRoles)); $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy()); - $collector->collect($this->getRequest(), $this->getResponse()); + $collector->collect(new Request(), new Response()); $collector->lateCollect(); $this->assertTrue($collector->isEnabled()); @@ -122,10 +128,32 @@ public function testCollectImpersonatedToken() $this->assertSame('hhamon', $collector->getUser()); } + public function testCollectSwitchUserToken() + { + $adminToken = new UsernamePasswordToken('yceruto', 'P4$$w0rD', 'provider', ['ROLE_ADMIN']); + + $tokenStorage = new TokenStorage(); + $tokenStorage->setToken(new SwitchUserToken('hhamon', 'P4$$w0rD', 'provider', ['ROLE_USER', 'ROLE_PREVIOUS_ADMIN'], $adminToken)); + + $collector = new SecurityDataCollector($tokenStorage, $this->getRoleHierarchy()); + $collector->collect(new Request(), new Response()); + $collector->lateCollect(); + + $this->assertTrue($collector->isEnabled()); + $this->assertTrue($collector->isAuthenticated()); + $this->assertTrue($collector->isImpersonated()); + $this->assertSame('yceruto', $collector->getImpersonatorUser()); + $this->assertSame(SwitchUserToken::class, $collector->getTokenClass()->getValue()); + $this->assertTrue($collector->supportsRoleHierarchy()); + $this->assertSame(['ROLE_USER', 'ROLE_PREVIOUS_ADMIN'], $collector->getRoles()->getValue(true)); + $this->assertSame([], $collector->getInheritedRoles()->getValue(true)); + $this->assertSame('hhamon', $collector->getUser()); + } + public function testGetFirewall() { $firewallConfig = new FirewallConfig('dummy', 'security.request_matcher.dummy', 'security.user_checker.dummy'); - $request = $this->getRequest(); + $request = new Request(); $firewallMap = $this ->getMockBuilder(FirewallMap::class) @@ -138,7 +166,7 @@ public function testGetFirewall() ->willReturn($firewallConfig); $collector = new SecurityDataCollector(null, null, null, null, $firewallMap, new TraceableFirewallListener($firewallMap, new EventDispatcher(), new LogoutUrlGenerator())); - $collector->collect($request, $this->getResponse()); + $collector->collect($request, new Response()); $collector->lateCollect(); $collected = $collector->getFirewall(); @@ -158,8 +186,8 @@ public function testGetFirewall() public function testGetFirewallReturnsNull() { - $request = $this->getRequest(); - $response = $this->getResponse(); + $request = new Request(); + $response = new Response(); // Don't inject any firewall map $collector = new SecurityDataCollector(); @@ -192,9 +220,9 @@ public function testGetFirewallReturnsNull() */ public function testGetListeners() { - $request = $this->getRequest(); + $request = new Request(); $event = new GetResponseEvent($this->getMockBuilder(HttpKernelInterface::class)->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); - $event->setResponse($response = $this->getResponse()); + $event->setResponse($response = new Response()); $listener = $this->getMockBuilder(ListenerInterface::class)->getMock(); $listener ->expects($this->once()) @@ -345,7 +373,7 @@ public function testCollectDecisionLog(string $strategy, array $decisionLog, arr ->willReturn($decisionLog); $dataCollector = new SecurityDataCollector(null, null, null, $accessDecisionManager); - $dataCollector->collect($this->getRequest(), $this->getResponse()); + $dataCollector->collect(new Request(), new Response()); $this->assertEquals($dataCollector->getAccessDecisionLog(), $expectedDecisionLog, 'Wrong value returned by getAccessDecisionLog'); @@ -367,7 +395,7 @@ public function provideRoles() [], ], [ - [new Role('ROLE_USER')], + [new Role('ROLE_USER', false)], ['ROLE_USER'], [], ], @@ -378,7 +406,7 @@ public function provideRoles() ['ROLE_USER', 'ROLE_ALLOWED_TO_SWITCH'], ], [ - [new Role('ROLE_ADMIN')], + [new Role('ROLE_ADMIN', false)], ['ROLE_ADMIN'], ['ROLE_USER', 'ROLE_ALLOWED_TO_SWITCH'], ], @@ -397,20 +425,4 @@ private function getRoleHierarchy() 'ROLE_OPERATOR' => ['ROLE_USER'], ]); } - - private function getRequest() - { - return $this - ->getMockBuilder('Symfony\Component\HttpFoundation\Request') - ->disableOriginalConstructor() - ->getMock(); - } - - private function getResponse() - { - return $this - ->getMockBuilder('Symfony\Component\HttpFoundation\Response') - ->disableOriginalConstructor() - ->getMock(); - } } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 23b40ea144635..074e8593178d6 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -21,7 +21,7 @@ "symfony/config": "^4.2", "symfony/dependency-injection": "^4.2", "symfony/http-kernel": "^4.1", - "symfony/security-core": "~4.2", + "symfony/security-core": "~4.3", "symfony/security-csrf": "~4.2", "symfony/security-guard": "~4.2", "symfony/security-http": "~4.2" diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 23d3ea43beed9..011d802ea1ff7 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -4,6 +4,13 @@ CHANGELOG 4.3.0 ----- +* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles + instead. +* The `RoleHierarchyInterface` is deprecated and will be removed in 5.0. +* The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0. + Use the `getReachableRoleNames()` method instead. +* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` + method instead and return roles as strings. * Made the `serialize()` and `unserialize()` methods of `AbstractToken` and `AuthenticationException` final, use `getState()`/`setState()` instead diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php index 5f9128fe7b50e..7a35bb056a720 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Core\Authentication\Provider; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; @@ -87,7 +88,12 @@ public function authenticate(TokenInterface $token) throw $e; } - $authenticatedToken = new UsernamePasswordToken($user, $token->getCredentials(), $this->providerKey, $this->getRoles($user, $token)); + if ($token instanceof SwitchUserToken) { + $authenticatedToken = new SwitchUserToken($user, $token->getCredentials(), $this->providerKey, $this->getRoles($user, $token), $token->getOriginalToken()); + } else { + $authenticatedToken = new UsernamePasswordToken($user, $token->getCredentials(), $this->providerKey, $this->getRoles($user, $token)); + } + $authenticatedToken->setAttributes($token->getAttributes()); return $authenticatedToken; @@ -110,7 +116,7 @@ private function getRoles(UserInterface $user, TokenInterface $token) { $roles = $user->getRoles(); - foreach ($token->getRoles() as $role) { + foreach ($token->getRoles(false) as $role) { if ($role instanceof SwitchUserRole) { $roles[] = $role; diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index f879cf8a87fdd..700634e7dcdac 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -26,11 +26,12 @@ abstract class AbstractToken implements TokenInterface { private $user; private $roles = []; + private $roleNames = []; private $authenticated = false; private $attributes = []; /** - * @param (Role|string)[] $roles An array of roles + * @param string[] $roles An array of roles * * @throws \InvalidArgumentException */ @@ -38,20 +39,30 @@ public function __construct(array $roles = []) { foreach ($roles as $role) { if (\is_string($role)) { - $role = new Role($role); + $role = new Role($role, false); } elseif (!$role instanceof Role) { throw new \InvalidArgumentException(sprintf('$roles must be an array of strings, or Role instances, but got %s.', \gettype($role))); } $this->roles[] = $role; + $this->roleNames[] = (string) $role; } } + public function getRoleNames(): array + { + return $this->roleNames; + } + /** * {@inheritdoc} */ public function getRoles() { + if (0 === \func_num_args() || func_get_arg(0)) { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3. Use the getRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED); + } + return $this->roles; } @@ -172,7 +183,7 @@ public function unserialize($serialized) */ protected function getState(): array { - return [$this->user, $this->authenticated, $this->roles, $this->attributes]; + return [$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames]; } /** @@ -193,7 +204,7 @@ protected function getState(): array */ protected function setState(array $data) { - [$this->user, $this->authenticated, $this->roles, $this->attributes] = $data; + [$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames] = $data; } /** @@ -225,7 +236,7 @@ public function setAttributes(array $attributes) */ public function hasAttribute($name) { - return array_key_exists($name, $this->attributes); + return \array_key_exists($name, $this->attributes); } /** @@ -239,7 +250,7 @@ public function hasAttribute($name) */ public function getAttribute($name) { - if (!array_key_exists($name, $this->attributes)) { + if (!\array_key_exists($name, $this->attributes)) { throw new \InvalidArgumentException(sprintf('This token has no "%s" attribute.', $name)); } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php index 18b2481330972..c233c2bd16dc3 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Core\Authentication\Token; -use Symfony\Component\Security\Core\Role\Role; - /** * AnonymousToken represents an anonymous token. * @@ -25,7 +23,7 @@ class AnonymousToken extends AbstractToken /** * @param string $secret A secret used to make sure the token is created by the app and not by a malicious client * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string - * @param Role[] $roles An array of roles + * @param string[] $roles An array of roles */ public function __construct(string $secret, $user, array $roles = []) { diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php index 733f29159a51c..eb407e50c9c66 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Core\Authentication\Token; -use Symfony\Component\Security\Core\Role\Role; - /** * PreAuthenticatedToken implements a pre-authenticated token. * @@ -24,10 +22,10 @@ class PreAuthenticatedToken extends AbstractToken private $providerKey; /** - * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string - * @param mixed $credentials The user credentials - * @param string $providerKey The provider key - * @param (Role|string)[] $roles An array of roles + * @param string|object $user The user can be a UserInterface instance, or an object implementing a __toString method or the username as a regular string + * @param mixed $credentials The user credentials + * @param string $providerKey The provider key + * @param string[] $roles An array of roles */ public function __construct($user, $credentials, string $providerKey, array $roles = []) { diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php b/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php index f1f5391ba7800..97534b8f70044 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/Storage/TokenStorage.php @@ -39,6 +39,10 @@ public function getToken() */ public function setToken(TokenInterface $token = null) { + if (null !== $token && !method_exists($token, 'getRoleNames')) { + @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); + } + $this->token = $token; } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php new file mode 100644 index 0000000000000..8e73876306aa9 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Authentication\Token; + +/** + * Token representing a user who temporarily impersonates another one. + * + * @author Christian Flothmann + */ +class SwitchUserToken extends UsernamePasswordToken +{ + private $originalToken; + + /** + * @param string|object $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method + * @param mixed $credentials This usually is the password of the user + * @param string $providerKey The provider key + * @param string[] $roles An array of roles + * @param TokenInterface $originalToken The token of the user who switched to the current user + * + * @throws \InvalidArgumentException + */ + public function __construct($user, $credentials, string $providerKey, array $roles = [], TokenInterface $originalToken) + { + parent::__construct($user, $credentials, $providerKey, $roles); + + $this->originalToken = $originalToken; + } + + public function getOriginalToken(): TokenInterface + { + return $this->originalToken; + } + + /** + * {@inheritdoc} + */ + protected function getState(): array + { + return [$this->originalToken, parent::getState()]; + } + + /** + * {@inheritdoc} + */ + protected function setState(array $data) + { + [$this->originalToken, $parentData] = $data; + parent::setState($parentData); + } +} diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php b/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php index bcf6fbdd94621..4d8c2522abd6d 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php @@ -18,6 +18,8 @@ * * @author Fabien Potencier * @author Johannes M. Schmitt + * + * @method string[] getRoleNames() The associated roles - not implementing it is deprecated since Symfony 4.3 */ interface TokenInterface extends \Serializable { @@ -34,6 +36,8 @@ public function __toString(); * Returns the user roles. * * @return Role[] An array of Role instances + * + * @deprecated since Symfony 4.3, use the getRoleNames() method instead */ public function getRoles(); diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php index d731906eb7e0f..79e5780f09ce6 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php @@ -11,8 +11,6 @@ namespace Symfony\Component\Security\Core\Authentication\Token; -use Symfony\Component\Security\Core\Role\Role; - /** * UsernamePasswordToken implements a username and password token. * @@ -24,10 +22,10 @@ class UsernamePasswordToken extends AbstractToken private $providerKey; /** - * @param string|object $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method - * @param mixed $credentials This usually is the password of the user - * @param string $providerKey The provider key - * @param (Role|string)[] $roles An array of roles + * @param string|object $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method + * @param mixed $credentials This usually is the password of the user + * @param string $providerKey The provider key + * @param string[] $roles An array of roles * * @throws \InvalidArgumentException */ diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php index d9530e071ce72..c04c2ab322737 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php @@ -18,6 +18,8 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\ExpressionLanguage; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; /** @@ -90,18 +92,34 @@ public function vote(TokenInterface $token, $subject, array $attributes) private function getVariables(TokenInterface $token, $subject) { - if (null !== $this->roleHierarchy) { - $roles = $this->roleHierarchy->getReachableRoles($token->getRoles()); + if ($this->roleHierarchy instanceof RoleHierarchy) { + if (method_exists($token, 'getRoleNames')) { + $rolesFromToken = $token->getRoleNames(); + } else { + @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); + + $rolesFromToken = $token->getRoles(false); + } + + $roles = $this->roleHierarchy->getReachableRoleNames($rolesFromToken); + } elseif (null !== $this->roleHierarchy) { + $roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false)); + } elseif (method_exists($token, 'getRoleNames')) { + $roles = $token->getRoleNames(); } else { - $roles = $token->getRoles(); + @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); + + $roles = $token->getRoles(false); } + $roles = array_map(function ($role) { return $role instanceof Role ? $role->getRole() : $role; }, $roles); + $variables = [ 'token' => $token, 'user' => $token->getUser(), 'object' => $subject, 'subject' => $subject, - 'roles' => array_map(function ($role) { return $role->getRole(); }, $roles), + 'roles' => $roles, 'trust_resolver' => $this->trustResolver, 'auth_checker' => $this->authChecker, ]; diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php index 06dfb4228ea89..4a1de12cf7fa8 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Core\Authorization\Voter; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; /** @@ -26,6 +27,10 @@ class RoleHierarchyVoter extends RoleVoter public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefix = 'ROLE_') { + if (!$roleHierarchy instanceof RoleHierarchy) { + @trigger_error(sprintf('Passing a role hierarchy to "%s" that is not an instance of "%s" is deprecated since Symfony 4.3 and support for it will be dropped in Symfony 5.0 ("%s" given).', __CLASS__, RoleHierarchy::class, \get_class($roleHierarchy)), E_USER_DEPRECATED); + } + $this->roleHierarchy = $roleHierarchy; parent::__construct($prefix); @@ -36,6 +41,18 @@ public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefi */ protected function extractRoles(TokenInterface $token) { - return $this->roleHierarchy->getReachableRoles($token->getRoles()); + if ($this->roleHierarchy instanceof RoleHierarchy) { + if (method_exists($token, 'getRoleNames')) { + $roles = $token->getRoleNames(); + } else { + @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); + + $roles = $token->getRoles(false); + } + + return $this->roleHierarchy->getReachableRoleNames($roles); + } + + return $this->roleHierarchy->getReachableRoles($token->getRoles(false)); } } diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php index fc2e6883e473f..deb542255c513 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php @@ -47,7 +47,7 @@ public function vote(TokenInterface $token, $subject, array $attributes) $result = VoterInterface::ACCESS_DENIED; foreach ($roles as $role) { - if ($attribute === $role->getRole()) { + if ($attribute === $role) { return VoterInterface::ACCESS_GRANTED; } } @@ -58,6 +58,12 @@ public function vote(TokenInterface $token, $subject, array $attributes) protected function extractRoles(TokenInterface $token) { - return $token->getRoles(); + if (method_exists($token, 'getRoleNames')) { + return $token->getRoleNames(); + } + + @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); + + return array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false)); } } diff --git a/src/Symfony/Component/Security/Core/Role/Role.php b/src/Symfony/Component/Security/Core/Role/Role.php index 208fe2f6b7e06..df6ccf7636225 100644 --- a/src/Symfony/Component/Security/Core/Role/Role.php +++ b/src/Symfony/Component/Security/Core/Role/Role.php @@ -15,6 +15,8 @@ * Role is a simple implementation representing a role identified by a string. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use strings as roles instead. */ class Role { @@ -22,6 +24,10 @@ class Role public function __construct(string $role) { + if (\func_num_args() < 2 || func_get_arg(1)) { + @trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3 and will be removed in 5.0. Use strings as roles instead.', __CLASS__), E_USER_DEPRECATED); + } + $this->role = $role; } @@ -34,4 +40,9 @@ public function getRole() { return $this->role; } + + public function __toString(): string + { + return $this->role; + } } diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php index f4a2e5b622974..d725000d1b826 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php @@ -36,6 +36,8 @@ public function __construct(array $hierarchy) */ public function getReachableRoles(array $roles) { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED); + $reachableRoles = $roles; foreach ($roles as $role) { if (!isset($this->map[$role->getRole()])) { @@ -50,6 +52,37 @@ public function getReachableRoles(array $roles) return $reachableRoles; } + /** + * @param string[] $roles + * + * @return string[] + */ + public function getReachableRoleNames(array $roles): array + { + $reachableRoles = $roles = array_map( + function ($role) { + if ($role instanceof Role) { + return $role->getRole(); + } + + return $role; + }, + $roles + ); + + foreach ($roles as $role) { + if (!isset($this->map[$role])) { + continue; + } + + foreach ($this->map[$role] as $r) { + $reachableRoles[] = $r; + } + } + + return $reachableRoles; + } + protected function buildRoleMap() { $this->map = []; diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php index 1a86db9901603..3a5112f7e5b91 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php @@ -15,6 +15,8 @@ * RoleHierarchyInterface is the interface for a role hierarchy. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface RoleHierarchyInterface { diff --git a/src/Symfony/Component/Security/Core/Role/SwitchUserRole.php b/src/Symfony/Component/Security/Core/Role/SwitchUserRole.php index d26c7067a2d90..85d7ddb1a56a6 100644 --- a/src/Symfony/Component/Security/Core/Role/SwitchUserRole.php +++ b/src/Symfony/Component/Security/Core/Role/SwitchUserRole.php @@ -18,9 +18,12 @@ * another one. * * @author Fabien Potencier + * + * @deprecated since version 4.3, to be removed in 5.0. Use strings as roles instead. */ class SwitchUserRole extends Role { + private $deprecationTriggered = false; private $source; /** @@ -29,7 +32,13 @@ class SwitchUserRole extends Role */ public function __construct(string $role, TokenInterface $source) { - parent::__construct($role); + if ($triggerDeprecation = \func_num_args() < 3 || func_get_arg(2)) { + @trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3 and will be removed in 5.0. Use strings as roles instead.', __CLASS__), E_USER_DEPRECATED); + + $this->deprecationTriggered = true; + } + + parent::__construct($role, $triggerDeprecation); $this->source = $source; } @@ -41,6 +50,12 @@ public function __construct(string $role, TokenInterface $source) */ public function getSource() { + if (!$this->deprecationTriggered && (\func_num_args() < 1 || func_get_arg(0))) { + @trigger_error(sprintf('The "%s" class is deprecated since version 4.3 and will be removed in 5.0. Use strings as roles instead.', __CLASS__), E_USER_DEPRECATED); + + $this->deprecationTriggered = true; + } + return $this->source; } } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php index a101208d681cc..d8d18ddeb9a42 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php @@ -70,7 +70,7 @@ public function testAuthenticate() $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken', $token); $this->assertEquals('pass', $token->getCredentials()); $this->assertEquals('key', $token->getProviderKey()); - $this->assertEquals([], $token->getRoles()); + $this->assertEquals([], $token->getRoleNames()); $this->assertEquals(['foo' => 'bar'], $token->getAttributes(), '->authenticate() copies token attributes'); $this->assertSame($user, $token->getUser()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/RememberMeAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/RememberMeAuthenticationProviderTest.php index 26287693d6b08..37d9a42a96319 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/RememberMeAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/RememberMeAuthenticationProviderTest.php @@ -14,7 +14,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Provider\RememberMeAuthenticationProvider; use Symfony\Component\Security\Core\Exception\DisabledException; -use Symfony\Component\Security\Core\Role\Role; class RememberMeAuthenticationProviderTest extends TestCase { @@ -78,7 +77,7 @@ public function testAuthenticate() $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\RememberMeToken', $authToken); $this->assertSame($user, $authToken->getUser()); - $this->assertEquals([new Role('ROLE_FOO')], $authToken->getRoles()); + $this->assertEquals(['ROLE_FOO'], $authToken->getRoleNames()); $this->assertEquals('', $authToken->getCredentials()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php index 7c306d2f1f0f6..e62ac3f9f5f29 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php @@ -12,11 +12,11 @@ namespace Symfony\Component\Security\Core\Tests\Authentication\Provider; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Exception\AccountExpiredException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\CredentialsExpiredException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; -use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\SwitchUserRole; class UserAuthenticationProviderTest extends TestCase @@ -189,11 +189,14 @@ public function testAuthenticate() $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $authToken); $this->assertSame($user, $authToken->getUser()); - $this->assertEquals([new Role('ROLE_FOO')], $authToken->getRoles()); + $this->assertEquals(['ROLE_FOO'], $authToken->getRoleNames()); $this->assertEquals('foo', $authToken->getCredentials()); $this->assertEquals(['foo' => 'bar'], $authToken->getAttributes(), '->authenticate() copies token attributes'); } + /** + * @group legacy + */ public function testAuthenticateWithPreservingRoleSwitchUserRole() { $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); @@ -224,12 +227,40 @@ public function testAuthenticateWithPreservingRoleSwitchUserRole() $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken', $authToken); $this->assertSame($user, $authToken->getUser()); - $this->assertContains(new Role('ROLE_FOO'), $authToken->getRoles(), '', false, false); + $this->assertContains('ROLE_FOO', $authToken->getRoleNames(), '', false, false); $this->assertContains($switchUserRole, $authToken->getRoles(), '', false, false); $this->assertEquals('foo', $authToken->getCredentials()); $this->assertEquals(['foo' => 'bar'], $authToken->getAttributes(), '->authenticate() copies token attributes'); } + public function testAuthenticatePreservesOriginalToken() + { + $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); + $user->expects($this->once()) + ->method('getRoles') + ->will($this->returnValue(['ROLE_FOO'])) + ; + + $provider = $this->getProvider(); + $provider->expects($this->once()) + ->method('retrieveUser') + ->will($this->returnValue($user)) + ; + + $originalToken = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); + $token = new SwitchUserToken($this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(), 'foo', 'key', [], $originalToken); + $token->setAttributes(['foo' => 'bar']); + + $authToken = $provider->authenticate($token); + + $this->assertInstanceOf(SwitchUserToken::class, $authToken); + $this->assertSame($originalToken, $authToken->getOriginalToken()); + $this->assertSame($user, $authToken->getUser()); + $this->assertContains('ROLE_FOO', $authToken->getRoleNames(), '', false, false); + $this->assertEquals('foo', $authToken->getCredentials()); + $this->assertEquals(['foo' => 'bar'], $authToken->getAttributes(), '->authenticate() copies token attributes'); + } + protected function getSupportedToken() { $mock = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken')->setMethods(['getCredentials', 'getProviderKey', 'getRoles'])->disableOriginalConstructor()->getMock(); diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 066ca6892ce53..e87d25a789f1d 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -14,61 +14,14 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Core\User\User; - -class TestUser -{ - protected $name; - - public function __construct($name) - { - $this->name = $name; - } - - public function __toString() - { - return $this->name; - } -} - -class ConcreteToken extends AbstractToken -{ - private $credentials = 'credentials_value'; - - public function __construct($user, array $roles = []) - { - parent::__construct($roles); - - $this->setUser($user); - } - - /** - * {@inheritdoc} - */ - public function serialize() - { - $serialized = [$this->credentials, parent::serialize(true)]; - - return $this->doSerialize($serialized, \func_num_args() ? \func_get_arg(0) : null); - } - - public function unserialize($serialized) - { - list($this->credentials, $parentStr) = unserialize($serialized); - parent::unserialize($parentStr); - } - - public function getCredentials() - { - } -} +use Symfony\Component\Security\Core\User\UserInterface; class AbstractTokenTest extends TestCase { public function testGetUsername() { - $token = $this->getToken(['ROLE_FOO']); + $token = new ConcreteToken(['ROLE_FOO']); $token->setUser('fabien'); $this->assertEquals('fabien', $token->getUsername()); @@ -83,7 +36,7 @@ public function testGetUsername() public function testEraseCredentials() { - $token = $this->getToken(['ROLE_FOO']); + $token = new ConcreteToken(['ROLE_FOO']); $user = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); $user->expects($this->once())->method('eraseCredentials'); @@ -94,19 +47,22 @@ public function testEraseCredentials() public function testSerialize() { - $token = $this->getToken(['ROLE_FOO', new Role('ROLE_BAR')]); + $token = new ConcreteToken(['ROLE_FOO', new Role('ROLE_BAR', false)]); $token->setAttributes(['foo' => 'bar']); $uToken = unserialize(serialize($token)); - $this->assertEquals($token->getRoles(), $uToken->getRoles()); + $this->assertEquals($token->getRoleNames(), $uToken->getRoleNames()); $this->assertEquals($token->getAttributes(), $uToken->getAttributes()); } + /** + * @group legacy + */ public function testSerializeWithRoleObjects() { $user = new User('name', 'password', [new Role('ROLE_FOO'), new Role('ROLE_BAR')]); - $token = new ConcreteToken($user, $user->getRoles()); + $token = new ConcreteToken($user->getRoles(), $user); $serialized = serialize($token); $unserialized = unserialize($serialized); @@ -116,35 +72,42 @@ public function testSerializeWithRoleObjects() $this->assertEquals($roles, $user->getRoles()); } - public function testSerializeParent() + public function testConstructor() { - $user = new TestUser('fabien'); - $token = new ConcreteToken($user, ['ROLE_FOO']); + $token = new ConcreteToken(['ROLE_FOO']); + $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); + } - $parentToken = new ConcreteToken($user, [new SwitchUserRole('ROLE_PREVIOUS', $token)]); - $uToken = unserialize(serialize($parentToken)); + /** + * @group legacy + */ + public function testConstructorWithRoleObjects() + { + $token = new ConcreteToken([new Role('ROLE_FOO')]); + $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); - $this->assertEquals( - current($parentToken->getRoles())->getSource()->getUser(), - current($uToken->getRoles())->getSource()->getUser() - ); + $token = new ConcreteToken([new Role('ROLE_FOO'), 'ROLE_BAR']); + $this->assertEquals(['ROLE_FOO', 'ROLE_BAR'], $token->getRoleNames()); } - public function testConstructor() + /** + * @group legacy + */ + public function testGetRoles() { - $token = $this->getToken(['ROLE_FOO']); + $token = new ConcreteToken(['ROLE_FOO']); $this->assertEquals([new Role('ROLE_FOO')], $token->getRoles()); - $token = $this->getToken([new Role('ROLE_FOO')]); + $token = new ConcreteToken([new Role('ROLE_FOO')]); $this->assertEquals([new Role('ROLE_FOO')], $token->getRoles()); - $token = $this->getToken([new Role('ROLE_FOO'), 'ROLE_BAR']); + $token = new ConcreteToken([new Role('ROLE_FOO'), 'ROLE_BAR']); $this->assertEquals([new Role('ROLE_FOO'), new Role('ROLE_BAR')], $token->getRoles()); } public function testAuthenticatedFlag() { - $token = $this->getToken(); + $token = new ConcreteToken(); $this->assertFalse($token->isAuthenticated()); $token->setAuthenticated(true); @@ -157,7 +120,7 @@ public function testAuthenticatedFlag() public function testAttributes() { $attributes = ['foo' => 'bar']; - $token = $this->getToken(); + $token = new ConcreteToken(); $token->setAttributes($attributes); $this->assertEquals($attributes, $token->getAttributes(), '->getAttributes() returns the token attributes'); @@ -181,7 +144,7 @@ public function testAttributes() */ public function testSetUser($user) { - $token = $this->getToken(); + $token = new ConcreteToken(); $token->setUser($user); $this->assertSame($user, $token->getUser()); } @@ -202,7 +165,7 @@ public function getUsers() */ public function testSetUserSetsAuthenticatedToFalseWhenUserChanges($firstUser, $secondUser) { - $token = $this->getToken(); + $token = new ConcreteToken(); $token->setAuthenticated(true); $this->assertTrue($token->isAuthenticated()); @@ -236,7 +199,7 @@ public function getUserChanges() */ public function testSetUserSetsAuthenticatedToFalseWhenUserChangesAdvancedUser($firstUser, $secondUser) { - $token = $this->getToken(); + $token = new ConcreteToken(); $token->setAuthenticated(true); $this->assertTrue($token->isAuthenticated()); @@ -275,7 +238,7 @@ public function getUserChangesAdvancedUser() */ public function testSetUserDoesNotSetAuthenticatedToFalseWhenUserDoesNotChange($user) { - $token = $this->getToken(); + $token = new ConcreteToken(); $token->setAuthenticated(true); $this->assertTrue($token->isAuthenticated()); @@ -285,9 +248,48 @@ public function testSetUserDoesNotSetAuthenticatedToFalseWhenUserDoesNotChange($ $token->setUser($user); $this->assertTrue($token->isAuthenticated()); } +} + +class TestUser +{ + protected $name; + + public function __construct($name) + { + $this->name = $name; + } + + public function __toString() + { + return $this->name; + } +} + +class ConcreteToken extends AbstractToken +{ + private $credentials = 'credentials_value'; + + public function __construct(array $roles = [], UserInterface $user = null) + { + parent::__construct($roles); + + if (null !== $user) { + $this->setUser($user); + } + } - protected function getToken(array $roles = []) + public function serialize() + { + return serialize([$this->credentials, parent::serialize()]); + } + + public function unserialize($serialized) + { + list($this->credentials, $parentStr) = unserialize($serialized); + parent::unserialize($parentStr); + } + + public function getCredentials() { - return $this->getMockForAbstractClass('Symfony\Component\Security\Core\Authentication\Token\AbstractToken', [$roles]); } } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AnonymousTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AnonymousTokenTest.php index 7024cc5356cd4..1b00fd4e76aec 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AnonymousTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AnonymousTokenTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; -use Symfony\Component\Security\Core\Role\Role; class AnonymousTokenTest extends TestCase { @@ -23,7 +22,7 @@ public function testConstructor() $this->assertTrue($token->isAuthenticated()); $token = new AnonymousToken('foo', 'bar', ['ROLE_FOO']); - $this->assertEquals([new Role('ROLE_FOO')], $token->getRoles()); + $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); } public function testGetKey() diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/PreAuthenticatedTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/PreAuthenticatedTokenTest.php index 7e64aa1a5d4e6..78cda619b2aff 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/PreAuthenticatedTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/PreAuthenticatedTokenTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; -use Symfony\Component\Security\Core\Role\Role; class PreAuthenticatedTokenTest extends TestCase { @@ -24,7 +23,7 @@ public function testConstructor() $token = new PreAuthenticatedToken('foo', 'bar', 'key', ['ROLE_FOO']); $this->assertTrue($token->isAuthenticated()); - $this->assertEquals([new Role('ROLE_FOO')], $token->getRoles()); + $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); $this->assertEquals('key', $token->getProviderKey()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/RememberMeTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/RememberMeTokenTest.php index 8fa0307108f54..fea6161d775a0 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/RememberMeTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/RememberMeTokenTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; -use Symfony\Component\Security\Core\Role\Role; class RememberMeTokenTest extends TestCase { @@ -24,7 +23,7 @@ public function testConstructor() $this->assertEquals('fookey', $token->getProviderKey()); $this->assertEquals('foo', $token->getSecret()); - $this->assertEquals([new Role('ROLE_FOO')], $token->getRoles()); + $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); $this->assertSame($user, $token->getUser()); $this->assertTrue($token->isAuthenticated()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php index fd30eea3c57c7..43261b3bd2b60 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; class TokenStorageTest extends TestCase { @@ -20,7 +21,7 @@ public function testGetSetToken() { $tokenStorage = new TokenStorage(); $this->assertNull($tokenStorage->getToken()); - $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); + $token = new UsernamePasswordToken('username', 'password', 'provider'); $tokenStorage->setToken($token); $this->assertSame($token, $tokenStorage->getToken()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php new file mode 100644 index 0000000000000..5841250959b09 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/SwitchUserTokenTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Core\Tests\Authentication\Token; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; + +class SwitchUserTokenTest extends TestCase +{ + public function testSerialize() + { + $originalToken = new UsernamePasswordToken('user', 'foo', 'provider-key', ['ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH']); + $token = new SwitchUserToken('admin', 'bar', 'provider-key', ['ROLE_USER'], $originalToken); + + $unserializedToken = unserialize(serialize($token)); + + $this->assertInstanceOf(SwitchUserToken::class, $unserializedToken); + $this->assertSame('admin', $unserializedToken->getUsername()); + $this->assertSame('bar', $unserializedToken->getCredentials()); + $this->assertSame('provider-key', $unserializedToken->getProviderKey()); + $this->assertEquals(['ROLE_USER'], $unserializedToken->getRoleNames()); + + $unserializedOriginalToken = $unserializedToken->getOriginalToken(); + + $this->assertInstanceOf(UsernamePasswordToken::class, $unserializedOriginalToken); + $this->assertSame('user', $unserializedOriginalToken->getUsername()); + $this->assertSame('foo', $unserializedOriginalToken->getCredentials()); + $this->assertSame('provider-key', $unserializedOriginalToken->getProviderKey()); + $this->assertEquals(['ROLE_ADMIN', 'ROLE_ALLOWED_TO_SWITCH'], $unserializedOriginalToken->getRoleNames()); + } +} diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/UsernamePasswordTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/UsernamePasswordTokenTest.php index 87dceea3d8422..ab0abaf6530c9 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/UsernamePasswordTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/UsernamePasswordTokenTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Symfony\Component\Security\Core\Role\Role; class UsernamePasswordTokenTest extends TestCase { @@ -23,7 +22,7 @@ public function testConstructor() $this->assertFalse($token->isAuthenticated()); $token = new UsernamePasswordToken('foo', 'bar', 'key', ['ROLE_FOO']); - $this->assertEquals([new Role('ROLE_FOO')], $token->getRoles()); + $this->assertEquals(['ROLE_FOO'], $token->getRoleNames()); $this->assertTrue($token->isAuthenticated()); $this->assertEquals('key', $token->getProviderKey()); } diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php index 6a07c94f2039c..f2dcb6fbc3c18 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/AuthorizationCheckerTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; class AuthorizationCheckerTest extends TestCase @@ -37,10 +38,10 @@ protected function setUp() public function testVoteAuthenticatesTokenIfNecessary() { - $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); + $token = new UsernamePasswordToken('username', 'password', 'provider'); $this->tokenStorage->setToken($token); - $newToken = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); + $newToken = new UsernamePasswordToken('username', 'password', 'provider'); $this->authenticationManager ->expects($this->once()) @@ -79,11 +80,7 @@ public function testVoteWithoutAuthenticationToken() */ public function testIsGranted($decide) { - $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); - $token - ->expects($this->once()) - ->method('isAuthenticated') - ->will($this->returnValue(true)); + $token = new UsernamePasswordToken('username', 'password', 'provider', ['ROLE_USER']); $this->accessDecisionManager ->expects($this->once()) diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php index 632c6d0ab07ca..d377718842456 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/ExpressionVoterTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; @@ -20,6 +21,7 @@ class ExpressionVoterTest extends TestCase { /** + * @group legacy * @dataProvider getVoteTests */ public function testVote($roles, $attributes, $expected, $tokenExpectsGetRoles = true, $expressionLanguageExpectsEvaluate = true) @@ -29,6 +31,16 @@ public function testVote($roles, $attributes, $expected, $tokenExpectsGetRoles = $this->assertSame($expected, $voter->vote($this->getToken($roles, $tokenExpectsGetRoles), null, $attributes)); } + /** + * @dataProvider getVoteTests + */ + public function testVoteWithTokenThatReturnsRoleNames($roles, $attributes, $expected, $tokenExpectsGetRoles = true, $expressionLanguageExpectsEvaluate = true) + { + $voter = new ExpressionVoter($this->createExpressionLanguage($expressionLanguageExpectsEvaluate), $this->createTrustResolver(), $this->createAuthorizationChecker()); + + $this->assertSame($expected, $voter->vote($this->getTokenWithRoleNames($roles, $tokenExpectsGetRoles), null, $attributes)); + } + public function getVoteTests() { return [ @@ -58,6 +70,19 @@ protected function getToken(array $roles, $tokenExpectsGetRoles = true) return $token; } + protected function getTokenWithRoleNames(array $roles, $tokenExpectsGetRoles = true) + { + $token = $this->getMockBuilder(AbstractToken::class)->getMock(); + + if ($tokenExpectsGetRoles) { + $token->expects($this->once()) + ->method('getRoleNames') + ->will($this->returnValue($roles)); + } + + return $token; + } + protected function createExpressionLanguage($expressionLanguageExpectsEvaluate = true) { $mock = $this->getMockBuilder('Symfony\Component\Security\Core\Authorization\ExpressionLanguage')->getMock(); diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php index 14705fbf960e5..ec21779a68ea8 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php @@ -18,6 +18,7 @@ class RoleHierarchyVoterTest extends RoleVoterTest { /** + * @group legacy * @dataProvider getVoteTests */ public function testVote($roles, $attributes, $expected) @@ -27,6 +28,16 @@ public function testVote($roles, $attributes, $expected) $this->assertSame($expected, $voter->vote($this->getToken($roles), null, $attributes)); } + /** + * @dataProvider getVoteTests + */ + public function testVoteUsingTokenThatReturnsRoleNames($roles, $attributes, $expected) + { + $voter = new RoleHierarchyVoter(new RoleHierarchy(['ROLE_FOO' => ['ROLE_FOOBAR']])); + + $this->assertSame($expected, $voter->vote($this->getTokenWithRoleNames($roles), null, $attributes)); + } + public function getVoteTests() { return array_merge(parent::getVoteTests(), [ @@ -35,6 +46,18 @@ public function getVoteTests() } /** + * @group legacy + * @dataProvider getLegacyVoteOnRoleObjectsTests + */ + public function testVoteOnRoleObjects($roles, $attributes, $expected) + { + $voter = new RoleHierarchyVoter(new RoleHierarchy(['ROLE_FOO' => ['ROLE_FOOBAR']])); + + $this->assertSame($expected, $voter->vote($this->getToken($roles), null, $attributes)); + } + + /** + * @group legacy * @dataProvider getVoteWithEmptyHierarchyTests */ public function testVoteWithEmptyHierarchy($roles, $attributes, $expected) @@ -44,6 +67,16 @@ public function testVoteWithEmptyHierarchy($roles, $attributes, $expected) $this->assertSame($expected, $voter->vote($this->getToken($roles), null, $attributes)); } + /** + * @dataProvider getVoteWithEmptyHierarchyTests + */ + public function testVoteWithEmptyHierarchyUsingTokenThatReturnsRoleNames($roles, $attributes, $expected) + { + $voter = new RoleHierarchyVoter(new RoleHierarchy([])); + + $this->assertSame($expected, $voter->vote($this->getTokenWithRoleNames($roles), null, $attributes)); + } + public function getVoteWithEmptyHierarchyTests() { return parent::getVoteTests(); diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleVoterTest.php index 5fb45e08b3925..6a1034417c837 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/RoleVoterTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; use Symfony\Component\Security\Core\Role\Role; @@ -19,6 +20,7 @@ class RoleVoterTest extends TestCase { /** + * @group legacy * @dataProvider getVoteTests */ public function testVote($roles, $attributes, $expected) @@ -28,6 +30,16 @@ public function testVote($roles, $attributes, $expected) $this->assertSame($expected, $voter->vote($this->getToken($roles), null, $attributes)); } + /** + * @dataProvider getVoteTests + */ + public function testVoteUsingTokenThatReturnsRoleNames($roles, $attributes, $expected) + { + $voter = new RoleVoter(); + + $this->assertSame($expected, $voter->vote($this->getTokenWithRoleNames($roles), null, $attributes)); + } + public function getVoteTests() { return [ @@ -41,6 +53,23 @@ public function getVoteTests() // Test mixed Types [[], [[]], VoterInterface::ACCESS_ABSTAIN], [[], [new \stdClass()], VoterInterface::ACCESS_ABSTAIN], + ]; + } + + /** + * @group legacy + * @dataProvider getLegacyVoteOnRoleObjectsTests + */ + public function testVoteOnRoleObjects($roles, $attributes, $expected) + { + $voter = new RoleVoter(); + + $this->assertSame($expected, $voter->vote($this->getToken($roles), null, $attributes)); + } + + public function getLegacyVoteOnRoleObjectsTests() + { + return [ [['ROLE_BAR'], [new Role('ROLE_BAR')], VoterInterface::ACCESS_GRANTED], [['ROLE_BAR'], [new Role('ROLE_FOO')], VoterInterface::ACCESS_DENIED], ]; @@ -58,4 +87,14 @@ protected function getToken(array $roles) return $token; } + + protected function getTokenWithRoleNames(array $roles) + { + $token = $this->getMockBuilder(AbstractToken::class)->getMock(); + $token->expects($this->once()) + ->method('getRoleNames') + ->will($this->returnValue($roles)); + + return $token; + } } diff --git a/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php b/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php index 4451f391adb30..c33fb953a1877 100644 --- a/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php @@ -17,6 +17,9 @@ class RoleHierarchyTest extends TestCase { + /** + * @group legacy + */ public function testGetReachableRoles() { $role = new RoleHierarchy([ @@ -30,4 +33,18 @@ public function testGetReachableRoles() $this->assertEquals([new Role('ROLE_FOO'), new Role('ROLE_ADMIN'), new Role('ROLE_USER')], $role->getReachableRoles([new Role('ROLE_FOO'), new Role('ROLE_ADMIN')])); $this->assertEquals([new Role('ROLE_SUPER_ADMIN'), new Role('ROLE_ADMIN'), new Role('ROLE_FOO'), new Role('ROLE_USER')], $role->getReachableRoles([new Role('ROLE_SUPER_ADMIN')])); } + + public function testGetReachableRoleNames() + { + $role = new RoleHierarchy(array( + 'ROLE_ADMIN' => array('ROLE_USER'), + 'ROLE_SUPER_ADMIN' => array('ROLE_ADMIN', 'ROLE_FOO'), + )); + + $this->assertEquals(array('ROLE_USER'), $role->getReachableRoleNames(array('ROLE_USER'))); + $this->assertEquals(array('ROLE_FOO'), $role->getReachableRoleNames(array('ROLE_FOO'))); + $this->assertEquals(array('ROLE_ADMIN', 'ROLE_USER'), $role->getReachableRoleNames(array('ROLE_ADMIN'))); + $this->assertEquals(array('ROLE_FOO', 'ROLE_ADMIN', 'ROLE_USER'), $role->getReachableRoleNames(array('ROLE_FOO', 'ROLE_ADMIN'))); + $this->assertEquals(array('ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_FOO', 'ROLE_USER'), $role->getReachableRoleNames(array('ROLE_SUPER_ADMIN'))); + } } diff --git a/src/Symfony/Component/Security/Core/Tests/Role/RoleTest.php b/src/Symfony/Component/Security/Core/Tests/Role/RoleTest.php index edf779413b636..e872a8c36b4ab 100644 --- a/src/Symfony/Component/Security/Core/Tests/Role/RoleTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Role/RoleTest.php @@ -14,6 +14,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Role\Role; +/** + * @group legacy + */ class RoleTest extends TestCase { public function testGetRole() diff --git a/src/Symfony/Component/Security/Core/Tests/Role/SwitchUserRoleTest.php b/src/Symfony/Component/Security/Core/Tests/Role/SwitchUserRoleTest.php index e40471733ce11..88f6a18abf7d1 100644 --- a/src/Symfony/Component/Security/Core/Tests/Role/SwitchUserRoleTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Role/SwitchUserRoleTest.php @@ -14,6 +14,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Role\SwitchUserRole; +/** + * @group legacy + */ class SwitchUserRoleTest extends TestCase { public function testGetSource() diff --git a/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php b/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php index 9e3646da45ccb..ac792b6a8713a 100644 --- a/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php +++ b/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Guard\Token; use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; -use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\User\UserInterface; /** @@ -28,9 +27,9 @@ class PostAuthenticationGuardToken extends AbstractToken implements GuardTokenIn private $providerKey; /** - * @param UserInterface $user The user! - * @param string $providerKey The provider (firewall) key - * @param (Role|string)[] $roles An array of roles + * @param UserInterface $user The user! + * @param string $providerKey The provider (firewall) key + * @param string[] $roles An array of roles * * @throws \InvalidArgumentException */ diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index c7a6dc96c88fd..e86dc5f2302ec 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; @@ -189,10 +190,14 @@ protected function refreshUser(TokenInterface $token) if (null !== $this->logger) { $context = ['provider' => \get_class($provider), 'username' => $refreshedUser->getUsername()]; - foreach ($token->getRoles() as $role) { - if ($role instanceof SwitchUserRole) { - $context['impersonator_username'] = $role->getSource()->getUsername(); - break; + if ($token instanceof SwitchUserToken) { + $context['impersonator_username'] = $token->getOriginalToken()->getUsername(); + } else { + foreach ($token->getRoles(false) as $role) { + if ($role instanceof SwitchUserRole) { + $context['impersonator_username'] = $role->getSource(false)->getUsername(); + break; + } } } diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 4aff3b45811fa..102ab30615209 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -17,8 +17,8 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; @@ -122,7 +122,7 @@ private function attemptSwitchUser(Request $request, $username) $token = $this->tokenStorage->getToken(); $originalToken = $this->getOriginalToken($token); - if (false !== $originalToken) { + if (null !== $originalToken) { if ($token->getUsername() === $username) { return $token; } @@ -146,9 +146,9 @@ private function attemptSwitchUser(Request $request, $username) $this->userChecker->checkPostAuth($user); $roles = $user->getRoles(); - $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->tokenStorage->getToken()); + $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->tokenStorage->getToken(), false); - $token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles); + $token = new SwitchUserToken($user, $user->getPassword(), $this->providerKey, $roles, $token); if (null !== $this->dispatcher) { $switchEvent = new SwitchUserEvent($request, $token->getUser(), $token); @@ -169,7 +169,7 @@ private function attemptSwitchUser(Request $request, $username) */ private function attemptExitUser(Request $request) { - if (false === $original = $this->getOriginalToken($this->tokenStorage->getToken())) { + if (null === ($currentToken = $this->tokenStorage->getToken()) || null === $original = $this->getOriginalToken($currentToken)) { throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); } @@ -183,19 +183,18 @@ private function attemptExitUser(Request $request) return $original; } - /** - * Gets the original Token from a switched one. - * - * @return TokenInterface|false The original TokenInterface instance, false if the current TokenInterface is not switched - */ - private function getOriginalToken(TokenInterface $token) + private function getOriginalToken(TokenInterface $token): ?TokenInterface { - foreach ($token->getRoles() as $role) { + if ($token instanceof SwitchUserToken) { + return $token->getOriginalToken(); + } + + foreach ($token->getRoles(false) as $role) { if ($role instanceof SwitchUserRole) { return $role->getSource(); } } - return false; + return null; } } diff --git a/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php b/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php index 25108e482d287..8bcb960aa66ed 100644 --- a/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php @@ -18,6 +18,7 @@ use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\Controller\UserValueResolver; @@ -35,7 +36,7 @@ public function testResolveNoToken() public function testResolveNoUser() { $mock = $this->getMockBuilder(UserInterface::class)->getMock(); - $token = $this->getMockBuilder(TokenInterface::class)->getMock(); + $token = new UsernamePasswordToken('username', 'password', 'provider'); $tokenStorage = new TokenStorage(); $tokenStorage->setToken($token); @@ -57,8 +58,7 @@ public function testResolveWrongType() public function testResolve() { $user = $this->getMockBuilder(UserInterface::class)->getMock(); - $token = $this->getMockBuilder(TokenInterface::class)->getMock(); - $token->expects($this->any())->method('getUser')->willReturn($user); + $token = new UsernamePasswordToken($user, 'password', 'provider'); $tokenStorage = new TokenStorage(); $tokenStorage->setToken($token); @@ -72,8 +72,7 @@ public function testResolve() public function testIntegration() { $user = $this->getMockBuilder(UserInterface::class)->getMock(); - $token = $this->getMockBuilder(TokenInterface::class)->getMock(); - $token->expects($this->any())->method('getUser')->willReturn($user); + $token = new UsernamePasswordToken($user, 'password', 'provider'); $tokenStorage = new TokenStorage(); $tokenStorage->setToken($token); @@ -83,7 +82,7 @@ public function testIntegration() public function testIntegrationNoUser() { - $token = $this->getMockBuilder(TokenInterface::class)->getMock(); + $token = new UsernamePasswordToken('username', 'password', 'provider'); $tokenStorage = new TokenStorage(); $tokenStorage->setToken($token); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index f26b72fc148e1..1468df66126bf 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Core\User\User; @@ -93,7 +94,7 @@ public function testExitUserThrowsAuthenticationExceptionIfOriginalTokenCannotBe public function testExitUserUpdatesToken() { $originalToken = new UsernamePasswordToken('username', '', 'key', []); - $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken)])); + $this->tokenStorage->setToken(new SwitchUserToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)], $originalToken)); $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); @@ -107,6 +108,22 @@ public function testExitUserUpdatesToken() $this->assertSame($originalToken, $this->tokenStorage->getToken()); } + /** + * @group legacy + */ + public function testExitUserBasedOnSwitchUserRoleUpdatesToken() + { + $originalToken = new UsernamePasswordToken('username', '', 'key', array()); + $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)), $originalToken)); + + $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); + + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener->handle($this->event); + + $this->assertSame($originalToken, $this->tokenStorage->getToken()); + } + public function testExitUserDispatchesEventWithRefreshedUser() { $originalUser = $this->getMockBuilder('Symfony\Component\Security\Core\User\UserInterface')->getMock(); @@ -118,7 +135,7 @@ public function testExitUserDispatchesEventWithRefreshedUser() ->with($originalUser) ->willReturn($refreshedUser); $originalToken = new UsernamePasswordToken($originalUser, '', 'key'); - $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken)])); + $this->tokenStorage->setToken(new SwitchUserToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)], $originalToken)); $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); @@ -142,7 +159,7 @@ public function testExitUserDoesNotDispatchEventWithStringUser() ->expects($this->never()) ->method('refreshUser'); $originalToken = new UsernamePasswordToken($originalUser, '', 'key'); - $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken)])); + $this->tokenStorage->setToken(new SwitchUserToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)], $originalToken)); $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); diff --git a/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php b/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php index 727dde0f81b30..12166602474ba 100644 --- a/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php @@ -95,7 +95,7 @@ public function testGuessFromCurrentFirewallContext() public function testGuessFromTokenWithoutProviderKeyFallbacksToCurrentFirewall() { - $this->tokenStorage->setToken($this->getMockBuilder(TokenInterface::class)->getMock()); + $this->tokenStorage->setToken(new UsernamePasswordToken('username', 'password', 'provider')); $this->generator->registerListener('secured_area', '/logout', null, null); $this->generator->setCurrentFirewall('secured_area'); diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index 7047eba06e9e8..7bfac0fdcf85f 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/security-core": "~3.4|~4.0", + "symfony/security-core": "~4.3", "symfony/event-dispatcher": "~3.4|~4.0", "symfony/http-foundation": "~3.4|~4.0", "symfony/http-kernel": "~3.4|~4.0", diff --git a/src/Symfony/Component/Workflow/EventListener/GuardListener.php b/src/Symfony/Component/Workflow/EventListener/GuardListener.php index 3a9b417f67978..60cd00ed2084f 100644 --- a/src/Symfony/Component/Workflow/EventListener/GuardListener.php +++ b/src/Symfony/Component/Workflow/EventListener/GuardListener.php @@ -14,6 +14,8 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Symfony\Component\Security\Core\Role\Role; +use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Workflow\Event\GuardEvent; @@ -80,19 +82,23 @@ private function getVariables(GuardEvent $event): array throw new InvalidTokenConfigurationException(sprintf('There are no tokens available for workflow %s.', $event->getWorkflowName())); } - if (null !== $this->roleHierarchy) { - $roles = $this->roleHierarchy->getReachableRoles($token->getRoles()); + if (method_exists($token, 'getRoleNames')) { + $roles = $token->getRoleNames(); } else { - $roles = $token->getRoles(); + $roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false)); + } + + if ($this->roleHierarchy instanceof RoleHierarchy) { + $roles = $this->roleHierarchy->getReachableRoleNames($roles); + } elseif (null !== $this->roleHierarchy) { + $roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false)); } $variables = [ 'token' => $token, 'user' => $token->getUser(), 'subject' => $event->getSubject(), - 'roles' => array_map(function ($role) { - return $role->getRole(); - }, $roles), + 'roles' => $roles, // needed for the is_granted expression function 'auth_checker' => $this->authorizationChecker, // needed for the is_* expression function diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php index 64df594b235b8..8e7a9cb779749 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php @@ -6,6 +6,7 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -35,8 +36,7 @@ protected function setUp() ], ]; $expressionLanguage = new ExpressionLanguage(); - $token = $this->getMockBuilder(TokenInterface::class)->getMock(); - $token->expects($this->any())->method('getRoles')->willReturn([new Role('ROLE_USER')]); + $token = new UsernamePasswordToken('username', 'credentials', 'provider', ['ROLE_USER']); $tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock(); $tokenStorage->expects($this->any())->method('getToken')->willReturn($token); $this->authenticationChecker = $this->getMockBuilder(AuthorizationCheckerInterface::class)->getMock(); From 057d1773784fca7bb4883ba60a75570d7ae35ede Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 23 Feb 2019 10:52:13 +0100 Subject: [PATCH 144/495] rename parent_form() to form_parent() We got some feedback on the blog post that form_parent() would be better for consistency with all the existing form_*() functions. I think that user has a point about that. --- src/Symfony/Bridge/Twig/CHANGELOG.md | 2 +- src/Symfony/Bridge/Twig/Extension/FormExtension.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index e81b36cdab791..35752fff125a3 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.3.0 ----- - * added the `parent_form()` function that allows to reliably retrieve the parent form in Twig templates + * added the `form_parent()` function that allows to reliably retrieve the parent form in Twig templates 4.2.0 ----- diff --git a/src/Symfony/Bridge/Twig/Extension/FormExtension.php b/src/Symfony/Bridge/Twig/Extension/FormExtension.php index 1b2e71c48d264..909e20d58d690 100644 --- a/src/Symfony/Bridge/Twig/Extension/FormExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/FormExtension.php @@ -54,7 +54,7 @@ public function getFunctions() new TwigFunction('form_start', null, ['node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => ['html']]), new TwigFunction('form_end', null, ['node_class' => 'Symfony\Bridge\Twig\Node\RenderBlockNode', 'is_safe' => ['html']]), new TwigFunction('csrf_token', ['Symfony\Component\Form\FormRenderer', 'renderCsrfToken']), - new TwigFunction('parent_form', 'Symfony\Bridge\Twig\Extension\twig_get_parent_form'), + new TwigFunction('form_parent', 'Symfony\Bridge\Twig\Extension\twig_get_form_parent'), ]; } @@ -120,7 +120,7 @@ function twig_is_root_form(FormView $formView) /** * @internal */ -function twig_get_parent_form(FormView $formView): ?FormView +function twig_get_form_parent(FormView $formView): ?FormView { return $formView->parent; } From 3895acd17598520682468ff1aa0994b7cfc1e316 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 23 Feb 2019 17:20:51 +0100 Subject: [PATCH 145/495] fix merge --- src/Symfony/Component/Routing/Generator/UrlGenerator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 1871437eae3f9..729d2b0f38d54 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -161,8 +161,8 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $important = $token[5] ?? false; if (!$optional || $important || !\array_key_exists($varName, $defaults) || (null !== $mergedParams[$varName] && (string) $mergedParams[$varName] !== (string) $defaults[$varName])) { - // check requirement - if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$varName])) { + // check requirement (while ignoring look-around patterns) + if (null !== $this->strictRequirements && !preg_match('#^'.preg_replace('/\(\?(?:=|<=|!|strictRequirements) { throw new InvalidParameterException(strtr($message, ['{parameter}' => $varName, '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$varName]])); } From 32c90ebc8e5061a4170045cca2d0c61214078b4f Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Wed, 7 Nov 2018 18:51:10 +0100 Subject: [PATCH 146/495] [Serializer] Normalize constraint violation parameters --- src/Symfony/Component/Serializer/CHANGELOG.md | 5 +++++ .../Normalizer/ConstraintViolationListNormalizer.php | 1 + .../Normalizer/ConstraintViolationListNormalizerTest.php | 6 +++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 99f32abff1a77..57e4ed1fd7c2a 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added the list of constraint violations' parameters in `ConstraintViolationListNormalizer` + 4.2.0 ----- diff --git a/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php index aa45a0fc1b33c..051ceaf3a385e 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php @@ -49,6 +49,7 @@ public function normalize($object, $format = null, array $context = []) $violationEntry = [ 'propertyPath' => $propertyPath, 'title' => $violation->getMessage(), + 'parameters' => $violation->getParameters(), ]; if (null !== $code = $violation->getCode()) { $violationEntry['type'] = sprintf('urn:uuid:%s', $code); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php index fa406ff227098..86008f361aef0 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php @@ -38,7 +38,7 @@ public function testSupportsNormalization() public function testNormalize() { $list = new ConstraintViolationList([ - new ConstraintViolation('a', 'b', [], 'c', 'd', 'e', null, 'f'), + new ConstraintViolation('a', 'b', ['value' => 'foo'], 'c', 'd', 'e', null, 'f'), new ConstraintViolation('1', '2', [], '3', '4', '5', null, '6'), ]); @@ -52,11 +52,15 @@ public function testNormalize() 'propertyPath' => 'd', 'title' => 'a', 'type' => 'urn:uuid:f', + 'parameters' => [ + 'value' => 'foo', + ], ], [ 'propertyPath' => '4', 'title' => '1', 'type' => 'urn:uuid:6', + 'parameters' => [], ], ], ]; From 17533da49ce7113ca5401fd1dc1705ddef15b58d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Fri, 22 Feb 2019 11:16:14 +0100 Subject: [PATCH 147/495] [Monolog] Disable DebugLogger in CLI --- src/Symfony/Bridge/Monolog/Logger.php | 15 +++++++++++++++ .../Compiler/AddDebugLogProcessorPass.php | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Symfony/Bridge/Monolog/Logger.php b/src/Symfony/Bridge/Monolog/Logger.php index de021426e03b9..ee4ffd243c644 100644 --- a/src/Symfony/Bridge/Monolog/Logger.php +++ b/src/Symfony/Bridge/Monolog/Logger.php @@ -75,6 +75,21 @@ public function reset() $this->clear(); } + public function removeDebugLogger() + { + foreach ($this->processors as $k => $processor) { + if ($processor instanceof DebugLoggerInterface) { + unset($this->processors[$k]); + } + } + + foreach ($this->handlers as $k => $handler) { + if ($handler instanceof DebugLoggerInterface) { + unset($this->handlers[$k]); + } + } + } + /** * Returns a DebugLoggerInterface instance if one is registered with this logger. * diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php index b4da145010403..dbe88b064bddd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php @@ -30,6 +30,14 @@ public function process(ContainerBuilder $container) } $definition = $container->getDefinition('monolog.logger_prototype'); + $definition->setConfigurator([__CLASS__, 'configureLogger']); $definition->addMethodCall('pushProcessor', [new Reference('debug.log_processor')]); } + + public static function configureLogger($logger) + { + if (method_exists($logger, 'removeDebugLogger') && \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { + $logger->removeDebugLogger(); + } + } } From 2d9bc18c1bfbfa7e2d3701c94b54e31c19d03ef9 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 23 Feb 2019 11:36:32 +0100 Subject: [PATCH 148/495] be able to specify the input format for times --- src/Symfony/Component/Form/CHANGELOG.md | 3 ++- .../Form/Extension/Core/Type/TimeType.php | 4 +++- .../Tests/Extension/Core/Type/TimeTypeTest.php | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index e8ca8090d9f6b..2328918d7d9d5 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -38,7 +38,8 @@ CHANGELOG } } ``` - * added new option `input_format` to `DateType` and `DateTimeType` to specify the date format when using the `string` input. + * added the `input_format` option to `DateType`, `DateTimeType`, and `TimeType` to specify the input format when setting + the `input` option to `string` 4.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php index 076e514ef5067..fb46274e31ab3 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -164,7 +164,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer()); } elseif ('string' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( - new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'H:i:s') + new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], $options['input_format']) )); } elseif ('timestamp' === $options['input']) { $builder->addModelTransformer(new ReversedTransformer( @@ -257,6 +257,7 @@ public function configureOptions(OptionsResolver $resolver) 'seconds' => range(0, 59), 'widget' => 'choice', 'input' => 'datetime', + 'input_format' => 'H:i:s', 'with_minutes' => true, 'with_seconds' => false, 'model_timezone' => null, @@ -298,6 +299,7 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setAllowedTypes('hours', 'array'); $resolver->setAllowedTypes('minutes', 'array'); $resolver->setAllowedTypes('seconds', 'array'); + $resolver->setAllowedTypes('input_format', 'string'); } /** diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php index 88c190be0d3fe..308207f2b32c5 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php @@ -80,6 +80,22 @@ public function testSubmitString() $this->assertEquals($input, $form->getViewData()); } + public function testSubmitStringWithCustomFormat() + { + $form = $this->factory->create(static::TESTED_TYPE, '11:33', [ + 'model_timezone' => 'UTC', + 'view_timezone' => 'UTC', + 'widget' => 'single_text', + 'input' => 'string', + 'input_format' => 'H:i', + ]); + + $form->submit('03:24'); + + $this->assertEquals('03:24', $form->getData()); + $this->assertEquals('03:24', $form->getViewData()); + } + public function testSubmitTimestamp() { $form = $this->factory->create(static::TESTED_TYPE, null, [ From 21f4e38800066944f43ce66080c04d229292dc3e Mon Sep 17 00:00:00 2001 From: David Maicher Date: Mon, 25 Feb 2019 19:34:05 +0100 Subject: [PATCH 149/495] [FrameworkBundle][Routing] allow boolean container parameters for routes --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Bundle/FrameworkBundle/Routing/Router.php | 4 ++++ .../Tests/Routing/RouterTest.php | 20 ++++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 4c91ff11bef31..4fc04f0671b62 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -17,6 +17,7 @@ CHANGELOG to the `session` section of the configuration * Added support for Translator paths, Twig paths in translation commands. * Added support for PHP files with translations in translation commands. + * Added support for boolean container parameters within routes. 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php index 6bea82e1ef13f..2f252846b7617 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php @@ -164,6 +164,10 @@ private function resolve($value) $resolved = ($this->paramFetcher)($match[1]); + if (\is_bool($resolved)) { + $resolved = (string) (int) $resolved; + } + if (\is_string($resolved) || is_numeric($resolved)) { $this->collectedParameters[$match[1]] = $resolved; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php index 329f1e7cbaf78..b2b848a7e2ff5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Routing/RouterTest.php @@ -27,7 +27,7 @@ class RouterTest extends TestCase */ public function testConstructThrowsOnNonSymfonyNorPsr11Container() { - new Router($this->getMockBuilder(ContainerInterface::class)->getMock(), 'foo'); + new Router($this->createMock(ContainerInterface::class), 'foo'); } public function testGenerateWithServiceParam() @@ -447,6 +447,24 @@ public function testGetRouteCollectionAddsContainerParametersResourceWithSfConta $this->assertEquals([new ContainerParametersResource(['locale' => 'en'])], $routeCollection->getResources()); } + public function testBooleanContainerParametersWithinRouteCondition() + { + $routes = new RouteCollection(); + + $route = new Route('foo'); + $route->setCondition('%parameter.true% or %parameter.false%'); + + $routes->add('foo', $route); + + $sc = $this->getPsr11ServiceContainer($routes); + $parameters = $this->getParameterBag(['parameter.true' => true, 'parameter.false' => false]); + + $router = new Router($sc, 'foo', [], null, $parameters); + $route = $router->getRouteCollection()->get('foo'); + + $this->assertSame('1 or 0', $route->getCondition()); + } + public function getNonStringValues() { return [[null], [false], [true], [new \stdClass()], [['foo', 'bar']], [[[]]]]; From ff9e4947763b2b78378425123060aef65b5fd63f Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 25 Feb 2019 16:12:18 -0500 Subject: [PATCH 150/495] Fix row update on finish ajax request --- .../Resources/views/Profiler/base_js.html.twig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index 2b33588bc15f5..bc42b1a5feb63 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -212,11 +212,11 @@ pendingRequests--; var row = request.DOMNode; /* Unpack the children from the row */ - var profilerCell = row.children[0]; - var methodCell = row.children[1]; - var statusCodeCell = row.children[3]; + var profilerCell = row.children[1]; + var methodCell = row.children[2]; + var statusCodeCell = row.children[4]; var statusCodeElem = statusCodeCell.children[0]; - var durationCell = row.children[5]; + var durationCell = row.children[6]; if (request.error) { row.className = 'sf-ajax-request sf-ajax-request-error'; From c3da27a83945730fabb3212ef24a6aa33059568c Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 26 Feb 2019 19:18:56 +0100 Subject: [PATCH 151/495] add deprecated router options to upgrade files --- UPGRADE-4.3.md | 6 ++++++ UPGRADE-5.0.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index a0d5e52b17632..79b38e2e7d5fe 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -50,6 +50,12 @@ HttpFoundation * The `FileinfoMimeTypeGuesser` class has been deprecated, use `Symfony\Component\Mime\FileinfoMimeTypeGuesser` instead. +Routing +------- + + * The `generator_base_class`, `generator_cache_class`, `matcher_base_class`, and `matcher_cache_class` router + options have been deprecated. + Security -------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index a959f2d06a179..1c729e2afcbd8 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -223,6 +223,12 @@ Process $process = Process::fromShellCommandline('ls -l'); ``` +Routing +------- + + * The `generator_base_class`, `generator_cache_class`, `matcher_base_class`, and `matcher_cache_class` router + options have been removed. + Security -------- From ee787d17b4fcba784f80fe832408ce21ec6eda29 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 17 Jan 2019 18:07:31 +0100 Subject: [PATCH 152/495] [Mime] added classes for generating MIME messages --- composer.json | 1 + src/Symfony/Bridge/Twig/Mime/Renderer.php | 100 +++ .../Bridge/Twig/Mime/TemplatedEmail.php | 87 +++ .../Twig/Mime/WrappedTemplatedEmail.php | 199 ++++++ .../Bridge/Twig/Tests/Mime/RendererTest.php | 174 +++++ .../Twig/Tests/Mime/TemplatedEmailTest.php | 25 + src/Symfony/Bridge/Twig/composer.json | 1 + src/Symfony/Component/Mime/Address.php | 98 +++ .../Component/Mime/CharacterStream.php | 224 +++++++ .../AddMimeTypeGuesserPass.php | 2 + src/Symfony/Component/Mime/Email.php | 604 ++++++++++++++++++ .../Mime/Encoder/AddressEncoderInterface.php | 30 + .../Mime/Encoder/Base64ContentEncoder.php | 50 ++ .../Component/Mime/Encoder/Base64Encoder.php | 43 ++ .../Mime/Encoder/Base64MimeHeaderEncoder.php | 45 ++ .../Mime/Encoder/ContentEncoderInterface.php | 32 + .../Mime/Encoder/EncoderInterface.php | 28 + .../Mime/Encoder/IdnAddressEncoder.php | 56 ++ .../Encoder/MimeHeaderEncoderInterface.php | 25 + .../Mime/Encoder/QpContentEncoder.php | 66 ++ .../Component/Mime/Encoder/QpEncoder.php | 199 ++++++ .../Mime/Encoder/QpMimeHeaderEncoder.php | 42 ++ .../Component/Mime/Encoder/Rfc2231Encoder.php | 52 ++ .../Exception/AddressEncoderException.php | 21 + .../Mime/Exception/ExceptionInterface.php | 21 + .../Exception/InvalidArgumentException.php | 21 + .../Mime/Exception/LogicException.php | 21 + .../Mime/Exception/RfcComplianceException.php | 21 + .../Mime/Exception/RuntimeException.php | 21 + .../Mime/FileBinaryMimeTypeGuesser.php | 9 +- .../Mime/FileinfoMimeTypeGuesser.php | 9 +- .../Component/Mime/Header/AbstractHeader.php | 281 ++++++++ .../Component/Mime/Header/DateHeader.php | 71 ++ .../Component/Mime/Header/HeaderInterface.php | 67 ++ src/Symfony/Component/Mime/Header/Headers.php | 275 ++++++++ .../Mime/Header/IdentificationHeader.php | 115 ++++ .../Component/Mime/Header/MailboxHeader.php | 93 +++ .../Mime/Header/MailboxListHeader.php | 139 ++++ .../Mime/Header/ParameterizedHeader.php | 176 +++++ .../Component/Mime/Header/PathHeader.php | 67 ++ .../Mime/Header/UnstructuredHeader.php | 73 +++ src/Symfony/Component/Mime/Message.php | 134 ++++ .../Component/Mime/MessageConverter.php | 132 ++++ .../Mime/MimeTypeGuesserInterface.php | 2 + src/Symfony/Component/Mime/MimeTypes.php | 6 +- .../Component/Mime/MimeTypesInterface.php | 2 + src/Symfony/Component/Mime/NamedAddress.php | 44 ++ .../Mime/Part/AbstractMultipartPart.php | 100 +++ .../Component/Mime/Part/AbstractPart.php | 64 ++ src/Symfony/Component/Mime/Part/DataPart.php | 152 +++++ .../Component/Mime/Part/MessagePart.php | 64 ++ .../Mime/Part/Multipart/AlternativePart.php | 27 + .../Mime/Part/Multipart/DigestPart.php | 33 + .../Mime/Part/Multipart/FormDataPart.php | 92 +++ .../Mime/Part/Multipart/MixedPart.php | 27 + .../Mime/Part/Multipart/RelatedPart.php | 57 ++ src/Symfony/Component/Mime/Part/TextPart.php | 191 ++++++ src/Symfony/Component/Mime/README.md | 5 +- src/Symfony/Component/Mime/RawMessage.php | 55 ++ .../Tests/AbstractMimeTypeGuesserTest.php | 14 +- .../Component/Mime/Tests/AddressTest.php | 61 ++ .../Mime/Tests/CharacterStreamTest.php | 87 +++ .../Component/Mime/Tests/EmailTest.php | 385 +++++++++++ .../Mime/Tests/Encoder/Base64EncoderTest.php | 158 +++++ .../Encoder/Base64MimeHeaderEncoderTest.php | 23 + .../Mime/Tests/Encoder/QpEncoderTest.php | 213 ++++++ .../Tests/Encoder/QpMimeHeaderEncoderTest.php | 139 ++++ .../Mime/Tests/Encoder/Rfc2231EncoderTest.php | 129 ++++ .../{ => mimetypes}/.unknownextension | 0 .../Fixtures/{ => mimetypes}/directory/.empty | 0 .../{ => mimetypes}/other-file.example | 0 .../Mime/Tests/Fixtures/{ => mimetypes}/test | Bin .../Tests/Fixtures/{ => mimetypes}/test.gif | Bin .../samples/charsets/iso-2022-jp/one.txt | 11 + .../samples/charsets/iso-8859-1/one.txt | 19 + .../Fixtures/samples/charsets/utf-8/one.txt | 22 + .../Fixtures/samples/charsets/utf-8/three.txt | 45 ++ .../Fixtures/samples/charsets/utf-8/two.txt | 3 + .../Mime/Tests/Header/DateHeaderTest.php | 80 +++ .../Mime/Tests/Header/HeadersTest.php | 234 +++++++ .../Tests/Header/IdentificationHeaderTest.php | 179 ++++++ .../Mime/Tests/Header/MailboxHeaderTest.php | 79 +++ .../Tests/Header/MailboxListHeaderTest.php | 133 ++++ .../Tests/Header/ParameterizedHeaderTest.php | 274 ++++++++ .../Mime/Tests/Header/PathHeaderTest.php | 81 +++ .../Tests/Header/UnstructuredHeaderTest.php | 247 +++++++ .../Mime/Tests/MessageConverterTest.php | 81 +++ .../Component/Mime/Tests/MessageTest.php | 141 ++++ .../Component/Mime/Tests/MimeTypesTest.php | 5 +- .../Component/Mime/Tests/NamedAddressTest.php | 27 + .../Mime/Tests/Part/DataPartTest.php | 149 +++++ .../Mime/Tests/Part/MessagePartTest.php | 42 ++ .../Part/Multipart/AlternativePartTest.php | 25 + .../Tests/Part/Multipart/DigestPartTest.php | 28 + .../Tests/Part/Multipart/FormDataPartTest.php | 44 ++ .../Tests/Part/Multipart/MixedPartTest.php | 25 + .../Tests/Part/Multipart/RelatedPartTest.php | 30 + .../Mime/Tests/Part/TextPartTest.php | 92 +++ .../Component/Mime/Tests/RawMessageTest.php | 35 + src/Symfony/Component/Mime/composer.json | 7 +- 100 files changed, 8201 insertions(+), 17 deletions(-) create mode 100644 src/Symfony/Bridge/Twig/Mime/Renderer.php create mode 100644 src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php create mode 100644 src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php create mode 100644 src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php create mode 100644 src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php create mode 100644 src/Symfony/Component/Mime/Address.php create mode 100644 src/Symfony/Component/Mime/CharacterStream.php create mode 100644 src/Symfony/Component/Mime/Email.php create mode 100644 src/Symfony/Component/Mime/Encoder/AddressEncoderInterface.php create mode 100644 src/Symfony/Component/Mime/Encoder/Base64ContentEncoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/Base64Encoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/Base64MimeHeaderEncoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/ContentEncoderInterface.php create mode 100644 src/Symfony/Component/Mime/Encoder/EncoderInterface.php create mode 100644 src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/MimeHeaderEncoderInterface.php create mode 100644 src/Symfony/Component/Mime/Encoder/QpContentEncoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/QpEncoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/QpMimeHeaderEncoder.php create mode 100644 src/Symfony/Component/Mime/Encoder/Rfc2231Encoder.php create mode 100644 src/Symfony/Component/Mime/Exception/AddressEncoderException.php create mode 100644 src/Symfony/Component/Mime/Exception/ExceptionInterface.php create mode 100644 src/Symfony/Component/Mime/Exception/InvalidArgumentException.php create mode 100644 src/Symfony/Component/Mime/Exception/LogicException.php create mode 100644 src/Symfony/Component/Mime/Exception/RfcComplianceException.php create mode 100644 src/Symfony/Component/Mime/Exception/RuntimeException.php create mode 100644 src/Symfony/Component/Mime/Header/AbstractHeader.php create mode 100644 src/Symfony/Component/Mime/Header/DateHeader.php create mode 100644 src/Symfony/Component/Mime/Header/HeaderInterface.php create mode 100644 src/Symfony/Component/Mime/Header/Headers.php create mode 100644 src/Symfony/Component/Mime/Header/IdentificationHeader.php create mode 100644 src/Symfony/Component/Mime/Header/MailboxHeader.php create mode 100644 src/Symfony/Component/Mime/Header/MailboxListHeader.php create mode 100644 src/Symfony/Component/Mime/Header/ParameterizedHeader.php create mode 100644 src/Symfony/Component/Mime/Header/PathHeader.php create mode 100644 src/Symfony/Component/Mime/Header/UnstructuredHeader.php create mode 100644 src/Symfony/Component/Mime/Message.php create mode 100644 src/Symfony/Component/Mime/MessageConverter.php create mode 100644 src/Symfony/Component/Mime/NamedAddress.php create mode 100644 src/Symfony/Component/Mime/Part/AbstractMultipartPart.php create mode 100644 src/Symfony/Component/Mime/Part/AbstractPart.php create mode 100644 src/Symfony/Component/Mime/Part/DataPart.php create mode 100644 src/Symfony/Component/Mime/Part/MessagePart.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/AlternativePart.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/DigestPart.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/MixedPart.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/RelatedPart.php create mode 100644 src/Symfony/Component/Mime/Part/TextPart.php create mode 100644 src/Symfony/Component/Mime/RawMessage.php create mode 100644 src/Symfony/Component/Mime/Tests/AddressTest.php create mode 100644 src/Symfony/Component/Mime/Tests/CharacterStreamTest.php create mode 100644 src/Symfony/Component/Mime/Tests/EmailTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Encoder/Base64EncoderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Encoder/QpEncoderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Encoder/QpMimeHeaderEncoderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Encoder/Rfc2231EncoderTest.php rename src/Symfony/Component/Mime/Tests/Fixtures/{ => mimetypes}/.unknownextension (100%) rename src/Symfony/Component/Mime/Tests/Fixtures/{ => mimetypes}/directory/.empty (100%) rename src/Symfony/Component/Mime/Tests/Fixtures/{ => mimetypes}/other-file.example (100%) rename src/Symfony/Component/Mime/Tests/Fixtures/{ => mimetypes}/test (100%) rename src/Symfony/Component/Mime/Tests/Fixtures/{ => mimetypes}/test.gif (100%) create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/one.txt create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/three.txt create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/two.txt create mode 100644 src/Symfony/Component/Mime/Tests/Header/DateHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/HeadersTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/MailboxHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/MailboxListHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Header/UnstructuredHeaderTest.php create mode 100644 src/Symfony/Component/Mime/Tests/MessageConverterTest.php create mode 100644 src/Symfony/Component/Mime/Tests/MessageTest.php create mode 100644 src/Symfony/Component/Mime/Tests/NamedAddressTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/DataPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/MessagePartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/AlternativePartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/DigestPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/MixedPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/RelatedPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/TextPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/RawMessageTest.php diff --git a/composer.json b/composer.json index 579847c2e81e0..e0544b61fbb6f 100644 --- a/composer.json +++ b/composer.json @@ -31,6 +31,7 @@ "symfony/contracts": "^1.0.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "~1.0", + "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php72": "~1.5", "symfony/polyfill-php73": "^1.8" diff --git a/src/Symfony/Bridge/Twig/Mime/Renderer.php b/src/Symfony/Bridge/Twig/Mime/Renderer.php new file mode 100644 index 0000000000000..13bf3d1bdd980 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Mime/Renderer.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Mime; + +use League\HTMLToMarkdown\HtmlConverter; +use Twig\Environment; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class Renderer +{ + private $twig; + private $context; + private $converter; + + public function __construct(Environment $twig, array $context = []) + { + $this->twig = $twig; + $this->context = $context; + if (class_exists(HtmlConverter::class)) { + $this->converter = new HtmlConverter([ + 'hard_break' => true, + 'strip_tags' => true, + 'remove_nodes' => 'head style', + ]); + } + } + + public function render(TemplatedEmail $email): TemplatedEmail + { + $email = clone $email; + + $vars = array_merge($this->context, $email->getContext(), [ + 'email' => new WrappedTemplatedEmail($this->twig, $email), + ]); + + if ($template = $email->getTemplate()) { + $this->renderFull($email, $template, $vars); + } + + if ($template = $email->getTextTemplate()) { + $email->text($this->twig->render($template, $vars)); + } + + if ($template = $email->getHtmlTemplate()) { + $email->html($this->twig->render($template, $vars)); + } + + // if text body is empty, compute one from the HTML body + if (!$email->getTextBody() && null !== $html = $email->getHtmlBody()) { + $email->text($this->convertHtmlToText(\is_resource($html) ? stream_get_contents($html) : $html)); + } + + return $email; + } + + private function renderFull(TemplatedEmail $email, string $template, array $vars): void + { + $template = $this->twig->load($template); + + if ($template->hasBlock('subject', $vars)) { + $email->subject($template->renderBlock('subject', $vars)); + } + + if ($template->hasBlock('text', $vars)) { + $email->text($template->renderBlock('text', $vars)); + } + + if ($template->hasBlock('html', $vars)) { + $email->html($template->renderBlock('html', $vars)); + } + + if ($template->hasBlock('config', $vars)) { + // we discard the output as we're only interested + // in the side effect of calling email methods + $template->renderBlock('config', $vars); + } + } + + private function convertHtmlToText(string $html): string + { + if (null !== $this->converter) { + return $this->converter->convert($html); + } + + return strip_tags($html); + } +} diff --git a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php new file mode 100644 index 0000000000000..14fb14c0a211a --- /dev/null +++ b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Mime; + +use Symfony\Component\Mime\Email; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class TemplatedEmail extends Email +{ + private $template; + private $htmlTemplate; + private $textTemplate; + private $context = []; + + /** + * @return $this + */ + public function template(?string $template) + { + $this->template = $template; + + return $this; + } + + /** + * @return $this + */ + public function textTemplate(?string $template) + { + $this->textTemplate = $template; + + return $this; + } + + /** + * @return $this + */ + public function htmlTemplate(?string $template) + { + $this->htmlTemplate = $template; + + return $this; + } + + public function getTemplate(): ?string + { + return $this->template; + } + + public function getTextTemplate(): ?string + { + return $this->textTemplate; + } + + public function getHtmlTemplate(): ?string + { + return $this->htmlTemplate; + } + + /** + * @return $this + */ + public function context(array $context) + { + $this->context = $context; + + return $this; + } + + public function getContext(): array + { + return $this->context; + } +} diff --git a/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php new file mode 100644 index 0000000000000..7c0b585a4eb63 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php @@ -0,0 +1,199 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Mime; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\NamedAddress; +use Twig\Environment; + +/** + * @internal + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class WrappedTemplatedEmail +{ + private $twig; + private $message; + + public function __construct(Environment $twig, TemplatedEmail $message) + { + $this->twig = $twig; + $this->message = $message; + } + + public function toName(): string + { + $to = $this->message->getTo()[0]; + + return $to instanceof NamedAddress ? $to->getName() : ''; + } + + public function image(string $image, string $contentType = null): string + { + $file = $this->twig->getLoader()->getSourceContext($image); + if ($path = $file->getPath()) { + $this->message->embedFromPath($path, $image, $contentType); + } else { + $this->message->embed($file->getCode(), $image, $contentType); + } + + return 'cid:'.$image; + } + + public function attach(string $file, string $name = null, string $contentType = null): void + { + $file = $this->twig->getLoader()->getSourceContext($file); + if ($path = $file->getPath()) { + $this->message->attachFromPath($path, $name, $contentType); + } else { + $this->message->attach($file->getCode(), $name, $contentType); + } + } + + /** + * @return $this + */ + public function setSubject(string $subject) + { + $this->message->subject($subject); + + return $this; + } + + public function getSubject(): ?string + { + return $this->message->getSubject(); + } + + /** + * @return $this + */ + public function setReturnPath(string $address) + { + $this->message->returnPath($address); + + return $this; + } + + public function getReturnPath(): string + { + return $this->message->getReturnPath(); + } + + /** + * @return $this + */ + public function addFrom(string $address, string $name = null) + { + $this->message->addFrom($name ? new NamedAddress($address, $name) : new Address($address)); + + return $this; + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getFrom(): array + { + return $this->message->getFrom(); + } + + /** + * @return $this + */ + public function addReplyTo(string $address) + { + $this->message->addReplyTo($address); + + return $this; + } + + /** + * @return Address[] + */ + public function getReplyTo(): array + { + return $this->message->getReplyTo(); + } + + /** + * @return $this + */ + public function addTo(string $address, string $name = null) + { + $this->message->addTo($name ? new NamedAddress($address, $name) : new Address($address)); + + return $this; + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getTo(): array + { + return $this->message->getTo(); + } + + /** + * @return $this + */ + public function addCc(string $address, string $name = null) + { + $this->message->addCc($name ? new NamedAddress($address, $name) : new Address($address)); + + return $this; + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getCc(): array + { + return $this->message->getCc(); + } + + /** + * @return $this + */ + public function addBcc(string $address, string $name = null) + { + $this->message->addBcc($name ? new NamedAddress($address, $name) : new Address($address)); + + return $this; + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getBcc(): array + { + return $this->message->getBcc(); + } + + /** + * @return $this + */ + public function setPriority(int $priority) + { + $this->message->setPriority($priority); + + return $this; + } + + public function getPriority(): int + { + return $this->message->getPriority(); + } +} diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php new file mode 100644 index 0000000000000..73ba80959a3a9 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Twig\Tests\Mime; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Twig\Mime\Renderer; +use Symfony\Bridge\Twig\Mime\TemplatedEmail; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; +use Twig\Environment; +use Twig\Loader\ArrayLoader; + +class RendererTest extends TestCase +{ + public function testRenderTextOnly(): void + { + $email = $this->prepareEmail(null, 'Text', null); + $this->assertEquals('Text', $email->getBody()->bodyToString()); + } + + public function testRenderHtmlOnly(): void + { + $email = $this->prepareEmail(null, null, 'HTML'); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('HTML', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderHtmlOnlyWithTextSet(): void + { + $email = $this->prepareEmail(null, null, 'HTML'); + $email->text('Text'); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderTextAndHtml(): void + { + $email = $this->prepareEmail(null, 'Text', 'HTML'); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderFullOnly(): void + { + $email = $this->prepareEmail(<<HTML{% endblock %} +EOF + , null, null); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('Subject', $email->getSubject()); + $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderFullOnlyWithTextOnly(): void + { + $email = $this->prepareEmail(<<getBody(); + $this->assertInstanceOf(TextPart::class, $body); + $this->assertEquals('', $email->getSubject()); + $this->assertEquals('Text', $body->bodyToString()); + } + + public function testRenderFullOnlyWithHtmlOnly(): void + { + $email = $this->prepareEmail(<<HTML{% endblock %} +EOF + , null, null); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('', $email->getSubject()); + $this->assertEquals('HTML', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderFullAndText(): void + { + $email = $this->prepareEmail(<<HTML{% endblock %} +EOF + , 'Text', null); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderFullAndHtml(): void + { + $email = $this->prepareEmail(<<HTML{% endblock %} +EOF + , null, 'HTML'); + $body = $email->getBody(); + $this->assertInstanceOf(AlternativePart::class, $body); + $this->assertEquals('Text full', $body->getParts()[0]->bodyToString()); + $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + } + + public function testRenderHtmlWithEmbeddedImages(): void + { + $email = $this->prepareEmail(null, null, ''); + $body = $email->getBody(); + $this->assertInstanceOf(RelatedPart::class, $body); + $this->assertInstanceOf(AlternativePart::class, $body->getParts()[0]); + $this->assertStringMatchesFormat('', $body->getParts()[0]->getParts()[1]->bodyToString()); + $this->assertEquals('Some image data', base64_decode($body->getParts()[1]->bodyToString())); + } + + public function testRenderFullWithAttachments(): void + { + $email = $this->prepareEmail(<<getBody(); + $this->assertInstanceOf(MixedPart::class, $body); + $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); + $this->assertEquals('Some text document...', base64_decode($body->getParts()[1]->bodyToString())); + } + + private function prepareEmail(?string $full, ?string $text, ?string $html): TemplatedEmail + { + $twig = new Environment(new ArrayLoader([ + 'full' => $full, + 'text' => $text, + 'html' => $html, + 'document.txt' => 'Some text document...', + 'image.jpg' => 'Some image data', + ])); + $renderer = new Renderer($twig); + $email = (new TemplatedEmail())->to('fabien@symfony.com')->from('helene@symfony.com'); + if (null !== $full) { + $email->template('full'); + } + if (null !== $text) { + $email->textTemplate('text'); + } + if (null !== $html) { + $email->htmlTemplate('html'); + } + + return $renderer->render($email); + } +} diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php new file mode 100644 index 0000000000000..8dab46a4c31f2 --- /dev/null +++ b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php @@ -0,0 +1,25 @@ +context($context = ['product' => 'Symfony']); + $this->assertEquals($context, $email->getContext()); + + $email->template($template = 'full'); + $this->assertEquals($template, $email->getTemplate()); + + $email->textTemplate($template = 'text'); + $this->assertEquals($template, $email->getTextTemplate()); + + $email->htmlTemplate($template = 'html'); + $this->assertEquals($template, $email->getHtmlTemplate()); + } +} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index f1509696a8910..0efd3f24e4e5f 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -27,6 +27,7 @@ "symfony/form": "^4.3", "symfony/http-foundation": "~3.4|~4.0", "symfony/http-kernel": "~3.4|~4.0", + "symfony/mime": "~4.3", "symfony/polyfill-intl-icu": "~1.0", "symfony/routing": "~3.4|~4.0", "symfony/templating": "~3.4|~4.0", diff --git a/src/Symfony/Component/Mime/Address.php b/src/Symfony/Component/Mime/Address.php new file mode 100644 index 0000000000000..f244f053e20cd --- /dev/null +++ b/src/Symfony/Component/Mime/Address.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Egulias\EmailValidator\EmailValidator; +use Egulias\EmailValidator\Validation\RFCValidation; +use Symfony\Component\Mime\Encoder\IdnAddressEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class Address +{ + private static $validator; + private static $encoder; + + private $address; + + public function __construct(string $address) + { + if (!class_exists(EmailValidator::class)) { + throw new LogicException(sprintf('The "%s" class cannot be used as it needs "%s"; try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); + } + + if (null === self::$validator) { + self::$validator = new EmailValidator(); + } + + if (null === self::$encoder) { + self::$encoder = new IdnAddressEncoder(); + } + + if (!self::$validator->isValid($address, new RFCValidation())) { + throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); + } + + $this->address = $address; + } + + public function getAddress(): string + { + return $this->address; + } + + public function getEncodedAddress(): string + { + return self::$encoder->encodeString($this->address); + } + + public function toString(): string + { + return $this->getEncodedAddress(); + } + + /** + * @param Address|string $address + */ + public static function create($address): self + { + if ($address instanceof self) { + return $address; + } + if (\is_string($address)) { + return new self($address); + } + + throw new InvalidArgumentException(sprintf('An address can be an instance of Address or a string ("%s") given).', \is_object($address) ? \get_class($address) : \gettype($address))); + } + + /** + * @param (Address|string)[] $addresses + * + * @return Address[] + */ + public static function createArray(array $addresses): array + { + $addrs = []; + foreach ($addresses as $address) { + $addrs[] = self::create($address); + } + + return $addrs; + } +} diff --git a/src/Symfony/Component/Mime/CharacterStream.php b/src/Symfony/Component/Mime/CharacterStream.php new file mode 100644 index 0000000000000..9b80b2efa481a --- /dev/null +++ b/src/Symfony/Component/Mime/CharacterStream.php @@ -0,0 +1,224 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + * @author Xavier De Cock + * + * @internal + * + * @experimental in 4.3 + */ +final class CharacterStream +{ + /** Pre-computed for optimization */ + private const UTF8_LENGTH_MAP = [ + "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, + "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, + "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, + "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, + "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, + "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, + "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, + "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, + "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, + "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, + "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, + "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, + "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, + "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, + "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, + "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, + "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, + "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, + "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, + "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, + "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, + "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, + "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, + "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, + "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, + "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, + "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, + "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, + "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, + "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, + "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, + "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, + ]; + + private $data = ''; + private $dataSize = 0; + private $map = []; + private $charCount = 0; + private $currentPos = 0; + private $fixedWidth = 0; + + /** + * @param resource|string $input + */ + public function __construct($input, ?string $charset = 'utf-8') + { + $charset = strtolower(trim($charset)) ?: 'utf-8'; + if ('utf-8' === $charset || 'utf8' === $charset) { + $this->fixedWidth = 0; + $this->map = ['p' => [], 'i' => []]; + } else { + switch ($charset) { + // 16 bits + case 'ucs2': + case 'ucs-2': + case 'utf16': + case 'utf-16': + $this->fixedWidth = 2; + break; + + // 32 bits + case 'ucs4': + case 'ucs-4': + case 'utf32': + case 'utf-32': + $this->fixedWidth = 4; + break; + + // 7-8 bit charsets: (us-)?ascii, (iso|iec)-?8859-?[0-9]+, windows-?125[0-9], cp-?[0-9]+, ansi, macintosh, + // koi-?7, koi-?8-?.+, mik, (cork|t1), v?iscii + // and fallback + default: + $this->fixedWidth = 1; + } + } + if (\is_resource($input)) { + $blocks = 512; + if (stream_get_meta_data($input)['seekable'] ?? false) { + rewind($input); + } + while (false !== $read = fread($input, $blocks)) { + $this->write($read); + } + } else { + $this->write($input); + } + } + + public function read(int $length): ?string + { + if ($this->currentPos >= $this->charCount) { + return null; + } + $ret = null; + $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; + if ($this->fixedWidth > 0) { + $len = $length * $this->fixedWidth; + $ret = substr($this->data, $this->currentPos * $this->fixedWidth, $len); + $this->currentPos += $length; + } else { + $end = $this->currentPos + $length; + $end = $end > $this->charCount ? $this->charCount : $end; + $ret = ''; + $start = 0; + if ($this->currentPos > 0) { + $start = $this->map['p'][$this->currentPos - 1]; + } + $to = $start; + for (; $this->currentPos < $end; ++$this->currentPos) { + if (isset($this->map['i'][$this->currentPos])) { + $ret .= substr($this->data, $start, $to - $start).'?'; + $start = $this->map['p'][$this->currentPos]; + } else { + $to = $this->map['p'][$this->currentPos]; + } + } + $ret .= substr($this->data, $start, $to - $start); + } + + return $ret; + } + + public function readBytes(int $length): ?array + { + if (null !== $read = $this->read($length)) { + return array_map('ord', str_split($read, 1)); + } + + return null; + } + + public function setPointer(int $charOffset): void + { + if ($this->charCount < $charOffset) { + $charOffset = $this->charCount; + } + $this->currentPos = $charOffset; + } + + public function write(string $chars): void + { + $ignored = ''; + $this->data .= $chars; + if ($this->fixedWidth > 0) { + $strlen = \strlen($chars); + $ignoredL = $strlen % $this->fixedWidth; + $ignored = $ignoredL ? substr($chars, -$ignoredL) : ''; + $this->charCount += ($strlen - $ignoredL) / $this->fixedWidth; + } else { + $this->charCount += $this->getUtf8CharPositions($chars, $this->dataSize, $ignored); + } + $this->dataSize = \strlen($this->data) - \strlen($ignored); + } + + private function getUtf8CharPositions(string $string, int $startOffset, &$ignoredChars): int + { + $strlen = \strlen($string); + $charPos = \count($this->map['p']); + $foundChars = 0; + $invalid = false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::UTF8_LENGTH_MAP[$char]; + if (0 == $size) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } + + if ($invalid) { + /* We mark the chars as invalid and start a new char */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i; + $this->map['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + + return $foundChars; + } +} diff --git a/src/Symfony/Component/Mime/DependencyInjection/AddMimeTypeGuesserPass.php b/src/Symfony/Component/Mime/DependencyInjection/AddMimeTypeGuesserPass.php index e24beb0da14ec..78450b91bd56c 100644 --- a/src/Symfony/Component/Mime/DependencyInjection/AddMimeTypeGuesserPass.php +++ b/src/Symfony/Component/Mime/DependencyInjection/AddMimeTypeGuesserPass.php @@ -19,6 +19,8 @@ * Registers custom mime types guessers. * * @author Fabien Potencier + * + * @experimental in 4.3 */ class AddMimeTypeGuesserPass implements CompilerPassInterface { diff --git a/src/Symfony/Component/Mime/Email.php b/src/Symfony/Component/Mime/Email.php new file mode 100644 index 0000000000000..ee5d478bf4612 --- /dev/null +++ b/src/Symfony/Component/Mime/Email.php @@ -0,0 +1,604 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class Email extends Message +{ + const PRIORITY_HIGHEST = 1; + const PRIORITY_HIGH = 2; + const PRIORITY_NORMAL = 3; + const PRIORITY_LOW = 4; + const PRIORITY_LOWEST = 5; + + private const PRIORITY_MAP = [ + self::PRIORITY_HIGHEST => 'Highest', + self::PRIORITY_HIGH => 'High', + self::PRIORITY_NORMAL => 'Normal', + self::PRIORITY_LOW => 'Low', + self::PRIORITY_LOWEST => 'Lowest', + ]; + + private $text; + private $textCharset; + private $html; + private $htmlCharset; + private $attachments = []; + + /** + * @return $this + */ + public function subject(string $subject) + { + return $this->setHeaderBody('Text', 'Subject', $subject); + } + + public function getSubject(): ?string + { + return $this->getHeaders()->getHeaderBody('Subject'); + } + + /** + * @return $this + */ + public function date(\DateTimeInterface $dateTime) + { + return $this->setHeaderBody('Date', 'Date', $dateTime); + } + + public function getDate(): ?\DateTimeImmutable + { + return $this->getHeaders()->getHeaderBody('Date'); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function returnPath($address) + { + return $this->setHeaderBody('Path', 'Return-Path', Address::create($address)); + } + + public function getReturnPath(): ?Address + { + return $this->getHeaders()->getHeaderBody('Return-Path'); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function sender($address) + { + return $this->setHeaderBody('Mailbox', 'Sender', Address::create($address)); + } + + public function getSender(): ?Address + { + return $this->getHeaders()->getHeaderBody('Sender'); + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addFrom(...$addresses) + { + return $this->addListAddressHeaderBody('From', $addresses); + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function from(...$addresses) + { + return $this->setListAddressHeaderBody('From', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getFrom(): array + { + return $this->getHeaders()->getHeaderBody('From') ?: []; + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function addReplyTo(...$addresses) + { + return $this->addListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function replyTo(...$addresses) + { + return $this->setListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @return Address[] + */ + public function getReplyTo(): array + { + return $this->getHeaders()->getHeaderBody('Reply-To') ?: []; + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addTo(...$addresses) + { + return $this->addListAddressHeaderBody('To', $addresses); + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function to(...$addresses) + { + return $this->setListAddressHeaderBody('To', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getTo(): array + { + return $this->getHeaders()->getHeaderBody('To') ?: []; + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addCc(...$addresses) + { + return $this->addListAddressHeaderBody('Cc', $addresses); + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function cc(...$addresses) + { + return $this->setListAddressHeaderBody('Cc', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getCc(): array + { + return $this->getHeaders()->getHeaderBody('Cc') ?: []; + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addBcc(...$addresses) + { + return $this->addListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function bcc(...$addresses) + { + return $this->setListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getBcc(): array + { + return $this->getHeaders()->getHeaderBody('Bcc') ?: []; + } + + /** + * Sets the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @return $this + */ + public function priority(int $priority) + { + if ($priority > 5) { + $priority = 5; + } elseif ($priority < 1) { + $priority = 1; + } + + return $this->setHeaderBody('Text', 'X-Priority', sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + */ + public function getPriority(): int + { + list($priority) = sscanf($this->getHeaders()->getHeaderBody('X-Priority'), '%[1-5]'); + + return $priority ?? 3; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function text($body, string $charset = 'utf-8') + { + $this->text = $body; + $this->textCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getTextBody() + { + return $this->text; + } + + public function getTextCharset(): ?string + { + return $this->textCharset; + } + + /** + * @param resource|string|null $body + * + * @return $this + */ + public function html($body, string $charset = 'utf-8') + { + $this->html = $body; + $this->htmlCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getHtmlBody() + { + return $this->html; + } + + public function getHtmlCharset(): ?string + { + return $this->htmlCharset; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function attach($body, string $name = null, string $contentType = null) + { + $this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => false]; + + return $this; + } + + /** + * @return $this + */ + public function attachFromPath(string $path, string $name = null, string $contentType = null) + { + $this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => false]; + + return $this; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function embed($body, string $name = null, string $contentType = null) + { + $this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => true]; + + return $this; + } + + /** + * @return $this + */ + public function embedFromPath(string $path, string $name = null, string $contentType = null) + { + $this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => true]; + + return $this; + } + + /** + * @return $this + */ + public function attachPart(AbstractPart $part) + { + $this->attachments[] = ['part' => $part]; + + return $this; + } + + /** + * @return AbstractPart[] + */ + public function getAttachments(): array + { + $parts = []; + foreach ($this->attachments as $attachment) { + $parts[] = $this->createDataPart($attachment); + } + + return $parts; + } + + public function getBody(): AbstractPart + { + if (null !== $body = parent::getBody()) { + return $body; + } + + return $this->generateBody(); + } + + /** + * Generates an AbstractPart based on the raw body of a message. + * + * The most "complex" part generated by this method is when there is text and HTML bodies + * with related images for the HTML part and some attachments: + * + * multipart/mixed + * | + * |------------> multipart/related + * | | + * | |------------> multipart/alternative + * | | | + * | | ------------> text/plain (with content) + * | | | + * | | ------------> text/html (with content) + * | | + * | ------------> image/png (with content) + * | + * ------------> application/pdf (with content) + */ + private function generateBody(): AbstractPart + { + if (null === $this->text && null === $this->html) { + throw new LogicException('A message must have a text and/or an HTML part.'); + } + + $part = null === $this->text ? null : new TextPart($this->text, $this->textCharset); + [$htmlPart, $attachmentParts, $inlineParts] = $this->prepareParts(); + if (null !== $htmlPart) { + if (null !== $part) { + $part = new AlternativePart($part, $htmlPart); + } else { + $part = $htmlPart; + } + } + + if ($inlineParts) { + $part = new RelatedPart($part, ...$inlineParts); + } + + if ($attachmentParts) { + $part = new MixedPart($part, ...$attachmentParts); + } + + return $part; + } + + private function prepareParts(): ?array + { + $names = []; + $htmlPart = null; + $html = $this->html; + if (null !== $this->html) { + if (\is_resource($html)) { + if (stream_get_meta_data($html)['seekable'] ?? false) { + rewind($html); + } + + $html = stream_get_contents($html); + } + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + preg_match_all('(]*src\s*=\s*(?:([\'"])cid:([^"]+)\\1|cid:([^>\s]+)))i', $html, $names); + $names = array_filter(array_unique(array_merge($names[2], $names[3]))); + } + + $attachmentParts = $inlineParts = []; + foreach ($this->attachments as $attachment) { + foreach ($names as $name) { + if (isset($attachment['part'])) { + continue; + } + if ($name !== $attachment['name']) { + continue; + } + if (isset($inlineParts[$name])) { + continue 2; + } + $attachment['inline'] = true; + $inlineParts[$name] = $part = $this->createDataPart($attachment); + $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html); + continue 2; + } + $attachmentParts[] = $this->createDataPart($attachment); + } + if (null !== $htmlPart) { + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + } + + return [$htmlPart, $attachmentParts, array_values($inlineParts)]; + } + + private function createDataPart(array $attachment): DataPart + { + if (isset($attachment['part'])) { + return $attachment['part']; + } + + if (isset($attachment['body'])) { + $part = new DataPart($attachment['body'], $attachment['name'] ?? null, $attachment['content-type'] ?? null); + } else { + $part = DataPart::fromPath($attachment['path'] ?? '', $attachment['name'] ?? null, $attachment['content-type'] ?? null); + } + if ($attachment['inline']) { + $part->asInline(); + } + + return $part; + } + + /** + * @return $this + */ + private function setHeaderBody(string $type, string $name, $body) + { + $this->getHeaders()->setHeaderBody($type, $name, $body); + + return $this; + } + + private function addListAddressHeaderBody($name, array $addresses) + { + if (!$to = $this->getHeaders()->get($name)) { + return $this->setListAddressHeaderBody($name, $addresses); + } + $to->addAddresses(Address::createArray($addresses)); + + return $this; + } + + private function setListAddressHeaderBody($name, array $addresses) + { + $addresses = Address::createArray($addresses); + $headers = $this->getHeaders(); + if ($to = $headers->get($name)) { + $to->setAddresses($addresses); + } else { + $headers->addMailboxListHeader($name, $addresses); + } + + return $this; + } + + public function __sleep() + { + $this->_headers = $this->getHeaders(); + $this->_raw = false; + + if (null !== $body = parent::getBody()) { + $r = new \ReflectionProperty(Message::class, 'body'); + $r->setAccessible(true); + $this->_body = $r->getValue($this); + $this->_raw = true; + + return ['_raw', '_headers', '_body']; + } + + if (\is_resource($this->text)) { + if (stream_get_meta_data($this->text)['seekable'] ?? false) { + rewind($this->text); + } + + $this->text = stream_get_contents($this->text); + } + + if (\is_resource($this->html)) { + if (stream_get_meta_data($this->html)['seekable'] ?? false) { + rewind($this->html); + } + + $this->html = stream_get_contents($this->html); + } + + foreach ($this->attachments as $i => $attachment) { + if (isset($attachment['body']) && \is_resource($attachment['body'])) { + if (stream_get_meta_data($attachment['body'])['seekable'] ?? false) { + rewind($attachment['body']); + } + + $this->attachments[$i]['body'] = stream_get_contents($attachment['body']); + } + } + + return ['_raw', '_headers', 'text', 'textCharset', 'html', 'htmlCharset', 'attachments']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(Message::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + + if ($this->_raw) { + $r = new \ReflectionProperty(Message::class, 'body'); + $r->setAccessible(true); + $r->setValue($this, $this->_body); + unset($this->_body); + } + unset($this->_raw); + } +} diff --git a/src/Symfony/Component/Mime/Encoder/AddressEncoderInterface.php b/src/Symfony/Component/Mime/Encoder/AddressEncoderInterface.php new file mode 100644 index 0000000000000..5d6ea3c66a1ad --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/AddressEncoderInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\AddressEncoderException; + +/** + * @author Christian Schmidt + * + * @experimental in 4.3 + */ +interface AddressEncoderInterface +{ + /** + * Encodes an email address. + * + * @throws AddressEncoderException if the email cannot be represented in + * the encoding implemented by this class + */ + public function encodeString(string $address): string; +} diff --git a/src/Symfony/Component/Mime/Encoder/Base64ContentEncoder.php b/src/Symfony/Component/Mime/Encoder/Base64ContentEncoder.php new file mode 100644 index 0000000000000..e9c352e20e32d --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/Base64ContentEncoder.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\RuntimeException; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class Base64ContentEncoder extends Base64Encoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + $filter = stream_filter_append($stream, 'convert.base64-encode', \STREAM_FILTER_READ, [ + 'line-length' => 0 >= $maxLineLength || 76 < $maxLineLength ? 76 : $maxLineLength, + 'line-break-chars' => "\r\n", + ]); + if (!\is_resource($filter)) { + throw new RuntimeException('Unable to set the base64 content encoder to the filter.'); + } + + if (stream_get_meta_data($stream)['seekable'] ?? false) { + rewind($stream); + } + while (!feof($stream)) { + yield fread($stream, 8192); + } + stream_filter_remove($filter); + } + + public function getName(): string + { + return 'base64'; + } +} diff --git a/src/Symfony/Component/Mime/Encoder/Base64Encoder.php b/src/Symfony/Component/Mime/Encoder/Base64Encoder.php new file mode 100644 index 0000000000000..25dae670b1e13 --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/Base64Encoder.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class Base64Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * Base64 encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if (0 >= $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + if (0 !== $firstLineOffset) { + $firstLine = substr($encodedString, 0, $maxLineLength - $firstLineOffset)."\r\n"; + $encodedString = substr($encodedString, $maxLineLength - $firstLineOffset); + } + + return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } +} diff --git a/src/Symfony/Component/Mime/Encoder/Base64MimeHeaderEncoder.php b/src/Symfony/Component/Mime/Encoder/Base64MimeHeaderEncoder.php new file mode 100644 index 0000000000000..8baee5b02ebb2 --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/Base64MimeHeaderEncoder.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class Base64MimeHeaderEncoder extends Base64Encoder implements MimeHeaderEncoderInterface +{ + public function getName(): string + { + return 'B'; + } + + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of + * default encodeString, otherwise pass to the parent method. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if ('iso-2022-jp' === strtolower($charset)) { + $old = mb_internal_encoding(); + mb_internal_encoding('utf-8'); + $newstring = mb_encode_mimeheader($string, 'iso-2022-jp', $this->getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength); + } +} diff --git a/src/Symfony/Component/Mime/Encoder/ContentEncoderInterface.php b/src/Symfony/Component/Mime/Encoder/ContentEncoderInterface.php new file mode 100644 index 0000000000000..b44e1a4a71332 --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/ContentEncoderInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface ContentEncoderInterface extends EncoderInterface +{ + /** + * Encodes the stream to a Generator. + * + * @param resource $stream + */ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable; + + /** + * Gets the MIME name of this content encoding scheme. + */ + public function getName(): string; +} diff --git a/src/Symfony/Component/Mime/Encoder/EncoderInterface.php b/src/Symfony/Component/Mime/Encoder/EncoderInterface.php new file mode 100644 index 0000000000000..3c2ef198e5873 --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/EncoderInterface.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface EncoderInterface +{ + /** + * Encode a given string to produce an encoded string. + * + * @param int $firstLineOffset if first line needs to be shorter + * @param int $maxLineLength - 0 indicates the default length for this encoding + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string; +} diff --git a/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php b/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php new file mode 100644 index 0000000000000..8936047ceb05c --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\AddressEncoderException; + +/** + * An IDN email address encoder. + * + * Encodes the domain part of an address using IDN. This is compatible will all + * SMTP servers. + * + * This encoder does not support email addresses with non-ASCII characters in + * local-part (the substring before @). To send to such addresses, use + * Utf8AddressEncoder together with SmtpUtf8Handler. Your outbound SMTP server must support + * the SMTPUTF8 extension. + * + * @author Christian Schmidt + * + * @experimental in 4.3 + */ +final class IdnAddressEncoder implements AddressEncoderInterface +{ + /** + * Encodes the domain part of an address using IDN. + * + * @throws AddressEncoderException If local-part contains non-ASCII characters + */ + public function encodeString(string $address): string + { + $i = strrpos($address, '@'); + if (false !== $i) { + $local = substr($address, 0, $i); + $domain = substr($address, $i + 1); + + if (preg_match('/[^\x00-\x7F]/', $local)) { + throw new AddressEncoderException(sprintf('Non-ASCII characters not supported in local-part os "%s".', $address)); + } + + if (preg_match('/[^\x00-\x7F]/', $domain)) { + $address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46)); + } + } + + return $address; + } +} diff --git a/src/Symfony/Component/Mime/Encoder/MimeHeaderEncoderInterface.php b/src/Symfony/Component/Mime/Encoder/MimeHeaderEncoderInterface.php new file mode 100644 index 0000000000000..f5756650caa8b --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/MimeHeaderEncoderInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface MimeHeaderEncoderInterface +{ + /** + * Get the MIME name of this content encoding scheme. + */ + public function getName(): string; +} diff --git a/src/Symfony/Component/Mime/Encoder/QpContentEncoder.php b/src/Symfony/Component/Mime/Encoder/QpContentEncoder.php new file mode 100644 index 0000000000000..ef2de46f0bb85 --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/QpContentEncoder.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Lars Strojny + * + * @experimental in 4.3 + */ +final class QpContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + // we don't use PHP stream filters here as the content should be small enough + if (stream_get_meta_data($stream)['seekable'] ?? false) { + rewind($stream); + } + + yield $this->encodeString(stream_get_contents($stream), 'utf-8', 0, $maxLineLength); + } + + public function getName(): string + { + return 'quoted-printable'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $this->standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + */ + private function standardize(string $string): string + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(? + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + +/** + * @final + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class QpEncoder implements EncoderInterface +{ + /** + * Pre-computed QP for HUGE optimization. + */ + private static $qpMap = [ + 0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', + 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', + 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', + 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', + 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', + 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', + 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', + 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', + 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', + 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', + 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', + 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', + 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', + 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', + 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', + 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', + 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', + 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', + 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', + 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', + 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', + 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', + 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', + 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', + 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', + 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', + 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', + 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', + 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', + 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', + 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', + 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', + 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', + 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', + 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', + 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', + 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', + 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', + 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', + 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', + 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', + 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', + 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', + 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', + 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', + 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', + 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', + 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', + 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', + 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', + 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', + 255 => '=FF', + ]; + + private static $safeMapShare = []; + + /** + * A map of non-encoded ascii characters. + * + * @var string[] + * + * @internal + */ + protected $safeMap = []; + + public function __construct() + { + $id = \get_class($this); + if (!isset(self::$safeMapShare[$id])) { + $this->initSafeMap(); + self::$safeMapShare[$id] = $this->safeMap; + } else { + $this->safeMap = self::$safeMapShare[$id]; + } + } + + protected function initSafeMap(): void + { + foreach (array_merge([0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { + $this->safeMap[$byte] = \chr($byte); + } + } + + /** + * {@inheritdoc} + * + * Takes an unencoded string and produces a QP encoded string from it. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $lines = []; + $lNo = 0; + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $size = $lineLen = 0; + $charStream = new CharacterStream($string, $charset); + + // Fetching more than 4 chars at one is slower, as is fetching fewer bytes + // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 + // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes + while (null !== $bytes = $charStream->readBytes(4)) { + $enc = $this->encodeByteSequence($bytes, $size); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + (false === $i ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if (false === $i) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + + return $this->standardize(implode("=\r\n", $lines)); + } + + /** + * Encode the given byte array into a verbatim QP form. + */ + private function encodeByteSequence(array $bytes, int &$size): string + { + $ret = ''; + $size = 0; + foreach ($bytes as $b) { + if (isset($this->safeMap[$b])) { + $ret .= $this->safeMap[$b]; + ++$size; + } else { + $ret .= self::$qpMap[$b]; + $size += 3; + } + } + + return $ret; + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + */ + private function standardize(string $string): string + { + $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); + switch ($end = \ord(substr($string, -1))) { + case 0x09: + case 0x20: + $string = substr_replace($string, self::$qpMap[$end], -1); + } + + return $string; + } +} diff --git a/src/Symfony/Component/Mime/Encoder/QpMimeHeaderEncoder.php b/src/Symfony/Component/Mime/Encoder/QpMimeHeaderEncoder.php new file mode 100644 index 0000000000000..0413959587bcb --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/QpMimeHeaderEncoder.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class QpMimeHeaderEncoder extends QpEncoder implements MimeHeaderEncoderInterface +{ + protected function initSafeMap(): void + { + foreach (array_merge( + range(0x61, 0x7A), range(0x41, 0x5A), + range(0x30, 0x39), [0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F] + ) as $byte) { + $this->safeMap[$byte] = \chr($byte); + } + } + + public function getName(): string + { + return 'Q'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], + parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/src/Symfony/Component/Mime/Encoder/Rfc2231Encoder.php b/src/Symfony/Component/Mime/Encoder/Rfc2231Encoder.php new file mode 100644 index 0000000000000..4743a7217c95f --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/Rfc2231Encoder.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class Rfc2231Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a string encoded according to RFC 2231 from it. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + $lines = []; + $lineCount = 0; + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $charStream = new CharacterStream($string, $charset); + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (null !== $char = $charStream->read(4)) { + $encodedChar = rawurlencode($char); + if (0 !== \strlen($currentLine) && \strlen($currentLine.$encodedChar) > $thisLineLength) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } +} diff --git a/src/Symfony/Component/Mime/Exception/AddressEncoderException.php b/src/Symfony/Component/Mime/Exception/AddressEncoderException.php new file mode 100644 index 0000000000000..73ef7f32228f3 --- /dev/null +++ b/src/Symfony/Component/Mime/Exception/AddressEncoderException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class AddressEncoderException extends RfcComplianceException +{ +} diff --git a/src/Symfony/Component/Mime/Exception/ExceptionInterface.php b/src/Symfony/Component/Mime/Exception/ExceptionInterface.php new file mode 100644 index 0000000000000..7dbcdc72b072c --- /dev/null +++ b/src/Symfony/Component/Mime/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/src/Symfony/Component/Mime/Exception/InvalidArgumentException.php b/src/Symfony/Component/Mime/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000000..59d04e234e750 --- /dev/null +++ b/src/Symfony/Component/Mime/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mime/Exception/LogicException.php b/src/Symfony/Component/Mime/Exception/LogicException.php new file mode 100644 index 0000000000000..07cb0440837f6 --- /dev/null +++ b/src/Symfony/Component/Mime/Exception/LogicException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mime/Exception/RfcComplianceException.php b/src/Symfony/Component/Mime/Exception/RfcComplianceException.php new file mode 100644 index 0000000000000..5dc4cf5f57553 --- /dev/null +++ b/src/Symfony/Component/Mime/Exception/RfcComplianceException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class RfcComplianceException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mime/Exception/RuntimeException.php b/src/Symfony/Component/Mime/Exception/RuntimeException.php new file mode 100644 index 0000000000000..84b11fba6ffae --- /dev/null +++ b/src/Symfony/Component/Mime/Exception/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php index f637e8710deff..a25ebe4d5cdcd 100644 --- a/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php +++ b/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php @@ -11,10 +11,15 @@ namespace Symfony\Component\Mime; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + /** * Guesses the MIME type with the binary "file" (only available on *nix). * * @author Bernhard Schussek + * + * @experimental in 4.3 */ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface { @@ -61,11 +66,11 @@ public function isGuesserSupported(): bool public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { - throw new \InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { - throw new \LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); } ob_start(); diff --git a/src/Symfony/Component/Mime/FileinfoMimeTypeGuesser.php b/src/Symfony/Component/Mime/FileinfoMimeTypeGuesser.php index 0219107e41f76..81c62ee2013ac 100644 --- a/src/Symfony/Component/Mime/FileinfoMimeTypeGuesser.php +++ b/src/Symfony/Component/Mime/FileinfoMimeTypeGuesser.php @@ -11,10 +11,15 @@ namespace Symfony\Component\Mime; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + /** * Guesses the MIME type using the PECL extension FileInfo. * * @author Bernhard Schussek + * + * @experimental in 4.3 */ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface { @@ -44,11 +49,11 @@ public function isGuesserSupported(): bool public function guessMimeType(string $path): ?string { if (!is_file($path) || !is_readable($path)) { - throw new \InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); } if (!$this->isGuesserSupported()) { - throw new \LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); } if (false === $finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { diff --git a/src/Symfony/Component/Mime/Header/AbstractHeader.php b/src/Symfony/Component/Mime/Header/AbstractHeader.php new file mode 100644 index 0000000000000..517ee8dfb2381 --- /dev/null +++ b/src/Symfony/Component/Mime/Header/AbstractHeader.php @@ -0,0 +1,281 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; + +/** + * An abstract base MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +abstract class AbstractHeader implements HeaderInterface +{ + const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)'; + + private static $encoder; + + private $name; + private $lineLength = 76; + private $lang; + private $charset = 'utf-8'; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function setCharset(string $charset) + { + $this->charset = $charset; + } + + public function getCharset(): ?string + { + return $this->charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + */ + public function setLanguage(string $lang) + { + $this->lang = $lang; + } + + public function getLanguage(): ?string + { + return $this->lang; + } + + public function getName(): string + { + return $this->name; + } + + public function setMaxLineLength(int $lineLength) + { + $this->lineLength = $lineLength; + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + public function toString(): string + { + return $this->tokensToString($this->toTokens()); + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param string $string as displayed + * @param bool $shorten the first line to make remove for header name + */ + protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string + { + // Treat token as exactly what was given + $phraseStr = $string; + + // If it's not valid + if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { + foreach (['\\', '"'] as $char) { + $phraseStr = str_replace($char, '\\'.$char, $phraseStr); + } + $phraseStr = '"'.$phraseStr.'"'; + } else { + // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = \strlen($header->getName().': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + */ + protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string + { + $value = ''; + $tokens = $this->getEncodableWordTokens($input); + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = \strlen($header->getName().': ') + \strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + } else { + $value .= $token; + } + } + + return $value; + } + + protected function tokenNeedsEncoding(string $token): bool + { + return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @return string[] + */ + protected function getEncodableWordTokens(string $string): array + { + $tokens = []; + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if (\strlen($encodedToken) > 0) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if (\strlen($encodedToken)) { + $tokens[] = $encodedToken; + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + */ + protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string + { + if (null === self::$encoder) { + self::$encoder = new QpMimeHeaderEncoder(); + } + + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->charset; + if (null !== $this->lang) { + $charsetDecl .= '*'.$this->lang; + } + $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??='); + + if ($firstLineOffset >= 75) { + //Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength) + ); + + if ('iso-2022-jp' !== strtolower($this->charset)) { + // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @return string[] + */ + protected function generateTokenLines(string $token): array + { + return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Generate a list of all tokens in the final header. + */ + protected function toTokens(string $string = null): array + { + if (null === $string) { + $string = $this->getBodyAsString(); + } + + $tokens = []; + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + */ + private function tokensToString(array $tokens): string + { + $lineCount = 0; + $headerLines = []; + $headerLines[] = $this->name.': '; + $currentLine = &$headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" === $token) || + ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) + && 0 < \strlen($currentLine)) { + $headerLines[] = ''; + $currentLine = &$headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" !== $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines); + } +} diff --git a/src/Symfony/Component/Mime/Header/DateHeader.php b/src/Symfony/Component/Mime/Header/DateHeader.php new file mode 100644 index 0000000000000..1e1a979569448 --- /dev/null +++ b/src/Symfony/Component/Mime/Header/DateHeader.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Date MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class DateHeader extends AbstractHeader +{ + private $dateTime; + + public function __construct(string $name, \DateTimeInterface $date) + { + parent::__construct($name); + + $this->setDateTime($date); + } + + /** + * @param \DateTimeInterface $body + */ + public function setBody($body) + { + $this->setDateTime($body); + } + + /** + * @return \DateTimeImmutable + */ + public function getBody() + { + return $this->getDateTime(); + } + + public function getDateTime(): \DateTimeImmutable + { + return $this->dateTime; + } + + /** + * Set the date-time of the Date in this Header. + * + * If a DateTime instance is provided, it is converted to DateTimeImmutable. + */ + public function setDateTime(\DateTimeInterface $dateTime) + { + if ($dateTime instanceof \DateTime) { + $immutable = new \DateTimeImmutable('@'.$dateTime->getTimestamp()); + $dateTime = $immutable->setTimezone($dateTime->getTimezone()); + } + $this->dateTime = $dateTime; + } + + public function getBodyAsString(): string + { + return $this->dateTime->format(\DateTime::RFC2822); + } +} diff --git a/src/Symfony/Component/Mime/Header/HeaderInterface.php b/src/Symfony/Component/Mime/Header/HeaderInterface.php new file mode 100644 index 0000000000000..b0638bca40a3b --- /dev/null +++ b/src/Symfony/Component/Mime/Header/HeaderInterface.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface HeaderInterface +{ + /** + * Sets the body. + * + * The type depends on the Header concrete class. + * + * @param mixed $body + */ + public function setBody($body); + + /** + * Gets the body. + * + * The return type depends on the Header concrete class. + * + * @return mixed + */ + public function getBody(); + + public function setCharset(string $charset); + + public function getCharset(): ?string; + + public function setLanguage(string $lang); + + public function getLanguage(): ?string; + + public function getName(): string; + + public function setMaxLineLength(int $lineLength); + + public function getMaxLineLength(): int; + + /** + * Gets this Header rendered as a compliant string. + */ + public function toString(): string; + + /** + * Gets the header's body, prepared for folding into a final header value. + * + * This is not necessarily RFC 2822 compliant since folding white space is + * not added at this stage (see {@link toString()} for that). + */ + public function getBodyAsString(): string; +} diff --git a/src/Symfony/Component/Mime/Header/Headers.php b/src/Symfony/Component/Mime/Header/Headers.php new file mode 100644 index 0000000000000..5556f64a6d54f --- /dev/null +++ b/src/Symfony/Component/Mime/Header/Headers.php @@ -0,0 +1,275 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\NamedAddress; + +/** + * A collection of headers. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class Headers +{ + private static $uniqueHeaders = [ + 'date', 'from', 'sender', 'reply-to', 'to', 'cc', 'bcc', + 'message-id', 'in-reply-to', 'references', 'subject', + ]; + + private $headers = []; + private $lineLength = 76; + + public function __construct(HeaderInterface ...$headers) + { + foreach ($headers as $header) { + $this->add($header); + } + } + + public function __clone() + { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $i => $header) { + $this->headers[$name][$i] = clone $header; + } + } + } + + public function setMaxLineLength(int $lineLength) + { + $this->lineLength = $lineLength; + foreach ($this->getAll() as $header) { + $header->setMaxLineLength($lineLength); + } + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + /** + * @param (NamedAddress|Address|string)[] $addresses + * + * @return $this + */ + public function addMailboxListHeader(string $name, array $addresses) + { + return $this->add(new MailboxListHeader($name, Address::createArray($addresses))); + } + + /** + * @param NamedAddress|Address|string $address + * + * @return $this + */ + public function addMailboxHeader(string $name, $address) + { + return $this->add(new MailboxHeader($name, Address::create($address))); + } + + /** + * @param string|array $ids + * + * @return $this + */ + public function addIdHeader(string $name, $ids) + { + return $this->add(new IdentificationHeader($name, $ids)); + } + + /** + * @param Address|string $path + * + * @return $this + */ + public function addPathHeader(string $name, $path) + { + return $this->add(new PathHeader($name, $path instanceof Address ? $path : new Address($path))); + } + + /** + * @return $this + */ + public function addDateHeader(string $name, \DateTimeInterface $dateTime) + { + return $this->add(new DateHeader($name, $dateTime)); + } + + /** + * @return $this + */ + public function addTextHeader(string $name, string $value) + { + return $this->add(new UnstructuredHeader($name, $value)); + } + + /** + * @return $this + */ + public function addParameterizedHeader(string $name, string $value, array $params = []) + { + return $this->add(new ParameterizedHeader($name, $value, $params)); + } + + public function has(string $name): bool + { + return isset($this->headers[strtolower($name)]); + } + + /** + * @return $this + */ + public function add(HeaderInterface $header) + { + static $map = [ + 'date' => DateHeader::class, + 'from' => MailboxListHeader::class, + 'sender' => MailboxHeader::class, + 'reply-to' => MailboxListHeader::class, + 'to' => MailboxListHeader::class, + 'cc' => MailboxListHeader::class, + 'bcc' => MailboxListHeader::class, + 'message-id' => IdentificationHeader::class, + 'in-reply-to' => IdentificationHeader::class, + 'references' => IdentificationHeader::class, + 'return-path' => PathHeader::class, + ]; + + $header->setMaxLineLength($this->lineLength); + $name = strtolower($header->getName()); + + if (isset($map[$name]) && !$header instanceof $map[$name]) { + throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), $map[$name], \get_class($header))); + } + + if (\in_array($name, self::$uniqueHeaders, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) { + throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); + } + + $this->headers[$name][] = $header; + + return $this; + } + + public function get(string $name): ?HeaderInterface + { + $name = strtolower($name); + if (!isset($this->headers[strtolower($name)])) { + return null; + } + + $values = array_values($this->headers[$name]); + + return array_shift($values); + } + + public function getAll(string $name = null): iterable + { + if (null === $name) { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $header) { + yield $name => $header; + } + } + } elseif (isset($this->headers[strtolower($name)])) { + foreach ($this->headers[strtolower($name)] as $header) { + yield $header; + } + } + } + + public function getNames(): array + { + return array_keys($this->headers); + } + + public function remove(string $name): void + { + unset($this->headers[strtolower($name)]); + } + + public static function isUniqueHeader(string $name): bool + { + return \in_array($name, self::$uniqueHeaders, true); + } + + public function toString(): string + { + $string = ''; + foreach ($this->getAll() as $header) { + if ('' !== $header->getBodyAsString()) { + $string .= $header->toString()."\r\n"; + } + } + + return $string; + } + + /** + * @internal + */ + public function getHeaderBody($name) + { + return $this->has($name) ? $this->get($name)->getBody() : null; + } + + /** + * @internal + */ + public function setHeaderBody(string $type, string $name, $body): void + { + if ($this->has($name)) { + $this->get($name)->setBody($body); + } else { + $this->{'add'.$type.'Header'}($name, $body); + } + } + + /** + * @internal + */ + public function getHeaderParameter(string $name, string $parameter): ?string + { + if (!$this->has($name)) { + return null; + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + return $header->getParameter($parameter); + } + + /** + * @internal + */ + public function setHeaderParameter(string $name, string $parameter, $value): void + { + if (!$this->has($name)) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + $header->setParameter($parameter, $value); + } +} diff --git a/src/Symfony/Component/Mime/Header/IdentificationHeader.php b/src/Symfony/Component/Mime/Header/IdentificationHeader.php new file mode 100644 index 0000000000000..0695b688da247 --- /dev/null +++ b/src/Symfony/Component/Mime/Header/IdentificationHeader.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * An ID MIME Header for something like Message-ID or Content-ID (one or more addresses). + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class IdentificationHeader extends AbstractHeader +{ + private $ids = []; + private $idsAsAddresses = []; + + /** + * @param string|array $ids + */ + public function __construct(string $name, $ids) + { + parent::__construct($name); + + $this->setId($ids); + } + + /** + * @param string|array $body a string ID or an array of IDs + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setId($body); + } + + /** + * @return array + */ + public function getBody() + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|array $id + * + * @throws RfcComplianceException + */ + public function setId($id) + { + $this->setIds(\is_array($id) ? $id : [$id]); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + */ + public function getId(): ?string + { + return $this->ids[0] ?? null; + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws RfcComplianceException + */ + public function setIds(array $ids) + { + $this->ids = []; + $this->idsAsAddresses = []; + foreach ($ids as $id) { + $this->idsAsAddresses[] = new Address($id); + $this->ids[] = $id; + } + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds(): array + { + return $this->ids; + } + + public function getBodyAsString(): string + { + $addrs = []; + foreach ($this->idsAsAddresses as $address) { + $addrs[] = '<'.$address->toString().'>'; + } + + return implode(' ', $addrs); + } +} diff --git a/src/Symfony/Component/Mime/Header/MailboxHeader.php b/src/Symfony/Component/Mime/Header/MailboxHeader.php new file mode 100644 index 0000000000000..c4f48f3e48cc8 --- /dev/null +++ b/src/Symfony/Component/Mime/Header/MailboxHeader.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; +use Symfony\Component\Mime\NamedAddress; + +/** + * A Mailbox MIME Header for something like Sender (one named address). + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class MailboxHeader extends AbstractHeader +{ + private $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddress($body); + } + + /** + * @throws RfcComplianceException + * + * @return Address + */ + public function getBody() + { + return $this->getAddress(); + } + + /** + * @throws RfcComplianceException + */ + public function setAddress(Address $address) + { + $this->address = $address; + } + + /** + * @return Address + */ + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + $str = $this->address->getEncodedAddress(); + if ($this->address instanceof NamedAddress && $name = $this->address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), true).' <'.$str.'>'; + } + + return $str; + } + + /** + * Redefine the encoding requirements for an address. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/src/Symfony/Component/Mime/Header/MailboxListHeader.php b/src/Symfony/Component/Mime/Header/MailboxListHeader.php new file mode 100644 index 0000000000000..51af2da87caab --- /dev/null +++ b/src/Symfony/Component/Mime/Header/MailboxListHeader.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; +use Symfony\Component\Mime\NamedAddress; + +/** + * A Mailbox list MIME Header for something like From, To, Cc, and Bcc (one or more named addresses). + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class MailboxListHeader extends AbstractHeader +{ + private $addresses = []; + + /** + * @param (NamedAddress|Address)[] $addresses + */ + public function __construct(string $name, array $addresses) + { + parent::__construct($name); + + $this->setAddresses($addresses); + } + + /** + * @param (NamedAddress|Address)[] $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddresses($body); + } + + /** + * @throws RfcComplianceException + * + * @return (NamedAddress|Address)[] + */ + public function getBody() + { + return $this->getAddresses(); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param (NamedAddress|Address)[] $addresses + * + * @throws RfcComplianceException + */ + public function setAddresses(array $addresses) + { + $this->addresses = []; + $this->addAddresses($addresses); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param (NamedAddress|Address)[] $addresses + * + * @throws RfcComplianceException + */ + public function addAddresses(array $addresses) + { + foreach ($addresses as $address) { + $this->addAddress($address); + } + } + + /** + * @throws RfcComplianceException + */ + public function addAddress(Address $address) + { + $this->addresses[] = $address; + } + + /** + * @return (NamedAddress|Address)[] + */ + public function getAddresses(): array + { + return $this->addresses; + } + + /** + * Gets the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * @throws RfcComplianceException + * + * @return string[] + */ + public function getAddressStrings(): array + { + $strings = []; + foreach ($this->addresses as $address) { + $str = $address->getEncodedAddress(); + if ($address instanceof NamedAddress && $name = $address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), empty($strings)).' <'.$str.'>'; + } + $strings[] = $str; + } + + return $strings; + } + + public function getBodyAsString(): string + { + return implode(', ', $this->getAddressStrings()); + } + + /** + * Redefine the encoding requirements for addresses. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/src/Symfony/Component/Mime/Header/ParameterizedHeader.php b/src/Symfony/Component/Mime/Header/ParameterizedHeader.php new file mode 100644 index 0000000000000..5813dcf79f047 --- /dev/null +++ b/src/Symfony/Component/Mime/Header/ParameterizedHeader.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\Rfc2231Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class ParameterizedHeader extends UnstructuredHeader +{ + /** + * RFC 2231's definition of a token. + * + * @var string + */ + const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)'; + + private $encoder; + private $parameters = []; + + public function __construct(string $name, string $value, array $parameters = []) + { + parent::__construct($name, $value); + + foreach ($parameters as $k => $v) { + $this->setParameter($k, $v); + } + + if ('content-disposition' === strtolower($name)) { + $this->encoder = new Rfc2231Encoder(); + } + } + + public function setParameter(string $parameter, ?string $value) + { + $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); + } + + public function getParameter(string $parameter): string + { + return $this->getParameters()[$parameter] ?? ''; + } + + /** + * @param string[] $parameters + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * @return string[] + */ + public function getParameters(): array + { + return $this->parameters; + } + + public function getBodyAsString(): string + { + $body = parent::getBodyAsString(); + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + $body .= '; '.$this->createParameter($name, $value); + } + } + + return $body; + } + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + */ + protected function toTokens(string $string = null): array + { + $tokens = parent::toTokens(parent::getBodyAsString()); + + // Try creating any parameters + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + // Add the semi-colon separator + $tokens[\count($tokens) - 1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value))); + } + } + + return $tokens; + } + + /** + * Render a RFC 2047 compliant header parameter from the $name and $value. + */ + private function createParameter(string $name, string $value): string + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; + $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'"); + } + } + + // Encode if we need to + if ($encoded || \strlen($value) > $maxValueLength) { + if (null !== $this->encoder) { + $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength); + } else { + // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = $this->encoder ? explode("\r\n", $value) : [$value]; + + // Need to add indices + if (\count($valueLines) > 1) { + $paramLines = []; + foreach ($valueLines as $i => $line) { + $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + */ + private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string + { + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + $value = '"'.$value.'"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'"; + } + } + + return $prepend.$value; + } +} diff --git a/src/Symfony/Component/Mime/Header/PathHeader.php b/src/Symfony/Component/Mime/Header/PathHeader.php new file mode 100644 index 0000000000000..6d16500a18a22 --- /dev/null +++ b/src/Symfony/Component/Mime/Header/PathHeader.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Path Header, such a Return-Path (one address). + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class PathHeader extends AbstractHeader +{ + private $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddress($body); + } + + /** + * @return Address + */ + public function getBody() + { + return $this->getAddress(); + } + + public function setAddress(Address $address) + { + $this->address = $address; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + return '<'.$this->address->toString().'>'; + } +} diff --git a/src/Symfony/Component/Mime/Header/UnstructuredHeader.php b/src/Symfony/Component/Mime/Header/UnstructuredHeader.php new file mode 100644 index 0000000000000..269e00eee8f9f --- /dev/null +++ b/src/Symfony/Component/Mime/Header/UnstructuredHeader.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Simple MIME Header. + * + * @final + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class UnstructuredHeader extends AbstractHeader +{ + private $value; + + public function __construct(string $name, string $value) + { + parent::__construct($name); + + $this->setValue($value); + } + + /** + * @param string $body + */ + public function setBody($body) + { + $this->setValue($body); + } + + /** + * @return string + */ + public function getBody() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + */ + public function getValue(): string + { + return $this->value; + } + + /** + * Set the (unencoded) value of this header. + */ + public function setValue(string $value) + { + $this->value = $value; + } + + /** + * Get the value of this header prepared for rendering. + */ + public function getBodyAsString(): string + { + return $this->encodeWords($this, $this->value); + } +} diff --git a/src/Symfony/Component/Mime/Message.php b/src/Symfony/Component/Mime/Message.php new file mode 100644 index 0000000000000..18aac00f3d9b8 --- /dev/null +++ b/src/Symfony/Component/Mime/Message.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class Message extends RawMessage +{ + private $headers; + private $body; + + public function __construct(Headers $headers = null, AbstractPart $body = null) + { + $this->headers = $headers ? clone $headers : new Headers(); + $this->body = $body; + } + + public function __clone() + { + if (null !== $this->headers) { + $this->headers = clone $this->headers; + } + + if (null !== $this->body) { + $this->body = clone $this->body; + } + } + + /** + * @return $this + */ + public function setBody(AbstractPart $body = null) + { + $this->body = $body; + + return $this; + } + + public function getBody(): ?AbstractPart + { + return $this->body; + } + + /** + * @return $this + */ + public function setHeaders(Headers $headers) + { + $this->headers = $headers; + + return $this; + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + + if (!$headers->has('From')) { + throw new LogicException('An email must have a "From" header.'); + } + + $headers->addTextHeader('MIME-Version', '1.0'); + + if (!$headers->has('Date')) { + $headers->addDateHeader('Date', new \DateTimeImmutable()); + } + + // determine the "real" sender + $senders = $headers->get('From')->getAddresses(); + $sender = $senders[0]; + if ($headers->has('Sender')) { + $sender = $headers->get('Sender')->getAddress(); + } elseif (\count($senders) > 1) { + $headers->addMailboxHeader('Sender', $sender); + } + + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $this->generateMessageId($sender->toString())); + } + + // remove the Bcc field which should NOT be part of the sent message + $headers->remove('Bcc'); + + return $headers; + } + + public function toString(): string + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + return $this->getPreparedHeaders()->toString().$body->toString(); + } + + public function toIterable(): iterable + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + yield $this->getPreparedHeaders()->toString(); + foreach ($body->toIterable() as $chunk) { + yield $chunk; + } + } + + private function generateMessageId(string $email): string + { + return bin2hex(random_bytes(16)).strstr($email, '@'); + } +} diff --git a/src/Symfony/Component/Mime/MessageConverter.php b/src/Symfony/Component/Mime/MessageConverter.php new file mode 100644 index 0000000000000..287cbd2f1cbc4 --- /dev/null +++ b/src/Symfony/Component/Mime/MessageConverter.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class MessageConverter +{ + /** + * @throws RuntimeException when unable to convert the message to an email + */ + public static function toEmail(RawMessage $message): Email + { + if ($message instanceof Email) { + return $message; + } + + if (RawMessage::class === \get_class($message)) { + // FIXME: parse the raw message to create the envelope? + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as it is not supported yet.', RawMessage::class)); + } + + // try to convert to a "simple" Email instance + $body = $message->getBody(); + if ($body instanceof TextPart) { + return self::createEmailFromTextPart($message, $body); + } + + if ($body instanceof AlternativePart) { + return self::createEmailFromAlternativePart($message, $body); + } + + if ($body instanceof RelatedPart) { + return self::createEmailFromRelatedPart($message, $body); + } + + if ($body instanceof MixedPart) { + $parts = $body->getParts(); + if ($parts[0] instanceof RelatedPart) { + $email = self::createEmailFromRelatedPart($message, $parts[0]); + } elseif ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + return self::attachParts($email, \array_slice($parts, 1)); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + private static function createEmailFromTextPart(Message $message, TextPart $part): Email + { + if ('text' === $part->getMediaType() && 'plain' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->text($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + if ('text' === $part->getMediaType() && 'html' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->html($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + private static function createEmailFromAlternativePart(Message $message, AlternativePart $part): Email + { + $parts = $part->getParts(); + if ( + 2 === \count($parts) && + $parts[0] instanceof TextPart && 'text' === $parts[0]->getMediaType() && 'plain' === $parts[0]->getMediaSubtype() && + $parts[1] instanceof TextPart && 'text' === $parts[1]->getMediaType() && 'html' === $parts[1]->getMediaSubtype() + ) { + return (new Email(clone $message->getHeaders())) + ->text($parts[0]->getBody(), $parts[0]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ->html($parts[1]->getBody(), $parts[1]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ; + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + private static function createEmailFromRelatedPart(Message $message, RelatedPart $part): Email + { + $parts = $part->getParts(); + if ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + return self::attachParts($email, \array_slice($parts, 1)); + } + + private static function attachParts(Email $email, array $parts): Email + { + foreach ($parts as $part) { + if (!$part instanceof DataPart) { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($email))); + } + + $headers = $part->getPreparedHeaders(); + $method = 'inline' === $headers->getHeaderBody('Content-Disposition') ? 'embed' : 'attach'; + $name = $headers->getHeaderParameter('Content-Disposition', 'filename'); + $email->$method($part->getBody(), $name, $part->getMediaType().'/'.$part->getMediaSubtype()); + } + + return $email; + } +} diff --git a/src/Symfony/Component/Mime/MimeTypeGuesserInterface.php b/src/Symfony/Component/Mime/MimeTypeGuesserInterface.php index 68b05055e6fbf..b7d27f53e2029 100644 --- a/src/Symfony/Component/Mime/MimeTypeGuesserInterface.php +++ b/src/Symfony/Component/Mime/MimeTypeGuesserInterface.php @@ -15,6 +15,8 @@ * Guesses the MIME type of a file. * * @author Fabien Potencier + * + * @experimental in 4.3 */ interface MimeTypeGuesserInterface { diff --git a/src/Symfony/Component/Mime/MimeTypes.php b/src/Symfony/Component/Mime/MimeTypes.php index b6aa5b62651cd..b0aee7fec2c48 100644 --- a/src/Symfony/Component/Mime/MimeTypes.php +++ b/src/Symfony/Component/Mime/MimeTypes.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Mime; +use Symfony\Component\Mime\Exception\LogicException; + /** * Manages MIME types and file extensions. * @@ -31,6 +33,8 @@ * $guesser->registerGuesser(new FileinfoMimeTypeGuesser('/path/to/magic/file')); * * @author Fabien Potencier + * + * @experimental in 4.3 */ final class MimeTypes implements MimeTypesInterface { @@ -122,7 +126,7 @@ public function guessMimeType(string $path): ?string } if (!$this->isGuesserSupported()) { - throw new \LogicException('Unable to guess the MIME type as no guessers are available (have you enable the php_fileinfo extension?).'); + throw new LogicException('Unable to guess the MIME type as no guessers are available (have you enable the php_fileinfo extension?).'); } return null; diff --git a/src/Symfony/Component/Mime/MimeTypesInterface.php b/src/Symfony/Component/Mime/MimeTypesInterface.php index 9fbd2cc2da24c..bdf20429a1cd6 100644 --- a/src/Symfony/Component/Mime/MimeTypesInterface.php +++ b/src/Symfony/Component/Mime/MimeTypesInterface.php @@ -13,6 +13,8 @@ /** * @author Fabien Potencier + * + * @experimental in 4.3 */ interface MimeTypesInterface extends MimeTypeGuesserInterface { diff --git a/src/Symfony/Component/Mime/NamedAddress.php b/src/Symfony/Component/Mime/NamedAddress.php new file mode 100644 index 0000000000000..0d58708a1cb7b --- /dev/null +++ b/src/Symfony/Component/Mime/NamedAddress.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class NamedAddress extends Address +{ + private $name; + + public function __construct(string $address, string $name) + { + parent::__construct($address); + + $this->name = $name; + } + + public function getName(): string + { + return $this->name; + } + + public function getEncodedNamedAddress(): string + { + return ($n = $this->getName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress(); + } + + public function toString(): string + { + return $this->getEncodedNamedAddress(); + } +} diff --git a/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php b/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php new file mode 100644 index 0000000000000..76e3e4979216b --- /dev/null +++ b/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +abstract class AbstractMultipartPart extends AbstractPart +{ + private $boundary; + private $parts = []; + + public function __construct(AbstractPart ...$parts) + { + parent::__construct(); + + foreach ($parts as $part) { + $this->parts[] = $part; + } + } + + /** + * @return AbstractPart[] + */ + public function getParts(): array + { + return $this->parts; + } + + public function getMediaType(): string + { + return 'multipart'; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + $headers->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary()); + + return $headers; + } + + public function bodyToString(): string + { + $parts = $this->getParts(); + + if (\count($parts) < 2) { + throw new LogicException(sprintf('A "%s" instance must have at least 2 parts.', __CLASS__)); + } + + $string = ''; + foreach ($parts as $part) { + $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n"; + } + $string .= '--'.$this->getBoundary()."--\r\n"; + + return $string; + } + + public function bodyToIterable(): iterable + { + $parts = $this->getParts(); + + if (\count($parts) < 2) { + throw new LogicException(sprintf('A "%s" instance must have at least 2 parts.', __CLASS__)); + } + + foreach ($parts as $part) { + yield '--'.$this->getBoundary()."\r\n"; + foreach ($part->toIterable() as $chunk) { + yield $chunk; + } + yield "\r\n"; + } + yield '--'.$this->getBoundary()."--\r\n"; + } + + private function getBoundary(): string + { + if (null === $this->boundary) { + $this->boundary = '_=_symfony_'.time().'_'.bin2hex(random_bytes(16)).'_=_'; + } + + return $this->boundary; + } +} diff --git a/src/Symfony/Component/Mime/Part/AbstractPart.php b/src/Symfony/Component/Mime/Part/AbstractPart.php new file mode 100644 index 0000000000000..8b50eaca4b297 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/AbstractPart.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +abstract class AbstractPart +{ + private $headers; + + public function __construct() + { + $this->headers = new Headers(); + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + + return $headers; + } + + public function toString(): string + { + return $this->getPreparedHeaders()->toString()."\r\n".$this->bodyToString(); + } + + public function toIterable(): iterable + { + yield $this->getPreparedHeaders()->toString(); + yield "\r\n"; + foreach ($this->bodyToIterable() as $chunk) { + yield $chunk; + } + } + + abstract public function bodyToString(): string; + + abstract public function bodyToIterable(): iterable; + + abstract public function getMediaType(): string; + + abstract public function getMediaSubtype(): string; +} diff --git a/src/Symfony/Component/Mime/Part/DataPart.php b/src/Symfony/Component/Mime/Part/DataPart.php new file mode 100644 index 0000000000000..ccbf12ebf4f18 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/DataPart.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\MimeTypes; + +/** + * @final + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class DataPart extends TextPart +{ + private static $mimeTypes; + + private $filename; + private $mediaType; + private $cid; + private $handle; + + /** + * @param resource|string $body + */ + public function __construct($body, string $filename = null, string $contentType = null, string $encoding = null) + { + if (null === $contentType) { + $contentType = 'application/octet-stream'; + } + list($this->mediaType, $subtype) = explode('/', $contentType); + + parent::__construct($body, null, $subtype, $encoding); + + $this->filename = $filename; + $this->setName($filename); + $this->setDisposition('attachment'); + } + + public static function fromPath(string $path, string $name = null, string $contentType = null): self + { + // FIXME: if file is not readable, exception? + + if (null === $contentType) { + $ext = strtolower(substr($path, strrpos($path, '.') + 1)); + if (null === self::$mimeTypes) { + self::$mimeTypes = new MimeTypes(); + } + $contentType = self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream'; + } + + if (false === $handle = @fopen($path, 'r', false)) { + throw new InvalidArgumentException(sprintf('Unable to open path "%s"', $path)); + } + $p = new self($handle, $name ?: basename($path), $contentType); + $p->handle = $handle; + + return $p; + } + + /** + * @return $this + */ + public function asInline() + { + return $this->setDisposition('inline'); + } + + public function getContentId(): string + { + return $this->cid ?: $this->cid = $this->generateContentId(); + } + + public function hasContentId(): bool + { + return null !== $this->cid; + } + + public function getMediaType(): string + { + return $this->mediaType; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + if (null !== $this->cid) { + $headers->setHeaderBody('Id', 'Content-ID', $this->cid); + } + + if (null !== $this->filename) { + $headers->setHeaderParameter('Content-Disposition', 'filename', $this->filename); + } + + return $headers; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + public function __destruct() + { + if (null !== $this->handle && \is_resource($this->handle)) { + fclose($this->handle); + } + } + + public function __sleep() + { + // converts the body to a string + parent::__sleep(); + + $this->_parent = []; + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setAccessible(true); + $this->_parent[$name] = $r->getValue($this); + } + $this->_headers = $this->getHeaders(); + + return ['_headers', '_parent', 'filename', 'mediaType']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setAccessible(true); + $r->setValue($this, $this->_parent[$name]); + } + unset($this->_parent); + } +} diff --git a/src/Symfony/Component/Mime/Part/MessagePart.php b/src/Symfony/Component/Mime/Part/MessagePart.php new file mode 100644 index 0000000000000..64a53404220d0 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/MessagePart.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @final + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MessagePart extends DataPart +{ + private $message; + + public function __construct(RawMessage $message) + { + if ($message instanceof Message) { + $name = $message->getHeaders()->getHeaderBody('Subject').'.eml'; + } else { + $name = 'email.eml'; + } + parent::__construct('', $name); + + $this->message = $message; + } + + public function getMediaType(): string + { + return 'message'; + } + + public function getMediaSubtype(): string + { + return 'rfc822'; + } + + public function getBody(): string + { + return $this->message->toString(); + } + + public function bodyToString(): string + { + return $this->getBody(); + } + + public function bodyToIterable(): iterable + { + return $this->message->toIterable(); + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/AlternativePart.php b/src/Symfony/Component/Mime/Part/Multipart/AlternativePart.php new file mode 100644 index 0000000000000..ad316a490a92a --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/AlternativePart.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class AlternativePart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'alternative'; + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/DigestPart.php b/src/Symfony/Component/Mime/Part/Multipart/DigestPart.php new file mode 100644 index 0000000000000..6199e5b8dba76 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/DigestPart.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\MessagePart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class DigestPart extends AbstractMultipartPart +{ + public function __construct(MessagePart ...$parts) + { + parent::__construct(...$parts); + } + + public function getMediaSubtype(): string + { + return 'digest'; + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php new file mode 100644 index 0000000000000..9f0635d588815 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * Implements RFC 7578. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class FormDataPart extends AbstractMultipartPart +{ + private $fields = []; + + /** + * @param (string|array|DataPart)[] $fields + */ + public function __construct(array $fields = []) + { + parent::__construct(); + + foreach ($fields as $name => $value) { + if (!\is_string($value) && !\is_array($value) && !$value instanceof TextPart) { + throw new InvalidArgumentException(sprintf('A form field value can only be a string, an array, or an instance of TextPart ("%s" given).', \is_object($value) ? \get_class($value) : \gettype($value))); + } + + $this->fields[$name] = $value; + } + // HTTP does not support \r\n in header values + $this->getHeaders()->setMaxLineLength(1000); + } + + public function getMediaSubtype(): string + { + return 'form-data'; + } + + public function getParts(): array + { + return $this->prepareFields($this->fields); + } + + private function prepareFields(array $fields): array + { + $values = []; + foreach ($fields as $name => $value) { + if (\is_array($value)) { + foreach ($value as $v) { + $values[] = $this->preparePart($name, $v); + } + } else { + $values[] = $this->preparePart($name, $value); + } + } + + return $values; + } + + private function preparePart($name, $value): TextPart + { + if (\is_string($value)) { + return $this->configurePart($name, new TextPart($value)); + } + + return $this->configurePart($name, $value); + } + + private function configurePart(string $name, TextPart $part): TextPart + { + $part->setDisposition('form-data'); + $part->setName($name); + // HTTP does not support \r\n in header values + $part->getHeaders()->setMaxLineLength(1000); + + return $part; + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/MixedPart.php b/src/Symfony/Component/Mime/Part/Multipart/MixedPart.php new file mode 100644 index 0000000000000..eaa869fbeea89 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/MixedPart.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class MixedPart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'mixed'; + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/RelatedPart.php b/src/Symfony/Component/Mime/Part/Multipart/RelatedPart.php new file mode 100644 index 0000000000000..2d5563073ce06 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/RelatedPart.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class RelatedPart extends AbstractMultipartPart +{ + private $mainPart; + + public function __construct(AbstractPart $mainPart, AbstractPart $part, AbstractPart ...$parts) + { + $this->mainPart = $mainPart; + $this->prepareParts($part, ...$parts); + + parent::__construct($part, ...$parts); + } + + public function getParts(): array + { + return array_merge([$this->mainPart], parent::getParts()); + } + + public function getMediaSubtype(): string + { + return 'related'; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + private function prepareParts(AbstractPart ...$parts): void + { + foreach ($parts as $part) { + if (!$part->getHeaders()->has('Content-ID')) { + $part->getHeaders()->setHeaderBody('Id', 'Content-ID', $this->generateContentId()); + } + } + } +} diff --git a/src/Symfony/Component/Mime/Part/TextPart.php b/src/Symfony/Component/Mime/Part/TextPart.php new file mode 100644 index 0000000000000..aed312c2408e9 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/TextPart.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Encoder\Base64ContentEncoder; +use Symfony\Component\Mime\Encoder\ContentEncoderInterface; +use Symfony\Component\Mime\Encoder\QpContentEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; + +/** + * @final + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class TextPart extends AbstractPart +{ + private static $encoders = []; + + private $body; + private $charset; + private $subtype; + private $disposition; + private $name; + + protected $encoding; + + /** + * @param resource|string $body + */ + public function __construct($body, ?string $charset = 'utf-8', $subtype = 'plain', string $encoding = null) + { + parent::__construct(); + + if (!\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body of "%s" must be a string or a resource (got "%s").', self::class, \is_object($body) ? \get_class($body) : \gettype($body))); + } + + $this->body = $body; + $this->charset = $charset; + $this->subtype = $subtype; + + // FIXME: can also be 7BIT, 8BIT, ... + if (null === $encoding) { + $this->encoding = $this->chooseEncoding(); + } else { + if ('quoted-printable' !== $encoding && 'base64' !== $encoding) { + throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable" or "base64" ("%s" given).', $encoding)); + } + $this->encoding = $encoding; + } + } + + public function getMediaType(): string + { + return 'text'; + } + + public function getMediaSubtype(): string + { + return $this->subtype; + } + + /** + * @param string $disposition one of attachment, inline, or form-data + * + * @return $this + */ + public function setDisposition(string $disposition) + { + $this->disposition = $disposition; + + return $this; + } + + /** + * Sets the name of the file (used by FormDataPart). + * + * @return $this + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + public function getBody(): string + { + if (!\is_resource($this->body)) { + return $this->body; + } + + if (stream_get_meta_data($this->body)['seekable'] ?? false) { + rewind($this->body); + } + + return stream_get_contents($this->body) ?: ''; + } + + public function bodyToString(): string + { + return $this->getEncoder()->encodeString($this->getBody(), $this->charset); + } + + public function bodyToIterable(): iterable + { + if (\is_resource($this->body)) { + if (stream_get_meta_data($this->body)['seekable'] ?? false) { + rewind($this->body); + } + foreach ($this->getEncoder()->encodeByteStream($this->body) as $chunk) { + yield $chunk; + } + } else { + yield $this->getEncoder()->encodeString($this->body); + } + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + if ($this->charset) { + $headers->setHeaderParameter('Content-Type', 'charset', $this->charset); + } + if ($this->name) { + $headers->setHeaderParameter('Content-Type', 'name', $this->name); + } + $headers->setHeaderBody('Text', 'Content-Transfer-Encoding', $this->encoding); + + if (!$headers->has('Content-Disposition') && null !== $this->disposition) { + $headers->setHeaderBody('Parameterized', 'Content-Disposition', $this->disposition); + if ($this->name) { + $headers->setHeaderParameter('Content-Disposition', 'name', $this->name); + } + } + + return $headers; + } + + protected function getEncoder(): ContentEncoderInterface + { + if ('quoted-printable' === $this->encoding) { + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new QpContentEncoder()); + } + + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new Base64ContentEncoder()); + } + + private function chooseEncoding(): string + { + if (null === $this->charset) { + return 'base64'; + } + + return 'quoted-printable'; + } + + public function __sleep() + { + // convert resources to strings for serialization + if (\is_resource($this->body)) { + $this->body = $this->getBody(); + } + + $this->_headers = $this->getHeaders(); + + return ['_headers', 'body', 'charset', 'subtype', 'disposition', 'name', 'encoding']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + } +} diff --git a/src/Symfony/Component/Mime/README.md b/src/Symfony/Component/Mime/README.md index deb93e1d0b98f..1433dc8141ae0 100644 --- a/src/Symfony/Component/Mime/README.md +++ b/src/Symfony/Component/Mime/README.md @@ -1,8 +1,11 @@ MIME Component ============== -The MIME component allows manipulating MIME types. +The MIME component allows manipulating MIME messages. +**This Component is experimental**. [Experimental +features](https://symfony.com/doc/current/contributing/code/experimental.html) +are not covered by Symfony's BC-break policy. Resources --------- diff --git a/src/Symfony/Component/Mime/RawMessage.php b/src/Symfony/Component/Mime/RawMessage.php new file mode 100644 index 0000000000000..a00bb094f9123 --- /dev/null +++ b/src/Symfony/Component/Mime/RawMessage.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class RawMessage +{ + private $message; + + /** + * @param iterable|string $message + */ + public function __construct($message) + { + $this->message = $message; + } + + public function toString(): string + { + if (\is_string($this->message)) { + return $this->message; + } + + return $this->message = implode('', iterator_to_array($this->message)); + } + + public function toIterable(): iterable + { + if (\is_string($this->message)) { + yield $this->message; + + return; + } + + $message = ''; + foreach ($this->message as $chunk) { + $message .= $chunk; + yield $chunk; + } + $this->message = $message; + } +} diff --git a/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php b/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php index 863c22c116060..f9f5ec5703b28 100644 --- a/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php +++ b/src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php @@ -18,7 +18,7 @@ abstract class AbstractMimeTypeGuesserTest extends TestCase { public static function tearDownAfterClass() { - $path = __DIR__.'/Fixtures/to_delete'; + $path = __DIR__.'/Fixtures/mimetypes/to_delete'; if (file_exists($path)) { @chmod($path, 0666); @unlink($path); @@ -33,7 +33,7 @@ public function testGuessImageWithoutExtension() $this->markTestSkipped('Guesser is not supported'); } - $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/test')); + $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/test')); } public function testGuessImageWithDirectory() @@ -43,7 +43,7 @@ public function testGuessImageWithDirectory() } $this->expectException('\InvalidArgumentException'); - $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/directory'); + $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/directory'); } public function testGuessImageWithKnownExtension() @@ -52,7 +52,7 @@ public function testGuessImageWithKnownExtension() $this->markTestSkipped('Guesser is not supported'); } - $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/test.gif')); + $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/test.gif')); } public function testGuessFileWithUnknownExtension() @@ -61,7 +61,7 @@ public function testGuessFileWithUnknownExtension() $this->markTestSkipped('Guesser is not supported'); } - $this->assertEquals('application/octet-stream', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/.unknownextension')); + $this->assertEquals('application/octet-stream', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/.unknownextension')); } public function testGuessWithIncorrectPath() @@ -71,7 +71,7 @@ public function testGuessWithIncorrectPath() } $this->expectException('\InvalidArgumentException'); - $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/not_here'); + $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/not_here'); } public function testGuessWithNonReadablePath() @@ -88,7 +88,7 @@ public function testGuessWithNonReadablePath() $this->markTestSkipped('This test will fail if run under superuser'); } - $path = __DIR__.'/Fixtures/to_delete'; + $path = __DIR__.'/Fixtures/mimetypes/to_delete'; touch($path); @chmod($path, 0333); diff --git a/src/Symfony/Component/Mime/Tests/AddressTest.php b/src/Symfony/Component/Mime/Tests/AddressTest.php new file mode 100644 index 0000000000000..dd7d3cebf67ca --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/AddressTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\NamedAddress; + +class AddressTest extends TestCase +{ + public function testConstructor() + { + $a = new Address('fabien@symfonï.com'); + $this->assertEquals('fabien@symfonï.com', $a->getAddress()); + $this->assertEquals('fabien@xn--symfon-nwa.com', $a->toString()); + $this->assertEquals('fabien@xn--symfon-nwa.com', $a->getEncodedAddress()); + } + + public function testConstructorWithInvalidAddress() + { + $this->expectException(\InvalidArgumentException::class); + new Address('fab pot@symfony.com'); + } + + public function testCreate() + { + $this->assertSame($a = new Address('fabien@symfony.com'), Address::create($a)); + $this->assertSame($b = new NamedAddress('helene@symfony.com', 'Helene'), Address::create($b)); + $this->assertEquals($a, Address::create('fabien@symfony.com')); + } + + public function testCreateWrongArg() + { + $this->expectException(\InvalidArgumentException::class); + Address::create(new \stdClass()); + } + + public function testCreateArray() + { + $fabien = new Address('fabien@symfony.com'); + $helene = new NamedAddress('helene@symfony.com', 'Helene'); + $this->assertSame([$fabien, $helene], Address::createArray([$fabien, $helene])); + + $this->assertEquals([$fabien], Address::createArray(['fabien@symfony.com'])); + } + + public function testCreateArrayWrongArg() + { + $this->expectException(\InvalidArgumentException::class); + Address::createArray([new \stdClass()]); + } +} diff --git a/src/Symfony/Component/Mime/Tests/CharacterStreamTest.php b/src/Symfony/Component/Mime/Tests/CharacterStreamTest.php new file mode 100644 index 0000000000000..62f4dc6fe8326 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/CharacterStreamTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\CharacterStream; + +class CharacterStreamTest extends TestCase +{ + public function testReadCharactersAreInTact() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + )); + $this->assertSame(pack('C*', 0xD0, 0x94), $stream->read(1)); + $this->assertSame(pack('C*', 0xD0, 0xB6, 0xD0, 0xBE), $stream->read(2)); + $this->assertSame(pack('C*', 0xD0, 0xBB), $stream->read(1)); + $this->assertSame(pack('C*', 0xD1, 0x8E, 0xD0, 0xB1, 0xD1, 0x8B), $stream->read(3)); + $this->assertSame(pack('C*', 0xD1, 0x85), $stream->read(1)); + $this->assertNull($stream->read(1)); + } + + public function testCharactersCanBeReadAsByteArrays() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + )); + $this->assertEquals([0xD0, 0x94], $stream->readBytes(1)); + $this->assertEquals([0xD0, 0xB6, 0xD0, 0xBE], $stream->readBytes(2)); + $this->assertEquals([0xD0, 0xBB], $stream->readBytes(1)); + $this->assertEquals([0xD1, 0x8E, 0xD0, 0xB1, 0xD1, 0x8B], $stream->readBytes(3)); + $this->assertEquals([0xD1, 0x85], $stream->readBytes(1)); + $this->assertNull($stream->readBytes(1)); + } + + public function testRequestingLargeCharCountPastEndOfStream() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $this->assertSame(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE), $stream->read(100)); + $this->assertNull($stream->read(1)); + } + + public function testRequestingByteArrayCountPastEndOfStream() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $this->assertEquals([0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE], $stream->readBytes(100)); + $this->assertNull($stream->readBytes(1)); + } + + public function testPointerOffsetCanBeSet() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $this->assertSame(pack('C*', 0xD0, 0x94), $stream->read(1)); + $stream->setPointer(0); + $this->assertSame(pack('C*', 0xD0, 0x94), $stream->read(1)); + $stream->setPointer(2); + $this->assertSame(pack('C*', 0xD0, 0xBE), $stream->read(1)); + } + + public function testAlgorithmWithFixedWidthCharsets() + { + $stream = new CharacterStream(pack('C*', 0xD1, 0x8D, 0xD0, 0xBB, 0xD0, 0xB0)); + $this->assertSame(pack('C*', 0xD1, 0x8D), $stream->read(1)); + $this->assertSame(pack('C*', 0xD0, 0xBB), $stream->read(1)); + $this->assertSame(pack('C*', 0xD0, 0xB0), $stream->read(1)); + $this->assertNull($stream->read(1)); + } +} diff --git a/src/Symfony/Component/Mime/Tests/EmailTest.php b/src/Symfony/Component/Mime/Tests/EmailTest.php new file mode 100644 index 0000000000000..1d45cab9f49ff --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/EmailTest.php @@ -0,0 +1,385 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\NamedAddress; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +class EmailTest extends TestCase +{ + public function testSubject() + { + $e = new Email(); + $e->subject('Subject'); + $this->assertEquals('Subject', $e->getSubject()); + } + + public function testDate() + { + $e = new Email(); + $e->date($d = new \DateTimeImmutable()); + $this->assertSame($d, $e->getDate()); + } + + public function testReturnPath() + { + $e = new Email(); + $e->returnPath('fabien@symfony.com'); + $this->assertEquals(new Address('fabien@symfony.com'), $e->getReturnPath()); + } + + public function testSender() + { + $e = new Email(); + $e->sender('fabien@symfony.com'); + $this->assertEquals(new Address('fabien@symfony.com'), $e->getSender()); + + $e->sender($fabien = new Address('fabien@symfony.com')); + $this->assertSame($fabien, $e->getSender()); + } + + public function testFrom() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->from('fabien@symfony.com', $helene, $thomas)); + $v = $e->getFrom(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addFrom('lucas@symfony.com', $caramel)); + $v = $e->getFrom(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addFrom('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getFrom()); + + $e = new Email(); + $e->from('lucas@symfony.com'); + $e->from($caramel); + $this->assertSame([$caramel], $e->getFrom()); + } + + public function testReplyTo() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->replyTo('fabien@symfony.com', $helene, $thomas)); + $v = $e->getReplyTo(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addReplyTo('lucas@symfony.com', $caramel)); + $v = $e->getReplyTo(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addReplyTo('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getReplyTo()); + + $e = new Email(); + $e->replyTo('lucas@symfony.com'); + $e->replyTo($caramel); + $this->assertSame([$caramel], $e->getReplyTo()); + } + + public function testTo() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->to('fabien@symfony.com', $helene, $thomas)); + $v = $e->getTo(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addTo('lucas@symfony.com', $caramel)); + $v = $e->getTo(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addTo('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getTo()); + + $e = new Email(); + $e->to('lucas@symfony.com'); + $e->to($caramel); + $this->assertSame([$caramel], $e->getTo()); + } + + public function testCc() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->cc('fabien@symfony.com', $helene, $thomas)); + $v = $e->getCc(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addCc('lucas@symfony.com', $caramel)); + $v = $e->getCc(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addCc('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getCc()); + + $e = new Email(); + $e->cc('lucas@symfony.com'); + $e->cc($caramel); + $this->assertSame([$caramel], $e->getCc()); + } + + public function testBcc() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->bcc('fabien@symfony.com', $helene, $thomas)); + $v = $e->getBcc(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addBcc('lucas@symfony.com', $caramel)); + $v = $e->getBcc(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addBcc('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getBcc()); + + $e = new Email(); + $e->bcc('lucas@symfony.com'); + $e->bcc($caramel); + $this->assertSame([$caramel], $e->getBcc()); + } + + public function testPriority() + { + $e = new Email(); + $this->assertEquals(3, $e->getPriority()); + + $e->priority(1); + $this->assertEquals(1, $e->getPriority()); + $e->priority(10); + $this->assertEquals(5, $e->getPriority()); + $e->priority(-10); + $this->assertEquals(1, $e->getPriority()); + } + + public function testGenerateBodyThrowsWhenEmptyBody() + { + $this->expectException(\LogicException::class); + (new Email())->getBody(); + } + + public function testGetBody() + { + $e = new Email(); + $e->setBody($text = new TextPart('text content')); + $this->assertEquals($text, $e->getBody()); + } + + public function testGenerateBody() + { + $text = new TextPart('text content'); + $html = new TextPart('html content', 'utf-8', 'html'); + $att = new DataPart($file = fopen(__DIR__.'/Fixtures/mimetypes/test', 'r')); + $img = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'), 'test.gif'); + + $e = new Email(); + $e->text('text content'); + $this->assertEquals($text, $e->getBody()); + $this->assertEquals('text content', $e->getTextBody()); + + $e = new Email(); + $e->html('html content'); + $this->assertEquals($html, $e->getBody()); + $this->assertEquals('html content', $e->getHtmlBody()); + + $e = new Email(); + $e->html('html content'); + $e->text('text content'); + $this->assertEquals(new AlternativePart($text, $html), $e->getBody()); + + $e = new Email(); + $e->html('html content', 'iso-8859-1'); + $e->text('text content', 'iso-8859-1'); + $this->assertEquals('iso-8859-1', $e->getTextCharset()); + $this->assertEquals('iso-8859-1', $e->getHtmlCharset()); + $this->assertEquals(new AlternativePart(new TextPart('text content', 'iso-8859-1'), new TextPart('html content', 'iso-8859-1', 'html')), $e->getBody()); + + $e = new Email(); + $e->attach($file); + $e->text('text content'); + $this->assertEquals(new MixedPart($text, $att), $e->getBody()); + + $e = new Email(); + $e->attach($file); + $e->html('html content'); + $this->assertEquals(new MixedPart($html, $att), $e->getBody()); + + $e = new Email(); + $e->html('html content'); + $e->text('text content'); + $e->attach($file); + $this->assertEquals(new MixedPart(new AlternativePart($text, $html), $att), $e->getBody()); + + $e = new Email(); + $e->html('html content'); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $this->assertEquals(new MixedPart(new AlternativePart($text, $html), $att, $img), $e->getBody()); + + $e = new Email(); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $this->assertEquals(new MixedPart($text, $att, $img), $e->getBody()); + + $e = new Email(); + $e->html($content = 'html content '); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $fullhtml = new TextPart($content, 'utf-8', 'html'); + $this->assertEquals(new MixedPart(new AlternativePart($text, $fullhtml), $att, $img), $e->getBody()); + + $e = new Email(); + $e->html($content = 'html content '); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $fullhtml = new TextPart($content, 'utf-8', 'html'); + $inlinedimg = (new DataPart($image, 'test.gif'))->asInline(); + $body = $e->getBody(); + $this->assertInstanceOf(MixedPart::class, $body); + $this->assertCount(2, $related = $body->getParts()); + $this->assertInstanceOf(RelatedPart::class, $related[0]); + $this->assertEquals($att, $related[1]); + $this->assertCount(2, $parts = $related[0]->getParts()); + $this->assertInstanceOf(AlternativePart::class, $parts[0]); + $generatedHtml = $parts[0]->getParts()[1]; + $this->assertContains('cid:'.$parts[1]->getContentId(), $generatedHtml->getBody()); + + $content = 'html content '; + $r = fopen('php://memory', 'r+', false); + fwrite($r, $content); + rewind($r); + + $e = new Email(); + $e->html($r); + // embedding the same image twice results in one image only in the email + $e->embed($image, 'test.gif'); + $e->embed($image, 'test.gif'); + $body = $e->getBody(); + $this->assertInstanceOf(RelatedPart::class, $body); + // 2 parts only, not 3 (text + embedded image once) + $this->assertCount(2, $parts = $body->getParts()); + $this->assertStringMatchesFormat('html content ', $parts[0]->bodyToString()); + } + + public function testAttachments() + { + $contents = file_get_contents($name = __DIR__.'/Fixtures/mimetypes/test', 'r'); + $att = new DataPart($file = fopen($name, 'r'), 'test'); + $inline = (new DataPart($contents, 'test'))->asInline(); + $e = new Email(); + $e->attach($file, 'test'); + $e->embed($contents, 'test'); + $this->assertEquals([$att, $inline], $e->getAttachments()); + + $att = DataPart::fromPath($name, 'test'); + $inline = DataPart::fromPath($name, 'test')->asInline(); + $e = new Email(); + $e->attachFromPath($name); + $e->embedFromPath($name); + $this->assertEquals([$att->bodyToString(), $inline->bodyToString()], array_map(function (DataPart $a) { return $a->bodyToString(); }, $e->getAttachments())); + $this->assertEquals([$att->getPreparedHeaders(), $inline->getPreparedHeaders()], array_map(function (DataPart $a) { return $a->getPreparedHeaders(); }, $e->getAttachments())); + } + + public function testSerialize() + { + $r = fopen('php://memory', 'r+', false); + fwrite($r, 'Text content'); + rewind($r); + + $e = new Email(); + $e->from('fabien@symfony.com'); + $e->text($r); + $e->html($r); + $contents = file_get_contents($name = __DIR__.'/Fixtures/mimetypes/test', 'r'); + $file = fopen($name, 'r'); + $e->attach($file, 'test'); + $expected = clone $e; + $n = unserialize(serialize($e)); + $this->assertEquals($expected->getHeaders(), $n->getHeaders()); + $this->assertEquals($e->getBody(), $n->getBody()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Encoder/Base64EncoderTest.php b/src/Symfony/Component/Mime/Tests/Encoder/Base64EncoderTest.php new file mode 100644 index 0000000000000..a90fbb70fcbdb --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Encoder/Base64EncoderTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\Base64Encoder; + +class Base64EncoderTest extends TestCase +{ + /* + There's really no point in testing the entire base64 encoding to the + level QP encoding has been tested. base64_encode() has been in PHP for + years. + */ + + public function testInputOutputRatioIs3to4Bytes() + { + /* + RFC 2045, 6.8 + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + */ + + $encoder = new Base64Encoder(); + $this->assertEquals('MTIz', $encoder->encodeString('123'), '3 bytes of input should yield 4 bytes of output'); + $this->assertEquals('MTIzNDU2', $encoder->encodeString('123456'), '6 bytes in input should yield 8 bytes of output'); + $this->assertEquals('MTIzNDU2Nzg5', $encoder->encodeString('123456789'), '%s: 9 bytes in input should yield 12 bytes of output'); + } + + public function testPadLength() + { + /* + RFC 2045, 6.8 + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a body. When fewer than 24 input bits + are available in an input group, zero bits are added (on the right) + to form an integral number of 6-bit groups. Padding at the end of + the data is performed using the "=" character. Since all base64 + input is an integral number of octets, only the following cases can + arise: (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded output will be + an integral multiple of 4 characters with no "=" padding, (2) the + final quantum of encoding input is exactly 8 bits; here, the final + unit of encoded output will be two characters followed by two "=" + padding characters, or (3) the final quantum of encoding input is + exactly 16 bits; here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + + $encoder = new Base64Encoder(); + for ($i = 0; $i < 30; ++$i) { + $input = pack('C', random_int(0, 255)); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{2}==$~', $encoder->encodeString($input), 'A single byte should have 2 bytes of padding'); + } + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C*', random_int(0, 255), random_int(0, 255)); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{3}=$~', $encoder->encodeString($input), 'Two bytes should have 1 byte of padding'); + } + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C*', random_int(0, 255), random_int(0, 255), random_int(0, 255)); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{4}$~', $encoder->encodeString($input), 'Three bytes should have no padding'); + } + } + + public function testMaximumLineLengthIs76Characters() + { + /* + The encoded output stream must be represented in lines of no more + than 76 characters each. All line breaks or other characters not + found in Table 1 must be ignored by decoding software. + */ + + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0xNTk9QUVJTVFVWV1hZWjEyMzQ1'."\r\n".//76 * + 'Njc4OTBhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3'.//38 + 'h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla'."\r\n".//76 * + 'MTIzNDU2Nzg5MEFCQ0RFRkdISUpLTE1OT1BRUl'.//38 + 'NUVVZXWFla'; //48 + + $encoder = new Base64Encoder(); + $this->assertEquals($output, $encoder->encodeString($input), 'Lines should be no more than 76 characters'); + } + + public function testMaximumLineLengthCanBeSpecified() + { + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0'."\r\n".//50 * + 'xNTk9QUVJTVFVWV1hZWjEyMzQ1Njc4OTBhYmNk'.//38 + 'ZWZnaGlqa2xt'."\r\n".//50 * + 'bm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1'.//38 + 'BRUlNUVVZXWF'."\r\n".//50 * + 'laMTIzNDU2Nzg5MEFCQ0RFRkdISUpLTE1OT1BR'.//38 + 'UlNUVVZXWFla'; //50 * + + $encoder = new Base64Encoder(); + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 0, 50), 'Lines should be no more than 100 characters'); + } + + public function testFirstLineLengthCanBeDifferent() + { + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0xNTk9QU'."\r\n".//57 * + 'VJTVFVWV1hZWjEyMzQ1Njc4OTBhYmNkZWZnaGl'.//38 + 'qa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLT'."\r\n".//76 * + 'E1OT1BRUlNUVVZXWFlaMTIzNDU2Nzg5MEFCQ0R'.//38 + 'FRkdISUpLTE1OT1BRUlNUVVZXWFla'; //67 + + $encoder = new Base64Encoder(); + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 19), 'First line offset is 19 so first line should be 57 chars long'); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php b/src/Symfony/Component/Mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php new file mode 100644 index 0000000000000..34bfe0d47c960 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\Base64MimeHeaderEncoder; + +class Base64MimeHeaderEncoderTest extends TestCase +{ + public function testNameIsB() + { + $this->assertEquals('B', (new Base64MimeHeaderEncoder())->getName()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Encoder/QpEncoderTest.php b/src/Symfony/Component/Mime/Tests/Encoder/QpEncoderTest.php new file mode 100644 index 0000000000000..bf08b2f095573 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Encoder/QpEncoderTest.php @@ -0,0 +1,213 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\QpEncoder; + +class QpEncoderTest extends TestCase +{ + /* -- RFC 2045, 6.7 -- + (1) (General 8bit representation) Any octet, except a CR or + LF that is part of a CRLF line break of the canonical + (standard) form of the data being encoded, may be + represented by an "=" followed by a two digit + hexadecimal representation of the octet's value. The + digits of the hexadecimal alphabet, for this purpose, + are "0123456789ABCDEF". Uppercase letters must be + used; lowercase letters are not allowed. Thus, for + example, the decimal value 12 (US-ASCII form feed) can + be represented by "=0C", and the decimal value 61 (US- + ASCII EQUAL SIGN) can be represented by "=3D". This + rule must be followed except when the following rules + allow an alternative encoding. + */ + + public function testPermittedCharactersAreNotEncoded() + { + /* -- RFC 2045, 6.7 -- + (2) (Literal representation) Octets with decimal values of + 33 through 60 inclusive, and 62 through 126, inclusive, + MAY be represented as the US-ASCII characters which + correspond to those octets (EXCLAMATION POINT through + LESS THAN, and GREATER THAN through TILDE, + respectively). + */ + + $encoder = new QpEncoder(); + foreach (array_merge(range(33, 60), range(62, 126)) as $ordinal) { + $char = \chr($ordinal); + $this->assertSame($char, $encoder->encodeString($char)); + } + } + + public function testWhiteSpaceAtLineEndingIsEncoded() + { + /* -- RFC 2045, 6.7 -- + (3) (White Space) Octets with values of 9 and 32 MAY be + represented as US-ASCII TAB (HT) and SPACE characters, + respectively, but MUST NOT be so represented at the end + of an encoded line. Any TAB (HT) or SPACE characters + on an encoded line MUST thus be followed on that line + by a printable character. In particular, an "=" at the + end of an encoded line, indicating a soft line break + (see rule #5) may follow one or more TAB (HT) or SPACE + characters. It follows that an octet with decimal + value 9 or 32 appearing at the end of an encoded line + must be represented according to Rule #1. This rule is + necessary because some MTAs (Message Transport Agents, + programs which transport messages from one user to + another, or perform a portion of such transfers) are + known to pad lines of text with SPACEs, and others are + known to remove "white space" characters from the end + of a line. Therefore, when decoding a Quoted-Printable + body, any trailing white space on a line must be + deleted, as it will necessarily have been added by + intermediate transport agents. + */ + + $encoder = new QpEncoder(); + + $HT = \chr(0x09); // 9 + $SPACE = \chr(0x20); // 32 + + // HT + $string = 'a'.$HT.$HT."\r\n".'b'; + $this->assertEquals('a'.$HT.'=09'."\r\n".'b', $encoder->encodeString($string)); + + // SPACE + $string = 'a'.$SPACE.$SPACE."\r\n".'b'; + $this->assertEquals('a'.$SPACE.'=20'."\r\n".'b', $encoder->encodeString($string)); + } + + public function testCRLFIsLeftAlone() + { + /* + (4) (Line Breaks) A line break in a text body, represented + as a CRLF sequence in the text canonical form, must be + represented by a (RFC 822) line break, which is also a + CRLF sequence, in the Quoted-Printable encoding. Since + the canonical representation of media types other than + text do not generally include the representation of + line breaks as CRLF sequences, no hard line breaks + (i.e. line breaks that are intended to be meaningful + and to be displayed to the user) can occur in the + quoted-printable encoding of such types. Sequences + like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely + appear in non-text data represented in quoted- + printable, of course. + + Note that many implementations may elect to encode the + local representation of various content types directly + rather than converting to canonical form first, + encoding, and then converting back to local + representation. In particular, this may apply to plain + text material on systems that use newline conventions + other than a CRLF terminator sequence. Such an + implementation optimization is permissible, but only + when the combined canonicalization-encoding step is + equivalent to performing the three steps separately. + */ + + $encoder = new QpEncoder(); + $string = 'a'."\r\n".'b'."\r\n".'c'."\r\n"; + $this->assertEquals($string, $encoder->encodeString($string)); + } + + public function testLinesLongerThan76CharactersAreSoftBroken() + { + /* + (5) (Soft Line Breaks) The Quoted-Printable encoding + REQUIRES that encoded lines be no more than 76 + characters long. If longer lines are to be encoded + with the Quoted-Printable encoding, "soft" line breaks + must be used. An equal sign as the last character on a + encoded line indicates such a non-significant ("soft") + line break in the encoded text. + */ + + $encoder = new QpEncoder(); + $input = str_repeat('a', 140); + $output = ''; + for ($i = 0; $i < 140; ++$i) { + // we read 4 chars at a time (max is 75) + if (18 * 4 /* 72 */ == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $this->assertEquals($output, $encoder->encodeString($input)); + } + + public function testMaxLineLengthCanBeSpecified() + { + $encoder = new QpEncoder(); + $input = str_repeat('a', 100); + $output = ''; + for ($i = 0; $i < 100; ++$i) { + // we read 4 chars at a time (max is 53) + if (13 * 4 /* 52 */ == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 0, 54)); + } + + public function testBytesBelowPermittedRangeAreEncoded() + { + // According to Rule (1 & 2) + $encoder = new QpEncoder(); + foreach (range(0, 32) as $ordinal) { + $char = \chr($ordinal); + $this->assertEquals(sprintf('=%02X', $ordinal), $encoder->encodeString($char)); + } + } + + public function testDecimalByte61IsEncoded() + { + // According to Rule (1 & 2) + $encoder = new QpEncoder(); + $this->assertEquals('=3D', $encoder->encodeString('=')); + } + + public function testBytesAbovePermittedRangeAreEncoded() + { + // According to Rule (1 & 2) + $encoder = new QpEncoder(); + foreach (range(127, 255) as $ordinal) { + $this->assertSame(sprintf('=%02X', $ordinal), $encoder->encodeString(\chr($ordinal), 'iso-8859-1')); + } + } + + public function testFirstLineLengthCanBeDifferent() + { + $encoder = new QpEncoder(); + $input = str_repeat('a', 140); + $output = ''; + for ($i = 0; $i < 140; ++$i) { + // we read 4 chars at a time (max is 54 for the first line and 75 for the second one) + if (13 * 4 == $i || 13 * 4 + 18 * 4 == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 22), 'First line should start at offset 22 so can only have max length 54'); + } + + public function testTextIsPreWrapped() + { + $encoder = new QpEncoder(); + $input = str_repeat('a', 70)."\r\n".str_repeat('a', 70)."\r\n".str_repeat('a', 70); + $this->assertEquals($input, $encoder->encodeString($input)); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Encoder/QpMimeHeaderEncoderTest.php b/src/Symfony/Component/Mime/Tests/Encoder/QpMimeHeaderEncoderTest.php new file mode 100644 index 0000000000000..f075452cbb1d4 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Encoder/QpMimeHeaderEncoderTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; + +class QpMimeHeaderEncoderTest extends TestCase +{ + public function testNameIsQ() + { + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('Q', $encoder->getName()); + } + + public function testSpaceAndTabNeverAppear() + { + /* -- RFC 2047, 4. + Only a subset of the printable ASCII characters may be used in + 'encoded-text'. Space and tab characters are not allowed, so that + the beginning and end of an 'encoded-word' are obvious. + */ + + $encoder = new QpMimeHeaderEncoder(); + $this->assertNotRegExp('~[ \t]~', $encoder->encodeString("a \t b"), 'encoded-words in headers cannot contain LWSP as per RFC 2047.'); + } + + public function testSpaceIsRepresentedByUnderscore() + { + /* -- RFC 2047, 4.2. + (2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be + represented as "_" (underscore, ASCII 95.). (This character may + not pass through some internetwork mail gateways, but its use + will greatly enhance readability of "Q" encoded data with mail + readers that do not support this encoding.) Note that the "_" + always represents hexadecimal 20, even if the SPACE character + occupies a different code position in the character set in use. + */ + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('a_b', $encoder->encodeString('a b'), 'Spaces can be represented by more readable underscores as per RFC 2047.'); + } + + public function testEqualsAndQuestionAndUnderscoreAreEncoded() + { + /* -- RFC 2047, 4.2. + (3) 8-bit values which correspond to printable ASCII characters other + than "=", "?", and "_" (underscore), MAY be represented as those + characters. (But see section 5 for restrictions.) In + particular, SPACE and TAB MUST NOT be represented as themselves + within encoded words. + */ + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('=3D=3F=5F', $encoder->encodeString('=?_'), 'Chars =, ? and _ (underscore) may not appear as per RFC 2047.'); + } + + public function testParensAndQuotesAreEncoded() + { + /* -- RFC 2047, 5 (2). + A "Q"-encoded 'encoded-word' which appears in a 'comment' MUST NOT + contain the characters "(", ")" or " + */ + + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('=28=22=29', $encoder->encodeString('(")'), 'Chars (, " (DQUOTE) and ) may not appear as per RFC 2047.'); + } + + public function testOnlyCharactersAllowedInPhrasesAreUsed() + { + /* -- RFC 2047, 5. + (3) As a replacement for a 'word' entity within a 'phrase', for example, + one that precedes an address in a From, To, or Cc header. The ABNF + definition for 'phrase' from RFC 822 thus becomes: + + phrase = 1*( encoded-word / word ) + + In this case the set of characters that may be used in a "Q"-encoded + 'encoded-word' is restricted to: . An 'encoded-word' that appears within a + 'phrase' MUST be separated from any adjacent 'word', 'text' or + 'special' by 'linear-white-space'. + */ + + $allowedBytes = array_merge( + range(\ord('a'), \ord('z')), range(\ord('A'), \ord('Z')), + range(\ord('0'), \ord('9')), + [\ord('!'), \ord('*'), \ord('+'), \ord('-'), \ord('/')] + ); + $encoder = new QpMimeHeaderEncoder(); + foreach (range(0x00, 0xFF) as $byte) { + $char = pack('C', $byte); + $encodedChar = $encoder->encodeString($char, 'iso-8859-1'); + if (\in_array($byte, $allowedBytes)) { + $this->assertEquals($char, $encodedChar, 'Character '.$char.' should not be encoded.'); + } elseif (0x20 == $byte) { + // special case + $this->assertEquals('_', $encodedChar, 'Space character should be replaced.'); + } else { + $this->assertEquals(sprintf('=%02X', $byte), $encodedChar, 'Byte '.$byte.' should be encoded.'); + } + } + } + + public function testEqualsNeverAppearsAtEndOfLine() + { + /* -- RFC 2047, 5 (3). + The 'encoded-text' in an 'encoded-word' must be self-contained; + 'encoded-text' MUST NOT be continued from one 'encoded-word' to + another. This implies that the 'encoded-text' portion of a "B" + 'encoded-word' will be a multiple of 4 characters long; for a "Q" + 'encoded-word', any "=" character that appears in the 'encoded-text' + portion will be followed by two hexadecimal characters. + */ + + $input = str_repeat('a', 140); + + $output = ''; + $seq = 0; + for (; $seq < 140; ++$seq) { + // compute the end of line (multiple of 4 chars) + if (18 * 4 === $seq) { + $output .= "\r\n"; // =\r\n + } + $output .= 'a'; + } + + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals($output, $encoder->encodeString($input)); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Encoder/Rfc2231EncoderTest.php b/src/Symfony/Component/Mime/Tests/Encoder/Rfc2231EncoderTest.php new file mode 100644 index 0000000000000..edcb15fcec371 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Encoder/Rfc2231EncoderTest.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\Rfc2231Encoder; + +class Rfc2231EncoderTest extends TestCase +{ + private $rfc2045Token = '/^[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+$/D'; + + /* -- + This algorithm is described in RFC 2231, but is barely touched upon except + for mentioning bytes can be represented as their octet values (e.g. %20 for + the SPACE character). + + The tests here focus on how to use that representation to always generate text + which matches RFC 2045's definition of "token". + */ + + public function testEncodingAsciiCharactersProducesValidToken() + { + $string = ''; + foreach (range(0x00, 0x7F) as $octet) { + $char = pack('C', $octet); + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string); + + foreach (explode("\r\n", $encoded) as $line) { + $this->assertRegExp($this->rfc2045Token, $line, 'Encoder should always return a valid RFC 2045 token.'); + } + } + + public function testEncodingNonAsciiCharactersProducesValidToken() + { + $string = ''; + foreach (range(0x80, 0xFF) as $octet) { + $char = pack('C', $octet); + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string); + + foreach (explode("\r\n", $encoded) as $line) { + $this->assertRegExp($this->rfc2045Token, $line, 'Encoder should always return a valid RFC 2045 token.'); + } + } + + public function testMaximumLineLengthCanBeSet() + { + $string = ''; + for ($x = 0; $x < 200; ++$x) { + $char = 'a'; + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string, 'utf-8', 0, 75); + + // 72 here and not 75 as we read 4 chars at a time + $this->assertEquals( + str_repeat('a', 72)."\r\n". + str_repeat('a', 72)."\r\n". + str_repeat('a', 56), + $encoded, + 'Lines should be wrapped at each 72 characters' + ); + } + + public function testFirstLineCanHaveShorterLength() + { + $string = ''; + for ($x = 0; $x < 200; ++$x) { + $char = 'a'; + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string, 'utf-8', 24, 72); + + $this->assertEquals( + str_repeat('a', 48)."\r\n". + str_repeat('a', 72)."\r\n". + str_repeat('a', 72)."\r\n". + str_repeat('a', 8), + $encoded, + 'First line should be 24 bytes shorter than the others.' + ); + } + + public function testEncodingAndDecodingSamples() + { + $dir = realpath(__DIR__.'/../Fixtures/samples/charsets'); + $sampleFp = opendir($dir); + while (false !== $encoding = readdir($sampleFp)) { + if ('.' == substr($encoding, 0, 1)) { + continue; + } + + $encoder = new Rfc2231Encoder(); + if (is_dir($dir.'/'.$encoding)) { + $fileFp = opendir($dir.'/'.$encoding); + while (false !== $sampleFile = readdir($fileFp)) { + if ('.' == substr($sampleFile, 0, 1)) { + continue; + } + + $text = file_get_contents($dir.'/'.$encoding.'/'.$sampleFile); + $encodedText = $encoder->encodeString($text, $encoding); + $this->assertEquals( + urldecode(implode('', explode("\r\n", $encodedText))), $text, + 'Encoded string should decode back to original string for sample '.$dir.'/'.$encoding.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/.unknownextension b/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/.unknownextension similarity index 100% rename from src/Symfony/Component/Mime/Tests/Fixtures/.unknownextension rename to src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/.unknownextension diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/directory/.empty b/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/directory/.empty similarity index 100% rename from src/Symfony/Component/Mime/Tests/Fixtures/directory/.empty rename to src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/directory/.empty diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/other-file.example b/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/other-file.example similarity index 100% rename from src/Symfony/Component/Mime/Tests/Fixtures/other-file.example rename to src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/other-file.example diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/test b/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/test similarity index 100% rename from src/Symfony/Component/Mime/Tests/Fixtures/test rename to src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/test diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/test.gif b/src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/test.gif similarity index 100% rename from src/Symfony/Component/Mime/Tests/Fixtures/test.gif rename to src/Symfony/Component/Mime/Tests/Fixtures/mimetypes/test.gif diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt new file mode 100644 index 0000000000000..c2923deb983a0 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt @@ -0,0 +1,11 @@ +ISO-2022-JPは、インターネット上(特に電子メール)などで使われる日本の文字用の文字符号化方式。ISO/IEC 2022のエスケープシーケンスを利用して文字集合を切り替える7ビットのコードであることを特徴とする (アナウンス機能のエスケープシーケンスは省略される)。俗に「JISコード」と呼ばれることもある。 + +概要 +日本語表記への利用が想定されている文字コードであり、日本語の利用されるネットワークにおいて、日本の規格を応用したものである。また文字集合としては、日本語で用いられる漢字、ひらがな、カタカナはもちろん、ラテン文字、ギリシア文字、キリル文字なども含んでおり、学術や産業の分野での利用も考慮たものとなっている。規格名に、ISOの日本語の言語コードであるjaではなく、国・地域名コードのJPが示されているゆえんである。 +文字集合としてJIS X 0201のC0集合(制御文字)、JIS X 0201のラテン文字集合、ISO 646の国際基準版図形文字、JIS X 0208の1978年版(JIS C 6226-1978)と1983年および1990年版が利用できる。JIS X 0201の片仮名文字集合は利用できない。1986年以降、日本の電子メールで用いられてきたJUNETコードを、村井純・Mark Crispin・Erik van der Poelが1993年にRFC化したもの(RFC 1468)。後にJIS X 0208:1997の附属書2としてJISに規定された。MIMEにおける文字符号化方式の識別用の名前として IANA に登録されている。 +なお、符号化の仕様についてはISO/IEC 2022#ISO-2022-JPも参照。 + +ISO-2022-JPと非標準的拡張使用 +「JISコード」(または「ISO-2022-JP」)というコード名の規定下では、その仕様通りの使用が求められる。しかし、Windows OS上では、実際にはCP932コード (MicrosoftによるShift JISを拡張した亜種。ISO-2022-JP規定外文字が追加されている。)による独自拡張(の文字)を断りなく使うアプリケーションが多い。この例としてInternet ExplorerやOutlook Expressがある。また、EmEditor、秀丸エディタやThunderbirdのようなMicrosoft社以外のWindowsアプリケーションでも同様の場合がある。この場合、ISO-2022-JPの範囲外の文字を使ってしまうと、異なる製品間では未定義不明文字として認識されるか、もしくは文字化けを起こす原因となる。そのため、Windows用の電子メールクライアントであっても独自拡張の文字を使用すると警告を出したり、あえて使えないように制限しているものも存在する。さらにはISO-2022-JPの範囲内であってもCP932は非標準文字(FULLWIDTH TILDE等)を持つので文字化けの原因になり得る。 +また、符号化方式名をISO-2022-JPとしているのに、文字集合としてはJIS X 0212 (いわゆる補助漢字) やJIS X 0201の片仮名文字集合 (いわゆる半角カナ) をも符号化している例があるが、ISO-2022-JPではこれらの文字を許容していない。これらの符号化は独自拡張の実装であり、中にはISO/IEC 2022の仕様に準拠すらしていないものもある[2]。従って受信側の電子メールクライアントがこれらの独自拡張に対応していない場合、その文字あるいはその文字を含む行、時にはテキスト全体が文字化けすることがある。 + diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt new file mode 100644 index 0000000000000..3101178af2d73 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt @@ -0,0 +1,19 @@ +Op mat eraus hinnen beschte, rou zënne schaddreg ké. Ké sin Eisen Kaffi prächteg, den haut esou Fielse wa, Well zielen d'Welt am dir. Aus grousse rëschten d'Stroos do, as dat Kléder gewëss d'Kàchen. Schied gehéiert d'Vioule net hu, rou ke zënter Säiten d'Hierz. Ze eise Fletschen mat, gei as gréng d'Lëtzebuerger. Wäit räich no mat. + +Säiten d'Liewen aus en. Un gëtt bléit lossen wee, da wéi alle weisen Kolrettchen. Et deser d'Pan d'Kirmes vun, en wuel Benn rëschten méi. En get drem ménger beschte, da wär Stad welle. Nun Dach d'Pied do, mä gét ruffen gehéiert. Ze onser ugedon fir, d'Liewen Plett'len ech no, si Räis wielen bereet wat. Iwer spilt fir jo. + +An hin däischter Margréitchen, eng ke Frot brommt, vu den Räis néierens. Da hir Hunn Frot nozegon, rout Fläiß Himmel zum si, net gutt Kaffi Gesträich fu. Vill lait Gaart sou wa, Land Mamm Schuebersonndeg rei do. Gei geet Minutt en, gei d'Leit beschte Kolrettchen et, Mamm fergiess un hun. + +Et gutt Heck kommen oft, Lann rëscht rei um, Hunn rëscht schéinste ke der. En lait zielen schnéiwäiss hir, fu rou botze éiweg Minutt, rem fest gudden schaddreg en. Noper bereet Margréitchen mat op, dem denkt d'Leit d'Vioule no, oft ké Himmel Hämmel. En denkt blénken Fréijor net, Gart Schiet d'Natur no wou. No hin Ierd Frot d'Kirmes. Hire aremt un rou, ké den éiweg wielen Milliounen. + +Mir si Hunn Blénkeg. Ké get ston derfir d'Kàchen. Haut d'Pan fu ons, dé frou löschteg d'Meereische rei. Sou op wuel Léift. Stret schlon grousse gin hu. Mä denkt d'Leit hinnen net, ké gét haut fort rëscht. + +Koum d'Pan hannendrun ass ké, ké den brét Kaffi geplot. Schéi Hären d'Pied fu gét, do d'Mier néierens bei. Rëm päift Hämmel am, wee Engel beschéngt mä. Brommt klinzecht der ke, wa rout jeitzt dén. Get Zalot d'Vioule däischter da, jo fir Bänk päift duerch, bei d'Beem schéinen Plett'len jo. Den haut Faarwen ze, eng en Biereg Kirmesdag, um sin alles Faarwen d'Vioule. + +Eng Hunn Schied et, wat wa Frot fest gebotzt. Bei jo bleiwe ruffen Klarinett. Un Feld klinzecht gét, rifft Margréitchen rem ke. Mir dé Noper duurch gewëss, ston sech kille sin en. Gei Stret d'Wise um, Haus Gart wee as. Monn ménger an blo, wat da Gart gefällt Hämmelsbrot. + +Brommt geplot och ze, dat wa Räis Well Kaffi. Do get spilt prächteg, as wär kille bleiwe gewalteg. Onser frësch Margréitchen rem ke, blo en huet ugedon. Onser Hemecht wär de, hu eraus d'Sonn dat, eise deser hannendrun da och. + +As durch Himmel hun, no fest iw'rem schéinste mir, Hunn séngt Hierz ke zum. Séngt iw'rem d'Natur zum an. Ke wär gutt Grénge. Kënnt gudden prächteg mä rei. Dé dir Blénkeg Klarinett Kolrettchen, da fort muerges d'Kanner wou, main Feld ruffen vu wéi. Da gin esou Zalot gewalteg, gét vill Hemecht blénken dé. + +Haut gréng nun et, nei vu Bass gréng d'Gaassen. Fest d'Beem uechter si gin. Oft vu sinn wellen kréien. Et ass lait Zalot schéinen. \ No newline at end of file diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/one.txt b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/one.txt new file mode 100644 index 0000000000000..26c94d5d231cb --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/one.txt @@ -0,0 +1,22 @@ +Код одно гринспана руководишь на. Его вы знания движение. Ты две начать +одиночку, сказать основатель удовольствием но миф. Бы какие система тем. +Полностью использует три мы, человек клоунов те нас, бы давать творческую +эзотерическая шеф. + +Мог не помнить никакого сэкономленного, две либо какие пишите бы. Должен +компанию кто те, этот заключалась проектировщик не ты. Глупые периоды ты +для. Вам который хороший он. Те любых кремния концентрируются мог, +собирать принадлежите без вы. + +Джоэла меньше хорошего вы миф, за тем году разработки. Даже управляющим +руководители был не. Три коде выпускать заботиться ну. То его система +удовольствием безостановочно, или ты главной процессорах. Мы без джоэл +знания получат, статьи остальные мы ещё. + +Них русском касается поскольку по, образование должником +систематизированный ну мои. Прийти кандидата университет но нас, для бы +должны никакого, биг многие причин интервьюирования за. + +Тем до плиту почему. Вот учёт такие одного бы, об биг разным внешних +промежуток. Вас до какому возможностей безответственный, были погодите бы +его, по них глупые долгий количества. diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/three.txt b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/three.txt new file mode 100644 index 0000000000000..c81ccd598b607 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/three.txt @@ -0,0 +1,45 @@ +Αν ήδη διάβασε γλιτώσει μεταγλωτίσει, αυτήν θυμάμαι μου μα. Την κατάσταση χρησιμοποίησέ να! Τα διαφορά φαινόμενο διολισθήσεις πες, υψηλότερη προκαλείς περισσότερες όχι κι. Με ελέγχου γίνεται σας, μικρής δημιουργούν τη του. Τις τα γράψει εικόνες απαράδεκτη? + +Να ότι πρώτοι απαραίτητο. Άμεση πετάνε κακόκεφος τον ώς, να χώρου πιθανότητες του. Το μέχρι ορίστε λιγότερους σας. Πω ναί φυσικά εικόνες. + +Μου οι κώδικα αποκλειστικούς, λες το μάλλον συνεχώς. Νέου σημεία απίστευτα σας μα. Χρόνου μεταγλωτιστής σε νέα, τη τις πιάνει μπορούσες προγραμματιστές. Των κάνε βγαίνει εντυπωσιακό τα? Κρατάει τεσσαρών δυστυχώς της κι, ήδη υψηλότερη εξακολουθεί τα? + +Ώρα πετάνε μπορούσε λιγότερους αν, τα απαράδεκτη συγχωνευτεί ροή. Τη έγραψες συνηθίζουν σαν. Όλα με υλικό στήλες χειρότερα. Ανώδυνη δουλέψει επί ως, αν διαδίκτυο εσωτερικών παράγοντες από. Κεντρικό επιτυχία πες το. + +Πω ναι λέει τελειώσει, έξι ως έργων τελειώσει. Με αρχεία βουτήξουν ανταγωνιστής ώρα, πολύ γραφικά σελίδων τα στη. Όρο οέλεγχος δημιουργούν δε, ας θέλεις ελέγχου συντακτικό όρο! Της θυμάμαι επιδιόρθωση τα. Για μπορούσε περισσότερο αν, μέγιστη σημαίνει αποφάσισε τα του, άτομο αποτελέσει τι στα. + +Τι στην αφήσεις διοίκηση στη. Τα εσφαλμένη δημιουργια επιχείριση έξι! Βήμα μαγικά εκτελέσει ανά τη. Όλη αφήσεις συνεχώς εμπορικά αν, το λες κόλπα επιτυχία. Ότι οι ζώνη κειμένων. Όρο κι ρωτάει γραμμής πελάτες, τελειώσει διολισθήσεις καθυστερούσε αν εγώ? Τι πετούν διοίκηση προβλήματα ήδη. + +Τη γλιτώσει αποθηκευτικού μια. Πω έξι δημιουργια πιθανότητες, ως πέντε ελέγχους εκτελείται λες. Πως ερωτήσεις διοικητικό συγκεντρωμένοι οι, ας συνεχώς διοικητικό αποστηθίσει σαν. Δε πρώτες συνεχώς διολισθήσεις έχω, από τι κανένας βουτήξουν, γειτονιάς προσεκτικά ανταγωνιστής κι σαν. + +Δημιουργια συνηθίζουν κλπ τι? Όχι ποσοστό διακοπής κι. Κλπ φακέλους δεδομένη εξοργιστικά θα? Υποψήφιο καθορίζουν με όλη, στα πήρε προσοχή εταιρείες πω, ώς τον συνάδελφος διοικητικό δημιουργήσεις! Δούλευε επιτίθενται σας θα, με ένας παραγωγικής ένα, να ναι σημεία μέγιστη απαράδεκτη? + +Σας τεσσαρών συνεντεύξης τη, αρπάζεις σίγουρος μη για', επί τοπικές εντολές ακούσει θα? Ως δυστυχής μεταγλωτιστής όλη, να την είχαν σφάλμα απαραίτητο! Μην ώς άτομο διορθώσει χρησιμοποιούνταν. Δεν τα κόλπα πετάξαμε, μη που άγχος υόρκη άμεση, αφού δυστυχώς διακόψουμε όρο αν! Όλη μαγικά πετάνε επιδιορθώσεις δε, ροή φυσικά αποτελέσει πω. + +Άπειρα παραπάνω φαινόμενο πω ώρα, σαν πόρτες κρατήσουν συνηθίζουν ως. Κι ώρα τρέξει είχαμε εφαρμογή. Απλό σχεδιαστής μεταγλωτιστής ας επί, τις τα όταν έγραψες γραμμής? Όλα κάνεις συνάδελφος εργαζόμενοι θα, χαρτιού χαμηλός τα ροή. Ως ναι όροφο έρθει, μην πελάτες αποφάσισε μεταφραστής με, να βιαστικά εκδόσεις αναζήτησης λες. Των φταίει εκθέσεις προσπαθήσεις οι, σπίτι αποστηθίσει ας λες? + +Ώς που υπηρεσία απαραίτητο δημιουργείς. Μη άρα χαρά καθώς νύχτας, πω ματ μπουν είχαν. Άμεση δημιουργείς ώς ροή, γράψει γραμμής σίγουρος στα τι! Αν αφού πρώτοι εργαζόμενων ναί. + +Άμεση διορθώσεις με δύο? Έχουν παράδειγμα των θα, μου έρθει θυμάμαι περισσότερο το. Ότι θα αφού χρειάζονται περισσότερες. Σαν συνεχώς περίπου οι. + +Ώς πρώτης πετάξαμε λες, όρο κι πρώτες ζητήσεις δυστυχής. Ανά χρόνου διακοπή επιχειρηματίες ας, ώς μόλις άτομο χειρότερα όρο, κρατάει σχεδιαστής προσπαθήσεις νέο το. Πουλάς προσθέσει όλη πω, τύπου χαρακτηριστικό εγώ σε, πω πιο δούλευε αναζήτησης? Αναφορά δίνοντας σαν μη, μάθε δεδομένη εσωτερικών με ναι, αναφέρονται περιβάλλοντος ώρα αν. Και λέει απόλαυσε τα, που το όροφο προσπαθούν? + +Πάντα χρόνου χρήματα ναι το, σαν σωστά θυμάμαι σκεφτείς τα. Μα αποτελέσει ανεπιθύμητη την, πιο το τέτοιο ατόμου, τη των τρόπο εργαλείων επιδιόρθωσης. Περιβάλλον παραγωγικής σου κι, κλπ οι τύπου κακόκεφους αποστηθίσει, δε των πλέον τρόποι. Πιθανότητες χαρακτηριστικών σας κι, γραφικά δημιουργήσεις μια οι, πω πολλοί εξαρτάται προσεκτικά εδώ. Σταματάς παράγοντες για' ώς, στις ρωτάει το ναι! Καρέκλα ζητήσεις συνδυασμούς τη ήδη! + +Για μαγικά συνεχώς ακούσει το. Σταματάς προϊόντα βουτήξουν ώς ροή. Είχαν πρώτες οι ναι, μα λες αποστηθίσει ανακαλύπτεις. Όροφο άλγεβρα παραπάνω εδώ τη, πρόσληψη λαμβάνουν καταλάθος ήδη ας? Ως και εισαγωγή κρατήσουν, ένας κακόκεφους κι μας, όχι κώδικάς παίξουν πω. Πω νέα κρατάει εκφράσουν, τότε τελικών τη όχι, ας της τρέξει αλλάζοντας αποκλειστικούς. + +Ένας βιβλίο σε άρα, ναι ως γράψει ταξινομεί διορθώσεις! Εδώ να γεγονός συγγραφείς, ώς ήδη διακόψουμε επιχειρηματίες? Ότι πακέτων εσφαλμένη κι, θα όρο κόλπα παραγωγικής? Αν έχω κεντρικό υψηλότερη, κι δεν ίδιο πετάνε παρατηρούμενη! Που λοιπόν σημαντικό μα, προκαλείς χειροκροτήματα ως όλα, μα επί κόλπα άγχος γραμμές! Δε σου κάνεις βουτήξουν, μη έργων επενδυτής χρησιμοποίησέ στα, ως του πρώτες διάσημα σημαντικό. + +Βιβλίο τεράστιο προκύπτουν σαν το, σαν τρόπο επιδιόρθωση ας. Είχαν προσοχή προσπάθεια κι ματ, εδώ ως έτσι σελίδων συζήτηση. Και στην βγαίνει εσφαλμένη με, δυστυχής παράδειγμα δε μας, από σε υόρκη επιδιόρθωσης. Νέα πω νέου πιθανό, στήλες συγγραφείς μπαίνοντας μα για', το ρωτήσει κακόκεφους της? Μου σε αρέσει συγγραφής συγχωνευτεί, μη μου υόρκη ξέχασε διακοπής! Ώς επί αποφάσισε αποκλειστικούς χρησιμοποιώντας, χρήματα σελίδων ταξινομεί ναι με. + +Μη ανά γραμμή απόλαυσε, πω ναι μάτσο διασφαλίζεται. Τη έξι μόλις εργάστηκε δημιουργούν, έκδοση αναφορά δυσκολότερο οι νέο. Σας ως μπορούσε παράδειγμα, αν ότι δούλευε μπορούσε αποκλειστικούς, πιο λέει βουτήξουν διορθώσει ως. Έχω τελευταία κακόκεφους ας, όσο εργαζόμενων δημιουργήσεις τα. + +Του αν δουλέψει μπορούσε, πετούν χαμηλός εδώ ας? Κύκλο τύπους με που, δεν σε έχουν συνεχώς χειρότερα, τις τι απαράδεκτη συνηθίζουν? Θα μην τους αυτήν, τη ένα πήρε πακέτων, κι προκύπτουν περιβάλλον πως. Μα για δουλέψει απόλαυσε εφαμοργής, ώς εδώ σημαίνει μπορούσες, άμεση ακούσει προσοχή τη εδώ? + +Στα δώσε αθόρυβες λιγότερους οι, δε αναγκάζονται αποκλειστικούς όλα! Ας μπουν διοικητικό μια, πάντα ελέγχου διορθώσεις ώς τον. Ότι πήρε κανόνα μα. Που άτομα κάνεις δημιουργίες τα, οι μας αφού κόλπα προγραμματιστής, αφού ωραίο προκύπτουν στα ως. Θέμα χρησιμοποιήσει αν όλα, του τα άλγεβρα σελίδων. Τα ότι ανώδυνη δυστυχώς συνδυασμούς, μας οι πάντα γνωρίζουμε ανταγωνιστής, όχι τα δοκιμάσεις σχεδιαστής! Στην συνεντεύξης επιδιόρθωση πιο τα, μα από πουλάς περιβάλλον παραγωγικής. + +Έχουν μεταγλωτίσει σε σας, σε πάντα πρώτης μειώσει των, γράψει ρουτίνα δυσκολότερο ήδη μα? Ταξινομεί διορθώσεις να μας. Θα της προσπαθούν περιεχόμενα, δε έχω τοπικές στέλνοντάς. Ανά δε αλφα άμεση, κάποιο ρωτάει γνωρίζουμε πω στη, φράση μαγικά συνέχεια δε δύο! Αν είχαμε μειώσει ροή, μας μετράει καθυστερούσε επιδιορθώσεις μη. Χάος υόρκη κεντρικό έχω σε, ανά περίπου αναγκάζονται πω. + +Όσο επιστρέφουν χρονοδιαγράμματα μη. Πως ωραίο κακόκεφος διαχειριστής ως, τις να διακοπής αναζήτησης. Κάποιο ποσοστό ταξινομεί επί τη? Μάθε άμεση αλλάζοντας δύο με, μου νέου πάντα να. + +Πω του δυστυχώς πιθανότητες. Κι ρωτάει υψηλότερη δημιουργια ότι, πω εισαγωγή τελευταία απομόνωση ναι. Των ζητήσεις γνωρίζουμε ώς? Για' μη παραδοτέου αναφέρονται! Ύψος παραγωγικά ροή ως, φυσικά διάβασε εικόνες όσο σε? Δεν υόρκη διορθώσεις επεξεργασία θα, ως μέση σύστημα χρησιμοποιήσει τις. \ No newline at end of file diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/two.txt b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/two.txt new file mode 100644 index 0000000000000..2443fc4d88e6a --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Fixtures/samples/charsets/utf-8/two.txt @@ -0,0 +1,3 @@ +रखति आवश्यकत प्रेरना मुख्यतह हिंदी किएलोग असक्षम कार्यलय करते विवरण किके मानसिक दिनांक पुर्व संसाध एवम् कुशलता अमितकुमार प्रोत्साहित जनित देखने उदेशीत विकसित बलवान ब्रौशर किएलोग विश्लेषण लोगो कैसे जागरुक प्रव्रुति प्रोत्साहित सदस्य आवश्यकत प्रसारन उपलब्धता अथवा हिंदी जनित दर्शाता यन्त्रालय बलवान अतित सहयोग शुरुआत सभीकुछ माहितीवानीज्य लिये खरिदे है।अभी एकत्रित सम्पर्क रिती मुश्किल प्राथमिक भेदनक्षमता विश्व उन्हे गटको द्वारा तकरीबन + +विश्व द्वारा व्याख्या सके। आजपर वातावरण व्याख्यान पहोच। हमारी कीसे प्राथमिक विचारशिलता पुर्व करती कम्प्युटर भेदनक्षमता लिये बलवान और्४५० यायेका वार्तालाप सुचना भारत शुरुआत लाभान्वित पढाए संस्था वर्णित मार्गदर्शन चुनने \ No newline at end of file diff --git a/src/Symfony/Component/Mime/Tests/Header/DateHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/DateHeaderTest.php new file mode 100644 index 0000000000000..4fc92b96aecf9 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/DateHeaderTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\DateHeader; + +class DateHeaderTest extends TestCase +{ + /* -- + The following tests refer to RFC 2822, section 3.6.1 and 3.3. + */ + + public function testGetDateTime() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable()); + $this->assertSame($dateTime, $header->getDateTime()); + } + + public function testDateTimeCanBeSetBySetter() + { + $header = new DateHeader('Date', new \DateTimeImmutable()); + $header->setDateTime($dateTime = new \DateTimeImmutable()); + $this->assertSame($dateTime, $header->getDateTime()); + } + + public function testDateTimeIsConvertedToImmutable() + { + $dateTime = new \DateTime(); + $header = new DateHeader('Date', $dateTime); + $this->assertInstanceOf('DateTimeImmutable', $header->getDateTime()); + $this->assertEquals($dateTime->getTimestamp(), $header->getDateTime()->getTimestamp()); + $this->assertEquals($dateTime->getTimezone(), $header->getDateTime()->getTimezone()); + } + + public function testDateTimeIsImmutable() + { + $header = new DateHeader('Date', $dateTime = new \DateTime('2000-01-01 12:00:00 Europe/Berlin')); + $dateTime->setDate(2002, 2, 2); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getDateTime()->format('r')); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getBodyAsString()); + } + + public function testDateTimeIsConvertedToRfc2822Date() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin')); + $header->setDateTime($dateTime); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getBodyAsString()); + } + + public function testSetBody() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable()); + $header->setBody($dateTime); + $this->assertEquals($dateTime->format('r'), $header->getBodyAsString()); + } + + public function testGetBody() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable()); + $header->setDateTime($dateTime); + $this->assertEquals($dateTime, $header->getBody()); + } + + public function testToString() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin')); + $header->setDateTime($dateTime); + $this->assertEquals('Date: Sat, 01 Jan 2000 12:00:00 +0100', $header->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php new file mode 100644 index 0000000000000..00c21a35cf30f --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php @@ -0,0 +1,234 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\IdentificationHeader; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; + +class HeadersTest extends TestCase +{ + public function testAddMailboxListHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addMailboxListHeader('From', ['person@domain']); + $this->assertNotNull($headers->get('From')); + } + + public function testAddDateHeaderDelegatesToFactory() + { + $dateTime = new \DateTimeImmutable(); + $headers = new Headers(); + $headers->addDateHeader('Date', $dateTime); + $this->assertNotNull($headers->get('Date')); + } + + public function testAddTextHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addTextHeader('Subject', 'some text'); + $this->assertNotNull($headers->get('Subject')); + } + + public function testAddParameterizedHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']); + $this->assertNotNull($headers->get('Content-Type')); + } + + public function testAddIdHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertNotNull($headers->get('Message-ID')); + } + + public function testAddPathHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addPathHeader('Return-Path', 'some@path'); + $this->assertNotNull($headers->get('Return-Path')); + } + + public function testHasReturnsFalseWhenNoHeaders() + { + $headers = new Headers(); + $this->assertFalse($headers->has('Some-Header')); + } + + public function testAddedMailboxListHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addMailboxListHeader('From', ['person@domain']); + $this->assertTrue($headers->has('From')); + } + + public function testAddedDateHeaderIsSeenByHas() + { + $dateTime = new \DateTimeImmutable(); + $headers = new Headers(); + $headers->addDateHeader('Date', $dateTime); + $this->assertTrue($headers->has('Date')); + } + + public function testAddedTextHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addTextHeader('Subject', 'some text'); + $this->assertTrue($headers->has('Subject')); + } + + public function testAddedParameterizedHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']); + $this->assertTrue($headers->has('Content-Type')); + } + + public function testAddedIdHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($headers->has('Message-ID')); + } + + public function testAddedPathHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addPathHeader('Return-Path', 'some@path'); + $this->assertTrue($headers->has('Return-Path')); + } + + public function testNewlySetHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->add(new UnstructuredHeader('X-Foo', 'bar')); + $this->assertTrue($headers->has('X-Foo')); + } + + public function testHasCanDistinguishMultipleHeaders() + { + $headers = new Headers(); + $headers->addTextHeader('X-Test', 'some@id'); + $headers->addTextHeader('X-Test', 'other@id'); + $this->assertTrue($headers->has('X-Test')); + } + + public function testGet() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals($header->toString(), $headers->get('Message-ID')->toString()); + } + + public function testGetReturnsNullIfHeaderNotSet() + { + $headers = new Headers(); + $this->assertNull($headers->get('Message-ID')); + } + + public function testGetAllReturnsAllHeadersMatchingName() + { + $header0 = new UnstructuredHeader('X-Test', 'some@id'); + $header1 = new UnstructuredHeader('X-Test', 'other@id'); + $header2 = new UnstructuredHeader('X-Test', 'more@id'); + $headers = new Headers(); + $headers->addTextHeader('X-Test', 'some@id'); + $headers->addTextHeader('X-Test', 'other@id'); + $headers->addTextHeader('X-Test', 'more@id'); + $this->assertEquals([$header0, $header1, $header2], iterator_to_array($headers->getAll('X-Test'))); + } + + public function testGetAllReturnsAllHeadersIfNoArguments() + { + $header0 = new IdentificationHeader('Message-ID', 'some@id'); + $header1 = new UnstructuredHeader('Subject', 'thing'); + $header2 = new MailboxListHeader('To', [new Address('person@example.org')]); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $headers->addTextHeader('Subject', 'thing'); + $headers->addMailboxListHeader('To', [new Address('person@example.org')]); + $this->assertEquals(['message-id' => $header0, 'subject' => $header1, 'to' => $header2], iterator_to_array($headers->getAll())); + } + + public function testGetAllReturnsEmptyArrayIfNoneSet() + { + $headers = new Headers(); + $this->assertEquals([], iterator_to_array($headers->getAll('Received'))); + } + + public function testRemoveRemovesAllHeadersWithName() + { + $header0 = new UnstructuredHeader('X-Test', 'some@id'); + $header1 = new UnstructuredHeader('X-Test', 'other@id'); + $headers = new Headers(); + $headers->addIdHeader('X-Test', 'some@id'); + $headers->addIdHeader('X-Test', 'other@id'); + $headers->remove('X-Test'); + $this->assertFalse($headers->has('X-Test')); + $this->assertFalse($headers->has('X-Test')); + } + + public function testHasIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($headers->has('message-id')); + } + + public function testGetIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals($header, $headers->get('message-id')); + } + + public function testGetAllIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals([$header], iterator_to_array($headers->getAll('message-id'))); + } + + public function testRemoveIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $headers->remove('message-id'); + $this->assertFalse($headers->has('Message-ID')); + } + + public function testToStringJoinsHeadersTogether() + { + $headers = new Headers(); + $headers->addTextHeader('Foo', 'bar'); + $headers->addTextHeader('Zip', 'buttons'); + $this->assertEquals("Foo: bar\r\nZip: buttons\r\n", $headers->toString()); + } + + public function testHeadersWithoutBodiesAreNotDisplayed() + { + $headers = new Headers(); + $headers->addTextHeader('Foo', 'bar'); + $headers->addTextHeader('Zip', ''); + $this->assertEquals("Foo: bar\r\n", $headers->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php new file mode 100644 index 0000000000000..7d94d4d19df1a --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php @@ -0,0 +1,179 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\IdentificationHeader; + +class IdentificationHeaderTest extends TestCase +{ + public function testValueMatchesMsgIdSpec() + { + /* -- RFC 2822, 3.6.4. + message-id = "Message-ID:" msg-id CRLF + + in-reply-to = "In-Reply-To:" 1*msg-id CRLF + + references = "References:" 1*msg-id CRLF + + msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] + + id-left = dot-atom-text / no-fold-quote / obs-id-left + + id-right = dot-atom-text / no-fold-literal / obs-id-right + + no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE + + no-fold-literal = "[" *(dtext / quoted-pair) "]" + */ + + $header = new IdentificationHeader('Message-ID', 'id-left@id-right'); + $this->assertEquals('', $header->getBodyAsString()); + } + + public function testIdCanBeRetrievedVerbatim() + { + $header = new IdentificationHeader('Message-ID', 'id-left@id-right'); + $this->assertEquals('id-left@id-right', $header->getId()); + } + + public function testMultipleIdsCanBeSet() + { + $header = new IdentificationHeader('References', 'c@d'); + $header->setIds(['a@b', 'x@y']); + $this->assertEquals(['a@b', 'x@y'], $header->getIds()); + } + + public function testSettingMultipleIdsProducesAListValue() + { + /* -- RFC 2822, 3.6.4. + The "References:" and "In-Reply-To:" field each contain one or more + unique message identifiers, optionally separated by CFWS. + + .. SNIP .. + + in-reply-to = "In-Reply-To:" 1*msg-id CRLF + + references = "References:" 1*msg-id CRLF + */ + + $header = new IdentificationHeader('References', ['a@b', 'x@y']); + $this->assertEquals(' ', $header->getBodyAsString()); + } + + public function testIdLeftCanBeQuoted() + { + /* -- RFC 2822, 3.6.4. + id-left = dot-atom-text / no-fold-quote / obs-id-left + */ + + $header = new IdentificationHeader('References', '"ab"@c'); + $this->assertEquals('"ab"@c', $header->getId()); + $this->assertEquals('<"ab"@c>', $header->getBodyAsString()); + } + + public function testIdLeftCanContainAnglesAsQuotedPairs() + { + /* -- RFC 2822, 3.6.4. + no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE + */ + + $header = new IdentificationHeader('References', '"a\\<\\>b"@c'); + $this->assertEquals('"a\\<\\>b"@c', $header->getId()); + $this->assertEquals('<"a\\<\\>b"@c>', $header->getBodyAsString()); + } + + public function testIdLeftCanBeDotAtom() + { + $header = new IdentificationHeader('References', 'a.b+&%$.c@d'); + $this->assertEquals('a.b+&%$.c@d', $header->getId()); + $this->assertEquals('', $header->getBodyAsString()); + } + + /** + * @expectedException \Exception + * @expectedMessageException "a b c" is not valid id-left + */ + public function testInvalidIdLeftThrowsException() + { + $header = new IdentificationHeader('References', 'a b c@d'); + } + + public function testIdRightCanBeDotAtom() + { + /* -- RFC 2822, 3.6.4. + id-right = dot-atom-text / no-fold-literal / obs-id-right + */ + + $header = new IdentificationHeader('References', 'a@b.c+&%$.d'); + $this->assertEquals('a@b.c+&%$.d', $header->getId()); + $this->assertEquals('', $header->getBodyAsString()); + } + + public function testIdRightCanBeLiteral() + { + /* -- RFC 2822, 3.6.4. + no-fold-literal = "[" *(dtext / quoted-pair) "]" + */ + + $header = new IdentificationHeader('References', 'a@[1.2.3.4]'); + $this->assertEquals('a@[1.2.3.4]', $header->getId()); + $this->assertEquals('', $header->getBodyAsString()); + } + + public function testIdRigthIsIdnEncoded() + { + $header = new IdentificationHeader('References', 'a@ä'); + $this->assertEquals('a@ä', $header->getId()); + $this->assertEquals('', $header->getBodyAsString()); + } + + /** + * @expectedException \Exception + * @expectedMessageException "b c d" is not valid id-right + */ + public function testInvalidIdRightThrowsException() + { + $header = new IdentificationHeader('References', 'a@b c d'); + } + + /** + * @expectedException \Exception + * @expectedMessageException "abc" is does not contain @ + */ + public function testMissingAtSignThrowsException() + { + /* -- RFC 2822, 3.6.4. + msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] + */ + $header = new IdentificationHeader('References', 'abc'); + } + + public function testSetBody() + { + $header = new IdentificationHeader('Message-ID', 'c@d'); + $header->setBody('a@b'); + $this->assertEquals(['a@b'], $header->getIds()); + } + + public function testGetBody() + { + $header = new IdentificationHeader('Message-ID', 'a@b'); + $this->assertEquals(['a@b'], $header->getBody()); + } + + public function testStringValue() + { + $header = new IdentificationHeader('References', ['a@b', 'x@y']); + $this->assertEquals('References: ', $header->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/MailboxHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/MailboxHeaderTest.php new file mode 100644 index 0000000000000..11a7ac9c54eb7 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/MailboxHeaderTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\MailboxHeader; +use Symfony\Component\Mime\NamedAddress; + +class MailboxHeaderTest extends TestCase +{ + public function testConstructor() + { + $header = new MailboxHeader('Sender', $address = new Address('fabien@symfony.com')); + $this->assertEquals($address, $header->getAddress()); + $this->assertEquals($address, $header->getBody()); + } + + public function testAddress() + { + $header = new MailboxHeader('Sender', new Address('fabien@symfony.com')); + $header->setBody($address = new Address('helene@symfony.com')); + $this->assertEquals($address, $header->getAddress()); + $this->assertEquals($address, $header->getBody()); + $header->setAddress($address = new Address('thomas@symfony.com')); + $this->assertEquals($address, $header->getAddress()); + $this->assertEquals($address, $header->getBody()); + } + + public function testgetBodyAsString() + { + $header = new MailboxHeader('Sender', new Address('fabien@symfony.com')); + $this->assertEquals('fabien@symfony.com', $header->getBodyAsString()); + + $header->setAddress(new Address('fabien@sïmfony.com')); + $this->assertEquals('fabien@xn--smfony-iwa.com', $header->getBodyAsString()); + + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier')); + $this->assertEquals('Fabien Potencier ', $header->getBodyAsString()); + + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier, "from Symfony"')); + $this->assertEquals('"Fabien Potencier, \"from Symfony\"" ', $header->getBodyAsString()); + + $header = new MailboxHeader('From', new NamedAddress('fabien@symfony.com', 'Fabien Potencier, \\escaped\\')); + $this->assertEquals('"Fabien Potencier, \\\\escaped\\\\" ', $header->getBodyAsString()); + + $name = 'P'.pack('C', 0x8F).'tencier'; + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien '.$name)); + $header->setCharset('iso-8859-1'); + $this->assertEquals('Fabien =?'.$header->getCharset().'?Q?P=8Ftencier?= ', $header->getBodyAsString()); + } + + /** + * @expectedException \Symfony\Component\Mime\Exception\AddressEncoderException + */ + public function testUtf8CharsInLocalPartThrows() + { + $header = new MailboxHeader('Sender', new Address('fabïen@symfony.com')); + $header->getBodyAsString(); + } + + public function testToString() + { + $header = new MailboxHeader('Sender', new Address('fabien@symfony.com')); + $this->assertEquals('Sender: fabien@symfony.com', $header->toString()); + + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier')); + $this->assertEquals('Sender: Fabien Potencier ', $header->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/MailboxListHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/MailboxListHeaderTest.php new file mode 100644 index 0000000000000..a2a28050f1d86 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/MailboxListHeaderTest.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\NamedAddress; + +class MailboxListHeaderTest extends TestCase +{ + // RFC 2822, 3.6.2 for all tests + + public function testMailboxIsSetForAddress() + { + $header = new MailboxListHeader('From', [new Address('chris@swiftmailer.org')]); + $this->assertEquals(['chris@swiftmailer.org'], $header->getAddressStrings()); + } + + public function testMailboxIsRenderedForNameAddress() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn')]); + $this->assertEquals(['Chris Corbyn '], $header->getAddressStrings()); + } + + public function testAddressCanBeReturnedForAddress() + { + $header = new MailboxListHeader('From', $addresses = [new Address('chris@swiftmailer.org')]); + $this->assertEquals($addresses, $header->getAddresses()); + } + + public function testQuotesInNameAreQuoted() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, "DHE"')]); + $this->assertEquals(['"Chris Corbyn, \"DHE\"" '], $header->getAddressStrings()); + } + + public function testEscapeCharsInNameAreQuoted() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, \\escaped\\')]); + $this->assertEquals(['"Chris Corbyn, \\\\escaped\\\\" '], $header->getAddressStrings()); + } + + public function testUtf8CharsInDomainAreIdnEncoded() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swïftmailer.org', 'Chris Corbyn')]); + $this->assertEquals(['Chris Corbyn '], $header->getAddressStrings()); + } + + /** + * @expectedException \Symfony\Component\Mime\Exception\AddressEncoderException + */ + public function testUtf8CharsInLocalPartThrows() + { + $header = new MailboxListHeader('From', [new NamedAddress('chrïs@swiftmailer.org', 'Chris Corbyn')]); + $header->getAddressStrings(); + } + + public function testGetMailboxesReturnsNameValuePairs() + { + $header = new MailboxListHeader('From', $addresses = [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, DHE')]); + $this->assertEquals($addresses, $header->getAddresses()); + } + + public function testMultipleAddressesAsMailboxStrings() + { + $header = new MailboxListHeader('From', [new Address('chris@swiftmailer.org'), new Address('mark@swiftmailer.org')]); + $this->assertEquals(['chris@swiftmailer.org', 'mark@swiftmailer.org'], $header->getAddressStrings()); + } + + public function testNameIsEncodedIfNonAscii() + { + $name = 'C'.pack('C', 0x8F).'rbyn'; + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris '.$name)]); + $header->setCharset('iso-8859-1'); + $addresses = $header->getAddressStrings(); + $this->assertEquals('Chris =?'.$header->getCharset().'?Q?C=8Frbyn?= ', array_shift($addresses)); + } + + public function testEncodingLineLengthCalculations() + { + /* -- RFC 2047, 2. + An 'encoded-word' may not be more than 75 characters long, including + 'charset', 'encoding', 'encoded-text', and delimiters. + */ + + $name = 'C'.pack('C', 0x8F).'rbyn'; + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris '.$name)]); + $header->setCharset('iso-8859-1'); + $addresses = $header->getAddressStrings(); + $this->assertEquals('Chris =?'.$header->getCharset().'?Q?C=8Frbyn?= ', array_shift($addresses)); + } + + public function testGetValueReturnsMailboxStringValue() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn')]); + $this->assertEquals('Chris Corbyn ', $header->getBodyAsString()); + } + + public function testGetValueReturnsMailboxStringValueForMultipleMailboxes() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn'), new NamedAddress('mark@swiftmailer.org', 'Mark Corbyn')]); + $this->assertEquals('Chris Corbyn , Mark Corbyn ', $header->getBodyAsString()); + } + + public function testSetBody() + { + $header = new MailboxListHeader('From', []); + $header->setBody($addresses = [new Address('chris@swiftmailer.org')]); + $this->assertEquals($addresses, $header->getAddresses()); + } + + public function testGetBody() + { + $header = new MailboxListHeader('From', $addresses = [new Address('chris@swiftmailer.org')]); + $this->assertEquals($addresses, $header->getBody()); + } + + public function testToString() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@example.org', 'Chris Corbyn'), new NamedAddress('mark@example.org', 'Mark Corbyn')]); + $this->assertEquals('From: Chris Corbyn , Mark Corbyn ', $header->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php new file mode 100644 index 0000000000000..aa8265814b607 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/ParameterizedHeaderTest.php @@ -0,0 +1,274 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\ParameterizedHeader; + +class ParameterizedHeaderTest extends TestCase +{ + private $charset = 'utf-8'; + private $lang = 'en-us'; + + public function testValueIsReturnedVerbatim() + { + $header = new ParameterizedHeader('Content-Type', 'text/plain'); + $this->assertEquals('text/plain', $header->getValue()); + } + + public function testParametersAreAppended() + { + /* -- RFC 2045, 5.1 + parameter := attribute "=" value + + attribute := token + ; Matching of attributes + ; is ALWAYS case-insensitive. + + value := token / quoted-string + + token := 1* + + tspecials := "(" / ")" / "<" / ">" / "@" / + "," / ";" / ":" / "\" / <"> + "/" / "[" / "]" / "?" / "=" + ; Must be in quoted-string, + ; to use within parameter values + */ + + $header = new ParameterizedHeader('Content-Type', 'text/plain'); + $header->setParameters(['charset' => 'utf-8']); + $this->assertEquals('text/plain; charset=utf-8', $header->getBodyAsString()); + } + + public function testSpaceInParamResultsInQuotedString() + { + $header = new ParameterizedHeader('Content-Type', 'attachment'); + $header->setParameters(['filename' => 'my file.txt']); + $this->assertEquals('attachment; filename="my file.txt"', $header->getBodyAsString()); + } + + public function testLongParamsAreBrokenIntoMultipleAttributeStrings() + { + /* -- RFC 2231, 3. + The asterisk character ("*") followed + by a decimal count is employed to indicate that multiple parameters + are being used to encapsulate a single parameter value. The count + starts at 0 and increments by 1 for each subsequent section of the + parameter value. Decimal values are used and neither leading zeroes + nor gaps in the sequence are allowed. + + The original parameter value is recovered by concatenating the + various sections of the parameter, in order. For example, the + content-type field + + Content-Type: message/external-body; access-type=URL; + URL*0="ftp://"; + URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + + is semantically identical to + + Content-Type: message/external-body; access-type=URL; + URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + + Note that quotes around parameter values are part of the value + syntax; they are NOT part of the value itself. Furthermore, it is + explicitly permitted to have a mixture of quoted and unquoted + continuation fields. + */ + + $value = str_repeat('a', 180); + + $header = new ParameterizedHeader('Content-Disposition', 'attachment'); + $header->setParameters(['filename' => $value]); + $this->assertEquals( + 'attachment; '. + 'filename*0*=utf-8\'\''.str_repeat('a', 60).";\r\n ". + 'filename*1*='.str_repeat('a', 60).";\r\n ". + 'filename*2*='.str_repeat('a', 60), + $header->getBodyAsString() + ); + } + + public function testEncodedParamDataIncludesCharsetAndLanguage() + { + /* -- RFC 2231, 4. + Asterisks ("*") are reused to provide the indicator that language and + character set information is present and encoding is being used. A + single quote ("'") is used to delimit the character set and language + information at the beginning of the parameter value. Percent signs + ("%") are used as the encoding flag, which agrees with RFC 2047. + + Specifically, an asterisk at the end of a parameter name acts as an + indicator that character set and language information may appear at + the beginning of the parameter value. A single quote is used to + separate the character set, language, and actual value information in + the parameter value string, and an percent sign is used to flag + octets encoded in hexadecimal. For example: + + Content-Type: application/x-stuff; + title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A + + Note that it is perfectly permissible to leave either the character + set or language field blank. Note also that the single quote + delimiters MUST be present even when one of the field values is + omitted. + */ + + $value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 10); + $header = new ParameterizedHeader('Content-Disposition', 'attachment'); + $header->setCharset('iso-8859-1'); + $header->setValue('attachment'); + $header->setParameters(['filename' => $value]); + $header->setLanguage($this->lang); + $this->assertEquals( + 'attachment; filename*='.$header->getCharset()."'".$this->lang."'". + str_repeat('a', 20).'%8F'.str_repeat('a', 10), + $header->getBodyAsString() + ); + } + + public function testMultipleEncodedParamLinesAreFormattedCorrectly() + { + /* -- RFC 2231, 4.1. + Character set and language information may be combined with the + parameter continuation mechanism. For example: + + Content-Type: application/x-stuff + title*0*=us-ascii'en'This%20is%20even%20more%20 + title*1*=%2A%2A%2Afun%2A%2A%2A%20 + title*2="isn't it!" + + Note that: + + (1) Language and character set information only appear at + the beginning of a given parameter value. + + (2) Continuations do not provide a facility for using more + than one character set or language in the same + parameter value. + + (3) A value presented using multiple continuations may + contain a mixture of encoded and unencoded segments. + + (4) The first segment of a continuation MUST be encoded if + language and character set information are given. + + (5) If the first segment of a continued parameter value is + encoded the language and character set field delimiters + MUST be present even when the fields are left blank. + */ + + $value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 60); + $header = new ParameterizedHeader('Content-Disposition', 'attachment'); + $header->setValue('attachment'); + $header->setCharset('utf-6'); + $header->setParameters(['filename' => $value]); + $header->setLanguage($this->lang); + $this->assertEquals( + 'attachment; filename*0*='.$header->getCharset()."'".$this->lang."'". + str_repeat('a', 20).'%8F'.str_repeat('a', 23).";\r\n ". + 'filename*1*='.str_repeat('a', 37), + $header->getBodyAsString() + ); + } + + public function testToString() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setParameters(['charset' => 'utf-8']); + $this->assertEquals('Content-Type: text/html; charset=utf-8', $header->toString()); + } + + public function testValueCanBeEncodedIfNonAscii() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', $value); + $header->setCharset('iso-8859-1'); + $header->setParameters(['lookslike' => 'foobar']); + $this->assertEquals('X-Foo: =?'.$header->getCharset().'?Q?fo=8Fbar?=; lookslike=foobar', $header->toString()); + } + + public function testValueAndParamCanBeEncodedIfNonAscii() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', $value); + $header->setCharset('iso-8859-1'); + $header->setParameters(['says' => $value]); + $this->assertEquals('X-Foo: =?'.$header->getCharset().'?Q?fo=8Fbar?=; says="=?'.$header->getCharset().'?Q?fo=8Fbar?="', $header->toString()); + } + + public function testParamsAreEncodedWithEncodedWordsIfNoParamEncoderSet() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', 'bar'); + $header->setCharset('iso-8859-1'); + $header->setParameters(['says' => $value]); + $this->assertEquals('X-Foo: bar; says="=?'.$header->getCharset().'?Q?fo=8Fbar?="', $header->toString()); + } + + public function testLanguageInformationAppearsInEncodedWords() + { + /* -- RFC 2231, 5. + 5. Language specification in Encoded Words + + RFC 2047 provides support for non-US-ASCII character sets in RFC 822 + message header comments, phrases, and any unstructured text field. + This is done by defining an encoded word construct which can appear + in any of these places. Given that these are fields intended for + display, it is sometimes necessary to associate language information + with encoded words as well as just the character set. This + specification extends the definition of an encoded word to allow the + inclusion of such information. This is simply done by suffixing the + character set specification with an asterisk followed by the language + tag. For example: + + From: =?US-ASCII*EN?Q?Keith_Moore?= + */ + + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', $value); + $header->setCharset('iso-8859-1'); + $header->setLanguage('en'); + $header->setParameters(['says' => $value]); + $this->assertEquals('X-Foo: =?'.$header->getCharset().'*en?Q?fo=8Fbar?=; says="=?'.$header->getCharset().'*en?Q?fo=8Fbar?="', $header->toString()); + } + + public function testSetBody() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setBody('text/plain'); + $this->assertEquals('text/plain', $header->getValue()); + } + + public function testGetBody() + { + $header = new ParameterizedHeader('Content-Type', 'text/plain'); + $this->assertEquals('text/plain', $header->getBody()); + } + + public function testSetParameter() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setParameters(['charset' => 'utf-8', 'delsp' => 'yes']); + $header->setParameter('delsp', 'no'); + $this->assertEquals(['charset' => 'utf-8', 'delsp' => 'no'], $header->getParameters()); + } + + public function testGetParameter() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setParameters(['charset' => 'utf-8', 'delsp' => 'yes']); + $this->assertEquals('utf-8', $header->getParameter('charset')); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php new file mode 100644 index 0000000000000..8f41959944478 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\PathHeader; + +class PathHeaderTest extends TestCase +{ + public function testSingleAddressCanBeSetAndFetched() + { + $header = new PathHeader('Return-Path', $address = new Address('chris@swiftmailer.org')); + $this->assertEquals($address, $header->getAddress()); + } + + /** + * @expectedException \Exception + */ + public function testAddressMustComplyWithRfc2822() + { + $header = new PathHeader('Return-Path', new Address('chr is@swiftmailer.org')); + } + + public function testValueIsAngleAddrWithValidAddress() + { + /* -- RFC 2822, 3.6.7. + + return = "Return-Path:" path CRLF + + path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / + obs-path + */ + + $header = new PathHeader('Return-Path', new Address('chris@swiftmailer.org')); + $this->assertEquals('', $header->getBodyAsString()); + } + + public function testAddressIsIdnEncoded() + { + $header = new PathHeader('Return-Path', new Address('chris@swïftmailer.org')); + $this->assertEquals('', $header->getBodyAsString()); + } + + /** + * @expectedException \Symfony\Component\Mime\Exception\AddressEncoderException + */ + public function testAddressMustBeEncodable() + { + $header = new PathHeader('Return-Path', new Address('chrïs@swiftmailer.org')); + $header->getBodyAsString(); + } + + public function testSetBody() + { + $header = new PathHeader('Return-Path', new Address('foo@example.com')); + $header->setBody($address = new Address('foo@bar.tld')); + $this->assertEquals($address, $header->getAddress()); + } + + public function testGetBody() + { + $header = new PathHeader('Return-Path', $address = new Address('foo@bar.tld')); + $this->assertEquals($address, $header->getBody()); + } + + public function testToString() + { + $header = new PathHeader('Return-Path', new Address('chris@swiftmailer.org')); + $this->assertEquals('Return-Path: ', $header->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Header/UnstructuredHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/UnstructuredHeaderTest.php new file mode 100644 index 0000000000000..3e065bf268a79 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Header/UnstructuredHeaderTest.php @@ -0,0 +1,247 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\UnstructuredHeader; + +class UnstructuredHeaderTest extends TestCase +{ + private $charset = 'utf-8'; + + public function testGetNameReturnsNameVerbatim() + { + $header = new UnstructuredHeader('Subject', ''); + $this->assertEquals('Subject', $header->getName()); + } + + public function testGetValueReturnsValueVerbatim() + { + $header = new UnstructuredHeader('Subject', 'Test'); + $this->assertEquals('Test', $header->getValue()); + } + + public function testBasicStructureIsKeyValuePair() + { + /* -- RFC 2822, 2.2 + Header fields are lines composed of a field name, followed by a colon + (":"), followed by a field body, and terminated by CRLF. + */ + $header = new UnstructuredHeader('Subject', 'Test'); + $this->assertEquals('Subject: Test', $header->toString()); + } + + public function testLongHeadersAreFoldedAtWordBoundary() + { + /* -- RFC 2822, 2.2.3 + Each header field is logically a single line of characters comprising + the field name, the colon, and the field body. For convenience + however, and to deal with the 998/78 character limitations per line, + the field body portion of a header field can be split into a multiple + line representation; this is called "folding". The general rule is + that wherever this standard allows for folding white space (not + simply WSP characters), a CRLF may be inserted before any WSP. + */ + + $value = 'The quick brown fox jumped over the fence, he was a very very '. + 'scary brown fox with a bushy tail'; + $header = new UnstructuredHeader('X-Custom-Header', $value); + /* + X-Custom-Header: The quick brown fox jumped over the fence, he was a very very + scary brown fox with a bushy tail + */ + $this->assertEquals( + 'X-Custom-Header: The quick brown fox jumped over the fence, he was a'. + ' very'."\r\n".//Folding + ' very scary brown fox with a bushy tail', + $header->toString(), '%s: The header should have been folded at 76th char' + ); + } + + public function testPrintableAsciiOnlyAppearsInHeaders() + { + /* -- RFC 2822, 2.2. + A field name MUST be composed of printable US-ASCII characters (i.e., + characters that have values between 33 and 126, inclusive), except + colon. A field body may be composed of any US-ASCII characters, + except for CR and LF. + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $this->assertRegExp('~^[^:\x00-\x20\x80-\xFF]+: [^\x80-\xFF\r\n]+$~s', $header->toString()); + } + + public function testEncodedWordsFollowGeneralStructure() + { + /* -- RFC 2047, 1. + Generally, an "encoded-word" is a sequence of printable ASCII + characters that begins with "=?", ends with "?=", and has two "?"s in + between. + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $this->assertRegExp('~^X-Test: \=?.*?\?.*?\?.*?\?=$~s', $header->toString()); + } + + public function testEncodedWordIncludesCharsetAndEncodingMethodAndText() + { + /* -- RFC 2047, 2. + An 'encoded-word' is defined by the following ABNF grammar. The + notation of RFC 822 is used, with the exception that white space + characters MUST NOT appear between components of an 'encoded-word'. + + encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8F?=', $header->toString()); + } + + public function testEncodedWordsAreUsedToEncodedNonPrintableAscii() + { + // SPACE and TAB permitted + $nonPrintableBytes = array_merge(range(0x00, 0x08), range(0x10, 0x19), [0x7F]); + foreach ($nonPrintableBytes as $byte) { + $char = pack('C', $byte); + $encodedChar = sprintf('=%02X', $byte); + $header = new UnstructuredHeader('X-A', $char); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-A: =?'.$header->getCharset().'?Q?'.$encodedChar.'?=', $header->toString(), 'Non-printable ascii should be encoded'); + } + } + + public function testEncodedWordsAreUsedToEncode8BitOctets() + { + foreach (range(0x80, 0xFF) as $byte) { + $char = pack('C', $byte); + $encodedChar = sprintf('=%02X', $byte); + $header = new UnstructuredHeader('X-A', $char); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-A: =?'.$header->getCharset().'?Q?'.$encodedChar.'?=', $header->toString(), '8-bit octets should be encoded'); + } + } + + public function testEncodedWordsAreNoMoreThan75CharsPerLine() + { + /* -- RFC 2047, 2. + An 'encoded-word' may not be more than 75 characters long, including + 'charset', 'encoding', 'encoded-text', and delimiters. + + ... SNIP ... + + While there is no limit to the length of a multiple-line header + field, each line of a header field that contains one or more + 'encoded-word's is limited to 76 characters. + */ + + $nonAsciiChar = pack('C', 0x8F); + + //Note that multi-line headers begin with LWSP which makes 75 + 1 = 76 + //Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63 + + //* X-Test: is 8 chars + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8F?=', $header->toString()); + } + + public function testFWSPIsUsedWhenEncoderReturnsMultipleLines() + { + /* --RFC 2047, 2. + If it is desirable to encode more text than will fit in an 'encoded-word' of + 75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may + be used. + */ + + // Note that multi-line headers begin with LWSP which makes 75 + 1 = 76 + // Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63 + + //* X-Test: is 8 chars + $header = new UnstructuredHeader('X-Test', pack('C', 0x8F).'line_one_here'."\r\n".'line_two_here'); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8Fline=5Fone=5Fhere?='."\r\n".' =?'.$header->getCharset().'?Q?line=5Ftwo=5Fhere?=', $header->toString()); + } + + public function testAdjacentWordsAreEncodedTogether() + { + /* -- RFC 2047, 5 (1) + Ordinary ASCII text and 'encoded-word's may appear together in the + same header field. However, an 'encoded-word' that appears in a + header field defined as '*text' MUST be separated from any adjacent + 'encoded-word' or 'text' by 'linear-white-space'. + + -- RFC 2047, 2. + IMPORTANT: 'encoded-word's are designed to be recognized as 'atom's + by an RFC 822 parser. As a consequence, unencoded white space + characters (such as SPACE and HTAB) are FORBIDDEN within an + 'encoded-word'. + */ + + // It would be valid to encode all words needed, however it's probably + // easiest to encode the longest amount required at a time + + $word = 'w'.pack('C', 0x8F).'rd'; + $text = 'start '.$word.' '.$word.' then '.$word; + // 'start', ' word word', ' and end', ' word' + + $header = new UnstructuredHeader('X-Test', $text); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: start =?'.$header->getCharset().'?Q?'. + 'w=8Frd_w=8Frd?= then =?'.$header->getCharset().'?Q?'. + 'w=8Frd?=', $header->toString(), + 'Adjacent encoded words should appear grouped with WSP encoded' + ); + } + + public function testLanguageInformationAppearsInEncodedWords() + { + /* -- RFC 2231, 5. + 5. Language specification in Encoded Words + + RFC 2047 provides support for non-US-ASCII character sets in RFC 822 + message header comments, phrases, and any unstructured text field. + This is done by defining an encoded word construct which can appear + in any of these places. Given that these are fields intended for + display, it is sometimes necessary to associate language information + with encoded words as well as just the character set. This + specification extends the definition of an encoded word to allow the + inclusion of such information. This is simply done by suffixing the + character set specification with an asterisk followed by the language + tag. For example: + + From: =?US-ASCII*EN?Q?Keith_Moore?= + */ + + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new UnstructuredHeader('Subject', $value); + $header->setLanguage('en'); + $header->setCharset('iso-8859-1'); + $this->assertEquals('Subject: =?iso-8859-1*en?Q?fo=8Fbar?=', $header->toString()); + } + + public function testSetBody() + { + $header = new UnstructuredHeader('X-Test', ''); + $header->setBody('test'); + $this->assertEquals('test', $header->getValue()); + } + + public function testGetBody() + { + $header = new UnstructuredHeader('Subject', 'test'); + $this->assertEquals('test', $header->getBody()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/MessageConverterTest.php b/src/Symfony/Component/Mime/Tests/MessageConverterTest.php new file mode 100644 index 0000000000000..6a78086246377 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/MessageConverterTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\MessageConverter; + +class MessageConverterTest extends TestCase +{ + public function testToEmail() + { + $file = file_get_contents(__DIR__.'/Fixtures/mimetypes/test.gif'); + $email = (new Email())->from('fabien@symfony.com'); + $this->assertSame($email, MessageConverter::toEmail($email)); + + $this->assertConversion((clone $email)->text('text content')); + $this->assertConversion((clone $email)->html('HTML content ')); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content ') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content ') + ->embed($file, 'test.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content ') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content ') + ->embed($file, 'test.jpg', 'image/gif') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->html('HTML content ') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->html('HTML content ') + ->embed($file, 'test.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->embed($file, 'test_attached.jpg', 'image/gif') + ); + } + + private function assertConversion(Email $expected) + { + $r = new \ReflectionMethod($expected, 'generateBody'); + $r->setAccessible(true); + + $message = new Message($expected->getHeaders(), $r->invoke($expected)); + $converted = MessageConverter::toEmail($message); + if ($expected->getHtmlBody()) { + $this->assertStringMatchesFormat(str_replace('cid:test.jpg', 'cid:%s', $expected->getHtmlBody()), $converted->getHtmlBody()); + $expected->html('HTML content'); + $converted->html('HTML content'); + } + $this->assertEquals($expected, $converted); + } +} diff --git a/src/Symfony/Component/Mime/Tests/MessageTest.php b/src/Symfony/Component/Mime/Tests/MessageTest.php new file mode 100644 index 0000000000000..f366e4e6bf83b --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/MessageTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\Part\TextPart; + +class MessageTest extends TestCase +{ + public function testConstruct() + { + $m = new Message(); + $this->assertNull($m->getBody()); + $this->assertEquals(new Headers(), $m->getHeaders()); + + $m = new Message($h = (new Headers())->addDateHeader('Date', new \DateTime()), $b = new TextPart('content')); + $this->assertSame($b, $m->getBody()); + $this->assertEquals($h, $m->getHeaders()); + + $m = new Message(); + $m->setBody($b); + $m->setHeaders($h); + $this->assertSame($b, $m->getBody()); + $this->assertSame($h, $m->getHeaders()); + } + + public function testGetPreparedHeadersThrowsWhenNoFrom() + { + $this->expectException(\LogicException::class); + (new Message())->getPreparedHeaders(); + } + + public function testGetPreparedHeadersCloneHeaders() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $this->assertNotSame($message->getPreparedHeaders(), $message->getHeaders()); + } + + public function testGetPreparedHeadersSetRequiredHeaders() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $headers = $message->getPreparedHeaders(); + $this->assertTrue($headers->has('MIME-Version')); + $this->assertTrue($headers->has('Message-ID')); + $this->assertTrue($headers->has('Date')); + $this->assertFalse($headers->has('Bcc')); + } + + public function testGetPreparedHeaders() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $h = $message->getPreparedHeaders(); + $this->assertCount(4, iterator_to_array($h->getAll())); + $this->assertEquals(new MailboxListHeader('From', [new Address('fabien@symfony.com')]), $h->get('From')); + $this->assertEquals(new UnstructuredHeader('MIME-Version', '1.0'), $h->get('mime-version')); + $this->assertTrue($h->has('Message-Id')); + $this->assertTrue($h->has('Date')); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $message->getHeaders()->addDateHeader('Date', $n = new \DateTimeImmutable()); + $this->assertEquals($n, $message->getPreparedHeaders()->get('Date')->getDateTime()); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $message->getHeaders()->addMailboxListHeader('Bcc', ['fabien@symfony.com']); + $this->assertNull($message->getPreparedHeaders()->get('Bcc')); + } + + public function testGetPreparedHeadersWithNoFrom() + { + $this->expectException(\LogicException::class); + (new Message())->getPreparedHeaders(); + } + + public function testGetPreparedHeadersHasSenderWhenNeeded() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $this->assertNull($message->getPreparedHeaders()->get('Sender')); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com', 'lucas@symfony.com']); + $this->assertEquals('fabien@symfony.com', $message->getPreparedHeaders()->get('Sender')->getAddress()->getAddress()); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com', 'lucas@symfony.com']); + $message->getHeaders()->addMailboxHeader('Sender', 'thomas@symfony.com'); + $this->assertEquals('thomas@symfony.com', $message->getPreparedHeaders()->get('Sender')->getAddress()->getAddress()); + } + + public function testToString() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $expected = << +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + +EOF; + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", $message->toString())); + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable())))); + + $message = new Message(null, new TextPart('content')); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $expected = << +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + +content +EOF; + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", $message->toString())); + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable())))); + } +} diff --git a/src/Symfony/Component/Mime/Tests/MimeTypesTest.php b/src/Symfony/Component/Mime/Tests/MimeTypesTest.php index e56e9c2a2a7dc..c5ff262b80ffa 100644 --- a/src/Symfony/Component/Mime/Tests/MimeTypesTest.php +++ b/src/Symfony/Component/Mime/Tests/MimeTypesTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Mime\Tests; +use Symfony\Component\Mime\Exception\RuntimeException; use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Mime\MimeTypes; @@ -35,10 +36,10 @@ public function isGuesserSupported(): bool public function guessMimeType(string $mimeType): ?string { - throw new \RuntimeException('Should never be called.'); + throw new RuntimeException('Should never be called.'); } }); - $this->assertEquals('image/gif', $guesser->guessMimeType(__DIR__.'/Fixtures/test')); + $this->assertEquals('image/gif', $guesser->guessMimeType(__DIR__.'/Fixtures/mimetypes/test')); } public function testGetExtensions() diff --git a/src/Symfony/Component/Mime/Tests/NamedAddressTest.php b/src/Symfony/Component/Mime/Tests/NamedAddressTest.php new file mode 100644 index 0000000000000..72840191d5af3 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/NamedAddressTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\NamedAddress; + +class NamedAddressTest extends TestCase +{ + public function testConstructor() + { + $a = new NamedAddress('fabien@symfonï.com', 'Fabien'); + $this->assertEquals('Fabien', $a->getName()); + $this->assertEquals('fabien@symfonï.com', $a->getAddress()); + $this->assertEquals('Fabien ', $a->toString()); + $this->assertEquals('fabien@xn--symfon-nwa.com', $a->getEncodedAddress()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php b/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php new file mode 100644 index 0000000000000..d8a08a24303c2 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\IdentificationHeader; +use Symfony\Component\Mime\Header\ParameterizedHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Part\DataPart; + +class DataPartTest extends TestCase +{ + public function testConstructor() + { + $p = new DataPart('content'); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals(base64_encode('content'), $p->bodyToString()); + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + // bodyToIterable() can be called several times + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('application', $p->getMediaType()); + $this->assertEquals('octet-stream', $p->getMediaSubType()); + + $p = new DataPart('content', null, 'text/html'); + $this->assertEquals('text', $p->getMediaType()); + $this->assertEquals('html', $p->getMediaSubType()); + } + + public function testConstructorWithResource() + { + $f = fopen('php://memory', 'r+', false); + fwrite($f, 'content'); + rewind($f); + $p = new DataPart($f); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals(base64_encode('content'), $p->bodyToString()); + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + fclose($f); + } + + public function testConstructorWithNonStringOrResource() + { + $this->expectException(\TypeError::class); + new DataPart(new \stdClass()); + } + + public function testHeaders() + { + $p = new DataPart('content'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'application/octet-stream'), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment') + ), $p->getPreparedHeaders()); + + $p = new DataPart('content', 'photo.jpg', 'text/html'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/html', ['name' => 'photo.jpg']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'photo.jpg', 'filename' => 'photo.jpg']) + ), $p->getPreparedHeaders()); + } + + public function testAsInline() + { + $p = new DataPart('content', 'photo.jpg', 'text/html'); + $p->asInline(); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/html', ['name' => 'photo.jpg']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'inline', ['name' => 'photo.jpg', 'filename' => 'photo.jpg']) + ), $p->getPreparedHeaders()); + } + + public function testAsInlineWithCID() + { + $p = new DataPart('content', 'photo.jpg', 'text/html'); + $p->asInline(); + $cid = $p->getContentId(); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/html', ['name' => 'photo.jpg']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'inline', ['name' => 'photo.jpg', 'filename' => 'photo.jpg']), + new IdentificationHeader('Content-ID', $cid) + ), $p->getPreparedHeaders()); + } + + public function testFromPath() + { + $p = DataPart::fromPath($file = __DIR__.'/../Fixtures/mimetypes/test.gif'); + $content = file_get_contents($file); + $this->assertEquals($content, $p->getBody()); + $this->assertEquals(base64_encode($content), $p->bodyToString()); + $this->assertEquals(base64_encode($content), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('image', $p->getMediaType()); + $this->assertEquals('gif', $p->getMediaSubType()); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'image/gif', ['name' => 'test.gif']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'test.gif', 'filename' => 'test.gif']) + ), $p->getPreparedHeaders()); + } + + public function testFromPathWithMeta() + { + $p = DataPart::fromPath($file = __DIR__.'/../Fixtures/mimetypes/test.gif', 'photo.gif', 'image/jpeg'); + $content = file_get_contents($file); + $this->assertEquals($content, $p->getBody()); + $this->assertEquals(base64_encode($content), $p->bodyToString()); + $this->assertEquals(base64_encode($content), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('image', $p->getMediaType()); + $this->assertEquals('jpeg', $p->getMediaSubType()); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'image/jpeg', ['name' => 'photo.gif']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'photo.gif', 'filename' => 'photo.gif']) + ), $p->getPreparedHeaders()); + } + + public function testHasContentId() + { + $p = new DataPart('content'); + $this->assertFalse($p->hasContentId()); + $p->getContentId(); + $this->assertTrue($p->hasContentId()); + } + + public function testSerialize() + { + $r = fopen('php://memory', 'r+', false); + fwrite($r, 'Text content'); + rewind($r); + + $p = new DataPart($r); + $p->getHeaders()->addTextHeader('foo', 'bar'); + $expected = clone $p; + $this->assertEquals($expected->toString(), unserialize(serialize($p))->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/MessagePartTest.php b/src/Symfony/Component/Mime/Tests/Part/MessagePartTest.php new file mode 100644 index 0000000000000..3855e085c4b39 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/MessagePartTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\ParameterizedHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Part\MessagePart; + +class MessagePartTest extends TestCase +{ + public function testConstructor() + { + $p = new MessagePart((new Email())->from('fabien@symfony.com')->text('content')); + $this->assertContains('content', $p->getBody()); + $this->assertContains('content', $p->bodyToString()); + $this->assertContains('content', implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('message', $p->getMediaType()); + $this->assertEquals('rfc822', $p->getMediaSubType()); + } + + public function testHeaders() + { + $p = new MessagePart((new Email())->from('fabien@symfony.com')->text('content')->subject('Subject')); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'message/rfc822', ['name' => 'Subject.eml']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'Subject.eml', 'filename' => 'Subject.eml']) + ), $p->getPreparedHeaders()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/AlternativePartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/AlternativePartTest.php new file mode 100644 index 0000000000000..2dbc1315ef1b4 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/AlternativePartTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; + +class AlternativePartTest extends TestCase +{ + public function testConstructor() + { + $a = new AlternativePart(); + $this->assertEquals('multipart', $a->getMediaType()); + $this->assertEquals('alternative', $a->getMediaSubtype()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/DigestPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/DigestPartTest.php new file mode 100644 index 0000000000000..82738efbc5cbe --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/DigestPartTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\Part\MessagePart; +use Symfony\Component\Mime\Part\Multipart\DigestPart; + +class DigestPartTest extends TestCase +{ + public function testConstructor() + { + $r = new DigestPart($a = new MessagePart(new Message()), $b = new MessagePart(new Message())); + $this->assertEquals('multipart', $r->getMediaType()); + $this->assertEquals('digest', $r->getMediaSubtype()); + $this->assertEquals([$a, $b], $r->getParts()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php new file mode 100644 index 0000000000000..f60b0b7c4194f --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Component\Mime\Part\TextPart; + +class FormDataPartTest extends TestCase +{ + public function testConstructor() + { + $b = new TextPart('content'); + $c = DataPart::fromPath($file = __DIR__.'/../../Fixtures/mimetypes/test.gif'); + $f = new FormDataPart([ + 'foo' => $content = 'very very long content that will not be cut even if the length i way more than 76 characters, ok?', + 'bar' => clone $b, + 'baz' => clone $c, + ]); + $this->assertEquals('multipart', $f->getMediaType()); + $this->assertEquals('form-data', $f->getMediaSubtype()); + $t = new TextPart($content); + $t->setDisposition('form-data'); + $t->setName('foo'); + $t->getHeaders()->setMaxLineLength(1000); + $b->setDisposition('form-data'); + $b->setName('bar'); + $b->getHeaders()->setMaxLineLength(1000); + $c->setDisposition('form-data'); + $c->setName('baz'); + $c->getHeaders()->setMaxLineLength(1000); + $this->assertEquals([$t, $b, $c], $f->getParts()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/MixedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/MixedPartTest.php new file mode 100644 index 0000000000000..3ff02ee6cacd5 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/MixedPartTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\Multipart\MixedPart; + +class MixedPartTest extends TestCase +{ + public function testConstructor() + { + $a = new MixedPart(); + $this->assertEquals('multipart', $a->getMediaType()); + $this->assertEquals('mixed', $a->getMediaSubtype()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/RelatedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/RelatedPartTest.php new file mode 100644 index 0000000000000..2a5a7bed97cd4 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/RelatedPartTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +class RelatedPartTest extends TestCase +{ + public function testConstructor() + { + $r = new RelatedPart($a = new TextPart('content'), $b = new TextPart('HTML content', 'utf-8', 'html'), $c = new TextPart('HTML content again', 'utf-8', 'html')); + $this->assertEquals('multipart', $r->getMediaType()); + $this->assertEquals('related', $r->getMediaSubtype()); + $this->assertEquals([$a, $b, $c], $r->getParts()); + $this->assertFalse($a->getHeaders()->has('Content-ID')); + $this->assertTrue($b->getHeaders()->has('Content-ID')); + $this->assertTrue($c->getHeaders()->has('Content-ID')); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php b/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php new file mode 100644 index 0000000000000..c3818b883d465 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\ParameterizedHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Part\TextPart; + +class TextPartTest extends TestCase +{ + public function testConstructor() + { + $p = new TextPart('content'); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals('content', $p->bodyToString()); + $this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable()))); + // bodyToIterable() can be called several times + $this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('text', $p->getMediaType()); + $this->assertEquals('plain', $p->getMediaSubType()); + + $p = new TextPart('content', null, 'html'); + $this->assertEquals('html', $p->getMediaSubType()); + } + + public function testConstructorWithResource() + { + $f = fopen('php://memory', 'r+', false); + fwrite($f, 'content'); + rewind($f); + $p = new TextPart($f); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals('content', $p->bodyToString()); + $this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable()))); + fclose($f); + } + + public function testConstructorWithNonStringOrResource() + { + $this->expectException(\TypeError::class); + new TextPart(new \stdClass()); + } + + public function testHeaders() + { + $p = new TextPart('content'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']), + new UnstructuredHeader('Content-Transfer-Encoding', 'quoted-printable') + ), $p->getPreparedHeaders()); + + $p = new TextPart('content', 'iso-8859-1'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'iso-8859-1']), + new UnstructuredHeader('Content-Transfer-Encoding', 'quoted-printable') + ), $p->getPreparedHeaders()); + } + + public function testEncoding() + { + $p = new TextPart('content', 'utf-8', 'plain', 'base64'); + $this->assertEquals(base64_encode('content'), $p->bodyToString()); + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64') + ), $p->getPreparedHeaders()); + } + + public function testSerialize() + { + $r = fopen('php://memory', 'r+', false); + fwrite($r, 'Text content'); + rewind($r); + + $p = new TextPart($r); + $p->getHeaders()->addTextHeader('foo', 'bar'); + $expected = clone $p; + $this->assertEquals($expected->toString(), unserialize(serialize($p))->toString()); + } +} diff --git a/src/Symfony/Component/Mime/Tests/RawMessageTest.php b/src/Symfony/Component/Mime/Tests/RawMessageTest.php new file mode 100644 index 0000000000000..5d1588bff00fa --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/RawMessageTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\RawMessage; + +class RawMessageTest extends TestCase +{ + public function testToString() + { + $message = new RawMessage('string'); + $this->assertEquals('string', $message->toString()); + $this->assertEquals('string', implode('', iterator_to_array($message->toIterable()))); + // calling methods more than once work + $this->assertEquals('string', $message->toString()); + $this->assertEquals('string', implode('', iterator_to_array($message->toIterable()))); + + $message = new RawMessage(new \ArrayObject(['some', ' ', 'string'])); + $this->assertEquals('some string', $message->toString()); + $this->assertEquals('some string', implode('', iterator_to_array($message->toIterable()))); + // calling methods more than once work + $this->assertEquals('some string', $message->toString()); + $this->assertEquals('some string', implode('', iterator_to_array($message->toIterable()))); + } +} diff --git a/src/Symfony/Component/Mime/composer.json b/src/Symfony/Component/Mime/composer.json index d06ed31dc1037..f1d2f0975c01d 100644 --- a/src/Symfony/Component/Mime/composer.json +++ b/src/Symfony/Component/Mime/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/mime", "type": "library", - "description": "A ", + "description": "A library to manipulate MIME messages", "keywords": ["mime", "mime-type"], "homepage": "https://symfony.com", "license": "MIT", @@ -16,9 +16,12 @@ } ], "require": { - "php": "^7.1.3" + "php": "^7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" }, "require-dev": { + "egulias/email-validator": "^2.0", "symfony/dependency-injection": "~3.4|^4.1" }, "autoload": { From a07627ea9a8801597937abb1e18f98fb0d793d6f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 2 Mar 2019 15:55:10 +0100 Subject: [PATCH 153/495] fixed tests --- src/Symfony/Bridge/Twig/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 0efd3f24e4e5f..be29084e4da07 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -21,6 +21,7 @@ "twig/twig": "^1.37.1|^2.6.2" }, "require-dev": { + "egulias/email-validator": "^2.0", "symfony/asset": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", From b3d536f04de4212277eb526bf3dd2955a9a434fe Mon Sep 17 00:00:00 2001 From: tsantos Date: Sun, 3 Mar 2019 07:59:38 -0300 Subject: [PATCH 154/495] [PropertyInfo] Removed useless namespace --- .../Component/PropertyInfo/Tests/Fixtures/DefaultValue.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php index f7a718e5c7b11..a7fe2c6a7b3d7 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DefaultValue.php @@ -1,7 +1,5 @@ Date: Fri, 21 Dec 2018 10:04:03 +0000 Subject: [PATCH 155/495] [Filesystem] Support resources and deprecate using arrays in dumpFile() and appendToFile() --- UPGRADE-5.0.md | 6 ++ src/Symfony/Component/Filesystem/CHANGELOG.md | 6 ++ .../Component/Filesystem/Filesystem.php | 16 +++-- .../Filesystem/Tests/FilesystemTest.php | 72 +++++++++++++++++-- 4 files changed, 89 insertions(+), 11 deletions(-) diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 7a845414bd869..24a5d56301a4a 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -65,6 +65,12 @@ EventDispatcher * The `TraceableEventDispatcherInterface` has been removed. +Filesystem +---------- + + * The `Filesystem::dumpFile()` method no longer supports arrays in the `$content` argument. + * The `Filesystem::appendToFile()` method no longer supports arrays in the `$content` argument. + Finder ------ diff --git a/src/Symfony/Component/Filesystem/CHANGELOG.md b/src/Symfony/Component/Filesystem/CHANGELOG.md index 9f1f817e753dd..f6453c16e32d2 100644 --- a/src/Symfony/Component/Filesystem/CHANGELOG.md +++ b/src/Symfony/Component/Filesystem/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +4.3.0 +----- + + * support for passing arrays to `Filesystem::dumpFile()` is deprecated and will be removed in 5.0 + * support for passing arrays to `Filesystem::appendToFile()` is deprecated and will be removed in 5.0 + 4.0.0 ----- diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 2d703843dc36b..4c0c99155ddcf 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -670,13 +670,17 @@ public function tempnam($dir, $prefix) /** * Atomically dumps content into a file. * - * @param string $filename The file to be written to - * @param string $content The data to write into the file + * @param string $filename The file to be written to + * @param string|resource $content The data to write into the file * * @throws IOException if the file cannot be written to */ public function dumpFile($filename, $content) { + if (\is_array($content)) { + @trigger_error(sprintf('Calling "%s()" with an array in the $content argument is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); + } + $dir = \dirname($filename); if (!is_dir($dir)) { @@ -703,13 +707,17 @@ public function dumpFile($filename, $content) /** * Appends content to an existing file. * - * @param string $filename The file to which to append content - * @param string $content The content to append + * @param string $filename The file to which to append content + * @param string|resource $content The content to append * * @throws IOException If the file is not writable */ public function appendToFile($filename, $content) { + if (\is_array($content)) { + @trigger_error(sprintf('Calling "%s()" with an array in the $content argument is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); + } + $dir = \dirname($filename); if (!is_dir($dir)) { diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 521c16b710222..94c7fea562ba6 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1334,13 +1334,13 @@ public function testMirrorContentsWithSameNameAsSourceOrTargetWithDeleteOption() public function testMirrorWithCustomIterator() { - $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR; + $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; mkdir($sourcePath); - $file = $sourcePath.DIRECTORY_SEPARATOR.'file'; + $file = $sourcePath.\DIRECTORY_SEPARATOR.'file'; file_put_contents($file, 'FILE'); - $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR; + $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; $splFile = new \SplFileInfo($file); $iterator = new \ArrayObject(array($splFile)); @@ -1348,7 +1348,7 @@ public function testMirrorWithCustomIterator() $this->filesystem->mirror($sourcePath, $targetPath, $iterator); $this->assertTrue(is_dir($targetPath)); - $this->assertFileEquals($file, $targetPath.DIRECTORY_SEPARATOR.'file'); + $this->assertFileEquals($file, $targetPath.\DIRECTORY_SEPARATOR.'file'); } /** @@ -1357,14 +1357,14 @@ public function testMirrorWithCustomIterator() */ public function testMirrorWithCustomIteratorWithRelativePath() { - $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR; - $realSourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR; + $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; + $realSourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; mkdir($realSourcePath); $file = $realSourcePath.'file'; file_put_contents($file, 'FILE'); - $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR; + $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; $splFile = new \SplFileInfo($file); $iterator = new \ArrayObject(array($splFile)); @@ -1518,6 +1518,10 @@ public function testDumpFile() } } + /** + * @group legacy + * @expectedDeprecation Calling "Symfony\Component\Filesystem\Filesystem::dumpFile()" with an array in the $content argument is deprecated since Symfony 4.3. + */ public function testDumpFileWithArray() { $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; @@ -1600,6 +1604,60 @@ public function testAppendToFile() } } + /** + * @group legacy + * @expectedDeprecation Calling "Symfony\Component\Filesystem\Filesystem::appendToFile()" with an array in the $content argument is deprecated since Symfony 4.3. + */ + public function testAppendToFileWithArray() + { + $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'bar.txt'; + + // skip mode check on Windows + if ('\\' !== \DIRECTORY_SEPARATOR) { + $oldMask = umask(0002); + } + + $this->filesystem->dumpFile($filename, 'foo'); + + $this->filesystem->appendToFile($filename, array('bar')); + + $this->assertFileExists($filename); + $this->assertStringEqualsFile($filename, 'foobar'); + + // skip mode check on Windows + if ('\\' !== \DIRECTORY_SEPARATOR) { + $this->assertFilePermissions(664, $filename); + umask($oldMask); + } + } + + public function testAppendToFileWithResource() + { + $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'bar.txt'; + + // skip mode check on Windows + if ('\\' !== \DIRECTORY_SEPARATOR) { + $oldMask = umask(0002); + } + + $this->filesystem->dumpFile($filename, 'foo'); + + $resource = fopen('php://memory', 'rw'); + fwrite($resource, 'bar'); + fseek($resource, 0); + + $this->filesystem->appendToFile($filename, $resource); + + $this->assertFileExists($filename); + $this->assertStringEqualsFile($filename, 'foobar'); + + // skip mode check on Windows + if ('\\' !== \DIRECTORY_SEPARATOR) { + $this->assertFilePermissions(664, $filename); + umask($oldMask); + } + } + public function testAppendToFileWithScheme() { $scheme = 'file://'; From 05d6475c5ed9b761cff4e8e45c0e41365cbf80c1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 17 Feb 2019 15:15:12 +0100 Subject: [PATCH 156/495] Drop more usages of Serializable --- UPGRADE-4.3.md | 2 + UPGRADE-5.0.md | 2 + .../Tests/Functional/app/AppKernel.php | 9 ++-- .../Bundle/FrameworkBundle/composer.json | 2 +- .../Cache/Tests/Adapter/AdapterTestCase.php | 9 +--- .../Component/Cache/Tests/Psr16CacheTest.php | 9 +--- .../Cache/Tests/Simple/CacheTestCase.php | 9 +--- .../phpt/fatal_with_nested_handlers.phpt | 4 +- src/Symfony/Component/Form/CHANGELOG.md | 1 + .../DataCollector/FormDataCollector.php | 11 ++++- src/Symfony/Component/Form/composer.json | 4 +- src/Symfony/Component/HttpKernel/CHANGELOG.md | 5 ++ .../DataCollector/DataCollector.php | 30 +++++++++++- .../DataCollector/DumpDataCollector.php | 39 +++++++++++---- src/Symfony/Component/HttpKernel/Kernel.php | 33 +++++++++++++ .../Component/HttpKernel/KernelInterface.php | 2 +- .../DataCollector/DumpDataCollectorTest.php | 10 ++-- .../Component/HttpKernel/Tests/KernelTest.php | 5 +- src/Symfony/Component/Routing/CHANGELOG.md | 2 + .../Component/Routing/CompiledRoute.php | 4 +- src/Symfony/Component/Routing/Route.php | 4 +- src/Symfony/Component/Security/CHANGELOG.md | 41 ++++++++-------- .../Authentication/Token/AbstractToken.php | 22 ++++----- .../Exception/AuthenticationException.php | 48 +++++++++++++------ .../Token/AbstractTokenTest.php | 10 ++-- ...UserMessageAuthenticationExceptionTest.php | 10 ++-- .../Component/Security/Core/composer.json | 3 ++ 27 files changed, 216 insertions(+), 114 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 79b38e2e7d5fe..6c348a3403637 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -55,6 +55,8 @@ Routing * The `generator_base_class`, `generator_cache_class`, `matcher_base_class`, and `matcher_cache_class` router options have been deprecated. + * Implementing `Serializable` for `Route` and `CompiledRoute` is deprecated; if you serialize them, please + ensure your unserialization logic can recover from a failure related to an updated serialization format Security -------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 319e5d245bacd..39d1ab4303ab3 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -234,6 +234,8 @@ Routing * The `generator_base_class`, `generator_cache_class`, `matcher_base_class`, and `matcher_cache_class` router options have been removed. + * `Route` and `CompiledRoute` don't implement `Serializable` anymore; if you serialize them, please + ensure your unserialization logic can recover from a failure related to an updated serialization format Security -------- diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php index ce54a88ece170..0c4d03bfc11af 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php @@ -79,15 +79,14 @@ protected function build(ContainerBuilder $container) $container->register('logger', NullLogger::class); } - public function serialize() + public function __sleep() { - return serialize([$this->varDir, $this->testCase, $this->rootConfig, $this->getEnvironment(), $this->isDebug()]); + return ['varDir', 'testCase', 'rootConfig', 'environment', 'debug']; } - public function unserialize($str) + public function __wakeup() { - $a = unserialize($str); - $this->__construct($a[0], $a[1], $a[2], $a[3], $a[4]); + $this->__construct($this->varDir, $this->testCase, $this->rootConfig, $this->environment, $this->debug); } protected function getKernelParameters() diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 4f620f3453f6d..764a0c0d2002f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -24,7 +24,7 @@ "symfony/dependency-injection": "^4.3", "symfony/event-dispatcher": "^4.1", "symfony/http-foundation": "^4.3", - "symfony/http-kernel": "^4.2", + "symfony/http-kernel": "^4.3", "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 0eceb6e572b39..f211e0f52ef7b 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -215,14 +215,9 @@ public function testPrune() } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/src/Symfony/Component/Cache/Tests/Psr16CacheTest.php b/src/Symfony/Component/Cache/Tests/Psr16CacheTest.php index 6692d3eb59ace..e56d99e44134f 100644 --- a/src/Symfony/Component/Cache/Tests/Psr16CacheTest.php +++ b/src/Symfony/Component/Cache/Tests/Psr16CacheTest.php @@ -159,14 +159,9 @@ protected function isPruned($cache, $name) } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php index 3c8824869bd08..d4b3d07f62729 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php @@ -132,14 +132,9 @@ public function testPrune() } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/src/Symfony/Component/Debug/Tests/phpt/fatal_with_nested_handlers.phpt b/src/Symfony/Component/Debug/Tests/phpt/fatal_with_nested_handlers.phpt index b3f0e0eb0995a..1736a3b5f2a73 100644 --- a/src/Symfony/Component/Debug/Tests/phpt/fatal_with_nested_handlers.phpt +++ b/src/Symfony/Component/Debug/Tests/phpt/fatal_with_nested_handlers.phpt @@ -24,7 +24,7 @@ var_dump([ $eHandler[0]->setExceptionHandler('print_r'); if (true) { - class Broken implements \Serializable + class Broken implements \JsonSerializable { } } @@ -37,6 +37,6 @@ array(1) { } object(Symfony\Component\Debug\Exception\FatalErrorException)#%d (%d) { ["message":protected]=> - string(199) "Error: Class Symfony\Component\Debug\Broken contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Serializable::serialize, Serializable::unserialize)" + string(179) "Error: Class Symfony\Component\Debug\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" %a } diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 2328918d7d9d5..f1b399cedc8be 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -15,6 +15,7 @@ CHANGELOG * added `block_prefix` option to `BaseType`. * added `help_html` option to display the `help` text as HTML. * `FormError` doesn't implement `Serializable` anymore + * `FormDataCollector` has been marked as `final` * added `label_translation_parameters`, `attr_translation_parameters`, `help_translation_parameters` options to `FormType` to pass translation parameters to form labels, attributes (`placeholder` and `title`) and help text respectively. The passed parameters will replace placeholders in translation messages. diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php index 96baf9b58d7f5..df7726a83f019 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php @@ -27,6 +27,8 @@ * * @author Robert Schönthal * @author Bernhard Schussek + * + * @final since Symfony 4.3 */ class FormDataCollector extends DataCollector implements FormDataCollectorInterface { @@ -229,7 +231,10 @@ public function getData() return $this->data; } - public function serialize() + /** + * @internal + */ + public function __sleep() { foreach ($this->data['forms_by_hash'] as &$form) { if (isset($form['type_class']) && !$form['type_class'] instanceof ClassStub) { @@ -237,7 +242,9 @@ public function serialize() } } - return serialize($this->cloneVar($this->data)); + $this->data = $this->cloneVar($this->data); + + return parent::__sleep(); } /** diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 4f72f19e8e5b4..fd39d77edc19e 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -31,7 +31,7 @@ "symfony/config": "~3.4|~4.0", "symfony/console": "~3.4|~4.0", "symfony/http-foundation": "~3.4|~4.0", - "symfony/http-kernel": "~3.4|~4.0", + "symfony/http-kernel": "~4.3", "symfony/security-csrf": "~3.4|~4.0", "symfony/translation": "~4.2", "symfony/var-dumper": "~3.4|~4.0" @@ -41,7 +41,7 @@ "symfony/dependency-injection": "<3.4", "symfony/doctrine-bridge": "<3.4", "symfony/framework-bundle": "<3.4", - "symfony/http-kernel": "<3.4", + "symfony/http-kernel": "<4.3", "symfony/translation": "<4.2", "symfony/twig-bridge": "<3.4.5|<4.0.5,>=4.0" }, diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 2d1cfc4ba1d9e..8a923812b5285 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -4,9 +4,14 @@ CHANGELOG 4.3.0 ----- + * `KernelInterface` doesn't extend `Serializable` anymore + * deprecated the `Kernel::serialize()` and `unserialize()` methods * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` * made `Symfony\Component\HttpKernel\EventListenerLocaleListener` set the default locale early * made `FileLinkFormatter` final and not implement `Serializable` anymore + * the base `DataCollector` doesn't implement `Serializable` anymore, you should + store all the serialized state in the data property instead + * `DumpDataCollector` has been marked as `final` 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php index 3b15868ff5c3e..d3020a312e02b 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php @@ -26,7 +26,7 @@ * @author Fabien Potencier * @author Bernhard Schussek */ -abstract class DataCollector implements DataCollectorInterface, \Serializable +abstract class DataCollector implements DataCollectorInterface { protected $data = []; @@ -35,16 +35,26 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable */ private $cloner; + /** + * @deprecated since Symfony 4.3, store all the serialized state in the data property instead + */ public function serialize() { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), E_USER_DEPRECATED); + $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); $isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object']; return $isCalledFromOverridingMethod ? $this->data : serialize($this->data); } + /** + * @deprecated since Symfony 4.3, store all the serialized state in the data property instead + */ public function unserialize($data) { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), E_USER_DEPRECATED); + $this->data = \is_array($data) ? $data : unserialize($data); } @@ -100,4 +110,22 @@ protected function getCasters() return $casters; } + + public function __sleep() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), E_USER_DEPRECATED); + $this->data = $this->serialize(); + } + + return ['data']; + } + + public function __wakeup() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), E_USER_DEPRECATED); + $this->unserialize($this->data); + } + } } diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index c88c73bb8221f..577eb2ca2e455 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -25,6 +25,8 @@ /** * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ class DumpDataCollector extends DataCollector implements DataDumperInterface { @@ -85,6 +87,9 @@ public function dump(Data $data) $this->isCollected = false; } + if (!$this->dataCount) { + $this->data = []; + } $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt'); ++$this->dataCount; @@ -95,6 +100,10 @@ public function dump(Data $data) public function collect(Request $request, Response $response, \Exception $exception = null) { + if (!$this->dataCount) { + $this->data = []; + } + // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper || ($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) { return; @@ -136,28 +145,38 @@ public function reset() $this->clonesIndex = 0; } - public function serialize() + /** + * @internal + */ + public function __sleep() { + if (!$this->dataCount) { + $this->data = []; + } + if ($this->clonesCount !== $this->clonesIndex) { - return 'a:0:{}'; + return []; } $this->data[] = $this->fileLinkFormat; $this->data[] = $this->charset; - $ser = serialize($this->data); - $this->data = []; $this->dataCount = 0; $this->isCollected = true; - return $ser; + return parent::__sleep(); } - public function unserialize($data) + /** + * @internal + */ + public function __wakeup() { - $this->data = unserialize($data); + parent::__wakeup(); + $charset = array_pop($this->data); $fileLinkFormat = array_pop($this->data); $this->dataCount = \count($this->data); + self::__construct($this->stopwatch, $fileLinkFormat, $charset); } @@ -178,6 +197,10 @@ public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1) } $dumps = []; + if (!$this->dataCount) { + return $this->data = []; + } + foreach ($this->data as $dump) { $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth)); $dump['data'] = stream_get_contents($data, -1, 0); @@ -196,7 +219,7 @@ public function getName() public function __destruct() { - if (0 === $this->clonesCount-- && !$this->isCollected && $this->data) { + if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) { $this->clonesCount = 0; $this->isCollected = true; diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 61236b8c817a5..23cb76a75edaa 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -833,15 +833,48 @@ public static function stripComments($source) return $output; } + /** + * @deprecated since Symfony 4.3 + */ public function serialize() { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); + return serialize([$this->environment, $this->debug]); } + /** + * @deprecated since Symfony 4.3 + */ public function unserialize($data) { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); list($environment, $debug) = unserialize($data, ['allowed_classes' => false]); $this->__construct($environment, $debug); } + + public function __sleep() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3.', $c), E_USER_DEPRECATED); + $this->serialized = $this->serialize(); + + return ['serialized']; + } + + return ['environment', 'debug']; + } + + public function __wakeup() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3.', $c), E_USER_DEPRECATED); + $this->unserialize($this->serialized); + unset($this->serialized); + + return; + } + $this->__construct($this->environment, $this->debug); + } } diff --git a/src/Symfony/Component/HttpKernel/KernelInterface.php b/src/Symfony/Component/HttpKernel/KernelInterface.php index 93c4190b9bc97..ead6920e7736f 100644 --- a/src/Symfony/Component/HttpKernel/KernelInterface.php +++ b/src/Symfony/Component/HttpKernel/KernelInterface.php @@ -24,7 +24,7 @@ * * @method string getProjectDir() Gets the project dir (path of the project's composer file) - not defining it is deprecated since Symfony 4.2 */ -interface KernelInterface extends HttpKernelInterface, \Serializable +interface KernelInterface extends HttpKernelInterface { /** * Returns an array of bundles to register. diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php index 76c1d96dcc36e..a40a482278155 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php @@ -52,9 +52,9 @@ public function testDump() ]; $this->assertEquals($xDump, $dump); - $this->assertStringMatchesFormat('a:3:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', $collector->serialize()); + $this->assertStringMatchesFormat('%a;a:%d:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', serialize($collector)); $this->assertSame(0, $collector->getDumpsCount()); - $this->assertSame('a:2:{i:0;b:0;i:1;s:5:"UTF-8";}', $collector->serialize()); + $this->assertSame("O:60:\"Symfony\Component\HttpKernel\DataCollector\DumpDataCollector\":1:{s:7:\"\0*\0data\";a:2:{i:0;b:0;i:1;s:5:\"UTF-8\";}}", serialize($collector)); } public function testDumpWithServerConnection() @@ -72,7 +72,7 @@ public function testDumpWithServerConnection() ob_start(); $collector->collect(new Request(), new Response()); $this->assertEmpty(ob_get_clean()); - $this->assertStringMatchesFormat('a:3:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', $collector->serialize()); + $this->assertStringMatchesFormat('%a;a:%d:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', serialize($collector)); } public function testCollectDefault() @@ -90,7 +90,7 @@ public function testCollectDefault() $this->assertSame("DumpDataCollectorTest.php on line {$line}:\n123\n", $output); $this->assertSame(1, $collector->getDumpsCount()); - $collector->serialize(); + serialize($collector); } public function testCollectHtml() @@ -118,7 +118,7 @@ public function testCollectHtml() $this->assertSame($xOutput, trim($output)); $this->assertSame(1, $collector->getDumpsCount()); - $collector->serialize(); + serialize($collector); } public function testFlush() diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index 57bd704c92d3e..1b66de40ffaf6 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -330,9 +330,8 @@ public function testSerialize() $env = 'test_env'; $debug = true; $kernel = new KernelForTest($env, $debug); - - $expected = serialize([$env, $debug]); - $this->assertEquals($expected, $kernel->serialize()); + $expected = "O:57:\"Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest\":2:{s:14:\"\0*\0environment\";s:8:\"test_env\";s:8:\"\0*\0debug\";b:1;}"; + $this->assertEquals($expected, serialize($kernel)); } /** diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index d695cd6bd1e91..4a5fba5cb4609 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -8,6 +8,8 @@ CHANGELOG * added `CompiledUrlGenerator` and `CompiledUrlGeneratorDumper` * deprecated `PhpGeneratorDumper` and `PhpMatcherDumper` * deprecated `generator_base_class`, `generator_cache_class`, `matcher_base_class` and `matcher_cache_class` router options + * deprecated implementing `Serializable` for `Route` and `CompiledRoute`; if you serialize them, please + ensure your unserialization logic can recover from a failure related to an updated serialization format 4.2.0 ----- diff --git a/src/Symfony/Component/Routing/CompiledRoute.php b/src/Symfony/Component/Routing/CompiledRoute.php index 8db812b075f66..b8919c56cc444 100644 --- a/src/Symfony/Component/Routing/CompiledRoute.php +++ b/src/Symfony/Component/Routing/CompiledRoute.php @@ -50,7 +50,7 @@ public function __construct(string $staticPrefix, string $regex, array $tokens, } /** - * {@inheritdoc} + * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore */ public function serialize() { @@ -67,7 +67,7 @@ public function serialize() } /** - * {@inheritdoc} + * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore */ public function unserialize($serialized) { diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 4e0463b57578c..8028d3801228d 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -63,7 +63,7 @@ public function __construct(string $path, array $defaults = [], array $requireme } /** - * {@inheritdoc} + * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore */ public function serialize() { @@ -81,7 +81,7 @@ public function serialize() } /** - * {@inheritdoc} + * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore */ public function unserialize($serialized) { diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 011d802ea1ff7..a04fd47e46ada 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -4,31 +4,32 @@ CHANGELOG 4.3.0 ----- -* The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles - instead. -* The `RoleHierarchyInterface` is deprecated and will be removed in 5.0. -* The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0. - Use the `getReachableRoleNames()` method instead. -* The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` - method instead and return roles as strings. -* Made the `serialize()` and `unserialize()` methods of `AbstractToken` and + * The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles + instead. + * The `RoleHierarchyInterface` is deprecated and will be removed in 5.0. + * The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0. + Use the `getReachableRoleNames()` method instead. + * The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` + method instead and return roles as strings. + * Made the `serialize()` and `unserialize()` methods of `AbstractToken` and `AuthenticationException` final, use `getState()`/`setState()` instead + * `AuthenticationException` doesn't implement `Serializable` anymore 4.2.0 ----- -* added the `is_granted()` function in security expressions -* deprecated the `has_role()` function in security expressions, use `is_granted()` instead -* Passing custom class names to the - `Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver` to define - custom anonymous and remember me token classes is deprecated. To - use custom tokens, extend the existing `Symfony\Component\Security\Core\Authentication\Token\AnonymousToken` - or `Symfony\Component\Security\Core\Authentication\Token\RememberMeToken`. -* allow passing null as $filter in LdapUserProvider to get the default filter -* accessing the user object that is not an instance of `UserInterface` from `Security::getUser()` is deprecated -* Deprecated `SimpleAuthenticatorInterface`, `SimpleFormAuthenticatorInterface`, - `SimplePreAuthenticatorInterface`, `SimpleAuthenticationProvider`, `SimpleAuthenticationHandler`, - `SimpleFormAuthenticationListener` and `SimplePreAuthenticationListener`. Use Guard instead. + * added the `is_granted()` function in security expressions + * deprecated the `has_role()` function in security expressions, use `is_granted()` instead + * Passing custom class names to the + `Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver` to define + custom anonymous and remember me token classes is deprecated. To + use custom tokens, extend the existing `Symfony\Component\Security\Core\Authentication\Token\AnonymousToken` + or `Symfony\Component\Security\Core\Authentication\Token\RememberMeToken`. + * allow passing null as $filter in LdapUserProvider to get the default filter + * accessing the user object that is not an instance of `UserInterface` from `Security::getUser()` is deprecated + * Deprecated `SimpleAuthenticatorInterface`, `SimpleFormAuthenticatorInterface`, + `SimplePreAuthenticatorInterface`, `SimpleAuthenticationProvider`, `SimpleAuthenticationHandler`, + `SimpleFormAuthenticationListener` and `SimplePreAuthenticationListener`. Use Guard instead. 4.1.0 ----- diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index 700634e7dcdac..b409e4b5635fd 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -151,7 +151,14 @@ public function eraseCredentials() */ public function serialize() { - return $this->doSerialize($this->getState(), \func_num_args() ? \func_get_arg(0) : null); + $serialized = $this->getState(); + + if (null === $isCalledFromOverridingMethod = \func_num_args() ? \func_get_arg(0) : null) { + $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); + $isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object']; + } + + return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); } /** @@ -284,19 +291,6 @@ public function __toString() return sprintf('%s(user="%s", authenticated=%s, roles="%s")', $class, $this->getUsername(), json_encode($this->authenticated), implode(', ', $roles)); } - /** - * @internal - */ - protected function doSerialize($serialized, $isCalledFromOverridingMethod) - { - if (null === $isCalledFromOverridingMethod) { - $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); - $isCalledFromOverridingMethod = isset($trace[2]['function'], $trace[2]['object']) && 'serialize' === $trace[2]['function'] && $this === $trace[2]['object']; - } - - return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); - } - private function hasUserChanged(UserInterface $user) { if (!($this->user instanceof UserInterface)) { diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index 2ee412bfd120f..82f6db65d6099 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -19,7 +19,7 @@ * @author Fabien Potencier * @author Alexander */ -class AuthenticationException extends RuntimeException implements \Serializable +class AuthenticationException extends RuntimeException { private $token; @@ -47,7 +47,14 @@ public function setToken(TokenInterface $token) */ public function serialize() { - return $this->doSerialize($this->getState(), \func_num_args() ? \func_get_arg(0) : null); + $serialized = $this->getState(); + + if (null === $isCalledFromOverridingMethod = \func_num_args() ? \func_get_arg(0) : null) { + $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); + $isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object']; + } + + return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); } /** @@ -62,6 +69,30 @@ public function unserialize($serialized) $this->setState(\is_array($serialized) ? $serialized : unserialize($serialized)); } + public function __sleep() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, implement the getState() and setState() methods instead.', $c), E_USER_DEPRECATED); + $this->serialized = $this->serialize(); + } else { + $this->serialized = $this->getState(); + } + + return ['serialized']; + } + + public function __wakeup() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, implement the getState() and setState() methods instead.', $c), E_USER_DEPRECATED); + $this->unserialize($this->serialized); + } else { + $this->setState($this->serialized); + } + + unset($this->serialized); + } + /** * Returns all the necessary state of the object for serialization purposes. * @@ -103,19 +134,6 @@ protected function setState(array $data) [$this->token, $this->code, $this->message, $this->file, $this->line] = $data; } - /** - * @internal - */ - protected function doSerialize($serialized, $isCalledFromOverridingMethod) - { - if (null === $isCalledFromOverridingMethod) { - $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 3); - $isCalledFromOverridingMethod = isset($trace[2]['function'], $trace[2]['object']) && 'serialize' === $trace[2]['function'] && $this === $trace[2]['object']; - } - - return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); - } - /** * Message key to be used by the translation component. * diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index e87d25a789f1d..188eeb5ab7def 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -278,15 +278,15 @@ public function __construct(array $roles = [], UserInterface $user = null) } } - public function serialize() + protected function getState(): array { - return serialize([$this->credentials, parent::serialize()]); + return [$this->credentials, parent::getState()]; } - public function unserialize($serialized) + protected function setState(array $data) { - list($this->credentials, $parentStr) = unserialize($serialized); - parent::unserialize($parentStr); + [$this->credentials, $parentState] = $data; + parent::setState($parentState); } public function getCredentials() diff --git a/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php b/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php index 32c76a452f702..58eb04efbdce9 100644 --- a/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php @@ -17,16 +17,16 @@ class ChildCustomUserMessageAuthenticationException extends CustomUserMessageAuthenticationException { - public function serialize() + protected function getState(): array { - return serialize([$this->childMember, parent::serialize()]); + return [$this->childMember, parent::getState()]; } - public function unserialize($str) + public function setState(array $data) { - list($this->childMember, $parentData) = unserialize($str); + [$this->childMember, $parentData] = $data; - parent::unserialize($parentData); + parent::setState($parentData); } } diff --git a/src/Symfony/Component/Security/Core/composer.json b/src/Symfony/Component/Security/Core/composer.json index f4128c65c2bc6..3f297cec44f7a 100644 --- a/src/Symfony/Component/Security/Core/composer.json +++ b/src/Symfony/Component/Security/Core/composer.json @@ -28,6 +28,9 @@ "symfony/validator": "~3.4|~4.0", "psr/log": "~1.0" }, + "conflict": { + "symfony/security-guard": "<4.3" + }, "suggest": { "psr/container-implementation": "To instantiate the Security class", "symfony/event-dispatcher": "", From 6c4ab8942e8fdb235f6a417febb7736f7e689c22 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Mar 2019 10:20:13 +0100 Subject: [PATCH 157/495] fixed CS --- .../Filesystem/Tests/FilesystemTest.php | 2 +- .../Core/Tests/Role/RoleHierarchyTest.php | 18 +++++++++--------- .../Tests/Controller/UserValueResolverTest.php | 1 - .../Tests/Firewall/SwitchUserListenerTest.php | 4 ++-- .../Tests/Logout/LogoutUrlGeneratorTest.php | 1 - .../Tests/EventListener/GuardListenerTest.php | 2 -- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index a70ae8558fc39..24df7a765c914 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1619,7 +1619,7 @@ public function testAppendToFileWithArray() $this->filesystem->dumpFile($filename, 'foo'); - $this->filesystem->appendToFile($filename, array('bar')); + $this->filesystem->appendToFile($filename, ['bar']); $this->assertFileExists($filename); $this->assertStringEqualsFile($filename, 'foobar'); diff --git a/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php b/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php index c33fb953a1877..e24ed84d2dd74 100644 --- a/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Role/RoleHierarchyTest.php @@ -36,15 +36,15 @@ public function testGetReachableRoles() public function testGetReachableRoleNames() { - $role = new RoleHierarchy(array( - 'ROLE_ADMIN' => array('ROLE_USER'), - 'ROLE_SUPER_ADMIN' => array('ROLE_ADMIN', 'ROLE_FOO'), - )); + $role = new RoleHierarchy([ + 'ROLE_ADMIN' => ['ROLE_USER'], + 'ROLE_SUPER_ADMIN' => ['ROLE_ADMIN', 'ROLE_FOO'], + ]); - $this->assertEquals(array('ROLE_USER'), $role->getReachableRoleNames(array('ROLE_USER'))); - $this->assertEquals(array('ROLE_FOO'), $role->getReachableRoleNames(array('ROLE_FOO'))); - $this->assertEquals(array('ROLE_ADMIN', 'ROLE_USER'), $role->getReachableRoleNames(array('ROLE_ADMIN'))); - $this->assertEquals(array('ROLE_FOO', 'ROLE_ADMIN', 'ROLE_USER'), $role->getReachableRoleNames(array('ROLE_FOO', 'ROLE_ADMIN'))); - $this->assertEquals(array('ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_FOO', 'ROLE_USER'), $role->getReachableRoleNames(array('ROLE_SUPER_ADMIN'))); + $this->assertEquals(['ROLE_USER'], $role->getReachableRoleNames(['ROLE_USER'])); + $this->assertEquals(['ROLE_FOO'], $role->getReachableRoleNames(['ROLE_FOO'])); + $this->assertEquals(['ROLE_ADMIN', 'ROLE_USER'], $role->getReachableRoleNames(['ROLE_ADMIN'])); + $this->assertEquals(['ROLE_FOO', 'ROLE_ADMIN', 'ROLE_USER'], $role->getReachableRoleNames(['ROLE_FOO', 'ROLE_ADMIN'])); + $this->assertEquals(['ROLE_SUPER_ADMIN', 'ROLE_ADMIN', 'ROLE_FOO', 'ROLE_USER'], $role->getReachableRoleNames(['ROLE_SUPER_ADMIN'])); } } diff --git a/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php b/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php index 8bcb960aa66ed..b037aaaaa8bd5 100644 --- a/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Controller/UserValueResolverTest.php @@ -17,7 +17,6 @@ use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DefaultValueResolver; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\Controller\UserValueResolver; diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index 1468df66126bf..fad023cd52309 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -113,8 +113,8 @@ public function testExitUserUpdatesToken() */ public function testExitUserBasedOnSwitchUserRoleUpdatesToken() { - $originalToken = new UsernamePasswordToken('username', '', 'key', array()); - $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', array(new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)), $originalToken)); + $originalToken = new UsernamePasswordToken('username', '', 'key', []); + $this->tokenStorage->setToken(new UsernamePasswordToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)], $originalToken)); $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); diff --git a/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php b/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php index 12166602474ba..fbdaf3d57e1ed 100644 --- a/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Logout/LogoutUrlGeneratorTest.php @@ -16,7 +16,6 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator; diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php index 8e7a9cb779749..6099cf20c8ad6 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php @@ -5,10 +5,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\EventListener\ExpressionLanguage; From 92bdc9b5f4d798c52b82ca05ba70e82a4d561fbc Mon Sep 17 00:00:00 2001 From: Soufian EZ ZANTAR Date: Sun, 18 Nov 2018 18:32:00 +0100 Subject: [PATCH 158/495] [FrameworkBundle] Added the condition routing option to the debug router command --- .../FrameworkBundle/Console/Descriptor/JsonDescriptor.php | 8 +++++++- .../Console/Descriptor/MarkdownDescriptor.php | 4 ++++ .../FrameworkBundle/Console/Descriptor/TextDescriptor.php | 4 ++++ .../FrameworkBundle/Console/Descriptor/XmlDescriptor.php | 5 +++++ .../Tests/Console/Descriptor/ObjectsProvider.php | 3 ++- .../Tests/Fixtures/Descriptor/route_2.json | 3 ++- .../FrameworkBundle/Tests/Fixtures/Descriptor/route_2.md | 1 + .../FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt | 1 + .../FrameworkBundle/Tests/Fixtures/Descriptor/route_2.xml | 1 + .../Tests/Fixtures/Descriptor/route_collection_1.json | 3 ++- .../Tests/Fixtures/Descriptor/route_collection_1.md | 1 + .../Tests/Fixtures/Descriptor/route_collection_1.xml | 1 + 12 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index e9650c7a9f31c..e19a764b05190 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -193,7 +193,7 @@ private function writeData(array $data, array $options) */ protected function getRouteData(Route $route) { - return array( + $data = array( 'path' => $route->getPath(), 'pathRegex' => $route->compile()->getRegex(), 'host' => '' !== $route->getHost() ? $route->getHost() : 'ANY', @@ -205,6 +205,12 @@ protected function getRouteData(Route $route) 'requirements' => $route->getRequirements() ?: 'NO CUSTOM', 'options' => $route->getOptions(), ); + + if ('' !== $route->getCondition()) { + $data['condition'] = $route->getCondition(); + } + + return $data; } private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false): array diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 9a93695e56fdc..49f59eda9257b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -60,6 +60,10 @@ protected function describeRoute(Route $route, array $options = array()) ."\n".'- Requirements: '.($route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM') ."\n".'- Options: '.$this->formatRouterConfig($route->getOptions()); + if ('' !== $route->getCondition()) { + $output .= "\n".'- Condition: '.$route->getCondition(); + } + $this->write(isset($options['name']) ? $options['name']."\n".str_repeat('-', \strlen($options['name']))."\n\n".$output : $output); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 90cd0e5254aab..5615069e218e4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -92,6 +92,10 @@ protected function describeRoute(Route $route, array $options = array()) array('Options', $this->formatRouterConfig($route->getOptions())), ); + if ('' !== $route->getCondition()) { + $tableRows[] = array('Condition', $route->getCondition()); + } + $table = new Table($this->getOutput()); $table->setHeaders($tableHeaders)->setRows($tableRows); $table->render(); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index ead8fd3744a66..68b4a806cc4ed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -215,6 +215,11 @@ private function getRouteDocument(Route $route, string $name = null): \DOMDocume } } + if ('' !== $route->getCondition()) { + $routeXML->appendChild($hostXML = $dom->createElement('condition')); + $hostXML->appendChild(new \DOMText($route->getCondition())); + } + return $dom; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index 666b77b30a2c4..ccfe07e3d9a2e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -53,7 +53,8 @@ public static function getRoutes() array('opt1' => 'val1', 'opt2' => 'val2'), 'localhost', array('http', 'https'), - array('put', 'post') + array('put', 'post'), + "context.getMethod() in ['GET', 'HEAD', 'POST']" ), ); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json index e190ef0cbf89a..5b70dde63acef 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json @@ -12,5 +12,6 @@ "compiler_class": "Symfony\\Component\\Routing\\RouteCompiler", "opt1": "val1", "opt2": "val2" - } + }, + "condition": "context.getMethod() in ['GET', 'HEAD', 'POST']" } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.md index 1d776c5ffe49e..c60a6296b28db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.md @@ -11,3 +11,4 @@ - `compiler_class`: Symfony\Component\Routing\RouteCompiler - `opt1`: val1 - `opt2`: val2 +- Condition: context.getMethod() in ['GET', 'HEAD', 'POST'] \ No newline at end of file diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt index 5593cc0d81ab0..5853dd013d3a3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.txt @@ -14,4 +14,5 @@ | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | | | opt1: val1 | | | opt2: val2 | +| Condition | context.getMethod() in ['GET', 'HEAD', 'POST'] | +--------------+-------------------------------------------------------------------+ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.xml index 584ab1b12de59..f06a5f0cc30c2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.xml @@ -11,4 +11,5 @@ + context.getMethod() in ['GET', 'HEAD', 'POST'] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json index bd60070ed5cf4..200108a166aac 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json @@ -33,6 +33,7 @@ "compiler_class": "Symfony\\Component\\Routing\\RouteCompiler", "opt1": "val1", "opt2": "val2" - } + }, + "condition": "context.getMethod() in ['GET', 'HEAD', 'POST']" } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.md index cbb70b4d31736..432001f0247fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.md @@ -34,4 +34,5 @@ route_2 - `compiler_class`: Symfony\Component\Routing\RouteCompiler - `opt1`: val1 - `opt2`: val2 +- Condition: context.getMethod() in ['GET', 'HEAD', 'POST'] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.xml index 666a53730dee0..6a07e059649c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.xml @@ -31,5 +31,6 @@ + context.getMethod() in ['GET', 'HEAD', 'POST'] From 0db9b30e1494b4165df3d320a1bbd39b8f90aca1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Mar 2019 10:25:03 +0100 Subject: [PATCH 159/495] fixed typo --- .../FrameworkBundle/Console/Descriptor/XmlDescriptor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index e1c3671327614..db0f346ebd72d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -216,8 +216,8 @@ private function getRouteDocument(Route $route, string $name = null): \DOMDocume } if ('' !== $route->getCondition()) { - $routeXML->appendChild($hostXML = $dom->createElement('condition')); - $hostXML->appendChild(new \DOMText($route->getCondition())); + $routeXML->appendChild($conditionXML = $dom->createElement('condition')); + $conditionXML->appendChild(new \DOMText($route->getCondition())); } return $dom; From 93c10013fa3370b38f73e2a0febd22d1b14aa385 Mon Sep 17 00:00:00 2001 From: Eric Masoero Date: Mon, 25 Feb 2019 10:32:52 +0100 Subject: [PATCH 160/495] [Messenger] Added new TransportException which is thrown if transport could not send a message --- UPGRADE-4.3.md | 5 +++++ src/Symfony/Component/Messenger/CHANGELOG.md | 5 +++++ .../Exception/TransportException.php | 21 +++++++++++++++++++ .../Transport/AmqpExt/AmqpSenderTest.php | 18 ++++++++++++++++ .../Transport/AmqpExt/AmqpSender.php | 7 ++++++- 5 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Messenger/Exception/TransportException.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 6c348a3403637..d81e393c44072 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -50,6 +50,11 @@ HttpFoundation * The `FileinfoMimeTypeGuesser` class has been deprecated, use `Symfony\Component\Mime\FileinfoMimeTypeGuesser` instead. +Messenger +--------- + + * `Amqp` transport does not throw `\AMQPException` anymore, catch `TransportException` instead. + Routing ------- diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index ff901be210f10..c7d0aad8ea73e 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -11,6 +11,11 @@ CHANGELOG changed from `Serializer` to `PhpSerializer` inside `AmqpReceiver`, `AmqpSender`, `AmqpTransport` and `AmqpTransportFactory`. + * Added `TransportException` to mark an exception transport-related + + * [BC BREAK] If listening to exceptions while using `AmqpSender`, `\AMQPException` is + no longer thrown in favor of `TransportException`. + 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Exception/TransportException.php b/src/Symfony/Component/Messenger/Exception/TransportException.php new file mode 100644 index 0000000000000..e94daba20993b --- /dev/null +++ b/src/Symfony/Component/Messenger/Exception/TransportException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * @author Eric Masoero + * + * @experimental in 4.2 + */ +class TransportException extends RuntimeException +{ +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php index caef14c9e2b1a..4ca0287d68a0c 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php @@ -37,4 +37,22 @@ public function testItSendsTheEncodedMessage() $sender = new AmqpSender($connection, $serializer); $sender->send($envelope); } + + /** + * @expectedException Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsATransportExceptionIfItCannotSendTheMessage() + { + $envelope = new Envelope(new DummyMessage('Oy')); + $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; + + $serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(); + $serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded); + + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $connection->method('publish')->with($encoded['body'], $encoded['headers'])->willThrowException(new \AMQPException()); + + $sender = new AmqpSender($connection, $serializer); + $sender->send($envelope); + } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php index 74ab0dfaa92aa..53ba10e4faabd 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Transport\AmqpExt; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\TransportException; use Symfony\Component\Messenger\Transport\Sender\SenderInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -41,7 +42,11 @@ public function send(Envelope $envelope): Envelope { $encodedMessage = $this->serializer->encode($envelope); - $this->connection->publish($encodedMessage['body'], $encodedMessage['headers']); + try { + $this->connection->publish($encodedMessage['body'], $encodedMessage['headers']); + } catch (\AMQPException $e) { + throw new TransportException('Current transport was not able to send given message, please try again'); + } return $envelope; } From 06c84040c4bbf3228351333b0a066fcf924871ee Mon Sep 17 00:00:00 2001 From: "nikos.sotiropoulos" Date: Wed, 20 Feb 2019 01:41:21 +0200 Subject: [PATCH 161/495] forgot one backslash, my bad --- .../Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php index 4ca0287d68a0c..7fcb41c15970a 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php @@ -39,7 +39,7 @@ public function testItSendsTheEncodedMessage() } /** - * @expectedException Symfony\Component\Messenger\Exception\TransportException + * @expectedException \Symfony\Component\Messenger\Exception\TransportException */ public function testItThrowsATransportExceptionIfItCannotSendTheMessage() { From b2b0640d807264973883121b55ff1cfbf3f63a29 Mon Sep 17 00:00:00 2001 From: Eric Masoero Date: Mon, 25 Feb 2019 11:24:06 +0100 Subject: [PATCH 162/495] Chain new exception with previous one --- .../Component/Messenger/Transport/AmqpExt/AmqpSender.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php index 53ba10e4faabd..72731c6312f34 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php @@ -45,7 +45,7 @@ public function send(Envelope $envelope): Envelope try { $this->connection->publish($encodedMessage['body'], $encodedMessage['headers']); } catch (\AMQPException $e) { - throw new TransportException('Current transport was not able to send given message, please try again'); + throw new TransportException('Current transport was not able to send given message, please try again', 0, $e); } return $envelope; From 62a08eeea07e4f926e6f9839fda844d3bc8c3bbe Mon Sep 17 00:00:00 2001 From: Eric Masoero Date: Wed, 27 Feb 2019 11:06:42 +0100 Subject: [PATCH 163/495] Updated exception message in AmqpSender, updated AmqpReceiver to throw new TransportException --- .../Transport/AmqpExt/AmqpReceiverTest.php | 77 +++++++++++++++++++ .../Transport/AmqpExt/AmqpReceiver.php | 15 +++- .../Transport/AmqpExt/AmqpSender.php | 2 +- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php index 23f1c8b2defd9..8e224e0653df7 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php @@ -101,6 +101,83 @@ public function testItRejectsTheMessageIfTheExceptionIsARejectMessageExceptionIn throw new WillNeverWorkException('Well...'); }); } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() + { + $serializer = new Serializer( + new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) + ); + + $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); + $envelope->method('getBody')->willReturn('{"message": "Hi"}'); + $envelope->method('getHeaders')->willReturn([ + 'type' => DummyMessage::class, + ]); + + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $connection->method('get')->willReturn($envelope); + + $connection->method('ack')->with($envelope)->willThrowException(new \AMQPException()); + + $receiver = new AmqpReceiver($connection, $serializer); + $receiver->receive(function (?Envelope $envelope) use ($receiver) { + $receiver->stop(); + }); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsATransportExceptionIfItCannotRejectMessage() + { + $serializer = new Serializer( + new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) + ); + + $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); + $envelope->method('getBody')->willReturn('{"message": "Hi"}'); + $envelope->method('getHeaders')->willReturn([ + 'type' => DummyMessage::class, + ]); + + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $connection->method('get')->willReturn($envelope); + $connection->method('reject')->with($envelope)->willThrowException(new \AMQPException()); + + $receiver = new AmqpReceiver($connection, $serializer); + $receiver->receive(function () { + throw new WillNeverWorkException('Well...'); + }); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsATransportExceptionIfItCannotNonAcknowledgeMessage() + { + $serializer = new Serializer( + new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) + ); + + $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); + $envelope->method('getBody')->willReturn('{"message": "Hi"}'); + $envelope->method('getHeaders')->willReturn([ + 'type' => DummyMessage::class, + ]); + + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $connection->method('get')->willReturn($envelope); + + $connection->method('nack')->with($envelope)->willThrowException(new \AMQPException()); + + $receiver = new AmqpReceiver($connection, $serializer); + $receiver->receive(function () { + throw new InterruptException('Well...'); + }); + } } class InterruptException extends \Exception diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index fdd81cac543ab..cb7a4db013fa9 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Messenger\Transport\AmqpExt; +use Symfony\Component\Messenger\Exception\TransportException; use Symfony\Component\Messenger\Transport\AmqpExt\Exception\RejectMessageExceptionInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; @@ -61,11 +62,21 @@ public function receive(callable $handler): void $this->connection->ack($AMQPEnvelope); } catch (RejectMessageExceptionInterface $e) { - $this->connection->reject($AMQPEnvelope); + try { + $this->connection->reject($AMQPEnvelope); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } throw $e; + } catch (\AMQPException $e) { + throw new TransportException($e->getMessage(), 0, $e); } catch (\Throwable $e) { - $this->connection->nack($AMQPEnvelope, AMQP_REQUEUE); + try { + $this->connection->nack($AMQPEnvelope, AMQP_REQUEUE); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } throw $e; } finally { diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php index 72731c6312f34..e9760ac2eb6ec 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php @@ -45,7 +45,7 @@ public function send(Envelope $envelope): Envelope try { $this->connection->publish($encodedMessage['body'], $encodedMessage['headers']); } catch (\AMQPException $e) { - throw new TransportException('Current transport was not able to send given message, please try again', 0, $e); + throw new TransportException($e->getMessage(), 0, $e); } return $envelope; From 7d6a3fa487940afcaadf7f531d4a3e51fa596c41 Mon Sep 17 00:00:00 2001 From: Eric Masoero Date: Wed, 27 Feb 2019 11:20:43 +0100 Subject: [PATCH 164/495] Updated changelog to document changes in AmqpReceiver --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index c7d0aad8ea73e..b7f604f41c00c 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -13,7 +13,7 @@ CHANGELOG * Added `TransportException` to mark an exception transport-related - * [BC BREAK] If listening to exceptions while using `AmqpSender`, `\AMQPException` is + * [BC BREAK] If listening to exceptions while using `AmqpSender` or `AmqpReceiver`, `\AMQPException` is no longer thrown in favor of `TransportException`. 4.2.0 From 774a89c0852bef30bf9b220974845f863555fb39 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 4 Mar 2019 11:38:54 +0100 Subject: [PATCH 165/495] moved XSD to HTTPS --- .../Bundle/FrameworkBundle/Resources/config/mime_type.xml | 2 +- .../DependencyInjection/Fixtures/xml/logout_delete_cookies.xml | 2 +- .../Tests/Fixtures/xml/deprecated_alias_definitions.xml | 2 +- .../Tests/Fixtures/xml/services_with_tagged_arguments.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mime_type.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mime_type.xml index 5153028d505e2..d4c1eb15b9088 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mime_type.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mime_type.xml @@ -2,7 +2,7 @@ + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml index 3243650c3294a..34b4a429e5fc3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml @@ -3,7 +3,7 @@ + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/deprecated_alias_definitions.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/deprecated_alias_definitions.xml index 69b9bbb15ea70..860f1c0d2b616 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/deprecated_alias_definitions.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/deprecated_alias_definitions.xml @@ -1,5 +1,5 @@ - + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml index 01022cc0e6d81..e979d5fc9be38 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml @@ -1,5 +1,5 @@ - + From aa6a60ead6c0d1074e40d7520dc4ad017e4e23a7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 4 Mar 2019 11:50:13 +0100 Subject: [PATCH 166/495] [Contracts] bump branch alias --- src/Symfony/Contracts/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Contracts/composer.json b/src/Symfony/Contracts/composer.json index 2f198a0c3b330..b01744783f6fd 100644 --- a/src/Symfony/Contracts/composer.json +++ b/src/Symfony/Contracts/composer.json @@ -38,7 +38,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.1-dev" } } } From 22ef4589a9b339a135ce2cf04f5c6da6cac6de75 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 4 Mar 2019 13:19:55 +0100 Subject: [PATCH 167/495] add back accidentally removed code --- .../FrameworkBundle/Console/Descriptor/JsonDescriptor.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index a8815bfdb4803..137114ebe7161 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -205,6 +205,12 @@ protected function getRouteData(Route $route) 'requirements' => $route->getRequirements() ?: 'NO CUSTOM', 'options' => $route->getOptions(), ]; + + if ('' !== $route->getCondition()) { + $data['condition'] = $route->getCondition(); + } + + return $data; } private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, bool $showArguments = false): array From fff93acf92fd92becd15180bd0d2234fdcf01ae8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 4 Mar 2019 14:12:17 +0100 Subject: [PATCH 168/495] [Mime] remove some @final annotations --- src/Symfony/Component/Mime/Encoder/QpEncoder.php | 2 -- src/Symfony/Component/Mime/Header/UnstructuredHeader.php | 2 -- src/Symfony/Component/Mime/Part/DataPart.php | 2 -- src/Symfony/Component/Mime/Part/TextPart.php | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/Symfony/Component/Mime/Encoder/QpEncoder.php b/src/Symfony/Component/Mime/Encoder/QpEncoder.php index 5b82848cebdca..4ffbaed78e9e4 100644 --- a/src/Symfony/Component/Mime/Encoder/QpEncoder.php +++ b/src/Symfony/Component/Mime/Encoder/QpEncoder.php @@ -14,8 +14,6 @@ use Symfony\Component\Mime\CharacterStream; /** - * @final - * * @author Chris Corbyn * * @experimental in 4.3 diff --git a/src/Symfony/Component/Mime/Header/UnstructuredHeader.php b/src/Symfony/Component/Mime/Header/UnstructuredHeader.php index 269e00eee8f9f..afb96152570f0 100644 --- a/src/Symfony/Component/Mime/Header/UnstructuredHeader.php +++ b/src/Symfony/Component/Mime/Header/UnstructuredHeader.php @@ -14,8 +14,6 @@ /** * A Simple MIME Header. * - * @final - * * @author Chris Corbyn * * @experimental in 4.3 diff --git a/src/Symfony/Component/Mime/Part/DataPart.php b/src/Symfony/Component/Mime/Part/DataPart.php index ccbf12ebf4f18..1cfb1e69b08d0 100644 --- a/src/Symfony/Component/Mime/Part/DataPart.php +++ b/src/Symfony/Component/Mime/Part/DataPart.php @@ -16,8 +16,6 @@ use Symfony\Component\Mime\MimeTypes; /** - * @final - * * @author Fabien Potencier * * @experimental in 4.3 diff --git a/src/Symfony/Component/Mime/Part/TextPart.php b/src/Symfony/Component/Mime/Part/TextPart.php index aed312c2408e9..323f62eccec74 100644 --- a/src/Symfony/Component/Mime/Part/TextPart.php +++ b/src/Symfony/Component/Mime/Part/TextPart.php @@ -18,8 +18,6 @@ use Symfony\Component\Mime\Header\Headers; /** - * @final - * * @author Fabien Potencier * * @experimental in 4.3 From c5b12479772038fe43c8d8b56fdf58d2f8a01507 Mon Sep 17 00:00:00 2001 From: Emmanuel BORGES Date: Wed, 27 Feb 2019 09:03:04 +0100 Subject: [PATCH 169/495] [FrameworkBundle] Fix UrlGenerator::generate to return an empty string instead of null --- UPGRADE-4.3.md | 1 + .../Routing/Generator/ConfigurableRequirementsInterface.php | 2 +- src/Symfony/Component/Routing/Generator/UrlGenerator.php | 4 ++-- .../Component/Routing/Tests/Generator/UrlGeneratorTest.php | 6 +++--- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index d81e393c44072..5bc2fcc022bb7 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -37,6 +37,7 @@ FrameworkBundle * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will be mandatory in 5.0. * Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead. + * The `generate()` method of the `UrlGenerator` class can return an empty string instead of null. HttpFoundation -------------- diff --git a/src/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php b/src/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php index dc97b7e724f7f..2e5dc5325bddf 100644 --- a/src/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php +++ b/src/Symfony/Component/Routing/Generator/ConfigurableRequirementsInterface.php @@ -20,7 +20,7 @@ * The possible configurations and use-cases: * - setStrictRequirements(true): Throw an exception for mismatching requirements. This * is mostly useful in development environment. - * - setStrictRequirements(false): Don't throw an exception but return null as URL for + * - setStrictRequirements(false): Don't throw an exception but return an empty string as URL for * mismatching requirements and log the problem. Useful when you cannot control all * params because they come from third party libs but don't want to have a 404 in * production environment. It should log the mismatch so one can review it. diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 729d2b0f38d54..fb53f8c1cd414 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -171,7 +171,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $this->logger->error($message, ['parameter' => $varName, 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$varName]]); } - return; + return ''; } $url = $token[1].$mergedParams[$varName].$url; @@ -226,7 +226,7 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $this->logger->error($message, ['parameter' => $token[3], 'route' => $name, 'expected' => $token[2], 'given' => $mergedParams[$token[3]]]); } - return; + return ''; } $routeHost = $token[1].$mergedParams[$token[3]].$routeHost; diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index 6ed5aa1787d04..86eb2e5dc3c30 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -203,7 +203,7 @@ public function testGenerateForRouteWithInvalidOptionalParameterNonStrict() $routes = $this->getRoutes('test', new Route('/testing/{foo}', ['foo' => '1'], ['foo' => 'd+'])); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(false); - $this->assertNull($generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertSame('', $generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger() @@ -214,7 +214,7 @@ public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLog ->method('error'); $generator = $this->getGenerator($routes, [], $logger); $generator->setStrictRequirements(false); - $this->assertNull($generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); + $this->assertSame('', $generator->generate('test', ['foo' => 'bar'], UrlGeneratorInterface::ABSOLUTE_URL)); } public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck() @@ -489,7 +489,7 @@ public function testUrlWithInvalidParameterInHostInNonStrictMode() $routes = $this->getRoutes('test', new Route('/', [], ['foo' => 'bar'], [], '{foo}.example.com')); $generator = $this->getGenerator($routes); $generator->setStrictRequirements(false); - $this->assertNull($generator->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH)); + $this->assertSame('', $generator->generate('test', ['foo' => 'baz'], UrlGeneratorInterface::ABSOLUTE_PATH)); } public function testHostIsCaseInsensitive() From 375ac9237f990d780ba2124c71949fcea0596de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jib=C3=A9=20Barth?= Date: Mon, 4 Mar 2019 20:56:49 +0100 Subject: [PATCH 170/495] [Mime] Fix generate message id with named address --- src/Symfony/Component/Mime/Message.php | 2 +- src/Symfony/Component/Mime/Tests/MessageTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Message.php b/src/Symfony/Component/Mime/Message.php index 18aac00f3d9b8..f64ffebf8326d 100644 --- a/src/Symfony/Component/Mime/Message.php +++ b/src/Symfony/Component/Mime/Message.php @@ -97,7 +97,7 @@ public function getPreparedHeaders(): Headers } if (!$headers->has('Message-ID')) { - $headers->addIdHeader('Message-ID', $this->generateMessageId($sender->toString())); + $headers->addIdHeader('Message-ID', $this->generateMessageId($sender->getAddress())); } // remove the Bcc field which should NOT be part of the sent message diff --git a/src/Symfony/Component/Mime/Tests/MessageTest.php b/src/Symfony/Component/Mime/Tests/MessageTest.php index f366e4e6bf83b..888e77e245bc3 100644 --- a/src/Symfony/Component/Mime/Tests/MessageTest.php +++ b/src/Symfony/Component/Mime/Tests/MessageTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Mime\Header\MailboxListHeader; use Symfony\Component\Mime\Header\UnstructuredHeader; use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\NamedAddress; use Symfony\Component\Mime\Part\TextPart; class MessageTest extends TestCase @@ -90,6 +91,15 @@ public function testGetPreparedHeadersWithNoFrom() (new Message())->getPreparedHeaders(); } + public function testGetPreparedHeadersWithNamedFrom() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', [new NamedAddress('fabien@symfony.com', 'Fabien')]); + $h = $message->getPreparedHeaders(); + $this->assertEquals(new MailboxListHeader('From', [new NamedAddress('fabien@symfony.com', 'Fabien')]), $h->get('From')); + $this->assertTrue($h->has('Message-Id')); + } + public function testGetPreparedHeadersHasSenderWhenNeeded() { $message = new Message(); From 3dd86719bf64943b8415940c23beb72f3edaa333 Mon Sep 17 00:00:00 2001 From: Gary PEGEOT Date: Wed, 20 Feb 2019 22:09:05 +0000 Subject: [PATCH 171/495] [HttpKernel] Prevent search engines from indexing dev applications --- .../DependencyInjection/Configuration.php | 14 ++++++ .../FrameworkExtension.php | 4 ++ .../FrameworkBundle/Resources/config/web.xml | 3 ++ .../DependencyInjection/ConfigurationTest.php | 1 + .../FrameworkExtensionTest.php | 21 +++++++++ src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../DisallowRobotsIndexingListener.php | 43 +++++++++++++++++ .../DisallowRobotsIndexingListenerTest.php | 47 +++++++++++++++++++ 8 files changed, 134 insertions(+) create mode 100644 src/Symfony/Component/HttpKernel/EventListener/DisallowRobotsIndexingListener.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0d2aa264adce2..421f669c952b0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -108,6 +108,7 @@ public function getConfigTreeBuilder() $this->addWebLinkSection($rootNode); $this->addLockSection($rootNode); $this->addMessengerSection($rootNode); + $this->addRobotsIndexSection($rootNode); return $treeBuilder; } @@ -1156,4 +1157,17 @@ function ($a) { ->end() ; } + + private function addRobotsIndexSection(ArrayNodeDefinition $rootNode) + { + $rootNode + ->children() + ->booleanNode('disallow_search_engine_index') + ->info('Enabled by default when debug is enabled.') + ->defaultValue($this->debug) + ->treatNullLike($this->debug) + ->end() + ->end() + ; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 714d92379dd26..874aeaa9773b9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -394,6 +394,10 @@ public function load(array $configs, ContainerBuilder $container) // remove tagged iterator argument for resource checkers $container->getDefinition('config_cache_factory')->setArguments([]); } + + if (!$config['disallow_search_engine_index'] ?? false) { + $container->removeDefinition('disallow_search_engine_index_response_listener'); + } } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml index 41c682c2111c7..07aa84c9cc033 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/web.xml @@ -85,5 +85,8 @@ + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 2ddf9175f310b..589ddf50a63fe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -330,6 +330,7 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'default_bus' => null, 'buses' => ['messenger.bus.default' => ['default_middleware' => true, 'middleware' => []]], ], + 'disallow_search_engine_index' => true, ]; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 6d3563d0781c9..586a3811e2277 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -1327,6 +1327,27 @@ public function testSessionCookieSecureAuto() $this->assertEquals($expected, array_keys($container->getDefinition('session_listener')->getArgument(0)->getValues())); } + public function testRobotsTagListenerIsRegisteredInDebugMode() + { + $container = $this->createContainer(['kernel.debug' => true]); + (new FrameworkExtension())->load([], $container); + $this->assertTrue($container->has('disallow_search_engine_index_response_listener'), 'DisallowRobotsIndexingListener should be registered'); + + $definition = $container->getDefinition('disallow_search_engine_index_response_listener'); + $this->assertTrue($definition->hasTag('kernel.event_subscriber'), 'DisallowRobotsIndexingListener should have the correct tag'); + + $container = $this->createContainer(['kernel.debug' => true]); + (new FrameworkExtension())->load([['disallow_search_engine_index' => false]], $container); + $this->assertFalse( + $container->has('disallow_search_engine_index_response_listener'), + 'DisallowRobotsIndexingListener should not be registered when explicitly disabled' + ); + + $container = $this->createContainer(['kernel.debug' => false]); + (new FrameworkExtension())->load([], $container); + $this->assertFalse($container->has('disallow_search_engine_index_response_listener'), 'DisallowRobotsIndexingListener should NOT be registered'); + } + protected function createContainer(array $data = []) { return new ContainerBuilder(new ParameterBag(array_merge([ diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 8a923812b5285..0fe512b30a291 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -12,6 +12,7 @@ CHANGELOG * the base `DataCollector` doesn't implement `Serializable` anymore, you should store all the serialized state in the data property instead * `DumpDataCollector` has been marked as `final` + * added an event listener to prevent search engines from indexing applications in debug mode. 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/EventListener/DisallowRobotsIndexingListener.php b/src/Symfony/Component/HttpKernel/EventListener/DisallowRobotsIndexingListener.php new file mode 100644 index 0000000000000..280bd90d069b6 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/EventListener/DisallowRobotsIndexingListener.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +/** + * Ensures that the application is not indexed by search engines. + * + * @author Gary PEGEOT + */ +class DisallowRobotsIndexingListener implements EventSubscriberInterface +{ + private const HEADER_NAME = 'X-Robots-Tag'; + + public function onResponse(FilterResponseEvent $event): void + { + if (!$event->getResponse()->headers->has(static::HEADER_NAME)) { + $event->getResponse()->headers->set(static::HEADER_NAME, 'noindex'); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + KernelEvents::RESPONSE => ['onResponse', -255], + ]; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php new file mode 100644 index 0000000000000..b50ace673b14b --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\EventListener; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\EventListener\DisallowRobotsIndexingListener; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelInterface; + +class DisallowRobotsIndexingListenerTest extends TestCase +{ + /** + * @dataProvider provideResponses + */ + public function testInvoke(?string $expected, Response $response): void + { + $listener = new DisallowRobotsIndexingListener(); + + $event = new FilterResponseEvent($this->createMock(HttpKernelInterface::class), $this->createMock(Request::class), KernelInterface::MASTER_REQUEST, $response); + + $listener->onResponse($event); + + $this->assertSame($expected, $response->headers->get('X-Robots-Tag'), 'Header doesn\'t match expectations'); + } + + public function provideResponses(): iterable + { + yield 'No header' => ['noindex', new Response()]; + + yield 'Header already set' => [ + 'something else', + new Response('', 204, ['X-Robots-Tag' => 'something else']), + ]; + } +} From f6c1622fb581534b6f36b5c92eba7ff1bd8375be Mon Sep 17 00:00:00 2001 From: Dmytro Date: Thu, 28 Feb 2019 17:21:40 +0200 Subject: [PATCH 172/495] [HttpKernel] Better exception page when the invokable controller returns nothing --- .../ControllerDoesNotReturnResponseException.php | 8 +++++++- .../Component/HttpKernel/Tests/HttpKernelTest.php | 13 ++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Exception/ControllerDoesNotReturnResponseException.php b/src/Symfony/Component/HttpKernel/Exception/ControllerDoesNotReturnResponseException.php index 517313db60466..1e87690ff1cc8 100644 --- a/src/Symfony/Component/HttpKernel/Exception/ControllerDoesNotReturnResponseException.php +++ b/src/Symfony/Component/HttpKernel/Exception/ControllerDoesNotReturnResponseException.php @@ -67,9 +67,15 @@ private function parseControllerDefinition(callable $controller): ?array if (\is_object($controller)) { $r = new \ReflectionClass($controller); + try { + $line = $r->getMethod('__invoke')->getEndLine(); + } catch (\ReflectionException $e) { + $line = $r->getEndLine(); + } + return [ 'file' => $r->getFileName(), - 'line' => $r->getEndLine(), + 'line' => $line, ]; } diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php index 4d1e267e3acdd..40a63f4d07192 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpKernelTest.php @@ -215,20 +215,19 @@ public function testHandleWhenTheControllerIsAStaticArray() public function testHandleWhenTheControllerDoesNotReturnAResponse() { $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, function () { return 'foo'; }); + $kernel = $this->getHttpKernel($dispatcher, function () {}); try { $kernel->handle(new Request()); $this->fail('The kernel should throw an exception.'); } catch (ControllerDoesNotReturnResponseException $e) { - } + $first = $e->getTrace()[0]; - $first = $e->getTrace()[0]; - - // `file` index the array starting at 0, and __FILE__ starts at 1 - $line = file($first['file'])[$first['line'] - 2]; - $this->assertContains('// call controller', $line); + // `file` index the array starting at 0, and __FILE__ starts at 1 + $line = file($first['file'])[$first['line'] - 2]; + $this->assertContains('// call controller', $line); + } } public function testHandleWhenTheControllerDoesNotReturnAResponseButAViewIsRegistered() From 9aeaea06fcc74181690f446ed5e2d5875a23a118 Mon Sep 17 00:00:00 2001 From: Ken Stanley Date: Tue, 9 Oct 2018 15:39:40 -0400 Subject: [PATCH 173/495] =?UTF-8?q?Add=20=E2=80=98symbol=E2=80=99=20option?= =?UTF-8?q?=20to=20PercentType?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/Form/bootstrap_4_layout.html.twig | 14 ++++--- .../Form/bootstrap_base_layout.html.twig | 10 +++-- .../views/Form/form_div_layout.html.twig | 2 +- .../views/Form/foundation_5_layout.html.twig | 18 +++++--- .../AbstractBootstrap3LayoutTest.php | 37 +++++++++++++++++ .../AbstractBootstrap4LayoutTest.php | 41 +++++++++++++++++++ .../views/Form/percent_widget.html.php | 14 ++++++- src/Symfony/Component/Form/CHANGELOG.md | 1 + .../Form/Extension/Core/Type/PercentType.php | 12 ++++++ .../Form/Tests/AbstractLayoutTest.php | 28 +++++++++++++ 10 files changed, 161 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig index 0b301b42cc4ad..03109bdf6cac2 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig @@ -106,12 +106,16 @@ {%- endblock dateinterval_widget %} {% block percent_widget -%} -
- {{- block('form_widget_simple') -}} -
- % + {%- if symbol -%} +
+ {{- block('form_widget_simple') -}} +
+ {{ symbol|default('%') }} +
-
+ {%- else -%} + {{- block('form_widget_simple') -}} + {%- endif -%} {%- endblock percent_widget %} {% block file_widget -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_base_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_base_layout.html.twig index 136cabccb19ed..a6ee019a094b6 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_base_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_base_layout.html.twig @@ -26,10 +26,14 @@ {%- endblock money_widget %} {% block percent_widget -%} -
+ {%- if symbol -%} +
+ {{- block('form_widget_simple') -}} + {{ symbol|default('%') }} +
+ {%- else -%} {{- block('form_widget_simple') -}} - % -
+ {%- endif -%} {%- endblock percent_widget %} {% block datetime_widget -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 52a639a33365f..1d7ad1c328649 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -196,7 +196,7 @@ {%- block percent_widget -%} {%- set type = type|default('text') -%} - {{ block('form_widget_simple') }} % + {{ block('form_widget_simple') }}{% if symbol %} {{ symbol|default('%') }}{% endif %} {%- endblock percent_widget -%} {%- block password_widget -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig index 3ae67935fb758..9547ea4900fe6 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig @@ -43,12 +43,18 @@ {% block percent_widget -%}
-
- {{- block('form_widget_simple') -}} -
-
- % -
+ {%- if symbol -%} +
+ {{- block('form_widget_simple') -}} +
+
+ {{ symbol|default('%') }} +
+ {%- else -%} +
+ {{- block('form_widget_simple') -}} +
+ {%- endif -%}
{%- endblock percent_widget %} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 254f9a4d1fc6b..91fb73f64627e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -2173,6 +2173,43 @@ public function testPercent() ); } + public function testPercentNoSymbol() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => false)); + + $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), +'/input + [@id="my&id"] + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="10"] +' + ); + } + + public function testPercentCustomSymbol() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => '‱')); + + $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), +'/div + [@class="input-group"] + [ + ./input + [@id="my&id"] + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="10"] + /following-sibling::span + [@class="input-group-addon"] + [contains(.., "‱")] + ] +' + ); + } + public function testCheckedRadio() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RadioType', true); diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php index d2263ea870217..47c1385dbcb29 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php @@ -1125,6 +1125,47 @@ public function testPercent() [contains(.., "%")] ] ] +' + ); + } + + public function testPercentNoSymbol() + { + $form = $this->factory->createNamed('name', PercentType::class, 0.1, array('symbol' => false)); + + $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), + '/input + [@id="my&id"] + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="10"] +' + ); + } + + public function testPercentCustomSymbol() + { + $form = $this->factory->createNamed('name', PercentType::class, 0.1, array('symbol' => '‱')); + + $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), + '/div + [@class="input-group"] + [ + ./input + [@id="my&id"] + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="10"] + /following-sibling::div + [@class="input-group-append"] + [ + ./span + [@class="input-group-text"] + [contains(.., "‱")] + ] + ] ' ); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php index f5839ebf70203..b5552543bc7bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php @@ -1 +1,13 @@ -block($form, 'form_widget_simple', ['type' => isset($type) ? $type : 'text']) ?> % + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$symbol = $symbol !== false ? (!empty($symbol) ? ' ' . $symbol : ' %') : ''; +echo $view['form']->block($form, 'form_widget_simple', ['type' => isset($type) ? $type : 'text']) . $symbol; ?> diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index f1b399cedc8be..4644e928ef1f2 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added a `symbol` option to the `PercentType` that allows to disable the output of the percent character * Using the `format` option of `DateType` and `DateTimeType` when the `html5` option is enabled is deprecated. * Using names for buttons that do not start with a letter, a digit, or an underscore is deprecated and will lead to an exception in 5.0. diff --git a/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php b/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php index dedb9e8cdd1cb..d45a85f2cfad5 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php @@ -14,6 +14,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\PercentToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; class PercentType extends AbstractType @@ -26,6 +28,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder->addViewTransformer(new PercentToLocalizedStringTransformer($options['scale'], $options['type'])); } + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + $view->vars['symbol'] = $options['symbol']; + } + /** * {@inheritdoc} */ @@ -33,6 +43,7 @@ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ 'scale' => 0, + 'symbol' => '%', 'type' => 'fractional', 'compound' => false, ]); @@ -43,6 +54,7 @@ public function configureOptions(OptionsResolver $resolver) ]); $resolver->setAllowedTypes('scale', 'int'); + $resolver->setAllowedTypes('symbol', array('bool', 'string')); } /** diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 5b4b84e9e5b99..d30de9b37aa84 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -1945,6 +1945,34 @@ public function testPercent() ); } + public function testPercentNoSymbol() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => false)); + + $this->assertWidgetMatchesXpath($form->createView(), array(), +'/input + [@type="text"] + [@name="name"] + [@value="10"] + [not(contains(.., "%"))] +' + ); + } + + public function testPercentCustomSymbol() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => '‱')); + + $this->assertWidgetMatchesXpath($form->createView(), array(), +'/input + [@type="text"] + [@name="name"] + [@value="10"] + [contains(.., "‱")] +' + ); + } + public function testCheckedRadio() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RadioType', true); From 53c5f41f3766dc7a1bffcb755a58eea3b2efbcbf Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 4 Mar 2019 10:16:34 +0100 Subject: [PATCH 174/495] [Form] Allow to disable and customize PercentType symbol --- .../AbstractBootstrap3LayoutTest.php | 21 +++++++------- .../AbstractBootstrap4LayoutTest.php | 28 +++++++++---------- .../views/Form/percent_widget.html.php | 15 ++-------- src/Symfony/Component/Form/CHANGELOG.md | 2 +- .../Form/Extension/Core/Type/PercentType.php | 2 +- .../Form/Tests/AbstractLayoutTest.php | 11 +++++--- 6 files changed, 34 insertions(+), 45 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 91fb73f64627e..489030cd7af12 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Twig\Tests\Extension; +use Symfony\Component\Form\Extension\Core\Type\PercentType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\Tests\AbstractLayoutTest; @@ -2175,24 +2176,22 @@ public function testPercent() public function testPercentNoSymbol() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => false)); - - $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), + $form = $this->factory->createNamed('name', PercentType::class, 0.1, ['symbol' => false]); + $this->assertWidgetMatchesXpath($form->createView(), ['id' => 'my&id', 'attr' => ['class' => 'my&class']], '/input - [@id="my&id"] - [@type="text"] - [@name="name"] - [@class="my&class form-control"] - [@value="10"] + [@id="my&id"] + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="10"] ' ); } public function testPercentCustomSymbol() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => '‱')); - - $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), + $form = $this->factory->createNamed('name', PercentType::class, 0.1, ['symbol' => '‱']); + $this->assertWidgetMatchesXpath($form->createView(), ['id' => 'my&id', 'attr' => ['class' => 'my&class']], '/div [@class="input-group"] [ diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php index 47c1385dbcb29..89fbacf2fc2d7 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php @@ -1082,7 +1082,7 @@ public function testMoney() ]); $this->assertWidgetMatchesXpath($form->createView(), ['id' => 'my&id', 'attr' => ['class' => 'my&class']], - '/div +'/div [@class="input-group"] [ ./div @@ -1108,7 +1108,7 @@ public function testPercent() $form = $this->factory->createNamed('name', PercentType::class, 0.1); $this->assertWidgetMatchesXpath($form->createView(), ['id' => 'my&id', 'attr' => ['class' => 'my&class']], - '/div +'/div [@class="input-group"] [ ./input @@ -1131,25 +1131,23 @@ public function testPercent() public function testPercentNoSymbol() { - $form = $this->factory->createNamed('name', PercentType::class, 0.1, array('symbol' => false)); - - $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), - '/input - [@id="my&id"] - [@type="text"] - [@name="name"] - [@class="my&class form-control"] - [@value="10"] + $form = $this->factory->createNamed('name', PercentType::class, 0.1, ['symbol' => false]); + $this->assertWidgetMatchesXpath($form->createView(), ['id' => 'my&id', 'attr' => ['class' => 'my&class']], +'/input + [@id="my&id"] + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="10"] ' ); } public function testPercentCustomSymbol() { - $form = $this->factory->createNamed('name', PercentType::class, 0.1, array('symbol' => '‱')); - - $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'my&id', 'attr' => array('class' => 'my&class')), - '/div + $form = $this->factory->createNamed('name', PercentType::class, 0.1, ['symbol' => '‱']); + $this->assertWidgetMatchesXpath($form->createView(), ['id' => 'my&id', 'attr' => ['class' => 'my&class']], +'/div [@class="input-group"] [ ./input diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php index b5552543bc7bb..56b417f1d5b5c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php @@ -1,13 +1,2 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -$symbol = $symbol !== false ? (!empty($symbol) ? ' ' . $symbol : ' %') : ''; -echo $view['form']->block($form, 'form_widget_simple', ['type' => isset($type) ? $type : 'text']) . $symbol; ?> + +block($form, 'form_widget_simple', ['type' => isset($type) ? $type : 'text']).$symbol ?> diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 4644e928ef1f2..409153d2be94d 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.3.0 ----- - * added a `symbol` option to the `PercentType` that allows to disable the output of the percent character + * added a `symbol` option to the `PercentType` that allows to disable or customize the output of the percent character * Using the `format` option of `DateType` and `DateTimeType` when the `html5` option is enabled is deprecated. * Using names for buttons that do not start with a letter, a digit, or an underscore is deprecated and will lead to an exception in 5.0. diff --git a/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php b/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php index d45a85f2cfad5..bd141a93697d4 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/PercentType.php @@ -54,7 +54,7 @@ public function configureOptions(OptionsResolver $resolver) ]); $resolver->setAllowedTypes('scale', 'int'); - $resolver->setAllowedTypes('symbol', array('bool', 'string')); + $resolver->setAllowedTypes('symbol', ['bool', 'string']); } /** diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index d30de9b37aa84..c85b449346672 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\SkippedTestError; +use Symfony\Component\Form\Extension\Core\Type\PercentType; use Symfony\Component\Form\Extension\Csrf\CsrfExtension; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormView; @@ -1947,9 +1948,10 @@ public function testPercent() public function testPercentNoSymbol() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => false)); + $this->requiresFeatureSet(403); - $this->assertWidgetMatchesXpath($form->createView(), array(), + $form = $this->factory->createNamed('name', PercentType::class, 0.1, ['symbol' => false]); + $this->assertWidgetMatchesXpath($form->createView(), [], '/input [@type="text"] [@name="name"] @@ -1961,9 +1963,10 @@ public function testPercentNoSymbol() public function testPercentCustomSymbol() { - $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\PercentType', 0.1, array('symbol' => '‱')); + $this->requiresFeatureSet(403); - $this->assertWidgetMatchesXpath($form->createView(), array(), + $form = $this->factory->createNamed('name', PercentType::class, 0.1, ['symbol' => '‱']); + $this->assertWidgetMatchesXpath($form->createView(), [], '/input [@type="text"] [@name="name"] From 7d5b7a3392e2adbb9623642e10862f23915a768f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 8 Nov 2018 17:18:12 +0100 Subject: [PATCH 175/495] [Workflow] Added a context to `Workflow::apply()` --- .../DependencyInjection/Configuration.php | 2 +- .../FrameworkExtension.php | 3 +- .../Resources/config/workflow.xml | 1 + .../FrameworkExtensionTest.php | 4 +- src/Symfony/Component/Workflow/CHANGELOG.md | 1 + .../ValidateWorkflowsPass.php | 6 +- .../MarkingStore/MarkingStoreInterface.php | 5 +- .../MarkingStore/MethodMarkingStore.php | 83 +++++++++++++++++++ .../MultipleStateMarkingStore.php | 2 +- .../MarkingStore/SingleStateMarkingStore.php | 2 +- .../MarkingStore/MethodMarkingStoreTest.php | 74 +++++++++++++++++ src/Symfony/Component/Workflow/Workflow.php | 4 +- .../Component/Workflow/WorkflowInterface.php | 2 +- 13 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php create mode 100644 src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 421f669c952b0..2788cf019f5be 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -268,7 +268,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->fixXmlConfig('argument') ->children() ->enumNode('type') - ->values(['multiple_state', 'single_state']) + ->values(['multiple_state', 'single_state', 'method']) ->end() ->arrayNode('arguments') ->beforeNormalization() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 874aeaa9773b9..a38518b2e9229 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -614,7 +614,8 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $definitionDefinition->addTag('workflow.definition', [ 'name' => $name, 'type' => $type, - 'marking_store' => isset($workflow['marking_store']['type']) ? $workflow['marking_store']['type'] : null, + 'marking_store' => $workflow['marking_store']['type'] ?? null, + 'single_state' => 'method' === ($workflow['marking_store']['type'] ?? null) && ($workflow['marking_store']['arguments'][0] ?? false), ]); // Create MarkingStore diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml index 5f349ea6a0a3c..0bba153b10317 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml @@ -22,6 +22,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 586a3811e2277..b38439349ad3b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -215,7 +215,7 @@ public function testWorkflows() $workflowDefinition->getArgument(0), 'Places are passed to the workflow definition' ); - $this->assertSame(['workflow.definition' => [['name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state']]], $workflowDefinition->getTags()); + $this->assertSame(['workflow.definition' => [['name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state', 'single_state' => false]]], $workflowDefinition->getTags()); $this->assertCount(4, $workflowDefinition->getArgument(1)); $this->assertSame('draft', $workflowDefinition->getArgument(2)); @@ -237,7 +237,7 @@ public function testWorkflows() $stateMachineDefinition->getArgument(0), 'Places are passed to the state machine definition' ); - $this->assertSame(['workflow.definition' => [['name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state']]], $stateMachineDefinition->getTags()); + $this->assertSame(['workflow.definition' => [['name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state', 'single_state' => false]]], $stateMachineDefinition->getTags()); $this->assertCount(9, $stateMachineDefinition->getArgument(1)); $this->assertSame('start', $stateMachineDefinition->getArgument(2)); diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 4668f2f68af17..7e54a59a61e8e 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * Trigger `entered` event for subject entering in the Workflow for the first time + * Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature. 4.1.0 ----- diff --git a/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php b/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php index 175a1f5b96d71..9294a1a7fb426 100644 --- a/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php +++ b/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php @@ -59,6 +59,10 @@ private function createValidator($tag) return new WorkflowValidator(true); } - return new WorkflowValidator(); + if ('multiple_state' === $tag['marking_store']) { + return new WorkflowValidator(false); + } + + return new WorkflowValidator($tag['single_state'] ?? false); } } diff --git a/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php b/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php index 76df9cc0d2160..991a2fc0bdad3 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php @@ -36,8 +36,7 @@ public function getMarking($subject); /** * Sets a Marking to a subject. * - * @param object $subject A subject - * @param Marking $marking A marking + * @param object $subject A subject */ - public function setMarking($subject, Marking $marking); + public function setMarking($subject, Marking $marking, array $context = []); } diff --git a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php new file mode 100644 index 0000000000000..e2e61e7278d85 --- /dev/null +++ b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\MarkingStore; + +use Symfony\Component\Workflow\Exception\LogicException; +use Symfony\Component\Workflow\Marking; + +/** + * MethodMarkingStore stores the marking with a subject's method. + * + * This store deals with a "single state" or "multiple state" Marking. + * + * @author Grégoire Pineau + */ +class MethodMarkingStore implements MarkingStoreInterface +{ + private $singleState; + private $property; + + /** + * @param string $property Used to determine methods to call + * The `getMarking` method will use `$subject->getProperty()` + * The `setMarking` method will use `$subject->setProperty(string|array $places, array $context = array())` + */ + public function __construct(bool $singleState = false, string $property = 'marking') + { + $this->singleState = $singleState; + $this->property = $property; + } + + /** + * {@inheritdoc} + */ + public function getMarking($subject) + { + $method = 'get'.ucfirst($this->property); + + if (!method_exists($subject, $method)) { + throw new LogicException(sprintf('The method "%s::%s()" does not exists.', \get_class($subject), $method)); + } + + $marking = $subject->{$method}(); + + if (!$marking) { + return new Marking(); + } + + if ($this->singleState) { + $marking = [$marking => 1]; + } + + return new Marking($marking); + } + + /** + * {@inheritdoc} + */ + public function setMarking($subject, Marking $marking, array $context = []) + { + $marking = $marking->getPlaces(); + + if ($this->singleState) { + $marking = key($marking); + } + + $method = 'set'.ucfirst($this->property); + + if (!method_exists($subject, $method)) { + throw new LogicException(sprintf('The method "%s::%s()" does not exists.', \get_class($subject), $method)); + } + + $subject->{$method}($marking, $context); + } +} diff --git a/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php index 3ac0ff5827635..9e70614e02c34 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php @@ -46,7 +46,7 @@ public function getMarking($subject) /** * {@inheritdoc} */ - public function setMarking($subject, Marking $marking) + public function setMarking($subject, Marking $marking, array $context = []) { $this->propertyAccessor->setValue($subject, $this->property, $marking->getPlaces()); } diff --git a/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php index 806b33340caa2..ca28017384ae9 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php @@ -51,7 +51,7 @@ public function getMarking($subject) /** * {@inheritdoc} */ - public function setMarking($subject, Marking $marking) + public function setMarking($subject, Marking $marking, array $context = []) { $this->propertyAccessor->setValue($subject, $this->property, key($marking->getPlaces())); } diff --git a/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php b/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php new file mode 100644 index 0000000000000..776f66002d23c --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php @@ -0,0 +1,74 @@ +getMarking($subject); + + $this->assertInstanceOf(Marking::class, $marking); + $this->assertCount(0, $marking->getPlaces()); + + $marking->mark('first_place'); + + $markingStore->setMarking($subject, $marking); + + $this->assertSame(['first_place' => 1], $subject->getMarking()); + + $marking2 = $markingStore->getMarking($subject); + + $this->assertEquals($marking, $marking2); + } + + public function testGetSetMarkingWithSingleState() + { + $subject = new Subject(); + + $markingStore = new MethodMarkingStore(true); + + $marking = $markingStore->getMarking($subject); + + $this->assertInstanceOf(Marking::class, $marking); + $this->assertCount(0, $marking->getPlaces()); + + $marking->mark('first_place'); + + $markingStore->setMarking($subject, $marking); + + $this->assertSame('first_place', $subject->getMarking()); + + $marking2 = $markingStore->getMarking($subject); + + $this->assertEquals($marking, $marking2); + } +} + +final class Subject +{ + private $marking; + + public function __construct($marking = null) + { + $this->marking = $marking; + } + + public function getMarking() + { + return $this->marking; + } + + public function setMarking($marking) + { + $this->marking = $marking; + } +} diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index ff229faabd314..7269defa2e11a 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -143,7 +143,7 @@ public function buildTransitionBlockerList($subject, string $transitionName): Tr /** * {@inheritdoc} */ - public function apply($subject, $transitionName) + public function apply($subject, $transitionName, array $context = []) { $marking = $this->getMarking($subject); @@ -172,7 +172,7 @@ public function apply($subject, $transitionName) $this->enter($subject, $transition, $marking); - $this->markingStore->setMarking($subject, $marking); + $this->markingStore->setMarking($subject, $marking, $context); $this->entered($subject, $transition, $marking); diff --git a/src/Symfony/Component/Workflow/WorkflowInterface.php b/src/Symfony/Component/Workflow/WorkflowInterface.php index 5a1f2c74e81aa..d6de18fee5794 100644 --- a/src/Symfony/Component/Workflow/WorkflowInterface.php +++ b/src/Symfony/Component/Workflow/WorkflowInterface.php @@ -58,7 +58,7 @@ public function buildTransitionBlockerList($subject, string $transitionName): Tr * * @throws LogicException If the transition is not applicable */ - public function apply($subject, $transitionName); + public function apply($subject, $transitionName, array $context = []); /** * Returns all enabled transitions. From aecb33a620f58c9cb32e83fd0927c1c236d23dd6 Mon Sep 17 00:00:00 2001 From: Anton Chernikov Date: Mon, 25 Feb 2019 19:29:40 +0300 Subject: [PATCH 176/495] [Validator] add MIR card scheme --- .../Component/Validator/Constraints/CardSchemeValidator.php | 4 ++++ .../Validator/Tests/Constraints/CardSchemeValidatorTest.php | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index dcc5ad0cb80b2..50b015baad04e 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -78,6 +78,10 @@ class CardSchemeValidator extends ConstraintValidator '/^5[1-5][0-9]{14}$/', '/^2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12})$/', ], + // Payment system MIR numbers start with 220, then 1 digit from 0 to 4, then 12 digits + 'MIR' => [ + '/^220[0-4][0-9]{12}$/', + ], // All UATP card numbers start with a 1 and have a length of 15 digits. 'UATP' => [ '/^1[0-9]{14}$/', diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index 24c23109f4615..ddc9edb6c094d 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -103,6 +103,7 @@ public function getValidNumbers() ['MASTERCARD', '2699999999999999'], ['MASTERCARD', '2709999999999999'], ['MASTERCARD', '2720995105105100'], + ['MIR', '2200381427330082'], ['UATP', '110165309696173'], ['VISA', '4111111111111111'], ['VISA', '4012888888881881'], @@ -135,6 +136,7 @@ public function getInvalidNumbers() ['MASTERCARD', '2721001234567890', CardScheme::INVALID_FORMAT_ERROR], // Not assigned yet ['MASTERCARD', '2220991234567890', CardScheme::INVALID_FORMAT_ERROR], // Not assigned yet ['UATP', '11016530969617', CardScheme::INVALID_FORMAT_ERROR], // invalid length + ['MIR', '22003814273300821', CardScheme::INVALID_FORMAT_ERROR], // invalid length ]; } } From ab04f25da435eb8f8b7fcc957641b0ee3a5e2fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ostroluck=C3=BD?= Date: Thu, 7 Mar 2019 09:54:57 +0100 Subject: [PATCH 177/495] [Translation] Add XLIFF 1 source to metadata to differentiate from attr --- .../Component/Translation/Loader/XliffFileLoader.php | 1 + .../Translation/Tests/Loader/XliffFileLoaderTest.php | 6 ++++++ .../Component/Translation/Tests/fixtures/withnote.xlf | 4 ++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index 78c3fe93813e5..2c59aeca16d64 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -105,6 +105,7 @@ private function extractXliff1(\DOMDocument $dom, MessageCatalogue $catalogue, s $catalogue->set((string) $source, $target, $domain); $metadata = [ + 'source' => (string) $translation->source, 'file' => [ 'original' => (string) $fileAttributes['original'], ], diff --git a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php index f475c065b2aae..1ca8336d52780 100644 --- a/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php +++ b/src/Symfony/Component/Translation/Tests/Loader/XliffFileLoaderTest.php @@ -86,6 +86,7 @@ public function testEncoding() $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1')); $this->assertEquals( [ + 'source' => 'foo', 'notes' => [['content' => utf8_decode('bäz')]], 'id' => '1', 'file' => [ @@ -175,6 +176,7 @@ public function testLoadNotes() $this->assertEquals( [ + 'source' => 'foo', 'notes' => [['priority' => 1, 'content' => 'foo']], 'id' => '1', 'file' => [ @@ -186,6 +188,7 @@ public function testLoadNotes() // message without target $this->assertEquals( [ + 'source' => 'extrasource', 'notes' => [['content' => 'bar', 'from' => 'foo']], 'id' => '2', 'file' => [ @@ -197,6 +200,7 @@ public function testLoadNotes() // message with empty target $this->assertEquals( [ + 'source' => 'key', 'notes' => [ ['content' => 'baz'], ['priority' => 2, 'from' => 'bar', 'content' => 'qux'], @@ -304,6 +308,7 @@ public function testLoadWithMultipleFileNodes() $this->assertEquals( [ + 'source' => 'foo', 'id' => '1', 'file' => [ 'original' => 'file.ext', @@ -313,6 +318,7 @@ public function testLoadWithMultipleFileNodes() ); $this->assertEquals( [ + 'source' => 'test', 'notes' => [['content' => 'note']], 'id' => '4', 'file' => [ diff --git a/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf b/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf index c045e21e232a2..f98cf7f97b04a 100644 --- a/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf +++ b/src/Symfony/Component/Translation/Tests/fixtures/withnote.xlf @@ -7,8 +7,8 @@ bar foo - - extra + + extrasource bar From d2d63a28e1e2ff7fa22423969382da5642c4b917 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jan 2019 21:00:39 +0100 Subject: [PATCH 178/495] [Contracts] introduce HttpClient contracts --- src/Symfony/Contracts/CHANGELOG.md | 5 + .../Contracts/HttpClient/ChunkInterface.php | 66 ++ .../Exception/ClientExceptionInterface.php | 23 + .../Exception/ExceptionInterface.php | 23 + .../RedirectionExceptionInterface.php | 23 + .../Exception/ServerExceptionInterface.php | 23 + .../Exception/TransportExceptionInterface.php | 23 + .../HttpClient/HttpClientInterface.php | 87 +++ .../HttpClient/ResponseInterface.php | 88 +++ .../HttpClient/ResponseStreamInterface.php | 26 + .../HttpClient/Test/Fixtures/web/index.php | 124 ++++ .../HttpClient/Test/HttpClientTestCase.php | 677 ++++++++++++++++++ .../HttpClient/Test/TestHttpServer.php | 54 ++ src/Symfony/Contracts/composer.json | 4 +- 14 files changed, 1245 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Contracts/HttpClient/ChunkInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/Exception/ClientExceptionInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/Exception/ExceptionInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/Exception/RedirectionExceptionInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/Exception/ServerExceptionInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/Exception/TransportExceptionInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/HttpClientInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/ResponseInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/ResponseStreamInterface.php create mode 100644 src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php create mode 100644 src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php create mode 100644 src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php diff --git a/src/Symfony/Contracts/CHANGELOG.md b/src/Symfony/Contracts/CHANGELOG.md index fba42d5954acc..b37bc2a705314 100644 --- a/src/Symfony/Contracts/CHANGELOG.md +++ b/src/Symfony/Contracts/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +1.1.0 +----- + + * added `HttpClient` namespace with contracts for implementing flexible HTTP clients + 1.0.0 ----- diff --git a/src/Symfony/Contracts/HttpClient/ChunkInterface.php b/src/Symfony/Contracts/HttpClient/ChunkInterface.php new file mode 100644 index 0000000000000..bbec2cdfa6066 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/ChunkInterface.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * The interface of chunks returned by ResponseStreamInterface::current(). + * + * When the chunk is first, last or timeout, the content MUST be empty. + * When an unchecked timeout or a network error occurs, a TransportExceptionInterface + * MUST be thrown by the destructor unless one was already thrown by another method. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface ChunkInterface +{ + /** + * Tells when the inactivity timeout has been reached. + * + * @throws TransportExceptionInterface on a network error + */ + public function isTimeout(): bool; + + /** + * Tells when headers just arrived. + * + * @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached + */ + public function isFirst(): bool; + + /** + * Tells when the body just completed. + * + * @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached + */ + public function isLast(): bool; + + /** + * Returns the content of the response chunk. + * + * @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached + */ + public function getContent(): string; + + /** + * Returns the offset of the chunk in the response body. + */ + public function getOffset(): int; + + /** + * In case of error, returns the message that describes it. + */ + public function getError(): ?string; +} diff --git a/src/Symfony/Contracts/HttpClient/Exception/ClientExceptionInterface.php b/src/Symfony/Contracts/HttpClient/Exception/ClientExceptionInterface.php new file mode 100644 index 0000000000000..a5f81dc1465bd --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Exception/ClientExceptionInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 4xx response is returned. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface ClientExceptionInterface extends ExceptionInterface +{ +} diff --git a/src/Symfony/Contracts/HttpClient/Exception/ExceptionInterface.php b/src/Symfony/Contracts/HttpClient/Exception/ExceptionInterface.php new file mode 100644 index 0000000000000..6d59715f70657 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Exception/ExceptionInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * The base interface for all exceptions in the contract. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/src/Symfony/Contracts/HttpClient/Exception/RedirectionExceptionInterface.php b/src/Symfony/Contracts/HttpClient/Exception/RedirectionExceptionInterface.php new file mode 100644 index 0000000000000..208d692c62409 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Exception/RedirectionExceptionInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 3xx response is returned and the "max_redirects" option has been reached. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface RedirectionExceptionInterface extends ExceptionInterface +{ +} diff --git a/src/Symfony/Contracts/HttpClient/Exception/ServerExceptionInterface.php b/src/Symfony/Contracts/HttpClient/Exception/ServerExceptionInterface.php new file mode 100644 index 0000000000000..a1be7d4f7f0d7 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Exception/ServerExceptionInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 5xx response is returned. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface ServerExceptionInterface extends ExceptionInterface +{ +} diff --git a/src/Symfony/Contracts/HttpClient/Exception/TransportExceptionInterface.php b/src/Symfony/Contracts/HttpClient/Exception/TransportExceptionInterface.php new file mode 100644 index 0000000000000..1cdc30a2fc4f2 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Exception/TransportExceptionInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When any error happens at the transport level. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface TransportExceptionInterface extends ExceptionInterface +{ +} diff --git a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php new file mode 100644 index 0000000000000..8d58e813e812f --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; + +/** + * Provides flexible methods for requesting HTTP resources synchronously or asynchronously. + * + * @see HttpClientTestCase for a reference test suite + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface HttpClientInterface +{ + public const OPTIONS_DEFAULTS = [ + 'auth' => null, // string - a username:password enabling HTTP Basic authentication + 'query' => [], // string[] - associative array of query string values to merge with the request's URL + 'headers' => [], // iterable|string[]|string[][] - headers names provided as keys or as part of values + 'body' => '', // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string + // smaller than the amount requested as argument; the empty string signals EOF; when + // an array is passed, it is meant as a form payload of field names and values + 'json' => null, // array|\JsonSerializable - when set, implementations MUST set the "body" option to + // the JSON-encoded value and set the "content-type" headers to a JSON-compatible + // value it is they are not defined - typically "application/json" + 'user_data' => null, // mixed - any extra data to attach to the request (scalar, callable, object...) that + // MUST be available via $response->getInfo('data') - not used internally + 'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower or equal to 0 means + // redirects should not be followed; "Authorization" and "Cookie" headers MUST + // NOT follow except for the initial host name + 'http_version' => null, // string - defaults to the best supported version, typically 1.1 or 2.0 + 'base_uri' => null, // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2 + 'buffer' => true, // bool - whether the content of the response should be buffered or not + 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort + // the request; it MUST be called on DNS resolution, on arrival of headers and on + // completion; it SHOULD be called on upload/download of data and at least 1/s + 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution + 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored + 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached + 'timeout' => null, // float - the inactivity timeout - defaults to ini_get('default_socket_timeout') + 'bindto' => '0', // string - the interface or the local socket to bind to + 'verify_peer' => true, // see https://php.net/context.ssl for the following options + 'verify_host' => true, + 'cafile' => null, + 'capath' => null, + 'local_cert' => null, + 'local_pk' => null, + 'passphrase' => null, + 'ciphers' => null, + 'peer_fingerprint' => null, + 'capture_peer_cert_chain' => false, + ]; + + /** + * Requests an HTTP resource. + * + * Responses MUST be lazy, but their status code MUST be + * checked even if none of their public methods are called. + * + * Implementations are not required to support all options described above; they can also + * support more custom options; but in any case, they MUST throw a TransportExceptionInterface + * when an unsupported option is passed. + * + * @throws TransportExceptionInterface When an unsupported option is passed + */ + public function request(string $method, string $url, array $options = []): ResponseInterface; + + /** + * Yields responses chunk by chunk as they complete. + * + * @param ResponseInterface|ResponseInterface[]|iterable $responses One or more responses created by the current HTTP client + * @param float|null $timeout The inactivity timeout before exiting the iterator + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface; +} diff --git a/src/Symfony/Contracts/HttpClient/ResponseInterface.php b/src/Symfony/Contracts/HttpClient/ResponseInterface.php new file mode 100644 index 0000000000000..7aeed6d5103d9 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/ResponseInterface.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * A (lazily retrieved) HTTP response. + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface ResponseInterface +{ + /** + * Gets the HTTP status code of the response. + * + * @throws TransportExceptionInterface when a network error occurs + */ + public function getStatusCode(): int; + + /** + * Gets the HTTP headers of the response. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @return string[][] The headers of the response keyed by header names in lowercase + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function getHeaders(bool $throw = true): array; + + /** + * Gets the response body as a string. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function getContent(bool $throw = true): string; + + /** + * Returns info coming from the transport layer. + * + * This method SHOULD NOT throw any ExceptionInterface and SHOULD be non-blocking. + * The returned info is "live": it can be empty and can change from one call to + * another, as the request/response progresses. + * + * The following info MUST be returned: + * - raw_headers - an array modelled after the special $http_response_header variable + * - redirect_count - the number of redirects followed while executing the request + * - redirect_url - the resolved location of redirect responses, null otherwise + * - start_time - the time when the request was sent or 0.0 when it's pending + * - http_code - the last response code or 0 when it is not known yet + * - error - the error message when the transfer was aborted, null otherwise + * - data - the value of the "data" request option, null if not set + * - url - the last effective URL of the request + * + * When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain" + * attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources. + * + * Other info SHOULD be named after curl_getinfo()'s associative return value. + * + * @return array|mixed|null An array of all available info, or one of them when $type is + * provided, or null when an unsupported type is requested + */ + public function getInfo(string $type = null); +} diff --git a/src/Symfony/Contracts/HttpClient/ResponseStreamInterface.php b/src/Symfony/Contracts/HttpClient/ResponseStreamInterface.php new file mode 100644 index 0000000000000..dfff554dfe7f7 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/ResponseStreamInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +/** + * Yields response chunks, returned by HttpClientInterface::stream(). + * + * @author Nicolas Grekas + * + * @experimental in 1.1 + */ +interface ResponseStreamInterface extends \Iterator +{ + public function key(): ResponseInterface; + + public function current(): ChunkInterface; +} diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php new file mode 100644 index 0000000000000..ec15196c6592c --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -0,0 +1,124 @@ + $v) { + switch ($k) { + default: + if (0 !== strpos($k, 'HTTP_')) { + continue 2; + } + // no break + case 'SERVER_NAME': + case 'SERVER_PROTOCOL': + case 'REQUEST_URI': + case 'REQUEST_METHOD': + case 'PHP_AUTH_USER': + case 'PHP_AUTH_PW': + $vars[$k] = $v; + } +} + +switch ($vars['REQUEST_URI']) { + default: + exit; + + case '/': + case '/?a=a&b=b': + case 'http://127.0.0.1:8057/': + case 'http://localhost:8057/': + header('Content-Type: application/json'); + ob_start('ob_gzhandler'); + break; + + case '/404': + header('Content-Type: application/json', true, 404); + break; + + case '/301': + if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) { + header('Location: http://127.0.0.1:8057/302', true, 301); + } + break; + + case '/301/bad-tld': + header('Location: http://foo.example.', true, 301); + break; + + case '/302': + if (!isset($vars['HTTP_AUTHORIZATION'])) { + header('Location: http://localhost:8057/', true, 302); + } + break; + + case '/302/relative': + header('Location: ..', true, 302); + break; + + case '/307': + header('Location: http://localhost:8057/post', true, 307); + break; + + case '/length-broken': + header('Content-Length: 1000'); + break; + + case '/post': + $output = json_encode($_POST + ['REQUEST_METHOD' => $vars['REQUEST_METHOD']], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + header('Content-Type: application/json', true); + header('Content-Length: '.\strlen($output)); + echo $output; + exit; + + case '/timeout-header': + usleep(300000); + break; + + case '/timeout-body': + echo '<1>'; + ob_flush(); + flush(); + usleep(500000); + echo '<2>'; + exit; + + case '/timeout-long': + ignore_user_abort(false); + sleep(1); + while (true) { + echo '<1>'; + ob_flush(); + flush(); + usleep(500); + } + exit; + + case '/chunked': + header('Transfer-Encoding: chunked'); + echo "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\nesome!\r\n0\r\n\r\n"; + exit; + + case '/chunked-broken': + header('Transfer-Encoding: chunked'); + echo "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\ne"; + exit; + + case '/gzip-broken': + header('Content-Encoding: gzip'); + echo str_repeat('-', 1000); + exit; +} + +header('Content-Type: application/json', true); + +echo json_encode($vars, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php new file mode 100644 index 0000000000000..59703d0ffbfad --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -0,0 +1,677 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Test; + +use PHPUnit\Framework\TestCase; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A reference test suite for HttpClientInterface implementations. + * + * @experimental in 1.1 + */ +abstract class HttpClientTestCase extends TestCase +{ + private static $server; + + public static function setUpBeforeClass() + { + TestHttpServer::start(); + } + + abstract protected function getHttpClient(): HttpClientInterface; + + public function testGetRequest() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => ['Foo' => 'baR'], + 'user_data' => $data = new \stdClass(), + ]); + + $this->assertSame([], $response->getInfo('raw_headers')); + $this->assertSame($data, $response->getInfo()['user_data']); + $this->assertSame(200, $response->getStatusCode()); + + $info = $response->getInfo(); + $this->assertNull($info['error']); + $this->assertSame(0, $info['redirect_count']); + $this->assertSame('HTTP/1.1 200 OK', $info['raw_headers'][0]); + $this->assertSame('Host: localhost:8057', $info['raw_headers'][1]); + $this->assertSame('http://localhost:8057/', $info['url']); + + $headers = $response->getHeaders(); + + $this->assertSame('localhost:8057', $headers['host'][0]); + $this->assertSame(['application/json'], $headers['content-type']); + + $body = json_decode($response->getContent(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertSame('baR', $body['HTTP_FOO']); + + $response = $client->request('GET', 'http://localhost:8057/length-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testNonBufferedGetRequest() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057', [ + 'buffer' => false, + 'headers' => ['Foo' => 'baR'], + ]); + + $body = json_decode($response->getContent(), true); + $this->assertSame('baR', $body['HTTP_FOO']); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testUnsupportedOption() + { + $client = $this->getHttpClient(); + + $this->expectException(\InvalidArgumentException::class); + $client->request('GET', 'http://localhost:8057', [ + 'capture_peer_cert' => 1.0, + ]); + } + + public function testHttpVersion() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057', [ + 'http_version' => 1.0, + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('raw_headers')[0]); + + $body = json_decode($response->getContent(), true); + + $this->assertSame('HTTP/1.0', $body['SERVER_PROTOCOL']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/', $body['REQUEST_URI']); + } + + public function testChunkedEncoding() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/chunked'); + + $this->assertSame(['chunked'], $response->getHeaders()['transfer-encoding']); + $this->assertSame('Symfony is awesome!', $response->getContent()); + + $response = $client->request('GET', 'http://localhost:8057/chunked-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testClientError() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/404'); + + $client->stream($response)->valid(); + + $this->assertSame(404, $response->getInfo('http_code')); + + try { + $response->getHeaders(); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + try { + $response->getContent(); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']); + $this->assertNotEmpty($response->getContent(false)); + } + + public function testIgnoreErrors() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/404'); + + $this->assertSame(404, $response->getStatusCode()); + } + + public function testDnsError() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); + + try { + $response->getStatusCode(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + try { + $response->getStatusCode(); + $this->fail(TransportExceptionInterface::class.' still expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); + + try { + foreach ($client->stream($response) as $r => $chunk) { + } + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $this->assertSame($response, $r); + $this->assertNotNull($chunk->getError()); + + foreach ($client->stream($response) as $chunk) { + $this->fail('Already errored responses shouldn\'t be yielded'); + } + } + + public function testInlineAuth() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057'); + + $body = json_decode($response->getContent(), true); + + $this->assertSame('foo', $body['PHP_AUTH_USER']); + $this->assertSame('bar=bar', $body['PHP_AUTH_PW']); + } + + public function testRedirects() + { + $client = $this->getHttpClient(); + $response = $client->request('POST', 'http://localhost:8057/301', [ + 'auth' => 'foo:bar', + 'body' => 'foo=bar', + ]); + + $body = json_decode($response->getContent(), true); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('Basic Zm9vOmJhcg==', $body['HTTP_AUTHORIZATION']); + $this->assertSame('http://localhost:8057/', $response->getInfo('url')); + + $this->assertSame(2, $response->getInfo('redirect_count')); + $this->assertNull($response->getInfo('redirect_url')); + + $expected = [ + 'HTTP/1.1 301 Moved Permanently', + 'Location: http://127.0.0.1:8057/302', + 'Content-Type: application/json', + 'HTTP/1.1 302 Found', + 'Location: http://localhost:8057/', + 'Content-Type: application/json', + 'HTTP/1.1 200 OK', + 'Content-Type: application/json', + ]; + + $filteredHeaders = array_intersect($expected, $response->getInfo('raw_headers')); + + $this->assertSame($expected, $filteredHeaders); + } + + public function testRelativeRedirects() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/302/relative'); + + $body = json_decode($response->getContent(), true); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertNull($response->getInfo('redirect_url')); + + $response = $client->request('GET', 'http://localhost:8057/302/relative', [ + 'max_redirects' => 0, + ]); + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + } + + public function testRedirect307() + { + $client = $this->getHttpClient(); + $response = $client->request('POST', 'http://localhost:8057/307', [ + 'body' => 'foo=bar', + ]); + + $body = json_decode($response->getContent(), true); + + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testMaxRedirects() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/301', [ + 'max_redirects' => 1, + 'auth' => 'foo:bar', + ]); + + try { + $response->getHeaders(); + $this->fail(RedirectionExceptionInterface::class.' expected'); + } catch (RedirectionExceptionInterface $e) { + } + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame(1, $response->getInfo('redirect_count')); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + + $expected = [ + 'HTTP/1.1 301 Moved Permanently', + 'Location: http://127.0.0.1:8057/302', + 'Content-Type: application/json', + 'HTTP/1.1 302 Found', + 'Location: http://localhost:8057/', + 'Content-Type: application/json', + ]; + + $filteredHeaders = array_intersect($expected, $response->getInfo('raw_headers')); + + $this->assertSame($expected, $filteredHeaders); + } + + public function testStream() + { + $client = $this->getHttpClient(); + + $response = $client->request('GET', 'http://localhost:8057'); + $chunks = $client->stream($response); + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } elseif ($chunk->isLast()) { + $result[] = 'l'; + } elseif ($chunk->isFirst()) { + $result[] = 'f'; + } + } + + $this->assertSame($response, $r); + $this->assertSame(['f', 'l'], $result); + } + + public function testAddToStream() + { + $client = $this->getHttpClient(); + + $r1 = $client->request('GET', 'http://localhost:8057'); + + $completed = []; + + $pool = [$r1]; + + while ($pool) { + $chunks = $client->stream($pool); + $pool = []; + + foreach ($chunks as $r => $chunk) { + if (!$chunk->isLast()) { + continue; + } + + if ($r1 === $r) { + $r2 = $client->request('GET', 'http://localhost:8057'); + $pool[] = $r2; + } + + $completed[] = $r; + } + } + + $this->assertSame([$r1, $r2], $completed); + } + + public function testCompleteTypeError() + { + $client = $this->getHttpClient(); + + $this->expectException(\TypeError::class); + $client->stream(123); + } + + public function testOnProgress() + { + $client = $this->getHttpClient(); + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'headers' => ['Content-Length' => 14], + 'body' => 'foo=0123456789', + 'on_progress' => function (...$state) use (&$steps) { $steps[] = $state; }, + ]); + + $body = json_decode($response->getContent(), true); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + $this->assertSame([0, 0], \array_slice($steps[0], 0, 2)); + $lastStep = \array_slice($steps, -1)[0]; + $this->assertSame([57, 57], \array_slice($lastStep, 0, 2)); + $this->assertSame('http://localhost:8057/post', $steps[0][2]['url']); + } + + public function testPostArray() + { + $client = $this->getHttpClient(); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => ['foo' => 'bar'], + ]); + + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], json_decode($response->getContent(), true)); + } + + public function testPostResource() + { + $client = $this->getHttpClient(); + + $h = fopen('php://temp', 'w+'); + fwrite($h, 'foo=0123456789'); + rewind($h); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => $h, + ]); + + $body = json_decode($response->getContent(), true); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testPostCallback() + { + $client = $this->getHttpClient(); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => function () { + yield 'foo'; + yield '='; + yield '0123456789'; + }, + ]); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], json_decode($response->getContent(), true)); + } + + public function testOnProgressCancel() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'on_progress' => function ($dlNow) { + if (0 < $dlNow) { + throw new \Exception('Aborting the request'); + } + }, + ]); + + try { + foreach ($client->stream([$response]) as $chunk) { + } + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->assertSame('Aborting the request', $e->getPrevious()->getMessage()); + } + + $this->assertNotNull($response->getInfo('error')); + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testOnProgressError() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'on_progress' => function ($dlNow) { + if (0 < $dlNow) { + throw new \Error('BUG'); + } + }, + ]); + + try { + foreach ($client->stream([$response]) as $chunk) { + } + $this->fail('Error expected'); + } catch (\Error $e) { + $this->assertSame('BUG', $e->getMessage()); + } + + $this->assertNotNull($response->getInfo('error')); + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testResolve() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://symfony.com:8057/', [ + 'resolve' => ['symfony.com' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame(200, $client->request('GET', 'http://symfony.com:8057/')->getStatusCode()); + + $response = null; + $this->expectException(TransportExceptionInterface::class); + $client->request('GET', 'http://symfony.com:8057/'); + } + + public function testTimeoutOnAccess() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/timeout-header', [ + 'timeout' => 0.1, + ]); + + $this->expectException(TransportExceptionInterface::class); + $response->getHeaders(); + } + + public function testTimeoutOnStream() + { + usleep(300000); // wait for the previous test to release the server + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + + $this->assertSame(200, $response->getStatusCode()); + $chunks = $client->stream([$response], 0.2); + + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } else { + $result[] = $chunk->getContent(); + } + } + + $this->assertSame(['<1>', 't'], $result); + + $chunks = $client->stream([$response]); + + foreach ($chunks as $r => $chunk) { + $this->assertSame('<2>', $chunk->getContent()); + $this->assertSame('<1><2>', $r->getContent()); + + return; + } + + $this->fail('The response should have completed'); + } + + public function testUncheckedTimeoutThrows() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + $chunks = $client->stream([$response], 0.1); + + $this->expectException(TransportExceptionInterface::class); + + foreach ($chunks as $r => $chunk) { + } + } + + public function testDestruct() + { + $client = $this->getHttpClient(); + + $downloaded = 0; + $start = microtime(true); + $client->request('GET', 'http://localhost:8057/timeout-long'); + $client = null; + $duration = microtime(true) - $start; + + $this->assertGreaterThan(1, $duration); + $this->assertLessThan(3, $duration); + } + + public function testProxy() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = json_decode($response->getContent(), true); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertRegexp('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://foo:b%3Dar@localhost:8057', + ]); + + $body = json_decode($response->getContent(), true); + $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']); + } + + public function testNoProxy() + { + putenv('no_proxy='.$_SERVER['no_proxy'] = 'example.com, localhost'); + + try { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = json_decode($response->getContent(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + } finally { + putenv('no_proxy'); + unset($_SERVER['no_proxy']); + } + } + + /** + * @requires extension zlib + */ + public function testAutoEncodingRequest() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057'); + + $this->assertSame(200, $response->getStatusCode()); + + $headers = $response->getHeaders(); + + $this->assertSame(['Accept-Encoding'], $headers['vary']); + $this->assertContains('gzip', $headers['content-encoding'][0]); + + $body = json_decode($response->getContent(), true); + + $this->assertContains('gzip', $body['HTTP_ACCEPT_ENCODING']); + } + + public function testBaseUri() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', '../404', [ + 'base_uri' => 'http://localhost:8057/abc/', + ]); + + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']); + } + + public function testQuery() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/?a=a', [ + 'query' => ['b' => 'b'], + ]); + + $body = json_decode($response->getContent(), true); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']); + } + + /** + * @requires extension zlib + */ + public function testUserlandEncodingRequest() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => ['Accept-Encoding' => 'gzip'], + ]); + + $headers = $response->getHeaders(); + + $this->assertSame(['Accept-Encoding'], $headers['vary']); + $this->assertContains('gzip', $headers['content-encoding'][0]); + + $body = $response->getContent(); + + $this->assertSame("\x1F", $body[0]); + $body = json_decode(gzdecode($body), true); + + $this->assertSame('gzip', $body['HTTP_ACCEPT_ENCODING']); + } + + /** + * @requires extension zlib + */ + public function testGzipBroken() + { + $client = $this->getHttpClient(); + $response = $client->request('GET', 'http://localhost:8057/gzip-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } +} diff --git a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php new file mode 100644 index 0000000000000..5b05f50562ff7 --- /dev/null +++ b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Test; + +use Symfony\Component\Process\PhpExecutableFinder; +use Symfony\Component\Process\Process; + +/** + * @experimental in 1.1 + */ +class TestHttpServer +{ + private static $server; + + public static function start() + { + if (null !== self::$server) { + return; + } + + $spec = [ + 1 => ['file', '\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null', 'w'], + 2 => ['file', '\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null', 'w'], + ]; + + $finder = new PhpExecutableFinder(); + $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:8057'])); + $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); + $process->setTimeout(300); + $process->start(); + + self::$server = new class() { + public $process; + + public function __destruct() + { + $this->process->stop(); + } + }; + + self::$server->process = $process; + + sleep('\\' === \DIRECTORY_SEPARATOR ? 10 : 1); + } +} diff --git a/src/Symfony/Contracts/composer.json b/src/Symfony/Contracts/composer.json index b01744783f6fd..f881258dc1a4a 100644 --- a/src/Symfony/Contracts/composer.json +++ b/src/Symfony/Contracts/composer.json @@ -20,12 +20,14 @@ }, "require-dev": { "psr/cache": "^1.0", - "psr/container": "^1.0" + "psr/container": "^1.0", + "symfony/polyfill-intl-idn": "^1.10" }, "suggest": { "psr/cache": "When using the Cache contracts", "psr/container": "When using the Service contracts", "symfony/cache-contracts-implementation": "", + "symfony/http-client-contracts-implementation": "", "symfony/service-contracts-implementation": "", "symfony/translation-contracts-implementation": "" }, From 8610668c1c51954eb1007087fe18fbda8d839d97 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jan 2019 21:00:39 +0100 Subject: [PATCH 179/495] [HttpClient] introduce the component --- composer.json | 3 +- src/Symfony/Component/HttpClient/CHANGELOG.md | 7 + .../Component/HttpClient/Chunk/DataChunk.php | 79 +++ .../Component/HttpClient/Chunk/ErrorChunk.php | 106 ++++ .../Component/HttpClient/Chunk/FirstChunk.php | 28 ++ .../Component/HttpClient/Chunk/LastChunk.php | 28 ++ .../Component/HttpClient/CurlHttpClient.php | 374 ++++++++++++++ .../HttpClient/Exception/ClientException.php | 26 + .../Exception/HttpExceptionTrait.php | 38 ++ .../Exception/InvalidArgumentException.php | 23 + .../Exception/RedirectionException.php | 26 + .../HttpClient/Exception/ServerException.php | 26 + .../Exception/TransportException.php | 23 + .../Component/HttpClient/HttpClient.php | 39 ++ .../Component/HttpClient/HttpClientTrait.php | 457 ++++++++++++++++++ .../Component/HttpClient/HttpOptions.php | 299 ++++++++++++ src/Symfony/Component/HttpClient/LICENSE | 19 + .../Component/HttpClient/NativeHttpClient.php | 420 ++++++++++++++++ src/Symfony/Component/HttpClient/README.md | 17 + .../HttpClient/Response/CurlResponse.php | 298 ++++++++++++ .../HttpClient/Response/NativeResponse.php | 305 ++++++++++++ .../HttpClient/Response/ResponseStream.php | 56 +++ .../HttpClient/Response/ResponseTrait.php | 299 ++++++++++++ .../HttpClient/Tests/CurlHttpClientTest.php | 27 ++ .../HttpClient/Tests/HttpClientTest.php | 29 ++ .../HttpClient/Tests/HttpClientTraitTest.php | 166 +++++++ .../HttpClient/Tests/NativeHttpClientTest.php | 24 + .../Component/HttpClient/composer.json | 40 ++ .../Component/HttpClient/phpunit.xml.dist | 30 ++ .../VarDumper/Caster/SymfonyCaster.php | 8 + .../VarDumper/Cloner/AbstractCloner.php | 4 + 31 files changed, 3323 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpClient/CHANGELOG.md create mode 100644 src/Symfony/Component/HttpClient/Chunk/DataChunk.php create mode 100644 src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php create mode 100644 src/Symfony/Component/HttpClient/Chunk/FirstChunk.php create mode 100644 src/Symfony/Component/HttpClient/Chunk/LastChunk.php create mode 100644 src/Symfony/Component/HttpClient/CurlHttpClient.php create mode 100644 src/Symfony/Component/HttpClient/Exception/ClientException.php create mode 100644 src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php create mode 100644 src/Symfony/Component/HttpClient/Exception/InvalidArgumentException.php create mode 100644 src/Symfony/Component/HttpClient/Exception/RedirectionException.php create mode 100644 src/Symfony/Component/HttpClient/Exception/ServerException.php create mode 100644 src/Symfony/Component/HttpClient/Exception/TransportException.php create mode 100644 src/Symfony/Component/HttpClient/HttpClient.php create mode 100644 src/Symfony/Component/HttpClient/HttpClientTrait.php create mode 100644 src/Symfony/Component/HttpClient/HttpOptions.php create mode 100644 src/Symfony/Component/HttpClient/LICENSE create mode 100644 src/Symfony/Component/HttpClient/NativeHttpClient.php create mode 100644 src/Symfony/Component/HttpClient/README.md create mode 100644 src/Symfony/Component/HttpClient/Response/CurlResponse.php create mode 100644 src/Symfony/Component/HttpClient/Response/NativeResponse.php create mode 100644 src/Symfony/Component/HttpClient/Response/ResponseStream.php create mode 100644 src/Symfony/Component/HttpClient/Response/ResponseTrait.php create mode 100644 src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php create mode 100644 src/Symfony/Component/HttpClient/Tests/HttpClientTest.php create mode 100644 src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php create mode 100644 src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php create mode 100644 src/Symfony/Component/HttpClient/composer.json create mode 100644 src/Symfony/Component/HttpClient/phpunit.xml.dist diff --git a/composer.json b/composer.json index e0544b61fbb6f..737a80ac00112 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "psr/link": "^1.0", "psr/log": "~1.0", "psr/simple-cache": "^1.0", - "symfony/contracts": "^1.0.2", + "symfony/contracts": "^1.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "~1.0", "symfony/polyfill-intl-idn": "^1.10", @@ -55,6 +55,7 @@ "symfony/finder": "self.version", "symfony/form": "self.version", "symfony/framework-bundle": "self.version", + "symfony/http-client": "self.version", "symfony/http-foundation": "self.version", "symfony/http-kernel": "self.version", "symfony/inflector": "self.version", diff --git a/src/Symfony/Component/HttpClient/CHANGELOG.md b/src/Symfony/Component/HttpClient/CHANGELOG.md new file mode 100644 index 0000000000000..44594a71d0827 --- /dev/null +++ b/src/Symfony/Component/HttpClient/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the component diff --git a/src/Symfony/Component/HttpClient/Chunk/DataChunk.php b/src/Symfony/Component/HttpClient/Chunk/DataChunk.php new file mode 100644 index 0000000000000..618112834d473 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Chunk/DataChunk.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +use Symfony\Contracts\HttpClient\ChunkInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class DataChunk implements ChunkInterface +{ + private $offset; + private $content; + + public function __construct(int $offset = 0, string $content = '') + { + $this->offset = $offset; + $this->content = $content; + } + + /** + * {@inheritdoc} + */ + public function isTimeout(): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function isFirst(): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function isLast(): bool + { + return false; + } + + /** + * {@inheritdoc} + */ + public function getContent(): string + { + return $this->content; + } + + /** + * {@inheritdoc} + */ + public function getOffset(): int + { + return $this->offset; + } + + /** + * {@inheritdoc} + */ + public function getError(): ?string + { + return null; + } +} diff --git a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php new file mode 100644 index 0000000000000..0c3f8dfc62bab --- /dev/null +++ b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ChunkInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class ErrorChunk implements ChunkInterface +{ + protected $didThrow; + + private $offset; + private $errorMessage; + private $error; + + /** + * @param bool &$didThrow Allows monitoring when the $error has been thrown or not + */ + public function __construct(bool &$didThrow, int $offset, \Throwable $error = null) + { + $didThrow = false; + $this->didThrow = &$didThrow; + $this->offset = $offset; + $this->error = $error; + $this->errorMessage = null !== $error ? $error->getMessage() : 'Reading from the response stream reached the inactivity timeout.'; + } + + /** + * {@inheritdoc} + */ + public function isTimeout(): bool + { + $this->didThrow = true; + + if (null !== $this->error) { + throw new TransportException($this->errorMessage, 0, $this->error); + } + + return true; + } + + /** + * {@inheritdoc} + */ + public function isFirst(): bool + { + $this->didThrow = true; + throw new TransportException($this->errorMessage, 0, $this->error); + } + + /** + * {@inheritdoc} + */ + public function isLast(): bool + { + $this->didThrow = true; + throw new TransportException($this->errorMessage, 0, $this->error); + } + + /** + * {@inheritdoc} + */ + public function getContent(): string + { + $this->didThrow = true; + throw new TransportException($this->errorMessage, 0, $this->error); + } + + /** + * {@inheritdoc} + */ + public function getOffset(): int + { + return $this->offset; + } + + /** + * {@inheritdoc} + */ + public function getError(): ?string + { + return $this->errorMessage; + } + + public function __destruct() + { + if (!$this->didThrow) { + $this->didThrow = true; + throw new TransportException($this->errorMessage, 0, $this->error); + } + } +} diff --git a/src/Symfony/Component/HttpClient/Chunk/FirstChunk.php b/src/Symfony/Component/HttpClient/Chunk/FirstChunk.php new file mode 100644 index 0000000000000..d891ca856d347 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Chunk/FirstChunk.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class FirstChunk extends DataChunk +{ + /** + * {@inheritdoc} + */ + public function isFirst(): bool + { + return true; + } +} diff --git a/src/Symfony/Component/HttpClient/Chunk/LastChunk.php b/src/Symfony/Component/HttpClient/Chunk/LastChunk.php new file mode 100644 index 0000000000000..84095d39257e8 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Chunk/LastChunk.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Chunk; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class LastChunk extends DataChunk +{ + /** + * {@inheritdoc} + */ + public function isLast(): bool + { + return true; + } +} diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php new file mode 100644 index 0000000000000..08bbb46d08fc7 --- /dev/null +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -0,0 +1,374 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Response\CurlResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * A performant implementation of the HttpClientInterface contracts based on the curl extension. + * + * This provides fully concurrent HTTP requests, with transparent + * HTTP/2 push when a curl version that supports it is installed. + * + * @author Nicolas Grekas + * + * @experimental in 4.3 + */ +final class CurlHttpClient implements HttpClientInterface +{ + use HttpClientTrait; + + private $defaultOptions = self::OPTIONS_DEFAULTS; + private $multi; + + /** + * @param array $defaultOptions Default requests' options + * @param int $maxHostConnections The maximum number of connections to a single host + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public function __construct(array $defaultOptions = [], int $maxHostConnections = 6) + { + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); + } + + $mh = curl_multi_init(); + + // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order + if (\defined('CURLPIPE_MULTIPLEX')) { + curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + } + curl_multi_setopt($mh, CURLMOPT_MAX_HOST_CONNECTIONS, $maxHostConnections); + + // Use an internal stdClass object to share state between the client and its responses + $this->multi = $multi = (object) [ + 'openHandles' => [], + 'handlesActivity' => [], + 'handle' => $mh, + 'pushedResponses' => [], + 'dnsCache' => [[], [], []], + ]; + + // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/76675 + if (\PHP_VERSION_ID < 70215 || \PHP_VERSION_ID === 70300 || \PHP_VERSION_ID === 70301) { + return; + } + + // HTTP/2 push crashes before curl 7.61 + if (!\defined('CURLMOPT_PUSHFUNCTION') || 0x073d00 > ($v = curl_version())['version_number'] || !(CURL_VERSION_HTTP2 & $v['features'])) { + return; + } + + // Keep a dummy "onPush" reference to work around a refcount bug in PHP + curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $multi->onPush = static function ($parent, $pushed, array $rawHeaders) use ($multi) { + return self::handlePush($parent, $pushed, $rawHeaders, $multi); + }); + } + + /** + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + * + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); + $scheme = $url['scheme']; + $authority = $url['authority']; + $host = parse_url($authority, PHP_URL_HOST); + $url = implode('', $url); + + if ([$pushedResponse, $pushedHeaders] = $this->multi->pushedResponses[$url] ?? null) { + unset($this->multi->pushedResponses[$url]); + // Accept pushed responses only if their headers related to authentication match the request + $expectedHeaders = [ + $options['headers']['authorization'] ?? null, + $options['headers']['cookie'] ?? null, + $options['headers']['x-requested-with'] ?? null, + $options['headers']['range'] ?? null, + ]; + + if ('GET' === $method && !$options['body'] && $expectedHeaders === $pushedHeaders) { + // Reinitialize the pushed response with request's options + $pushedResponse->__construct($this->multi, $url, $options); + + return $pushedResponse; + } + } + + $curlopts = [ + CURLOPT_URL => $url, + CURLOPT_USERAGENT => 'Symfony HttpClient/Curl', + CURLOPT_TCP_NODELAY => true, + CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, + CURLOPT_REDIR_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 0 < $options['max_redirects'] ? $options['max_redirects'] : 0, + CURLOPT_COOKIEFILE => '', // Keep track of cookies during redirects + CURLOPT_CONNECTTIMEOUT_MS => 1000 * $options['timeout'], + CURLOPT_PROXY => $options['proxy'], + CURLOPT_NOPROXY => $options['no_proxy'] ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? '', + CURLOPT_SSL_VERIFYPEER => $options['verify_peer'], + CURLOPT_SSL_VERIFYHOST => $options['verify_host'] ? 2 : 0, + CURLOPT_CAINFO => $options['cafile'], + CURLOPT_CAPATH => $options['capath'], + CURLOPT_SSL_CIPHER_LIST => $options['ciphers'], + CURLOPT_SSLCERT => $options['local_cert'], + CURLOPT_SSLKEY => $options['local_pk'], + CURLOPT_KEYPASSWD => $options['passphrase'], + CURLOPT_CERTINFO => $options['capture_peer_cert_chain'], + ]; + + if (!ZEND_THREAD_SAFE) { + $curlopts[CURLOPT_DNS_USE_GLOBAL_CACHE] = false; + } + + if (\defined('CURLOPT_HEADEROPT')) { + $curlopts[CURLOPT_HEADEROPT] = CURLHEADER_SEPARATE; + } + + // curl's resolve feature varies by host:port but ours varies by host only, let's handle this with our own DNS map + if (isset($this->multi->dnsCache[0][$host])) { + $options['resolve'] += [$host => $this->multi->dnsCache[0][$host]]; + } + + if ($options['resolve'] || $this->multi->dnsCache[2]) { + // First reset any old DNS cache entries then add the new ones + $resolve = $this->multi->dnsCache[2]; + $this->multi->dnsCache[2] = []; + $port = parse_url($authority, PHP_URL_PORT) ?: ('http:' === $scheme ? 80 : 443); + + if ($resolve && 0x072a00 > curl_version()['version_number']) { + // DNS cache removals require curl 7.42 or higher + // On lower versions, we have to create a new multi handle + curl_multi_close($this->multi->handle); + $this->multi->handle = (new self())->multi->handle; + } + + foreach ($options['resolve'] as $host => $ip) { + $resolve[] = null === $ip ? "-$host:$port" : "$host:$port:$ip"; + $this->multi->dnsCache[0][$host] = $ip; + $this->multi->dnsCache[1]["-$host:$port"] = "-$host:$port"; + } + + $curlopts[CURLOPT_RESOLVE] = $resolve; + } + + if (1.0 === (float) $options['http_version']) { + $curlopts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0; + } elseif (1.1 === (float) $options['http_version'] || 'https:' !== $scheme) { + $curlopts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1; + } elseif (CURL_VERSION_HTTP2 & curl_version()['features']) { + $curlopts[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0; + } + + if ('POST' === $method) { + // Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303 + $curlopts[CURLOPT_POST] = true; + } else { + $curlopts[CURLOPT_CUSTOMREQUEST] = $method; + } + + if ('\\' !== \DIRECTORY_SEPARATOR && $options['timeout'] < 1) { + $curlopts[CURLOPT_NOSIGNAL] = true; + } + + if (!isset($options['headers']['accept-encoding'])) { + $curlopts[CURLOPT_ENCODING] = ''; // Enable HTTP compression + } + + foreach ($options['raw_headers'] as $header) { + if (':' === $header[-2] && \strlen($header) - 2 === strpos($header, ': ')) { + // curl requires a special syntax to send empty headers + $curlopts[CURLOPT_HTTPHEADER][] = substr_replace($header, ';', -2); + } else { + $curlopts[CURLOPT_HTTPHEADER][] = $header; + } + } + + // Prevent curl from sending its default Accept and Expect headers + foreach (['accept', 'expect'] as $header) { + if (!isset($options['headers'][$header])) { + $curlopts[CURLOPT_HTTPHEADER][] = $header.':'; + } + } + + if (!\is_string($body = $options['body'])) { + if (\is_resource($body)) { + $curlopts[CURLOPT_INFILE] = $body; + } else { + $eof = false; + $buffer = ''; + $curlopts[CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body, &$buffer, &$eof) { + return self::readRequestBody($length, $body, $buffer, $eof); + }; + } + + if (isset($options['headers']['content-length'][0])) { + $curlopts[CURLOPT_INFILESIZE] = $options['headers']['content-length'][0]; + } elseif (!isset($options['headers']['transfer-encoding'])) { + $curlopts[CURLOPT_HTTPHEADER][] = 'Transfer-Encoding: chunked'; // Enable chunked request bodies + } + + if ('POST' !== $method) { + $curlopts[CURLOPT_UPLOAD] = true; + } + } elseif ('' !== $body) { + $curlopts[CURLOPT_POSTFIELDS] = $body; + } + + if ($options['peer_fingerprint']) { + if (!isset($options['peer_fingerprint']['pin-sha256'])) { + throw new TransportException(__CLASS__.' supports only "pin-sha256" fingerprints.'); + } + + $curlopts[CURLOPT_PINNEDPUBLICKEY] = 'sha256//'.implode(';sha256//', $options['peer_fingerprint']['pin-sha256']); + } + + if ($options['bindto']) { + $curlopts[file_exists($options['bindto']) ? CURLOPT_UNIX_SOCKET_PATH : CURLOPT_INTERFACE] = $options['bindto']; + } + + $ch = curl_init(); + + foreach ($curlopts as $opt => $value) { + if (null !== $value && !curl_setopt($ch, $opt, $value) && CURLOPT_CERTINFO !== $opt) { + $constants = array_filter(get_defined_constants(), static function ($v, $k) use ($opt) { + return $v === $opt && 'C' === $k[0] && (0 === strpos($k, 'CURLOPT_') || 0 === strpos($k, 'CURLINFO_')); + }, ARRAY_FILTER_USE_BOTH); + + throw new TransportException(sprintf('Curl option "%s" is not supported.', key($constants) ?? $opt)); + } + } + + return new CurlResponse($this->multi, $ch, $options, self::createRedirectResolver($options, $host)); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof CurlResponse) { + $responses = [$responses]; + } elseif (!\is_iterable($responses)) { + throw new \TypeError(sprintf('%s() expects parameter 1 to be an iterable of CurlResponse objects, %s given.', __METHOD__, \is_object($responses) ? \get_class($responses) : \gettype($responses))); + } + + while (CURLM_CALL_MULTI_PERFORM === curl_multi_exec($this->multi->handle, $active)); + + return new ResponseStream(CurlResponse::stream($responses, $timeout)); + } + + public function __destruct() + { + $this->multi->pushedResponses = []; + if (\defined('CURLMOPT_PUSHFUNCTION')) { + curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, null); + } + } + + private static function handlePush($parent, $pushed, array $rawHeaders, \stdClass $multi): int + { + $headers = []; + + foreach ($rawHeaders as $h) { + if (false !== $i = strpos($h, ':', 1)) { + $headers[substr($h, 0, $i)] = substr($h, 1 + $i); + } + } + + if ('GET' !== $headers[':method'] || isset($headers['range'])) { + return CURL_PUSH_DENY; + } + + $url = $headers[':scheme'].'://'.$headers[':authority']; + + // curl before 7.65 doesn't validate the pushed ":authority" header, + // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, + // ignoring domains mentioned as alt-name in the certificate for now (same as curl). + if (0 !== strpos(curl_getinfo($parent, CURLINFO_EFFECTIVE_URL), $url.'/')) { + return CURL_PUSH_DENY; + } + + $multi->pushedResponses[$url.$headers[':path']] = [ + new CurlResponse($multi, $pushed), + [ + $headers['authorization'] ?? null, + $headers['cookie'] ?? null, + $headers['x-requested-with'] ?? null, + null, + ], + ]; + + return CURL_PUSH_OK; + } + + /** + * Wraps the request's body callback to allow it to return strings longer than curl requested. + */ + private static function readRequestBody(int $length, \Closure $body, string &$buffer, bool &$eof): string + { + if (!$eof && \strlen($buffer) < $length) { + if (!\is_string($data = $body($length))) { + throw new TransportException(sprintf('The return value of the "body" option callback must be a string, %s returned.', \gettype($data))); + } + + $buffer .= $data; + $eof = '' === $data; + } + + $data = substr($buffer, 0, $length); + $buffer = substr($buffer, $length); + + return $data; + } + + /** + * Resolves relative URLs on redirects and deals with authentication headers. + * + * Work around CVE-2018-1000007: Authorization and Cookie headers should not follow redirects - fixed in Curl 7.64 + */ + private static function createRedirectResolver(array $options, string $host): \Closure + { + $redirectHeaders = []; + if (0 < $options['max_redirects']) { + $redirectHeaders['host'] = $host; + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + return 0 !== stripos($h, 'Host:'); + }); + + if (isset($options['headers']['authorization']) || isset($options['headers']['cookie'])) { + $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); + }); + } + } + + return static function ($ch, string $location) use ($redirectHeaders) { + if ($host = parse_url($location, PHP_URL_HOST)) { + $rawHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; + curl_setopt($ch, CURLOPT_HTTPHEADER, $rawHeaders); + } + + $url = self::parseUrl(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)); + + return implode('', self::resolveUrl(self::parseUrl($location), $url)); + }; + } +} diff --git a/src/Symfony/Component/HttpClient/Exception/ClientException.php b/src/Symfony/Component/HttpClient/Exception/ClientException.php new file mode 100644 index 0000000000000..3eb997432b3c8 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/ClientException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; + +/** + * Represents a 4xx response. + * + * @author Nicolas Grekas + * + * @internal + */ +final class ClientException extends \RuntimeException implements ClientExceptionInterface +{ + use HttpExceptionTrait; +} diff --git a/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php b/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php new file mode 100644 index 0000000000000..48f7b880eba43 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait HttpExceptionTrait +{ + public function __construct(ResponseInterface $response) + { + $code = $response->getInfo('http_code'); + $url = $response->getInfo('url'); + $message = sprintf('HTTP %d returned for URL "%s".', $code, $url); + + foreach (array_reverse($response->getInfo('raw_headers')) as $h) { + if (0 === strpos($h, 'HTTP/')) { + $message = sprintf('%s returned for URL "%s".', $h, $url); + break; + } + } + + parent::__construct($message, $code); + } +} diff --git a/src/Symfony/Component/HttpClient/Exception/InvalidArgumentException.php b/src/Symfony/Component/HttpClient/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000000..59afbd6ad0351 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/InvalidArgumentException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class InvalidArgumentException extends \InvalidArgumentException implements TransportExceptionInterface +{ +} diff --git a/src/Symfony/Component/HttpClient/Exception/RedirectionException.php b/src/Symfony/Component/HttpClient/Exception/RedirectionException.php new file mode 100644 index 0000000000000..1c62f973b8ef7 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/RedirectionException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; + +/** + * Represents a 3xx response. + * + * @author Nicolas Grekas + * + * @internal + */ +final class RedirectionException extends \RuntimeException implements RedirectionExceptionInterface +{ + use HttpExceptionTrait; +} diff --git a/src/Symfony/Component/HttpClient/Exception/ServerException.php b/src/Symfony/Component/HttpClient/Exception/ServerException.php new file mode 100644 index 0000000000000..7b91de486558f --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/ServerException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; + +/** + * Represents a 5xx response. + * + * @author Nicolas Grekas + * + * @internal + */ +final class ServerException extends \RuntimeException implements ServerExceptionInterface +{ + use HttpExceptionTrait; +} diff --git a/src/Symfony/Component/HttpClient/Exception/TransportException.php b/src/Symfony/Component/HttpClient/Exception/TransportException.php new file mode 100644 index 0000000000000..85606aa3b830f --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/TransportException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class TransportException extends \RuntimeException implements TransportExceptionInterface +{ +} diff --git a/src/Symfony/Component/HttpClient/HttpClient.php b/src/Symfony/Component/HttpClient/HttpClient.php new file mode 100644 index 0000000000000..6d680d9b49837 --- /dev/null +++ b/src/Symfony/Component/HttpClient/HttpClient.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A factory to instantiate the best possible HTTP client for the runtime. + * + * @author Nicolas Grekas + * + * @experimental in 4.3 + */ +final class HttpClient +{ + /** + * @param array $defaultOptions Default requests' options + * @param int $maxHostConnections The maximum number of connections to a single host + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public static function create(array $defaultOptions = [], int $maxHostConnections = 6): HttpClientInterface + { + if (\extension_loaded('curl')) { + return new CurlHttpClient($defaultOptions, $maxHostConnections); + } + + return new NativeHttpClient($defaultOptions, $maxHostConnections); + } +} diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php new file mode 100644 index 0000000000000..ab9bbca5c94e6 --- /dev/null +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -0,0 +1,457 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * Provides the common logic from writing HttpClientInterface implementations. + * + * All methods are static to prevent implementers from creating memory leaks via circular references. + * + * @author Nicolas Grekas + * + * @experimental in 4.3 + */ +trait HttpClientTrait +{ + private static $CHUNK_SIZE = 16372; + + /** + * Validates and normalizes method, URL and options, and merges them with defaults. + * + * @throws InvalidArgumentException When a not-supported option is found + */ + private static function prepareRequest(?string $method, ?string $url, array $options, array $defaultOptions = [], bool $allowExtraOptions = false): array + { + if (null !== $method && \strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) { + throw new InvalidArgumentException(sprintf('Invalid HTTP method "%s", only uppercase letters are accepted.', $method)); + } + + $options = self::mergeDefaultOptions($options, $defaultOptions, $allowExtraOptions); + + if (isset($options['json'])) { + $options['body'] = self::jsonEncode($options['json']); + $options['headers']['content-type'] = $options['headers']['content-type'] ?? ['application/json']; + } + + if (isset($options['body'])) { + $options['body'] = self::normalizeBody($options['body']); + } + + if (isset($options['peer_fingerprint'])) { + $options['peer_fingerprint'] = self::normalizePeerFingerprint($options['peer_fingerprint']); + } + + // Compute raw headers + $rawHeaders = $headers = []; + + foreach ($options['headers'] as $name => $values) { + foreach ($values as $value) { + $rawHeaders[] = $name.': '.$headers[$name][] = $value = (string) $value; + + if (\strlen($value) !== strcspn($value, "\r\n\0")) { + throw new InvalidArgumentException(sprintf('Invalid header value: CR/LF/NUL found in "%s".', $value)); + } + } + } + + // Validate on_progress + if (!\is_callable($onProgress = $options['on_progress'] ?? 'var_dump')) { + throw new InvalidArgumentException(sprintf('Option "on_progress" must be callable, %s given.', \is_object($onProgress) ? \get_class($onProgress) : \gettype($onProgress))); + } + + if (!\is_string($options['auth'] ?? '')) { + throw new InvalidArgumentException(sprintf('Option "auth" must be string, %s given.', \gettype($options['auth']))); + } + + if (null !== $url) { + // Merge auth with headers + if (($options['auth'] ?? false) && !($headers['authorization'] ?? false)) { + $rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth']); + } + + $options['raw_headers'] = $rawHeaders; + unset($options['auth']); + + // Parse base URI + if (\is_string($options['base_uri'])) { + $options['base_uri'] = self::parseUrl($options['base_uri']); + } + + // Validate and resolve URL + $url = self::parseUrl($url, $options['query']); + $url = self::resolveUrl($url, $options['base_uri'], $defaultOptions['query'] ?? []); + } + + // Finalize normalization of options + $options['headers'] = $headers; + $options['http_version'] = (string) ($options['http_version'] ?? ''); + $options['timeout'] = (float) ($options['timeout'] ?? ini_get('default_socket_timeout')); + + return [$url, $options]; + } + + /** + * @throws InvalidArgumentException When an invalid option is found + */ + private static function mergeDefaultOptions(array $options, array $defaultOptions, bool $allowExtraOptions = false): array + { + $options['headers'] = self::normalizeHeaders($options['headers'] ?? []); + + if ($defaultOptions['headers'] ?? false) { + $options['headers'] += self::normalizeHeaders($defaultOptions['headers']); + } + + if ($options['resolve'] ?? false) { + $options['resolve'] = array_change_key_case($options['resolve']); + } + + // Option "query" is never inherited from defaults + $options['query'] = $options['query'] ?? []; + + $options += $defaultOptions; + + if ($defaultOptions['resolve'] ?? false) { + $options['resolve'] += array_change_key_case($defaultOptions['resolve']); + } + + if ($allowExtraOptions || !$defaultOptions) { + return $options; + } + + // Look for unsupported options + foreach ($options as $name => $v) { + if (\array_key_exists($name, $defaultOptions)) { + continue; + } + + $alternatives = []; + + foreach ($defaultOptions as $key => $v) { + if (levenshtein($name, $key) <= \strlen($name) / 3 || false !== strpos($key, $name)) { + $alternatives[] = $key; + } + } + + throw new InvalidArgumentException(sprintf('Unsupported option "%s" passed to %s, did you mean "%s"?', $name, __CLASS__, implode('", "', $alternatives ?: array_keys($defaultOptions)))); + } + + return $options; + } + + /** + * Normalizes headers by putting their names as lowercased keys. + * + * @return string[][] + */ + private static function normalizeHeaders(array $headers): array + { + $normalizedHeaders = []; + + foreach ($headers as $name => $values) { + if (\is_int($name)) { + [$name, $values] = explode(':', $values, 2); + $values = [ltrim($values)]; + } elseif (!\is_iterable($values)) { + $values = (array) $values; + } + + $normalizedHeaders[$name = strtolower($name)] = []; + + foreach ($values as $value) { + $normalizedHeaders[$name][] = $value; + } + } + + return $normalizedHeaders; + } + + /** + * @param array|string|resource|\Traversable|\Closure $body + * + * @return string|resource|\Closure + * + * @throws InvalidArgumentException When an invalid body is passed + */ + private static function normalizeBody($body) + { + if (\is_array($body)) { + return http_build_query($body, '', '&', PHP_QUERY_RFC1738); + } + + if ($body instanceof \Traversable) { + $body = function () use ($body) { yield from $body; }; + } + + if ($body instanceof \Closure) { + $r = new \ReflectionFunction($body); + $body = $r->getClosure(); + + if ($r->isGenerator()) { + $body = $body(self::$CHUNK_SIZE); + $body = function () use ($body) { + $chunk = $body->valid() ? $body->current() : ''; + $body->next(); + + return $chunk; + }; + } + + return $body; + } + + if (!\is_string($body) && !\is_array(@stream_get_meta_data($body))) { + throw new InvalidArgumentException(sprintf('Option "body" must be string, stream resource, iterable or callable, %s given.', \is_resource($body) ? get_resource_type($body) : \gettype($body))); + } + + return $body; + } + + /** + * @param string|string[] $fingerprint + * + * @throws InvalidArgumentException When an invalid fingerprint is passed + */ + private static function normalizePeerFingerprint($fingerprint): array + { + if (\is_string($fingerprint)) { + switch (\strlen($fingerprint = str_replace(':', '', $fingerprint))) { + case 32: $fingerprint = ['md5' => $fingerprint]; break; + case 40: $fingerprint = ['sha1' => $fingerprint]; break; + case 44: $fingerprint = ['pin-sha256' => [$fingerprint]]; break; + case 64: $fingerprint = ['sha256' => $fingerprint]; break; + default: throw new InvalidArgumentException(sprintf('Cannot auto-detect fingerprint algorithm for "%s".', $fingerprint)); + } + } elseif (\is_array($fingerprint)) { + foreach ($fingerprint as $algo => $hash) { + $fingerprint[$algo] = 'pin-sha256' === $algo ? (array) $hash : str_replace(':', '', $hash); + } + } else { + throw new InvalidArgumentException(sprintf('Option "peer_fingerprint" must be string or array, %s given.', \gettype($body))); + } + + return $fingerprint; + } + + /** + * @param array|\JsonSerializable $value + * + * @throws InvalidArgumentException When the value cannot be json-encoded + */ + private static function jsonEncode($value, int $flags = null, int $maxDepth = 512): string + { + $flags = $flags ?? (JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_PRESERVE_ZERO_FRACTION); + + if (!\is_array($value) && !$value instanceof \JsonSerializable) { + throw new InvalidArgumentException(sprintf('Option "json" must be array or JsonSerializable, %s given.', __CLASS__, \is_object($value) ? \get_class($value) : \gettype($value))); + } + + try { + $value = json_encode($value, $flags | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0), $maxDepth); + } catch (\JsonException $e) { + throw new InvalidArgumentException(sprintf('Invalid value for "json" option: %s.', $e->getMessage())); + } + + if (\PHP_VERSION_ID < 70300 && JSON_ERROR_NONE !== json_last_error() && (false === $value || !($flags & JSON_PARTIAL_OUTPUT_ON_ERROR))) { + throw new InvalidArgumentException(sprintf('Invalid value for "json" option: %s.', json_last_error_msg())); + } + + return $value; + } + + /** + * Resolves a URL against a base URI. + * + * @see https://tools.ietf.org/html/rfc3986#section-5.2.2 + * + * @throws InvalidArgumentException When an invalid URL is passed + */ + private static function resolveUrl(array $url, ?array $base, array $queryDefaults = []): array + { + if (null !== $base && '' === ($base['scheme'] ?? '').($base['authority'] ?? '')) { + throw new InvalidArgumentException(sprintf('Invalid "base_uri" option: host or scheme is missing in "%s".', implode('', $base))); + } + + if (null === $base && '' === $url['scheme'].$url['authority']) { + throw new InvalidArgumentException(sprintf('Invalid URL: no "base_uri" option was provided and host or scheme is missing in "%s".', implode('', $url))); + } + + if (null !== $url['scheme']) { + $url['path'] = self::removeDotSegments($url['path'] ?? ''); + } else { + if (null !== $url['authority']) { + $url['path'] = self::removeDotSegments($url['path'] ?? ''); + } else { + if (null === $url['path']) { + $url['path'] = $base['path']; + $url['query'] = $url['query'] ?? $base['query']; + } else { + if ('/' !== $url['path'][0]) { + if (null === $base['path']) { + $url['path'] = '/'.$url['path']; + } else { + $segments = explode('/', $base['path']); + array_splice($segments, -1, 1, [$url['path']]); + $url['path'] = implode('/', $segments); + } + } + + $url['path'] = self::removeDotSegments($url['path']); + } + + $url['authority'] = $base['authority']; + + if ($queryDefaults) { + $url['query'] = '?'.self::mergeQueryString(substr($url['query'] ?? '', 1), $queryDefaults, false); + } + } + + $url['scheme'] = $base['scheme']; + } + + if ('' === ($url['path'] ?? '')) { + $url['path'] = '/'; + } + + return $url; + } + + /** + * Parses a URL and fixes its encoding if needed. + * + * @throws InvalidArgumentException When an invalid URL is passed + */ + private static function parseUrl(string $url, array $query = [], array $allowedSchemes = ['http' => 80, 'https' => 443]): array + { + if (false === $parts = parse_url($url)) { + throw new InvalidArgumentException(sprintf('Malformed URL "%s".', $url)); + } + + if ($query) { + $parts['query'] = self::mergeQueryString($parts['query'] ?? null, $query, true); + } + + $port = $parts['port'] ?? 0; + + if (null !== $scheme = $parts['scheme'] ?? null) { + if (!isset($allowedSchemes[$scheme = strtolower($scheme)])) { + throw new InvalidArgumentException(sprintf('Unsupported scheme in "%s".', $url)); + } + + $port = $allowedSchemes[$scheme] === $port ? 0 : $port; + $scheme .= ':'; + } + + if (null !== $host = $parts['host'] ?? null) { + if (!\defined('INTL_IDNA_VARIANT_UTS46') && preg_match('/[\x80-\xFF]/', $host)) { + throw new InvalidArgumentException(sprintf('Unsupported IDN "%s", try enabling the "intl" PHP extension or running "composer require symfony/polyfill-intl-idn".', $host)); + } + + if (false === $host = \defined('INTL_IDNA_VARIANT_UTS46') ? idn_to_ascii($host, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46) : strtolower($host)) { + throw new InvalidArgumentException(sprintf('Unsupported host in "%s".', $url)); + } + + $host .= $port ? ':'.$port : ''; + } + + foreach (['user', 'pass', 'path', 'query', 'fragment'] as $part) { + if (!isset($parts[$part])) { + continue; + } + + if (false !== strpos($parts[$part], '%')) { + // https://tools.ietf.org/html/rfc3986#section-2.3 + $parts[$part] = preg_replace_callback('/%(?:2[DE]|3[0-9]|[46][1-9A-F]|5F|[57][0-9A]|7E)++/i', function ($m) { return rawurldecode($m[0]); }, $parts[$part]); + } + + // https://tools.ietf.org/html/rfc3986#section-3.3 + $parts[$part] = preg_replace_callback("#[^-A-Za-z0-9._~!$&/'()*+,;=:@%]++#", function ($m) { return rawurlencode($m[0]); }, $parts[$part]); + } + + return [ + 'scheme' => $scheme, + 'authority' => null !== $host ? '//'.(isset($parts['user']) ? $parts['user'].(isset($parts['pass']) ? ':'.$parts['pass'] : '').'@' : '').$host : null, + 'path' => isset($parts['path'][0]) ? $parts['path'] : null, + 'query' => isset($parts['query']) ? '?'.$parts['query'] : null, + 'fragment' => isset($parts['fragment']) ? '#'.$parts['fragment'] : null, + ]; + } + + /** + * Removes dot-segments from a path. + * + * @see https://tools.ietf.org/html/rfc3986#section-5.2.4 + */ + private static function removeDotSegments(string $path) + { + $result = ''; + + while (!\in_array($path, ['', '.', '..'], true)) { + if ('.' === $path[0] && (0 === strpos($path, $p = '../') || 0 === strpos($path, $p = './'))) { + $path = substr($path, \strlen($p)); + } elseif ('/.' === $path || 0 === strpos($path, '/./')) { + $path = substr_replace($path, '/', 0, 3); + } elseif ('/..' === $path || 0 === strpos($path, '/../')) { + $i = strrpos($result, '/'); + $result = $i ? substr($result, 0, $i) : ''; + $path = substr_replace($path, '/', 0, 4); + } else { + $i = strpos($path, '/', 1) ?: \strlen($path); + $result .= substr($path, 0, $i); + $path = substr($path, $i); + } + } + + return $result; + } + + /** + * Merges and encodes a query array with a query string. + * + * @throws InvalidArgumentException When an invalid query-string value is passed + */ + private static function mergeQueryString(?string $queryString, array $queryArray, bool $replace): ?string + { + if (!$queryArray) { + return $queryString; + } + + $query = []; + + if (null !== $queryString) { + foreach (explode('&', $queryString) as $v) { + if ('' !== $v) { + $k = urldecode(explode('=', $v, 2)[0]); + $query[$k] = (isset($query[$k]) ? $query[$k].'&' : '').$v; + } + } + } + + foreach ($queryArray as $k => $v) { + if (is_scalar($v)) { + $queryArray[$k] = rawurlencode($k).'='.rawurlencode($v); + } elseif (null === $v) { + unset($queryArray[$k]); + + if ($replace) { + unset($query[$k]); + } + } else { + throw new InvalidArgumentException(sprintf('Unsupported value for query parameter "%s": scalar or null expected, %s given.', $k, \gettype($v))); + } + } + + return implode('&', $replace ? array_replace($query, $queryArray) : ($query + $queryArray)); + } +} diff --git a/src/Symfony/Component/HttpClient/HttpOptions.php b/src/Symfony/Component/HttpClient/HttpOptions.php new file mode 100644 index 0000000000000..ce85eaf274d5b --- /dev/null +++ b/src/Symfony/Component/HttpClient/HttpOptions.php @@ -0,0 +1,299 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A helper providing autocompletion for available options. + * + * @see HttpClientInterface for a description of each options. + * + * @author Nicolas Grekas + * + * @experimental in 4.3 + */ +class HttpOptions +{ + private $options = []; + + public function toArray(): array + { + return $this->options; + } + + /** + * @return $this + */ + public function setAuth(string $userinfo) + { + $this->options['auth'] = $userinfo; + + return $this; + } + + /** + * @return $this + */ + public function setQuery(array $query) + { + $this->options['query'] = $query; + + return $this; + } + + /** + * @return $this + */ + public function setHeaders(iterable $headers) + { + $this->options['headers'] = $headers; + + return $this; + } + + /** + * @param array|string|resource|\Traversable|\Closure $body + * + * @return $this + */ + public function setBody($body) + { + $this->options['body'] = $body; + + return $this; + } + + /** + * @param array|\JsonSerializable $json + * + * @return $this + */ + public function setJson($json) + { + $this->options['json'] = $json; + + return $this; + } + + /** + * @return $this + */ + public function setUserData($data) + { + $this->options['user_data'] = $data; + + return $this; + } + + /** + * @return $this + */ + public function setMaxRedirects(int $max) + { + $this->options['max_redirects'] = $max; + + return $this; + } + + /** + * @return $this + */ + public function setHttpVersion(string $version) + { + $this->options['http_version'] = $version; + + return $this; + } + + /** + * @return $this + */ + public function setBaseUri(string $uri) + { + $this->options['base_uri'] = $uri; + + return $this; + } + + /** + * @return $this + */ + public function buffer(bool $buffer) + { + $this->options['buffer'] = $buffer; + + return $this; + } + + /** + * @return $this + */ + public function setOnProgress(callable $callback) + { + $this->options['on_progress'] = $callback; + + return $this; + } + + /** + * @return $this + */ + public function resolve(array $hostIps) + { + $this->options['resolve'] = $hostIps; + + return $this; + } + + /** + * @return $this + */ + public function setProxy(string $proxy) + { + $this->options['proxy'] = $proxy; + + return $this; + } + + /** + * @return $this + */ + public function setNoProxy(string $noProxy) + { + $this->options['no_proxy'] = $noProxy; + + return $this; + } + + /** + * @return $this + */ + public function setTimeout(float $timeout) + { + $this->options['timeout'] = $timeout; + + return $this; + } + + /** + * @return $this + */ + public function bindTo(string $bindto) + { + $this->options['bindto'] = $bindto; + + return $this; + } + + /** + * @return $this + */ + public function verifyPeer(bool $verify) + { + $this->options['verify_peer'] = $verify; + + return $this; + } + + /** + * @return $this + */ + public function verifyHost(bool $verify) + { + $this->options['verify_host'] = $verify; + + return $this; + } + + /** + * @return $this + */ + public function setCaFile(string $cafile) + { + $this->options['cafile'] = $cafile; + + return $this; + } + + /** + * @return $this + */ + public function setCaPath(string $capath) + { + $this->options['capath'] = $capath; + + return $this; + } + + /** + * @return $this + */ + public function setLocalCert(string $cert) + { + $this->options['local_cert'] = $cert; + + return $this; + } + + /** + * @return $this + */ + public function setLocalPk(string $pk) + { + $this->options['local_pk'] = $pk; + + return $this; + } + + /** + * @return $this + */ + public function setPassphrase(string $passphrase) + { + $this->options['passphrase'] = $passphrase; + + return $this; + } + + /** + * @return $this + */ + public function setCiphers(string $ciphers) + { + $this->options['ciphers'] = $ciphers; + + return $this; + } + + /** + * @param string|array $fingerprint + * + * @return $this + */ + public function setPeerFingerprint($fingerprint) + { + $this->options['peer_fingerprint'] = $fingerprint; + + return $this; + } + + /** + * @return $this + */ + public function capturePeerCertChain(bool $capture) + { + $this->options['capture_peer_cert_chain'] = $capture; + + return $this; + } +} diff --git a/src/Symfony/Component/HttpClient/LICENSE b/src/Symfony/Component/HttpClient/LICENSE new file mode 100644 index 0000000000000..3f853aaf35fe1 --- /dev/null +++ b/src/Symfony/Component/HttpClient/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php new file mode 100644 index 0000000000000..c79f9af7b34a2 --- /dev/null +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -0,0 +1,420 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Response\NativeResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * A portable implementation of the HttpClientInterface contracts based on PHP stream wrappers. + * + * PHP stream wrappers are able to fetch response bodies concurrently, + * but each request is opened synchronously. + * + * @author Nicolas Grekas + * + * @experimental in 4.3 + */ +final class NativeHttpClient implements HttpClientInterface +{ + use HttpClientTrait; + + private $defaultOptions = self::OPTIONS_DEFAULTS; + private $multi; + + /** + * @param array $defaultOptions Default requests' options + * @param int $maxHostConnections The maximum number of connections to open + * + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + */ + public function __construct(array $defaultOptions = [], int $maxHostConnections = 6) + { + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); + } + + // Use an internal stdClass object to share state between the client and its responses + $this->multi = (object) [ + 'openHandles' => [], + 'handlesActivity' => [], + 'pendingResponses' => [], + 'maxHostConnections' => $maxHostConnections, + 'responseCount' => 0, + 'dnsCache' => [], + 'handles' => [], + 'sleep' => false, + 'id' => random_int(PHP_INT_MIN, PHP_INT_MAX), + ]; + } + + /** + * @see HttpClientInterface::OPTIONS_DEFAULTS for available options + * + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); + + if ($options['bindto'] && file_exists($options['bindto'])) { + throw new TransportException(__CLASS__.' cannot bind to local Unix sockets, use e.g. CurlHttpClient instead.'); + } + + $options['body'] = self::getBodyAsString($options['body']); + + if ('' !== $options['body'] && 'POST' === $method && !isset($options['headers']['content-type'])) { + $options['raw_headers'][] = 'content-type: application/x-www-form-urlencoded'; + } + + if ($gzipEnabled = \extension_loaded('zlib') && !isset($options['headers']['accept-encoding'])) { + // gzip is the most widely available algo, no need to deal with deflate + $options['raw_headers'][] = 'accept-encoding: gzip'; + } + + if ($options['peer_fingerprint']) { + if (isset($options['peer_fingerprint']['pin-sha256']) && 1 === \count($options['peer_fingerprint'])) { + throw new TransportException(__CLASS__.' cannot verify "pin-sha256" fingerprints, please provide a "sha256" one.'); + } + + unset($options['peer_fingerprint']['pin-sha256']); + } + + $info = [ + 'raw_headers' => [], + 'url' => $url, + 'error' => null, + 'http_code' => 0, + 'redirect_count' => 0, + 'start_time' => 0.0, + 'fopen_time' => 0.0, + 'connect_time' => 0.0, + 'redirect_time' => 0.0, + 'starttransfer_time' => 0.0, + 'total_time' => 0.0, + 'namelookup_time' => 0.0, + 'size_upload' => 0, + 'size_download' => 0, + 'size_body' => \strlen($options['body']), + 'primary_ip' => '', + 'primary_port' => 'http:' === $url['scheme'] ? 80 : 443, + ]; + + if ($onProgress = $options['on_progress']) { + // Memoize the last progress to ease calling the callback periodically when no network transfer happens + $lastProgress = [0, 0]; + $onProgress = static function (...$progress) use ($onProgress, &$lastProgress, &$info) { + $progressInfo = $info; + $progressInfo['url'] = implode('', $info['url']); + unset($progressInfo['fopen_time'], $progressInfo['size_body']); + + if ($progress && -1 === $progress[0]) { + // Response completed + $lastProgress[0] = max($lastProgress); + } else { + $lastProgress = $progress ?: $lastProgress; + } + + $onProgress($lastProgress[0], $lastProgress[1], $progressInfo); + }; + } + + // Always register a notification callback to compute live stats about the response + $notification = static function (int $code, int $severity, ?string $msg, int $msgCode, int $dlNow, int $dlSize) use ($onProgress, &$info) { + $now = microtime(true); + $info['total_time'] = $now - $info['start_time']; + + if (STREAM_NOTIFY_PROGRESS === $code) { + $info['size_upload'] += $dlNow ? 0 : $info['size_body']; + $info['size_download'] = $dlNow; + } elseif (STREAM_NOTIFY_CONNECT === $code) { + $info['connect_time'] += $now - $info['fopen_time']; + } else { + return; + } + + if ($onProgress) { + $onProgress($dlNow, $dlSize); + } + }; + + if ($options['resolve']) { + $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; + } + + [$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress); + + if (!isset($options['headers']['host'])) { + $options['raw_headers'][] = 'host: '.$host.$port; + } + + $context = [ + 'http' => [ + 'protocol_version' => $options['http_version'] ?: '1.1', + 'method' => $method, + 'content' => $options['body'], + 'ignore_errors' => true, + 'user_agent' => 'Symfony HttpClient/Native', + 'curl_verify_ssl_peer' => $options['verify_peer'], + 'curl_verify_ssl_host' => $options['verify_host'], + 'auto_decode' => false, // Disable dechunk filter, it's incompatible with stream_select() + 'timeout' => $options['timeout'], + 'follow_location' => false, // We follow redirects ourselves - the native logic is too limited + ], + 'ssl' => array_filter([ + 'peer_name' => $host, + 'verify_peer' => $options['verify_peer'], + 'verify_peer_name' => $options['verify_host'], + 'cafile' => $options['cafile'], + 'capath' => $options['capath'], + 'local_cert' => $options['local_cert'], + 'local_pk' => $options['local_pk'], + 'passphrase' => $options['passphrase'], + 'ciphers' => $options['ciphers'], + 'peer_fingerprint' => $options['peer_fingerprint'], + 'capture_peer_cert_chain' => $options['capture_peer_cert_chain'], + 'allow_self_signed' => (bool) $options['peer_fingerprint'], + 'SNI_enabled' => true, + 'disable_compression' => true, + ], static function ($v) { return null !== $v; }), + 'socket' => [ + 'bindto' => $options['bindto'], + 'tcp_nodelay' => true, + ], + ]; + + $proxy = self::getProxy($options['proxy'], $url); + $noProxy = $noProxy ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? ''; + $noProxy = $noProxy ? preg_split('/[\s,]+/', $noProxy) : []; + + $resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress); + $context = stream_context_create($context, ['notification' => $notification]); + self::configureHeadersAndProxy($context, $host, $options['raw_headers'], $proxy, $noProxy); + + return new NativeResponse($this->multi, $context, implode('', $url), $options, $gzipEnabled, $info, $resolveRedirect, $onProgress); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof NativeResponse) { + $responses = [$responses]; + } elseif (!\is_iterable($responses)) { + throw new \TypeError(sprintf('%s() expects parameter 1 to be an iterable of NativeResponse objects, %s given.', __METHOD__, \is_object($responses) ? \get_class($responses) : \gettype($responses))); + } + + return new ResponseStream(NativeResponse::stream($responses, $timeout)); + } + + private static function getBodyAsString($body): string + { + if (\is_resource($body)) { + return stream_get_contents($body); + } + + if (!$body instanceof \Closure) { + return $body; + } + + $result = ''; + + while ('' !== $data = $body(self::$CHUNK_SIZE)) { + if (!\is_string($data)) { + throw new TransportException(sprintf('Return value of the "body" option callback must be string, %s returned.', \gettype($data))); + } + + $result .= $data; + } + + return $result; + } + + /** + * Loads proxy configuration from the same environment variables as curl when no proxy is explicitly set. + */ + private static function getProxy(?string $proxy, array $url): ?array + { + if (null === $proxy) { + // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities + $proxy = $_SERVER['http_proxy'] ?? ('cli' === \PHP_SAPI ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; + + if ('https:' === $url['scheme']) { + $proxy = $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? $proxy; + } + } + + if (null === $proxy) { + return null; + } + + $proxy = (parse_url($proxy) ?: []) + ['scheme' => 'http']; + + if (!isset($proxy['host'])) { + throw new TransportException('Invalid HTTP proxy: host is missing.'); + } + + if ('http' === $proxy['scheme']) { + $proxyUrl = 'tcp://'.$proxy['host'].':'.($proxy['port'] ?? '80'); + } elseif ('https' === $proxy['scheme']) { + $proxyUrl = 'ssl://'.$proxy['host'].':'.($proxy['port'] ?? '443'); + } else { + throw new TransportException(sprintf('Unsupported proxy scheme "%s": "http" or "https" expected.', $proxy['scheme'])); + } + + return [ + 'url' => $proxyUrl, + 'auth' => isset($proxy['user']) ? 'Basic '.base64_encode(rawurldecode($proxy['user']).':'.rawurldecode($proxy['pass'] ?? '')) : null, + ]; + } + + /** + * Resolves the IP of the host using the local DNS cache if possible. + */ + private static function dnsResolve(array $url, \stdClass $multi, array &$info, ?\Closure $onProgress): array + { + if ($port = parse_url($url['authority'], PHP_URL_PORT) ?: '') { + $info['primary_port'] = $port; + $port = ':'.$port; + } else { + $info['primary_port'] = 'http:' === $url['scheme'] ? 80 : 443; + } + + $host = parse_url($url['authority'], PHP_URL_HOST); + + if (null === $ip = $multi->dnsCache[$host] ?? null) { + $now = microtime(true); + + if (!$ip = gethostbynamel($host)) { + throw new TransportException(sprintf('Could not resolve host "%s".', $host)); + } + + $info['namelookup_time'] += microtime(true) - $now; + $multi->dnsCache[$host] = $ip = $ip[0]; + } + + $info['primary_ip'] = $ip; + + if ($onProgress) { + // Notify DNS resolution + $onProgress(); + } + + return [$host, $port, substr_replace($url['authority'], $ip, -\strlen($host) - \strlen($port), \strlen($host))]; + } + + /** + * Handles redirects - the native logic is too buggy to be used. + */ + private static function createRedirectResolver(array $options, string $host, ?array $proxy, array $noProxy, array &$info, ?\Closure $onProgress): \Closure + { + $redirectHeaders = []; + if (0 < $maxRedirects = $options['max_redirects']) { + $redirectHeaders = ['host' => $host]; + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + return 0 !== stripos($h, 'Host:'); + }); + + if (isset($options['headers']['authorization']) || isset($options['headers']['cookie'])) { + $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); + }); + } + } + + return static function (\stdClass $multi, int $statusCode, ?string $location, $context) use ($redirectHeaders, $proxy, $noProxy, &$info, $maxRedirects, $onProgress): ?string { + if (null === $location || $statusCode < 300 || 400 <= $statusCode) { + $info['redirect_url'] = null; + + return null; + } + + $url = self::resolveUrl(self::parseUrl($location), $info['url']); + $info['redirect_url'] = implode('', $url); + + if ($info['redirect_count'] >= $maxRedirects) { + return null; + } + + $now = microtime(true); + $info['url'] = $url; + ++$info['redirect_count']; + $info['redirect_time'] = $now - $info['start_time']; + + // Do like curl and browsers: turn POST to GET on 301, 302 and 303 + if (\in_array($statusCode, [301, 302, 303], true)) { + $options = stream_context_get_options($context)['http']; + + if ('POST' === $options['method'] || 303 === $statusCode) { + $options['method'] = 'HEAD' === $options['method'] ? 'HEAD' : 'GET'; + $options['content'] = ''; + $options['header'] = array_filter($options['header'], static function ($h) { + return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:'); + }); + + stream_context_set_option($context, ['http' => $options]); + } + } + + [$host, $port, $url['authority']] = self::dnsResolve($url, $multi, $info, $onProgress); + stream_context_set_option($context, 'ssl', 'peer_name', $host); + + if (false !== (parse_url($location, PHP_URL_HOST) ?? false)) { + // Authorization and Cookie headers MUST NOT follow except for the initial host name + $rawHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; + $rawHeaders[] = 'host: '.$host.$port; + self::configureHeadersAndProxy($context, $host, $rawHeaders, $proxy, $noProxy); + } + + return implode('', $url); + }; + } + + private static function configureHeadersAndProxy($context, string $host, array $rawHeaders, ?array $proxy, array $noProxy) + { + if (null === $proxy) { + return stream_context_set_option($context, 'http', 'header', $rawHeaders); + } + + // Matching "no_proxy" should follow the behavior of curl + + foreach ($noProxy as $rule) { + if ('*' === $rule) { + return stream_context_set_option($context, 'http', 'header', $rawHeaders); + } + + if ($host === $rule) { + return stream_context_set_option($context, 'http', 'header', $rawHeaders); + } + + $rule = '.'.ltrim($rule, '.'); + + if (substr($host, -\strlen($rule)) === $rule) { + return stream_context_set_option($context, 'http', 'header', $rawHeaders); + } + } + + stream_context_set_option($context, 'http', 'proxy', $proxy['url']); + stream_context_set_option($context, 'http', 'request_fulluri', true); + + if (null !== $proxy['auth']) { + $rawHeaders[] = 'Proxy-Authorization: '.$proxy['auth']; + } + + return stream_context_set_option($context, 'http', 'header', $rawHeaders); + } +} diff --git a/src/Symfony/Component/HttpClient/README.md b/src/Symfony/Component/HttpClient/README.md new file mode 100644 index 0000000000000..55a0c78ebd39e --- /dev/null +++ b/src/Symfony/Component/HttpClient/README.md @@ -0,0 +1,17 @@ +HttpClient component +==================== + +The HttpClient component provides powerful methods to fetch HTTP resources synchronously or asynchronously. + +**This Component is experimental**. [Experimental +features](https://symfony.com/doc/current/contributing/code/experimental.html) +are not covered by Symfony's BC-break policy. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/http_client.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php new file mode 100644 index 0000000000000..dadd841d8e485 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -0,0 +1,298 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class CurlResponse implements ResponseInterface +{ + use ResponseTrait; + + private static $performing = false; + + /** + * @internal + */ + public function __construct(\stdClass $multi, $ch, array $options = null, callable $resolveRedirect = null) + { + $this->multi = $multi; + + if (\is_resource($ch)) { + $this->handle = $ch; + } else { + $this->info['url'] = $ch; + $ch = $this->handle; + } + + $this->id = $id = (int) $ch; + $this->timeout = $options['timeout'] ?? null; + $this->info['user_data'] = $options['user_data'] ?? null; + $this->info['start_time'] = $this->info['start_time'] ?? microtime(true); + $info = &$this->info; + + if (!$info['raw_headers']) { + // Used to keep track of what we're waiting for + curl_setopt($ch, CURLOPT_PRIVATE, 'headers'); + } + + if (null === $content = &$this->content) { + $content = ($options['buffer'] ?? true) ? fopen('php://temp', 'w+') : null; + } else { + // Move the pushed response to the activity list + if (ftell($content)) { + rewind($content); + $multi->handlesActivity[$id][] = stream_get_contents($content); + } + $content = ($options['buffer'] ?? true) ? $content : null; + } + + curl_setopt($ch, CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, $options, $multi, $id, &$location, $resolveRedirect): int { + return self::parseHeaderLine($ch, $data, $info, $options, $multi, $id, $location, $resolveRedirect); + }); + + if (null === $options) { + // Pushed response: buffer until requested + curl_setopt($ch, CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use (&$content): int { + return fwrite($content, $data); + }); + + return; + } + + if ($onProgress = $options['on_progress']) { + $url = isset($info['url']) ? ['url' => $info['url']] : []; + curl_setopt($ch, CURLOPT_NOPROGRESS, false); + curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url) { + try { + $onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info); + } catch (\Throwable $e) { + $info['error'] = $e; + + return 1; // Abort the request + } + }); + } + + curl_setopt($ch, CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use (&$content, $multi, $id): int { + $multi->handlesActivity[$id][] = $data; + + return null !== $content ? fwrite($content, $data) : \strlen($data); + }); + + $this->initializer = static function (self $response) { + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + + if (\in_array(curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) { + try { + if (\defined('CURLOPT_STREAM_WEIGHT')) { + curl_setopt($ch, CURLOPT_STREAM_WEIGHT, 32); + } + self::stream([$response])->current(); + } catch (\Throwable $e) { + $response->info['error'] = $e->getMessage(); + $response->close(); + throw $e; + } + } + + curl_setopt($ch, CURLOPT_HEADERFUNCTION, null); + curl_setopt($ch, CURLOPT_READFUNCTION, null); + curl_setopt($ch, CURLOPT_INFILE, null); + + $response->addRawHeaders($response->info['raw_headers']); + }; + + // Schedule the request in a non-blocking way + $multi->openHandles[$id] = $ch; + curl_multi_add_handle($multi->handle, $ch); + self::perform($multi); + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + if (!$info = $this->finalInfo) { + self::perform($this->multi); + $info = array_merge($this->info, curl_getinfo($this->handle)); + $info['url'] = $this->info['url'] ?? $info['url']; + $info['redirect_url'] = $this->info['redirect_url'] ?? null; + + // workaround curl not subtracting the time offset for pushed responses + if (isset($this->info['url']) && $info['start_time'] / 1000 < $info['total_time']) { + $info['total_time'] -= $info['starttransfer_time'] ?: $info['total_time']; + $info['starttransfer_time'] = 0.0; + } + + if (!\in_array(curl_getinfo($this->handle, CURLINFO_PRIVATE), ['headers', 'content'], true)) { + $this->finalInfo = $info; + } + } + + return null !== $type ? $info[$type] ?? null : $info; + } + + public function __destruct() + { + try { + if (null === $this->timeout || isset($this->info['url'])) { + return; // pushed response + } + + if ('content' === $waitFor = curl_getinfo($this->handle, CURLINFO_PRIVATE)) { + $this->close(); + } elseif ('headers' === $waitFor) { + curl_setopt($this->handle, CURLOPT_PRIVATE, 'destruct'); + } + + $this->doDestruct(); + } finally { + $this->close(); + + // Clear local caches when the only remaining handles are about pushed responses + if (\count($this->multi->openHandles) === \count($this->multi->pushedResponses)) { + $this->multi->pushedResponses = []; + // Schedule DNS cache eviction for the next request + $this->multi->dnsCache[2] = $this->multi->dnsCache[2] ?: $this->multi->dnsCache[1]; + $this->multi->dnsCache[1] = $this->multi->dnsCache[0] = []; + } + } + } + + /** + * {@inheritdoc} + */ + protected function close(): void + { + unset($this->multi->openHandles[$this->id], $this->multi->handlesActivity[$this->id]); + curl_multi_remove_handle($this->multi->handle, $this->handle); + curl_setopt_array($this->handle, [ + CURLOPT_PRIVATE => '', + CURLOPT_NOPROGRESS => true, + CURLOPT_PROGRESSFUNCTION => null, + CURLOPT_HEADERFUNCTION => null, + CURLOPT_WRITEFUNCTION => null, + CURLOPT_READFUNCTION => null, + CURLOPT_INFILE => null, + ]); + } + + /** + * {@inheritdoc} + */ + protected static function schedule(self $response, array &$runningResponses): void + { + if ('' === curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE)) { + // no-op - response already completed + } elseif (isset($runningResponses[$i = (int) $response->multi->handle])) { + $runningResponses[$i][1][$response->id] = $response; + } else { + $runningResponses[$i] = [$response->multi, [$response->id => $response]]; + } + } + + /** + * {@inheritdoc} + */ + protected static function perform(\stdClass $multi, array &$responses = null): void + { + if (self::$performing) { + return; + } + + try { + self::$performing = true; + while (CURLM_CALL_MULTI_PERFORM === curl_multi_exec($multi->handle, $active)); + + while ($info = curl_multi_info_read($multi->handle)) { + $multi->handlesActivity[(int) $info['handle']][] = null; + $multi->handlesActivity[(int) $info['handle']][] = \in_array($info['result'], [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) ? null : new TransportException(curl_error($info['handle'])); + } + } finally { + self::$performing = false; + } + } + + /** + * {@inheritdoc} + */ + protected static function select(\stdClass $multi, float $timeout): int + { + return curl_multi_select($multi->handle, $timeout); + } + + /** + * Parses header lines as curl yields them to us. + */ + private static function parseHeaderLine($ch, string $data, array &$info, ?array $options, \stdClass $multi, int $id, ?string &$location, ?callable $resolveRedirect): int + { + if (!\in_array($waitFor = @curl_getinfo($ch, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) { + return \strlen($data); // Ignore HTTP trailers + } + + if ("\r\n" !== $data) { + // Regular header line: add it to the list + $info['raw_headers'][] = substr($data, 0, -2); + + if (0 === stripos($data, 'Location:')) { + $location = trim(substr($data, 9, -2)); + } + + return \strlen($data); + } + + // End of headers: handle redirects and add to the activity list + $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); + $info['redirect_url'] = null; + + if (300 <= $statusCode && $statusCode < 400 && null !== $location) { + $info['redirect_url'] = $resolveRedirect($ch, $location); + $url = parse_url($location ?? ':'); + + if (isset($url['host']) && null !== $ip = $multi->dnsCache[0][$url['host'] = strtolower($url['host'])] ?? null) { + // Populate DNS cache for redirects if needed + $port = $url['port'] ?? ('http' === ($url['scheme'] ?? parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL), PHP_URL_SCHEME)) ? 80 : 443); + curl_setopt($ch, CURLOPT_RESOLVE, ["{$url['host']}:$port:$ip"]); + $multi->dnsCache[1]["-{$url['host']}:$port"] = "-{$url['host']}:$port"; + } + } + + $location = null; + + if ($statusCode < 300 || 400 <= $statusCode || curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) { + // Headers and redirects completed, time to get the response's body + $multi->handlesActivity[$id] = [new FirstChunk()]; + + if ('destruct' === $waitFor) { + return 0; + } + + if ($certinfo = curl_getinfo($ch, CURLINFO_CERTINFO)) { + $info['peer_certificate_chain'] = array_map('openssl_x509_read', array_column($certinfo, 'Cert')); + } + + curl_setopt($ch, CURLOPT_PRIVATE, 'content'); + } + + return \strlen($data); + } +} diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php new file mode 100644 index 0000000000000..3e9ee3a3758cd --- /dev/null +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -0,0 +1,305 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class NativeResponse implements ResponseInterface +{ + use ResponseTrait; + + private $context; + private $url; + private $resolveRedirect; + private $onProgress; + private $remaining; + private $buffer; + private $inflate; + + /** + * @internal + */ + public function __construct(\stdClass $multi, $context, string $url, $options, bool $gzipEnabled, array &$info, callable $resolveRedirect, ?callable $onProgress) + { + $this->multi = $multi; + $this->id = (int) $context; + $this->context = $context; + $this->url = $url; + $this->timeout = $options['timeout']; + $this->info = &$info; + $this->resolveRedirect = $resolveRedirect; + $this->onProgress = $onProgress; + $this->content = $options['buffer'] ? fopen('php://temp', 'w+') : null; + + // Temporary resources to dechunk/inflate the response stream + $this->buffer = fopen('php://temp', 'w+'); + $this->inflate = $gzipEnabled ? inflate_init(ZLIB_ENCODING_GZIP) : null; + + $info['user_data'] = $options['user_data']; + ++$multi->responseCount; + + $this->initializer = static function (self $response) { + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + + if (null === $response->remaining) { + self::stream([$response])->current(); + } + }; + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + if (!$info = $this->finalInfo) { + self::perform($this->multi); + $info = $this->info; + $info['url'] = implode('', $info['url']); + unset($info['fopen_time'], $info['size_body']); + + if (null === $this->buffer) { + $this->finalInfo = $info; + } + } + + return null !== $type ? $info[$type] ?? null : $info; + } + + public function __destruct() + { + try { + $this->doDestruct(); + } finally { + $this->close(); + + // Clear the DNS cache when all requests completed + if (0 >= --$this->multi->responseCount) { + $this->multi->responseCount = 0; + $this->multi->dnsCache = []; + } + } + } + + private function open(): void + { + set_error_handler(function ($type, $msg) { throw new TransportException($msg); }); + + try { + $this->info['start_time'] = microtime(true); + $url = $this->url; + + do { + // Send request and follow redirects when needed + $this->info['fopen_time'] = microtime(true); + $this->handle = $h = fopen($url, 'r', false, $this->context); + $this->addRawHeaders($http_response_header); + $url = ($this->resolveRedirect)($this->multi, $this->statusCode, $this->headers['location'][0] ?? null, $this->context); + } while (null !== $url); + } catch (\Throwable $e) { + $this->statusCode = 0; + $this->close(); + $this->multi->handlesActivity[$this->id][] = null; + $this->multi->handlesActivity[$this->id][] = $e; + + return; + } finally { + $this->info['starttransfer_time'] = $this->info['total_time'] = microtime(true) - $this->info['start_time']; + restore_error_handler(); + } + + stream_set_blocking($h, false); + $context = stream_context_get_options($this->context); + $this->context = $this->resolveRedirect = null; + + if (isset($context['ssl']['peer_certificate_chain'])) { + $this->info['peer_certificate_chain'] = $context['ssl']['peer_certificate_chain']; + } + + // Create dechunk and inflate buffers + if (isset($this->headers['content-length'])) { + $this->remaining = (int) $this->headers['content-length'][0]; + } elseif ('chunked' === ($this->headers['transfer-encoding'][0] ?? null)) { + stream_filter_append($this->buffer, 'dechunk', STREAM_FILTER_WRITE); + $this->remaining = -1; + } else { + $this->remaining = -2; + } + + if ($this->inflate && 'gzip' !== ($this->headers['content-encoding'][0] ?? null)) { + $this->inflate = null; + } + + $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, &$this->content, $this->onProgress, &$this->remaining, &$this->info]; + $this->multi->handlesActivity[$this->id] = [new FirstChunk()]; + } + + /** + * {@inheritdoc} + */ + private function close(): void + { + unset($this->multi->openHandles[$this->id], $this->multi->handlesActivity[$this->id]); + $this->handle = $this->buffer = $this->inflate = $this->onProgress = null; + } + + /** + * {@inheritdoc} + */ + private static function schedule(self $response, array &$runningResponses): void + { + if (null === $response->buffer) { + return; + } + + if (!isset($runningResponses[$i = $response->multi->id])) { + $runningResponses[$i] = [$response->multi, []]; + } + + if (null === $response->remaining) { + $response->multi->pendingResponses[] = $response; + } else { + $runningResponses[$i][1][$response->id] = $response; + } + } + + /** + * {@inheritdoc} + */ + private static function perform(\stdClass $multi, array &$responses = null): void + { + // List of native handles for stream_select() + if (null !== $responses) { + $multi->handles = []; + } + + foreach ($multi->openHandles as $i => [$h, $buffer, $inflate, $content, $onProgress]) { + $hasActivity = false; + $remaining = &$multi->openHandles[$i][5]; + $info = &$multi->openHandles[$i][6]; + $e = null; + + // Read incoming buffer and write it to the dechunk one + try { + while ($remaining && '' !== $data = (string) fread($h, 0 > $remaining ? 16372 : $remaining)) { + fwrite($buffer, $data); + $hasActivity = true; + $multi->sleep = false; + + if (-1 !== $remaining) { + $remaining -= \strlen($data); + } + } + } catch (\Throwable $e) { + $hasActivity = $onProgress = false; + } + + if (!$hasActivity) { + if ($onProgress) { + try { + // Notify the progress callback so that it can e.g. cancel + // the request if the stream is inactive for too long + $onProgress(); + } catch (\Throwable $e) { + // no-op + } + } + } elseif ('' !== $data = stream_get_contents($buffer, -1, 0)) { + rewind($buffer); + ftruncate($buffer, 0); + + if (null !== $inflate && false === $data = @inflate_add($inflate, $data)) { + $e = new TransportException('Error while processing content unencoding.'); + } + + if ('' !== $data && null === $e) { + $multi->handlesActivity[$i][] = $data; + + if (null !== $content && \strlen($data) !== fwrite($content, $data)) { + $e = new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($data))); + } + } + } + + if (null !== $e || !$remaining || feof($h)) { + // Stream completed + $info['total_time'] = microtime(true) - $info['start_time']; + + if ($onProgress) { + try { + $onProgress(-1); + } catch (\Throwable $e) { + // no-op + } + } + + if (null === $e) { + if (0 < $remaining) { + $e = new TransportException(sprintf('Transfer closed with %s bytes remaining to read.', $remaining)); + } elseif (-1 === $remaining && fwrite($buffer, '-') && '' !== stream_get_contents($buffer, -1, 0)) { + $e = new TransportException('Transfer closed with outstanding data remaining from chunked response.'); + } + } + + $multi->handlesActivity[$i][] = null; + $multi->handlesActivity[$i][] = $e; + unset($multi->openHandles[$i]); + $multi->sleep = false; + } elseif (null !== $responses) { + $multi->handles[] = $h; + } + } + + if (null === $responses) { + return; + } + + if ($multi->pendingResponses && \count($multi->handles) < $multi->maxHostConnections) { + // Open the next pending request - this is a blocking operation so we do only one of them + $response = array_shift($multi->pendingResponses); + $response->open(); + $responses[$response->id] = $response; + $multi->sleep = false; + self::perform($response->multi); + + if (null !== $response->handle) { + $multi->handles[] = $response->handle; + } + } + + if ($multi->pendingResponses) { + // Create empty activity list to tell ResponseTrait::stream() we still have pending requests + $response = $multi->pendingResponses[0]; + $responses[$response->id] = $response; + $multi->handlesActivity[$response->id] = []; + } + } + + /** + * {@inheritdoc} + */ + private static function select(\stdClass $multi, float $timeout): int + { + $_ = []; + + return (!$multi->sleep = !$multi->sleep) ? -1 : stream_select($multi->handles, $_, $_, (int) $timeout, (int) (1E6 * ($timeout - (int) $timeout))); + } +} diff --git a/src/Symfony/Component/HttpClient/Response/ResponseStream.php b/src/Symfony/Component/HttpClient/Response/ResponseStream.php new file mode 100644 index 0000000000000..cf53abcded58e --- /dev/null +++ b/src/Symfony/Component/HttpClient/Response/ResponseStream.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Contracts\HttpClient\ChunkInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class ResponseStream implements ResponseStreamInterface +{ + private $generator; + + public function __construct(\Generator $generator) + { + $this->generator = $generator; + } + + public function key(): ResponseInterface + { + return $this->generator->key(); + } + + public function current(): ChunkInterface + { + return $this->generator->current(); + } + + public function next(): void + { + $this->generator->next(); + } + + public function rewind(): void + { + $this->generator->rewind(); + } + + public function valid(): bool + { + return $this->generator->valid(); + } +} diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php new file mode 100644 index 0000000000000..b31af23d4c3ce --- /dev/null +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -0,0 +1,299 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\DataChunk; +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\LastChunk; +use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\Exception\RedirectionException; +use Symfony\Component\HttpClient\Exception\ServerException; +use Symfony\Component\HttpClient\Exception\TransportException; + +/** + * Implements the common logic for response classes. + * + * @author Nicolas Grekas + * + * @internal + */ +trait ResponseTrait +{ + private $statusCode = 0; + private $headers = []; + + /** + * @var callable|null A callback that initializes the two previous properties + */ + private $initializer; + + /** + * @var resource A php://temp stream typically + */ + private $content; + + private $info = [ + 'raw_headers' => [], + 'error' => null, + ]; + + private $multi; + private $handle; + private $id; + private $timeout; + private $finalInfo; + private $offset = 0; + + /** + * {@inheritdoc} + */ + public function getStatusCode(): int + { + if ($this->initializer) { + ($this->initializer)($this); + $this->initializer = null; + } + + return $this->statusCode; + } + + /** + * {@inheritdoc} + */ + public function getHeaders(bool $throw = true): array + { + if ($this->initializer) { + ($this->initializer)($this); + $this->initializer = null; + } + + if ($throw) { + $this->checkStatusCode(); + } + + return $this->headers; + } + + /** + * {@inheritdoc} + */ + public function getContent(bool $throw = true): string + { + if ($this->initializer) { + ($this->initializer)($this); + $this->initializer = null; + } + + if ($throw) { + $this->checkStatusCode(); + } + + if (null === $this->content) { + $content = ''; + $chunk = null; + + foreach (self::stream([$this]) as $chunk) { + $content .= $chunk->getContent(); + } + + if (null === $chunk) { + throw new TransportException('Cannot get the content of the response twice: the request was issued with option "buffer" set to false.'); + } + + return $content; + } + + foreach (self::stream([$this]) as $chunk) { + // Chunks are buffered in $this->content already + } + + rewind($this->content); + + return stream_get_contents($this->content); + } + + /** + * Closes the response and all its network handles. + */ + abstract protected function close(): void; + + /** + * Adds pending responses to the activity list. + */ + abstract protected static function schedule(self $response, array &$runningResponses): void; + + /** + * Performs all pending non-blocking operations. + */ + abstract protected static function perform(\stdClass $multi, array &$responses): void; + + /** + * Waits for network activity. + */ + abstract protected static function select(\stdClass $multi, float $timeout): int; + + private function addRawHeaders(array $rawHeaders): void + { + foreach ($rawHeaders as $h) { + if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([12345]\d\d) .*#', $h, $m)) { + $this->headers = []; + $this->info['http_code'] = $this->statusCode = (int) $m[1]; + } elseif (2 === \count($m = explode(':', $h, 2))) { + $this->headers[strtolower($m[0])][] = ltrim($m[1]); + } + + $this->info['raw_headers'][] = $h; + } + + if (!$this->statusCode) { + throw new TransportException('Invalid or missing HTTP status line.'); + } + } + + private function checkStatusCode() + { + if (500 <= $this->statusCode) { + throw new ServerException($this); + } + + if (400 <= $this->statusCode) { + throw new ClientException($this); + } + + if (300 <= $this->statusCode) { + throw new RedirectionException($this); + } + } + + /** + * Ensures the request is always sent and that the response code was checked. + */ + private function doDestruct() + { + if ($this->initializer && null === $this->info['error']) { + ($this->initializer)($this); + $this->initializer = null; + $this->checkStatusCode(); + } + } + + /** + * Implements an event loop based on a buffer activity queue. + * + * @internal + */ + public static function stream(iterable $responses, float $timeout = null): \Generator + { + $runningResponses = []; + + foreach ($responses as $response) { + self::schedule($response, $runningResponses); + } + + $lastActivity = microtime(true); + $isTimeout = false; + + while (true) { + $hasActivity = false; + $timeoutMax = 0; + $timeoutMin = $timeout ?? INF; + + foreach ($runningResponses as $i => [$multi]) { + $responses = &$runningResponses[$i][1]; + self::perform($multi, $responses); + + foreach ($responses as $j => $response) { + $timeoutMax = $timeout ?? max($timeoutMax, $response->timeout); + $timeoutMin = min($timeoutMin, $response->timeout, 1); + // ErrorChunk instances will set $didThrow to true when the + // exception they wrap has been thrown after yielding + $chunk = $didThrow = false; + + if (isset($multi->handlesActivity[$j])) { + // no-op + } elseif (!isset($multi->openHandles[$j])) { + unset($responses[$j]); + continue; + } elseif ($isTimeout) { + $multi->handlesActivity[$j] = [new ErrorChunk($didThrow, $response->offset)]; + } else { + continue; + } + + while ($multi->handlesActivity[$j] ?? false) { + $hasActivity = true; + $isTimeout = false; + + if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) { + $response->offset += \strlen($chunk); + $chunk = new DataChunk($response->offset, $chunk); + } elseif (null === $chunk) { + if (null !== $e = $response->info['error'] ?? $multi->handlesActivity[$j][0]) { + $response->info['error'] = $e->getMessage(); + + if ($e instanceof \Error) { + unset($responses[$j], $multi->handlesActivity[$j]); + $response->close(); + throw $e; + } + + $chunk = new ErrorChunk($didThrow, $response->offset, $e); + } else { + $chunk = new LastChunk($response->offset); + } + + unset($responses[$j]); + $response->close(); + } elseif ($chunk instanceof ErrorChunk) { + unset($responses[$j]); + $isTimeout = true; + } + + yield $response => $chunk; + } + + unset($multi->handlesActivity[$j]); + + if ($chunk instanceof FirstChunk && null === $response->initializer) { + // Ensure the HTTP status code is always checked + $response->getHeaders(true); + } elseif ($chunk instanceof ErrorChunk && !$didThrow) { + // Ensure transport exceptions are always thrown + $chunk->getContent(); + } + } + + if (!$responses) { + unset($runningResponses[$i]); + } + + // Prevent memory leaks + $multi->handlesActivity = $multi->handlesActivity ?: []; + $multi->openHandles = $multi->openHandles ?: []; + } + + if (!$runningResponses) { + break; + } + + if ($hasActivity) { + $lastActivity = microtime(true); + continue; + } + + switch (self::select($multi, $timeoutMin)) { + case -1: usleep(min(500, 1E6 * $timeoutMin)); break; + case 0: $isTimeout = microtime(true) - $lastActivity > $timeoutMax; break; + } + } + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php new file mode 100644 index 0000000000000..7c51d42236201 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\CurlHttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; + +/** + * @requires extension curl + */ +class CurlHttpClientTest extends HttpClientTestCase +{ + protected function getHttpClient(): HttpClientInterface + { + return new CurlHttpClient(); + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTest.php new file mode 100644 index 0000000000000..9f70b743965d5 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\CurlHttpClient; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; + +class HttpClientTest extends TestCase +{ + public function testCreateClient() + { + if (\extension_loaded('curl')) { + $this->assertInstanceOf(CurlHttpClient::class, HttpClient::create()); + } else { + $this->assertInstanceOf(NativeHttpClient::class, HttpClient::create()); + } + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php new file mode 100644 index 0000000000000..815a1ab617d0b --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\HttpClientTrait; + +class HttpClientTraitTest extends TestCase +{ + use HttpClientTrait; + + private const RFC3986_BASE = 'http://a/b/c/d;p?q'; + + /** + * @dataProvider providePrepareRequestUrl + */ + public function testPrepareRequestUrl($expected, $url, $query = []) + { + $defaults = [ + 'base_uri' => 'http://example.com?c=c', + 'query' => ['a' => 1, 'b' => 'b'], + ]; + [, $defaults] = self::prepareRequest(null, null, $defaults); + + [$url] = self::prepareRequest(null, $url, ['query' => $query], $defaults); + $this->assertSame($expected, implode('', $url)); + } + + public function providePrepareRequestUrl() + { + yield ['http://example.com/', 'http://example.com/']; + yield ['http://example.com/?a=1&b=b', '.']; + yield ['http://example.com/?a=2&b=b', '.?a=2']; + yield ['http://example.com/?a=3&b=b', '.', ['a' => 3]]; + yield ['http://example.com/?a=3&b=b', '.?a=0', ['a' => 3]]; + } + + /** + * @dataProvider provideResolveUrl + */ + public function testResolveUrl($base, $url, $expected) + { + $this->assertSame($expected, implode('', self::resolveUrl(self::parseUrl($url), self::parseUrl($base)))); + } + + /** + * From https://github.com/guzzle/psr7/blob/master/tests/UriResoverTest.php. + */ + public function provideResolveUrl() + { + return [ + [self::RFC3986_BASE, 'http:h', 'http:h'], + [self::RFC3986_BASE, 'g', 'http://a/b/c/g'], + [self::RFC3986_BASE, './g', 'http://a/b/c/g'], + [self::RFC3986_BASE, 'g/', 'http://a/b/c/g/'], + [self::RFC3986_BASE, '/g', 'http://a/g'], + [self::RFC3986_BASE, '//g', 'http://g/'], + [self::RFC3986_BASE, '?y', 'http://a/b/c/d;p?y'], + [self::RFC3986_BASE, 'g?y', 'http://a/b/c/g?y'], + [self::RFC3986_BASE, '#s', 'http://a/b/c/d;p?q#s'], + [self::RFC3986_BASE, 'g#s', 'http://a/b/c/g#s'], + [self::RFC3986_BASE, 'g?y#s', 'http://a/b/c/g?y#s'], + [self::RFC3986_BASE, ';x', 'http://a/b/c/;x'], + [self::RFC3986_BASE, 'g;x', 'http://a/b/c/g;x'], + [self::RFC3986_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s'], + [self::RFC3986_BASE, '', self::RFC3986_BASE], + [self::RFC3986_BASE, '.', 'http://a/b/c/'], + [self::RFC3986_BASE, './', 'http://a/b/c/'], + [self::RFC3986_BASE, '..', 'http://a/b/'], + [self::RFC3986_BASE, '../', 'http://a/b/'], + [self::RFC3986_BASE, '../g', 'http://a/b/g'], + [self::RFC3986_BASE, '../..', 'http://a/'], + [self::RFC3986_BASE, '../../', 'http://a/'], + [self::RFC3986_BASE, '../../g', 'http://a/g'], + [self::RFC3986_BASE, '../../../g', 'http://a/g'], + [self::RFC3986_BASE, '../../../../g', 'http://a/g'], + [self::RFC3986_BASE, '/./g', 'http://a/g'], + [self::RFC3986_BASE, '/../g', 'http://a/g'], + [self::RFC3986_BASE, 'g.', 'http://a/b/c/g.'], + [self::RFC3986_BASE, '.g', 'http://a/b/c/.g'], + [self::RFC3986_BASE, 'g..', 'http://a/b/c/g..'], + [self::RFC3986_BASE, '..g', 'http://a/b/c/..g'], + [self::RFC3986_BASE, './../g', 'http://a/b/g'], + [self::RFC3986_BASE, 'foo////g', 'http://a/b/c/foo////g'], + [self::RFC3986_BASE, './g/.', 'http://a/b/c/g/'], + [self::RFC3986_BASE, 'g/./h', 'http://a/b/c/g/h'], + [self::RFC3986_BASE, 'g/../h', 'http://a/b/c/h'], + [self::RFC3986_BASE, 'g;x=1/./y', 'http://a/b/c/g;x=1/y'], + [self::RFC3986_BASE, 'g;x=1/../y', 'http://a/b/c/y'], + // dot-segments in the query or fragment + [self::RFC3986_BASE, 'g?y/./x', 'http://a/b/c/g?y/./x'], + [self::RFC3986_BASE, 'g?y/../x', 'http://a/b/c/g?y/../x'], + [self::RFC3986_BASE, 'g#s/./x', 'http://a/b/c/g#s/./x'], + [self::RFC3986_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x'], + [self::RFC3986_BASE, 'g#s/../x', 'http://a/b/c/g#s/../x'], + [self::RFC3986_BASE, '?y#s', 'http://a/b/c/d;p?y#s'], + // base with fragment + ['http://a/b/c?q#s', '?y', 'http://a/b/c?y'], + // base with user info + ['http://u@a/b/c/d;p?q', '.', 'http://u@a/b/c/'], + ['http://u:p@a/b/c/d;p?q', '.', 'http://u:p@a/b/c/'], + // path ending with slash or no slash at all + ['http://a/b/c/d/', 'e', 'http://a/b/c/d/e'], + ['http:no-slash', 'e', 'http:e'], + // falsey relative parts + [self::RFC3986_BASE, '//0', 'http://0/'], + [self::RFC3986_BASE, '0', 'http://a/b/c/0'], + [self::RFC3986_BASE, '?0', 'http://a/b/c/d;p?0'], + [self::RFC3986_BASE, '#0', 'http://a/b/c/d;p?q#0'], + ]; + } + + /** + * @dataProvider provideParseUrl + */ + public function testParseUrl($expected, $url, $query = []) + { + $expected = array_combine(['scheme', 'authority', 'path', 'query', 'fragment'], $expected); + + $this->assertSame($expected, self::parseUrl($url, $query)); + } + + public function provideParseUrl() + { + yield [['http:', '//example.com', null, null, null], 'http://Example.coM:80']; + yield [['https:', '//xn--dj-kia8a.example.com:8000', '/', null, null], 'https://DÉjà.Example.com:8000/']; + yield [[null, null, '/f%20o.o', '?a=b', '#c'], '/f o%2Eo?a=b#c']; + yield [[null, '//a:b@foo', '/bar', null, null], '//a:b@foo/bar']; + yield [['http:', null, null, null, null], 'http:']; + yield [['http:', null, 'bar', null, null], 'http:bar']; + yield [[null, null, 'bar', '?a=1&c=c', null], 'bar?a=a&b=b', ['b' => null, 'c' => 'c', 'a' => 1]]; + yield [[null, null, 'bar', '?a=b+c&b=b', null], 'bar?a=b+c', ['b' => 'b']]; + yield [[null, null, 'bar', '?a=b%2B%20c', null], 'bar?a=b+c', ['a' => 'b+ c']]; + } + + /** + * @dataProvider provideRemoveDotSegments + */ + public function testRemoveDotSegments($expected, $url) + { + $this->assertSame($expected, self::removeDotSegments($url)); + } + + public function provideRemoveDotSegments() + { + yield ['', '']; + yield ['', '.']; + yield ['', '..']; + yield ['a', './a']; + yield ['a', '../a']; + yield ['/a/b', '/a/./b']; + yield ['/b/', '/a/../b/.']; + yield ['/a//b/', '/a///../b/.']; + yield ['/a/', '/a/b/..']; + yield ['/a///b', '/a///b']; + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php new file mode 100644 index 0000000000000..d2af0584f9edb --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; + +class NativeHttpClientTest extends HttpClientTestCase +{ + protected function getHttpClient(): HttpClientInterface + { + return new NativeHttpClient(); + } +} diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json new file mode 100644 index 0000000000000..e2e922aa943ba --- /dev/null +++ b/src/Symfony/Component/HttpClient/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/http-client", + "type": "library", + "description": "Symfony HttpClient component", + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "provide": { + "psr/http-client-implementation": "1.0", + "symfony/http-client-contracts-implementation": "1.1" + }, + "require": { + "php": "^7.1.3", + "symfony/contracts": "^1.1" + }, + "require-dev": { + "symfony/process": "~4.2" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\HttpClient\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/HttpClient/phpunit.xml.dist b/src/Symfony/Component/HttpClient/phpunit.xml.dist new file mode 100644 index 0000000000000..4a055dcf508cc --- /dev/null +++ b/src/Symfony/Component/HttpClient/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php b/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php index ae7134f55b2a1..78acb90b66a68 100644 --- a/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SymfonyCaster.php @@ -40,4 +40,12 @@ public static function castRequest(Request $request, array $a, Stub $stub, $isNe return $a; } + + public static function castHttpClient($client, array $a, Stub $stub, $isNested) + { + $multiKey = sprintf("\0%s\0multi", \get_class($client)); + $a[$multiKey] = new CutStub($a[$multiKey]); + + return $a; + } } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 9836040e34fea..e2393c4dbe5ee 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -75,6 +75,10 @@ abstract class AbstractCloner implements ClonerInterface 'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'], 'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'], 'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'], 'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'], From fc831206911b954ae6d20af6f8d3e98ae845fda9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 30 Jan 2019 23:43:28 +0100 Subject: [PATCH 180/495] [HttpClient] Add Psr18Client - aka a PSR-18 adapter --- composer.json | 2 + .../Component/HttpClient/Psr18Client.php | 109 ++++++++++++++++++ .../HttpClient/Tests/Psr18ClientTest.php | 77 +++++++++++++ .../Component/HttpClient/composer.json | 2 + 4 files changed, 190 insertions(+) create mode 100644 src/Symfony/Component/HttpClient/Psr18Client.php create mode 100644 src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php diff --git a/composer.json b/composer.json index 737a80ac00112..46fdef11218c0 100644 --- a/composer.json +++ b/composer.json @@ -102,8 +102,10 @@ "doctrine/reflection": "~1.0", "doctrine/doctrine-bundle": "~1.4", "monolog/monolog": "~1.11", + "nyholm/psr7": "^1.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", "predis/predis": "~1.1", + "psr/http-client": "^1.0", "egulias/email-validator": "~1.2,>=1.2.8|~2.0", "symfony/phpunit-bridge": "~3.4|~4.0", "symfony/security-acl": "~2.8|~3.0", diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php new file mode 100644 index 0000000000000..9c00940339058 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Psr18Client.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Http\Client\ClientInterface; +use Psr\Http\Client\NetworkExceptionInterface; +use Psr\Http\Client\RequestExceptionInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseFactoryInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * An adapter to turn a Symfony HttpClientInterface into a PSR-18 ClientInterface. + * + * Run "composer require psr/http-client" to install the base ClientInterface. Run + * "composer require nyholm/psr7" to install an efficient implementation of response + * and stream factories with flex-provided autowiring aliases. + * + * @author Nicolas Grekas + * + * @experimental in 4.3 + */ +final class Psr18Client implements ClientInterface +{ + private $client; + private $responseFactory; + private $streamFactory; + + public function __construct(HttpClientInterface $client, ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory) + { + $this->client = $client; + $this->responseFactory = $responseFactory; + $this->streamFactory = $streamFactory; + } + + public function sendRequest(RequestInterface $request): ResponseInterface + { + try { + $response = $this->client->request($request->getMethod(), (string) $request->getUri(), [ + 'headers' => $request->getHeaders(), + 'body' => (string) $request->getBody(), + 'http_version' => '1.0' === $request->getProtocolVersion() ? '1.0' : null, + ]); + + $psrResponse = $this->responseFactory->createResponse($response->getStatusCode()); + + foreach ($response->getHeaders() as $name => $values) { + foreach ($values as $value) { + $psrResponse = $psrResponse->withAddedHeader($name, $value); + } + } + + return $psrResponse->withBody($this->streamFactory->createStream($response->getContent())); + } catch (TransportExceptionInterface $e) { + if ($e instanceof \InvalidArgumentException) { + throw new Psr18RequestException($e, $request); + } + + throw new Psr18NetworkException($e, $request); + } + } +} + +/** + * @internal + */ +trait Psr18ExceptionTrait +{ + private $request; + + public function __construct(TransportExceptionInterface $e, RequestInterface $request) + { + parent::__construct($e->getMessage(), 0, $e); + $this->request = $request; + } + + public function getRequest(): RequestInterface + { + return $this->request; + } +} + +/** + * @internal + */ +class Psr18NetworkException extends \RuntimeException implements NetworkExceptionInterface +{ + use Psr18ExceptionTrait; +} + +/** + * @internal + */ +class Psr18RequestException extends \InvalidArgumentException implements RequestExceptionInterface +{ + use Psr18ExceptionTrait; +} diff --git a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php new file mode 100644 index 0000000000000..edb2891a374ff --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Nyholm\Psr7\Factory\Psr17Factory; +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Psr18Client; +use Symfony\Component\HttpClient\Psr18NetworkException; +use Symfony\Component\HttpClient\Psr18RequestException; +use Symfony\Contracts\HttpClient\Test\TestHttpServer; + +class Psr18ClientTest extends TestCase +{ + private static $server; + + public static function setUpBeforeClass() + { + TestHttpServer::start(); + } + + public function testSendRequest() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $response = $client->sendRequest($factory->createRequest('GET', 'http://localhost:8057')); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('application/json', $response->getHeaderLine('content-type')); + + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + } + + public function testPostRequest() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $request = $factory->createRequest('POST', 'http://localhost:8057/post') + ->withBody($factory->createStream('foo=0123456789')); + + $response = $client->sendRequest($request); + $body = json_decode((string) $response->getBody(), true); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testNetworkException() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $this->expectException(Psr18NetworkException::class); + $client->sendRequest($factory->createRequest('GET', 'http://localhost:8058')); + } + + public function testRequestException() + { + $factory = new Psr17Factory(); + $client = new Psr18Client(new NativeHttpClient(), $factory, $factory); + + $this->expectException(Psr18RequestException::class); + $client->sendRequest($factory->createRequest('BAD.METHOD', 'http://localhost:8057')); + } +} diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index e2e922aa943ba..854c2c64fe9c2 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -23,6 +23,8 @@ "symfony/contracts": "^1.1" }, "require-dev": { + "nyholm/psr7": "^1.0", + "psr/http-client": "^1.0", "symfony/process": "~4.2" }, "autoload": { From 857ac9519e1e5545de4d2eef81af52f6fde62d7e Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 26 Feb 2019 15:14:06 +0100 Subject: [PATCH 181/495] [SecurityBundle] Validate the IPs configured in access_control --- .../DependencyInjection/MainConfiguration.php | 35 +++++++++++++++++++ .../Resources/config/routing.yml | 9 +++++ .../SecurityRoutingIntegrationTest.php | 15 ++++++++ .../app/StandardFormLogin/config.yml | 4 +++ .../invalid_ip_access_control.yml | 22 ++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/invalid_ip_access_control.yml diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 6b3ba9e8fdbfb..60de7afc598d0 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -143,6 +143,15 @@ private function addAccessControlSection(ArrayNodeDefinition $rootNode) ->integerNode('port')->defaultNull()->end() ->arrayNode('ips') ->beforeNormalization()->ifString()->then(function ($v) { return [$v]; })->end() + ->beforeNormalization()->always()->then(function ($v) { + foreach ($v as $ip) { + if (false === $this->isValidIp($ip)) { + throw new \LogicException(sprintf('The given "%s" value in the "access_control" config option is not a valid IP address.', $ip)); + } + } + + return $v; + })->end() ->prototype('scalar')->end() ->end() ->arrayNode('methods') @@ -419,4 +428,30 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode) ->end() ; } + + private function isValidIp(string $cidr): bool + { + $cidrParts = explode('/', $cidr); + + if (1 === \count($cidrParts)) { + return false !== filter_var($cidrParts[0], FILTER_VALIDATE_IP); + } + + $ip = $cidrParts[0]; + $netmask = $cidrParts[1]; + + if (!ctype_digit($netmask)) { + return false; + } + + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + return $netmask <= 32; + } + + if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + return $netmask <= 128; + } + + return false; + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml index 30466deb32da2..2fff93dcad2ef 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Resources/config/routing.yml @@ -31,6 +31,15 @@ secured-by-one-ip: secured-by-two-ips: path: /secured-by-two-ips +secured-by-one-real-ip: + path: /secured-by-one-real-ip + +secured-by-one-real-ip-with-mask: + path: /secured-by-one-real-ip-with-mask + +secured-by-one-real-ipv6: + path: /secured-by-one-real-ipv6 + form_logout: path: /logout_path diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php index 0d2d6da0cfc51..682c561ac5aa5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SecurityRoutingIntegrationTest.php @@ -71,10 +71,16 @@ public function testSecurityConfigurationForMultipleIPAddresses($config) { $allowedClientA = $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => $config], ['REMOTE_ADDR' => '1.1.1.1']); $allowedClientB = $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => $config], ['REMOTE_ADDR' => '2.2.2.2']); + $allowedClientC = $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => $config], ['REMOTE_ADDR' => '203.0.113.0']); $barredClient = $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => $config], ['REMOTE_ADDR' => '192.168.1.1']); $this->assertAllowed($allowedClientA, '/secured-by-two-ips'); $this->assertAllowed($allowedClientB, '/secured-by-two-ips'); + + $this->assertRestricted($allowedClientA, '/secured-by-one-real-ip'); + $this->assertRestricted($allowedClientA, '/secured-by-one-real-ipv6'); + $this->assertAllowed($allowedClientC, '/secured-by-one-real-ip-with-mask'); + $this->assertRestricted($barredClient, '/secured-by-two-ips'); } @@ -100,6 +106,15 @@ public function testSecurityConfigurationForExpression($config) $this->assertAllowed($allowedClient, '/protected-via-expression'); } + public function testInvalidIpsInAccessControl() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The given "256.357.458.559" value in the "access_control" config option is not a valid IP address.'); + + $client = $this->createClient(['test_case' => 'StandardFormLogin', 'root_config' => 'invalid_ip_access_control.yml']); + $client->request('GET', '/unprotected_resource'); + } + private function assertAllowed($client, $path) { $client->request('GET', $path); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml index d7c73aa0b6dc0..df03c20c5c514 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/config.yml @@ -39,6 +39,10 @@ security: - { path: ^/secure-but-not-covered-by-access-control$, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/secured-by-one-ip$, ip: 10.10.10.10, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/secured-by-two-ips$, ips: [1.1.1.1, 2.2.2.2], roles: IS_AUTHENTICATED_ANONYMOUSLY } + # these real IP addresses are reserved for docs/examples (https://tools.ietf.org/search/rfc5737) + - { path: ^/secured-by-one-real-ip$, ips: 198.51.100.0, roles: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/secured-by-one-real-ip-with-mask$, ips: '203.0.113.0/24', roles: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/secured-by-one-real-ipv6$, ips: 0:0:0:0:0:ffff:c633:6400, roles: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/highly_protected_resource$, roles: IS_ADMIN } - { path: ^/protected-via-expression$, allow_if: "(is_anonymous() and request.headers.get('user-agent') matches '/Firefox/i') or is_granted('ROLE_USER')" } - { path: .*, roles: IS_AUTHENTICATED_FULLY } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/invalid_ip_access_control.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/invalid_ip_access_control.yml new file mode 100644 index 0000000000000..e4f46c4704af6 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/StandardFormLogin/invalid_ip_access_control.yml @@ -0,0 +1,22 @@ +imports: + - { resource: ./../config/default.yml } + +security: + encoders: + Symfony\Component\Security\Core\User\User: plaintext + + providers: + in_memory: + memory: + users: + johannes: { password: test, roles: [ROLE_USER] } + + firewalls: + default: + form_login: ~ + logout: ~ + anonymous: ~ + + access_control: + # the '256.357.458.559' IP is wrong on purpose, to check invalid IP errors + - { path: ^/unprotected_resource$, ips: [1.1.1.1, 256.357.458.559], roles: IS_AUTHENTICATED_ANONYMOUSLY } From df1b627417ad6b47fba6fdfabdf82bb347beaa72 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 7 Mar 2019 21:44:01 +0100 Subject: [PATCH 182/495] [Mime] used yield-from when possible --- src/Symfony/Component/Mime/Message.php | 4 +--- src/Symfony/Component/Mime/Part/AbstractMultipartPart.php | 4 +--- src/Symfony/Component/Mime/Part/AbstractPart.php | 4 +--- src/Symfony/Component/Mime/Part/TextPart.php | 4 +--- src/Symfony/Component/Mime/RawMessage.php | 2 +- src/Symfony/Component/Mime/Tests/MessageTest.php | 4 ++-- 6 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Mime/Message.php b/src/Symfony/Component/Mime/Message.php index f64ffebf8326d..43b5fe40c911a 100644 --- a/src/Symfony/Component/Mime/Message.php +++ b/src/Symfony/Component/Mime/Message.php @@ -122,9 +122,7 @@ public function toIterable(): iterable } yield $this->getPreparedHeaders()->toString(); - foreach ($body->toIterable() as $chunk) { - yield $chunk; - } + yield from $body->toIterable(); } private function generateMessageId(string $email): string diff --git a/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php b/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php index 76e3e4979216b..02023afd4f2be 100644 --- a/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php +++ b/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php @@ -81,9 +81,7 @@ public function bodyToIterable(): iterable foreach ($parts as $part) { yield '--'.$this->getBoundary()."\r\n"; - foreach ($part->toIterable() as $chunk) { - yield $chunk; - } + yield from $part->toIterable(); yield "\r\n"; } yield '--'.$this->getBoundary()."--\r\n"; diff --git a/src/Symfony/Component/Mime/Part/AbstractPart.php b/src/Symfony/Component/Mime/Part/AbstractPart.php index 8b50eaca4b297..29eaa1ebfdc32 100644 --- a/src/Symfony/Component/Mime/Part/AbstractPart.php +++ b/src/Symfony/Component/Mime/Part/AbstractPart.php @@ -49,9 +49,7 @@ public function toIterable(): iterable { yield $this->getPreparedHeaders()->toString(); yield "\r\n"; - foreach ($this->bodyToIterable() as $chunk) { - yield $chunk; - } + yield from $this->bodyToIterable(); } abstract public function bodyToString(): string; diff --git a/src/Symfony/Component/Mime/Part/TextPart.php b/src/Symfony/Component/Mime/Part/TextPart.php index 323f62eccec74..c02f00f855a6b 100644 --- a/src/Symfony/Component/Mime/Part/TextPart.php +++ b/src/Symfony/Component/Mime/Part/TextPart.php @@ -118,9 +118,7 @@ public function bodyToIterable(): iterable if (stream_get_meta_data($this->body)['seekable'] ?? false) { rewind($this->body); } - foreach ($this->getEncoder()->encodeByteStream($this->body) as $chunk) { - yield $chunk; - } + yield from $this->getEncoder()->encodeByteStream($this->body); } else { yield $this->getEncoder()->encodeString($this->body); } diff --git a/src/Symfony/Component/Mime/RawMessage.php b/src/Symfony/Component/Mime/RawMessage.php index a00bb094f9123..790c7eea5351c 100644 --- a/src/Symfony/Component/Mime/RawMessage.php +++ b/src/Symfony/Component/Mime/RawMessage.php @@ -34,7 +34,7 @@ public function toString(): string return $this->message; } - return $this->message = implode('', iterator_to_array($this->message)); + return $this->message = implode('', iterator_to_array($this->message, false)); } public function toIterable(): iterable diff --git a/src/Symfony/Component/Mime/Tests/MessageTest.php b/src/Symfony/Component/Mime/Tests/MessageTest.php index 888e77e245bc3..dbeb0a55443c0 100644 --- a/src/Symfony/Component/Mime/Tests/MessageTest.php +++ b/src/Symfony/Component/Mime/Tests/MessageTest.php @@ -131,7 +131,7 @@ public function testToString() EOF; $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", $message->toString())); - $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable())))); + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable(), false)))); $message = new Message(null, new TextPart('content')); $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); @@ -146,6 +146,6 @@ public function testToString() content EOF; $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", $message->toString())); - $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable())))); + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable(), false)))); } } From 0450c4f2445d58ccb74463d5564129569a7be34a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 7 Mar 2019 22:30:20 +0100 Subject: [PATCH 183/495] [Mime] fixed support for date form parts --- .../Mime/Encoder/EightBitContentEncoder.php | 35 +++++++++++++++++++ .../Mime/Part/Multipart/FormDataPart.php | 26 ++++++++------ src/Symfony/Component/Mime/Part/TextPart.php | 15 ++++---- .../Tests/Part/Multipart/FormDataPartTest.php | 30 +++++++++++++--- 4 files changed, 85 insertions(+), 21 deletions(-) create mode 100644 src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php diff --git a/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php b/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php new file mode 100644 index 0000000000000..7211c0333f652 --- /dev/null +++ b/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class EightBitContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + yield from $stream; + } + + public function getName(): string + { + return '8bit'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $string; + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php index 9f0635d588815..90d449b9badfe 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php @@ -42,7 +42,7 @@ public function __construct(array $fields = []) $this->fields[$name] = $value; } // HTTP does not support \r\n in header values - $this->getHeaders()->setMaxLineLength(1000); + $this->getHeaders()->setMaxLineLength(-1); } public function getMediaSubtype(): string @@ -58,15 +58,11 @@ public function getParts(): array private function prepareFields(array $fields): array { $values = []; - foreach ($fields as $name => $value) { - if (\is_array($value)) { - foreach ($value as $v) { - $values[] = $this->preparePart($name, $v); - } - } else { - $values[] = $this->preparePart($name, $value); + array_walk_recursive($fields, function ($item, $key) use (&$values) { + if (!\is_array($item)) { + $values[] = $this->preparePart($key, $item); } - } + }); return $values; } @@ -74,7 +70,7 @@ private function prepareFields(array $fields): array private function preparePart($name, $value): TextPart { if (\is_string($value)) { - return $this->configurePart($name, new TextPart($value)); + return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit')); } return $this->configurePart($name, $value); @@ -82,10 +78,18 @@ private function preparePart($name, $value): TextPart private function configurePart(string $name, TextPart $part): TextPart { + static $r; + + if (null === $r) { + $r = new \ReflectionProperty(TextPart::class, 'encoding'); + $r->setAccessible(true); + } + $part->setDisposition('form-data'); $part->setName($name); // HTTP does not support \r\n in header values - $part->getHeaders()->setMaxLineLength(1000); + $part->getHeaders()->setMaxLineLength(-1); + $r->setValue($part, '8bit'); return $part; } diff --git a/src/Symfony/Component/Mime/Part/TextPart.php b/src/Symfony/Component/Mime/Part/TextPart.php index 323f62eccec74..568bd81a08dd4 100644 --- a/src/Symfony/Component/Mime/Part/TextPart.php +++ b/src/Symfony/Component/Mime/Part/TextPart.php @@ -13,6 +13,7 @@ use Symfony\Component\Mime\Encoder\Base64ContentEncoder; use Symfony\Component\Mime\Encoder\ContentEncoderInterface; +use Symfony\Component\Mime\Encoder\EightBitContentEncoder; use Symfony\Component\Mime\Encoder\QpContentEncoder; use Symfony\Component\Mime\Exception\InvalidArgumentException; use Symfony\Component\Mime\Header\Headers; @@ -31,8 +32,7 @@ class TextPart extends AbstractPart private $subtype; private $disposition; private $name; - - protected $encoding; + private $encoding; /** * @param resource|string $body @@ -49,12 +49,11 @@ public function __construct($body, ?string $charset = 'utf-8', $subtype = 'plain $this->charset = $charset; $this->subtype = $subtype; - // FIXME: can also be 7BIT, 8BIT, ... if (null === $encoding) { $this->encoding = $this->chooseEncoding(); } else { - if ('quoted-printable' !== $encoding && 'base64' !== $encoding) { - throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable" or "base64" ("%s" given).', $encoding)); + if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) { + throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); } $this->encoding = $encoding; } @@ -149,8 +148,12 @@ public function getPreparedHeaders(): Headers return $headers; } - protected function getEncoder(): ContentEncoderInterface + private function getEncoder(): ContentEncoderInterface { + if ('8bit' === $this->encoding) { + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new EightBitContentEncoder()); + } + if ('quoted-printable' === $this->encoding) { return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new QpContentEncoder()); } diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php index f60b0b7c4194f..ec2fcf46cddef 100644 --- a/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php @@ -20,6 +20,9 @@ class FormDataPartTest extends TestCase { public function testConstructor() { + $r = new \ReflectionProperty(TextPart::class, 'encoding'); + $r->setAccessible(true); + $b = new TextPart('content'); $c = DataPart::fromPath($file = __DIR__.'/../../Fixtures/mimetypes/test.gif'); $f = new FormDataPart([ @@ -29,16 +32,35 @@ public function testConstructor() ]); $this->assertEquals('multipart', $f->getMediaType()); $this->assertEquals('form-data', $f->getMediaSubtype()); - $t = new TextPart($content); + $t = new TextPart($content, 'utf-8', 'plain', '8bit'); $t->setDisposition('form-data'); $t->setName('foo'); - $t->getHeaders()->setMaxLineLength(1000); + $t->getHeaders()->setMaxLineLength(-1); $b->setDisposition('form-data'); $b->setName('bar'); - $b->getHeaders()->setMaxLineLength(1000); + $b->getHeaders()->setMaxLineLength(-1); + $r->setValue($b, '8bit'); $c->setDisposition('form-data'); $c->setName('baz'); - $c->getHeaders()->setMaxLineLength(1000); + $c->getHeaders()->setMaxLineLength(-1); + $r->setValue($c, '8bit'); $this->assertEquals([$t, $b, $c], $f->getParts()); } + + public function testToString() + { + $p = DataPart::fromPath($file = __DIR__.'/../../Fixtures/mimetypes/test.gif'); + $this->assertEquals(base64_encode(file_get_contents($file)), $p->bodyToString()); + } + + public function testContentLineLength() + { + $f = new FormDataPart([ + 'foo' => new DataPart($foo = str_repeat('foo', 1000), 'foo.txt', 'text/plain'), + 'bar' => $bar = str_repeat('bar', 1000), + ]); + $parts = $f->getParts(); + $this->assertEquals($foo, $parts[0]->bodyToString()); + $this->assertEquals($bar, $parts[1]->bodyToString()); + } } From 5c8a4e3deb228acd6ec612b5b144d74cf5389700 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 7 Mar 2019 23:32:55 +0100 Subject: [PATCH 184/495] [Mime] removed the 2 parts constraints on Multipart (not true for DataFormPart for instance) --- .../Component/Mime/Part/AbstractMultipartPart.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php b/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php index 76e3e4979216b..285b94b9f6c2f 100644 --- a/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php +++ b/src/Symfony/Component/Mime/Part/AbstractMultipartPart.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Mime\Part; -use Symfony\Component\Mime\Exception\LogicException; use Symfony\Component\Mime\Header\Headers; /** @@ -57,11 +56,6 @@ public function getPreparedHeaders(): Headers public function bodyToString(): string { $parts = $this->getParts(); - - if (\count($parts) < 2) { - throw new LogicException(sprintf('A "%s" instance must have at least 2 parts.', __CLASS__)); - } - $string = ''; foreach ($parts as $part) { $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n"; @@ -74,11 +68,6 @@ public function bodyToString(): string public function bodyToIterable(): iterable { $parts = $this->getParts(); - - if (\count($parts) < 2) { - throw new LogicException(sprintf('A "%s" instance must have at least 2 parts.', __CLASS__)); - } - foreach ($parts as $part) { yield '--'.$this->getBoundary()."\r\n"; foreach ($part->toIterable() as $chunk) { From c7a22910db4578719d6cd5ed9cd8bfeb7fbc1e85 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 8 Mar 2019 00:01:31 +0100 Subject: [PATCH 185/495] fixed typo --- src/Symfony/Component/Mime/Header/AbstractHeader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Header/AbstractHeader.php b/src/Symfony/Component/Mime/Header/AbstractHeader.php index 517ee8dfb2381..7093e121589e3 100644 --- a/src/Symfony/Component/Mime/Header/AbstractHeader.php +++ b/src/Symfony/Component/Mime/Header/AbstractHeader.php @@ -263,7 +263,7 @@ private function tokensToString(array $tokens): string foreach ($tokens as $i => $token) { // Line longer than specified maximum or token was just a new line if (("\r\n" === $token) || - ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) + ($this->lineLength > 0 && $i > 0 && \strlen($currentLine.$token) > $this->lineLength) && 0 < \strlen($currentLine)) { $headerLines[] = ''; $currentLine = &$headerLines[$lineCount++]; From ed4a74a83a9818f37d562de04ee9fca2db857f2e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 8 Mar 2019 00:10:16 +0100 Subject: [PATCH 186/495] fixed logic --- src/Symfony/Component/Mime/Header/AbstractHeader.php | 2 +- src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php | 4 ++-- .../Mime/Tests/Part/Multipart/FormDataPartTest.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Mime/Header/AbstractHeader.php b/src/Symfony/Component/Mime/Header/AbstractHeader.php index 7093e121589e3..517ee8dfb2381 100644 --- a/src/Symfony/Component/Mime/Header/AbstractHeader.php +++ b/src/Symfony/Component/Mime/Header/AbstractHeader.php @@ -263,7 +263,7 @@ private function tokensToString(array $tokens): string foreach ($tokens as $i => $token) { // Line longer than specified maximum or token was just a new line if (("\r\n" === $token) || - ($this->lineLength > 0 && $i > 0 && \strlen($currentLine.$token) > $this->lineLength) + ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) && 0 < \strlen($currentLine)) { $headerLines[] = ''; $currentLine = &$headerLines[$lineCount++]; diff --git a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php index 90d449b9badfe..75d69a88a08fc 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php @@ -42,7 +42,7 @@ public function __construct(array $fields = []) $this->fields[$name] = $value; } // HTTP does not support \r\n in header values - $this->getHeaders()->setMaxLineLength(-1); + $this->getHeaders()->setMaxLineLength(PHP_INT_MAX); } public function getMediaSubtype(): string @@ -88,7 +88,7 @@ private function configurePart(string $name, TextPart $part): TextPart $part->setDisposition('form-data'); $part->setName($name); // HTTP does not support \r\n in header values - $part->getHeaders()->setMaxLineLength(-1); + $part->getHeaders()->setMaxLineLength(PHP_INT_MAX); $r->setValue($part, '8bit'); return $part; diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php index ec2fcf46cddef..127fce000a532 100644 --- a/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/FormDataPartTest.php @@ -35,14 +35,14 @@ public function testConstructor() $t = new TextPart($content, 'utf-8', 'plain', '8bit'); $t->setDisposition('form-data'); $t->setName('foo'); - $t->getHeaders()->setMaxLineLength(-1); + $t->getHeaders()->setMaxLineLength(PHP_INT_MAX); $b->setDisposition('form-data'); $b->setName('bar'); - $b->getHeaders()->setMaxLineLength(-1); + $b->getHeaders()->setMaxLineLength(PHP_INT_MAX); $r->setValue($b, '8bit'); $c->setDisposition('form-data'); $c->setName('baz'); - $c->getHeaders()->setMaxLineLength(-1); + $c->getHeaders()->setMaxLineLength(PHP_INT_MAX); $r->setValue($c, '8bit'); $this->assertEquals([$t, $b, $c], $f->getParts()); } From 788bb812bff24a6453304ff625a52d11b9e9b8a8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 8 Mar 2019 08:03:18 +0100 Subject: [PATCH 187/495] [Mime] added Headers::toArray() --- src/Symfony/Component/Mime/Header/Headers.php | 14 ++++++++++++-- .../Component/Mime/Tests/Header/HeadersTest.php | 11 +++++++++++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mime/Header/Headers.php b/src/Symfony/Component/Mime/Header/Headers.php index 5556f64a6d54f..f60cd474a6cb1 100644 --- a/src/Symfony/Component/Mime/Header/Headers.php +++ b/src/Symfony/Component/Mime/Header/Headers.php @@ -210,13 +210,23 @@ public static function isUniqueHeader(string $name): bool public function toString(): string { $string = ''; + foreach ($this->toArray() as $str) { + $string .= $str."\r\n"; + } + + return $string; + } + + public function toArray(): array + { + $arr = []; foreach ($this->getAll() as $header) { if ('' !== $header->getBodyAsString()) { - $string .= $header->toString()."\r\n"; + $arr[] = $header->toString(); } } - return $string; + return $arr; } /** diff --git a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php index 00c21a35cf30f..2f4a1dd6358a8 100644 --- a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php +++ b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php @@ -231,4 +231,15 @@ public function testHeadersWithoutBodiesAreNotDisplayed() $headers->addTextHeader('Zip', ''); $this->assertEquals("Foo: bar\r\n", $headers->toString()); } + + public function testToArray() + { + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $headers->addTextHeader('Foo', str_repeat('a', 60).pack('C', 0x8F)); + $this->assertEquals([ + 'Message-ID: ', + "Foo: =?utf-8?Q?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?=\r\n =?utf-8?Q?aaaa?=", + ], $headers->toArray()); + } } From 3eca2b448de83796147d023236c86074c4f521a1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 8 Mar 2019 14:46:03 +0100 Subject: [PATCH 188/495] [HttpClient] fixes --- .../Component/HttpClient/CurlHttpClient.php | 4 ++-- .../Component/HttpClient/HttpClientTrait.php | 12 +++++++--- .../Component/HttpClient/NativeHttpClient.php | 11 +++++---- .../HttpClient/Response/CurlResponse.php | 23 +++++++++++++------ .../HttpClient/Response/NativeResponse.php | 5 ++-- .../HttpClient/Response/ResponseTrait.php | 22 +++++++++--------- .../HttpClient/ResponseInterface.php | 1 + .../HttpClient/Test/HttpClientTestCase.php | 23 ++++++++++++++++--- 8 files changed, 67 insertions(+), 34 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 08bbb46d08fc7..f5b81485292ee 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -256,7 +256,7 @@ public function request(string $method, string $url, array $options = []): Respo } } - return new CurlResponse($this->multi, $ch, $options, self::createRedirectResolver($options, $host)); + return new CurlResponse($this->multi, $ch, $options, $method, self::createRedirectResolver($options, $host)); } /** @@ -361,7 +361,7 @@ private static function createRedirectResolver(array $options, string $host): \C } return static function ($ch, string $location) use ($redirectHeaders) { - if ($host = parse_url($location, PHP_URL_HOST)) { + if ($redirectHeaders && $host = parse_url($location, PHP_URL_HOST)) { $rawHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; curl_setopt($ch, CURLOPT_HTTPHEADER, $rawHeaders); } diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index ab9bbca5c94e6..3b81f4ba9e270 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -201,10 +201,16 @@ private static function normalizeBody($body) if ($r->isGenerator()) { $body = $body(self::$CHUNK_SIZE); $body = function () use ($body) { - $chunk = $body->valid() ? $body->current() : ''; - $body->next(); + while ($body->valid()) { + $chunk = $body->current(); + $body->next(); - return $chunk; + if ('' !== $chunk) { + return $chunk; + } + } + + return ''; }; } diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index c79f9af7b34a2..afd8fbd0897b2 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -97,6 +97,7 @@ public function request(string $method, string $url, array $options = []): Respo 'raw_headers' => [], 'url' => $url, 'error' => null, + 'http_method' => $method, 'http_code' => 0, 'redirect_count' => 0, 'start_time' => 0.0, @@ -336,8 +337,8 @@ private static function createRedirectResolver(array $options, string $host, ?ar } } - return static function (\stdClass $multi, int $statusCode, ?string $location, $context) use ($redirectHeaders, $proxy, $noProxy, &$info, $maxRedirects, $onProgress): ?string { - if (null === $location || $statusCode < 300 || 400 <= $statusCode) { + return static function (\stdClass $multi, ?string $location, $context) use ($redirectHeaders, $proxy, $noProxy, &$info, $maxRedirects, $onProgress): ?string { + if (null === $location || $info['http_code'] < 300 || 400 <= $info['http_code']) { $info['redirect_url'] = null; return null; @@ -356,11 +357,11 @@ private static function createRedirectResolver(array $options, string $host, ?ar $info['redirect_time'] = $now - $info['start_time']; // Do like curl and browsers: turn POST to GET on 301, 302 and 303 - if (\in_array($statusCode, [301, 302, 303], true)) { + if (\in_array($info['http_code'], [301, 302, 303], true)) { $options = stream_context_get_options($context)['http']; - if ('POST' === $options['method'] || 303 === $statusCode) { - $options['method'] = 'HEAD' === $options['method'] ? 'HEAD' : 'GET'; + if ('POST' === $options['method'] || 303 === $info['http_code']) { + $info['http_method'] = $options['method'] = 'HEAD' === $options['method'] ? 'HEAD' : 'GET'; $options['content'] = ''; $options['header'] = array_filter($options['header'], static function ($h) { return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:'); diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index dadd841d8e485..cb9886e0e26ca 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -29,7 +29,7 @@ final class CurlResponse implements ResponseInterface /** * @internal */ - public function __construct(\stdClass $multi, $ch, array $options = null, callable $resolveRedirect = null) + public function __construct(\stdClass $multi, $ch, array $options = null, string $method = 'GET', callable $resolveRedirect = null) { $this->multi = $multi; @@ -42,9 +42,11 @@ public function __construct(\stdClass $multi, $ch, array $options = null, callab $this->id = $id = (int) $ch; $this->timeout = $options['timeout'] ?? null; + $this->info['http_method'] = $method; $this->info['user_data'] = $options['user_data'] ?? null; $this->info['start_time'] = $this->info['start_time'] ?? microtime(true); $info = &$this->info; + $headers = &$this->headers; if (!$info['raw_headers']) { // Used to keep track of what we're waiting for @@ -62,8 +64,8 @@ public function __construct(\stdClass $multi, $ch, array $options = null, callab $content = ($options['buffer'] ?? true) ? $content : null; } - curl_setopt($ch, CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, $options, $multi, $id, &$location, $resolveRedirect): int { - return self::parseHeaderLine($ch, $data, $info, $options, $multi, $id, $location, $resolveRedirect); + curl_setopt($ch, CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, &$headers, $options, $multi, $id, &$location, $resolveRedirect): int { + return self::parseHeaderLine($ch, $data, $info, $headers, $options, $multi, $id, $location, $resolveRedirect); }); if (null === $options) { @@ -116,8 +118,6 @@ public function __construct(\stdClass $multi, $ch, array $options = null, callab curl_setopt($ch, CURLOPT_HEADERFUNCTION, null); curl_setopt($ch, CURLOPT_READFUNCTION, null); curl_setopt($ch, CURLOPT_INFILE, null); - - $response->addRawHeaders($response->info['raw_headers']); }; // Schedule the request in a non-blocking way @@ -243,7 +243,7 @@ protected static function select(\stdClass $multi, float $timeout): int /** * Parses header lines as curl yields them to us. */ - private static function parseHeaderLine($ch, string $data, array &$info, ?array $options, \stdClass $multi, int $id, ?string &$location, ?callable $resolveRedirect): int + private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, \stdClass $multi, int $id, ?string &$location, ?callable $resolveRedirect): int { if (!\in_array($waitFor = @curl_getinfo($ch, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) { return \strlen($data); // Ignore HTTP trailers @@ -251,7 +251,16 @@ private static function parseHeaderLine($ch, string $data, array &$info, ?array if ("\r\n" !== $data) { // Regular header line: add it to the list - $info['raw_headers'][] = substr($data, 0, -2); + self::addRawHeaders([substr($data, 0, -2)], $info, $headers); + + if (0 === strpos($data, 'HTTP') && 300 <= $info['http_code'] && $info['http_code'] < 400) { + if (curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) { + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + } elseif (303 === $info['http_code'] || ('POST' === $info['http_method'] && \in_array($info['http_code'], [301, 302], true))) { + $info['http_method'] = 'HEAD' === $info['http_method'] ? 'HEAD' : 'GET'; + curl_setopt($ch, CURLOPT_POSTFIELDS, ''); + } + } if (0 === stripos($data, 'Location:')) { $location = trim(substr($data, 9, -2)); diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 3e9ee3a3758cd..c2bfb84caba1b 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -111,11 +111,10 @@ private function open(): void // Send request and follow redirects when needed $this->info['fopen_time'] = microtime(true); $this->handle = $h = fopen($url, 'r', false, $this->context); - $this->addRawHeaders($http_response_header); - $url = ($this->resolveRedirect)($this->multi, $this->statusCode, $this->headers['location'][0] ?? null, $this->context); + self::addRawHeaders($http_response_header, $this->info, $this->headers); + $url = ($this->resolveRedirect)($this->multi, $this->headers['location'][0] ?? null, $this->context); } while (null !== $url); } catch (\Throwable $e) { - $this->statusCode = 0; $this->close(); $this->multi->handlesActivity[$this->id][] = null; $this->multi->handlesActivity[$this->id][] = $e; diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index b31af23d4c3ce..a83a4de516763 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -28,7 +28,6 @@ */ trait ResponseTrait { - private $statusCode = 0; private $headers = []; /** @@ -43,6 +42,7 @@ trait ResponseTrait private $info = [ 'raw_headers' => [], + 'http_code' => 0, 'error' => null, ]; @@ -63,7 +63,7 @@ public function getStatusCode(): int $this->initializer = null; } - return $this->statusCode; + return $this->info['http_code']; } /** @@ -141,35 +141,35 @@ abstract protected static function perform(\stdClass $multi, array &$responses): */ abstract protected static function select(\stdClass $multi, float $timeout): int; - private function addRawHeaders(array $rawHeaders): void + private static function addRawHeaders(array $rawHeaders, array &$info, array &$headers): void { foreach ($rawHeaders as $h) { if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([12345]\d\d) .*#', $h, $m)) { - $this->headers = []; - $this->info['http_code'] = $this->statusCode = (int) $m[1]; + $headers = []; + $info['http_code'] = (int) $m[1]; } elseif (2 === \count($m = explode(':', $h, 2))) { - $this->headers[strtolower($m[0])][] = ltrim($m[1]); + $headers[strtolower($m[0])][] = ltrim($m[1]); } - $this->info['raw_headers'][] = $h; + $info['raw_headers'][] = $h; } - if (!$this->statusCode) { + if (!$info['http_code']) { throw new TransportException('Invalid or missing HTTP status line.'); } } private function checkStatusCode() { - if (500 <= $this->statusCode) { + if (500 <= $this->info['http_code']) { throw new ServerException($this); } - if (400 <= $this->statusCode) { + if (400 <= $this->info['http_code']) { throw new ClientException($this); } - if (300 <= $this->statusCode) { + if (300 <= $this->info['http_code']) { throw new RedirectionException($this); } } diff --git a/src/Symfony/Contracts/HttpClient/ResponseInterface.php b/src/Symfony/Contracts/HttpClient/ResponseInterface.php index 7aeed6d5103d9..244accc094acb 100644 --- a/src/Symfony/Contracts/HttpClient/ResponseInterface.php +++ b/src/Symfony/Contracts/HttpClient/ResponseInterface.php @@ -71,6 +71,7 @@ public function getContent(bool $throw = true): string; * - redirect_count - the number of redirects followed while executing the request * - redirect_url - the resolved location of redirect responses, null otherwise * - start_time - the time when the request was sent or 0.0 when it's pending + * - http_method - the HTTP verb of the last request * - http_code - the last response code or 0 when it is not known yet * - error - the error message when the transfer was aborted, null otherwise * - data - the value of the "data" request option, null if not set diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 59703d0ffbfad..af6e0dc3759b0 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -214,7 +214,9 @@ public function testRedirects() $client = $this->getHttpClient(); $response = $client->request('POST', 'http://localhost:8057/301', [ 'auth' => 'foo:bar', - 'body' => 'foo=bar', + 'body' => function () { + yield 'foo=bar'; + }, ]); $body = json_decode($response->getContent(), true); @@ -236,7 +238,9 @@ public function testRedirects() 'Content-Type: application/json', ]; - $filteredHeaders = array_intersect($expected, $response->getInfo('raw_headers')); + $filteredHeaders = array_values(array_filter($response->getInfo('raw_headers'), function ($h) { + return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true) && 'Content-Encoding: gzip' !== $h; + })); $this->assertSame($expected, $filteredHeaders); } @@ -261,6 +265,16 @@ public function testRelativeRedirects() public function testRedirect307() { $client = $this->getHttpClient(); + + $response = $client->request('POST', 'http://localhost:8057/307', [ + 'body' => function () { + yield 'foo=bar'; + }, + 'max_redirects' => 0, + ]); + + $this->assertSame(307, $response->getStatusCode()); + $response = $client->request('POST', 'http://localhost:8057/307', [ 'body' => 'foo=bar', ]); @@ -297,7 +311,9 @@ public function testMaxRedirects() 'Content-Type: application/json', ]; - $filteredHeaders = array_intersect($expected, $response->getInfo('raw_headers')); + $filteredHeaders = array_values(array_filter($response->getInfo('raw_headers'), function ($h) { + return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true); + })); $this->assertSame($expected, $filteredHeaders); } @@ -416,6 +432,7 @@ public function testPostCallback() $response = $client->request('POST', 'http://localhost:8057/post', [ 'body' => function () { yield 'foo'; + yield ''; yield '='; yield '0123456789'; }, From 0e2ea8719918831a6bf144f543050068465760b4 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 9 Mar 2019 17:08:21 +0100 Subject: [PATCH 189/495] [HttpClient] Remove dead code --- src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php index 5b05f50562ff7..8e7a469c42603 100644 --- a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php +++ b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php @@ -27,11 +27,6 @@ public static function start() return; } - $spec = [ - 1 => ['file', '\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null', 'w'], - 2 => ['file', '\\' === \DIRECTORY_SEPARATOR ? 'NUL' : '/dev/null', 'w'], - ]; - $finder = new PhpExecutableFinder(); $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:8057'])); $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); From 836970c776bcb42f9f408e55c4dd460f026a74d3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 9 Mar 2019 17:40:15 +0100 Subject: [PATCH 190/495] [Mime] fixed wrong logic --- src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php b/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php index 7211c0333f652..94b838ce603f5 100644 --- a/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php +++ b/src/Symfony/Component/Mime/Encoder/EightBitContentEncoder.php @@ -20,7 +20,9 @@ final class EightBitContentEncoder implements ContentEncoderInterface { public function encodeByteStream($stream, int $maxLineLength = 0): iterable { - yield from $stream; + while (!feof($stream)) { + yield fread($stream, 16372); + } } public function getName(): string From aabd1d455e89f85642c7771031b7e31b343d323c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 9 Mar 2019 17:12:38 +0100 Subject: [PATCH 191/495] [HttpClient] add ResponseInterface::toArray() --- composer.json | 2 +- .../HttpClient/Exception/JsonException.php | 25 +++++++++++ .../HttpClient/Response/ResponseTrait.php | 43 +++++++++++++++++++ .../Component/HttpClient/composer.json | 3 +- .../HttpClient/ResponseInterface.php | 12 ++++++ .../HttpClient/Test/HttpClientTestCase.php | 35 +++++++-------- 6 files changed, 101 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/HttpClient/Exception/JsonException.php diff --git a/composer.json b/composer.json index 46fdef11218c0..56c224e216378 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,7 @@ "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php72": "~1.5", - "symfony/polyfill-php73": "^1.8" + "symfony/polyfill-php73": "^1.11" }, "replace": { "symfony/asset": "self.version", diff --git a/src/Symfony/Component/HttpClient/Exception/JsonException.php b/src/Symfony/Component/HttpClient/Exception/JsonException.php new file mode 100644 index 0000000000000..5dd63455803aa --- /dev/null +++ b/src/Symfony/Component/HttpClient/Exception/JsonException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * Thrown by responses' toArray() method when their content cannot be JSON-decoded. + * + * @author Nicolas Grekas + * + * @internal + */ +final class JsonException extends \JsonException implements TransportExceptionInterface +{ +} diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index a83a4de516763..3d890b911d59b 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpClient\Chunk\ErrorChunk; use Symfony\Component\HttpClient\Chunk\LastChunk; use Symfony\Component\HttpClient\Exception\ClientException; +use Symfony\Component\HttpClient\Exception\JsonException; use Symfony\Component\HttpClient\Exception\RedirectionException; use Symfony\Component\HttpClient\Exception\ServerException; use Symfony\Component\HttpClient\Exception\TransportException; @@ -52,6 +53,7 @@ trait ResponseTrait private $timeout; private $finalInfo; private $offset = 0; + private $jsonData; /** * {@inheritdoc} @@ -121,6 +123,47 @@ public function getContent(bool $throw = true): string return stream_get_contents($this->content); } + /** + * {@inheritdoc} + */ + public function toArray(bool $throw = true): array + { + if ('' === $content = $this->getContent($throw)) { + throw new TransportException('Response body is empty.'); + } + + if (null !== $this->jsonData) { + return $this->jsonData; + } + + $contentType = $this->headers['content-type'][0] ?? 'application/json'; + + if (!preg_match('/\bjson\b/i', $contentType)) { + throw new JsonException(sprintf('Response content-type is "%s" while a JSON-compatible one was expected.', $contentType)); + } + + try { + $content = json_decode($content, true, 512, JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? JSON_THROW_ON_ERROR : 0)); + } catch (\JsonException $e) { + throw new JsonException($e->getMessage(), $e->getCode()); + } + + if (\PHP_VERSION_ID < 70300 && JSON_ERROR_NONE !== json_last_error()) { + throw new JsonException(json_last_error_msg(), json_last_error()); + } + + if (!\is_array($content)) { + throw new JsonException(sprintf('JSON content was expected to decode to an array, %s returned.', \gettype($content))); + } + + if (null !== $this->content) { + // Option "buffer" is true + return $this->jsonData = $content; + } + + return $content; + } + /** * Closes the response and all its network handles. */ diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index 854c2c64fe9c2..979385626d2cb 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -20,7 +20,8 @@ }, "require": { "php": "^7.1.3", - "symfony/contracts": "^1.1" + "symfony/contracts": "^1.1", + "symfony/polyfill-php73": "^1.11" }, "require-dev": { "nyholm/psr7": "^1.0", diff --git a/src/Symfony/Contracts/HttpClient/ResponseInterface.php b/src/Symfony/Contracts/HttpClient/ResponseInterface.php index 244accc094acb..549bfcda3f18c 100644 --- a/src/Symfony/Contracts/HttpClient/ResponseInterface.php +++ b/src/Symfony/Contracts/HttpClient/ResponseInterface.php @@ -59,6 +59,18 @@ public function getHeaders(bool $throw = true): array; */ public function getContent(bool $throw = true): string; + /** + * Gets the response body decoded as array, typically from a JSON payload. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @throws TransportExceptionInterface When the body cannot be decoded or when a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function toArray(bool $throw = true): array; + /** * Returns info coming from the transport layer. * diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index af6e0dc3759b0..fb63a9f07d9f5 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -58,6 +58,7 @@ public function testGetRequest() $this->assertSame(['application/json'], $headers['content-type']); $body = json_decode($response->getContent(), true); + $this->assertSame($body, $response->toArray()); $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); $this->assertSame('/', $body['REQUEST_URI']); @@ -79,7 +80,7 @@ public function testNonBufferedGetRequest() 'headers' => ['Foo' => 'baR'], ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('baR', $body['HTTP_FOO']); $this->expectException(TransportExceptionInterface::class); @@ -106,7 +107,7 @@ public function testHttpVersion() $this->assertSame(200, $response->getStatusCode()); $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('raw_headers')[0]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('HTTP/1.0', $body['SERVER_PROTOCOL']); $this->assertSame('GET', $body['REQUEST_METHOD']); @@ -203,7 +204,7 @@ public function testInlineAuth() $client = $this->getHttpClient(); $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057'); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('foo', $body['PHP_AUTH_USER']); $this->assertSame('bar=bar', $body['PHP_AUTH_PW']); @@ -219,7 +220,7 @@ public function testRedirects() }, ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('GET', $body['REQUEST_METHOD']); $this->assertSame('Basic Zm9vOmJhcg==', $body['HTTP_AUTHORIZATION']); $this->assertSame('http://localhost:8057/', $response->getInfo('url')); @@ -250,7 +251,8 @@ public function testRelativeRedirects() $client = $this->getHttpClient(); $response = $client->request('GET', 'http://localhost:8057/302/relative'); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); + $this->assertSame('/', $body['REQUEST_URI']); $this->assertNull($response->getInfo('redirect_url')); @@ -279,7 +281,7 @@ public function testRedirect307() 'body' => 'foo=bar', ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); } @@ -388,7 +390,7 @@ public function testOnProgress() 'on_progress' => function (...$state) use (&$steps) { $steps[] = $state; }, ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); $this->assertSame([0, 0], \array_slice($steps[0], 0, 2)); @@ -405,7 +407,7 @@ public function testPostArray() 'body' => ['foo' => 'bar'], ]); - $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], json_decode($response->getContent(), true)); + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $response->toArray()); } public function testPostResource() @@ -420,7 +422,7 @@ public function testPostResource() 'body' => $h, ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); } @@ -438,7 +440,7 @@ public function testPostCallback() }, ]); - $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], json_decode($response->getContent(), true)); + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $response->toArray()); } public function testOnProgressCancel() @@ -581,7 +583,7 @@ public function testProxy() 'proxy' => 'http://localhost:8057', ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('localhost:8057', $body['HTTP_HOST']); $this->assertRegexp('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); @@ -589,7 +591,7 @@ public function testProxy() 'proxy' => 'http://foo:b%3Dar@localhost:8057', ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']); } @@ -603,7 +605,7 @@ public function testNoProxy() 'proxy' => 'http://localhost:8057', ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); $this->assertSame('/', $body['REQUEST_URI']); @@ -629,7 +631,7 @@ public function testAutoEncodingRequest() $this->assertSame(['Accept-Encoding'], $headers['vary']); $this->assertContains('gzip', $headers['content-encoding'][0]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertContains('gzip', $body['HTTP_ACCEPT_ENCODING']); } @@ -652,7 +654,7 @@ public function testQuery() 'query' => ['b' => 'b'], ]); - $body = json_decode($response->getContent(), true); + $body = $response->toArray(); $this->assertSame('GET', $body['REQUEST_METHOD']); $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']); } @@ -673,10 +675,9 @@ public function testUserlandEncodingRequest() $this->assertContains('gzip', $headers['content-encoding'][0]); $body = $response->getContent(); - $this->assertSame("\x1F", $body[0]); - $body = json_decode(gzdecode($body), true); + $body = json_decode(gzdecode($body), true); $this->assertSame('gzip', $body['HTTP_ACCEPT_ENCODING']); } From c50aad2be16ac785f54ab53bcfee02193bc651c7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 9 Mar 2019 23:18:01 +0100 Subject: [PATCH 192/495] [DI] replace "nullable" env processor by improving the "default" one --- .../Component/DependencyInjection/CHANGELOG.md | 3 +-- .../DependencyInjection/EnvVarProcessor.php | 17 +++++++++-------- .../RegisterEnvVarProcessorsPassTest.php | 1 - .../Tests/EnvVarProcessorTest.php | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index e5fcd4f768579..7390e4289f510 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -5,8 +5,7 @@ CHANGELOG ----- * added `%env(trim:...)%` processor to trim a string value - * added `%env(default:...)%` processor to fallback to a default value - * added `%env(nullable:...)%` processor to allow empty variables to be processed as null values + * added `%env(default:param_name:...)%` processor to fallback to a parameter or to null when using `%env(default::...)%` * added support for deprecating aliases * made `ContainerParametersResource` final and not implement `Serializable` anymore * added ability to define an index for a tagged collection diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 137fc97798cc3..d734cf5b8fc1d 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -41,7 +41,6 @@ public static function getProvidedTypes() 'int' => 'int', 'json' => 'array', 'key' => 'bool|int|float|string|array', - 'nullable' => 'bool|int|float|string|array', 'resolve' => 'string', 'default' => 'bool|int|float|string|array', 'string' => 'string', @@ -84,15 +83,21 @@ public function getEnv($prefix, $name, \Closure $getEnv) $next = substr($name, $i + 1); $default = substr($name, 0, $i); - if (!$this->container->hasParameter($default)) { + if ('' !== $default && !$this->container->hasParameter($default)) { throw new RuntimeException(sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.', $name, $default)); } try { - return $getEnv($next); + $env = $getEnv($next); + + if ('' !== $env && null !== $env) { + return $env; + } } catch (EnvNotFoundException $e) { - return $this->container->getParameter($default); + // no-op } + + return '' === $default ? null : $this->container->getParameter($default); } if ('file' === $prefix) { @@ -196,10 +201,6 @@ public function getEnv($prefix, $name, \Closure $getEnv) return str_getcsv($env); } - if ('nullable' === $prefix) { - return '' === $env ? null : $env; - } - if ('trim' === $prefix) { return trim($env); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php index 7d73f6cfb37e9..f376165dfc0a1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php @@ -39,7 +39,6 @@ public function testSimpleProcessor() 'int' => ['int'], 'json' => ['array'], 'key' => ['bool', 'int', 'float', 'string', 'array'], - 'nullable' => ['bool', 'int', 'float', 'string', 'array'], 'resolve' => ['string'], 'default' => ['bool', 'int', 'float', 'string', 'array'], 'string' => ['string'], diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index 31614ce7d064f..7192127691546 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -440,7 +440,7 @@ public function testGetEnvKeyChained() public function testGetEnvNullable($value, $processed) { $processor = new EnvVarProcessor(new Container()); - $result = $processor->getEnv('nullable', 'foo', function ($name) use ($value) { + $result = $processor->getEnv('default', ':foo', function ($name) use ($value) { $this->assertSame('foo', $name); return $value; From 22b20cab1057a17646cf61d0335173d6d9ec9e27 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sun, 10 Mar 2019 14:20:19 -0400 Subject: [PATCH 193/495] Fix debug:form dateTime --- src/Symfony/Component/Form/Command/DebugCommand.php | 2 +- .../Component/Form/Tests/Command/DebugCommandTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Command/DebugCommand.php b/src/Symfony/Component/Form/Command/DebugCommand.php index b0957690c76f6..3a86e2669192c 100644 --- a/src/Symfony/Component/Form/Command/DebugCommand.php +++ b/src/Symfony/Component/Form/Command/DebugCommand.php @@ -115,7 +115,7 @@ protected function execute(InputInterface $input, OutputInterface $output) sort($options[$k]); } } else { - if (!class_exists($class)) { + if (!class_exists($class) || !is_subclass_of($class, FormTypeInterface::class)) { $class = $this->getFqcnTypeClass($input, $io, $class); } $resolvedType = $this->formRegistry->getType($class); diff --git a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php index b572daf7b2bbe..4319a23f10360 100644 --- a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php @@ -66,6 +66,15 @@ public function testDebugSingleFormType() $this->assertContains('Symfony\Component\Form\Extension\Core\Type\FormType (Block prefix: "form")', $tester->getDisplay()); } + public function testDebugDateTimeType() + { + $tester = $this->createCommandTester(); + $tester->execute(['class' => 'DateTime'], ['decorated' => false, 'interactive' => false]); + + $this->assertEquals(0, $tester->getStatusCode(), 'Returns 0 in case of success'); + $this->assertContains('Symfony\Component\Form\Extension\Core\Type\DateTimeType (Block prefix: "datetime")', $tester->getDisplay()); + } + public function testDebugFormTypeOption() { $tester = $this->createCommandTester(); From f54c89c530294b734c82d7bf75eee958dd79608d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 10 Mar 2019 23:05:13 +0100 Subject: [PATCH 194/495] [HttpClient] add missing test case --- .../HttpClient/Test/HttpClientTestCase.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index fb63a9f07d9f5..2f79d6f9af7fd 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -399,6 +399,21 @@ public function testOnProgress() $this->assertSame('http://localhost:8057/post', $steps[0][2]['url']); } + public function testPostJson() + { + $client = $this->getHttpClient(); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'json' => ['foo' => 'bar'], + ]); + + $body = $response->toArray(); + + $this->assertContains('json', $body['content-type']); + unset($body['content-type']); + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); + } + public function testPostArray() { $client = $this->getHttpClient(); From e11ef7ed124440273c7f86998655c8b7796b46b0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 11 Mar 2019 10:55:59 +0100 Subject: [PATCH 195/495] [HttpClient] yield a last chunk for completed responses also --- .../HttpClient/Response/CurlResponse.php | 16 +++++++++++----- .../HttpClient/Response/NativeResponse.php | 10 ++++++---- .../HttpClient/Response/ResponseTrait.php | 19 ++++++++++--------- .../HttpClient/Test/HttpClientTestCase.php | 12 +++++++++++- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index cb9886e0e26ca..189b6718b2e12 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -80,11 +80,12 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string if ($onProgress = $options['on_progress']) { $url = isset($info['url']) ? ['url' => $info['url']] : []; curl_setopt($ch, CURLOPT_NOPROGRESS, false); - curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url) { + curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, static function ($ch, $dlSize, $dlNow) use ($onProgress, &$info, $url, $multi) { try { $onProgress($dlNow, $dlSize, $url + curl_getinfo($ch) + $info); } catch (\Throwable $e) { - $info['error'] = $e; + $multi->handlesActivity[(int) $ch][] = null; + $multi->handlesActivity[(int) $ch][] = $e; return 1; // Abort the request } @@ -109,6 +110,7 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string } self::stream([$response])->current(); } catch (\Throwable $e) { + // Persist timeouts thrown during initialization $response->info['error'] = $e->getMessage(); $response->close(); throw $e; @@ -201,13 +203,17 @@ protected function close(): void */ protected static function schedule(self $response, array &$runningResponses): void { - if ('' === curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE)) { - // no-op - response already completed - } elseif (isset($runningResponses[$i = (int) $response->multi->handle])) { + if (isset($runningResponses[$i = (int) $response->multi->handle])) { $runningResponses[$i][1][$response->id] = $response; } else { $runningResponses[$i] = [$response->multi, [$response->id => $response]]; } + + if ('' === curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE)) { + // Response already completed + $response->multi->handlesActivity[$response->id][] = null; + $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } } /** diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index c2bfb84caba1b..f210e754404fd 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -165,10 +165,6 @@ private function close(): void */ private static function schedule(self $response, array &$runningResponses): void { - if (null === $response->buffer) { - return; - } - if (!isset($runningResponses[$i = $response->multi->id])) { $runningResponses[$i] = [$response->multi, []]; } @@ -178,6 +174,12 @@ private static function schedule(self $response, array &$runningResponses): void } else { $runningResponses[$i][1][$response->id] = $response; } + + if (null === $response->buffer) { + // Response already completed + $response->multi->handlesActivity[$response->id][] = null; + $response->multi->handlesActivity[$response->id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } } /** diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 3d890b911d59b..381bab5dc30fd 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -100,14 +100,16 @@ public function getContent(bool $throw = true): string } if (null === $this->content) { - $content = ''; + $content = null; $chunk = null; foreach (self::stream([$this]) as $chunk) { - $content .= $chunk->getContent(); + if (!$chunk->isLast()) { + $content .= $chunk->getContent(); + } } - if (null === $chunk) { + if (null === $content) { throw new TransportException('Cannot get the content of the response twice: the request was issued with option "buffer" set to false.'); } @@ -280,12 +282,14 @@ public static function stream(iterable $responses, float $timeout = null): \Gene $response->offset += \strlen($chunk); $chunk = new DataChunk($response->offset, $chunk); } elseif (null === $chunk) { - if (null !== $e = $response->info['error'] ?? $multi->handlesActivity[$j][0]) { + $e = $multi->handlesActivity[$j][0]; + unset($responses[$j], $multi->handlesActivity[$j]); + $response->close(); + + if (null !== $e) { $response->info['error'] = $e->getMessage(); if ($e instanceof \Error) { - unset($responses[$j], $multi->handlesActivity[$j]); - $response->close(); throw $e; } @@ -293,9 +297,6 @@ public static function stream(iterable $responses, float $timeout = null): \Gene } else { $chunk = new LastChunk($response->offset); } - - unset($responses[$j]); - $response->close(); } elseif ($chunk instanceof ErrorChunk) { unset($responses[$j]); $isTimeout = true; diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 2f79d6f9af7fd..44ee92bfa5937 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -194,8 +194,8 @@ public function testDnsError() $this->assertSame($response, $r); $this->assertNotNull($chunk->getError()); + $this->expectException(TransportExceptionInterface::class); foreach ($client->stream($response) as $chunk) { - $this->fail('Already errored responses shouldn\'t be yielded'); } } @@ -340,6 +340,16 @@ public function testStream() $this->assertSame($response, $r); $this->assertSame(['f', 'l'], $result); + + $chunk = null; + $i = 0; + + foreach ($client->stream($response) as $chunk) { + ++$i; + } + + $this->assertSame(1, $i); + $this->assertTrue($chunk->isLast()); } public function testAddToStream() From 250a2c8332d80af732ca19a967196d76dc94d80f Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Fri, 15 Feb 2019 15:50:49 +0100 Subject: [PATCH 196/495] [DI] Allow tagged_locator tag to be used as an argument Signed-off-by: Anthony MARTIN --- .../Argument/ServiceLocatorArgument.php | 22 ++++++ .../Argument/TaggedIteratorArgument.php | 2 - .../DependencyInjection/CHANGELOG.md | 1 + .../Compiler/ServiceLocatorTagPass.php | 7 ++ .../DependencyInjection/Dumper/XmlDumper.php | 14 +++- .../DependencyInjection/Dumper/YamlDumper.php | 12 +++ .../Configurator/ContainerConfigurator.php | 8 ++ .../Loader/XmlFileLoader.php | 7 ++ .../Loader/YamlFileLoader.php | 13 ++++ .../schema/dic/services/services-1.0.xsd | 1 + .../Tests/Compiler/IntegrationTest.php | 76 +++++++++++++++++-- .../PriorityTaggedServiceTraitTest.php | 2 +- .../Tests/Dumper/XmlDumperTest.php | 10 ++- .../Tests/Dumper/YamlDumperTest.php | 7 +- .../xml/services_with_tagged_arguments.xml | 3 + .../yaml/services_with_tagged_argument.yml | 5 +- .../Tests/Loader/XmlFileLoaderTest.php | 7 +- .../Tests/Loader/YamlFileLoaderTest.php | 9 ++- 18 files changed, 187 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php index 8214f8bb3a6c3..fcbf478c627f9 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php @@ -11,6 +11,8 @@ namespace Symfony\Component\DependencyInjection\Argument; +use Symfony\Component\DependencyInjection\Reference; + /** * Represents a closure acting as a service locator. * @@ -19,4 +21,24 @@ class ServiceLocatorArgument implements ArgumentInterface { use ReferenceSetArgumentTrait; + + private $taggedIteratorArgument; + + /** + * @param Reference[]|TaggedIteratorArgument $values + */ + public function __construct($values = []) + { + if ($values instanceof TaggedIteratorArgument) { + $this->taggedIteratorArgument = $values; + $this->values = []; + } else { + $this->setValues($values); + } + } + + public function getTaggedIteratorArgument(): ?TaggedIteratorArgument + { + return $this->taggedIteratorArgument; + } } diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php index fabfb00451851..a3099686d16df 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php @@ -23,8 +23,6 @@ class TaggedIteratorArgument extends IteratorArgument private $defaultIndexMethod; /** - * TaggedIteratorArgument constructor. - * * @param string $tag The name of the tag identifying the target services * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection * @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 7390e4289f510..c8ef90f5bc1ef 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG * added support for deprecating aliases * made `ContainerParametersResource` final and not implement `Serializable` anymore * added ability to define an index for a tagged collection + * added ability to define an index for services in an injected service locator argument 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php index e335307482aec..2030d3774cc17 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php @@ -27,11 +27,18 @@ */ final class ServiceLocatorTagPass extends AbstractRecursivePass { + use PriorityTaggedServiceTrait; + protected function processValue($value, $isRoot = false) { if ($value instanceof ServiceLocatorArgument) { + if ($value->getTaggedIteratorArgument()) { + $value->setValues($this->findAndSortTaggedServices($value->getTaggedIteratorArgument(), $this->container)); + } + return self::register($this->container, $value->getValues()); } + if (!$value instanceof Definition || !$value->hasTag('container.service_locator')) { return parent::processValue($value, $isRoot); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index eb56becd8da09..5b9edd03510ba 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -298,8 +298,18 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent $element->setAttribute('type', 'iterator'); $this->convertParameters($value->getValues(), $type, $element, 'key'); } elseif ($value instanceof ServiceLocatorArgument) { - $element->setAttribute('type', 'service_locator'); - $this->convertParameters($value->getValues(), $type, $element, 'key'); + if ($value->getTaggedIteratorArgument()) { + $element->setAttribute('type', 'tagged_locator'); + $element->setAttribute('tag', $value->getTaggedIteratorArgument()->getTag()); + $element->setAttribute('index-by', $value->getTaggedIteratorArgument()->getIndexAttribute()); + + if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { + $element->setAttribute('default-index-method', $value->getTaggedIteratorArgument()->getDefaultIndexMethod()); + } + } else { + $element->setAttribute('type', 'service_locator'); + $this->convertParameters($value->getValues(), $type, $element, 'key'); + } } elseif ($value instanceof Reference) { $element->setAttribute('type', 'service'); $element->setAttribute('id', (string) $value); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index 875ebbc0abc8b..b4c899379c4c4 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -252,6 +252,18 @@ private function dumpValue($value) $tag = 'iterator'; } elseif ($value instanceof ServiceLocatorArgument) { $tag = 'service_locator'; + if ($value->getTaggedIteratorArgument()) { + $taggedValueContent = [ + 'tag' => $value->getTaggedIteratorArgument()->getTag(), + 'index_by' => $value->getTaggedIteratorArgument()->getIndexAttribute(), + ]; + + if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { + $taggedValueContent['default_index_method'] = $value->getTaggedIteratorArgument()->getDefaultIndexMethod(); + } + + return new TaggedValue('tagged_locator', $taggedValueContent); + } } else { throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value))); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index f75ba1be85790..d4b03fc2c177e 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -121,6 +121,14 @@ function tagged(string $tag, string $indexAttribute = null, string $defaultIndex return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod); } +/** + * Creates a service locator by tag name. + */ +function tagged_locator(string $tag, string $indexAttribute, string $defaultIndexMethod = null): ServiceLocatorArgument +{ + return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod)); +} + /** * Creates an expression. */ diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index b5e076888fb1e..ced8b0142d25d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -533,6 +533,13 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_locator" only accepts maps of type="service" references in "%s".', $name, $file)); } break; + case 'tagged_locator': + if (!$arg->getAttribute('tag') || !$arg->getAttribute('index-by')) { + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged_locator" has no or empty "tag" or "index-by" attributes in "%s".', $name, $file)); + } + + $arguments[$key] = new ServiceLocatorArgument(new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by'), $arg->getAttribute('default-index-method') ?: null)); + break; case 'tagged': if (!$arg->getAttribute('tag')) { throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file)); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 06fcbb4a91af1..4d9da4e314f9b 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -702,7 +702,9 @@ private function resolveServices($value, $file, $isParameter = false) if (!\is_array($argument)) { throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps in "%s".', $file)); } + $argument = $this->resolveServices($argument, $file, $isParameter); + try { return new ServiceLocatorArgument($argument); } catch (InvalidArgumentException $e) { @@ -724,6 +726,17 @@ private function resolveServices($value, $file, $isParameter = false) throw new InvalidArgumentException(sprintf('"!tagged" tags only accept a non empty string or an array with a key "tag" in "%s".', $file)); } + if ('tagged_locator' === $value->getTag()) { + if (\is_array($argument) && isset($argument['tag'], $argument['index_by']) && $argument['tag'] && $argument['index_by']) { + if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { + throw new InvalidArgumentException(sprintf('"!tagged_locator" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); + } + + return new ServiceLocatorArgument(new TaggedIteratorArgument($argument['tag'], $argument['index_by'], $argument['default_index_method'] ?? null)); + } + + throw new InvalidArgumentException(sprintf('"!tagged_locator" tags only accept an array with at least keys "tag" and "index_by" in "%s".', $file)); + } if ('service' === $value->getTag()) { if ($isParameter) { throw new InvalidArgumentException(sprintf('Using an anonymous service in a parameter is not allowed in "%s".', $file)); diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index b14ffc8dcd212..841e807943174 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -264,6 +264,7 @@ + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index 1ba0a53eaa679..a2bbbe20cf12a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -14,10 +14,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Alias; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\BarTagClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\FooBarTaggedClass; @@ -242,15 +244,15 @@ public function getYamlCompileTests() public function testTaggedServiceWithIndexAttribute() { $container = new ContainerBuilder(); - $container->register(BarTagClass::class, BarTagClass::class) + $container->register(BarTagClass::class) ->setPublic(true) ->addTag('foo_bar', ['foo' => 'bar']) ; - $container->register(FooTagClass::class, FooTagClass::class) + $container->register(FooTagClass::class) ->setPublic(true) ->addTag('foo_bar') ; - $container->register(FooBarTaggedClass::class, FooBarTaggedClass::class) + $container->register(FooBarTaggedClass::class) ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo')) ->setPublic(true) ; @@ -266,15 +268,15 @@ public function testTaggedServiceWithIndexAttribute() public function testTaggedServiceWithIndexAttributeAndDefaultMethod() { $container = new ContainerBuilder(); - $container->register(BarTagClass::class, BarTagClass::class) + $container->register(BarTagClass::class) ->setPublic(true) ->addTag('foo_bar') ; - $container->register(FooTagClass::class, FooTagClass::class) + $container->register(FooTagClass::class) ->setPublic(true) ->addTag('foo_bar', ['foo' => 'foo']) ; - $container->register(FooBarTaggedClass::class, FooBarTaggedClass::class) + $container->register(FooBarTaggedClass::class) ->addArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar')) ->setPublic(true) ; @@ -286,6 +288,68 @@ public function testTaggedServiceWithIndexAttributeAndDefaultMethod() $param = iterator_to_array($s->getParam()->getIterator()); $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $param); } + + public function testTaggedServiceLocatorWithIndexAttribute() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar', ['foo' => 'bar']) + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooBarTaggedClass::class) + ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo'))) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + /** @var ServiceLocator $serviceLocator */ + $serviceLocator = $s->getParam(); + $this->assertTrue($s->getParam() instanceof ServiceLocator, sprintf('Wrong instance, should be an instance of ServiceLocator, %s given', \is_object($serviceLocator) ? \get_class($serviceLocator) : \gettype($serviceLocator))); + + $same = [ + 'bar' => $serviceLocator->get('bar'), + 'foo_tag_class' => $serviceLocator->get('foo_tag_class'), + ]; + $this->assertSame(['bar' => $container->get(BarTagClass::class), 'foo_tag_class' => $container->get(FooTagClass::class)], $same); + } + + public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooTagClass::class) + ->setPublic(true) + ->addTag('foo_bar', ['foo' => 'foo']) + ; + $container->register(FooBarTaggedClass::class) + ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', 'foo', 'getFooBar'))) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + /** @var ServiceLocator $serviceLocator */ + $serviceLocator = $s->getParam(); + $this->assertTrue($s->getParam() instanceof ServiceLocator, sprintf('Wrong instance, should be an instance of ServiceLocator, %s given', \is_object($serviceLocator) ? \get_class($serviceLocator) : \gettype($serviceLocator))); + + $same = [ + 'bar_tab_class_with_defaultmethod' => $serviceLocator->get('bar_tab_class_with_defaultmethod'), + 'foo' => $serviceLocator->get('foo'), + ]; + $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $same); + } } class ServiceSubscriberStub implements ServiceSubscriberInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php index 57ca9af427128..adf9696acd3ef 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php @@ -93,6 +93,6 @@ class PriorityTaggedServiceTraitImplementation public function test($tagName, ContainerBuilder $container) { - return $this->findAndSortTaggedServices($tagName, $container); + return self::findAndSortTaggedServices($tagName, $container); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index 2c5615bc69bf7..cc80a69455b97 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -201,13 +202,18 @@ public function testDumpLoad() $this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_dump_load.xml', $dumper->dump()); } - public function testTaggedArgument() + public function testTaggedArguments() { + $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); $container = new ContainerBuilder(); $container->register('foo', 'Foo')->addTag('foo_tag'); $container->register('foo_tagged_iterator', 'Bar') ->setPublic(true) - ->addArgument(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar')) + ->addArgument($taggedIterator) + ; + $container->register('foo_tagged_locator', 'Bar') + ->setPublic(true) + ->addArgument(new ServiceLocatorArgument($taggedIterator)) ; $dumper = new XmlDumper($container); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index 61a1aec5105dc..72901c855e414 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -96,11 +97,13 @@ public function testInlineServices() $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_inline.yml', $dumper->dump()); } - public function testTaggedArgument() + public function testTaggedArguments() { + $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); $container = new ContainerBuilder(); $container->register('foo_service', 'Foo')->addTag('foo'); - $container->register('foo_service_tagged', 'Bar')->addArgument(new TaggedIteratorArgument('foo', 'barfoo', 'foobar')); + $container->register('foo_service_tagged_iterator', 'Bar')->addArgument($taggedIterator); + $container->register('foo_service_tagged_locator', 'Bar')->addArgument(new ServiceLocatorArgument($taggedIterator)); $dumper = new YamlDumper($container); $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_tagged_argument.yml', $dumper->dump()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml index e979d5fc9be38..e3e51d352d837 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_tagged_arguments.xml @@ -8,6 +8,9 @@ + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml index bf7cf06930d0c..5e071d327802e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_tagged_argument.yml @@ -8,9 +8,12 @@ services: class: Foo tags: - { name: foo } - foo_service_tagged: + foo_service_tagged_iterator: class: Bar arguments: [!tagged { tag: foo, index_by: barfoo, default_index_method: foobar }] + foo_service_tagged_locator: + class: Bar + arguments: [!tagged_locator { tag: foo, index_by: barfoo, default_index_method: foobar }] Psr\Container\ContainerInterface: alias: service_container public: false diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 20c80258e2686..3e326ed85ab4b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Dumper\PhpDumper; @@ -324,7 +325,11 @@ public function testParseTaggedArgumentsWithIndexBy() $this->assertCount(1, $container->getDefinition('foo')->getTag('foo_tag')); $this->assertCount(1, $container->getDefinition('foo_tagged_iterator')->getArguments()); - $this->assertEquals(new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'), $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + $this->assertCount(1, $container->getDefinition('foo_tagged_locator')->getArguments()); + + $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); + $this->assertEquals($taggedIterator, $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0)); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 7870a521a9dbe..0da99f437b7f8 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; @@ -287,8 +288,12 @@ public function testTaggedArgumentsWithIndex() $loader->load('services_with_tagged_argument.yml'); $this->assertCount(1, $container->getDefinition('foo_service')->getTag('foo')); - $this->assertCount(1, $container->getDefinition('foo_service_tagged')->getArguments()); - $this->assertEquals(new TaggedIteratorArgument('foo', 'barfoo', 'foobar'), $container->getDefinition('foo_service_tagged')->getArgument(0)); + $this->assertCount(1, $container->getDefinition('foo_service_tagged_iterator')->getArguments()); + $this->assertCount(1, $container->getDefinition('foo_service_tagged_locator')->getArguments()); + + $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); + $this->assertEquals($taggedIterator, $container->getDefinition('foo_service_tagged_iterator')->getArgument(0)); + $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_service_tagged_locator')->getArgument(0)); } public function testNameOnlyTagsAreAllowedAsString() From cb3c56bc0c58abe076c67284a8da132db7697c08 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 7 Mar 2019 15:19:37 +0100 Subject: [PATCH 197/495] Support indexing tagged locators by FQCN as fallback --- .../Argument/TaggedIteratorArgument.php | 17 +++++---- .../Compiler/PriorityTaggedServiceTrait.php | 27 ++++++++++---- .../DependencyInjection/Dumper/XmlDumper.php | 32 ++++++----------- .../DependencyInjection/Dumper/YamlDumper.php | 35 +++++++------------ .../Configurator/ContainerConfigurator.php | 2 +- .../Loader/XmlFileLoader.php | 17 ++++----- .../Loader/YamlFileLoader.php | 23 ++++++------ .../Tests/Compiler/IntegrationTest.php | 26 ++++++++++++++ .../PriorityTaggedServiceTraitTest.php | 2 +- .../Tests/Loader/XmlFileLoaderTest.php | 2 ++ .../Tests/Loader/YamlFileLoaderTest.php | 2 ++ 11 files changed, 107 insertions(+), 78 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php index a3099686d16df..f3b323ce4c2a0 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/TaggedIteratorArgument.php @@ -21,22 +21,22 @@ class TaggedIteratorArgument extends IteratorArgument private $tag; private $indexAttribute; private $defaultIndexMethod; + private $useFqcnAsFallback = false; /** * @param string $tag The name of the tag identifying the target services * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection * @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute + * @param bool $useFqcnAsFallback Whether the FQCN of the service should be used as index when neither the attribute nor the method are defined */ - public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null) + public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $useFqcnAsFallback = false) { parent::__construct([]); $this->tag = $tag; - - if ($indexAttribute) { - $this->indexAttribute = $indexAttribute; - $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name'); - } + $this->indexAttribute = $indexAttribute; + $this->defaultIndexMethod = $defaultIndexMethod ?: ('getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute ?? ''))).'Name'); + $this->useFqcnAsFallback = $useFqcnAsFallback; } public function getTag() @@ -53,4 +53,9 @@ public function getDefaultIndexMethod(): ?string { return $this->defaultIndexMethod; } + + public function useFqcnAsFallback(): bool + { + return $this->useFqcnAsFallback; + } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php index f9046d3c3283b..3bf8e3be18be3 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php @@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; /** * Trait that allows a generic method to find and sort service by priority option in the tag. @@ -40,34 +41,48 @@ trait PriorityTaggedServiceTrait */ private function findAndSortTaggedServices($tagName, ContainerBuilder $container) { - $indexAttribute = $defaultIndexMethod = null; + $indexAttribute = $defaultIndexMethod = $useFqcnAsFallback = null; + if ($tagName instanceof TaggedIteratorArgument) { $indexAttribute = $tagName->getIndexAttribute(); $defaultIndexMethod = $tagName->getDefaultIndexMethod(); + $useFqcnAsFallback = $tagName->useFqcnAsFallback(); $tagName = $tagName->getTag(); } + $services = []; foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) { $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - if (null === $indexAttribute) { + if (null === $indexAttribute && !$useFqcnAsFallback) { $services[$priority][] = new Reference($serviceId); continue; } - if (isset($attributes[0][$indexAttribute])) { - $services[$priority][$attributes[0][$indexAttribute]] = new Reference($serviceId); + $class = $container->getDefinition($serviceId)->getClass(); + $class = $container->getParameterBag()->resolveValue($class) ?: null; + + if (null !== $indexAttribute && isset($attributes[0][$indexAttribute])) { + $services[$priority][$attributes[0][$indexAttribute]] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $attributes[0][$indexAttribute]); continue; } - if (!$r = $container->getReflectionClass($class = $container->getDefinition($serviceId)->getClass())) { + if (!$r = $container->getReflectionClass($class)) { throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $serviceId)); } + $class = $r->name; + if (!$r->hasMethod($defaultIndexMethod)) { + if ($useFqcnAsFallback) { + $services[$priority][$class] = new TypedReference($serviceId, $class); + + continue; + } + throw new InvalidArgumentException(sprintf('Method "%s::%s()" not found: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, $tagName, $serviceId, $indexAttribute)); } @@ -85,7 +100,7 @@ private function findAndSortTaggedServices($tagName, ContainerBuilder $container throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return a string, got %s: tag "%s" on service "%s" is missing "%s" attribute.', $class, $defaultIndexMethod, \gettype($key), $tagName, $serviceId, $indexAttribute)); } - $services[$priority][$key] = new Reference($serviceId); + $services[$priority][$key] = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $key); } if ($services) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index 5b9edd03510ba..57ac2675aeda4 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -280,36 +280,26 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent if ($value instanceof ServiceClosureArgument) { $value = $value->getValues()[0]; } - if (\is_array($value)) { + if (\is_array($tag = $value)) { $element->setAttribute('type', 'collection'); $this->convertParameters($value, $type, $element, 'key'); - } elseif ($value instanceof TaggedIteratorArgument) { - $element->setAttribute('type', 'tagged'); - $element->setAttribute('tag', $value->getTag()); + } elseif ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) { + $element->setAttribute('type', $value instanceof TaggedIteratorArgument ? 'tagged' : 'tagged_locator'); + $element->setAttribute('tag', $tag->getTag()); - if (null !== $value->getIndexAttribute()) { - $element->setAttribute('index-by', $value->getIndexAttribute()); - } + if (null !== $tag->getIndexAttribute()) { + $element->setAttribute('index-by', $tag->getIndexAttribute()); - if (null !== $value->getDefaultIndexMethod()) { - $element->setAttribute('default-index-method', $value->getDefaultIndexMethod()); + if (null !== $tag->getDefaultIndexMethod()) { + $element->setAttribute('default-index-method', $tag->getDefaultIndexMethod()); + } } } elseif ($value instanceof IteratorArgument) { $element->setAttribute('type', 'iterator'); $this->convertParameters($value->getValues(), $type, $element, 'key'); } elseif ($value instanceof ServiceLocatorArgument) { - if ($value->getTaggedIteratorArgument()) { - $element->setAttribute('type', 'tagged_locator'); - $element->setAttribute('tag', $value->getTaggedIteratorArgument()->getTag()); - $element->setAttribute('index-by', $value->getTaggedIteratorArgument()->getIndexAttribute()); - - if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { - $element->setAttribute('default-index-method', $value->getTaggedIteratorArgument()->getDefaultIndexMethod()); - } - } else { - $element->setAttribute('type', 'service_locator'); - $this->convertParameters($value->getValues(), $type, $element, 'key'); - } + $element->setAttribute('type', 'service_locator'); + $this->convertParameters($value->getValues(), $type, $element, 'key'); } elseif ($value instanceof Reference) { $element->setAttribute('type', 'service'); $element->setAttribute('id', (string) $value); diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index b4c899379c4c4..89dae636de023 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -232,38 +232,29 @@ private function dumpValue($value) $value = $value->getValues()[0]; } if ($value instanceof ArgumentInterface) { - if ($value instanceof TaggedIteratorArgument) { - if (null !== $value->getIndexAttribute()) { - $taggedValueContent = [ - 'tag' => $value->getTag(), - 'index_by' => $value->getIndexAttribute(), + $tag = $value; + + if ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) { + if (null === $tag->getIndexAttribute()) { + $content = $tag->getTag(); + } else { + $content = [ + 'tag' => $tag->getTag(), + 'index_by' => $tag->getIndexAttribute(), ]; - if (null !== $value->getDefaultIndexMethod()) { - $taggedValueContent['default_index_method'] = $value->getDefaultIndexMethod(); + if (null !== $tag->getDefaultIndexMethod()) { + $content['default_index_method'] = $tag->getDefaultIndexMethod(); } - - return new TaggedValue('tagged', $taggedValueContent); } - return new TaggedValue('tagged', $value->getTag()); + return new TaggedValue($value instanceof TaggedIteratorArgument ? 'tagged' : 'tagged_locator', $content); } + if ($value instanceof IteratorArgument) { $tag = 'iterator'; } elseif ($value instanceof ServiceLocatorArgument) { $tag = 'service_locator'; - if ($value->getTaggedIteratorArgument()) { - $taggedValueContent = [ - 'tag' => $value->getTaggedIteratorArgument()->getTag(), - 'index_by' => $value->getTaggedIteratorArgument()->getIndexAttribute(), - ]; - - if (null !== $value->getTaggedIteratorArgument()->getDefaultIndexMethod()) { - $taggedValueContent['default_index_method'] = $value->getTaggedIteratorArgument()->getDefaultIndexMethod(); - } - - return new TaggedValue('tagged_locator', $taggedValueContent); - } } else { throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value))); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index d4b03fc2c177e..87b066faf5030 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -126,7 +126,7 @@ function tagged(string $tag, string $indexAttribute = null, string $defaultIndex */ function tagged_locator(string $tag, string $indexAttribute, string $defaultIndexMethod = null): ServiceLocatorArgument { - return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod)); + return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true)); } /** diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index ced8b0142d25d..92c27e6ebf139 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -533,19 +533,20 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_locator" only accepts maps of type="service" references in "%s".', $name, $file)); } break; + case 'tagged': case 'tagged_locator': - if (!$arg->getAttribute('tag') || !$arg->getAttribute('index-by')) { - throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged_locator" has no or empty "tag" or "index-by" attributes in "%s".', $name, $file)); - } + $type = $arg->getAttribute('type'); + $forLocator = 'tagged_locator' === $type; - $arguments[$key] = new ServiceLocatorArgument(new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by'), $arg->getAttribute('default-index-method') ?: null)); - break; - case 'tagged': if (!$arg->getAttribute('tag')) { - throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file)); + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="%s" has no or empty "tag" attribute in "%s".', $name, $type, $file)); } - $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null); + $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator); + + if ($forLocator) { + $arguments[$key] = new ServiceLocatorArgument($arguments[$key]); + } break; case 'binary': if (false === $value = base64_decode($arg->nodeValue)) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 4d9da4e314f9b..ecd66dd276319 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -711,31 +711,28 @@ private function resolveServices($value, $file, $isParameter = false) throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps of "@service" references in "%s".', $file)); } } - if ('tagged' === $value->getTag()) { + if (\in_array($value->getTag(), ['tagged', 'tagged_locator'], true)) { + $forLocator = 'tagged_locator' === $value->getTag(); + if (\is_string($argument) && $argument) { - return new TaggedIteratorArgument($argument); + return new TaggedIteratorArgument($argument, null, null, $forLocator); } if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) { if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { - throw new InvalidArgumentException(sprintf('"!tagged" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); + throw new InvalidArgumentException(sprintf('"!%s" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', $value->getTag(), implode('"", "', $diff))); } - return new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null); - } + $argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'], $argument['default_index_method'] ?? null, $forLocator); - throw new InvalidArgumentException(sprintf('"!tagged" tags only accept a non empty string or an array with a key "tag" in "%s".', $file)); - } - if ('tagged_locator' === $value->getTag()) { - if (\is_array($argument) && isset($argument['tag'], $argument['index_by']) && $argument['tag'] && $argument['index_by']) { - if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method'])) { - throw new InvalidArgumentException(sprintf('"!tagged_locator" tag contains unsupported key "%s"; supported ones are "tag", "index_by" and "default_index_method".', implode('"", "', $diff))); + if ($forLocator) { + $argument = new ServiceLocatorArgument($argument); } - return new ServiceLocatorArgument(new TaggedIteratorArgument($argument['tag'], $argument['index_by'], $argument['default_index_method'] ?? null)); + return $argument; } - throw new InvalidArgumentException(sprintf('"!tagged_locator" tags only accept an array with at least keys "tag" and "index_by" in "%s".', $file)); + throw new InvalidArgumentException(sprintf('"!%s" tags only accept a non empty string or an array with a key "tag" in "%s".', $value->getTag(), $file)); } if ('service' === $value->getTag()) { if ($isParameter) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index a2bbbe20cf12a..feeb163edb023 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -350,6 +350,32 @@ public function testTaggedServiceLocatorWithIndexAttributeAndDefaultMethod() ]; $this->assertSame(['bar_tab_class_with_defaultmethod' => $container->get(BarTagClass::class), 'foo' => $container->get(FooTagClass::class)], $same); } + + public function testTaggedServiceLocatorWithFqcnFallback() + { + $container = new ContainerBuilder(); + $container->register(BarTagClass::class) + ->setPublic(true) + ->addTag('foo_bar') + ; + $container->register(FooBarTaggedClass::class) + ->addArgument(new ServiceLocatorArgument(new TaggedIteratorArgument('foo_bar', null, null, true))) + ->setPublic(true) + ; + + $container->compile(); + + $s = $container->get(FooBarTaggedClass::class); + + /** @var ServiceLocator $serviceLocator */ + $serviceLocator = $s->getParam(); + $this->assertTrue($s->getParam() instanceof ServiceLocator, sprintf('Wrong instance, should be an instance of ServiceLocator, %s given', \is_object($serviceLocator) ? \get_class($serviceLocator) : \gettype($serviceLocator))); + + $same = [ + BarTagClass::class => $serviceLocator->get(BarTagClass::class), + ]; + $this->assertSame([BarTagClass::class => $container->get(BarTagClass::class)], $same); + } } class ServiceSubscriberStub implements ServiceSubscriberInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php index adf9696acd3ef..57ca9af427128 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/PriorityTaggedServiceTraitTest.php @@ -93,6 +93,6 @@ class PriorityTaggedServiceTraitImplementation public function test($tagName, ContainerBuilder $container) { - return self::findAndSortTaggedServices($tagName, $container); + return $this->findAndSortTaggedServices($tagName, $container); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 3e326ed85ab4b..681a43b332df3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -329,6 +329,8 @@ public function testParseTaggedArgumentsWithIndexBy() $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar'); $this->assertEquals($taggedIterator, $container->getDefinition('foo_tagged_iterator')->getArgument(0)); + + $taggedIterator = new TaggedIteratorArgument('foo_tag', 'barfoo', 'foobar', true); $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_tagged_locator')->getArgument(0)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 0da99f437b7f8..83e034c482a81 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -293,6 +293,8 @@ public function testTaggedArgumentsWithIndex() $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar'); $this->assertEquals($taggedIterator, $container->getDefinition('foo_service_tagged_iterator')->getArgument(0)); + + $taggedIterator = new TaggedIteratorArgument('foo', 'barfoo', 'foobar', true); $this->assertEquals(new ServiceLocatorArgument($taggedIterator), $container->getDefinition('foo_service_tagged_locator')->getArgument(0)); } From 2a4f8a11d487de192b32afaa623292f50c53cb66 Mon Sep 17 00:00:00 2001 From: Andrew Berry Date: Mon, 11 Mar 2019 13:46:11 -0400 Subject: [PATCH 198/495] [PropertyInfo] Use a single cache item per method --- .../PropertyInfoCacheExtractor.php | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php index 0eb9f63a54856..d75bf91a94a4f 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php @@ -24,6 +24,13 @@ class PropertyInfoCacheExtractor implements PropertyInfoExtractorInterface, Prop { private $propertyInfoExtractor; private $cacheItemPool; + + /** + * A cache of property information, first keyed by the method called and + * then by the serialized method arguments. + * + * @var array + */ private $arrayCache = []; public function __construct(PropertyInfoExtractorInterface $propertyInfoExtractor, CacheItemPoolInterface $cacheItemPool) @@ -103,22 +110,34 @@ private function extract(string $method, array $arguments) } // Calling rawurlencode escapes special characters not allowed in PSR-6's keys - $key = rawurlencode($method.'.'.$serializedArguments); - - if (\array_key_exists($key, $this->arrayCache)) { - return $this->arrayCache[$key]; + $encodedMethod = \rawurlencode($method); + if (\array_key_exists($encodedMethod, $this->arrayCache) && \array_key_exists($serializedArguments, $this->arrayCache[$encodedMethod])) { + return $this->arrayCache[$encodedMethod][$serializedArguments]; } - $item = $this->cacheItemPool->getItem($key); + $item = $this->cacheItemPool->getItem($encodedMethod); + $data = $item->get(); if ($item->isHit()) { - return $this->arrayCache[$key] = $item->get(); + $this->arrayCache[$encodedMethod] = $data[$encodedMethod]; + // Only match if the specific arguments have been cached. + if (\array_key_exists($serializedArguments, $data[$encodedMethod])) { + return $this->arrayCache[$encodedMethod][$serializedArguments]; + } + } + + // It's possible that the method has been called, but with different + // arguments, in which case $data will already be initialized. + if (!$data) { + $data = []; } $value = $this->propertyInfoExtractor->{$method}(...$arguments); - $item->set($value); + $data[$encodedMethod][$serializedArguments] = $value; + $this->arrayCache[$encodedMethod][$serializedArguments] = $value; + $item->set($data); $this->cacheItemPool->save($item); - return $this->arrayCache[$key] = $value; + return $this->arrayCache[$encodedMethod][$serializedArguments]; } } From a608797165a245bfcc67310b30065bbb5f8ffe4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 4 Dec 2018 19:19:25 +0100 Subject: [PATCH 199/495] [Workflow] Move code from ValidateWorkflowsPass to the FrameworkExtension --- .../FrameworkExtension.php | 37 +++- .../FrameworkBundle/FrameworkBundle.php | 2 - .../Fixtures/php/workflow_not_valid.php | 30 +++ .../Fixtures/xml/workflow_not_valid.xml | 22 +++ .../Fixtures/xml/workflows.xml | 6 +- .../Fixtures/yml/workflow_not_valid.yml | 11 ++ .../FrameworkExtensionTest.php | 11 +- .../PhpFrameworkExtensionTest.php | 174 ++++++++++++++++++ .../ValidateWorkflowsPass.php | 2 + .../ValidateWorkflowsPassTest.php | 32 ---- 10 files changed, 281 insertions(+), 46 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_not_valid.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_not_valid.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_not_valid.yml delete mode 100644 src/Symfony/Component/Workflow/Tests/DependencyInjection/ValidateWorkflowsPassTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a38518b2e9229..96b779feafea0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -603,20 +603,15 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ // Create places $places = array_column($workflow['places'], 'name'); + $initialPlace = $workflow['initial_place'] ?? null; // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); $definitionDefinition->addArgument($places); $definitionDefinition->addArgument($transitions); - $definitionDefinition->addArgument($workflow['initial_place'] ?? null); + $definitionDefinition->addArgument($initialPlace); $definitionDefinition->addArgument($metadataStoreDefinition); - $definitionDefinition->addTag('workflow.definition', [ - 'name' => $name, - 'type' => $type, - 'marking_store' => $workflow['marking_store']['type'] ?? null, - 'single_state' => 'method' === ($workflow['marking_store']['type'] ?? null) && ($workflow['marking_store']['arguments'][0] ?? false), - ]); // Create MarkingStore if (isset($workflow['marking_store']['type'])) { @@ -641,6 +636,34 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $container->setDefinition(sprintf('%s.definition', $workflowId), $definitionDefinition); $container->registerAliasForArgument($workflowId, WorkflowInterface::class, $name.'.'.$type); + // Validate Workflow + $validator = null; + switch (true) { + case 'state_machine' === $workflow['type']: + $validator = new Workflow\Validator\StateMachineValidator(); + break; + case 'method' === ($workflow['marking_store']['type'] ?? null): + $singlePlace = $workflow['marking_store']['arguments'][0] ?? false; + $validator = new Workflow\Validator\WorkflowValidator($singlePlace); + break; + case 'single_state' === ($workflow['marking_store']['type'] ?? null): + $validator = new Workflow\Validator\WorkflowValidator(true); + break; + case 'multiple_state' === ($workflow['marking_store']['type'] ?? false): + $validator = new Workflow\Validator\WorkflowValidator(false); + break; + } + if ($validator) { + $realDefinition = (new Workflow\DefinitionBuilder($places)) + ->addTransitions(array_map(function (Reference $ref) use ($container): Workflow\Transition { + return $container->get((string) $ref); + }, $transitions)) + ->setInitialPlace($initialPlace) + ->build() + ; + $validator->validate($realDefinition, $name); + } + // Add workflow to Registry if ($workflow['supports']) { foreach ($workflow['supports'] as $supportedClassName) { diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 7f86b9e4bb76d..78ddaeb3d866e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -54,7 +54,6 @@ use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass; use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass; use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass; -use Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass; /** * Bundle. @@ -115,7 +114,6 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new DataCollectorTranslatorPass()); $container->addCompilerPass(new ControllerArgumentValueResolverPass()); $container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32); - $this->addCompilerPassIfExists($container, ValidateWorkflowsPass::class); $container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new CachePoolPrunerPass(), PassConfig::TYPE_AFTER_REMOVING); $this->addCompilerPassIfExists($container, FormPass::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_not_valid.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_not_valid.php new file mode 100644 index 0000000000000..5d6ed54d6739f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_not_valid.php @@ -0,0 +1,30 @@ +loadFromExtension('framework', [ + 'workflows' => [ + 'my_workflow' => [ + 'type' => 'state_machine', + 'supports' => [ + FrameworkExtensionTest::class, + ], + 'places' => [ + 'first', + 'middle', + 'last', + ], + 'transitions' => [ + 'go' => [ + 'from' => [ + 'first', + ], + 'to' => [ + 'middle', + 'last', + ], + ], + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_not_valid.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_not_valid.xml new file mode 100644 index 0000000000000..df299c89deb50 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_not_valid.xml @@ -0,0 +1,22 @@ + + + + + + + Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + + + + + first + middle + last + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml index fe32756f2e00b..862ecae17cde5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml @@ -29,12 +29,12 @@ approved_by_journalist - wait_for_spellcheker - approved_by_spellchker + wait_for_spellchecker + approved_by_spellchecker approved_by_journalist - approved_by_spellchker + approved_by_spellchecker published diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_not_valid.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_not_valid.yml new file mode 100644 index 0000000000000..123505de9754f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_not_valid.yml @@ -0,0 +1,11 @@ +framework: + workflows: + my_workflow: + type: state_machine + supports: + - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + places: [first, middle, last] + transitions: + go: + from: first + to: [last, middle ] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index b38439349ad3b..1afe5f199c14d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -215,7 +215,6 @@ public function testWorkflows() $workflowDefinition->getArgument(0), 'Places are passed to the workflow definition' ); - $this->assertSame(['workflow.definition' => [['name' => 'article', 'type' => 'workflow', 'marking_store' => 'multiple_state', 'single_state' => false]]], $workflowDefinition->getTags()); $this->assertCount(4, $workflowDefinition->getArgument(1)); $this->assertSame('draft', $workflowDefinition->getArgument(2)); @@ -237,7 +236,6 @@ public function testWorkflows() $stateMachineDefinition->getArgument(0), 'Places are passed to the state machine definition' ); - $this->assertSame(['workflow.definition' => [['name' => 'pull_request', 'type' => 'state_machine', 'marking_store' => 'single_state', 'single_state' => false]]], $stateMachineDefinition->getTags()); $this->assertCount(9, $stateMachineDefinition->getArgument(1)); $this->assertSame('start', $stateMachineDefinition->getArgument(2)); @@ -272,6 +270,15 @@ public function testWorkflows() $this->assertGreaterThan(0, \count($registryDefinition->getMethodCalls())); } + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" where found on StateMachine "my_workflow". + */ + public function testWorkflowAreValidated() + { + $this->createContainerFromFile('workflow_not_valid'); + } + /** * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException * @expectedExceptionMessage "type" and "service" cannot be used together. diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php index ec39372b1dcde..19bad8e825a0a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php @@ -56,4 +56,178 @@ public function testAssetPackageCannotHavePathAndUrl() ]); }); } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage A transition from a place/state must have an unique name. Multiple transitions named "a_to_b" from place/state "a" where found on StateMachine "article". + */ + public function testWorkflowValidationStateMachine() + { + $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', [ + 'workflows' => [ + 'article' => [ + 'type' => 'state_machine', + 'supports' => [ + __CLASS__, + ], + 'places' => [ + 'a', + 'b', + 'c', + ], + 'transitions' => [ + 'a_to_b' => [ + 'from' => ['a'], + 'to' => ['b', 'c'], + ], + ], + ], + ], + ]); + }); + } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage The marking store of workflow "article" can not store many places. But the transition "a_to_b" has too many output (2). Only one is accepted. + */ + public function testWorkflowValidationMethodSingle() + { + $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', [ + 'workflows' => [ + 'article' => [ + 'type' => 'workflow', + 'marking_store' => [ + 'type' => 'method', + 'arguments' => [ + true, + ], + ], + 'supports' => [ + __CLASS__, + ], + 'places' => [ + 'a', + 'b', + 'c', + ], + 'transitions' => [ + 'a_to_b' => [ + 'from' => ['a'], + 'to' => ['b', 'c'], + ], + ], + ], + ], + ]); + }); + } + + public function testWorkflowValidationMethodNotSingle() + { + $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', [ + 'workflows' => [ + 'article' => [ + 'type' => 'workflow', + 'marking_store' => [ + 'type' => 'method', + 'arguments' => [ + false, + ], + ], + 'supports' => [ + __CLASS__, + ], + 'places' => [ + 'a', + 'b', + 'c', + ], + 'transitions' => [ + 'a_to_b' => [ + 'from' => ['a'], + 'to' => ['b', 'c'], + ], + ], + ], + ], + ]); + }); + + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); + } + + public function testWorkflowValidationMultipleState() + { + $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', [ + 'workflows' => [ + 'article' => [ + 'type' => 'workflow', + 'marking_store' => [ + 'type' => 'multiple_state', + ], + 'supports' => [ + __CLASS__, + ], + 'places' => [ + 'a', + 'b', + 'c', + ], + 'transitions' => [ + 'a_to_b' => [ + 'from' => ['a'], + 'to' => ['b', 'c'], + ], + ], + ], + ], + ]); + }); + + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); + } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage The marking store of workflow "article" can not store many places. But the transition "a_to_b" has too many output (2). Only one is accepted. + */ + public function testWorkflowValidationSingleState() + { + $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', [ + 'workflows' => [ + 'article' => [ + 'type' => 'workflow', + 'marking_store' => [ + 'type' => 'single_state', + ], + 'supports' => [ + __CLASS__, + ], + 'places' => [ + 'a', + 'b', + 'c', + ], + 'transitions' => [ + 'a_to_b' => [ + 'from' => ['a'], + 'to' => ['b', 'c'], + ], + ], + ], + ], + ]); + }); + + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); + } } diff --git a/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php b/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php index 9294a1a7fb426..3ef4af2580f4b 100644 --- a/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php +++ b/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php @@ -19,6 +19,8 @@ /** * @author Tobias Nyholm + * + * @deprecated since Symfony 4.3 */ class ValidateWorkflowsPass implements CompilerPassInterface { diff --git a/src/Symfony/Component/Workflow/Tests/DependencyInjection/ValidateWorkflowsPassTest.php b/src/Symfony/Component/Workflow/Tests/DependencyInjection/ValidateWorkflowsPassTest.php deleted file mode 100644 index c9cb84024970a..0000000000000 --- a/src/Symfony/Component/Workflow/Tests/DependencyInjection/ValidateWorkflowsPassTest.php +++ /dev/null @@ -1,32 +0,0 @@ -register('definition1', WorkflowDefinition::class) - ->addArgument(['a', 'b', 'c']) - ->addArgument([ - new Definition(Transition::class, ['t1', 'a', 'b']), - new Definition(Transition::class, ['t2', 'a', 'c']), - ]) - ->addTag('workflow.definition', ['name' => 'wf1', 'type' => 'state_machine', 'marking_store' => 'foo']); - - (new ValidateWorkflowsPass())->process($container); - - $workflowDefinition = $container->get('definition1'); - - $this->assertSame(['a' => 'a', 'b' => 'b', 'c' => 'c'], $workflowDefinition->getPlaces()); - $this->assertEquals([new Transition('t1', 'a', 'b'), new Transition('t2', 'a', 'c')], $workflowDefinition->getTransitions()); - } -} From dbe4f8605b66d4b5286037483ee455510d341eb0 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 12 Mar 2019 21:10:42 +0100 Subject: [PATCH 200/495] renamed Client to Browser --- UPGRADE-4.3.md | 6 + UPGRADE-5.0.md | 2 + .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + src/Symfony/Bundle/FrameworkBundle/Client.php | 192 +---- .../FrameworkExtension.php | 4 +- .../Bundle/FrameworkBundle/KernelBrowser.php | 206 +++++ .../FrameworkBundle/Resources/config/test.xml | 2 +- .../FrameworkBundle/Test/WebTestCase.php | 6 +- .../{ClientTest.php => KernelBrowserTest.php} | 10 +- .../Bundle/FrameworkBundle/composer.json | 3 +- .../Component/BrowserKit/AbstractBrowser.php | 739 ++++++++++++++++++ src/Symfony/Component/BrowserKit/CHANGELOG.md | 1 + src/Symfony/Component/BrowserKit/Client.php | 722 +---------------- ...ClientTest.php => AbstractBrowserTest.php} | 20 +- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + src/Symfony/Component/HttpKernel/Client.php | 190 +---- .../HttpKernel/HttpKernelBrowser.php | 204 +++++ .../HttpKernel/Tests/Fixtures/TestClient.php | 4 +- ...ientTest.php => HttpKernelBrowserTest.php} | 16 +- .../Component/HttpKernel/composer.json | 3 +- 20 files changed, 1201 insertions(+), 1131 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php rename src/Symfony/Bundle/FrameworkBundle/Tests/{ClientTest.php => KernelBrowserTest.php} (87%) create mode 100644 src/Symfony/Component/BrowserKit/AbstractBrowser.php rename src/Symfony/Component/BrowserKit/Tests/{ClientTest.php => AbstractBrowserTest.php} (97%) create mode 100644 src/Symfony/Component/HttpKernel/HttpKernelBrowser.php rename src/Symfony/Component/HttpKernel/Tests/{ClientTest.php => HttpKernelBrowserTest.php} (93%) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 5bc2fcc022bb7..a6a4d2e307dc5 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.2 to 4.3 BrowserKit ---------- + * Renamed `Client` to `AbstractBrowser` * Marked `Response` final. * Deprecated `Response::buildHeader()` * Deprecated `Response::getStatus()`, use `Response::getStatusCode()` instead @@ -51,6 +52,11 @@ HttpFoundation * The `FileinfoMimeTypeGuesser` class has been deprecated, use `Symfony\Component\Mime\FileinfoMimeTypeGuesser` instead. +HttpKernel +---------- + + * renamed `Client` to `HttpKernelBrowser` + Messenger --------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 39d1ab4303ab3..1805e312e4744 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -4,6 +4,7 @@ UPGRADE FROM 4.x to 5.0 BrowserKit ---------- + * Removed `Client`, use `AbstractBrowser` instead * Removed the possibility to extend `Response` by making it final. * Removed `Response::buildHeader()` * Removed `Response::getStatus()`, use `Response::getStatusCode()` instead @@ -199,6 +200,7 @@ HttpFoundation HttpKernel ---------- + * Removed `Client`, use `HttpKernelBrowser` instead * The `Kernel::getRootDir()` and the `kernel.root_dir` parameter have been removed * The `KernelInterface::getName()` and the `kernel.name` parameter have been removed * Removed the first and second constructor argument of `ConfigDataCollector` diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 4fc04f0671b62..7ecd3acd76d1d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * renamed `Client` to `KernelBrowser` * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will be mandatory in 5.0. * Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead diff --git a/src/Symfony/Bundle/FrameworkBundle/Client.php b/src/Symfony/Bundle/FrameworkBundle/Client.php index 6473f97584f39..e36f0cac68607 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Client.php +++ b/src/Symfony/Bundle/FrameworkBundle/Client.php @@ -11,196 +11,8 @@ namespace Symfony\Bundle\FrameworkBundle; -use Symfony\Component\BrowserKit\CookieJar; -use Symfony\Component\BrowserKit\History; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Client as BaseClient; -use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\HttpKernel\Profiler\Profile as HttpProfile; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Client::class, KernelBrowser::class), E_USER_DEPRECATED); -/** - * Client simulates a browser and makes requests to a Kernel object. - * - * @author Fabien Potencier - */ -class Client extends BaseClient +class Client extends KernelBrowser { - private $hasPerformedRequest = false; - private $profiler = false; - private $reboot = true; - - /** - * {@inheritdoc} - */ - public function __construct(KernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) - { - parent::__construct($kernel, $server, $history, $cookieJar); - } - - /** - * Returns the container. - * - * @return ContainerInterface|null Returns null when the Kernel has been shutdown or not started yet - */ - public function getContainer() - { - return $this->kernel->getContainer(); - } - - /** - * Returns the kernel. - * - * @return KernelInterface - */ - public function getKernel() - { - return $this->kernel; - } - - /** - * Gets the profile associated with the current Response. - * - * @return HttpProfile|false A Profile instance - */ - public function getProfile() - { - if (!$this->kernel->getContainer()->has('profiler')) { - return false; - } - - return $this->kernel->getContainer()->get('profiler')->loadProfileFromResponse($this->response); - } - - /** - * Enables the profiler for the very next request. - * - * If the profiler is not enabled, the call to this method does nothing. - */ - public function enableProfiler() - { - if ($this->kernel->getContainer()->has('profiler')) { - $this->profiler = true; - } - } - - /** - * Disables kernel reboot between requests. - * - * By default, the Client reboots the Kernel for each request. This method - * allows to keep the same kernel across requests. - */ - public function disableReboot() - { - $this->reboot = false; - } - - /** - * Enables kernel reboot between requests. - */ - public function enableReboot() - { - $this->reboot = true; - } - - /** - * {@inheritdoc} - * - * @param Request $request A Request instance - * - * @return Response A Response instance - */ - protected function doRequest($request) - { - // avoid shutting down the Kernel if no request has been performed yet - // WebTestCase::createClient() boots the Kernel but do not handle a request - if ($this->hasPerformedRequest && $this->reboot) { - $this->kernel->shutdown(); - } else { - $this->hasPerformedRequest = true; - } - - if ($this->profiler) { - $this->profiler = false; - - $this->kernel->boot(); - $this->kernel->getContainer()->get('profiler')->enable(); - } - - return parent::doRequest($request); - } - - /** - * {@inheritdoc} - * - * @param Request $request A Request instance - * - * @return Response A Response instance - */ - protected function doRequestInProcess($request) - { - $response = parent::doRequestInProcess($request); - - $this->profiler = false; - - return $response; - } - - /** - * Returns the script to execute when the request must be insulated. - * - * It assumes that the autoloader is named 'autoload.php' and that it is - * stored in the same directory as the kernel (this is the case for the - * Symfony Standard Edition). If this is not your case, create your own - * client and override this method. - * - * @param Request $request A Request instance - * - * @return string The script content - */ - protected function getScript($request) - { - $kernel = var_export(serialize($this->kernel), true); - $request = var_export(serialize($request), true); - $errorReporting = error_reporting(); - - $requires = ''; - foreach (get_declared_classes() as $class) { - if (0 === strpos($class, 'ComposerAutoloaderInit')) { - $r = new \ReflectionClass($class); - $file = \dirname(\dirname($r->getFileName())).'/autoload.php'; - if (file_exists($file)) { - $requires .= 'require_once '.var_export($file, true).";\n"; - } - } - } - - if (!$requires) { - throw new \RuntimeException('Composer autoloader not found.'); - } - - $requires .= 'require_once '.var_export((new \ReflectionObject($this->kernel))->getFileName(), true).";\n"; - - $profilerCode = ''; - if ($this->profiler) { - $profilerCode = '$kernel->getContainer()->get(\'profiler\')->enable();'; - } - - $code = <<boot(); -$profilerCode - -\$request = unserialize($request); -EOF; - - return $code.$this->getHandleScript(); - } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a38518b2e9229..cb9a06218bee7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -22,7 +22,7 @@ use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader; use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher; use Symfony\Bundle\FullStack; -use Symfony\Component\BrowserKit\Client; +use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; @@ -207,7 +207,7 @@ public function load(array $configs, ContainerBuilder $container) if (!empty($config['test'])) { $loader->load('test.xml'); - if (!class_exists(Client::class)) { + if (!class_exists(AbstractBrowser::class)) { $container->removeDefinition('test.client'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php new file mode 100644 index 0000000000000..b86c1b5c34643 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php @@ -0,0 +1,206 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle; + +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\History; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\HttpKernelBrowser; +use Symfony\Component\HttpKernel\KernelInterface; +use Symfony\Component\HttpKernel\Profiler\Profile as HttpProfile; + +/** + * Client simulates a browser and makes requests to a Kernel object. + * + * @author Fabien Potencier + */ +class KernelBrowser extends HttpKernelBrowser +{ + private $hasPerformedRequest = false; + private $profiler = false; + private $reboot = true; + + /** + * {@inheritdoc} + */ + public function __construct(KernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) + { + parent::__construct($kernel, $server, $history, $cookieJar); + } + + /** + * Returns the container. + * + * @return ContainerInterface|null Returns null when the Kernel has been shutdown or not started yet + */ + public function getContainer() + { + return $this->kernel->getContainer(); + } + + /** + * Returns the kernel. + * + * @return KernelInterface + */ + public function getKernel() + { + return $this->kernel; + } + + /** + * Gets the profile associated with the current Response. + * + * @return HttpProfile|false A Profile instance + */ + public function getProfile() + { + if (!$this->kernel->getContainer()->has('profiler')) { + return false; + } + + return $this->kernel->getContainer()->get('profiler')->loadProfileFromResponse($this->response); + } + + /** + * Enables the profiler for the very next request. + * + * If the profiler is not enabled, the call to this method does nothing. + */ + public function enableProfiler() + { + if ($this->kernel->getContainer()->has('profiler')) { + $this->profiler = true; + } + } + + /** + * Disables kernel reboot between requests. + * + * By default, the Client reboots the Kernel for each request. This method + * allows to keep the same kernel across requests. + */ + public function disableReboot() + { + $this->reboot = false; + } + + /** + * Enables kernel reboot between requests. + */ + public function enableReboot() + { + $this->reboot = true; + } + + /** + * {@inheritdoc} + * + * @param Request $request A Request instance + * + * @return Response A Response instance + */ + protected function doRequest($request) + { + // avoid shutting down the Kernel if no request has been performed yet + // WebTestCase::createClient() boots the Kernel but do not handle a request + if ($this->hasPerformedRequest && $this->reboot) { + $this->kernel->shutdown(); + } else { + $this->hasPerformedRequest = true; + } + + if ($this->profiler) { + $this->profiler = false; + + $this->kernel->boot(); + $this->kernel->getContainer()->get('profiler')->enable(); + } + + return parent::doRequest($request); + } + + /** + * {@inheritdoc} + * + * @param Request $request A Request instance + * + * @return Response A Response instance + */ + protected function doRequestInProcess($request) + { + $response = parent::doRequestInProcess($request); + + $this->profiler = false; + + return $response; + } + + /** + * Returns the script to execute when the request must be insulated. + * + * It assumes that the autoloader is named 'autoload.php' and that it is + * stored in the same directory as the kernel (this is the case for the + * Symfony Standard Edition). If this is not your case, create your own + * client and override this method. + * + * @param Request $request A Request instance + * + * @return string The script content + */ + protected function getScript($request) + { + $kernel = var_export(serialize($this->kernel), true); + $request = var_export(serialize($request), true); + $errorReporting = error_reporting(); + + $requires = ''; + foreach (get_declared_classes() as $class) { + if (0 === strpos($class, 'ComposerAutoloaderInit')) { + $r = new \ReflectionClass($class); + $file = \dirname(\dirname($r->getFileName())).'/autoload.php'; + if (file_exists($file)) { + $requires .= 'require_once '.var_export($file, true).";\n"; + } + } + } + + if (!$requires) { + throw new \RuntimeException('Composer autoloader not found.'); + } + + $requires .= 'require_once '.var_export((new \ReflectionObject($this->kernel))->getFileName(), true).";\n"; + + $profilerCode = ''; + if ($this->profiler) { + $profilerCode = '$kernel->getContainer()->get(\'profiler\')->enable();'; + } + + $code = <<boot(); +$profilerCode + +\$request = unserialize($request); +EOF; + + return $code.$this->getHandleScript(); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/test.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/test.xml index d47bc769d3651..ef571fdbc6748 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/test.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/test.xml @@ -11,7 +11,7 @@ - + %test.client.parameters% diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php index e56e938dd9946..9fc654ae935b8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php @@ -11,7 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Test; -use Symfony\Bundle\FrameworkBundle\Client; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; /** @@ -22,12 +22,12 @@ abstract class WebTestCase extends KernelTestCase { /** - * Creates a Client. + * Creates a KernelBrowser. * * @param array $options An array of options to pass to the createKernel method * @param array $server An array of server parameters * - * @return Client A Client instance + * @return KernelBrowser A KernelBrowser instance */ protected static function createClient(array $options = [], array $server = []) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/ClientTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/KernelBrowserTest.php similarity index 87% rename from src/Symfony/Bundle/FrameworkBundle/Tests/ClientTest.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/KernelBrowserTest.php index ba253d1d1f511..7fb27a63ee720 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/ClientTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/KernelBrowserTest.php @@ -11,18 +11,18 @@ namespace Symfony\Bundle\FrameworkBundle\Tests; -use Symfony\Bundle\FrameworkBundle\Client; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; use Symfony\Bundle\FrameworkBundle\Tests\Functional\WebTestCase; use Symfony\Component\HttpFoundation\Response; -class ClientTest extends WebTestCase +class KernelBrowserTest extends WebTestCase { public function testRebootKernelBetweenRequests() { $mock = $this->getKernelMock(); $mock->expects($this->once())->method('shutdown'); - $client = new Client($mock); + $client = new KernelBrowser($mock); $client->request('GET', '/'); $client->request('GET', '/'); } @@ -32,7 +32,7 @@ public function testDisabledRebootKernel() $mock = $this->getKernelMock(); $mock->expects($this->never())->method('shutdown'); - $client = new Client($mock); + $client = new KernelBrowser($mock); $client->disableReboot(); $client->request('GET', '/'); $client->request('GET', '/'); @@ -43,7 +43,7 @@ public function testEnableRebootKernel() $mock = $this->getKernelMock(); $mock->expects($this->once())->method('shutdown'); - $client = new Client($mock); + $client = new KernelBrowser($mock); $client->disableReboot(); $client->request('GET', '/'); $client->request('GET', '/'); diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 764a0c0d2002f..cdf40d12a21f1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -34,7 +34,7 @@ "doctrine/cache": "~1.0", "fig/link-util": "^1.0", "symfony/asset": "~3.4|~4.0", - "symfony/browser-kit": "~3.4|~4.0", + "symfony/browser-kit": "^4.3", "symfony/console": "~3.4|~4.0", "symfony/css-selector": "~3.4|~4.0", "symfony/dom-crawler": "~3.4|~4.0", @@ -67,6 +67,7 @@ "phpdocumentor/type-resolver": "<0.2.1", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/asset": "<3.4", + "symfony/browser-kit": "<4.3", "symfony/console": "<3.4", "symfony/dotenv": "<4.2", "symfony/form": "<4.3", diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php new file mode 100644 index 0000000000000..fd6dc27a0d4f6 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php @@ -0,0 +1,739 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit; + +use Symfony\Component\BrowserKit\Exception\BadMethodCallException; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Form; +use Symfony\Component\DomCrawler\Link; +use Symfony\Component\Process\PhpProcess; + +/** + * Simulates a browser. + * + * To make the actual request, you need to implement the doRequest() method. + * + * HttpBrowser is an implementation that uses the HttpClient component + * to make real HTTP requests. + * + * If you want to be able to run requests in their own process (insulated flag), + * you need to also implement the getScript() method. + * + * @author Fabien Potencier + */ +abstract class AbstractBrowser +{ + protected $history; + protected $cookieJar; + protected $server = []; + protected $internalRequest; + protected $request; + protected $internalResponse; + protected $response; + protected $crawler; + protected $insulated = false; + protected $redirect; + protected $followRedirects = true; + protected $followMetaRefresh = false; + + private $maxRedirects = -1; + private $redirectCount = 0; + private $redirects = []; + private $isMainRequest = true; + + /** + * @param array $server The server parameters (equivalent of $_SERVER) + * @param History $history A History instance to store the browser history + * @param CookieJar $cookieJar A CookieJar instance to store the cookies + */ + public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + $this->setServerParameters($server); + $this->history = $history ?: new History(); + $this->cookieJar = $cookieJar ?: new CookieJar(); + } + + /** + * Sets whether to automatically follow redirects or not. + * + * @param bool $followRedirect Whether to follow redirects + */ + public function followRedirects($followRedirect = true) + { + $this->followRedirects = (bool) $followRedirect; + } + + /** + * Sets whether to automatically follow meta refresh redirects or not. + */ + public function followMetaRefresh(bool $followMetaRefresh = true) + { + $this->followMetaRefresh = $followMetaRefresh; + } + + /** + * Returns whether client automatically follows redirects or not. + * + * @return bool + */ + public function isFollowingRedirects() + { + return $this->followRedirects; + } + + /** + * Sets the maximum number of redirects that crawler can follow. + * + * @param int $maxRedirects + */ + public function setMaxRedirects($maxRedirects) + { + $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects; + $this->followRedirects = -1 != $this->maxRedirects; + } + + /** + * Returns the maximum number of redirects that crawler can follow. + * + * @return int + */ + public function getMaxRedirects() + { + return $this->maxRedirects; + } + + /** + * Sets the insulated flag. + * + * @param bool $insulated Whether to insulate the requests or not + * + * @throws \RuntimeException When Symfony Process Component is not installed + */ + public function insulate($insulated = true) + { + if ($insulated && !class_exists('Symfony\\Component\\Process\\Process')) { + throw new \LogicException('Unable to isolate requests as the Symfony Process Component is not installed.'); + } + + $this->insulated = (bool) $insulated; + } + + /** + * Sets server parameters. + * + * @param array $server An array of server parameters + */ + public function setServerParameters(array $server) + { + $this->server = array_merge([ + 'HTTP_USER_AGENT' => 'Symfony BrowserKit', + ], $server); + } + + /** + * Sets single server parameter. + * + * @param string $key A key of the parameter + * @param string $value A value of the parameter + */ + public function setServerParameter($key, $value) + { + $this->server[$key] = $value; + } + + /** + * Gets single server parameter for specified key. + * + * @param string $key A key of the parameter to get + * @param string $default A default value when key is undefined + * + * @return string A value of the parameter + */ + public function getServerParameter($key, $default = '') + { + return isset($this->server[$key]) ? $this->server[$key] : $default; + } + + public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler + { + $this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest'); + + try { + return $this->request($method, $uri, $parameters, $files, $server, $content, $changeHistory); + } finally { + unset($this->server['HTTP_X_REQUESTED_WITH']); + } + } + + /** + * Returns the History instance. + * + * @return History A History instance + */ + public function getHistory() + { + return $this->history; + } + + /** + * Returns the CookieJar instance. + * + * @return CookieJar A CookieJar instance + */ + public function getCookieJar() + { + return $this->cookieJar; + } + + /** + * Returns the current Crawler instance. + * + * @return Crawler A Crawler instance + */ + public function getCrawler() + { + if (null === $this->crawler) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->crawler; + } + + /** + * Returns the current BrowserKit Response instance. + * + * @return Response A BrowserKit Response instance + */ + public function getInternalResponse() + { + if (null === $this->internalResponse) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->internalResponse; + } + + /** + * Returns the current origin response instance. + * + * The origin response is the response instance that is returned + * by the code that handles requests. + * + * @return object A response instance + * + * @see doRequest() + */ + public function getResponse() + { + if (null === $this->response) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->response; + } + + /** + * Returns the current BrowserKit Request instance. + * + * @return Request A BrowserKit Request instance + */ + public function getInternalRequest() + { + if (null === $this->internalRequest) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->internalRequest; + } + + /** + * Returns the current origin Request instance. + * + * The origin request is the request instance that is sent + * to the code that handles requests. + * + * @return object A Request instance + * + * @see doRequest() + */ + public function getRequest() + { + if (null === $this->request) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->request; + } + + /** + * Clicks on a given link. + * + * @return Crawler + */ + public function click(Link $link) + { + if ($link instanceof Form) { + return $this->submit($link); + } + + return $this->request($link->getMethod(), $link->getUri()); + } + + /** + * Clicks the first link (or clickable image) that contains the given text. + * + * @param string $linkText The text of the link or the alt attribute of the clickable image + */ + public function clickLink(string $linkText): Crawler + { + if (null === $this->crawler) { + throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->click($this->crawler->selectLink($linkText)->link()); + } + + /** + * Submits a form. + * + * @param Form $form A Form instance + * @param array $values An array of form field values + * @param array $serverParameters An array of server parameters + * + * @return Crawler + */ + public function submit(Form $form, array $values = []/*, array $serverParameters = []*/) + { + if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { + @trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + } + + $form->setValues($values); + $serverParameters = 2 < \func_num_args() ? func_get_arg(2) : []; + + return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles(), $serverParameters); + } + + /** + * Finds the first form that contains a button with the given content and + * uses it to submit the given form field values. + * + * @param string $button The text content, id, value or name of the form
" layout: - * - * use Symfony\Component\Form\Extension\Templating\TemplatingExtension; - * - * $formFactory = Forms::createFormFactoryBuilder() - * ->addExtension(new TemplatingExtension($engine, null, [ - * 'FrameworkBundle:Form', - * 'FrameworkBundle:FormTable', - * ])) - * ->getFormFactory(); - * * @author Bernhard Schussek */ final class Forms diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index fd39d77edc19e..bb3d43077ec3a 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -48,8 +48,7 @@ "suggest": { "symfony/validator": "For form validation.", "symfony/security-csrf": "For protecting forms against CSRF attacks.", - "symfony/twig-bridge": "For templating with Twig.", - "symfony/framework-bundle": "For templating with PHP." + "symfony/twig-bridge": "For templating with Twig." }, "autoload": { "psr-4": { "Symfony\\Component\\Form\\": "" }, diff --git a/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php index 7b8e7619223bd..9a700a9b1158b 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php @@ -59,6 +59,10 @@ public function setTemplating($templating) throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of Twig\Environment or Symfony\Component\Templating\EngineInterface'); } + if ($templating instanceof EngineInterface) { + @trigger_error(sprintf('Using a "%s" instance for "%s" is deprecated since version 4.3; use a \Twig\Environment instance instead.', EngineInterface::class, __CLASS__), E_USER_DEPRECATED); + } + $this->templating = $templating; } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php index 6125d95ff4ca8..f80f5f811a1b6 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php @@ -16,6 +16,8 @@ use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer; use Symfony\Component\HttpKernel\UriSigner; +use Twig\Environment; +use Twig\Loader\ArrayLoader; class HIncludeFragmentRendererTest extends TestCase { @@ -74,29 +76,26 @@ public function testRenderWithAttributesOptions() $this->assertEquals('default', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'id' => 'bar', 'attributes' => ['p1' => 'v1', 'p2' => 'v2']])->getContent()); } - public function testRenderWithDefaultText() + public function testRenderWithTwigAndDefaultText() { - $engine = $this->getMockBuilder('Symfony\\Component\\Templating\\EngineInterface')->getMock(); - $engine->expects($this->once()) - ->method('exists') - ->with('default') - ->willThrowException(new \InvalidArgumentException()); - - // only default - $strategy = new HIncludeFragmentRenderer($engine); - $this->assertEquals('default', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent()); + $twig = new Environment($loader = new ArrayLoader()); + $strategy = new HIncludeFragmentRenderer($twig); + $this->assertEquals('loading...', $strategy->render('/foo', Request::create('/'), ['default' => 'loading...'])->getContent()); } - public function testRenderWithEngineAndDefaultText() + /** + * @group legacy + */ + public function testRenderWithDefaultTextLegacy() { $engine = $this->getMockBuilder('Symfony\\Component\\Templating\\EngineInterface')->getMock(); $engine->expects($this->once()) ->method('exists') - ->with('loading...') - ->willThrowException(new \RuntimeException()); + ->with('default') + ->willThrowException(new \InvalidArgumentException()); // only default $strategy = new HIncludeFragmentRenderer($engine); - $this->assertEquals('loading...', $strategy->render('/foo', Request::create('/'), ['default' => 'loading...'])->getContent()); + $this->assertEquals('default', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent()); } } diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 7cae1e74845fd..998f14f6e6f1b 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -39,7 +39,8 @@ "symfony/templating": "~3.4|~4.0", "symfony/translation": "~4.2", "symfony/var-dumper": "^4.1.1", - "psr/cache": "~1.0" + "psr/cache": "~1.0", + "twig/twig": "^1.34|^2.4" }, "provide": { "psr/log-implementation": "1.0" From 8fd7584158a39a52ed8dfb9f22e1696208a9755f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 19 Mar 2019 10:44:44 +0100 Subject: [PATCH 233/495] [HttpClient] add MockHttpClient --- .../Component/HttpClient/Chunk/ErrorChunk.php | 17 +- .../Component/HttpClient/HttpClientTrait.php | 4 +- .../Component/HttpClient/MockHttpClient.php | 85 ++++++ .../HttpClient/Response/MockResponse.php | 265 ++++++++++++++++++ .../HttpClient/Response/NativeResponse.php | 2 +- .../HttpClient/Response/ResponseTrait.php | 10 +- .../HttpClient/Tests/CurlHttpClientTest.php | 2 +- .../HttpClient/Tests/MockHttpClientTest.php | 130 +++++++++ .../HttpClient/Tests/NativeHttpClientTest.php | 2 +- .../HttpClient/Test/HttpClientTestCase.php | 85 +++--- 10 files changed, 549 insertions(+), 53 deletions(-) create mode 100644 src/Symfony/Component/HttpClient/MockHttpClient.php create mode 100644 src/Symfony/Component/HttpClient/Response/MockResponse.php create mode 100644 src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php diff --git a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php index 0c3f8dfc62bab..5899a9ce7c6bd 100644 --- a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php +++ b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php @@ -21,19 +21,14 @@ */ class ErrorChunk implements ChunkInterface { - protected $didThrow; - + private $didThrow = false; private $offset; private $errorMessage; private $error; - /** - * @param bool &$didThrow Allows monitoring when the $error has been thrown or not - */ - public function __construct(bool &$didThrow, int $offset, \Throwable $error = null) + public function __construct(int $offset, \Throwable $error = null) { $didThrow = false; - $this->didThrow = &$didThrow; $this->offset = $offset; $this->error = $error; $this->errorMessage = null !== $error ? $error->getMessage() : 'Reading from the response stream reached the inactivity timeout.'; @@ -96,6 +91,14 @@ public function getError(): ?string return $this->errorMessage; } + /** + * @return bool Whether the wrapped error has been thrown or not + */ + public function didThrow(): bool + { + return $this->didThrow; + } + public function __destruct() { if (!$this->didThrow) { diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 223eba3e010fc..24bcdee217220 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -117,7 +117,7 @@ private static function prepareRequest(?string $method, ?string $url, array $opt // Finalize normalization of options $options['headers'] = $headers; - $options['http_version'] = (string) ($options['http_version'] ?? ''); + $options['http_version'] = (string) ($options['http_version'] ?? '') ?: null; $options['timeout'] = (float) ($options['timeout'] ?? ini_get('default_socket_timeout')); return [$url, $options]; @@ -128,6 +128,8 @@ private static function prepareRequest(?string $method, ?string $url, array $opt */ private static function mergeDefaultOptions(array $options, array $defaultOptions, bool $allowExtraOptions = false): array { + unset($options['raw_headers'], $defaultOptions['raw_headers']); + $options['headers'] = self::normalizeHeaders($options['headers'] ?? []); if ($defaultOptions['headers'] ?? false) { diff --git a/src/Symfony/Component/HttpClient/MockHttpClient.php b/src/Symfony/Component/HttpClient/MockHttpClient.php new file mode 100644 index 0000000000000..1d3d7b8b68172 --- /dev/null +++ b/src/Symfony/Component/HttpClient/MockHttpClient.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * A test-friendly HttpClient that doesn't make actual HTTP requests. + * + * @author Nicolas Grekas + */ +class MockHttpClient implements HttpClientInterface +{ + use HttpClientTrait; + + private $responseFactory; + private $baseUri; + + /** + * @param callable|ResponseInterface|ResponseInterface[]|iterable $responseFactory + */ + public function __construct($responseFactory, string $baseUri = null) + { + if ($responseFactory instanceof ResponseInterface) { + $responseFactory = [$responseFactory]; + } + + if (!\is_callable($responseFactory) && !$responseFactory instanceof \Iterator) { + $responseFactory = (function () use ($responseFactory) { + yield from $responseFactory; + })(); + } + + $this->responseFactory = $responseFactory; + $this->baseUri = $baseUri; + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = $this->prepareRequest($method, $url, $options, ['base_uri' => $this->baseUri], true); + $url = implode('', $url); + + if (\is_callable($this->responseFactory)) { + $response = ($this->responseFactory)($method, $url, $options); + } elseif (!$this->responseFactory->valid()) { + throw new TransportException('The response factory iterator passed to MockHttpClient is empty.'); + } else { + $response = $this->responseFactory->current(); + $this->responseFactory->next(); + } + + return MockResponse::fromRequest($method, $url, $options, $response); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof ResponseInterface) { + $responses = [$responses]; + } elseif (!\is_iterable($responses)) { + throw new \TypeError(sprintf('%s() expects parameter 1 to be an iterable of MockResponse objects, %s given.', __METHOD__, \is_object($responses) ? \get_class($responses) : \gettype($responses))); + } + + return new ResponseStream(MockResponse::stream($responses, $timeout)); + } +} diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php new file mode 100644 index 0000000000000..4d0bc43ea4d15 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -0,0 +1,265 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Response; + +use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * A test-friendly response. + * + * @author Nicolas Grekas + */ +class MockResponse implements ResponseInterface +{ + use ResponseTrait; + + private $body; + + private static $mainMulti; + private static $idSequence = 0; + + /** + * @param string|string[]|iterable $body The response body as a string or an iterable of strings, + * yielding an empty string simulates a timeout, + * exceptions are turned to TransportException + * + * @see ResponseInterface::getInfo() for possible info, e.g. "raw_headers" + */ + public function __construct($body = '', array $info = []) + { + $this->body = \is_iterable($body) ? $body : (string) $body; + $this->info = $info + $this->info; + } + + /** + * {@inheritdoc} + */ + public function getInfo(string $type = null) + { + return null !== $type ? $this->info[$type] ?? null : $this->info; + } + + /** + * {@inheritdoc} + */ + protected function close(): void + { + $this->body = []; + } + + /** + * @internal + */ + public static function fromRequest(string $method, string $url, array $options, ResponseInterface $mock): self + { + $response = new self([]); + $response->id = ++self::$idSequence; + $response->content = ($options['buffer'] ?? true) ? fopen('php://temp', 'w+') : null; + $response->initializer = static function (self $response) { + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + + if (\is_array($response->body[0] ?? null)) { + // Consume the first chunk if it's not yielded yet + self::stream([$response])->current(); + } + }; + + $response->info['redirect_count'] = 0; + $response->info['redirect_url'] = null; + $response->info['start_time'] = microtime(true); + $response->info['http_method'] = $method; + $response->info['http_code'] = 0; + $response->info['user_data'] = $options['user_data'] ?? null; + $response->info['url'] = $url; + + self::writeRequest($response, $options, $mock); + $response->body[] = [$options, $mock]; + + return $response; + } + + /** + * {@inheritdoc} + */ + protected static function schedule(self $response, array &$runningResponses): void + { + if (!$response->id) { + throw new InvalidArgumentException('MockResponse instances must be issued by MockHttpClient before processing.'); + } + + $multi = self::$mainMulti ?? self::$mainMulti = (object) [ + 'handlesActivity' => [], + 'openHandles' => [], + ]; + + if (!isset($runningResponses[0])) { + $runningResponses[0] = [$multi, []]; + } + + $runningResponses[0][1][$response->id] = $response; + } + + /** + * {@inheritdoc} + */ + protected static function perform(\stdClass $multi, array &$responses): void + { + foreach ($responses as $response) { + $id = $response->id; + + if (!$response->body) { + // Last chunk + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = null !== $response->info['error'] ? new TransportException($response->info['error']) : null; + } elseif (null === $chunk = array_shift($response->body)) { + // Last chunk + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = array_shift($response->body); + } elseif (\is_array($chunk)) { + // First chunk + try { + $offset = 0; + $chunk[1]->getStatusCode(); + $response->headers = $chunk[1]->getHeaders(false); + $multi->handlesActivity[$id][] = new FirstChunk(); + self::readResponse($response, $chunk[0], $chunk[1], $offset); + } catch (\Throwable $e) { + $multi->handlesActivity[$id][] = null; + $multi->handlesActivity[$id][] = $e; + } + } else { + // Data or timeout chunk + $multi->handlesActivity[$id][] = $chunk; + + if (\is_string($chunk) && null !== $response->content) { + // Buffer response body + fwrite($response->content, $chunk); + } + } + } + } + + /** + * {@inheritdoc} + */ + protected static function select(\stdClass $multi, float $timeout): int + { + return 42; + } + + /** + * Simulates sending the request. + */ + private static function writeRequest(self $response, array $options, ResponseInterface $mock) + { + $onProgress = $options['on_progress'] ?? static function () {}; + $response->info += $mock->getInfo() ?: []; + + // simulate "size_upload" if it is set + if (isset($response->info['size_upload'])) { + $response->info['size_upload'] = 0.0; + } + + // simulate "total_time" if it is set + if (isset($response->info['total_time'])) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + } + + // "notify" DNS resolution + $onProgress(0, 0, $response->info); + + // consume the request body + if (\is_resource($body = $options['body'] ?? '')) { + $data = stream_get_contents($body); + if (isset($response->info['size_upload'])) { + $response->info['size_upload'] += \strlen($data); + } + } elseif ($body instanceof \Closure) { + while ('' !== $data = $body(16372)) { + if (!\is_string($data)) { + throw new TransportException(sprintf('Return value of the "body" option callback must be string, %s returned.', \gettype($data))); + } + + // "notify" upload progress + if (isset($response->info['size_upload'])) { + $response->info['size_upload'] += \strlen($data); + } + + $onProgress(0, 0, $response->info); + } + } + } + + /** + * Simulates reading the response. + */ + private static function readResponse(self $response, array $options, ResponseInterface $mock, int &$offset) + { + $onProgress = $options['on_progress'] ?? static function () {}; + + // populate info related to headers + $info = $mock->getInfo() ?: []; + $response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode(false) ?: 200; + $response->addRawHeaders($info['raw_headers'] ?? [], $response->info, $response->headers); + $dlSize = (int) ($response->headers['content-length'][0] ?? 0); + + $response->info = [ + 'start_time' => $response->info['start_time'], + 'user_data' => $response->info['user_data'], + 'http_code' => $response->info['http_code'], + ] + $info + $response->info; + + if (isset($response->info['total_time'])) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + } + + // "notify" headers arrival + $onProgress(0, $dlSize, $response->info); + + // cast response body to activity list + $body = $mock instanceof self ? $mock->body : $mock->getContent(false); + + if (!\is_string($body)) { + foreach ($body as $chunk) { + if ('' === $chunk = (string) $chunk) { + // simulate a timeout + $response->body[] = new ErrorChunk($offset); + } else { + $response->body[] = $chunk; + $offset += \strlen($chunk); + // "notify" download progress + $onProgress($offset, $dlSize, $response->info); + } + } + } elseif ('' !== $body) { + $response->body[] = $body; + $offset = \strlen($body); + } + + if (isset($response->info['total_time'])) { + $response->info['total_time'] = microtime(true) - $response->info['start_time']; + } + + // "notify" completion + $onProgress($offset, $dlSize, $response->info); + + if (isset($response->headers['content-length']) && $offset !== $dlSize) { + throw new TransportException(sprintf('Transfer closed with %s bytes remaining to read.', $dlSize - $offset)); + } + } +} diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index f210e754404fd..4071a9f9185e0 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -147,7 +147,7 @@ private function open(): void $this->inflate = null; } - $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, &$this->content, $this->onProgress, &$this->remaining, &$this->info]; + $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, $this->content, $this->onProgress, &$this->remaining, &$this->info]; $this->multi->handlesActivity[$this->id] = [new FirstChunk()]; } diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 381bab5dc30fd..7429547293303 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -259,9 +259,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene foreach ($responses as $j => $response) { $timeoutMax = $timeout ?? max($timeoutMax, $response->timeout); $timeoutMin = min($timeoutMin, $response->timeout, 1); - // ErrorChunk instances will set $didThrow to true when the - // exception they wrap has been thrown after yielding - $chunk = $didThrow = false; + $chunk = false; if (isset($multi->handlesActivity[$j])) { // no-op @@ -269,7 +267,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene unset($responses[$j]); continue; } elseif ($isTimeout) { - $multi->handlesActivity[$j] = [new ErrorChunk($didThrow, $response->offset)]; + $multi->handlesActivity[$j] = [new ErrorChunk($response->offset)]; } else { continue; } @@ -293,7 +291,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene throw $e; } - $chunk = new ErrorChunk($didThrow, $response->offset, $e); + $chunk = new ErrorChunk($response->offset, $e); } else { $chunk = new LastChunk($response->offset); } @@ -310,7 +308,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene if ($chunk instanceof FirstChunk && null === $response->initializer) { // Ensure the HTTP status code is always checked $response->getHeaders(true); - } elseif ($chunk instanceof ErrorChunk && !$didThrow) { + } elseif ($chunk instanceof ErrorChunk && !$chunk->didThrow()) { // Ensure transport exceptions are always thrown $chunk->getContent(); } diff --git a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php index 7c51d42236201..476dc729762f1 100644 --- a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php @@ -20,7 +20,7 @@ */ class CurlHttpClientTest extends HttpClientTestCase { - protected function getHttpClient(): HttpClientInterface + protected function getHttpClient(string $testCase): HttpClientInterface { return new CurlHttpClient(); } diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php new file mode 100644 index 0000000000000..1484526e18cf9 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -0,0 +1,130 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\NativeHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; + +class MockHttpClientTest extends HttpClientTestCase +{ + protected function getHttpClient(string $testCase): HttpClientInterface + { + $responses = []; + + $headers = [ + 'Host: localhost:8057', + 'Content-Type: application/json', + ]; + + $body = '{ + "SERVER_PROTOCOL": "HTTP/1.1", + "SERVER_NAME": "127.0.0.1", + "REQUEST_URI": "/", + "REQUEST_METHOD": "GET", + "HTTP_FOO": "baR", + "HTTP_HOST": "localhost:8057" + }'; + + $client = new NativeHttpClient(); + + switch ($testCase) { + default: + return new MockHttpClient(function (string $method, string $url, array $options) use ($client) { + try { + // force the request to be completed so that we don't test side effects of the transport + $response = $client->request($method, $url, $options); + $content = $response->getContent(false); + + return new MockResponse($content, $response->getInfo()); + } catch (\Throwable $e) { + $this->fail($e->getMessage()); + } + }); + + case 'testUnsupportedOption': + $this->markTestSkipped('MockHttpClient accepts any options by default'); + break; + + case 'testChunkedEncoding': + $this->markTestSkipped("MockHttpClient doesn't dechunk"); + break; + + case 'testGzipBroken': + $this->markTestSkipped("MockHttpClient doesn't unzip"); + break; + + case 'testDestruct': + $this->markTestSkipped("MockHttpClient doesn't timeout on destruct"); + break; + + case 'testGetRequest': + array_unshift($headers, 'HTTP/1.1 200 OK'); + $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + + $headers = [ + 'Host: localhost:8057', + 'Content-Length: 1000', + 'Content-Type: application/json', + ]; + + $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + break; + + case 'testDnsError': + $mock = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mock->expects($this->any()) + ->method('getStatusCode') + ->willThrowException(new TransportException('DSN error')); + $mock->expects($this->any()) + ->method('getInfo') + ->willReturn([]); + + $responses[] = $mock; + $responses[] = $mock; + break; + + case 'testBadRequestBody': + case 'testOnProgressCancel': + case 'testOnProgressError': + $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + break; + + case 'testTimeoutOnAccess': + $mock = $this->getMockBuilder(ResponseInterface::class)->getMock(); + $mock->expects($this->any()) + ->method('getHeaders') + ->willThrowException(new TransportException('Timeout')); + + $responses[] = $mock; + break; + + case 'testResolve': + $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = $client->request('GET', 'http://symfony.com:8057/'); + break; + + case 'testTimeoutOnStream': + case 'testUncheckedTimeoutThrows': + $body = ['<1>', '', '<2>']; + $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + break; + } + + return new MockHttpClient($responses); + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php index d2af0584f9edb..783167791dd60 100644 --- a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php @@ -17,7 +17,7 @@ class NativeHttpClientTest extends HttpClientTestCase { - protected function getHttpClient(): HttpClientInterface + protected function getHttpClient(string $testCase): HttpClientInterface { return new NativeHttpClient(); } diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 9c98d5bb32f34..400f8dc6b2e8e 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -31,11 +31,11 @@ public static function setUpBeforeClass() TestHttpServer::start(); } - abstract protected function getHttpClient(): HttpClientInterface; + abstract protected function getHttpClient(string $testCase): HttpClientInterface; public function testGetRequest() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057', [ 'headers' => ['Foo' => 'baR'], 'user_data' => $data = new \stdClass(), @@ -74,7 +74,7 @@ public function testGetRequest() public function testNonBufferedGetRequest() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057', [ 'buffer' => false, 'headers' => ['Foo' => 'baR'], @@ -89,7 +89,7 @@ public function testNonBufferedGetRequest() public function testUnsupportedOption() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $this->expectException(\InvalidArgumentException::class); $client->request('GET', 'http://localhost:8057', [ @@ -99,7 +99,7 @@ public function testUnsupportedOption() public function testHttpVersion() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057', [ 'http_version' => 1.0, ]); @@ -116,7 +116,7 @@ public function testHttpVersion() public function testChunkedEncoding() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/chunked'); $this->assertSame(['chunked'], $response->getHeaders()['transfer-encoding']); @@ -130,7 +130,7 @@ public function testChunkedEncoding() public function testClientError() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/404'); $client->stream($response)->valid(); @@ -156,7 +156,7 @@ public function testClientError() public function testIgnoreErrors() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/404'); $this->assertSame(404, $response->getStatusCode()); @@ -164,7 +164,7 @@ public function testIgnoreErrors() public function testDnsError() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); try { @@ -201,7 +201,7 @@ public function testDnsError() public function testInlineAuth() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057'); $body = $response->toArray(); @@ -210,9 +210,22 @@ public function testInlineAuth() $this->assertSame('bar=bar', $body['PHP_AUTH_PW']); } + public function testBadRequestBody() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(TransportExceptionInterface::class); + + $response = $client->request('POST', 'http://localhost:8057/', [ + 'body' => function () { yield []; }, + ]); + + $response->getStatusCode(); + } + public function testRedirects() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/301', [ 'auth_basic' => 'foo:bar', 'body' => function () { @@ -248,7 +261,7 @@ public function testRedirects() public function testRelativeRedirects() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/302/relative'); $body = $response->toArray(); @@ -266,7 +279,7 @@ public function testRelativeRedirects() public function testRedirect307() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/307', [ 'body' => function () { @@ -288,7 +301,7 @@ public function testRedirect307() public function testMaxRedirects() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/301', [ 'max_redirects' => 1, 'auth_basic' => 'foo:bar', @@ -322,7 +335,7 @@ public function testMaxRedirects() public function testStream() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057'); $chunks = $client->stream($response); @@ -354,7 +367,7 @@ public function testStream() public function testAddToStream() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $r1 = $client->request('GET', 'http://localhost:8057'); @@ -385,7 +398,7 @@ public function testAddToStream() public function testCompleteTypeError() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $this->expectException(\TypeError::class); $client->stream(123); @@ -393,7 +406,7 @@ public function testCompleteTypeError() public function testOnProgress() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/post', [ 'headers' => ['Content-Length' => 14], 'body' => 'foo=0123456789', @@ -411,7 +424,7 @@ public function testOnProgress() public function testPostJson() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/post', [ 'json' => ['foo' => 'bar'], @@ -426,7 +439,7 @@ public function testPostJson() public function testPostArray() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/post', [ 'body' => ['foo' => 'bar'], @@ -437,7 +450,7 @@ public function testPostArray() public function testPostResource() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $h = fopen('php://temp', 'w+'); fwrite($h, 'foo=0123456789'); @@ -454,7 +467,7 @@ public function testPostResource() public function testPostCallback() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('POST', 'http://localhost:8057/post', [ 'body' => function () { @@ -470,7 +483,7 @@ public function testPostCallback() public function testOnProgressCancel() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ 'on_progress' => function ($dlNow) { if (0 < $dlNow) { @@ -494,7 +507,7 @@ public function testOnProgressCancel() public function testOnProgressError() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ 'on_progress' => function ($dlNow) { if (0 < $dlNow) { @@ -518,7 +531,7 @@ public function testOnProgressError() public function testResolve() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://symfony.com:8057/', [ 'resolve' => ['symfony.com' => '127.0.0.1'], ]); @@ -533,7 +546,7 @@ public function testResolve() public function testTimeoutOnAccess() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/timeout-header', [ 'timeout' => 0.1, ]); @@ -545,7 +558,7 @@ public function testTimeoutOnAccess() public function testTimeoutOnStream() { usleep(300000); // wait for the previous test to release the server - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/timeout-body'); $this->assertSame(200, $response->getStatusCode()); @@ -577,7 +590,7 @@ public function testTimeoutOnStream() public function testUncheckedTimeoutThrows() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/timeout-body'); $chunks = $client->stream([$response], 0.1); @@ -589,7 +602,7 @@ public function testUncheckedTimeoutThrows() public function testDestruct() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $downloaded = 0; $start = microtime(true); @@ -603,7 +616,7 @@ public function testDestruct() public function testProxy() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/', [ 'proxy' => 'http://localhost:8057', ]); @@ -625,7 +638,7 @@ public function testNoProxy() putenv('no_proxy='.$_SERVER['no_proxy'] = 'example.com, localhost'); try { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/', [ 'proxy' => 'http://localhost:8057', ]); @@ -646,7 +659,7 @@ public function testNoProxy() */ public function testAutoEncodingRequest() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057'); $this->assertSame(200, $response->getStatusCode()); @@ -663,7 +676,7 @@ public function testAutoEncodingRequest() public function testBaseUri() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', '../404', [ 'base_uri' => 'http://localhost:8057/abc/', ]); @@ -674,7 +687,7 @@ public function testBaseUri() public function testQuery() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/?a=a', [ 'query' => ['b' => 'b'], ]); @@ -689,7 +702,7 @@ public function testQuery() */ public function testUserlandEncodingRequest() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057', [ 'headers' => ['Accept-Encoding' => 'gzip'], ]); @@ -711,7 +724,7 @@ public function testUserlandEncodingRequest() */ public function testGzipBroken() { - $client = $this->getHttpClient(); + $client = $this->getHttpClient(__FUNCTION__); $response = $client->request('GET', 'http://localhost:8057/gzip-broken'); $this->expectException(TransportExceptionInterface::class); From 10afb99e3f65f43cec02a0d01b83f8de95a0f007 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 19 Mar 2019 22:04:09 +0100 Subject: [PATCH 234/495] throw TypeErrors to prepare for type hints in 5.0 --- .../Component/Serializer/Normalizer/DataUriNormalizer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php index 8c646a9761d20..3ab7bd45f8882 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php @@ -53,7 +53,7 @@ public function __construct($mimeTypeGuesser = null) $mimeTypeGuesser = MimeTypeGuesser::getInstance(); } } elseif (!$mimeTypeGuesser instanceof MimeTypes) { - throw new \InvalidArgumentException(sprintf('Argument 1 passed to "%s()" must be an instance of "%s" or null, %s given.', __METHOD__, MimeTypes::class, \is_object($mimeTypeGuesser) ? \get_class($mimeTypeGuesser) : \gettype($mimeTypeGuesser))); + throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be an instance of "%s" or null, %s given.', __METHOD__, MimeTypes::class, \is_object($mimeTypeGuesser) ? \get_class($mimeTypeGuesser) : \gettype($mimeTypeGuesser))); } $this->mimeTypeGuesser = $mimeTypeGuesser; From 3378f5e9a1aa17b13f6655d4f099d20dde33222f Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 19 Mar 2019 22:30:37 +0100 Subject: [PATCH 235/495] fix max host connections option for XML configs --- .../Resources/config/schema/symfony-1.0.xsd | 1 + .../Fixtures/php/http_client_override_default_options.php | 2 ++ .../Fixtures/xml/http_client_override_default_options.xml | 4 ++-- .../Fixtures/yml/http_client_override_default_options.yml | 2 ++ .../Tests/DependencyInjection/FrameworkExtensionTest.php | 8 +++++--- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index c1242a1e08a92..98baeb978b440 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -486,6 +486,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php index 5482f2903e6c9..26b76359da3fb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php @@ -2,11 +2,13 @@ $container->loadFromExtension('framework', [ 'http_client' => [ + 'max_host_connections' => 4, 'default_options' => [ 'headers' => ['foo' => 'bar'], ], 'clients' => [ 'foo' => [ + 'max_host_connections' => 5, 'default_options' => [ 'headers' => ['bar' => 'baz'], ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml index 33c201ef9f6e1..085b4721cc7d8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml @@ -6,11 +6,11 @@ http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + bar - + baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml index 37516441720a3..9a3d69e3585b4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml @@ -1,8 +1,10 @@ framework: http_client: + max_host_connections: 4 default_options: headers: {'foo': 'bar'} clients: foo: + max_host_connections: 5 default_options: headers: {'bar': 'baz'} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 0e6eff1e1076c..5c0352b2658da 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -1389,15 +1389,17 @@ public function testHttpClientOverrideDefaultOptions() { $container = $this->createContainerFromFile('http_client_override_default_options'); - $this->assertSame(['foo' => ['bar']], $container->getDefinition('http_client')->getArguments()[0]['headers']); - $this->assertSame(['bar' => ['baz'], 'foo' => ['bar']], $container->getDefinition('foo')->getArguments()[0]['headers']); + $this->assertSame(['foo' => ['bar']], $container->getDefinition('http_client')->getArgument(0)['headers']); + $this->assertSame(4, $container->getDefinition('http_client')->getArgument(1)); + $this->assertSame(['bar' => ['baz'], 'foo' => ['bar']], $container->getDefinition('foo')->getArgument(0)['headers']); + $this->assertSame(5, $container->getDefinition('foo')->getArgument(1)); } public function testHttpClientFullDefaultOptions() { $container = $this->createContainerFromFile('http_client_full_default_options'); - $defaultOptions = $container->getDefinition('http_client')->getArguments()[0]; + $defaultOptions = $container->getDefinition('http_client')->getArgument(0); $this->assertSame('foo:bar', $defaultOptions['auth_basic']); $this->assertSame(['foo' => 'bar', 'bar' => 'baz'], $defaultOptions['query']); From 7e2852dd4466e7de83e80d746fb5e07584e4b221 Mon Sep 17 00:00:00 2001 From: Alex Vasilchenko Date: Tue, 19 Mar 2019 17:56:40 +0200 Subject: [PATCH 236/495] [Cache] added DSN support for rediss in AbstractAdapter and RedisTrait --- .../Cache/Adapter/AbstractAdapter.php | 2 +- .../Cache/Tests/Adapter/RedisAdapterTest.php | 25 +++++++++++++------ .../Component/Cache/Traits/RedisTrait.php | 10 +++++--- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 6897fbceee530..011a239bf6ac1 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -132,7 +132,7 @@ public static function createConnection($dsn, array $options = []) if (!\is_string($dsn)) { throw new InvalidArgumentException(sprintf('The %s() method expect argument #1 to be string, %s given.', __METHOD__, \gettype($dsn))); } - if (0 === strpos($dsn, 'redis:')) { + if (0 === strpos($dsn, 'redis:') || 0 === strpos($dsn, 'rediss:')) { return RedisAdapter::createConnection($dsn, $options); } if (0 === strpos($dsn, 'memcached:')) { diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php index c83abaf91bce1..4d9bc319ebd53 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php @@ -31,30 +31,33 @@ public function createCachePool($defaultLifetime = 0) return $adapter; } - public function testCreateConnection() + /** + * @dataProvider provideValidSchemes + */ + public function testCreateConnection($dsnScheme) { - $redis = RedisAdapter::createConnection('redis:?host[h1]&host[h2]&host[/foo:]'); + $redis = RedisAdapter::createConnection($dsnScheme.':?host[h1]&host[h2]&host[/foo:]'); $this->assertInstanceOf(\RedisArray::class, $redis); $this->assertSame(['h1:6379', 'h2:6379', '/foo'], $redis->_hosts()); @$redis = null; // some versions of phpredis connect on destruct, let's silence the warning $redisHost = getenv('REDIS_HOST'); - $redis = RedisAdapter::createConnection('redis://'.$redisHost); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost); $this->assertInstanceOf(\Redis::class, $redis); $this->assertTrue($redis->isConnected()); $this->assertSame(0, $redis->getDbNum()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'/2'); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost.'/2'); $this->assertSame(2, $redis->getDbNum()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['timeout' => 3]); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost, ['timeout' => 3]); $this->assertEquals(3, $redis->getTimeout()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'?timeout=4'); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost.'?timeout=4'); $this->assertEquals(4, $redis->getTimeout()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['read_timeout' => 5]); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost, ['read_timeout' => 5]); $this->assertEquals(5, $redis->getReadTimeout()); } @@ -87,6 +90,14 @@ public function testInvalidCreateConnection($dsn) RedisAdapter::createConnection($dsn); } + public function provideValidSchemes() + { + return [ + ['redis'], + ['rediss'], + ]; + } + public function provideInvalidCreateConnection() { return [ diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 350a54360e6cd..0b79a7d1adb30 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -80,15 +80,19 @@ private function init($redisClient, $namespace, $defaultLifetime, ?MarshallerInt */ public static function createConnection($dsn, array $options = []) { - if (0 !== strpos($dsn, 'redis:')) { - throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis:".', $dsn)); + if (0 === strpos($dsn, 'redis:')) { + $scheme = 'redis'; + } elseif (0 === strpos($dsn, 'rediss:')) { + $scheme = 'rediss'; + } else { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis:" or "rediss".', $dsn)); } if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { throw new CacheException(sprintf('Cannot find the "redis" extension nor the "predis/predis" package: %s', $dsn)); } - $params = preg_replace_callback('#^redis:(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { + $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { if (isset($m[2])) { $auth = $m[2]; } From 2911490c80d265e69b81c8342e79dcc03b56a3d4 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sun, 10 Mar 2019 17:53:50 +0100 Subject: [PATCH 237/495] [Routing] Exposed "utf8" option, defaults "locale" and "format" in configuration --- .../Component/Routing/Annotation/Route.php | 18 +++++ src/Symfony/Component/Routing/CHANGELOG.md | 1 + .../Loader/Configurator/Traits/RouteTrait.php | 36 +++++++++ .../Routing/Loader/XmlFileLoader.php | 10 +++ .../Routing/Loader/YamlFileLoader.php | 20 ++++- .../Loader/schema/routing/routing-1.0.xsd | 6 ++ .../GlobalDefaultsClass.php | 34 ++++++++ .../Utf8ActionControllers.php | 25 ++++++ .../Routing/Tests/Fixtures/defaults.php | 10 +++ .../Routing/Tests/Fixtures/defaults.xml | 8 ++ .../Routing/Tests/Fixtures/defaults.yml | 4 + .../Tests/Fixtures/imported-with-defaults.php | 10 +++ .../Tests/Fixtures/imported-with-defaults.xml | 11 +++ .../Tests/Fixtures/imported-with-defaults.yml | 7 ++ .../Tests/Fixtures/importer-with-defaults.php | 11 +++ .../Tests/Fixtures/importer-with-defaults.xml | 10 +++ .../Tests/Fixtures/importer-with-defaults.yml | 5 ++ .../Fixtures/localized/imported-with-utf8.php | 10 +++ .../Fixtures/localized/imported-with-utf8.xml | 8 ++ .../Fixtures/localized/imported-with-utf8.yml | 5 ++ .../Fixtures/localized/importer-with-utf8.php | 7 ++ .../Fixtures/localized/importer-with-utf8.xml | 7 ++ .../Fixtures/localized/importer-with-utf8.yml | 3 + .../Routing/Tests/Fixtures/localized/utf8.php | 10 +++ .../Routing/Tests/Fixtures/localized/utf8.yml | 6 ++ .../Loader/AnnotationClassLoaderTest.php | 28 +++++++ .../Tests/Loader/PhpFileLoaderTest.php | 74 +++++++++++++++++ .../Tests/Loader/XmlFileLoaderTest.php | 80 ++++++++++++++++--- .../Tests/Loader/YamlFileLoaderTest.php | 76 ++++++++++++++++++ src/Symfony/Component/Routing/composer.json | 2 +- 30 files changed, 529 insertions(+), 13 deletions(-) create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/GlobalDefaultsClass.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/Utf8ActionControllers.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/defaults.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.xml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.yml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.xml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.yml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.xml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.yml create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.php create mode 100644 src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.yml diff --git a/src/Symfony/Component/Routing/Annotation/Route.php b/src/Symfony/Component/Routing/Annotation/Route.php index f9e1ddcae0bb7..4d5f618115591 100644 --- a/src/Symfony/Component/Routing/Annotation/Route.php +++ b/src/Symfony/Component/Routing/Annotation/Route.php @@ -31,6 +31,9 @@ class Route private $methods = []; private $schemes = []; private $condition; + private $locale; + private $format; + private $utf8; /** * @param array $data An array of key/value parameters @@ -53,6 +56,21 @@ public function __construct(array $data) unset($data['path']); } + if (isset($data['locale'])) { + $data['defaults']['_locale'] = $data['locale']; + unset($data['locale']); + } + + if (isset($data['format'])) { + $data['defaults']['_format'] = $data['format']; + unset($data['format']); + } + + if (isset($data['utf8'])) { + $data['options']['utf8'] = filter_var($data['utf8'], FILTER_VALIDATE_BOOLEAN) ?: false; + unset($data['utf8']); + } + foreach ($data as $key => $value) { $method = 'set'.str_replace('_', '', $key); if (!method_exists($this, $method)) { diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 4a5fba5cb4609..73c6dd4dccbcc 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -10,6 +10,7 @@ CHANGELOG * deprecated `generator_base_class`, `generator_cache_class`, `matcher_base_class` and `matcher_cache_class` router options * deprecated implementing `Serializable` for `Route` and `CompiledRoute`; if you serialize them, please ensure your unserialization logic can recover from a failure related to an updated serialization format + * exposed `utf8` Route option, defaults "locale" and "format" in configuration loaders and configurators 4.2.0 ----- diff --git a/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php b/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php index 4fe5a0d60eea7..92c4d2ffdcccf 100644 --- a/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php +++ b/src/Symfony/Component/Routing/Loader/Configurator/Traits/RouteTrait.php @@ -57,6 +57,18 @@ final public function options(array $options) return $this; } + /** + * Whether paths should accept utf8 encoding. + * + * @return $this + */ + final public function utf8(bool $utf8 = true) + { + $this->route->addOptions(['utf8' => $utf8]); + + return $this; + } + /** * Sets the condition. * @@ -124,4 +136,28 @@ final public function controller($controller) return $this; } + + /** + * Adds the "_locale" entry to defaults. + * + * @return $this + */ + final public function locale(string $locale) + { + $this->route->addDefaults(['_locale' => $locale]); + + return $this; + } + + /** + * Adds the "_format" entry to defaults. + * + * @return $this + */ + final public function format(string $format) + { + $this->route->addDefaults(['_format' => $format]); + + return $this; + } } diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index 0632a17823024..7a2cbb94b48f3 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php @@ -168,6 +168,7 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, $ $this->setCurrentDir(\dirname($path)); + /** @var RouteCollection[] $imported */ $imported = $this->import($resource, ('' !== $type ? $type : null), false, $file); if (!\is_array($imported)) { @@ -312,6 +313,15 @@ private function parseConfigs(\DOMElement $node, $path) $defaults['_controller'] = $controller; } + if ($node->hasAttribute('locale')) { + $defaults['_locale'] = $node->getAttribute('locale'); + } + if ($node->hasAttribute('format')) { + $defaults['_format'] = $node->getAttribute('format'); + } + if ($node->hasAttribute('utf8')) { + $options['utf8'] = XmlUtils::phpize($node->getAttribute('utf8')); + } return [$defaults, $requirements, $options, $condition, $paths, $prefixes]; } diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php index dad46b3243375..15c223ecadcf4 100644 --- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php @@ -28,7 +28,7 @@ class YamlFileLoader extends FileLoader { private static $availableKeys = [ - 'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', + 'resource', 'type', 'prefix', 'path', 'host', 'schemes', 'methods', 'defaults', 'requirements', 'options', 'condition', 'controller', 'name_prefix', 'trailing_slash_on_root', 'locale', 'format', 'utf8', ]; private $yamlParser; @@ -125,6 +125,15 @@ protected function parseRoute(RouteCollection $collection, $name, array $config, if (isset($config['controller'])) { $defaults['_controller'] = $config['controller']; } + if (isset($config['locale'])) { + $defaults['_locale'] = $config['locale']; + } + if (isset($config['format'])) { + $defaults['_format'] = $config['format']; + } + if (isset($config['utf8'])) { + $options['utf8'] = $config['utf8']; + } if (\is_array($config['path'])) { $route = new Route('', $defaults, $requirements, $options, $host, $schemes, $methods, $condition); @@ -166,6 +175,15 @@ protected function parseImport(RouteCollection $collection, array $config, $path if (isset($config['controller'])) { $defaults['_controller'] = $config['controller']; } + if (isset($config['locale'])) { + $defaults['_locale'] = $config['locale']; + } + if (isset($config['format'])) { + $defaults['_format'] = $config['format']; + } + if (isset($config['utf8'])) { + $options['utf8'] = $config['utf8']; + } $this->setCurrentDir(\dirname($path)); diff --git a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd index 1ea4651c3ac2b..ebf6632a57269 100644 --- a/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd +++ b/src/Symfony/Component/Routing/Loader/schema/routing/routing-1.0.xsd @@ -52,6 +52,9 @@ + + + @@ -67,7 +70,10 @@ + + + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/GlobalDefaultsClass.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/GlobalDefaultsClass.php new file mode 100644 index 0000000000000..a4acb310c2a80 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/GlobalDefaultsClass.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures; + +use Symfony\Component\Routing\Annotation\Route; + +/** + * @Route("/defaults", locale="g_locale", format="g_format") + */ +class GlobalDefaultsClass +{ + /** + * @Route("/specific-locale", name="specific_locale", locale="s_locale") + */ + public function locale() + { + } + + /** + * @Route("/specific-format", name="specific_format", format="s_format") + */ + public function format() + { + } +} diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/Utf8ActionControllers.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/Utf8ActionControllers.php new file mode 100644 index 0000000000000..ea5505f779efb --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/Utf8ActionControllers.php @@ -0,0 +1,25 @@ +add('defaults', '/defaults') + ->locale('en') + ->format('html') + ; +}; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml new file mode 100644 index 0000000000000..dfa9153a86b11 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml new file mode 100644 index 0000000000000..a563ae084b7c2 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/defaults.yml @@ -0,0 +1,4 @@ +defaults: + path: /defaults + locale: en + format: html diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.php b/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.php new file mode 100644 index 0000000000000..3606f3e662698 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.php @@ -0,0 +1,10 @@ +add('one', '/one') + ->add('two', '/two')->defaults(['specific' => 'imported']) + ; +}; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.xml b/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.xml new file mode 100644 index 0000000000000..64fd35b799ee2 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.xml @@ -0,0 +1,11 @@ + + + + + + imported + + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.yml b/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.yml new file mode 100644 index 0000000000000..9af819067f6f5 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/imported-with-defaults.yml @@ -0,0 +1,7 @@ +one: + path: /one + +two: + path: /two + defaults: + specific: imported diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php new file mode 100644 index 0000000000000..6ac9d69e623ba --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.php @@ -0,0 +1,11 @@ +import('imported-with-defaults.php') + ->prefix('/defaults') + ->locale('g_locale') + ->format('g_format') + ; +}; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml new file mode 100644 index 0000000000000..bdd25318d5101 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml new file mode 100644 index 0000000000000..2e7d59002145b --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/importer-with-defaults.yml @@ -0,0 +1,5 @@ +defaults: + resource: imported-with-defaults.yml + prefix: /defaults + locale: g_locale + format: g_format diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.php b/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.php new file mode 100644 index 0000000000000..a32189fb99282 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.php @@ -0,0 +1,10 @@ +add('utf8_one', '/one') + ->add('utf8_two', '/two') + ; +}; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.xml b/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.xml new file mode 100644 index 0000000000000..751d5c5441da8 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.yml b/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.yml new file mode 100644 index 0000000000000..f04e7ac731385 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/imported-with-utf8.yml @@ -0,0 +1,5 @@ +utf8_one: + path: /one + +utf8_two: + path: /two diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.php b/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.php new file mode 100644 index 0000000000000..105528dda43df --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.php @@ -0,0 +1,7 @@ +import('imported-with-utf8.php')->utf8(); +}; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.xml b/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.xml new file mode 100644 index 0000000000000..20f8e38ee1b43 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.xml @@ -0,0 +1,7 @@ + + + + diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.yml b/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.yml new file mode 100644 index 0000000000000..20ad443bb1770 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/importer-with-utf8.yml @@ -0,0 +1,3 @@ +utf8_routes: + resource: imported-with-utf8.yml + utf8: true diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.php b/src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.php new file mode 100644 index 0000000000000..e7826d0a7896b --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.php @@ -0,0 +1,10 @@ +add('some_route', '/') + ->add('some_utf8_route', '/utf8')->utf8() + ; +}; diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.yml b/src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.yml new file mode 100644 index 0000000000000..3154c83fd0020 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/localized/utf8.yml @@ -0,0 +1,6 @@ +some_route: + path: / + +some_utf8_route: + path: /utf8 + utf8: true diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php index 74dfcf8f49ff8..95dbe0f714793 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php @@ -20,6 +20,7 @@ use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\ActionPathController; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\DefaultValueController; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\ExplicitLocalizedActionPathController; +use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\GlobalDefaultsClass; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\InvokableController; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\InvokableLocalizedController; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\LocalizedActionPathController; @@ -35,6 +36,7 @@ use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\PrefixedActionPathController; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RequirementsWithoutPlaceholderNameController; use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\RouteWithPrefixController; +use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\Utf8ActionControllers; class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest { @@ -157,6 +159,32 @@ public function testInvokableClassRouteLoadWithMethodAnnotation() $this->assertEquals('/the/path', $routes->get('post.en')->getPath()); } + public function testGlobalDefaultsRoutesLoadWithAnnotation() + { + $routes = $this->loader->load(GlobalDefaultsClass::class); + $this->assertCount(2, $routes); + + $specificLocaleRoute = $routes->get('specific_locale'); + + $this->assertSame('/defaults/specific-locale', $specificLocaleRoute->getPath()); + $this->assertSame('s_locale', $specificLocaleRoute->getDefault('_locale')); + $this->assertSame('g_format', $specificLocaleRoute->getDefault('_format')); + + $specificFormatRoute = $routes->get('specific_format'); + + $this->assertSame('/defaults/specific-format', $specificFormatRoute->getPath()); + $this->assertSame('g_locale', $specificFormatRoute->getDefault('_locale')); + $this->assertSame('s_format', $specificFormatRoute->getDefault('_format')); + } + + public function testUtf8RoutesLoadWithAnnotation() + { + $routes = $this->loader->load(Utf8ActionControllers::class); + $this->assertCount(2, $routes); + $this->assertTrue($routes->get('one')->getOption('utf8'), 'The route must accept utf8'); + $this->assertFalse($routes->get('two')->getOption('utf8'), 'The route must not accept utf8'); + } + public function testRouteWithPathWithPrefix() { $routes = $this->loader->load(PrefixedActionPathController::class); diff --git a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php index fcde870373489..71f9df15470a1 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/PhpFileLoaderTest.php @@ -84,6 +84,80 @@ public function testThatDefiningVariableInConfigFileHasNoSideEffects() ); } + public function testLoadingRouteWithDefaults() + { + $loader = new PhpFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); + $routes = $loader->load('defaults.php'); + + $this->assertCount(1, $routes); + + $defaultsRoute = $routes->get('defaults'); + + $this->assertSame('/defaults', $defaultsRoute->getPath()); + $this->assertSame('en', $defaultsRoute->getDefault('_locale')); + $this->assertSame('html', $defaultsRoute->getDefault('_format')); + } + + public function testLoadingImportedRoutesWithDefaults() + { + $loader = new PhpFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); + $routes = $loader->load('importer-with-defaults.php'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('one', $localeRoute = new Route('/defaults/one')); + $localeRoute->setDefault('_locale', 'g_locale'); + $localeRoute->setDefault('_format', 'g_format'); + $expectedRoutes->add('two', $formatRoute = new Route('/defaults/two')); + $formatRoute->setDefault('_locale', 'g_locale'); + $formatRoute->setDefault('_format', 'g_format'); + $formatRoute->setDefault('specific', 'imported'); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/imported-with-defaults.php')); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/importer-with-defaults.php')); + + $this->assertEquals($expectedRoutes, $routes); + } + + public function testLoadingUtf8Route() + { + $loader = new PhpFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); + $routes = $loader->load('utf8.php'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('some_route', new Route('/')); + + $expectedRoutes->add('some_utf8_route', $route = new Route('/utf8')); + $route->setOption('utf8', true); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/utf8.php')); + + $this->assertEquals($expectedRoutes, $routes); + } + + public function testLoadingUtf8ImportedRoutes() + { + $loader = new PhpFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); + $routes = $loader->load('importer-with-utf8.php'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('utf8_one', $one = new Route('/one')); + $one->setOption('utf8', true); + + $expectedRoutes->add('utf8_two', $two = new Route('/two')); + $two->setOption('utf8', true); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/imported-with-utf8.php')); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/importer-with-utf8.php')); + + $this->assertEquals($expectedRoutes, $routes); + } + public function testRoutingConfigurator() { $locator = new FileLocator([__DIR__.'/../Fixtures']); diff --git a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php index c4fe699a40d79..da86e6308cbd9 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/XmlFileLoaderTest.php @@ -13,7 +13,10 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; +use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Loader\XmlFileLoader; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\Tests\Fixtures\CustomXmlFileLoader; class XmlFileLoaderTest extends TestCase @@ -83,24 +86,79 @@ public function testLoadWithImport() } } - public function testUtf8Route() + public function testLoadingRouteWithDefaults() + { + $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); + $routes = $loader->load('defaults.xml'); + + $this->assertCount(1, $routes); + + $defaultsRoute = $routes->get('defaults'); + + $this->assertSame('/defaults', $defaultsRoute->getPath()); + $this->assertSame('en', $defaultsRoute->getDefault('_locale')); + $this->assertSame('html', $defaultsRoute->getDefault('_format')); + } + + public function testLoadingImportedRoutesWithDefaults() + { + $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); + $routes = $loader->load('importer-with-defaults.xml'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('one', $localeRoute = new Route('/defaults/one')); + $localeRoute->setDefault('_locale', 'g_locale'); + $localeRoute->setDefault('_format', 'g_format'); + $expectedRoutes->add('two', $formatRoute = new Route('/defaults/two')); + $formatRoute->setDefault('_locale', 'g_locale'); + $formatRoute->setDefault('_format', 'g_format'); + $formatRoute->setDefault('specific', 'imported'); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/imported-with-defaults.xml')); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/importer-with-defaults.xml')); + + $this->assertEquals($expectedRoutes, $routes); + } + + public function testLoadingUtf8Route() { $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); - $routeCollection = $loader->load('utf8.xml'); - $routes = $routeCollection->all(); + $routes = $loader->load('utf8.xml'); - $this->assertCount(2, $routes, 'Two routes are loaded'); - $this->assertContainsOnly('Symfony\Component\Routing\Route', $routes); + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('app_utf8', $route = new Route('/utf8')); + $route->setOption('utf8', true); + + $expectedRoutes->add('app_no_utf8', $route = new Route('/no-utf8')); + $route->setOption('utf8', false); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/utf8.xml')); + + $this->assertEquals($expectedRoutes, $routes); + } + + public function testLoadingUtf8ImportedRoutes() + { + $loader = new XmlFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); + $routes = $loader->load('importer-with-utf8.xml'); + + $this->assertCount(2, $routes); - $utf8Route = $routeCollection->get('app_utf8'); + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('utf8_one', $one = new Route('/one')); + $one->setOption('utf8', true); - $this->assertSame('/utf8', $utf8Route->getPath()); - $this->assertTrue($utf8Route->getOption('utf8'), 'Must be utf8'); + $expectedRoutes->add('utf8_two', $two = new Route('/two')); + $two->setOption('utf8', true); - $noUtf8Route = $routeCollection->get('app_no_utf8'); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/imported-with-utf8.xml')); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/importer-with-utf8.xml')); - $this->assertSame('/no-utf8', $noUtf8Route->getPath()); - $this->assertFalse($noUtf8Route->getOption('utf8'), 'Must not be utf8'); + $this->assertEquals($expectedRoutes, $routes); } public function testLoadLocalized() diff --git a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php index 296bbe4226b89..ad7720884fd56 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/YamlFileLoaderTest.php @@ -15,6 +15,8 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Resource\FileResource; use Symfony\Component\Routing\Loader\YamlFileLoader; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; class YamlFileLoaderTest extends TestCase { @@ -222,6 +224,80 @@ public function testRemoteSourcesAreNotAccepted() $loader->load('http://remote.com/here.yml'); } + public function testLoadingRouteWithDefaults() + { + $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); + $routes = $loader->load('defaults.yml'); + + $this->assertCount(1, $routes); + + $defaultsRoute = $routes->get('defaults'); + + $this->assertSame('/defaults', $defaultsRoute->getPath()); + $this->assertSame('en', $defaultsRoute->getDefault('_locale')); + $this->assertSame('html', $defaultsRoute->getDefault('_format')); + } + + public function testLoadingImportedRoutesWithDefaults() + { + $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures'])); + $routes = $loader->load('importer-with-defaults.yml'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('one', $localeRoute = new Route('/defaults/one')); + $localeRoute->setDefault('_locale', 'g_locale'); + $localeRoute->setDefault('_format', 'g_format'); + $expectedRoutes->add('two', $formatRoute = new Route('/defaults/two')); + $formatRoute->setDefault('_locale', 'g_locale'); + $formatRoute->setDefault('_format', 'g_format'); + $formatRoute->setDefault('specific', 'imported'); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/imported-with-defaults.yml')); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/importer-with-defaults.yml')); + + $this->assertEquals($expectedRoutes, $routes); + } + + public function testLoadingUtf8Route() + { + $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); + $routes = $loader->load('utf8.yml'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('some_route', new Route('/')); + + $expectedRoutes->add('some_utf8_route', $route = new Route('/utf8')); + $route->setOption('utf8', true); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/utf8.yml')); + + $this->assertEquals($expectedRoutes, $routes); + } + + public function testLoadingUtf8ImportedRoutes() + { + $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); + $routes = $loader->load('importer-with-utf8.yml'); + + $this->assertCount(2, $routes); + + $expectedRoutes = new RouteCollection(); + $expectedRoutes->add('utf8_one', $one = new Route('/one')); + $one->setOption('utf8', true); + + $expectedRoutes->add('utf8_two', $two = new Route('/two')); + $two->setOption('utf8', true); + + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/imported-with-utf8.yml')); + $expectedRoutes->addResource(new FileResource(__DIR__.'/../Fixtures/localized/importer-with-utf8.yml')); + + $this->assertEquals($expectedRoutes, $routes); + } + public function testLoadingLocalizedRoute() { $loader = new YamlFileLoader(new FileLocator([__DIR__.'/../Fixtures/localized'])); diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json index d99d703eeef8e..77d7ce981c82e 100644 --- a/src/Symfony/Component/Routing/composer.json +++ b/src/Symfony/Component/Routing/composer.json @@ -24,7 +24,7 @@ "symfony/yaml": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", - "doctrine/annotations": "~1.0", + "doctrine/annotations": "~1.2", "psr/log": "~1.0" }, "conflict": { From 1af1bf29ef5f1306dfcaf15970df46146a6dbdc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 6 Mar 2019 21:59:33 +0100 Subject: [PATCH 238/495] Added support for many inital places --- UPGRADE-4.3.md | 21 +++++++++ UPGRADE-5.0.md | 1 + .../DependencyInjection/Configuration.php | 12 ++++- .../FrameworkExtension.php | 6 +-- .../Resources/config/schema/symfony-1.0.xsd | 1 + .../Fixtures/php/workflow-legacy.php | 25 +++++++++++ .../php/workflow_with_guard_expression.php | 2 +- ...th_multiple_transitions_with_same_name.php | 2 +- .../Fixtures/php/workflows.php | 4 +- .../php/workflows_explicitly_enabled.php | 2 +- ...ows_explicitly_enabled_named_workflows.php | 2 +- .../Fixtures/xml/workflow-legacy.xml | 20 +++++++++ .../xml/workflow_with_guard_expression.xml | 3 +- ...th_multiple_transitions_with_same_name.xml | 3 +- .../Fixtures/xml/workflows.xml | 3 +- .../xml/workflows_explicitly_enabled.xml | 3 +- ...ows_explicitly_enabled_named_workflows.xml | 3 +- .../Fixtures/yml/workflow-legacy.yml | 14 ++++++ .../yml/workflow_with_guard_expression.yml | 2 +- ...th_multiple_transitions_with_same_name.yml | 2 +- .../Fixtures/yml/workflows.yml | 4 +- .../yml/workflows_explicitly_enabled.yml | 2 +- ...ows_explicitly_enabled_named_workflows.yml | 2 +- .../FrameworkExtensionTest.php | 26 ++++++++++- .../Bundle/FrameworkBundle/composer.json | 4 +- src/Symfony/Component/Workflow/CHANGELOG.md | 1 + src/Symfony/Component/Workflow/Definition.php | 45 ++++++++++++++----- .../Workflow/Dumper/GraphvizDumper.php | 2 +- .../Workflow/Dumper/PlantUmlDumper.php | 2 +- .../Workflow/Tests/DefinitionBuilderTest.php | 2 +- .../Workflow/Tests/DefinitionTest.php | 12 ++++- .../Validator/StateMachineValidatorTest.php | 28 ++++++++++++ .../Tests/Validator/WorkflowValidatorTest.php | 14 ++++++ .../DefinitionValidatorInterface.php | 1 + .../Validator/StateMachineValidator.php | 7 ++- .../Workflow/Validator/WorkflowValidator.php | 6 +++ src/Symfony/Component/Workflow/Workflow.php | 6 ++- 37 files changed, 250 insertions(+), 45 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 52165c10b539e..a45814f09e673 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -127,6 +127,27 @@ Security } ``` +Workflow +-------- + + * `initial_place` is deprecated in favour of `initial_places`. + + Before: + ```yaml + framework: + workflows: + article: + initial_place: draft + ``` + + After: + ```yaml + framework: + workflows: + article: + initial_places: [draft] + ``` + Yaml ---- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 60b16b1c58df8..16a034a85dc05 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -368,6 +368,7 @@ Workflow * `SupportStrategyInterface` has been removed, use `WorkflowSupportStrategyInterface` instead. * `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead. * `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`. + * Removed support of `initial_place`. Use `initial_places` instead. Yaml ---- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 1e52ce9322486..04f2bdbe16c26 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -231,7 +231,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) $workflows = []; } - if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_place', 'places', 'transitions']))) { + if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_places', 'places', 'transitions']))) { $workflows = $workflows['workflows']; } @@ -258,6 +258,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->prototype('array') ->fixXmlConfig('support') ->fixXmlConfig('place') + ->fixXmlConfig('initial_place') ->fixXmlConfig('transition') ->children() ->arrayNode('audit_trail') @@ -312,8 +313,17 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->cannotBeEmpty() ->end() ->scalarNode('initial_place') + ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3, use the "initial_places" configuration key instead.') ->defaultNull() ->end() + ->arrayNode('initial_places') + ->beforeNormalization() + ->ifTrue(function ($v) { return !\is_array($v); }) + ->then(function ($v) { return [$v]; }) + ->end() + ->defaultValue([]) + ->prototype('scalar')->end() + ->end() ->arrayNode('places') ->beforeNormalization() ->always() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 870c499aafbd6..f2f2ab00fcf7e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -615,14 +615,14 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ // Create places $places = array_column($workflow['places'], 'name'); - $initialPlace = $workflow['initial_place'] ?? null; + $initialPlaces = $workflow['initial_places'] ?? $workflow['initial_place'] ?? []; // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); $definitionDefinition->addArgument($places); $definitionDefinition->addArgument($transitions); - $definitionDefinition->addArgument($initialPlace); + $definitionDefinition->addArgument($initialPlaces); $definitionDefinition->addArgument($metadataStoreDefinition); // Create MarkingStore @@ -670,7 +670,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ ->addTransitions(array_map(function (Reference $ref) use ($container): Workflow\Transition { return $container->get((string) $ref); }, $transitions)) - ->setInitialPlace($initialPlace) + ->setInitialPlace($initialPlaces) ->build() ; $validator->validate($realDefinition, $name); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 98baeb978b440..254c0085e8d15 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -270,6 +270,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php new file mode 100644 index 0000000000000..e7d8919315da9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php @@ -0,0 +1,25 @@ +loadFromExtension('framework', [ + 'workflows' => [ + 'legacy' => [ + 'type' => 'workflow', + 'supports' => [ + stdClass::class, + ], + 'initial_place' => 'draft', + 'places' => [ + 'draft', + 'published', + ], + 'transitions' => [ + 'publish' => [ + 'from' => 'draft', + 'to' => 'published', + ], + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php index 19de6363e62c0..03b6a0b79b0cb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php @@ -12,7 +12,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'draft', + 'initial_places' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php index c1a525db03cdc..613a38c6c0ebe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php @@ -12,7 +12,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'draft', + 'initial_places' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php index 9d066a21ba361..17a0e1fa4a7eb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php @@ -12,7 +12,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'draft', + 'initial_places' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', @@ -47,7 +47,7 @@ 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_place' => 'start', + 'initial_places' => ['start'], 'metadata' => [ 'title' => 'workflow title', ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php index 165d0daa11ae5..1c8190bd09d5c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php @@ -6,7 +6,7 @@ 'foo' => [ 'type' => 'workflow', 'supports' => ['Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest'], - 'initial_place' => 'bar', + 'initial_places' => ['bar'], 'places' => ['bar', 'baz'], 'transitions' => [ 'bar_baz' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php index 17055ec16f7df..6faae44f45ced 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php @@ -6,7 +6,7 @@ 'workflows' => [ 'type' => 'workflow', 'supports' => ['Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest'], - 'initial_place' => 'bar', + 'initial_places' => ['bar'], 'places' => ['bar', 'baz'], 'transitions' => [ 'bar_baz' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml new file mode 100644 index 0000000000000..d1339d5f65cc1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml @@ -0,0 +1,20 @@ + + + + + + + stdClass + + + + draft + published + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml index fa5a96ab11881..32c33db5b812a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml @@ -7,7 +7,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + draft a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml index 51413201298de..ffc316c99e70a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml @@ -7,7 +7,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + draft a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml index 862ecae17cde5..da5cd4c758200 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml @@ -7,7 +7,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + draft a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml index 08855f7569aa2..b564c6ff7644a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml @@ -6,7 +6,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + bar Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest bar baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml index 8415c9c280668..b218480fe68a7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml @@ -6,7 +6,8 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - + + bar Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest bar baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml new file mode 100644 index 0000000000000..7ff70074d400c --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml @@ -0,0 +1,14 @@ +framework: + workflows: + legacy: + type: workflow + initial_place: draft + supports: + - stdClass + places: + - draft + - published + transitions: + publish: + from: draft + to: published diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml index 458cb4ae1ee77..433771601c3d7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml @@ -6,7 +6,7 @@ framework: type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: draft + initial_places: [draft] places: - draft - wait_for_journalist diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml index 36d00de46501c..fee71c2645693 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml @@ -6,7 +6,7 @@ framework: type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: draft + initial_places: [draft] places: - draft - wait_for_journalist diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml index c82c92791c864..894d5dcde207c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml @@ -6,7 +6,7 @@ framework: type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: draft + initial_places: [draft] places: # simple format - draft @@ -33,7 +33,7 @@ framework: type: single_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: start + initial_places: [start] metadata: title: workflow title places: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml index 21abbf03055a4..d1545374705d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml @@ -6,7 +6,7 @@ framework: type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: bar + initial_places: [bar] places: - bar - baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml index a6c03de95d1b3..bb468254aca0b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml @@ -5,7 +5,7 @@ framework: type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_place: bar + initial_places: [bar] places: - bar - baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 5c0352b2658da..dd626d62c40bf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -217,7 +217,7 @@ public function testWorkflows() 'Places are passed to the workflow definition' ); $this->assertCount(4, $workflowDefinition->getArgument(1)); - $this->assertSame('draft', $workflowDefinition->getArgument(2)); + $this->assertSame(['draft'], $workflowDefinition->getArgument(2)); $this->assertTrue($container->hasDefinition('state_machine.pull_request'), 'State machine is registered as a service'); $this->assertSame('state_machine.abstract', $container->getDefinition('state_machine.pull_request')->getParent()); @@ -238,7 +238,7 @@ public function testWorkflows() 'Places are passed to the state machine definition' ); $this->assertCount(9, $stateMachineDefinition->getArgument(1)); - $this->assertSame('start', $stateMachineDefinition->getArgument(2)); + $this->assertSame(['start'], $stateMachineDefinition->getArgument(2)); $metadataStoreDefinition = $stateMachineDefinition->getArgument(3); $this->assertInstanceOf(Definition::class, $metadataStoreDefinition); @@ -271,6 +271,28 @@ public function testWorkflows() $this->assertGreaterThan(0, \count($registryDefinition->getMethodCalls())); } + public function testWorkflowLegacy() + { + $container = $this->createContainerFromFile('workflow-legacy'); + + $this->assertTrue($container->hasDefinition('workflow.legacy'), 'Workflow is registered as a service'); + $this->assertSame('workflow.abstract', $container->getDefinition('workflow.legacy')->getParent()); + $this->assertTrue($container->hasDefinition('workflow.legacy.definition'), 'Workflow definition is registered as a service'); + + $workflowDefinition = $container->getDefinition('workflow.legacy.definition'); + + $this->assertSame(['draft'], $workflowDefinition->getArgument(2)); + + $this->assertSame( + [ + 'draft', + 'published', + ], + $workflowDefinition->getArgument(0), + 'Places are passed to the workflow definition' + ); + } + /** * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException * @expectedExceptionMessage A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" where found on StateMachine "my_workflow". diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 8279d4c7a3e7f..86ad2fe1e6e6e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -54,7 +54,7 @@ "symfony/twig-bundle": "~2.8|~3.2|~4.0", "symfony/validator": "^4.1", "symfony/var-dumper": "~3.4|~4.0", - "symfony/workflow": "^4.1", + "symfony/workflow": "^4.3", "symfony/yaml": "~3.4|~4.0", "symfony/property-info": "~3.4|~4.0", "symfony/lock": "~3.4|~4.0", @@ -79,7 +79,7 @@ "symfony/translation": "<4.3", "symfony/twig-bridge": "<4.1.1", "symfony/validator": "<4.1", - "symfony/workflow": "<4.1" + "symfony/workflow": "<4.3" }, "suggest": { "ext-apcu": "For best performance of the system caches", diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index a37db3857c474..0801deccc711b 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -26,6 +26,7 @@ CHANGELOG * Dispatch `EnteredEvent` on `workflow.entered` * Dispatch `CompletedEvent` on `workflow.completed` * Dispatch `AnnounceEvent` on `workflow.announce` + * Added support for many `initialPlaces` 4.1.0 ----- diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index f614d46a30551..dd0c0626cf785 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -24,14 +24,15 @@ final class Definition { private $places = []; private $transitions = []; - private $initialPlace; + private $initialPlaces = []; private $metadataStore; /** - * @param string[] $places - * @param Transition[] $transitions + * @param string[] $places + * @param Transition[] $transitions + * @param string|string[]|null $initialPlaces */ - public function __construct(array $places, array $transitions, string $initialPlace = null, MetadataStoreInterface $metadataStore = null) + public function __construct(array $places, array $transitions, $initialPlaces = null, MetadataStoreInterface $metadataStore = null) { foreach ($places as $place) { $this->addPlace($place); @@ -41,17 +42,33 @@ public function __construct(array $places, array $transitions, string $initialPl $this->addTransition($transition); } - $this->setInitialPlace($initialPlace); + $this->setInitialPlaces($initialPlaces); $this->metadataStore = $metadataStore ?: new InMemoryMetadataStore(); } /** + * @deprecated since Symfony 4.3. Use the getInitialPlaces() instead. + * * @return string|null */ public function getInitialPlace() { - return $this->initialPlace; + @trigger_error(sprintf('Calling %s::getInitialPlace() is deprecated. Call %s::getInitialPlaces() instead.', __CLASS__, __CLASS__)); + + if (!$this->initialPlaces) { + return null; + } + + return reset($this->initialPlaces); + } + + /** + * @return string[] + */ + public function getInitialPlaces(): array + { + return $this->initialPlaces; } /** @@ -75,23 +92,27 @@ public function getMetadataStore(): MetadataStoreInterface return $this->metadataStore; } - private function setInitialPlace(string $place = null) + private function setInitialPlaces($places = null) { - if (null === $place) { + if (null === $places) { return; } - if (!isset($this->places[$place])) { - throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); + $places = (array) $places; + + foreach ($places as $place) { + if (!isset($this->places[$place])) { + throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); + } } - $this->initialPlace = $place; + $this->initialPlaces = $places; } private function addPlace(string $place) { if (!\count($this->places)) { - $this->initialPlace = $place; + $this->initialPlaces = [$place]; } $this->places[$place] = $place; diff --git a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php index 6822eab86bdac..55cd832bbd7b2 100644 --- a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php @@ -69,7 +69,7 @@ protected function findPlaces(Definition $definition, Marking $marking = null) foreach ($definition->getPlaces() as $place) { $attributes = []; - if ($place === $definition->getInitialPlace()) { + if (\in_array($place, $definition->getInitialPlaces(), true)) { $attributes['style'] = 'filled'; } if ($marking && $marking->has($place)) { diff --git a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php index 50d9046f26550..977ef69cdd2fa 100644 --- a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php @@ -199,7 +199,7 @@ private function getState(string $place, Definition $definition, Marking $markin $placeEscaped = $this->escape($place); $output = "state $placeEscaped". - ($definition->getInitialPlace() === $place ? ' '.self::INITIAL : ''). + (\in_array($place, $definition->getInitialPlaces(), true) ? ' '.self::INITIAL : ''). ($marking && $marking->has($place) ? ' '.self::MARKED : ''); $backgroundColor = $workflowMetadata->getMetadata('bg_color', $place); diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php index fdc4703a1b426..62351d7d9218a 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php @@ -15,7 +15,7 @@ public function testSetInitialPlace() $builder->setInitialPlace('b'); $definition = $builder->build(); - $this->assertEquals('b', $definition->getInitialPlace()); + $this->assertEquals(['b'], $definition->getInitialPlaces()); } public function testAddTransition() diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php index e10aad81cf143..8bbac4a8c784d 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php @@ -15,7 +15,7 @@ public function testAddPlaces() $this->assertCount(5, $definition->getPlaces()); - $this->assertEquals('a', $definition->getInitialPlace()); + $this->assertEquals(['a'], $definition->getInitialPlaces()); } public function testSetInitialPlace() @@ -23,7 +23,15 @@ public function testSetInitialPlace() $places = range('a', 'e'); $definition = new Definition($places, [], $places[3]); - $this->assertEquals($places[3], $definition->getInitialPlace()); + $this->assertEquals([$places[3]], $definition->getInitialPlaces()); + } + + public function testSetInitialPlaces() + { + $places = range('a', 'e'); + $definition = new Definition($places, [], ['a', 'e']); + + $this->assertEquals(['a', 'e'], $definition->getInitialPlaces()); } /** diff --git a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php index 4e344560557d4..35da1f2ec8061 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php @@ -109,4 +109,32 @@ public function testValid() // | t2 | --> | c | // +----+ +----+ } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage The state machine "foo" can not store many places. But the definition has 2 initial places. Only one is supported. + */ + public function testWithTooManyInitialPlaces() + { + $places = range('a', 'c'); + $transitions = []; + $definition = new Definition($places, $transitions, ['a', 'b']); + + (new StateMachineValidator())->validate($definition, 'foo'); + + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) + $this->addToAssertionCount(1); + + // The graph looks like: + // + // +----+ +----+ +---+ + // | a | --> | t1 | --> | b | + // +----+ +----+ +---+ + // | + // | + // v + // +----+ +----+ + // | t2 | --> | c | + // +----+ +----+ + } } diff --git a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php index 4a5c5a57dd85f..5aa020fea45ae 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php @@ -51,6 +51,20 @@ public function testWorkflowWithInvalidNames() (new WorkflowValidator())->validate($definition, 'foo'); } + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage The marking store of workflow "foo" can not store many places. But the definition has 2 initial places. Only one is supported. + */ + public function testWithTooManyInitialPlaces() + { + $places = range('a', 'c'); + $transitions = []; + + $definition = new Definition($places, $transitions, ['a', 'b']); + + (new WorkflowValidator(true))->validate($definition, 'foo'); + } + public function testSameTransitionNameButNotSamePlace() { $places = range('a', 'd'); diff --git a/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php b/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php index 244dceae9a9da..1282c966b7d32 100644 --- a/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php +++ b/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php @@ -16,6 +16,7 @@ /** * @author Tobias Nyholm + * @author Grégoire Pineau */ interface DefinitionValidatorInterface { diff --git a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php index 7dbe694940518..78b32e648e328 100644 --- a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php +++ b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php @@ -37,10 +37,15 @@ public function validate(Definition $definition, $name) // Enforcing uniqueness of the names of transitions starting at each node $from = reset($froms); if (isset($transitionFromNames[$from][$transition->getName()])) { - throw new InvalidDefinitionException(sprintf('A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" where found on StateMachine "%s". ', $transition->getName(), $from, $name)); + throw new InvalidDefinitionException(sprintf('A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" where found on StateMachine "%s".', $transition->getName(), $from, $name)); } $transitionFromNames[$from][$transition->getName()] = true; } + + $initialPlaces = $definition->getInitialPlaces(); + if (2 <= count($initialPlaces)) { + throw new InvalidDefinitionException(sprintf('The state machine "%s" can not store many places. But the definition has %s initial places. Only one is supported.', $name, \count($initialPlaces))); + } } } diff --git a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php index 0cb420ba6ad4a..2a31ec8e46594 100644 --- a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php +++ b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php @@ -16,6 +16,7 @@ /** * @author Tobias Nyholm + * @author Grégoire Pineau */ class WorkflowValidator implements DefinitionValidatorInterface { @@ -48,5 +49,10 @@ public function validate(Definition $definition, $name) throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" can not store many places. But the transition "%s" has too many output (%d). Only one is accepted.', $name, $transition->getName(), \count($transition->getTos()))); } } + + $initialPlaces = $definition->getInitialPlaces(); + if (2 <= count($initialPlaces)) { + throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" can not store many places. But the definition has %s initial places. Only one is supported.', $name, \count($initialPlaces))); + } } } diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index c0866c663796a..11fbe5f348375 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -61,10 +61,12 @@ public function getMarking($subject) // check if the subject is already in the workflow if (!$marking->getPlaces()) { - if (!$this->definition->getInitialPlace()) { + if (!$this->definition->getInitialPlaces()) { throw new LogicException(sprintf('The Marking is empty and there is no initial place for workflow "%s".', $this->name)); } - $marking->mark($this->definition->getInitialPlace()); + foreach ($this->definition->getInitialPlaces() as $place) { + $marking->mark($place); + } // update the subject with the new marking $this->markingStore->setMarking($subject, $marking); From af28965c24873dceb4c4c2bdfa2633345f7b5a1c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 20 Mar 2019 21:49:31 +0100 Subject: [PATCH 239/495] fixed encoder in Mime --- src/Symfony/Component/Mime/Address.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Mime/Address.php b/src/Symfony/Component/Mime/Address.php index f244f053e20cd..86a80426db970 100644 --- a/src/Symfony/Component/Mime/Address.php +++ b/src/Symfony/Component/Mime/Address.php @@ -40,10 +40,6 @@ public function __construct(string $address) self::$validator = new EmailValidator(); } - if (null === self::$encoder) { - self::$encoder = new IdnAddressEncoder(); - } - if (!self::$validator->isValid($address, new RFCValidation())) { throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); } @@ -58,6 +54,10 @@ public function getAddress(): string public function getEncodedAddress(): string { + if (null === self::$encoder) { + self::$encoder = new IdnAddressEncoder(); + } + return self::$encoder->encodeString($this->address); } From b579b023bda3c9b51d93b7d9e6e0c93bfaea5508 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 30 Jan 2019 10:26:19 +0100 Subject: [PATCH 240/495] [HttpKernel] add RealHttpKernel: handle requests with HttpClientInterface --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../Component/HttpKernel/RealHttpKernel.php | 104 ++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/Symfony/Component/HttpKernel/RealHttpKernel.php diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 7b5dc28332966..d3007e8aec80f 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -21,6 +21,7 @@ CHANGELOG * renamed `GetResponseForControllerResultEvent` to `ViewEvent` * renamed `GetResponseForExceptionEvent` to `ExceptionEvent` * renamed `PostResponseEvent` to `TerminateEvent` + * added `RealHttpKernel` for handling requests with an `HttpClientInterface` instance 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/RealHttpKernel.php b/src/Symfony/Component/HttpKernel/RealHttpKernel.php new file mode 100644 index 0000000000000..d78fda1f8dac9 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/RealHttpKernel.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Component\Mime\Part\TextPart; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * An implementation of a Symfony HTTP kernel using a "real" HTTP client. + * + * @author Fabien Potencier + */ +final class RealHttpKernel implements HttpKernelInterface +{ + private $client; + private $logger; + + public function __construct(HttpClientInterface $client = null, LoggerInterface $logger = null) + { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = $client ?? HttpClient::create(); + $this->logger = $logger ?? new NullLogger(); + } + + public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) + { + $this->logger->debug(sprintf('Request: %s %s', $request->getMethod(), $request->getUri())); + + $headers = $this->getHeaders($request); + $body = ''; + if (null !== $part = $this->getBody($request)) { + $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); + $body = $part->bodyToIterable(); + } + $response = $this->client->request($request->getMethod(), $request->getUri(), [ + 'headers' => $headers, + 'body' => $body, + 'max_redirects' => 0, + ] + $request->attributes->get('http_client_options', [])); + + $this->logger->debug(sprintf('Response: %s %s', $response->getStatusCode(), $request->getUri())); + + return new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); + } + + private function getBody(Request $request): ?AbstractPart + { + if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { + return null; + } + + if (!class_exists(AbstractPart::class)) { + throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".'); + } + + if ($content = $request->getContent()) { + return new TextPart($content, 'utf-8', 'plain', '8bit'); + } + + $fields = $request->request->all(); + foreach ($request->files->all() as $name => $file) { + $fields[$name] = DataPart::fromPath($file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType()); + } + + return new FormDataPart($fields); + } + + private function getHeaders(Request $request): array + { + $headers = []; + foreach ($request->headers as $key => $value) { + $headers[$key] = $value; + } + $cookies = []; + foreach ($request->cookies->all() as $name => $value) { + $cookies[] = $name.'='.$value; + } + if ($cookies) { + $headers['cookie'] = implode('; ', $cookies); + } + + return $headers; + } +} From 2d64e703c20c26f24fbb5e57dc55d0e6e02aef9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Tue, 26 Jun 2018 17:35:39 +0200 Subject: [PATCH 241/495] [Validator][DoctrineBridge][FWBundle] Automatic data validation --- .../Tests/Fixtures/DoctrineLoaderEntity.php | 58 ++++++ .../Tests/Validator/DoctrineLoaderTest.php | 94 ++++++++++ .../Doctrine/Validator/DoctrineLoader.php | 121 +++++++++++++ .../DependencyInjection/Configuration.php | 39 ++++ .../FrameworkExtension.php | 13 +- .../FrameworkBundle/FrameworkBundle.php | 2 + .../Resources/config/schema/symfony-1.0.xsd | 8 + .../Resources/config/validator.xml | 7 + .../DependencyInjection/ConfigurationTest.php | 1 + .../Fixtures/php/validation_auto_mapping.php | 12 ++ .../Fixtures/xml/validation_auto_mapping.xml | 20 ++ .../Fixtures/yml/validation_auto_mapping.yml | 7 + .../FrameworkExtensionTest.php | 19 ++ .../AddAutoMappingConfigurationPass.php | 93 ++++++++++ .../Mapping/Loader/PropertyInfoLoader.php | 151 ++++++++++++++++ .../AddAutoMappingConfigurationPassTest.php | 73 ++++++++ .../Fixtures/PropertyInfoLoaderEntity.php | 49 +++++ .../Mapping/Loader/PropertyInfoLoaderTest.php | 171 ++++++++++++++++++ src/Symfony/Component/Validator/composer.json | 2 + 19 files changed, 937 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php create mode 100644 src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_auto_mapping.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_auto_mapping.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_auto_mapping.yml create mode 100644 src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php create mode 100644 src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php create mode 100644 src/Symfony/Component/Validator/Tests/DependencyInjection/AddAutoMappingConfigurationPassTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/PropertyInfoLoaderEntity.php create mode 100644 src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php new file mode 100644 index 0000000000000..4a92edec8fa14 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DoctrineLoaderEntity.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping as ORM; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Validator\Constraints as Assert; + +/** + * @ORM\Entity + * @UniqueEntity(fields={"alreadyMappedUnique"}) + * + * @author Kévin Dunglas + */ +class DoctrineLoaderEntity +{ + /** + * @ORM\Id + * @ORM\Column + */ + public $id; + + /** + * @ORM\Column(length=20) + */ + public $maxLength; + + /** + * @ORM\Column(length=20) + * @Assert\Length(min=5) + */ + public $mergedMaxLength; + + /** + * @ORM\Column(length=20) + * @Assert\Length(min=1, max=10) + */ + public $alreadyMappedMaxLength; + + /** + * @ORM\Column(unique=true) + */ + public $unique; + + /** + * @ORM\Column(unique=true) + */ + public $alreadyMappedUnique; +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php new file mode 100644 index 0000000000000..9599ac8995cda --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Validator; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderEntity; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Bridge\Doctrine\Validator\DoctrineLoader; +use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Validation; +use Symfony\Component\Validator\ValidatorBuilder; + +/** + * @author Kévin Dunglas + */ +class DoctrineLoaderTest extends TestCase +{ + public function testLoadClassMetadata() + { + if (!method_exists(ValidatorBuilder::class, 'addLoader')) { + $this->markTestSkipped('Auto-mapping requires symfony/validation 4.2+'); + } + + $validator = Validation::createValidatorBuilder() + ->enableAnnotationMapping() + ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager())) + ->getValidator() + ; + + $classMetadata = $validator->getMetadataFor(new DoctrineLoaderEntity()); + + $classConstraints = $classMetadata->getConstraints(); + $this->assertCount(2, $classConstraints); + $this->assertInstanceOf(UniqueEntity::class, $classConstraints[0]); + $this->assertInstanceOf(UniqueEntity::class, $classConstraints[1]); + $this->assertSame(['alreadyMappedUnique'], $classConstraints[0]->fields); + $this->assertSame('unique', $classConstraints[1]->fields); + + $maxLengthMetadata = $classMetadata->getPropertyMetadata('maxLength'); + $this->assertCount(1, $maxLengthMetadata); + $maxLengthConstraints = $maxLengthMetadata[0]->getConstraints(); + $this->assertCount(1, $maxLengthConstraints); + $this->assertInstanceOf(Length::class, $maxLengthConstraints[0]); + $this->assertSame(20, $maxLengthConstraints[0]->max); + + $mergedMaxLengthMetadata = $classMetadata->getPropertyMetadata('mergedMaxLength'); + $this->assertCount(1, $mergedMaxLengthMetadata); + $mergedMaxLengthConstraints = $mergedMaxLengthMetadata[0]->getConstraints(); + $this->assertCount(1, $mergedMaxLengthConstraints); + $this->assertInstanceOf(Length::class, $mergedMaxLengthConstraints[0]); + $this->assertSame(20, $mergedMaxLengthConstraints[0]->max); + $this->assertSame(5, $mergedMaxLengthConstraints[0]->min); + + $alreadyMappedMaxLengthMetadata = $classMetadata->getPropertyMetadata('alreadyMappedMaxLength'); + $this->assertCount(1, $alreadyMappedMaxLengthMetadata); + $alreadyMappedMaxLengthConstraints = $alreadyMappedMaxLengthMetadata[0]->getConstraints(); + $this->assertCount(1, $alreadyMappedMaxLengthConstraints); + $this->assertInstanceOf(Length::class, $alreadyMappedMaxLengthConstraints[0]); + $this->assertSame(10, $alreadyMappedMaxLengthConstraints[0]->max); + $this->assertSame(1, $alreadyMappedMaxLengthConstraints[0]->min); + } + + /** + * @dataProvider regexpProvider + */ + public function testClassValidator(bool $expected, string $classValidatorRegexp = null) + { + $doctrineLoader = new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), $classValidatorRegexp); + + $classMetadata = new ClassMetadata(DoctrineLoaderEntity::class); + $this->assertSame($expected, $doctrineLoader->loadClassMetadata($classMetadata)); + } + + public function regexpProvider() + { + return [ + [true, null], + [true, '{^'.preg_quote(DoctrineLoaderEntity::class).'$|^'.preg_quote(Entity::class).'$}'], + [false, '{^'.preg_quote(Entity::class).'$}'], + ]; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php new file mode 100644 index 0000000000000..3b6d065fe6e1f --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Validator; + +use Doctrine\Common\Persistence\Mapping\MappingException; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\MappingException as OrmMappingException; +use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; +use Symfony\Component\Validator\Constraints\Length; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\LoaderInterface; + +/** + * Guesses and loads the appropriate constraints using Doctrine's metadata. + * + * @author Kévin Dunglas + */ +final class DoctrineLoader implements LoaderInterface +{ + private $entityManager; + private $classValidatorRegexp; + + public function __construct(EntityManagerInterface $entityManager, string $classValidatorRegexp = null) + { + $this->entityManager = $entityManager; + $this->classValidatorRegexp = $classValidatorRegexp; + } + + /** + * {@inheritdoc} + */ + public function loadClassMetadata(ClassMetadata $metadata): bool + { + $className = $metadata->getClassName(); + if (null !== $this->classValidatorRegexp && !preg_match($this->classValidatorRegexp, $className)) { + return false; + } + + try { + $doctrineMetadata = $this->entityManager->getClassMetadata($className); + } catch (MappingException | OrmMappingException $exception) { + return false; + } + + if (!$doctrineMetadata instanceof ClassMetadataInfo) { + return false; + } + + /* Available keys: + - type + - scale + - length + - unique + - nullable + - precision + */ + $existingUniqueFields = $this->getExistingUniqueFields($metadata); + + // Type and nullable aren't handled here, use the PropertyInfo Loader instead. + foreach ($doctrineMetadata->fieldMappings as $mapping) { + if (true === $mapping['unique'] && !isset($existingUniqueFields[$mapping['fieldName']])) { + $metadata->addConstraint(new UniqueEntity(['fields' => $mapping['fieldName']])); + } + + if (null === $mapping['length']) { + continue; + } + + $constraint = $this->getLengthConstraint($metadata, $mapping['fieldName']); + if (null === $constraint) { + $metadata->addPropertyConstraint($mapping['fieldName'], new Length(['max' => $mapping['length']])); + } elseif (null === $constraint->max) { + // If a Length constraint exists and no max length has been explicitly defined, set it + $constraint->max = $mapping['length']; + } + } + + return true; + } + + private function getLengthConstraint(ClassMetadata $metadata, string $fieldName): ?Length + { + foreach ($metadata->getPropertyMetadata($fieldName) as $propertyMetadata) { + foreach ($propertyMetadata->getConstraints() as $constraint) { + if ($constraint instanceof Length) { + return $constraint; + } + } + } + + return null; + } + + private function getExistingUniqueFields(ClassMetadata $metadata): array + { + $fields = []; + foreach ($metadata->getConstraints() as $constraint) { + if (!$constraint instanceof UniqueEntity) { + continue; + } + + if (\is_string($constraint->fields)) { + $fields[$constraint->fields] = true; + } elseif (\is_array($constraint->fields) && 1 === \count($constraint->fields)) { + $fields[$constraint->fields[0]] = true; + } + } + + return $fields; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 1e52ce9322486..6f9ff0f387b4f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -792,6 +792,45 @@ private function addValidationSection(ArrayNodeDefinition $rootNode) ->end() ->end() ->end() + ->arrayNode('auto_mapping') + ->useAttributeAsKey('namespace') + ->normalizeKeys(false) + ->beforeNormalization() + ->ifArray() + ->then(function (array $values): array { + foreach ($values as $k => $v) { + if (isset($v['service'])) { + continue; + } + + if (isset($v['namespace'])) { + $values[$k]['services'] = []; + continue; + } + + if (!\is_array($v)) { + $values[$v]['services'] = []; + unset($values[$k]); + continue; + } + + $tmp = $v; + unset($values[$k]); + $values[$k]['services'] = $tmp; + } + + return $values; + }) + ->end() + ->arrayPrototype() + ->fixXmlConfig('service') + ->children() + ->arrayNode('services') + ->prototype('scalar')->end() + ->end() + ->end() + ->end() + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 870c499aafbd6..eb99aed085aea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -107,6 +107,7 @@ use Symfony\Component\Translation\Command\XliffLintCommand as BaseXliffLintCommand; use Symfony\Component\Translation\Translator; use Symfony\Component\Validator\ConstraintValidatorInterface; +use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader; use Symfony\Component\Validator\ObjectInitializerInterface; use Symfony\Component\WebLink\HttpHeaderSerializer; use Symfony\Component\Workflow; @@ -280,7 +281,8 @@ public function load(array $configs, ContainerBuilder $container) $container->removeDefinition('console.command.messenger_debug'); } - $this->registerValidationConfiguration($config['validation'], $container, $loader); + $propertyInfoEnabled = $this->isConfigEnabled($container, $config['property_info']); + $this->registerValidationConfiguration($config['validation'], $container, $loader, $propertyInfoEnabled); $this->registerEsiConfiguration($config['esi'], $container, $loader); $this->registerSsiConfiguration($config['ssi'], $container, $loader); $this->registerFragmentsConfiguration($config['fragments'], $container, $loader); @@ -301,7 +303,7 @@ public function load(array $configs, ContainerBuilder $container) $this->registerSerializerConfiguration($config['serializer'], $container, $loader); } - if ($this->isConfigEnabled($container, $config['property_info'])) { + if ($propertyInfoEnabled) { $this->registerPropertyInfoConfiguration($container, $loader); } @@ -1152,7 +1154,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder } } - private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) + private function registerValidationConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader, bool $propertyInfoEnabled) { if (!$this->validatorConfigEnabled = $this->isConfigEnabled($container, $config)) { return; @@ -1203,6 +1205,11 @@ private function registerValidationConfiguration(array $config, ContainerBuilder if (!$container->getParameter('kernel.debug')) { $validatorBuilder->addMethodCall('setMetadataCache', [new Reference('validator.mapping.cache.symfony')]); } + + $container->setParameter('validator.auto_mapping', $config['auto_mapping']); + if (!$propertyInfoEnabled || !$config['auto_mapping'] || !class_exists(PropertyInfoLoader::class)) { + $container->removeDefinition('validator.property_info_loader'); + } } private function registerValidatorMapping(ContainerBuilder $container, array $config, array &$files) diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 670c7fc318e8d..c7b37222ae20e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -53,6 +53,7 @@ use Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass; use Symfony\Component\Translation\DependencyInjection\TranslatorPass; use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass; +use Symfony\Component\Validator\DependencyInjection\AddAutoMappingConfigurationPass; use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass; use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass; @@ -124,6 +125,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING); $this->addCompilerPassIfExists($container, AddMimeTypeGuesserPass::class); $this->addCompilerPassIfExists($container, MessengerPass::class); + $this->addCompilerPassIfExists($container, AddAutoMappingConfigurationPass::class); $container->addCompilerPass(new RegisterReverseContainerPass(true)); $container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 98baeb978b440..f975184822545 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -190,6 +190,7 @@ + @@ -207,6 +208,13 @@ + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml index 8a0919f3e281a..4fd3da7a633ea 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml @@ -60,5 +60,12 @@ + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 56be70050ccf5..69fdba0726d3e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -232,6 +232,7 @@ protected static function getBundleDefaultConfig() 'mapping' => [ 'paths' => [], ], + 'auto_mapping' => [], ], 'annotations' => [ 'cache' => 'php_array', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_auto_mapping.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_auto_mapping.php new file mode 100644 index 0000000000000..e15762d6d8a13 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/validation_auto_mapping.php @@ -0,0 +1,12 @@ +loadFromExtension('framework', [ + 'property_info' => ['enabled' => true], + 'validation' => [ + 'auto_mapping' => [ + 'App\\' => ['foo', 'bar'], + 'Symfony\\' => ['a', 'b'], + 'Foo\\', + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_auto_mapping.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_auto_mapping.xml new file mode 100644 index 0000000000000..a05aaf8016a56 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/validation_auto_mapping.xml @@ -0,0 +1,20 @@ + + + + + + + + + foo + bar + + + a + b + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_auto_mapping.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_auto_mapping.yml new file mode 100644 index 0000000000000..2564a8d243ef8 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/validation_auto_mapping.yml @@ -0,0 +1,7 @@ +framework: + property_info: { enabled: true } + validation: + auto_mapping: + 'App\': ['foo', 'bar'] + 'Symfony\': ['a', 'b'] + 'Foo\': [] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 5c0352b2658da..a793fd94674e4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -50,6 +50,8 @@ use Symfony\Component\Serializer\Serializer; use Symfony\Component\Translation\DependencyInjection\TranslatorPass; use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass; +use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader; +use Symfony\Component\Validator\Validation; use Symfony\Component\Workflow; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -1033,6 +1035,23 @@ public function testValidationMapping() $this->assertContains('validation.yaml', $calls[4][1][0][2]); } + public function testValidationAutoMapping() + { + if (!class_exists(PropertyInfoLoader::class)) { + $this->markTestSkipped('Auto-mapping requires symfony/validation 4.2+'); + } + + $container = $this->createContainerFromFile('validation_auto_mapping'); + $parameter = [ + 'App\\' => ['services' => ['foo', 'bar']], + 'Symfony\\' => ['services' => ['a', 'b']], + 'Foo\\' => ['services' => []], + ]; + + $this->assertSame($parameter, $container->getParameter('validator.auto_mapping')); + $this->assertTrue($container->hasDefinition('validator.property_info_loader')); + } + public function testFormsCanBeEnabledWithoutCsrfProtection() { $container = $this->createContainerFromFile('form_no_csrf'); diff --git a/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php b/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php new file mode 100644 index 0000000000000..fc110bbbe66a9 --- /dev/null +++ b/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Injects the automapping configuration as last argument of loaders tagged with the "validator.auto_mapper" tag. + * + * @author Kévin Dunglas + */ +class AddAutoMappingConfigurationPass implements CompilerPassInterface +{ + private $validatorBuilderService; + private $tag; + + public function __construct(string $validatorBuilderService = 'validator.builder', string $tag = 'validator.auto_mapper') + { + $this->validatorBuilderService = $validatorBuilderService; + $this->tag = $tag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasParameter('validator.auto_mapping') || !$container->hasDefinition($this->validatorBuilderService)) { + return; + } + + $config = $container->getParameter('validator.auto_mapping'); + + $globalNamespaces = []; + $servicesToNamespaces = []; + foreach ($config as $namespace => $value) { + if ([] === $value['services']) { + $globalNamespaces[] = $namespace; + + continue; + } + + foreach ($value['services'] as $service) { + $servicesToNamespaces[$service][] = $namespace; + } + } + + $validatorBuilder = $container->getDefinition($this->validatorBuilderService); + foreach ($container->findTaggedServiceIds($this->tag) as $id => $tags) { + $regexp = $this->getRegexp(array_merge($globalNamespaces, $servicesToNamespaces[$id] ?? [])); + + $container->getDefinition($id)->setArgument('$classValidatorRegexp', $regexp); + $validatorBuilder->addMethodCall('addLoader', [new Reference($id)]); + } + + $container->getParameterBag()->remove('validator.auto_mapping'); + } + + /** + * Builds a regexp to check if a class is auto-mapped. + */ + private function getRegexp(array $patterns): string + { + $regexps = []; + foreach ($patterns as $pattern) { + // Escape namespace + $regex = preg_quote(ltrim($pattern, '\\')); + + // Wildcards * and ** + $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']); + + // If this class does not end by a slash, anchor the end + if ('\\' !== substr($regex, -1)) { + $regex .= '$'; + } + + $regexps[] = '^'.$regex; + } + + return sprintf('{%s}', implode('|', $regexps)); + } +} diff --git a/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php b/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php new file mode 100644 index 0000000000000..58ed2669d6f2f --- /dev/null +++ b/src/Symfony/Component/Validator/Mapping/Loader/PropertyInfoLoader.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Mapping\Loader; + +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; +use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; +use Symfony\Component\PropertyInfo\Type as PropertyInfoType; +use Symfony\Component\Validator\Constraints\All; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Validator\Constraints\Type; +use Symfony\Component\Validator\Mapping\ClassMetadata; + +/** + * Guesses and loads the appropriate constraints using PropertyInfo. + * + * @author Kévin Dunglas + */ +final class PropertyInfoLoader implements LoaderInterface +{ + private $listExtractor; + private $typeExtractor; + private $classValidatorRegexp; + + public function __construct(PropertyListExtractorInterface $listExtractor, PropertyTypeExtractorInterface $typeExtractor, string $classValidatorRegexp = null) + { + $this->listExtractor = $listExtractor; + $this->typeExtractor = $typeExtractor; + $this->classValidatorRegexp = $classValidatorRegexp; + } + + /** + * {@inheritdoc} + */ + public function loadClassMetadata(ClassMetadata $metadata) + { + $className = $metadata->getClassName(); + if (null !== $this->classValidatorRegexp && !preg_match($this->classValidatorRegexp, $className)) { + return false; + } + + if (!$properties = $this->listExtractor->getProperties($className)) { + return false; + } + + foreach ($properties as $property) { + $types = $this->typeExtractor->getTypes($className, $property); + if (null === $types) { + continue; + } + + $hasTypeConstraint = false; + $hasNotNullConstraint = false; + $hasNotBlankConstraint = false; + $allConstraint = null; + foreach ($metadata->getPropertyMetadata($property) as $propertyMetadata) { + foreach ($propertyMetadata->getConstraints() as $constraint) { + if ($constraint instanceof Type) { + $hasTypeConstraint = true; + } elseif ($constraint instanceof NotNull) { + $hasNotNullConstraint = true; + } elseif ($constraint instanceof NotBlank) { + $hasNotBlankConstraint = true; + } elseif ($constraint instanceof All) { + $allConstraint = $constraint; + } + } + } + + $builtinTypes = []; + $nullable = false; + $scalar = true; + foreach ($types as $type) { + $builtinTypes[] = $type->getBuiltinType(); + + if ($scalar && !\in_array($type->getBuiltinType(), [PropertyInfoType::BUILTIN_TYPE_INT, PropertyInfoType::BUILTIN_TYPE_FLOAT, PropertyInfoType::BUILTIN_TYPE_STRING, PropertyInfoType::BUILTIN_TYPE_BOOL], true)) { + $scalar = false; + } + + if (!$nullable && $type->isNullable()) { + $nullable = true; + } + } + if (!$hasTypeConstraint) { + if (1 === \count($builtinTypes)) { + if ($types[0]->isCollection() && (null !== $collectionValueType = $types[0]->getCollectionValueType())) { + $this->handleAllConstraint($property, $allConstraint, $collectionValueType, $metadata); + } + + $metadata->addPropertyConstraint($property, $this->getTypeConstraint($builtinTypes[0], $types[0])); + } elseif ($scalar) { + $metadata->addPropertyConstraint($property, new Type(['type' => 'scalar'])); + } + } + + if (!$nullable && !$hasNotBlankConstraint && !$hasNotNullConstraint) { + $metadata->addPropertyConstraint($property, new NotNull()); + } + } + + return true; + } + + private function getTypeConstraint(string $builtinType, PropertyInfoType $type): Type + { + if (PropertyInfoType::BUILTIN_TYPE_OBJECT === $builtinType && null !== $className = $type->getClassName()) { + return new Type(['type' => $className]); + } + + return new Type(['type' => $builtinType]); + } + + private function handleAllConstraint(string $property, ?All $allConstraint, PropertyInfoType $propertyInfoType, ClassMetadata $metadata) + { + $containsTypeConstraint = false; + $containsNotNullConstraint = false; + if (null !== $allConstraint) { + foreach ($allConstraint->constraints as $constraint) { + if ($constraint instanceof Type) { + $containsTypeConstraint = true; + } elseif ($constraint instanceof NotNull) { + $containsNotNullConstraint = true; + } + } + } + + $constraints = []; + if (!$containsNotNullConstraint && !$propertyInfoType->isNullable()) { + $constraints[] = new NotNull(); + } + + if (!$containsTypeConstraint) { + $constraints[] = $this->getTypeConstraint($propertyInfoType->getBuiltinType(), $propertyInfoType); + } + + if (null === $allConstraint) { + $metadata->addPropertyConstraint($property, new All(['constraints' => $constraints])); + } else { + $allConstraint->constraints = array_merge($allConstraint->constraints, $constraints); + } + } +} diff --git a/src/Symfony/Component/Validator/Tests/DependencyInjection/AddAutoMappingConfigurationPassTest.php b/src/Symfony/Component/Validator/Tests/DependencyInjection/AddAutoMappingConfigurationPassTest.php new file mode 100644 index 0000000000000..b4b5699760404 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/DependencyInjection/AddAutoMappingConfigurationPassTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\Validator\DependencyInjection\AddAutoMappingConfigurationPass; +use Symfony\Component\Validator\Tests\Fixtures\PropertyInfoLoaderEntity; +use Symfony\Component\Validator\ValidatorBuilder; + +/** + * @author Kévin Dunglas + */ +class AddAutoMappingConfigurationPassTest extends TestCase +{ + public function testNoConfigParameter() + { + $container = new ContainerBuilder(); + (new AddAutoMappingConfigurationPass())->process($container); + $this->assertCount(1, $container->getDefinitions()); + } + + public function testNoValidatorBuilder() + { + $container = new ContainerBuilder(); + (new AddAutoMappingConfigurationPass())->process($container); + $this->assertCount(1, $container->getDefinitions()); + } + + /** + * @dataProvider mappingProvider + */ + public function testProcess(string $namespace, array $services, string $expectedRegexp) + { + $container = new ContainerBuilder(); + $container->setParameter('validator.auto_mapping', [ + 'App\\' => ['services' => []], + $namespace => ['services' => $services], + ]); + + $container->register('validator.builder', ValidatorBuilder::class); + foreach ($services as $service) { + $container->register($service)->addTag('validator.auto_mapper'); + } + + (new AddAutoMappingConfigurationPass())->process($container); + + foreach ($services as $service) { + $this->assertSame($expectedRegexp, $container->getDefinition($service)->getArgument('$classValidatorRegexp')); + } + $this->assertCount(\count($services), $container->getDefinition('validator.builder')->getMethodCalls()); + } + + public function mappingProvider(): array + { + return [ + ['Foo\\', ['foo', 'baz'], '{^App\\\\|^Foo\\\\}'], + [PropertyInfoLoaderEntity::class, ['class'], '{^App\\\\|^Symfony\\\\Component\\\\Validator\\\\Tests\\\\Fixtures\\\\PropertyInfoLoaderEntity$}'], + ['Symfony\Component\Validator\Tests\Fixtures\\', ['trailing_antislash'], '{^App\\\\|^Symfony\\\\Component\\\\Validator\\\\Tests\\\\Fixtures\\\\}'], + ['Symfony\Component\Validator\Tests\Fixtures\\*', ['trailing_star'], '{^App\\\\|^Symfony\\\\Component\\\\Validator\\\\Tests\\\\Fixtures\\\\[^\\\\]*?$}'], + ['Symfony\Component\Validator\Tests\Fixtures\\**', ['trailing_double_star'], '{^App\\\\|^Symfony\\\\Component\\\\Validator\\\\Tests\\\\Fixtures\\\\.*?$}'], + ]; + } +} diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/PropertyInfoLoaderEntity.php b/src/Symfony/Component/Validator/Tests/Fixtures/PropertyInfoLoaderEntity.php new file mode 100644 index 0000000000000..6e66c08b20365 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/PropertyInfoLoaderEntity.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Fixtures; + +use Symfony\Component\Validator\Constraints as Assert; + +/** + * @author Kévin Dunglas + */ +class PropertyInfoLoaderEntity +{ + public $nullableString; + public $string; + public $scalar; + public $object; + public $collection; + + /** + * @Assert\Type(type="int") + */ + public $alreadyMappedType; + + /** + * @Assert\NotNull + */ + public $alreadyMappedNotNull; + + /** + * @Assert\NotBlank + */ + public $alreadyMappedNotBlank; + + /** + * @Assert\All({ + * @Assert\Type(type="string"), + * @Assert\Iban + * }) + */ + public $alreadyPartiallyMappedCollection; +} diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php new file mode 100644 index 0000000000000..87898341d29bb --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/PropertyInfoLoaderTest.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Mapping\Loader; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; +use Symfony\Component\PropertyInfo\Type; +use Symfony\Component\Validator\Constraints\All; +use Symfony\Component\Validator\Constraints\Iban; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Validator\Constraints\Type as TypeConstraint; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader; +use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Tests\Fixtures\PropertyInfoLoaderEntity; +use Symfony\Component\Validator\Validation; + +/** + * @author Kévin Dunglas + */ +class PropertyInfoLoaderTest extends TestCase +{ + public function testLoadClassMetadata() + { + $propertyInfoStub = $this->createMock(PropertyInfoExtractorInterface::class); + $propertyInfoStub + ->method('getProperties') + ->willReturn([ + 'nullableString', + 'string', + 'scalar', + 'object', + 'collection', + 'alreadyMappedType', + 'alreadyMappedNotNull', + 'alreadyMappedNotBlank', + 'alreadyPartiallyMappedCollection', + ]) + ; + $propertyInfoStub + ->method('getTypes') + ->will($this->onConsecutiveCalls( + [new Type(Type::BUILTIN_TYPE_STRING, true)], + [new Type(Type::BUILTIN_TYPE_STRING)], + [new Type(Type::BUILTIN_TYPE_STRING, true), new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_BOOL)], + [new Type(Type::BUILTIN_TYPE_OBJECT, true, Entity::class)], + [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, null, new Type(Type::BUILTIN_TYPE_OBJECT, false, Entity::class))], + [new Type(Type::BUILTIN_TYPE_FLOAT, true)], // The existing constraint is float + [new Type(Type::BUILTIN_TYPE_STRING, true)], + [new Type(Type::BUILTIN_TYPE_STRING, true)], + [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true, null, new Type(Type::BUILTIN_TYPE_FLOAT))] + )) + ; + + $propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub); + + $validator = Validation::createValidatorBuilder() + ->enableAnnotationMapping() + ->addLoader($propertyInfoLoader) + ->getValidator() + ; + + $classMetadata = $validator->getMetadataFor(new PropertyInfoLoaderEntity()); + + $nullableStringMetadata = $classMetadata->getPropertyMetadata('nullableString'); + $this->assertCount(1, $nullableStringMetadata); + $nullableStringConstraints = $nullableStringMetadata[0]->getConstraints(); + $this->assertCount(1, $nullableStringConstraints); + $this->assertInstanceOf(TypeConstraint::class, $nullableStringConstraints[0]); + $this->assertSame('string', $nullableStringConstraints[0]->type); + + $stringMetadata = $classMetadata->getPropertyMetadata('string'); + $this->assertCount(1, $stringMetadata); + $stringConstraints = $stringMetadata[0]->getConstraints(); + $this->assertCount(2, $stringConstraints); + $this->assertInstanceOf(TypeConstraint::class, $stringConstraints[0]); + $this->assertSame('string', $stringConstraints[0]->type); + $this->assertInstanceOf(NotNull::class, $stringConstraints[1]); + + $scalarMetadata = $classMetadata->getPropertyMetadata('scalar'); + $this->assertCount(1, $scalarMetadata); + $scalarConstraints = $scalarMetadata[0]->getConstraints(); + $this->assertCount(1, $scalarConstraints); + $this->assertInstanceOf(TypeConstraint::class, $scalarConstraints[0]); + $this->assertSame('scalar', $scalarConstraints[0]->type); + + $objectMetadata = $classMetadata->getPropertyMetadata('object'); + $this->assertCount(1, $objectMetadata); + $objectConstraints = $objectMetadata[0]->getConstraints(); + $this->assertCount(1, $objectConstraints); + $this->assertInstanceOf(TypeConstraint::class, $objectConstraints[0]); + $this->assertSame(Entity::class, $objectConstraints[0]->type); + + $collectionMetadata = $classMetadata->getPropertyMetadata('collection'); + $this->assertCount(1, $collectionMetadata); + $collectionConstraints = $collectionMetadata[0]->getConstraints(); + $this->assertCount(2, $collectionConstraints); + $this->assertInstanceOf(All::class, $collectionConstraints[0]); + $this->assertInstanceOf(NotNull::class, $collectionConstraints[0]->constraints[0]); + $this->assertInstanceOf(TypeConstraint::class, $collectionConstraints[0]->constraints[1]); + $this->assertSame(Entity::class, $collectionConstraints[0]->constraints[1]->type); + + $alreadyMappedTypeMetadata = $classMetadata->getPropertyMetadata('alreadyMappedType'); + $this->assertCount(1, $alreadyMappedTypeMetadata); + $alreadyMappedTypeConstraints = $alreadyMappedTypeMetadata[0]->getConstraints(); + $this->assertCount(1, $alreadyMappedTypeMetadata); + $this->assertInstanceOf(TypeConstraint::class, $alreadyMappedTypeConstraints[0]); + + $alreadyMappedNotNullMetadata = $classMetadata->getPropertyMetadata('alreadyMappedNotNull'); + $this->assertCount(1, $alreadyMappedNotNullMetadata); + $alreadyMappedNotNullConstraints = $alreadyMappedNotNullMetadata[0]->getConstraints(); + $this->assertCount(1, $alreadyMappedNotNullMetadata); + $this->assertInstanceOf(NotNull::class, $alreadyMappedNotNullConstraints[0]); + + $alreadyMappedNotBlankMetadata = $classMetadata->getPropertyMetadata('alreadyMappedNotBlank'); + $this->assertCount(1, $alreadyMappedNotBlankMetadata); + $alreadyMappedNotBlankConstraints = $alreadyMappedNotBlankMetadata[0]->getConstraints(); + $this->assertCount(1, $alreadyMappedNotBlankMetadata); + $this->assertInstanceOf(NotBlank::class, $alreadyMappedNotBlankConstraints[0]); + + $alreadyPartiallyMappedCollectionMetadata = $classMetadata->getPropertyMetadata('alreadyPartiallyMappedCollection'); + $this->assertCount(1, $alreadyPartiallyMappedCollectionMetadata); + $alreadyPartiallyMappedCollectionConstraints = $alreadyPartiallyMappedCollectionMetadata[0]->getConstraints(); + $this->assertCount(2, $alreadyPartiallyMappedCollectionConstraints); + $this->assertInstanceOf(All::class, $alreadyPartiallyMappedCollectionConstraints[0]); + $this->assertInstanceOf(TypeConstraint::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[0]); + $this->assertSame('string', $alreadyPartiallyMappedCollectionConstraints[0]->constraints[0]->type); + $this->assertInstanceOf(Iban::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[1]); + $this->assertInstanceOf(NotNull::class, $alreadyPartiallyMappedCollectionConstraints[0]->constraints[2]); + } + + /** + * @dataProvider regexpProvider + */ + public function testClassValidator(bool $expected, string $classValidatorRegexp = null) + { + $propertyInfoStub = $this->createMock(PropertyInfoExtractorInterface::class); + $propertyInfoStub + ->method('getProperties') + ->willReturn(['string']) + ; + $propertyInfoStub + ->method('getTypes') + ->willReturn([new Type(Type::BUILTIN_TYPE_STRING)]) + ; + + $propertyInfoLoader = new PropertyInfoLoader($propertyInfoStub, $propertyInfoStub, $classValidatorRegexp); + + $classMetadata = new ClassMetadata(PropertyInfoLoaderEntity::class); + $this->assertSame($expected, $propertyInfoLoader->loadClassMetadata($classMetadata)); + } + + public function regexpProvider() + { + return [ + [true, null], + [true, '{^'.preg_quote(PropertyInfoLoaderEntity::class).'$|^'.preg_quote(Entity::class).'$}'], + [false, '{^'.preg_quote(Entity::class).'$}'], + ]; + } +} diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index c17fd098f5743..9bb26f56785ec 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -32,6 +32,7 @@ "symfony/expression-language": "~3.4|~4.0", "symfony/cache": "~3.4|~4.0", "symfony/property-access": "~3.4|~4.0", + "symfony/property-info": "~3.4|~4.0", "symfony/translation": "~4.2", "doctrine/annotations": "~1.0", "doctrine/cache": "~1.0", @@ -56,6 +57,7 @@ "symfony/config": "", "egulias/email-validator": "Strict (RFC compliant) email validation", "symfony/property-access": "For accessing properties within comparison constraints", + "symfony/property-info": "To automatically add NotNull and Type constraints", "symfony/expression-language": "For using the Expression validator" }, "autoload": { From 26f6e28160ecedd4bb600bcb52cb28bbdfaebad0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 21 Mar 2019 12:59:19 +0100 Subject: [PATCH 242/495] [HttpClient] improve MockResponse --- .../HttpClient/Response/MockResponse.php | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 4d0bc43ea4d15..c6630b65bcc08 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -27,6 +27,7 @@ class MockResponse implements ResponseInterface use ResponseTrait; private $body; + private $requestOptions = []; private static $mainMulti; private static $idSequence = 0; @@ -42,6 +43,28 @@ public function __construct($body = '', array $info = []) { $this->body = \is_iterable($body) ? $body : (string) $body; $this->info = $info + $this->info; + + if (!isset($info['raw_headers'])) { + return; + } + + $rawHeaders = []; + + foreach ($info['raw_headers'] as $k => $v) { + foreach ((array) $v as $v) { + $rawHeaders[] = (\is_string($k) ? $k.': ' : '').$v; + } + } + + $info['raw_headers'] = $rawHeaders; + } + + /** + * Returns the options used when doing the request. + */ + public function getRequestOptions(): array + { + return $this->requestOptions; } /** @@ -66,6 +89,7 @@ protected function close(): void public static function fromRequest(string $method, string $url, array $options, ResponseInterface $mock): self { $response = new self([]); + $response->requestOptions = $options; $response->id = ++self::$idSequence; $response->content = ($options['buffer'] ?? true) ? fopen('php://temp', 'w+') : null; $response->initializer = static function (self $response) { From 7e30c971abe6712a8e0d37f467d8f19fc40b2baa Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 22 Mar 2019 07:07:54 +0100 Subject: [PATCH 243/495] fixed CS --- .../Processor/ConsoleCommandProcessor.php | 10 +++--- .../Monolog/Processor/RouteProcessor.php | 14 ++++---- .../Processor/ConsoleCommandProcessorTest.php | 16 ++++----- .../Tests/Processor/RouteProcessorTest.php | 36 +++++++++---------- .../Console/Descriptor/TextDescriptor.php | 2 +- .../Fixtures/php/templating.php | 18 +++++----- .../Tests/Functional/AutowiringTypesTest.php | 2 +- .../Tests/LegacyEventDispatcherTest.php | 1 - .../Event/ControllerArgumentsEventTest.php | 4 +-- .../AuthenticationProviderManager.php | 2 +- .../AuthenticationProviderManagerTest.php | 2 +- .../Firewall/GuardAuthenticationListener.php | 2 +- .../Component/Security/Http/Firewall.php | 2 +- .../Tests/Firewall/ExceptionListenerTest.php | 2 +- src/Symfony/Component/Workflow/Workflow.php | 7 ++-- 15 files changed, 59 insertions(+), 61 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php b/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php index 1fb8cc1ef37d4..2891f4f2f4916 100644 --- a/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/ConsoleCommandProcessor.php @@ -49,9 +49,9 @@ public function reset() public function addCommandData(ConsoleEvent $event) { - $this->commandData = array( + $this->commandData = [ 'name' => $event->getCommand()->getName(), - ); + ]; if ($this->includeArguments) { $this->commandData['arguments'] = $event->getInput()->getArguments(); } @@ -62,8 +62,8 @@ public function addCommandData(ConsoleEvent $event) public static function getSubscribedEvents() { - return array( - ConsoleEvents::COMMAND => array('addCommandData', 1), - ); + return [ + ConsoleEvents::COMMAND => ['addCommandData', 1], + ]; } } diff --git a/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php b/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php index b00c97079b38d..0160754ad9575 100644 --- a/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/RouteProcessor.php @@ -44,7 +44,7 @@ public function __invoke(array $records) public function reset() { - $this->routeData = array(); + $this->routeData = []; } public function addRouteData(GetResponseEvent $event) @@ -58,10 +58,10 @@ public function addRouteData(GetResponseEvent $event) return; } - $currentRequestData = array( + $currentRequestData = [ 'controller' => $request->attributes->get('_controller'), 'route' => $request->attributes->get('_route'), - ); + ]; if ($this->includeParams) { $currentRequestData['route_params'] = $request->attributes->get('_route_params'); @@ -78,9 +78,9 @@ public function removeRouteData(FinishRequestEvent $event) public static function getSubscribedEvents() { - return array( - KernelEvents::REQUEST => array('addRouteData', 1), - KernelEvents::FINISH_REQUEST => array('removeRouteData', 1), - ); + return [ + KernelEvents::REQUEST => ['addRouteData', 1], + KernelEvents::FINISH_REQUEST => ['removeRouteData', 1], + ]; } } diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php index 2709c6a395bfe..4c9774b4a4385 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/ConsoleCommandProcessorTest.php @@ -19,8 +19,8 @@ class ConsoleCommandProcessorTest extends TestCase { - private const TEST_ARGUMENTS = array('test' => 'argument'); - private const TEST_OPTIONS = array('test' => 'option'); + private const TEST_ARGUMENTS = ['test' => 'argument']; + private const TEST_OPTIONS = ['test' => 'option']; private const TEST_NAME = 'some:test'; public function testProcessor() @@ -28,11 +28,11 @@ public function testProcessor() $processor = new ConsoleCommandProcessor(); $processor->addCommandData($this->getConsoleEvent()); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayHasKey('command', $record['extra']); $this->assertEquals( - array('name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS), + ['name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS], $record['extra']['command'] ); } @@ -42,11 +42,11 @@ public function testProcessorWithOptions() $processor = new ConsoleCommandProcessor(true, true); $processor->addCommandData($this->getConsoleEvent()); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayHasKey('command', $record['extra']); $this->assertEquals( - array('name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS, 'options' => self::TEST_OPTIONS), + ['name' => self::TEST_NAME, 'arguments' => self::TEST_ARGUMENTS, 'options' => self::TEST_OPTIONS], $record['extra']['command'] ); } @@ -55,8 +55,8 @@ public function testProcessorDoesNothingWhenNotInConsole() { $processor = new ConsoleCommandProcessor(true, true); - $record = $processor(array('extra' => array())); - $this->assertEquals(array('extra' => array()), $record); + $record = $processor(['extra' => []]); + $this->assertEquals(['extra' => []], $record); } private function getConsoleEvent(): ConsoleEvent diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/RouteProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/RouteProcessorTest.php index 2a9c06588628d..5534240ba278a 100644 --- a/src/Symfony/Bridge/Monolog/Tests/Processor/RouteProcessorTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/RouteProcessorTest.php @@ -22,7 +22,7 @@ class RouteProcessorTest extends TestCase { private const TEST_CONTROLLER = 'App\Controller\SomeController::someMethod'; private const TEST_ROUTE = 'someRouteName'; - private const TEST_PARAMS = array('param1' => 'value1'); + private const TEST_PARAMS = ['param1' => 'value1']; public function testProcessor() { @@ -30,12 +30,12 @@ public function testProcessor() $processor = new RouteProcessor(); $processor->addRouteData($this->mockGetResponseEvent($request)); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayHasKey('requests', $record['extra']); $this->assertCount(1, $record['extra']['requests']); $this->assertEquals( - array('controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE, 'route_params' => self::TEST_PARAMS), + ['controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE, 'route_params' => self::TEST_PARAMS], $record['extra']['requests'][0] ); } @@ -46,12 +46,12 @@ public function testProcessorWithoutParams() $processor = new RouteProcessor(false); $processor->addRouteData($this->mockGetResponseEvent($request)); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayHasKey('requests', $record['extra']); $this->assertCount(1, $record['extra']['requests']); $this->assertEquals( - array('controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE), + ['controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE], $record['extra']['requests'][0] ); } @@ -66,16 +66,16 @@ public function testProcessorWithSubRequests() $processor->addRouteData($this->mockGetResponseEvent($mainRequest)); $processor->addRouteData($this->mockGetResponseEvent($subRequest)); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayHasKey('requests', $record['extra']); $this->assertCount(2, $record['extra']['requests']); $this->assertEquals( - array('controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE), + ['controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE], $record['extra']['requests'][0] ); $this->assertEquals( - array('controller' => $controllerFromSubRequest, 'route' => self::TEST_ROUTE), + ['controller' => $controllerFromSubRequest, 'route' => self::TEST_ROUTE], $record['extra']['requests'][1] ); } @@ -89,17 +89,17 @@ public function testFinishRequestRemovesRelatedEntry() $processor->addRouteData($this->mockGetResponseEvent($mainRequest)); $processor->addRouteData($this->mockGetResponseEvent($subRequest)); $processor->removeRouteData($this->mockFinishRequestEvent($subRequest)); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayHasKey('requests', $record['extra']); $this->assertCount(1, $record['extra']['requests']); $this->assertEquals( - array('controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE), + ['controller' => self::TEST_CONTROLLER, 'route' => self::TEST_ROUTE], $record['extra']['requests'][0] ); $processor->removeRouteData($this->mockFinishRequestEvent($mainRequest)); - $record = $processor(array('extra' => array())); + $record = $processor(['extra' => []]); $this->assertArrayNotHasKey('requests', $record['extra']); } @@ -110,16 +110,16 @@ public function testProcessorWithEmptyRequest() $processor = new RouteProcessor(); $processor->addRouteData($this->mockGetResponseEvent($request)); - $record = $processor(array('extra' => array())); - $this->assertEquals(array('extra' => array()), $record); + $record = $processor(['extra' => []]); + $this->assertEquals(['extra' => []], $record); } public function testProcessorDoesNothingWhenNoRequest() { $processor = new RouteProcessor(); - $record = $processor(array('extra' => array())); - $this->assertEquals(array('extra' => array()), $record); + $record = $processor(['extra' => []]); + $this->assertEquals(['extra' => []], $record); } private function mockGetResponseEvent(Request $request): GetResponseEvent @@ -140,16 +140,16 @@ private function mockFinishRequestEvent(Request $request): FinishRequestEvent private function mockEmptyRequest(): Request { - return $this->mockRequest(array()); + return $this->mockRequest([]); } private function mockFilledRequest(string $controller = self::TEST_CONTROLLER): Request { - return $this->mockRequest(array( + return $this->mockRequest([ '_controller' => $controller, '_route' => self::TEST_ROUTE, '_route_params' => self::TEST_PARAMS, - )); + ]); } private function mockRequest(array $attributes): Request diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 3fbeb87ab0436..8980a9ee41f5e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -93,7 +93,7 @@ protected function describeRoute(Route $route, array $options = []) ]; if ('' !== $route->getCondition()) { - $tableRows[] = array('Condition', $route->getCondition()); + $tableRows[] = ['Condition', $route->getCondition()]; } $table = new Table($this->getOutput()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating.php index 162d09199fd86..a7edabf763afd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/templating.php @@ -1,14 +1,14 @@ loadFromExtension('framework', array( - 'templating' => array( +$container->loadFromExtension('framework', [ + 'templating' => [ 'cache' => '/path/to/cache', - 'engines' => array('php', 'twig'), - 'loader' => array('loader.foo', 'loader.bar'), - 'form' => array( - 'resources' => array('theme1', 'theme2'), - ), + 'engines' => ['php', 'twig'], + 'loader' => ['loader.foo', 'loader.bar'], + 'form' => [ + 'resources' => ['theme1', 'theme2'], + ], 'hinclude_default_template' => 'global_hinclude_template', - ), + ], 'assets' => null, -)); +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php index 8e582b13a89a0..e4338e3746c11 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AutowiringTypesTest.php @@ -42,7 +42,7 @@ public function testCachedAnnotationReaderAutowiring() */ public function testTemplatingAutowiring() { - static::bootKernel(array('root_config' => 'templating.yml', 'environment' => 'templating')); + static::bootKernel(['root_config' => 'templating.yml', 'environment' => 'templating']); $autowiredServices = static::$container->get('test.autowiring_types.autowired_services'); $this->assertInstanceOf(FrameworkBundleEngineInterface::class, $autowiredServices->getFrameworkBundleEngine()); diff --git a/src/Symfony/Component/EventDispatcher/Tests/LegacyEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/LegacyEventDispatcherTest.php index d17e9f14062f6..49aa2f9ff3f92 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/LegacyEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/LegacyEventDispatcherTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\EventDispatcher\Tests; -use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; diff --git a/src/Symfony/Component/HttpKernel/Tests/Event/ControllerArgumentsEventTest.php b/src/Symfony/Component/HttpKernel/Tests/Event/ControllerArgumentsEventTest.php index 50faf232919b8..7758a66667f6d 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Event/ControllerArgumentsEventTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Event/ControllerArgumentsEventTest.php @@ -11,7 +11,7 @@ class ControllerArgumentsEventTest extends TestCase { public function testControllerArgumentsEvent() { - $filterController = new ControllerArgumentsEvent(new TestHttpKernel(), function () {}, array('test'), new Request(), 1); - $this->assertEquals($filterController->getArguments(), array('test')); + $filterController = new ControllerArgumentsEvent(new TestHttpKernel(), function () {}, ['test'], new Request(), 1); + $this->assertEquals($filterController->getArguments(), ['test']); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php index 5a3a4cec53c5e..fca4add09c3a3 100644 --- a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php +++ b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php @@ -16,8 +16,8 @@ use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\AuthenticationEvents; -use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent; +use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\Exception\AccountStatusException; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\ProviderNotFoundException; diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php index c2a66a49f68bf..4252bfe64dc9d 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationProviderManagerTest.php @@ -16,8 +16,8 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\AuthenticationEvents; -use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent; +use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\Exception\AccountStatusException; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\ProviderNotFoundException; diff --git a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php index 2821d2a91d834..25de3ce44079c 100644 --- a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php +++ b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php @@ -21,8 +21,8 @@ use Symfony\Component\Security\Guard\AuthenticatorInterface; use Symfony\Component\Security\Guard\GuardAuthenticatorHandler; use Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken; -use Symfony\Component\Security\Http\Firewall\ListenerInterface; use Symfony\Component\Security\Http\Firewall\LegacyListenerTrait; +use Symfony\Component\Security\Http\Firewall\ListenerInterface; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; /** diff --git a/src/Symfony/Component/Security/Http/Firewall.php b/src/Symfony/Component/Security/Http/Firewall.php index a1bdaa02be973..bff8e3e884c49 100644 --- a/src/Symfony/Component/Security/Http/Firewall.php +++ b/src/Symfony/Component/Security/Http/Firewall.php @@ -14,8 +14,8 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; -use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Http\Firewall\AccessListener; use Symfony\Component\Security\Http\Firewall\LogoutListener; diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 96b8940ccbd09..ecbf614a693c3 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -14,9 +14,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index c0866c663796a..69e36a133a071 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -13,13 +13,12 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; -use Symfony\Component\Workflow\Event\Event; -use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Event\AnnounceEvent; -use Symfony\Component\Workflow\Event\EnterEvent; +use Symfony\Component\Workflow\Event\CompletedEvent; use Symfony\Component\Workflow\Event\EnteredEvent; +use Symfony\Component\Workflow\Event\EnterEvent; +use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Event\LeaveEvent; -use Symfony\Component\Workflow\Event\CompletedEvent; use Symfony\Component\Workflow\Event\TransitionEvent; use Symfony\Component\Workflow\Exception\LogicException; use Symfony\Component\Workflow\Exception\NotEnabledTransitionException; From 9491393dc2f7bf9da9421ef45faeb313a544ea2b Mon Sep 17 00:00:00 2001 From: Ahmed Abdou Date: Tue, 5 Mar 2019 01:59:42 +0100 Subject: [PATCH 244/495] [Finder] Ignore paths from .gitignore #26714 --- src/Symfony/Component/Finder/CHANGELOG.md | 5 + src/Symfony/Component/Finder/Finder.php | 27 ++++ src/Symfony/Component/Finder/Gitignore.php | 107 ++++++++++++++++ .../Component/Finder/Tests/FinderTest.php | 34 ++++- .../Component/Finder/Tests/GitignoreTest.php | 118 ++++++++++++++++++ .../Iterator/DepthRangeFilterIteratorTest.php | 2 + .../ExcludeDirectoryFilterIteratorTest.php | 3 + .../Tests/Iterator/RealIteratorTestCase.php | 2 + 8 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Finder/Gitignore.php create mode 100644 src/Symfony/Component/Finder/Tests/GitignoreTest.php diff --git a/src/Symfony/Component/Finder/CHANGELOG.md b/src/Symfony/Component/Finder/CHANGELOG.md index 9abccfc237f44..2045184e83331 100644 --- a/src/Symfony/Component/Finder/CHANGELOG.md +++ b/src/Symfony/Component/Finder/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added Finder::ignoreVCSIgnored() to ignore files based on rules listed in .gitignore + 4.2.0 ----- diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php index 83163f51d52eb..f791f8cf32a8f 100644 --- a/src/Symfony/Component/Finder/Finder.php +++ b/src/Symfony/Component/Finder/Finder.php @@ -39,6 +39,7 @@ class Finder implements \IteratorAggregate, \Countable { const IGNORE_VCS_FILES = 1; const IGNORE_DOT_FILES = 2; + const IGNORE_VCS_IGNORED_FILES = 4; private $mode = 0; private $names = []; @@ -373,6 +374,24 @@ public function ignoreVCS($ignoreVCS) return $this; } + /** + * Forces Finder to obey .gitignore and ignore files based on rules listed there. + * + * This option is disabled by default. + * + * @return $this + */ + public function ignoreVCSIgnored(bool $ignoreVCSIgnored) + { + if ($ignoreVCSIgnored) { + $this->ignore |= static::IGNORE_VCS_IGNORED_FILES; + } else { + $this->ignore &= ~static::IGNORE_VCS_IGNORED_FILES; + } + + return $this; + } + /** * Adds VCS patterns. * @@ -685,6 +704,14 @@ private function searchInDirectory(string $dir): \Iterator $notPaths[] = '#(^|/)\..+(/|$)#'; } + if (static::IGNORE_VCS_IGNORED_FILES === (static::IGNORE_VCS_IGNORED_FILES & $this->ignore)) { + $gitignoreFilePath = sprintf('%s/.gitignore', $dir); + if (!is_readable($gitignoreFilePath)) { + throw new \RuntimeException(sprintf('The "ignoreVCSIgnored" option cannot be used by the Finder as the "%s" file is not readable.', $gitignoreFilePath)); + } + $notPaths = array_merge($notPaths, [Gitignore::toRegex(file_get_contents($gitignoreFilePath))]); + } + $minDepth = 0; $maxDepth = PHP_INT_MAX; diff --git a/src/Symfony/Component/Finder/Gitignore.php b/src/Symfony/Component/Finder/Gitignore.php new file mode 100644 index 0000000000000..fbeabdbd520b1 --- /dev/null +++ b/src/Symfony/Component/Finder/Gitignore.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Finder; + +/** + * Gitignore matches against text. + * + * @author Ahmed Abdou + */ +class Gitignore +{ + /** + * Returns a regexp which is the equivalent of the gitignore pattern. + * + * @param string $gitignoreFileContent + * + * @return string The regexp + */ + public static function toRegex(string $gitignoreFileContent): string + { + $gitignoreFileContent = preg_replace('/^[^\\\\]*#.*/', '', $gitignoreFileContent); + $gitignoreLines = preg_split('/\r\n|\r|\n/', $gitignoreFileContent); + $gitignoreLines = array_map('trim', $gitignoreLines); + $gitignoreLines = array_filter($gitignoreLines); + + $ignoreLinesPositive = array_filter($gitignoreLines, function (string $line) { + return !preg_match('/^!/', $line); + }); + + $ignoreLinesNegative = array_filter($gitignoreLines, function (string $line) { + return preg_match('/^!/', $line); + }); + + $ignoreLinesNegative = array_map(function (string $line) { + return preg_replace('/^!(.*)/', '${1}', $line); + }, $ignoreLinesNegative); + $ignoreLinesNegative = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesNegative); + + $ignoreLinesPositive = array_map([__CLASS__, 'getRegexFromGitignore'], $ignoreLinesPositive); + if (empty($ignoreLinesPositive)) { + return '/^$/'; + } + + if (empty($ignoreLinesNegative)) { + return sprintf('/%s/', implode('|', $ignoreLinesPositive)); + } + + return sprintf('/(?=^(?:(?!(%s)).)*$)(%s)/', implode('|', $ignoreLinesNegative), implode('|', $ignoreLinesPositive)); + } + + private static function getRegexFromGitignore(string $gitignorePattern): string + { + $regex = '('; + if (0 === strpos($gitignorePattern, '/')) { + $gitignorePattern = substr($gitignorePattern, 1); + $regex .= '^'; + } else { + $regex .= '(^|\/)'; + } + + if ('/' === $gitignorePattern[\strlen($gitignorePattern) - 1]) { + $gitignorePattern = substr($gitignorePattern, 0, -1); + } + + $iMax = \strlen($gitignorePattern); + for ($i = 0; $i < $iMax; ++$i) { + $doubleChars = substr($gitignorePattern, $i, 2); + if ('**' === $doubleChars) { + $regex .= '.+'; + ++$i; + continue; + } + + $c = $gitignorePattern[$i]; + switch ($c) { + case '*': + $regex .= '[^\/]+'; + break; + case '/': + case '.': + case ':': + case '(': + case ')': + case '{': + case '}': + $regex .= '\\'.$c; + break; + default: + $regex .= $c; + } + } + + $regex .= '($|\/)'; + $regex .= ')'; + + return $regex; + } +} diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 9217cb7190b53..9899c61fa6a5f 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -347,6 +347,7 @@ public function testIgnoreVCS() $finder = $this->buildFinder(); $this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false)); $this->assertIterator($this->toAbsolute([ + '.gitignore', '.git', 'foo', 'foo/bar.tmp', @@ -373,6 +374,7 @@ public function testIgnoreVCS() $finder = $this->buildFinder(); $finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false); $this->assertIterator($this->toAbsolute([ + '.gitignore', '.git', 'foo', 'foo/bar.tmp', @@ -399,6 +401,7 @@ public function testIgnoreVCS() $finder = $this->buildFinder(); $this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false)); $this->assertIterator($this->toAbsolute([ + '.gitignore', 'foo', 'foo/bar.tmp', 'test.php', @@ -421,6 +424,28 @@ public function testIgnoreVCS() ]), $finder->in(self::$tmpDir)->getIterator()); } + public function testIgnoreVCSIgnored() + { + $finder = $this->buildFinder(); + $this->assertSame( + $finder, + $finder + ->ignoreVCS(true) + ->ignoreDotFiles(true) + ->ignoreVCSIgnored(true) + ); + $this->assertIterator($this->toAbsolute([ + 'foo', + 'foo/bar.tmp', + 'test.py', + 'toto', + 'foo bar', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + ]), $finder->in(self::$tmpDir)->getIterator()); + } + public function testIgnoreVCSCanBeDisabledAfterFirstIteration() { $finder = $this->buildFinder(); @@ -428,6 +453,7 @@ public function testIgnoreVCSCanBeDisabledAfterFirstIteration() $finder->ignoreDotFiles(false); $this->assertIterator($this->toAbsolute([ + '.gitignore', 'foo', 'foo/bar.tmp', 'qux', @@ -450,7 +476,9 @@ public function testIgnoreVCSCanBeDisabledAfterFirstIteration() ]), $finder->getIterator()); $finder->ignoreVCS(false); - $this->assertIterator($this->toAbsolute(['.git', + $this->assertIterator($this->toAbsolute([ + '.gitignore', + '.git', 'foo', 'foo/bar.tmp', 'qux', @@ -479,6 +507,7 @@ public function testIgnoreDotFiles() $finder = $this->buildFinder(); $this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false)); $this->assertIterator($this->toAbsolute([ + '.gitignore', '.git', '.bar', '.foo', @@ -505,6 +534,7 @@ public function testIgnoreDotFiles() $finder = $this->buildFinder(); $finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false); $this->assertIterator($this->toAbsolute([ + '.gitignore', '.git', '.bar', '.foo', @@ -574,6 +604,7 @@ public function testIgnoreDotFilesCanBeDisabledAfterFirstIteration() $finder->ignoreDotFiles(false); $this->assertIterator($this->toAbsolute([ + '.gitignore', 'foo', 'foo/bar.tmp', 'qux', @@ -842,6 +873,7 @@ public function testIn() $expected = [ self::$tmpDir.\DIRECTORY_SEPARATOR.'test.php', + __DIR__.\DIRECTORY_SEPARATOR.'GitignoreTest.php', __DIR__.\DIRECTORY_SEPARATOR.'FinderTest.php', __DIR__.\DIRECTORY_SEPARATOR.'GlobTest.php', self::$tmpDir.\DIRECTORY_SEPARATOR.'qux_0_1.php', diff --git a/src/Symfony/Component/Finder/Tests/GitignoreTest.php b/src/Symfony/Component/Finder/Tests/GitignoreTest.php new file mode 100644 index 0000000000000..fca846d86e484 --- /dev/null +++ b/src/Symfony/Component/Finder/Tests/GitignoreTest.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Finder\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Finder\Gitignore; + +class GitignoreTest extends TestCase +{ + /** + * @dataProvider provider + * + * @param string $patterns + * @param array $matchingCases + * @param array $nonMatchingCases + */ + public function testCases(string $patterns, array $matchingCases, array $nonMatchingCases) + { + $regex = Gitignore::toRegex($patterns); + + foreach ($matchingCases as $matchingCase) { + $this->assertRegExp($regex, $matchingCase, sprintf('Failed asserting path [%s] matches gitignore patterns [%s] using regex [%s]', $matchingCase, $patterns, $regex)); + } + + foreach ($nonMatchingCases as $nonMatchingCase) { + $this->assertNotRegExp($regex, $nonMatchingCase, sprintf('Failed asserting path [%s] not matching gitignore patterns [%s] using regex [%s]', $nonMatchingCase, $patterns, $regex)); + } + } + + /** + * @return array return is array of + * [ + * [ + * '', // Git-ignore Pattern + * [], // array of file paths matching + * [], // array of file paths not matching + * ], + * ] + */ + public function provider() + { + return [ + [ + ' + * + !/bin/bash + ', + ['bin/cat', 'abc/bin/cat'], + ['bin/bash'], + ], + [ + 'fi#le.txt', + [], + ['#file.txt'], + ], + [ + ' + /bin/ + /usr/local/ + !/bin/bash + !/usr/local/bin/bash + ', + ['bin/cat'], + ['bin/bash'], + ], + [ + '*.py[co]', + ['file.pyc', 'file.pyc'], + ['filexpyc', 'file.pycx', 'file.py'], + ], + [ + 'dir1/**/dir2/', + ['dir1/dirA/dir2/', 'dir1/dirA/dirB/dir2/'], + [], + ], + [ + 'dir1/*/dir2/', + ['dir1/dirA/dir2/'], + ['dir1/dirA/dirB/dir2/'], + ], + [ + '/*.php', + ['file.php'], + ['app/file.php'], + ], + [ + '\#file.txt', + ['#file.txt'], + [], + ], + [ + '*.php', + ['app/file.php', 'file.php'], + ['file.phps', 'file.phps', 'filephps'], + ], + [ + 'app/cache/', + ['app/cache/file.txt', 'app/cache/dir1/dir2/file.txt', 'a/app/cache/file.txt'], + [], + ], + [ + ' + #IamComment + /app/cache/', + ['app/cache/file.txt', 'app/cache/subdir/ile.txt'], + ['a/app/cache/file.txt'], + ], + ]; + } +} diff --git a/src/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php index ef4fa2e9ac8dc..7c2572d21047c 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/DepthRangeFilterIteratorTest.php @@ -33,6 +33,7 @@ public function testAccept($minDepth, $maxDepth, $expected) public function getAcceptData() { $lessThan1 = [ + '.gitignore', '.git', 'test.py', 'foo', @@ -51,6 +52,7 @@ public function getAcceptData() ]; $lessThanOrEqualTo1 = [ + '.gitignore', '.git', 'test.py', 'foo', diff --git a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php index 1729766fe4bd0..dbf461f60e85d 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/ExcludeDirectoryFilterIteratorTest.php @@ -31,6 +31,7 @@ public function testAccept($directories, $expected) public function getAcceptData() { $foo = [ + '.gitignore', '.bar', '.foo', '.foo/.bar', @@ -53,6 +54,7 @@ public function getAcceptData() ]; $fo = [ + '.gitignore', '.bar', '.foo', '.foo/.bar', @@ -77,6 +79,7 @@ public function getAcceptData() ]; $toto = [ + '.gitignore', '.bar', '.foo', '.foo/.bar', diff --git a/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php b/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php index bd14167ab8332..4f4ba016a718a 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/RealIteratorTestCase.php @@ -63,6 +63,8 @@ public static function setUpBeforeClass() file_put_contents(self::toAbsolute('test.php'), str_repeat(' ', 800)); file_put_contents(self::toAbsolute('test.py'), str_repeat(' ', 2000)); + file_put_contents(self::toAbsolute('.gitignore'), '*.php'); + touch(self::toAbsolute('foo/bar.tmp'), strtotime('2005-10-15')); touch(self::toAbsolute('test.php'), strtotime('2005-10-15')); } From dd55845706afbc44037cd1f805050a27240a511c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 30 Jan 2019 10:26:19 +0100 Subject: [PATCH 245/495] [BrowserKit] added support for HttpClient --- src/Symfony/Component/BrowserKit/CHANGELOG.md | 1 + .../Component/BrowserKit/HttpBrowser.php | 109 ++++++++++++++++++ src/Symfony/Component/BrowserKit/README.md | 3 + .../Component/BrowserKit/composer.json | 3 +- .../HttpClient/Response/MockResponse.php | 2 +- 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/BrowserKit/HttpBrowser.php diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index 185071e6b2d66..b966974d8d716 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Added `HttpBrowser`, an implementation of a browser with the HttpClient component * Renamed `Client` to `AbstractBrowser` * Marked `Response` final. * Deprecated `Response::buildHeader()` diff --git a/src/Symfony/Component/BrowserKit/HttpBrowser.php b/src/Symfony/Component/BrowserKit/HttpBrowser.php new file mode 100644 index 0000000000000..cb13c738d38f9 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/HttpBrowser.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit; + +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Component\Mime\Part\TextPart; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * An implementation of a browser using the HttpClient component + * to make real HTTP requests. + * + * @author Fabien Potencier + * + * @final + */ +class HttpBrowser extends AbstractBrowser +{ + private $client; + + public function __construct(HttpClientInterface $client = null, History $history = null, CookieJar $cookieJar = null) + { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = $client ?? HttpClient::create(); + + parent::__construct([], $history, $cookieJar); + } + + protected function doRequest($request) + { + $headers = $this->getHeaders($request); + $body = ''; + if (null !== $part = $this->getBody($request)) { + $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); + $body = $part->bodyToIterable(); + } + $response = $this->client->request($request->getMethod(), $request->getUri(), [ + 'headers' => $headers, + 'body' => $body, + 'max_redirects' => 0, + ]); + + return new Response($response->getContent(false), $response->getStatusCode(), $response->getHeaders(false)); + } + + private function getBody(Request $request): ?AbstractPart + { + if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { + return null; + } + + if (!class_exists(AbstractPart::class)) { + throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".'); + } + + if (null !== $content = $request->getContent()) { + return new TextPart($content, 'utf-8', 'plain', '8bit'); + } + + $fields = $request->getParameters(); + foreach ($request->getFiles() as $name => $file) { + if (!isset($file['tmp_name'])) { + continue; + } + + $fields[$name] = DataPart::fromPath($file['tmp_name'], $file['name']); + } + + return new FormDataPart($fields); + } + + private function getHeaders(Request $request): array + { + $headers = []; + foreach ($request->getServer() as $key => $value) { + $key = strtolower(str_replace('_', '-', $key)); + $contentHeaders = ['content-length' => true, 'content-md5' => true, 'content-type' => true]; + if (0 === strpos($key, 'http-')) { + $headers[substr($key, 5)] = $value; + } elseif (isset($contentHeaders[$key])) { + // CONTENT_* are not prefixed with HTTP_ + $headers[$key] = $value; + } + } + $cookies = []; + foreach ($this->getCookieJar()->allRawValues($request->getUri()) as $name => $value) { + $cookies[] = $name.'='.$value; + } + if ($cookies) { + $headers['cookie'] = implode('; ', $cookies); + } + + return $headers; + } +} diff --git a/src/Symfony/Component/BrowserKit/README.md b/src/Symfony/Component/BrowserKit/README.md index a0083ac5bd7ea..ef6d75b7837e5 100644 --- a/src/Symfony/Component/BrowserKit/README.md +++ b/src/Symfony/Component/BrowserKit/README.md @@ -4,6 +4,9 @@ BrowserKit Component The BrowserKit component simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically. +The component comes with a concrete implementation that uses the HttpClient +component to make real HTTP requests. + Resources --------- diff --git a/src/Symfony/Component/BrowserKit/composer.json b/src/Symfony/Component/BrowserKit/composer.json index 4c0567b5da9ef..89d78c87567eb 100644 --- a/src/Symfony/Component/BrowserKit/composer.json +++ b/src/Symfony/Component/BrowserKit/composer.json @@ -21,7 +21,8 @@ }, "require-dev": { "symfony/process": "~3.4|~4.0", - "symfony/css-selector": "~3.4|~4.0" + "symfony/css-selector": "~3.4|~4.0", + "symfony/mime": "^4.3" }, "suggest": { "symfony/process": "" diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index c6630b65bcc08..9c63f0052ebdd 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -56,7 +56,7 @@ public function __construct($body = '', array $info = []) } } - $info['raw_headers'] = $rawHeaders; + $this->info['raw_headers'] = $rawHeaders; } /** From b5b2a2557c538183fe246b9cef4ba6d1de270277 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?THERAGE=20K=C3=A9vin?= Date: Wed, 20 Mar 2019 20:56:18 +0100 Subject: [PATCH 246/495] Add tests for HttpBrowser --- .../BrowserKit/Tests/AbstractBrowserTest.php | 141 +++++++++--------- .../BrowserKit/Tests/HttpBrowserTest.php | 115 ++++++++++++++ .../Component/BrowserKit/composer.json | 5 +- 3 files changed, 191 insertions(+), 70 deletions(-) create mode 100644 src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php diff --git a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php index c51ea95e21188..13bb2db1053c1 100644 --- a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php @@ -75,21 +75,26 @@ protected function getScript($request) class AbstractBrowserTest extends TestCase { + public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + return new TestClient($server, $history, $cookieJar); + } + public function testGetHistory() { - $client = new TestClient([], $history = new History()); + $client = $this->getBrowser([], $history = new History()); $this->assertSame($history, $client->getHistory(), '->getHistory() returns the History'); } public function testGetCookieJar() { - $client = new TestClient([], null, $cookieJar = new CookieJar()); + $client = $this->getBrowser([], null, $cookieJar = new CookieJar()); $this->assertSame($cookieJar, $client->getCookieJar(), '->getCookieJar() returns the CookieJar'); } public function testGetRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://example.com/'); $this->assertEquals('http://example.com/', $client->getRequest()->getUri(), '->getCrawler() returns the Request of the last request'); @@ -101,13 +106,13 @@ public function testGetRequest() */ public function testGetRequestNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getRequest()); } public function testXmlHttpRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->xmlHttpRequest('GET', 'http://example.com/', [], [], [], null, true); $this->assertEquals($client->getRequest()->getServer()['HTTP_X_REQUESTED_WITH'], 'XMLHttpRequest'); $this->assertFalse($client->getServerParameter('HTTP_X_REQUESTED_WITH', false)); @@ -115,7 +120,7 @@ public function testXmlHttpRequest() public function testGetRequestWithIpAsHttpHost() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'https://example.com/foo', [], [], ['HTTP_HOST' => '127.0.0.1']); $this->assertEquals('https://example.com/foo', $client->getRequest()->getUri()); @@ -125,7 +130,7 @@ public function testGetRequestWithIpAsHttpHost() public function testGetResponse() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $client->request('GET', 'http://example.com/'); @@ -139,13 +144,13 @@ public function testGetResponse() */ public function testGetResponseNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getResponse()); } public function testGetInternalResponse() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new SpecialResponse('foo')); $client->request('GET', 'http://example.com/'); @@ -160,7 +165,7 @@ public function testGetInternalResponse() */ public function testGetInternalResponseNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getInternalResponse()); } @@ -168,14 +173,14 @@ public function testGetContent() { $json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}'; - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('POST', 'http://example.com/jsonrpc', [], [], [], $json); $this->assertEquals($json, $client->getRequest()->getContent()); } public function testGetCrawler() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $crawler = $client->request('GET', 'http://example.com/'); @@ -188,18 +193,18 @@ public function testGetCrawler() */ public function testGetCrawlerNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getCrawler()); } public function testRequestHttpHeaders() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', '/'); $headers = $client->getRequest()->getServer(); $this->assertEquals('localhost', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com'); $headers = $client->getRequest()->getServer(); $this->assertEquals('www.example.com', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header'); @@ -208,7 +213,7 @@ public function testRequestHttpHeaders() $headers = $client->getRequest()->getServer(); $this->assertTrue($headers['HTTPS'], '->request() sets the HTTPS header'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com:8080'); $headers = $client->getRequest()->getServer(); $this->assertEquals('www.example.com:8080', $headers['HTTP_HOST'], '->request() sets the HTTP_HOST header with port'); @@ -216,20 +221,20 @@ public function testRequestHttpHeaders() public function testRequestURIConversion() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', '/foo'); $this->assertEquals('http://localhost/foo', $client->getRequest()->getUri(), '->request() converts the URI to an absolute one'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com'); $this->assertEquals('http://www.example.com', $client->getRequest()->getUri(), '->request() does not change absolute URIs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/'); $client->request('GET', '/foo'); $this->assertEquals('http://www.example.com/foo', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', '#'); $this->assertEquals('http://www.example.com/foo#', $client->getRequest()->getUri(), '->request() uses the previous request for #'); @@ -238,32 +243,32 @@ public function testRequestURIConversion() $client->request('GET', '#foo'); $this->assertEquals('http://www.example.com/foo#foo', $client->getRequest()->getUri(), '->request() uses the previous request for #'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/'); $client->request('GET', 'bar'); $this->assertEquals('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); $this->assertEquals('http://www.example.com/foo/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/'); $client->request('GET', 'http'); $this->assertEquals('http://www.example.com/foo/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', 'http/bar'); $this->assertEquals('http://www.example.com/http/bar', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/'); $client->request('GET', 'http'); $this->assertEquals('http://www.example.com/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->request('GET', '?'); $this->assertEquals('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); @@ -275,7 +280,7 @@ public function testRequestURIConversion() public function testRequestReferer() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); $server = $client->getRequest()->getServer(); @@ -284,7 +289,7 @@ public function testRequestReferer() public function testRequestHistory() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->request('GET', 'bar'); @@ -294,7 +299,7 @@ public function testRequestHistory() public function testRequestCookies() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo', 200, ['Set-Cookie' => 'foo=bar'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals(['foo' => 'bar'], $client->getCookieJar()->allValues('http://www.example.com/foo/foobar'), '->request() updates the CookieJar'); @@ -305,7 +310,7 @@ public function testRequestCookies() public function testRequestSecureCookies() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo', 200, ['Set-Cookie' => 'foo=bar; path=/; secure'])); $client->request('GET', 'https://www.example.com/foo/foobar'); @@ -314,7 +319,7 @@ public function testRequestSecureCookies() public function testClick() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -325,7 +330,7 @@ public function testClick() public function testClickLink() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foo')); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->clickLink('foo'); @@ -335,7 +340,7 @@ public function testClickLink() public function testClickLinkNotFound() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('foobar')); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -349,7 +354,7 @@ public function testClickLinkNotFound() public function testClickForm() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -360,7 +365,7 @@ public function testClickForm() public function testSubmit() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -371,7 +376,7 @@ public function testSubmit() public function testSubmitForm() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -391,7 +396,7 @@ public function testSubmitForm() public function testSubmitFormNotFound() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -408,7 +413,7 @@ public function testSubmitFormNotFound() public function testSubmitPreserveAuth() { - $client = new TestClient(['PHP_AUTH_USER' => 'foo', 'PHP_AUTH_PW' => 'bar']); + $client = $this->getBrowser(['PHP_AUTH_USER' => 'foo', 'PHP_AUTH_PW' => 'bar']); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -431,7 +436,7 @@ public function testSubmitPreserveAuth() public function testSubmitPassthrewHeaders() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('
')); $crawler = $client->request('GET', 'http://www.example.com/foo/foobar'); $headers = ['Accept-Language' => 'de']; @@ -445,7 +450,7 @@ public function testSubmitPassthrewHeaders() public function testFollowRedirect() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->followRedirects(false); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -462,19 +467,19 @@ public function testFollowRedirect() $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() automatically follows redirects if followRedirects is true'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 201, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/foo/foobar', $client->getRequest()->getUri(), '->followRedirect() does not follow redirect if HTTP Code is not 30x'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 201, ['Location' => 'http://www.example.com/redirected'])); $client->followRedirects(false); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -489,12 +494,12 @@ public function testFollowRedirect() public function testFollowRelativeRedirect() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '/redirected:1234'])); $client->request('GET', 'http://www.example.com/foo/foobar'); $this->assertEquals('http://www.example.com/redirected:1234', $client->getRequest()->getUri(), '->followRedirect() follows relative urls'); @@ -502,7 +507,7 @@ public function testFollowRelativeRedirect() public function testFollowRedirectWithMaxRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->setMaxRedirects(1); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -525,13 +530,13 @@ public function testFollowRedirectWithMaxRedirects() $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => '//www.example.org/'])); $client->request('GET', 'https://www.example.com/'); $this->assertEquals('https://www.example.org/', $client->getRequest()->getUri(), '->followRedirect() follows protocol-relative URLs'); - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', ['name' => 'bar']); @@ -541,7 +546,7 @@ public function testFollowRedirectWithMaxRedirects() public function testFollowRedirectWithCookies() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->followRedirects(false); $client->setNextResponse(new Response('', 302, [ 'Location' => 'http://www.example.com/redirected', @@ -562,7 +567,7 @@ public function testFollowRedirectWithHeaders() 'HTTPS' => false, ]; - $client = new TestClient(); + $client = $this->getBrowser(); $client->followRedirects(false); $client->setNextResponse(new Response('', 302, [ 'Location' => 'http://www.example.com/redirected', @@ -589,7 +594,7 @@ public function testFollowRedirectWithPort() 'HTTP_REFERER' => 'http://www.example.com:8080/', ]; - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 302, [ 'Location' => 'http://www.example.com:8080/redirected', ])); @@ -600,7 +605,7 @@ public function testFollowRedirectWithPort() public function testIsFollowingRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertTrue($client->isFollowingRedirects(), '->getFollowRedirects() returns default value'); $client->followRedirects(false); $this->assertFalse($client->isFollowingRedirects(), '->getFollowRedirects() returns assigned value'); @@ -608,7 +613,7 @@ public function testIsFollowingRedirects() public function testGetMaxRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals(-1, $client->getMaxRedirects(), '->getMaxRedirects() returns default value'); $client->setMaxRedirects(3); $this->assertEquals(3, $client->getMaxRedirects(), '->getMaxRedirects() returns assigned value'); @@ -621,7 +626,7 @@ public function testFollowRedirectWithPostMethod() $server = ['X_TEST_FOO' => 'bazbar']; $content = 'foobarbaz'; - $client = new TestClient(); + $client = $this->getBrowser(); $client->setNextResponse(new Response('', 307, ['Location' => 'http://www.example.com/redirected'])); $client->request('POST', 'http://www.example.com/foo/foobar', $parameters, $files, $server, $content); @@ -641,7 +646,7 @@ public function testFollowRedirectDropPostMethod() $server = ['X_TEST_FOO' => 'bazbar']; $content = 'foobarbaz'; - $client = new TestClient(); + $client = $this->getBrowser(); foreach ([301, 302, 303] as $code) { $client->setNextResponse(new Response('', $code, ['Location' => 'http://www.example.com/redirected'])); @@ -661,7 +666,7 @@ public function testFollowRedirectDropPostMethod() */ public function testFollowMetaRefresh(string $content, string $expectedEndingUrl, bool $followMetaRefresh = true) { - $client = new TestClient(); + $client = $this->getBrowser(); $client->followMetaRefresh($followMetaRefresh); $client->setNextResponse(new Response($content)); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -691,7 +696,7 @@ public function getTestsForMetaRefresh() public function testBack() { - $client = new TestClient(); + $client = $this->getBrowser(); $parameters = ['foo' => 'bar']; $files = ['myfile.foo' => 'baz']; @@ -711,7 +716,7 @@ public function testBack() public function testForward() { - $client = new TestClient(); + $client = $this->getBrowser(); $parameters = ['foo' => 'bar']; $files = ['myfile.foo' => 'baz']; @@ -732,7 +737,7 @@ public function testForward() public function testBackAndFrowardWithRedirects() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo'); $client->setNextResponse(new Response('', 301, ['Location' => 'http://www.example.com/redirected'])); @@ -751,7 +756,7 @@ public function testBackAndFrowardWithRedirects() public function testReload() { - $client = new TestClient(); + $client = $this->getBrowser(); $parameters = ['foo' => 'bar']; $files = ['myfile.foo' => 'baz']; @@ -770,7 +775,7 @@ public function testReload() public function testRestart() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'http://www.example.com/foo/foobar'); $client->restart(); @@ -780,7 +785,7 @@ public function testRestart() public function testInsulatedRequests() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->insulate(); $client->setNextScript("new Symfony\Component\BrowserKit\Response('foobar')"); $client->request('GET', 'http://www.example.com/foo/foobar'); @@ -799,7 +804,7 @@ public function testInsulatedRequests() public function testGetServerParameter() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); $this->assertEquals('testvalue', $client->getServerParameter('testkey', 'testvalue')); @@ -807,7 +812,7 @@ public function testGetServerParameter() public function testSetServerParameter() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); @@ -821,7 +826,7 @@ public function testSetServerParameter() public function testSetServerParameterInRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertEquals('', $client->getServerParameter('HTTP_HOST')); $this->assertEquals('Symfony BrowserKit', $client->getServerParameter('HTTP_USER_AGENT')); @@ -855,7 +860,7 @@ public function testSetServerParameterInRequest() public function testRequestWithRelativeUri() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', '/', [], [], [ 'HTTP_HOST' => 'testhost', @@ -872,7 +877,7 @@ public function testRequestWithRelativeUri() public function testInternalRequest() { - $client = new TestClient(); + $client = $this->getBrowser(); $client->request('GET', 'https://www.example.com/https/www.example.com', [], [], [ 'HTTP_HOST' => 'testhost', @@ -890,7 +895,7 @@ public function testInternalRequest() */ public function testInternalRequestNull() { - $client = new TestClient(); + $client = $this->getBrowser(); $this->assertNull($client->getInternalRequest()); } diff --git a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php new file mode 100644 index 0000000000000..be1996d1713fb --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\BrowserKit\Tests; + +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\History; +use Symfony\Component\BrowserKit\HttpBrowser; +use Symfony\Component\BrowserKit\Response; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; + +class SpecialHttpResponse extends Response +{ +} + +class TestHttpClient extends HttpBrowser +{ + protected $nextResponse = null; + protected $nextScript = null; + + public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + $client = new MockHttpClient(function (string $method, string $url, array $options) { + if (null === $this->nextResponse) { + return new MockResponse(); + } + + return new MockResponse($this->nextResponse->getContent(), [ + 'http_code' => $this->nextResponse->getStatusCode(), + 'raw_headers' => $this->nextResponse->getHeaders(), + ]); + }); + parent::__construct($client); + + $this->setServerParameters($server); + $this->history = $history ?? new History(); + $this->cookieJar = $cookieJar ?? new CookieJar(); + } + + public function setNextResponse(Response $response) + { + $this->nextResponse = $response; + } + + public function setNextScript($script) + { + $this->nextScript = $script; + } + + protected function filterResponse($response) + { + if ($response instanceof SpecialHttpResponse) { + return new Response($response->getContent(), $response->getStatusCode(), $response->getHeaders()); + } + + return $response; + } + + protected function doRequest($request) + { + $response = parent::doRequest($request); + + if (null === $this->nextResponse) { + return $response; + } + + $class = \get_class($this->nextResponse); + $response = new $class($response->getContent(), $response->getStatusCode(), $response->getHeaders()); + $this->nextResponse = null; + + return $response; + } + + protected function getScript($request) + { + $r = new \ReflectionClass('Symfony\Component\BrowserKit\Response'); + $path = $r->getFileName(); + + return <<nextScript); +EOF; + } +} + +class HttpBrowserTest extends AbstractBrowserTest +{ + public function getBrowser(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + return new TestHttpClient($server, $history, $cookieJar); + } + + public function testGetInternalResponse() + { + $client = $this->getBrowser(); + $client->setNextResponse(new SpecialHttpResponse('foo')); + $client->request('GET', 'http://example.com/'); + + $this->assertInstanceOf('Symfony\Component\BrowserKit\Response', $client->getInternalResponse()); + $this->assertNotInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getInternalResponse()); + $this->assertInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getResponse()); + } +} diff --git a/src/Symfony/Component/BrowserKit/composer.json b/src/Symfony/Component/BrowserKit/composer.json index 89d78c87567eb..b5efd066a02c0 100644 --- a/src/Symfony/Component/BrowserKit/composer.json +++ b/src/Symfony/Component/BrowserKit/composer.json @@ -20,9 +20,10 @@ "symfony/dom-crawler": "~3.4|~4.0" }, "require-dev": { - "symfony/process": "~3.4|~4.0", "symfony/css-selector": "~3.4|~4.0", - "symfony/mime": "^4.3" + "symfony/http-client": "^4.3", + "symfony/mime": "^4.3", + "symfony/process": "~3.4|~4.0" }, "suggest": { "symfony/process": "" From 28b6dd243e6e5a93e96342d03dcb580cd86d892a Mon Sep 17 00:00:00 2001 From: Serkan Yildiz Date: Fri, 22 Mar 2019 12:59:39 +0100 Subject: [PATCH 247/495] Replace class with new name. --- src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php index b088219afccfc..5334d583610c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php @@ -36,7 +36,7 @@ protected static function createClient(array $options = [], array $server = []) try { $client = $kernel->getContainer()->get('test.client'); } catch (ServiceNotFoundException $e) { - if (class_exists(Client::class)) { + if (class_exists(KernelBrowser::class)) { throw new \LogicException('You cannot create the client used in functional tests if the "framework.test" config is not set to true.'); } throw new \LogicException('You cannot create the client used in functional tests if the BrowserKit component is not available. Try running "composer require symfony/browser-kit"'); From bbf582bce59cdfe9ed2f6d93e1684a83aed1bde8 Mon Sep 17 00:00:00 2001 From: Valentin Udaltsov Date: Fri, 22 Mar 2019 16:04:03 +0300 Subject: [PATCH 248/495] Make MethodMarkingStore final --- .../Component/Workflow/MarkingStore/MethodMarkingStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php index e2e61e7278d85..e51ac0afa914b 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php @@ -21,7 +21,7 @@ * * @author Grégoire Pineau */ -class MethodMarkingStore implements MarkingStoreInterface +final class MethodMarkingStore implements MarkingStoreInterface { private $singleState; private $property; From e8b9856ec3c7b5c0893d3e3262ac97be59d932a6 Mon Sep 17 00:00:00 2001 From: gpenverne Date: Fri, 22 Mar 2019 14:41:52 +0100 Subject: [PATCH 249/495] Alias for each assets package --- .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 41e22bdfc8b5b..3354ea53dda25 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -23,6 +23,7 @@ use Symfony\Bundle\FrameworkBundle\Routing\AnnotatedRouteControllerLoader; use Symfony\Bundle\FrameworkBundle\Routing\RedirectableUrlMatcher; use Symfony\Bundle\FullStack; +use Symfony\Component\Asset\PackageInterface; use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Adapter\AdapterInterface; @@ -996,6 +997,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co } $container->setDefinition('assets._package_'.$name, $this->createPackageDefinition($package['base_path'], $package['base_urls'], $version)); + $container->registerAliasForArgument('assets._package_'.$name, PackageInterface::class, $name.'.package'); $namedPackages[$name] = new Reference('assets._package_'.$name); } From 4d58beb7c871ab0eb6c4f653dd9bbf25a4b8872a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 13 Mar 2019 17:02:04 +0100 Subject: [PATCH 250/495] [Workflow] Deprecate MultipleStateMarkingStore and SingleStateMarkingStore in favor of MethodMarkingStore --- UPGRADE-4.3.md | 43 +++++++ UPGRADE-5.0.md | 2 + .../Tests/Extension/WorkflowExtensionTest.php | 46 +++++--- src/Symfony/Bridge/Twig/composer.json | 5 +- src/Symfony/Component/Workflow/CHANGELOG.md | 4 +- .../MarkingStore/MethodMarkingStore.php | 6 + .../MultipleStateMarkingStore.php | 4 + .../MarkingStore/SingleStateMarkingStore.php | 4 + .../EventListener/AuditTrailListenerTest.php | 14 +-- .../Tests/EventListener/GuardListenerTest.php | 6 +- .../MarkingStore/MethodMarkingStoreTest.php | 21 +--- .../MultipleStateMarkingStoreTest.php | 1 + .../SingleStateMarkingStoreTest.php | 1 + .../Workflow/Tests/StateMachineTest.php | 30 ++--- .../Component/Workflow/Tests/Subject.php | 23 ++++ .../Component/Workflow/Tests/WorkflowTest.php | 106 +++++++----------- 16 files changed, 189 insertions(+), 127 deletions(-) create mode 100644 src/Symfony/Component/Workflow/Tests/Subject.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index a45814f09e673..655095a3b8e40 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -177,3 +177,46 @@ Workflow } } ``` + + * `MultipleStateMarkingStore` is deprecated. Use `MethodMarkingStore` instead. + + Before: + ```yaml + framework: + workflows: + article: + marking_store: + type: multiple + ``` + + After: + ```yaml + framework: + workflows: + article: + marking_store: + type: method + + ``` + + * `SingleStateMarkingStore` is deprecated. Use `MethodMarkingStore` instead. + + Before: + ```yaml + framework: + workflows: + article: + marking_store: + type: single + ``` + + After: + ```yaml + framework: + workflows: + article: + marking_store: + type: method + arguments: + - true + ``` diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 16a034a85dc05..a5b2f0849e519 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -369,6 +369,8 @@ Workflow * `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead. * `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`. * Removed support of `initial_place`. Use `initial_places` instead. + * `MultipleStateMarkingStore` has been removed. + * `SingleStateMarkingStore` has been removed. Yaml ---- diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php index a3e3ca2daec6b..32f4e82dad1c8 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Twig\Extension\WorkflowExtension; use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore; use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore; use Symfony\Component\Workflow\Registry; use Symfony\Component\Workflow\SupportStrategy\ClassInstanceSupportStrategy; @@ -49,21 +50,20 @@ protected function setUp() ); } $definition = new Definition($places, $transitions, null, $metadataStore); - $workflow = new Workflow($definition); + $workflow = new Workflow($definition, new MethodMarkingStore()); $registry = new Registry(); $addWorkflow = method_exists($registry, 'addWorkflow') ? 'addWorkflow' : 'add'; $supportStrategy = class_exists(InstanceOfSupportStrategy::class) - ? new InstanceOfSupportStrategy(\stdClass::class) - : new ClassInstanceSupportStrategy(\stdClass::class); + ? new InstanceOfSupportStrategy(Subject::class) + : new ClassInstanceSupportStrategy(Subject::class); $registry->$addWorkflow($workflow, $supportStrategy); $this->extension = new WorkflowExtension($registry); } public function testCanTransition() { - $subject = new \stdClass(); - $subject->marking = []; + $subject = new Subject(); $this->assertTrue($this->extension->canTransition($subject, 't1')); $this->assertFalse($this->extension->canTransition($subject, 't2')); @@ -71,8 +71,7 @@ public function testCanTransition() public function testGetEnabledTransitions() { - $subject = new \stdClass(); - $subject->marking = []; + $subject = new Subject(); $transitions = $this->extension->getEnabledTransitions($subject); @@ -83,9 +82,7 @@ public function testGetEnabledTransitions() public function testHasMarkedPlace() { - $subject = new \stdClass(); - $subject->marking = []; - $subject->marking = ['ordered' => 1, 'waiting_for_payment' => 1]; + $subject = new Subject(['ordered' => 1, 'waiting_for_payment' => 1]); $this->assertTrue($this->extension->hasMarkedPlace($subject, 'ordered')); $this->assertTrue($this->extension->hasMarkedPlace($subject, 'waiting_for_payment')); @@ -94,12 +91,10 @@ public function testHasMarkedPlace() public function testGetMarkedPlaces() { - $subject = new \stdClass(); - $subject->marking = []; - $subject->marking = ['ordered' => 1, 'waiting_for_payment' => 1]; + $subject = new Subject(['ordered' => 1, 'waiting_for_payment' => 1]); $this->assertSame(['ordered', 'waiting_for_payment'], $this->extension->getMarkedPlaces($subject)); - $this->assertSame($subject->marking, $this->extension->getMarkedPlaces($subject, false)); + $this->assertSame($subject->getMarking(), $this->extension->getMarkedPlaces($subject, false)); } public function testGetMetadata() @@ -107,8 +102,7 @@ public function testGetMetadata() if (!class_exists(InMemoryMetadataStore::class)) { $this->markTestSkipped('This test requires symfony/workflow:4.1.'); } - $subject = new \stdClass(); - $subject->marking = []; + $subject = new Subject(); $this->assertSame('workflow title', $this->extension->getMetadata($subject, 'title')); $this->assertSame('ordered title', $this->extension->getMetadata($subject, 'title', 'orderer')); @@ -117,3 +111,23 @@ public function testGetMetadata() $this->assertNull($this->extension->getMetadata($subject, 'not found', $this->t1)); } } + +final class Subject +{ + private $marking; + + public function __construct($marking = null) + { + $this->marking = $marking; + } + + public function getMarking() + { + return $this->marking; + } + + public function setMarking($marking) + { + $this->marking = $marking; + } +} diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 2c6e0625d39d1..c083ff32f44b2 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -41,12 +41,13 @@ "symfony/var-dumper": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/web-link": "~3.4|~4.0", - "symfony/workflow": "~3.4|~4.0" + "symfony/workflow": "~4.3" }, "conflict": { "symfony/console": "<3.4", "symfony/form": "<4.3", - "symfony/translation": "<4.2" + "symfony/translation": "<4.2", + "symfony/workflow": "<4.3" }, "suggest": { "symfony/finder": "", diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index 0801deccc711b..c3869c0424391 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.3.0 ----- - * Trigger `entered` event for subject entering in the Workflow for the first time + * Trigger `entered` event for subject entering in the Workflow for the first time. * Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature. * Add style to transitions by declaring metadata: @@ -27,6 +27,8 @@ CHANGELOG * Dispatch `CompletedEvent` on `workflow.completed` * Dispatch `AnnounceEvent` on `workflow.announce` * Added support for many `initialPlaces` + * Deprecated the `MultipleStateMarkingStore` class, use the `MethodMarkingStore` instead. + * Deprecated the `SingleStateMarkingStore` class, use the `MethodMarkingStore` instead. 4.1.0 ----- diff --git a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php index e2e61e7278d85..029f8f1d3bebf 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MethodMarkingStore.php @@ -19,6 +19,12 @@ * * This store deals with a "single state" or "multiple state" Marking. * + * "single state" Marking means a subject can be in one and only one state at + * the same time. Use it with state machine or specific workflow. + * + * "multiple state" Marking means a subject can be in many states at the same + * time. Use it with workflow. + * * @author Grégoire Pineau */ class MethodMarkingStore implements MarkingStoreInterface diff --git a/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php index db6b03b30a4b1..af37ae313a179 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Workflow\MarkingStore; +@trigger_error(sprintf('"%s" is deprecated since Symfony 4.3, use "%s" instead.', MultipleStateMarkingStore::class, MethodMarkingStore::class), E_USER_DEPRECATED); + use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Workflow\Marking; @@ -22,6 +24,8 @@ * This store deals with a "multiple state" Marking. It means a subject can be * in many states at the same time. * + * @deprecated since Symfony 4.3, use MethodMarkingStore instead. + * * @author Grégoire Pineau */ class MultipleStateMarkingStore implements MarkingStoreInterface diff --git a/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php index 41da9b49b9ee4..eca8a5d2a1449 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Workflow\MarkingStore; +@trigger_error(sprintf('"%s" is deprecated since Symfony 4.3, use "%s" instead.', SingleStateMarkingStore::class, MethodMarkingStore::class), E_USER_DEPRECATED); + use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Workflow\Marking; @@ -21,6 +23,8 @@ * This store deals with a "single state" Marking. It means a subject can be in * one and only one state at the same time. * + * @deprecated since Symfony 4.3, use MethodMarkingStore instead. + * * @author Grégoire Pineau */ class SingleStateMarkingStore implements MarkingStoreInterface diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php index 8fab0e9ec7175..9ebe6f4fb6047 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php @@ -6,7 +6,8 @@ use Psr\Log\AbstractLogger; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Workflow\EventListener\AuditTrailListener; -use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; +use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore; +use Symfony\Component\Workflow\Tests\Subject; use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait; use Symfony\Component\Workflow\Workflow; @@ -18,22 +19,21 @@ public function testItWorks() { $definition = $this->createSimpleWorkflowDefinition(); - $object = new \stdClass(); - $object->marking = null; + $object = new Subject(); $logger = new Logger(); $ed = new EventDispatcher(); $ed->addSubscriber(new AuditTrailListener($logger)); - $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $ed); + $workflow = new Workflow($definition, new MethodMarkingStore(), $ed); $workflow->apply($object, 't1'); $expected = [ - 'Leaving "a" for subject of class "stdClass" in workflow "unnamed".', - 'Transition "t1" for subject of class "stdClass" in workflow "unnamed".', - 'Entering "b" for subject of class "stdClass" in workflow "unnamed".', + 'Leaving "a" for subject of class "Symfony\Component\Workflow\Tests\Subject" in workflow "unnamed".', + 'Transition "t1" for subject of class "Symfony\Component\Workflow\Tests\Subject" in workflow "unnamed".', + 'Entering "b" for subject of class "Symfony\Component\Workflow\Tests\Subject" in workflow "unnamed".', ]; $this->assertSame($expected, $logger->logs); diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php index 6099cf20c8ad6..805b626246561 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php @@ -13,6 +13,7 @@ use Symfony\Component\Workflow\EventListener\GuardExpression; use Symfony\Component\Workflow\EventListener\GuardListener; use Symfony\Component\Workflow\Marking; +use Symfony\Component\Workflow\Tests\Subject; use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\WorkflowInterface; @@ -130,13 +131,12 @@ public function testGuardExpressionBlocks() private function createEvent(Transition $transition = null) { - $subject = new \stdClass(); - $subject->marking = new Marking(); + $subject = new Subject(); $transition = $transition ?: new Transition('name', 'from', 'to'); $workflow = $this->getMockBuilder(WorkflowInterface::class)->getMock(); - return new GuardEvent($subject, $subject->marking, $transition, $workflow); + return new GuardEvent($subject, new Marking($subject->getMarking() ?? []), $transition, $workflow); } private function configureAuthenticationChecker($isUsed, $granted = true) diff --git a/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php b/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php index 776f66002d23c..7b5c7ffa91391 100644 --- a/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php +++ b/src/Symfony/Component/Workflow/Tests/MarkingStore/MethodMarkingStoreTest.php @@ -5,6 +5,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore; +use Symfony\Component\Workflow\Tests\Subject; class MethodMarkingStoreTest extends TestCase { @@ -52,23 +53,3 @@ public function testGetSetMarkingWithSingleState() $this->assertEquals($marking, $marking2); } } - -final class Subject -{ - private $marking; - - public function __construct($marking = null) - { - $this->marking = $marking; - } - - public function getMarking() - { - return $this->marking; - } - - public function setMarking($marking) - { - $this->marking = $marking; - } -} diff --git a/src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php b/src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php index 647ae42b4b11b..4ca81e1cd75f0 100644 --- a/src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php +++ b/src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php @@ -6,6 +6,7 @@ use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; +/** @group legacy*/ class MultipleStateMarkingStoreTest extends TestCase { public function testGetSetMarking() diff --git a/src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php b/src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php index 2e00714d2762a..7b640559ffff2 100644 --- a/src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php +++ b/src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php @@ -6,6 +6,7 @@ use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore; +/** @group legacy*/ class SingleStateMarkingStoreTest extends TestCase { public function testGetSetMarking() diff --git a/src/Symfony/Component/Workflow/Tests/StateMachineTest.php b/src/Symfony/Component/Workflow/Tests/StateMachineTest.php index 7f76c4a70b1ea..dd791239c4b76 100644 --- a/src/Symfony/Component/Workflow/Tests/StateMachineTest.php +++ b/src/Symfony/Component/Workflow/Tests/StateMachineTest.php @@ -17,15 +17,15 @@ public function testCan() $definition = $this->createComplexStateMachineDefinition(); $net = new StateMachine($definition); - $subject = new \stdClass(); + $subject = new Subject(); // If you are in place "a" you should be able to apply "t1" - $subject->marking = 'a'; + $subject->setMarking('a'); $this->assertTrue($net->can($subject, 't1')); - $subject->marking = 'd'; + $subject->setMarking('d'); $this->assertTrue($net->can($subject, 't1')); - $subject->marking = 'b'; + $subject->setMarking('b'); $this->assertFalse($net->can($subject, 't1')); } @@ -34,10 +34,10 @@ public function testCanWithMultipleTransition() $definition = $this->createComplexStateMachineDefinition(); $net = new StateMachine($definition); - $subject = new \stdClass(); + $subject = new Subject(); // If you are in place "b" you should be able to apply "t1" and "t2" - $subject->marking = 'b'; + $subject->setMarking('b'); $this->assertTrue($net->can($subject, 't2')); $this->assertTrue($net->can($subject, 't3')); } @@ -47,14 +47,14 @@ public function testBuildTransitionBlockerList() $definition = $this->createComplexStateMachineDefinition(); $net = new StateMachine($definition); - $subject = new \stdClass(); + $subject = new Subject(); - $subject->marking = 'a'; + $subject->setMarking('a'); $this->assertTrue($net->buildTransitionBlockerList($subject, 't1')->isEmpty()); - $subject->marking = 'd'; + $subject->setMarking('d'); $this->assertTrue($net->buildTransitionBlockerList($subject, 't1')->isEmpty()); - $subject->marking = 'b'; + $subject->setMarking('b'); $this->assertFalse($net->buildTransitionBlockerList($subject, 't1')->isEmpty()); } @@ -63,9 +63,9 @@ public function testBuildTransitionBlockerListWithMultipleTransitions() $definition = $this->createComplexStateMachineDefinition(); $net = new StateMachine($definition); - $subject = new \stdClass(); + $subject = new Subject(); - $subject->marking = 'b'; + $subject->setMarking('b'); $this->assertTrue($net->buildTransitionBlockerList($subject, 't2')->isEmpty()); $this->assertTrue($net->buildTransitionBlockerList($subject, 't3')->isEmpty()); } @@ -81,7 +81,7 @@ public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge $event->addTransitionBlocker(new TransitionBlocker(\sprintf('Transition blocker of place %s', $event->getTransition()->getFroms()[0]), 'blocker')); }); - $subject = new \stdClass(); + $subject = new Subject(); // There may be multiple transitions with the same name. Make sure that transitions // that are not enabled by the marking are evaluated. @@ -89,7 +89,7 @@ public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge // Test if when you are in place "a"trying transition "t1" then returned // blocker list contains guard blocker instead blockedByMarking - $subject->marking = 'a'; + $subject->setMarking('a'); $transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1'); $this->assertCount(1, $transitionBlockerList); $blockers = iterator_to_array($transitionBlockerList); @@ -99,7 +99,7 @@ public function testBuildTransitionBlockerListReturnsExpectedReasonOnBranchMerge // Test if when you are in place "d" trying transition "t1" then // returned blocker list contains guard blocker instead blockedByMarking - $subject->marking = 'd'; + $subject->setMarking('d'); $transitionBlockerList = $net->buildTransitionBlockerList($subject, 't1'); $this->assertCount(1, $transitionBlockerList); $blockers = iterator_to_array($transitionBlockerList); diff --git a/src/Symfony/Component/Workflow/Tests/Subject.php b/src/Symfony/Component/Workflow/Tests/Subject.php new file mode 100644 index 0000000000000..fafb167ee7e4b --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/Subject.php @@ -0,0 +1,23 @@ +marking = $marking; + } + + public function getMarking() + { + return $this->marking; + } + + public function setMarking($marking) + { + $this->marking = $marking; + } +} diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 62150d2cb732a..8762656a4550d 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -10,6 +10,7 @@ use Symfony\Component\Workflow\Exception\NotEnabledTransitionException; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; +use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore; use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\TransitionBlocker; @@ -25,8 +26,7 @@ class WorkflowTest extends TestCase */ public function testGetMarkingWithInvalidStoreReturn() { - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow(new Definition([], []), $this->getMockBuilder(MarkingStoreInterface::class)->getMock()); $workflow->getMarking($subject); @@ -38,8 +38,7 @@ public function testGetMarkingWithInvalidStoreReturn() */ public function testGetMarkingWithEmptyDefinition() { - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow(new Definition([], []), new MultipleStateMarkingStore()); $workflow->getMarking($subject); @@ -51,8 +50,8 @@ public function testGetMarkingWithEmptyDefinition() */ public function testGetMarkingWithImpossiblePlace() { - $subject = new \stdClass(); - $subject->marking = ['nope' => 1]; + $subject = new Subject(); + $subject->setMarking(['nope' => 1]); $workflow = new Workflow(new Definition([], []), new MultipleStateMarkingStore()); $workflow->getMarking($subject); @@ -61,23 +60,21 @@ public function testGetMarkingWithImpossiblePlace() public function testGetMarkingWithEmptyInitialMarking() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->getMarking($subject); $this->assertInstanceOf(Marking::class, $marking); $this->assertTrue($marking->has('a')); - $this->assertSame(['a' => 1], $subject->marking); + $this->assertSame(['a' => 1], $subject->getMarking()); } public function testGetMarkingWithExistingMarking() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; - $subject->marking = ['b' => 1, 'c' => 1]; + $subject = new Subject(); + $subject->setMarking(['b' => 1, 'c' => 1]); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->getMarking($subject); @@ -90,8 +87,7 @@ public function testGetMarkingWithExistingMarking() public function testCanWithUnexistingTransition() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $this->assertFalse($workflow->can($subject, 'foobar')); @@ -100,26 +96,25 @@ public function testCanWithUnexistingTransition() public function testCan() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $this->assertTrue($workflow->can($subject, 't1')); $this->assertFalse($workflow->can($subject, 't2')); - $subject->marking = ['b' => 1]; + $subject->setMarking(['b' => 1]); $this->assertFalse($workflow->can($subject, 't1')); // In a workflow net, all "from" places should contain a token to enable // the transition. $this->assertFalse($workflow->can($subject, 't2')); - $subject->marking = ['b' => 1, 'c' => 1]; + $subject->setMarking(['b' => 1, 'c' => 1]); $this->assertFalse($workflow->can($subject, 't1')); $this->assertTrue($workflow->can($subject, 't2')); - $subject->marking = ['f' => 1]; + $subject->setMarking(['f' => 1]); $this->assertFalse($workflow->can($subject, 't5')); $this->assertTrue($workflow->can($subject, 't6')); @@ -128,8 +123,7 @@ public function testCan() public function testCanWithGuard() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $eventDispatcher = new EventDispatcher(); $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); @@ -142,8 +136,7 @@ public function testCanWithGuard() public function testCanDoesNotTriggerGuardEventsForNotEnabledTransitions() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $dispatchedEvents = []; $eventDispatcher = new EventDispatcher(); @@ -169,13 +162,12 @@ public function testCanWithSameNameTransition() $definition = $this->createWorkflowWithSameNameTransition(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $this->assertTrue($workflow->can($subject, 'a_to_bc')); $this->assertFalse($workflow->can($subject, 'b_to_c')); $this->assertFalse($workflow->can($subject, 'to_a')); - $subject->marking = ['b' => 1]; + $subject->setMarking(['b' => 1]); $this->assertFalse($workflow->can($subject, 'a_to_bc')); $this->assertTrue($workflow->can($subject, 'b_to_c')); $this->assertTrue($workflow->can($subject, 'to_a')); @@ -188,9 +180,8 @@ public function testCanWithSameNameTransition() public function testBuildTransitionBlockerListReturnsUndefinedTransition() { $definition = $this->createSimpleWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; - $workflow = new Workflow($definition); + $subject = new Subject(); + $workflow = new Workflow($definition, new MethodMarkingStore()); $workflow->buildTransitionBlockerList($subject, '404 Not Found'); } @@ -198,24 +189,23 @@ public function testBuildTransitionBlockerListReturnsUndefinedTransition() public function testBuildTransitionBlockerList() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $this->assertTrue($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty()); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty()); - $subject->marking = ['b' => 1]; + $subject->setMarking(['b' => 1]); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty()); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty()); - $subject->marking = ['b' => 1, 'c' => 1]; + $subject->setMarking(['b' => 1, 'c' => 1]); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't1')->isEmpty()); $this->assertTrue($workflow->buildTransitionBlockerList($subject, 't2')->isEmpty()); - $subject->marking = ['f' => 1]; + $subject->setMarking(['f' => 1]); $this->assertFalse($workflow->buildTransitionBlockerList($subject, 't5')->isEmpty()); $this->assertTrue($workflow->buildTransitionBlockerList($subject, 't6')->isEmpty()); @@ -224,8 +214,7 @@ public function testBuildTransitionBlockerList() public function testBuildTransitionBlockerListReturnsReasonsProvidedByMarking() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $transitionBlockerList = $workflow->buildTransitionBlockerList($subject, 't2'); @@ -238,8 +227,7 @@ public function testBuildTransitionBlockerListReturnsReasonsProvidedByMarking() public function testBuildTransitionBlockerListReturnsReasonsProvidedInGuards() { $definition = $this->createSimpleWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $dispatcher = new EventDispatcher(); $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $dispatcher); @@ -274,8 +262,7 @@ public function testBuildTransitionBlockerListReturnsReasonsProvidedInGuards() public function testApplyWithNotExisingTransition() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $workflow->apply($subject, '404 Not Found'); @@ -284,8 +271,7 @@ public function testApplyWithNotExisingTransition() public function testApplyWithNotEnabledTransition() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); try { @@ -306,8 +292,7 @@ public function testApplyWithNotEnabledTransition() public function testApply() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->apply($subject, 't1'); @@ -320,8 +305,7 @@ public function testApply() public function testApplyWithSameNameTransition() { - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $definition = $this->createWorkflowWithSameNameTransition(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); @@ -353,8 +337,8 @@ public function testApplyWithSameNameTransition() public function testApplyWithSameNameTransition2() { - $subject = new \stdClass(); - $subject->marking = ['a' => 1, 'b' => 1]; + $subject = new Subject(); + $subject->setMarking(['a' => 1, 'b' => 1]); $places = range('a', 'd'); $transitions = []; @@ -373,8 +357,8 @@ public function testApplyWithSameNameTransition2() public function testApplyWithSameNameTransition3() { - $subject = new \stdClass(); - $subject->marking = ['a' => 1]; + $subject = new Subject(); + $subject->setMarking(['a' => 1]); $places = range('a', 'd'); $transitions = []; @@ -393,8 +377,7 @@ public function testApplyWithSameNameTransition3() public function testApplyWithEventDispatcher() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $eventDispatcher = new EventDispatcherMock(); $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); @@ -438,8 +421,7 @@ public function testApplyWithEventDispatcher() public function testEventName() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $dispatcher = new EventDispatcher(); $name = 'workflow_name'; $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $dispatcher, $name); @@ -468,8 +450,8 @@ public function testMarkingStateOnApplyWithEventDispatcher() { $definition = new Definition(range('a', 'f'), [new Transition('t', range('a', 'c'), range('d', 'f'))]); - $subject = new \stdClass(); - $subject->marking = ['a' => 1, 'b' => 1, 'c' => 1]; + $subject = new Subject(); + $subject->setMarking(['a' => 1, 'b' => 1, 'c' => 1]); $dispatcher = new EventDispatcher(); @@ -502,8 +484,7 @@ public function testMarkingStateOnApplyWithEventDispatcher() public function testGetEnabledTransitions() { $definition = $this->createComplexWorkflowDefinition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $eventDispatcher = new EventDispatcher(); $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); @@ -512,13 +493,13 @@ public function testGetEnabledTransitions() $this->assertEmpty($workflow->getEnabledTransitions($subject)); - $subject->marking = ['d' => 1]; + $subject->setMarking(['d' => 1]); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(2, $transitions); $this->assertSame('t3', $transitions[0]->getName()); $this->assertSame('t4', $transitions[1]->getName()); - $subject->marking = ['c' => 1, 'e' => 1]; + $subject->setMarking(['c' => 1, 'e' => 1]); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(1, $transitions); $this->assertSame('t5', $transitions[0]->getName()); @@ -527,15 +508,14 @@ public function testGetEnabledTransitions() public function testGetEnabledTransitionsWithSameNameTransition() { $definition = $this->createWorkflowWithSameNameTransition(); - $subject = new \stdClass(); - $subject->marking = null; + $subject = new Subject(); $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(1, $transitions); $this->assertSame('a_to_bc', $transitions[0]->getName()); - $subject->marking = ['b' => 1, 'c' => 1]; + $subject->setMarking(['b' => 1, 'c' => 1]); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(3, $transitions); $this->assertSame('b_to_c', $transitions[0]->getName()); From 2d3f2b7a74e70bec23dd0e7ff765698e447a4729 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 26 Feb 2019 19:23:16 +0100 Subject: [PATCH 251/495] undeprecate the RoleHierarchyInterface Instead of deprecating the interface it is sufficient to deprecate its getReachableRoles() method and add a new getReachableRoleNames() method in Symfony 5. --- UPGRADE-4.3.md | 5 ++- UPGRADE-5.0.md | 4 +-- .../DataCollector/SecurityDataCollector.php | 3 +- .../Resources/config/security.xml | 2 -- src/Symfony/Component/Security/CHANGELOG.md | 5 ++- .../Authorization/Voter/ExpressionVoter.php | 32 +++++++++---------- .../Voter/RoleHierarchyVoter.php | 9 +++--- .../Security/Core/Role/RoleHierarchy.php | 15 +++------ .../Core/Role/RoleHierarchyInterface.php | 16 +++------- .../Workflow/EventListener/GuardListener.php | 21 +++++++++--- 10 files changed, 52 insertions(+), 60 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 52165c10b539e..f91bdb8bf6b16 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -88,9 +88,8 @@ Security * The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles instead. - * The `RoleHierarchyInterface` is deprecated and will be removed in 5.0. - * The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0. - Use the `getReachableRoleNames()` method instead. + * The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0. + Role hierarchies must implement the `getReachableRoleNames()` method instead and return roles as strings. * The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` method instead and return roles as strings. * The `ListenerInterface` is deprecated, turn your listeners into callables instead. diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 60b16b1c58df8..5757661bec94f 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -256,8 +256,8 @@ Security -------- * The `Role` and `SwitchUserRole` classes have been removed. - * The `RoleHierarchyInterface` has been removed. - * The `getReachableRoles()` method of the `RoleHierarchy` class has been removed. + * The `getReachableRoles()` method of the `RoleHierarchy` class has been removed. It has been replaced by the new + `getReachableRoleNames()` method. * The `getRoles()` method has been removed from the `TokenInterface`. It has been replaced by the new `getRoleNames()` method. * The `ContextListener::setLogoutOnUserChange()` method has been removed. diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index d33d227ff137c..0d122efe7fd81 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -23,7 +23,6 @@ use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager; use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Http\Firewall\SwitchUserListener; @@ -113,7 +112,7 @@ public function collect(Request $request, Response $response, \Exception $except } if (null !== $this->roleHierarchy) { - if ($this->roleHierarchy instanceof RoleHierarchy) { + if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) { $allRoles = $this->roleHierarchy->getReachableRoleNames($assignedRoles); } else { $allRoles = array_map(function (Role $role) { return (string) $role; }, $this->roleHierarchy->getReachableRoles($token->getRoles(false))); diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index d4d6f1a2e362d..1d2f0c4e503b3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -98,8 +98,6 @@ %security.role_hierarchy.roles% - - diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index e29070f0cc4ca..fc6b60a3a1309 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -6,9 +6,8 @@ CHANGELOG * The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles instead. - * The `RoleHierarchyInterface` is deprecated and will be removed in 5.0. - * The `getReachableRoles()` method of the `RoleHierarchy` class is deprecated and will be removed in 5.0. - Use the `getReachableRoleNames()` method instead. + * The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0. + Role hierarchies must implement the `getReachableRoleNames()` method instead and return roles as strings. * The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` method instead and return roles as strings. * Made the `serialize()` and `unserialize()` methods of `AbstractToken` and diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php index c84fc5d9b43cc..e35583555d60e 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php @@ -19,7 +19,6 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\ExpressionLanguage; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; /** @@ -43,6 +42,10 @@ public function __construct(ExpressionLanguage $expressionLanguage, Authenticati @trigger_error(sprintf('Passing a RoleHierarchyInterface to "%s()" is deprecated since Symfony 4.2. Pass an AuthorizationCheckerInterface instead.', __METHOD__), E_USER_DEPRECATED); $roleHierarchy = $authChecker; $authChecker = null; + + if (!method_exists($roleHierarchy, 'getReachableRoleNames')) { + @trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($this->roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED); + } } elseif (null === $authChecker) { @trigger_error(sprintf('Argument 3 passed to "%s()" should be an instance of AuthorizationCheckerInterface, not passing it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); } elseif (!$authChecker instanceof AuthorizationCheckerInterface) { @@ -92,27 +95,23 @@ public function vote(TokenInterface $token, $subject, array $attributes) private function getVariables(TokenInterface $token, $subject) { - if ($this->roleHierarchy instanceof RoleHierarchy) { - if (method_exists($token, 'getRoleNames')) { - $rolesFromToken = $token->getRoleNames(); - } else { - @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); - - $rolesFromToken = $token->getRoles(false); - } - - $roles = $this->roleHierarchy->getReachableRoleNames($rolesFromToken); - } elseif (null !== $this->roleHierarchy) { - $roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false)); - } elseif (method_exists($token, 'getRoleNames')) { - $roles = $token->getRoleNames(); + if (method_exists($token, 'getRoleNames')) { + $roleNames = $token->getRoleNames(); + $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames); } else { @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); $roles = $token->getRoles(false); + $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles); } - $roles = array_map(function ($role) { return $role instanceof Role ? $role->getRole() : $role; }, $roles); + if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) { + $roleNames = $this->roleHierarchy->getReachableRoleNames($roleNames); + $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames); + } elseif (null !== $this->roleHierarchy) { + $roles = $this->roleHierarchy->getReachableRoles($roles); + $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles); + } $variables = [ 'token' => $token, @@ -120,6 +119,7 @@ private function getVariables(TokenInterface $token, $subject) 'object' => $subject, 'subject' => $subject, 'roles' => $roles, + 'role_names' => $roleNames, 'trust_resolver' => $this->trustResolver, 'auth_checker' => $this->authChecker, ]; diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php index 4a1de12cf7fa8..d4524667c5715 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleHierarchyVoter.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Core\Authorization\Voter; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; @@ -27,8 +28,8 @@ class RoleHierarchyVoter extends RoleVoter public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefix = 'ROLE_') { - if (!$roleHierarchy instanceof RoleHierarchy) { - @trigger_error(sprintf('Passing a role hierarchy to "%s" that is not an instance of "%s" is deprecated since Symfony 4.3 and support for it will be dropped in Symfony 5.0 ("%s" given).', __CLASS__, RoleHierarchy::class, \get_class($roleHierarchy)), E_USER_DEPRECATED); + if (!method_exists($roleHierarchy, 'getReachableRoleNames')) { + @trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED); } $this->roleHierarchy = $roleHierarchy; @@ -41,13 +42,13 @@ public function __construct(RoleHierarchyInterface $roleHierarchy, string $prefi */ protected function extractRoles(TokenInterface $token) { - if ($this->roleHierarchy instanceof RoleHierarchy) { + if (method_exists($this->roleHierarchy, 'getReachableRoleNames')) { if (method_exists($token, 'getRoleNames')) { $roles = $token->getRoleNames(); } else { @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); - $roles = $token->getRoles(false); + $roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false)); } return $this->roleHierarchy->getReachableRoleNames($roles); diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php index d725000d1b826..c1116cd2c3d55 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchy.php @@ -36,7 +36,9 @@ public function __construct(array $hierarchy) */ public function getReachableRoles(array $roles) { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED); + if (0 === \func_num_args() || func_get_arg(0)) { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.3 and will be removed in 5.0. Use roles as strings and the getReachableRoleNames() method instead.', __METHOD__), E_USER_DEPRECATED); + } $reachableRoles = $roles; foreach ($roles as $role) { @@ -59,16 +61,7 @@ public function getReachableRoles(array $roles) */ public function getReachableRoleNames(array $roles): array { - $reachableRoles = $roles = array_map( - function ($role) { - if ($role instanceof Role) { - return $role->getRole(); - } - - return $role; - }, - $roles - ); + $reachableRoles = $roles; foreach ($roles as $role) { if (!isset($this->map[$role])) { diff --git a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php index 3a5112f7e5b91..9f54042db0e4b 100644 --- a/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php +++ b/src/Symfony/Component/Security/Core/Role/RoleHierarchyInterface.php @@ -14,21 +14,13 @@ /** * RoleHierarchyInterface is the interface for a role hierarchy. * + * The getReachableRoles(Role[] $roles) method that returns an array of all reachable Role objects is deprecated + * since Symfony 4.3. + * * @author Fabien Potencier * - * @deprecated since Symfony 4.3, to be removed in 5.0. + * @method string[] getReachableRoleNames(string[] $roles) The associated roles - not implementing it is deprecated since Symfony 4.3 */ interface RoleHierarchyInterface { - /** - * Returns an array of all reachable roles by the given ones. - * - * Reachable roles are the roles directly assigned but also all roles that - * are transitively reachable from them in the role hierarchy. - * - * @param Role[] $roles An array of directly assigned roles - * - * @return Role[] An array of all reachable roles - */ - public function getReachableRoles(array $roles); } diff --git a/src/Symfony/Component/Workflow/EventListener/GuardListener.php b/src/Symfony/Component/Workflow/EventListener/GuardListener.php index 60cd00ed2084f..a1795b8f47b02 100644 --- a/src/Symfony/Component/Workflow/EventListener/GuardListener.php +++ b/src/Symfony/Component/Workflow/EventListener/GuardListener.php @@ -13,9 +13,9 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Role\Role; -use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Workflow\Event\GuardEvent; @@ -37,6 +37,10 @@ class GuardListener public function __construct(array $configuration, ExpressionLanguage $expressionLanguage, TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorizationChecker, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null, ValidatorInterface $validator = null) { + if (null !== $roleHierarchy && !method_exists($roleHierarchy, 'getReachableRoleNames')) { + @trigger_error(sprintf('Not implementing the getReachableRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($roleHierarchy), RoleHierarchyInterface::class), E_USER_DEPRECATED); + } + $this->configuration = $configuration; $this->expressionLanguage = $expressionLanguage; $this->tokenStorage = $tokenStorage; @@ -83,15 +87,21 @@ private function getVariables(GuardEvent $event): array } if (method_exists($token, 'getRoleNames')) { - $roles = $token->getRoleNames(); + $roleNames = $token->getRoleNames(); + $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames); } else { - $roles = array_map(function (Role $role) { return $role->getRole(); }, $token->getRoles(false)); + @trigger_error(sprintf('Not implementing the getRoleNames() method in %s which implements %s is deprecated since Symfony 4.3.', \get_class($token), TokenInterface::class), E_USER_DEPRECATED); + + $roles = $token->getRoles(false); + $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles); } - if ($this->roleHierarchy instanceof RoleHierarchy) { - $roles = $this->roleHierarchy->getReachableRoleNames($roles); + if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) { + $roleNames = $this->roleHierarchy->getReachableRoleNames($roles); + $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames); } elseif (null !== $this->roleHierarchy) { $roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false)); + $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles); } $variables = [ @@ -99,6 +109,7 @@ private function getVariables(GuardEvent $event): array 'user' => $token->getUser(), 'subject' => $event->getSubject(), 'roles' => $roles, + 'role_names' => $roleNames, // needed for the is_granted expression function 'auth_checker' => $this->authorizationChecker, // needed for the is_* expression function From dae5686722b2dc5800ec5ccdc1c0c6ffdbe04f50 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 30 Jan 2019 10:26:19 +0100 Subject: [PATCH 252/495] [HttpClient] added CachingHttpClient --- .../HttpClient/CachingHttpClient.php | 142 ++++++++++++++++++ .../Component/HttpClient/HttpClientTrait.php | 4 + .../Component/HttpClient/HttpOptions.php | 10 ++ .../HttpClient/Response/MockResponse.php | 2 +- .../Component/HttpClient/composer.json | 3 +- ...ealHttpKernel.php => HttpClientKernel.php} | 2 +- .../HttpClient/HttpClientInterface.php | 1 + 7 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/HttpClient/CachingHttpClient.php rename src/Symfony/Component/HttpKernel/{RealHttpKernel.php => HttpClientKernel.php} (98%) diff --git a/src/Symfony/Component/HttpClient/CachingHttpClient.php b/src/Symfony/Component/HttpClient/CachingHttpClient.php new file mode 100644 index 0000000000000..30f370078f265 --- /dev/null +++ b/src/Symfony/Component/HttpClient/CachingHttpClient.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\Response\ResponseStream; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\HttpCache\HttpCache; +use Symfony\Component\HttpKernel\HttpCache\StoreInterface; +use Symfony\Component\HttpKernel\HttpClientKernel; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * Adds caching on top of an HTTP client. + * + * The implementation buffers responses in memory and doesn't stream directly from the network. + * You can disable/enable this layer by setting option "no_cache" under "extra" to true/false. + * By default, caching is enabled unless the "buffer" option is set to false. + * + * @author Nicolas Grekas + */ +class CachingHttpClient implements HttpClientInterface +{ + use HttpClientTrait; + + private $client; + private $cache; + private $defaultOptions = self::OPTIONS_DEFAULTS; + + public function __construct(HttpClientInterface $client, StoreInterface $store, array $defaultOptions = [], LoggerInterface $logger = null) + { + if (!class_exists(HttpClientKernel::class)) { + throw new \LogicException(sprintf('Using "%s" requires that the HttpKernel component version 4.3 or higher is installed, try running "composer require symfony/http-kernel:^4.3".', __CLASS__)); + } + + $this->client = $client; + $kernel = new HttpClientKernel($client, $logger); + $this->cache = new HttpCache($kernel, $store, null, $defaultOptions); + + unset($defaultOptions['debug']); + unset($defaultOptions['default_ttl']); + unset($defaultOptions['private_headers']); + unset($defaultOptions['allow_reload']); + unset($defaultOptions['allow_revalidate']); + unset($defaultOptions['stale_while_revalidate']); + unset($defaultOptions['stale_if_error']); + + if ($defaultOptions) { + [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, $this->defaultOptions); + } + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + [$url, $options] = $this->prepareRequest($method, $url, $options, $this->defaultOptions, true); + $url = implode('', $url); + $options['extra']['no_cache'] = $options['extra']['no_cache'] ?? !$options['buffer']; + + if ($options['extra']['no_cache'] || !empty($options['body']) || !\in_array($method, ['GET', 'HEAD', 'OPTIONS'])) { + return $this->client->request($method, $url, $options); + } + + $request = Request::create($url, $method); + $request->attributes->set('http_client_options', $options); + + foreach ($options['headers'] as $name => $values) { + if ('cookie' !== $name) { + $request->headers->set($name, $values); + continue; + } + + foreach ($values as $cookies) { + foreach (explode('; ', $cookies) as $cookie) { + if ('' !== $cookie) { + $cookie = explode('=', $cookie, 2); + $request->cookies->set($cookie[0], $cookie[1] ?? null); + } + } + } + } + + $response = $this->cache->handle($request); + $response = new MockResponse($response->getContent(), [ + 'http_code' => $response->getStatusCode(), + 'raw_headers' => $response->headers->allPreserveCase(), + ]); + + return MockResponse::fromRequest($method, $url, $options, $response); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + if ($responses instanceof ResponseInterface) { + $responses = [$responses]; + } elseif (!\is_iterable($responses)) { + throw new \TypeError(sprintf('%s() expects parameter 1 to be an iterable of ResponseInterface objects, %s given.', __METHOD__, \is_object($responses) ? \get_class($responses) : \gettype($responses))); + } + + $mockResponses = []; + $clientResponses = []; + + foreach ($responses as $response) { + if ($response instanceof MockResponse) { + $mockResponses[] = $response; + } else { + $clientResponses[] = $response; + } + } + + if (!$mockResponses) { + return $this->client->stream($clientResponses, $timeout); + } + + if (!$clientResponses) { + return new ResponseStream(MockResponse::stream($mockResponses, $timeout)); + } + + return new ResponseStream((function () use ($mockResponses, $clientResponses, $timeout) { + yield from MockResponse::stream($mockResponses, $timeout); + yield $this->client->stream($clientResponses, $timeout); + })()); + } +} diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 04178ae656247..9a45d420b98eb 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -147,6 +147,10 @@ private static function mergeDefaultOptions(array $options, array $defaultOption $options[$k] = $options[$k] ?? $v; } + if (isset($defaultOptions['extra'])) { + $options['extra'] += $defaultOptions['extra']; + } + if ($defaultOptions['resolve'] ?? false) { $options['resolve'] += array_change_key_case($defaultOptions['resolve']); } diff --git a/src/Symfony/Component/HttpClient/HttpOptions.php b/src/Symfony/Component/HttpClient/HttpOptions.php index 2a29fc66fbebf..85b55f0d08525 100644 --- a/src/Symfony/Component/HttpClient/HttpOptions.php +++ b/src/Symfony/Component/HttpClient/HttpOptions.php @@ -309,4 +309,14 @@ public function capturePeerCertChain(bool $capture) return $this; } + + /** + * @return $this + */ + public function setExtra(string $name, $value) + { + $this->options['extra'][$name] = $value; + + return $this; + } } diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index c6630b65bcc08..9c63f0052ebdd 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -56,7 +56,7 @@ public function __construct($body = '', array $info = []) } } - $info['raw_headers'] = $rawHeaders; + $this->info['raw_headers'] = $rawHeaders; } /** diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index 979385626d2cb..803b424d3d339 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -26,7 +26,8 @@ "require-dev": { "nyholm/psr7": "^1.0", "psr/http-client": "^1.0", - "symfony/process": "~4.2" + "symfony/http-kernel": "^4.3", + "symfony/process": "^4.2" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpClient\\": "" }, diff --git a/src/Symfony/Component/HttpKernel/RealHttpKernel.php b/src/Symfony/Component/HttpKernel/HttpClientKernel.php similarity index 98% rename from src/Symfony/Component/HttpKernel/RealHttpKernel.php rename to src/Symfony/Component/HttpKernel/HttpClientKernel.php index d78fda1f8dac9..29a6a97cefe22 100644 --- a/src/Symfony/Component/HttpKernel/RealHttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpClientKernel.php @@ -27,7 +27,7 @@ * * @author Fabien Potencier */ -final class RealHttpKernel implements HttpKernelInterface +final class HttpClientKernel implements HttpKernelInterface { private $client; private $logger; diff --git a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php index 6abc459fee787..194a8fb8afeea 100644 --- a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php +++ b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php @@ -64,6 +64,7 @@ interface HttpClientInterface 'ciphers' => null, 'peer_fingerprint' => null, 'capture_peer_cert_chain' => false, + 'extra' => [], // array - additional options that can be ignored if unsupported, unlike regular options ]; /** From c40017d63ca567dd357c58fb5662a25f66e7d800 Mon Sep 17 00:00:00 2001 From: tdutrion Date: Fri, 22 Mar 2019 19:14:40 +0100 Subject: [PATCH 253/495] Allow user to set the project dir Currently, the project directory is defined by the location of the composer.json file. That file is not required in production, which therefore breaks the method getProjectDir (who sends back null). This does not fix the behaviour, but allows the developer to pass the project dir as a parameter. --- src/Symfony/Component/HttpKernel/Kernel.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 402e0391447a8..cc726999eb8c7 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -83,12 +83,13 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl const END_OF_MAINTENANCE = '07/2019'; const END_OF_LIFE = '01/2020'; - public function __construct(string $environment, bool $debug) + public function __construct(string $environment, bool $debug, string $projectDir = null) { $this->environment = $environment; $this->debug = $debug; $this->rootDir = $this->getRootDir(false); $this->name = $this->getName(false); + $this->projectDir = $projectDir; } public function __clone() From 1ee0a1147a7b3e5459b35dd132d4f483f775e5eb Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Thu, 14 Mar 2019 14:45:37 +0100 Subject: [PATCH 254/495] [HttpClient] Add a ScopingHttpClient --- .../HttpClient/ScopingHttpClient.php | 80 ++++++++++++++++ .../Tests/ScopingHttpClientTest.php | 96 +++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 src/Symfony/Component/HttpClient/ScopingHttpClient.php create mode 100644 src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php diff --git a/src/Symfony/Component/HttpClient/ScopingHttpClient.php b/src/Symfony/Component/HttpClient/ScopingHttpClient.php new file mode 100644 index 0000000000000..5c8a0c411f1ab --- /dev/null +++ b/src/Symfony/Component/HttpClient/ScopingHttpClient.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient; + +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; +use Symfony\Contracts\HttpClient\ResponseStreamInterface; + +/** + * Auto-configure the default options based on the requested URL. + * + * @author Anthony Martin + * + * @experimental in 4.3 + */ +class ScopingHttpClient implements HttpClientInterface +{ + use HttpClientTrait; + + private $client; + private $defaultOptionsByRegexp; + private $defaultRegexp; + + public function __construct(HttpClientInterface $client, array $defaultOptionsByRegexp, string $defaultRegexp = null) + { + $this->client = $client; + $this->defaultOptionsByRegexp = $defaultOptionsByRegexp; + $this->defaultRegexp = $defaultRegexp; + } + + /** + * {@inheritdoc} + */ + public function request(string $method, string $url, array $options = []): ResponseInterface + { + $url = self::parseUrl($url, $options['query'] ?? []); + + if (\is_string($options['base_uri'] ?? null)) { + $options['base_uri'] = self::parseUrl($options['base_uri']); + } + + try { + $url = implode('', self::resolveUrl($url, $options['base_uri'] ?? null)); + } catch (InvalidArgumentException $e) { + if (null === $this->defaultRegexp) { + throw $e; + } + + [$url, $options] = self::prepareRequest($method, implode('', $url), $options, $this->defaultOptionsByRegexp[$this->defaultRegexp], true); + $url = implode('', $url); + } + + foreach ($this->defaultOptionsByRegexp as $regexp => $defaultOptions) { + if (preg_match("{{$regexp}}A", $url)) { + $options = self::mergeDefaultOptions($options, $defaultOptions, true); + break; + } + } + + return $this->client->request($method, $url, $options); + } + + /** + * {@inheritdoc} + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface + { + return $this->client->stream($responses, $timeout); + } +} diff --git a/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php new file mode 100644 index 0000000000000..9ab34c2b1f6f8 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\InvalidArgumentException; +use Symfony\Component\HttpClient\MockHttpClient; +use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Component\HttpClient\ScopingHttpClient; + +class ScopingHttpClientTest extends TestCase +{ + public function testRelativeUrl() + { + $mockClient = new MockHttpClient([]); + $client = new ScopingHttpClient($mockClient, []); + + $this->expectException(InvalidArgumentException::class); + $client->request('GET', '/foo'); + } + + public function testRelativeUrlWithDefaultRegexp() + { + $mockClient = new MockHttpClient(new MockResponse()); + $client = new ScopingHttpClient($mockClient, ['.*' => ['base_uri' => 'http://example.com']], '.*'); + + $this->assertSame('http://example.com/foo', $client->request('GET', '/foo')->getInfo('url')); + } + + /** + * @dataProvider provideMatchingUrls + */ + public function testMatchingUrls(string $regexp, string $url, array $options) + { + $mockClient = new MockHttpClient(new MockResponse()); + $client = new ScopingHttpClient($mockClient, $options); + + $response = $client->request('GET', $url); + $reuestedOptions = $response->getRequestOptions(); + + $this->assertEquals($reuestedOptions['case'], $options[$regexp]['case']); + } + + public function provideMatchingUrls() + { + $defaultOptions = [ + '.*/foo-bar' => ['case' => 1], + '.*' => ['case' => 2], + ]; + + yield ['regexp' => '.*/foo-bar', 'url' => 'http://example.com/foo-bar', 'default_options' => $defaultOptions]; + yield ['regexp' => '.*', 'url' => 'http://example.com/bar-foo', 'default_options' => $defaultOptions]; + yield ['regexp' => '.*', 'url' => 'http://example.com/foobar', 'default_options' => $defaultOptions]; + } + + public function testMatchingUrlsAndOptions() + { + $defaultOptions = [ + '.*/foo-bar' => ['headers' => ['x-app' => 'unit-test-foo-bar']], + '.*' => ['headers' => ['content-type' => 'text/html']], + ]; + + $mockResponses = [ + new MockResponse(), + new MockResponse(), + new MockResponse(), + ]; + + $mockClient = new MockHttpClient($mockResponses); + $client = new ScopingHttpClient($mockClient, $defaultOptions); + + $response = $client->request('GET', 'http://example.com/foo-bar', ['json' => ['url' => 'http://example.com']]); + $requestOptions = $response->getRequestOptions(); + $this->assertEquals($requestOptions['json']['url'], 'http://example.com'); + $this->assertEquals($requestOptions['headers']['x-app'][0], $defaultOptions['.*/foo-bar']['headers']['x-app']); + + $response = $client->request('GET', 'http://example.com/bar-foo', ['headers' => ['x-app' => 'unit-test']]); + $requestOptions = $response->getRequestOptions(); + $this->assertEquals($requestOptions['headers']['x-app'][0], 'unit-test'); + $this->assertEquals($requestOptions['headers']['content-type'][0], 'text/html'); + + $response = $client->request('GET', 'http://example.com/foobar-foo', ['headers' => ['x-app' => 'unit-test']]); + $requestOptions = $response->getRequestOptions(); + $this->assertEquals($requestOptions['headers']['x-app'][0], 'unit-test'); + $this->assertEquals($requestOptions['headers']['content-type'][0], 'text/html'); + } +} From a989384999692e75b5905e92c8d81e20b69035e9 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Wed, 13 Mar 2019 15:48:28 -0400 Subject: [PATCH 255/495] Adding global retry support, events & more to messenger transport Co-authored-by: Samuel ROZE --- .../DependencyInjection/Configuration.php | 14 ++ .../FrameworkExtension.php | 19 +++ .../Resources/config/console.xml | 4 + .../Resources/config/messenger.xml | 13 ++ src/Symfony/Component/Messenger/CHANGELOG.md | 29 +++- .../Command/ConsumeMessagesCommand.php | 22 ++- src/Symfony/Component/Messenger/Envelope.php | 12 ++ .../Event/AbstractWorkerMessageEvent.php | 43 +++++ .../Event/WorkerMessageFailedEvent.php | 45 ++++++ .../Event/WorkerMessageHandledEvent.php | 23 +++ .../Event/WorkerMessageReceivedEvent.php | 23 +++ .../MessageDecodingFailedException.php | 21 +++ .../UnrecoverableMessageHandlingException.php | 26 +++ .../Middleware/SendMessageMiddleware.php | 16 +- .../Retry/MultiplierRetryStrategy.php | 98 +++++++++++ .../Retry/RetryStrategyInterface.php | 31 ++++ .../Component/Messenger/Stamp/DelayStamp.php | 35 ++++ .../Messenger/Stamp/RedeliveryStamp.php | 60 +++++++ .../DependencyInjection/MessengerPassTest.php | 9 ++ .../Messenger/Tests/EnvelopeTest.php | 13 +- .../Tests/Fixtures/CallbackReceiver.php | 23 +++ .../Middleware/SendMessageMiddlewareTest.php | 76 ++++++++- .../Retry/MultiplierRetryStrategyTest.php | 80 +++++++++ .../Tests/Stamp/RedeliveryStampTest.php | 34 ++++ .../AmqpExt/AmqpExtIntegrationTest.php | 90 +++++++++-- .../Transport/AmqpExt/AmqpReceiverTest.php | 121 ++------------ .../Transport/AmqpExt/ConnectionTest.php | 80 +++++++++ .../AmqpExt/Fixtures/long_receiver.php | 7 +- .../Serialization/PhpSerializerTest.php | 25 +++ .../Serialization/SerializerTest.php | 25 +++ .../Component/Messenger/Tests/WorkerTest.php | 140 ++++++++++++++-- .../Transport/AmqpExt/AmqpReceivedStamp.php | 34 ++++ .../Transport/AmqpExt/AmqpReceiver.php | 93 +++++++---- .../Transport/AmqpExt/AmqpSender.php | 10 +- .../Transport/AmqpExt/AmqpTransport.php | 16 ++ .../Transport/AmqpExt/Connection.php | 152 ++++++++++++++++-- .../RejectMessageExceptionInterface.php | 27 ---- .../Transport/Receiver/ReceiverInterface.php | 24 +++ .../StopWhenMemoryUsageIsExceededReceiver.php | 10 ++ ...StopWhenMessageCountIsExceededReceiver.php | 10 ++ .../StopWhenTimeLimitIsReachedReceiver.php | 10 ++ .../Transport/Sender/SenderInterface.php | 3 + .../Transport/Serialization/PhpSerializer.php | 34 +++- .../Transport/Serialization/Serializer.php | 14 +- .../Serialization/SerializerInterface.php | 3 + src/Symfony/Component/Messenger/Worker.php | 131 ++++++++++++++- src/Symfony/Component/Messenger/composer.json | 4 + 47 files changed, 1603 insertions(+), 229 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php create mode 100644 src/Symfony/Component/Messenger/Event/WorkerMessageFailedEvent.php create mode 100644 src/Symfony/Component/Messenger/Event/WorkerMessageHandledEvent.php create mode 100644 src/Symfony/Component/Messenger/Event/WorkerMessageReceivedEvent.php create mode 100644 src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php create mode 100644 src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php create mode 100644 src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php create mode 100644 src/Symfony/Component/Messenger/Retry/RetryStrategyInterface.php create mode 100644 src/Symfony/Component/Messenger/Stamp/DelayStamp.php create mode 100644 src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php create mode 100644 src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php create mode 100644 src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php delete mode 100644 src/Symfony/Component/Messenger/Transport/AmqpExt/Exception/RejectMessageExceptionInterface.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 04f2bdbe16c26..4355e632f3310 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1111,6 +1111,20 @@ function ($a) { ->prototype('variable') ->end() ->end() + ->arrayNode('retry_strategy') + ->addDefaultsIfNotSet() + ->validate() + ->ifTrue(function ($v) { return null !== $v['service'] && (isset($v['max_retries']) || isset($v['delay']) || isset($v['multiplier']) || isset($v['max_delay'])); }) + ->thenInvalid('"service" cannot be used along with the other retry_strategy options.') + ->end() + ->children() + ->scalarNode('service')->defaultNull()->info('Service id to override the retry strategy entirely')->end() + ->integerNode('max_retries')->defaultValue(3)->min(0)->end() + ->integerNode('delay')->defaultValue(1000)->min(0)->info('Time in ms to delay (or the initial value when multiplier is used)')->end() + ->floatNode('multiplier')->defaultValue(2)->min(1)->info('If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries))')->end() + ->integerNode('max_delay')->defaultValue(0)->min(0)->info('Max time in ms that a retry should ever be delayed (0 = infinite)')->end() + ->end() + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index d2d0181f8c006..0e12127272fdb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1653,6 +1653,7 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder } $senderAliases = []; + $transportRetryReferences = []; foreach ($config['transports'] as $name => $transport) { if (0 === strpos($transport['dsn'], 'amqp://') && !$container->hasDefinition('messenger.transport.amqp.factory')) { throw new LogicException('The default AMQP transport is not available. Make sure you have installed and enabled the Serializer component. Try enabling it or running "composer require symfony/serializer-pack".'); @@ -1665,6 +1666,21 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder ; $container->setDefinition($transportId = 'messenger.transport.'.$name, $transportDefinition); $senderAliases[$name] = $transportId; + + if (null !== $transport['retry_strategy']['service']) { + $transportRetryReferences[$name] = new Reference($transport['retry_strategy']['service']); + } else { + $retryServiceId = sprintf('messenger.retry.multiplier_retry_strategy.%s', $name); + $retryDefinition = new ChildDefinition('messenger.retry.abstract_multiplier_retry_strategy'); + $retryDefinition + ->replaceArgument(0, $transport['retry_strategy']['max_retries']) + ->replaceArgument(1, $transport['retry_strategy']['delay']) + ->replaceArgument(2, $transport['retry_strategy']['multiplier']) + ->replaceArgument(3, $transport['retry_strategy']['max_delay']); + $container->setDefinition($retryServiceId, $retryDefinition); + + $transportRetryReferences[$name] = new Reference($retryServiceId); + } } $messageToSendersMapping = []; @@ -1686,6 +1702,9 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder ->replaceArgument(0, $messageToSendersMapping) ->replaceArgument(1, $messagesToSendAndHandle) ; + + $container->getDefinition('messenger.retry_strategy_locator') + ->replaceArgument(0, $transportRetryReferences); } private function registerCacheConfiguration(array $config, ContainerBuilder $container) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 9ce2c77373ed0..eeb36961f7d53 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -82,8 +82,12 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index d50d13bde287f..3d471c9338934 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -64,5 +64,18 @@ + + + + + + + + + + + + + diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 227cddb5eeb82..40f8c1dc043fa 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -3,7 +3,34 @@ CHANGELOG 4.3.0 ----- - + + * [BC BREAK] 2 new methods were added to `ReceiverInterface`: + `ack()` and `reject()`. + * [BC BREAK] Error handling was moved from the receivers into + `Worker`. Implementations of `ReceiverInterface::handle()` + should now allow all exceptions to be thrown, except for transport + exceptions. They should also not retry (e.g. if there's a queue, + remove from the queue) if there is a problem decoding the message. + * [BC BREAK] `RejectMessageExceptionInterface` was removed and replaced + by `Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException`, + which has the same behavior: a message will not be retried + * The default command name for `ConsumeMessagesCommand` was + changed from `messenger:consume-messages` to `messenger:consume` + * `ConsumeMessagesCommand` has two new optional constructor arguments + * `Worker` has 4 new option constructor arguments. + * The `Worker` class now handles calling `pcntl_signal_dispatch()` the + receiver no longer needs to call this. + * The `AmqpSender` will now retry messages using a dead-letter exchange + and delayed queues, instead of retrying via `nack()` + * Senders now receive the `Envelope` with the `SentStamp` on it. Previously, + the `Envelope` was passed to the sender and *then* the `SentStamp` + was added. + * `SerializerInterface` implementations should now throw a + `Symfony\Component\Messenger\Exception\MessageDecodingFailedException` + if `decode()` fails for any reason. + * [BC BREAK] The default `Serializer` will now throw a + `MessageDecodingFailedException` if `decode()` fails, instead + of the underlying exceptions from the Serializer component. * Added `PhpSerializer` which uses PHP's native `serialize()` and `unserialize()` to serialize messages to a transport * [BC BREAK] If no serializer were passed, the default serializer diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index 5f854f257f792..a973a2337d459 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -20,6 +20,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Transport\Receiver\StopWhenMemoryUsageIsExceededReceiver; use Symfony\Component\Messenger\Transport\Receiver\StopWhenMessageCountIsExceededReceiver; use Symfony\Component\Messenger\Transport\Receiver\StopWhenTimeLimitIsReachedReceiver; @@ -32,21 +33,25 @@ */ class ConsumeMessagesCommand extends Command { - protected static $defaultName = 'messenger:consume-messages'; + protected static $defaultName = 'messenger:consume'; private $busLocator; private $receiverLocator; private $logger; private $receiverNames; private $busNames; + private $retryStrategyLocator; + private $eventDispatcher; - public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], array $busNames = []) + public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], array $busNames = [], ContainerInterface $retryStrategyLocator = null, EventDispatcherInterface $eventDispatcher = null) { $this->busLocator = $busLocator; $this->receiverLocator = $receiverLocator; $this->logger = $logger; $this->receiverNames = $receiverNames; $this->busNames = $busNames; + $this->retryStrategyLocator = $retryStrategyLocator; + $this->eventDispatcher = $eventDispatcher; parent::__construct(); } @@ -132,6 +137,12 @@ protected function interact(InputInterface $input, OutputInterface $output) */ protected function execute(InputInterface $input, OutputInterface $output): void { + if (false !== strpos($input->getFirstArgument(), ':consume-')) { + $message = 'The use of the "messenger:consume-messages" command is deprecated since version 4.3 and will be removed in 5.0. Use "messenger:consume" instead.'; + @trigger_error($message, E_USER_DEPRECATED); + $output->writeln(sprintf('%s', $message)); + } + if (!$this->receiverLocator->has($receiverName = $input->getArgument('receiver'))) { throw new RuntimeException(sprintf('Receiver "%s" does not exist.', $receiverName)); } @@ -140,8 +151,13 @@ protected function execute(InputInterface $input, OutputInterface $output): void throw new RuntimeException(sprintf('Bus "%s" does not exist.', $busName)); } + if (null !== $this->retryStrategyLocator && !$this->retryStrategyLocator->has($receiverName)) { + throw new RuntimeException(sprintf('Receiver "%s" does not have a configured retry strategy.', $receiverName)); + } + $receiver = $this->receiverLocator->get($receiverName); $bus = $this->busLocator->get($busName); + $retryStrategy = null !== $this->retryStrategyLocator ? $this->retryStrategyLocator->get($receiverName) : null; $stopsWhen = []; if ($limit = $input->getOption('limit')) { @@ -174,7 +190,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void $io->comment('Re-run the command with a -vv option to see logs about consumed messages.'); } - $worker = new Worker($receiver, $bus); + $worker = new Worker($receiver, $bus, $receiverName, $retryStrategy, $this->eventDispatcher, $this->logger); $worker->run(); } diff --git a/src/Symfony/Component/Messenger/Envelope.php b/src/Symfony/Component/Messenger/Envelope.php index 02d0dca123863..2e70480886385 100644 --- a/src/Symfony/Component/Messenger/Envelope.php +++ b/src/Symfony/Component/Messenger/Envelope.php @@ -54,6 +54,18 @@ public function with(StampInterface ...$stamps): self return $cloned; } + /** + * @return Envelope a new Envelope instance without any stamps of the given class + */ + public function withoutAll(string $stampFqcn): self + { + $cloned = clone $this; + + unset($cloned->stamps[$stampFqcn]); + + return $cloned; + } + public function last(string $stampFqcn): ?StampInterface { return isset($this->stamps[$stampFqcn]) ? end($this->stamps[$stampFqcn]) : null; diff --git a/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php b/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php new file mode 100644 index 0000000000000..0f2b644139394 --- /dev/null +++ b/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Messenger\Envelope; + +/** + * @experimental in 4.3 + */ +abstract class AbstractWorkerMessageEvent extends Event +{ + private $envelope; + private $receiverName; + + public function __construct(Envelope $envelope, string $receiverName) + { + $this->envelope = $envelope; + $this->receiverName = $receiverName; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + /** + * Returns a unique identifier for transport receiver this message was received from. + */ + public function getReceiverName(): string + { + return $this->receiverName; + } +} diff --git a/src/Symfony/Component/Messenger/Event/WorkerMessageFailedEvent.php b/src/Symfony/Component/Messenger/Event/WorkerMessageFailedEvent.php new file mode 100644 index 0000000000000..b3118633a3f1e --- /dev/null +++ b/src/Symfony/Component/Messenger/Event/WorkerMessageFailedEvent.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\Messenger\Envelope; + +/** + * Dispatched when a message was received from a transport and handling failed. + * + * The event name is the class name. + * + * @experimental in 4.3 + */ +class WorkerMessageFailedEvent extends AbstractWorkerMessageEvent +{ + private $throwable; + private $willRetry; + + public function __construct(Envelope $envelope, string $receiverName, \Throwable $error, bool $willRetry) + { + $this->throwable = $error; + $this->willRetry = $willRetry; + + parent::__construct($envelope, $receiverName); + } + + public function getThrowable(): \Throwable + { + return $this->throwable; + } + + public function willRetry(): bool + { + return $this->willRetry; + } +} diff --git a/src/Symfony/Component/Messenger/Event/WorkerMessageHandledEvent.php b/src/Symfony/Component/Messenger/Event/WorkerMessageHandledEvent.php new file mode 100644 index 0000000000000..c911a01288dde --- /dev/null +++ b/src/Symfony/Component/Messenger/Event/WorkerMessageHandledEvent.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +/** + * Dispatched after a message was received from a transport and successfully handled. + * + * The event name is the class name. + * + * @experimental in 4.3 + */ +class WorkerMessageHandledEvent extends AbstractWorkerMessageEvent +{ +} diff --git a/src/Symfony/Component/Messenger/Event/WorkerMessageReceivedEvent.php b/src/Symfony/Component/Messenger/Event/WorkerMessageReceivedEvent.php new file mode 100644 index 0000000000000..3df75b8723477 --- /dev/null +++ b/src/Symfony/Component/Messenger/Event/WorkerMessageReceivedEvent.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +/** + * Dispatched when a message was received from a transport but before sent to the bus. + * + * The event name is the class name. + * + * @experimental in 4.3 + */ +class WorkerMessageReceivedEvent extends AbstractWorkerMessageEvent +{ +} diff --git a/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php b/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php new file mode 100644 index 0000000000000..9e429ecc9b4fe --- /dev/null +++ b/src/Symfony/Component/Messenger/Exception/MessageDecodingFailedException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * Thrown when a message cannot be decoded in a serializer. + * + * @experimental in 4.3 + */ +class MessageDecodingFailedException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php b/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php new file mode 100644 index 0000000000000..df08e79d8bbf6 --- /dev/null +++ b/src/Symfony/Component/Messenger/Exception/UnrecoverableMessageHandlingException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Exception; + +/** + * Thrown while handling a message to indicate that handling will continue to fail. + * + * If something goes wrong while handling a message that's received from a transport + * and the message should not be retried, a handler can throw this exception. + * + * @author Frederic Bouchery + * + * @experimental in 4.3 + */ +class UnrecoverableMessageHandlingException extends RuntimeException +{ +} diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index 6d6696a4721bd..bc6f71761c39a 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -15,6 +15,7 @@ use Psr\Log\NullLogger; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface; @@ -54,9 +55,22 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope // it's a received message, do not send it back $this->logger->info('Received message "{class}"', $context); } else { + /** @var RedeliveryStamp|null $redeliveryStamp */ + $redeliveryStamp = $envelope->last(RedeliveryStamp::class); + foreach ($this->sendersLocator->getSenders($envelope, $handle) as $alias => $sender) { + // on redelivery, only deliver to the given sender + if (null !== $redeliveryStamp && !$redeliveryStamp->shouldRedeliverToSender(\get_class($sender), $alias)) { + continue; + } + $this->logger->info('Sending message "{class}" with "{sender}"', $context + ['sender' => \get_class($sender)]); - $envelope = $sender->send($envelope)->with(new SentStamp(\get_class($sender), \is_string($alias) ? $alias : null)); + $envelope = $sender->send($envelope->with(new SentStamp(\get_class($sender), \is_string($alias) ? $alias : null))); + } + + // on a redelivery, never call local handlers + if (null !== $redeliveryStamp) { + $handle = false; } } diff --git a/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php b/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php new file mode 100644 index 0000000000000..394be2509d2c5 --- /dev/null +++ b/src/Symfony/Component/Messenger/Retry/MultiplierRetryStrategy.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Retry; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; + +/** + * A retry strategy with a constant or exponential retry delay. + * + * For example, if $delayMilliseconds=10000 & $multiplier=1 (default), + * each retry will wait exactly 10 seconds. + * + * But if $delayMilliseconds=10000 & $multiplier=2: + * * Retry 1: 10 second delay + * * Retry 2: 20 second delay (10000 * 2 = 20000) + * * Retry 3: 40 second delay (20000 * 2 = 40000) + * + * @author Ryan Weaver + * + * @experimental in 4.3 + * @final + */ +class MultiplierRetryStrategy implements RetryStrategyInterface +{ + private $maxRetries; + private $delayMilliseconds; + private $multiplier; + private $maxDelayMilliseconds; + + /** + * @param int $maxRetries The maximum number of time to retry (0 means indefinitely) + * @param int $delayMilliseconds Amount of time to delay (or the initial value when multiplier is used) + * @param float $multiplier Multiplier to apply to the delay each time a retry occurs + * @param int $maxDelayMilliseconds Maximum delay to allow (0 means no maximum) + */ + public function __construct(int $maxRetries = 3, int $delayMilliseconds = 1000, float $multiplier = 1, int $maxDelayMilliseconds = 0) + { + $this->maxRetries = $maxRetries; + + if ($delayMilliseconds < 0) { + throw new InvalidArgumentException(sprintf('Delay must be greater than or equal to zero: "%s" passed.', $delayMilliseconds)); + } + $this->delayMilliseconds = $delayMilliseconds; + + if ($multiplier < 1) { + throw new InvalidArgumentException(sprintf('Multiplier must be greater than zero: "%s" passed.', $multiplier)); + } + $this->multiplier = $multiplier; + + if ($maxDelayMilliseconds < 0) { + throw new InvalidArgumentException(sprintf('Max delay must be greater than or equal to zero: "%s" passed.', $maxDelayMilliseconds)); + } + $this->maxDelayMilliseconds = $maxDelayMilliseconds; + } + + public function isRetryable(Envelope $message): bool + { + if (0 === $this->maxRetries) { + return true; + } + + $retries = $this->getCurrentRetryCount($message); + + return $retries < $this->maxRetries; + } + + public function getWaitingTime(Envelope $message): int + { + $retries = $this->getCurrentRetryCount($message); + + $delay = $this->delayMilliseconds * pow($this->multiplier, $retries); + + if ($delay > $this->maxDelayMilliseconds && 0 !== $this->maxDelayMilliseconds) { + return $this->maxDelayMilliseconds; + } + + return $delay; + } + + private function getCurrentRetryCount(Envelope $message): int + { + /** @var RedeliveryStamp|null $retryMessageStamp */ + $retryMessageStamp = $message->last(RedeliveryStamp::class); + + return $retryMessageStamp ? $retryMessageStamp->getRetryCount() : 0; + } +} diff --git a/src/Symfony/Component/Messenger/Retry/RetryStrategyInterface.php b/src/Symfony/Component/Messenger/Retry/RetryStrategyInterface.php new file mode 100644 index 0000000000000..474651de02b5b --- /dev/null +++ b/src/Symfony/Component/Messenger/Retry/RetryStrategyInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Retry; + +use Symfony\Component\Messenger\Envelope; + +/** + * @author Fabien Potencier + * @author Grégoire Pineau + * @author Ryan Weaver + * + * @experimental in 4.3 + */ +interface RetryStrategyInterface +{ + public function isRetryable(Envelope $message): bool; + + /** + * @return int The time to delay/wait in milliseconds + */ + public function getWaitingTime(Envelope $message): int; +} diff --git a/src/Symfony/Component/Messenger/Stamp/DelayStamp.php b/src/Symfony/Component/Messenger/Stamp/DelayStamp.php new file mode 100644 index 0000000000000..0fc5597044e47 --- /dev/null +++ b/src/Symfony/Component/Messenger/Stamp/DelayStamp.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Apply this stamp to delay delivery of your message on a transport. + * + * @experimental in 4.3 + */ +class DelayStamp implements StampInterface +{ + private $delay; + + /** + * @param int $delay The delay in milliseconds + */ + public function __construct(int $delay) + { + $this->delay = $delay; + } + + public function getDelay(): int + { + return $this->delay; + } +} diff --git a/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php b/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php new file mode 100644 index 0000000000000..d5f1259972696 --- /dev/null +++ b/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Stamp applied when a messages needs to be redelivered. + * + * @experimental in 4.3 + */ +class RedeliveryStamp implements StampInterface +{ + private $retryCount; + private $senderClassOrAlias; + + /** + * @param string $senderClassOrAlias Alias from SendersLocator or just the class name + */ + public function __construct(int $retryCount, string $senderClassOrAlias) + { + $this->retryCount = $retryCount; + $this->senderClassOrAlias = $senderClassOrAlias; + } + + public function getRetryCount(): int + { + return $this->retryCount; + } + + /** + * Needed for this class to serialize through Symfony's serializer. + * + * @internal + */ + public function getSenderClassOrAlias(): int + { + return $this->retryCount; + } + + public function shouldRedeliverToSender(string $senderClass, ?string $senderAlias): bool + { + if (null !== $senderAlias && $senderAlias === $this->senderClassOrAlias) { + return true; + } + + if ($senderClass === $this->senderClassOrAlias) { + return true; + } + + return false; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 6c97608c9f4fc..24820df0c61c6 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -251,6 +251,7 @@ public function testItRegistersMultipleReceiversAndSetsTheReceiverNamesOnTheComm $container->register('console.command.messenger_consume_messages', ConsumeMessagesCommand::class)->setArguments([ null, new Reference('messenger.receiver_locator'), + new Reference('messenger.retry_strategy_locator'), null, null, null, @@ -605,6 +606,14 @@ public function receive(callable $handler): void public function stop(): void { } + + public function ack(Envelope $envelope): void + { + } + + public function reject(Envelope $envelope): void + { + } } class InvalidReceiver diff --git a/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php b/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php index 67609d8cd9a76..04b99d9141a0c 100644 --- a/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php +++ b/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\DelayStamp; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\ValidationStamp; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; @@ -34,11 +35,21 @@ public function testConstruct() public function testWithReturnsNewInstance() { - $envelope = new Envelope($dummy = new DummyMessage('dummy')); + $envelope = new Envelope(new DummyMessage('dummy')); $this->assertNotSame($envelope, $envelope->with(new ReceivedStamp())); } + public function testWithoutAll() + { + $envelope = new Envelope(new DummyMessage('dummy'), new ReceivedStamp(), new ReceivedStamp(), new DelayStamp(5000)); + + $envelope = $envelope->withoutAll(ReceivedStamp::class); + + $this->assertEmpty($envelope->all(ReceivedStamp::class)); + $this->assertCount(1, $envelope->all(DelayStamp::class)); + } + public function testLast() { $receivedStamp = new ReceivedStamp(); diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php b/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php index 1470de5914991..b1d26934d252c 100644 --- a/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php @@ -2,11 +2,14 @@ namespace Symfony\Component\Messenger\Tests\Fixtures; +use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; class CallbackReceiver implements ReceiverInterface { private $callable; + private $acknowledgeCount = 0; + private $rejectCount = 0; public function __construct(callable $callable) { @@ -22,4 +25,24 @@ public function receive(callable $handler): void public function stop(): void { } + + public function ack(Envelope $envelope): void + { + ++$this->acknowledgeCount; + } + + public function reject(Envelope $envelope): void + { + ++$this->rejectCount; + } + + public function getAcknowledgeCount(): int + { + return $this->acknowledgeCount; + } + + public function getRejectCount(): int + { + return $this->rejectCount; + } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index e74b18245ef20..be43799bf8556 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase; use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage; @@ -32,7 +33,7 @@ public function testItSendsTheMessageToAssignedSender() $middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender]])); - $sender->expects($this->once())->method('send')->with($envelope)->willReturn($envelope); + $sender->expects($this->once())->method('send')->with($envelope->with(new SentStamp(\get_class($sender))))->will($this->returnArgument(0)); $envelope = $middleware->handle($envelope, $this->getStackMock(false)); @@ -42,6 +43,69 @@ public function testItSendsTheMessageToAssignedSender() $this->assertStringMatchesFormat('Mock_SenderInterface_%s', $stamp->getSenderClass()); } + public function testItSendsTheMessageToMultipleSenders() + { + $envelope = new Envelope(new DummyMessage('Hey')); + $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); + $sender2 = $this->getMockBuilder(SenderInterface::class)->getMock(); + + $middleware = new SendMessageMiddleware(new SendersLocator([ + DummyMessage::class => ['foo' => $sender, 'bar' => $sender2], + ])); + + $sender->expects($this->once()) + ->method('send') + ->with($this->callback(function (Envelope $envelope) { + /** @var SentStamp|null $lastSentStamp */ + $lastSentStamp = $envelope->last(SentStamp::class); + + // last SentStamp should be the "foo" alias + return null !== $lastSentStamp && 'foo' === $lastSentStamp->getSenderAlias(); + })) + ->will($this->returnArgument(0)); + $sender2->expects($this->once()) + ->method('send') + ->with($this->callback(function (Envelope $envelope) { + /** @var SentStamp|null $lastSentStamp */ + $lastSentStamp = $envelope->last(SentStamp::class); + + // last SentStamp should be the "bar" alias + return null !== $lastSentStamp && 'bar' === $lastSentStamp->getSenderAlias(); + })) + ->will($this->returnArgument(0)); + + $envelope = $middleware->handle($envelope, $this->getStackMock(false)); + + /** @var SentStamp[] $sentStamps */ + $sentStamps = $envelope->all(SentStamp::class); + $this->assertCount(2, $sentStamps); + } + + public function testItSendsToOnlyOneSenderOnRedelivery() + { + $envelope = new Envelope(new DummyMessage('Hey'), new RedeliveryStamp(5, 'bar')); + $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); + $sender2 = $this->getMockBuilder(SenderInterface::class)->getMock(); + + $middleware = new SendMessageMiddleware(new SendersLocator([ + DummyMessage::class => ['foo' => $sender, 'bar' => $sender2], + ], [ + // normally, this class sends and handles (but not on retry) + DummyMessage::class => true, + ])); + + $sender->expects($this->never()) + ->method('send') + ; + $sender2->expects($this->once()) + ->method('send') + ->will($this->returnArgument(0)); + + $mockStack = $this->getStackMock(false); // false because next should not be called + $envelope = $middleware->handle($envelope, $mockStack); + $this->assertCount(1, $envelope->all(SentStamp::class)); + } + public function testItSendsTheMessageToAssignedSenderWithPreWrappedMessage() { $envelope = new Envelope(new ChildDummyMessage('Hey')); @@ -49,7 +113,7 @@ public function testItSendsTheMessageToAssignedSenderWithPreWrappedMessage() $middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender]])); - $sender->expects($this->once())->method('send')->with($envelope)->willReturn($envelope); + $sender->expects($this->once())->method('send')->with($envelope->with(new SentStamp(\get_class($sender))))->willReturn($envelope); $middleware->handle($envelope, $this->getStackMock(false)); } @@ -64,7 +128,7 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageClass() DummyMessage::class => true, ])); - $sender->expects($this->once())->method('send')->with($envelope)->willReturn($envelope); + $sender->expects($this->once())->method('send')->with($envelope->with(new SentStamp(\get_class($sender))))->willReturn($envelope); $middleware->handle($envelope, $this->getStackMock()); } @@ -79,7 +143,7 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageParentClass() DummyMessage::class => true, ])); - $sender->expects($this->once())->method('send')->with($envelope)->willReturn($envelope); + $sender->expects($this->once())->method('send')->with($envelope->with(new SentStamp(\get_class($sender))))->willReturn($envelope); $middleware->handle($envelope, $this->getStackMock()); } @@ -94,7 +158,7 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnTheMessageInterface() DummyMessageInterface::class => true, ])); - $sender->expects($this->once())->method('send')->with($envelope)->willReturn($envelope); + $sender->expects($this->once())->method('send')->with($envelope->with(new SentStamp(\get_class($sender))))->willReturn($envelope); $middleware->handle($envelope, $this->getStackMock()); } @@ -109,7 +173,7 @@ public function testItAlsoCallsTheNextMiddlewareBasedOnWildcard() '*' => true, ])); - $sender->expects($this->once())->method('send')->with($envelope)->willReturn($envelope); + $sender->expects($this->once())->method('send')->with($envelope->with(new SentStamp(\get_class($sender))))->willReturn($envelope); $middleware->handle($envelope, $this->getStackMock()); } diff --git a/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php b/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php new file mode 100644 index 0000000000000..6ff4d9af276d9 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Retry; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Retry\MultiplierRetryStrategy; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; + +class MultiplierRetryStrategyTest extends TestCase +{ + public function testIsRetryable() + { + $strategy = new MultiplierRetryStrategy(3); + $envelope = new Envelope(new \stdClass(), new RedeliveryStamp(0, 'sender_alias')); + + $this->assertTrue($strategy->isRetryable($envelope)); + } + + public function testIsNotRetryable() + { + $strategy = new MultiplierRetryStrategy(3); + $envelope = new Envelope(new \stdClass(), new RedeliveryStamp(3, 'sender_alias')); + + $this->assertFalse($strategy->isRetryable($envelope)); + } + + public function testIsRetryableWithNoStamp() + { + $strategy = new MultiplierRetryStrategy(3); + $envelope = new Envelope(new \stdClass()); + + $this->assertTrue($strategy->isRetryable($envelope)); + } + + /** + * @dataProvider getWaitTimeTests + */ + public function testGetWaitTime(int $delay, int $multiplier, int $maxDelay, int $previousRetries, int $expectedDelay) + { + $strategy = new MultiplierRetryStrategy(10, $delay, $multiplier, $maxDelay); + $envelope = new Envelope(new \stdClass(), new RedeliveryStamp($previousRetries, 'sender_alias')); + + $this->assertSame($expectedDelay, $strategy->getWaitingTime($envelope)); + } + + public function getWaitTimeTests() + { + // delay, multiplier, maxDelay, retries, expectedDelay + yield [1000, 1, 5000, 0, 1000]; + yield [1000, 1, 5000, 1, 1000]; + yield [1000, 1, 5000, 2, 1000]; + + yield [1000, 2, 10000, 0, 1000]; + yield [1000, 2, 10000, 1, 2000]; + yield [1000, 2, 10000, 2, 4000]; + yield [1000, 2, 10000, 3, 8000]; + yield [1000, 2, 10000, 4, 10000]; // max hit + yield [1000, 2, 0, 4, 16000]; // no max + + yield [1000, 3, 10000, 0, 1000]; + yield [1000, 3, 10000, 1, 3000]; + yield [1000, 3, 10000, 2, 9000]; + + yield [1000, 1, 500, 0, 500]; // max hit immediately + + // never a delay + yield [0, 2, 10000, 0, 0]; + yield [0, 2, 10000, 1, 0]; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php b/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php new file mode 100644 index 0000000000000..b6eb477a7182d --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Stamp; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; + +class RedeliveryStampTest extends TestCase +{ + public function testShouldRedeliverToSenderWithAlias() + { + $stamp = new RedeliveryStamp(5, 'foo_alias'); + + $this->assertFalse($stamp->shouldRedeliverToSender('Foo\Bar\Sender', 'bar_alias')); + $this->assertTrue($stamp->shouldRedeliverToSender('Foo\Bar\Sender', 'foo_alias')); + } + + public function testShouldRedeliverToSenderWithoutAlias() + { + $stampToRedeliverToSender1 = new RedeliveryStamp(5, 'App\Sender1'); + + $this->assertTrue($stampToRedeliverToSender1->shouldRedeliverToSender('App\Sender1', null)); + $this->assertFalse($stampToRedeliverToSender1->shouldRedeliverToSender('App\Sender2', null)); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php index e77253bb7eb2d..2949ae837fe36 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php @@ -13,15 +13,20 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpSender; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\Serializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Process\PhpProcess; use Symfony\Component\Process\Process; use Symfony\Component\Serializer as SerializerComponent; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; /** @@ -40,9 +45,7 @@ protected function setUp() public function testItSendsAndReceivesMessages() { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); + $serializer = $this->createSerializer(); $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); $connection->setup(); @@ -56,7 +59,9 @@ public function testItSendsAndReceivesMessages() $receivedMessages = 0; $receiver->receive(function (?Envelope $envelope) use ($receiver, &$receivedMessages, $first, $second) { - $this->assertEquals(0 === $receivedMessages ? $first : $second, $envelope); + $expectedEnvelope = 0 === $receivedMessages ? $first : $second; + $this->assertEquals($expectedEnvelope->getMessage(), $envelope->getMessage()); + $this->assertInstanceOf(AmqpReceivedStamp::class, $envelope->last(AmqpReceivedStamp::class)); if (2 === ++$receivedMessages) { $receiver->stop(); @@ -64,11 +69,68 @@ public function testItSendsAndReceivesMessages() }); } + public function testRetryAndDelay() + { + $serializer = $this->createSerializer(); + + $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); + $connection->setup(); + $connection->queue()->purge(); + + $sender = new AmqpSender($connection, $serializer); + $receiver = new AmqpReceiver($connection, $serializer); + + $sender->send($first = new Envelope(new DummyMessage('First'))); + + $receivedMessages = 0; + $startTime = time(); + $receiver->receive(function (?Envelope $envelope) use ($receiver, $sender, &$receivedMessages, $startTime) { + if (null === $envelope) { + // if we have been processing for 4 seconds + have received 2 messages + // then it's safe to say no other messages will be received + if (time() > $startTime + 4 && 2 === $receivedMessages) { + $receiver->stop(); + } + + return; + } + + ++$receivedMessages; + + // retry the first time + if (1 === $receivedMessages) { + // imitate what Worker does + $envelope = $envelope + ->with(new DelayStamp(2000)) + ->with(new RedeliveryStamp(1, 'not_important')); + $sender->send($envelope); + $receiver->ack($envelope); + + return; + } + + if (2 === $receivedMessages) { + // should have a 2 second delay + $this->assertGreaterThanOrEqual($startTime + 2, time()); + // but only a 2 second delay + $this->assertLessThan($startTime + 4, time()); + + /** @var RedeliveryStamp|null $retryStamp */ + // verify the stamp still exists from the last send + $retryStamp = $envelope->last(RedeliveryStamp::class); + $this->assertNotNull($retryStamp); + $this->assertSame(1, $retryStamp->getRetryCount()); + + $receiver->ack($envelope); + + return; + } + }); + } + public function testItReceivesSignals() { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); + $serializer = $this->createSerializer(); $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); $connection->setup(); @@ -91,17 +153,20 @@ public function testItReceivesSignals() $signalTime = microtime(true); $timedOutTime = time() + 10; + // immediately after the process has started "booted", kill it $process->signal(15); while ($process->isRunning() && time() < $timedOutTime) { usleep(100 * 1000); // 100ms } + // make sure the process exited, after consuming only the 1 message $this->assertFalse($process->isRunning()); $this->assertLessThan($amqpReadTimeout, microtime(true) - $signalTime); $this->assertSame($expectedOutput.<<<'TXT' Get envelope with message: Symfony\Component\Messenger\Tests\Fixtures\DummyMessage with stamps: [ + "Symfony\\Component\\Messenger\\Transport\\AmqpExt\\AmqpReceivedStamp", "Symfony\\Component\\Messenger\\Stamp\\ReceivedStamp" ] Done. @@ -115,9 +180,7 @@ public function testItReceivesSignals() */ public function testItSupportsTimeoutAndTicksNullMessagesToTheHandler() { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); + $serializer = $this->createSerializer(); $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN'), ['read_timeout' => '1']); $connection->setup(); @@ -149,4 +212,11 @@ private function waitForOutput(Process $process, string $output, $timeoutInSecon throw new \RuntimeException('Expected output never arrived. Got "'.$process->getOutput().'" instead.'); } + + private function createSerializer(): SerializerInterface + { + return new Serializer( + new SerializerComponent\Serializer([new ObjectNormalizer(), new ArrayDenormalizer()], ['json' => new JsonEncoder()]) + ); + } } diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php index 8e224e0653df7..d0c8abfa3564e 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php @@ -16,7 +16,6 @@ use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; -use Symfony\Component\Messenger\Transport\AmqpExt\Exception\RejectMessageExceptionInterface; use Symfony\Component\Messenger\Transport\Serialization\Serializer; use Symfony\Component\Serializer as SerializerComponent; use Symfony\Component\Serializer\Encoder\JsonEncoder; @@ -27,22 +26,15 @@ */ class AmqpReceiverTest extends TestCase { - public function testItSendTheDecodedMessageToTheHandlerAndAcknowledgeIt() + public function testItSendTheDecodedMessageToTheHandler() { $serializer = new Serializer( new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) ); - $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); - $envelope->method('getBody')->willReturn('{"message": "Hi"}'); - $envelope->method('getHeaders')->willReturn([ - 'type' => DummyMessage::class, - ]); - + $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($envelope); - - $connection->expects($this->once())->method('ack')->with($envelope); + $connection->method('get')->willReturn($amqpEnvelope); $receiver = new AmqpReceiver($connection, $serializer); $receiver->receive(function (?Envelope $envelope) use ($receiver) { @@ -51,57 +43,6 @@ public function testItSendTheDecodedMessageToTheHandlerAndAcknowledgeIt() }); } - /** - * @expectedException \Symfony\Component\Messenger\Tests\Transport\AmqpExt\InterruptException - */ - public function testItNonAcknowledgeTheMessageIfAnExceptionHappened() - { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); - - $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); - $envelope->method('getBody')->willReturn('{"message": "Hi"}'); - $envelope->method('getHeaders')->willReturn([ - 'type' => DummyMessage::class, - ]); - - $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($envelope); - - $connection->expects($this->once())->method('nack')->with($envelope); - - $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function () { - throw new InterruptException('Well...'); - }); - } - - /** - * @expectedException \Symfony\Component\Messenger\Tests\Transport\AmqpExt\WillNeverWorkException - */ - public function testItRejectsTheMessageIfTheExceptionIsARejectMessageExceptionInterface() - { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); - - $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); - $envelope->method('getBody')->willReturn('{"message": "Hi"}'); - $envelope->method('getHeaders')->willReturn([ - 'type' => DummyMessage::class, - ]); - - $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($envelope); - $connection->expects($this->once())->method('reject')->with($envelope); - - $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function () { - throw new WillNeverWorkException('Well...'); - }); - } - /** * @expectedException \Symfony\Component\Messenger\Exception\TransportException */ @@ -111,19 +52,14 @@ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) ); - $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); - $envelope->method('getBody')->willReturn('{"message": "Hi"}'); - $envelope->method('getHeaders')->willReturn([ - 'type' => DummyMessage::class, - ]); - + $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($envelope); - - $connection->method('ack')->with($envelope)->willThrowException(new \AMQPException()); + $connection->method('get')->willReturn($amqpEnvelope); + $connection->method('ack')->with($amqpEnvelope)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); $receiver->receive(function (?Envelope $envelope) use ($receiver) { + $receiver->ack($envelope); $receiver->stop(); }); } @@ -137,53 +73,26 @@ public function testItThrowsATransportExceptionIfItCannotRejectMessage() new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) ); - $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); - $envelope->method('getBody')->willReturn('{"message": "Hi"}'); - $envelope->method('getHeaders')->willReturn([ - 'type' => DummyMessage::class, - ]); - + $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($envelope); - $connection->method('reject')->with($envelope)->willThrowException(new \AMQPException()); + $connection->method('get')->willReturn($amqpEnvelope); + $connection->method('nack')->with($amqpEnvelope, AMQP_NOPARAM)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function () { - throw new WillNeverWorkException('Well...'); + $receiver->receive(function (?Envelope $envelope) use ($receiver) { + $receiver->reject($envelope); + $receiver->stop(); }); } - /** - * @expectedException \Symfony\Component\Messenger\Exception\TransportException - */ - public function testItThrowsATransportExceptionIfItCannotNonAcknowledgeMessage() + private function createAMQPEnvelope() { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); - $envelope = $this->getMockBuilder(\AMQPEnvelope::class)->getMock(); $envelope->method('getBody')->willReturn('{"message": "Hi"}'); $envelope->method('getHeaders')->willReturn([ 'type' => DummyMessage::class, ]); - $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($envelope); - - $connection->method('nack')->with($envelope)->willThrowException(new \AMQPException()); - - $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function () { - throw new InterruptException('Well...'); - }); + return $envelope; } } - -class InterruptException extends \Exception -{ -} - -class WillNeverWorkException extends \Exception implements RejectMessageExceptionInterface -{ -} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index 3cea581a8cabd..73ae25de3c7f7 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -255,6 +255,86 @@ public function testPublishWithQueueOptions() $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[attributes][delivery_mode]=2&queue[attributes][headers][token]=uuid&queue[flags]=1', [], $factory); $connection->publish('body', $headers); } + + public function testItDelaysTheMessage() + { + $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(); + $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(); + $delayQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(); + + $factory = $this->getMockBuilder(AmqpFactory::class)->getMock(); + $factory->method('createConnection')->willReturn($amqpConnection); + $factory->method('createChannel')->willReturn($amqpChannel); + $factory->method('createQueue')->willReturn($delayQueue); + $factory->method('createExchange')->will($this->onConsecutiveCalls( + $delayExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock(), + $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + )); + + $amqpExchange->expects($this->once())->method('setName')->with('messages'); + $amqpExchange->method('getName')->willReturn('messages'); + + $delayExchange->expects($this->once())->method('setName')->with('delay'); + $delayExchange->expects($this->once())->method('declareExchange'); + $delayExchange->method('getName')->willReturn('delay'); + + $delayQueue->expects($this->once())->method('setName')->with('delay_queue_5000'); + $delayQueue->expects($this->once())->method('setArguments')->with([ + 'x-message-ttl' => 5000, + 'x-dead-letter-exchange' => 'messages', + ]); + + $delayQueue->expects($this->once())->method('declareQueue'); + $delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_5000'); + + $delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_5000', AMQP_NOPARAM, ['headers' => ['x-some-headers' => 'foo']]); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', [], $factory); + $connection->publish('{}', ['x-some-headers' => 'foo'], 5000); + } + + public function testItDelaysTheMessageWithADifferentRoutingKeyAndTTLs() + { + $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(); + $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(); + $delayQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(); + + $factory = $this->getMockBuilder(AmqpFactory::class)->getMock(); + $factory->method('createConnection')->willReturn($amqpConnection); + $factory->method('createChannel')->willReturn($amqpChannel); + $factory->method('createQueue')->willReturn($delayQueue); + $factory->method('createExchange')->will($this->onConsecutiveCalls( + $delayExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock(), + $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + )); + + $amqpExchange->expects($this->once())->method('setName')->with('messages'); + $amqpExchange->method('getName')->willReturn('messages'); + + $delayExchange->expects($this->once())->method('setName')->with('delay'); + $delayExchange->expects($this->once())->method('declareExchange'); + $delayExchange->method('getName')->willReturn('delay'); + + $connectionOptions = [ + 'retry' => [ + 'dead_routing_key' => 'my_dead_routing_key', + ], + ]; + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', $connectionOptions, $factory); + + $delayQueue->expects($this->once())->method('setName')->with('delay_queue_120000'); + $delayQueue->expects($this->once())->method('setArguments')->with([ + 'x-message-ttl' => 120000, + 'x-dead-letter-exchange' => 'messages', + ]); + + $delayQueue->expects($this->once())->method('declareQueue'); + $delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_120000'); + + $delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_120000', AMQP_NOPARAM, ['headers' => []]); + $connection->publish('{}', [], 120000); + } } class TestAmqpFactory extends AmqpFactory diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php index a7d4d8dcd758c..ba7236103579b 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php @@ -14,20 +14,23 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Retry\MultiplierRetryStrategy; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\Serializer; use Symfony\Component\Messenger\Worker; use Symfony\Component\Serializer as SerializerComponent; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) + new SerializerComponent\Serializer([new ObjectNormalizer(), new ArrayDenormalizer()], ['json' => new JsonEncoder()]) ); $connection = Connection::fromDsn(getenv('DSN')); $receiver = new AmqpReceiver($connection, $serializer); +$retryStrategy = new MultiplierRetryStrategy(3, 0); $worker = new Worker($receiver, new class() implements MessageBusInterface { public function dispatch($envelope): Envelope @@ -40,7 +43,7 @@ public function dispatch($envelope): Envelope return $envelope; } -}); +}, 'the_receiver', $retryStrategy); echo "Receiving messages...\n"; $worker->run(); diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php index d3f1da25e456c..f9cd817f05cf8 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; @@ -26,4 +27,28 @@ public function testEncodedIsDecodable() $this->assertEquals($envelope, $serializer->decode($serializer->encode($envelope))); } + + public function testDecodingFailsWithBadFormat() + { + $this->expectException(MessageDecodingFailedException::class); + $this->expectExceptionMessageRegExp('/Could not decode/'); + + $serializer = new PhpSerializer(); + + $serializer->decode([ + 'body' => '{"message": "bar"}', + ]); + } + + public function testDecodingFailsWithBadClass() + { + $this->expectException(MessageDecodingFailedException::class); + $this->expectExceptionMessageRegExp('/class "ReceivedSt0mp" not found/'); + + $serializer = new PhpSerializer(); + + $serializer->decode([ + 'body' => 'O:13:"ReceivedSt0mp":0:{}', + ]); + } } diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php index d68103f7ca682..c46b3df15a964 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Stamp\SerializerStamp; use Symfony\Component\Messenger\Stamp\ValidationStamp; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; @@ -94,4 +95,28 @@ public function testEncodedWithSymfonySerializerForStamps() $this->assertEquals($serializerStamp, $decoded->last(SerializerStamp::class)); $this->assertEquals($validationStamp, $decoded->last(ValidationStamp::class)); } + + public function testDecodingFailsWithBadFormat() + { + $this->expectException(MessageDecodingFailedException::class); + + $serializer = new Serializer(); + + $serializer->decode([ + 'body' => '{foo', + 'headers' => ['type' => 'stdClass'], + ]); + } + + public function testDecodingFailsWithBadClass() + { + $this->expectException(MessageDecodingFailedException::class); + + $serializer = new Serializer(); + + $serializer->decode([ + 'body' => '{}', + 'headers' => ['type' => 'NonExistentClass'], + ]); + } } diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php index 0f6e208277d38..cd833b223dce2 100644 --- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php +++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php @@ -12,9 +12,17 @@ namespace Symfony\Component\Messenger\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; +use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; +use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Retry\RetryStrategyInterface; use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Tests\Fixtures\CallbackReceiver; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Worker; @@ -33,11 +41,13 @@ public function testWorkerDispatchTheReceivedMessage() $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); - $bus->expects($this->at(0))->method('dispatch')->with(($envelope = new Envelope($apiMessage))->with(new ReceivedStamp()))->willReturn($envelope); - $bus->expects($this->at(1))->method('dispatch')->with(($envelope = new Envelope($ipaMessage))->with(new ReceivedStamp()))->willReturn($envelope); + $bus->expects($this->at(0))->method('dispatch')->with($envelope = new Envelope($apiMessage, new ReceivedStamp()))->willReturn($envelope); + $bus->expects($this->at(1))->method('dispatch')->with($envelope = new Envelope($ipaMessage, new ReceivedStamp()))->willReturn($envelope); - $worker = new Worker($receiver, $bus); + $worker = new Worker($receiver, $bus, 'receiver_id'); $worker->run(); + + $this->assertSame(2, $receiver->getAcknowledgeCount()); } public function testWorkerDoesNotWrapMessagesAlreadyWrappedWithReceivedMessage() @@ -50,29 +60,79 @@ public function testWorkerDoesNotWrapMessagesAlreadyWrappedWithReceivedMessage() $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->expects($this->at(0))->method('dispatch')->with($envelope)->willReturn($envelope); + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); - $worker = new Worker($receiver, $bus); + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); $worker->run(); } - public function testWorkerIsThrowingExceptionsBackToGenerators() + public function testDispatchCausesRetry() { $receiver = new CallbackReceiver(function ($handler) { - try { - $handler(new Envelope(new DummyMessage('Hello'))); - - $this->assertTrue(false, 'This should not be called because the exception is sent back to the generator.'); - } catch (\InvalidArgumentException $e) { - // This should be called because of the exception sent back to the generator. - $this->assertTrue(true); - } + $handler(new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))); + }); + + $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); + $bus->expects($this->at(0))->method('dispatch')->willThrowException(new \InvalidArgumentException('Why not')); + + // 2nd call will be the retry + $bus->expects($this->at(1))->method('dispatch')->with($this->callback(function (Envelope $envelope) { + /** @var RedeliveryStamp|null $redeliveryStamp */ + $redeliveryStamp = $envelope->last(RedeliveryStamp::class); + $this->assertNotNull($redeliveryStamp); + // retry count now at 1 + $this->assertSame(1, $redeliveryStamp->getRetryCount()); + $this->assertTrue($redeliveryStamp->shouldRedeliverToSender('Some\Sender', 'sender_alias')); + + // received stamp is removed + $this->assertNull($envelope->last(ReceivedStamp::class)); + + return true; + }))->willReturnArgument(0); + + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); + $retryStrategy->expects($this->once())->method('isRetryable')->willReturn(true); + + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); + $worker->run(); + + // old message acknowledged + $this->assertSame(1, $receiver->getAcknowledgeCount()); + } + + public function testDispatchCausesRejectWhenNoRetry() + { + $receiver = new CallbackReceiver(function ($handler) { + $handler(new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))); }); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->method('dispatch')->willThrowException(new \InvalidArgumentException('Why not')); - $worker = new Worker($receiver, $bus); + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); + $retryStrategy->expects($this->once())->method('isRetryable')->willReturn(false); + + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); + $worker->run(); + $this->assertSame(1, $receiver->getRejectCount()); + $this->assertSame(0, $receiver->getAcknowledgeCount()); + } + + public function testDispatchCausesRejectOnUnrecoverableMessage() + { + $receiver = new CallbackReceiver(function ($handler) { + $handler(new Envelope(new DummyMessage('Hello'))); + }); + + $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); + $bus->method('dispatch')->willThrowException(new UnrecoverableMessageHandlingException('Will never work')); + + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); + $retryStrategy->expects($this->never())->method('isRetryable'); + + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); $worker->run(); + $this->assertSame(1, $receiver->getRejectCount()); } public function testWorkerDoesNotSendNullMessagesToTheBus() @@ -83,8 +143,58 @@ public function testWorkerDoesNotSendNullMessagesToTheBus() $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->expects($this->never())->method('dispatch'); + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); + + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); + $worker->run(); + } + + public function testWorkerDispatchesEventsOnSuccess() + { + $envelope = new Envelope(new DummyMessage('Hello')); + $receiver = new CallbackReceiver(function ($handler) use ($envelope) { + $handler($envelope); + }); + + $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); + $bus->method('dispatch')->willReturn($envelope); + + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); + $eventDispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); + + $eventDispatcher->expects($this->exactly(2)) + ->method('dispatch') + ->withConsecutive( + [$this->isInstanceOf(WorkerMessageReceivedEvent::class)], + [$this->isInstanceOf(WorkerMessageHandledEvent::class)] + ); + + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy, $eventDispatcher); + $worker->run(); + } + + public function testWorkerDispatchesEventsOnError() + { + $envelope = new Envelope(new DummyMessage('Hello')); + $receiver = new CallbackReceiver(function ($handler) use ($envelope) { + $handler($envelope); + }); + + $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); + $exception = new \InvalidArgumentException('Oh no!'); + $bus->method('dispatch')->willThrowException($exception); + + $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); + $eventDispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); + + $eventDispatcher->expects($this->exactly(2)) + ->method('dispatch') + ->withConsecutive( + [$this->isInstanceOf(WorkerMessageReceivedEvent::class)], + [$this->isInstanceOf(WorkerMessageFailedEvent::class)] + ); - $worker = new Worker($receiver, $bus); + $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy, $eventDispatcher); $worker->run(); } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php new file mode 100644 index 0000000000000..9ed3dc30a3664 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Stamp\StampInterface; + +/** + * Stamp applied when a message is received from Amqp. + * + * @experimental in 4.3 + */ +class AmqpReceivedStamp implements StampInterface +{ + private $amqpEnvelope; + + public function __construct(\AMQPEnvelope $amqpEnvelope) + { + $this->amqpEnvelope = $amqpEnvelope; + } + + public function getAmqpEnvelope(): \AMQPEnvelope + { + return $this->amqpEnvelope; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index cb7a4db013fa9..93afbaff5d8b8 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -11,8 +11,10 @@ namespace Symfony\Component\Messenger\Transport\AmqpExt; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Exception\TransportException; -use Symfony\Component\Messenger\Transport\AmqpExt\Exception\RejectMessageExceptionInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -42,53 +44,74 @@ public function __construct(Connection $connection, SerializerInterface $seriali public function receive(callable $handler): void { while (!$this->shouldStop) { - $AMQPEnvelope = $this->connection->get(); - if (null === $AMQPEnvelope) { + try { + $amqpEnvelope = $this->connection->get(); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + if (null === $amqpEnvelope) { $handler(null); - usleep($this->connection->getConnectionCredentials()['loop_sleep'] ?? 200000); - if (\function_exists('pcntl_signal_dispatch')) { - pcntl_signal_dispatch(); - } + usleep($this->connection->getConnectionConfiguration()['loop_sleep'] ?? 200000); continue; } try { - $handler($this->serializer->decode([ - 'body' => $AMQPEnvelope->getBody(), - 'headers' => $AMQPEnvelope->getHeaders(), - ])); - - $this->connection->ack($AMQPEnvelope); - } catch (RejectMessageExceptionInterface $e) { - try { - $this->connection->reject($AMQPEnvelope); - } catch (\AMQPException $exception) { - throw new TransportException($exception->getMessage(), 0, $exception); - } - - throw $e; - } catch (\AMQPException $e) { - throw new TransportException($e->getMessage(), 0, $e); - } catch (\Throwable $e) { - try { - $this->connection->nack($AMQPEnvelope, AMQP_REQUEUE); - } catch (\AMQPException $exception) { - throw new TransportException($exception->getMessage(), 0, $exception); - } - - throw $e; - } finally { - if (\function_exists('pcntl_signal_dispatch')) { - pcntl_signal_dispatch(); - } + $envelope = $this->serializer->decode([ + 'body' => $amqpEnvelope->getBody(), + 'headers' => $amqpEnvelope->getHeaders(), + ]); + } catch (MessageDecodingFailedException $exception) { + // invalid message of some type + $this->rejectAmqpEnvelope($amqpEnvelope); + + throw $exception; } + + $envelope = $envelope->with(new AmqpReceivedStamp($amqpEnvelope)); + $handler($envelope); } } + public function ack(Envelope $envelope): void + { + try { + $this->connection->ack($this->findAmqpEnvelope($envelope)); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + public function reject(Envelope $envelope): void + { + $this->rejectAmqpEnvelope($this->findAmqpEnvelope($envelope)); + } + public function stop(): void { $this->shouldStop = true; } + + private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope): void + { + try { + $this->connection->nack($amqpEnvelope, AMQP_NOPARAM); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + private function findAmqpEnvelope(Envelope $envelope): \AMQPEnvelope + { + /** @var AmqpReceivedStamp|null $amqpReceivedStamp */ + $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); + + if (null === $amqpReceivedStamp) { + throw new LogicException('No AmqpReceivedStamp found on the Envelope.'); + } + + return $amqpReceivedStamp->getAmqpEnvelope(); + } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php index daf8199a5df26..021a6bfaf8b51 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php @@ -13,6 +13,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Stamp\DelayStamp; use Symfony\Component\Messenger\Transport\Sender\SenderInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -42,8 +43,15 @@ public function send(Envelope $envelope): Envelope { $encodedMessage = $this->serializer->encode($envelope); + /** @var DelayStamp|null $delayStamp */ + $delayStamp = $envelope->last(DelayStamp::class); + $delay = 0; + if (null !== $delayStamp) { + $delay = $delayStamp->getDelay(); + } + try { - $this->connection->publish($encodedMessage['body'], $encodedMessage['headers'] ?? []); + $this->connection->publish($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay); } catch (\AMQPException $e) { throw new TransportException($e->getMessage(), 0, $e); } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php index 36967c8459dca..a98c90596634c 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php @@ -50,6 +50,22 @@ public function stop(): void ($this->receiver ?? $this->getReceiver())->stop(); } + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->ack($envelope); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->reject($envelope); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index f1875a8b49101..5d7a3e18e5703 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -33,7 +33,7 @@ class Connection 'x-message-ttl', ]; - private $connectionCredentials; + private $connectionConfiguration; private $exchangeConfiguration; private $queueConfiguration; private $amqpFactory; @@ -53,9 +53,47 @@ class Connection */ private $amqpQueue; - public function __construct(array $connectionCredentials, array $exchangeConfiguration, array $queueConfiguration, AmqpFactory $amqpFactory = null) + /** + * @var \AMQPExchange|null + */ + private $amqpDelayExchange; + + /** + * Constructor. + * + * Available options: + * + * * host: Hostname of the AMQP service + * * port: Port of the AMQP service + * * vhost: Virtual Host to use with the AMQP service + * * user: Username to use to connect the the AMQP service + * * password: Password to use the connect to the AMQP service + * * queue: + * * name: Name of the queue + * * routing_key: The routing key (if any) to use to push the messages to + * * flags: Queue flags (Default: AMQP_DURABLE) + * * arguments: Extra arguments + * * exchange: + * * name: Name of the exchange + * * type: Type of exchange (Default: fanout) + * * flags: Exchange flags (Default: AMQP_DURABLE) + * * arguments: Extra arguments + * * delay: + * * routing_key_pattern: The pattern of the routing key (Default: "delay_%delay%") + * * queue_name_pattern: Pattern to use to create the queues (Default: "delay_queue_%delay%") + * * exchange_name: Name of the exchange to be used for the retried messages (Default: "retry") + * * auto-setup: Enable or not the auto-setup of queues and exchanges (Default: true) + * * loop_sleep: Amount of micro-seconds to wait if no message are available (Default: 200000) + */ + public function __construct(array $connectionConfiguration, array $exchangeConfiguration, array $queueConfiguration, AmqpFactory $amqpFactory = null) { - $this->connectionCredentials = $connectionCredentials; + $this->connectionConfiguration = array_replace_recursive([ + 'delay' => [ + 'routing_key_pattern' => 'delay_%delay%', + 'exchange_name' => 'delay', + 'queue_name_pattern' => 'delay_queue_%delay%', + ], + ], $connectionConfiguration); $this->exchangeConfiguration = $exchangeConfiguration; $this->queueConfiguration = $queueConfiguration; $this->amqpFactory = $amqpFactory ?: new AmqpFactory(); @@ -123,20 +161,102 @@ private static function normalizeQueueArguments(array $arguments): array } /** + * @param int $delay The delay in milliseconds + * * @throws \AMQPException */ - public function publish(string $body, array $headers = []): void + public function publish(string $body, array $headers = [], int $delay = 0): void { + if (0 !== $delay) { + $this->publishWithDelay($body, $headers, $delay); + + return; + } + if ($this->shouldSetup()) { $this->setup(); } $flags = $this->queueConfiguration['flags'] ?? AMQP_NOPARAM; - $attributes = array_merge_recursive($this->queueConfiguration['attributes'] ?? [], ['headers' => $headers]); + $attributes = $this->getAttributes($headers); $this->exchange()->publish($body, $this->queueConfiguration['routing_key'] ?? null, $flags, $attributes); } + /** + * @throws \AMQPException + */ + private function publishWithDelay(string $body, array $headers = [], int $delay) + { + if ($this->shouldSetup()) { + $this->setupDelay($delay); + } + + $routingKey = $this->getRoutingKeyForDelay($delay); + $flags = $this->queueConfiguration['flags'] ?? AMQP_NOPARAM; + $attributes = $this->getAttributes($headers); + + $this->getDelayExchange()->publish($body, $routingKey, $flags, $attributes); + } + + private function setupDelay(int $delay) + { + if (!$this->channel()->isConnected()) { + $this->clear(); + } + + $exchange = $this->getDelayExchange(); + $exchange->declareExchange(); + + $queue = $this->createDelayQueue($delay); + $queue->declareQueue(); + $queue->bind($exchange->getName(), $this->getRoutingKeyForDelay($delay)); + } + + private function getDelayExchange(): \AMQPExchange + { + if (null === $this->amqpDelayExchange) { + $this->amqpDelayExchange = $this->amqpFactory->createExchange($this->channel()); + $this->amqpDelayExchange->setName($this->connectionConfiguration['delay']['exchange_name']); + $this->amqpDelayExchange->setType(AMQP_EX_TYPE_DIRECT); + } + + return $this->amqpDelayExchange; + } + + /** + * Creates a delay queue that will delay for a certain amount of time. + * + * This works by setting message TTL for the delay and pointing + * the dead letter exchange to the original exchange. The result + * is that after the TTL, the message is sent to the dead-letter-exchange, + * which is the original exchange, resulting on it being put back into + * the original queue. + */ + private function createDelayQueue(int $delay) + { + $delayConfiguration = $this->connectionConfiguration['delay']; + + $queue = $this->amqpFactory->createQueue($this->channel()); + $queue->setName(str_replace('%delay%', $delay, $delayConfiguration['queue_name_pattern'])); + $queue->setArguments([ + 'x-message-ttl' => $delay, + 'x-dead-letter-exchange' => $this->exchange()->getName(), + ]); + + if (isset($this->queueConfiguration['routing_key'])) { + // after being released from to DLX, this routing key will be used + $queue->setArgument('x-dead-letter-routing-key', $this->queueConfiguration['routing_key']); + } + + return $queue; + } + + private function getRoutingKeyForDelay(int $delay): string + { + return str_replace('%delay%', $delay, $this->connectionConfiguration['delay']['routing_key_pattern']); + } + /** * Waits and gets a message from the configured queue. * @@ -171,11 +291,6 @@ public function ack(\AMQPEnvelope $message): bool return $this->queue()->ack($message->getDeliveryTag()); } - public function reject(\AMQPEnvelope $message): bool - { - return $this->queue()->reject($message->getDeliveryTag()); - } - public function nack(\AMQPEnvelope $message, int $flags = AMQP_NOPARAM): bool { return $this->queue()->nack($message->getDeliveryTag(), $flags); @@ -196,8 +311,8 @@ public function setup(): void public function channel(): \AMQPChannel { if (null === $this->amqpChannel) { - $connection = $this->amqpFactory->createConnection($this->connectionCredentials); - $connectMethod = 'true' === ($this->connectionCredentials['persistent'] ?? 'false') ? 'pconnect' : 'connect'; + $connection = $this->amqpFactory->createConnection($this->connectionConfiguration); + $connectMethod = 'true' === ($this->connectionConfiguration['persistent'] ?? 'false') ? 'pconnect' : 'connect'; try { $connection->{$connectMethod}(); @@ -244,9 +359,9 @@ public function exchange(): \AMQPExchange return $this->amqpExchange; } - public function getConnectionCredentials(): array + public function getConnectionConfiguration(): array { - return $this->connectionCredentials; + return $this->connectionConfiguration; } private function clear(): void @@ -258,14 +373,19 @@ private function clear(): void private function shouldSetup(): bool { - if (!\array_key_exists('auto-setup', $this->connectionCredentials)) { + if (!\array_key_exists('auto-setup', $this->connectionConfiguration)) { return true; } - if (\in_array($this->connectionCredentials['auto-setup'], [false, 'false'], true)) { + if (\in_array($this->connectionConfiguration['auto-setup'], [false, 'false'], true)) { return false; } return true; } + + private function getAttributes(array $headers): array + { + return array_merge_recursive($this->queueConfiguration['attributes'] ?? [], ['headers' => $headers]); + } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Exception/RejectMessageExceptionInterface.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Exception/RejectMessageExceptionInterface.php deleted file mode 100644 index 9b820a7d8fbf8..0000000000000 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Exception/RejectMessageExceptionInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Transport\AmqpExt\Exception; - -/** - * If something goes wrong while consuming and handling a message from the AMQP broker, there are two choices: rejecting - * or re-queuing the message. - * - * If the exception that is thrown by the bus while dispatching the message implements this interface, the message will - * be rejected. Otherwise, it will be re-queued. - * - * @author Samuel Roze - * - * @experimental in 4.2 - */ -interface RejectMessageExceptionInterface extends \Throwable -{ -} diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php index 6843bb7c348ba..29da741a11f34 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php @@ -11,8 +11,12 @@ namespace Symfony\Component\Messenger\Transport\Receiver; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\TransportException; + /** * @author Samuel Roze + * @author Ryan Weaver * * @experimental in 4.2 */ @@ -23,6 +27,12 @@ interface ReceiverInterface * * The handler will have, as argument, the received {@link \Symfony\Component\Messenger\Envelope} containing the message. * Note that this envelope can be `null` if the timeout to receive something has expired. + * + * If the received message cannot be decoded, the message should not + * be retried again (e.g. if there's a queue, it should be removed) + * and a MessageDecodingFailedException should be thrown. + * + * @throws TransportException If there is an issue communicating with the transport */ public function receive(callable $handler): void; @@ -30,4 +40,18 @@ public function receive(callable $handler): void; * Stop receiving some messages. */ public function stop(): void; + + /** + * Acknowledge that the passed message was handled. + * + * @throws TransportException If there is an issue communicating with the transport + */ + public function ack(Envelope $envelope): void; + + /** + * Called when handling the message failed and it should not be retried. + * + * @throws TransportException If there is an issue communicating with the transport + */ + public function reject(Envelope $envelope): void; } diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php index 41e0df22bc501..09af4673b87b4 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php @@ -55,4 +55,14 @@ public function stop(): void { $this->decoratedReceiver->stop(); } + + public function ack(Envelope $envelope): void + { + $this->decoratedReceiver->ack($envelope); + } + + public function reject(Envelope $envelope): void + { + $this->decoratedReceiver->reject($envelope); + } } diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php index 8d36a15f8e602..8be38d157e8f1 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php @@ -52,4 +52,14 @@ public function stop(): void { $this->decoratedReceiver->stop(); } + + public function ack(Envelope $envelope): void + { + $this->decoratedReceiver->ack($envelope); + } + + public function reject(Envelope $envelope): void + { + $this->decoratedReceiver->reject($envelope); + } } diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php index b9bc24a16c870..ade088b7dabb1 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php @@ -53,4 +53,14 @@ public function stop(): void { $this->decoratedReceiver->stop(); } + + public function ack(Envelope $envelope): void + { + $this->decoratedReceiver->ack($envelope); + } + + public function reject(Envelope $envelope): void + { + $this->decoratedReceiver->reject($envelope); + } } diff --git a/src/Symfony/Component/Messenger/Transport/Sender/SenderInterface.php b/src/Symfony/Component/Messenger/Transport/Sender/SenderInterface.php index f6b5edb4257d5..f526a413e5ba2 100644 --- a/src/Symfony/Component/Messenger/Transport/Sender/SenderInterface.php +++ b/src/Symfony/Component/Messenger/Transport/Sender/SenderInterface.php @@ -22,6 +22,9 @@ interface SenderInterface { /** * Sends the given envelope. + * + * The sender can read different stamps for transport configuration, + * like delivery delay. */ public function send(Envelope $envelope): Envelope; } diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php index ec6176c85ddca..da232d947a5cb 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php @@ -13,6 +13,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; /** * @author Ryan Weaver @@ -30,7 +31,7 @@ public function decode(array $encodedEnvelope): Envelope throw new InvalidArgumentException('Encoded envelope should have at least a "body".'); } - return unserialize($encodedEnvelope['body']); + return $this->safelyUnserialize($encodedEnvelope['body']); } /** @@ -42,4 +43,35 @@ public function encode(Envelope $envelope): array 'body' => serialize($envelope), ]; } + + private function safelyUnserialize($contents) + { + $e = null; + $signalingException = new MessageDecodingFailedException(sprintf('Could not decode message using PHP serialization: %s.', $contents)); + $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); + $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { + if (__FILE__ === $file) { + throw $signalingException; + } + + return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false; + }); + + try { + $meta = unserialize($contents); + } finally { + restore_error_handler(); + ini_set('unserialize_callback_func', $prevUnserializeHandler); + } + + return $meta; + } + + /** + * @internal + */ + public static function handleUnserializeCallback($class) + { + throw new MessageDecodingFailedException(sprintf('Message class "%s" not found during decoding.', $class)); + } } diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php index 3f0979bcef1d3..8b64d18d9d0db 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php @@ -14,9 +14,11 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\InvalidArgumentException; use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Stamp\SerializerStamp; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; +use Symfony\Component\Serializer\Exception\UnexpectedValueException; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer as SymfonySerializer; @@ -75,7 +77,11 @@ public function decode(array $encodedEnvelope): Envelope $context = end($stamps[SerializerStamp::class])->getContext() + $context; } - $message = $this->serializer->deserialize($encodedEnvelope['body'], $encodedEnvelope['headers']['type'], $this->format, $context); + try { + $message = $this->serializer->deserialize($encodedEnvelope['body'], $encodedEnvelope['headers']['type'], $this->format, $context); + } catch (UnexpectedValueException $e) { + throw new MessageDecodingFailedException(sprintf('Could not decode message: %s.', $e->getMessage()), $e->getCode(), $e); + } return new Envelope($message, ...$stamps); } @@ -107,7 +113,11 @@ private function decodeStamps(array $encodedEnvelope): array continue; } - $stamps[] = $this->serializer->deserialize($value, substr($name, \strlen(self::STAMP_HEADER_PREFIX)).'[]', $this->format, $this->context); + try { + $stamps[] = $this->serializer->deserialize($value, substr($name, \strlen(self::STAMP_HEADER_PREFIX)).'[]', $this->format, $this->context); + } catch (UnexpectedValueException $e) { + throw new MessageDecodingFailedException(sprintf('Could not decode stamp: %s.', $e->getMessage()), $e->getCode(), $e); + } } if ($stamps) { $stamps = array_merge(...$stamps); diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/SerializerInterface.php b/src/Symfony/Component/Messenger/Transport/Serialization/SerializerInterface.php index df25a1191167d..f534659f50af0 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/SerializerInterface.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/SerializerInterface.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Transport\Serialization; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; /** * @author Samuel Roze @@ -29,6 +30,8 @@ interface SerializerInterface * The most common keys are: * - `body` (string) - the message body * - `headers` (string) - a key/value pair of headers + * + * @throws MessageDecodingFailedException */ public function decode(array $encodedEnvelope): Envelope; diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index ae903217acebb..19c5a4b0fafea 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -11,7 +11,19 @@ namespace Symfony\Component\Messenger; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; +use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; +use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; +use Symfony\Component\Messenger\Retry\RetryStrategyInterface; +use Symfony\Component\Messenger\Stamp\DelayStamp; use Symfony\Component\Messenger\Stamp\ReceivedStamp; +use Symfony\Component\Messenger\Stamp\RedeliveryStamp; +use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; /** @@ -25,11 +37,24 @@ class Worker { private $receiver; private $bus; + private $receiverName; + private $retryStrategy; + private $eventDispatcher; + private $logger; - public function __construct(ReceiverInterface $receiver, MessageBusInterface $bus) + public function __construct(ReceiverInterface $receiver, MessageBusInterface $bus, string $receiverName = null, RetryStrategyInterface $retryStrategy = null, EventDispatcherInterface $eventDispatcher = null, LoggerInterface $logger = null) { $this->receiver = $receiver; $this->bus = $bus; + if (null === $receiverName) { + @trigger_error(sprintf('Instantiating the "%s" class without passing a third argument is deprecated since Symfony 4.3.', __CLASS__), E_USER_DEPRECATED); + + $receiverName = 'unknown'; + } + $this->receiverName = $receiverName; + $this->retryStrategy = $retryStrategy; + $this->eventDispatcher = $eventDispatcher; + $this->logger = $logger; } /** @@ -45,10 +70,112 @@ public function run() $this->receiver->receive(function (?Envelope $envelope) { if (null === $envelope) { + if (\function_exists('pcntl_signal_dispatch')) { + pcntl_signal_dispatch(); + } + return; } - $this->bus->dispatch($envelope->with(new ReceivedStamp())); + $this->dispatchEvent(new WorkerMessageReceivedEvent($envelope, $this->receiverName)); + + $message = $envelope->getMessage(); + $context = [ + 'message' => $message, + 'class' => \get_class($message), + ]; + + try { + $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp())); + } catch (\Throwable $throwable) { + $shouldRetry = $this->shouldRetry($throwable, $envelope); + + $this->dispatchEvent(new WorkerMessageFailedEvent($envelope, $this->receiverName, $throwable, $shouldRetry)); + + if ($shouldRetry) { + if (null === $this->retryStrategy) { + // not logically allowed, but check just in case + throw new LogicException('Retrying is not supported without a retry strategy.'); + } + + $retryCount = $this->getRetryCount($envelope) + 1; + if (null !== $this->logger) { + $this->logger->info('Retrying {class} - retry #{retryCount}.', $context + ['retryCount' => $retryCount, 'error' => $throwable]); + } + + // add the delay and retry stamp info + remove ReceivedStamp + $retryEnvelope = $envelope->with(new DelayStamp($this->retryStrategy->getWaitingTime($envelope))) + ->with(new RedeliveryStamp($retryCount, $this->getSenderAlias($envelope))) + ->withoutAll(ReceivedStamp::class); + + // re-send the message + $this->bus->dispatch($retryEnvelope); + // acknowledge the previous message has received + $this->receiver->ack($envelope); + } else { + if (null !== $this->logger) { + $this->logger->info('Rejecting {class} (removing from transport).', $context + ['error' => $throwable]); + } + + $this->receiver->reject($envelope); + } + + if (\function_exists('pcntl_signal_dispatch')) { + pcntl_signal_dispatch(); + } + + return; + } + + $this->dispatchEvent(new WorkerMessageHandledEvent($envelope, $this->receiverName)); + + if (null !== $this->logger) { + $this->logger->info('{class} was handled successfully (acknowledging to transport).', $context); + } + + $this->receiver->ack($envelope); + + if (\function_exists('pcntl_signal_dispatch')) { + pcntl_signal_dispatch(); + } }); } + + private function dispatchEvent(Event $event) + { + if (null === $this->eventDispatcher) { + return; + } + + $this->eventDispatcher->dispatch($event); + } + + private function shouldRetry(\Throwable $e, Envelope $envelope): bool + { + if ($e instanceof UnrecoverableMessageHandlingException) { + return false; + } + + if (null === $this->retryStrategy) { + return false; + } + + return $this->retryStrategy->isRetryable($envelope); + } + + private function getRetryCount(Envelope $envelope): int + { + /** @var RedeliveryStamp|null $retryMessageStamp */ + $retryMessageStamp = $envelope->last(RedeliveryStamp::class); + + return $retryMessageStamp ? $retryMessageStamp->getRetryCount() : 0; + } + + private function getSenderAlias(Envelope $envelope): ?string + { + /** @var SentStamp|null $sentStamp */ + $sentStamp = $envelope->last(SentStamp::class); + + return $sentStamp ? $sentStamp->getSenderAlias() : null; + } } diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index d0b6fe31f9888..d40963e2f6d18 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -22,6 +22,7 @@ "require-dev": { "symfony/console": "~3.4|~4.0", "symfony/dependency-injection": "~3.4.19|^4.1.8", + "symfony/event-dispatcher": "~4.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/process": "~3.4|~4.0", "symfony/property-access": "~3.4|~4.0", @@ -30,6 +31,9 @@ "symfony/validator": "~3.4|~4.0", "symfony/var-dumper": "~3.4|~4.0" }, + "conflict": { + "symfony/event-dispatcher": "<4.3" + }, "suggest": { "enqueue/messenger-adapter": "For using the php-enqueue library as a transport." }, From 46b9476b525f9a4d7db6e198f528447a80d11c23 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sat, 23 Mar 2019 21:09:32 +0700 Subject: [PATCH 256/495] Ensure an exception is thrown when the AMQP connect() does not work --- .../Transport/AmqpExt/ConnectionTest.php | 21 +++++++++++++++++++ .../Transport/AmqpExt/Connection.php | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index 73ae25de3c7f7..e29ee083319d9 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -335,6 +335,27 @@ public function testItDelaysTheMessageWithADifferentRoutingKeyAndTTLs() $delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_120000', AMQP_NOPARAM, ['headers' => []]); $connection->publish('{}', [], 120000); } + + /** + * @expectedException \AMQPException + * @expectedExceptionMessage Could not connect to the AMQP server. Please verify the provided DSN. ({"delay":{"routing_key_pattern":"delay_%delay%","exchange_name":"delay","queue_name_pattern":"delay_queue_%delay%"},"host":"localhost","port":5672,"vhost":"\/","login":"user","password":"********"}) + */ + public function testObfuscatePasswordInDsn() + { + $factory = new TestAmqpFactory( + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) + ); + + $amqpConnection->method('connect')->willThrowException( + new \AMQPConnectionException('Oups.') + ); + + $connection = Connection::fromDsn('amqp://user:secretpassword@localhost/%2f/messages', [], $factory); + $connection->channel(); + } } class TestAmqpFactory extends AmqpFactory diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 5d7a3e18e5703..18f620c4543f8 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -317,7 +317,7 @@ public function channel(): \AMQPChannel try { $connection->{$connectMethod}(); } catch (\AMQPConnectionException $e) { - $credentials = $this->connectionCredentials; + $credentials = $this->connectionConfiguration; $credentials['password'] = '********'; throw new \AMQPException(sprintf('Could not connect to the AMQP server. Please verify the provided DSN. (%s)', json_encode($credentials)), 0, $e); From a7ad1b4ccc684e28ba3daa274ff6fb08b3d2d07c Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 22 Mar 2019 12:10:25 -0400 Subject: [PATCH 257/495] Dispatching two events when a message is sent & handled --- .../Event/SendMessageToTransportsEvent.php | 44 +++++++++++++++++++ .../Middleware/SendMessageMiddleware.php | 16 ++++++- .../Middleware/SendMessageMiddlewareTest.php | 22 ++++++++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php diff --git a/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php b/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php new file mode 100644 index 0000000000000..a54622e83cf99 --- /dev/null +++ b/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Event; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Messenger\Envelope; + +/** + * Event is dispatched before a message is sent to the transport. + * + * The event is *only* dispatched if the message will actually + * be sent to at least one transport. If the message is sent + * to multiple transports, the message is dispatched only one time. + * + * @author Ryan Weaver + */ +class SendMessageToTransportsEvent extends Event +{ + private $envelope; + + public function __construct(Envelope $envelope) + { + $this->envelope = $envelope; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + public function setEnvelope(Envelope $envelope) + { + $this->envelope = $envelope; + } +} diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index bc6f71761c39a..b978a9c1cb302 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -13,7 +13,9 @@ use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; @@ -30,10 +32,12 @@ class SendMessageMiddleware implements MiddlewareInterface use LoggerAwareTrait; private $sendersLocator; + private $eventDispatcher; - public function __construct(SendersLocatorInterface $sendersLocator) + public function __construct(SendersLocatorInterface $sendersLocator, EventDispatcherInterface $eventDispatcher = null) { $this->sendersLocator = $sendersLocator; + $this->eventDispatcher = $eventDispatcher; $this->logger = new NullLogger(); } @@ -58,7 +62,15 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope /** @var RedeliveryStamp|null $redeliveryStamp */ $redeliveryStamp = $envelope->last(RedeliveryStamp::class); - foreach ($this->sendersLocator->getSenders($envelope, $handle) as $alias => $sender) { + $senders = \iterator_to_array($this->sendersLocator->getSenders($envelope, $handle)); + + if (null !== $this->eventDispatcher && \count($senders) > 0) { + $event = new SendMessageToTransportsEvent($envelope); + $this->eventDispatcher->dispatch($event); + $envelope = $event->getEnvelope(); + } + + foreach ($senders as $alias => $sender) { // on redelivery, only deliver to the given sender if (null !== $redeliveryStamp && !$redeliveryStamp->shouldRedeliverToSender(\get_class($sender), $alias)) { continue; diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index be43799bf8556..8237838a3a0b5 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Messenger\Tests\Middleware; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; @@ -202,4 +204,24 @@ public function testItSkipsReceivedMessages() $this->assertNull($envelope->last(SentStamp::class), 'it does not add sent stamp for received messages'); } + + public function testItDispatchesTheEventOnceTime() + { + $envelope = new Envelope(new DummyMessage('original envelope')); + + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $dispatcher->expects($this->once()) + ->method('dispatch') + ->with(new SendMessageToTransportsEvent($envelope)); + + $sender1 = $this->getMockBuilder(SenderInterface::class)->getMock(); + $sender2 = $this->getMockBuilder(SenderInterface::class)->getMock(); + + $middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender1, $sender2]]), $dispatcher); + + $sender1->expects($this->once())->method('send')->willReturn($envelope); + $sender2->expects($this->once())->method('send')->willReturn($envelope); + + $middleware->handle($envelope, $this->getStackMock(false)); + } } From ef077cf26c4124b7c1f16220a6b05e1979219978 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 22 Mar 2019 14:25:21 -0400 Subject: [PATCH 258/495] Fixing a bug where a transport could receive a message and dispatch it to a different bus --- .../FrameworkExtension.php | 14 +++- .../Resources/config/console.xml | 1 - .../Resources/config/messenger.xml | 2 + .../FrameworkExtensionTest.php | 2 + src/Symfony/Component/Messenger/CHANGELOG.md | 7 +- .../Command/ConsumeMessagesCommand.php | 45 +++++------- .../DependencyInjection/MessengerPass.php | 3 +- .../Middleware/AddBusNameStampMiddleware.php | 39 +++++++++++ .../Messenger/RoutableMessageBus.php | 58 ++++++++++++++++ .../Messenger/Stamp/BusNameStamp.php | 34 +++++++++ .../DependencyInjection/MessengerPassTest.php | 1 - .../AddBusNameStampMiddlewareTest.php | 33 +++++++++ .../Tests/RoutableMessageBusTest.php | 69 +++++++++++++++++++ 13 files changed, 272 insertions(+), 36 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Middleware/AddBusNameStampMiddleware.php create mode 100644 src/Symfony/Component/Messenger/RoutableMessageBus.php create mode 100644 src/Symfony/Component/Messenger/Stamp/BusNameStamp.php create mode 100644 src/Symfony/Component/Messenger/Tests/Middleware/AddBusNameStampMiddlewareTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 0e12127272fdb..fa505bbb0cf67 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1616,8 +1616,14 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder } $defaultMiddleware = [ - 'before' => [['id' => 'dispatch_after_current_bus']], - 'after' => [['id' => 'send_message'], ['id' => 'handle_message']], + 'before' => [ + ['id' => 'add_bus_name_stamp_middleware'], + ['id' => 'dispatch_after_current_bus'], + ], + 'after' => [ + ['id' => 'send_message'], + ['id' => 'handle_message'], + ], ]; foreach ($config['buses'] as $busId => $bus) { $middleware = $bus['middleware']; @@ -1628,6 +1634,10 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder } else { unset($defaultMiddleware['after'][1]['arguments']); } + + // argument to add_bus_name_stamp_middleware + $defaultMiddleware['before'][0]['arguments'] = [$busId]; + $middleware = array_merge($defaultMiddleware['before'], $middleware, $defaultMiddleware['after']); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index eeb36961f7d53..35d9f813c4223 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -81,7 +81,6 @@ - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index 3d471c9338934..b4e6cd69ef64a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -39,6 +39,8 @@ + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index dd626d62c40bf..ddd9d64286ff5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -727,6 +727,7 @@ public function testMessengerWithMultipleBuses() $this->assertTrue($container->has('messenger.bus.commands')); $this->assertSame([], $container->getDefinition('messenger.bus.commands')->getArgument(0)); $this->assertEquals([ + ['id' => 'add_bus_name_stamp_middleware', 'arguments' => ['messenger.bus.commands']], ['id' => 'dispatch_after_current_bus'], ['id' => 'send_message'], ['id' => 'handle_message'], @@ -734,6 +735,7 @@ public function testMessengerWithMultipleBuses() $this->assertTrue($container->has('messenger.bus.events')); $this->assertSame([], $container->getDefinition('messenger.bus.events')->getArgument(0)); $this->assertEquals([ + ['id' => 'add_bus_name_stamp_middleware', 'arguments' => ['messenger.bus.events']], ['id' => 'dispatch_after_current_bus'], ['id' => 'with_factory', 'arguments' => ['foo', true, ['bar' => 'baz']]], ['id' => 'send_message'], diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 40f8c1dc043fa..519966d3e9c5b 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -3,7 +3,12 @@ CHANGELOG 4.3.0 ----- - + + * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` + and `BusNameStamp` were added, which allow you to add a bus identifier + to the `Envelope` then find the correct bus when receiving from + the transport. See `ConsumeMessagesCommand`. + * An optional `ConsumeMessagesCommand` constructor argument was removed. * [BC BREAK] 2 new methods were added to `ReceiverInterface`: `ack()` and `reject()`. * [BC BREAK] Error handling was moved from the receivers into diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index a973a2337d459..ca1973afd4c15 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -21,6 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Messenger\RoutableMessageBus; use Symfony\Component\Messenger\Transport\Receiver\StopWhenMemoryUsageIsExceededReceiver; use Symfony\Component\Messenger\Transport\Receiver\StopWhenMessageCountIsExceededReceiver; use Symfony\Component\Messenger\Transport\Receiver\StopWhenTimeLimitIsReachedReceiver; @@ -39,17 +40,15 @@ class ConsumeMessagesCommand extends Command private $receiverLocator; private $logger; private $receiverNames; - private $busNames; private $retryStrategyLocator; private $eventDispatcher; - public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], array $busNames = [], ContainerInterface $retryStrategyLocator = null, EventDispatcherInterface $eventDispatcher = null) + public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], ContainerInterface $retryStrategyLocator = null, EventDispatcherInterface $eventDispatcher = null) { $this->busLocator = $busLocator; $this->receiverLocator = $receiverLocator; $this->logger = $logger; $this->receiverNames = $receiverNames; - $this->busNames = $busNames; $this->retryStrategyLocator = $retryStrategyLocator; $this->eventDispatcher = $eventDispatcher; @@ -62,7 +61,6 @@ public function __construct(ContainerInterface $busLocator, ContainerInterface $ protected function configure(): void { $defaultReceiverName = 1 === \count($this->receiverNames) ? current($this->receiverNames) : null; - $defaultBusName = 1 === \count($this->busNames) ? current($this->busNames) : null; $this ->setDefinition([ @@ -70,7 +68,7 @@ protected function configure(): void new InputOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit the number of received messages'), new InputOption('memory-limit', 'm', InputOption::VALUE_REQUIRED, 'The memory limit the worker can consume'), new InputOption('time-limit', 't', InputOption::VALUE_REQUIRED, 'The time limit in seconds the worker can run'), - new InputOption('bus', 'b', InputOption::VALUE_REQUIRED, 'Name of the bus to which received messages should be dispatched', $defaultBusName), + new InputOption('bus', 'b', InputOption::VALUE_REQUIRED, 'Name of the bus to which received messages should be dispatched (if not passed, bus is determined automatically.'), ]) ->setDescription('Consumes messages') ->setHelp(<<<'EOF' @@ -89,6 +87,12 @@ protected function configure(): void Use the --time-limit option to stop the worker when the given time limit (in seconds) is reached: php %command.full_name% --time-limit=3600 + +Use the --bus option to specify the message bus to dispatch received messages +to instead of trying to determine it automatically. This is required if the +messages didn't originate from Messenger: + + php %command.full_name% --bus=event_bus EOF ) ; @@ -112,24 +116,6 @@ protected function interact(InputInterface $input, OutputInterface $output) } } } - - $busName = $input->getOption('bus'); - if ($this->busNames && !$this->busLocator->has($busName)) { - if (null === $busName) { - $io->block('Missing bus argument.', null, 'error', ' ', true); - $input->setOption('bus', $io->choice('Select one of the available buses', $this->busNames)); - } elseif ($alternatives = $this->findAlternatives($busName, $this->busNames)) { - $io->block(sprintf('Bus "%s" is not defined.', $busName), null, 'error', ' ', true); - - if (1 === \count($alternatives)) { - if ($io->confirm(sprintf('Do you want to dispatch to "%s" instead? ', $alternatives[0]), true)) { - $input->setOption('bus', $alternatives[0]); - } - } else { - $input->setOption('bus', $io->choice('Did you mean one of the following buses instead?', $alternatives, $alternatives[0])); - } - } - } } /** @@ -147,18 +133,19 @@ protected function execute(InputInterface $input, OutputInterface $output): void throw new RuntimeException(sprintf('Receiver "%s" does not exist.', $receiverName)); } - if (!$this->busLocator->has($busName = $input->getOption('bus'))) { - throw new RuntimeException(sprintf('Bus "%s" does not exist.', $busName)); - } - if (null !== $this->retryStrategyLocator && !$this->retryStrategyLocator->has($receiverName)) { throw new RuntimeException(sprintf('Receiver "%s" does not have a configured retry strategy.', $receiverName)); } $receiver = $this->receiverLocator->get($receiverName); - $bus = $this->busLocator->get($busName); $retryStrategy = null !== $this->retryStrategyLocator ? $this->retryStrategyLocator->get($receiverName) : null; + if (null !== $input->getOption('bus')) { + $bus = $this->busLocator->get($input->getOption('bus')); + } else { + $bus = new RoutableMessageBus($this->busLocator); + } + $stopsWhen = []; if ($limit = $input->getOption('limit')) { $stopsWhen[] = "processed {$limit} messages"; @@ -176,7 +163,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void } $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); - $io->success(sprintf('Consuming messages from transport "%s" on bus "%s".', $receiverName, $busName)); + $io->success(sprintf('Consuming messages from transport "%s".', $receiverName)); if ($stopsWhen) { $last = array_pop($stopsWhen); diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index 8c4773462e18a..92ddfc2d4a3ce 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -248,8 +248,7 @@ private function registerReceivers(ContainerBuilder $container, array $busIds) $container->getDefinition('console.command.messenger_consume_messages') ->replaceArgument(0, ServiceLocatorTagPass::register($container, $buses)) - ->replaceArgument(3, array_values($receiverNames)) - ->replaceArgument(4, $busIds); + ->replaceArgument(3, array_values($receiverNames)); } $container->getDefinition('messenger.receiver_locator')->replaceArgument(0, $receiverMapping); diff --git a/src/Symfony/Component/Messenger/Middleware/AddBusNameStampMiddleware.php b/src/Symfony/Component/Messenger/Middleware/AddBusNameStampMiddleware.php new file mode 100644 index 0000000000000..94392e3c98c58 --- /dev/null +++ b/src/Symfony/Component/Messenger/Middleware/AddBusNameStampMiddleware.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\BusNameStamp; + +/** + * Adds the BusNameStamp to the bus. + * + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +class AddBusNameStampMiddleware implements MiddlewareInterface +{ + private $busName; + + public function __construct(string $busName) + { + $this->busName = $busName; + } + + public function handle(Envelope $envelope, StackInterface $stack): Envelope + { + $envelope = $envelope->with(new BusNameStamp($this->busName)); + + return $stack->next()->handle($envelope, $stack); + } +} diff --git a/src/Symfony/Component/Messenger/RoutableMessageBus.php b/src/Symfony/Component/Messenger/RoutableMessageBus.php new file mode 100644 index 0000000000000..3b1aba9751cc9 --- /dev/null +++ b/src/Symfony/Component/Messenger/RoutableMessageBus.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Stamp\BusNameStamp; + +/** + * Bus of buses that is routable using a BusNameStamp. + * + * This is useful when passed to Worker: messages received + * from the transport can be sent to the correct bus. + * + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +class RoutableMessageBus implements MessageBusInterface +{ + private $busLocator; + + /** + * @param ContainerInterface $busLocator A locator full of MessageBusInterface objects + */ + public function __construct(ContainerInterface $busLocator) + { + $this->busLocator = $busLocator; + } + + public function dispatch($envelope): Envelope + { + if (!$envelope instanceof Envelope) { + throw new InvalidArgumentException('Messages passed to RoutableMessageBus::dispatch() must be inside an Envelope'); + } + + /** @var BusNameStamp $busNameStamp */ + $busNameStamp = $envelope->last(BusNameStamp::class); + if (null === $busNameStamp) { + throw new InvalidArgumentException('Envelope does not contain a BusNameStamp.'); + } + + if (!$this->busLocator->has($busNameStamp->getBusName())) { + throw new InvalidArgumentException(sprintf('Invalid bus name "%s" on BusNameStamp.', $busNameStamp->getBusName())); + } + + return $this->busLocator->get($busNameStamp->getBusName())->dispatch($envelope); + } +} diff --git a/src/Symfony/Component/Messenger/Stamp/BusNameStamp.php b/src/Symfony/Component/Messenger/Stamp/BusNameStamp.php new file mode 100644 index 0000000000000..eee3f9e8465fa --- /dev/null +++ b/src/Symfony/Component/Messenger/Stamp/BusNameStamp.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Stamp used to identify which bus it was passed to. + * + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +class BusNameStamp implements StampInterface +{ + private $busName; + + public function __construct(string $busName) + { + $this->busName = $busName; + } + + public function getBusName(): string + { + return $this->busName; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 24820df0c61c6..c6ef2c0cecb59 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -263,7 +263,6 @@ public function testItRegistersMultipleReceiversAndSetsTheReceiverNamesOnTheComm (new MessengerPass())->process($container); $this->assertSame(['amqp', 'dummy'], $container->getDefinition('console.command.messenger_consume_messages')->getArgument(3)); - $this->assertSame(['message_bus'], $container->getDefinition('console.command.messenger_consume_messages')->getArgument(4)); } public function testItShouldNotThrowIfGeneratorIsReturnedInsteadOfArray() diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/AddBusNameStampMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/AddBusNameStampMiddlewareTest.php new file mode 100644 index 0000000000000..71fe15b25e90c --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Middleware/AddBusNameStampMiddlewareTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Middleware; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Middleware\AddBusNameStampMiddleware; +use Symfony\Component\Messenger\Stamp\BusNameStamp; +use Symfony\Component\Messenger\Test\Middleware\MiddlewareTestCase; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; + +class AddBusNameStampMiddlewareTest extends MiddlewareTestCase +{ + public function testItSendsTheMessageToAssignedSender() + { + $middleware = new AddBusNameStampMiddleware('the_bus_name'); + $envelope = new Envelope(new DummyMessage('the message')); + + $finalEnvelope = $middleware->handle($envelope, $this->getStackMock()); + /** @var BusNameStamp $busNameStamp */ + $busNameStamp = $finalEnvelope->last(BusNameStamp::class); + $this->assertNotNull($busNameStamp); + $this->assertSame('the_bus_name', $busNameStamp->getBusName()); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php b/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php new file mode 100644 index 0000000000000..517a57914cc85 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\RoutableMessageBus; +use Symfony\Component\Messenger\Stamp\BusNameStamp; + +class RoutableMessageBusTest extends TestCase +{ + public function testItRoutesToTheCorrectBus() + { + $envelope = new Envelope(new \stdClass(), new BusNameStamp('foo_bus')); + + $bus1 = $this->createMock(MessageBusInterface::class); + $bus2 = $this->createMock(MessageBusInterface::class); + + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once())->method('has')->with('foo_bus')->willReturn(true); + $container->expects($this->once())->method('get')->will($this->returnValue($bus2)); + + $bus1->expects($this->never())->method('dispatch'); + $bus2->expects($this->once())->method('dispatch')->with($envelope)->willReturn($envelope); + + $routableBus = new RoutableMessageBus($container); + $this->assertSame($envelope, $routableBus->dispatch($envelope)); + } + + public function testItExceptionOnMissingStamp() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('does not contain a BusNameStamp'); + + $envelope = new Envelope(new \stdClass()); + + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->never())->method('has'); + + $routableBus = new RoutableMessageBus($container); + $routableBus->dispatch($envelope); + } + + public function testItExceptionOnBusNotFound() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid bus name'); + + $envelope = new Envelope(new \stdClass(), new BusNameStamp('foo_bus')); + + $container = $this->createMock(ContainerInterface::class); + $container->expects($this->once())->method('has')->willReturn(false); + + $routableBus = new RoutableMessageBus($container); + $routableBus->dispatch($envelope); + } +} From 1a693039e42e2b33d0809d7bc6cd7c1a5d314291 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sat, 23 Mar 2019 21:33:00 +0700 Subject: [PATCH 259/495] FWB 4.3 requires Messenger 4.3 --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 86ad2fe1e6e6e..681dd45fd3b68 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -72,7 +72,7 @@ "symfony/console": "<3.4", "symfony/dotenv": "<4.2", "symfony/form": "<4.3", - "symfony/messenger": "<4.2", + "symfony/messenger": "<4.3", "symfony/property-info": "<3.4", "symfony/serializer": "<4.2", "symfony/stopwatch": "<3.4", From d6c0de2f1b358751551f4cb7b4792ff09219b3e1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 23 Mar 2019 16:10:57 +0100 Subject: [PATCH 260/495] fixed CS --- src/Symfony/Component/HttpClient/CachingHttpClient.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CachingHttpClient.php b/src/Symfony/Component/HttpClient/CachingHttpClient.php index 30f370078f265..0135a268b6035 100644 --- a/src/Symfony/Component/HttpClient/CachingHttpClient.php +++ b/src/Symfony/Component/HttpClient/CachingHttpClient.php @@ -15,7 +15,6 @@ use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpClient\Response\ResponseStream; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\HttpCache\HttpCache; use Symfony\Component\HttpKernel\HttpCache\StoreInterface; use Symfony\Component\HttpKernel\HttpClientKernel; @@ -43,7 +42,7 @@ class CachingHttpClient implements HttpClientInterface public function __construct(HttpClientInterface $client, StoreInterface $store, array $defaultOptions = [], LoggerInterface $logger = null) { if (!class_exists(HttpClientKernel::class)) { - throw new \LogicException(sprintf('Using "%s" requires that the HttpKernel component version 4.3 or higher is installed, try running "composer require symfony/http-kernel:^4.3".', __CLASS__)); + throw new \LogicException(sprintf('Using "%s" requires that the HttpKernel component version 4.3 or higher is installed, try running "composer require symfony/http-kernel:^4.3".', __CLASS__)); } $this->client = $client; From f206538c79b7df5808c6fa200ebc9e0523fcec13 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 23 Mar 2019 16:11:21 +0100 Subject: [PATCH 261/495] fixed typo --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index d3007e8aec80f..310f9818d85de 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -21,7 +21,7 @@ CHANGELOG * renamed `GetResponseForControllerResultEvent` to `ViewEvent` * renamed `GetResponseForExceptionEvent` to `ExceptionEvent` * renamed `PostResponseEvent` to `TerminateEvent` - * added `RealHttpKernel` for handling requests with an `HttpClientInterface` instance + * added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance 4.2.0 ----- From 21235310e3c726b730cea012b6f52bb05b3b7f93 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sat, 23 Mar 2019 22:30:49 +0700 Subject: [PATCH 262/495] Add a BC layer for the `ConsumeMessagesCommand` arguments --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- .../Messenger/Command/ConsumeMessagesCommand.php | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 519966d3e9c5b..54c32c1618ddd 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -8,7 +8,7 @@ CHANGELOG and `BusNameStamp` were added, which allow you to add a bus identifier to the `Envelope` then find the correct bus when receiving from the transport. See `ConsumeMessagesCommand`. - * An optional `ConsumeMessagesCommand` constructor argument was removed. + * The optional `$busNames` constructor argument of the class `ConsumeMessagesCommand` was removed. * [BC BREAK] 2 new methods were added to `ReceiverInterface`: `ack()` and `reject()`. * [BC BREAK] Error handling was moved from the receivers into diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index ca1973afd4c15..af916cb785c1c 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -43,8 +43,14 @@ class ConsumeMessagesCommand extends Command private $retryStrategyLocator; private $eventDispatcher; - public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], ContainerInterface $retryStrategyLocator = null, EventDispatcherInterface $eventDispatcher = null) + public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], /* ContainerInterface */ $retryStrategyLocator = null, EventDispatcherInterface $eventDispatcher = null) { + if (\is_array($retryStrategyLocator)) { + @trigger_error(sprintf('The 5th argument of the class "%s" should be a retry-strategy locator, an array of bus names as a value is deprecated since Symfony 4.3.', __CLASS__), E_USER_DEPRECATED); + + $retryStrategyLocator = null; + } + $this->busLocator = $busLocator; $this->receiverLocator = $receiverLocator; $this->logger = $logger; From fc7465c02c242582ae9286762d83d75461fb9dfe Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Wed, 17 Oct 2018 09:07:10 +0200 Subject: [PATCH 263/495] [Console] Add dumper --- .../Component/Console/Helper/Dumper.php | 64 +++++++++++++++++++ .../Tests/Helper/DumperNativeFallbackTest.php | 58 +++++++++++++++++ .../Console/Tests/Helper/DumperTest.php | 58 +++++++++++++++++ src/Symfony/Component/Console/composer.json | 1 + .../VarDumper/Test/VarDumperTestTrait.php | 1 + 5 files changed, 182 insertions(+) create mode 100644 src/Symfony/Component/Console/Helper/Dumper.php create mode 100644 src/Symfony/Component/Console/Tests/Helper/DumperNativeFallbackTest.php create mode 100644 src/Symfony/Component/Console/Tests/Helper/DumperTest.php diff --git a/src/Symfony/Component/Console/Helper/Dumper.php b/src/Symfony/Component/Console/Helper/Dumper.php new file mode 100644 index 0000000000000..b013b6c527b6c --- /dev/null +++ b/src/Symfony/Component/Console/Helper/Dumper.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Helper; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Cloner\ClonerInterface; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * @author Roland Franssen + */ +final class Dumper +{ + private $output; + private $dumper; + private $cloner; + private $handler; + + public function __construct(OutputInterface $output, CliDumper $dumper = null, ClonerInterface $cloner = null) + { + $this->output = $output; + $this->dumper = $dumper; + $this->cloner = $cloner; + + if (class_exists(CliDumper::class)) { + $this->handler = function ($var): string { + $dumper = $this->dumper ?? $this->dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR); + $dumper->setColors($this->output->isDecorated()); + + return rtrim($dumper->dump(($this->cloner ?? $this->cloner = new VarCloner())->cloneVar($var)->withRefHandles(false), true)); + }; + } else { + $this->handler = function ($var): string { + switch (true) { + case null === $var: + return 'null'; + case true === $var: + return 'true'; + case false === $var: + return 'false'; + case \is_string($var): + return '"'.$var.'"'; + default: + return rtrim(print_r($var, true)); + } + }; + } + } + + public function __invoke($var): string + { + return ($this->handler)($var); + } +} diff --git a/src/Symfony/Component/Console/Tests/Helper/DumperNativeFallbackTest.php b/src/Symfony/Component/Console/Tests/Helper/DumperNativeFallbackTest.php new file mode 100644 index 0000000000000..b9fa2dc2947ec --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Helper/DumperNativeFallbackTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ClassExistsMock; +use Symfony\Component\Console\Helper\Dumper; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +class DumperNativeFallbackTest extends TestCase +{ + public static function setUpBeforeClass() + { + ClassExistsMock::register(Dumper::class); + ClassExistsMock::withMockedClasses([ + CliDumper::class => false, + ]); + } + + public static function tearDownAfterClass() + { + ClassExistsMock::withMockedClasses([]); + } + + /** + * @dataProvider provideVariables + */ + public function testInvoke($variable, $primitiveString) + { + $dumper = new Dumper($this->getMockBuilder(OutputInterface::class)->getMock()); + + $this->assertSame($primitiveString, $dumper($variable)); + } + + public function provideVariables() + { + return [ + [null, 'null'], + [true, 'true'], + [false, 'false'], + [1, '1'], + [-1.5, '-1.5'], + ['string', '"string"'], + [[1, '2'], "Array\n(\n [0] => 1\n [1] => 2\n)"], + [new \stdClass(), "stdClass Object\n(\n)"], + ]; + } +} diff --git a/src/Symfony/Component/Console/Tests/Helper/DumperTest.php b/src/Symfony/Component/Console/Tests/Helper/DumperTest.php new file mode 100644 index 0000000000000..00c480a6a9018 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Helper/DumperTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Helper; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Helper\Dumper; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; + +class DumperTest extends TestCase +{ + use VarDumperTestTrait; + + public static function setUpBeforeClass() + { + putenv('DUMP_LIGHT_ARRAY=1'); + putenv('DUMP_COMMA_SEPARATOR=1'); + } + + public static function tearDownAfterClass() + { + putenv('DUMP_LIGHT_ARRAY'); + putenv('DUMP_COMMA_SEPARATOR'); + } + + /** + * @dataProvider provideVariables + */ + public function testInvoke($variable) + { + $dumper = new Dumper($this->getMockBuilder(OutputInterface::class)->getMock()); + + $this->assertDumpMatchesFormat($dumper($variable), $variable); + } + + public function provideVariables() + { + return [ + [null], + [true], + [false], + [1], + [-1.5], + ['string'], + [[1, '2']], + [new \stdClass()], + ]; + } +} diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index 0fae716e91720..8eff5b7458e4c 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -27,6 +27,7 @@ "symfony/dependency-injection": "~3.4|~4.0", "symfony/lock": "~3.4|~4.0", "symfony/process": "~3.4|~4.0", + "symfony/var-dumper": "^4.3", "psr/log": "~1.0" }, "provide": { diff --git a/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php b/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php index bcf55dee8bff7..11c9b92659069 100644 --- a/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php +++ b/src/Symfony/Component/VarDumper/Test/VarDumperTestTrait.php @@ -33,6 +33,7 @@ protected function getDump($data, $key = null, $filter = 0) { $flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0; $flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0; + $flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0; $cloner = new VarCloner(); $cloner->setMaxItems(-1); From 96df4464a171b7e3605a7d6292cb2c20e50d9020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Wed, 13 Mar 2019 23:02:02 +0100 Subject: [PATCH 264/495] [HttpClient] Parse common API error formats for better exception messages --- .../Exception/HttpExceptionTrait.php | 33 +++++++++- .../Exception/HttpExceptionTraitTest.php | 62 +++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php diff --git a/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php b/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php index 48f7b880eba43..e2293f7b285c5 100644 --- a/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php +++ b/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php @@ -26,10 +26,41 @@ public function __construct(ResponseInterface $response) $url = $response->getInfo('url'); $message = sprintf('HTTP %d returned for URL "%s".', $code, $url); + $httpCodeFound = false; + $isJson = false; foreach (array_reverse($response->getInfo('raw_headers')) as $h) { if (0 === strpos($h, 'HTTP/')) { + if ($httpCodeFound) { + break; + } + $message = sprintf('%s returned for URL "%s".', $h, $url); - break; + $httpCodeFound = true; + } + + if (0 === stripos($h, 'content-type:')) { + if (preg_match('/\bjson\b/i', $h)) { + $isJson = true; + } + + if ($httpCodeFound) { + break; + } + } + } + + // Try to guess a better error message using common API error formats + // The MIME type isn't explicitly checked because some formats inherit from others + // Ex: JSON:API follows RFC 7807 semantics, Hydra can be used in any JSON-LD-compatible format + if ($isJson && $body = json_decode($response->getContent(false), true)) { + if (isset($body['hydra:title']) || isset($body['hydra:description'])) { + // see http://www.hydra-cg.com/spec/latest/core/#description-of-http-status-codes-and-errors + $separator = isset($body['hydra:title'], $body['hydra:description']) ? "\n\n" : ''; + $message = ($body['hydra:title'] ?? '').$separator.($body['hydra:description'] ?? ''); + } elseif (isset($body['title']) || isset($body['detail'])) { + // see RFC 7807 and https://jsonapi.org/format/#error-objects + $separator = isset($body['title'], $body['detail']) ? "\n\n" : ''; + $message = ($body['title'] ?? '').$separator.($body['detail'] ?? ''); } } diff --git a/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php b/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php new file mode 100644 index 0000000000000..4993bae71a278 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpClient\Tests\Exception; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\Exception\HttpExceptionTrait; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Kévin Dunglas + */ +class HttpExceptionTraitTest extends TestCase +{ + public function provideParseError() + { + yield ['application/ld+json', '{"hydra:title": "An error occurred", "hydra:description": "Some details"}']; + yield ['application/problem+json', '{"title": "An error occurred", "detail": "Some details"}']; + yield ['application/vnd.api+json', '{"title": "An error occurred", "detail": "Some details"}']; + } + + /** + * @dataProvider provideParseError + */ + public function testParseError(string $mimeType, string $json): void + { + $response = $this->createMock(ResponseInterface::class); + $response + ->method('getInfo') + ->will($this->returnValueMap([ + ['http_code', 400], + ['url', 'http://example.com'], + ['raw_headers', [ + 'HTTP/1.1 400 Bad Request', + 'Content-Type: '.$mimeType, + ]], + ])); + $response->method('getContent')->willReturn($json); + + $e = new TestException($response); + $this->assertSame(400, $e->getCode()); + $this->assertSame(<<getMessage()); + } +} + +class TestException extends \Exception +{ + use HttpExceptionTrait; +} From 8059c50e75108f5752cc7bc9916764cb9f9e4cf6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 25 Mar 2019 08:46:22 +0100 Subject: [PATCH 265/495] fixed type hints for email attachments --- src/Symfony/Component/Mime/Email.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mime/Email.php b/src/Symfony/Component/Mime/Email.php index ee5d478bf4612..5a1e57aa6746f 100644 --- a/src/Symfony/Component/Mime/Email.php +++ b/src/Symfony/Component/Mime/Email.php @@ -372,7 +372,7 @@ public function embedFromPath(string $path, string $name = null, string $content /** * @return $this */ - public function attachPart(AbstractPart $part) + public function attachPart(DataPart $part) { $this->attachments[] = ['part' => $part]; @@ -380,7 +380,7 @@ public function attachPart(AbstractPart $part) } /** - * @return AbstractPart[] + * @return DataPart[] */ public function getAttachments(): array { From a94228edba048144a5bab0e69c3e801e3bfeed59 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sun, 24 Mar 2019 12:36:23 +0100 Subject: [PATCH 266/495] [Form][Console] Use dumper --- .../Console/Descriptor/TextDescriptor.php | 25 +------------ .../Form/Tests/Command/DebugCommandTest.php | 37 +++++++++++++++++++ src/Symfony/Component/Form/composer.json | 5 ++- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php index 90dd8f1dfeacb..da0fc652f6d21 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php @@ -11,12 +11,10 @@ namespace Symfony\Component\Form\Console\Descriptor; +use Symfony\Component\Console\Helper\Dumper; use Symfony\Component\Console\Helper\TableSeparator; use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\VarDumper\Caster\Caster; -use Symfony\Component\VarDumper\Cloner\VarCloner; -use Symfony\Component\VarDumper\Dumper\CliDumper; /** * @author Yonel Ceruto @@ -97,7 +95,7 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio { $definition = $this->getOptionDefinition($optionsResolver, $options['option']); - $dump = $this->getDumpFunction(); + $dump = new Dumper($this->output); $map = []; if ($definition['deprecated']) { $map = [ @@ -180,23 +178,4 @@ private function normalizeAndSortOptionsColumns(array $options) return $options; } - - private function getDumpFunction() - { - $cloner = new VarCloner(); - $cloner->addCasters(['Closure' => function ($c, $a) { - $prefix = Caster::PREFIX_VIRTUAL; - - return [ - $prefix.'file' => $a[$prefix.'file'], - $prefix.'line' => $a[$prefix.'line'], - ]; - }]); - $dumper = new CliDumper(null, null, CliDumper::DUMP_LIGHT_ARRAY | CliDumper::DUMP_COMMA_SEPARATOR); - $dumper->setColors($this->output->isDecorated()); - - return function ($value) use ($dumper, $cloner) { - return rtrim($dumper->dump($cloner->cloneVar($value)->withRefHandles(false), true)); - }; - } } diff --git a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php index 4319a23f10360..fd6a8db2ada14 100644 --- a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php @@ -153,6 +153,43 @@ public function testDebugInvalidFormType() $this->createCommandTester()->execute(['class' => 'test']); } + public function testDebugCustomFormTypeOption() + { + $tester = $this->createCommandTester([], [FooType::class]); + $ret = $tester->execute(['class' => FooType::class, 'option' => 'foo'], ['decorated' => false]); + + $this->assertEquals(0, $ret, 'Returns 0 in case of success'); + $this->assertStringMatchesFormat(<<<'TXT' + +Symfony\Component\Form\Tests\Command\FooType (foo) +================================================== + + ---------------- ---------------------------------------------------------------------------%s + Required true %w + ---------------- ---------------------------------------------------------------------------%s + Default - %w + ---------------- ---------------------------------------------------------------------------%s + Allowed types [ %w + "string" %w + ] %w + ---------------- ---------------------------------------------------------------------------%s + Allowed values [ %w + "bar", %w + "baz" %w + ] %w + ---------------- ---------------------------------------------------------------------------%s + Normalizer Closure(Options $options, $value) { %w + class: "Symfony\Component\Form\Tests\Command\FooType" %w + this: Symfony\Component\Form\Tests\Command\FooType { …} %w + file: "%s"%w + line: "%d to %d"%w + } %w + ---------------- ---------------------------------------------------------------------------%s + +TXT + , $tester->getDisplay(true)); + } + private function createCommandTester(array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], array $types = []) { $formRegistry = new FormRegistry([], new ResolvedFormTypeFactory()); diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 256041a7c188d..6de2563a7bb09 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -29,15 +29,16 @@ "symfony/validator": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", "symfony/config": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", + "symfony/console": "^4.3", "symfony/http-foundation": "~3.4|~4.0", "symfony/http-kernel": "~4.3", "symfony/security-csrf": "~3.4|~4.0", "symfony/translation": "~4.2", - "symfony/var-dumper": "~3.4|~4.0" + "symfony/var-dumper": "^4.3" }, "conflict": { "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", + "symfony/console": "<4.3", "symfony/dependency-injection": "<3.4", "symfony/doctrine-bridge": "<3.4", "symfony/framework-bundle": "<3.4", From b813a05aa5358c7e7de53a664090b10ac34a50cb Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Fri, 22 Jun 2018 12:44:17 +0200 Subject: [PATCH 267/495] [FrameworkBundle] Debug container environment variables --- .../Command/ContainerDebugCommand.php | 25 +++++-- .../Console/Descriptor/Descriptor.php | 39 +++++++++++ .../Console/Descriptor/JsonDescriptor.php | 9 +++ .../Console/Descriptor/MarkdownDescriptor.php | 9 +++ .../Console/Descriptor/TextDescriptor.php | 66 ++++++++++++++++++ .../Console/Descriptor/XmlDescriptor.php | 9 +++ .../Functional/ContainerDebugCommandTest.php | 69 +++++++++++++++++++ .../Functional/app/ContainerDebug/config.yml | 10 +++ .../Bundle/FrameworkBundle/composer.json | 6 +- 9 files changed, 235 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 9b5193d63bcea..13ddc962765c0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -58,6 +58,8 @@ protected function configure() new InputOption('parameter', null, InputOption::VALUE_REQUIRED, 'Displays a specific parameter for an application'), new InputOption('parameters', null, InputOption::VALUE_NONE, 'Displays parameters for an application'), new InputOption('types', null, InputOption::VALUE_NONE, 'Displays types (classes/interfaces) available in the container'), + new InputOption('env-var', null, InputOption::VALUE_REQUIRED, 'Displays a specific environment variable used in the container'), + new InputOption('env-vars', null, InputOption::VALUE_NONE, 'Displays environment variables used in the container'), new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (txt, xml, json, or md)', 'txt'), new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'), ]) @@ -75,6 +77,14 @@ protected function configure() php %command.full_name% --types +To see environment variables used by the container, use the --env-vars flag: + + php %command.full_name% --env-vars + +Display a specific environment variable by specifying its name with the --env-var option: + + php %command.full_name% --env-var=APP_ENV + Use the --tags option to display tagged public services grouped by tag: php %command.full_name% --tags @@ -116,7 +126,11 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->validateInput($input); $object = $this->getContainerBuilder(); - if ($input->getOption('types')) { + if ($input->getOption('env-vars')) { + $options = ['env-vars' => true]; + } elseif ($envVar = $input->getOption('env-var')) { + $options = ['env-vars' => true, 'name' => $envVar]; + } elseif ($input->getOption('types')) { $options = []; $options['filter'] = [$this, 'filterToServiceTypes']; } elseif ($input->getOption('parameters')) { @@ -156,7 +170,7 @@ protected function execute(InputInterface $input, OutputInterface $output) throw $e; } - if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && $input->isInteractive()) { + if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && !$input->getOption('env-vars') && !$input->getOption('env-var') && $input->isInteractive()) { if ($input->getOption('tags')) { $errorIo->comment('To search for a specific tag, re-run this command with a search term. (e.g. debug:container --tag=form.type)'); } elseif ($input->getOption('parameters')) { @@ -209,12 +223,15 @@ protected function getContainerBuilder() if (!$kernel->isDebug() || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) { $buildContainer = \Closure::bind(function () { return $this->buildContainer(); }, $kernel, \get_class($kernel)); $container = $buildContainer(); - $container->getCompilerPassConfig()->setRemovingPasses([]); - $container->compile(); } else { (new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump')); + $container->setParameter('container.build_hash', $hash = ContainerBuilder::hash(__METHOD__)); + $container->setParameter('container.build_id', hash('crc32', $hash.time())); } + $container->getCompilerPassConfig()->setRemovingPasses([]); + $container->compile(); + return $this->containerBuilder = $container; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php index 484ca4fefd8c2..7babbd39129f2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php @@ -52,6 +52,9 @@ public function describe(OutputInterface $output, $object, array $options = []) case $object instanceof ParameterBag: $this->describeContainerParameters($object, $options); break; + case $object instanceof ContainerBuilder && !empty($options['env-vars']): + $this->describeContainerEnvVars($this->getContainerEnvVars($object), $options); + break; case $object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by']: $this->describeContainerTags($object, $options); break; @@ -157,6 +160,11 @@ abstract protected function describeContainerAlias(Alias $alias, array $options */ abstract protected function describeContainerParameter($parameter, array $options = []); + /** + * Describes container environment variables. + */ + abstract protected function describeContainerEnvVars(array $envs, array $options = []); + /** * Describes event dispatcher listeners. * @@ -311,4 +319,35 @@ public static function getClassDescription(string $class, string &$resolvedClass return ''; } + + private function getContainerEnvVars(ContainerBuilder $container): array + { + $getEnvReflection = new \ReflectionMethod($container, 'getEnv'); + $getEnvReflection->setAccessible(true); + $envs = []; + foreach (array_keys($container->getEnvCounters()) as $env) { + $processor = 'string'; + if (false !== $i = strrpos($name = $env, ':')) { + $name = substr($env, $i + 1); + $processor = substr($env, 0, $i); + } + $defaultValue = ($hasDefault = $container->hasParameter("env($name)")) ? $container->getParameter("env($name)") : null; + if (false === ($runtimeValue = $_ENV[$name] ?? $_SERVER[$name] ?? getenv($name))) { + $runtimeValue = null; + } + $processedValue = ($hasRuntime = null !== $runtimeValue) || $hasDefault ? $getEnvReflection->invoke($container, $env) : null; + $envs[$name.$processor] = [ + 'name' => $name, + 'processor' => $processor, + 'default_available' => $hasDefault, + 'default_value' => $defaultValue, + 'runtime_available' => $hasRuntime, + 'runtime_value' => $runtimeValue, + 'processed_value' => $processedValue, + ]; + } + ksort($envs); + + return array_values($envs); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 137114ebe7161..e50f50722b082 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor; +use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -177,6 +178,14 @@ protected function describeContainerParameter($parameter, array $options = []) $this->writeData([$key => $parameter], $options); } + /** + * {@inheritdoc} + */ + protected function describeContainerEnvVars(array $envs, array $options = []) + { + throw new LogicException('Using the JSON format to debug environment variables is not supported.'); + } + /** * Writes data as json. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index e68152b9a5d43..162e68f84d9a0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor; +use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; @@ -273,6 +274,14 @@ protected function describeContainerParameter($parameter, array $options = []) $this->write(isset($options['parameter']) ? sprintf("%s\n%s\n\n%s", $options['parameter'], str_repeat('=', \strlen($options['parameter'])), $this->formatParameter($parameter)) : $parameter); } + /** + * {@inheritdoc} + */ + protected function describeContainerEnvVars(array $envs, array $options = []) + { + throw new LogicException('Using the markdown format to debug environment variables is not supported.'); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 8980a9ee41f5e..1861916896161 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor; use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\Dumper; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Alias; @@ -384,6 +385,71 @@ protected function describeContainerParameter($parameter, array $options = []) ]); } + /** + * {@inheritdoc} + */ + protected function describeContainerEnvVars(array $envs, array $options = []) + { + $dump = new Dumper($this->output); + $options['output']->title('Symfony Container Environment Variables'); + + if (null !== $name = $options['name'] ?? null) { + $options['output']->comment('Displaying detailed environment variable usage matching '.$name); + + $matches = false; + foreach ($envs as $env) { + if ($name === $env['name'] || false !== stripos($env['name'], $name)) { + $matches = true; + $options['output']->section('%env('.$env['processor'].':'.$env['name'].')%'); + $options['output']->table([], [ + ['Default value', $env['default_available'] ? $dump($env['default_value']) : 'n/a'], + ['Real value', $env['runtime_available'] ? $dump($env['runtime_value']) : 'n/a'], + ['Processed value', $env['default_available'] || $env['runtime_available'] ? $dump($env['processed_value']) : 'n/a'], + ]); + } + } + + if (!$matches) { + $options['output']->block('None of the environment variables match this name.'); + } else { + $options['output']->comment('Note real values might be different between web and CLI.'); + } + + return; + } + + if (!$envs) { + $options['output']->block('No environment variables are being used.'); + + return; + } + + $rows = []; + $missing = []; + foreach ($envs as $env) { + if (isset($rows[$env['name']])) { + continue; + } + + $rows[$env['name']] = [ + $env['name'], + $env['default_available'] ? $dump($env['default_value']) : 'n/a', + $env['runtime_available'] ? $dump($env['runtime_value']) : 'n/a', + ]; + if (!$env['default_available'] && !$env['runtime_available']) { + $missing[$env['name']] = true; + } + } + + $options['output']->table(['Name', 'Default value', 'Real value'], $rows); + $options['output']->comment('Note real values might be different between web and CLI.'); + + if ($missing) { + $options['output']->warning('The following variables are missing:'); + $options['output']->listing(array_keys($missing)); + } + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index db0f346ebd72d..a58c837823263 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor; +use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; @@ -131,6 +132,14 @@ protected function describeContainerParameter($parameter, array $options = []) $this->writeDocument($this->getContainerParameterDocument($parameter, $options)); } + /** + * {@inheritdoc} + */ + protected function describeContainerEnvVars(array $envs, array $options = []) + { + throw new LogicException('Using the XML format to debug environment variables is not supported.'); + } + /** * Writes DOM document. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php index ee13386a4b767..310646e428f69 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php @@ -80,6 +80,75 @@ public function testIgnoreBackslashWhenFindingService(string $validServiceId) $this->assertNotContains('No services found', $tester->getDisplay()); } + public function testDescribeEnvVars() + { + putenv('REAL=value'); + static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']); + + $application = new Application(static::$kernel); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(['command' => 'debug:container', '--env-vars' => true], ['decorated' => false]); + + $this->assertStringMatchesFormat(<<<'TXT' + +Symfony Container Environment Variables +======================================= + + --------- ----------------- ------------ + Name Default value Real value + --------- ----------------- ------------ + JSON "[1, "2.5", 3]" n/a + REAL n/a "value" + UNKNOWN n/a n/a + --------- ----------------- ------------ + + // Note real values might be different between web and CLI.%w + + [WARNING] The following variables are missing:%w + + * UNKNOWN + +TXT + , $tester->getDisplay(true)); + + putenv('REAL'); + } + + public function testDescribeEnvVar() + { + static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']); + + $application = new Application(static::$kernel); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(['command' => 'debug:container', '--env-var' => 'js'], ['decorated' => false]); + + $this->assertContains(<<<'TXT' +%env(float:key:2:json:JSON)% +---------------------------- + + ----------------- ----------------- + Default value "[1, "2.5", 3]" + Real value n/a + Processed value 3.0 + ----------------- ----------------- + +%env(int:key:2:json:JSON)% +-------------------------- + + ----------------- ----------------- + Default value "[1, "2.5", 3]" + Real value n/a + Processed value 3 + ----------------- ----------------- + +TXT + , $tester->getDisplay(true)); + } + public function provideIgnoreBackslashWhenFindingService() { return [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml index fb3b3b9b9a8d6..0cc73dbc81422 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/ContainerDebug/config.yml @@ -1,6 +1,9 @@ imports: - { resource: ../config/default.yml } +parameters: + env(JSON): '[1, "2.5", 3]' + services: _defaults: { public: true } public: @@ -10,3 +13,10 @@ services: public: false Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass: class: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BackslashClass + env: + class: stdClass + arguments: + - '%env(UNKNOWN)%' + - '%env(REAL)%' + - '%env(int:key:2:json:JSON)%' + - '%env(float:key:2:json:JSON)%' diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 681dd45fd3b68..57a7e256234cf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -34,7 +34,7 @@ "fig/link-util": "^1.0", "symfony/asset": "~3.4|~4.0", "symfony/browser-kit": "^4.3", - "symfony/console": "~3.4|~4.0", + "symfony/console": "^4.3", "symfony/css-selector": "~3.4|~4.0", "symfony/dom-crawler": "~3.4|~4.0", "symfony/polyfill-intl-icu": "~1.0", @@ -53,7 +53,7 @@ "symfony/templating": "~3.4|~4.0", "symfony/twig-bundle": "~2.8|~3.2|~4.0", "symfony/validator": "^4.1", - "symfony/var-dumper": "~3.4|~4.0", + "symfony/var-dumper": "^4.3", "symfony/workflow": "^4.3", "symfony/yaml": "~3.4|~4.0", "symfony/property-info": "~3.4|~4.0", @@ -69,7 +69,7 @@ "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/asset": "<3.4", "symfony/browser-kit": "<4.3", - "symfony/console": "<3.4", + "symfony/console": "<4.3", "symfony/dotenv": "<4.2", "symfony/form": "<4.3", "symfony/messenger": "<4.3", From 20664caf2569e63b8e0694ef4a69d460731f3b79 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 25 Mar 2019 11:54:55 +0100 Subject: [PATCH 268/495] [Messenger] added missing information in messenger logs --- .../Component/Messenger/Middleware/LoggingMiddleware.php | 2 +- .../Component/Messenger/Middleware/SendMessageMiddleware.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php b/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php index a2941055fa67d..f68b6d802d8ad 100644 --- a/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/LoggingMiddleware.php @@ -46,7 +46,7 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope $envelope = $stack->next()->handle($envelope, $stack); } catch (\Throwable $e) { $context['exception'] = $e; - $this->logger->warning('An exception occurred while handling message "{class}"', $context); + $this->logger->warning('An exception occurred while handling message "{class}": '.$e->getMessage(), $context); throw $e; } diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index b978a9c1cb302..e389da910cbf9 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -91,7 +91,7 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope } } catch (\Throwable $e) { $context['exception'] = $e; - $this->logger->warning('An exception occurred while handling message "{class}"', $context); + $this->logger->warning('An exception occurred while handling message "{class}": '.$e->getMessage(), $context); throw $e; } From 94198876d05399807cc0e5e9c32afa411f41fcc5 Mon Sep 17 00:00:00 2001 From: Patrick Landolt Date: Mon, 25 Mar 2019 12:20:53 +0100 Subject: [PATCH 269/495] [Mime] Removed unnecessary strtolower --- src/Symfony/Component/Mime/Header/Headers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Header/Headers.php b/src/Symfony/Component/Mime/Header/Headers.php index f60cd474a6cb1..c0e45e0d0a852 100644 --- a/src/Symfony/Component/Mime/Header/Headers.php +++ b/src/Symfony/Component/Mime/Header/Headers.php @@ -168,7 +168,7 @@ public function add(HeaderInterface $header) public function get(string $name): ?HeaderInterface { $name = strtolower($name); - if (!isset($this->headers[strtolower($name)])) { + if (!isset($this->headers[$name])) { return null; } From e3d42a971caf2356d0ac18a54c14da1abc9aba7a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 25 Mar 2019 12:45:23 +0100 Subject: [PATCH 270/495] fixed missing dot for error message --- src/Symfony/Component/Validator/Constraints/Unique.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Unique.php b/src/Symfony/Component/Validator/Constraints/Unique.php index 391c4eaa13086..743ec02e91d4e 100644 --- a/src/Symfony/Component/Validator/Constraints/Unique.php +++ b/src/Symfony/Component/Validator/Constraints/Unique.php @@ -27,5 +27,5 @@ class Unique extends Constraint self::IS_NOT_UNIQUE => 'IS_NOT_UNIQUE', ]; - public $message = 'This collection should contain only unique elements'; + public $message = 'This collection should contain only unique elements.'; } From f5eaba07986df5705dfec5292eb100ba428d8b75 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 25 Mar 2019 14:49:18 +0100 Subject: [PATCH 271/495] fix lowest deps tests --- .../Form/Tests/Command/DebugCommandTest.php | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php index fd6a8db2ada14..71dedf67eaa48 100644 --- a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php @@ -164,27 +164,27 @@ public function testDebugCustomFormTypeOption() Symfony\Component\Form\Tests\Command\FooType (foo) ================================================== - ---------------- ---------------------------------------------------------------------------%s - Required true %w - ---------------- ---------------------------------------------------------------------------%s - Default - %w - ---------------- ---------------------------------------------------------------------------%s - Allowed types [ %w - "string" %w - ] %w - ---------------- ---------------------------------------------------------------------------%s - Allowed values [ %w - "bar", %w - "baz" %w - ] %w - ---------------- ---------------------------------------------------------------------------%s - Normalizer Closure(Options $options, $value) { %w - class: "Symfony\Component\Form\Tests\Command\FooType" %w - this: Symfony\Component\Form\Tests\Command\FooType { …} %w + ---------------- -----------------------------------------------------------%s + Required true %w + ---------------- -----------------------------------------------------------%s + Default - %w + ---------------- -----------------------------------------------------------%s + Allowed types [ %w + "string" %w + ] %w + ---------------- -----------------------------------------------------------%s + Allowed values [ %w + "bar", %w + "baz" %w + ] %w + ---------------- -----------------------------------------------------------%s + Normalizer Closure(Options $options, $value) { %w + class: "Symfony\Component\Form\Tests\Command\FooType" %w + this: Symfony\Component\Form\Tests\Command\FooType { …} %w file: "%s"%w line: "%d to %d"%w - } %w - ---------------- ---------------------------------------------------------------------------%s + } %w + ---------------- -----------------------------------------------------------%s TXT , $tester->getDisplay(true)); From b8ab296adfbe55fe1a02d4f6b4f5fa2a1e05fae7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 25 Mar 2019 17:39:02 +0100 Subject: [PATCH 272/495] fix typo --- src/Symfony/Component/Workflow/WorkflowEvents.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Workflow/WorkflowEvents.php b/src/Symfony/Component/Workflow/WorkflowEvents.php index dba91f7d2a648..7262be5f7d3f8 100644 --- a/src/Symfony/Component/Workflow/WorkflowEvents.php +++ b/src/Symfony/Component/Workflow/WorkflowEvents.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Workflow; /** - * To learn more about how form events work check the documentation + * To learn more about how workflow events work check the documentation * entry at {@link https://symfony.com/doc/current/workflow/usage.html#using-events}. */ final class WorkflowEvents From 3c3db2f14a8d8dc96581560f8a24ce2f866eabda Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 25 Mar 2019 17:04:58 +0100 Subject: [PATCH 273/495] [Contracts][EventDispatcher] add EventDispatcherInterface to symfony/contracts and use it where possible --- .../Resources/config/services.xml | 1 + .../AutowiringTypes/AutowiredServices.php | 2 +- .../Bundle/FrameworkBundle/composer.json | 2 +- .../EventListener/FirewallListener.php | 2 + .../SecurityDataCollectorTest.php | 2 +- src/Symfony/Component/Console/Application.php | 3 + src/Symfony/Component/Console/composer.json | 2 +- .../Compiler/AutowirePass.php | 11 +--- .../Exception/AutowiringFailedException.php | 4 ++ .../Debug/TraceableEventDispatcher.php | 33 ++++++++--- .../EventDispatcher/Debug/WrappedListener.php | 5 +- .../EventDispatcher/EventDispatcher.php | 18 +++++- .../EventDispatcherInterface.php | 15 +---- .../LegacyEventDispatcherProxy.php | 8 ++- .../Component/EventDispatcher/composer.json | 6 +- .../Component/Form/Test/TypeTestCase.php | 6 +- .../DataCollector/EventDataCollector.php | 2 +- .../Debug/TraceableEventDispatcher.php | 4 +- .../EventListener/ExceptionListener.php | 4 ++ .../Fragment/InlineFragmentRenderer.php | 2 +- .../Component/HttpKernel/HttpKernel.php | 2 +- .../Fragment/InlineFragmentRendererTest.php | 5 +- .../Component/HttpKernel/composer.json | 2 +- .../Command/ConsumeMessagesCommand.php | 2 +- .../Event/AbstractWorkerMessageEvent.php | 3 +- .../Event/SendMessageToTransportsEvent.php | 3 +- .../Middleware/SendMessageMiddleware.php | 2 +- .../Middleware/SendMessageMiddlewareTest.php | 2 +- .../Component/Messenger/Tests/WorkerTest.php | 2 +- src/Symfony/Component/Messenger/Worker.php | 5 +- .../AuthenticationProviderManager.php | 3 + .../Authorization/Voter/TraceableVoter.php | 7 ++- .../Voter/TraceableVoterTest.php | 4 +- .../Component/Security/Core/composer.json | 2 +- .../Guard/GuardAuthenticatorHandler.php | 2 +- .../Tests/GuardAuthenticatorHandlerTest.php | 12 ++-- .../Component/Security/Http/Firewall.php | 2 + .../AbstractAuthenticationListener.php | 2 +- .../AbstractPreAuthenticatedListener.php | 2 +- .../Http/Firewall/ExceptionListener.php | 2 +- .../Http/Firewall/RememberMeListener.php | 2 +- .../RemoteUserAuthenticationListener.php | 2 +- .../Http/Firewall/SwitchUserListener.php | 2 +- ...namePasswordFormAuthenticationListener.php | 2 +- ...namePasswordJsonAuthenticationListener.php | 2 +- .../Firewall/X509AuthenticationListener.php | 2 +- .../Tests/Firewall/RememberMeListenerTest.php | 3 +- .../Tests/Firewall/SwitchUserListenerTest.php | 7 ++- src/Symfony/Component/Security/composer.json | 2 +- .../Component/Workflow/StateMachine.php | 2 +- .../Component/Workflow/Tests/RegistryTest.php | 2 +- src/Symfony/Component/Workflow/Workflow.php | 2 +- src/Symfony/Contracts/CHANGELOG.md | 1 + .../EventDispatcherInterface.php | 58 +++++++++++++++++++ src/Symfony/Contracts/composer.json | 1 + 55 files changed, 196 insertions(+), 92 deletions(-) create mode 100644 src/Symfony/Contracts/EventDispatcher/EventDispatcherInterface.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index b4829942f2ded..7f4f5890fa899 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -49,6 +49,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php index d9a7b59d46ba6..4743460e6ee5b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/AutowiringTypes/AutowiredServices.php @@ -13,7 +13,7 @@ use Doctrine\Common\Annotations\Reader; use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class AutowiredServices { diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 57a7e256234cf..853711aca32cd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -20,7 +20,7 @@ "ext-xml": "*", "symfony/cache": "~4.3", "symfony/config": "~4.2", - "symfony/contracts": "^1.0.2", + "symfony/contracts": "^1.1", "symfony/dependency-injection": "^4.3", "symfony/http-foundation": "^4.3", "symfony/http-kernel": "^4.3", diff --git a/src/Symfony/Bundle/SecurityBundle/EventListener/FirewallListener.php b/src/Symfony/Bundle/SecurityBundle/EventListener/FirewallListener.php index 1a3712c7507c4..3dca451d9ab17 100644 --- a/src/Symfony/Bundle/SecurityBundle/EventListener/FirewallListener.php +++ b/src/Symfony/Bundle/SecurityBundle/EventListener/FirewallListener.php @@ -30,6 +30,8 @@ class FirewallListener extends Firewall public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher, LogoutUrlGenerator $logoutUrlGenerator) { + // the type-hint will be updated to the "EventDispatcherInterface" from symfony/contracts in 5.0 + $this->map = $map; $this->logoutUrlGenerator = $logoutUrlGenerator; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php index 209248cc85bd0..7e583facf7b09 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php @@ -17,7 +17,6 @@ use Symfony\Bundle\SecurityBundle\Security\FirewallConfig; use Symfony\Bundle\SecurityBundle\Security\FirewallMap; use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\RequestEvent; @@ -34,6 +33,7 @@ use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Http\FirewallMapInterface; use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SecurityDataCollectorTest extends TestCase { diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index fcb334a8a1756..667be07b5afd8 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -91,6 +91,9 @@ public function __construct(string $name = 'UNKNOWN', string $version = 'UNKNOWN $this->defaultCommand = 'list'; } + /** + * @final since Symfony 4.3, the type-hint will be updated to the interface from symfony/contracts in 5.0 + */ public function setDispatcher(EventDispatcherInterface $dispatcher) { $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index 8eff5b7458e4c..b8033b2272fec 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0", + "symfony/contracts": "^1.1", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php73": "^1.8" }, diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 6a9c9237682fc..5aa6680e7e01d 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -226,16 +226,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a if ($parameter->isDefaultValueAvailable()) { $value = $parameter->getDefaultValue(); } elseif (!$parameter->allowsNull()) { - if (\function_exists('xdebug_disable')) { - xdebug_disable(); - } - try { - throw new AutowiringFailedException($this->currentId, $failureMessage); - } finally { - if (\function_exists('xdebug_enable')) { - xdebug_enable(); - } - } + throw new AutowiringFailedException($this->currentId, $failureMessage); } } diff --git a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php index be2bd26dcad1d..99a5b17ccd044 100644 --- a/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php +++ b/src/Symfony/Component/DependencyInjection/Exception/AutowiringFailedException.php @@ -23,6 +23,10 @@ public function __construct(string $serviceId, $message = '', int $code = 0, \Ex { $this->serviceId = $serviceId; + if ($message instanceof \Closure && \function_exists('xdebug_is_enabled') && xdebug_is_enabled()) { + $message = $message(); + } + if (!$message instanceof \Closure) { parent::__construct($message, $code, $previous); diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index 0a0dde4230d0d..f40dfa4bef982 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -11,6 +11,7 @@ namespace Symfony\Component\EventDispatcher\Debug; +use Psr\EventDispatcher\StoppableEventInterface; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -133,7 +134,7 @@ public function dispatch($event/*, string $eventName = null*/) $eventName = 1 < \func_num_args() ? \func_get_arg(1) : null; - if ($event instanceof Event) { + if (\is_object($event)) { $eventName = $eventName ?? \get_class($event); } else { @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), E_USER_DEPRECATED); @@ -146,13 +147,13 @@ public function dispatch($event/*, string $eventName = null*/) } } - if (null !== $this->logger && $event->isPropagationStopped()) { + if (null !== $this->logger && ($event instanceof Event || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); } $this->preProcess($eventName); try { - $this->preDispatch($eventName, $event); + $this->beforeDispatch($eventName, $event); try { $e = $this->stopwatch->start($eventName, 'section'); try { @@ -163,7 +164,7 @@ public function dispatch($event/*, string $eventName = null*/) } } } finally { - $this->postDispatch($eventName, $event); + $this->afterDispatch($eventName, $event); } } finally { $this->postProcess($eventName); @@ -262,18 +263,32 @@ public function __call($method, $arguments) /** * Called before dispatching the event. * - * @param string $eventName The event name - * @param Event $event The event + * @param object $event */ - protected function preDispatch($eventName, Event $event) + protected function beforeDispatch(string $eventName, $event) { + $this->preDispatch($eventName, $event); } /** * Called after dispatching the event. * - * @param string $eventName The event name - * @param Event $event The event + * @param object $event + */ + protected function afterDispatch(string $eventName, $event) + { + $this->postDispatch($eventName, $event); + } + + /** + * @deprecated since Symfony 4.3, will be removed in 5.0, use beforeDispatch instead + */ + protected function preDispatch($eventName, Event $event) + { + } + + /** + * @deprecated since Symfony 4.3, will be removed in 5.0, use afterDispatch instead */ protected function postDispatch($eventName, Event $event) { diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index 8aa3f80a76713..5342fc88a1a54 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -11,6 +11,7 @@ namespace Symfony\Component\EventDispatcher\Debug; +use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Stopwatch\Stopwatch; @@ -18,6 +19,8 @@ /** * @author Fabien Potencier + * + * @final since Symfony 4.3: the "Event" type-hint on __invoke() will be replaced by "object" in 5.0 */ class WrappedListener { @@ -120,7 +123,7 @@ public function __invoke(Event $event, $eventName, EventDispatcherInterface $dis $e->stop(); } - if ($event->isPropagationStopped()) { + if (($event instanceof Event || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { $this->stoppedPropagation = true; } } diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 80b3105e6a66c..d6a78d1871cb7 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -11,6 +11,8 @@ namespace Symfony\Component\EventDispatcher; +use Psr\EventDispatcher\StoppableEventInterface; + /** * The EventDispatcherInterface is the central point of Symfony's event listener system. * @@ -48,7 +50,7 @@ public function dispatch($event/*, string $eventName = null*/) { $eventName = 1 < \func_num_args() ? \func_get_arg(1) : null; - if ($event instanceof Event) { + if (\is_object($event)) { $eventName = $eventName ?? \get_class($event); } else { @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), E_USER_DEPRECATED); @@ -223,12 +225,22 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) * * @param callable[] $listeners The event listeners * @param string $eventName The name of the event to dispatch - * @param Event $event The event object to pass to the event handlers/listeners + * @param object $event The event object to pass to the event handlers/listeners + */ + protected function callListeners(iterable $listeners, string $eventName, $event) + { + $this->doDispatch($listeners, $eventName, $event); + } + + /** + * @deprecated since Symfony 4.3, use callListeners() instead */ protected function doDispatch($listeners, $eventName, Event $event) { + $stoppable = $event instanceof Event || $event instanceof StoppableEventInterface; + foreach ($listeners as $listener) { - if ($event->isPropagationStopped()) { + if ($stoppable && $event->isPropagationStopped()) { break; } $listener($event, $eventName, $this); diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php b/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php index 672f5044d720a..ceaa62aeb0472 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcherInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Component\EventDispatcher; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; + /** * The EventDispatcherInterface is the central point of Symfony's event listener system. * Listeners are registered on the manager and events are dispatched through the @@ -18,19 +20,8 @@ * * @author Bernhard Schussek */ -interface EventDispatcherInterface +interface EventDispatcherInterface extends ContractsEventDispatcherInterface { - /** - * Dispatches an event to all registered listeners. - * - * @param Event $event The event to pass to the event handlers/listeners - * @param string|null $eventName The name of the event to dispatch. If not supplied, - * the class of $event should be used instead. - * - * @return Event - */ - public function dispatch($event/*, string $eventName = null*/); - /** * Adds an event listener that listens on the specified events. * diff --git a/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php b/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php index 8539376206bc7..54de7a44386d1 100644 --- a/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php +++ b/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php @@ -11,6 +11,9 @@ namespace Symfony\Component\EventDispatcher; +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; + /** * An helper class to provide BC/FC with the legacy signature of EventDispatcherInterface::dispatch(). * @@ -51,7 +54,7 @@ public function dispatch($event/*, string $eventName = null*/) { $eventName = 1 < \func_num_args() ? \func_get_arg(1) : null; - if ($event instanceof Event) { + if (\is_object($event)) { $eventName = $eventName ?? \get_class($event); } else { @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), E_USER_DEPRECATED); @@ -65,9 +68,10 @@ public function dispatch($event/*, string $eventName = null*/) } $listeners = $this->getListeners($eventName); + $stoppable = $event instanceof Event || $event instanceof StoppableEventInterface; foreach ($listeners as $listener) { - if ($event->isPropagationStopped()) { + if ($stoppable && $event->isPropagationStopped()) { break; } $listener($event, $eventName, $this); diff --git a/src/Symfony/Component/EventDispatcher/composer.json b/src/Symfony/Component/EventDispatcher/composer.json index 6cdc762bc301b..163149f412beb 100644 --- a/src/Symfony/Component/EventDispatcher/composer.json +++ b/src/Symfony/Component/EventDispatcher/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0" + "symfony/contracts": "^1.1" }, "require-dev": { "symfony/dependency-injection": "~3.4|~4.0", @@ -29,6 +29,10 @@ "conflict": { "symfony/dependency-injection": "<3.4" }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, "suggest": { "symfony/dependency-injection": "", "symfony/http-kernel": "" diff --git a/src/Symfony/Component/Form/Test/TypeTestCase.php b/src/Symfony/Component/Form/Test/TypeTestCase.php index 19fb5c32a0739..76074d133fa60 100644 --- a/src/Symfony/Component/Form/Test/TypeTestCase.php +++ b/src/Symfony/Component/Form/Test/TypeTestCase.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Form\Test; -use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait; @@ -25,7 +25,7 @@ abstract class TypeTestCase extends FormIntegrationTestCase protected $builder; /** - * @var EventDispatcher + * @var EventDispatcherInterface */ protected $dispatcher; @@ -33,7 +33,7 @@ private function doSetUp() { parent::setUp(); - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $this->dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $this->builder = new FormBuilder('', null, $this->dispatcher, $this->factory); } diff --git a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php index c0de2509405ed..8e84c6acf6973 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php @@ -13,9 +13,9 @@ use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ResetInterface; /** diff --git a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php index ddf4fa7cecf05..6bd45caa7a02a 100644 --- a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php @@ -27,7 +27,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher /** * {@inheritdoc} */ - protected function preDispatch($eventName, Event $event) + protected function beforeDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::REQUEST: @@ -58,7 +58,7 @@ protected function preDispatch($eventName, Event $event) /** * {@inheritdoc} */ - protected function postDispatch($eventName, Event $event) + protected function afterDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::CONTROLLER_ARGUMENTS: diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php index 9d6d31ea96e64..8e31ecc944e37 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php @@ -54,6 +54,10 @@ public function logKernelException(GetResponseForExceptionEvent $event) $this->logException($event->getException(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine())); } + /** + * @param string $eventName + * @param EventDispatcherInterface $eventDispatcher + */ public function onKernelException(GetResponseForExceptionEvent $event) { if (null === $this->controller) { diff --git a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php index bc397438d2488..7d6243552a7bd 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php @@ -11,7 +11,6 @@ namespace Symfony\Component\HttpKernel\Fragment; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -20,6 +19,7 @@ use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Implements the inline rendering strategy where the Request is rendered by the current HTTP kernel. diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 3de9b0202b530..64e931f2bd40d 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -11,7 +11,6 @@ namespace Symfony\Component\HttpKernel; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpFoundation\Request; @@ -32,6 +31,7 @@ use Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * HttpKernel notifies events to convert a Request object to a Response one. diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php index c8b79e8ff3c9e..d6f0ff7771e2b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -21,6 +21,7 @@ use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class InlineFragmentRendererTest extends TestCase { @@ -73,7 +74,7 @@ public function testRenderWithTrustedHeaderDisabled() */ public function testRenderExceptionNoIgnoreErrors() { - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher->expects($this->never())->method('dispatch'); $strategy = new InlineFragmentRenderer($this->getKernel($this->throwException(new \RuntimeException('foo'))), $dispatcher); @@ -87,7 +88,7 @@ public function testRenderExceptionIgnoreErrors() $kernel = $this->getKernel($this->throwException($exception)); $request = Request::create('/'); $expectedEvent = new ExceptionEvent($kernel, $request, $kernel::SUB_REQUEST, $exception); - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher->expects($this->once())->method('dispatch')->with($expectedEvent, KernelEvents::EXCEPTION); $strategy = new InlineFragmentRenderer($kernel, $dispatcher); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index b250dd30f702f..ca818d16707ab 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0.2", + "symfony/contracts": "^1.1", "symfony/event-dispatcher": "^4.3", "symfony/http-foundation": "^4.1.1", "symfony/debug": "~3.4|~4.0", diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index af916cb785c1c..e49b28705c876 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -20,12 +20,12 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\RoutableMessageBus; use Symfony\Component\Messenger\Transport\Receiver\StopWhenMemoryUsageIsExceededReceiver; use Symfony\Component\Messenger\Transport\Receiver\StopWhenMessageCountIsExceededReceiver; use Symfony\Component\Messenger\Transport\Receiver\StopWhenTimeLimitIsReachedReceiver; use Symfony\Component\Messenger\Worker; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @author Samuel Roze diff --git a/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php b/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php index 0f2b644139394..237f244758ffd 100644 --- a/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php +++ b/src/Symfony/Component/Messenger/Event/AbstractWorkerMessageEvent.php @@ -11,13 +11,12 @@ namespace Symfony\Component\Messenger\Event; -use Symfony\Component\EventDispatcher\Event; use Symfony\Component\Messenger\Envelope; /** * @experimental in 4.3 */ -abstract class AbstractWorkerMessageEvent extends Event +abstract class AbstractWorkerMessageEvent { private $envelope; private $receiverName; diff --git a/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php b/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php index a54622e83cf99..2e11a9209afec 100644 --- a/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php +++ b/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Messenger\Event; -use Symfony\Component\EventDispatcher\Event; use Symfony\Component\Messenger\Envelope; /** @@ -23,7 +22,7 @@ * * @author Ryan Weaver */ -class SendMessageToTransportsEvent extends Event +class SendMessageToTransportsEvent { private $envelope; diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index e389da910cbf9..ba267ae7d2ca5 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -13,13 +13,13 @@ use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Transport\Sender\SendersLocatorInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @author Samuel Roze diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index 8237838a3a0b5..fa2ee76bd5b5c 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Messenger\Tests\Middleware; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; @@ -24,6 +23,7 @@ use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageInterface; use Symfony\Component\Messenger\Transport\Sender\SenderInterface; use Symfony\Component\Messenger\Transport\Sender\SendersLocator; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SendMessageMiddlewareTest extends MiddlewareTestCase { diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php index cd833b223dce2..4ecb7719cbaef 100644 --- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php +++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Messenger\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; @@ -26,6 +25,7 @@ use Symfony\Component\Messenger\Tests\Fixtures\CallbackReceiver; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Worker; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class WorkerTest extends TestCase { diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index 19c5a4b0fafea..72319c014c9ba 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -12,8 +12,6 @@ namespace Symfony\Component\Messenger; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; @@ -25,6 +23,7 @@ use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @author Samuel Roze @@ -141,7 +140,7 @@ public function run() }); } - private function dispatchEvent(Event $event) + private function dispatchEvent($event) { if (null === $this->eventDispatcher) { return; diff --git a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php index fca4add09c3a3..9a64565c523a0 100644 --- a/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php +++ b/src/Symfony/Component/Security/Core/Authentication/AuthenticationProviderManager.php @@ -51,6 +51,9 @@ public function __construct(iterable $providers, bool $eraseCredentials = true) $this->eraseCredentials = $eraseCredentials; } + /** + * @final since Symfony 4.3, the type-hint will be updated to the interface from symfony/contracts in 5.0 + */ public function setEventDispatcher(EventDispatcherInterface $dispatcher) { $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php index 6dbff4466a746..e5ce1f696be36 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php @@ -11,9 +11,10 @@ namespace Symfony\Component\Security\Core\Authorization\Voter; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Event\VoteEvent; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Decorates voter classes to send result events. @@ -30,14 +31,14 @@ class TraceableVoter implements VoterInterface public function __construct(VoterInterface $voter, EventDispatcherInterface $eventDispatcher) { $this->voter = $voter; - $this->eventDispatcher = $eventDispatcher; + $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); } public function vote(TokenInterface $token, $subject, array $attributes) { $result = $this->voter->vote($token, $subject, $attributes); - $this->eventDispatcher->dispatch('debug.security.authorization.vote', new VoteEvent($this->voter, $subject, $attributes, $result)); + $this->eventDispatcher->dispatch(new VoteEvent($this->voter, $subject, $attributes, $result), 'debug.security.authorization.vote'); return $result; } diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/TraceableVoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/TraceableVoterTest.php index 99bf1f6eff90a..53e6a277453f5 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/TraceableVoterTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/TraceableVoterTest.php @@ -12,11 +12,11 @@ namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\TraceableVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; use Symfony\Component\Security\Core\Event\VoteEvent; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class TraceableVoterTest extends TestCase { @@ -44,7 +44,7 @@ public function testVote() $eventDispatcher ->expects($this->once()) ->method('dispatch') - ->with('debug.security.authorization.vote', new VoteEvent($voter, 'anysubject', ['attr1'], VoterInterface::ACCESS_DENIED)); + ->with(new VoteEvent($voter, 'anysubject', ['attr1'], VoterInterface::ACCESS_DENIED), 'debug.security.authorization.vote'); $sut = new TraceableVoter($voter, $eventDispatcher); $result = $sut->vote($token, 'anysubject', ['attr1']); diff --git a/src/Symfony/Component/Security/Core/composer.json b/src/Symfony/Component/Security/Core/composer.json index 42691b86c38aa..05c1c3dbbe835 100644 --- a/src/Symfony/Component/Security/Core/composer.json +++ b/src/Symfony/Component/Security/Core/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0" + "symfony/contracts": "^1.1" }, "require-dev": { "psr/container": "^1.0", diff --git a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php index 780dd93b44049..f146f59fd685e 100644 --- a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php +++ b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Security\Guard; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -22,6 +21,7 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * A utility class that does much of the *work* during the guard authentication process. diff --git a/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php b/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php index 9b513c42f941c..8cca27f875fae 100644 --- a/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php +++ b/src/Symfony/Component/Security/Guard/Tests/GuardAuthenticatorHandlerTest.php @@ -14,11 +14,15 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Guard\AuthenticatorInterface; use Symfony\Component\Security\Guard\GuardAuthenticatorHandler; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class GuardAuthenticatorHandlerTest extends TestCase { @@ -158,11 +162,11 @@ public function testSessionStrategyIsNotCalledWhenStateless() protected function setUp() { - $this->tokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface')->getMock(); - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock(); + $this->tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock(); + $this->dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); + $this->token = $this->getMockBuilder(TokenInterface::class)->getMock(); $this->request = new Request([], [], [], [], [], []); - $this->sessionStrategy = $this->getMockBuilder('Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface')->getMock(); + $this->sessionStrategy = $this->getMockBuilder(SessionAuthenticationStrategyInterface::class)->getMock(); $this->guardAuthenticator = $this->getMockBuilder(AuthenticatorInterface::class)->getMock(); } diff --git a/src/Symfony/Component/Security/Http/Firewall.php b/src/Symfony/Component/Security/Http/Firewall.php index bff8e3e884c49..7cd51ce21e872 100644 --- a/src/Symfony/Component/Security/Http/Firewall.php +++ b/src/Symfony/Component/Security/Http/Firewall.php @@ -38,6 +38,8 @@ class Firewall implements EventSubscriberInterface public function __construct(FirewallMapInterface $map, EventDispatcherInterface $dispatcher) { + // the type-hint will be updated to the "EventDispatcherInterface" from symfony/contracts in 5.0 + $this->map = $map; $this->dispatcher = $dispatcher; $this->exceptionListeners = new \SplObjectStorage(); diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php index 06a3b2d2a7eb3..58e188cc4c567 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -31,6 +30,7 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * The AbstractAuthenticationListener is the preferred base class for all diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php index 60817ecd1c63d..500ae43e498bd 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\RequestEvent; @@ -25,6 +24,7 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * AbstractPreAuthenticatedListener is the base class for all listener that diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index bfd4d5be298a4..76a5a9107b4c2 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -39,7 +39,7 @@ * * @author Fabien Potencier * - * @final since Symfony 4.3 + * @final since Symfony 4.3, EventDispatcherInterface type-hints will be updated to the interface from symfony/contracts in 5.0 */ class ExceptionListener { diff --git a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php index 16073859f85b6..ebc03db862952 100644 --- a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; @@ -23,6 +22,7 @@ use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * RememberMeListener implements authentication capabilities via a cookie. diff --git a/src/Symfony/Component/Security/Http/Firewall/RemoteUserAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/RemoteUserAuthenticationListener.php index d384b2f286179..592e0127e5122 100644 --- a/src/Symfony/Component/Security/Http/Firewall/RemoteUserAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/RemoteUserAuthenticationListener.php @@ -12,11 +12,11 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * REMOTE_USER authentication listener. diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 092b334ae6ff6..c94eb7e89b380 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -30,6 +29,7 @@ use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Event\SwitchUserEvent; use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * SwitchUserListener allows a user to impersonate another one temporarily diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 2b8ab8d09f578..4cc0677af86c5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; @@ -28,6 +27,7 @@ use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\ParameterBagUtils; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * UsernamePasswordFormAuthenticationListener is the default implementation of diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php index 90a8225b35dca..ab991572f11cf 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -35,6 +34,7 @@ use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * UsernamePasswordJsonAuthenticationListener is a stateless implementation of diff --git a/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php index 2d3c26f28c3cd..fc770ae936fb2 100644 --- a/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/X509AuthenticationListener.php @@ -12,11 +12,11 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * X509 authentication listener. diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php index fe237e3dbf043..1be9bf88e22f7 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Firewall\RememberMeListener; use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class RememberMeListenerTest extends TestCase { @@ -447,7 +448,7 @@ protected function getTokenStorage() protected function getDispatcher() { - return $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + return $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); } private function getSessionStrategy() diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index c8b3ed245cb67..6fd60c0c02bbd 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -23,6 +23,7 @@ use Symfony\Component\Security\Http\Event\SwitchUserEvent; use Symfony\Component\Security\Http\Firewall\SwitchUserListener; use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class SwitchUserListenerTest extends TestCase { @@ -138,7 +139,7 @@ public function testExitUserDispatchesEventWithRefreshedUser() $this->tokenStorage->setToken(new SwitchUserToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)], $originalToken)); $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher ->expects($this->once()) ->method('dispatch') @@ -165,7 +166,7 @@ public function testExitUserDoesNotDispatchEventWithStringUser() $this->tokenStorage->setToken(new SwitchUserToken('username', '', 'key', [new SwitchUserRole('ROLE_PREVIOUS', $originalToken, false)], $originalToken)); $this->request->query->set('_switch_user', SwitchUserListener::EXIT_VALUE); - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher ->expects($this->never()) ->method('dispatch') @@ -267,7 +268,7 @@ public function testSwitchUserWithReplacedToken() ->method('loadUserByUsername')->with('kuba') ->will($this->returnValue($user)); - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher ->expects($this->once()) ->method('dispatch') diff --git a/src/Symfony/Component/Security/composer.json b/src/Symfony/Component/Security/composer.json index fddc5165910f2..7a0e0c23107c3 100644 --- a/src/Symfony/Component/Security/composer.json +++ b/src/Symfony/Component/Security/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0", + "symfony/contracts": "^1.1", "symfony/http-foundation": "~3.4|~4.0", "symfony/http-kernel": "^4.3", "symfony/property-access": "~3.4|~4.0" diff --git a/src/Symfony/Component/Workflow/StateMachine.php b/src/Symfony/Component/Workflow/StateMachine.php index ad6a26c2d883c..c9f88a022bfe6 100644 --- a/src/Symfony/Component/Workflow/StateMachine.php +++ b/src/Symfony/Component/Workflow/StateMachine.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Workflow; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @author Tobias Nyholm diff --git a/src/Symfony/Component/Workflow/Tests/RegistryTest.php b/src/Symfony/Component/Workflow/Tests/RegistryTest.php index 867046f7c5db3..a13c43549758e 100644 --- a/src/Symfony/Component/Workflow/Tests/RegistryTest.php +++ b/src/Symfony/Component/Workflow/Tests/RegistryTest.php @@ -3,13 +3,13 @@ namespace Symfony\Component\Workflow\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; use Symfony\Component\Workflow\Registry; use Symfony\Component\Workflow\SupportStrategy\SupportStrategyInterface; use Symfony\Component\Workflow\SupportStrategy\WorkflowSupportStrategyInterface; use Symfony\Component\Workflow\Workflow; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class RegistryTest extends TestCase { diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index ca6b8f229115a..188d69e7d3c25 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Workflow; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\Workflow\Event\AnnounceEvent; use Symfony\Component\Workflow\Event\CompletedEvent; @@ -26,6 +25,7 @@ use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; use Symfony\Component\Workflow\Metadata\MetadataStoreInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * @author Fabien Potencier diff --git a/src/Symfony/Contracts/CHANGELOG.md b/src/Symfony/Contracts/CHANGELOG.md index b37bc2a705314..b5f1d76aecda5 100644 --- a/src/Symfony/Contracts/CHANGELOG.md +++ b/src/Symfony/Contracts/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * added `HttpClient` namespace with contracts for implementing flexible HTTP clients + * added `EventDispatcher\EventDispatcherInterface` 1.0.0 ----- diff --git a/src/Symfony/Contracts/EventDispatcher/EventDispatcherInterface.php b/src/Symfony/Contracts/EventDispatcher/EventDispatcherInterface.php new file mode 100644 index 0000000000000..9b1a69add2336 --- /dev/null +++ b/src/Symfony/Contracts/EventDispatcher/EventDispatcherInterface.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; + +if (interface_exists(PsrEventDispatcherInterface::class)) { + /** + * Allows providing hooks on domain-specific lifecycles by dispatching events. + */ + interface EventDispatcherInterface extends PsrEventDispatcherInterface + { + /** + * Dispatches an event to all registered listeners. + * + * For BC with Symfony 4, the $eventName argument is not declared explicitly on the + * signature of the method. Implementations that are not bound by this BC contraint + * MUST declare it explicitly, as allowed by PHP. + * + * @param object $event The event to pass to the event handlers/listeners + * @param string|null $eventName The name of the event to dispatch. If not supplied, + * the class of $event should be used instead. + * + * @return object The passed $event MUST be returned + */ + public function dispatch($event/*, string $eventName = null*/); + } +} else { + /** + * Allows providing hooks on domain-specific lifecycles by dispatching events. + */ + interface EventDispatcherInterface + { + /** + * Dispatches an event to all registered listeners. + * + * For BC with Symfony 4, the $eventName argument is not declared explicitly on the + * signature of the method. Implementations that are not bound by this BC contraint + * MUST declare it explicitly, as allowed by PHP. + * + * @param object $event The event to pass to the event handlers/listeners + * @param string|null $eventName The name of the event to dispatch. If not supplied, + * the class of $event should be used instead. + * + * @return object The passed $event MUST be returned + */ + public function dispatch($event/*, string $eventName = null*/); + } +} diff --git a/src/Symfony/Contracts/composer.json b/src/Symfony/Contracts/composer.json index f881258dc1a4a..b83e7c0535cfc 100644 --- a/src/Symfony/Contracts/composer.json +++ b/src/Symfony/Contracts/composer.json @@ -27,6 +27,7 @@ "psr/cache": "When using the Cache contracts", "psr/container": "When using the Service contracts", "symfony/cache-contracts-implementation": "", + "symfony/event-dispatcher-implementation": "", "symfony/http-client-contracts-implementation": "", "symfony/service-contracts-implementation": "", "symfony/translation-contracts-implementation": "" From 226dbbc54fd61c5db7274c11cf3cc75ad715cead Mon Sep 17 00:00:00 2001 From: Gregor Harlan Date: Tue, 26 Mar 2019 00:17:13 +0100 Subject: [PATCH 274/495] [Contracts] fix phpdoc for http-client (user_data) --- src/Symfony/Contracts/HttpClient/HttpClientInterface.php | 2 +- src/Symfony/Contracts/HttpClient/ResponseInterface.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php index 194a8fb8afeea..d30d0822646d2 100644 --- a/src/Symfony/Contracts/HttpClient/HttpClientInterface.php +++ b/src/Symfony/Contracts/HttpClient/HttpClientInterface.php @@ -39,7 +39,7 @@ interface HttpClientInterface // the JSON-encoded value and set the "content-type" headers to a JSON-compatible // value it is they are not defined - typically "application/json" 'user_data' => null, // mixed - any extra data to attach to the request (scalar, callable, object...) that - // MUST be available via $response->getInfo('data') - not used internally + // MUST be available via $response->getInfo('user_data') - not used internally 'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower or equal to 0 means // redirects should not be followed; "Authorization" and "Cookie" headers MUST // NOT follow except for the initial host name diff --git a/src/Symfony/Contracts/HttpClient/ResponseInterface.php b/src/Symfony/Contracts/HttpClient/ResponseInterface.php index 549bfcda3f18c..03cc6a2be29c0 100644 --- a/src/Symfony/Contracts/HttpClient/ResponseInterface.php +++ b/src/Symfony/Contracts/HttpClient/ResponseInterface.php @@ -86,7 +86,7 @@ public function toArray(bool $throw = true): array; * - http_method - the HTTP verb of the last request * - http_code - the last response code or 0 when it is not known yet * - error - the error message when the transfer was aborted, null otherwise - * - data - the value of the "data" request option, null if not set + * - user_data - the value of the "user_data" request option, null if not set * - url - the last effective URL of the request * * When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain" From 6eddb52333c3a974f5a95caf85c711c50c53f0ad Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 26 Mar 2019 01:54:03 +0100 Subject: [PATCH 275/495] [HttpClient] Fix missing use statement --- src/Symfony/Component/HttpClient/Response/ResponseTrait.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 7429547293303..cc8c7b439ffa9 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpClient\Chunk\DataChunk; use Symfony\Component\HttpClient\Chunk\ErrorChunk; +use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Chunk\LastChunk; use Symfony\Component\HttpClient\Exception\ClientException; use Symfony\Component\HttpClient\Exception\JsonException; From 3ac6bf9f2403a9db4a39a82cc3927415500b65e0 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 24 Mar 2019 22:13:23 -0400 Subject: [PATCH 276/495] Avoid dispatching SendMessageToTransportsEvent on redeliver This purpose of this event is to be a hook when a message is sent to a transport. If that message is redelivered later, that's not the purpose of this hook (there are Worker events for that) and could cause problems if the user unknowingly tries to modify the Envelope in some way, not thinking about how this might be a redelivery message. --- .../Event/SendMessageToTransportsEvent.php | 2 ++ .../Middleware/SendMessageMiddleware.php | 19 ++++++------ .../Middleware/SendMessageMiddlewareTest.php | 29 ++++++++++++++++++- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php b/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php index a54622e83cf99..e0f3a07137aa5 100644 --- a/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php +++ b/src/Symfony/Component/Messenger/Event/SendMessageToTransportsEvent.php @@ -20,6 +20,8 @@ * The event is *only* dispatched if the message will actually * be sent to at least one transport. If the message is sent * to multiple transports, the message is dispatched only one time. + * This message is only dispatched the first time a message + * is sent to a transport, not also if it is retried. * * @author Ryan Weaver */ diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index e389da910cbf9..b4b50f9e892d3 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -62,20 +62,21 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope /** @var RedeliveryStamp|null $redeliveryStamp */ $redeliveryStamp = $envelope->last(RedeliveryStamp::class); - $senders = \iterator_to_array($this->sendersLocator->getSenders($envelope, $handle)); - - if (null !== $this->eventDispatcher && \count($senders) > 0) { - $event = new SendMessageToTransportsEvent($envelope); - $this->eventDispatcher->dispatch($event); - $envelope = $event->getEnvelope(); - } - - foreach ($senders as $alias => $sender) { + // dispatch event unless this is a redelivery + $shouldDispatchEvent = null === $redeliveryStamp; + foreach ($this->sendersLocator->getSenders($envelope, $handle) as $alias => $sender) { // on redelivery, only deliver to the given sender if (null !== $redeliveryStamp && !$redeliveryStamp->shouldRedeliverToSender(\get_class($sender), $alias)) { continue; } + if (null !== $this->eventDispatcher && $shouldDispatchEvent) { + $event = new SendMessageToTransportsEvent($envelope); + $this->eventDispatcher->dispatch($event); + $envelope = $event->getEnvelope(); + $shouldDispatchEvent = false; + } + $this->logger->info('Sending message "{class}" with "{sender}"', $context + ['sender' => \get_class($sender)]); $envelope = $sender->send($envelope->with(new SentStamp(\get_class($sender), \is_string($alias) ? $alias : null))); } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index 8237838a3a0b5..0a23a0dbba5c3 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -205,7 +205,7 @@ public function testItSkipsReceivedMessages() $this->assertNull($envelope->last(SentStamp::class), 'it does not add sent stamp for received messages'); } - public function testItDispatchesTheEventOnceTime() + public function testItDispatchesTheEventOneTime() { $envelope = new Envelope(new DummyMessage('original envelope')); @@ -224,4 +224,31 @@ public function testItDispatchesTheEventOnceTime() $middleware->handle($envelope, $this->getStackMock(false)); } + + public function testItDoesNotDispatchWithNoSenders() + { + $envelope = new Envelope(new DummyMessage('original envelope')); + + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $dispatcher->expects($this->never())->method('dispatch'); + + $middleware = new SendMessageMiddleware(new SendersLocator([]), $dispatcher); + + $middleware->handle($envelope, $this->getStackMock()); + } + + public function testItDoesNotDispatchOnRetry() + { + $envelope = new Envelope(new DummyMessage('original envelope')); + $envelope = $envelope->with(new RedeliveryStamp(3, 'foo_sender')); + + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $dispatcher->expects($this->never())->method('dispatch'); + + $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); + + $middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender]]), $dispatcher); + + $middleware->handle($envelope, $this->getStackMock(false)); + } } From 6263e4839244f8c7c5eabda70c40647ab464c207 Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 26 Mar 2019 11:03:16 +0100 Subject: [PATCH 277/495] [Messenger] rename `auto-setup` amqp option into `auto_setup` --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- .../Messenger/Tests/Transport/AmqpExt/ConnectionTest.php | 6 +++--- .../Component/Messenger/Transport/AmqpExt/Connection.php | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 54c32c1618ddd..24641be9f2d37 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -49,7 +49,7 @@ CHANGELOG both no longer have `$isDebug` arguments. * [BC BREAK] The Amqp Transport now automatically sets up the exchanges and queues by default. Previously, this was done when in "debug" mode - only. Pass the `auto-setup` connection option to control this. + only. Pass the `auto_setup` connection option to control this. 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index e29ee083319d9..56c249924f696 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -228,13 +228,13 @@ public function testItCanDisableTheSetup() $amqpQueue->expects($this->never())->method('declareQueue'); $amqpQueue->expects($this->never())->method('bind'); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', ['auto-setup' => 'false'], $factory); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', ['auto_setup' => 'false'], $factory); $connection->publish('body'); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', ['auto-setup' => false], $factory); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', ['auto_setup' => false], $factory); $connection->publish('body'); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key&auto-setup=false', [], $factory); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key&auto_setup=false', [], $factory); $connection->publish('body'); } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 18f620c4543f8..87515c914dda2 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -82,7 +82,7 @@ class Connection * * routing_key_pattern: The pattern of the routing key (Default: "delay_%delay%") * * queue_name_pattern: Pattern to use to create the queues (Default: "delay_queue_%delay%") * * exchange_name: Name of the exchange to be used for the retried messages (Default: "retry") - * * auto-setup: Enable or not the auto-setup of queues and exchanges (Default: true) + * * auto_setup: Enable or not the auto-setup of queues and exchanges (Default: true) * * loop_sleep: Amount of micro-seconds to wait if no message are available (Default: 200000) */ public function __construct(array $connectionConfiguration, array $exchangeConfiguration, array $queueConfiguration, AmqpFactory $amqpFactory = null) @@ -373,11 +373,11 @@ private function clear(): void private function shouldSetup(): bool { - if (!\array_key_exists('auto-setup', $this->connectionConfiguration)) { + if (!\array_key_exists('auto_setup', $this->connectionConfiguration)) { return true; } - if (\in_array($this->connectionConfiguration['auto-setup'], [false, 'false'], true)) { + if (\in_array($this->connectionConfiguration['auto_setup'], [false, 'false'], true)) { return false; } From 131e4952698046cd39f80cc7d1d9d733f8a3bb4c Mon Sep 17 00:00:00 2001 From: Marko Kaznovac Date: Sun, 24 Mar 2019 14:40:33 +0100 Subject: [PATCH 278/495] [Validator] BIC remove unused sprintf and parameter --- src/Symfony/Component/Validator/Constraints/Bic.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/Bic.php b/src/Symfony/Component/Validator/Constraints/Bic.php index 9637d9576afa8..c0eeade9a9d48 100644 --- a/src/Symfony/Component/Validator/Constraints/Bic.php +++ b/src/Symfony/Component/Validator/Constraints/Bic.php @@ -53,7 +53,7 @@ public function __construct($options = null) } if (isset($options['iban']) && isset($options['ibanPropertyPath'])) { - throw new ConstraintDefinitionException(sprintf('The "iban" and "ibanPropertyPath" options of the Iban constraint cannot be used at the same time.', self::class)); + throw new ConstraintDefinitionException('The "iban" and "ibanPropertyPath" options of the Iban constraint cannot be used at the same time.'); } if (isset($options['ibanPropertyPath']) && !class_exists(PropertyAccess::class)) { From 2311437c9f20d6bd1eb57b8bd221d129fb6299cb Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Mon, 2 Jul 2018 20:21:13 +0200 Subject: [PATCH 279/495] [DI] Deprecate non-string default envs --- UPGRADE-4.3.md | 17 ++++++++++ UPGRADE-5.0.md | 17 ++++++++++ .../DependencyInjection/CHANGELOG.md | 1 + .../EnvPlaceholderParameterBag.php | 13 ++++++-- .../ValidateEnvPlaceholdersPassTest.php | 28 +++++++++++++--- .../EnvPlaceholderParameterBagTest.php | 32 +++++++++++++++++++ 6 files changed, 102 insertions(+), 6 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 5bd139fc93114..e60f75789dea6 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -21,6 +21,23 @@ Config * Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` +DependencyInjection +------------------- + + * Deprecated support for non-string default env() parameters + + Before: + ```yaml + parameters: + env(NAME): 1.5 + ``` + + After: + ```yaml + parameters: + env(NAME): '1.5' + ``` + EventDispatcher --------------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index f886a94e68fa4..ec6f60951ec61 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -72,6 +72,23 @@ EventDispatcher * The `TraceableEventDispatcherInterface` has been removed. * The signature of the `EventDispatcherInterface::dispatch()` method has been updated to `dispatch($event, string $eventName = null)` +DependencyInjection +------------------- + + * Removed support for non-string default env() parameters + + Before: + ```yaml + parameters: + env(NAME): 1.5 + ``` + + After: + ```yaml + parameters: + env(NAME): '1.5' + ``` + Filesystem ---------- diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 9935b8a58052a..edc6ddf11577a 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * added `ReverseContainer`: a container that turns services back to their ids * added ability to define an index for a tagged collection * added ability to define an index for services in an injected service locator argument + * deprecated support for non-string default env() parameters 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php index 1a15793380637..200351bf42551 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php @@ -49,8 +49,11 @@ public function get($name) if ($this->has($name)) { $defaultValue = parent::get($name); - if (null !== $defaultValue && !is_scalar($defaultValue)) { + if (null !== $defaultValue && !is_scalar($defaultValue)) { // !is_string in 5.0 + //throw new RuntimeException(sprintf('The default value of an env() parameter must be a string or null, but "%s" given to "%s".', \gettype($defaultValue), $name)); throw new RuntimeException(sprintf('The default value of an env() parameter must be scalar or null, but "%s" given to "%s".', \gettype($defaultValue), $name)); + } elseif (is_scalar($defaultValue) && !\is_string($defaultValue)) { + @trigger_error(sprintf('A non-string default value of an env() parameter is deprecated since 4.3, cast "%s" to string instead.', $name), E_USER_DEPRECATED); } } @@ -147,9 +150,15 @@ public function resolve() continue; } if (is_numeric($default = $this->parameters[$name])) { + if (!\is_string($default)) { + @trigger_error(sprintf('A non-string default value of env parameter "%s" is deprecated since 4.3, cast it to string instead.', $env), E_USER_DEPRECATED); + } $this->parameters[$name] = (string) $default; - } elseif (null !== $default && !is_scalar($default)) { + } elseif (null !== $default && !is_scalar($default)) { // !is_string in 5.0 + //throw new RuntimeException(sprintf('The default value of env parameter "%s" must be a string or null, %s given.', $env, \gettype($default))); throw new RuntimeException(sprintf('The default value of env parameter "%s" must be scalar or null, %s given.', $env, \gettype($default))); + } elseif (is_scalar($default) && !\is_string($default)) { + @trigger_error(sprintf('A non-string default value of env parameter "%s" is deprecated since 4.3, cast it to string instead.', $env), E_USER_DEPRECATED); } } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php index 22950f34550a5..cd1a47a1076b2 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php @@ -27,13 +27,14 @@ public function testEnvsAreValidatedInConfig() { $container = new ContainerBuilder(); $container->setParameter('env(NULLED)', null); - $container->setParameter('env(FLOATISH)', 3.2); + $container->setParameter('env(FLOATISH)', '3.2'); $container->registerExtension($ext = new EnvExtension()); $container->prependExtensionConfig('env_extension', $expected = [ 'scalar_node' => '%env(NULLED)%', 'scalar_node_not_empty' => '%env(FLOATISH)%', 'int_node' => '%env(int:FOO)%', 'float_node' => '%env(float:BAR)%', + 'string_node' => '%env(UNDEFINED)%', ]); $this->doProcess($container); @@ -41,6 +42,26 @@ public function testEnvsAreValidatedInConfig() $this->assertSame($expected, $container->resolveEnvPlaceholders($ext->getConfig())); } + /** + * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException + * @expectedExceptionMessage Invalid configuration for path "env_extension.string_node": "fail" is not a valid string + */ + public function testDefaultEnvIsValidatedInConfig() + { + $container = new ContainerBuilder(); + $container->setParameter('env(STRING)', 'fail'); + $container->registerExtension($ext = new EnvExtension()); + $container->prependExtensionConfig('env_extension', $expected = [ + 'string_node' => '%env(STRING)%', + ]); + + $this->doProcess($container); + } + + /** + * @group legacy + * @expectedDeprecation A non-string default value of an env() parameter is deprecated since 4.3, cast "env(FLOATISH)" to string instead. + */ public function testDefaultEnvWithoutPrefixIsValidatedInConfig() { $container = new ContainerBuilder(); @@ -48,7 +69,6 @@ public function testDefaultEnvWithoutPrefixIsValidatedInConfig() $container->registerExtension($ext = new EnvExtension()); $container->prependExtensionConfig('env_extension', $expected = [ 'float_node' => '%env(FLOATISH)%', - 'string_node' => '%env(UNDEFINED)%', ]); $this->doProcess($container); @@ -357,9 +377,9 @@ public function getConfigTreeBuilder() ->scalarNode('string_node') ->validate() ->ifTrue(function ($value) { - return !\is_string($value); + return !\is_string($value) || 'fail' === $value; }) - ->thenInvalid('%s is not a string') + ->thenInvalid('%s is not a valid string') ->end() ->end() ->end(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php b/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php index e7c88d2bb58ec..b245823f670d4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php @@ -111,6 +111,10 @@ public function testMergeWithDifferentIdentifiersForPlaceholders() $this->assertCount(2, $merged[$envName]); } + /** + * @group legacy + * @expectedDeprecation A non-string default value of env parameter "INT_VAR" is deprecated since 4.3, cast it to string instead. + */ public function testResolveEnvCastsIntToString() { $bag = new EnvPlaceholderParameterBag(); @@ -120,6 +124,34 @@ public function testResolveEnvCastsIntToString() $this->assertSame('2', $bag->all()['env(INT_VAR)']); } + /** + * @group legacy + * @expectedDeprecation A non-string default value of an env() parameter is deprecated since 4.3, cast "env(INT_VAR)" to string instead. + * @expectedDeprecation A non-string default value of env parameter "INT_VAR" is deprecated since 4.3, cast it to string instead. + */ + public function testGetDefaultScalarEnv() + { + $bag = new EnvPlaceholderParameterBag(); + $bag->set('env(INT_VAR)', 2); + $this->assertStringMatchesFormat('env_%s_INT_VAR_%s', $bag->get('env(INT_VAR)')); + $this->assertSame(2, $bag->all()['env(INT_VAR)']); + $bag->resolve(); + $this->assertStringMatchesFormat('env_%s_INT_VAR_%s', $bag->get('env(INT_VAR)')); + $this->assertSame('2', $bag->all()['env(INT_VAR)']); + } + + public function testGetDefaultEnv() + { + $bag = new EnvPlaceholderParameterBag(); + $this->assertStringMatchesFormat('env_%s_INT_VAR_%s', $bag->get('env(INT_VAR)')); + $bag->set('env(INT_VAR)', '2'); + $this->assertStringMatchesFormat('env_%s_INT_VAR_%s', $bag->get('env(INT_VAR)')); + $this->assertSame('2', $bag->all()['env(INT_VAR)']); + $bag->resolve(); + $this->assertStringMatchesFormat('env_%s_INT_VAR_%s', $bag->get('env(INT_VAR)')); + $this->assertSame('2', $bag->all()['env(INT_VAR)']); + } + public function testResolveEnvAllowsNull() { $bag = new EnvPlaceholderParameterBag(); From fbb534a8385e42c43c34f36358a65c75f256c200 Mon Sep 17 00:00:00 2001 From: Vincent Touzet Date: Wed, 21 Nov 2018 22:50:37 +0100 Subject: [PATCH 280/495] [Messenger] Add a command to setup transports --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../FrameworkExtension.php | 1 + .../Resources/config/console.xml | 7 ++ src/Symfony/Component/Messenger/CHANGELOG.md | 2 + .../Command/SetupTransportsCommand.php | 80 ++++++++++++++++ .../DependencyInjection/MessengerPass.php | 13 ++- .../Command/SetupTransportsCommandTest.php | 92 +++++++++++++++++++ .../DependencyInjection/MessengerPassTest.php | 17 ++++ .../Transport/AmqpExt/AmqpTransport.php | 11 ++- .../Transport/SetupableTransportInterface.php | 23 +++++ 10 files changed, 242 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php create mode 100644 src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php create mode 100644 src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 7ecd3acd76d1d..d993fbe2584a2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -19,6 +19,7 @@ CHANGELOG * Added support for Translator paths, Twig paths in translation commands. * Added support for PHP files with translations in translation commands. * Added support for boolean container parameters within routes. + * Added the `messenger:setup-transports` command to setup messenger transports 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index fa505bbb0cf67..4ed9cbb8a20cf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -279,6 +279,7 @@ public function load(array $configs, ContainerBuilder $container) } else { $container->removeDefinition('console.command.messenger_consume_messages'); $container->removeDefinition('console.command.messenger_debug'); + $container->removeDefinition('console.command.messenger_setup_transports'); } $this->registerValidationConfiguration($config['validation'], $container, $loader); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 35d9f813c4223..6ae1cb8cc306d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -89,6 +89,13 @@ + + + + + + + diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 24641be9f2d37..cb0b734f9fe72 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -51,6 +51,8 @@ CHANGELOG and queues by default. Previously, this was done when in "debug" mode only. Pass the `auto_setup` connection option to control this. + * Added a `SetupTransportsCommand` command to setup the transports + 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php b/src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php new file mode 100644 index 0000000000000..1adac92a25419 --- /dev/null +++ b/src/Symfony/Component/Messenger/Command/SetupTransportsCommand.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Container\ContainerInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; + +/** + * @author Vincent Touzet + */ +class SetupTransportsCommand extends Command +{ + protected static $defaultName = 'messenger:setup-transports'; + + private $transportLocator; + private $transportNames; + + public function __construct(ContainerInterface $transportLocator, array $transportNames = []) + { + $this->transportLocator = $transportLocator; + $this->transportNames = $transportNames; + + parent::__construct(); + } + + protected function configure() + { + $this + ->addArgument('transport', InputArgument::OPTIONAL, 'Name of the transport to setup', null) + ->setHelp(<<%command.name% command setups the transports: + + php %command.full_name% + +Or a specific transport only: + + php %command.full_name% +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output); + + $transportNames = $this->transportNames; + // do we want to setup only one transport? + if ($transport = $input->getArgument('transport')) { + if (!$this->transportLocator->has($transport)) { + throw new \RuntimeException(sprintf('The "%s" transport does not exist.', $transport)); + } + $transportNames = [$transport]; + } + + foreach ($transportNames as $id => $transportName) { + $transport = $this->transportLocator->get($transportName); + if ($transport instanceof SetupableTransportInterface) { + $transport->setup(); + $io->success(sprintf('The "%s" transport was setup successfully.', $transportName)); + } else { + $io->note(sprintf('The "%s" transport does not support setup.', $transportName)); + } + } + } +} diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index 92ddfc2d4a3ce..fc0252e64b02a 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -236,11 +236,11 @@ private function registerReceivers(ContainerBuilder $container, array $busIds) } } + $receiverNames = []; + foreach ($receiverMapping as $name => $reference) { + $receiverNames[(string) $reference] = $name; + } if ($container->hasDefinition('console.command.messenger_consume_messages')) { - $receiverNames = []; - foreach ($receiverMapping as $name => $reference) { - $receiverNames[(string) $reference] = $name; - } $buses = []; foreach ($busIds as $busId) { $buses[$busId] = new Reference($busId); @@ -251,6 +251,11 @@ private function registerReceivers(ContainerBuilder $container, array $busIds) ->replaceArgument(3, array_values($receiverNames)); } + if ($container->hasDefinition('console.command.messenger_setup_transports')) { + $container->getDefinition('console.command.messenger_setup_transports') + ->replaceArgument(1, array_values($receiverNames)); + } + $container->getDefinition('messenger.receiver_locator')->replaceArgument(0, $receiverMapping); } diff --git a/src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php new file mode 100644 index 0000000000000..48df2782bdb6e --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Command/SetupTransportsCommandTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Command; + +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +class SetupTransportsCommandTest extends TestCase +{ + public function testReceiverNames() + { + // mock a service locator + /** @var MockObject|ServiceLocator $serviceLocator */ + $serviceLocator = $this->createMock(ServiceLocator::class); + // get method must be call twice and will return consecutively a setup-able transport and a non setup-able transport + $serviceLocator->expects($this->exactly(2)) + ->method('get') + ->will($this->onConsecutiveCalls( + $this->createMock(SetupableTransportInterface::class), + $this->createMock(TransportInterface::class) + )); + $serviceLocator + ->method('has') + ->willReturn(true); + + $command = new SetupTransportsCommand($serviceLocator, ['amqp', 'other_transport']); + $tester = new CommandTester($command); + $tester->execute([]); + $display = $tester->getDisplay(); + + $this->assertContains('The "amqp" transport was setup successfully.', $display); + $this->assertContains('The "other_transport" transport does not support setup.', $display); + } + + public function testReceiverNameArgument() + { + // mock a service locator + /** @var MockObject|ServiceLocator $serviceLocator */ + $serviceLocator = $this->createMock(ServiceLocator::class); + // get method must be call twice and will return consecutively a setup-able transport and a non setup-able transport + $serviceLocator->expects($this->exactly(1)) + ->method('get') + ->will($this->onConsecutiveCalls( + $this->createMock(SetupableTransportInterface::class) + )); + $serviceLocator->expects($this->exactly(1)) + ->method('has') + ->willReturn(true); + + $command = new SetupTransportsCommand($serviceLocator, ['amqp', 'other_transport']); + $tester = new CommandTester($command); + $tester->execute(['transport' => 'amqp']); + $display = $tester->getDisplay(); + + $this->assertContains('The "amqp" transport was setup successfully.', $display); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage The "not_found" transport does not exist. + */ + public function testReceiverNameArgumentNotFound() + { + // mock a service locator + /** @var MockObject|ServiceLocator $serviceLocator */ + $serviceLocator = $this->createMock(ServiceLocator::class); + // get method must be call twice and will return consecutively a setup-able transport and a non setup-able transport + $serviceLocator->expects($this->exactly(0)) + ->method('get'); + $serviceLocator->expects($this->exactly(1)) + ->method('has') + ->willReturn(false); + + $command = new SetupTransportsCommand($serviceLocator, ['amqp', 'other_transport']); + $tester = new CommandTester($command); + $tester->execute(['transport' => 'not_found']); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index c6ef2c0cecb59..4e32ba9b49aab 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\Messenger\Command\ConsumeMessagesCommand; use Symfony\Component\Messenger\Command\DebugCommand; +use Symfony\Component\Messenger\Command\SetupTransportsCommand; use Symfony\Component\Messenger\DataCollector\MessengerDataCollector; use Symfony\Component\Messenger\DependencyInjection\MessengerPass; use Symfony\Component\Messenger\Envelope; @@ -265,6 +266,22 @@ public function testItRegistersMultipleReceiversAndSetsTheReceiverNamesOnTheComm $this->assertSame(['amqp', 'dummy'], $container->getDefinition('console.command.messenger_consume_messages')->getArgument(3)); } + public function testItSetsTheReceiverNamesOnTheSetupTransportsCommand() + { + $container = $this->getContainerBuilder(); + $container->register('console.command.messenger_setup_transports', SetupTransportsCommand::class)->setArguments([ + new Reference('messenger.receiver_locator'), + null, + ]); + + $container->register(AmqpReceiver::class, AmqpReceiver::class)->addTag('messenger.receiver', ['alias' => 'amqp']); + $container->register(DummyReceiver::class, DummyReceiver::class)->addTag('messenger.receiver', ['alias' => 'dummy']); + + (new MessengerPass())->process($container); + + $this->assertSame(['amqp', 'dummy'], $container->getDefinition('console.command.messenger_setup_transports')->getArgument(1)); + } + public function testItShouldNotThrowIfGeneratorIsReturnedInsteadOfArray() { $container = $this->getContainerBuilder($busId = 'message_bus'); diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php index a98c90596634c..2146bd900d29c 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php @@ -14,6 +14,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; use Symfony\Component\Messenger\Transport\TransportInterface; /** @@ -21,7 +22,7 @@ * * @experimental in 4.2 */ -class AmqpTransport implements TransportInterface +class AmqpTransport implements TransportInterface, SetupableTransportInterface { private $serializer; private $connection; @@ -74,6 +75,14 @@ public function send(Envelope $envelope): Envelope return ($this->sender ?? $this->getSender())->send($envelope); } + /** + * {@inheritdoc} + */ + public function setup(): void + { + $this->connection->setup(); + } + private function getReceiver() { return $this->receiver = new AmqpReceiver($this->connection, $this->serializer); diff --git a/src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php b/src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php new file mode 100644 index 0000000000000..8b6a857f60f52 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/SetupableTransportInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport; + +/** + * @author Vincent Touzet + */ +interface SetupableTransportInterface +{ + /** + * Setup the transport. + */ + public function setup(): void; +} From d11055cc1cfb6b4403eb1bbc2a61c01893abaf99 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Sun, 18 Dec 2016 14:08:54 +0100 Subject: [PATCH 281/495] [Form] TransformationFailedException: Support specifying message to display --- .../TransformationFailedException.php | 31 +++++++ .../Validator/Constraints/FormValidator.php | 12 ++- src/Symfony/Component/Form/Form.php | 8 +- .../Extension/Core/Type/FormTypeTest.php | 84 +++++++++++++++++++ .../Constraints/FormValidatorTest.php | 41 +++++++++ 5 files changed, 169 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Form/Exception/TransformationFailedException.php b/src/Symfony/Component/Form/Exception/TransformationFailedException.php index d32896e69c911..89eba088edbdb 100644 --- a/src/Symfony/Component/Form/Exception/TransformationFailedException.php +++ b/src/Symfony/Component/Form/Exception/TransformationFailedException.php @@ -18,4 +18,35 @@ */ class TransformationFailedException extends RuntimeException { + private $invalidMessage; + private $invalidMessageParameters; + + public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, string $invalidMessage = null, array $invalidMessageParameters = []) + { + parent::__construct($message, $code, $previous); + + $this->setInvalidMessage($invalidMessage, $invalidMessageParameters); + } + + /** + * Sets the message that will be shown to the user. + * + * @param string|null $invalidMessage The message or message key + * @param array $invalidMessageParameters Data to be passed into the translator + */ + public function setInvalidMessage(string $invalidMessage = null, array $invalidMessageParameters = []): void + { + $this->invalidMessage = $invalidMessage; + $this->invalidMessageParameters = $invalidMessageParameters; + } + + public function getInvalidMessage(): ?string + { + return $this->invalidMessage; + } + + public function getInvalidMessageParameters(): array + { + return $this->invalidMessageParameters; + } } diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 8a5cd14ff4dca..ca3cf80fde358 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -118,12 +118,18 @@ public function validate($form, Constraint $formConstraint) ? (string) $form->getViewData() : \gettype($form->getViewData()); + $failure = $form->getTransformationFailure(); + $this->context->setConstraint($formConstraint); - $this->context->buildViolation($config->getOption('invalid_message')) - ->setParameters(array_replace(['{{ value }}' => $clientDataAsString], $config->getOption('invalid_message_parameters'))) + $this->context->buildViolation($failure->getInvalidMessage() ?? $config->getOption('invalid_message')) + ->setParameters(array_replace( + ['{{ value }}' => $clientDataAsString], + $config->getOption('invalid_message_parameters'), + $failure->getInvalidMessageParameters() + )) ->setInvalidValue($form->getViewData()) ->setCode(Form::NOT_SYNCHRONIZED_ERROR) - ->setCause($form->getTransformationFailure()) + ->setCause($failure) ->addViolation(); } } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 40b7f4d23db69..30bd02cc160ba 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -1070,7 +1070,7 @@ private function modelToNorm($value) $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException('Unable to transform value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception); + throw new TransformationFailedException('Unable to transform value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; @@ -1094,7 +1094,7 @@ private function normToModel($value) $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException('Unable to reverse value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception); + throw new TransformationFailedException('Unable to reverse value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; @@ -1125,7 +1125,7 @@ private function normToView($value) $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException('Unable to transform value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception); + throw new TransformationFailedException('Unable to transform value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; @@ -1153,7 +1153,7 @@ private function viewToNorm($value) $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException('Unable to reverse value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception); + throw new TransformationFailedException('Unable to reverse value for property path "'.$this->getPropertyPath().'": '.$exception->getMessage(), $exception->getCode(), $exception, $exception->getInvalidMessage(), $exception->getInvalidMessageParameters()); } return $value; diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 0c7f97dc1e744..2607f1d3760ab 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -12,10 +12,18 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\DataMapperInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\CurrencyType; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\FormError; +use Symfony\Component\Form\Forms; use Symfony\Component\Form\Tests\Fixtures\Author; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; use Symfony\Component\PropertyAccess\PropertyPath; +use Symfony\Component\Validator\Validation; class FormTest_AuthorWithoutRefSetter { @@ -624,6 +632,32 @@ public function testNormDataIsPassedToView() $this->assertSame('baz', $view->vars['value']); } + public function testDataMapperTransformationFailedExceptionInvalidMessageIsUsed() + { + $money = new Money(20.5, 'EUR'); + $factory = Forms::createFormFactoryBuilder() + ->addExtensions([new ValidatorExtension(Validation::createValidator())]) + ->getFormFactory() + ; + + $builder = $factory + ->createBuilder(FormType::class, $money, ['invalid_message' => 'not the one to display']) + ->add('amount', TextType::class) + ->add('currency', CurrencyType::class) + ; + $builder->setDataMapper(new MoneyDataMapper()); + $form = $builder->getForm(); + + $form->submit(['amount' => 'invalid_amount', 'currency' => 'USD']); + + $this->assertFalse($form->isValid()); + $this->assertNull($form->getData()); + $this->assertCount(1, $form->getErrors()); + $this->assertSame('Expected numeric value', $form->getTransformationFailure()->getMessage()); + $error = $form->getErrors()[0]; + $this->assertSame('Money amount should be numeric. "invalid_amount" is invalid.', $error->getMessage()); + } + // https://github.com/symfony/symfony/issues/6862 public function testPassZeroLabelToView() { @@ -700,3 +734,53 @@ public function testPreferOwnHelpTranslationParameters() $this->assertEquals(['%parent_param%' => 'parent_value', '%override_param%' => 'child_value'], $view['child']->vars['help_translation_parameters']); } } + +class Money +{ + private $amount; + private $currency; + + public function __construct($amount, $currency) + { + $this->amount = $amount; + $this->currency = $currency; + } + + public function getAmount() + { + return $this->amount; + } + + public function getCurrency() + { + return $this->currency; + } +} + +class MoneyDataMapper implements DataMapperInterface +{ + public function mapDataToForms($data, $forms) + { + $forms = iterator_to_array($forms); + $forms['amount']->setData($data ? $data->getAmount() : 0); + $forms['currency']->setData($data ? $data->getCurrency() : 'EUR'); + } + + public function mapFormsToData($forms, &$data) + { + $forms = iterator_to_array($forms); + + $amount = $forms['amount']->getData(); + if (!is_numeric($amount)) { + $failure = new TransformationFailedException('Expected numeric value'); + $failure->setInvalidMessage('Money amount should be numeric. {{ amount }} is invalid.', ['{{ amount }}' => json_encode($amount)]); + + throw $failure; + } + + $data = new Money( + $forms['amount']->getData(), + $forms['currency']->getData() + ); + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index f23cc204f81a3..45fe0ebd8be7e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -343,6 +343,47 @@ function () { throw new TransformationFailedException(); } ->assertRaised(); } + public function testTransformationFailedExceptionInvalidMessageIsUsed() + { + $object = $this->createMock('\stdClass'); + + $form = $this + ->getBuilder('name', '\stdClass', [ + 'invalid_message' => 'invalid_message_key', + 'invalid_message_parameters' => ['{{ foo }}' => 'foo'], + ]) + ->setData($object) + ->addViewTransformer(new CallbackTransformer( + function ($data) { return $data; }, + function () { + $failure = new TransformationFailedException(); + $failure->setInvalidMessage('safe message to be used', ['{{ bar }}' => 'bar']); + + throw $failure; + } + )) + ->getForm() + ; + + $form->submit('value'); + + $this->expectNoValidate(); + + $this->validator->validate($form, new Form()); + + $this->buildViolation('safe message to be used') + ->setParameters([ + '{{ value }}' => 'value', + '{{ foo }}' => 'foo', + '{{ bar }}' => 'bar', + ]) + ->setInvalidValue('value') + ->setCode(Form::NOT_SYNCHRONIZED_ERROR) + ->setCause($form->getTransformationFailure()) + ->assertRaised() + ; + } + // https://github.com/symfony/symfony/issues/4359 public function testDontMarkInvalidIfAnyChildIsNotSynchronized() { From f3b3b2f4f356ede01182a5e2b012a403111e3047 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 26 Mar 2019 23:10:31 -0400 Subject: [PATCH 282/495] Fixing bad return on getter --- src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php | 4 ++-- .../Messenger/Tests/Stamp/RedeliveryStampTest.php | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php b/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php index d5f1259972696..fd7c88bcbc5bb 100644 --- a/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php +++ b/src/Symfony/Component/Messenger/Stamp/RedeliveryStamp.php @@ -40,9 +40,9 @@ public function getRetryCount(): int * * @internal */ - public function getSenderClassOrAlias(): int + public function getSenderClassOrAlias(): string { - return $this->retryCount; + return $this->senderClassOrAlias; } public function shouldRedeliverToSender(string $senderClass, ?string $senderAlias): bool diff --git a/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php b/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php index b6eb477a7182d..43fe0c0b08112 100644 --- a/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php +++ b/src/Symfony/Component/Messenger/Tests/Stamp/RedeliveryStampTest.php @@ -31,4 +31,11 @@ public function testShouldRedeliverToSenderWithoutAlias() $this->assertTrue($stampToRedeliverToSender1->shouldRedeliverToSender('App\Sender1', null)); $this->assertFalse($stampToRedeliverToSender1->shouldRedeliverToSender('App\Sender2', null)); } + + public function testGetters() + { + $stamp = new RedeliveryStamp(10, 'sender_alias'); + $this->assertSame(10, $stamp->getRetryCount()); + $this->assertSame('sender_alias', $stamp->getSenderClassOrAlias()); + } } From 05e487f3b25787d2a2df94805e5187676c23371a Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Tue, 26 Mar 2019 13:35:16 +0100 Subject: [PATCH 283/495] [PropertyInfo] Add possibility to extract private and protected properties in reflection extractor --- .../Extractor/ReflectionExtractor.php | 50 ++++++++++++++++--- .../Extractor/ReflectionExtractorTest.php | 22 ++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index a0a97fb2242f5..c56dbdc2cb990 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -42,6 +42,10 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp */ public static $defaultArrayMutatorPrefixes = ['add', 'remove']; + public const ALLOW_PRIVATE = 1; + public const ALLOW_PROTECTED = 2; + public const ALLOW_PUBLIC = 4; + private const MAP_TYPES = [ 'integer' => Type::BUILTIN_TYPE_INT, 'boolean' => Type::BUILTIN_TYPE_BOOL, @@ -52,18 +56,20 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp private $accessorPrefixes; private $arrayMutatorPrefixes; private $enableConstructorExtraction; + private $accessFlags; /** * @param string[]|null $mutatorPrefixes * @param string[]|null $accessorPrefixes * @param string[]|null $arrayMutatorPrefixes */ - public function __construct(array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null, bool $enableConstructorExtraction = true) + public function __construct(array $mutatorPrefixes = null, array $accessorPrefixes = null, array $arrayMutatorPrefixes = null, bool $enableConstructorExtraction = true, int $accessFlags = self::ALLOW_PUBLIC) { $this->mutatorPrefixes = null !== $mutatorPrefixes ? $mutatorPrefixes : self::$defaultMutatorPrefixes; $this->accessorPrefixes = null !== $accessorPrefixes ? $accessorPrefixes : self::$defaultAccessorPrefixes; $this->arrayMutatorPrefixes = null !== $arrayMutatorPrefixes ? $arrayMutatorPrefixes : self::$defaultArrayMutatorPrefixes; $this->enableConstructorExtraction = $enableConstructorExtraction; + $this->accessFlags = $accessFlags; } /** @@ -77,16 +83,34 @@ public function getProperties($class, array $context = []) return; } + $propertyFlags = 0; + $methodFlags = 0; + + if ($this->accessFlags & self::ALLOW_PUBLIC) { + $propertyFlags = $propertyFlags | \ReflectionProperty::IS_PUBLIC; + $methodFlags = $methodFlags | \ReflectionMethod::IS_PUBLIC; + } + + if ($this->accessFlags & self::ALLOW_PRIVATE) { + $propertyFlags = $propertyFlags | \ReflectionProperty::IS_PRIVATE; + $methodFlags = $methodFlags | \ReflectionMethod::IS_PRIVATE; + } + + if ($this->accessFlags & self::ALLOW_PROTECTED) { + $propertyFlags = $propertyFlags | \ReflectionProperty::IS_PROTECTED; + $methodFlags = $methodFlags | \ReflectionMethod::IS_PROTECTED; + } + $reflectionProperties = $reflectionClass->getProperties(); $properties = []; foreach ($reflectionProperties as $reflectionProperty) { - if ($reflectionProperty->isPublic()) { + if ($reflectionProperty->getModifiers() & $propertyFlags) { $properties[$reflectionProperty->name] = $reflectionProperty->name; } } - foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { + foreach ($reflectionClass->getMethods($methodFlags) as $reflectionMethod) { if ($reflectionMethod->isStatic()) { continue; } @@ -134,7 +158,7 @@ public function getTypes($class, $property, array $context = []) */ public function isReadable($class, $property, array $context = []) { - if ($this->isPublicProperty($class, $property)) { + if ($this->isAllowedProperty($class, $property)) { return true; } @@ -148,7 +172,7 @@ public function isReadable($class, $property, array $context = []) */ public function isWritable($class, $property, array $context = []) { - if ($this->isPublicProperty($class, $property)) { + if ($this->isAllowedProperty($class, $property)) { return true; } @@ -317,12 +341,24 @@ private function resolveTypeName(string $name, \ReflectionMethod $reflectionMeth return $name; } - private function isPublicProperty(string $class, string $property): bool + private function isAllowedProperty(string $class, string $property): bool { try { $reflectionProperty = new \ReflectionProperty($class, $property); - return $reflectionProperty->isPublic(); + if ($this->accessFlags & self::ALLOW_PUBLIC && $reflectionProperty->isPublic()) { + return true; + } + + if ($this->accessFlags & self::ALLOW_PROTECTED && $reflectionProperty->isProtected()) { + return true; + } + + if ($this->accessFlags & self::ALLOW_PRIVATE && $reflectionProperty->isPrivate()) { + return true; + } + + return false; } catch (\ReflectionException $e) { // Return false if the property doesn't exist } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 84f3d8f9255dc..b7dafe7d8f156 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -15,6 +15,7 @@ use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\PropertyInfo\Tests\Fixtures\AdderRemoverDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\DefaultValue; +use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\NotInstantiable; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyExtended2; @@ -294,6 +295,27 @@ public function testSingularize() $this->assertEquals(['analyses', 'feet'], $this->extractor->getProperties(AdderRemoverDummy::class)); } + public function testPrivatePropertyExtractor() + { + $privateExtractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PUBLIC | ReflectionExtractor::ALLOW_PRIVATE | ReflectionExtractor::ALLOW_PROTECTED); + $properties = $privateExtractor->getProperties(Dummy::class); + + $this->assertContains('bar', $properties); + $this->assertContains('baz', $properties); + + $this->assertTrue($privateExtractor->isReadable(Dummy::class, 'bar')); + $this->assertTrue($privateExtractor->isReadable(Dummy::class, 'baz')); + + $protectedExtractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PUBLIC | ReflectionExtractor::ALLOW_PROTECTED); + $properties = $protectedExtractor->getProperties(Dummy::class); + + $this->assertNotContains('bar', $properties); + $this->assertContains('baz', $properties); + + $this->assertFalse($protectedExtractor->isReadable(Dummy::class, 'bar')); + $this->assertTrue($protectedExtractor->isReadable(Dummy::class, 'baz')); + } + /** * @dataProvider getInitializableProperties */ From f5386ffb2a2be14b27669aed88cdc056b3f6265c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Mar 2019 07:08:11 +0100 Subject: [PATCH 284/495] [Mime] fixed serialization of Message instances --- .../Bridge/Twig/Mime/TemplatedEmail.php | 18 +++++++++ .../Twig/Tests/Mime/TemplatedEmailTest.php | 14 +++++++ src/Symfony/Component/Mime/Email.php | 37 ++++++------------- src/Symfony/Component/Mime/Message.php | 16 ++++++++ src/Symfony/Component/Mime/RawMessage.php | 34 ++++++++++++++++- 5 files changed, 92 insertions(+), 27 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php index 14fb14c0a211a..d840e268c4847 100644 --- a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php +++ b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php @@ -84,4 +84,22 @@ public function getContext(): array { return $this->context; } + + /** + * @internal + */ + public function __serialize(): array + { + return [$this->template, $this->htmlTemplate, $this->textTemplate, $this->context, parent::__serialize()]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->template, $this->htmlTemplate, $this->textTemplate, $this->context, $parentData] = $data; + + parent::__unserialize($parentData); + } } diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php index 8dab46a4c31f2..f5d9235a6d503 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php @@ -22,4 +22,18 @@ public function test() $email->htmlTemplate($template = 'html'); $this->assertEquals($template, $email->getHtmlTemplate()); } + + public function testSerialize() + { + $email = (new TemplatedEmail()) + ->textTemplate('text.txt.twig') + ->htmlTemplate('text.html.twig') + ->context($context = ['a' => 'b']) + ; + + $email = unserialize(serialize($email)); + $this->assertEquals('text.txt.twig', $email->getTextTemplate()); + $this->assertEquals('text.html.twig', $email->getHtmlTemplate()); + $this->assertEquals($context, $email->getContext()); + } } diff --git a/src/Symfony/Component/Mime/Email.php b/src/Symfony/Component/Mime/Email.php index 5a1e57aa6746f..7812372d5372f 100644 --- a/src/Symfony/Component/Mime/Email.php +++ b/src/Symfony/Component/Mime/Email.php @@ -543,20 +543,11 @@ private function setListAddressHeaderBody($name, array $addresses) return $this; } - public function __sleep() + /** + * @internal + */ + public function __serialize(): array { - $this->_headers = $this->getHeaders(); - $this->_raw = false; - - if (null !== $body = parent::getBody()) { - $r = new \ReflectionProperty(Message::class, 'body'); - $r->setAccessible(true); - $this->_body = $r->getValue($this); - $this->_raw = true; - - return ['_raw', '_headers', '_body']; - } - if (\is_resource($this->text)) { if (stream_get_meta_data($this->text)['seekable'] ?? false) { rewind($this->text); @@ -583,22 +574,16 @@ public function __sleep() } } - return ['_raw', '_headers', 'text', 'textCharset', 'html', 'htmlCharset', 'attachments']; + return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()]; } - public function __wakeup() + /** + * @internal + */ + public function __unserialize(array $data): void { - $r = new \ReflectionProperty(Message::class, 'headers'); - $r->setAccessible(true); - $r->setValue($this, $this->_headers); - unset($this->_headers); + [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data; - if ($this->_raw) { - $r = new \ReflectionProperty(Message::class, 'body'); - $r->setAccessible(true); - $r->setValue($this, $this->_body); - unset($this->_body); - } - unset($this->_raw); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Mime/Message.php b/src/Symfony/Component/Mime/Message.php index 43b5fe40c911a..db6e13fae6a4d 100644 --- a/src/Symfony/Component/Mime/Message.php +++ b/src/Symfony/Component/Mime/Message.php @@ -129,4 +129,20 @@ private function generateMessageId(string $email): string { return bin2hex(random_bytes(16)).strstr($email, '@'); } + + /** + * @internal + */ + public function __serialize(): array + { + return [$this->headers, $this->body]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->headers, $this->body] = $data; + } } diff --git a/src/Symfony/Component/Mime/RawMessage.php b/src/Symfony/Component/Mime/RawMessage.php index 790c7eea5351c..16b090c95474e 100644 --- a/src/Symfony/Component/Mime/RawMessage.php +++ b/src/Symfony/Component/Mime/RawMessage.php @@ -16,7 +16,7 @@ * * @experimental in 4.3 */ -class RawMessage +class RawMessage implements \Serializable { private $message; @@ -52,4 +52,36 @@ public function toIterable(): iterable } $this->message = $message; } + + /** + * @internal + */ + final public function serialize() + { + return serialize($this->__serialize()); + } + + /** + * @internal + */ + final public function unserialize($serialized) + { + $this->__unserialize(unserialize($serialized)); + } + + /** + * @internal + */ + public function __serialize(): array + { + return [$this->message]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->message] = $data; + } } From 0c9d684d0a15b56c94cf8bdd9da5ddc1b4bf4810 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Mar 2019 08:05:38 +0100 Subject: [PATCH 285/495] [Mime] added BodyRendererInterface --- .../Mime/{Renderer.php => BodyRenderer.php} | 40 ++++++++++--------- .../Component/Mime/BodyRendererInterface.php | 22 ++++++++++ 2 files changed, 43 insertions(+), 19 deletions(-) rename src/Symfony/Bridge/Twig/Mime/{Renderer.php => BodyRenderer.php} (57%) create mode 100644 src/Symfony/Component/Mime/BodyRendererInterface.php diff --git a/src/Symfony/Bridge/Twig/Mime/Renderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php similarity index 57% rename from src/Symfony/Bridge/Twig/Mime/Renderer.php rename to src/Symfony/Bridge/Twig/Mime/BodyRenderer.php index 13bf3d1bdd980..e9b04b71ab734 100644 --- a/src/Symfony/Bridge/Twig/Mime/Renderer.php +++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php @@ -12,6 +12,8 @@ namespace Symfony\Bridge\Twig\Mime; use League\HTMLToMarkdown\HtmlConverter; +use Symfony\Component\Mime\BodyRendererInterface; +use Symfony\Component\Mime\Message; use Twig\Environment; /** @@ -19,7 +21,7 @@ * * @experimental in 4.3 */ -final class Renderer +final class BodyRenderer implements BodyRendererInterface { private $twig; private $context; @@ -38,48 +40,48 @@ public function __construct(Environment $twig, array $context = []) } } - public function render(TemplatedEmail $email): TemplatedEmail + public function render(Message $message): void { - $email = clone $email; + if (!$message instanceof TemplatedEmail) { + return; + } - $vars = array_merge($this->context, $email->getContext(), [ - 'email' => new WrappedTemplatedEmail($this->twig, $email), + $vars = array_merge($this->context, $message->getContext(), [ + 'email' => new WrappedTemplatedEmail($this->twig, $message), ]); - if ($template = $email->getTemplate()) { - $this->renderFull($email, $template, $vars); + if ($template = $message->getTemplate()) { + $this->renderFull($message, $template, $vars); } - if ($template = $email->getTextTemplate()) { - $email->text($this->twig->render($template, $vars)); + if ($template = $message->getTextTemplate()) { + $message->text($this->twig->render($template, $vars)); } - if ($template = $email->getHtmlTemplate()) { - $email->html($this->twig->render($template, $vars)); + if ($template = $message->getHtmlTemplate()) { + $message->html($this->twig->render($template, $vars)); } // if text body is empty, compute one from the HTML body - if (!$email->getTextBody() && null !== $html = $email->getHtmlBody()) { - $email->text($this->convertHtmlToText(\is_resource($html) ? stream_get_contents($html) : $html)); + if (!$message->getTextBody() && null !== $html = $message->getHtmlBody()) { + $message->text($this->convertHtmlToText(\is_resource($html) ? stream_get_contents($html) : $html)); } - - return $email; } - private function renderFull(TemplatedEmail $email, string $template, array $vars): void + private function renderFull(TemplatedEmail $message, string $template, array $vars): void { $template = $this->twig->load($template); if ($template->hasBlock('subject', $vars)) { - $email->subject($template->renderBlock('subject', $vars)); + $message->subject($template->renderBlock('subject', $vars)); } if ($template->hasBlock('text', $vars)) { - $email->text($template->renderBlock('text', $vars)); + $message->text($template->renderBlock('text', $vars)); } if ($template->hasBlock('html', $vars)) { - $email->html($template->renderBlock('html', $vars)); + $message->html($template->renderBlock('html', $vars)); } if ($template->hasBlock('config', $vars)) { diff --git a/src/Symfony/Component/Mime/BodyRendererInterface.php b/src/Symfony/Component/Mime/BodyRendererInterface.php new file mode 100644 index 0000000000000..8fcc401595549 --- /dev/null +++ b/src/Symfony/Component/Mime/BodyRendererInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +interface BodyRendererInterface +{ + public function render(Message $message): void; +} From 821e55ab80373b111cbec8b341dbb341376234db Mon Sep 17 00:00:00 2001 From: Anton Chernikov Date: Sun, 24 Mar 2019 14:00:46 +0300 Subject: [PATCH 286/495] [Finder] Get filename without extension --- src/Symfony/Component/Finder/SplFileInfo.php | 7 ++++ .../Component/Finder/Tests/FinderTest.php | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/Symfony/Component/Finder/SplFileInfo.php b/src/Symfony/Component/Finder/SplFileInfo.php index b8143ed799162..ee798dc703f00 100644 --- a/src/Symfony/Component/Finder/SplFileInfo.php +++ b/src/Symfony/Component/Finder/SplFileInfo.php @@ -57,6 +57,13 @@ public function getRelativePathname() return $this->relativePathname; } + public function getFilenameWithoutExtension(): string + { + $filename = $this->getFilename(); + + return \pathinfo($filename, PATHINFO_FILENAME); + } + /** * Returns the contents of the file. * diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 9899c61fa6a5f..6b9a4b00c6d68 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -1007,6 +1007,40 @@ public function testRelativePathname() $this->assertEquals($ref, $paths); } + public function testGetFilenameWithoutExtension() + { + $finder = $this->buildFinder()->in(self::$tmpDir)->sortByName(); + + $fileNames = []; + + foreach ($finder as $file) { + $fileNames[] = $file->getFilenameWithoutExtension(); + } + + $ref = [ + 'test', + 'toto', + 'test', + 'foo', + 'bar', + 'foo bar', + 'qux', + 'baz_100_1', + 'baz_1_2', + 'qux_0_1', + 'qux_1000_1', + 'qux_1002_0', + 'qux_10_2', + 'qux_12_0', + 'qux_2_0', + ]; + + sort($fileNames); + sort($ref); + + $this->assertEquals($ref, $fileNames); + } + public function testAppendWithAFinder() { $finder = $this->buildFinder(); From 578d842bcdb893d6929d50ff001f226fa6d31048 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 27 Mar 2019 10:09:36 +0100 Subject: [PATCH 287/495] fix tests --- src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php index 73ba80959a3a9..3c30821bb45e4 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php @@ -12,7 +12,7 @@ namespace Symfony\Bridge\Twig\Tests\Mime; use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Twig\Mime\Renderer; +use Symfony\Bridge\Twig\Mime\BodyRenderer; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\Mime\Part\Multipart\AlternativePart; use Symfony\Component\Mime\Part\Multipart\MixedPart; @@ -157,7 +157,7 @@ private function prepareEmail(?string $full, ?string $text, ?string $html): Temp 'document.txt' => 'Some text document...', 'image.jpg' => 'Some image data', ])); - $renderer = new Renderer($twig); + $renderer = new BodyRenderer($twig); $email = (new TemplatedEmail())->to('fabien@symfony.com')->from('helene@symfony.com'); if (null !== $full) { $email->template('full'); @@ -168,7 +168,8 @@ private function prepareEmail(?string $full, ?string $text, ?string $html): Temp if (null !== $html) { $email->htmlTemplate('html'); } + $renderer->render($email); - return $renderer->render($email); + return $email; } } From 59437a4af9790edbc729dc783f3d8f0f6aeefd99 Mon Sep 17 00:00:00 2001 From: Fleuv Date: Fri, 11 Jan 2019 22:17:09 +0100 Subject: [PATCH 288/495] Skipping iterations in the mirror() method where the iterated file's path name is equal to the target path Added a new test what is called testMirrorAvoidCopyingTargetDirectoryIfInSourceDirectory Adjustments to comply with the Symfony Code Standards --- .../Component/Filesystem/Filesystem.php | 4 +++ .../Filesystem/Tests/FilesystemTest.php | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 046ca4551f250..a9a372f4f16fc 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -569,6 +569,10 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o } foreach ($iterator as $file) { + if ($file->getPathName() === $targetDir) { + continue; + } + if (false === strpos($file->getPath(), $originDir)) { throw new IOException(sprintf('Unable to mirror "%s" directory. If the origin directory is relative, try using "realpath" before calling the mirror method.', $originDir), 0, null, $originDir); } diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 24df7a765c914..545415c0ddd31 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1372,6 +1372,31 @@ public function testMirrorWithCustomIteratorWithRelativePath() $this->filesystem->mirror($sourcePath, $targetPath, $iterator); } + public function testMirrorAvoidCopyingTargetDirectoryIfInSourceDirectory() + { + $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; + $directory = $sourcePath.'directory'.\DIRECTORY_SEPARATOR; + $file1 = $directory.'file1'; + $file2 = $sourcePath.'file2'; + + mkdir($sourcePath); + mkdir($directory); + file_put_contents($file1, 'FILE1'); + file_put_contents($file2, 'FILE2'); + + $targetPath = $sourcePath.'target'.\DIRECTORY_SEPARATOR; + + $this->filesystem->mirror($sourcePath, $targetPath); + + $this->assertTrue(is_dir($targetPath)); + $this->assertTrue(is_dir($targetPath.'directory')); + + $this->assertFileEquals($file1, $targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1'); + $this->assertFileEquals($file2, $targetPath.'file2'); + + $this->assertFileNotExists($targetPath.'target'); + } + /** * @dataProvider providePathsForIsAbsolutePath */ From 8011f494d4d733d3de494b53da701e8df936d220 Mon Sep 17 00:00:00 2001 From: Anthony MARTIN Date: Fri, 8 Feb 2019 15:34:28 +0100 Subject: [PATCH 289/495] Handling relative/absolute path --- .../Component/Filesystem/Filesystem.php | 39 +++++--------- .../Filesystem/Tests/FilesystemTest.php | 53 ++++--------------- 2 files changed, 23 insertions(+), 69 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index a9a372f4f16fc..9240a215c656b 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -541,6 +541,10 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o $originDir = rtrim($originDir, '/\\'); $originDirLen = \strlen($originDir); + if (!$this->exists($originDir)) { + throw new IOException(sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); + } + // Iterate in destination folder to remove obsolete entries if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) { $deleteIterator = $iterator; @@ -564,39 +568,24 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST); } - if ($this->exists($originDir)) { - $this->mkdir($targetDir); - } + $this->mkdir($targetDir); + $targetDirInfo = new \SplFileInfo($targetDir); foreach ($iterator as $file) { - if ($file->getPathName() === $targetDir) { + if ($file->getPathName() === $targetDir || $file->getRealPath() === $targetDir || 0 === strpos($file->getRealPath(), $targetDirInfo->getRealPath())) { continue; } - if (false === strpos($file->getPath(), $originDir)) { - throw new IOException(sprintf('Unable to mirror "%s" directory. If the origin directory is relative, try using "realpath" before calling the mirror method.', $originDir), 0, null, $originDir); - } - $target = $targetDir.substr($file->getPathname(), $originDirLen); - if ($copyOnWindows) { - if (is_file($file)) { - $this->copy($file, $target, isset($options['override']) ? $options['override'] : false); - } elseif (is_dir($file)) { - $this->mkdir($target); - } else { - throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); - } + if (!$copyOnWindows && is_link($file)) { + $this->symlink($file->getLinkTarget(), $target); + } elseif (is_dir($file)) { + $this->mkdir($target); + } elseif (is_file($file)) { + $this->copy($file, $target, isset($options['override']) ? $options['override'] : false); } else { - if (is_link($file)) { - $this->symlink($file->getLinkTarget(), $target); - } elseif (is_dir($file)) { - $this->mkdir($target); - } elseif (is_file($file)) { - $this->copy($file, $target, isset($options['override']) ? $options['override'] : false); - } else { - throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); - } + throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); } } } diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 545415c0ddd31..a1a3ce0e6e444 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1332,46 +1332,6 @@ public function testMirrorContentsWithSameNameAsSourceOrTargetWithDeleteOption() $this->assertFileNotExists($targetPath.'target'); } - public function testMirrorWithCustomIterator() - { - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - mkdir($sourcePath); - - $file = $sourcePath.\DIRECTORY_SEPARATOR.'file'; - file_put_contents($file, 'FILE'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $splFile = new \SplFileInfo($file); - $iterator = new \ArrayObject([$splFile]); - - $this->filesystem->mirror($sourcePath, $targetPath, $iterator); - - $this->assertTrue(is_dir($targetPath)); - $this->assertFileEquals($file, $targetPath.\DIRECTORY_SEPARATOR.'file'); - } - - /** - * @expectedException \Symfony\Component\Filesystem\Exception\IOException - * @expectedExceptionMessageRegExp /Unable to mirror "(.*)" directory/ - */ - public function testMirrorWithCustomIteratorWithRelativePath() - { - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - $realSourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - mkdir($realSourcePath); - - $file = $realSourcePath.'file'; - file_put_contents($file, 'FILE'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $splFile = new \SplFileInfo($file); - $iterator = new \ArrayObject([$splFile]); - - $this->filesystem->mirror($sourcePath, $targetPath, $iterator); - } - public function testMirrorAvoidCopyingTargetDirectoryIfInSourceDirectory() { $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; @@ -1386,15 +1346,20 @@ public function testMirrorAvoidCopyingTargetDirectoryIfInSourceDirectory() $targetPath = $sourcePath.'target'.\DIRECTORY_SEPARATOR; - $this->filesystem->mirror($sourcePath, $targetPath); + if ('\\' !== \DIRECTORY_SEPARATOR) { + $this->filesystem->symlink($targetPath, $sourcePath.'target_simlink'); + } - $this->assertTrue(is_dir($targetPath)); - $this->assertTrue(is_dir($targetPath.'directory')); + $this->filesystem->mirror($sourcePath, $targetPath, null, ['delete' => true]); + + $this->assertTrue($this->filesystem->exists($targetPath)); + $this->assertTrue($this->filesystem->exists($targetPath.'directory')); $this->assertFileEquals($file1, $targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1'); $this->assertFileEquals($file2, $targetPath.'file2'); - $this->assertFileNotExists($targetPath.'target'); + $this->assertFalse($this->filesystem->exists($targetPath.'target_simlink')); + $this->assertFalse($this->filesystem->exists($targetPath.'target')); } /** From 40dc4c89df479d6a328eeeabfe160d251facc724 Mon Sep 17 00:00:00 2001 From: Emmanuel BORGES Date: Tue, 19 Mar 2019 17:21:05 +0100 Subject: [PATCH 290/495] [Validator] allow brackets in the optional query string --- .../Component/Validator/Constraints/UrlValidator.php | 6 +++--- .../Validator/Tests/Constraints/UrlValidatorTest.php | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 20d8ded87069e..ff1925e9e1272 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -35,9 +35,9 @@ class UrlValidator extends ConstraintValidator \] # an IPv6 address ) (:[0-9]+)? # a port (optional) - (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%%[0-9A-Fa-f]{2})* )* # a path - (?:\? (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a query (optional) - (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a fragment (optional) + (?:/ (?:[\pL\pN\-._\~!$&\'()*+,;=:@]|%%[0-9A-Fa-f]{2})* )* # a path + (?:\? (?:[\pL\pN\-._\~!$&\'\[\]()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a query (optional) + (?:\# (?:[\pL\pN\-._\~!$&\'()*+,;=:@/?]|%%[0-9A-Fa-f]{2})* )? # a fragment (optional) $~ixu'; /** diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index 47b723311311e..f065aa19a7210 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -151,6 +151,7 @@ public function getValidUrls() ['http://symfony.com#fragment'], ['http://symfony.com/#fragment'], ['http://symfony.com/#one_more%20test'], + ['http://example.com/exploit.html?hello[0]=test'], ]; } From 8c5663d1cfb77f3f933a49f791d597ebc8228318 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Wed, 27 Mar 2019 14:33:41 +0100 Subject: [PATCH 291/495] Add missing changelog for private / protected --- src/Symfony/Component/PropertyInfo/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/PropertyInfo/CHANGELOG.md b/src/Symfony/Component/PropertyInfo/CHANGELOG.md index 9db346c21787f..19120c9f603b3 100644 --- a/src/Symfony/Component/PropertyInfo/CHANGELOG.md +++ b/src/Symfony/Component/PropertyInfo/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- +* Added the ability to extract private and protected properties and methods on `ReflectionExtractor` * Added the ability to extract property type based on its initial value 4.2.0 From 60b077337ccb9b1f0f868acbbbc43c7d7523aa39 Mon Sep 17 00:00:00 2001 From: Samuel NELA Date: Thu, 28 Mar 2019 10:30:05 +0100 Subject: [PATCH 292/495] [HttpClient] Remove unused local variable --- src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php index 5899a9ce7c6bd..6b1e44f69f382 100644 --- a/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php +++ b/src/Symfony/Component/HttpClient/Chunk/ErrorChunk.php @@ -28,7 +28,6 @@ class ErrorChunk implements ChunkInterface public function __construct(int $offset, \Throwable $error = null) { - $didThrow = false; $this->offset = $offset; $this->error = $error; $this->errorMessage = null !== $error ? $error->getMessage() : 'Reading from the response stream reached the inactivity timeout.'; From 47777eedd63cb9e747f9141c6a848be2089bd691 Mon Sep 17 00:00:00 2001 From: fbouchery Date: Sun, 24 Mar 2019 17:01:17 +0100 Subject: [PATCH 293/495] Add optional parameter `prefetching` in connection configuration, to setup channel prefetch count Co-Authored-By: f2r --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 ++ .../Transport/AmqpExt/ConnectionTest.php | 19 +++++++++++++++++++ .../Transport/AmqpExt/Connection.php | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 54c32c1618ddd..167d4bd08c95e 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * Added optional parameter `prefetch_count` in connection configuration, + to setup channel prefetch count * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` and `BusNameStamp` were added, which allow you to add a bus identifier to the `Envelope` then find the correct bus when receiving from diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index e29ee083319d9..7952f5d19b913 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -256,6 +256,25 @@ public function testPublishWithQueueOptions() $connection->publish('body', $headers); } + public function testSetChannelPrefetchWhenSetup() + { + $factory = new TestAmqpFactory( + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) + ); + + // makes sure the channel looks connected, so it's not re-created + $amqpChannel->expects($this->exactly(2))->method('isConnected')->willReturn(true); + + $amqpChannel->expects($this->exactly(2))->method('setPrefetchCount')->with(2); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?prefetch_count=2', [], $factory); + $connection->setup(); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', ['prefetch_count' => 2], $factory); + $connection->setup(); + } + public function testItDelaysTheMessage() { $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(); diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 18f620c4543f8..6afc10687e762 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -84,6 +84,7 @@ class Connection * * exchange_name: Name of the exchange to be used for the retried messages (Default: "retry") * * auto-setup: Enable or not the auto-setup of queues and exchanges (Default: true) * * loop_sleep: Amount of micro-seconds to wait if no message are available (Default: 200000) + * * prefetch_count: set channel prefetch count */ public function __construct(array $connectionConfiguration, array $exchangeConfiguration, array $queueConfiguration, AmqpFactory $amqpFactory = null) { @@ -323,6 +324,10 @@ public function channel(): \AMQPChannel throw new \AMQPException(sprintf('Could not connect to the AMQP server. Please verify the provided DSN. (%s)', json_encode($credentials)), 0, $e); } $this->amqpChannel = $this->amqpFactory->createChannel($connection); + + if (isset($this->connectionConfiguration['prefetch_count'])) { + $this->amqpChannel->setPrefetchCount($this->connectionConfiguration['prefetch_count']); + } } return $this->amqpChannel; From aaf5422cfbcd889226ba7f615bb5a975281335ea Mon Sep 17 00:00:00 2001 From: Mateusz Sip Date: Sun, 7 Jan 2018 04:01:46 +0100 Subject: [PATCH 294/495] [DI][Contracts] add and implement ServiceProviderInterface --- .../Argument/ServiceLocator.php | 12 ++++++- .../DependencyInjection/CHANGELOG.md | 1 + .../ResolveServiceSubscribersPass.php | 3 +- .../DependencyInjection/ContainerBuilder.php | 5 +-- .../DependencyInjection/Dumper/PhpDumper.php | 4 ++- .../DependencyInjection/ServiceLocator.php | 4 +-- .../Tests/Fixtures/php/services_rot13_env.php | 2 ++ .../php/services_service_locator_argument.php | 6 ++++ .../Fixtures/php/services_subscriber.php | 5 +++ .../Tests/ServiceLocatorTest.php | 15 ++++++++ .../DependencyInjection/composer.json | 2 +- src/Symfony/Contracts/CHANGELOG.md | 1 + .../Contracts/Service/ServiceLocatorTrait.php | 25 ++++++++++++- .../Service/ServiceProviderInterface.php | 36 +++++++++++++++++++ 14 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 src/Symfony/Contracts/Service/ServiceProviderInterface.php diff --git a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php index fcb2b6a6b906f..2001a9561705b 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php +++ b/src/Symfony/Component/DependencyInjection/Argument/ServiceLocator.php @@ -22,11 +22,13 @@ class ServiceLocator extends BaseServiceLocator { private $factory; private $serviceMap; + private $serviceTypes; - public function __construct(\Closure $factory, array $serviceMap) + public function __construct(\Closure $factory, array $serviceMap, array $serviceTypes = null) { $this->factory = $factory; $this->serviceMap = $serviceMap; + $this->serviceTypes = $serviceTypes; parent::__construct($serviceMap); } @@ -37,4 +39,12 @@ public function get($id) { return isset($this->serviceMap[$id]) ? ($this->factory)(...$this->serviceMap[$id]) : parent::get($id); } + + /** + * {@inheritdoc} + */ + public function getProvidedServices(): array + { + return $this->serviceTypes ?? $this->serviceTypes = array_map(function () { return '?'; }, $this->serviceMap); + } } diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index edc6ddf11577a..3d71d72844d26 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -13,6 +13,7 @@ CHANGELOG * added `ReverseContainer`: a container that turns services back to their ids * added ability to define an index for a tagged collection * added ability to define an index for services in an injected service locator argument + * made `ServiceLocator` implement `ServiceProviderInterface` * deprecated support for non-string default env() parameters 4.2.0 diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveServiceSubscribersPass.php index cc87f3a8b753e..399f349046a36 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveServiceSubscribersPass.php @@ -14,6 +14,7 @@ use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Contracts\Service\ServiceProviderInterface; /** * Compiler pass to inject their service locator to service subscribers. @@ -26,7 +27,7 @@ class ResolveServiceSubscribersPass extends AbstractRecursivePass protected function processValue($value, $isRoot = false) { - if ($value instanceof Reference && $this->serviceLocator && ContainerInterface::class === (string) $value) { + if ($value instanceof Reference && $this->serviceLocator && \in_array((string) $value, [ContainerInterface::class, ServiceProviderInterface::class], true)) { return new Reference($this->serviceLocator); } diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 943df8d314f11..94a95661a41b4 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1234,13 +1234,14 @@ private function doResolveServices($value, array &$inlineServices = [], $isConst return $count; }); } elseif ($value instanceof ServiceLocatorArgument) { - $refs = []; + $refs = $types = []; foreach ($value->getValues() as $k => $v) { if ($v) { $refs[$k] = [$v]; + $types[$k] = $v instanceof TypedReference ? $v->getType() : '?'; } } - $value = new ServiceLocator(\Closure::fromCallable([$this, 'resolveServices']), $refs); + $value = new ServiceLocator(\Closure::fromCallable([$this, 'resolveServices']), $refs, $types); } elseif ($value instanceof Reference) { $value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices, $isConstructorArgument); } elseif ($value instanceof Definition) { diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 4cf663b3dd234..cfac05ddd0e92 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -1546,6 +1546,7 @@ private function dumpValue($value, bool $interpolate = true): string if ($value instanceof ServiceLocatorArgument) { $serviceMap = ''; + $serviceTypes = ''; foreach ($value->getValues() as $k => $v) { if (!$v) { continue; @@ -1559,11 +1560,12 @@ private function dumpValue($value, bool $interpolate = true): string $this->export(ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $v->getInvalidBehavior() && !\is_string($load) ? $this->generateMethodName($id).($load ? '.php' : '') : null), $this->export($load) ); + $serviceTypes .= sprintf("\n %s => %s,", $this->export($k), $this->export($v instanceof TypedReference ? $v->getType() : '?')); $this->locatedIds[$id] = true; } $this->addGetService = true; - return sprintf('new \%s($this->getService, [%s%s])', ServiceLocator::class, $serviceMap, $serviceMap ? "\n " : ''); + return sprintf('new \%s($this->getService, [%s%s], [%s%s])', ServiceLocator::class, $serviceMap, $serviceMap ? "\n " : '', $serviceTypes, $serviceTypes ? "\n " : ''); } } finally { list($this->definitionVariables, $this->referenceVariables) = $scope; diff --git a/src/Symfony/Component/DependencyInjection/ServiceLocator.php b/src/Symfony/Component/DependencyInjection/ServiceLocator.php index 45a352413563c..6741281d90325 100644 --- a/src/Symfony/Component/DependencyInjection/ServiceLocator.php +++ b/src/Symfony/Component/DependencyInjection/ServiceLocator.php @@ -12,19 +12,19 @@ namespace Symfony\Component\DependencyInjection; use Psr\Container\ContainerExceptionInterface; -use Psr\Container\ContainerInterface as PsrContainerInterface; use Psr\Container\NotFoundExceptionInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Contracts\Service\ServiceLocatorTrait; +use Symfony\Contracts\Service\ServiceProviderInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; /** * @author Robin Chalas * @author Nicolas Grekas */ -class ServiceLocator implements PsrContainerInterface +class ServiceLocator implements ServiceProviderInterface { use ServiceLocatorTrait { get as private doGet; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php index 64cc5df2580cb..bf3caef842af6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_rot13_env.php @@ -72,6 +72,8 @@ protected function getContainer_EnvVarProcessorsLocatorService() { return $this->services['container.env_var_processors_locator'] = new \Symfony\Component\DependencyInjection\Argument\ServiceLocator($this->getService, [ 'rot13' => ['services', 'Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor', 'getRot13EnvVarProcessorService', false], + ], [ + 'rot13' => '?', ]); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_service_locator_argument.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_service_locator_argument.php index c30a6c9e44794..94b5931ed3acb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_service_locator_argument.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_service_locator_argument.php @@ -72,6 +72,12 @@ protected function getBarService() 'foo3' => [false, 'foo3', 'getFoo3Service', false], 'foo4' => ['privates', 'foo4', NULL, 'BOOM'], 'foo5' => ['services', 'foo5', NULL, false], + ], [ + 'foo1' => '?', + 'foo2' => '?', + 'foo3' => '?', + 'foo4' => '?', + 'foo5' => '?', ]); return $instance; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php index b60b3b87b3de0..ac00d4bf361d4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php @@ -75,6 +75,11 @@ protected function getFooServiceService() 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => ['services', 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber', 'getTestServiceSubscriberService', false], 'bar' => ['services', 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber', 'getTestServiceSubscriberService', false], 'baz' => ['privates', 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition', 'getCustomDefinitionService', false], + ], [ + 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition', + 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber', + 'bar' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition', + 'baz' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition', ]))->withContext('foo_service', $this)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php index 9c0962880fc92..eb43029696f8c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php @@ -86,6 +86,21 @@ public function testInvoke() $this->assertSame('baz', $locator('bar')); $this->assertNull($locator('dummy'), '->__invoke() should return null on invalid service'); } + + public function testProvidesServicesInformation() + { + $locator = new ServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function (): string { return 'baz'; }, + 'baz' => function (): ?string { return 'zaz'; }, + ]); + + $this->assertSame($locator->getProvidedServices(), [ + 'foo' => '?', + 'bar' => 'string', + 'baz' => '?string', + ]); + } } class SomeServiceSubscriber implements ServiceSubscriberInterface diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index 4acf55465075f..94a729df8dd24 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.1.3", "psr/container": "^1.0", - "symfony/contracts": "^1.0" + "symfony/contracts": "^1.1" }, "require-dev": { "symfony/yaml": "~3.4|~4.0", diff --git a/src/Symfony/Contracts/CHANGELOG.md b/src/Symfony/Contracts/CHANGELOG.md index b5f1d76aecda5..1106a6f5a0386 100644 --- a/src/Symfony/Contracts/CHANGELOG.md +++ b/src/Symfony/Contracts/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * added `HttpClient` namespace with contracts for implementing flexible HTTP clients * added `EventDispatcher\EventDispatcherInterface` + * added `ServiceProviderInterface` 1.0.0 ----- diff --git a/src/Symfony/Contracts/Service/ServiceLocatorTrait.php b/src/Symfony/Contracts/Service/ServiceLocatorTrait.php index eed44f5d33e7a..71b1b7460dffe 100644 --- a/src/Symfony/Contracts/Service/ServiceLocatorTrait.php +++ b/src/Symfony/Contracts/Service/ServiceLocatorTrait.php @@ -15,7 +15,7 @@ use Psr\Container\NotFoundExceptionInterface; /** - * A trait to help implement PSR-11 service locators. + * A trait to help implement ServiceProviderInterface. * * @author Robin Chalas * @author Nicolas Grekas @@ -24,6 +24,7 @@ trait ServiceLocatorTrait { private $factories; private $loading = []; + private $providedTypes; /** * @param callable[] $factories @@ -66,6 +67,28 @@ public function get($id) } } + /** + * {@inheritdoc} + */ + public function getProvidedServices(): array + { + if (null === $this->providedTypes) { + $this->providedTypes = []; + + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').$type->getName() : '?'; + } + } + } + + return $this->providedTypes; + } + private function createNotFoundException(string $id): NotFoundExceptionInterface { if (!$alternatives = array_keys($this->factories)) { diff --git a/src/Symfony/Contracts/Service/ServiceProviderInterface.php b/src/Symfony/Contracts/Service/ServiceProviderInterface.php new file mode 100644 index 0000000000000..c60ad0bd4bf26 --- /dev/null +++ b/src/Symfony/Contracts/Service/ServiceProviderInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; + +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return string[] The provided service types, keyed by service names + */ + public function getProvidedServices(): array; +} From 48d5f94cda13e693c4729d41395e607704b74343 Mon Sep 17 00:00:00 2001 From: Andreas Erhard Date: Thu, 28 Mar 2019 12:16:35 +0100 Subject: [PATCH 295/495] Throw a dedicated exception for non-existing directory Makes Finder::in() throw a DirectoryNotFoundException instead of an InvalidArgumentException if one of the directories is not found. This behavior is more consistent with the AccessDeniedException for files which are unreadable due to insufficient permissions. To keep BC, the new exception class inherits from InvalidArgumentException. --- .../Exception/DirectoryNotFoundException.php | 19 +++++++++++++++++++ src/Symfony/Component/Finder/Finder.php | 5 +++-- .../Component/Finder/Tests/FinderTest.php | 11 ++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Finder/Exception/DirectoryNotFoundException.php diff --git a/src/Symfony/Component/Finder/Exception/DirectoryNotFoundException.php b/src/Symfony/Component/Finder/Exception/DirectoryNotFoundException.php new file mode 100644 index 0000000000000..c6cc0f2736370 --- /dev/null +++ b/src/Symfony/Component/Finder/Exception/DirectoryNotFoundException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Finder\Exception; + +/** + * @author Andreas Erhard + */ +class DirectoryNotFoundException extends \InvalidArgumentException +{ +} diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php index f791f8cf32a8f..33b1805979469 100644 --- a/src/Symfony/Component/Finder/Finder.php +++ b/src/Symfony/Component/Finder/Finder.php @@ -13,6 +13,7 @@ use Symfony\Component\Finder\Comparator\DateComparator; use Symfony\Component\Finder\Comparator\NumberComparator; +use Symfony\Component\Finder\Exception\DirectoryNotFoundException; use Symfony\Component\Finder\Iterator\CustomFilterIterator; use Symfony\Component\Finder\Iterator\DateRangeFilterIterator; use Symfony\Component\Finder\Iterator\DepthRangeFilterIterator; @@ -585,7 +586,7 @@ public function ignoreUnreadableDirs($ignore = true) * * @return $this * - * @throws \InvalidArgumentException if one of the directories does not exist + * @throws DirectoryNotFoundException if one of the directories does not exist */ public function in($dirs) { @@ -597,7 +598,7 @@ public function in($dirs) } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) { $resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob)); } else { - throw new \InvalidArgumentException(sprintf('The "%s" directory does not exist.', $dir)); + throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir)); } } diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 6b9a4b00c6d68..2e4e55b3b5d86 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -888,7 +888,7 @@ public function testIn() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Symfony\Component\Finder\Exception\DirectoryNotFoundException */ public function testInWithNonExistentDirectory() { @@ -896,6 +896,15 @@ public function testInWithNonExistentDirectory() $finder->in('foobar'); } + /** + * @expectedException \InvalidArgumentException + */ + public function testInWithNonExistentDirectoryLegacyException() + { + $finder = new Finder(); + $finder->in('foobar'); + } + public function testInWithGlob() { $finder = $this->buildFinder(); From 332a88c8ce6a6e68eafd7beb965abc7863a473f1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 Mar 2019 16:51:35 +0100 Subject: [PATCH 296/495] [HttpClient] correctly clean state on destruct in CurlResponse --- src/Symfony/Component/HttpClient/Response/CurlResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 189b6718b2e12..5f16ba2b9dd9c 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -231,7 +231,7 @@ protected static function perform(\stdClass $multi, array &$responses = null): v while ($info = curl_multi_info_read($multi->handle)) { $multi->handlesActivity[(int) $info['handle']][] = null; - $multi->handlesActivity[(int) $info['handle']][] = \in_array($info['result'], [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) ? null : new TransportException(curl_error($info['handle'])); + $multi->handlesActivity[(int) $info['handle']][] = \in_array($info['result'], [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || (\CURLE_WRITE_ERROR === $info['result'] && 'destruct' === @curl_getinfo($info['handle'], CURLINFO_PRIVATE)) ? null : new TransportException(curl_error($info['handle'])); } } finally { self::$performing = false; From f2222e4bf5ed676f426aa1a4dcbce3aeb3892dd3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 Mar 2019 16:19:14 +0100 Subject: [PATCH 297/495] [HttpClient] use "nyholm/psr7" by default in Psr18Client --- .../Component/HttpClient/Psr18Client.php | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php index 9c00940339058..17a3d3bd116ac 100644 --- a/src/Symfony/Component/HttpClient/Psr18Client.php +++ b/src/Symfony/Component/HttpClient/Psr18Client.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpClient; +use Nyholm\Psr7\Factory\Psr17Factory; use Psr\Http\Client\ClientInterface; use Psr\Http\Client\NetworkExceptionInterface; use Psr\Http\Client\RequestExceptionInterface; @@ -21,6 +22,10 @@ use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; +if (!interface_exists(ClientInterface::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as the "psr/http-client" package is not installed. Try running "composer require psr/http-client".'); +} + /** * An adapter to turn a Symfony HttpClientInterface into a PSR-18 ClientInterface. * @@ -38,11 +43,23 @@ final class Psr18Client implements ClientInterface private $responseFactory; private $streamFactory; - public function __construct(HttpClientInterface $client, ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory) + public function __construct(HttpClientInterface $client = null, ResponseFactoryInterface $responseFactory = null, StreamFactoryInterface $streamFactory = null) { - $this->client = $client; + $this->client = $client ?? HttpClient::create(); $this->responseFactory = $responseFactory; - $this->streamFactory = $streamFactory; + $this->streamFactory = $streamFactory ?? ($responseFactory instanceof StreamFactoryInterface ? $responseFactory : null); + + if (null !== $this->responseFactory && null !== $this->streamFactory) { + return; + } + + if (!class_exists(Psr17Factory::class)) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".'); + } + + $psr17Factory = new Psr17Factory(); + $this->responseFactory = $this->responseFactory ?? $psr17Factory; + $this->streamFactory = $this->streamFactory ?? $psr17Factory; } public function sendRequest(RequestInterface $request): ResponseInterface From a4c95745bb4dfb4ddc9245275f77b7fd2a16a775 Mon Sep 17 00:00:00 2001 From: RJ Garcia Date: Thu, 28 Mar 2019 11:50:55 -0700 Subject: [PATCH 298/495] [PropertyAccess] Allow Can Accessor in Property Access - Added ability to support `can` methods in the property access in order to be compatible with PropertyInfo component which allows for can accessors Signed-off-by: RJ Garcia --- .../Component/PropertyAccess/PropertyAccessor.php | 4 ++++ .../PropertyAccess/Tests/Fixtures/TestClass.php | 12 ++++++++++++ .../PropertyAccess/Tests/PropertyAccessorTest.php | 1 + 3 files changed, 17 insertions(+) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index b7333dac309e4..db9c6b84652ea 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -455,6 +455,7 @@ private function getReadAccessInfo($class, $property) $getsetter = lcfirst($camelProp); // jQuery style, e.g. read: last(), write: last($item) $isser = 'is'.$camelProp; $hasser = 'has'.$camelProp; + $canAccessor = 'can'.$camelProp; if ($reflClass->hasMethod($getter) && $reflClass->getMethod($getter)->isPublic()) { $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; @@ -468,6 +469,9 @@ private function getReadAccessInfo($class, $property) } elseif ($reflClass->hasMethod($hasser) && $reflClass->getMethod($hasser)->isPublic()) { $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; $access[self::ACCESS_NAME] = $hasser; + } elseif ($reflClass->hasMethod($canAccessor) && $reflClass->getMethod($canAccessor)->isPublic()) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_METHOD; + $access[self::ACCESS_NAME] = $canAccessor; } elseif ($reflClass->hasMethod('__get') && $reflClass->getMethod('__get')->isPublic()) { $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_PROPERTY; $access[self::ACCESS_NAME] = $property; diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php index e63af3a8bac5d..a667997a9b7e4 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TestClass.php @@ -25,6 +25,7 @@ class TestClass private $publicAccessorWithMoreRequiredParameters; private $publicIsAccessor; private $publicHasAccessor; + private $publicCanAccessor; private $publicGetter; private $date; @@ -39,6 +40,7 @@ public function __construct($value) $this->publicAccessorWithMoreRequiredParameters = $value; $this->publicIsAccessor = $value; $this->publicHasAccessor = $value; + $this->publicCanAccessor = $value; $this->publicGetter = $value; } @@ -102,6 +104,16 @@ public function hasPublicHasAccessor() return $this->publicHasAccessor; } + public function setPublicCanAccessor($value) + { + $this->publicCanAccessor = $value; + } + + public function canPublicCanAccessor() + { + return $this->publicCanAccessor; + } + public function publicGetSetter($value = null) { if (null !== $value) { diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 5151489eb0603..2a7dd8a83192b 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -450,6 +450,7 @@ public function getValidPropertyPaths() [new TestClass('Bernhard'), 'publicIsAccessor', 'Bernhard'], [new TestClass('Bernhard'), 'publicHasAccessor', 'Bernhard'], [new TestClass('Bernhard'), 'publicGetSetter', 'Bernhard'], + [new TestClass('Bernhard'), 'publicCanAccessor', 'Bernhard'], // Methods are camelized [new TestClass('Bernhard'), 'public_accessor', 'Bernhard'], From 3da5a438aa187a01f714ab017ffa991e9854f705 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 28 Mar 2019 14:48:35 -0400 Subject: [PATCH 299/495] Adding the "sync" transport to call handlers synchronously --- .../Resources/config/messenger.xml | 4 ++ src/Symfony/Component/Messenger/CHANGELOG.md | 2 + .../Middleware/SendMessageMiddleware.php | 9 +++- .../Stamp/ForceCallHandlersStamp.php | 27 ++++++++++ .../Middleware/SendMessageMiddlewareTest.php | 19 ++++++- .../Transport/Sync/SyncTransport.php | 52 +++++++++++++++++++ .../Transport/Sync/SyncTransportFactory.php | 33 ++++++++++++ 7 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Stamp/ForceCallHandlersStamp.php create mode 100644 src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php create mode 100644 src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index b4e6cd69ef64a..55976d1c02269 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -67,6 +67,10 @@ + + + + diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 9638de4e49092..41a7e3438e0d9 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to + explicitly handle messages asynchronously. * Added optional parameter `prefetch_count` in connection configuration, to setup channel prefetch count * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index f1b561d03a18d..d2ebaf8cfa011 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -15,6 +15,7 @@ use Psr\Log\NullLogger; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; +use Symfony\Component\Messenger\Stamp\ForceCallHandlersStamp; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; @@ -81,7 +82,13 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope $envelope = $sender->send($envelope->with(new SentStamp(\get_class($sender), \is_string($alias) ? $alias : null))); } - // on a redelivery, never call local handlers + // if the message was marked (usually by SyncTransport) that it handlers + // MUST be called, mark them to be handled. + if (null !== $envelope->last(ForceCallHandlersStamp::class)) { + $handle = true; + } + + // on a redelivery, only send back to queue: never call local handlers if (null !== $redeliveryStamp) { $handle = false; } diff --git a/src/Symfony/Component/Messenger/Stamp/ForceCallHandlersStamp.php b/src/Symfony/Component/Messenger/Stamp/ForceCallHandlersStamp.php new file mode 100644 index 0000000000000..5c9eb3a6d96dd --- /dev/null +++ b/src/Symfony/Component/Messenger/Stamp/ForceCallHandlersStamp.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Stamp; + +/** + * Stamp marks that the handlers *should* be called immediately. + * + * This is used by the SyncTransport to indicate to the + * SendMessageMiddleware that handlers *should* be called + * immediately, even though a transport was set. + * + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +class ForceCallHandlersStamp implements StampInterface +{ +} diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index 301f01b86086b..92e48bc78204d 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Event\SendMessageToTransportsEvent; use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; +use Symfony\Component\Messenger\Stamp\ForceCallHandlersStamp; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; @@ -86,6 +87,8 @@ public function testItSendsTheMessageToMultipleSenders() public function testItSendsToOnlyOneSenderOnRedelivery() { $envelope = new Envelope(new DummyMessage('Hey'), new RedeliveryStamp(5, 'bar')); + // even with a ForceCallHandlersStamp, the next middleware won't be called + $envelope = $envelope->with(new ForceCallHandlersStamp()); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); $sender2 = $this->getMockBuilder(SenderInterface::class)->getMock(); @@ -237,7 +240,7 @@ public function testItDoesNotDispatchWithNoSenders() $middleware->handle($envelope, $this->getStackMock()); } - public function testItDoesNotDispatchOnRetry() + public function testItDoesNotDispatchOnRedeliver() { $envelope = new Envelope(new DummyMessage('original envelope')); $envelope = $envelope->with(new RedeliveryStamp(3, 'foo_sender')); @@ -251,4 +254,18 @@ public function testItDoesNotDispatchOnRetry() $middleware->handle($envelope, $this->getStackMock(false)); } + + public function testItHandlesWithForceCallHandlersStamp() + { + $envelope = new Envelope(new DummyMessage('original envelope')); + $envelope = $envelope->with(new ForceCallHandlersStamp()); + + $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); + $sender->expects($this->once())->method('send')->willReturn($envelope); + + $middleware = new SendMessageMiddleware(new SendersLocator([DummyMessage::class => [$sender]])); + + // next handler *should* be called + $middleware->handle($envelope, $this->getStackMock(true)); + } } diff --git a/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php new file mode 100644 index 0000000000000..6d45e7f6df34c --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sync; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Stamp\ForceCallHandlersStamp; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * A "fake" transport that marks messages to be handled immediately. + * + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +class SyncTransport implements TransportInterface +{ + public function receive(callable $handler): void + { + throw new InvalidArgumentException('You cannot receive messages from the SyncTransport.'); + } + + public function stop(): void + { + throw new InvalidArgumentException('You cannot call stop() on the SyncTransport.'); + } + + public function ack(Envelope $envelope): void + { + throw new InvalidArgumentException('You cannot call ack() on the SyncTransport.'); + } + + public function reject(Envelope $envelope): void + { + throw new InvalidArgumentException('You cannot call reject() on the SyncTransport.'); + } + + public function send(Envelope $envelope): Envelope + { + return $envelope->with(new ForceCallHandlersStamp()); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php new file mode 100644 index 0000000000000..0eba740813a56 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Sync; + +use Symfony\Component\Messenger\Transport\TransportFactoryInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +class SyncTransportFactory implements TransportFactoryInterface +{ + public function createTransport(string $dsn, array $options): TransportInterface + { + return new SyncTransport(); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'sync://'); + } +} From 9c04639dc30c73221e0ae08c23307035387be9fb Mon Sep 17 00:00:00 2001 From: Joe Bennett Date: Fri, 29 Mar 2019 23:39:57 +1000 Subject: [PATCH 300/495] #27345 Added Lock/Store/MongoDbStore --- phpunit.xml.dist | 1 + src/Symfony/Component/Lock/composer.json | 5 +++-- src/Symfony/Component/Lock/phpunit.xml.dist | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7e78dd8f75208..f7fe9d3464ac1 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -19,6 +19,7 @@ + diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index 7c5fa0acd599d..3e8e77e5a3819 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -20,8 +20,9 @@ "psr/log": "~1.0" }, "require-dev": { - "predis/predis": "~1.0", - "doctrine/dbal": "~2.4" + "doctrine/dbal": "~2.4", + "mongodb/mongodb": "~1.1", + "predis/predis": "~1.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Lock\\": "" }, diff --git a/src/Symfony/Component/Lock/phpunit.xml.dist b/src/Symfony/Component/Lock/phpunit.xml.dist index 4a066573f7d08..96c3ea1903abe 100644 --- a/src/Symfony/Component/Lock/phpunit.xml.dist +++ b/src/Symfony/Component/Lock/phpunit.xml.dist @@ -12,6 +12,7 @@ + From 9153c48bc4d7e274b3f6a49abdc7e078a1ae5661 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Fri, 29 Mar 2019 09:51:35 -0400 Subject: [PATCH 301/495] Changing message handling log levels to higher levels --- src/Symfony/Component/Messenger/Worker.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index 72319c014c9ba..a273b39da95a7 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -99,7 +99,7 @@ public function run() $retryCount = $this->getRetryCount($envelope) + 1; if (null !== $this->logger) { - $this->logger->info('Retrying {class} - retry #{retryCount}.', $context + ['retryCount' => $retryCount, 'error' => $throwable]); + $this->logger->error('Retrying {class} - retry #{retryCount}.', $context + ['retryCount' => $retryCount, 'error' => $throwable]); } // add the delay and retry stamp info + remove ReceivedStamp @@ -113,7 +113,7 @@ public function run() $this->receiver->ack($envelope); } else { if (null !== $this->logger) { - $this->logger->info('Rejecting {class} (removing from transport).', $context + ['error' => $throwable]); + $this->logger->critical('Rejecting {class} (removing from transport).', $context + ['error' => $throwable]); } $this->receiver->reject($envelope); From 2389d7c6868dec3f5226253c9fc87323ec0cbd86 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 29 Mar 2019 18:00:10 +0100 Subject: [PATCH 302/495] Revert "feature #30651 Allow user to set the project dir (tdutrion)" This reverts commit aa12dd0bd7d1d5361518c10103c4d9b82277db35, reversing changes made to 7d01aae41e7c7f04d31ed1d932bf77be34b423bc. --- src/Symfony/Component/HttpKernel/Kernel.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7fc2a3113e348..23cb76a75edaa 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -83,13 +83,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl const END_OF_MAINTENANCE = '01/2020'; const END_OF_LIFE = '07/2020'; - public function __construct(string $environment, bool $debug, string $projectDir = null) + public function __construct(string $environment, bool $debug) { $this->environment = $environment; $this->debug = $debug; $this->rootDir = $this->getRootDir(false); $this->name = $this->getName(false); - $this->projectDir = $projectDir; } public function __clone() From a4ce08ec303e3c91b614e083352a5729150c99cc Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 29 Mar 2019 19:41:30 +0100 Subject: [PATCH 303/495] [Contracts][EventDispatcher] move the Event class to symfony/contracts --- UPGRADE-4.3.md | 1 + UPGRADE-5.0.md | 1 + .../Component/EventDispatcher/CHANGELOG.md | 1 + .../Debug/TraceableEventDispatcher.php | 3 +- .../EventDispatcher/Debug/WrappedListener.php | 3 +- .../Component/EventDispatcher/Event.php | 28 +----- .../EventDispatcher/EventDispatcher.php | 3 +- .../LegacyEventDispatcherProxy.php | 3 +- .../EventDispatcher/Tests/EventTest.php | 2 +- src/Symfony/Contracts/CHANGELOG.md | 4 +- .../Contracts/EventDispatcher/Event.php | 96 +++++++++++++++++++ 11 files changed, 114 insertions(+), 31 deletions(-) create mode 100644 src/Symfony/Contracts/EventDispatcher/Event.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index e60f75789dea6..ba8ab75cb2965 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -42,6 +42,7 @@ EventDispatcher --------------- * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated + * The `Event` class has been deprecated, use `Symfony\Contracts\EventDispatcher\Event` instead Form ---- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index ec6f60951ec61..00a819543d2e7 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -71,6 +71,7 @@ EventDispatcher * The `TraceableEventDispatcherInterface` has been removed. * The signature of the `EventDispatcherInterface::dispatch()` method has been updated to `dispatch($event, string $eventName = null)` + * The `Event` class has been removed, use `Symfony\Contracts\EventDispatcher\Event` instead DependencyInjection ------------------- diff --git a/src/Symfony/Component/EventDispatcher/CHANGELOG.md b/src/Symfony/Component/EventDispatcher/CHANGELOG.md index 26a4cbc427905..7653cad1c0eb0 100644 --- a/src/Symfony/Component/EventDispatcher/CHANGELOG.md +++ b/src/Symfony/Component/EventDispatcher/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated + * deprecated the `Event` class, use `Symfony\Contracts\EventDispatcher\Event` instead 4.1.0 ----- diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index f40dfa4bef982..e0a161ebde478 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -18,6 +18,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** * Collects some data about event listeners. @@ -147,7 +148,7 @@ public function dispatch($event/*, string $eventName = null*/) } } - if (null !== $this->logger && ($event instanceof Event || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { + if (null !== $this->logger && ($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); } diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index 5342fc88a1a54..3450c1283c270 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -16,6 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** * @author Fabien Potencier @@ -123,7 +124,7 @@ public function __invoke(Event $event, $eventName, EventDispatcherInterface $dis $e->stop(); } - if (($event instanceof Event || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { + if (($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { $this->stoppedPropagation = true; } } diff --git a/src/Symfony/Component/EventDispatcher/Event.php b/src/Symfony/Component/EventDispatcher/Event.php index 9c56b2f55b8a7..307c4be5de0c2 100644 --- a/src/Symfony/Component/EventDispatcher/Event.php +++ b/src/Symfony/Component/EventDispatcher/Event.php @@ -12,32 +12,16 @@ namespace Symfony\Component\EventDispatcher; /** - * Event is the base class for classes containing event data. - * - * This class contains no event data. It is used by events that do not pass - * state information to an event handler when an event is raised. - * - * You can call the method stopPropagation() to abort the execution of - * further listeners in your event listener. - * - * @author Guilherme Blanco - * @author Jonathan Wage - * @author Roman Borschel - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead */ class Event { - /** - * @var bool Whether no further event listeners should be triggered - */ private $propagationStopped = false; /** - * Returns whether further event listeners should be triggered. - * - * @see Event::stopPropagation() - * * @return bool Whether propagation was already stopped for this event + * + * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead */ public function isPropagationStopped() { @@ -45,11 +29,7 @@ public function isPropagationStopped() } /** - * Stops the propagation of the event to further event listeners. - * - * If multiple event listeners are connected to the same event, no - * further event listener will be triggered once any trigger calls - * stopPropagation(). + * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead */ public function stopPropagation() { diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index d6a78d1871cb7..b593e068d3c4c 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -12,6 +12,7 @@ namespace Symfony\Component\EventDispatcher; use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** * The EventDispatcherInterface is the central point of Symfony's event listener system. @@ -237,7 +238,7 @@ protected function callListeners(iterable $listeners, string $eventName, $event) */ protected function doDispatch($listeners, $eventName, Event $event) { - $stoppable = $event instanceof Event || $event instanceof StoppableEventInterface; + $stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface; foreach ($listeners as $listener) { if ($stoppable && $event->isPropagationStopped()) { diff --git a/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php b/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php index 54de7a44386d1..e1f8aaee00d07 100644 --- a/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php +++ b/src/Symfony/Component/EventDispatcher/LegacyEventDispatcherProxy.php @@ -12,6 +12,7 @@ namespace Symfony\Component\EventDispatcher; use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -68,7 +69,7 @@ public function dispatch($event/*, string $eventName = null*/) } $listeners = $this->getListeners($eventName); - $stoppable = $event instanceof Event || $event instanceof StoppableEventInterface; + $stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface; foreach ($listeners as $listener) { if ($stoppable && $event->isPropagationStopped()) { diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventTest.php index 5be2ea09f9d2f..ca8e945c649cf 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventTest.php @@ -15,7 +15,7 @@ use Symfony\Component\EventDispatcher\Event; /** - * Test class for Event. + * @group legacy */ class EventTest extends TestCase { diff --git a/src/Symfony/Contracts/CHANGELOG.md b/src/Symfony/Contracts/CHANGELOG.md index 1106a6f5a0386..f909b4976f64b 100644 --- a/src/Symfony/Contracts/CHANGELOG.md +++ b/src/Symfony/Contracts/CHANGELOG.md @@ -5,8 +5,8 @@ CHANGELOG ----- * added `HttpClient` namespace with contracts for implementing flexible HTTP clients - * added `EventDispatcher\EventDispatcherInterface` - * added `ServiceProviderInterface` + * added `EventDispatcherInterface` and `Event` in namespace `EventDispatcher` + * added `ServiceProviderInterface` in namespace `Service` 1.0.0 ----- diff --git a/src/Symfony/Contracts/EventDispatcher/Event.php b/src/Symfony/Contracts/EventDispatcher/Event.php new file mode 100644 index 0000000000000..84f60f3ed0460 --- /dev/null +++ b/src/Symfony/Contracts/EventDispatcher/Event.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; + +if (interface_exists(StoppableEventInterface::class)) { + /** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Nicolas Grekas + */ + class Event implements StoppableEventInterface + { + private $propagationStopped = false; + + /** + * Returns whether further event listeners should be triggered. + */ + public function isPropagationStopped(): bool + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + */ + public function stopPropagation(): void + { + $this->propagationStopped = true; + } + } +} else { + /** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Nicolas Grekas + */ + class Event + { + private $propagationStopped = false; + + /** + * Returns whether further event listeners should be triggered. + */ + public function isPropagationStopped(): bool + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + */ + public function stopPropagation(): void + { + $this->propagationStopped = true; + } + } +} From e800bd5bdeae83970ce01a25cd28d84900d538cd Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 26 Mar 2019 09:12:30 -0400 Subject: [PATCH 304/495] [Messenger] ReceiverInterface::handle() to get() & Worker with prioritized transports --- src/Symfony/Component/Messenger/CHANGELOG.md | 9 +- .../Command/ConsumeMessagesCommand.php | 77 ++++-- .../Command/ConsumeMessagesCommandTest.php | 12 +- .../DependencyInjection/MessengerPassTest.php | 6 +- .../Tests/Fixtures/CallbackReceiver.php | 48 ---- .../Messenger/Tests/Fixtures/DummyWorker.php | 46 ++++ .../AmqpExt/AmqpExtIntegrationTest.php | 113 +++----- .../Transport/AmqpExt/AmqpReceiverTest.php | 31 +-- .../Transport/AmqpExt/AmqpTransportTest.php | 7 +- .../AmqpExt/Fixtures/long_receiver.php | 4 +- ...pWhenMemoryUsageIsExceededReceiverTest.php | 84 ------ ...WhenMessageCountIsExceededReceiverTest.php | 103 ------- ...StopWhenTimeLimitIsReachedReceiverTest.php | 49 ---- ...topWhenMemoryUsageIsExceededWorkerTest.php | 71 +++++ ...opWhenMessageCountIsExceededWorkerTest.php | 71 +++++ .../StopWhenTimeLimitIsReachedWorkerTest.php | 44 +++ .../Component/Messenger/Tests/WorkerTest.php | 255 ++++++++++++++---- .../Transport/AmqpExt/AmqpReceiver.php | 59 ++-- .../Transport/AmqpExt/AmqpTransport.php | 12 +- .../Transport/Receiver/ReceiverInterface.php | 22 +- .../StopWhenMemoryUsageIsExceededReceiver.php | 68 ----- ...StopWhenMessageCountIsExceededReceiver.php | 65 ----- .../StopWhenTimeLimitIsReachedReceiver.php | 66 ----- src/Symfony/Component/Messenger/Worker.php | 184 +++++++------ .../StopWhenMemoryUsageIsExceededWorker.php | 61 +++++ .../StopWhenMessageCountIsExceededWorker.php | 58 ++++ .../StopWhenTimeLimitIsReachedWorker.php | 59 ++++ .../Component/Messenger/WorkerInterface.php | 37 +++ 28 files changed, 917 insertions(+), 804 deletions(-) delete mode 100644 src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php create mode 100644 src/Symfony/Component/Messenger/Tests/Fixtures/DummyWorker.php delete mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiverTest.php delete mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMessageCountIsExceededReceiverTest.php delete mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenTimeLimitIsReachedReceiverTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Worker/StopWhenMemoryUsageIsExceededWorkerTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Worker/StopWhenMessageCountIsExceededWorkerTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Worker/StopWhenTimeLimitIsReachedWorkerTest.php delete mode 100644 src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php delete mode 100644 src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php delete mode 100644 src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php create mode 100644 src/Symfony/Component/Messenger/Worker/StopWhenMemoryUsageIsExceededWorker.php create mode 100644 src/Symfony/Component/Messenger/Worker/StopWhenMessageCountIsExceededWorker.php create mode 100644 src/Symfony/Component/Messenger/Worker/StopWhenTimeLimitIsReachedWorker.php create mode 100644 src/Symfony/Component/Messenger/WorkerInterface.php diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 9638de4e49092..54b22a321f086 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -11,8 +11,9 @@ CHANGELOG to the `Envelope` then find the correct bus when receiving from the transport. See `ConsumeMessagesCommand`. * The optional `$busNames` constructor argument of the class `ConsumeMessagesCommand` was removed. - * [BC BREAK] 2 new methods were added to `ReceiverInterface`: - `ack()` and `reject()`. + * [BC BREAK] 3 new methods were added to `ReceiverInterface`: + `ack()`, `reject()` and `get()`. The methods `receive()` + and `stop()` were removed. * [BC BREAK] Error handling was moved from the receivers into `Worker`. Implementations of `ReceiverInterface::handle()` should now allow all exceptions to be thrown, except for transport @@ -24,7 +25,9 @@ CHANGELOG * The default command name for `ConsumeMessagesCommand` was changed from `messenger:consume-messages` to `messenger:consume` * `ConsumeMessagesCommand` has two new optional constructor arguments - * `Worker` has 4 new option constructor arguments. + * [BC BREAK] The first argument to Worker changed from a single + `ReceiverInterface` to an array of `ReceiverInterface`. + * `Worker` has 3 new optional constructor arguments. * The `Worker` class now handles calling `pcntl_signal_dispatch()` the receiver no longer needs to call this. * The `AmqpSender` will now retry messages using a dead-letter exchange diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index e49b28705c876..bd3a7a177c6c3 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -19,12 +19,13 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Messenger\RoutableMessageBus; -use Symfony\Component\Messenger\Transport\Receiver\StopWhenMemoryUsageIsExceededReceiver; -use Symfony\Component\Messenger\Transport\Receiver\StopWhenMessageCountIsExceededReceiver; -use Symfony\Component\Messenger\Transport\Receiver\StopWhenTimeLimitIsReachedReceiver; use Symfony\Component\Messenger\Worker; +use Symfony\Component\Messenger\Worker\StopWhenMemoryUsageIsExceededWorker; +use Symfony\Component\Messenger\Worker\StopWhenMessageCountIsExceededWorker; +use Symfony\Component\Messenger\Worker\StopWhenTimeLimitIsReachedWorker; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** @@ -70,10 +71,11 @@ protected function configure(): void $this ->setDefinition([ - new InputArgument('receiver', $defaultReceiverName ? InputArgument::OPTIONAL : InputArgument::REQUIRED, 'Name of the receiver', $defaultReceiverName), + new InputArgument('receivers', InputArgument::IS_ARRAY, 'Names of the receivers/transports to consume in order of priority', $defaultReceiverName ? [$defaultReceiverName] : []), new InputOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit the number of received messages'), new InputOption('memory-limit', 'm', InputOption::VALUE_REQUIRED, 'The memory limit the worker can consume'), new InputOption('time-limit', 't', InputOption::VALUE_REQUIRED, 'The time limit in seconds the worker can run'), + new InputOption('sleep', null, InputOption::VALUE_REQUIRED, 'Seconds to sleep before asking for new messages after no messages were found', 1), new InputOption('bus', 'b', InputOption::VALUE_REQUIRED, 'Name of the bus to which received messages should be dispatched (if not passed, bus is determined automatically.'), ]) ->setDescription('Consumes messages') @@ -82,6 +84,10 @@ protected function configure(): void php %command.full_name% +To receive from multiple transports, pass each name: + + php %command.full_name% receiver1 receiver2 + Use the --limit option to limit the number of messages received: php %command.full_name% --limit=10 @@ -111,16 +117,22 @@ protected function interact(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); - if ($this->receiverNames && !$this->receiverLocator->has($receiverName = $input->getArgument('receiver'))) { - if (null === $receiverName) { - $io->block('Missing receiver argument.', null, 'error', ' ', true); - $input->setArgument('receiver', $io->choice('Select one of the available receivers', $this->receiverNames)); - } elseif ($alternatives = $this->findAlternatives($receiverName, $this->receiverNames)) { - $io->block(sprintf('Receiver "%s" is not defined.', $receiverName), null, 'error', ' ', true); - if ($io->confirm(sprintf('Do you want to receive from "%s" instead? ', $alternatives[0]), false)) { - $input->setArgument('receiver', $alternatives[0]); - } + if ($this->receiverNames && 0 === \count($input->getArgument('receivers'))) { + $io->block('Which transports/receivers do you want to consume?', null, 'fg=white;bg=blue', ' ', true); + + $io->writeln('Choose which receivers you want to consume messages from in order of priority.'); + if (\count($this->receiverNames) > 1) { + $io->writeln(sprintf('Hint: to consume from multiple, use a list of their names, e.g. %s', implode(', ', $this->receiverNames))); } + + $question = new ChoiceQuestion('Select receivers to consume:', $this->receiverNames, 0); + $question->setMultiselect(true); + + $input->setArgument('receivers', $io->askQuestion($question)); + } + + if (0 === \count($input->getArgument('receivers'))) { + throw new RuntimeException('Please pass at least one receiver.'); } } @@ -135,16 +147,25 @@ protected function execute(InputInterface $input, OutputInterface $output): void $output->writeln(sprintf('%s', $message)); } - if (!$this->receiverLocator->has($receiverName = $input->getArgument('receiver'))) { - throw new RuntimeException(sprintf('Receiver "%s" does not exist.', $receiverName)); - } + $receivers = []; + $retryStrategies = []; + foreach ($receiverNames = $input->getArgument('receivers') as $receiverName) { + if (!$this->receiverLocator->has($receiverName)) { + $message = sprintf('The receiver "%s" does not exist.', $receiverName); + if ($this->receiverNames) { + $message .= sprintf(' Valid receivers are: %s.', implode(', ', $this->receiverNames)); + } - if (null !== $this->retryStrategyLocator && !$this->retryStrategyLocator->has($receiverName)) { - throw new RuntimeException(sprintf('Receiver "%s" does not have a configured retry strategy.', $receiverName)); - } + throw new RuntimeException($message); + } - $receiver = $this->receiverLocator->get($receiverName); - $retryStrategy = null !== $this->retryStrategyLocator ? $this->retryStrategyLocator->get($receiverName) : null; + if (null !== $this->retryStrategyLocator && !$this->retryStrategyLocator->has($receiverName)) { + throw new RuntimeException(sprintf('Receiver "%s" does not have a configured retry strategy.', $receiverName)); + } + + $receivers[$receiverName] = $this->receiverLocator->get($receiverName); + $retryStrategies[$receiverName] = null !== $this->retryStrategyLocator ? $this->retryStrategyLocator->get($receiverName) : null; + } if (null !== $input->getOption('bus')) { $bus = $this->busLocator->get($input->getOption('bus')); @@ -152,24 +173,25 @@ protected function execute(InputInterface $input, OutputInterface $output): void $bus = new RoutableMessageBus($this->busLocator); } + $worker = new Worker($receivers, $bus, $retryStrategies, $this->eventDispatcher, $this->logger); $stopsWhen = []; if ($limit = $input->getOption('limit')) { $stopsWhen[] = "processed {$limit} messages"; - $receiver = new StopWhenMessageCountIsExceededReceiver($receiver, $limit, $this->logger); + $worker = new StopWhenMessageCountIsExceededWorker($worker, $limit, $this->logger); } if ($memoryLimit = $input->getOption('memory-limit')) { $stopsWhen[] = "exceeded {$memoryLimit} of memory"; - $receiver = new StopWhenMemoryUsageIsExceededReceiver($receiver, $this->convertToBytes($memoryLimit), $this->logger); + $worker = new StopWhenMemoryUsageIsExceededWorker($worker, $this->convertToBytes($memoryLimit), $this->logger); } if ($timeLimit = $input->getOption('time-limit')) { $stopsWhen[] = "been running for {$timeLimit}s"; - $receiver = new StopWhenTimeLimitIsReachedReceiver($receiver, $timeLimit, $this->logger); + $worker = new StopWhenTimeLimitIsReachedWorker($worker, $timeLimit, $this->logger); } $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); - $io->success(sprintf('Consuming messages from transport "%s".', $receiverName)); + $io->success(sprintf('Consuming messages from transport%s "%s".', \count($receivers) > 0 ? 's' : '', implode(', ', $receiverNames))); if ($stopsWhen) { $last = array_pop($stopsWhen); @@ -183,8 +205,9 @@ protected function execute(InputInterface $input, OutputInterface $output): void $io->comment('Re-run the command with a -vv option to see logs about consumed messages.'); } - $worker = new Worker($receiver, $bus, $receiverName, $retryStrategy, $this->eventDispatcher, $this->logger); - $worker->run(); + $worker->run([ + 'sleep' => $input->getOption('sleep') * 1000000, + ]); } private function convertToBytes(string $memoryLimit): int diff --git a/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php index 336cd8129cf4c..e7ce90b85c0bf 100644 --- a/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/ConsumeMessagesCommandTest.php @@ -20,16 +20,8 @@ class ConsumeMessagesCommandTest extends TestCase public function testConfigurationWithDefaultReceiver() { $command = new ConsumeMessagesCommand($this->createMock(ServiceLocator::class), $this->createMock(ServiceLocator::class), null, ['amqp']); - $inputArgument = $command->getDefinition()->getArgument('receiver'); + $inputArgument = $command->getDefinition()->getArgument('receivers'); $this->assertFalse($inputArgument->isRequired()); - $this->assertSame('amqp', $inputArgument->getDefault()); - } - - public function testConfigurationWithoutDefaultReceiver() - { - $command = new ConsumeMessagesCommand($this->createMock(ServiceLocator::class), $this->createMock(ServiceLocator::class), null, ['amqp', 'dummy']); - $inputArgument = $command->getDefinition()->getArgument('receiver'); - $this->assertTrue($inputArgument->isRequired()); - $this->assertNull($inputArgument->getDefault()); + $this->assertSame(['amqp'], $inputArgument->getDefault()); } } diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 4e32ba9b49aab..51e7cbc88c1f3 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -612,11 +612,9 @@ public function __invoke(DummyMessage $message): void class DummyReceiver implements ReceiverInterface { - public function receive(callable $handler): void + public function get(): iterable { - for ($i = 0; $i < 3; ++$i) { - $handler(new Envelope(new DummyMessage("Dummy $i"))); - } + yield new Envelope(new DummyMessage('Dummy')); } public function stop(): void diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php b/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php deleted file mode 100644 index b1d26934d252c..0000000000000 --- a/src/Symfony/Component/Messenger/Tests/Fixtures/CallbackReceiver.php +++ /dev/null @@ -1,48 +0,0 @@ -callable = $callable; - } - - public function receive(callable $handler): void - { - $callable = $this->callable; - $callable($handler); - } - - public function stop(): void - { - } - - public function ack(Envelope $envelope): void - { - ++$this->acknowledgeCount; - } - - public function reject(Envelope $envelope): void - { - ++$this->rejectCount; - } - - public function getAcknowledgeCount(): int - { - return $this->acknowledgeCount; - } - - public function getRejectCount(): int - { - return $this->rejectCount; - } -} diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/DummyWorker.php b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyWorker.php new file mode 100644 index 0000000000000..2c66bdedbeba6 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyWorker.php @@ -0,0 +1,46 @@ +envelopesToReceive = $envelopesToReceive; + } + + public function run(array $options = [], callable $onHandledCallback = null): void + { + foreach ($this->envelopesToReceive as $envelope) { + if (true === $this->isStopped) { + break; + } + + if ($onHandledCallback) { + $onHandledCallback($envelope); + ++$this->envelopesHandled; + } + } + } + + public function stop(): void + { + $this->isStopped = true; + } + + public function isStopped(): bool + { + return $this->isStopped; + } + + public function countEnvelopesHandled() + { + return $this->envelopesHandled; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php index 2949ae837fe36..b2ebfe4ab5043 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php @@ -57,16 +57,20 @@ public function testItSendsAndReceivesMessages() $sender->send($first = new Envelope(new DummyMessage('First'))); $sender->send($second = new Envelope(new DummyMessage('Second'))); - $receivedMessages = 0; - $receiver->receive(function (?Envelope $envelope) use ($receiver, &$receivedMessages, $first, $second) { - $expectedEnvelope = 0 === $receivedMessages ? $first : $second; - $this->assertEquals($expectedEnvelope->getMessage(), $envelope->getMessage()); - $this->assertInstanceOf(AmqpReceivedStamp::class, $envelope->last(AmqpReceivedStamp::class)); - - if (2 === ++$receivedMessages) { - $receiver->stop(); - } - }); + $envelopes = iterator_to_array($receiver->get()); + $this->assertCount(1, $envelopes); + /** @var Envelope $envelope */ + $envelope = $envelopes[0]; + $this->assertEquals($first->getMessage(), $envelope->getMessage()); + $this->assertInstanceOf(AmqpReceivedStamp::class, $envelope->last(AmqpReceivedStamp::class)); + + $envelopes = iterator_to_array($receiver->get()); + $this->assertCount(1, $envelopes); + /** @var Envelope $envelope */ + $envelope = $envelopes[0]; + $this->assertEquals($second->getMessage(), $envelope->getMessage()); + + $this->assertEmpty(iterator_to_array($receiver->get())); } public function testRetryAndDelay() @@ -82,50 +86,38 @@ public function testRetryAndDelay() $sender->send($first = new Envelope(new DummyMessage('First'))); - $receivedMessages = 0; - $startTime = time(); - $receiver->receive(function (?Envelope $envelope) use ($receiver, $sender, &$receivedMessages, $startTime) { - if (null === $envelope) { - // if we have been processing for 4 seconds + have received 2 messages - // then it's safe to say no other messages will be received - if (time() > $startTime + 4 && 2 === $receivedMessages) { - $receiver->stop(); - } - - return; - } - - ++$receivedMessages; - - // retry the first time - if (1 === $receivedMessages) { - // imitate what Worker does - $envelope = $envelope - ->with(new DelayStamp(2000)) - ->with(new RedeliveryStamp(1, 'not_important')); - $sender->send($envelope); - $receiver->ack($envelope); + $envelopes = iterator_to_array($receiver->get()); + /** @var Envelope $envelope */ + $envelope = $envelopes[0]; + $newEnvelope = $envelope + ->with(new DelayStamp(2000)) + ->with(new RedeliveryStamp(1, 'not_important')); + $sender->send($newEnvelope); + $receiver->ack($envelope); - return; - } + $envelopes = []; + $startTime = time(); + // wait for next message, but only for max 3 seconds + while (0 === \count($envelopes) && $startTime + 3 > time()) { + $envelopes = iterator_to_array($receiver->get()); + } - if (2 === $receivedMessages) { - // should have a 2 second delay - $this->assertGreaterThanOrEqual($startTime + 2, time()); - // but only a 2 second delay - $this->assertLessThan($startTime + 4, time()); + $this->assertCount(1, $envelopes); + /** @var Envelope $envelope */ + $envelope = $envelopes[0]; - /** @var RedeliveryStamp|null $retryStamp */ - // verify the stamp still exists from the last send - $retryStamp = $envelope->last(RedeliveryStamp::class); - $this->assertNotNull($retryStamp); - $this->assertSame(1, $retryStamp->getRetryCount()); + // should have a 2 second delay + $this->assertGreaterThanOrEqual($startTime + 2, time()); + // but only a 2 second delay + $this->assertLessThan($startTime + 4, time()); - $receiver->ack($envelope); + /** @var RedeliveryStamp|null $retryStamp */ + // verify the stamp still exists from the last send + $retryStamp = $envelope->last(RedeliveryStamp::class); + $this->assertNotNull($retryStamp); + $this->assertSame(1, $retryStamp->getRetryCount()); - return; - } - }); + $receiver->ack($envelope); } public function testItReceivesSignals() @@ -175,29 +167,6 @@ public function testItReceivesSignals() , $process->getOutput()); } - /** - * @runInSeparateProcess - */ - public function testItSupportsTimeoutAndTicksNullMessagesToTheHandler() - { - $serializer = $this->createSerializer(); - - $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN'), ['read_timeout' => '1']); - $connection->setup(); - $connection->queue()->purge(); - - $receiver = new AmqpReceiver($connection, $serializer); - - $receivedMessages = 0; - $receiver->receive(function (?Envelope $envelope) use ($receiver, &$receivedMessages) { - $this->assertNull($envelope); - - if (2 === ++$receivedMessages) { - $receiver->stop(); - } - }); - } - private function waitForOutput(Process $process, string $output, $timeoutInSeconds = 10) { $timedOutTime = time() + $timeoutInSeconds; diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php index d0c8abfa3564e..d27ddb9cd26a9 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php @@ -14,9 +14,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\Serializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Serializer as SerializerComponent; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; @@ -26,7 +28,7 @@ */ class AmqpReceiverTest extends TestCase { - public function testItSendTheDecodedMessageToTheHandler() + public function testItReturnsTheDecodedMessageToTheHandler() { $serializer = new Serializer( new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) @@ -37,10 +39,9 @@ public function testItSendTheDecodedMessageToTheHandler() $connection->method('get')->willReturn($amqpEnvelope); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function (?Envelope $envelope) use ($receiver) { - $this->assertEquals(new DummyMessage('Hi'), $envelope->getMessage()); - $receiver->stop(); - }); + $actualEnvelopes = iterator_to_array($receiver->get()); + $this->assertCount(1, $actualEnvelopes); + $this->assertEquals(new DummyMessage('Hi'), $actualEnvelopes[0]->getMessage()); } /** @@ -48,20 +49,14 @@ public function testItSendTheDecodedMessageToTheHandler() */ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); - + $serializer = $this->createMock(SerializerInterface::class); $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $connection->method('get')->willReturn($amqpEnvelope); $connection->method('ack')->with($amqpEnvelope)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function (?Envelope $envelope) use ($receiver) { - $receiver->ack($envelope); - $receiver->stop(); - }); + $receiver->ack(new Envelope(new \stdClass(), new AmqpReceivedStamp($amqpEnvelope))); } /** @@ -69,20 +64,14 @@ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() */ public function testItThrowsATransportExceptionIfItCannotRejectMessage() { - $serializer = new Serializer( - new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) - ); - + $serializer = $this->createMock(SerializerInterface::class); $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); $connection->method('get')->willReturn($amqpEnvelope); $connection->method('nack')->with($amqpEnvelope, AMQP_NOPARAM)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->receive(function (?Envelope $envelope) use ($receiver) { - $receiver->reject($envelope); - $receiver->stop(); - }); + $receiver->reject(new Envelope(new \stdClass(), new AmqpReceivedStamp($amqpEnvelope))); } private function createAMQPEnvelope() diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php index c343c29226369..b3e8b5729dd70 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php @@ -47,11 +47,8 @@ public function testReceivesMessages() $serializer->method('decode')->with(['body' => 'body', 'headers' => ['my' => 'header']])->willReturn(new Envelope($decodedMessage)); $connection->method('get')->willReturn($amqpEnvelope); - $transport->receive(function (Envelope $envelope) use ($transport, $decodedMessage) { - $this->assertSame($decodedMessage, $envelope->getMessage()); - - $transport->stop(); - }); + $envelopes = iterator_to_array($transport->get()); + $this->assertSame($decodedMessage, $envelopes[0]->getMessage()); } private function getTransport(SerializerInterface $serializer = null, Connection $connection = null) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php index ba7236103579b..f51412093451c 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php @@ -32,7 +32,7 @@ $receiver = new AmqpReceiver($connection, $serializer); $retryStrategy = new MultiplierRetryStrategy(3, 0); -$worker = new Worker($receiver, new class() implements MessageBusInterface { +$worker = new Worker(['the_receiver' => $receiver], new class() implements MessageBusInterface { public function dispatch($envelope): Envelope { echo 'Get envelope with message: '.\get_class($envelope->getMessage())."\n"; @@ -43,7 +43,7 @@ public function dispatch($envelope): Envelope return $envelope; } -}, 'the_receiver', $retryStrategy); +}); echo "Receiving messages...\n"; $worker->run(); diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiverTest.php deleted file mode 100644 index 27314e75502e7..0000000000000 --- a/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiverTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Tests\Transport\Receiver; - -use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Tests\Fixtures\CallbackReceiver; -use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -use Symfony\Component\Messenger\Transport\Receiver\StopWhenMemoryUsageIsExceededReceiver; - -class StopWhenMemoryUsageIsExceededReceiverTest extends TestCase -{ - /** - * @dataProvider memoryProvider - */ - public function testReceiverStopsWhenMemoryLimitExceeded(int $memoryUsage, int $memoryLimit, bool $shouldStop) - { - $callable = function ($handler) { - $handler(new Envelope(new DummyMessage('API'))); - }; - - $decoratedReceiver = $this->getMockBuilder(CallbackReceiver::class) - ->setConstructorArgs([$callable]) - ->enableProxyingToOriginalMethods() - ->getMock(); - - $decoratedReceiver->expects($this->once())->method('receive'); - if (true === $shouldStop) { - $decoratedReceiver->expects($this->once())->method('stop'); - } else { - $decoratedReceiver->expects($this->never())->method('stop'); - } - - $memoryResolver = function () use ($memoryUsage) { - return $memoryUsage; - }; - - $memoryLimitReceiver = new StopWhenMemoryUsageIsExceededReceiver($decoratedReceiver, $memoryLimit, null, $memoryResolver); - $memoryLimitReceiver->receive(function () {}); - } - - public function memoryProvider() - { - yield [2048, 1024, true]; - yield [1024, 1024, false]; - yield [1024, 2048, false]; - } - - public function testReceiverLogsMemoryExceededWhenLoggerIsGiven() - { - $callable = function ($handler) { - $handler(new Envelope(new DummyMessage('API'))); - }; - - $decoratedReceiver = $this->getMockBuilder(CallbackReceiver::class) - ->setConstructorArgs([$callable]) - ->enableProxyingToOriginalMethods() - ->getMock(); - - $decoratedReceiver->expects($this->once())->method('receive'); - $decoratedReceiver->expects($this->once())->method('stop'); - - $logger = $this->createMock(LoggerInterface::class); - $logger->expects($this->once())->method('info') - ->with('Receiver stopped due to memory limit of {limit} exceeded', ['limit' => 64 * 1024 * 1024]); - - $memoryResolver = function () { - return 70 * 1024 * 1024; - }; - - $memoryLimitReceiver = new StopWhenMemoryUsageIsExceededReceiver($decoratedReceiver, 64 * 1024 * 1024, $logger, $memoryResolver); - $memoryLimitReceiver->receive(function () {}); - } -} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMessageCountIsExceededReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMessageCountIsExceededReceiverTest.php deleted file mode 100644 index 1a303728a94e4..0000000000000 --- a/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenMessageCountIsExceededReceiverTest.php +++ /dev/null @@ -1,103 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Tests\Transport\Receiver; - -use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Tests\Fixtures\CallbackReceiver; -use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -use Symfony\Component\Messenger\Transport\Receiver\StopWhenMessageCountIsExceededReceiver; - -class StopWhenMessageCountIsExceededReceiverTest extends TestCase -{ - /** - * @dataProvider countProvider - */ - public function testReceiverStopsWhenMaximumCountExceeded($max, $shouldStop) - { - $callable = function ($handler) { - $handler(new Envelope(new DummyMessage('First message'))); - $handler(new Envelope(new DummyMessage('Second message'))); - $handler(new Envelope(new DummyMessage('Third message'))); - }; - - $decoratedReceiver = $this->getMockBuilder(CallbackReceiver::class) - ->setConstructorArgs([$callable]) - ->enableProxyingToOriginalMethods() - ->getMock(); - - $decoratedReceiver->expects($this->once())->method('receive'); - if (true === $shouldStop) { - $decoratedReceiver->expects($this->any())->method('stop'); - } else { - $decoratedReceiver->expects($this->never())->method('stop'); - } - - $maximumCountReceiver = new StopWhenMessageCountIsExceededReceiver($decoratedReceiver, $max); - $maximumCountReceiver->receive(function () {}); - } - - public function countProvider() - { - yield [1, true]; - yield [2, true]; - yield [3, true]; - yield [4, false]; - } - - public function testReceiverDoesntIncreaseItsCounterWhenReceiveNullMessage() - { - $callable = function ($handler) { - $handler(null); - $handler(null); - $handler(null); - $handler(null); - }; - - $decoratedReceiver = $this->getMockBuilder(CallbackReceiver::class) - ->setConstructorArgs([$callable]) - ->enableProxyingToOriginalMethods() - ->getMock(); - - $decoratedReceiver->expects($this->once())->method('receive'); - $decoratedReceiver->expects($this->never())->method('stop'); - - $maximumCountReceiver = new StopWhenMessageCountIsExceededReceiver($decoratedReceiver, 1); - $maximumCountReceiver->receive(function () {}); - } - - public function testReceiverLogsMaximumCountExceededWhenLoggerIsGiven() - { - $callable = function ($handler) { - $handler(new Envelope(new DummyMessage('First message'))); - }; - - $decoratedReceiver = $this->getMockBuilder(CallbackReceiver::class) - ->setConstructorArgs([$callable]) - ->enableProxyingToOriginalMethods() - ->getMock(); - - $decoratedReceiver->expects($this->once())->method('receive'); - $decoratedReceiver->expects($this->once())->method('stop'); - - $logger = $this->createMock(LoggerInterface::class); - $logger->expects($this->once())->method('info') - ->with( - $this->equalTo('Receiver stopped due to maximum count of {count} exceeded'), - $this->equalTo(['count' => 1]) - ); - - $maximumCountReceiver = new StopWhenMessageCountIsExceededReceiver($decoratedReceiver, 1, $logger); - $maximumCountReceiver->receive(function () {}); - } -} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenTimeLimitIsReachedReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenTimeLimitIsReachedReceiverTest.php deleted file mode 100644 index 472703fe6f7f1..0000000000000 --- a/src/Symfony/Component/Messenger/Tests/Transport/Receiver/StopWhenTimeLimitIsReachedReceiverTest.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Tests\Transport\Receiver; - -use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Tests\Fixtures\CallbackReceiver; -use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -use Symfony\Component\Messenger\Transport\Receiver\StopWhenTimeLimitIsReachedReceiver; - -class StopWhenTimeLimitIsReachedReceiverTest extends TestCase -{ - /** - * @group time-sensitive - */ - public function testReceiverStopsWhenTimeLimitIsReached() - { - $callable = function ($handler) { - $handler(new Envelope(new DummyMessage('API'))); - }; - - $decoratedReceiver = $this->getMockBuilder(CallbackReceiver::class) - ->setConstructorArgs([$callable]) - ->enableProxyingToOriginalMethods() - ->getMock(); - - $decoratedReceiver->expects($this->once())->method('receive'); - $decoratedReceiver->expects($this->once())->method('stop'); - - $logger = $this->createMock(LoggerInterface::class); - $logger->expects($this->once())->method('info') - ->with('Receiver stopped due to time limit of {timeLimit}s reached', ['timeLimit' => 1]); - - $timeoutReceiver = new StopWhenTimeLimitIsReachedReceiver($decoratedReceiver, 1, $logger); - $timeoutReceiver->receive(function () { - sleep(2); - }); - } -} diff --git a/src/Symfony/Component/Messenger/Tests/Worker/StopWhenMemoryUsageIsExceededWorkerTest.php b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenMemoryUsageIsExceededWorkerTest.php new file mode 100644 index 0000000000000..d8a80e37a1468 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenMemoryUsageIsExceededWorkerTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Worker; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Tests\Fixtures\DummyWorker; +use Symfony\Component\Messenger\Worker\StopWhenMemoryUsageIsExceededWorker; + +class StopWhenMemoryUsageIsExceededWorkerTest extends TestCase +{ + /** + * @dataProvider memoryProvider + */ + public function testWorkerStopsWhenMemoryLimitExceeded(int $memoryUsage, int $memoryLimit, bool $shouldStop) + { + $handlerCalledTimes = 0; + $handledCallback = function () use (&$handlerCalledTimes) { + ++$handlerCalledTimes; + }; + $decoratedWorker = new DummyWorker([ + new Envelope(new \stdClass()), + ]); + + $memoryResolver = function () use ($memoryUsage) { + return $memoryUsage; + }; + + $memoryLimitWorker = new StopWhenMemoryUsageIsExceededWorker($decoratedWorker, $memoryLimit, null, $memoryResolver); + $memoryLimitWorker->run([], $handledCallback); + + // handler should be called exactly 1 time + $this->assertSame($handlerCalledTimes, 1); + $this->assertSame($shouldStop, $decoratedWorker->isStopped()); + } + + public function memoryProvider() + { + yield [2048, 1024, true]; + yield [1024, 1024, false]; + yield [1024, 2048, false]; + } + + public function testWorkerLogsMemoryExceededWhenLoggerIsGiven() + { + $decoratedWorker = new DummyWorker([ + new Envelope(new \stdClass()), + ]); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once())->method('info') + ->with('Worker stopped due to memory limit of {limit} exceeded', ['limit' => 64 * 1024 * 1024]); + + $memoryResolver = function () { + return 70 * 1024 * 1024; + }; + + $memoryLimitWorker = new StopWhenMemoryUsageIsExceededWorker($decoratedWorker, 64 * 1024 * 1024, $logger, $memoryResolver); + $memoryLimitWorker->run(); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Worker/StopWhenMessageCountIsExceededWorkerTest.php b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenMessageCountIsExceededWorkerTest.php new file mode 100644 index 0000000000000..f22d4524bfd37 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenMessageCountIsExceededWorkerTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Worker; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Tests\Fixtures\DummyWorker; +use Symfony\Component\Messenger\Worker\StopWhenMessageCountIsExceededWorker; + +class StopWhenMessageCountIsExceededWorkerTest extends TestCase +{ + /** + * @dataProvider countProvider + */ + public function testWorkerStopsWhenMaximumCountExceeded($max, $shouldStop) + { + $handlerCalledTimes = 0; + $handledCallback = function () use (&$handlerCalledTimes) { + ++$handlerCalledTimes; + }; + // receive 3 real messages + $decoratedWorker = new DummyWorker([ + new Envelope(new DummyMessage('First message')), + null, + new Envelope(new DummyMessage('Second message')), + null, + new Envelope(new DummyMessage('Third message')), + ]); + + $maximumCountWorker = new StopWhenMessageCountIsExceededWorker($decoratedWorker, $max); + $maximumCountWorker->run([], $handledCallback); + + $this->assertSame($shouldStop, $decoratedWorker->isStopped()); + } + + public function countProvider() + { + yield [1, true]; + yield [2, true]; + yield [3, true]; + yield [4, false]; + } + + public function testWorkerLogsMaximumCountExceededWhenLoggerIsGiven() + { + $decoratedWorker = new DummyWorker([ + new Envelope(new \stdClass()), + ]); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once())->method('info') + ->with( + $this->equalTo('Worker stopped due to maximum count of {count} exceeded'), + $this->equalTo(['count' => 1]) + ); + + $maximumCountWorker = new StopWhenMessageCountIsExceededWorker($decoratedWorker, 1, $logger); + $maximumCountWorker->run(); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Worker/StopWhenTimeLimitIsReachedWorkerTest.php b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenTimeLimitIsReachedWorkerTest.php new file mode 100644 index 0000000000000..4b06c7392b4a6 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenTimeLimitIsReachedWorkerTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Worker; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Tests\Fixtures\DummyWorker; +use Symfony\Component\Messenger\Worker\StopWhenTimeLimitIsReachedWorker; + +class StopWhenTimeLimitIsReachedWorkerTest extends TestCase +{ + /** + * @group time-sensitive + */ + public function testWorkerStopsWhenTimeLimitIsReached() + { + $decoratedWorker = new DummyWorker([ + new Envelope(new \stdClass()), + new Envelope(new \stdClass()), + ]); + + $logger = $this->createMock(LoggerInterface::class); + $logger->expects($this->once())->method('info') + ->with('Worker stopped due to time limit of {timeLimit}s reached', ['timeLimit' => 1]); + + $timeoutWorker = new StopWhenTimeLimitIsReachedWorker($decoratedWorker, 1, $logger); + $timeoutWorker->run([], function () { + sleep(2); + }); + + $this->assertTrue($decoratedWorker->isStopped()); + $this->assertSame(1, $decoratedWorker->countEnvelopesHandled()); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php index 4ecb7719cbaef..b5c6a6557b2cd 100644 --- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php +++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php @@ -22,11 +22,14 @@ use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Stamp\RedeliveryStamp; use Symfony\Component\Messenger\Stamp\SentStamp; -use Symfony\Component\Messenger\Tests\Fixtures\CallbackReceiver; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Component\Messenger\Worker; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +/** + * @group time-sensitive + */ class WorkerTest extends TestCase { public function testWorkerDispatchTheReceivedMessage() @@ -34,18 +37,22 @@ public function testWorkerDispatchTheReceivedMessage() $apiMessage = new DummyMessage('API'); $ipaMessage = new DummyMessage('IPA'); - $receiver = new CallbackReceiver(function ($handler) use ($apiMessage, $ipaMessage) { - $handler(new Envelope($apiMessage)); - $handler(new Envelope($ipaMessage)); - }); + $receiver = new DummyReceiver([ + [new Envelope($apiMessage), new Envelope($ipaMessage)], + ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->expects($this->at(0))->method('dispatch')->with($envelope = new Envelope($apiMessage, new ReceivedStamp()))->willReturn($envelope); $bus->expects($this->at(1))->method('dispatch')->with($envelope = new Envelope($ipaMessage, new ReceivedStamp()))->willReturn($envelope); - $worker = new Worker($receiver, $bus, 'receiver_id'); - $worker->run(); + $worker = new Worker([$receiver], $bus); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); $this->assertSame(2, $receiver->getAcknowledgeCount()); } @@ -53,24 +60,26 @@ public function testWorkerDispatchTheReceivedMessage() public function testWorkerDoesNotWrapMessagesAlreadyWrappedWithReceivedMessage() { $envelope = new Envelope(new DummyMessage('API')); - $receiver = new CallbackReceiver(function ($handler) use ($envelope) { - $handler($envelope); - }); + $receiver = new DummyReceiver([[$envelope]]); $envelope = $envelope->with(new ReceivedStamp()); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->expects($this->at(0))->method('dispatch')->with($envelope)->willReturn($envelope); - $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); - $worker->run(); + $worker = new Worker([$receiver], $bus, []); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); } public function testDispatchCausesRetry() { - $receiver = new CallbackReceiver(function ($handler) { - $handler(new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))); - }); + $receiver = new DummyReceiver([ + [new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))], + ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->expects($this->at(0))->method('dispatch')->willThrowException(new \InvalidArgumentException('Why not')); @@ -93,8 +102,13 @@ public function testDispatchCausesRetry() $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); $retryStrategy->expects($this->once())->method('isRetryable')->willReturn(true); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); - $worker->run(); + $worker = new Worker(['receiver1' => $receiver], $bus, ['receiver1' => $retryStrategy]); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); // old message acknowledged $this->assertSame(1, $receiver->getAcknowledgeCount()); @@ -102,9 +116,9 @@ public function testDispatchCausesRetry() public function testDispatchCausesRejectWhenNoRetry() { - $receiver = new CallbackReceiver(function ($handler) { - $handler(new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))); - }); + $receiver = new DummyReceiver([ + [new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))], + ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->method('dispatch')->willThrowException(new \InvalidArgumentException('Why not')); @@ -112,17 +126,22 @@ public function testDispatchCausesRejectWhenNoRetry() $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); $retryStrategy->expects($this->once())->method('isRetryable')->willReturn(false); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); - $worker->run(); + $worker = new Worker(['receiver1' => $receiver], $bus, ['receiver1' => $retryStrategy]); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); $this->assertSame(1, $receiver->getRejectCount()); $this->assertSame(0, $receiver->getAcknowledgeCount()); } public function testDispatchCausesRejectOnUnrecoverableMessage() { - $receiver = new CallbackReceiver(function ($handler) { - $handler(new Envelope(new DummyMessage('Hello'))); - }); + $receiver = new DummyReceiver([ + [new Envelope(new DummyMessage('Hello'))], + ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->method('dispatch')->willThrowException(new UnrecoverableMessageHandlingException('Will never work')); @@ -130,36 +149,42 @@ public function testDispatchCausesRejectOnUnrecoverableMessage() $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); $retryStrategy->expects($this->never())->method('isRetryable'); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); - $worker->run(); + $worker = new Worker(['receiver1' => $receiver], $bus, ['receiver1' => $retryStrategy]); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); $this->assertSame(1, $receiver->getRejectCount()); } public function testWorkerDoesNotSendNullMessagesToTheBus() { - $receiver = new CallbackReceiver(function ($handler) { - $handler(null); - }); + $receiver = new DummyReceiver([ + null, + ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->expects($this->never())->method('dispatch'); - $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy); - $worker->run(); + $worker = new Worker([$receiver], $bus); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); } public function testWorkerDispatchesEventsOnSuccess() { $envelope = new Envelope(new DummyMessage('Hello')); - $receiver = new CallbackReceiver(function ($handler) use ($envelope) { - $handler($envelope); - }); + $receiver = new DummyReceiver([[$envelope]]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $bus->method('dispatch')->willReturn($envelope); - $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); $eventDispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $eventDispatcher->expects($this->exactly(2)) @@ -169,22 +194,24 @@ public function testWorkerDispatchesEventsOnSuccess() [$this->isInstanceOf(WorkerMessageHandledEvent::class)] ); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy, $eventDispatcher); - $worker->run(); + $worker = new Worker([$receiver], $bus, [], $eventDispatcher); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); } public function testWorkerDispatchesEventsOnError() { $envelope = new Envelope(new DummyMessage('Hello')); - $receiver = new CallbackReceiver(function ($handler) use ($envelope) { - $handler($envelope); - }); + $receiver = new DummyReceiver([[$envelope]]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); $exception = new \InvalidArgumentException('Oh no!'); $bus->method('dispatch')->willThrowException($exception); - $retryStrategy = $this->getMockBuilder(RetryStrategyInterface::class)->getMock(); $eventDispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $eventDispatcher->expects($this->exactly(2)) @@ -194,7 +221,143 @@ public function testWorkerDispatchesEventsOnError() [$this->isInstanceOf(WorkerMessageFailedEvent::class)] ); - $worker = new Worker($receiver, $bus, 'receiver_id', $retryStrategy, $eventDispatcher); - $worker->run(); + $worker = new Worker([$receiver], $bus, [], $eventDispatcher); + $worker->run([], function (?Envelope $envelope) use ($worker) { + // stop after the messages finish + if (null === $envelope) { + $worker->stop(); + } + }); + } + + public function testTimeoutIsConfigurable() + { + $apiMessage = new DummyMessage('API'); + $receiver = new DummyReceiver([ + [new Envelope($apiMessage), new Envelope($apiMessage)], + [], // will cause a wait + [], // will cause a wait + [new Envelope($apiMessage)], + [new Envelope($apiMessage)], + [], // will cause a wait + [new Envelope($apiMessage)], + ]); + + $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); + + $worker = new Worker([$receiver], $bus); + $receivedCount = 0; + $startTime = microtime(true); + // sleep .1 after each idle + $worker->run(['sleep' => 100000], function (?Envelope $envelope) use ($worker, &$receivedCount, $startTime) { + if (null !== $envelope) { + ++$receivedCount; + } + + if (5 === $receivedCount) { + $worker->stop(); + $duration = microtime(true) - $startTime; + + // wait time should be .3 seconds + // use .29 & .31 for timing "wiggle room" + $this->assertGreaterThanOrEqual(.29, $duration); + $this->assertLessThan(.31, $duration); + } + }); + } + + public function testWorkerWithMultipleReceivers() + { + // envelopes, in their expected delivery order + $envelope1 = new Envelope(new DummyMessage('message1')); + $envelope2 = new Envelope(new DummyMessage('message2')); + $envelope3 = new Envelope(new DummyMessage('message3')); + $envelope4 = new Envelope(new DummyMessage('message4')); + $envelope5 = new Envelope(new DummyMessage('message5')); + $envelope6 = new Envelope(new DummyMessage('message6')); + + /* + * Round 1) receiver 1 & 2 have nothing, receiver 3 processes envelope1 and envelope2 + * Round 2) receiver 1 has nothing, receiver 2 processes envelope3, receiver 3 is not called + * Round 3) receiver 1 processes envelope 4, receivers 2 & 3 are not called + * Round 4) receiver 1 processes envelope 5, receivers 2 & 3 are not called + * Round 5) receiver 1 has nothing, receiver 2 has nothing, receiver 3 has envelope 6 + */ + $receiver1 = new DummyReceiver([ + [], + [], + [$envelope4], + [$envelope5], + [], + ]); + $receiver2 = new DummyReceiver([ + [], + [$envelope3], + [], + ]); + $receiver3 = new DummyReceiver([ + [$envelope1, $envelope2], + [], + [$envelope6], + ]); + + $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); + + $receivedCount = 0; + $worker = new Worker([$receiver1, $receiver2, $receiver3], $bus); + $processedEnvelopes = []; + $worker->run([], function (?Envelope $envelope) use ($worker, &$receivedCount, &$processedEnvelopes) { + if (null !== $envelope) { + $processedEnvelopes[] = $envelope; + ++$receivedCount; + } + + // stop after the messages finish + if (6 === $receivedCount) { + $worker->stop(); + } + }); + + // make sure they were processed in the correct order + $this->assertSame([$envelope1, $envelope2, $envelope3, $envelope4, $envelope5, $envelope6], $processedEnvelopes); + } +} + +class DummyReceiver implements ReceiverInterface +{ + private $deliveriesOfEnvelopes; + private $acknowledgeCount = 0; + private $rejectCount = 0; + + public function __construct(array $deliveriesOfEnvelopes) + { + $this->deliveriesOfEnvelopes = $deliveriesOfEnvelopes; + } + + public function get(): iterable + { + $val = array_shift($this->deliveriesOfEnvelopes); + + return null === $val ? [] : $val; + } + + public function ack(Envelope $envelope): void + { + ++$this->acknowledgeCount; + } + + public function reject(Envelope $envelope): void + { + ++$this->rejectCount; + } + + public function getAcknowledgeCount(): int + { + return $this->acknowledgeCount; + } + + public function getRejectCount(): int + { + return $this->rejectCount; } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index 93afbaff5d8b8..ce1918e1da0c1 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -30,7 +30,6 @@ class AmqpReceiver implements ReceiverInterface { private $serializer; private $connection; - private $shouldStop; public function __construct(Connection $connection, SerializerInterface $serializer = null) { @@ -41,38 +40,31 @@ public function __construct(Connection $connection, SerializerInterface $seriali /** * {@inheritdoc} */ - public function receive(callable $handler): void + public function get(): iterable { - while (!$this->shouldStop) { - try { - $amqpEnvelope = $this->connection->get(); - } catch (\AMQPException $exception) { - throw new TransportException($exception->getMessage(), 0, $exception); - } - - if (null === $amqpEnvelope) { - $handler(null); - - usleep($this->connection->getConnectionConfiguration()['loop_sleep'] ?? 200000); - - continue; - } - - try { - $envelope = $this->serializer->decode([ - 'body' => $amqpEnvelope->getBody(), - 'headers' => $amqpEnvelope->getHeaders(), - ]); - } catch (MessageDecodingFailedException $exception) { - // invalid message of some type - $this->rejectAmqpEnvelope($amqpEnvelope); - - throw $exception; - } - - $envelope = $envelope->with(new AmqpReceivedStamp($amqpEnvelope)); - $handler($envelope); + try { + $amqpEnvelope = $this->connection->get(); + } catch (\AMQPException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + if (null === $amqpEnvelope) { + return []; + } + + try { + $envelope = $this->serializer->decode([ + 'body' => $amqpEnvelope->getBody(), + 'headers' => $amqpEnvelope->getHeaders(), + ]); + } catch (MessageDecodingFailedException $exception) { + // invalid message of some type + $this->rejectAmqpEnvelope($amqpEnvelope); + + throw $exception; } + + yield $envelope->with(new AmqpReceivedStamp($amqpEnvelope)); } public function ack(Envelope $envelope): void @@ -89,11 +81,6 @@ public function reject(Envelope $envelope): void $this->rejectAmqpEnvelope($this->findAmqpEnvelope($envelope)); } - public function stop(): void - { - $this->shouldStop = true; - } - private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope): void { try { diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php index 2146bd900d29c..586e16c4d86dd 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php @@ -38,17 +38,9 @@ public function __construct(Connection $connection, SerializerInterface $seriali /** * {@inheritdoc} */ - public function receive(callable $handler): void + public function get(): iterable { - ($this->receiver ?? $this->getReceiver())->receive($handler); - } - - /** - * {@inheritdoc} - */ - public function stop(): void - { - ($this->receiver ?? $this->getReceiver())->stop(); + return ($this->receiver ?? $this->getReceiver())->get(); } /** diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php index 29da741a11f34..d974ff00b7902 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php @@ -25,21 +25,25 @@ interface ReceiverInterface /** * Receive some messages to the given handler. * - * The handler will have, as argument, the received {@link \Symfony\Component\Messenger\Envelope} containing the message. - * Note that this envelope can be `null` if the timeout to receive something has expired. + * While this method could return an unlimited number of messages, + * the intention is that it returns only one, or a "small number" + * of messages each time. This gives the user more flexibility: + * they can finish processing the one (or "small number") of messages + * from this receiver and move on to check other receivers for messages. + * If a this method returns too many messages, it could cause a + * blocking effect where handling the messages received from one + * call to get() takes a long time, blocking other receivers from + * being called. * - * If the received message cannot be decoded, the message should not + * If a received message cannot be decoded, the message should not * be retried again (e.g. if there's a queue, it should be removed) * and a MessageDecodingFailedException should be thrown. * * @throws TransportException If there is an issue communicating with the transport + * + * @return Envelope[] */ - public function receive(callable $handler): void; - - /** - * Stop receiving some messages. - */ - public function stop(): void; + public function get(): iterable; /** * Acknowledge that the passed message was handled. diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php deleted file mode 100644 index 09af4673b87b4..0000000000000 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMemoryUsageIsExceededReceiver.php +++ /dev/null @@ -1,68 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Transport\Receiver; - -use Psr\Log\LoggerInterface; -use Symfony\Component\Messenger\Envelope; - -/** - * @author Simon Delicata - * - * @experimental in 4.2 - */ -class StopWhenMemoryUsageIsExceededReceiver implements ReceiverInterface -{ - private $decoratedReceiver; - private $memoryLimit; - private $logger; - private $memoryResolver; - - public function __construct(ReceiverInterface $decoratedReceiver, int $memoryLimit, LoggerInterface $logger = null, callable $memoryResolver = null) - { - $this->decoratedReceiver = $decoratedReceiver; - $this->memoryLimit = $memoryLimit; - $this->logger = $logger; - $this->memoryResolver = $memoryResolver ?: function () { - return \memory_get_usage(); - }; - } - - public function receive(callable $handler): void - { - $this->decoratedReceiver->receive(function (?Envelope $envelope) use ($handler) { - $handler($envelope); - - $memoryResolver = $this->memoryResolver; - if ($memoryResolver() > $this->memoryLimit) { - $this->stop(); - if (null !== $this->logger) { - $this->logger->info('Receiver stopped due to memory limit of {limit} exceeded', ['limit' => $this->memoryLimit]); - } - } - }); - } - - public function stop(): void - { - $this->decoratedReceiver->stop(); - } - - public function ack(Envelope $envelope): void - { - $this->decoratedReceiver->ack($envelope); - } - - public function reject(Envelope $envelope): void - { - $this->decoratedReceiver->reject($envelope); - } -} diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php deleted file mode 100644 index 8be38d157e8f1..0000000000000 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenMessageCountIsExceededReceiver.php +++ /dev/null @@ -1,65 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Transport\Receiver; - -use Psr\Log\LoggerInterface; -use Symfony\Component\Messenger\Envelope; - -/** - * @author Samuel Roze - * - * @experimental in 4.2 - */ -class StopWhenMessageCountIsExceededReceiver implements ReceiverInterface -{ - private $decoratedReceiver; - private $maximumNumberOfMessages; - private $logger; - - public function __construct(ReceiverInterface $decoratedReceiver, int $maximumNumberOfMessages, LoggerInterface $logger = null) - { - $this->decoratedReceiver = $decoratedReceiver; - $this->maximumNumberOfMessages = $maximumNumberOfMessages; - $this->logger = $logger; - } - - public function receive(callable $handler): void - { - $receivedMessages = 0; - - $this->decoratedReceiver->receive(function (?Envelope $envelope) use ($handler, &$receivedMessages) { - $handler($envelope); - - if (null !== $envelope && ++$receivedMessages >= $this->maximumNumberOfMessages) { - $this->stop(); - if (null !== $this->logger) { - $this->logger->info('Receiver stopped due to maximum count of {count} exceeded', ['count' => $this->maximumNumberOfMessages]); - } - } - }); - } - - public function stop(): void - { - $this->decoratedReceiver->stop(); - } - - public function ack(Envelope $envelope): void - { - $this->decoratedReceiver->ack($envelope); - } - - public function reject(Envelope $envelope): void - { - $this->decoratedReceiver->reject($envelope); - } -} diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php b/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php deleted file mode 100644 index ade088b7dabb1..0000000000000 --- a/src/Symfony/Component/Messenger/Transport/Receiver/StopWhenTimeLimitIsReachedReceiver.php +++ /dev/null @@ -1,66 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Messenger\Transport\Receiver; - -use Psr\Log\LoggerInterface; -use Symfony\Component\Messenger\Envelope; - -/** - * @author Simon Delicata - * - * @experimental in 4.2 - */ -class StopWhenTimeLimitIsReachedReceiver implements ReceiverInterface -{ - private $decoratedReceiver; - private $timeLimitInSeconds; - private $logger; - - public function __construct(ReceiverInterface $decoratedReceiver, int $timeLimitInSeconds, LoggerInterface $logger = null) - { - $this->decoratedReceiver = $decoratedReceiver; - $this->timeLimitInSeconds = $timeLimitInSeconds; - $this->logger = $logger; - } - - public function receive(callable $handler): void - { - $startTime = microtime(true); - $endTime = $startTime + $this->timeLimitInSeconds; - - $this->decoratedReceiver->receive(function (?Envelope $envelope) use ($handler, $endTime) { - $handler($envelope); - - if ($endTime < microtime(true)) { - $this->stop(); - if (null !== $this->logger) { - $this->logger->info('Receiver stopped due to time limit of {timeLimit}s reached', ['timeLimit' => $this->timeLimitInSeconds]); - } - } - }); - } - - public function stop(): void - { - $this->decoratedReceiver->stop(); - } - - public function ack(Envelope $envelope): void - { - $this->decoratedReceiver->ack($envelope); - } - - public function reject(Envelope $envelope): void - { - $this->decoratedReceiver->reject($envelope); - } -} diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index a273b39da95a7..1e7f539f6ce40 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -32,112 +32,144 @@ * * @final */ -class Worker +class Worker implements WorkerInterface { - private $receiver; + private $receivers; private $bus; - private $receiverName; - private $retryStrategy; + private $retryStrategies; private $eventDispatcher; private $logger; + private $shouldStop = false; - public function __construct(ReceiverInterface $receiver, MessageBusInterface $bus, string $receiverName = null, RetryStrategyInterface $retryStrategy = null, EventDispatcherInterface $eventDispatcher = null, LoggerInterface $logger = null) + /** + * @param ReceiverInterface[] $receivers Where the key will be used as the string "identifier" + * @param RetryStrategyInterface[] $retryStrategies Retry strategies for each receiver (array keys must match) + */ + public function __construct(array $receivers, MessageBusInterface $bus, $retryStrategies = [], EventDispatcherInterface $eventDispatcher = null, LoggerInterface $logger = null) { - $this->receiver = $receiver; + $this->receivers = $receivers; $this->bus = $bus; - if (null === $receiverName) { - @trigger_error(sprintf('Instantiating the "%s" class without passing a third argument is deprecated since Symfony 4.3.', __CLASS__), E_USER_DEPRECATED); - - $receiverName = 'unknown'; - } - $this->receiverName = $receiverName; - $this->retryStrategy = $retryStrategy; + $this->retryStrategies = $retryStrategies; $this->eventDispatcher = $eventDispatcher; $this->logger = $logger; } /** * Receive the messages and dispatch them to the bus. + * + * Valid options are: + * * sleep (default: 1000000): Time in microseconds to sleep after no messages are found */ - public function run() + public function run(array $options = [], callable $onHandledCallback = null): void { + $options = array_merge([ + 'sleep' => 1000000, + ], $options); + if (\function_exists('pcntl_signal')) { pcntl_signal(SIGTERM, function () { - $this->receiver->stop(); + $this->stop(); }); } - $this->receiver->receive(function (?Envelope $envelope) { - if (null === $envelope) { - if (\function_exists('pcntl_signal_dispatch')) { - pcntl_signal_dispatch(); - } + $onHandled = function (?Envelope $envelope) use ($onHandledCallback) { + if (\function_exists('pcntl_signal_dispatch')) { + pcntl_signal_dispatch(); + } - return; + if (null !== $onHandledCallback) { + $onHandledCallback($envelope); } + }; - $this->dispatchEvent(new WorkerMessageReceivedEvent($envelope, $this->receiverName)); - - $message = $envelope->getMessage(); - $context = [ - 'message' => $message, - 'class' => \get_class($message), - ]; - - try { - $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp())); - } catch (\Throwable $throwable) { - $shouldRetry = $this->shouldRetry($throwable, $envelope); - - $this->dispatchEvent(new WorkerMessageFailedEvent($envelope, $this->receiverName, $throwable, $shouldRetry)); - - if ($shouldRetry) { - if (null === $this->retryStrategy) { - // not logically allowed, but check just in case - throw new LogicException('Retrying is not supported without a retry strategy.'); - } - - $retryCount = $this->getRetryCount($envelope) + 1; - if (null !== $this->logger) { - $this->logger->error('Retrying {class} - retry #{retryCount}.', $context + ['retryCount' => $retryCount, 'error' => $throwable]); - } - - // add the delay and retry stamp info + remove ReceivedStamp - $retryEnvelope = $envelope->with(new DelayStamp($this->retryStrategy->getWaitingTime($envelope))) - ->with(new RedeliveryStamp($retryCount, $this->getSenderAlias($envelope))) - ->withoutAll(ReceivedStamp::class); - - // re-send the message - $this->bus->dispatch($retryEnvelope); - // acknowledge the previous message has received - $this->receiver->ack($envelope); - } else { - if (null !== $this->logger) { - $this->logger->critical('Rejecting {class} (removing from transport).', $context + ['error' => $throwable]); - } - - $this->receiver->reject($envelope); - } + while (false === $this->shouldStop) { + $envelopeHandled = false; + foreach ($this->receivers as $receiverName => $receiver) { + $envelopes = $receiver->get(); + + foreach ($envelopes as $envelope) { + $envelopeHandled = true; - if (\function_exists('pcntl_signal_dispatch')) { - pcntl_signal_dispatch(); + $this->handleMessage($envelope, $receiver, $receiverName, $this->retryStrategies[$receiverName] ?? null); + $onHandled($envelope); } - return; + // after handling a single receiver, quit and start the loop again + // this should prevent multiple lower priority receivers from + // blocking too long before the higher priority are checked + if ($envelopeHandled) { + break; + } } - $this->dispatchEvent(new WorkerMessageHandledEvent($envelope, $this->receiverName)); + if (false === $envelopeHandled) { + $onHandled(null); - if (null !== $this->logger) { - $this->logger->info('{class} was handled successfully (acknowledging to transport).', $context); + usleep($options['sleep']); } + } + } - $this->receiver->ack($envelope); + private function handleMessage(Envelope $envelope, ReceiverInterface $receiver, string $receiverName, ?RetryStrategyInterface $retryStrategy) + { + $this->dispatchEvent(new WorkerMessageReceivedEvent($envelope, $receiverName)); - if (\function_exists('pcntl_signal_dispatch')) { - pcntl_signal_dispatch(); + $message = $envelope->getMessage(); + $context = [ + 'message' => $message, + 'class' => \get_class($message), + ]; + + try { + $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp())); + } catch (\Throwable $throwable) { + $shouldRetry = $this->shouldRetry($throwable, $envelope, $retryStrategy); + + $this->dispatchEvent(new WorkerMessageFailedEvent($envelope, $receiverName, $throwable, $shouldRetry)); + + if ($shouldRetry) { + if (null === $retryStrategy) { + // not logically allowed, but check just in case + throw new LogicException('Retrying is not supported without a retry strategy.'); + } + + $retryCount = $this->getRetryCount($envelope) + 1; + if (null !== $this->logger) { + $this->logger->error('Retrying {class} - retry #{retryCount}.', $context + ['retryCount' => $retryCount, 'error' => $throwable]); + } + + // add the delay and retry stamp info + remove ReceivedStamp + $retryEnvelope = $envelope->with(new DelayStamp($retryStrategy->getWaitingTime($envelope))) + ->with(new RedeliveryStamp($retryCount, $this->getSenderAlias($envelope))) + ->withoutAll(ReceivedStamp::class); + + // re-send the message + $this->bus->dispatch($retryEnvelope); + // acknowledge the previous message has received + $receiver->ack($envelope); + } else { + if (null !== $this->logger) { + $this->logger->critical('Rejecting {class} (removing from transport).', $context + ['error' => $throwable]); + } + + $receiver->reject($envelope); } - }); + + return; + } + + $this->dispatchEvent(new WorkerMessageHandledEvent($envelope, $receiverName)); + + if (null !== $this->logger) { + $this->logger->info('{class} was handled successfully (acknowledging to transport).', $context); + } + + $receiver->ack($envelope); + } + + public function stop(): void + { + $this->shouldStop = true; } private function dispatchEvent($event) @@ -149,17 +181,17 @@ private function dispatchEvent($event) $this->eventDispatcher->dispatch($event); } - private function shouldRetry(\Throwable $e, Envelope $envelope): bool + private function shouldRetry(\Throwable $e, Envelope $envelope, ?RetryStrategyInterface $retryStrategy): bool { if ($e instanceof UnrecoverableMessageHandlingException) { return false; } - if (null === $this->retryStrategy) { + if (null === $retryStrategy) { return false; } - return $this->retryStrategy->isRetryable($envelope); + return $retryStrategy->isRetryable($envelope); } private function getRetryCount(Envelope $envelope): int diff --git a/src/Symfony/Component/Messenger/Worker/StopWhenMemoryUsageIsExceededWorker.php b/src/Symfony/Component/Messenger/Worker/StopWhenMemoryUsageIsExceededWorker.php new file mode 100644 index 0000000000000..77e848898234d --- /dev/null +++ b/src/Symfony/Component/Messenger/Worker/StopWhenMemoryUsageIsExceededWorker.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Worker; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\WorkerInterface; + +/** + * @author Simon Delicata + * + * @experimental in 4.3 + */ +class StopWhenMemoryUsageIsExceededWorker implements WorkerInterface +{ + private $decoratedWorker; + private $memoryLimit; + private $logger; + private $memoryResolver; + + public function __construct(WorkerInterface $decoratedWorker, int $memoryLimit, LoggerInterface $logger = null, callable $memoryResolver = null) + { + $this->decoratedWorker = $decoratedWorker; + $this->memoryLimit = $memoryLimit; + $this->logger = $logger; + $this->memoryResolver = $memoryResolver ?: function () { + return \memory_get_usage(); + }; + } + + public function run(array $options = [], callable $onHandledCallback = null): void + { + $this->decoratedWorker->run($options, function (?Envelope $envelope) use ($onHandledCallback) { + if (null !== $onHandledCallback) { + $onHandledCallback($envelope); + } + + $memoryResolver = $this->memoryResolver; + if ($memoryResolver() > $this->memoryLimit) { + $this->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to memory limit of {limit} exceeded', ['limit' => $this->memoryLimit]); + } + } + }); + } + + public function stop(): void + { + $this->decoratedWorker->stop(); + } +} diff --git a/src/Symfony/Component/Messenger/Worker/StopWhenMessageCountIsExceededWorker.php b/src/Symfony/Component/Messenger/Worker/StopWhenMessageCountIsExceededWorker.php new file mode 100644 index 0000000000000..c72e2cc954a78 --- /dev/null +++ b/src/Symfony/Component/Messenger/Worker/StopWhenMessageCountIsExceededWorker.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Worker; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\WorkerInterface; + +/** + * @author Samuel Roze + * + * @experimental in 4.3 + */ +class StopWhenMessageCountIsExceededWorker implements WorkerInterface +{ + private $decoratedWorker; + private $maximumNumberOfMessages; + private $logger; + + public function __construct(WorkerInterface $decoratedWorker, int $maximumNumberOfMessages, LoggerInterface $logger = null) + { + $this->decoratedWorker = $decoratedWorker; + $this->maximumNumberOfMessages = $maximumNumberOfMessages; + $this->logger = $logger; + } + + public function run(array $options = [], callable $onHandledCallback = null): void + { + $receivedMessages = 0; + + $this->decoratedWorker->run($options, function (?Envelope $envelope) use ($onHandledCallback, &$receivedMessages) { + if (null !== $onHandledCallback) { + $onHandledCallback($envelope); + } + + if (null !== $envelope && ++$receivedMessages >= $this->maximumNumberOfMessages) { + $this->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to maximum count of {count} exceeded', ['count' => $this->maximumNumberOfMessages]); + } + } + }); + } + + public function stop(): void + { + $this->decoratedWorker->stop(); + } +} diff --git a/src/Symfony/Component/Messenger/Worker/StopWhenTimeLimitIsReachedWorker.php b/src/Symfony/Component/Messenger/Worker/StopWhenTimeLimitIsReachedWorker.php new file mode 100644 index 0000000000000..3a4dcf859d859 --- /dev/null +++ b/src/Symfony/Component/Messenger/Worker/StopWhenTimeLimitIsReachedWorker.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Worker; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\WorkerInterface; + +/** + * @author Simon Delicata + * + * @experimental in 4.3 + */ +class StopWhenTimeLimitIsReachedWorker implements WorkerInterface +{ + private $decoratedWorker; + private $timeLimitInSeconds; + private $logger; + + public function __construct(WorkerInterface $decoratedWorker, int $timeLimitInSeconds, LoggerInterface $logger = null) + { + $this->decoratedWorker = $decoratedWorker; + $this->timeLimitInSeconds = $timeLimitInSeconds; + $this->logger = $logger; + } + + public function run(array $options = [], callable $onHandledCallback = null): void + { + $startTime = microtime(true); + $endTime = $startTime + $this->timeLimitInSeconds; + + $this->decoratedWorker->run($options, function (?Envelope $envelope) use ($onHandledCallback, $endTime) { + if (null !== $onHandledCallback) { + $onHandledCallback($envelope); + } + + if ($endTime < microtime(true)) { + $this->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped due to time limit of {timeLimit}s reached', ['timeLimit' => $this->timeLimitInSeconds]); + } + } + }); + } + + public function stop(): void + { + $this->decoratedWorker->stop(); + } +} diff --git a/src/Symfony/Component/Messenger/WorkerInterface.php b/src/Symfony/Component/Messenger/WorkerInterface.php new file mode 100644 index 0000000000000..a4b3566871cb2 --- /dev/null +++ b/src/Symfony/Component/Messenger/WorkerInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger; + +/** + * Interface for Workers that handle messages from transports. + * + * @experimental in 4.3 + * + * @author Ryan Weaver + */ +interface WorkerInterface +{ + /** + * Receive the messages and dispatch them to the bus. + * + * The $onHandledCallback will be passed the Envelope that was just + * handled or null if nothing was handled. + * + * @param mixed[] $options options used to control worker behavior + */ + public function run(array $options = [], callable $onHandledCallback = null): void; + + /** + * Stop receiving messages. + */ + public function stop(): void; +} From f4176b0cf6c8306f07aaf5de03e01f5e9dfc6cd2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 08:02:29 +0100 Subject: [PATCH 305/495] fixed typos --- .../Messenger/Transport/Receiver/ReceiverInterface.php | 6 +++--- src/Symfony/Component/Messenger/WorkerInterface.php | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php index d974ff00b7902..fabb112a98b89 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php @@ -23,14 +23,14 @@ interface ReceiverInterface { /** - * Receive some messages to the given handler. + * Receives some messages to the given handler. * * While this method could return an unlimited number of messages, * the intention is that it returns only one, or a "small number" * of messages each time. This gives the user more flexibility: * they can finish processing the one (or "small number") of messages * from this receiver and move on to check other receivers for messages. - * If a this method returns too many messages, it could cause a + * If this method returns too many messages, it could cause a * blocking effect where handling the messages received from one * call to get() takes a long time, blocking other receivers from * being called. @@ -46,7 +46,7 @@ interface ReceiverInterface public function get(): iterable; /** - * Acknowledge that the passed message was handled. + * Acknowledges that the passed message was handled. * * @throws TransportException If there is an issue communicating with the transport */ diff --git a/src/Symfony/Component/Messenger/WorkerInterface.php b/src/Symfony/Component/Messenger/WorkerInterface.php index a4b3566871cb2..9cde7e57b630b 100644 --- a/src/Symfony/Component/Messenger/WorkerInterface.php +++ b/src/Symfony/Component/Messenger/WorkerInterface.php @@ -21,7 +21,7 @@ interface WorkerInterface { /** - * Receive the messages and dispatch them to the bus. + * Receives the messages and dispatch them to the bus. * * The $onHandledCallback will be passed the Envelope that was just * handled or null if nothing was handled. @@ -31,7 +31,7 @@ interface WorkerInterface public function run(array $options = [], callable $onHandledCallback = null): void; /** - * Stop receiving messages. + * Stops receiving messages. */ public function stop(): void; } From 7cb14f3186c47d9bddde0509f0327e2e2cd5dc9d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 08:22:54 +0100 Subject: [PATCH 306/495] fixed typo --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 1662b8fda6124..304790630b759 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -5,7 +5,7 @@ CHANGELOG ----- * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to - explicitly handle messages asynchronously. + explicitly handle messages synchronously. * Added optional parameter `prefetch_count` in connection configuration, to setup channel prefetch count * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` From 15cb4754e7b1f75ff5cd60c83bf3a24c62c5a5a2 Mon Sep 17 00:00:00 2001 From: Silvio Ginter Date: Wed, 27 Mar 2019 14:03:43 +0100 Subject: [PATCH 307/495] [HttpKernel] change $previous argument for HttpException to \Throwable --- .../Exception/AccessDeniedHttpException.php | 4 ++-- .../HttpKernel/Exception/BadRequestHttpException.php | 4 ++-- .../HttpKernel/Exception/ConflictHttpException.php | 4 ++-- .../HttpKernel/Exception/GoneHttpException.php | 4 ++-- .../Component/HttpKernel/Exception/HttpException.php | 2 +- .../Exception/LengthRequiredHttpException.php | 4 ++-- .../Exception/MethodNotAllowedHttpException.php | 4 ++-- .../Exception/NotAcceptableHttpException.php | 4 ++-- .../HttpKernel/Exception/NotFoundHttpException.php | 4 ++-- .../Exception/PreconditionFailedHttpException.php | 4 ++-- .../Exception/PreconditionRequiredHttpException.php | 4 ++-- .../Exception/ServiceUnavailableHttpException.php | 4 ++-- .../Exception/TooManyRequestsHttpException.php | 4 ++-- .../Exception/UnauthorizedHttpException.php | 4 ++-- .../Exception/UnprocessableEntityHttpException.php | 4 ++-- .../Exception/UnsupportedMediaTypeHttpException.php | 4 ++-- .../Exception/AccessDeniedHttpExceptionTest.php | 4 ++-- .../Tests/Exception/BadRequestHttpExceptionTest.php | 4 ++-- .../Tests/Exception/ConflictHttpExceptionTest.php | 4 ++-- .../Tests/Exception/GoneHttpExceptionTest.php | 4 ++-- .../HttpKernel/Tests/Exception/HttpExceptionTest.php | 12 ++++++++++-- .../Exception/LengthRequiredHttpExceptionTest.php | 4 ++-- .../Exception/MethodNotAllowedHttpExceptionTest.php | 5 +++++ .../Exception/NotAcceptableHttpExceptionTest.php | 4 ++-- .../Tests/Exception/NotFoundHttpExceptionTest.php | 4 ++-- .../PreconditionFailedHttpExceptionTest.php | 4 ++-- .../PreconditionRequiredHttpExceptionTest.php | 4 ++-- .../ServiceUnavailableHttpExceptionTest.php | 4 ++-- .../Exception/TooManyRequestsHttpExceptionTest.php | 4 ++-- .../Exception/UnauthorizedHttpExceptionTest.php | 5 +++++ .../UnprocessableEntityHttpExceptionTest.php | 4 ++-- .../UnsupportedMediaTypeHttpExceptionTest.php | 4 ++-- 32 files changed, 77 insertions(+), 59 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Exception/AccessDeniedHttpException.php b/src/Symfony/Component/HttpKernel/Exception/AccessDeniedHttpException.php index f6f4ff53f06e5..326e9361efea8 100644 --- a/src/Symfony/Component/HttpKernel/Exception/AccessDeniedHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/AccessDeniedHttpException.php @@ -19,11 +19,11 @@ class AccessDeniedHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(403, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/BadRequestHttpException.php b/src/Symfony/Component/HttpKernel/Exception/BadRequestHttpException.php index 4b25adcba3bb7..db031bea7d11c 100644 --- a/src/Symfony/Component/HttpKernel/Exception/BadRequestHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/BadRequestHttpException.php @@ -18,11 +18,11 @@ class BadRequestHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(400, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/ConflictHttpException.php b/src/Symfony/Component/HttpKernel/Exception/ConflictHttpException.php index 6c8a1b3c537b8..e1542cd0563cf 100644 --- a/src/Symfony/Component/HttpKernel/Exception/ConflictHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/ConflictHttpException.php @@ -18,11 +18,11 @@ class ConflictHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(409, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/GoneHttpException.php b/src/Symfony/Component/HttpKernel/Exception/GoneHttpException.php index de0d5f2c2c4d6..5d75f92b19f9c 100644 --- a/src/Symfony/Component/HttpKernel/Exception/GoneHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/GoneHttpException.php @@ -18,11 +18,11 @@ class GoneHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(410, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/HttpException.php b/src/Symfony/Component/HttpKernel/Exception/HttpException.php index 3acb52ac35866..d822cd5d49a77 100644 --- a/src/Symfony/Component/HttpKernel/Exception/HttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/HttpException.php @@ -21,7 +21,7 @@ class HttpException extends \RuntimeException implements HttpExceptionInterface private $statusCode; private $headers; - public function __construct(int $statusCode, string $message = null, \Exception $previous = null, array $headers = [], ?int $code = 0) + public function __construct(int $statusCode, string $message = null, \Throwable $previous = null, array $headers = [], ?int $code = 0) { $this->statusCode = $statusCode; $this->headers = $headers; diff --git a/src/Symfony/Component/HttpKernel/Exception/LengthRequiredHttpException.php b/src/Symfony/Component/HttpKernel/Exception/LengthRequiredHttpException.php index 287c07a0c1a05..5e6eda04db0e9 100644 --- a/src/Symfony/Component/HttpKernel/Exception/LengthRequiredHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/LengthRequiredHttpException.php @@ -18,11 +18,11 @@ class LengthRequiredHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(411, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/MethodNotAllowedHttpException.php b/src/Symfony/Component/HttpKernel/Exception/MethodNotAllowedHttpException.php index e9a3f069f1c17..388c8c704e6cb 100644 --- a/src/Symfony/Component/HttpKernel/Exception/MethodNotAllowedHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/MethodNotAllowedHttpException.php @@ -19,11 +19,11 @@ class MethodNotAllowedHttpException extends HttpException /** * @param array $allow An array of allowed methods * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(array $allow, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct(array $allow, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { $headers['Allow'] = strtoupper(implode(', ', $allow)); diff --git a/src/Symfony/Component/HttpKernel/Exception/NotAcceptableHttpException.php b/src/Symfony/Component/HttpKernel/Exception/NotAcceptableHttpException.php index 5596330881b24..5bdacf69140e2 100644 --- a/src/Symfony/Component/HttpKernel/Exception/NotAcceptableHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/NotAcceptableHttpException.php @@ -18,11 +18,11 @@ class NotAcceptableHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(406, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/NotFoundHttpException.php b/src/Symfony/Component/HttpKernel/Exception/NotFoundHttpException.php index 551b3edc59f42..c52587d37fb7c 100644 --- a/src/Symfony/Component/HttpKernel/Exception/NotFoundHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/NotFoundHttpException.php @@ -18,11 +18,11 @@ class NotFoundHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(404, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/PreconditionFailedHttpException.php b/src/Symfony/Component/HttpKernel/Exception/PreconditionFailedHttpException.php index c1a59fb8df471..9bd895c88f5a3 100644 --- a/src/Symfony/Component/HttpKernel/Exception/PreconditionFailedHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/PreconditionFailedHttpException.php @@ -18,11 +18,11 @@ class PreconditionFailedHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(412, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/PreconditionRequiredHttpException.php b/src/Symfony/Component/HttpKernel/Exception/PreconditionRequiredHttpException.php index fd95b042c5c50..6aed73406e63d 100644 --- a/src/Symfony/Component/HttpKernel/Exception/PreconditionRequiredHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/PreconditionRequiredHttpException.php @@ -20,11 +20,11 @@ class PreconditionRequiredHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(428, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/ServiceUnavailableHttpException.php b/src/Symfony/Component/HttpKernel/Exception/ServiceUnavailableHttpException.php index 18b12d83cc69b..34a749fa47566 100644 --- a/src/Symfony/Component/HttpKernel/Exception/ServiceUnavailableHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/ServiceUnavailableHttpException.php @@ -19,11 +19,11 @@ class ServiceUnavailableHttpException extends HttpException /** * @param int|string $retryAfter The number of seconds or HTTP-date after which the request may be retried * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct($retryAfter = null, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct($retryAfter = null, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { if ($retryAfter) { $headers['Retry-After'] = $retryAfter; diff --git a/src/Symfony/Component/HttpKernel/Exception/TooManyRequestsHttpException.php b/src/Symfony/Component/HttpKernel/Exception/TooManyRequestsHttpException.php index 91e65e2d70036..e69961b7dedf8 100644 --- a/src/Symfony/Component/HttpKernel/Exception/TooManyRequestsHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/TooManyRequestsHttpException.php @@ -21,11 +21,11 @@ class TooManyRequestsHttpException extends HttpException /** * @param int|string $retryAfter The number of seconds or HTTP-date after which the request may be retried * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct($retryAfter = null, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct($retryAfter = null, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { if ($retryAfter) { $headers['Retry-After'] = $retryAfter; diff --git a/src/Symfony/Component/HttpKernel/Exception/UnauthorizedHttpException.php b/src/Symfony/Component/HttpKernel/Exception/UnauthorizedHttpException.php index bc42877fe8773..7f7d0b4739407 100644 --- a/src/Symfony/Component/HttpKernel/Exception/UnauthorizedHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/UnauthorizedHttpException.php @@ -19,11 +19,11 @@ class UnauthorizedHttpException extends HttpException /** * @param string $challenge WWW-Authenticate challenge string * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $challenge, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct(string $challenge, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { $headers['WWW-Authenticate'] = $challenge; diff --git a/src/Symfony/Component/HttpKernel/Exception/UnprocessableEntityHttpException.php b/src/Symfony/Component/HttpKernel/Exception/UnprocessableEntityHttpException.php index 9cad444c6c1d0..7fbc7eff0cef2 100644 --- a/src/Symfony/Component/HttpKernel/Exception/UnprocessableEntityHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/UnprocessableEntityHttpException.php @@ -18,11 +18,11 @@ class UnprocessableEntityHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(422, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Exception/UnsupportedMediaTypeHttpException.php b/src/Symfony/Component/HttpKernel/Exception/UnsupportedMediaTypeHttpException.php index e52e1d88d2a9b..3bfac7f481294 100644 --- a/src/Symfony/Component/HttpKernel/Exception/UnsupportedMediaTypeHttpException.php +++ b/src/Symfony/Component/HttpKernel/Exception/UnsupportedMediaTypeHttpException.php @@ -18,11 +18,11 @@ class UnsupportedMediaTypeHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(415, $message, $previous, $headers, $code); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/AccessDeniedHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/AccessDeniedHttpExceptionTest.php index 2bfcb2bf80306..3a34cc47bce72 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/AccessDeniedHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/AccessDeniedHttpExceptionTest.php @@ -6,8 +6,8 @@ class AccessDeniedHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new AccessDeniedHttpException(); + return new AccessDeniedHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/BadRequestHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/BadRequestHttpExceptionTest.php index 5fd54ccf44a0b..462fd9cb1dbc3 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/BadRequestHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/BadRequestHttpExceptionTest.php @@ -6,8 +6,8 @@ class BadRequestHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new BadRequestHttpException(); + return new BadRequestHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/ConflictHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/ConflictHttpExceptionTest.php index 63cb49e6e05b9..760600a10fc32 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/ConflictHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/ConflictHttpExceptionTest.php @@ -6,8 +6,8 @@ class ConflictHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new ConflictHttpException(); + return new ConflictHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/GoneHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/GoneHttpExceptionTest.php index ec5339d2af562..30dafe4922751 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/GoneHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/GoneHttpExceptionTest.php @@ -6,8 +6,8 @@ class GoneHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new GoneHttpException(); + return new GoneHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/HttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/HttpExceptionTest.php index f5fe97255bdb8..a9431f4b5a722 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/HttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/HttpExceptionTest.php @@ -46,8 +46,16 @@ public function testHeadersSetter($headers) $this->assertSame($headers, $exception->getHeaders()); } - protected function createException() + public function testThrowableIsAllowedForPrevious() { - return new HttpException(200); + $previous = new class('Error of PHP 7+') extends \Error { + }; + $exception = $this->createException(null, $previous); + $this->assertSame($previous, $exception->getPrevious()); + } + + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) + { + return new HttpException(200, $message, $previous, $headers, $code); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/LengthRequiredHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/LengthRequiredHttpExceptionTest.php index 462d3ca4fcf27..8676d67238c14 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/LengthRequiredHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/LengthRequiredHttpExceptionTest.php @@ -6,8 +6,8 @@ class LengthRequiredHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new LengthRequiredHttpException(); + return new LengthRequiredHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php index 991f97582d1ec..efb0b50cafd00 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php @@ -34,4 +34,9 @@ public function testHeadersSetter($headers) $exception->setHeaders($headers); $this->assertSame($headers, $exception->getHeaders()); } + + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) + { + return new MethodNotAllowedHttpException(['get'], $message, $previous, $code, $headers); + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/NotAcceptableHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/NotAcceptableHttpExceptionTest.php index 4c0db7a3cb659..021c69e28954b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/NotAcceptableHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/NotAcceptableHttpExceptionTest.php @@ -6,8 +6,8 @@ class NotAcceptableHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new NotAcceptableHttpException(); + return new NotAcceptableHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/NotFoundHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/NotFoundHttpExceptionTest.php index 62ede5b4b82a2..0bf369b1a0ce4 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/NotFoundHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/NotFoundHttpExceptionTest.php @@ -6,8 +6,8 @@ class NotFoundHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new NotFoundHttpException(); + return new NotFoundHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php index 809252b75780c..04d79c499d037 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php @@ -6,8 +6,8 @@ class PreconditionFailedHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new PreconditionFailedHttpException(); + return new PreconditionFailedHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php index 69d362e3f6cf9..82076617a8779 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php @@ -6,8 +6,8 @@ class PreconditionRequiredHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new PreconditionRequiredHttpException(); + return new PreconditionRequiredHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php index daa4fa407a09e..fac197c852e3e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php @@ -35,8 +35,8 @@ public function testHeadersSetter($headers) $this->assertSame($headers, $exception->getHeaders()); } - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new ServiceUnavailableHttpException(); + return new ServiceUnavailableHttpException(null, $message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php index 0048ec85c0c85..8b59e9894adb5 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php @@ -35,8 +35,8 @@ public function testHeadersSetter($headers) $this->assertSame($headers, $exception->getHeaders()); } - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new TooManyRequestsHttpException(); + return new TooManyRequestsHttpException(null, $message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/UnauthorizedHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/UnauthorizedHttpExceptionTest.php index c7239e70b3d0e..92d427b6e4a9e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/UnauthorizedHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/UnauthorizedHttpExceptionTest.php @@ -34,4 +34,9 @@ public function testHeadersSetter($headers) $exception->setHeaders($headers); $this->assertSame($headers, $exception->getHeaders()); } + + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) + { + return new UnauthorizedHttpException('Challenge', $message, $previous, $code, $headers); + } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php index 05d8d787aa5c5..ffa4e177ee526 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php @@ -6,8 +6,8 @@ class UnprocessableEntityHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new UnprocessableEntityHttpException(); + return new UnprocessableEntityHttpException($message, $previous, $code, $headers); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php b/src/Symfony/Component/HttpKernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php index 4dae039c11fc1..fa28bbd19b410 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php @@ -6,8 +6,8 @@ class UnsupportedMediaTypeHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new UnsupportedMediaTypeHttpException(); + return new UnsupportedMediaTypeHttpException($message, $previous, $code, $headers); } } From 8d25319783b4e517e10254f7a2bec050e8f3a723 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 08:15:10 +0100 Subject: [PATCH 308/495] removed obsolete code --- src/Symfony/Component/HttpKernel/Kernel.php | 1 - src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php | 1 - src/Symfony/Component/Translation/Extractor/PhpExtractor.php | 1 - 3 files changed, 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7fc2a3113e348..b3f70fb8798e8 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -827,7 +827,6 @@ public static function stripComments($source) $output .= $rawChunk; - // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 unset($tokens, $rawChunk); gc_mem_caches(); diff --git a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php index d0f0ce44414e6..7d1f17a09823d 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php @@ -60,7 +60,6 @@ public function load($file, $type = null) $collection->addCollection($this->loader->load($class, $type)); } - // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 gc_mem_caches(); return $collection; diff --git a/src/Symfony/Component/Translation/Extractor/PhpExtractor.php b/src/Symfony/Component/Translation/Extractor/PhpExtractor.php index 5f6aecd50a2a9..4ef1cf0d4f88c 100644 --- a/src/Symfony/Component/Translation/Extractor/PhpExtractor.php +++ b/src/Symfony/Component/Translation/Extractor/PhpExtractor.php @@ -83,7 +83,6 @@ public function extract($resource, MessageCatalogue $catalog) foreach ($files as $file) { $this->parseTokens(token_get_all(file_get_contents($file)), $catalog); - // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 gc_mem_caches(); } } From f92efeb429c48c76b7cc68b8c74dc0eaa83508e3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 08:40:00 +0100 Subject: [PATCH 309/495] fixed some exception previous type hints --- .../Component/Config/Exception/FileLoaderLoadException.php | 4 ++-- .../Component/Console/Exception/CommandNotFoundException.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Config/Exception/FileLoaderLoadException.php b/src/Symfony/Component/Config/Exception/FileLoaderLoadException.php index 45e73e3ce84b7..16beec5930c82 100644 --- a/src/Symfony/Component/Config/Exception/FileLoaderLoadException.php +++ b/src/Symfony/Component/Config/Exception/FileLoaderLoadException.php @@ -24,10 +24,10 @@ class FileLoaderLoadException extends \Exception * @param string $resource The resource that could not be imported * @param string $sourceResource The original resource importing the new resource * @param int $code The error code - * @param \Exception $previous A previous exception + * @param \Throwable $previous A previous exception * @param string $type The type of resource */ - public function __construct(string $resource, string $sourceResource = null, int $code = null, \Exception $previous = null, string $type = null) + public function __construct(string $resource, string $sourceResource = null, int $code = null, \Throwable $previous = null, string $type = null) { $message = ''; if ($previous) { diff --git a/src/Symfony/Component/Console/Exception/CommandNotFoundException.php b/src/Symfony/Component/Console/Exception/CommandNotFoundException.php index 15ac522c67880..69d5cb996a084 100644 --- a/src/Symfony/Component/Console/Exception/CommandNotFoundException.php +++ b/src/Symfony/Component/Console/Exception/CommandNotFoundException.php @@ -24,9 +24,9 @@ class CommandNotFoundException extends \InvalidArgumentException implements Exce * @param string $message Exception message to throw * @param array $alternatives List of similar defined names * @param int $code Exception code - * @param \Exception $previous Previous exception used for the exception chaining + * @param \Throwable $previous Previous exception used for the exception chaining */ - public function __construct(string $message, array $alternatives = [], int $code = 0, \Exception $previous = null) + public function __construct(string $message, array $alternatives = [], int $code = 0, \Throwable $previous = null) { parent::__construct($message, $code, $previous); From 69b9ee794c4303efaf6db1c797cc5ee46adafd11 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 6 Feb 2019 12:34:55 +0100 Subject: [PATCH 310/495] added the Mailer component --- .../DependencyInjection/Configuration.php | 17 ++ .../FrameworkExtension.php | 15 + .../Resources/config/mailer.xml | 28 ++ .../DependencyInjection/ConfigurationTest.php | 5 + .../Bundle/FrameworkBundle/composer.json | 1 + .../DependencyInjection/TwigExtension.php | 5 + .../TwigBundle/Resources/config/mailer.xml | 17 ++ .../Mailer/Bridge/Amazon/CHANGELOG.md | 7 + .../Bridge/Amazon/Http/Api/SesTransport.php | 103 +++++++ .../Bridge/Amazon/Http/SesTransport.php | 75 +++++ .../Component/Mailer/Bridge/Amazon/LICENSE | 19 ++ .../Component/Mailer/Bridge/Amazon/README.md | 12 + .../Bridge/Amazon/Smtp/SesTransport.php | 35 +++ .../Mailer/Bridge/Amazon/composer.json | 37 +++ .../Mailer/Bridge/Amazon/phpunit.xml.dist | 31 ++ .../Mailer/Bridge/Google/CHANGELOG.md | 7 + .../Component/Mailer/Bridge/Google/LICENSE | 19 ++ .../Component/Mailer/Bridge/Google/README.md | 12 + .../Bridge/Google/Smtp/GmailTransport.php | 32 ++ .../Mailer/Bridge/Google/composer.json | 37 +++ .../Mailer/Bridge/Google/phpunit.xml.dist | 31 ++ .../Mailer/Bridge/Mailchimp/CHANGELOG.md | 7 + .../Mailchimp/Http/Api/MandrillTransport.php | 114 +++++++ .../Mailchimp/Http/MandrillTransport.php | 60 ++++ .../Component/Mailer/Bridge/Mailchimp/LICENSE | 19 ++ .../Mailer/Bridge/Mailchimp/README.md | 12 + .../Mailchimp/Smtp/MandrillTransport.php | 30 ++ .../Mailer/Bridge/Mailchimp/composer.json | 37 +++ .../Mailer/Bridge/Mailchimp/phpunit.xml.dist | 31 ++ .../Mailer/Bridge/Mailgun/CHANGELOG.md | 7 + .../Mailgun/Http/Api/MailgunTransport.php | 132 ++++++++ .../Bridge/Mailgun/Http/MailgunTransport.php | 68 +++++ .../Component/Mailer/Bridge/Mailgun/LICENSE | 19 ++ .../Component/Mailer/Bridge/Mailgun/README.md | 12 + .../Bridge/Mailgun/Smtp/MailgunTransport.php | 32 ++ .../Mailer/Bridge/Mailgun/composer.json | 37 +++ .../Mailer/Bridge/Mailgun/phpunit.xml.dist | 31 ++ .../Mailer/Bridge/Postmark/CHANGELOG.md | 7 + .../Postmark/Http/Api/PostmarkTransport.php | 108 +++++++ .../Component/Mailer/Bridge/Postmark/LICENSE | 19 ++ .../Mailer/Bridge/Postmark/README.md | 12 + .../Postmark/Smtp/PostmarkTransport.php | 32 ++ .../Mailer/Bridge/Postmark/composer.json | 37 +++ .../Mailer/Bridge/Postmark/phpunit.xml.dist | 31 ++ .../Mailer/Bridge/Sendgrid/.gitignore | 3 + .../Mailer/Bridge/Sendgrid/CHANGELOG.md | 7 + .../Sendgrid/Http/Api/SendgridTransport.php | 131 ++++++++ .../Component/Mailer/Bridge/Sendgrid/LICENSE | 19 ++ .../Mailer/Bridge/Sendgrid/README.md | 12 + .../Sendgrid/Smtp/SendgridTransport.php | 32 ++ .../Mailer/Bridge/Sendgrid/composer.json | 37 +++ .../Mailer/Bridge/Sendgrid/phpunit.xml.dist | 31 ++ src/Symfony/Component/Mailer/CHANGELOG.md | 7 + .../Component/Mailer/Event/MessageEvent.php | 55 ++++ .../Mailer/EventListener/EnvelopeListener.php | 62 ++++ .../Mailer/EventListener/MessageListener.php | 84 ++++++ .../Mailer/Exception/ExceptionInterface.php | 23 ++ .../Exception/HttpTransportException.php | 21 ++ .../Exception/InvalidArgumentException.php | 21 ++ .../Mailer/Exception/LogicException.php | 21 ++ .../Mailer/Exception/RuntimeException.php | 21 ++ .../Mailer/Exception/TransportException.php | 21 ++ .../Exception/TransportExceptionInterface.php | 21 ++ src/Symfony/Component/Mailer/LICENSE | 19 ++ src/Symfony/Component/Mailer/Mailer.php | 45 +++ .../Component/Mailer/MailerInterface.php | 32 ++ .../Mailer/Messenger/MessageHandler.php | 34 +++ .../Mailer/Messenger/SendEmailMessage.php | 45 +++ src/Symfony/Component/Mailer/README.md | 12 + src/Symfony/Component/Mailer/SentMessage.php | 62 ++++ src/Symfony/Component/Mailer/SmtpEnvelope.php | 114 +++++++ .../Mailer/Tests/SentMessageTest.php | 36 +++ .../Mailer/Tests/SmtpEnvelopeTest.php | 99 ++++++ .../Tests/Transport/AbstractTransportTest.php | 49 +++ .../Tests/Transport/FailoverTransportTest.php | 83 +++++ .../Transport/RoundRobinTransportTest.php | 79 +++++ .../Smtp/Stream/AbstractStreamTest.php | 38 +++ .../Component/Mailer/Tests/TransportTest.php | 283 ++++++++++++++++++ src/Symfony/Component/Mailer/Transport.php | 180 +++++++++++ .../Mailer/Transport/AbstractTransport.php | 118 ++++++++ .../Mailer/Transport/FailoverTransport.php | 33 ++ .../Http/Api/AbstractApiTransport.php | 68 +++++ .../Mailer/Transport/NullTransport.php | 28 ++ .../Mailer/Transport/RoundRobinTransport.php | 87 ++++++ .../Mailer/Transport/SendmailTransport.php | 103 +++++++ .../Smtp/Auth/AuthenticatorInterface.php | 37 +++ .../Smtp/Auth/CramMd5Authenticator.php | 64 ++++ .../Smtp/Auth/LoginAuthenticator.php | 41 +++ .../Smtp/Auth/PlainAuthenticator.php | 39 +++ .../Smtp/Auth/XOAuth2Authenticator.php | 41 +++ .../Mailer/Transport/Smtp/EsmtpTransport.php | 205 +++++++++++++ .../Mailer/Transport/Smtp/SmtpTransport.php | 283 ++++++++++++++++++ .../Transport/Smtp/Stream/AbstractStream.php | 119 ++++++++ .../Transport/Smtp/Stream/ProcessStream.php | 67 +++++ .../Transport/Smtp/Stream/SocketStream.php | 172 +++++++++++ .../Mailer/Transport/TransportInterface.php | 35 +++ src/Symfony/Component/Mailer/composer.json | 45 +++ src/Symfony/Component/Mailer/phpunit.xml.dist | 30 ++ 98 files changed, 4893 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml create mode 100644 src/Symfony/Bundle/TwigBundle/Resources/config/mailer.xml create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/README.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/composer.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Amazon/phpunit.xml.dist create mode 100644 src/Symfony/Component/Mailer/Bridge/Google/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Google/LICENSE create mode 100644 src/Symfony/Component/Mailer/Bridge/Google/README.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Google/composer.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Google/phpunit.xml.dist create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailchimp/phpunit.xml.dist create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/README.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Mailgun/phpunit.xml.dist create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/README.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/composer.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Postmark/phpunit.xml.dist create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/.gitignore create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json create mode 100644 src/Symfony/Component/Mailer/Bridge/Sendgrid/phpunit.xml.dist create mode 100644 src/Symfony/Component/Mailer/CHANGELOG.md create mode 100644 src/Symfony/Component/Mailer/Event/MessageEvent.php create mode 100644 src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php create mode 100644 src/Symfony/Component/Mailer/EventListener/MessageListener.php create mode 100644 src/Symfony/Component/Mailer/Exception/ExceptionInterface.php create mode 100644 src/Symfony/Component/Mailer/Exception/HttpTransportException.php create mode 100644 src/Symfony/Component/Mailer/Exception/InvalidArgumentException.php create mode 100644 src/Symfony/Component/Mailer/Exception/LogicException.php create mode 100644 src/Symfony/Component/Mailer/Exception/RuntimeException.php create mode 100644 src/Symfony/Component/Mailer/Exception/TransportException.php create mode 100644 src/Symfony/Component/Mailer/Exception/TransportExceptionInterface.php create mode 100644 src/Symfony/Component/Mailer/LICENSE create mode 100644 src/Symfony/Component/Mailer/Mailer.php create mode 100644 src/Symfony/Component/Mailer/MailerInterface.php create mode 100644 src/Symfony/Component/Mailer/Messenger/MessageHandler.php create mode 100644 src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php create mode 100644 src/Symfony/Component/Mailer/README.md create mode 100644 src/Symfony/Component/Mailer/SentMessage.php create mode 100644 src/Symfony/Component/Mailer/SmtpEnvelope.php create mode 100644 src/Symfony/Component/Mailer/Tests/SentMessageTest.php create mode 100644 src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php create mode 100644 src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php create mode 100644 src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php create mode 100644 src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php create mode 100644 src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/AbstractStreamTest.php create mode 100644 src/Symfony/Component/Mailer/Tests/TransportTest.php create mode 100644 src/Symfony/Component/Mailer/Transport.php create mode 100644 src/Symfony/Component/Mailer/Transport/AbstractTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/FailoverTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/Http/Api/AbstractApiTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/NullTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/SendmailTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthenticatorInterface.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Auth/CramMd5Authenticator.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Auth/LoginAuthenticator.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Auth/PlainAuthenticator.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Stream/AbstractStream.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Stream/ProcessStream.php create mode 100644 src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php create mode 100644 src/Symfony/Component/Mailer/Transport/TransportInterface.php create mode 100644 src/Symfony/Component/Mailer/composer.json create mode 100644 src/Symfony/Component/Mailer/phpunit.xml.dist diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 4355e632f3310..ef5fa8862e85b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -26,6 +26,7 @@ use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\Store\SemaphoreStore; +use Symfony\Component\Mailer\Mailer; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -112,6 +113,7 @@ public function getConfigTreeBuilder() $this->addMessengerSection($rootNode); $this->addRobotsIndexSection($rootNode); $this->addHttpClientSection($rootNode); + $this->addMailerSection($rootNode); return $treeBuilder; } @@ -1344,4 +1346,19 @@ private function addHttpClientOptionsSection(NodeBuilder $rootNode) ->end() ; } + + private function addMailerSection(ArrayNodeDefinition $rootNode) + { + $rootNode + ->children() + ->arrayNode('mailer') + ->info('Mailer configuration') + ->{!class_exists(FullStack::class) && class_exists(Mailer::class) ? 'canBeDisabled' : 'canBeEnabled'}() + ->children() + ->scalarNode('dsn')->defaultValue('smtp://null')->end() + ->end() + ->end() + ->end() + ; + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 670033be015bf..ceb3062c60c19 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -74,6 +74,7 @@ use Symfony\Component\Lock\Store\FlockStore; use Symfony\Component\Lock\Store\StoreFactory; use Symfony\Component\Lock\StoreInterface; +use Symfony\Component\Mailer\Mailer; use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBusInterface; @@ -316,6 +317,10 @@ public function load(array $configs, ContainerBuilder $container) $this->registerHttpClientConfiguration($config['http_client'], $container, $loader); } + if ($this->isConfigEnabled($container, $config['mailer'])) { + $this->registerMailerConfiguration($config['mailer'], $container, $loader); + } + if ($this->isConfigEnabled($container, $config['web_link'])) { if (!class_exists(HttpHeaderSerializer::class)) { throw new LogicException('WebLink support cannot be enabled as the WebLink component is not installed. Try running "composer require symfony/weblink".'); @@ -1854,6 +1859,16 @@ public function merge(array $options, array $defaultOptions) } } + private function registerMailerConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) + { + if (!class_exists(Mailer::class)) { + throw new LogicException('Mailer support cannot be enabled as the component is not installed. Try running "composer require symfony/mailer".'); + } + + $loader->load('mailer.xml'); + $container->getDefinition('mailer.transport')->setArgument(0, $config['dsn']); + } + /** * Returns the base path for the XSD files. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml new file mode 100644 index 0000000000000..2365eb629d4fd --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 56be70050ccf5..388b5bb4f4d66 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Config\Definition\Processor; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\Lock\Store\SemaphoreStore; +use Symfony\Component\Mailer\Mailer; use Symfony\Component\Messenger\MessageBusInterface; class ConfigurationTest extends TestCase @@ -336,6 +337,10 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'enabled' => !class_exists(FullStack::class) && class_exists(HttpClient::class), 'clients' => [], ], + 'mailer' => [ + 'dsn' => 'smtp://null', + 'enabled' => !class_exists(FullStack::class) && class_exists(Mailer::class), + ], ]; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 853711aca32cd..3e406515a9f0a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -42,6 +42,7 @@ "symfony/form": "^4.3", "symfony/expression-language": "~3.4|~4.0", "symfony/http-client": "^4.3", + "symfony/mailer": "^4.3", "symfony/messenger": "^4.3", "symfony/mime": "^4.3", "symfony/process": "~3.4|~4.0", diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index a9db7bf6a8612..9e43596d438d6 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -19,6 +19,7 @@ use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\Mailer\Mailer; use Symfony\Component\Translation\Translator; use Twig\Extension\ExtensionInterface; use Twig\Extension\RuntimeExtensionInterface; @@ -49,6 +50,10 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('console.xml'); } + if (class_exists(Mailer::class)) { + $loader->load('mailer.xml'); + } + if (!class_exists(Translator::class)) { $container->removeDefinition('twig.translation.extractor'); } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/mailer.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/mailer.xml new file mode 100644 index 0000000000000..d61bc32c45406 --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/mailer.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Amazon/CHANGELOG.md new file mode 100644 index 0000000000000..453e0d98fa8a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the bridge diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php new file mode 100644 index 0000000000000..e71e29a013661 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Amazon\Http\Api; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport; +use Symfony\Component\Mime\Email; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @experimental in 4.3 + */ +class SesTransport extends AbstractApiTransport +{ + private const ENDPOINT = 'https://email.%region%.amazonaws.com'; + + private $accessKey; + private $secretKey; + private $region; + + /** + * @param string $region Amazon SES region (currently one of us-east-1, us-west-2, or eu-west-1) + */ + public function __construct(string $accessKey, string $secretKey, string $region = null, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->accessKey = $accessKey; + $this->secretKey = $secretKey; + $this->region = $region ?: 'eu-west-1'; + + parent::__construct($client, $dispatcher, $logger); + } + + protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void + { + $date = gmdate('D, d M Y H:i:s e'); + $auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date)); + + $endpoint = str_replace('%region%', $this->region, self::ENDPOINT); + $response = $this->client->request('POST', $endpoint, [ + 'headers' => [ + 'X-Amzn-Authorization' => $auth, + 'Date' => $date, + 'Content-Type' => 'application/x-www-form-urlencoded', + ], + 'body' => $this->getPayload($email, $envelope), + ]); + + if (200 !== $response->getStatusCode()) { + $error = new \SimpleXMLElement($response->getContent(false)); + + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code)); + } + } + + private function getSignature(string $string): string + { + return base64_encode(hash_hmac('sha256', $string, $this->secretKey, true)); + } + + private function getPayload(Email $email, SmtpEnvelope $envelope): array + { + if ($email->getAttachments()) { + return [ + 'Action' => 'SendRawEmail', + 'RawMessage.Data' => \base64_encode($email->toString()), + ]; + } + + $payload = [ + 'Action' => 'SendEmail', + 'Destination.ToAddresses.member' => $this->stringifyAddresses($this->getRecipients($email, $envelope)), + 'Message.Subject.Data' => $email->getSubject(), + 'Source' => $envelope->getSender()->toString(), + ]; + + if ($emails = $email->getCc()) { + $payload['Destination.CcAddresses.member'] = $this->stringifyAddresses($emails); + } + if ($emails = $email->getBcc()) { + $payload['Destination.BccAddresses.member'] = $this->stringifyAddresses($emails); + } + if ($email->getTextBody()) { + $payload['Message.Body.Text.Data'] = $email->getTextBody(); + } + if ($email->getHtmlBody()) { + $payload['Message.Body.Html.Data'] = $email->getHtmlBody(); + } + + return $payload; + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php new file mode 100644 index 0000000000000..3a31c8f9d8b7d --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Amazon\Http; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @experimental in 4.3 + */ +class SesTransport extends AbstractTransport +{ + private const ENDPOINT = 'https://email.%region%.amazonaws.com'; + + private $client; + private $accessKey; + private $secretKey; + private $region; + + /** + * @param string $region Amazon SES region (currently one of us-east-1, us-west-2, or eu-west-1) + */ + public function __construct(string $accessKey, string $secretKey, string $region = null, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->client = $client ?? HttpClient::create(); + $this->accessKey = $accessKey; + $this->secretKey = $secretKey; + $this->region = $region ?: 'eu-west-1'; + + parent::__construct($dispatcher, $logger); + } + + protected function doSend(SentMessage $message): void + { + $date = gmdate('D, d M Y H:i:s e'); + $auth = sprintf('AWS3-HTTPS AWSAccessKeyId=%s,Algorithm=HmacSHA256,Signature=%s', $this->accessKey, $this->getSignature($date)); + + $endpoint = str_replace('%region%', $this->region, self::ENDPOINT); + $response = $this->client->request('POST', $endpoint, [ + 'headers' => [ + 'X-Amzn-Authorization' => $auth, + 'Date' => $date, + ], + 'body' => [ + 'Action' => 'SendRawEmail', + 'RawMessage.Data' => \base64_encode($message->toString()), + ], + ]); + + if (200 !== $response->getStatusCode()) { + $error = new \SimpleXMLElement($response->getContent(false)); + + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error->Error->Message, $error->Error->Code)); + } + } + + private function getSignature(string $string): string + { + return base64_encode(hash_hmac('sha256', $string, $this->secretKey, true)); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE b/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/README.md b/src/Symfony/Component/Mailer/Bridge/Amazon/README.md new file mode 100644 index 0000000000000..1159927c41f9f --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/README.md @@ -0,0 +1,12 @@ +Amazon Mailer +============= + +Provides Amazon SES integration for Symfony Mailer. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php new file mode 100644 index 0000000000000..1d666cdecb4aa --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Amazon\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class SesTransport extends EsmtpTransport +{ + /** + * @param string $region Amazon SES region (currently one of us-east-1, us-west-2, or eu-west-1) + */ + public function __construct(string $username, string $password, string $region = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct(\sprintf('email-smtp.%s.amazonaws.com', $region ?: 'eu-west-1'), 587, 'tls', null, $dispatcher, $logger); + + $this->setUsername($username); + $this->setPassword($password); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json b/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json new file mode 100644 index 0000000000000..bda7c65123a5d --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/amazon-mailer", + "type": "symfony-bridge", + "description": "Symfony Amazon Mailer Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "symfony/mailer": "^4.3" + }, + "require-dev": { + "symfony/http-client": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Amazon\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/phpunit.xml.dist b/src/Symfony/Component/Mailer/Bridge/Amazon/phpunit.xml.dist new file mode 100644 index 0000000000000..d8f7d50fa7579 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Mailer/Bridge/Google/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Google/CHANGELOG.md new file mode 100644 index 0000000000000..453e0d98fa8a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Google/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the bridge diff --git a/src/Symfony/Component/Mailer/Bridge/Google/LICENSE b/src/Symfony/Component/Mailer/Bridge/Google/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Google/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Bridge/Google/README.md b/src/Symfony/Component/Mailer/Bridge/Google/README.md new file mode 100644 index 0000000000000..ac382d2169ddc --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Google/README.md @@ -0,0 +1,12 @@ +Google Mailer +============= + +Provides Google Gmail integration for Symfony Mailer. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php b/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php new file mode 100644 index 0000000000000..91da68fcec709 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Google\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class GmailTransport extends EsmtpTransport +{ + public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct('smtp.gmail.com', 465, 'ssl', null, $dispatcher, $logger); + + $this->setUsername($username); + $this->setPassword($password); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Google/composer.json b/src/Symfony/Component/Mailer/Bridge/Google/composer.json new file mode 100644 index 0000000000000..bca36a66feaa4 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Google/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/google-mailer", + "type": "symfony-bridge", + "description": "Symfony Google Mailer Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "symfony/mailer": "^4.3" + }, + "require-dev": { + "symfony/http-client": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Google\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Google/phpunit.xml.dist b/src/Symfony/Component/Mailer/Bridge/Google/phpunit.xml.dist new file mode 100644 index 0000000000000..62face7defd8d --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Google/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Mailchimp/CHANGELOG.md new file mode 100644 index 0000000000000..453e0d98fa8a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the bridge diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php new file mode 100644 index 0000000000000..c1ef083ed224f --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailchimp\Http\Api; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport; +use Symfony\Component\Mime\Email; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @experimental in 4.3 + */ +class MandrillTransport extends AbstractApiTransport +{ + private const ENDPOINT = 'https://mandrillapp.com/api/1.0/messages/send.json'; + + private $key; + + public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->key = $key; + + parent::__construct($client, $dispatcher, $logger); + } + + protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void + { + $response = $this->client->request('POST', self::ENDPOINT, [ + 'json' => $this->getPayload($email, $envelope), + ]); + + if (200 !== $response->getStatusCode()) { + $result = $response->toArray(false); + if ('error' === ($result['status'] ?? false)) { + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code'])); + } + + throw new TransportException(sprintf('Unable to send an email (code %s).', $result['code'])); + } + } + + private function getPayload(Email $email, SmtpEnvelope $envelope): array + { + $payload = [ + 'key' => $this->key, + 'message' => [ + 'html' => $email->getHtmlBody(), + 'text' => $email->getTextBody(), + 'subject' => $email->getSubject(), + 'from_email' => $envelope->getSender()->toString(), + 'to' => $this->getRecipients($email, $envelope), + ], + ]; + + foreach ($email->getAttachments() as $attachment) { + $headers = $attachment->getPreparedHeaders(); + $disposition = $headers->getHeaderBody('Content-Disposition'); + + $att = [ + 'content' => $attachment->bodyToString(), + 'type' => $headers->get('Content-Type')->getBody(), + ]; + + if ('inline' === $disposition) { + $payload['images'][] = $att; + } else { + $payload['attachments'][] = $att; + } + } + + $headersToBypass = ['from', 'to', 'cc', 'bcc', 'subject', 'content-type']; + foreach ($email->getHeaders()->getAll() as $name => $header) { + if (\in_array($name, $headersToBypass, true)) { + continue; + } + + $payload['message']['headers'][] = $name.': '.$header->toString(); + } + + return $payload; + } + + protected function getRecipients(Email $email, SmtpEnvelope $envelope): array + { + $recipients = []; + foreach ($envelope->getRecipients() as $recipient) { + $type = 'to'; + if (\in_array($recipient, $email->getBcc(), true)) { + $type = 'bcc'; + } elseif (\in_array($recipient, $email->getCc(), true)) { + $type = 'cc'; + } + + $recipients[] = [ + 'email' => $recipient->toString(), + 'type' => $type, + ]; + } + + return $recipients; + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php new file mode 100644 index 0000000000000..188d0bcf90a70 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailchimp\Http; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @experimental in 4.3 + */ +class MandrillTransport extends AbstractTransport +{ + private const ENDPOINT = 'https://mandrillapp.com/api/1.0/messages/send-raw.json'; + private $client; + private $key; + + public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->key = $key; + $this->client = $client ?? HttpClient::create(); + + parent::__construct($dispatcher, $logger); + } + + protected function doSend(SentMessage $message): void + { + $envelope = $message->getEnvelope(); + $response = $this->client->request('POST', self::ENDPOINT, [ + 'json' => [ + 'key' => $this->key, + 'to' => $this->stringifyAddresses($envelope->getRecipients()), + 'from_email' => $envelope->getSender()->toString(), + 'raw_message' => $message->toString(), + ], + ]); + + if (200 !== $response->getStatusCode()) { + $result = $response->toArray(false); + if ('error' === ($result['status'] ?? false)) { + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $result['message'], $result['code'])); + } + + throw new TransportException(sprintf('Unable to send an email (code %s).', $result['code'])); + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE b/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md b/src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md new file mode 100644 index 0000000000000..56224554a504b --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/README.md @@ -0,0 +1,12 @@ +Mailchimp Mailer +================ + +Provides Mandrill integration for Symfony Mailer. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php new file mode 100644 index 0000000000000..cc61702d8fc49 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailchimp\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * @experimental in 4.3 + */ +class MandrillTransport extends EsmtpTransport +{ + public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct('smtp.mandrillapp.com', 587, 'tls', null, $dispatcher, $logger); + + $this->setUsername($username); + $this->setPassword($password); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json b/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json new file mode 100644 index 0000000000000..761ec6989a0a8 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/mailchimp-mailer", + "type": "symfony-bridge", + "description": "Symfony Mailchimp Mailer Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "symfony/mailer": "^4.3" + }, + "require-dev": { + "symfony/http-client": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Mailchimp\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/phpunit.xml.dist b/src/Symfony/Component/Mailer/Bridge/Mailchimp/phpunit.xml.dist new file mode 100644 index 0000000000000..85e6b69896175 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md new file mode 100644 index 0000000000000..453e0d98fa8a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the bridge diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php new file mode 100644 index 0000000000000..f3e69d00db572 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailgun\Http\Api; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MailgunTransport extends AbstractApiTransport +{ + private const ENDPOINT = 'https://api.mailgun.net/v3/%domain%/messages'; + + private $key; + private $domain; + + public function __construct(string $key, string $domain, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->key = $key; + $this->domain = $domain; + + parent::__construct($client, $dispatcher, $logger); + } + + protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void + { + $body = new FormDataPart($this->getPayload($email, $envelope)); + $headers = []; + foreach ($body->getPreparedHeaders()->getAll() as $header) { + $headers[] = $header->toString(); + } + + $endpoint = str_replace('%domain%', urlencode($this->domain), self::ENDPOINT); + $response = $this->client->request('POST', $endpoint, [ + 'auth_basic' => 'api:'.$this->key, + 'headers' => $headers, + 'body' => $body->bodyToIterable(), + ]); + + if (200 !== $response->getStatusCode()) { + $error = $response->toArray(false); + + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error['message'], $response->getStatusCode())); + } + } + + private function getPayload(Email $email, SmtpEnvelope $envelope): array + { + $headers = $email->getHeaders(); + $html = $email->getHtmlBody(); + if (null !== $html) { + if (stream_get_meta_data($html)['seekable'] ?? false) { + rewind($html); + } + $html = stream_get_contents($html); + } + [$attachments, $inlines, $html] = $this->prepareAttachments($email, $html); + + $payload = [ + 'from' => $envelope->getSender()->toString(), + 'to' => implode(',', $this->stringifyAddresses($this->getRecipients($email, $envelope))), + 'subject' => $email->getSubject(), + 'attachment' => $attachments, + 'inline' => $inlines, + ]; + if ($emails = $email->getCc()) { + $payload['cc'] = implode(',', $this->stringifyAddresses($emails)); + } + if ($emails = $email->getBcc()) { + $payload['bcc'] = implode(',', $this->stringifyAddresses($emails)); + } + if ($email->getTextBody()) { + $payload['text'] = $email->getTextBody(); + } + if ($html) { + $payload['html'] = $html; + } + + $headersToBypass = ['from', 'to', 'cc', 'bcc', 'subject', 'content-type']; + foreach ($headers->getAll() as $name => $header) { + if (\in_array($name, $headersToBypass, true)) { + continue; + } + + $payload['h:'.$name] = $header->toString(); + } + + return $payload; + } + + private function prepareAttachments(Email $email, ?string $html): array + { + $attachments = $inlines = []; + foreach ($email->getAttachments() as $attachment) { + $headers = $attachment->getPreparedHeaders(); + if ('inline' === $headers->getHeaderBody('Content-Disposition')) { + // replace the cid with just a file name (the only supported way by Mailgun) + if ($html) { + $filename = $headers->getHeaderParameter('Content-Disposition', 'filename'); + $new = basename($filename); + $html = str_replace('cid:'.$filename, 'cid:'.$new, $html); + $p = new \ReflectionProperty($attachment, 'filename'); + $p->setAccessible(true); + $p->setValue($attachment, $new); + } + $inlines[] = $attachment; + } else { + $attachments[] = $attachment; + } + } + + return [$attachments, $inlines, $html]; + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php new file mode 100644 index 0000000000000..0cc7fccd9343e --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailgun\Http; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MailgunTransport extends AbstractTransport +{ + private const ENDPOINT = 'https://api.mailgun.net/v3/%domain%/messages.mime'; + private $key; + private $domain; + private $client; + + public function __construct(string $key, string $domain, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->key = $key; + $this->domain = $domain; + $this->client = $client ?? HttpClient::create(); + + parent::__construct($dispatcher, $logger); + } + + protected function doSend(SentMessage $message): void + { + $body = new FormDataPart([ + 'to' => implode(',', $this->stringifyAddresses($message->getEnvelope()->getRecipients())), + 'message' => new DataPart($message->toString(), 'message.mime'), + ]); + $headers = []; + foreach ($body->getPreparedHeaders()->getAll() as $header) { + $headers[] = $header->toString(); + } + $endpoint = str_replace('%domain%', urlencode($this->domain), self::ENDPOINT); + $response = $this->client->request('POST', $endpoint, [ + 'auth_basic' => 'api:'.$this->key, + 'headers' => $headers, + 'body' => $body->bodyToIterable(), + ]); + + if (200 !== $response->getStatusCode()) { + $error = $response->toArray(false); + + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error['message'], $response->getStatusCode())); + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE b/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md b/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md new file mode 100644 index 0000000000000..4c04b71595d54 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/README.md @@ -0,0 +1,12 @@ +Mailgun Mailer +============== + +Provides Mailgun integration for Symfony Mailer. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php new file mode 100644 index 0000000000000..c9cf087bad3ed --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Mailgun\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MailgunTransport extends EsmtpTransport +{ + public function __construct(string $username, string $password, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct('smtp.mailgun.org', 465, 'ssl', null, $dispatcher, $logger); + + $this->setUsername($username); + $this->setPassword($password); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json new file mode 100644 index 0000000000000..6f00d507ebe60 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/mailgun-mailer", + "type": "symfony-bridge", + "description": "Symfony Mailgun Mailer Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "symfony/mailer": "^4.3" + }, + "require-dev": { + "symfony/http-client": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Mailgun\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/phpunit.xml.dist b/src/Symfony/Component/Mailer/Bridge/Mailgun/phpunit.xml.dist new file mode 100644 index 0000000000000..7c705f80d49ba --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Postmark/CHANGELOG.md new file mode 100644 index 0000000000000..453e0d98fa8a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the bridge diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php new file mode 100644 index 0000000000000..7a73579ce500f --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Postmark\Http\Api; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport; +use Symfony\Component\Mime\Email; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class PostmarkTransport extends AbstractApiTransport +{ + private const ENDPOINT = 'http://api.postmarkapp.com/email'; + + private $key; + + public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->key = $key; + + parent::__construct($client, $dispatcher, $logger); + } + + protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void + { + $response = $this->client->request('POST', self::ENDPOINT, [ + 'headers' => [ + 'Accept' => 'application/json', + 'X-Postmark-Server-Token' => $this->key, + ], + 'json' => $this->getPayload($email, $envelope), + ]); + + if (200 !== $response->getStatusCode()) { + $error = $response->toArray(false); + + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', $error['Message'], $error['ErrorCode'])); + } + } + + private function getPayload(Email $email, SmtpEnvelope $envelope): array + { + $payload = [ + 'From' => $envelope->getSender()->toString(), + 'To' => implode(',', $this->stringifyAddresses($this->getRecipients($email, $envelope))), + 'Cc' => implode(',', $this->stringifyAddresses($email->getCc())), + 'Bcc' => implode(',', $this->stringifyAddresses($email->getBcc())), + 'Subject' => $email->getSubject(), + 'TextBody' => $email->getTextBody(), + 'HtmlBody' => $email->getHtmlBody(), + 'Attachments' => $this->getAttachments($email), + ]; + + $headersToBypass = ['from', 'to', 'cc', 'bcc', 'subject', 'content-type', 'sender']; + foreach ($email->getHeaders()->getAll() as $name => $header) { + if (\in_array($name, $headersToBypass, true)) { + continue; + } + + $payload['Headers'][] = [ + 'Name' => $name, + 'Value' => $header->toString(), + ]; + } + + return $payload; + } + + private function getAttachments(Email $email): array + { + $attachments = []; + foreach ($email->getAttachments() as $attachment) { + $headers = $attachment->getPreparedHeaders(); + $filename = $headers->getHeaderParameter('Content-Disposition', 'filename'); + $disposition = $headers->getHeaderBody('Content-Disposition'); + + $att = [ + 'Name' => $filename, + 'Content' => $attachment->bodyToString(), + 'ContentType' => $headers->get('Content-Type')->getBody(), + ]; + + if ('inline' === $disposition) { + $att['ContentID'] = 'cid:'.$filename; + } + + $attachments[] = $att; + } + + return $attachments; + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE b/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/README.md b/src/Symfony/Component/Mailer/Bridge/Postmark/README.md new file mode 100644 index 0000000000000..44246cfe0904c --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/README.md @@ -0,0 +1,12 @@ +Postmark Bridge +=============== + +Provides Postmark integration for Symfony Mailer. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php new file mode 100644 index 0000000000000..ceee67d722a36 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Postmark\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class PostmarkTransport extends EsmtpTransport +{ + public function __construct(string $id, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct('smtp.postmarkapp.com', 587, 'tls', null, $dispatcher, $logger); + + $this->setUsername($id); + $this->setPassword($id); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json b/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json new file mode 100644 index 0000000000000..0493f1dfb0853 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/postmark-mailer", + "type": "symfony-bridge", + "description": "Symfony Postmark Mailer Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "symfony/mailer": "^4.3" + }, + "require-dev": { + "symfony/http-client": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Postmark\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/phpunit.xml.dist b/src/Symfony/Component/Mailer/Bridge/Postmark/phpunit.xml.dist new file mode 100644 index 0000000000000..07e40cc0c53a0 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/.gitignore b/src/Symfony/Component/Mailer/Bridge/Sendgrid/.gitignore new file mode 100644 index 0000000000000..c49a5d8df5c65 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/CHANGELOG.md b/src/Symfony/Component/Mailer/Bridge/Sendgrid/CHANGELOG.md new file mode 100644 index 0000000000000..453e0d98fa8a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * added the bridge diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php new file mode 100644 index 0000000000000..9e4871e72dd7c --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Sendgrid\Http\Api; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @experimental in 4.3 + */ +class SendgridTransport extends AbstractApiTransport +{ + private const ENDPOINT = 'https://api.sendgrid.com/v3/mail/send'; + + private $key; + + public function __construct(string $key, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->key = $key; + + parent::__construct($client, $dispatcher, $logger); + } + + protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void + { + $response = $this->client->request('POST', self::ENDPOINT, [ + 'json' => $this->getPayload($email, $envelope), + 'auth_bearer' => $this->key, + ]); + + if (202 !== $response->getStatusCode()) { + $errors = $response->toArray(false); + + throw new TransportException(sprintf('Unable to send an email: %s (code %s).', implode('; ', array_column($errors['errors'], 'message')), $response->getStatusCode())); + } + } + + private function getPayload(Email $email, SmtpEnvelope $envelope): array + { + $addressStringifier = function (Address $address) {return ['email' => $address->toString()]; }; + + $payload = [ + 'personalizations' => [], + 'from' => ['email' => $envelope->getSender()->toString()], + 'content' => $this->getContent($email), + ]; + + if ($email->getAttachments()) { + $payload['attachments'] = $this->getAttachments($email); + } + + $personalization = [ + 'to' => \array_map($addressStringifier, $this->getRecipients($email, $envelope)), + 'subject' => $email->getSubject(), + ]; + if ($emails = array_map($addressStringifier, $email->getCc())) { + $personalization['cc'] = $emails; + } + if ($emails = array_map($addressStringifier, $email->getBcc())) { + $personalization['bcc'] = $emails; + } + + $payload['personalizations'][] = $personalization; + + // these headers can't be overwritten according to Sendgrid docs + // see https://developers.pepipost.com/migration-api/new-subpage/email-send + $headersToBypass = ['x-sg-id', 'x-sg-eid', 'received', 'dkim-signature', 'content-transfer-encoding', 'from', 'to', 'cc', 'bcc', 'subject', 'content-type', 'reply-to']; + foreach ($email->getHeaders()->getAll() as $name => $header) { + if (\in_array($name, $headersToBypass, true)) { + continue; + } + + $payload['headers'][$name] = $header->toString(); + } + + return $payload; + } + + private function getContent(Email $email): array + { + $content = []; + if (null !== $text = $email->getTextBody()) { + $content[] = ['type' => 'text/plain', 'value' => $text]; + } + if (null !== $html = $email->getHtmlBody()) { + $content[] = ['type' => 'text/html', 'value' => $html]; + } + + return $content; + } + + private function getAttachments(Email $email): array + { + $attachments = []; + foreach ($email->getAttachments() as $attachment) { + $headers = $attachment->getPreparedHeaders(); + $filename = $headers->getHeaderParameter('Content-Disposition', 'filename'); + $disposition = $headers->getHeaderBody('Content-Disposition'); + + $att = [ + 'content' => $attachment->bodyToString(), + 'type' => $headers->get('Content-Type')->getBody(), + 'filename' => $filename, + 'disposition' => $disposition, + ]; + + if ('inline' === $disposition) { + $att['content_id'] = $filename; + } + + $attachments[] = $att; + } + + return $attachments; + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE b/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md b/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md new file mode 100644 index 0000000000000..647d746be973f --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/README.md @@ -0,0 +1,12 @@ +Sendgrid Bridge +=============== + +Provides Sendgrid integration for Symfony Mailer. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php new file mode 100644 index 0000000000000..fc28a6e2cb376 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Bridge\Sendgrid\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class SendgridTransport extends EsmtpTransport +{ + public function __construct(string $key, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct('smtp.sendgrid.net', 465, 'ssl', null, $dispatcher, $logger); + + $this->setUsername('apikey'); + $this->setPassword($key); + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json b/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json new file mode 100644 index 0000000000000..5630f5d3f40f8 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/sendgrid-mailer", + "type": "symfony-bridge", + "description": "Symfony Sendgrid Mailer Bridge", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "symfony/mailer": "^4.3" + }, + "require-dev": { + "symfony/http-client": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Sendgrid\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/phpunit.xml.dist b/src/Symfony/Component/Mailer/Bridge/Sendgrid/phpunit.xml.dist new file mode 100644 index 0000000000000..350d6c2059c11 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Symfony/Component/Mailer/CHANGELOG.md b/src/Symfony/Component/Mailer/CHANGELOG.md new file mode 100644 index 0000000000000..086e3305a7eb8 --- /dev/null +++ b/src/Symfony/Component/Mailer/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.3.0 +----- + + * Added the component diff --git a/src/Symfony/Component/Mailer/Event/MessageEvent.php b/src/Symfony/Component/Mailer/Event/MessageEvent.php new file mode 100644 index 0000000000000..a0891e98688ca --- /dev/null +++ b/src/Symfony/Component/Mailer/Event/MessageEvent.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Event; + +use Symfony\Component\EventDispatcher\Event; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\RawMessage; + +/** + * Allows the transformation of a Message. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MessageEvent extends Event +{ + private $message; + private $envelope; + + public function __construct(RawMessage $message, SmtpEnvelope $envelope) + { + $this->message = $message; + $this->envelope = $envelope; + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function setMessage(RawMessage $message): void + { + $this->message = $message; + } + + public function getEnvelope(): SmtpEnvelope + { + return $this->envelope; + } + + public function setEnvelope(SmtpEnvelope $envelope): void + { + $this->envelope = $envelope; + } +} diff --git a/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php b/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php new file mode 100644 index 0000000000000..e4b22b48baaa6 --- /dev/null +++ b/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mime\Address; + +/** + * Manipulates the Envelope of a Message. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class EnvelopeListener implements EventSubscriberInterface +{ + private $sender; + private $recipients; + + /** + * @param Address|string $sender + * @param (Address|string)[] $recipients + */ + public function __construct($sender = null, array $recipients = null) + { + if (null !== $sender) { + $this->sender = Address::create($sender); + } + if (null !== $recipients) { + $this->recipients = Address::createArray($recipients); + } + } + + public function onMessage(MessageEvent $event): void + { + if ($this->sender) { + $event->getEnvelope()->setSender($this->sender); + } + + if ($this->recipients) { + $event->getEnvelope()->setRecipients($this->recipients); + } + } + + public static function getSubscribedEvents() + { + return [ + // should be the last one to allow header changes by other listeners first + MessageEvent::class => ['onMessage', -255], + ]; + } +} diff --git a/src/Symfony/Component/Mailer/EventListener/MessageListener.php b/src/Symfony/Component/Mailer/EventListener/MessageListener.php new file mode 100644 index 0000000000000..c63595ada02fe --- /dev/null +++ b/src/Symfony/Component/Mailer/EventListener/MessageListener.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mime\BodyRendererInterface; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Message; + +/** + * Manipulates the headers and the body of a Message. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MessageListener implements EventSubscriberInterface +{ + private $headers; + private $renderer; + + public function __construct(Headers $headers = null, BodyRendererInterface $renderer = null) + { + $this->headers = $headers; + $this->renderer = $renderer; + } + + public function onMessage(MessageEvent $event): void + { + $message = $event->getMessage(); + if (!$message instanceof Message) { + return; + } + + $this->setHeaders($message); + $this->renderMessage($message); + } + + private function setHeaders(Message $message): void + { + if (!$this->headers) { + return; + } + + $headers = $message->getHeaders(); + foreach ($this->headers->getAll() as $name => $header) { + if (!$headers->has($name)) { + $headers->add($header); + } else { + if (Headers::isUniqueHeader($name)) { + continue; + } + $headers->add($header); + } + } + $message->setHeaders($headers); + } + + private function renderMessage(Message $message): void + { + if (!$this->renderer) { + return; + } + + $this->renderer->render($message); + } + + public static function getSubscribedEvents() + { + return [ + MessageEvent::class => 'onMessage', + ]; + } +} diff --git a/src/Symfony/Component/Mailer/Exception/ExceptionInterface.php b/src/Symfony/Component/Mailer/Exception/ExceptionInterface.php new file mode 100644 index 0000000000000..6339d82260d94 --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/ExceptionInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * Exception interface for all exceptions thrown by the component. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/src/Symfony/Component/Mailer/Exception/HttpTransportException.php b/src/Symfony/Component/Mailer/Exception/HttpTransportException.php new file mode 100644 index 0000000000000..ea9c1c85fb8f3 --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/HttpTransportException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class HttpTransportException extends TransportException +{ +} diff --git a/src/Symfony/Component/Mailer/Exception/InvalidArgumentException.php b/src/Symfony/Component/Mailer/Exception/InvalidArgumentException.php new file mode 100644 index 0000000000000..371bef87dd28e --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mailer/Exception/LogicException.php b/src/Symfony/Component/Mailer/Exception/LogicException.php new file mode 100644 index 0000000000000..9cbc6c5ea32f8 --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/LogicException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mailer/Exception/RuntimeException.php b/src/Symfony/Component/Mailer/Exception/RuntimeException.php new file mode 100644 index 0000000000000..0904c65d8883b --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/RuntimeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mailer/Exception/TransportException.php b/src/Symfony/Component/Mailer/Exception/TransportException.php new file mode 100644 index 0000000000000..3763694f68ed0 --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/TransportException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class TransportException extends RuntimeException implements TransportExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mailer/Exception/TransportExceptionInterface.php b/src/Symfony/Component/Mailer/Exception/TransportExceptionInterface.php new file mode 100644 index 0000000000000..47e7e8dc3e324 --- /dev/null +++ b/src/Symfony/Component/Mailer/Exception/TransportExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Exception; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +interface TransportExceptionInterface extends ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Mailer/LICENSE b/src/Symfony/Component/Mailer/LICENSE new file mode 100644 index 0000000000000..1a1869751d250 --- /dev/null +++ b/src/Symfony/Component/Mailer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/Mailer/Mailer.php b/src/Symfony/Component/Mailer/Mailer.php new file mode 100644 index 0000000000000..6ed345146fe2d --- /dev/null +++ b/src/Symfony/Component/Mailer/Mailer.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Messenger\SendEmailMessage; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class Mailer implements MailerInterface +{ + private $transport; + private $bus; + + public function __construct(TransportInterface $transport, MessageBusInterface $bus = null) + { + $this->transport = $transport; + $this->bus = $bus; + } + + public function send(RawMessage $message, SmtpEnvelope $envelope = null): void + { + if (null === $this->bus) { + $this->transport->send($message, $envelope); + + return; + } + + $this->bus->dispatch(new SendEmailMessage($message, $envelope)); + } +} diff --git a/src/Symfony/Component/Mailer/MailerInterface.php b/src/Symfony/Component/Mailer/MailerInterface.php new file mode 100644 index 0000000000000..1a54e4d4c0639 --- /dev/null +++ b/src/Symfony/Component/Mailer/MailerInterface.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * Interface for mailers able to send emails synchronous and/or asynchronous. + * + * Implementations must support synchronous and asynchronous sending. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +interface MailerInterface +{ + /** + * @throws TransportExceptionInterface + */ + public function send(RawMessage $message, SmtpEnvelope $envelope = null): void; +} diff --git a/src/Symfony/Component/Mailer/Messenger/MessageHandler.php b/src/Symfony/Component/Mailer/Messenger/MessageHandler.php new file mode 100644 index 0000000000000..6f1d609ceed16 --- /dev/null +++ b/src/Symfony/Component/Mailer/Messenger/MessageHandler.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Messenger; + +use Symfony\Component\Mailer\Transport\TransportInterface; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class MessageHandler +{ + private $transport; + + public function __construct(TransportInterface $transport) + { + $this->transport = $transport; + } + + public function __invoke(SendEmailMessage $message) + { + $this->transport->send($message->getMessage(), $message->getEnvelope()); + } +} diff --git a/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php b/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php new file mode 100644 index 0000000000000..862a1eecc83ff --- /dev/null +++ b/src/Symfony/Component/Mailer/Messenger/SendEmailMessage.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Messenger; + +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class SendEmailMessage +{ + private $message; + private $envelope; + + /** + * @internal + */ + public function __construct(RawMessage $message, SmtpEnvelope $envelope = null) + { + $this->message = $message; + $this->envelope = $envelope; + } + + public function getMessage(): RawMessage + { + return $this->message; + } + + public function getEnvelope(): ?SmtpEnvelope + { + return $this->envelope; + } +} diff --git a/src/Symfony/Component/Mailer/README.md b/src/Symfony/Component/Mailer/README.md new file mode 100644 index 0000000000000..0f70cc30d74b2 --- /dev/null +++ b/src/Symfony/Component/Mailer/README.md @@ -0,0 +1,12 @@ +Mailer Component +================ + +The Mailer component helps sending emails. + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/Mailer/SentMessage.php b/src/Symfony/Component/Mailer/SentMessage.php new file mode 100644 index 0000000000000..3a7f5ddfa86bf --- /dev/null +++ b/src/Symfony/Component/Mailer/SentMessage.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class SentMessage +{ + private $original; + private $raw; + private $envelope; + + /** + * @internal + */ + public function __construct(RawMessage $message, SmtpEnvelope $envelope) + { + $this->raw = $message instanceof Message ? new RawMessage($message->toIterable()) : $message; + $this->original = $message; + $this->envelope = $envelope; + } + + public function getMessage(): RawMessage + { + return $this->raw; + } + + public function getOriginalMessage(): RawMessage + { + return $this->original; + } + + public function getEnvelope(): SmtpEnvelope + { + return $this->envelope; + } + + public function toString(): string + { + return $this->raw->toString(); + } + + public function toIterable(): iterable + { + return $this->raw->toIterable(); + } +} diff --git a/src/Symfony/Component/Mailer/SmtpEnvelope.php b/src/Symfony/Component/Mailer/SmtpEnvelope.php new file mode 100644 index 0000000000000..6a41027305c17 --- /dev/null +++ b/src/Symfony/Component/Mailer/SmtpEnvelope.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\NamedAddress; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class SmtpEnvelope +{ + private $sender; + private $recipients = []; + + /** + * @param Address[] $recipients + */ + public function __construct(Address $sender, array $recipients) + { + $this->setSender($sender); + $this->setRecipients($recipients); + } + + public static function create(RawMessage $message): self + { + if ($message instanceof Message) { + $headers = $message->getHeaders(); + + return new self(self::getSenderFromHeaders($headers), self::getRecipientsFromHeaders($headers)); + } + + // FIXME: parse the raw message to create the envelope? + throw new InvalidArgumentException(sprintf('Unable to create an SmtpEnvelope from a "%s" message.', RawMessage::class)); + } + + public function setSender(Address $sender): void + { + $this->sender = $sender instanceof NamedAddress ? new Address($sender->getAddress()) : $sender; + } + + public function getSender(): Address + { + return $this->sender; + } + + public function setRecipients(array $recipients): void + { + if (!$recipients) { + throw new InvalidArgumentException('An envelope must have at least one recipient.'); + } + + $this->recipients = []; + foreach ($recipients as $recipient) { + if ($recipient instanceof NamedAddress) { + $recipient = new Address($recipient->getAddress()); + } elseif (!$recipient instanceof Address) { + throw new InvalidArgumentException(sprintf('A recipient must be an instance of "%s" (got "%s").', Address::class, \is_object($recipient) ? \get_class($recipient) : \gettype($recipient))); + } + $this->recipients[] = $recipient; + } + } + + /** + * @return Address[] + */ + public function getRecipients(): array + { + return $this->recipients; + } + + private static function getRecipientsFromHeaders(Headers $headers): array + { + $recipients = []; + foreach (['to', 'cc', 'bcc'] as $name) { + foreach ($headers->getAll($name) as $header) { + $recipients = array_merge($recipients, $header->getAddresses()); + } + } + + return $recipients; + } + + private static function getSenderFromHeaders(Headers $headers): Address + { + if ($return = $headers->get('Return-Path')) { + return $return->getAddress(); + } + if ($sender = $headers->get('Sender')) { + return $sender->getAddress(); + } + if ($from = $headers->get('From')) { + return $from->getAddresses()[0]; + } + + throw new LogicException('Unable to determine the sender of the message.'); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/SentMessageTest.php b/src/Symfony/Component/Mailer/Tests/SentMessageTest.php new file mode 100644 index 0000000000000..a8193bb04a5df --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/SentMessageTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\RawMessage; + +class SentMessageTest extends TestCase +{ + public function test() + { + $m = new SentMessage($r = new RawMessage('Email'), $e = new SmtpEnvelope(new Address('fabien@example.com'), [new Address('helene@example.com')])); + $this->assertSame($r, $m->getOriginalMessage()); + $this->assertSame($r, $m->getMessage()); + $this->assertSame($e, $m->getEnvelope()); + $this->assertEquals($r->toString(), $m->toString()); + $this->assertEquals($r->toIterable(), $m->toIterable()); + + $m = new SentMessage($r = (new Email())->from('fabien@example.com')->to('helene@example.com')->text('text'), $e); + $this->assertSame($r, $m->getOriginalMessage()); + $this->assertNotSame($r, $m->getMessage()); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php b/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php new file mode 100644 index 0000000000000..4e0c17f5e838b --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\NamedAddress; +use Symfony\Component\Mime\RawMessage; + +class SmtpEnvelopeTest extends TestCase +{ + public function testConstructorWithAddressSender() + { + $e = new SmtpEnvelope(new Address('fabien@symfony.com'), [new Address('thomas@symfony.com')]); + $this->assertEquals(new Address('fabien@symfony.com'), $e->getSender()); + } + + public function testConstructorWithNamedAddressSender() + { + $e = new SmtpEnvelope(new NamedAddress('fabien@symfony.com', 'Fabien'), [new Address('thomas@symfony.com')]); + $this->assertEquals(new Address('fabien@symfony.com'), $e->getSender()); + } + + public function testConstructorWithAddressRecipients() + { + $e = new SmtpEnvelope(new Address('fabien@symfony.com'), [new Address('thomas@symfony.com'), new NamedAddress('lucas@symfony.com', 'Lucas')]); + $this->assertEquals([new Address('thomas@symfony.com'), new Address('lucas@symfony.com')], $e->getRecipients()); + } + + public function testConstructorWithNoRecipients() + { + $this->expectException(\InvalidArgumentException::class); + $e = new SmtpEnvelope(new Address('fabien@symfony.com'), []); + } + + public function testConstructorWithWrongRecipients() + { + $this->expectException(\InvalidArgumentException::class); + $e = new SmtpEnvelope(new Address('fabien@symfony.com'), ['lucas@symfony.com']); + } + + public function testSenderFromHeaders() + { + $headers = new Headers(); + $headers->addPathHeader('Return-Path', 'return@symfony.com'); + $headers->addMailboxListHeader('To', ['from@symfony.com']); + $e = SmtpEnvelope::create(new Message($headers)); + $this->assertEquals('return@symfony.com', $e->getSender()->getAddress()); + + $headers = new Headers(); + $headers->addMailboxHeader('Sender', 'sender@symfony.com'); + $headers->addMailboxListHeader('To', ['from@symfony.com']); + $e = SmtpEnvelope::create(new Message($headers)); + $this->assertEquals('sender@symfony.com', $e->getSender()->getAddress()); + + $headers = new Headers(); + $headers->addMailboxListHeader('From', ['from@symfony.com', 'some@symfony.com']); + $headers->addMailboxListHeader('To', ['from@symfony.com']); + $e = SmtpEnvelope::create(new Message($headers)); + $this->assertEquals('from@symfony.com', $e->getSender()->getAddress()); + } + + public function testSenderFromHeadersWithoutData() + { + $this->expectException(\LogicException::class); + $headers = new Headers(); + $headers->addMailboxListHeader('To', ['from@symfony.com']); + SmtpEnvelope::create(new Message($headers)); + } + + public function testRecipientsFromHeaders() + { + $headers = new Headers(); + $headers->addPathHeader('Return-Path', 'return@symfony.com'); + $headers->addMailboxListHeader('To', ['to@symfony.com']); + $headers->addMailboxListHeader('Cc', ['cc@symfony.com']); + $headers->addMailboxListHeader('Bcc', ['bcc@symfony.com']); + $e = SmtpEnvelope::create(new Message($headers)); + $this->assertEquals([new Address('to@symfony.com'), new Address('cc@symfony.com'), new Address('bcc@symfony.com')], $e->getRecipients()); + } + + public function testCreateWithRawMessage() + { + $this->expectException(\InvalidArgumentException::class); + SmtpEnvelope::create(new RawMessage('')); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php new file mode 100644 index 0000000000000..d3d8e438bd3f7 --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/Transport/AbstractTransportTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\NullTransport; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\RawMessage; + +/** + * @group time-sensitive + */ +class AbstractTransportTest extends TestCase +{ + public function testThrottling() + { + $transport = new NullTransport(); + $transport->setMaxPerSecond(2 / 10); + $message = new RawMessage(''); + $envelope = new SmtpEnvelope(new Address('fabien@example.com'), [new Address('helene@example.com')]); + + $start = time(); + $transport->send($message, $envelope); + $this->assertEquals(0, time() - $start, '', 1); + $transport->send($message, $envelope); + $this->assertEquals(5, time() - $start, '', 1); + $transport->send($message, $envelope); + $this->assertEquals(10, time() - $start, '', 1); + $transport->send($message, $envelope); + $this->assertEquals(15, time() - $start, '', 1); + + $start = time(); + $transport->setMaxPerSecond(-3); + $transport->send($message, $envelope); + $this->assertEquals(0, time() - $start, '', 1); + $transport->send($message, $envelope); + $this->assertEquals(0, time() - $start, '', 1); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php new file mode 100644 index 0000000000000..dc3bc21a7dc44 --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Transport\FailoverTransport; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * @group time-sensitive + */ +class FailoverTransportTest extends TestCase +{ + public function testSendNoTransports() + { + $this->expectException(TransportException::class); + new FailoverTransport([]); + } + + public function testSendFirstWork() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->exactly(3))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->never())->method('send'); + $t = new FailoverTransport([$t1, $t2]); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + } + + public function testSendAllDead() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->once())->method('send')->will($this->throwException(new TransportException())); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->once())->method('send')->will($this->throwException(new TransportException())); + $t = new FailoverTransport([$t1, $t2]); + $this->expectException(TransportException::class); + $this->expectExceptionMessage('All transports failed.'); + $t->send(new RawMessage('')); + } + + public function testSendOneDead() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->once())->method('send')->will($this->throwException(new TransportException())); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->exactly(3))->method('send'); + $t = new FailoverTransport([$t1, $t2]); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + } + + public function testSendOneDeadButRecover() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->at(1))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send'); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->at(2))->method('send')->will($this->throwException(new TransportException())); + $t = new FailoverTransport([$t1, $t2], 1); + $t->send(new RawMessage('')); + sleep(1); + $t->send(new RawMessage('')); + sleep(1); + $t->send(new RawMessage('')); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php new file mode 100644 index 0000000000000..b27a3e7949845 --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Transport\RoundRobinTransport; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\RawMessage; + +/** + * @group time-sensitive + */ +class RoundRobinTransportTest extends TestCase +{ + public function testSendNoTransports() + { + $this->expectException(TransportException::class); + new RoundRobinTransport([]); + } + + public function testSendAlternate() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->exactly(2))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->once())->method('send'); + $t = new RoundRobinTransport([$t1, $t2]); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + } + + public function testSendAllDead() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->once())->method('send')->will($this->throwException(new TransportException())); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->once())->method('send')->will($this->throwException(new TransportException())); + $t = new RoundRobinTransport([$t1, $t2]); + $this->expectException(TransportException::class); + $this->expectExceptionMessage('All transports failed.'); + $t->send(new RawMessage('')); + } + + public function testSendOneDead() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->once())->method('send')->will($this->throwException(new TransportException())); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->exactly(3))->method('send'); + $t = new RoundRobinTransport([$t1, $t2]); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + } + + public function testSendOneDeadButRecover() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->at(1))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->once())->method('send'); + $t = new RoundRobinTransport([$t1, $t2], 1); + $t->send(new RawMessage('')); + sleep(2); + $t->send(new RawMessage('')); + } +} diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/AbstractStreamTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/AbstractStreamTest.php new file mode 100644 index 0000000000000..cc901ccb7ceab --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/AbstractStreamTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests\Transport\Smtp\Stream; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; + +class AbstractStreamTest extends TestCase +{ + /** + * @dataProvider provideReplace + */ + public function testReplace(string $expected, string $from, string $to, array $chunks) + { + $result = ''; + foreach (AbstractStream::replace($from, $to, $chunks) as $chunk) { + $result .= $chunk; + } + + $this->assertSame($expected, $result); + } + + public function provideReplace() + { + yield ['ca', 'ab', 'c', ['a', 'b', 'a']]; + yield ['ac', 'ab', 'c', ['a', 'ab']]; + yield ['cbc', 'aba', 'c', ['ababa', 'ba']]; + } +} diff --git a/src/Symfony/Component/Mailer/Tests/TransportTest.php b/src/Symfony/Component/Mailer/Tests/TransportTest.php new file mode 100644 index 0000000000000..4ecec2e66a0f6 --- /dev/null +++ b/src/Symfony/Component/Mailer/Tests/TransportTest.php @@ -0,0 +1,283 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Tests; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Bridge\Amazon; +use Symfony\Component\Mailer\Bridge\Google; +use Symfony\Component\Mailer\Bridge\Mailchimp; +use Symfony\Component\Mailer\Bridge\Mailgun; +use Symfony\Component\Mailer\Bridge\Postmark; +use Symfony\Component\Mailer\Bridge\Sendgrid; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\Transport; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +class TransportTest extends TestCase +{ + public function testFromDsnNull() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://null', $dispatcher, null, $logger); + $this->assertInstanceOf(Transport\NullTransport::class, $transport); + $p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher'); + $p->setAccessible(true); + $this->assertSame($dispatcher, $p->getValue($transport)); + } + + public function testFromDsnSendmail() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://sendmail', $dispatcher, null, $logger); + $this->assertInstanceOf(Transport\SendmailTransport::class, $transport); + $p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher'); + $p->setAccessible(true); + $this->assertSame($dispatcher, $p->getValue($transport)); + } + + public function testFromDsnSmtp() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://localhost:44?auth_mode=plain&encryption=tls', $dispatcher, null, $logger); + $this->assertInstanceOf(Transport\Smtp\SmtpTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger); + $this->assertEquals('localhost', $transport->getStream()->getHost()); + $this->assertEquals('plain', $transport->getAuthMode()); + $this->assertTrue($transport->getStream()->isTLS()); + $this->assertEquals(44, $transport->getStream()->getPort()); + } + + public function testFromInvalidDsn() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "some://" mailer DSN is invalid.'); + Transport::fromDsn('some://'); + } + + public function testFromInvalidDsnNoHost() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "?!" mailer DSN must contain a mailer name.'); + Transport::fromDsn('?!'); + } + + public function testFromInvalidTransportName() + { + $this->expectException(LogicException::class); + Transport::fromDsn('api://foobar'); + } + + public function testFromDsnGmail() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@gmail', $dispatcher, null, $logger); + $this->assertInstanceOf(Google\Smtp\GmailTransport::class, $transport); + $this->assertEquals('u$er', $transport->getUsername()); + $this->assertEquals('pa$s', $transport->getPassword()); + $this->assertProperties($transport, $dispatcher, $logger); + + $this->expectException(LogicException::class); + Transport::fromDsn('http://gmail'); + } + + public function testFromDsnMailgun() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, null, $logger); + $this->assertInstanceOf(Mailgun\Smtp\MailgunTransport::class, $transport); + $this->assertEquals('u$er', $transport->getUsername()); + $this->assertEquals('pa$s', $transport->getPassword()); + $this->assertProperties($transport, $dispatcher, $logger); + + $client = $this->createMock(HttpClientInterface::class); + $transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger); + $this->assertInstanceOf(Mailgun\Http\MailgunTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'key' => 'u$er', + 'domain' => 'pa$s', + 'client' => $client, + ]); + + $transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@mailgun', $dispatcher, $client, $logger); + $this->assertInstanceOf(Mailgun\Http\Api\MailgunTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'key' => 'u$er', + 'domain' => 'pa$s', + 'client' => $client, + ]); + + $this->expectException(LogicException::class); + Transport::fromDsn('foo://mailgun'); + } + + public function testFromDsnPostmark() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://'.urlencode('u$er').'@postmark', $dispatcher, null, $logger); + $this->assertInstanceOf(Postmark\Smtp\PostmarkTransport::class, $transport); + $this->assertEquals('u$er', $transport->getUsername()); + $this->assertEquals('u$er', $transport->getPassword()); + $this->assertProperties($transport, $dispatcher, $logger); + + $client = $this->createMock(HttpClientInterface::class); + $transport = Transport::fromDsn('api://'.urlencode('u$er').'@postmark', $dispatcher, $client, $logger); + $this->assertInstanceOf(Postmark\Http\Api\PostmarkTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'key' => 'u$er', + 'client' => $client, + ]); + + $this->expectException(LogicException::class); + Transport::fromDsn('http://postmark'); + } + + public function testFromDsnSendgrid() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://'.urlencode('u$er').'@sendgrid', $dispatcher, null, $logger); + $this->assertInstanceOf(Sendgrid\Smtp\SendgridTransport::class, $transport); + $this->assertEquals('apikey', $transport->getUsername()); + $this->assertEquals('u$er', $transport->getPassword()); + $this->assertProperties($transport, $dispatcher, $logger); + + $client = $this->createMock(HttpClientInterface::class); + $transport = Transport::fromDsn('api://'.urlencode('u$er').'@sendgrid', $dispatcher, $client, $logger); + $this->assertInstanceOf(Sendgrid\Http\Api\SendgridTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'key' => 'u$er', + 'client' => $client, + ]); + + $this->expectException(LogicException::class); + Transport::fromDsn('http://sendgrid'); + } + + public function testFromDsnAmazonSes() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, null, $logger); + $this->assertInstanceOf(Amazon\Smtp\SesTransport::class, $transport); + $this->assertEquals('u$er', $transport->getUsername()); + $this->assertEquals('pa$s', $transport->getPassword()); + $this->assertContains('.sun.', $transport->getStream()->getHost()); + $this->assertProperties($transport, $dispatcher, $logger); + + $client = $this->createMock(HttpClientInterface::class); + $transport = Transport::fromDsn('http://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, $client, $logger); + $this->assertInstanceOf(Amazon\Http\SesTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'accessKey' => 'u$er', + 'secretKey' => 'pa$s', + 'region' => 'sun', + 'client' => $client, + ]); + + $transport = Transport::fromDsn('api://'.urlencode('u$er').':'.urlencode('pa$s').'@ses?region=sun', $dispatcher, $client, $logger); + $this->assertInstanceOf(Amazon\Http\Api\SesTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'accessKey' => 'u$er', + 'secretKey' => 'pa$s', + 'region' => 'sun', + 'client' => $client, + ]); + + $this->expectException(LogicException::class); + Transport::fromDsn('foo://ses'); + } + + public function testFromDsnMailchimp() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://'.urlencode('u$er').':'.urlencode('pa$s').'@mandrill', $dispatcher, null, $logger); + $this->assertInstanceOf(Mailchimp\Smtp\MandrillTransport::class, $transport); + $this->assertEquals('u$er', $transport->getUsername()); + $this->assertEquals('pa$s', $transport->getPassword()); + $this->assertProperties($transport, $dispatcher, $logger); + + $client = $this->createMock(HttpClientInterface::class); + $transport = Transport::fromDsn('http://'.urlencode('u$er').'@mandrill', $dispatcher, $client, $logger); + $this->assertInstanceOf(Mailchimp\Http\MandrillTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'key' => 'u$er', + 'client' => $client, + ]); + + $transport = Transport::fromDsn('api://'.urlencode('u$er').'@mandrill', $dispatcher, $client, $logger); + $this->assertInstanceOf(Mailchimp\Http\Api\MandrillTransport::class, $transport); + $this->assertProperties($transport, $dispatcher, $logger, [ + 'key' => 'u$er', + 'client' => $client, + ]); + + $this->expectException(LogicException::class); + Transport::fromDsn('foo://mandrill'); + } + + public function testFromDsnFailover() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://null || smtp://null || smtp://null', $dispatcher, null, $logger); + $this->assertInstanceOf(Transport\FailoverTransport::class, $transport); + $p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports'); + $p->setAccessible(true); + $transports = $p->getValue($transport); + $this->assertCount(3, $transports); + foreach ($transports as $transport) { + $this->assertProperties($transport, $dispatcher, $logger); + } + } + + public function testFromDsnRoundRobin() + { + $dispatcher = $this->createMock(EventDispatcherInterface::class); + $logger = $this->createMock(LoggerInterface::class); + $transport = Transport::fromDsn('smtp://null && smtp://null && smtp://null', $dispatcher, null, $logger); + $this->assertInstanceOf(Transport\RoundRobinTransport::class, $transport); + $p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports'); + $p->setAccessible(true); + $transports = $p->getValue($transport); + $this->assertCount(3, $transports); + foreach ($transports as $transport) { + $this->assertProperties($transport, $dispatcher, $logger); + } + } + + private function assertProperties(Transport\TransportInterface $transport, EventDispatcherInterface $dispatcher, LoggerInterface $logger, array $props = []) + { + $p = new \ReflectionProperty(Transport\AbstractTransport::class, 'dispatcher'); + $p->setAccessible(true); + $this->assertSame($dispatcher, $p->getValue($transport)); + + $p = new \ReflectionProperty(Transport\AbstractTransport::class, 'logger'); + $p->setAccessible(true); + $this->assertSame($logger, $p->getValue($transport)); + + foreach ($props as $prop => $value) { + $p = new \ReflectionProperty($transport, $prop); + $p->setAccessible(true); + $this->assertEquals($value, $p->getValue($transport)); + } + } +} diff --git a/src/Symfony/Component/Mailer/Transport.php b/src/Symfony/Component/Mailer/Transport.php new file mode 100644 index 0000000000000..c97f0c49a3a57 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport.php @@ -0,0 +1,180 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Bridge\Amazon; +use Symfony\Component\Mailer\Bridge\Google; +use Symfony\Component\Mailer\Bridge\Mailchimp; +use Symfony\Component\Mailer\Bridge\Mailgun; +use Symfony\Component\Mailer\Bridge\Postmark; +use Symfony\Component\Mailer\Bridge\Sendgrid; +use Symfony\Component\Mailer\Exception\InvalidArgumentException; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class Transport +{ + public static function fromDsn(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface + { + // failover? + $dsns = preg_split('/\s++\|\|\s++/', $dsn); + if (\count($dsns) > 1) { + $transports = []; + foreach ($dsns as $dsn) { + $transports[] = self::createTransport($dsn, $dispatcher, $client, $logger); + } + + return new Transport\FailoverTransport($transports); + } + + // round robin? + $dsns = preg_split('/\s++&&\s++/', $dsn); + if (\count($dsns) > 1) { + $transports = []; + foreach ($dsns as $dsn) { + $transports[] = self::createTransport($dsn, $dispatcher, $client, $logger); + } + + return new Transport\RoundRobinTransport($transports); + } + + return self::createTransport($dsn, $dispatcher, $client, $logger); + } + + private static function createTransport(string $dsn, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null, LoggerInterface $logger = null): TransportInterface + { + if (false === $parsedDsn = parse_url($dsn)) { + throw new InvalidArgumentException(sprintf('The "%s" mailer DSN is invalid.', $dsn)); + } + + if (!isset($parsedDsn['host'])) { + throw new InvalidArgumentException(sprintf('The "%s" mailer DSN must contain a mailer name.', $dsn)); + } + + $user = \urldecode($parsedDsn['user'] ?? ''); + $pass = \urldecode($parsedDsn['pass'] ?? ''); + \parse_str($parsedDsn['query'] ?? '', $query); + + switch ($parsedDsn['host']) { + case 'null': + if ('smtp' === $parsedDsn['scheme']) { + return new Transport\NullTransport($dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'sendmail': + if ('smtp' === $parsedDsn['scheme']) { + return new Transport\SendmailTransport(null, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'gmail': + if (!class_exists(Google\Smtp\GmailTransport::class)) { + throw new \LogicException('Unable to send emails via Gmail as the Google bridge is not installed. Try running "composer require symfony/google-bridge".'); + } + + if ('smtp' === $parsedDsn['scheme']) { + return new Google\Smtp\GmailTransport($user, $pass, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'mailgun': + if (!class_exists(Mailgun\Smtp\MailgunTransport::class)) { + throw new \LogicException('Unable to send emails via Mailgun as the bridge is not installed. Try running "composer require symfony/mailgun-bridge".'); + } + + if ('smtp' === $parsedDsn['scheme']) { + return new Mailgun\Smtp\MailgunTransport($user, $pass, $dispatcher, $logger); + } + if ('http' === $parsedDsn['scheme']) { + return new Mailgun\Http\MailgunTransport($user, $pass, $client, $dispatcher, $logger); + } + if ('api' === $parsedDsn['scheme']) { + return new Mailgun\Http\Api\MailgunTransport($user, $pass, $client, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'postmark': + if (!class_exists(Postmark\Smtp\PostmarkTransport::class)) { + throw new \LogicException('Unable to send emails via Postmark as the bridge is not installed. Try running "composer require symfony/postmark-bridge".'); + } + + if ('smtp' === $parsedDsn['scheme']) { + return new Postmark\Smtp\PostmarkTransport($user, $dispatcher, $logger); + } + if ('api' === $parsedDsn['scheme']) { + return new Postmark\Http\Api\PostmarkTransport($user, $client, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'sendgrid': + if (!class_exists(Sendgrid\Smtp\SendgridTransport::class)) { + throw new \LogicException('Unable to send emails via Sendgrid as the bridge is not installed. Try running "composer require symfony/sendgrid-bridge".'); + } + + if ('smtp' === $parsedDsn['scheme']) { + return new Sendgrid\Smtp\SendgridTransport($user, $dispatcher, $logger); + } + if ('api' === $parsedDsn['scheme']) { + return new Sendgrid\Http\Api\SendgridTransport($user, $client, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'ses': + if (!class_exists(Amazon\Smtp\SesTransport::class)) { + throw new \LogicException('Unable to send emails via Amazon SES as the bridge is not installed. Try running "composer require symfony/amazon-bridge".'); + } + + if ('smtp' === $parsedDsn['scheme']) { + return new Amazon\Smtp\SesTransport($user, $pass, $query['region'] ?? null, $dispatcher, $logger); + } + if ('api' === $parsedDsn['scheme']) { + return new Amazon\Http\Api\SesTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger); + } + if ('http' === $parsedDsn['scheme']) { + return new Amazon\Http\SesTransport($user, $pass, $query['region'] ?? null, $client, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + case 'mandrill': + if (!class_exists(Mailchimp\Smtp\MandrillTransport::class)) { + throw new \LogicException('Unable to send emails via Mandrill as the bridge is not installed. Try running "composer require symfony/mailchimp-bridge".'); + } + + if ('smtp' === $parsedDsn['scheme']) { + return new Mailchimp\Smtp\MandrillTransport($user, $pass, $dispatcher, $logger); + } + if ('api' === $parsedDsn['scheme']) { + return new Mailchimp\Http\Api\MandrillTransport($user, $client, $dispatcher, $logger); + } + if ('http' === $parsedDsn['scheme']) { + return new Mailchimp\Http\MandrillTransport($user, $client, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); + default: + if ('smtp' === $parsedDsn['scheme']) { + return new Transport\Smtp\EsmtpTransport($parsedDsn['host'], $parsedDsn['port'] ?? 25, $query['encryption'] ?? null, $query['auth_mode'] ?? null, $dispatcher, $logger); + } + + throw new LogicException(sprintf('The "%s" mailer is not supported.', $parsedDsn['host'])); + } + } +} diff --git a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php new file mode 100644 index 0000000000000..deebd538f5e7f --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Event\MessageEvent; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\RawMessage; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +abstract class AbstractTransport implements TransportInterface +{ + private $dispatcher; + private $logger; + private $rate = 0; + private $lastSent = 0; + + public function __construct(EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->dispatcher = $dispatcher ?: new EventDispatcher(); + $this->logger = $logger ?: new NullLogger(); + } + + /** + * Sets the maximum number of messages to send per second (0 to disable). + */ + public function setMaxPerSecond(float $rate): self + { + if (0 >= $rate) { + $rate = 0; + } + + $this->rate = $rate; + $this->lastSent = 0; + + return $this; + } + + public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage + { + $message = clone $message; + if (null !== $envelope) { + $envelope = clone $envelope; + } else { + try { + $envelope = SmtpEnvelope::create($message); + } catch (\Exception $e) { + throw new TransportException('Cannot send message without a valid envelope.', 0, $e); + } + } + + $event = new MessageEvent($message, $envelope); + $this->dispatcher->dispatch($event); + $envelope = $event->getEnvelope(); + if (!$envelope->getRecipients()) { + return null; + } + + $message = new SentMessage($event->getMessage(), $envelope); + $this->doSend($message); + + $this->checkThrottling(); + + return $message; + } + + abstract protected function doSend(SentMessage $message): void; + + /** + * @param Address[] $addresses + * + * @return string[] + */ + protected function stringifyAddresses(array $addresses): array + { + return \array_map(function (Address $a) { + return $a->toString(); + }, $addresses); + } + + protected function getLogger(): LoggerInterface + { + return $this->logger; + } + + private function checkThrottling() + { + if (0 == $this->rate) { + return; + } + + $sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent); + if (0 < $sleep) { + $this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep)); + usleep($sleep * 1000000); + } + $this->lastSent = microtime(true); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/FailoverTransport.php b/src/Symfony/Component/Mailer/Transport/FailoverTransport.php new file mode 100644 index 0000000000000..9bb9b58638ee7 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/FailoverTransport.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +/** + * Uses several Transports using a failover algorithm. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class FailoverTransport extends RoundRobinTransport +{ + private $currentTransport; + + protected function getNextTransport(): ?TransportInterface + { + if (null === $this->currentTransport || $this->isTransportDead($this->currentTransport)) { + $this->currentTransport = parent::getNextTransport(); + } + + return $this->currentTransport; + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Http/Api/AbstractApiTransport.php b/src/Symfony/Component/Mailer/Transport/Http/Api/AbstractApiTransport.php new file mode 100644 index 0000000000000..89c25ca37661d --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Http/Api/AbstractApiTransport.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Http\Api; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Mailer\Exception\RuntimeException; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\MessageConverter; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +abstract class AbstractApiTransport extends AbstractTransport +{ + protected $client; + + public function __construct(HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + $this->client = $client; + if (null === $client) { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = HttpClient::create(); + } + + parent::__construct($dispatcher, $logger); + } + + abstract protected function doSendEmail(Email $email, SmtpEnvelope $envelope): void; + + protected function doSend(SentMessage $message): void + { + try { + $email = MessageConverter::toEmail($message->getOriginalMessage()); + } catch (\Exception $e) { + throw new RuntimeException(sprintf('Unable to send message with the "%s" transport: %s', __CLASS__, $e->getMessage()), 0, $e); + } + + $this->doSendEmail($email, $message->getEnvelope()); + } + + protected function getRecipients(Email $email, SmtpEnvelope $envelope): array + { + return \array_filter($envelope->getRecipients(), function (Address $address) use ($email) { + return false === \in_array($address, \array_merge($email->getCc(), $email->getBcc()), true); + }); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/NullTransport.php b/src/Symfony/Component/Mailer/Transport/NullTransport.php new file mode 100644 index 0000000000000..ac5e7d2406d1b --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/NullTransport.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\SentMessage; + +/** + * Pretends messages have been sent, but just ignores them. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +final class NullTransport extends AbstractTransport +{ + protected function doSend(SentMessage $message): void + { + } +} diff --git a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php new file mode 100644 index 0000000000000..22b1ba9714347 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\RawMessage; + +/** + * Uses several Transports using a round robin algorithm. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +class RoundRobinTransport implements TransportInterface +{ + private $deadTransports; + private $transports = []; + private $retryPeriod; + + /** + * @param TransportInterface[] $transports + */ + public function __construct(array $transports, int $retryPeriod = 60) + { + if (!$transports) { + throw new TransportException(__CLASS__.' must have at least one transport configured.'); + } + + $this->transports = $transports; + $this->deadTransports = new \SplObjectStorage(); + $this->retryPeriod = $retryPeriod; + } + + public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage + { + while ($transport = $this->getNextTransport()) { + try { + return $transport->send($message, $envelope); + } catch (TransportExceptionInterface $e) { + $this->deadTransports[$transport] = microtime(true); + } + } + + throw new TransportException('All transports failed.'); + } + + /** + * Rotates the transport list around and returns the first instance. + */ + protected function getNextTransport(): ?TransportInterface + { + while ($transport = array_shift($this->transports)) { + if (!$this->isTransportDead($transport)) { + break; + } + if ((microtime(true) - $this->deadTransports[$transport]) > $this->retryPeriod) { + $this->deadTransports->detach($transport); + + break; + } + } + + if ($transport) { + $this->transports[] = $transport; + } + + return $transport; + } + + protected function isTransportDead(TransportInterface $transport): bool + { + return $this->deadTransports->contains($transport); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/SendmailTransport.php b/src/Symfony/Component/Mailer/Transport/SendmailTransport.php new file mode 100644 index 0000000000000..b8b4512a3603c --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/SendmailTransport.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\ProcessStream; +use Symfony\Component\Mime\RawMessage; + +/** + * SendmailTransport for sending mail through a Sendmail/Postfix (etc..) binary. + * + * Supported modes are -bs and -t, with any additional flags desired. + * It is advised to use -bs mode since error reporting with -t mode is not + * possible. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class SendmailTransport extends AbstractTransport +{ + private $command = '/usr/sbin/sendmail -bs'; + private $stream; + private $transport; + + /** + * Constructor. + * + * If using -t mode you are strongly advised to include -oi or -i in the flags. + * For example: /usr/sbin/sendmail -oi -t + * -f flag will be appended automatically if one is not present. + * + * The recommended mode is "-bs" since it is interactive and failure notifications are hence possible. + */ + public function __construct(string $command = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct($dispatcher, $logger); + + if (null !== $command) { + if (false === strpos($command, ' -bs') && false === strpos($command, ' -t')) { + throw new \InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command)); + } + + $this->command = $command; + } + + $this->stream = new ProcessStream(); + if (false !== strpos($this->command, ' -bs')) { + $this->stream->setCommand($this->command); + $this->transport = new SmtpTransport($this->stream, $dispatcher, $logger); + } + } + + public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage + { + if ($this->transport) { + return $this->transport->send($message, $envelope); + } + + return parent::send($message, $envelope); + } + + protected function doSend(SentMessage $message): void + { + $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + + $command = $this->command; + if (false === strpos($command, ' -f')) { + $command .= ' -f'.escapeshellarg($message->getEnvelope()->getSender()->getEncodedAddress()); + } + + $chunks = AbstractStream::replace("\r\n", "\n", $message->toIterable()); + + if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { + $chunks = AbstractStream::replace("\n.", "\n..", $chunks); + } + + $this->stream->setCommand($command); + $this->stream->initialize(); + foreach ($chunks as $chunk) { + $this->stream->write($chunk); + } + $this->stream->flush(); + $this->stream->terminate(); + + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthenticatorInterface.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthenticatorInterface.php new file mode 100644 index 0000000000000..c5171b2e1d939 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/AuthenticatorInterface.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * An Authentication mechanism. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface AuthenticatorInterface +{ + /** + * Tries to authenticate the user. + * + * @throws TransportExceptionInterface + */ + public function authenticate(EsmtpTransport $client): void; + + /** + * Gets the name of the AUTH mechanism this Authenticator handles. + */ + public function getAuthKeyword(): string; +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/CramMd5Authenticator.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/CramMd5Authenticator.php new file mode 100644 index 0000000000000..a79c2b445aa1b --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/CramMd5Authenticator.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles CRAM-MD5 authentication. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class CramMd5Authenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'CRAM-MD5'; + } + + /** + * {@inheritdoc} + * + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $challenge = $client->executeCommand("AUTH CRAM-MD5\r\n", [334]); + $challenge = base64_decode(substr($challenge, 4)); + $message = base64_encode($client->getUsername().' '.$this->getResponse($client->getPassword(), $challenge)); + $client->executeCommand(sprintf("%s\r\n", $message), [235]); + } + + /** + * Generates a CRAM-MD5 response from a server challenge. + */ + private function getResponse(string $secret, string $challenge): string + { + if (\strlen($secret) > 64) { + $secret = pack('H32', md5($secret)); + } + + if (\strlen($secret) < 64) { + $secret = str_pad($secret, 64, \chr(0)); + } + + $kipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64); + $kopad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64); + + $inner = pack('H32', md5($kipad.$challenge)); + $digest = md5($kopad.$inner); + + return $digest; + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/LoginAuthenticator.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/LoginAuthenticator.php new file mode 100644 index 0000000000000..b8203bd1363e7 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/LoginAuthenticator.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles LOGIN authentication. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class LoginAuthenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'LOGIN'; + } + + /** + * {@inheritdoc} + * + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand("AUTH LOGIN\r\n", [334]); + $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getUsername())), [334]); + $client->executeCommand(sprintf("%s\r\n", base64_encode($client->getPassword())), [235]); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/PlainAuthenticator.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/PlainAuthenticator.php new file mode 100644 index 0000000000000..eb8386e17f1a5 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/PlainAuthenticator.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles PLAIN authentication. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class PlainAuthenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'PLAIN'; + } + + /** + * {@inheritdoc} + * + * @see https://www.ietf.org/rfc/rfc4954.txt + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand(sprintf("AUTH PLAIN %s\r\n", base64_encode($client->getUsername().\chr(0).$client->getUsername().\chr(0).$client->getPassword())), [235]); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 0000000000000..931df6514f07a --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Auth; + +use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; + +/** + * Handles XOAUTH2 authentication. + * + * @author xu.li + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol + * + * @experimental in 4.3 + */ +class XOAuth2Authenticator implements AuthenticatorInterface +{ + public function getAuthKeyword(): string + { + return 'XOAUTH2'; + } + + /** + * {@inheritdoc} + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism + */ + public function authenticate(EsmtpTransport $client): void + { + $client->executeCommand('AUTH XOAUTH2 '.base64_encode('user='.$client->getUsername()."\1auth=Bearer ".$client->getPassword()."\1\1")."\r\n", [235]); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php new file mode 100644 index 0000000000000..fc0ee2ca8f618 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php @@ -0,0 +1,205 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\Transport\Smtp\Auth\AuthenticatorInterface; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; + +/** + * Sends Emails over SMTP with ESMTP support. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class EsmtpTransport extends SmtpTransport +{ + private $authenticators = []; + private $username; + private $password; + private $authMode; + + public function __construct(string $host = 'localhost', int $port = 25, string $encryption = null, string $authMode = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct(null, $dispatcher, $logger); + + $this->authenticators = [ + new Auth\PlainAuthenticator(), + new Auth\LoginAuthenticator(), + new Auth\XOAuth2Authenticator(), + new Auth\CramMd5Authenticator(), + ]; + + /** @var SocketStream $stream */ + $stream = $this->getStream(); + $stream->setHost($host); + $stream->setPort($port); + if (null !== $encryption) { + $stream->setEncryption($encryption); + } + if (null !== $authMode) { + $this->setAuthMode($authMode); + } + } + + public function setUsername(string $username): self + { + $this->username = $username; + + return $this; + } + + public function getUsername(): string + { + return $this->username; + } + + public function setPassword(string $password): self + { + $this->password = $password; + + return $this; + } + + public function getPassword(): string + { + return $this->password; + } + + public function setAuthMode(string $mode): self + { + $this->authMode = $mode; + + return $this; + } + + public function getAuthMode(): string + { + return $this->authMode; + } + + public function addAuthenticator(AuthenticatorInterface $authenticator): void + { + $this->authenticators[] = $authenticator; + } + + protected function doHeloCommand(): void + { + try { + $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + } catch (TransportExceptionInterface $e) { + parent::doHeloCommand(); + + return; + } + + /** @var SocketStream $stream */ + $stream = $this->getStream(); + if ($stream->isTLS()) { + $this->executeCommand("STARTTLS\r\n", [220]); + + if (!$stream->startTLS()) { + throw new TransportException('Unable to connect with TLS encryption.'); + } + + try { + $response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]); + } catch (TransportExceptionInterface $e) { + parent::doHeloCommand(); + + return; + } + } + + $capabilities = $this->getCapabilities($response); + if (\array_key_exists('AUTH', $capabilities)) { + $this->handleAuth($capabilities['AUTH']); + } + } + + private function getCapabilities($ehloResponse): array + { + $capabilities = []; + $lines = explode("\r\n", trim($ehloResponse)); + array_shift($lines); + foreach ($lines as $line) { + if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { + $value = strtoupper(ltrim($matches[2], ' =')); + $capabilities[strtoupper($matches[1])] = $value ? explode(' ', $value) : []; + } + } + + return $capabilities; + } + + private function handleAuth(array $modes): void + { + if (!$this->username) { + return; + } + + $authNames = []; + $errors = []; + $modes = array_map('strtolower', $modes); + foreach ($this->getActiveAuthenticators() as $authenticator) { + if (!\in_array(strtolower($authenticator->getAuthKeyword()), $modes, true)) { + continue; + } + + $authNames[] = $authenticator->getAuthKeyword(); + try { + $authenticator->authenticate($this); + + return; + } catch (TransportExceptionInterface $e) { + $this->executeCommand("RSET\r\n", [250]); + + // keep the error message, but tries the other authenticators + $errors[$authenticator->getAuthKeyword()] = $e; + } + } + + if (!$authNames) { + throw new TransportException('Failed to find an authenticator supported by the SMTP server.'); + } + + $message = sprintf('Failed to authenticate on SMTP server with username "%s" using the following authenticators: "%s".', $this->username, implode('", "', $authNames)); + foreach ($errors as $name => $error) { + $message .= sprintf(' Authenticator "%s" returned "%s".', $name, $error); + } + + throw new TransportException($message); + } + + /** + * @return AuthenticatorInterface[] + */ + private function getActiveAuthenticators(): array + { + if (!$mode = strtolower($this->authMode)) { + return $this->authenticators; + } + + foreach ($this->authenticators as $authenticator) { + if (strtolower($authenticator->getAuthKeyword()) === $mode) { + return [$authenticator]; + } + } + + throw new TransportException(sprintf('Auth mode "%s" is invalid.', $mode)); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php new file mode 100644 index 0000000000000..54f5e2a096555 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -0,0 +1,283 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp; + +use Psr\Log\LoggerInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Mailer\Exception\LogicException; +use Symfony\Component\Mailer\Exception\TransportException; +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mailer\Transport\AbstractTransport; +use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; +use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream; +use Symfony\Component\Mime\RawMessage; + +/** + * Sends emails over SMTP. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class SmtpTransport extends AbstractTransport +{ + private $started = false; + private $restartThreshold = 100; + private $restartThresholdSleep = 0; + private $restartCounter; + private $stream; + private $domain = '[127.0.0.1]'; + + public function __construct(AbstractStream $stream = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) + { + parent::__construct($dispatcher, $logger); + + $this->stream = $stream ?: new SocketStream(); + } + + public function getStream(): AbstractStream + { + return $this->stream; + } + + /** + * Sets the maximum number of messages to send before re-starting the transport. + * + * By default, the threshold is set to 100 (and no sleep at restart). + * + * @param int $threshold The maximum number of messages (0 to disable) + * @param int $sleep The number of seconds to sleep between stopping and re-starting the transport + */ + public function setRestartThreshold(int $threshold, int $sleep = 0): self + { + $this->restartThreshold = $threshold; + $this->restartThresholdSleep = $sleep; + + return $this; + } + + /** + * Sets the name of the local domain that will be used in HELO. + * + * This should be a fully-qualified domain name and should be truly the domain + * you're using. + * + * If your server does not have a domain name, use the IP address. This will + * automatically be wrapped in square brackets as described in RFC 5321, + * section 4.1.3. + */ + public function setLocalDomain(string $domain): self + { + if ('' !== $domain && '[' !== $domain[0]) { + if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + $domain = '['.$domain.']'; + } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $domain = '[IPv6:'.$domain.']'; + } + } + + $this->domain = $domain; + + return $this; + } + + /** + * Gets the name of the domain that will be used in HELO. + * + * If an IP address was specified, this will be returned wrapped in square + * brackets as described in RFC 5321, section 4.1.3. + */ + public function getLocalDomain(): string + { + return $this->domain; + } + + public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage + { + $this->ping(); + if (!$this->started) { + $this->start(); + } + + $message = parent::send($message, $envelope); + + $this->checkRestartThreshold(); + + return $message; + } + + /** + * Runs a command against the stream, expecting the given response codes. + * + * @param int[] $codes + * + * @return string The server response + * + * @throws TransportException when an invalid response if received + * + * @internal + */ + public function executeCommand(string $command, array $codes): string + { + $this->getLogger()->debug(sprintf('Email transport "%s" sent command "%s"', __CLASS__, trim($command))); + $this->stream->write($command); + $response = $this->getFullResponse(); + $this->assertResponseCode($response, $codes); + + return $response; + } + + protected function doSend(SentMessage $message): void + { + $envelope = $message->getEnvelope(); + $this->doMailFromCommand($envelope->getSender()->toString()); + foreach ($envelope->getRecipients() as $recipient) { + $this->doRcptToCommand($recipient->toString()); + } + + $this->executeCommand("DATA\r\n", [354]); + foreach (AbstractStream::replace("\r\n.", "\r\n..", $message->toIterable()) as $chunk) { + $this->stream->write($chunk); + } + $this->stream->flush(); + $this->executeCommand("\r\n.\r\n", [250]); + } + + protected function doHeloCommand(): void + { + $this->executeCommand(sprintf("HELO %s\r\n", $this->domain), [250]); + } + + private function doMailFromCommand($address): void + { + $this->executeCommand(sprintf("MAIL FROM:<%s>\r\n", $address), [250]); + } + + private function doRcptToCommand($address): void + { + $this->executeCommand(sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252]); + } + + private function start(): void + { + if ($this->started) { + return; + } + + $this->getLogger()->debug(sprintf('Email transport "%s" starting', __CLASS__)); + + $this->stream->initialize(); + $this->assertResponseCode($this->getFullResponse(), [220]); + $this->doHeloCommand(); + $this->started = true; + + $this->getLogger()->debug(sprintf('Email transport "%s" started', __CLASS__)); + } + + private function stop(): void + { + if (!$this->started) { + return; + } + + $this->getLogger()->debug(sprintf('Email transport "%s" stopping', __CLASS__)); + + try { + $this->executeCommand("QUIT\r\n", [221]); + } catch (TransportExceptionInterface $e) { + } finally { + $this->stream->terminate(); + $this->started = false; + $this->getLogger()->debug(sprintf('Email transport "%s" stopped', __CLASS__)); + } + } + + private function ping(): void + { + if (!$this->started) { + return; + } + + try { + $this->executeCommand("NOOP\r\n", [250]); + } catch (TransportExceptionInterface $e) { + try { + $this->stop(); + } catch (TransportExceptionInterface $e) { + } + } + } + + /** + * @throws TransportException if a response code is incorrect + */ + private function assertResponseCode(string $response, array $codes): void + { + if (!$codes) { + throw new LogicException('You must set the expected response code.'); + } + + if (!$response) { + throw new TransportException(sprintf('Expected response code "%s" but got an empty response.', implode('/', $codes))); + } + + list($code) = sscanf($response, '%3d'); + $valid = \in_array($code, $codes); + + $this->getLogger()->debug(sprintf('Email transport "%s" received response "%s" (%s).', __CLASS__, trim($response), $valid ? 'ok' : 'error')); + + if (!$valid) { + throw new TransportException(sprintf('Expected response code "%s" but got code "%s", with message "%s".', implode('/', $codes), $code, trim($response)), $code); + } + } + + private function getFullResponse(): string + { + $response = ''; + do { + $line = $this->stream->readLine(); + $response .= $line; + } while ($line && isset($line[3]) && ' ' !== $line[3]); + + return $response; + } + + private function checkRestartThreshold(): void + { + // when using sendmail via non-interactive mode, the transport is never "started" + if (!$this->started) { + return; + } + + ++$this->restartCounter; + if ($this->restartCounter < $this->restartThreshold) { + return; + } + + $this->stop(); + if (0 < $sleep = $this->restartThresholdSleep) { + $this->getLogger()->debug(sprintf('Email transport "%s" sleeps for %d seconds after stopping', __CLASS__, $sleep)); + + sleep($sleep); + } + $this->start(); + $this->restartCounter = 0; + } + + public function __destruct() + { + $this->stop(); + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/AbstractStream.php b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/AbstractStream.php new file mode 100644 index 0000000000000..5d9e2715c3f3d --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/AbstractStream.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting remote sockets and local processes. + * + * @author Fabien Potencier + * @author Nicolas Grekas + * @author Chris Corbyn + * + * @internal + * + * @experimental in 4.3 + */ +abstract class AbstractStream +{ + protected $stream; + protected $in; + protected $out; + + public function write(string $bytes): void + { + $bytesToWrite = \strlen($bytes); + $totalBytesWritten = 0; + while ($totalBytesWritten < $bytesToWrite) { + $bytesWritten = fwrite($this->in, substr($bytes, $totalBytesWritten)); + if (false === $bytesWritten || 0 === $bytesWritten) { + throw new TransportException('Unable to write bytes on the wire.'); + } + + $totalBytesWritten += $bytesWritten; + } + } + + /** + * Flushes the contents of the stream (empty it) and set the internal pointer to the beginning. + */ + public function flush(): void + { + fflush($this->in); + } + + /** + * Performs any initialization needed. + */ + abstract public function initialize(): void; + + public function terminate(): void + { + $this->stream = $this->out = $this->in = null; + } + + public function readLine(): string + { + if (feof($this->out)) { + return ''; + } + + $line = fgets($this->out); + if (0 === \strlen($line)) { + $metas = stream_get_meta_data($this->out); + if ($metas['timed_out']) { + throw new TransportException(sprintf('Connection to "%s" timed out.', $this->getReadConnectionDescription())); + } + } + + return $line; + } + + public static function replace(string $from, string $to, iterable $chunks): \Generator + { + if ('' === $from) { + yield from $chunks; + + return; + } + + $carry = ''; + $fromLen = \strlen($from); + + foreach ($chunks as $chunk) { + if ('' === $chunk = $carry.$chunk) { + continue; + } + + if (false !== strpos($chunk, $from)) { + $chunk = explode($from, $chunk); + $carry = array_pop($chunk); + + yield implode($to, $chunk).$to; + } else { + $carry = $chunk; + } + + if (\strlen($carry) > $fromLen) { + yield substr($carry, 0, -$fromLen); + $carry = substr($carry, -$fromLen); + } + } + + if ('' !== $carry) { + yield $carry; + } + } + + abstract protected function getReadConnectionDescription(): string; +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/ProcessStream.php b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/ProcessStream.php new file mode 100644 index 0000000000000..dfbf930840d89 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/ProcessStream.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting local processes. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @internal + * + * @experimental in 4.3 + */ +final class ProcessStream extends AbstractStream +{ + private $command; + + public function setCommand(string $command) + { + $this->command = $command; + } + + public function initialize(): void + { + $descriptorSpec = [ + 0 => ['pipe', 'r'], + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ]; + $pipes = []; + $this->stream = proc_open($this->command, $descriptorSpec, $pipes); + stream_set_blocking($pipes[2], false); + if ($err = stream_get_contents($pipes[2])) { + throw new TransportException(sprintf('Process could not be started: %s.', $err)); + } + $this->in = &$pipes[0]; + $this->out = &$pipes[1]; + } + + public function terminate(): void + { + if (null !== $this->stream) { + fclose($this->in); + fclose($this->out); + proc_close($this->stream); + } + + parent::terminate(); + } + + protected function getReadConnectionDescription(): string + { + return 'process '.$this->command; + } +} diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php new file mode 100644 index 0000000000000..07692b11bac71 --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/Smtp/Stream/SocketStream.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport\Smtp\Stream; + +use Symfony\Component\Mailer\Exception\TransportException; + +/** + * A stream supporting remote sockets. + * + * @author Fabien Potencier + * @author Chris Corbyn + * + * @internal + * + * @experimental in 4.3 + */ +final class SocketStream extends AbstractStream +{ + private $url; + private $host = 'localhost'; + private $protocol = 'tcp'; + private $port = 25; + private $timeout = 15; + private $tls = false; + private $sourceIp; + private $streamContextOptions = []; + + public function setTimeout(int $timeout): self + { + $this->timeout = $timeout; + + return $this; + } + + public function getTimeout(): int + { + return $this->timeout; + } + + /** + * Literal IPv6 addresses should be wrapped in square brackets. + */ + public function setHost(string $host): self + { + $this->host = $host; + + return $this; + } + + public function getHost(): string + { + return $this->host; + } + + public function setPort(int $port): self + { + $this->port = $port; + + return $this; + } + + public function getPort(): int + { + return $this->port; + } + + /** + * Sets the encryption type (tls or ssl). + */ + public function setEncryption(string $encryption): self + { + $encryption = strtolower($encryption); + if ('tls' === $encryption) { + $this->protocol = 'tcp'; + $this->tls = true; + } else { + $this->protocol = $encryption; + $this->tls = false; + } + + return $this; + } + + public function isTLS(): bool + { + return $this->tls; + } + + public function setStreamOptions(array $options): self + { + $this->streamContextOptions = $options; + + return $this; + } + + public function getStreamOptions(): array + { + return $this->streamContextOptions; + } + + /** + * Sets the source IP. + * + * IPv6 addresses should be wrapped in square brackets. + */ + public function setSourceIp(string $ip): self + { + $this->sourceIp = $ip; + + return $this; + } + + /** + * Returns the IP used to connect to the destination. + */ + public function getSourceIp(): ?string + { + return $this->sourceIp; + } + + public function initialize(): void + { + $this->url = $this->host.':'.$this->port; + if ($this->protocol) { + $this->url = $this->protocol.'://'.$this->url; + } + $options = []; + if ($this->sourceIp) { + $options['socket']['bindto'] = $this->sourceIp.':0'; + } + if ($this->streamContextOptions) { + $options = array_merge($options, $this->streamContextOptions); + } + $streamContext = stream_context_create($options); + $this->stream = @stream_socket_client($this->url, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $streamContext); + if (false === $this->stream) { + throw new TransportException(sprintf('Connection could not be established with host "%s": %s (%s)', $this->url, $errstr, $errno)); + } + stream_set_blocking($this->stream, true); + stream_set_timeout($this->stream, $this->timeout); + $this->in = &$this->stream; + $this->out = &$this->stream; + } + + public function startTLS(): bool + { + return (bool) stream_socket_enable_crypto($this->stream, true); + } + + public function terminate(): void + { + if (null !== $this->stream) { + fclose($this->stream); + } + + parent::terminate(); + } + + protected function getReadConnectionDescription(): string + { + return $this->url; + } +} diff --git a/src/Symfony/Component/Mailer/Transport/TransportInterface.php b/src/Symfony/Component/Mailer/Transport/TransportInterface.php new file mode 100644 index 0000000000000..852db42be78ea --- /dev/null +++ b/src/Symfony/Component/Mailer/Transport/TransportInterface.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mailer\Transport; + +use Symfony\Component\Mailer\Exception\TransportExceptionInterface; +use Symfony\Component\Mailer\SentMessage; +use Symfony\Component\Mailer\SmtpEnvelope; +use Symfony\Component\Mime\RawMessage; + +/** + * Interface for all mailer transports. + * + * When sending emails, you should prefer MailerInterface implementations + * as they allow asynchronous sending. + * + * @author Fabien Potencier + * + * @experimental in 4.3 + */ +interface TransportInterface +{ + /** + * @throws TransportExceptionInterface + */ + public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentMessage; +} diff --git a/src/Symfony/Component/Mailer/composer.json b/src/Symfony/Component/Mailer/composer.json new file mode 100644 index 0000000000000..27a5db082a737 --- /dev/null +++ b/src/Symfony/Component/Mailer/composer.json @@ -0,0 +1,45 @@ +{ + "name": "symfony/mailer", + "type": "library", + "description": "Symfony Mailer Component", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3", + "psr/log": "~1.0", + "symfony/event-dispatcher": "^4.3", + "symfony/mime": "^4.3" + }, + "require-dev": { + "symfony/amazon-mailer": "^4.3", + "egulias/email-validator": "^2.0", + "symfony/google-mailer": "^4.3", + "symfony/mailgun-mailer": "^4.3", + "symfony/mailchimp-mailer": "^4.3", + "symfony/postmark-mailer": "^4.3", + "symfony/sendgrid-mailer": "^4.3" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mailer\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/src/Symfony/Component/Mailer/phpunit.xml.dist b/src/Symfony/Component/Mailer/phpunit.xml.dist new file mode 100644 index 0000000000000..adcc4721d47a0 --- /dev/null +++ b/src/Symfony/Component/Mailer/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Tests + ./vendor + + + + From 827e61f645839a4bb6598407c6897d251b45736d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 13:09:36 +0100 Subject: [PATCH 311/495] fixed author --- .../Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php | 2 ++ .../Component/Mailer/Bridge/Amazon/Http/SesTransport.php | 2 ++ .../Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php | 2 +- .../Component/Mailer/Bridge/Google/Smtp/GmailTransport.php | 2 +- .../Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php | 1 + .../Mailer/Bridge/Mailchimp/Http/MandrillTransport.php | 2 ++ .../Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php | 2 ++ .../Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php | 2 +- .../Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php | 2 +- .../Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php | 2 +- .../Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php | 2 +- .../Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php | 2 +- .../Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php | 2 ++ .../Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php | 2 +- 14 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php index e71e29a013661..0bd4b5aa1db46 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/Api/SesTransport.php @@ -20,6 +20,8 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** + * @author Kevin Verschaeve + * * @experimental in 4.3 */ class SesTransport extends AbstractApiTransport diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php index 3a31c8f9d8b7d..df635c4b1c172 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Http/SesTransport.php @@ -20,6 +20,8 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** + * @author Kevin Verschaeve + * * @experimental in 4.3 */ class SesTransport extends AbstractTransport diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php index 1d666cdecb4aa..dc72f959c4d3f 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Smtp/SesTransport.php @@ -16,7 +16,7 @@ use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php b/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php index 91da68fcec709..fb7f58264748a 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Google/Smtp/GmailTransport.php @@ -16,7 +16,7 @@ use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php index c1ef083ed224f..a177e664b62a2 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php @@ -20,6 +20,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** + * @author Kevin Verschaeve * @experimental in 4.3 */ class MandrillTransport extends AbstractApiTransport diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php index 188d0bcf90a70..a54251d9b4749 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php @@ -20,6 +20,8 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** + * @author Kevin Verschaeve + * * @experimental in 4.3 */ class MandrillTransport extends AbstractTransport diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php index cc61702d8fc49..75c665f3cc128 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Smtp/MandrillTransport.php @@ -16,6 +16,8 @@ use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; /** + * @author Kevin Verschaeve + * * @experimental in 4.3 */ class MandrillTransport extends EsmtpTransport diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php index f3e69d00db572..dc047c2e87291 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/Api/MailgunTransport.php @@ -21,7 +21,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php index 0cc7fccd9343e..940cabc6ea8c8 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Http/MailgunTransport.php @@ -22,7 +22,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php index c9cf087bad3ed..105ab46ecd98c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Smtp/MailgunTransport.php @@ -16,7 +16,7 @@ use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php index 7a73579ce500f..3ec9c640a655d 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Http/Api/PostmarkTransport.php @@ -20,7 +20,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php index ceee67d722a36..4407a1bf1b0af 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Smtp/PostmarkTransport.php @@ -16,7 +16,7 @@ use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php index 9e4871e72dd7c..e45db91181f3c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php @@ -21,6 +21,8 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; /** + * @author Kevin Verschaeve + * * @experimental in 4.3 */ class SendgridTransport extends AbstractApiTransport diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php index fc28a6e2cb376..60ef601a16a62 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Smtp/SendgridTransport.php @@ -16,7 +16,7 @@ use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; /** - * @author Fabien Potencier + * @author Kevin Verschaeve * * @experimental in 4.3 */ From 9cf665f2ea8fe762c1bcc133fdfb6a4422d2be29 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 14:28:10 +0100 Subject: [PATCH 312/495] [Mailer] fixed typo --- src/Symfony/Component/Mailer/Transport.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Mailer/Transport.php b/src/Symfony/Component/Mailer/Transport.php index c97f0c49a3a57..f5202242a35a9 100644 --- a/src/Symfony/Component/Mailer/Transport.php +++ b/src/Symfony/Component/Mailer/Transport.php @@ -87,7 +87,7 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); case 'gmail': if (!class_exists(Google\Smtp\GmailTransport::class)) { - throw new \LogicException('Unable to send emails via Gmail as the Google bridge is not installed. Try running "composer require symfony/google-bridge".'); + throw new \LogicException('Unable to send emails via Gmail as the Google bridge is not installed. Try running "composer require symfony/google-mailer".'); } if ('smtp' === $parsedDsn['scheme']) { @@ -97,7 +97,7 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); case 'mailgun': if (!class_exists(Mailgun\Smtp\MailgunTransport::class)) { - throw new \LogicException('Unable to send emails via Mailgun as the bridge is not installed. Try running "composer require symfony/mailgun-bridge".'); + throw new \LogicException('Unable to send emails via Mailgun as the bridge is not installed. Try running "composer require symfony/mailgun-mailer".'); } if ('smtp' === $parsedDsn['scheme']) { @@ -113,7 +113,7 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); case 'postmark': if (!class_exists(Postmark\Smtp\PostmarkTransport::class)) { - throw new \LogicException('Unable to send emails via Postmark as the bridge is not installed. Try running "composer require symfony/postmark-bridge".'); + throw new \LogicException('Unable to send emails via Postmark as the bridge is not installed. Try running "composer require symfony/postmark-mailer".'); } if ('smtp' === $parsedDsn['scheme']) { @@ -126,7 +126,7 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); case 'sendgrid': if (!class_exists(Sendgrid\Smtp\SendgridTransport::class)) { - throw new \LogicException('Unable to send emails via Sendgrid as the bridge is not installed. Try running "composer require symfony/sendgrid-bridge".'); + throw new \LogicException('Unable to send emails via Sendgrid as the bridge is not installed. Try running "composer require symfony/sendgrid-mailer".'); } if ('smtp' === $parsedDsn['scheme']) { @@ -139,7 +139,7 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); case 'ses': if (!class_exists(Amazon\Smtp\SesTransport::class)) { - throw new \LogicException('Unable to send emails via Amazon SES as the bridge is not installed. Try running "composer require symfony/amazon-bridge".'); + throw new \LogicException('Unable to send emails via Amazon SES as the bridge is not installed. Try running "composer require symfony/amazon-mailer".'); } if ('smtp' === $parsedDsn['scheme']) { @@ -155,7 +155,7 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); case 'mandrill': if (!class_exists(Mailchimp\Smtp\MandrillTransport::class)) { - throw new \LogicException('Unable to send emails via Mandrill as the bridge is not installed. Try running "composer require symfony/mailchimp-bridge".'); + throw new \LogicException('Unable to send emails via Mandrill as the bridge is not installed. Try running "composer require symfony/mailchimp-mailer".'); } if ('smtp' === $parsedDsn['scheme']) { From 3d25c1c613ba31e7dd8b26c8b48bdaa21b995152 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Mar 2019 14:46:29 +0100 Subject: [PATCH 313/495] [Mailer] fixed SMTP support when a message cannot be sent --- .../Component/Mailer/Transport/Smtp/SmtpTransport.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index 54f5e2a096555..7c3e074aee33b 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -111,7 +111,13 @@ public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentM $this->start(); } - $message = parent::send($message, $envelope); + try { + $message = parent::send($message, $envelope); + } catch (TransportExceptionInterface $e) { + $this->executeCommand("RSET\r\n", [250]); + + throw $e; + } $this->checkRestartThreshold(); From 907adf47e312e7db24014fbc1a8c4a4bc933e2a2 Mon Sep 17 00:00:00 2001 From: Sebastiaan Stok Date: Sat, 30 Mar 2019 16:56:09 +0100 Subject: [PATCH 314/495] [Mailer] Remove unneeded catch in ping() The stop() method doesn't throw --- .../Component/Mailer/Transport/Smtp/SmtpTransport.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index 7c3e074aee33b..05bbc0df59b6f 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -219,10 +219,7 @@ private function ping(): void try { $this->executeCommand("NOOP\r\n", [250]); } catch (TransportExceptionInterface $e) { - try { - $this->stop(); - } catch (TransportExceptionInterface $e) { - } + $this->stop(); } } From 32743c850f901b77b81232b9239b2128d5c6f041 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Mon, 3 Dec 2018 20:31:09 -0600 Subject: [PATCH 315/495] [Ldap] Entry move support --- .../Ldap/Adapter/EntryManagerInterface.php | 2 ++ .../Ldap/Adapter/ExtLdap/EntryManager.php | 25 +++++++++++++++++++ src/Symfony/Component/Ldap/CHANGELOG.md | 5 ++++ .../Tests/Adapter/ExtLdap/LdapManagerTest.php | 18 +++++++++++++ 4 files changed, 50 insertions(+) diff --git a/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php b/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php index 82c023d5ec06d..34b879a6f0204 100644 --- a/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php +++ b/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php @@ -21,6 +21,8 @@ * @author Charles Sarrazin * @author Bob van de Vijver * @author Kevin Schuurmans + * + * @method void move(Entry $entry, string $newParent) Moves an entry on the Ldap server */ interface EntryManagerInterface { diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php index f80601b3baa45..68778cb42dc10 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php @@ -110,6 +110,22 @@ public function rename(Entry $entry, $newRdn, $removeOldRdn = true) } } + /** + * Moves an entry on the Ldap server. + * + * @throws NotBoundException if the connection has not been previously bound. + * @throws LdapException if an error is thrown during the rename operation. + */ + public function move(Entry $entry, string $newParent) + { + $con = $this->getConnectionResource(); + $rdn = $this->parseRdnFromEntry($entry); + // deleteOldRdn does not matter here, since the Rdn will not be changing in the move. + if (!@ldap_rename($con, $entry->getDn(), $rdn, $newParent, true)) { + throw new LdapException(sprintf('Could not move entry "%s" to "%s": %s.', $entry->getDn(), $newParent, ldap_error($con))); + } + } + /** * Get the connection resource, but first check if the connection is bound. */ @@ -139,4 +155,13 @@ public function applyOperations(string $dn, iterable $operations): void throw new UpdateOperationException(sprintf('Error executing UpdateOperation on "%s": "%s".', $dn, ldap_error($this->getConnectionResource()))); } } + + private function parseRdnFromEntry(Entry $entry) + { + if (!preg_match('/^([^,]+),/', $entry->getDn(), $matches)) { + throw new LdapException(sprintf('Entry "%s" malformed, could not parse RDN', $entry->getDn())); + } + + return $matches[1]; + } } diff --git a/src/Symfony/Component/Ldap/CHANGELOG.md b/src/Symfony/Component/Ldap/CHANGELOG.md index 7dc0c81b3dfda..ef189219dcbca 100644 --- a/src/Symfony/Component/Ldap/CHANGELOG.md +++ b/src/Symfony/Component/Ldap/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added `EntryManager::move`, not implementing it is deprecated + 4.2.0 ----- diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php index 70723515559d3..7b557eee7ef6b 100644 --- a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/LdapManagerTest.php @@ -341,4 +341,22 @@ public function testUpdateOperationsThrowsExceptionWhenAddedDuplicatedValue() $entryManager->applyOperations($entry->getDn(), $duplicateIterator); } + + /** + * @group functional + */ + public function testLdapMove() + { + $result = $this->executeSearchQuery(1); + + $entry = $result[0]; + $this->assertNotContains('ou=Ldap', $entry->getDn()); + + $entryManager = $this->adapter->getEntryManager(); + $entryManager->move($entry, 'ou=Ldap,ou=Components,dc=symfony,dc=com'); + + $result = $this->executeSearchQuery(1); + $movedEntry = $result[0]; + $this->assertContains('ou=Ldap', $movedEntry->getDn()); + } } From 5e079536c9c0ce866290c88796e1dd1181471ba3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 10:31:43 +0200 Subject: [PATCH 316/495] [LDAP] fixed typos and CS --- .../Component/Ldap/Adapter/EntryManagerInterface.php | 1 + src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php b/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php index 34b879a6f0204..06ef4ddeec763 100644 --- a/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php +++ b/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php @@ -22,6 +22,7 @@ * @author Bob van de Vijver * @author Kevin Schuurmans * + * The move() methods must be added to the interface in Symfony 5.0 * @method void move(Entry $entry, string $newParent) Moves an entry on the Ldap server */ interface EntryManagerInterface diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php index 68778cb42dc10..31559ec824825 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php @@ -114,7 +114,7 @@ public function rename(Entry $entry, $newRdn, $removeOldRdn = true) * Moves an entry on the Ldap server. * * @throws NotBoundException if the connection has not been previously bound. - * @throws LdapException if an error is thrown during the rename operation. + * @throws LdapException if an error is thrown during the rename operation. */ public function move(Entry $entry, string $newParent) { @@ -156,10 +156,10 @@ public function applyOperations(string $dn, iterable $operations): void } } - private function parseRdnFromEntry(Entry $entry) + private function parseRdnFromEntry(Entry $entry) { if (!preg_match('/^([^,]+),/', $entry->getDn(), $matches)) { - throw new LdapException(sprintf('Entry "%s" malformed, could not parse RDN', $entry->getDn())); + throw new LdapException(sprintf('Entry "%s" malformed, could not parse RDN.', $entry->getDn())); } return $matches[1]; From b96347485c862767257ea79726982fbcb3321219 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 6 Dec 2018 22:37:05 -0600 Subject: [PATCH 317/495] [Ldap] Implement pagination --- .travis.yml | 3 + .../Component/Ldap/Adapter/AbstractQuery.php | 1 + .../Ldap/Adapter/ExtLdap/Collection.php | 33 ++-- .../Component/Ldap/Adapter/ExtLdap/Query.php | 154 ++++++++++++++---- src/Symfony/Component/Ldap/CHANGELOG.md | 5 + .../Tests/Adapter/ExtLdap/AdapterTest.php | 124 ++++++++++++++ .../Ldap/Tests/Fixtures/conf/slapd.conf | 5 +- 7 files changed, 281 insertions(+), 44 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8f023685bbf49..c8ab525f1d982 100644 --- a/.travis.yml +++ b/.travis.yml @@ -62,6 +62,9 @@ before_install: set -e stty cols 120 mkdir /tmp/slapd + if [ ! -e /tmp/slapd-modules ]; then + [ -d /usr/lib/openldap ] && ln -s /usr/lib/openldap /tmp/slapd-modules || ln -s /usr/lib/ldap /tmp/slapd-modules + fi slapd -f src/Symfony/Component/Ldap/Tests/Fixtures/conf/slapd.conf -h ldap://localhost:3389 & [ -d ~/.composer ] || mkdir ~/.composer cp .composer/* ~/.composer/ diff --git a/src/Symfony/Component/Ldap/Adapter/AbstractQuery.php b/src/Symfony/Component/Ldap/Adapter/AbstractQuery.php index 442936b578e9a..b2b777d8454dd 100644 --- a/src/Symfony/Component/Ldap/Adapter/AbstractQuery.php +++ b/src/Symfony/Component/Ldap/Adapter/AbstractQuery.php @@ -35,6 +35,7 @@ public function __construct(ConnectionInterface $connection, string $dn, string 'deref' => static::DEREF_NEVER, 'attrsOnly' => 0, 'scope' => static::SCOPE_SUB, + 'pageSize' => 0, ]); $resolver->setAllowedValues('deref', [static::DEREF_ALWAYS, static::DEREF_NEVER, static::DEREF_FINDING, static::DEREF_SEARCHING]); $resolver->setAllowedValues('scope', [static::SCOPE_BASE, static::SCOPE_ONE, static::SCOPE_SUB]); diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php index fade430753dcc..4aa9663dc9930 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Collection.php @@ -44,31 +44,40 @@ public function toArray() public function count() { - if (false !== $count = ldap_count_entries($this->connection->getResource(), $this->search->getResource())) { - return $count; + $con = $this->connection->getResource(); + $searches = $this->search->getResources(); + $count = 0; + foreach ($searches as $search) { + $searchCount = ldap_count_entries($con, $search); + if (false === $searchCount) { + throw new LdapException(sprintf('Error while retrieving entry count: %s.', ldap_error($con))); + } + $count += $searchCount; } - throw new LdapException(sprintf('Error while retrieving entry count: %s.', ldap_error($this->connection->getResource()))); + return $count; } public function getIterator() { - $con = $this->connection->getResource(); - $search = $this->search->getResource(); - $current = ldap_first_entry($con, $search); - if (0 === $this->count()) { return; } - if (false === $current) { - throw new LdapException(sprintf('Could not rewind entries array: %s.', ldap_error($con))); - } + $con = $this->connection->getResource(); + $searches = $this->search->getResources(); + foreach ($searches as $search) { + $current = ldap_first_entry($con, $search); - yield $this->getSingleEntry($con, $current); + if (false === $current) { + throw new LdapException(sprintf('Could not rewind entries array: %s.', ldap_error($con))); + } - while (false !== $current = ldap_next_entry($con, $current)) { yield $this->getSingleEntry($con, $current); + + while (false !== $current = ldap_next_entry($con, $current)) { + yield $this->getSingleEntry($con, $current); + } } } diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php index 2147acb4d15f4..44ad077d72955 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php @@ -21,11 +21,14 @@ */ class Query extends AbstractQuery { + // As of PHP 7.2, we can use LDAP_CONTROL_PAGEDRESULTS instead of this + const PAGINATION_OID = '1.2.840.113556.1.4.319'; + /** @var Connection */ protected $connection; - /** @var resource */ - private $search; + /** @var resource[] */ + private $results; public function __construct(Connection $connection, string $dn, string $query, array $options = []) { @@ -37,16 +40,19 @@ public function __destruct() $con = $this->connection->getResource(); $this->connection = null; - if (null === $this->search || false === $this->search) { + if (null === $this->results) { return; } - $success = ldap_free_result($this->search); - $this->search = null; - - if (!$success) { - throw new LdapException(sprintf('Could not free results: %s.', ldap_error($con))); + foreach ($this->results as $result) { + if (false === $result || null === $result) { + continue; + } + if (!ldap_free_result($result)) { + throw new LdapException(sprintf('Could not free results: %s.', ldap_error($con))); + } } + $this->results = null; } /** @@ -54,12 +60,13 @@ public function __destruct() */ public function execute() { - if (null === $this->search) { + if (null === $this->results) { // If the connection is not bound, throw an exception. Users should use an explicit bind call first. if (!$this->connection->isBound()) { throw new NotBoundException('Query execution is not possible without binding the connection first.'); } + $this->results = []; $con = $this->connection->getResource(); switch ($this->options['scope']) { @@ -76,39 +83,126 @@ public function execute() throw new LdapException(sprintf('Could not search in scope "%s".', $this->options['scope'])); } - $this->search = @$func( - $con, - $this->dn, - $this->query, - $this->options['filter'], - $this->options['attrsOnly'], - $this->options['maxItems'], - $this->options['timeout'], - $this->options['deref'] - ); - } - - if (false === $this->search) { - $ldapError = ''; - if ($errno = ldap_errno($con)) { - $ldapError = sprintf(' LDAP error was [%d] %s', $errno, ldap_error($con)); + $itemsLeft = $maxItems = $this->options['maxItems']; + $pageSize = $this->options['pageSize']; + // Deal with the logic to handle maxItems properly. If we can satisfy it in + // one request based on pageSize, we don't need to bother sending page control + // to the server so that it can determine what we already know. + if (0 !== $maxItems && $pageSize > $maxItems) { + $pageSize = 0; + } elseif (0 !== $maxItems) { + $pageSize = min($maxItems, $pageSize); + } + $pageControl = $this->options['scope'] != static::SCOPE_BASE && $pageSize > 0; + $cookie = ''; + do { + if ($pageControl) { + ldap_control_paged_result($con, $pageSize, true, $cookie); + } + $sizeLimit = $itemsLeft; + if ($pageSize > 0 && $sizeLimit >= $pageSize) { + $sizeLimit = 0; + } + $search = @$func( + $con, + $this->dn, + $this->query, + $this->options['filter'], + $this->options['attrsOnly'], + $sizeLimit, + $this->options['timeout'], + $this->options['deref'] + ); + + if (false === $search) { + $ldapError = ''; + if ($errno = ldap_errno($con)) { + $ldapError = sprintf(' LDAP error was [%d] %s', $errno, ldap_error($con)); + } + if ($pageControl) { + $this->resetPagination(); + } + + throw new LdapException(sprintf('Could not complete search with dn "%s", query "%s" and filters "%s".%s', $this->dn, $this->query, implode(',', $this->options['filter']), $ldapError)); + } + + $this->results[] = $search; + $itemsLeft -= min($itemsLeft, $pageSize); + + if (0 !== $maxItems && 0 === $itemsLeft) { + break; + } + if ($pageControl) { + ldap_control_paged_result_response($con, $search, $cookie); + } + } while (null !== $cookie && '' !== $cookie); + + if ($pageControl) { + $this->resetPagination(); } - - throw new LdapException(sprintf('Could not complete search with dn "%s", query "%s" and filters "%s".%s', $this->dn, $this->query, implode(',', $this->options['filter']), $ldapError)); } return new Collection($this->connection, $this); } /** - * Returns a LDAP search resource. + * Returns a LDAP search resource. If this query resulted in multiple searches, only the first + * page will be returned. * * @return resource * * @internal */ - public function getResource() + public function getResource($idx = 0) { - return $this->search; + if (null === $this->results || $idx >= \count($this->results)) { + return null; + } + + return $this->results[$idx]; + } + + /** + * Returns all LDAP search resources. + * + * @return resource[] + * + * @internal + */ + public function getResources() + { + return $this->results; + } + + /** + * Resets pagination on the current connection. + * + * @internal + */ + private function resetPagination() + { + $con = $this->connection->getResource(); + ldap_control_paged_result($con, 0); + + // This is a workaround for a bit of a bug in the above invocation + // of ldap_control_paged_result. Instead of indicating to extldap that + // we no longer wish to page queries on this link, this invocation sets + // the LDAP_CONTROL_PAGEDRESULTS OID with a page size of 0. This isn't + // well defined by RFC 2696 if there is no cookie present, so some servers + // will interpret it differently and do the wrong thing. Forcefully remove + // the OID for now until a fix can make its way through the versions of PHP + // the we support. + // + // This is not supported in PHP < 7.2, so these versions will remain broken. + $ctl = []; + ldap_get_option($con, LDAP_OPT_SERVER_CONTROLS, $ctl); + if (!empty($ctl)) { + foreach ($ctl as $idx => $info) { + if (static::PAGINATION_OID == $info['oid']) { + unset($ctl[$idx]); + } + } + ldap_set_option($con, LDAP_OPT_SERVER_CONTROLS, $ctl); + } } } diff --git a/src/Symfony/Component/Ldap/CHANGELOG.md b/src/Symfony/Component/Ldap/CHANGELOG.md index 7dc0c81b3dfda..05b46af2350e5 100644 --- a/src/Symfony/Component/Ldap/CHANGELOG.md +++ b/src/Symfony/Component/Ldap/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * Added pagination support to the ExtLdap adapter with the pageSize query option. + 4.2.0 ----- diff --git a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php index f5c856f9d520a..96faaedd80bdc 100644 --- a/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php +++ b/src/Symfony/Component/Ldap/Tests/Adapter/ExtLdap/AdapterTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Ldap\Adapter\ExtLdap\Collection; use Symfony\Component\Ldap\Adapter\ExtLdap\Query; use Symfony\Component\Ldap\Entry; +use Symfony\Component\Ldap\Exception\LdapException; use Symfony\Component\Ldap\Exception\NotBoundException; use Symfony\Component\Ldap\LdapInterface; @@ -23,6 +24,12 @@ */ class AdapterTest extends LdapTestCase { + const PAGINATION_REQUIRED_CONFIG = [ + 'options' => [ + 'protocol_version' => 3, + ], + ]; + public function testLdapEscape() { $ldap = new Adapter(); @@ -111,4 +118,121 @@ public function testLdapQueryScopeOneLevel() $this->assertEquals($one_level_result->count(), 1); $this->assertEquals($one_level_result[0]->getAttribute('ou'), ['Ldap']); } + + public function testLdapPagination() + { + $ldap = new Adapter(array_merge($this->getLdapConfig(), static::PAGINATION_REQUIRED_CONFIG)); + $ldap->getConnection()->bind('cn=admin,dc=symfony,dc=com', 'symfony'); + $entries = $this->setupTestUsers($ldap); + + $unpaged_query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectClass=applicationProcess)(cn=user*))', [ + 'scope' => Query::SCOPE_ONE, + ]); + $fully_paged_query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectClass=applicationProcess)(cn=user*))', [ + 'scope' => Query::SCOPE_ONE, + 'pageSize' => 25, + ]); + $paged_query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectClass=applicationProcess)(cn=user*))', [ + 'scope' => Query::SCOPE_ONE, + 'pageSize' => 5, + ]); + + try { + $unpaged_results = $unpaged_query->execute(); + $fully_paged_results = $fully_paged_query->execute(); + $paged_results = $paged_query->execute(); + + // All four of the above queries should result in the 25 'users' being returned + $this->assertEquals($unpaged_results->count(), 25); + $this->assertEquals($fully_paged_results->count(), 25); + $this->assertEquals($paged_results->count(), 25); + + // They should also result in 1 or 25 / pageSize results + $this->assertEquals(\count($unpaged_query->getResources()), 1); + $this->assertEquals(\count($fully_paged_query->getResources()), 1); + $this->assertEquals(\count($paged_query->getResources()), 5); + + if (PHP_MAJOR_VERSION > 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION >= 2)) { + // This last query is to ensure that we haven't botched the state of our connection + // by not resetting pagination properly. extldap <= PHP 7.1 do not implement the necessary + // bits to work around an implementation flaw, so we simply can't guarantee this to work there. + $final_query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectClass=applicationProcess)(cn=user*))', [ + 'scope' => Query::SCOPE_ONE, + ]); + + $final_results = $final_query->execute(); + + $this->assertEquals($final_results->count(), 25); + $this->assertEquals(\count($final_query->getResources()), 1); + } + } catch (LdapException $exc) { + $this->markTestSkipped('Test LDAP server does not support pagination'); + } + + $this->destroyEntries($ldap, $entries); + } + + private function setupTestUsers($ldap) + { + $entries = []; + + // Create 25 'users' that we'll query for in different page sizes + $em = $ldap->getEntryManager(); + for ($i = 0; $i < 25; ++$i) { + $cn = sprintf('user%d', $i); + $entry = new Entry(sprintf('cn=%s,dc=symfony,dc=com', $cn)); + $entry->setAttribute('objectClass', ['applicationProcess']); + $entry->setAttribute('cn', [$cn]); + try { + $em->add($entry); + } catch (LdapException $exc) { + // ignored + } + $entries[] = $entry; + } + + return $entries; + } + + private function destroyEntries($ldap, $entries) + { + $em = $ldap->getEntryManager(); + foreach ($entries as $entry) { + $em->remove($entry); + } + } + + public function testLdapPaginationLimits() + { + $ldap = new Adapter(array_merge($this->getLdapConfig(), static::PAGINATION_REQUIRED_CONFIG)); + $ldap->getConnection()->bind('cn=admin,dc=symfony,dc=com', 'symfony'); + + $entries = $this->setupTestUsers($ldap); + + $low_max_query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectClass=applicationProcess)(cn=user*))', [ + 'scope' => Query::SCOPE_ONE, + 'pageSize' => 10, + 'maxItems' => 5, + ]); + $high_max_query = $ldap->createQuery('dc=symfony,dc=com', '(&(objectClass=applicationProcess)(cn=user*))', [ + 'scope' => Query::SCOPE_ONE, + 'pageSize' => 10, + 'maxItems' => 13, + ]); + + try { + $low_max_results = $low_max_query->execute(); + $high_max_results = $high_max_query->execute(); + + $this->assertEquals($low_max_results->count(), 5); + $this->assertEquals($high_max_results->count(), 13); + + $this->assertEquals(\count($low_max_query->getResources()), 1); + $this->assertEquals(\count($high_max_query->getResources()), 2); + } catch (LdapException $exc) { + $this->markTestSkipped('Test LDAP server does not support pagination'); + } + + $this->destroyEntries($ldap, $entries); + } } diff --git a/src/Symfony/Component/Ldap/Tests/Fixtures/conf/slapd.conf b/src/Symfony/Component/Ldap/Tests/Fixtures/conf/slapd.conf index 35f7fe5652b38..24eebcb2dbe33 100644 --- a/src/Symfony/Component/Ldap/Tests/Fixtures/conf/slapd.conf +++ b/src/Symfony/Component/Ldap/Tests/Fixtures/conf/slapd.conf @@ -7,9 +7,10 @@ include /etc/ldap/schema/nis.schema pidfile /tmp/slapd/slapd.pid argsfile /tmp/slapd/slapd.args -modulepath /usr/lib/openldap +modulepath /tmp/slapd-modules +moduleload back_hdb -database ldif +database hdb directory /tmp/slapd suffix "dc=symfony,dc=com" From 47242e36e09f64e58dbe57ade4f6e1a786936ad6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 10:40:49 +0200 Subject: [PATCH 318/495] fixed CS --- src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php index 44ad077d72955..5180736ce8360 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php @@ -176,8 +176,6 @@ public function getResources() /** * Resets pagination on the current connection. - * - * @internal */ private function resetPagination() { From 6d51eaf5fc7cd9b905fd1d22cc859885bd9b9e1a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 12:10:11 +0200 Subject: [PATCH 319/495] fixed CS --- src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php | 4 ++-- .../Component/Workflow/Validator/StateMachineValidator.php | 2 +- .../Component/Workflow/Validator/WorkflowValidator.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php index 31559ec824825..d64e4b32899f1 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php @@ -113,8 +113,8 @@ public function rename(Entry $entry, $newRdn, $removeOldRdn = true) /** * Moves an entry on the Ldap server. * - * @throws NotBoundException if the connection has not been previously bound. - * @throws LdapException if an error is thrown during the rename operation. + * @throws NotBoundException if the connection has not been previously bound + * @throws LdapException if an error is thrown during the rename operation */ public function move(Entry $entry, string $newParent) { diff --git a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php index 78b32e648e328..b2a5c83b52e59 100644 --- a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php +++ b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php @@ -44,7 +44,7 @@ public function validate(Definition $definition, $name) } $initialPlaces = $definition->getInitialPlaces(); - if (2 <= count($initialPlaces)) { + if (2 <= \count($initialPlaces)) { throw new InvalidDefinitionException(sprintf('The state machine "%s" can not store many places. But the definition has %s initial places. Only one is supported.', $name, \count($initialPlaces))); } } diff --git a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php index 2a31ec8e46594..5e6df2dd24468 100644 --- a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php +++ b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php @@ -51,7 +51,7 @@ public function validate(Definition $definition, $name) } $initialPlaces = $definition->getInitialPlaces(); - if (2 <= count($initialPlaces)) { + if (2 <= \count($initialPlaces)) { throw new InvalidDefinitionException(sprintf('The marking store of workflow "%s" can not store many places. But the definition has %s initial places. Only one is supported.', $name, \count($initialPlaces))); } } From 9c63112d7cd81cabf859a41c0a10b7ac9f224fa2 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sun, 31 Mar 2019 11:12:50 +0100 Subject: [PATCH 320/495] Remove the mention of handler in the phpdoc. --- .../Messenger/Transport/Receiver/ReceiverInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php index fabb112a98b89..38f9b9ff35a64 100644 --- a/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php +++ b/src/Symfony/Component/Messenger/Transport/Receiver/ReceiverInterface.php @@ -23,7 +23,7 @@ interface ReceiverInterface { /** - * Receives some messages to the given handler. + * Receives some messages. * * While this method could return an unlimited number of messages, * the intention is that it returns only one, or a "small number" From cf41254223e076e9ae89017c13514f6441de7083 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Tue, 19 Feb 2019 15:58:35 -0500 Subject: [PATCH 321/495] [OptionsResolver] Add a new method addNormalizer and normalization hierarchy --- .../Component/OptionsResolver/CHANGELOG.md | 5 ++ .../Debug/OptionsResolverIntrospector.php | 8 +++ .../OptionsResolver/OptionsResolver.php | 59 +++++++++++++++++-- .../Debug/OptionsResolverIntrospectorTest.php | 36 +++++++++++ .../Tests/OptionsResolverTest.php | 57 ++++++++++++++++++ 5 files changed, 160 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/OptionsResolver/CHANGELOG.md b/src/Symfony/Component/OptionsResolver/CHANGELOG.md index a6f8f0ff47c03..60ea43f7ec20c 100644 --- a/src/Symfony/Component/OptionsResolver/CHANGELOG.md +++ b/src/Symfony/Component/OptionsResolver/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * added `OptionsResolver::addNormalizer` method + 4.2.0 ----- diff --git a/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php b/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php index ccce082fed29d..9ce5263334e15 100644 --- a/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php +++ b/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php @@ -84,6 +84,14 @@ public function getAllowedValues(string $option): array * @throws NoConfigurationException on no configured normalizer */ public function getNormalizer(string $option): \Closure + { + return current($this->getNormalizers($option)); + } + + /** + * @throws NoConfigurationException when no normalizer is configured + */ + public function getNormalizers(string $option): array { return ($this->get)('normalizers', $option, sprintf('No normalizer was set for the "%s" option.', $option)); } diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index eb0a6c2480601..0e68e75ff83ce 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -57,7 +57,7 @@ class OptionsResolver implements Options /** * A list of normalizer closures. * - * @var \Closure[] + * @var \Closure[][] */ private $normalizers = []; @@ -484,7 +484,56 @@ public function setNormalizer($option, \Closure $normalizer) throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); } - $this->normalizers[$option] = $normalizer; + $this->normalizers[$option] = [$normalizer]; + + // Make sure the option is processed + unset($this->resolved[$option]); + + return $this; + } + + /** + * Adds a normalizer for an option. + * + * The normalizer should be a closure with the following signature: + * + * function (Options $options, $value): mixed { + * // ... + * } + * + * The closure is invoked when {@link resolve()} is called. The closure + * has access to the resolved values of other options through the passed + * {@link Options} instance. + * + * The second parameter passed to the closure is the value of + * the option. + * + * The resolved option value is set to the return value of the closure. + * + * @param string $option The option name + * @param \Closure $normalizer The normalizer + * @param bool $forcePrepend If set to true, prepend instead of appending + * + * @return $this + * + * @throws UndefinedOptionsException If the option is undefined + * @throws AccessException If called from a lazy option or normalizer + */ + public function addNormalizer(string $option, \Closure $normalizer, bool $forcePrepend = false): self + { + if ($this->locked) { + throw new AccessException('Normalizers cannot be set from a lazy option or normalizer.'); + } + + if (!isset($this->defined[$option])) { + throw new UndefinedOptionsException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); + } + + if ($forcePrepend) { + array_unshift($this->normalizers[$option], $normalizer); + } else { + $this->normalizers[$option][] = $normalizer; + } // Make sure the option is processed unset($this->resolved[$option]); @@ -966,15 +1015,15 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) throw new OptionDefinitionException(sprintf('The options "%s" have a cyclic dependency.', implode('", "', array_keys($this->calling)))); } - $normalizer = $this->normalizers[$option]; - // The following section must be protected from cyclic // calls. Set $calling for the current $option to detect a cyclic // dependency // BEGIN $this->calling[$option] = true; try { - $value = $normalizer($this, $value); + foreach ($this->normalizers[$option] as $normalizer) { + $value = $normalizer($this, $value); + } } finally { unset($this->calling[$option]); } diff --git a/src/Symfony/Component/OptionsResolver/Tests/Debug/OptionsResolverIntrospectorTest.php b/src/Symfony/Component/OptionsResolver/Tests/Debug/OptionsResolverIntrospectorTest.php index c6615573cd881..64a1ead1fe014 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/Debug/OptionsResolverIntrospectorTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/Debug/OptionsResolverIntrospectorTest.php @@ -201,6 +201,42 @@ public function testGetNormalizerThrowsOnNotDefinedOption() $this->assertSame('bar', $debug->getNormalizer('foo')); } + public function testGetNormalizers() + { + $resolver = new OptionsResolver(); + $resolver->setDefined('foo'); + $resolver->addNormalizer('foo', $normalizer1 = function () {}); + $resolver->addNormalizer('foo', $normalizer2 = function () {}); + + $debug = new OptionsResolverIntrospector($resolver); + $this->assertSame([$normalizer1, $normalizer2], $debug->getNormalizers('foo')); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\NoConfigurationException + * @expectedExceptionMessage No normalizer was set for the "foo" option. + */ + public function testGetNormalizersThrowsOnNoConfiguredValue() + { + $resolver = new OptionsResolver(); + $resolver->setDefined('foo'); + + $debug = new OptionsResolverIntrospector($resolver); + $debug->getNormalizers('foo'); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + * @expectedExceptionMessage The option "foo" does not exist. + */ + public function testGetNormalizersThrowsOnNotDefinedOption() + { + $resolver = new OptionsResolver(); + + $debug = new OptionsResolverIntrospector($resolver); + $debug->getNormalizers('foo'); + } + public function testGetDeprecationMessage() { $resolver = new OptionsResolver(); diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php index 886a88ebfa66c..edf53cd2e2565 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php @@ -1554,6 +1554,63 @@ public function testNormalizerNotCalledForUnsetOptions() $this->assertEmpty($this->resolver->resolve()); } + public function testAddNormalizerReturnsThis() + { + $this->resolver->setDefault('foo', 'bar'); + + $this->assertSame($this->resolver, $this->resolver->addNormalizer('foo', function () {})); + } + + public function testAddNormalizerClosure() + { + // defined by superclass + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setNormalizer('foo', function (Options $options, $value) { + return '1st-normalized-'.$value; + }); + // defined by subclass + $this->resolver->addNormalizer('foo', function (Options $options, $value) { + return '2nd-normalized-'.$value; + }); + + $this->assertEquals(['foo' => '2nd-normalized-1st-normalized-bar'], $this->resolver->resolve()); + } + + public function testForcePrependNormalizerClosure() + { + // defined by superclass + $this->resolver->setDefault('foo', 'bar'); + $this->resolver->setNormalizer('foo', function (Options $options, $value) { + return '2nd-normalized-'.$value; + }); + // defined by subclass + $this->resolver->addNormalizer('foo', function (Options $options, $value) { + return '1st-normalized-'.$value; + }, true); + + $this->assertEquals(['foo' => '2nd-normalized-1st-normalized-bar'], $this->resolver->resolve()); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException + */ + public function testAddNormalizerFailsIfUnknownOption() + { + $this->resolver->addNormalizer('foo', function () {}); + } + + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\AccessException + */ + public function testFailIfAddNormalizerFromLazyOption() + { + $this->resolver->setDefault('foo', function (Options $options) { + $options->addNormalizer('foo', function () {}); + }); + + $this->resolver->resolve(); + } + public function testSetDefaultsReturnsThis() { $this->assertSame($this->resolver, $this->resolver->setDefaults(['foo', 'bar'])); From 7ab1b00e02f8db72c1fbd5e1a428fedb5771fe51 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Wed, 20 Feb 2019 15:26:42 +0100 Subject: [PATCH 322/495] [Form][TwigBridge] Add row_attr to form theme --- .../Twig/Resources/views/Form/form_div_layout.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index 52a639a33365f..bbda607f6e58b 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -325,7 +325,7 @@ {%- if help is not empty -%} {%- set widget_attr = {attr: {'aria-describedby': id ~"_help"}} -%} {%- endif -%} -
+
{{- form_label(form) -}} {{- form_errors(form) -}} {{- form_widget(form, widget_attr) -}} @@ -334,7 +334,7 @@ {%- endblock form_row -%} {%- block button_row -%} -
+
{{- form_widget(form) -}}
{%- endblock button_row -%} From caa0aded897d9a61049612c54081caf90d6842d9 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 31 Mar 2019 13:27:47 +0200 Subject: [PATCH 323/495] [EventDispatcher] Fix BC layer --- .../EventDispatcher/EventDispatcher.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index b593e068d3c4c..92867fdd07d97 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -230,7 +230,20 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) */ protected function callListeners(iterable $listeners, string $eventName, $event) { - $this->doDispatch($listeners, $eventName, $event); + if ($event instanceof Event) { + $this->doDispatch($listeners, $eventName, $event); + + return; + } + + $stoppable = $event instanceof ContractsEvent || $event instanceof StoppableEventInterface; + + foreach ($listeners as $listener) { + if ($stoppable && $event->isPropagationStopped()) { + break; + } + $listener($event, $eventName, $this); + } } /** @@ -238,10 +251,8 @@ protected function callListeners(iterable $listeners, string $eventName, $event) */ protected function doDispatch($listeners, $eventName, Event $event) { - $stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface; - foreach ($listeners as $listener) { - if ($stoppable && $event->isPropagationStopped()) { + if ($event->isPropagationStopped()) { break; } $listener($event, $eventName, $this); From fbfc623b72cf043729f3a1bb5e1fbd06a35a1c0e Mon Sep 17 00:00:00 2001 From: Simeon Kolev Date: Thu, 14 Mar 2019 14:19:23 +0200 Subject: [PATCH 324/495] [FrameworkBundle][HttpKernel] Provide intuitive error message when a controller fails because it's not registered as a service --- .../Resources/config/debug.xml | 5 + .../NotTaggedControllerValueResolver.php | 81 ++++++++++++ ...RegisterControllerArgumentLocatorsPass.php | 19 ++- .../NotTaggedControllerValueResolverTest.php | 117 ++++++++++++++++++ ...sterControllerArgumentLocatorsPassTest.php | 13 ++ 5 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml index 2c0d446b323c8..9b39912087110 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml @@ -23,5 +23,10 @@ + + + + + diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php new file mode 100644 index 0000000000000..19e324dc24957 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; + +use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; + +/** + * Provides an intuitive error message when controller fails because it is not registered as a service. + * + * @author Simeon Kolev + */ +final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface +{ + private $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function supports(Request $request, ArgumentMetadata $argument) + { + $controller = $request->attributes->get('_controller'); + + if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { + $controller = $controller[0].'::'.$controller[1]; + } elseif (!\is_string($controller) || '' === $controller) { + return false; + } + + if ('\\' === $controller[0]) { + $controller = ltrim($controller, '\\'); + } + + if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { + $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); + } + + return false === $this->container->has($controller); + } + + /** + * {@inheritdoc} + */ + public function resolve(Request $request, ArgumentMetadata $argument) + { + if (\is_array($controller = $request->attributes->get('_controller'))) { + $controller = $controller[0].'::'.$controller[1]; + } + + if ('\\' === $controller[0]) { + $controller = ltrim($controller, '\\'); + } + + if (!$this->container->has($controller)) { + $i = strrpos($controller, ':'); + $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); + } + + $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); + $message = sprintf('Could not resolve %s, maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?', $what); + + throw new RuntimeException($message); + } +} diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index 64d5e02473031..c5a823cc7ee1e 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -34,17 +34,19 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface private $resolverServiceId; private $controllerTag; private $controllerLocator; + private $notTaggedControllerResolverServiceId; - public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator') + public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator', string $notTaggedControllerResolverServiceId = 'argument_resolver.not_tagged_controller') { $this->resolverServiceId = $resolverServiceId; $this->controllerTag = $controllerTag; $this->controllerLocator = $controllerLocator; + $this->notTaggedControllerResolverServiceId = $notTaggedControllerResolverServiceId; } public function process(ContainerBuilder $container) { - if (false === $container->hasDefinition($this->resolverServiceId)) { + if (false === $container->hasDefinition($this->resolverServiceId) && false === $container->hasDefinition($this->notTaggedControllerResolverServiceId)) { return; } @@ -181,8 +183,17 @@ public function process(ContainerBuilder $container) } } - $container->getDefinition($this->resolverServiceId) - ->replaceArgument(0, $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers)); + $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers); + + if ($container->hasDefinition($this->resolverServiceId)) { + $container->getDefinition($this->resolverServiceId) + ->replaceArgument(0, $controllerLocatorRef); + } + + if ($container->hasDefinition($this->notTaggedControllerResolverServiceId)) { + $container->getDefinition($this->notTaggedControllerResolverServiceId) + ->replaceArgument(0, $controllerLocatorRef); + } $container->setAlias($this->controllerLocator, (string) $controllerLocatorRef); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php new file mode 100644 index 0000000000000..bd22adde91ee6 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentResolver\NotTaggedControllerValueResolver; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; + +class NotTaggedControllerValueResolverTest extends TestCase +{ + public function testDoSupportWhenControllerDoNotExists() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'my_controller']); + + $this->assertTrue($resolver->supports($request, $argument)); + } + + public function testDoNotSupportWhenControllerExists() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([ + 'App\\Controller\\Mine::method' => function () { + return new ServiceLocator([ + 'dummy' => function () { + return new \stdClass(); + }, + ]); + }, + ])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']); + + $this->assertFalse($resolver->supports($request, $argument)); + } + + public function testDoNotSupportEmptyController() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => '']); + $this->assertFalse($resolver->supports($request, $argument)); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testController() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testControllerWithATrailingBackSlash() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => '\\App\\Controller\\Mine::method']); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testControllerWithMethodNameStartUppercase() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::Method']); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testControllerNameIsAnArray() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => ['App\\Controller\\Mine', 'method']]); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + private function requestWithAttributes(array $attributes) + { + $request = Request::create('/'); + foreach ($attributes as $name => $value) { + $request->attributes->set($name, $value); + } + + return $request; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index cf685b2ae2979..948311556cb53 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -376,6 +376,19 @@ public function testBindingsOnChildDefinitions() $this->assertInstanceOf(ServiceClosureArgument::class, $locator['someArg']); $this->assertEquals(new Reference('parent'), $locator['someArg']->getValues()[0]); } + + public function testNotTaggedControllerServiceReceivesLocatorArgument() + { + $container = new ContainerBuilder(); + $resolver = $container->register('argument_resolver.not_tagged_controller')->addArgument([]); + + $pass = new RegisterControllerArgumentLocatorsPass(); + $pass->process($container); + + $locatorArgument = $container->getDefinition('argument_resolver.not_tagged_controller')->getArgument(0); + + $this->assertInstanceOf(Reference::class, $locatorArgument); + } } class RegisterTestController From dd47fda441638efa2a92c43e2713fe3dc79de7f4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 14:18:54 +0200 Subject: [PATCH 325/495] fixed bad merge --- src/Symfony/Component/Validator/CHANGELOG.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index b0acf5b406d5a..3ba214dda764b 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -8,13 +8,9 @@ CHANGELOG * added UATP cards support to `CardSchemeValidator` * added option `allowNull` to NotBlank constraint * added `Json` constraint -<<<<<<< HEAD * added `Unique` constraint - -======= * added a new `normalizer` option to the string constraints and to the `NotBlank` constraint ->>>>>>> pull/26484 4.2.0 ----- From 07276642dea3d3c6c9d8122a1c31fb81013655a1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 15:49:16 +0200 Subject: [PATCH 326/495] fixed typo --- src/Symfony/Contracts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Contracts/README.md b/src/Symfony/Contracts/README.md index 9cb73af23f1dd..d9cfd2c225598 100644 --- a/src/Symfony/Contracts/README.md +++ b/src/Symfony/Contracts/README.md @@ -11,7 +11,7 @@ Design Principles * contracts are split by domain, each into their own sub-namespaces; * contracts are small and consistent sets of PHP interfaces, traits, normative - docblocks and reference test suites when applicable, etc.; + docblocks and reference test suites when applicable, ...; * all contracts must have a proven implementation to enter this repository; * they must be backward compatible with existing Symfony components. From 88d008c82844806cdc46843e5cfaaded635d4e12 Mon Sep 17 00:00:00 2001 From: Vincent Touzet Date: Sat, 30 Mar 2019 13:37:54 +0100 Subject: [PATCH 327/495] [Messenger] Add a Doctrine transport --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- .../Transport/Doctrine/ConnectionTest.php | 214 +++++++++++++++ .../Doctrine/DoctrineIntegrationTest.php | 127 +++++++++ .../Doctrine/DoctrineReceiverTest.php | 77 ++++++ .../Transport/Doctrine/DoctrineSenderTest.php | 57 ++++ .../Doctrine/DoctrineTransportFactoryTest.php | 75 +++++ .../Transport/AmqpExt/AmqpReceiver.php | 6 + .../Transport/Doctrine/Connection.php | 259 ++++++++++++++++++ .../Doctrine/DoctrineReceivedStamp.php | 34 +++ .../Transport/Doctrine/DoctrineReceiver.php | 95 +++++++ .../Transport/Doctrine/DoctrineSender.php | 57 ++++ .../Transport/Doctrine/DoctrineTransport.php | 87 ++++++ .../Doctrine/DoctrineTransportFactory.php | 56 ++++ src/Symfony/Component/Messenger/composer.json | 2 + 14 files changed, 1147 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineSenderTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php create mode 100644 src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php create mode 100644 src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceivedStamp.php create mode 100644 src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php create mode 100644 src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php create mode 100644 src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php create mode 100644 src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 304790630b759..cd4481d752d68 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -57,8 +57,8 @@ CHANGELOG * [BC BREAK] The Amqp Transport now automatically sets up the exchanges and queues by default. Previously, this was done when in "debug" mode only. Pass the `auto_setup` connection option to control this. - * Added a `SetupTransportsCommand` command to setup the transports + * Added a Doctrine transport. For example, the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php new file mode 100644 index 0000000000000..26878e3647bfe --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -0,0 +1,214 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; + +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Driver\Statement; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Query\QueryBuilder; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\Doctrine\Connection; + +class ConnectionTest extends TestCase +{ + public function testGetAMessageWillChangeItsStatus() + { + $queryBuilder = $this->getQueryBuilderMock(); + $driverConnection = $this->getDBALConnectionMock(); + $stmt = $this->getStatementMock([ + 'id' => 1, + 'body' => '{"message":"Hi"}', + 'headers' => \json_encode(['type' => DummyMessage::class]), + ]); + + $driverConnection + ->method('createQueryBuilder') + ->willReturn($queryBuilder); + $queryBuilder + ->method('getSQL') + ->willReturn(''); + $driverConnection + ->method('prepare') + ->willReturn($stmt); + + $connection = new Connection([], $driverConnection); + $doctrineEnvelope = $connection->get(); + $this->assertEquals(1, $doctrineEnvelope['id']); + $this->assertEquals('{"message":"Hi"}', $doctrineEnvelope['body']); + $this->assertEquals(['type' => DummyMessage::class], $doctrineEnvelope['headers']); + } + + public function testGetWithNoPendingMessageWillReturnNull() + { + $queryBuilder = $this->getQueryBuilderMock(); + $driverConnection = $this->getDBALConnectionMock(); + $stmt = $this->getStatementMock(false); + + $driverConnection->expects($this->once()) + ->method('createQueryBuilder') + ->willReturn($queryBuilder); + $driverConnection->method('prepare') + ->willReturn($stmt); + $driverConnection->expects($this->never()) + ->method('update'); + + $connection = new Connection([], $driverConnection); + $doctrineEnvelope = $connection->get(); + $this->assertNull($doctrineEnvelope); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() + { + $driverConnection = $this->getDBALConnectionMock(); + $driverConnection->method('delete')->willThrowException(new DBALException()); + + $connection = new Connection([], $driverConnection); + $connection->ack('dummy_id'); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsATransportExceptionIfItCannotRejectMessage() + { + $driverConnection = $this->getDBALConnectionMock(); + $driverConnection->method('delete')->willThrowException(new DBALException()); + + $connection = new Connection([], $driverConnection); + $connection->reject('dummy_id'); + } + + private function getDBALConnectionMock() + { + $driverConnection = $this->getMockBuilder(\Doctrine\DBAL\Connection::class) + ->disableOriginalConstructor() + ->getMock(); + $platform = $this->getMockBuilder(AbstractPlatform::class) + ->getMock(); + $platform->method('getWriteLockSQL')->willReturn('FOR UPDATE'); + $driverConnection->method('getDatabasePlatform')->willReturn($platform); + + return $driverConnection; + } + + private function getQueryBuilderMock() + { + $queryBuilder = $this->getMockBuilder(QueryBuilder::class) + ->disableOriginalConstructor() + ->getMock(); + + $queryBuilder->method('select')->willReturn($queryBuilder); + $queryBuilder->method('update')->willReturn($queryBuilder); + $queryBuilder->method('from')->willReturn($queryBuilder); + $queryBuilder->method('set')->willReturn($queryBuilder); + $queryBuilder->method('where')->willReturn($queryBuilder); + $queryBuilder->method('andWhere')->willReturn($queryBuilder); + $queryBuilder->method('orderBy')->willReturn($queryBuilder); + $queryBuilder->method('setMaxResults')->willReturn($queryBuilder); + $queryBuilder->method('setParameter')->willReturn($queryBuilder); + + return $queryBuilder; + } + + private function getStatementMock($expectedResult) + { + $stmt = $this->getMockBuilder(Statement::class) + ->disableOriginalConstructor() + ->getMock(); + $stmt->expects($this->once()) + ->method('fetch') + ->willReturn($expectedResult); + + return $stmt; + } + + /** + * @dataProvider buildConfigurationProvider + */ + public function testBuildConfiguration($dsn, $options, $expectedManager, $expectedTableName, $expectedRedeliverTimeout, $expectedQueue) + { + $config = Connection::buildConfiguration($dsn, $options); + $this->assertEquals($expectedManager, $config['connection']); + $this->assertEquals($expectedTableName, $config['table_name']); + $this->assertEquals($expectedRedeliverTimeout, $config['redeliver_timeout']); + $this->assertEquals($expectedQueue, $config['queue_name']); + } + + public function buildConfigurationProvider() + { + return [ + [ + 'dsn' => 'doctrine://default', + 'options' => [], + 'expectedManager' => 'default', + 'expectedTableName' => 'messenger_messages', + 'expectedRedeliverTimeout' => 3600, + 'expectedQueue' => 'default', + ], + // test options from options array + [ + 'dsn' => 'doctrine://default', + 'options' => [ + 'table_name' => 'name_from_options', + 'redeliver_timeout' => 1800, + 'queue_name' => 'important', + ], + 'expectedManager' => 'default', + 'expectedTableName' => 'name_from_options', + 'expectedRedeliverTimeout' => 1800, + 'expectedQueue' => 'important', + ], + // tests options from dsn + [ + 'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal', + 'options' => [], + 'expectedManager' => 'default', + 'expectedTableName' => 'name_from_dsn', + 'expectedRedeliverTimeout' => 1200, + 'expectedQueue' => 'normal', + ], + // test options from options array wins over options from dsn + [ + 'dsn' => 'doctrine://default?table_name=name_from_dsn&redeliver_timeout=1200&queue_name=normal', + 'options' => [ + 'table_name' => 'name_from_options', + 'redeliver_timeout' => 1800, + 'queue_name' => 'important', + ], + 'expectedManager' => 'default', + 'expectedTableName' => 'name_from_options', + 'expectedRedeliverTimeout' => 1800, + 'expectedQueue' => 'important', + ], + ]; + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsAnExceptionIfAnExtraOptionsInDefined() + { + Connection::buildConfiguration('doctrine://default', ['new_option' => 'woops']); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + */ + public function testItThrowsAnExceptionIfAnExtraOptionsInDefinedInDSN() + { + Connection::buildConfiguration('doctrine://default?new_option=woops'); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php new file mode 100644 index 0000000000000..ffcde2039306d --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; + +use Doctrine\DBAL\DriverManager; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\Doctrine\Connection; + +/** + * @requires pdo_mysql + */ +class DoctrineIntegrationTest extends TestCase +{ + private $driverConnection; + private $connection; + + protected function setUp() + { + parent::setUp(); + + if (!getenv('MESSENGER_DOCTRINE_DSN')) { + $this->markTestSkipped('The "MESSENGER_DOCTRINE_DSN" environment variable is required.'); + } + $dsn = getenv('MESSENGER_DOCTRINE_DSN'); + $this->driverConnection = DriverManager::getConnection(['url' => $dsn]); + $this->connection = new Connection([], $this->driverConnection); + // call send to auto-setup the table + $this->connection->setup(); + // ensure the table is clean for tests + $this->driverConnection->exec('DELETE FROM messenger_messages'); + } + + public function testConnectionSendAndGet() + { + $this->connection->send('{"message": "Hi"}', ['type' => DummyMessage::class]); + $encoded = $this->connection->get(); + $this->assertEquals('{"message": "Hi"}', $encoded['body']); + $this->assertEquals(['type' => DummyMessage::class], $encoded['headers']); + } + + public function testSendWithDelay() + { + $this->connection->send('{"message": "Hi i am delayed"}', ['type' => DummyMessage::class], 600000); + + $available_at = $this->driverConnection->createQueryBuilder() + ->select('m.available_at') + ->from('messenger_messages', 'm') + ->where('m.body = :body') + ->setParameter(':body', '{"message": "Hi i am delayed"}') + ->execute() + ->fetchColumn(); + + $available_at = new \DateTime($available_at); + + $now = \DateTime::createFromFormat('U.u', microtime(true)); + $now->modify('+60 seconds'); + $this->assertGreaterThan($now, $available_at); + } + + public function testItRetrieveTheFirstAvailableMessage() + { + // insert messages + // one currently handled + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi handled"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'delivered_at' => Connection::formatDateTime(\DateTime::createFromFormat('U.u', microtime(true))), + ]); + // one available later + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi delayed"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 13:00:00')), + ]); + // one available + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi available"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')), + ]); + + $encoded = $this->connection->get(); + $this->assertEquals('{"message": "Hi available"}', $encoded['body']); + } + + public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout() + { + $twoHoursAgo = new \DateTime('now'); + $twoHoursAgo->modify('-2 hours'); + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi requeued"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'delivered_at' => Connection::formatDateTime($twoHoursAgo), + ]); + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi available"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')), + ]); + + $next = $this->connection->get(); + $this->assertEquals('{"message": "Hi requeued"}', $next['body']); + $this->connection->reject($next['id']); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php new file mode 100644 index 0000000000000..0507a0ccfa91e --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineReceiverTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\Doctrine\Connection; +use Symfony\Component\Messenger\Transport\Doctrine\DoctrineReceiver; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\Serializer; +use Symfony\Component\Serializer as SerializerComponent; +use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; + +class DoctrineReceiverTest extends TestCase +{ + public function testItReturnsTheDecodedMessageToTheHandler() + { + $serializer = $this->createSerializer(); + + $doctrineEnvelop = $this->createDoctrineEnvelope(); + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $connection->method('get')->willReturn($doctrineEnvelop); + + $receiver = new DoctrineReceiver($connection, $serializer); + $actualEnvelopes = iterator_to_array($receiver->get()); + $this->assertCount(1, $actualEnvelopes); + $this->assertEquals(new DummyMessage('Hi'), $actualEnvelopes[0]->getMessage()); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\MessageDecodingFailedException + */ + public function testItRejectTheMessageIfThereIsAMessageDecodingFailedException() + { + $serializer = $this->createMock(PhpSerializer::class); + $serializer->method('decode')->willThrowException(new MessageDecodingFailedException()); + + $doctrineEnvelop = $this->createDoctrineEnvelope(); + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $connection->method('get')->willReturn($doctrineEnvelop); + $connection->expects($this->once())->method('reject'); + + $receiver = new DoctrineReceiver($connection, $serializer); + iterator_to_array($receiver->get()); + } + + private function createDoctrineEnvelope() + { + return [ + 'id' => 1, + 'body' => '{"message": "Hi"}', + 'headers' => [ + 'type' => DummyMessage::class, + ], + ]; + } + + private function createSerializer(): Serializer + { + $serializer = new Serializer( + new SerializerComponent\Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]) + ); + + return $serializer; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineSenderTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineSenderTest.php new file mode 100644 index 0000000000000..26badf93340f5 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineSenderTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\Doctrine\Connection; +use Symfony\Component\Messenger\Transport\Doctrine\DoctrineSender; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +class DoctrineSenderTest extends TestCase +{ + public function testSend() + { + $envelope = new Envelope(new DummyMessage('Oy')); + $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; + + $connection = $this->getMockBuilder(Connection::class) + ->disableOriginalConstructor() + ->getMock(); + $connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers']); + + $serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(); + $serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded); + + $sender = new DoctrineSender($connection, $serializer); + $sender->send($envelope); + } + + public function testSendWithDelay() + { + $envelope = (new Envelope(new DummyMessage('Oy')))->with(new DelayStamp(500)); + $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; + + $connection = $this->getMockBuilder(Connection::class) + ->disableOriginalConstructor() + ->getMock(); + $connection->expects($this->once())->method('send')->with($encoded['body'], $encoded['headers'], 500); + + $serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(); + $serializer->method('encode')->with($envelope)->willReturnOnConsecutiveCalls($encoded); + + $sender = new DoctrineSender($connection, $serializer); + $sender->send($envelope); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php new file mode 100644 index 0000000000000..104de47dcd16b --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Doctrine\RegistryInterface; +use Symfony\Component\Messenger\Transport\Doctrine\Connection; +use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport; +use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransportFactory; + +class DoctrineTransportFactoryTest extends TestCase +{ + public function testSupports() + { + $factory = new DoctrineTransportFactory( + $this->getMockBuilder(RegistryInterface::class)->getMock(), + null, + false + ); + + $this->assertTrue($factory->supports('doctrine://default', [])); + $this->assertFalse($factory->supports('amqp://localhost', [])); + } + + public function testCreateTransport() + { + $connection = $this->getMockBuilder(\Doctrine\DBAL\Connection::class) + ->disableOriginalConstructor() + ->getMock(); + $registry = $this->getMockBuilder(RegistryInterface::class)->getMock(); + $registry->expects($this->once()) + ->method('getConnection') + ->willReturn($connection); + + $factory = new DoctrineTransportFactory( + $registry, + null + ); + + $this->assertEquals( + new DoctrineTransport(new Connection(Connection::buildConfiguration('doctrine://default'), $connection), null), + $factory->createTransport('doctrine://default', []) + ); + } + + /** + * @expectedException \Symfony\Component\Messenger\Exception\TransportException + * @expectedExceptionMessage Could not find Doctrine connection from DSN "doctrine://default". + */ + public function testCreateTransportMustThrowAnExceptionIfManagerIsNotFound() + { + $registry = $this->getMockBuilder(RegistryInterface::class)->getMock(); + $registry->expects($this->once()) + ->method('getConnection') + ->will($this->returnCallback(function () { + throw new \InvalidArgumentException(); + })); + + $factory = new DoctrineTransportFactory( + $registry, + null + ); + + $factory->createTransport('doctrine://default', []); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index ce1918e1da0c1..9f1e25a40267a 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -67,6 +67,9 @@ public function get(): iterable yield $envelope->with(new AmqpReceivedStamp($amqpEnvelope)); } + /** + * {@inheritdoc} + */ public function ack(Envelope $envelope): void { try { @@ -76,6 +79,9 @@ public function ack(Envelope $envelope): void } } + /** + * {@inheritdoc} + */ public function reject(Envelope $envelope): void { $this->rejectAmqpEnvelope($this->findAmqpEnvelope($envelope)); diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php new file mode 100644 index 0000000000000..6bf4bd2e32955 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -0,0 +1,259 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Doctrine\DBAL\Connection as DBALConnection; +use Doctrine\DBAL\DBALException; +use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer; +use Doctrine\DBAL\Types\Type; +use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Exception\TransportException; + +/** + * @author Vincent Touzet + * + * @final + * + * @experimental in 4.3 + */ +class Connection +{ + const DEFAULT_OPTIONS = [ + 'table_name' => 'messenger_messages', + 'queue_name' => 'default', + 'redeliver_timeout' => 3600, + 'loop_sleep' => 200000, + 'auto_setup' => true, + ]; + + /** + * Configuration of the connection. + * + * Available options: + * + * * table_name: name of the table + * * connection: name of the Doctrine's entity manager + * * queue_name: name of the queue + * * redeliver_timeout: Timeout before redeliver messages still in handling state (i.e: delivered_at is not null and message is still in table). Default 3600 + * * loop_sleep: Number of micro seconds to wait for a next message to handle + * * auto_setup: Whether the table should be created automatically during send / get. Default : true + */ + private $configuration = []; + private $driverConnection; + + public function __construct(array $configuration, DBALConnection $driverConnection) + { + $this->configuration = array_replace_recursive(self::DEFAULT_OPTIONS, $configuration); + $this->driverConnection = $driverConnection; + } + + public function getConfiguration(): array + { + return $this->configuration; + } + + public static function buildConfiguration($dsn, array $options = []) + { + if (false === $parsedUrl = parse_url($dsn)) { + throw new InvalidArgumentException(sprintf('The given Doctrine DSN "%s" is invalid.', $dsn)); + } + + $components = parse_url($dsn); + $query = []; + if (isset($components['query'])) { + parse_str($components['query'], $query); + } + + $configuration = [ + 'connection' => $components['host'], + 'table_name' => $options['table_name'] ?? ($query['table_name'] ?? self::DEFAULT_OPTIONS['table_name']), + 'queue_name' => $options['queue_name'] ?? ($query['queue_name'] ?? self::DEFAULT_OPTIONS['queue_name']), + 'redeliver_timeout' => $options['redeliver_timeout'] ?? ($query['redeliver_timeout'] ?? self::DEFAULT_OPTIONS['redeliver_timeout']), + 'loop_sleep' => $options['loop_sleep'] ?? ($query['loop_sleep'] ?? self::DEFAULT_OPTIONS['loop_sleep']), + 'auto_setup' => $options['auto_setup'] ?? ($query['auto_setup'] ?? self::DEFAULT_OPTIONS['auto_setup']), + ]; + + // check for extra keys in options + $optionsExtraKeys = array_diff(array_keys($options), array_keys($configuration)); + if (0 < \count($optionsExtraKeys)) { + throw new TransportException(sprintf('Unknown option found : [%s]. Allowed options are [%s]', implode(', ', $optionsExtraKeys), implode(', ', self::DEFAULT_OPTIONS))); + } + + // check for extra keys in options + $queryExtraKeys = array_diff(array_keys($query), array_keys($configuration)); + if (0 < \count($queryExtraKeys)) { + throw new TransportException(sprintf('Unknown option found in DSN: [%s]. Allowed options are [%s]', implode(', ', $queryExtraKeys), implode(', ', self::DEFAULT_OPTIONS))); + } + + return $configuration; + } + + /** + * @param int $delay The delay in milliseconds + * + * @throws \Doctrine\DBAL\DBALException + */ + public function send(string $body, array $headers, int $delay = 0): void + { + $now = (\DateTime::createFromFormat('U.u', microtime(true))); + $availableAt = (clone $now)->modify(sprintf('+%d seconds', $delay / 1000)); + + $queryBuilder = $this->driverConnection->createQueryBuilder() + ->insert($this->configuration['table_name']) + ->values([ + 'body' => ':body', + 'headers' => ':headers', + 'queue_name' => ':queue_name', + 'created_at' => ':created_at', + 'available_at' => ':available_at', + ]); + + $this->executeQuery($queryBuilder->getSQL(), [ + ':body' => $body, + ':headers' => \json_encode($headers), + ':queue_name' => $this->configuration['queue_name'], + ':created_at' => self::formatDateTime($now), + ':available_at' => self::formatDateTime($availableAt), + ]); + } + + public function get(): ?array + { + $this->driverConnection->beginTransaction(); + try { + $query = $this->driverConnection->createQueryBuilder() + ->select('m.*') + ->from($this->configuration['table_name'], 'm') + ->where('m.delivered_at is null OR m.delivered_at < :redeliver_limit') + ->andWhere('m.available_at <= :now') + ->andWhere('m.queue_name = :queue_name') + ->orderBy('available_at', 'ASC') + ->setMaxResults(1); + + $now = \DateTime::createFromFormat('U.u', microtime(true)); + $redeliverLimit = (clone $now)->modify(sprintf('-%d seconds', $this->configuration['redeliver_timeout'])); + // use SELECT ... FOR UPDATE to lock table + $doctrineEnvelope = $this->executeQuery( + $query->getSQL().' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL(), + [ + ':now' => self::formatDateTime($now), + ':queue_name' => $this->configuration['queue_name'], + ':redeliver_limit' => self::formatDateTime($redeliverLimit), + ] + )->fetch(); + + if (false === $doctrineEnvelope) { + $this->driverConnection->commit(); + + return null; + } + + $doctrineEnvelope['headers'] = \json_decode($doctrineEnvelope['headers'], true); + + $queryBuilder = $this->driverConnection->createQueryBuilder() + ->update($this->configuration['table_name']) + ->set('delivered_at', ':delivered_at') + ->where('id = :id'); + $this->executeQuery($queryBuilder->getSQL(), [ + ':id' => $doctrineEnvelope['id'], + ':delivered_at' => self::formatDateTime($now), + ]); + + $this->driverConnection->commit(); + + return $doctrineEnvelope; + } catch (\Throwable $e) { + $this->driverConnection->rollBack(); + + throw $e; + } + } + + public function ack(string $id): bool + { + try { + return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0; + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + public function reject(string $id): bool + { + try { + return $this->driverConnection->delete($this->configuration['table_name'], ['id' => $id]) > 0; + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + } + + public function setup(): void + { + $synchronizer = new SingleDatabaseSynchronizer($this->driverConnection); + $synchronizer->updateSchema($this->getSchema(), true); + } + + private function executeQuery(string $sql, array $parameters = []) + { + $stmt = null; + try { + $stmt = $this->driverConnection->prepare($sql); + $stmt->execute($parameters); + } catch (TableNotFoundException $e) { + // create table + if (!$this->driverConnection->isTransactionActive() && $this->configuration['auto_setup']) { + $this->setup(); + } + // statement not prepared ? SQLite throw on exception on prepare if the table does not exist + if (null === $stmt) { + $stmt = $this->driverConnection->prepare($sql); + } + $stmt->execute($parameters); + } + + return $stmt; + } + + private function getSchema(): Schema + { + $schema = new Schema(); + $table = $schema->createTable($this->configuration['table_name']); + $table->addColumn('id', Type::BIGINT) + ->setAutoincrement(true) + ->setNotnull(true); + $table->addColumn('body', Type::TEXT) + ->setNotnull(true); + $table->addColumn('headers', Type::STRING) + ->setNotnull(true); + $table->addColumn('queue_name', Type::STRING) + ->setNotnull(true); + $table->addColumn('created_at', Type::DATETIME) + ->setNotnull(true); + $table->addColumn('available_at', Type::DATETIME) + ->setNotnull(true); + $table->addColumn('delivered_at', Type::DATETIME) + ->setNotnull(false); + $table->setPrimaryKey(['id']); + $table->addIndex(['queue_name']); + $table->addIndex(['available_at']); + $table->addIndex(['delivered_at']); + + return $schema; + } + + public static function formatDateTime(\DateTimeInterface $dateTime) + { + return $dateTime->format('Y-m-d\TH:i:s.uZ'); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceivedStamp.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceivedStamp.php new file mode 100644 index 0000000000000..f11217a74afcb --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceivedStamp.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Stamp\StampInterface; + +/** + * @author Vincent Touzet + * + * @experimental in 4.3 + */ +class DoctrineReceivedStamp implements StampInterface +{ + private $id; + + public function __construct(string $id) + { + $this->id = $id; + } + + public function getId(): string + { + return $this->id; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php new file mode 100644 index 0000000000000..3198e143dca84 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Doctrine\DBAL\DBALException; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\LogicException; +use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Vincent Touzet + * + * @experimental in 4.3 + */ +class DoctrineReceiver implements ReceiverInterface +{ + private $connection; + private $serializer; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + try { + $doctrineEnvelope = $this->connection->get(); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + if (null === $doctrineEnvelope) { + return []; + } + + try { + $envelope = $this->serializer->decode([ + 'body' => $doctrineEnvelope['body'], + 'headers' => $doctrineEnvelope['headers'], + ]); + } catch (MessageDecodingFailedException $exception) { + $this->connection->reject($doctrineEnvelope['id']); + + throw $exception; + } + + yield $envelope->with(new DoctrineReceivedStamp($doctrineEnvelope['id'])); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + $this->connection->ack($this->findDoctrineReceivedStamp($envelope)->getId()); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + $this->connection->reject($this->findDoctrineReceivedStamp($envelope)->getId()); + } + + private function findDoctrineReceivedStamp(Envelope $envelope): DoctrineReceivedStamp + { + /** @var DoctrineReceivedStamp|null $doctrineReceivedStamp */ + $doctrineReceivedStamp = $envelope->last(DoctrineReceivedStamp::class); + + if (null === $doctrineReceivedStamp) { + throw new LogicException('No DoctrineReceivedStamp found on the Envelope.'); + } + + return $doctrineReceivedStamp; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php new file mode 100644 index 0000000000000..8329d2a53f1bd --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineSender.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Doctrine\DBAL\DBALException; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Stamp\DelayStamp; +use Symfony\Component\Messenger\Transport\Sender\SenderInterface; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @author Vincent Touzet + * + * @experimental in 4.3 + */ +class DoctrineSender implements SenderInterface +{ + private $connection; + private $serializer; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + $encodedMessage = $this->serializer->encode($envelope); + + /** @var DelayStamp|null $delayStamp */ + $delayStamp = $envelope->last(DelayStamp::class); + $delay = null !== $delayStamp ? $delayStamp->getDelay() : 0; + + try { + $this->connection->send($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay); + } catch (DBALException $exception) { + throw new TransportException($exception->getMessage(), 0, $exception); + } + + return $envelope; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php new file mode 100644 index 0000000000000..97c2a0a629557 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\SetupableTransportInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Vincent Touzet + * + * @experimental in 4.3 + */ +class DoctrineTransport implements TransportInterface, SetupableTransportInterface +{ + private $connection; + private $serializer; + private $receiver; + private $sender; + + public function __construct(Connection $connection, SerializerInterface $serializer = null) + { + $this->connection = $connection; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + ($this->receiver ?? $this->getReceiver())->get(); + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->ack($envelope); + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + ($this->receiver ?? $this->getReceiver())->reject($envelope); + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + return ($this->sender ?? $this->getSender())->send($envelope); + } + + /** + * {@inheritdoc} + */ + public function setup(): void + { + $this->connection->setup(); + } + + private function getReceiver(): DoctrineReceiver + { + return $this->receiver = new DoctrineReceiver($this->connection, $this->serializer); + } + + private function getSender(): DoctrineSender + { + return $this->sender = new DoctrineSender($this->connection, $this->serializer); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php new file mode 100644 index 0000000000000..74f37933904be --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Transport\Doctrine; + +use Symfony\Bridge\Doctrine\RegistryInterface; +use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\TransportFactoryInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +/** + * @author Vincent Touzet + * + * @experimental in 4.3 + */ +class DoctrineTransportFactory implements TransportFactoryInterface +{ + private $registry; + private $serializer; + + public function __construct(RegistryInterface $registry, SerializerInterface $serializer = null) + { + $this->registry = $registry; + $this->serializer = $serializer ?? new PhpSerializer(); + } + + public function createTransport(string $dsn, array $options): TransportInterface + { + $configuration = Connection::buildConfiguration($dsn, $options); + + try { + $driverConnection = $this->registry->getConnection($configuration['connection']); + } catch (\InvalidArgumentException $e) { + throw new TransportException(sprintf('Could not find Doctrine connection from DSN "%s".', $dsn), 0, $e); + } + + $connection = new Connection($configuration, $driverConnection); + + return new DoctrineTransport($connection, $this->serializer); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'doctrine://'); + } +} diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index d40963e2f6d18..17eebcca92093 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -20,8 +20,10 @@ "psr/log": "~1.0" }, "require-dev": { + "doctrine/dbal": "~2.4", "symfony/console": "~3.4|~4.0", "symfony/dependency-injection": "~3.4.19|^4.1.8", + "symfony/doctrine-bridge": "~3.4|~4.0", "symfony/event-dispatcher": "~4.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/process": "~3.4|~4.0", From 49ab2cd9d94c2e48250b58e27a455551841784fc Mon Sep 17 00:00:00 2001 From: Nicholas Ruunu Date: Sat, 8 Dec 2018 13:49:18 +0000 Subject: [PATCH 328/495] Make MessengerPass less strict when auto-register handlers --- .../Messenger/DependencyInjection/MessengerPass.php | 6 +++--- .../Tests/DependencyInjection/MessengerPassTest.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index 1701994297639..7deffbd48acc3 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -206,11 +206,11 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser throw new RuntimeException(sprintf('Invalid handler service "%s": class "%s" must have an "__invoke()" method.', $serviceId, $handlerClass->getName())); } - $parameters = $method->getParameters(); - if (1 !== \count($parameters)) { - throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::__invoke()" must have exactly one argument corresponding to the message it handles.', $serviceId, $handlerClass->getName())); + if (0 === $method->getNumberOfRequiredParameters()) { + throw new RuntimeException(sprintf('Invalid handler service "%s": method "%s::__invoke()" requires at least one argument, first one being the message it handles.', $serviceId, $handlerClass->getName())); } + $parameters = $method->getParameters(); if (!$type = $parameters[0]->getType()) { throw new RuntimeException(sprintf('Invalid handler service "%s": argument "$%s" of method "%s::__invoke()" must have a type-hint corresponding to the message class it handles.', $serviceId, $parameters[0]->getName(), $handlerClass->getName())); } diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 2c219607bf46d..d3e26611ee7ff 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -391,7 +391,7 @@ public function testNotInvokableHandler() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentHandler": method "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentHandler::__invoke()" must have exactly one argument corresponding to the message it handles. + * @expectedExceptionMessage Invalid handler service "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentHandler": method "Symfony\Component\Messenger\Tests\DependencyInjection\MissingArgumentHandler::__invoke()" requires at least one argument, first one being the message it handles. */ public function testMissingArgumentHandler() { From ef6f23e8b9b856c7db9777c6eef8a6ad0a113d16 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 21 Mar 2019 10:47:28 -0400 Subject: [PATCH 329/495] Making the serializer configurable by transport --- .../Bundle/FrameworkBundle/CHANGELOG.md | 11 +++++- .../DependencyInjection/Configuration.php | 25 ++++-------- .../FrameworkExtension.php | 39 ++++++------------- .../Resources/config/messenger.xml | 3 +- .../Resources/config/schema/symfony-1.0.xsd | 7 ++-- .../DependencyInjection/ConfigurationTest.php | 4 +- .../Fixtures/php/messenger.php | 2 +- ...messenger_amqp_transport_no_serializer.php | 10 ----- .../Fixtures/php/messenger_routing.php | 2 +- .../Fixtures/php/messenger_transport.php | 4 +- .../php/messenger_transport_no_serializer.php | 13 ------- .../Fixtures/php/messenger_transports.php | 3 +- ...messenger_amqp_transport_no_serializer.xml | 14 ------- .../Fixtures/xml/messenger_routing.xml | 2 +- .../Fixtures/xml/messenger_transport.xml | 5 ++- .../xml/messenger_transport_no_serializer.xml | 15 ------- .../Fixtures/xml/messenger_transports.xml | 4 +- .../Fixtures/yml/messenger.yml | 2 +- ...messenger_amqp_transport_no_serializer.yml | 5 --- .../Fixtures/yml/messenger_routing.yml | 2 +- .../Fixtures/yml/messenger_transport.yml | 4 +- .../yml/messenger_transport_no_serializer.yml | 7 ---- .../Fixtures/yml/messenger_transports.yml | 3 +- .../FrameworkExtensionTest.php | 27 +++---------- src/Symfony/Component/Messenger/CHANGELOG.md | 4 +- .../AmqpExt/AmqpTransportFactoryTest.php | 11 ++---- .../AmqpExt/AmqpTransportFactory.php | 12 +----- .../Messenger/Transport/TransportFactory.php | 5 ++- .../Transport/TransportFactoryInterface.php | 4 +- 29 files changed, 75 insertions(+), 174 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_amqp_transport_no_serializer.php delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_no_serializer.php delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_amqp_transport_no_serializer.xml delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_no_serializer.xml delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_amqp_transport_no_serializer.yml delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_no_serializer.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index d993fbe2584a2..ac3d97189822f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -8,11 +8,18 @@ CHANGELOG * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will be mandatory in 5.0. * Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead + * Added the ability to specify a custom `serializer` option for each + transport under`framework.messenger.transports`. * [BC Break] When using Messenger, the default transport changed from using Symfony's serializer service to use `PhpSerializer`, which uses PHP's native `serialize()` and `unserialize()` functions. To use the - original serialization method, set the `framework.messenger.serializer.id` - config option to `messenger.transport.symfony_serializer`. + original serialization method, set the `framework.messenger.defaut_serializer` + config option to `messenger.transport.symfony_serializer`. Or set the + `serializer` option under one specific `transport`. + * [BC Break] The `framework.messenger.serializer` config key changed to + `framework.messenger.default_serializer`, which holds the string service + id and `framework.messenger.symfony_serializer`, which configures the + options if you're using Symfony's serializer. * Added information about deprecated aliases in `debug:autowiring` * Added php ini session options `sid_length` and `sid_bits_per_character` to the `session` section of the configuration diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 1b1c079ec0aec..1b23702913404 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1107,29 +1107,19 @@ function ($a) { ->end() ->end() ->end() - ->arrayNode('serializer') + ->scalarNode('default_serializer') + ->defaultValue('messenger.transport.native_php_serializer') + ->info('Service id to use as the default serializer for the transports.') + ->end() + ->arrayNode('symfony_serializer') ->addDefaultsIfNotSet() - ->beforeNormalization() - ->always() - ->then(function ($config) { - if (false === $config) { - return ['id' => null]; - } - - if (\is_string($config)) { - return ['id' => $config]; - } - - return $config; - }) - ->end() ->children() - ->scalarNode('id')->defaultValue('messenger.transport.native_php_serializer')->end() - ->scalarNode('format')->defaultValue('json')->end() + ->scalarNode('format')->defaultValue('json')->info('Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default).')->end() ->arrayNode('context') ->normalizeKeys(false) ->useAttributeAsKey('name') ->defaultValue([]) + ->info('Context array for the messenger.transport.symfony_serializer service (which is not the serializer used by default).') ->prototype('variable')->end() ->end() ->end() @@ -1146,6 +1136,7 @@ function ($a) { ->fixXmlConfig('option') ->children() ->scalarNode('dsn')->end() + ->scalarNode('serializer')->defaultNull()->info('Service id of a custom serializer to use.')->end() ->arrayNode('options') ->normalizeKeys(false) ->defaultValue([]) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 65de91c4f7879..192154fa06af8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -78,7 +78,6 @@ use Symfony\Component\Messenger\Handler\MessageHandlerInterface; use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBusInterface; -use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportFactoryInterface; use Symfony\Component\Messenger\Transport\TransportInterface; use Symfony\Component\Mime\MimeTypeGuesserInterface; @@ -1604,28 +1603,6 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $loader->load('messenger.xml'); - if (empty($config['transports'])) { - $container->removeDefinition('messenger.transport.symfony_serializer'); - $container->removeDefinition('messenger.transport.amqp.factory'); - } else { - if ('messenger.transport.symfony_serializer' === $config['serializer']['id']) { - if (!$this->isConfigEnabled($container, $serializerConfig)) { - throw new LogicException('The Messenger serializer cannot be enabled as the Serializer support is not available. Try enabling it or running "composer require symfony/serializer-pack".'); - } - - $container->getDefinition('messenger.transport.symfony_serializer') - ->replaceArgument(1, $config['serializer']['format']) - ->replaceArgument(2, $config['serializer']['context']); - } - - if ($config['serializer']['id']) { - $container->setAlias('messenger.transport.serializer', $config['serializer']['id']); - } else { - $container->removeDefinition('messenger.transport.amqp.factory'); - $container->removeDefinition(SerializerInterface::class); - } - } - if (null === $config['default_bus'] && 1 === \count($config['buses'])) { $config['default_bus'] = key($config['buses']); } @@ -1677,16 +1654,24 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder } } + if (empty($config['transports'])) { + $container->removeDefinition('messenger.transport.symfony_serializer'); + $container->removeDefinition('messenger.transport.amqp.factory'); + } else { + $container->getDefinition('messenger.transport.symfony_serializer') + ->replaceArgument(1, $config['symfony_serializer']['format']) + ->replaceArgument(2, $config['symfony_serializer']['context']); + $container->setAlias('messenger.default_serializer', $config['default_serializer']); + } + $senderAliases = []; $transportRetryReferences = []; foreach ($config['transports'] as $name => $transport) { - if (0 === strpos($transport['dsn'], 'amqp://') && !$container->hasDefinition('messenger.transport.amqp.factory')) { - throw new LogicException('The default AMQP transport is not available. Make sure you have installed and enabled the Serializer component. Try enabling it or running "composer require symfony/serializer-pack".'); - } + $serializerId = $transport['serializer'] ?? 'messenger.default_serializer'; $transportDefinition = (new Definition(TransportInterface::class)) ->setFactory([new Reference('messenger.transport_factory'), 'createTransport']) - ->setArguments([$transport['dsn'], $transport['options']]) + ->setArguments([$transport['dsn'], $transport['options'], new Reference($serializerId)]) ->addTag('messenger.receiver', ['alias' => $name]) ; $container->setDefinition($transportId = 'messenger.transport.'.$name, $transportDefinition); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index 55976d1c02269..1720ea72e71aa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -26,7 +26,7 @@ - + @@ -64,7 +64,6 @@ - diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 4a2705b950874..0415fa9559c54 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -402,7 +402,8 @@ - + + @@ -412,12 +413,11 @@ - + - @@ -437,6 +437,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 88eb6529ed68d..bc1ee582fc081 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -325,8 +325,8 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'enabled' => !class_exists(FullStack::class) && interface_exists(MessageBusInterface::class), 'routing' => [], 'transports' => [], - 'serializer' => [ - 'id' => 'messenger.transport.native_php_serializer', + 'default_serializer' => 'messenger.transport.native_php_serializer', + 'symfony_serializer' => [ 'format' => 'json', 'context' => [], ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php index d0a234eccc4b5..c74b64f3ffb1d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php @@ -5,7 +5,7 @@ $container->loadFromExtension('framework', [ 'messenger' => [ - 'serializer' => false, + 'default_serializer' => false, 'routing' => [ FooMessage::class => ['sender.bar', 'sender.biz'], BarMessage::class => 'sender.foo', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_amqp_transport_no_serializer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_amqp_transport_no_serializer.php deleted file mode 100644 index 10d31660f90b7..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_amqp_transport_no_serializer.php +++ /dev/null @@ -1,10 +0,0 @@ -loadFromExtension('framework', [ - 'messenger' => [ - 'serializer' => false, - 'transports' => [ - 'default' => 'amqp://localhost/%2f/messages', - ], - ], -]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php index 08aae8f27d763..6e0b7c61f1297 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php @@ -3,7 +3,7 @@ $container->loadFromExtension('framework', [ 'serializer' => true, 'messenger' => [ - 'serializer' => 'messenger.transport.symfony_serializer', + 'default_serializer' => 'messenger.transport.symfony_serializer', 'routing' => [ 'Symfony\Component\Messenger\Tests\Fixtures\DummyMessage' => ['amqp', 'audit'], 'Symfony\Component\Messenger\Tests\Fixtures\SecondMessage' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php index cab5efe30a631..6a1c729fd460b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php @@ -3,8 +3,8 @@ $container->loadFromExtension('framework', [ 'serializer' => true, 'messenger' => [ - 'serializer' => [ - 'id' => 'messenger.transport.symfony_serializer', + 'default_serializer' => 'messenger.transport.symfony_serializer', + 'symfony_serializer' => [ 'format' => 'csv', 'context' => ['enable_max_depth' => true], ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_no_serializer.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_no_serializer.php deleted file mode 100644 index 7580c3c1e5751..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport_no_serializer.php +++ /dev/null @@ -1,13 +0,0 @@ -loadFromExtension('framework', [ - 'serializer' => [ - 'enabled' => false, - ], - 'messenger' => [ - 'serializer' => 'messenger.transport.symfony_serializer', - 'transports' => [ - 'default' => 'amqp://localhost/%2f/messages', - ], - ], -]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php index fd4b6feee71b2..a326c505e62b2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php @@ -3,12 +3,13 @@ $container->loadFromExtension('framework', [ 'serializer' => true, 'messenger' => [ - 'serializer' => 'messenger.transport.symfony_serializer', + 'default_serializer' => 'messenger.transport.symfony_serializer', 'transports' => [ 'default' => 'amqp://localhost/%2f/messages', 'customised' => [ 'dsn' => 'amqp://localhost/%2f/messages?exchange_name=exchange_name', 'options' => ['queue' => ['name' => 'Queue']], + 'serializer' => 'messenger.transport.native_php_serializer', ], ], ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_amqp_transport_no_serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_amqp_transport_no_serializer.xml deleted file mode 100644 index b030604466c40..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_amqp_transport_no_serializer.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml index ccb93ba7f0330..6231a7a82e98a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml @@ -8,7 +8,7 @@ - + messenger.transport.symfony_serializer diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml index c58fc9a5d4758..82a85aedcc849 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml @@ -8,11 +8,12 @@ - + messenger.transport.symfony_serializer + true - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_no_serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_no_serializer.xml deleted file mode 100644 index 7471f32e683d8..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport_no_serializer.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml index ceaba5bfc8f6d..70cdb69a8ada4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml @@ -8,9 +8,9 @@ - + messenger.transport.symfony_serializer - + Queue diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml index 0983f2ef321ee..42df49ea4d1cb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml @@ -1,6 +1,6 @@ framework: messenger: - serializer: false + default_serializer: false routing: 'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\FooMessage': ['sender.bar', 'sender.biz'] 'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\BarMessage': 'sender.foo' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_amqp_transport_no_serializer.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_amqp_transport_no_serializer.yml deleted file mode 100644 index e31f3275a479b..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_amqp_transport_no_serializer.yml +++ /dev/null @@ -1,5 +0,0 @@ -framework: - messenger: - serializer: false - transports: - default: 'amqp://localhost/%2f/messages' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml index 1eedbbd03d0e6..4481a16d46033 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml @@ -1,7 +1,7 @@ framework: serializer: true messenger: - serializer: messenger.transport.symfony_serializer + default_serializer: messenger.transport.symfony_serializer routing: 'Symfony\Component\Messenger\Tests\Fixtures\DummyMessage': [amqp, audit] 'Symfony\Component\Messenger\Tests\Fixtures\SecondMessage': diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml index 05b2083e0abdc..8740f37bd6ec1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml @@ -1,8 +1,8 @@ framework: serializer: true messenger: - serializer: - id: messenger.transport.symfony_serializer + default_serializer: messenger.transport.symfony_serializer + symfony_serializer: format: csv context: enable_max_depth: true diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_no_serializer.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_no_serializer.yml deleted file mode 100644 index bde0d3537d57b..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport_no_serializer.yml +++ /dev/null @@ -1,7 +0,0 @@ -framework: - serializer: - enabled: false - messenger: - serializer: messenger.transport.symfony_serializer - transports: - default: 'amqp://localhost/%2f/messages' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml index 6d2c535b72f80..48ff8c6c82364 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml @@ -1,7 +1,7 @@ framework: serializer: true messenger: - serializer: messenger.transport.symfony_serializer + default_serializer: messenger.transport.symfony_serializer transports: default: 'amqp://localhost/%2f/messages' customised: @@ -9,3 +9,4 @@ framework: options: queue: name: Queue + serializer: 'messenger.transport.native_php_serializer' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 6649315f9b0ce..e2cd21cd1dffd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -661,15 +661,18 @@ public function testMessengerTransports() $this->assertTrue($container->hasDefinition('messenger.transport.default')); $this->assertTrue($container->getDefinition('messenger.transport.default')->hasTag('messenger.receiver')); $this->assertEquals([['alias' => 'default']], $container->getDefinition('messenger.transport.default')->getTag('messenger.receiver')); + $transportArguments = $container->getDefinition('messenger.transport.default')->getArguments(); + $this->assertEquals(new Reference('messenger.default_serializer'), $transportArguments[2]); $this->assertTrue($container->hasDefinition('messenger.transport.customised')); $transportFactory = $container->getDefinition('messenger.transport.customised')->getFactory(); $transportArguments = $container->getDefinition('messenger.transport.customised')->getArguments(); $this->assertEquals([new Reference('messenger.transport_factory'), 'createTransport'], $transportFactory); - $this->assertCount(2, $transportArguments); + $this->assertCount(3, $transportArguments); $this->assertSame('amqp://localhost/%2f/messages?exchange_name=exchange_name', $transportArguments[0]); - $this->assertSame(['queue' => ['name' => 'Queue']], $transportArguments[1]); + $this->assertEquals(['queue' => ['name' => 'Queue']], $transportArguments[1]); + $this->assertEquals(new Reference('messenger.transport.native_php_serializer'), $transportArguments[2]); $this->assertTrue($container->hasDefinition('messenger.transport.amqp.factory')); } @@ -693,29 +696,11 @@ public function testMessengerRouting() ], $sendersMapping[DummyMessage::class]->getValues()); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException - * @expectedExceptionMessage The Messenger serializer cannot be enabled as the Serializer support is not available. Try enabling it or running "composer require symfony/serializer-pack". - */ - public function testMessengerTransportConfigurationWithoutSerializer() - { - $this->createContainerFromFile('messenger_transport_no_serializer'); - } - - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\LogicException - * @expectedExceptionMessage The default AMQP transport is not available. Make sure you have installed and enabled the Serializer component. Try enabling it or running "composer require symfony/serializer-pack". - */ - public function testMessengerAMQPTransportConfigurationWithoutSerializer() - { - $this->createContainerFromFile('messenger_amqp_transport_no_serializer'); - } - public function testMessengerTransportConfiguration() { $container = $this->createContainerFromFile('messenger_transport'); - $this->assertSame('messenger.transport.symfony_serializer', (string) $container->getAlias('messenger.transport.serializer')); + $this->assertSame('messenger.transport.symfony_serializer', (string) $container->getAlias('messenger.default_serializer')); $serializerTransportDefinition = $container->getDefinition('messenger.transport.symfony_serializer'); $this->assertSame('csv', $serializerTransportDefinition->getArgument(1)); diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 304790630b759..a2f94de63d406 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -4,10 +4,12 @@ CHANGELOG 4.3.0 ----- + * [BC BREAK] The `TransportFactoryInterface::createTransport()` signature + changed: a required 3rd `SerializerInterface` argument was added. * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to explicitly handle messages synchronously. * Added optional parameter `prefetch_count` in connection configuration, - to setup channel prefetch count + to setup channel prefetch count. * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` and `BusNameStamp` were added, which allow you to add a bus identifier to the `Envelope` then find the correct bus when receiving from diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php index 8e4d66ff3e63a..60d5e806e357c 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportFactoryTest.php @@ -21,9 +21,7 @@ class AmqpTransportFactoryTest extends TestCase { public function testSupportsOnlyAmqpTransports() { - $factory = new AmqpTransportFactory( - $this->getMockBuilder(SerializerInterface::class)->getMock() - ); + $factory = new AmqpTransportFactory(); $this->assertTrue($factory->supports('amqp://localhost', [])); $this->assertFalse($factory->supports('sqs://localhost', [])); @@ -32,12 +30,11 @@ public function testSupportsOnlyAmqpTransports() public function testItCreatesTheTransport() { - $factory = new AmqpTransportFactory( - $serializer = $this->getMockBuilder(SerializerInterface::class)->getMock() - ); + $factory = new AmqpTransportFactory(); + $serializer = $this->createMock(SerializerInterface::class); $expectedTransport = new AmqpTransport(Connection::fromDsn('amqp://localhost', ['foo' => 'bar']), $serializer); - $this->assertEquals($expectedTransport, $factory->createTransport('amqp://localhost', ['foo' => 'bar'])); + $this->assertEquals($expectedTransport, $factory->createTransport('amqp://localhost', ['foo' => 'bar'], $serializer)); } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransportFactory.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransportFactory.php index 28c826891945c..d4293e12070dd 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransportFactory.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransportFactory.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Messenger\Transport\AmqpExt; -use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportFactoryInterface; use Symfony\Component\Messenger\Transport\TransportInterface; @@ -23,16 +22,9 @@ */ class AmqpTransportFactory implements TransportFactoryInterface { - private $serializer; - - public function __construct(SerializerInterface $serializer = null) - { - $this->serializer = $serializer ?? new PhpSerializer(); - } - - public function createTransport(string $dsn, array $options): TransportInterface + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface { - return new AmqpTransport(Connection::fromDsn($dsn, $options), $this->serializer); + return new AmqpTransport(Connection::fromDsn($dsn, $options), $serializer); } public function supports(string $dsn, array $options): bool diff --git a/src/Symfony/Component/Messenger/Transport/TransportFactory.php b/src/Symfony/Component/Messenger/Transport/TransportFactory.php index 6c447f6844555..89833fac3bf5e 100644 --- a/src/Symfony/Component/Messenger/Transport/TransportFactory.php +++ b/src/Symfony/Component/Messenger/Transport/TransportFactory.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Transport; use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; /** * @author Samuel Roze @@ -30,11 +31,11 @@ public function __construct(iterable $factories) $this->factories = $factories; } - public function createTransport(string $dsn, array $options): TransportInterface + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface { foreach ($this->factories as $factory) { if ($factory->supports($dsn, $options)) { - return $factory->createTransport($dsn, $options); + return $factory->createTransport($dsn, $options, $serializer); } } diff --git a/src/Symfony/Component/Messenger/Transport/TransportFactoryInterface.php b/src/Symfony/Component/Messenger/Transport/TransportFactoryInterface.php index 4c1d9539fbd51..7c3c3a65cdb0e 100644 --- a/src/Symfony/Component/Messenger/Transport/TransportFactoryInterface.php +++ b/src/Symfony/Component/Messenger/Transport/TransportFactoryInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Messenger\Transport; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + /** * Creates a Messenger transport. * @@ -20,7 +22,7 @@ */ interface TransportFactoryInterface { - public function createTransport(string $dsn, array $options): TransportInterface; + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface; public function supports(string $dsn, array $options): bool; } From 2df023be46d798bf3e33659a343c949aa21be591 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Sun, 31 Mar 2019 11:44:05 -0400 Subject: [PATCH 330/495] Updating SyncTransport for recent changes + tests --- .../Sync/SyncTransportFactoryTest.php | 28 +++++++++++++++++ .../Transport/Sync/SyncTransportTest.php | 30 +++++++++++++++++++ .../Transport/Sync/SyncTransport.php | 2 +- .../Transport/Sync/SyncTransportFactory.php | 3 +- 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportFactoryTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportTest.php diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportFactoryTest.php new file mode 100644 index 0000000000000..1bef09b2d126d --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportFactoryTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\AmqpExt; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\Sync\SyncTransport; +use Symfony\Component\Messenger\Transport\Sync\SyncTransportFactory; + +class SyncTransportFactoryTest extends TestCase +{ + public function testCreateTransport() + { + $serializer = $this->createMock(SerializerInterface::class); + $factory = new SyncTransportFactory(); + $transport = $factory->createTransport('sync://', [], $serializer); + $this->assertInstanceOf(SyncTransport::class, $transport); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportTest.php new file mode 100644 index 0000000000000..25bc6290d6dff --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Sync/SyncTransportTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Transport\AmqpExt; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Stamp\ForceCallHandlersStamp; +use Symfony\Component\Messenger\Transport\Sync\SyncTransport; + +class SyncTransportTest extends TestCase +{ + public function testSend() + { + $message = new \stdClass(); + $envelope = new Envelope($message); + $transport = new SyncTransport(); + $envelope = $transport->send($envelope); + $this->assertSame($message, $envelope->getMessage()); + $this->assertNotNull($envelope->last(ForceCallHandlersStamp::class)); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php index 6d45e7f6df34c..99bdbc03b3b04 100644 --- a/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php +++ b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransport.php @@ -25,7 +25,7 @@ */ class SyncTransport implements TransportInterface { - public function receive(callable $handler): void + public function get(): iterable { throw new InvalidArgumentException('You cannot receive messages from the SyncTransport.'); } diff --git a/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php index 0eba740813a56..d3a3459e9eb56 100644 --- a/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php +++ b/src/Symfony/Component/Messenger/Transport/Sync/SyncTransportFactory.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Messenger\Transport\Sync; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportFactoryInterface; use Symfony\Component\Messenger\Transport\TransportInterface; @@ -21,7 +22,7 @@ */ class SyncTransportFactory implements TransportFactoryInterface { - public function createTransport(string $dsn, array $options): TransportInterface + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface { return new SyncTransport(); } From 4be827d3ca97b19248a17ca2aec47c32968f5ad4 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 28 Mar 2019 09:00:24 -0400 Subject: [PATCH 331/495] Changing to MessageDecodingFailedException so that invalid messages are rejected --- .../Serialization/PhpSerializerTest.php | 10 ++++++ .../Serialization/SerializerTest.php | 31 +++++++++++++++++++ .../Transport/Serialization/PhpSerializer.php | 3 +- .../Transport/Serialization/Serializer.php | 5 ++- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php index f9cd817f05cf8..1532db5872773 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php @@ -28,6 +28,16 @@ public function testEncodedIsDecodable() $this->assertEquals($envelope, $serializer->decode($serializer->encode($envelope))); } + public function testDecodingFailsWithMissingBodyKey() + { + $this->expectException(MessageDecodingFailedException::class); + $this->expectExceptionMessage('Encoded envelope should have at least a "body".'); + + $serializer = new PhpSerializer(); + + $serializer->decode([]); + } + public function testDecodingFailsWithBadFormat() { $this->expectException(MessageDecodingFailedException::class); diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php index c46b3df15a964..167b60e419556 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/SerializerTest.php @@ -108,6 +108,37 @@ public function testDecodingFailsWithBadFormat() ]); } + /** + * @dataProvider getMissingKeyTests + */ + public function testDecodingFailsWithMissingKeys(array $data, string $expectedMessage) + { + $this->expectException(MessageDecodingFailedException::class); + $this->expectExceptionMessage($expectedMessage); + + $serializer = new Serializer(); + + $serializer->decode($data); + } + + public function getMissingKeyTests() + { + yield 'no_body' => [ + ['headers' => ['type' => 'bar']], + 'Encoded envelope should have at least a "body" and some "headers".', + ]; + + yield 'no_headers' => [ + ['body' => '{}'], + 'Encoded envelope should have at least a "body" and some "headers".', + ]; + + yield 'no_headers_type' => [ + ['body' => '{}', 'headers' => ['foo' => 'bar']], + 'Encoded envelope does not have a "type" header.', + ]; + } + public function testDecodingFailsWithBadClass() { $this->expectException(MessageDecodingFailedException::class); diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php index da232d947a5cb..f9aed0e0d267a 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Messenger\Transport\Serialization; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\InvalidArgumentException; use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; /** @@ -28,7 +27,7 @@ class PhpSerializer implements SerializerInterface public function decode(array $encodedEnvelope): Envelope { if (empty($encodedEnvelope['body'])) { - throw new InvalidArgumentException('Encoded envelope should have at least a "body".'); + throw new MessageDecodingFailedException('Encoded envelope should have at least a "body".'); } return $this->safelyUnserialize($encodedEnvelope['body']); diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php index 8b64d18d9d0db..d076297540b6e 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Messenger\Transport\Serialization; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\InvalidArgumentException; use Symfony\Component\Messenger\Exception\LogicException; use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Stamp\SerializerStamp; @@ -63,11 +62,11 @@ public static function create(): self public function decode(array $encodedEnvelope): Envelope { if (empty($encodedEnvelope['body']) || empty($encodedEnvelope['headers'])) { - throw new InvalidArgumentException('Encoded envelope should have at least a "body" and some "headers".'); + throw new MessageDecodingFailedException('Encoded envelope should have at least a "body" and some "headers".'); } if (empty($encodedEnvelope['headers']['type'])) { - throw new InvalidArgumentException('Encoded envelope does not have a "type" header.'); + throw new MessageDecodingFailedException('Encoded envelope does not have a "type" header.'); } $stamps = $this->decodeStamps($encodedEnvelope); From e861de7e6171d03da09de3e8658cd5b9574ff475 Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Tue, 26 Mar 2019 08:34:20 -0400 Subject: [PATCH 332/495] Allow stamps to be passed directly to MessageBusInterface::dispatch() And changing signature of Envelope::__construct() to accept an array of envelopes --- src/Symfony/Component/Messenger/CHANGELOG.md | 6 +++++ src/Symfony/Component/Messenger/Envelope.php | 18 +++++++++++-- .../Component/Messenger/MessageBus.php | 4 +-- .../Messenger/MessageBusInterface.php | 7 +++-- .../Messenger/RoutableMessageBus.php | 4 +-- .../Messenger/Tests/EnvelopeTest.php | 25 +++++++++++++++--- .../Messenger/Tests/HandleTraitTest.php | 6 ++--- .../Messenger/Tests/MessageBusTest.php | 20 +++++++++++--- .../DispatchAfterCurrentBusMiddlewareTest.php | 8 +++--- .../Middleware/SendMessageMiddlewareTest.php | 2 +- .../Retry/MultiplierRetryStrategyTest.php | 6 ++--- .../Tests/RoutableMessageBusTest.php | 10 ++++--- .../Tests/TraceableMessageBusTest.php | 26 ++++++++++++------- .../Transport/AmqpExt/AmqpReceiverTest.php | 4 +-- .../AmqpExt/Fixtures/long_receiver.php | 5 +--- .../Component/Messenger/Tests/WorkerTest.php | 8 +++--- .../Messenger/TraceableMessageBus.php | 6 ++--- .../Transport/Serialization/Serializer.php | 2 +- 18 files changed, 115 insertions(+), 52 deletions(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index a2f94de63d406..ebf789f8c49f5 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -4,6 +4,12 @@ CHANGELOG 4.3.0 ----- + * [BC BREAK] The `Envelope::__construct()` signature changed: + you can no longer pass an unlimited number of stamps as the second, + third, fourth, arguments etc: stamps are now an array passed to the + second argument. + * [BC BREAK] The `MessageBusInterface::dispatch()` signature changed: + a second argument `array $stamps = []` was added. * [BC BREAK] The `TransportFactoryInterface::createTransport()` signature changed: a required 3rd `SerializerInterface` argument was added. * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to diff --git a/src/Symfony/Component/Messenger/Envelope.php b/src/Symfony/Component/Messenger/Envelope.php index 2e70480886385..0be3355e2ee4d 100644 --- a/src/Symfony/Component/Messenger/Envelope.php +++ b/src/Symfony/Component/Messenger/Envelope.php @@ -26,9 +26,10 @@ final class Envelope private $message; /** - * @param object $message + * @param object $message + * @param StampInterface[] $stamps */ - public function __construct($message, StampInterface ...$stamps) + public function __construct($message, array $stamps = []) { if (!\is_object($message)) { throw new \TypeError(sprintf('Invalid argument provided to "%s()": expected object but got %s.', __METHOD__, \gettype($message))); @@ -40,6 +41,19 @@ public function __construct($message, StampInterface ...$stamps) } } + /** + * Makes sure the message is in an Envelope and adds the given stamps. + * + * @param object|Envelope $message + * @param StampInterface[] $stamps + */ + public static function wrap($message, array $stamps = []): self + { + $envelope = $message instanceof self ? $message : new self($message); + + return $envelope->with(...$stamps); + } + /** * @return Envelope a new Envelope instance with additional stamp */ diff --git a/src/Symfony/Component/Messenger/MessageBus.php b/src/Symfony/Component/Messenger/MessageBus.php index 28fe2d1111152..0698f8e81a250 100644 --- a/src/Symfony/Component/Messenger/MessageBus.php +++ b/src/Symfony/Component/Messenger/MessageBus.php @@ -52,12 +52,12 @@ public function getIterator() /** * {@inheritdoc} */ - public function dispatch($message): Envelope + public function dispatch($message, array $stamps = []): Envelope { if (!\is_object($message)) { throw new \TypeError(sprintf('Invalid argument provided to "%s()": expected object, but got %s.', __METHOD__, \gettype($message))); } - $envelope = $message instanceof Envelope ? $message : new Envelope($message); + $envelope = Envelope::wrap($message, $stamps); $middlewareIterator = $this->middlewareAggregate->getIterator(); while ($middlewareIterator instanceof \IteratorAggregate) { diff --git a/src/Symfony/Component/Messenger/MessageBusInterface.php b/src/Symfony/Component/Messenger/MessageBusInterface.php index 4af88a186e0bc..58b7a631b5307 100644 --- a/src/Symfony/Component/Messenger/MessageBusInterface.php +++ b/src/Symfony/Component/Messenger/MessageBusInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Messenger; +use Symfony\Component\Messenger\Stamp\StampInterface; + /** * @author Samuel Roze * @@ -21,7 +23,8 @@ interface MessageBusInterface /** * Dispatches the given message. * - * @param object|Envelope $message The message or the message pre-wrapped in an envelope + * @param object|Envelope $message The message or the message pre-wrapped in an envelope + * @param StampInterface[] $stamps */ - public function dispatch($message): Envelope; + public function dispatch($message, array $stamps = []): Envelope; } diff --git a/src/Symfony/Component/Messenger/RoutableMessageBus.php b/src/Symfony/Component/Messenger/RoutableMessageBus.php index 3b1aba9751cc9..aa5421eeb7b1c 100644 --- a/src/Symfony/Component/Messenger/RoutableMessageBus.php +++ b/src/Symfony/Component/Messenger/RoutableMessageBus.php @@ -37,7 +37,7 @@ public function __construct(ContainerInterface $busLocator) $this->busLocator = $busLocator; } - public function dispatch($envelope): Envelope + public function dispatch($envelope, array $stamps = []): Envelope { if (!$envelope instanceof Envelope) { throw new InvalidArgumentException('Messages passed to RoutableMessageBus::dispatch() must be inside an Envelope'); @@ -53,6 +53,6 @@ public function dispatch($envelope): Envelope throw new InvalidArgumentException(sprintf('Invalid bus name "%s" on BusNameStamp.', $busNameStamp->getBusName())); } - return $this->busLocator->get($busNameStamp->getBusName())->dispatch($envelope); + return $this->busLocator->get($busNameStamp->getBusName())->dispatch($envelope, $stamps); } } diff --git a/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php b/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php index 04b99d9141a0c..3fb24ce2e8130 100644 --- a/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php +++ b/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php @@ -26,7 +26,7 @@ class EnvelopeTest extends TestCase public function testConstruct() { $receivedStamp = new ReceivedStamp(); - $envelope = new Envelope($dummy = new DummyMessage('dummy'), $receivedStamp); + $envelope = new Envelope($dummy = new DummyMessage('dummy'), [$receivedStamp]); $this->assertSame($dummy, $envelope->getMessage()); $this->assertArrayHasKey(ReceivedStamp::class, $stamps = $envelope->all()); @@ -42,7 +42,7 @@ public function testWithReturnsNewInstance() public function testWithoutAll() { - $envelope = new Envelope(new DummyMessage('dummy'), new ReceivedStamp(), new ReceivedStamp(), new DelayStamp(5000)); + $envelope = new Envelope(new DummyMessage('dummy'), [new ReceivedStamp(), new ReceivedStamp(), new DelayStamp(5000)]); $envelope = $envelope->withoutAll(ReceivedStamp::class); @@ -53,7 +53,7 @@ public function testWithoutAll() public function testLast() { $receivedStamp = new ReceivedStamp(); - $envelope = new Envelope($dummy = new DummyMessage('dummy'), $receivedStamp); + $envelope = new Envelope($dummy = new DummyMessage('dummy'), [$receivedStamp]); $this->assertSame($receivedStamp, $envelope->last(ReceivedStamp::class)); $this->assertNull($envelope->last(ValidationStamp::class)); @@ -72,4 +72,23 @@ public function testAll() $this->assertArrayHasKey(ValidationStamp::class, $stamps); $this->assertSame($validationStamp, $stamps[ValidationStamp::class][0]); } + + public function testWrapWithMessage() + { + $message = new \stdClass(); + $stamp = new ReceivedStamp(); + $envelope = Envelope::wrap($message, [$stamp]); + + $this->assertSame($message, $envelope->getMessage()); + $this->assertSame([ReceivedStamp::class => [$stamp]], $envelope->all()); + } + + public function testWrapWithEnvelope() + { + $envelope = new Envelope(new \stdClass(), [new DelayStamp(5)]); + $envelope = Envelope::wrap($envelope, [new ReceivedStamp()]); + + $this->assertCount(1, $envelope->all(DelayStamp::class)); + $this->assertCount(1, $envelope->all(ReceivedStamp::class)); + } } diff --git a/src/Symfony/Component/Messenger/Tests/HandleTraitTest.php b/src/Symfony/Component/Messenger/Tests/HandleTraitTest.php index a4dbc2de99e44..30d8b0a9766f6 100644 --- a/src/Symfony/Component/Messenger/Tests/HandleTraitTest.php +++ b/src/Symfony/Component/Messenger/Tests/HandleTraitTest.php @@ -31,7 +31,7 @@ public function testHandleReturnsHandledStampResult() $query = new DummyMessage('Hello'); $bus->expects($this->once())->method('dispatch')->willReturn( - new Envelope($query, new HandledStamp('result', 'DummyHandler::__invoke')) + new Envelope($query, [new HandledStamp('result', 'DummyHandler::__invoke')]) ); $this->assertSame('result', $queryBus->query($query)); @@ -42,7 +42,7 @@ public function testHandleAcceptsEnvelopes() $bus = $this->createMock(MessageBus::class); $queryBus = new TestQueryBus($bus); - $envelope = new Envelope(new DummyMessage('Hello'), new HandledStamp('result', 'DummyHandler::__invoke')); + $envelope = new Envelope(new DummyMessage('Hello'), [new HandledStamp('result', 'DummyHandler::__invoke')]); $bus->expects($this->once())->method('dispatch')->willReturn($envelope); $this->assertSame('result', $queryBus->query($envelope)); @@ -74,7 +74,7 @@ public function testHandleThrowsOnMultipleHandledStamps() $query = new DummyMessage('Hello'); $bus->expects($this->once())->method('dispatch')->willReturn( - new Envelope($query, new HandledStamp('first_result', 'FirstDummyHandler::__invoke'), new HandledStamp('second_result', 'SecondDummyHandler::__invoke', 'dummy_2')) + new Envelope($query, [new HandledStamp('first_result', 'FirstDummyHandler::__invoke'), new HandledStamp('second_result', 'SecondDummyHandler::__invoke', 'dummy_2')]) ); $queryBus->query($query); diff --git a/src/Symfony/Component/Messenger/Tests/MessageBusTest.php b/src/Symfony/Component/Messenger/Tests/MessageBusTest.php index 1d56d1010425e..b00e2a693ad5c 100644 --- a/src/Symfony/Component/Messenger/Tests/MessageBusTest.php +++ b/src/Symfony/Component/Messenger/Tests/MessageBusTest.php @@ -16,6 +16,8 @@ use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Stamp\BusNameStamp; +use Symfony\Component\Messenger\Stamp\DelayStamp; use Symfony\Component\Messenger\Stamp\ReceivedStamp; use Symfony\Component\Messenger\Tests\Fixtures\AnEnvelopeStamp; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; @@ -69,7 +71,7 @@ public function testItCallsMiddleware() public function testThatAMiddlewareCanAddSomeStampsToTheEnvelope() { $message = new DummyMessage('Hello'); - $envelope = new Envelope($message, new ReceivedStamp()); + $envelope = new Envelope($message, [new ReceivedStamp()]); $envelopeWithAnotherStamp = $envelope->with(new AnEnvelopeStamp()); $firstMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); @@ -107,10 +109,10 @@ public function testThatAMiddlewareCanAddSomeStampsToTheEnvelope() public function testThatAMiddlewareCanUpdateTheMessageWhileKeepingTheEnvelopeStamps() { $message = new DummyMessage('Hello'); - $envelope = new Envelope($message, ...$stamps = [new ReceivedStamp()]); + $envelope = new Envelope($message, $stamps = [new ReceivedStamp()]); $changedMessage = new DummyMessage('Changed'); - $expectedEnvelope = new Envelope($changedMessage, ...$stamps); + $expectedEnvelope = new Envelope($changedMessage, $stamps); $firstMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); $firstMiddleware->expects($this->once()) @@ -134,4 +136,16 @@ public function testThatAMiddlewareCanUpdateTheMessageWhileKeepingTheEnvelopeSta $bus->dispatch($envelope); } + + public function testItAddsTheStamps() + { + $finalEnvelope = (new MessageBus())->dispatch(new \stdClass(), [new DelayStamp(5), new BusNameStamp('bar')]); + $this->assertCount(2, $finalEnvelope->all()); + } + + public function testItAddsTheStampsToEnvelope() + { + $finalEnvelope = (new MessageBus())->dispatch(new Envelope(new \stdClass()), [new DelayStamp(5), new BusNameStamp('bar')]); + $this->assertCount(2, $finalEnvelope->all()); + } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php index 6b6d99c4e11fb..f2217affda0c1 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/DispatchAfterCurrentBusMiddlewareTest.php @@ -44,8 +44,8 @@ public function testEventsInNewTransactionAreHandledAfterMainMessage() $messageBus = new MessageBus([ $middleware, new DispatchingMiddleware($eventBus, [ - new Envelope($firstEvent, new DispatchAfterCurrentBusStamp()), - new Envelope($secondEvent, new DispatchAfterCurrentBusStamp()), + new Envelope($firstEvent, [new DispatchAfterCurrentBusStamp()]), + new Envelope($secondEvent, [new DispatchAfterCurrentBusStamp()]), $thirdEvent, // Not in a new transaction ]), $handlingMiddleware, @@ -80,8 +80,8 @@ public function testThrowingEventsHandlingWontStopExecution() $messageBus = new MessageBus([ $middleware, new DispatchingMiddleware($eventBus, [ - new Envelope($firstEvent, new DispatchAfterCurrentBusStamp()), - new Envelope($secondEvent, new DispatchAfterCurrentBusStamp()), + new Envelope($firstEvent, [new DispatchAfterCurrentBusStamp()]), + new Envelope($secondEvent, [new DispatchAfterCurrentBusStamp()]), ]), $handlingMiddleware, ]); diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php index 92e48bc78204d..7e84f18f8fcf3 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/SendMessageMiddlewareTest.php @@ -86,7 +86,7 @@ public function testItSendsTheMessageToMultipleSenders() public function testItSendsToOnlyOneSenderOnRedelivery() { - $envelope = new Envelope(new DummyMessage('Hey'), new RedeliveryStamp(5, 'bar')); + $envelope = new Envelope(new DummyMessage('Hey'), [new RedeliveryStamp(5, 'bar')]); // even with a ForceCallHandlersStamp, the next middleware won't be called $envelope = $envelope->with(new ForceCallHandlersStamp()); $sender = $this->getMockBuilder(SenderInterface::class)->getMock(); diff --git a/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php b/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php index 6ff4d9af276d9..a6c8c8352404b 100644 --- a/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php +++ b/src/Symfony/Component/Messenger/Tests/Retry/MultiplierRetryStrategyTest.php @@ -21,7 +21,7 @@ class MultiplierRetryStrategyTest extends TestCase public function testIsRetryable() { $strategy = new MultiplierRetryStrategy(3); - $envelope = new Envelope(new \stdClass(), new RedeliveryStamp(0, 'sender_alias')); + $envelope = new Envelope(new \stdClass(), [new RedeliveryStamp(0, 'sender_alias')]); $this->assertTrue($strategy->isRetryable($envelope)); } @@ -29,7 +29,7 @@ public function testIsRetryable() public function testIsNotRetryable() { $strategy = new MultiplierRetryStrategy(3); - $envelope = new Envelope(new \stdClass(), new RedeliveryStamp(3, 'sender_alias')); + $envelope = new Envelope(new \stdClass(), [new RedeliveryStamp(3, 'sender_alias')]); $this->assertFalse($strategy->isRetryable($envelope)); } @@ -48,7 +48,7 @@ public function testIsRetryableWithNoStamp() public function testGetWaitTime(int $delay, int $multiplier, int $maxDelay, int $previousRetries, int $expectedDelay) { $strategy = new MultiplierRetryStrategy(10, $delay, $multiplier, $maxDelay); - $envelope = new Envelope(new \stdClass(), new RedeliveryStamp($previousRetries, 'sender_alias')); + $envelope = new Envelope(new \stdClass(), [new RedeliveryStamp($previousRetries, 'sender_alias')]); $this->assertSame($expectedDelay, $strategy->getWaitingTime($envelope)); } diff --git a/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php b/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php index 517a57914cc85..2f6d9fed33fbf 100644 --- a/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php +++ b/src/Symfony/Component/Messenger/Tests/RoutableMessageBusTest.php @@ -18,12 +18,13 @@ use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\RoutableMessageBus; use Symfony\Component\Messenger\Stamp\BusNameStamp; +use Symfony\Component\Messenger\Stamp\DelayStamp; class RoutableMessageBusTest extends TestCase { public function testItRoutesToTheCorrectBus() { - $envelope = new Envelope(new \stdClass(), new BusNameStamp('foo_bus')); + $envelope = new Envelope(new \stdClass(), [new BusNameStamp('foo_bus')]); $bus1 = $this->createMock(MessageBusInterface::class); $bus2 = $this->createMock(MessageBusInterface::class); @@ -32,11 +33,12 @@ public function testItRoutesToTheCorrectBus() $container->expects($this->once())->method('has')->with('foo_bus')->willReturn(true); $container->expects($this->once())->method('get')->will($this->returnValue($bus2)); + $stamp = new DelayStamp(5); $bus1->expects($this->never())->method('dispatch'); - $bus2->expects($this->once())->method('dispatch')->with($envelope)->willReturn($envelope); + $bus2->expects($this->once())->method('dispatch')->with($envelope, [$stamp])->willReturn($envelope); $routableBus = new RoutableMessageBus($container); - $this->assertSame($envelope, $routableBus->dispatch($envelope)); + $this->assertSame($envelope, $routableBus->dispatch($envelope, [$stamp])); } public function testItExceptionOnMissingStamp() @@ -58,7 +60,7 @@ public function testItExceptionOnBusNotFound() $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid bus name'); - $envelope = new Envelope(new \stdClass(), new BusNameStamp('foo_bus')); + $envelope = new Envelope(new \stdClass(), [new BusNameStamp('foo_bus')]); $container = $this->createMock(ContainerInterface::class); $container->expects($this->once())->method('has')->willReturn(false); diff --git a/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php b/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php index 23e47d28d0d21..13bf06b012517 100644 --- a/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php +++ b/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\MessageBusInterface; +use Symfony\Component\Messenger\Stamp\DelayStamp; use Symfony\Component\Messenger\Tests\Fixtures\AnEnvelopeStamp; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\TraceableMessageBus; @@ -24,22 +25,25 @@ public function testItTracesDispatch() { $message = new DummyMessage('Hello'); + $stamp = new DelayStamp(5); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); - $bus->expects($this->once())->method('dispatch')->with($message)->willReturn(new Envelope($message)); + $bus->expects($this->once())->method('dispatch')->with($message, [$stamp])->willReturn(new Envelope($message)); $traceableBus = new TraceableMessageBus($bus); $line = __LINE__ + 1; - $traceableBus->dispatch($message); + $traceableBus->dispatch($message, [$stamp]); $this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages()); - $this->assertArraySubset([ + $actualTracedMessage = $tracedMessages[0]; + unset($actualTracedMessage['callTime']); // don't check, too variable + $this->assertEquals([ 'message' => $message, - 'stamps' => [], + 'stamps' => [[$stamp]], 'caller' => [ 'name' => 'TraceableMessageBusTest.php', 'file' => __FILE__, 'line' => $line, ], - ], $tracedMessages[0], true); + ], $actualTracedMessage); } public function testItTracesDispatchWithEnvelope() @@ -54,7 +58,9 @@ public function testItTracesDispatchWithEnvelope() $line = __LINE__ + 1; $traceableBus->dispatch($envelope); $this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages()); - $this->assertArraySubset([ + $actualTracedMessage = $tracedMessages[0]; + unset($actualTracedMessage['callTime']); // don't check, too variable + $this->assertEquals([ 'message' => $message, 'stamps' => [[$stamp]], 'caller' => [ @@ -62,7 +68,7 @@ public function testItTracesDispatchWithEnvelope() 'file' => __FILE__, 'line' => $line, ], - ], $tracedMessages[0], true); + ], $actualTracedMessage); } public function testItTracesExceptions() @@ -82,7 +88,9 @@ public function testItTracesExceptions() } $this->assertCount(1, $tracedMessages = $traceableBus->getDispatchedMessages()); - $this->assertArraySubset([ + $actualTracedMessage = $tracedMessages[0]; + unset($actualTracedMessage['callTime']); // don't check, too variable + $this->assertEquals([ 'message' => $message, 'exception' => $exception, 'stamps' => [], @@ -91,6 +99,6 @@ public function testItTracesExceptions() 'file' => __FILE__, 'line' => $line, ], - ], $tracedMessages[0], true); + ], $actualTracedMessage); } } diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php index d27ddb9cd26a9..7a20fd2042799 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php @@ -56,7 +56,7 @@ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() $connection->method('ack')->with($amqpEnvelope)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->ack(new Envelope(new \stdClass(), new AmqpReceivedStamp($amqpEnvelope))); + $receiver->ack(new Envelope(new \stdClass(), [new AmqpReceivedStamp($amqpEnvelope)])); } /** @@ -71,7 +71,7 @@ public function testItThrowsATransportExceptionIfItCannotRejectMessage() $connection->method('nack')->with($amqpEnvelope, AMQP_NOPARAM)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->reject(new Envelope(new \stdClass(), new AmqpReceivedStamp($amqpEnvelope))); + $receiver->reject(new Envelope(new \stdClass(), [new AmqpReceivedStamp($amqpEnvelope)])); } private function createAMQPEnvelope() diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php index f51412093451c..cb6b718773d91 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php @@ -12,13 +12,10 @@ require_once $autoload; -use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Retry\MultiplierRetryStrategy; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\Serializer; -use Symfony\Component\Messenger\Worker; use Symfony\Component\Serializer as SerializerComponent; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; @@ -33,7 +30,7 @@ $retryStrategy = new MultiplierRetryStrategy(3, 0); $worker = new Worker(['the_receiver' => $receiver], new class() implements MessageBusInterface { - public function dispatch($envelope): Envelope + public function dispatch($envelope, array $stamps = []): Envelope { echo 'Get envelope with message: '.\get_class($envelope->getMessage())."\n"; echo sprintf("with stamps: %s\n", json_encode(array_keys($envelope->all()), JSON_PRETTY_PRINT)); diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php index b5c6a6557b2cd..6cc5632ec71c5 100644 --- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php +++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php @@ -43,8 +43,8 @@ public function testWorkerDispatchTheReceivedMessage() $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); - $bus->expects($this->at(0))->method('dispatch')->with($envelope = new Envelope($apiMessage, new ReceivedStamp()))->willReturn($envelope); - $bus->expects($this->at(1))->method('dispatch')->with($envelope = new Envelope($ipaMessage, new ReceivedStamp()))->willReturn($envelope); + $bus->expects($this->at(0))->method('dispatch')->with($envelope = new Envelope($apiMessage, [new ReceivedStamp()]))->willReturn($envelope); + $bus->expects($this->at(1))->method('dispatch')->with($envelope = new Envelope($ipaMessage, [new ReceivedStamp()]))->willReturn($envelope); $worker = new Worker([$receiver], $bus); $worker->run([], function (?Envelope $envelope) use ($worker) { @@ -78,7 +78,7 @@ public function testWorkerDoesNotWrapMessagesAlreadyWrappedWithReceivedMessage() public function testDispatchCausesRetry() { $receiver = new DummyReceiver([ - [new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))], + [new Envelope(new DummyMessage('Hello'), [new SentStamp('Some\Sender', 'sender_alias')])], ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); @@ -117,7 +117,7 @@ public function testDispatchCausesRetry() public function testDispatchCausesRejectWhenNoRetry() { $receiver = new DummyReceiver([ - [new Envelope(new DummyMessage('Hello'), new SentStamp('Some\Sender', 'sender_alias'))], + [new Envelope(new DummyMessage('Hello'), [new SentStamp('Some\Sender', 'sender_alias')])], ]); $bus = $this->getMockBuilder(MessageBusInterface::class)->getMock(); diff --git a/src/Symfony/Component/Messenger/TraceableMessageBus.php b/src/Symfony/Component/Messenger/TraceableMessageBus.php index 1d910d4540a1c..f370c6d8aa028 100644 --- a/src/Symfony/Component/Messenger/TraceableMessageBus.php +++ b/src/Symfony/Component/Messenger/TraceableMessageBus.php @@ -29,9 +29,9 @@ public function __construct(MessageBusInterface $decoratedBus) /** * {@inheritdoc} */ - public function dispatch($message): Envelope + public function dispatch($message, array $stamps = []): Envelope { - $envelope = $message instanceof Envelope ? $message : new Envelope($message); + $envelope = Envelope::wrap($message, $stamps); $context = [ 'stamps' => array_values($envelope->all()), 'message' => $envelope->getMessage(), @@ -40,7 +40,7 @@ public function dispatch($message): Envelope ]; try { - return $this->decoratedBus->dispatch($message); + return $this->decoratedBus->dispatch($message, $stamps); } catch (\Throwable $e) { $context['exception'] = $e; diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php index 8b64d18d9d0db..d80c5b0ce20ca 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/Serializer.php @@ -83,7 +83,7 @@ public function decode(array $encodedEnvelope): Envelope throw new MessageDecodingFailedException(sprintf('Could not decode message: %s.', $e->getMessage()), $e->getCode(), $e); } - return new Envelope($message, ...$stamps); + return new Envelope($message, $stamps); } /** From e897e6cc4edb8d8ee4b1829eb0b3c1ac6c32cfd7 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sun, 31 Mar 2019 17:26:00 +0100 Subject: [PATCH 333/495] Add missing word in CHANGELOG --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index af0d0005b5376..62f5be0a96ded 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -60,7 +60,7 @@ CHANGELOG and queues by default. Previously, this was done when in "debug" mode only. Pass the `auto_setup` connection option to control this. * Added a `SetupTransportsCommand` command to setup the transports - * Added a Doctrine transport. For example, the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) + * Added a Doctrine transport. For example, use the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) 4.2.0 ----- From fd4146c7682f3256d01282efbd62fa008b65e765 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sun, 31 Mar 2019 17:34:04 +0100 Subject: [PATCH 334/495] Add back missing `use`s --- .../Tests/Transport/AmqpExt/Fixtures/long_receiver.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php index cb6b718773d91..3f852e44feb15 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/Fixtures/long_receiver.php @@ -12,10 +12,13 @@ require_once $autoload; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Messenger\Retry\MultiplierRetryStrategy; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\Serializer; +use Symfony\Component\Messenger\Worker; use Symfony\Component\Serializer as SerializerComponent; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; From 58971627f5e03a667d682bb2cf5f9c53f4d3eded Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Thu, 28 Mar 2019 11:34:48 -0400 Subject: [PATCH 335/495] [Messenger] New messenger:stop-workers Command --- .../Resources/config/cache.xml | 4 + .../Resources/config/console.xml | 8 ++ src/Symfony/Component/Messenger/CHANGELOG.md | 2 + .../Command/ConsumeMessagesCommand.php | 14 ++++ .../Messenger/Command/StopWorkersCommand.php | 73 +++++++++++++++++++ .../Tests/Command/StopWorkersCommandTest.php | 35 +++++++++ .../StopWhenRestartSignalIsReceivedTest.php | 71 ++++++++++++++++++ .../StopWhenRestartSignalIsReceived.php | 72 ++++++++++++++++++ 8 files changed, 279 insertions(+) create mode 100644 src/Symfony/Component/Messenger/Command/StopWorkersCommand.php create mode 100644 src/Symfony/Component/Messenger/Tests/Command/StopWorkersCommandTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Worker/StopWhenRestartSignalIsReceivedTest.php create mode 100644 src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml index a3a5c812ef5b1..4fd8b70fac7aa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml @@ -36,6 +36,10 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 6ae1cb8cc306d..f753b214192da 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -83,6 +83,9 @@ + + + @@ -101,6 +104,11 @@ + + + + + diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index a2f94de63d406..b2bc787558b57 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * Added new `messenger:stop-workers` command that sends a signal + to stop all `messenger:consume` workers. * [BC BREAK] The `TransportFactoryInterface::createTransport()` signature changed: a required 3rd `SerializerInterface` argument was added. * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index bd3a7a177c6c3..dea3a204daf2b 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Messenger\Command; +use Psr\Cache\CacheItemPoolInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Command\Command; @@ -25,6 +26,7 @@ use Symfony\Component\Messenger\Worker; use Symfony\Component\Messenger\Worker\StopWhenMemoryUsageIsExceededWorker; use Symfony\Component\Messenger\Worker\StopWhenMessageCountIsExceededWorker; +use Symfony\Component\Messenger\Worker\StopWhenRestartSignalIsReceived; use Symfony\Component\Messenger\Worker\StopWhenTimeLimitIsReachedWorker; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; @@ -43,6 +45,8 @@ class ConsumeMessagesCommand extends Command private $receiverNames; private $retryStrategyLocator; private $eventDispatcher; + /** @var CacheItemPoolInterface|null */ + private $restartSignalCachePool; public function __construct(ContainerInterface $busLocator, ContainerInterface $receiverLocator, LoggerInterface $logger = null, array $receiverNames = [], /* ContainerInterface */ $retryStrategyLocator = null, EventDispatcherInterface $eventDispatcher = null) { @@ -62,6 +66,11 @@ public function __construct(ContainerInterface $busLocator, ContainerInterface $ parent::__construct(); } + public function setCachePoolForRestartSignal(CacheItemPoolInterface $restartSignalCachePool) + { + $this->restartSignalCachePool = $restartSignalCachePool; + } + /** * {@inheritdoc} */ @@ -190,6 +199,11 @@ protected function execute(InputInterface $input, OutputInterface $output): void $worker = new StopWhenTimeLimitIsReachedWorker($worker, $timeLimit, $this->logger); } + if (null !== $this->restartSignalCachePool) { + $stopsWhen[] = 'received a stop signal via the messenger:stop-workers command'; + $worker = new StopWhenRestartSignalIsReceived($worker, $this->restartSignalCachePool, $this->logger); + } + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); $io->success(sprintf('Consuming messages from transport%s "%s".', \count($receivers) > 0 ? 's' : '', implode(', ', $receiverNames))); diff --git a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php new file mode 100644 index 0000000000000..afb2ce0dd654b --- /dev/null +++ b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Command; + +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\Messenger\Worker\StopWhenRestartSignalIsReceived; + +/** + * @author Ryan Weaver + * + * @experimental in 4.3 + */ +class StopWorkersCommand extends Command +{ + protected static $defaultName = 'messenger:stop-workers'; + + private $restartSignalCachePool; + + public function __construct(CacheItemPoolInterface $restartSignalCachePool) + { + $this->restartSignalCachePool = $restartSignalCachePool; + + parent::__construct(); + } + + /** + * {@inheritdoc} + */ + protected function configure(): void + { + $this + ->setDefinition([]) + ->setDescription('Stops workers after their current message') + ->setHelp(<<<'EOF' +The %command.name% command sends a signal to stop any messenger:consume processes that are running. + + php %command.full_name% + +Each worker command will finish the message they are currently processing +and then exit. Worker commands are *not* automatically restarted: that +should be handled by something like supervisord. +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output): void + { + $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); + + $cacheItem = $this->restartSignalCachePool->getItem(StopWhenRestartSignalIsReceived::RESTART_REQUESTED_TIMESTAMP_KEY); + $cacheItem->set(time()); + $this->restartSignalCachePool->save($cacheItem); + + $io->success('Signal successfully sent to stop any running workers.'); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Command/StopWorkersCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/StopWorkersCommandTest.php new file mode 100644 index 0000000000000..fd5ddae244b70 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Command/StopWorkersCommandTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Command; + +use PHPUnit\Framework\TestCase; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Messenger\Command\StopWorkersCommand; + +class StopWorkersCommandTest extends TestCase +{ + public function testItSetsCacheItem() + { + $cachePool = $this->createMock(CacheItemPoolInterface::class); + $cacheItem = $this->createMock(CacheItemInterface::class); + $cacheItem->expects($this->once())->method('set'); + $cachePool->expects($this->once())->method('getItem')->willReturn($cacheItem); + $cachePool->expects($this->once())->method('save')->with($cacheItem); + + $command = new StopWorkersCommand($cachePool); + + $tester = new CommandTester($command); + $tester->execute([]); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Worker/StopWhenRestartSignalIsReceivedTest.php b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenRestartSignalIsReceivedTest.php new file mode 100644 index 0000000000000..a5a4937fd0351 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Worker/StopWhenRestartSignalIsReceivedTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Worker; + +use PHPUnit\Framework\TestCase; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Tests\Fixtures\DummyWorker; +use Symfony\Component\Messenger\Worker\StopWhenRestartSignalIsReceived; + +/** + * @group time-sensitive + */ +class StopWhenRestartSignalIsReceivedTest extends TestCase +{ + /** + * @dataProvider restartTimeProvider + */ + public function testWorkerStopsWhenMemoryLimitExceeded(?int $lastRestartTimeOffset, bool $shouldStop) + { + $decoratedWorker = new DummyWorker([ + new Envelope(new \stdClass()), + ]); + + $cachePool = $this->createMock(CacheItemPoolInterface::class); + $cacheItem = $this->createMock(CacheItemInterface::class); + $cacheItem->expects($this->once())->method('isHIt')->willReturn(true); + $cacheItem->expects($this->once())->method('get')->willReturn(null === $lastRestartTimeOffset ? null : time() + $lastRestartTimeOffset); + $cachePool->expects($this->once())->method('getItem')->willReturn($cacheItem); + + $stopOnSignalWorker = new StopWhenRestartSignalIsReceived($decoratedWorker, $cachePool); + $stopOnSignalWorker->run(); + + $this->assertSame($shouldStop, $decoratedWorker->isStopped()); + } + + public function restartTimeProvider() + { + yield [null, false]; // no cached restart time, do not restart + yield [+10, true]; // 10 seconds after starting, a restart was requested + yield [-10, false]; // a restart was requested, but 10 seconds before we started + } + + public function testWorkerDoesNotStopIfRestartNotInCache() + { + $decoratedWorker = new DummyWorker([ + new Envelope(new \stdClass()), + ]); + + $cachePool = $this->createMock(CacheItemPoolInterface::class); + $cacheItem = $this->createMock(CacheItemInterface::class); + $cacheItem->expects($this->once())->method('isHIt')->willReturn(false); + $cacheItem->expects($this->never())->method('get'); + $cachePool->expects($this->once())->method('getItem')->willReturn($cacheItem); + + $stopOnSignalWorker = new StopWhenRestartSignalIsReceived($decoratedWorker, $cachePool); + $stopOnSignalWorker->run(); + + $this->assertFalse($decoratedWorker->isStopped()); + } +} diff --git a/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php b/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php new file mode 100644 index 0000000000000..63f6ea04d67bb --- /dev/null +++ b/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Worker; + +use Psr\Cache\CacheItemPoolInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\WorkerInterface; + +/** + * @author Ryan Weaver + * + * @experimental in 4.3 + */ +class StopWhenRestartSignalIsReceived implements WorkerInterface +{ + public const RESTART_REQUESTED_TIMESTAMP_KEY = 'workers.restart_requested_timestamp'; + + private $decoratedWorker; + private $cachePool; + private $logger; + + public function __construct(WorkerInterface $decoratedWorker, CacheItemPoolInterface $cachePool, LoggerInterface $logger = null) + { + $this->decoratedWorker = $decoratedWorker; + $this->cachePool = $cachePool; + $this->logger = $logger; + } + + public function run(array $options = [], callable $onHandledCallback = null): void + { + $workerStartedTimestamp = time(); + + $this->decoratedWorker->run($options, function (?Envelope $envelope) use ($onHandledCallback, $workerStartedTimestamp) { + if (null !== $onHandledCallback) { + $onHandledCallback($envelope); + } + + if ($this->shouldRestart($workerStartedTimestamp)) { + $this->stop(); + if (null !== $this->logger) { + $this->logger->info('Worker stopped because a restart was requested.'); + } + } + }); + } + + public function stop(): void + { + $this->decoratedWorker->stop(); + } + + private function shouldRestart(int $workerStartedAt) + { + $cacheItem = $this->cachePool->getItem(self::RESTART_REQUESTED_TIMESTAMP_KEY); + if (!$cacheItem->isHit()) { + // no restart has ever been scheduled + return false; + } + + return $workerStartedAt < $cacheItem->get(); + } +} From 75e3355da588fb64b3855ef61ce708b67ad48c3b Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sun, 31 Mar 2019 17:50:14 +0100 Subject: [PATCH 336/495] Fix the Doctrine transport to use the new interface --- .../Doctrine/DoctrineTransportFactoryTest.php | 23 +++++++------------ .../Transport/Doctrine/DoctrineTransport.php | 5 ++-- .../Doctrine/DoctrineTransportFactory.php | 9 +++----- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php index 104de47dcd16b..03780ad1e7a8d 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportFactoryTest.php @@ -16,15 +16,14 @@ use Symfony\Component\Messenger\Transport\Doctrine\Connection; use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport; use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransportFactory; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; class DoctrineTransportFactoryTest extends TestCase { public function testSupports() { $factory = new DoctrineTransportFactory( - $this->getMockBuilder(RegistryInterface::class)->getMock(), - null, - false + $this->getMockBuilder(RegistryInterface::class)->getMock() ); $this->assertTrue($factory->supports('doctrine://default', [])); @@ -41,14 +40,12 @@ public function testCreateTransport() ->method('getConnection') ->willReturn($connection); - $factory = new DoctrineTransportFactory( - $registry, - null - ); + $factory = new DoctrineTransportFactory($registry); + $serializer = $this->createMock(SerializerInterface::class); $this->assertEquals( - new DoctrineTransport(new Connection(Connection::buildConfiguration('doctrine://default'), $connection), null), - $factory->createTransport('doctrine://default', []) + new DoctrineTransport(new Connection(Connection::buildConfiguration('doctrine://default'), $connection), $serializer), + $factory->createTransport('doctrine://default', [], $serializer) ); } @@ -65,11 +62,7 @@ public function testCreateTransportMustThrowAnExceptionIfManagerIsNotFound() throw new \InvalidArgumentException(); })); - $factory = new DoctrineTransportFactory( - $registry, - null - ); - - $factory->createTransport('doctrine://default', []); + $factory = new DoctrineTransportFactory($registry); + $factory->createTransport('doctrine://default', [], $this->createMock(SerializerInterface::class)); } } diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php index 97c2a0a629557..b9c1d8ee8c00b 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Messenger\Transport\Doctrine; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\SetupableTransportInterface; use Symfony\Component\Messenger\Transport\TransportInterface; @@ -29,10 +28,10 @@ class DoctrineTransport implements TransportInterface, SetupableTransportInterfa private $receiver; private $sender; - public function __construct(Connection $connection, SerializerInterface $serializer = null) + public function __construct(Connection $connection, SerializerInterface $serializer) { $this->connection = $connection; - $this->serializer = $serializer ?? new PhpSerializer(); + $this->serializer = $serializer; } /** diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php index 74f37933904be..a5ee99464221d 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransportFactory.php @@ -13,7 +13,6 @@ use Symfony\Bridge\Doctrine\RegistryInterface; use Symfony\Component\Messenger\Exception\TransportException; -use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\TransportFactoryInterface; use Symfony\Component\Messenger\Transport\TransportInterface; @@ -26,15 +25,13 @@ class DoctrineTransportFactory implements TransportFactoryInterface { private $registry; - private $serializer; - public function __construct(RegistryInterface $registry, SerializerInterface $serializer = null) + public function __construct(RegistryInterface $registry) { $this->registry = $registry; - $this->serializer = $serializer ?? new PhpSerializer(); } - public function createTransport(string $dsn, array $options): TransportInterface + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface { $configuration = Connection::buildConfiguration($dsn, $options); @@ -46,7 +43,7 @@ public function createTransport(string $dsn, array $options): TransportInterface $connection = new Connection($configuration, $driverConnection); - return new DoctrineTransport($connection, $this->serializer); + return new DoctrineTransport($connection, $serializer); } public function supports(string $dsn, array $options): bool From a3de9020c8d0ae349a00ca4fe0c1497ae89b990f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 31 Mar 2019 19:00:04 +0200 Subject: [PATCH 337/495] [Messenger] fix review --- .../Component/Messenger/Command/StopWorkersCommand.php | 2 +- .../Messenger/Worker/StopWhenRestartSignalIsReceived.php | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php index afb2ce0dd654b..0ea9582897a09 100644 --- a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php +++ b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php @@ -65,7 +65,7 @@ protected function execute(InputInterface $input, OutputInterface $output): void $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); $cacheItem = $this->restartSignalCachePool->getItem(StopWhenRestartSignalIsReceived::RESTART_REQUESTED_TIMESTAMP_KEY); - $cacheItem->set(time()); + $cacheItem->set(microtime(true)); $this->restartSignalCachePool->save($cacheItem); $io->success('Signal successfully sent to stop any running workers.'); diff --git a/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php b/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php index 63f6ea04d67bb..29b52c87da91b 100644 --- a/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php +++ b/src/Symfony/Component/Messenger/Worker/StopWhenRestartSignalIsReceived.php @@ -38,14 +38,14 @@ public function __construct(WorkerInterface $decoratedWorker, CacheItemPoolInter public function run(array $options = [], callable $onHandledCallback = null): void { - $workerStartedTimestamp = time(); + $workerStartedAt = microtime(true); - $this->decoratedWorker->run($options, function (?Envelope $envelope) use ($onHandledCallback, $workerStartedTimestamp) { + $this->decoratedWorker->run($options, function (?Envelope $envelope) use ($onHandledCallback, $workerStartedAt) { if (null !== $onHandledCallback) { $onHandledCallback($envelope); } - if ($this->shouldRestart($workerStartedTimestamp)) { + if ($this->shouldRestart($workerStartedAt)) { $this->stop(); if (null !== $this->logger) { $this->logger->info('Worker stopped because a restart was requested.'); @@ -59,9 +59,10 @@ public function stop(): void $this->decoratedWorker->stop(); } - private function shouldRestart(int $workerStartedAt) + private function shouldRestart(float $workerStartedAt) { $cacheItem = $this->cachePool->getItem(self::RESTART_REQUESTED_TIMESTAMP_KEY); + if (!$cacheItem->isHit()) { // no restart has ever been scheduled return false; From 481140037220e47bd8a7c32bafc4d67147ef9f26 Mon Sep 17 00:00:00 2001 From: Vincent Touzet Date: Sun, 31 Mar 2019 19:12:50 +0200 Subject: [PATCH 338/495] [Messenger] Remove unused option in the Doctrine transport --- .../Component/Messenger/Transport/Doctrine/Connection.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 6bf4bd2e32955..ffb1d137798fc 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -33,7 +33,6 @@ class Connection 'table_name' => 'messenger_messages', 'queue_name' => 'default', 'redeliver_timeout' => 3600, - 'loop_sleep' => 200000, 'auto_setup' => true, ]; @@ -46,7 +45,6 @@ class Connection * * connection: name of the Doctrine's entity manager * * queue_name: name of the queue * * redeliver_timeout: Timeout before redeliver messages still in handling state (i.e: delivered_at is not null and message is still in table). Default 3600 - * * loop_sleep: Number of micro seconds to wait for a next message to handle * * auto_setup: Whether the table should be created automatically during send / get. Default : true */ private $configuration = []; @@ -80,7 +78,6 @@ public static function buildConfiguration($dsn, array $options = []) 'table_name' => $options['table_name'] ?? ($query['table_name'] ?? self::DEFAULT_OPTIONS['table_name']), 'queue_name' => $options['queue_name'] ?? ($query['queue_name'] ?? self::DEFAULT_OPTIONS['queue_name']), 'redeliver_timeout' => $options['redeliver_timeout'] ?? ($query['redeliver_timeout'] ?? self::DEFAULT_OPTIONS['redeliver_timeout']), - 'loop_sleep' => $options['loop_sleep'] ?? ($query['loop_sleep'] ?? self::DEFAULT_OPTIONS['loop_sleep']), 'auto_setup' => $options['auto_setup'] ?? ($query['auto_setup'] ?? self::DEFAULT_OPTIONS['auto_setup']), ]; From 01870398eb211fed5dcf91adbbf4215234ab9316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Thu, 27 Sep 2018 18:36:17 +0200 Subject: [PATCH 339/495] [Validator] add number constraints --- src/Symfony/Component/Validator/CHANGELOG.md | 4 + .../Validator/Constraints/Negative.php | 35 ++++++ .../Validator/Constraints/NegativeOrZero.php | 35 ++++++ .../Constraints/NumberConstraintTrait.php | 41 +++++++ .../Validator/Constraints/Positive.php | 35 ++++++ .../Validator/Constraints/PositiveOrZero.php | 35 ++++++ .../Resources/translations/validators.de.xlf | 16 +++ .../Resources/translations/validators.en.xlf | 16 +++ .../Resources/translations/validators.vi.xlf | 16 +++ ...idatorWithPositiveOrZeroConstraintTest.php | 111 +++++++++++++++++ ...hanValidatorWithPositiveConstraintTest.php | 114 ++++++++++++++++++ ...idatorWithNegativeOrZeroConstraintTest.php | 114 ++++++++++++++++++ ...hanValidatorWithNegativeConstraintTest.php | 114 ++++++++++++++++++ 13 files changed, 686 insertions(+) create mode 100644 src/Symfony/Component/Validator/Constraints/Negative.php create mode 100644 src/Symfony/Component/Validator/Constraints/NegativeOrZero.php create mode 100644 src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php create mode 100644 src/Symfony/Component/Validator/Constraints/Positive.php create mode 100644 src/Symfony/Component/Validator/Constraints/PositiveOrZero.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 3ba214dda764b..0a1aac70ed580 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -10,6 +10,10 @@ CHANGELOG * added `Json` constraint * added `Unique` constraint * added a new `normalizer` option to the string constraints and to the `NotBlank` constraint + * added `Positive` constraint + * added `PositiveOrZero` constraint + * added `Negative` constraint + * added `NegativeOrZero` constraint 4.2.0 ----- diff --git a/src/Symfony/Component/Validator/Constraints/Negative.php b/src/Symfony/Component/Validator/Constraints/Negative.php new file mode 100644 index 0000000000000..7dc394a2579a8 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Negative.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class Negative extends LessThan +{ + use NumberConstraintTrait; + + public $message = 'This value should be negative.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return LessThanValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/NegativeOrZero.php b/src/Symfony/Component/Validator/Constraints/NegativeOrZero.php new file mode 100644 index 0000000000000..3b2274ba6373a --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/NegativeOrZero.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class NegativeOrZero extends LessThanOrEqual +{ + use NumberConstraintTrait; + + public $message = 'This value should be either negative or zero.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return LessThanOrEqualValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php b/src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php new file mode 100644 index 0000000000000..ff189cf3e8acb --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/NumberConstraintTrait.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; + +/** + * @author Jan Schädlich + */ +trait NumberConstraintTrait +{ + private function configureNumberConstraintOptions($options): array + { + if (null === $options) { + $options = []; + } elseif (!\is_array($options)) { + $options = [$this->getDefaultOption() => $options]; + } + + if (isset($options['propertyPath'])) { + throw new ConstraintDefinitionException(sprintf('The "propertyPath" option of the "%s" constraint cannot be set.', \get_class($this))); + } + + if (isset($options['value'])) { + throw new ConstraintDefinitionException(sprintf('The "value" option of the "%s" constraint cannot be set.', \get_class($this))); + } + + $options['value'] = 0; + + return $options; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/Positive.php b/src/Symfony/Component/Validator/Constraints/Positive.php new file mode 100644 index 0000000000000..6efba4a9b2ede --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Positive.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class Positive extends GreaterThan +{ + use NumberConstraintTrait; + + public $message = 'This value should be positive.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return GreaterThanValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Constraints/PositiveOrZero.php b/src/Symfony/Component/Validator/Constraints/PositiveOrZero.php new file mode 100644 index 0000000000000..2e525db4647ba --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/PositiveOrZero.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Constraints; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Jan Schädlich + */ +class PositiveOrZero extends GreaterThanOrEqual +{ + use NumberConstraintTrait; + + public $message = 'This value should be either positive or zero.'; + + public function __construct($options = null) + { + parent::__construct($this->configureNumberConstraintOptions($options)); + } + + public function validatedBy(): string + { + return GreaterThanOrEqualValidator::class; + } +} diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index aab53e727b9e4..604df8017ddf8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -330,6 +330,22 @@ This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. Diese internationale Bankleitzahl (BIC) ist nicht mit der IBAN {{ iban }} assoziiert. + + This value should be positive. + Dieser Wert sollte positiv sein. + + + This value should be either positive or zero. + Dieser Wert sollte entweder positiv oder 0 sein. + + + This value should be negative. + Dieser Wert sollte negativ sein. + + + This value should be either negative or zero. + Dieser Wert sollte entweder negativ oder 0 sein. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 465ad220d8790..481df7a0f6bc8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -334,6 +334,22 @@ This value should be valid JSON. This value should be valid JSON. + + This value should be positive. + This value should be positive. + + + This value should be either positive or zero. + This value should be either positive or zero. + + + This value should be negative. + This value should be negative. + + + This value should be either negative or zero. + This value should be either negative or zero. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 750a4d91e2c61..4713a161f2ad9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -278,6 +278,22 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Giá trị không được phép giống như {{ compared_value_type }} {{ compared_value }}. + + This value should be positive. + Giá trị này có thể thực hiện được. + + + This value should be either positive or zero. + Giá trị này có thể thực hiện được hoặc bằng không. + + + This value should be negative. + Giá trị này nên bị từ chối. + + + This value should be either negative or zero. + Giá trị này nên bị từ chối hoặc bằng không. + diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php new file mode 100644 index 0000000000000..7ac3e57919ae6 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\PositiveOrZero; + +/** + * @author Jan Schädlich + */ +class GreaterThanOrEqualValidatorWithPositiveOrZeroConstraintTest extends GreaterThanOrEqualValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new PositiveOrZero(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [0, 0], + [1, 0], + [2, 0], + [2.5, 0], + ['0', '0'], + ['333', '0'], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [-1, '-1', 0, '0', 'integer'], + [-2, '-2', 0, '0', 'integer'], + [-2.5, '-2.5', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\PositiveOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new PositiveOrZero(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\PositiveOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new PositiveOrZero(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for PositiveOrZero constraint'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for PositiveOrZero constraint automatically'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in PositiveOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in PositiveOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php new file mode 100644 index 0000000000000..7a33e1553058c --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorWithPositiveConstraintTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Positive; + +/** + * @author Jan Schädlich + */ +class GreaterThanValidatorWithPositiveConstraintTest extends GreaterThanValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new Positive(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [2, 0], + [2.5, 0], + ['333', '0'], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [0, '0', 0, '0', 'integer'], + [-1, '-1', 0, '0', 'integer'], + [-2, '-2', 0, '0', 'integer'], + [-2.5, '-2.5', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\Positive" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new Positive(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\Positive" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new Positive(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for Positive constraint.'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for Positive constraint automatically'); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php new file mode 100644 index 0000000000000..fa7fa2ec23461 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\NegativeOrZero; + +/** + * @author Jan Schädlich + */ +class LessThanOrEqualValidatorWithNegativeOrZeroConstraintTest extends LessThanOrEqualValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new NegativeOrZero(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [0, 0], + [-1, 0], + [-2, 0], + [-2.5, 0], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [2, '2', 0, '0', 'integer'], + [2.5, '2.5', 0, '0', 'integer'], + [333, '333', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\NegativeOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new NegativeOrZero(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\NegativeOrZero" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new NegativeOrZero(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for NegativeOrZero constraint'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for NegativeOrZero constraint automatically'); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in NegativeOrZero constraint'); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php new file mode 100644 index 0000000000000..d3e2b7afb38ad --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorWithNegativeConstraintTest.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Negative; + +/** + * @author Jan Schädlich + */ +class LessThanValidatorWithNegativeConstraintTest extends LessThanValidatorTest +{ + protected function createConstraint(array $options = null) + { + return new Negative(); + } + + /** + * {@inheritdoc} + */ + public function provideValidComparisons() + { + return [ + [-1, 0], + [-2, 0], + [-2.5, 0], + [null, 0], + ]; + } + + /** + * {@inheritdoc} + */ + public function provideInvalidComparisons() + { + return [ + [0, '0', 0, '0', 'integer'], + [2, '2', 0, '0', 'integer'], + [2.5, '2.5', 0, '0', 'integer'], + [333, '333', 0, '0', 'integer'], + ]; + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "propertyPath" option of the "Symfony\Component\Validator\Constraints\Negative" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfPropertyPath() + { + return new Negative(['propertyPath' => 'field']); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage The "value" option of the "Symfony\Component\Validator\Constraints\Negative" constraint cannot be set. + */ + public function testThrowsConstraintExceptionIfValue() + { + return new Negative(['value' => 0]); + } + + /** + * @dataProvider provideInvalidConstraintOptions + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires either the "value" or "propertyPath" option to be set. + */ + public function testThrowsConstraintExceptionIfNoValueOrPropertyPath($options) + { + $this->markTestSkipped('Value option always set for Negative constraint'); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + * @expectedExceptionMessage requires only one of the "value" or "propertyPath" options to be set, not both. + */ + public function testThrowsConstraintExceptionIfBothValueAndPropertyPath() + { + $this->markTestSkipped('Value option is set for Negative constraint automatically'); + } + + public function testNoViolationOnNullObjectWithPropertyPath() + { + $this->markTestSkipped('PropertyPath option is not used in Negative constraint'); + } + + public function testInvalidValuePath() + { + $this->markTestSkipped('PropertyPath option is not used in Negative constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPath($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Negative constraint'); + } + + /** + * @dataProvider provideValidComparisonsToPropertyPath + */ + public function testValidComparisonToPropertyPathOnArray($comparedValue) + { + $this->markTestSkipped('PropertyPath option is not used in Positive constraint'); + } +} From 0b5004f59fb5d5b7759be3f6624d5071f73fe5e3 Mon Sep 17 00:00:00 2001 From: Samuel ROZE Date: Sun, 31 Mar 2019 18:13:35 +0100 Subject: [PATCH 340/495] Add `psr/cache` on Messenger's dependencies --- src/Symfony/Component/Messenger/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index 17eebcca92093..d3adb0271dd37 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -21,6 +21,7 @@ }, "require-dev": { "doctrine/dbal": "~2.4", + "psr/cache": "~1.0", "symfony/console": "~3.4|~4.0", "symfony/dependency-injection": "~3.4.19|^4.1.8", "symfony/doctrine-bridge": "~3.4|~4.0", From 563900ffaa857fa70462fbb46fb33311929bfcd7 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 19:31:00 +0200 Subject: [PATCH 341/495] fixed CS --- src/Symfony/Component/Inflector/Inflector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Inflector/Inflector.php b/src/Symfony/Component/Inflector/Inflector.php index a183009c3058c..758e591d07149 100644 --- a/src/Symfony/Component/Inflector/Inflector.php +++ b/src/Symfony/Component/Inflector/Inflector.php @@ -298,7 +298,7 @@ final class Inflector ); /** - * A list of words which should not be inflected + * A list of words which should not be inflected. * * @var array */ From 9669e135542e082cdc0b9022de463403ad9c55d3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 19:35:08 +0200 Subject: [PATCH 342/495] [Messenger] made a const private --- .../Component/Messenger/Transport/Doctrine/Connection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index ffb1d137798fc..aadcb2fadc24e 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -29,7 +29,7 @@ */ class Connection { - const DEFAULT_OPTIONS = [ + private const DEFAULT_OPTIONS = [ 'table_name' => 'messenger_messages', 'queue_name' => 'default', 'redeliver_timeout' => 3600, From 27466498d02b4ed1f5ab397d88cfce8b40f46116 Mon Sep 17 00:00:00 2001 From: Vincent Touzet Date: Sun, 31 Mar 2019 20:44:41 +0200 Subject: [PATCH 343/495] [Messenger] Fix get in Doctrine Transport --- .../Doctrine/DoctrineTransportTest.php | 60 +++++++++++++++++++ .../Transport/Doctrine/Connection.php | 2 +- .../Transport/Doctrine/DoctrineTransport.php | 2 +- 3 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportTest.php diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportTest.php new file mode 100644 index 0000000000000..145397f889a04 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineTransportTest.php @@ -0,0 +1,60 @@ + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\Doctrine\Connection; +use Symfony\Component\Messenger\Transport\Doctrine\DoctrineTransport; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Component\Messenger\Transport\TransportInterface; + +class DoctrineTransportTest extends TestCase +{ + public function testItIsATransport() + { + $transport = $this->getTransport(); + + $this->assertInstanceOf(TransportInterface::class, $transport); + } + + public function testReceivesMessages() + { + $transport = $this->getTransport( + $serializer = $this->getMockBuilder(SerializerInterface::class)->getMock(), + $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock() + ); + + $decodedMessage = new DummyMessage('Decoded.'); + + $doctrineEnvelope = [ + 'id' => '5', + 'body' => 'body', + 'headers' => ['my' => 'header'], + ]; + + $serializer->method('decode')->with(['body' => 'body', 'headers' => ['my' => 'header']])->willReturn(new Envelope($decodedMessage)); + $connection->method('get')->willReturn($doctrineEnvelope); + + $envelopes = iterator_to_array($transport->get()); + $this->assertSame($decodedMessage, $envelopes[0]->getMessage()); + } + + private function getTransport(SerializerInterface $serializer = null, Connection $connection = null) + { + $serializer = $serializer ?: $this->getMockBuilder(SerializerInterface::class)->getMock(); + $connection = $connection ?: $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + + return new DoctrineTransport($connection, $serializer); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index aadcb2fadc24e..0b23267c8995f 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -231,7 +231,7 @@ private function getSchema(): Schema ->setNotnull(true); $table->addColumn('body', Type::TEXT) ->setNotnull(true); - $table->addColumn('headers', Type::STRING) + $table->addColumn('headers', Type::TEXT) ->setNotnull(true); $table->addColumn('queue_name', Type::STRING) ->setNotnull(true); diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php index b9c1d8ee8c00b..09d9d5cadfa95 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineTransport.php @@ -39,7 +39,7 @@ public function __construct(Connection $connection, SerializerInterface $seriali */ public function get(): iterable { - ($this->receiver ?? $this->getReceiver())->get(); + return ($this->receiver ?? $this->getReceiver())->get(); } /** From 1044dfb93dd4218e0e79ad79df5bcac479683a62 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 22:18:13 +0200 Subject: [PATCH 344/495] [Messenger] simplified code --- .../Component/Messenger/Transport/Doctrine/Connection.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index aadcb2fadc24e..faf6b8919b19a 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -63,11 +63,10 @@ public function getConfiguration(): array public static function buildConfiguration($dsn, array $options = []) { - if (false === $parsedUrl = parse_url($dsn)) { + if (false === $components = parse_url($dsn)) { throw new InvalidArgumentException(sprintf('The given Doctrine DSN "%s" is invalid.', $dsn)); } - $components = parse_url($dsn); $query = []; if (isset($components['query'])) { parse_str($components['query'], $query); From 96dee1ee20ac22a9cfc4bb55456d9e9db3ba947f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 Mar 2019 22:37:12 +0200 Subject: [PATCH 345/495] [Messenger] fixed missing use statement --- .../Component/Messenger/Command/ConsumeMessagesCommand.php | 3 ++- src/Symfony/Component/Messenger/Command/StopWorkersCommand.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index dea3a204daf2b..b5a617577969f 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -19,6 +19,7 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Style\SymfonyStyle; @@ -148,7 +149,7 @@ protected function interact(InputInterface $input, OutputInterface $output) /** * {@inheritdoc} */ - protected function execute(InputInterface $input, OutputInterface $output): void + protected function execute(InputInterface $input, OutputInterface $output) { if (false !== strpos($input->getFirstArgument(), ':consume-')) { $message = 'The use of the "messenger:consume-messages" command is deprecated since version 4.3 and will be removed in 5.0. Use "messenger:consume" instead.'; diff --git a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php index 0ea9582897a09..228c24bcbb32d 100644 --- a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php +++ b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php @@ -14,6 +14,7 @@ use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Messenger\Worker\StopWhenRestartSignalIsReceived; @@ -60,7 +61,7 @@ protected function configure(): void /** * {@inheritdoc} */ - protected function execute(InputInterface $input, OutputInterface $output): void + protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output); From 2e02986b2694b7c28541b2df24b525d07d129ec4 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 31 Mar 2019 22:04:08 +0200 Subject: [PATCH 346/495] [EventDispatcher] Fix FC layer (really) --- .../EventDispatcher/Debug/WrappedListener.php | 5 ++ .../EventDispatcher/EventDispatcher.php | 4 +- .../Tests/EventDispatcherTest.php | 21 ++++++- .../EventDispatcher/WrappedEvent.php | 57 +++++++++++++++++++ 4 files changed, 82 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/EventDispatcher/WrappedEvent.php diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index 3450c1283c270..d5c137b94b2ad 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -14,6 +14,7 @@ use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\WrappedEvent; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Caster\ClassStub; use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; @@ -111,6 +112,10 @@ public function getInfo($eventName) public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) { + if ($event instanceof WrappedEvent) { + $event = $event->getWrappedEvent(); + } + $dispatcher = $this->dispatcher ?: $dispatcher; $this->called = true; diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 92867fdd07d97..60283882a8848 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -71,7 +71,7 @@ public function dispatch($event/*, string $eventName = null*/) } if ($listeners) { - $this->doDispatch($listeners, $eventName, $event); + $this->callListeners($listeners, $eventName, $event); } return $event; @@ -242,7 +242,7 @@ protected function callListeners(iterable $listeners, string $eventName, $event) if ($stoppable && $event->isPropagationStopped()) { break; } - $listener($event, $eventName, $this); + $listener($event instanceof Event ? $event : new WrappedEvent($event), $eventName, $this); } } diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index cfdc9c137d962..b809cd9f51c9a 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -15,6 +15,7 @@ use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; class EventDispatcherTest extends TestCase { @@ -128,6 +129,20 @@ public function testGetListenerPriority() } public function testDispatch() + { + $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); + $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); + $this->dispatcher->dispatch(new ContractsEvent(), self::preFoo); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), 'noevent')); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), self::preFoo)); + $event = new Event(); + $return = $this->dispatcher->dispatch($event, self::preFoo); + $this->assertSame($event, $return); + } + + public function testDispatchContractsEvent() { $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); @@ -413,12 +428,12 @@ class TestEventListener /* Listener methods */ - public function preFoo(Event $e) + public function preFoo($e) { $this->preFooInvoked = true; } - public function postFoo(Event $e) + public function postFoo($e) { $this->postFooInvoked = true; @@ -433,7 +448,7 @@ class TestWithDispatcher public $name; public $dispatcher; - public function foo(Event $e, $name, $dispatcher) + public function foo($e, $name, $dispatcher) { $this->name = $name; $this->dispatcher = $dispatcher; diff --git a/src/Symfony/Component/EventDispatcher/WrappedEvent.php b/src/Symfony/Component/EventDispatcher/WrappedEvent.php new file mode 100644 index 0000000000000..705d1aeda1596 --- /dev/null +++ b/src/Symfony/Component/EventDispatcher/WrappedEvent.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; + +/** + * @internal to be removed in 5.0. + */ +final class WrappedEvent extends Event +{ + private $event; + + /** + * @param object $event + */ + public function __construct($event) + { + $this->event = $event; + } + + /** + * @return object $event + */ + public function getWrappedEvent() + { + return $this->event; + } + + public function isPropagationStopped() + { + if (!$this->event instanceof ContractsEvent && !$this->event instanceof StoppableEventInterface) { + return false; + } + + return $this->event->isPropagationStopped(); + } + + public function stopPropagation() + { + if (!$this->event instanceof ContractsEvent) { + return; + } + + $this->event->stopPropagation(); + } +} From 9bcea2e9f45934bc12b056f48aa4cbd44ebdb484 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 31 Mar 2019 23:15:36 +0200 Subject: [PATCH 347/495] fix test name --- .../Component/EventDispatcher/Tests/EventDispatcherTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php index b809cd9f51c9a..e89f78cda8e89 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/EventDispatcherTest.php @@ -132,7 +132,7 @@ public function testDispatch() { $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); - $this->dispatcher->dispatch(new ContractsEvent(), self::preFoo); + $this->dispatcher->dispatch(new Event(), self::preFoo); $this->assertTrue($this->listener->preFooInvoked); $this->assertFalse($this->listener->postFooInvoked); $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), 'noevent')); @@ -146,7 +146,7 @@ public function testDispatchContractsEvent() { $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); - $this->dispatcher->dispatch(new Event(), self::preFoo); + $this->dispatcher->dispatch(new ContractsEvent(), self::preFoo); $this->assertTrue($this->listener->preFooInvoked); $this->assertFalse($this->listener->postFooInvoked); $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), 'noevent')); From 3cee1cac12e55aeff77ca2dfb7bab8f2f50134bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?THERAGE=20K=C3=A9vin?= Date: Mon, 25 Mar 2019 17:16:11 +0100 Subject: [PATCH 348/495] #30690 - Changing messenger bus id from 'message_bus' to 'messenger.default_bus' --- .../Bundle/FrameworkBundle/Controller/AbstractController.php | 1 + .../Bundle/FrameworkBundle/Controller/ControllerTrait.php | 4 ++-- .../DependencyInjection/FrameworkExtension.php | 3 ++- .../Tests/Controller/AbstractControllerTest.php | 1 + .../Tests/DependencyInjection/FrameworkExtensionTest.php | 4 ++++ 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php index a8b83f1e8b2fd..ac7ab231e01a9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php @@ -88,6 +88,7 @@ public static function getSubscribedServices() 'security.csrf.token_manager' => '?'.CsrfTokenManagerInterface::class, 'parameter_bag' => '?'.ContainerBagInterface::class, 'message_bus' => '?'.MessageBusInterface::class, + 'messenger.default_bus' => '?'.MessageBusInterface::class, ]; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index e32f7b6e25d0a..2f20678e318e3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -403,12 +403,12 @@ protected function isCsrfTokenValid(string $id, ?string $token): bool */ protected function dispatchMessage($message): Envelope { - if (!$this->container->has('message_bus')) { + if (!$this->container->has('messenger.default_bus')) { $message = class_exists(Envelope::class) ? 'You need to define the "messenger.default_bus" configuration option.' : 'Try running "composer require symfony/messenger".'; throw new \LogicException('The message bus is not enabled in your application. '.$message); } - return $this->container->get('message_bus')->dispatch($message); + return $this->container->get('messenger.default_bus')->dispatch($message); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index fa505bbb0cf67..76ccb42ba2b83 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1655,7 +1655,8 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $container->register($busId, MessageBus::class)->addArgument([])->addTag('messenger.bus'); if ($busId === $config['default_bus']) { - $container->setAlias('message_bus', $busId)->setPublic(true); + $container->setAlias('message_bus', $busId)->setPublic(true)->setDeprecated(true, 'The "%alias_id%" service is deprecated, use the "messenger.default_bus" service instead.'); + $container->setAlias('messenger.default_bus', $busId)->setPublic(true); $container->setAlias(MessageBusInterface::class, $busId); } else { $container->registerAliasForArgument($busId, MessageBusInterface::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php index ddab6af2b6628..9c1e0b8d9a51d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/AbstractControllerTest.php @@ -43,6 +43,7 @@ public function testSubscribedServices() 'form.factory' => '?Symfony\\Component\\Form\\FormFactoryInterface', 'parameter_bag' => '?Symfony\\Component\\DependencyInjection\\ParameterBag\\ContainerBagInterface', 'message_bus' => '?Symfony\\Component\\Messenger\\MessageBusInterface', + 'messenger.default_bus' => '?Symfony\\Component\\Messenger\\MessageBusInterface', 'security.token_storage' => '?Symfony\\Component\\Security\\Core\\Authentication\\Token\\Storage\\TokenStorageInterface', 'security.csrf.token_manager' => '?Symfony\\Component\\Security\\Csrf\\CsrfTokenManagerInterface', ]; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index ddd9d64286ff5..a5812e6e3cf40 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -648,6 +648,8 @@ public function testMessenger() $container = $this->createContainerFromFile('messenger'); $this->assertTrue($container->hasAlias('message_bus')); $this->assertTrue($container->getAlias('message_bus')->isPublic()); + $this->assertTrue($container->hasAlias('messenger.default_bus')); + $this->assertTrue($container->getAlias('messenger.default_bus')->isPublic()); $this->assertFalse($container->hasDefinition('messenger.transport.amqp.factory')); $this->assertTrue($container->hasDefinition('messenger.transport_factory')); $this->assertSame(TransportFactory::class, $container->getDefinition('messenger.transport_factory')->getClass()); @@ -750,6 +752,8 @@ public function testMessengerWithMultipleBuses() $this->assertTrue($container->hasAlias('message_bus')); $this->assertSame('messenger.bus.commands', (string) $container->getAlias('message_bus')); + $this->assertTrue($container->hasAlias('messenger.default_bus')); + $this->assertSame('messenger.bus.commands', (string) $container->getAlias('messenger.default_bus')); } /** From fe7ad812c7b385207cee0742361ab24304e367cc Mon Sep 17 00:00:00 2001 From: Ryan Weaver Date: Mon, 1 Apr 2019 08:36:54 -0400 Subject: [PATCH 349/495] base64_encoding inside PhpSerializer to avoid null characters --- .../Transport/Serialization/PhpSerializerTest.php | 2 +- .../Transport/Serialization/PhpSerializer.php | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php index 1532db5872773..53905a053d1a5 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php @@ -58,7 +58,7 @@ public function testDecodingFailsWithBadClass() $serializer = new PhpSerializer(); $serializer->decode([ - 'body' => 'O:13:"ReceivedSt0mp":0:{}', + 'body' => base64_encode('O:13:"ReceivedSt0mp":0:{}'), ]); } } diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php index f9aed0e0d267a..6a27529c5592d 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php @@ -30,7 +30,13 @@ public function decode(array $encodedEnvelope): Envelope throw new MessageDecodingFailedException('Encoded envelope should have at least a "body".'); } - return $this->safelyUnserialize($encodedEnvelope['body']); + $serializeEnvelope = base64_decode($encodedEnvelope['body']); + + if (false === $serializeEnvelope) { + throw new MessageDecodingFailedException('The "body" key could not be base64 decoded.'); + } + + return $this->safelyUnserialize($serializeEnvelope); } /** @@ -39,7 +45,7 @@ public function decode(array $encodedEnvelope): Envelope public function encode(Envelope $envelope): array { return [ - 'body' => serialize($envelope), + 'body' => base64_encode(serialize($envelope)), ]; } From d27858f77b4c9d839af789ed0df6e90a2279b94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 1 Apr 2019 15:29:45 +0200 Subject: [PATCH 350/495] [Process] Added more detail to the exception when the CWD is invalid --- src/Symfony/Component/Process/Process.php | 2 +- src/Symfony/Component/Process/Tests/ProcessTest.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 8b7f539e0fe10..55dd0112a679c 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -331,7 +331,7 @@ public function start(callable $callback = null, array $env = []) } if (!is_dir($this->cwd)) { - throw new RuntimeException('The provided cwd does not exist.'); + throw new RuntimeException(sprintf('The provided cwd "%s" does not exist.', $this->cwd)); } $this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $options); diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 187226bd49de0..476456d1b0234 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -49,7 +49,8 @@ protected function tearDown() /** * @expectedException \Symfony\Component\Process\Exception\RuntimeException - * @expectedExceptionMessage The provided cwd does not exist. + * @expectedExceptionMessage The provided cwd " + * @expectedExceptionMessage "does not exist. */ public function testInvalidCwd() { From 164b45b79c46a6c9bf8054666426245643c0af6b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 1 Apr 2019 08:46:53 +0200 Subject: [PATCH 351/495] [Inflector] remove "internal" marker from the component --- src/Symfony/Component/Inflector/Inflector.php | 157 ++++++------ src/Symfony/Component/Inflector/README.md | 7 - .../Inflector/Tests/InflectorTest.php | 238 +++++++++--------- 3 files changed, 194 insertions(+), 208 deletions(-) diff --git a/src/Symfony/Component/Inflector/Inflector.php b/src/Symfony/Component/Inflector/Inflector.php index 758e591d07149..19edd1ae6acd5 100644 --- a/src/Symfony/Component/Inflector/Inflector.php +++ b/src/Symfony/Component/Inflector/Inflector.php @@ -15,16 +15,12 @@ * Converts words between singular and plural forms. * * @author Bernhard Schussek - * - * @internal */ final class Inflector { /** * Map English plural to singular suffixes. * - * @var array - * * @see http://english-zone.com/spelling/plurals.html */ private static $pluralMap = [ @@ -142,11 +138,9 @@ final class Inflector /** * Map English singular to plural suffixes. * - * @var array - * * @see http://english-zone.com/spelling/plurals.html */ - private static $singularMap = array( + private static $singularMap = [ // First entry: singular suffix, reversed // Second entry: length of singular suffix // Third entry: Whether the suffix may succeed a vocal @@ -154,163 +148,168 @@ final class Inflector // Fifth entry: plural suffix, normal // criterion (criteria) - array('airetirc', 8, false, false, 'criterion'), + ['airetirc', 8, false, false, 'criterion'], // nebulae (nebula) - array('aluben', 6, false, false, 'nebulae'), + ['aluben', 6, false, false, 'nebulae'], // children (child) - array('dlihc', 5, true, true, 'children'), + ['dlihc', 5, true, true, 'children'], // prices (price) - array('eci', 3, false, true, 'ices'), + ['eci', 3, false, true, 'ices'], // services (service) - array('ecivres', 7, true, true, 'services'), + ['ecivres', 7, true, true, 'services'], // lives (life), wives (wife) - array('efi', 3, false, true, 'ives'), + ['efi', 3, false, true, 'ives'], // selfies (selfie) - array('eifles', 6, true, true, 'selfies'), + ['eifles', 6, true, true, 'selfies'], // movies (movie) - array('eivom', 5, true, true, 'movies'), + ['eivom', 5, true, true, 'movies'], // lice (louse) - array('esuol', 5, false, true, 'lice'), + ['esuol', 5, false, true, 'lice'], // mice (mouse) - array('esuom', 5, false, true, 'mice'), + ['esuom', 5, false, true, 'mice'], // geese (goose) - array('esoo', 4, false, true, 'eese'), + ['esoo', 4, false, true, 'eese'], // houses (house), bases (base) - array('es', 2, true, true, 'ses'), + ['es', 2, true, true, 'ses'], // geese (goose) - array('esoog', 5, true, true, 'geese'), + ['esoog', 5, true, true, 'geese'], // caves (cave) - array('ev', 2, true, true, 'ves'), + ['ev', 2, true, true, 'ves'], // drives (drive) - array('evird', 5, false, true, 'drives'), + ['evird', 5, false, true, 'drives'], // objectives (objective), alternative (alternatives) - array('evit', 4, true, true, 'tives'), + ['evit', 4, true, true, 'tives'], // moves (move) - array('evom', 4, true, true, 'moves'), + ['evom', 4, true, true, 'moves'], // staves (staff) - array('ffats', 5, true, true, 'staves'), + ['ffats', 5, true, true, 'staves'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) - array('ff', 2, true, true, 'ffs'), + ['ff', 2, true, true, 'ffs'], // hooves (hoof), dwarves (dwarf), elves (elf), leaves (leaf) - array('f', 1, true, true, array('fs', 'ves')), + ['f', 1, true, true, ['fs', 'ves']], // arches (arch) - array('hc', 2, true, true, 'ches'), + ['hc', 2, true, true, 'ches'], // bushes (bush) - array('hs', 2, true, true, 'shes'), + ['hs', 2, true, true, 'shes'], // teeth (tooth) - array('htoot', 5, true, true, 'teeth'), + ['htoot', 5, true, true, 'teeth'], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - array('mu', 2, true, true, 'a'), - - // echoes (echo) - array('ohce', 4, true, true, 'echoes'), + ['mu', 2, true, true, 'a'], // men (man), women (woman) - array('nam', 3, true, true, 'men'), + ['nam', 3, true, true, 'men'], // people (person) - array('nosrep', 6, true, true, array('persons', 'people')), + ['nosrep', 6, true, true, ['persons', 'people']], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - array('noi', 3, true, true, 'ions'), + ['noi', 3, true, true, 'ions'], // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - array('no', 2, true, true, 'a'), + ['no', 2, true, true, 'a'], + + // echoes (echo) + ['ohce', 4, true, true, 'echoes'], + + // heroes (hero) + ['oreh', 4, true, true, 'heroes'], // atlases (atlas) - array('salta', 5, true, true, 'atlases'), + ['salta', 5, true, true, 'atlases'], // irises (iris) - array('siri', 4, true, true, 'irises'), + ['siri', 4, true, true, 'irises'], // analyses (analysis), ellipses (ellipsis), neuroses (neurosis) // theses (thesis), emphases (emphasis), oases (oasis), // crises (crisis) - array('sis', 3, true, true, 'ses'), + ['sis', 3, true, true, 'ses'], // accesses (access), addresses (address), kisses (kiss) - array('ss', 2, true, false, 'sses'), + ['ss', 2, true, false, 'sses'], // syllabi (syllabus) - array('suballys', 8, true, true, 'syllabi'), + ['suballys', 8, true, true, 'syllabi'], // buses (bus) - array('sub', 3, true, true, 'buses'), + ['sub', 3, true, true, 'buses'], + + // circuses (circus) + ['suc', 3, true, true, 'cuses'], // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) - array('su', 2, true, true, 'i'), + ['su', 2, true, true, 'i'], // news (news) - array('swen', 4, true, true, 'news'), + ['swen', 4, true, true, 'news'], // feet (foot) - array('toof', 4, true, true, 'feet'), + ['toof', 4, true, true, 'feet'], // chateaux (chateau), bureaus (bureau) - array('uae', 3, false, true, array('eaus', 'eaux')), + ['uae', 3, false, true, ['eaus', 'eaux']], // oxen (ox) - array('xo', 2, false, false, 'oxen'), + ['xo', 2, false, false, 'oxen'], // hoaxes (hoax) - array('xaoh', 4, true, false, 'hoaxes'), + ['xaoh', 4, true, false, 'hoaxes'], // indices (index) - array('xedni', 5, false, true, array('indicies', 'indexes')), + ['xedni', 5, false, true, ['indicies', 'indexes']], // indexes (index), matrixes (matrix) - array('x', 1, true, false, array('cies', 'xes')), + ['x', 1, true, false, ['cies', 'xes']], // appendices (appendix) - array('xi', 2, false, true, 'ices'), + ['xi', 2, false, true, 'ices'], // babies (baby) - array('y', 1, false, true, 'ies'), + ['y', 1, false, true, 'ies'], // quizzes (quiz) - array('ziuq', 4, true, false, 'quizzes'), + ['ziuq', 4, true, false, 'quizzes'], // waltzes (waltz) - array('z', 1, true, false, 'zes'), - ); + ['z', 1, true, true, 'zes'], + ]; /** - * A list of words which should not be inflected. - * - * @var array + * A list of words which should not be inflected, reversed. */ - private static $uninflected = array( - 'data', - 'deer', - 'feedback', - 'fish', - 'moose', - 'series', - 'sheep', - ); + private static $uninflected = [ + 'atad', + 'reed', + 'kcabdeef', + 'hsif', + 'ofni', + 'esoom', + 'seires', + 'peehs', + ]; /** * This class should not be instantiated. @@ -327,10 +326,7 @@ private function __construct() * * @param string $plural A word in plural form * - * @return string|array The singular form or an array of possible singular - * forms - * - * @internal + * @return string|array The singular form or an array of possible singular forms */ public static function singularize(string $plural) { @@ -339,7 +335,7 @@ public static function singularize(string $plural) $pluralLength = \strlen($lowerPluralRev); // Check if the word is one which is not inflected, return early if so - if (in_array(strtolower($plural), self::$uninflected, true)) { + if (\in_array($lowerPluralRev, self::$uninflected, true)) { return $plural; } @@ -416,19 +412,16 @@ public static function singularize(string $plural) * * @param string $singular A word in plural form * - * @return string|array The plural form or an array of possible plural - * forms - * - * @internal + * @return string|array The plural form or an array of possible plural forms */ public static function pluralize(string $singular) { $singularRev = strrev($singular); $lowerSingularRev = strtolower($singularRev); - $singularLength = strlen($lowerSingularRev); + $singularLength = \strlen($lowerSingularRev); // Check if the word is one which is not inflected, return early if so - if (in_array(strtolower($singular), self::$uninflected, true)) { + if (\in_array($lowerSingularRev, self::$uninflected, true)) { return $singular; } @@ -474,8 +467,8 @@ public static function pluralize(string $singular) // the singular suffix too $firstUpper = ctype_upper($singularRev[$j - 1]); - if (is_array($newSuffix)) { - $plurals = array(); + if (\is_array($newSuffix)) { + $plurals = []; foreach ($newSuffix as $newSuffixEntry) { $plurals[] = $newBase.($firstUpper ? ucfirst($newSuffixEntry) : $newSuffixEntry); diff --git a/src/Symfony/Component/Inflector/README.md b/src/Symfony/Component/Inflector/README.md index 8b81839dbcca8..67568fb5a2b0c 100644 --- a/src/Symfony/Component/Inflector/README.md +++ b/src/Symfony/Component/Inflector/README.md @@ -3,13 +3,6 @@ Inflector Component Inflector converts words between their singular and plural forms (English only). -Disclaimer ----------- - -This component is currently marked as internal. Do not use it in your own code. -Breaking changes may be introduced in the next minor version of Symfony, or the -component itself might even be removed completely. - Resources --------- diff --git a/src/Symfony/Component/Inflector/Tests/InflectorTest.php b/src/Symfony/Component/Inflector/Tests/InflectorTest.php index f6c3d830f26ce..1178edf35b5bc 100644 --- a/src/Symfony/Component/Inflector/Tests/InflectorTest.php +++ b/src/Symfony/Component/Inflector/Tests/InflectorTest.php @@ -58,7 +58,7 @@ public function singularizeProvider() ['crises', ['cris', 'crise', 'crisis']], ['criteria', ['criterion', 'criterium']], ['cups', 'cup'], - ['data', ['daton', 'datum']], + ['data', 'data'], ['days', 'day'], ['discos', 'disco'], ['devices', ['devex', 'devix', 'device']], @@ -159,124 +159,124 @@ public function pluralizeProvider() { // see http://english-zone.com/spelling/plurals.html // see http://www.scribd.com/doc/3271143/List-of-100-Irregular-Plural-Nouns-in-English - return array( - array('access', 'accesses'), - array('address', 'addresses'), - array('agenda', 'agendas'), - array('alumnus', 'alumni'), - array('analysis', 'analyses'), - array('antenna', 'antennas'), //antennae - array('appendix', array('appendicies', 'appendixes')), - array('arch', 'arches'), - array('atlas', 'atlases'), - array('axe', 'axes'), - array('baby', 'babies'), - array('bacterium', 'bacteria'), - array('base', 'bases'), - array('batch', 'batches'), - array('beau', array('beaus', 'beaux')), - array('bee', 'bees'), - array('box', array('bocies', 'boxes')), - array('boy', 'boys'), - array('bureau', array('bureaus', 'bureaux')), - array('bus', 'buses'), - array('bush', 'bushes'), - array('calf', array('calfs', 'calves')), - array('car', 'cars'), - array('cassette', 'cassettes'), - array('cave', 'caves'), - array('chateau', array('chateaus', 'chateaux')), - array('cheese', 'cheeses'), - array('child', 'children'), - array('circus', 'circuses'), - array('cliff', 'cliffs'), - array('committee', 'committees'), - array('crisis', 'crises'), - array('criteria', 'criterion'), - array('cup', 'cups'), - array('data', 'data'), - array('day', 'days'), - array('disco', 'discos'), - array('device', 'devices'), - array('drive', 'drives'), - array('driver', 'drivers'), - array('dwarf', array('dwarfs', 'dwarves')), - array('echo', 'echoes'), - array('elf', array('elfs', 'elves')), - array('emphasis', 'emphases'), - array('fax', array('facies', 'faxes')), - array('feedback', 'feedback'), - array('focus', 'foci'), - array('foot', 'feet'), - array('formula', 'formulas'), //formulae - array('fungus', 'fungi'), - array('garage', 'garages'), - array('goose', 'geese'), - array('half', array('halfs', 'halves')), - array('hat', 'hats'), - array('hero', 'heroes'), - array('hippopotamus', 'hippopotami'), //hippopotamuses - array('hoax', 'hoaxes'), - array('hoof', array('hoofs', 'hooves')), - array('house', 'houses'), - array('index', array('indicies', 'indexes')), - array('ion', 'ions'), - array('iris', 'irises'), - array('kiss', 'kisses'), - array('knife', 'knives'), - array('lamp', 'lamps'), - array('leaf', array('leafs', 'leaves')), - array('life', 'lives'), - array('louse', 'lice'), - array('man', 'men'), - array('matrix', array('matricies', 'matrixes')), - array('mouse', 'mice'), - array('move', 'moves'), - array('movie', 'movies'), - array('nebula', 'nebulae'), - array('neurosis', 'neuroses'), - array('news', 'news'), - array('oasis', 'oases'), - array('objective', 'objectives'), - array('ox', 'oxen'), - array('party', 'parties'), - array('person', array('persons', 'people')), - array('phenomenon', 'phenomena'), - array('photo', 'photos'), - array('piano', 'pianos'), - array('plateau', array('plateaus', 'plateaux')), - array('poppy', 'poppies'), - array('price', 'prices'), - array('quiz', 'quizzes'), - array('radius', 'radii'), - array('roof', array('roofs', 'rooves')), - array('rose', 'roses'), - array('sandwich', 'sandwiches'), - array('scarf', array('scarfs', 'scarves')), - array('schema', 'schemas'), //schemata - array('selfie', 'selfies'), - array('series', 'series'), - array('service', 'services'), - array('sheriff', 'sheriffs'), - array('shoe', 'shoes'), - array('spy', 'spies'), - array('staff', 'staves'), - array('story', 'stories'), - array('stratum', 'strata'), - array('suitcase', 'suitcases'), - array('syllabus', 'syllabi'), - array('tag', 'tags'), - array('thief', array('thiefs', 'thieves')), - array('tooth', 'teeth'), - array('tree', 'trees'), - array('waltz', 'waltzes'), - array('wife', 'wives'), + return [ + ['access', 'accesses'], + ['address', 'addresses'], + ['agenda', 'agendas'], + ['alumnus', 'alumni'], + ['analysis', 'analyses'], + ['antenna', 'antennas'], //antennae + ['appendix', ['appendicies', 'appendixes']], + ['arch', 'arches'], + ['atlas', 'atlases'], + ['axe', 'axes'], + ['baby', 'babies'], + ['bacterium', 'bacteria'], + ['base', 'bases'], + ['batch', 'batches'], + ['beau', ['beaus', 'beaux']], + ['bee', 'bees'], + ['box', ['bocies', 'boxes']], + ['boy', 'boys'], + ['bureau', ['bureaus', 'bureaux']], + ['bus', 'buses'], + ['bush', 'bushes'], + ['calf', ['calfs', 'calves']], + ['car', 'cars'], + ['cassette', 'cassettes'], + ['cave', 'caves'], + ['chateau', ['chateaus', 'chateaux']], + ['cheese', 'cheeses'], + ['child', 'children'], + ['circus', 'circuses'], + ['cliff', 'cliffs'], + ['committee', 'committees'], + ['crisis', 'crises'], + ['criteria', 'criterion'], + ['cup', 'cups'], + ['data', 'data'], + ['day', 'days'], + ['disco', 'discos'], + ['device', 'devices'], + ['drive', 'drives'], + ['driver', 'drivers'], + ['dwarf', ['dwarfs', 'dwarves']], + ['echo', 'echoes'], + ['elf', ['elfs', 'elves']], + ['emphasis', 'emphases'], + ['fax', ['facies', 'faxes']], + ['feedback', 'feedback'], + ['focus', 'focuses'], + ['foot', 'feet'], + ['formula', 'formulas'], //formulae + ['fungus', 'fungi'], + ['garage', 'garages'], + ['goose', 'geese'], + ['half', ['halfs', 'halves']], + ['hat', 'hats'], + ['hero', 'heroes'], + ['hippopotamus', 'hippopotami'], //hippopotamuses + ['hoax', 'hoaxes'], + ['hoof', ['hoofs', 'hooves']], + ['house', 'houses'], + ['index', ['indicies', 'indexes']], + ['ion', 'ions'], + ['iris', 'irises'], + ['kiss', 'kisses'], + ['knife', 'knives'], + ['lamp', 'lamps'], + ['leaf', ['leafs', 'leaves']], + ['life', 'lives'], + ['louse', 'lice'], + ['man', 'men'], + ['matrix', ['matricies', 'matrixes']], + ['mouse', 'mice'], + ['move', 'moves'], + ['movie', 'movies'], + ['nebula', 'nebulae'], + ['neurosis', 'neuroses'], + ['news', 'news'], + ['oasis', 'oases'], + ['objective', 'objectives'], + ['ox', 'oxen'], + ['party', 'parties'], + ['person', ['persons', 'people']], + ['phenomenon', 'phenomena'], + ['photo', 'photos'], + ['piano', 'pianos'], + ['plateau', ['plateaus', 'plateaux']], + ['poppy', 'poppies'], + ['price', 'prices'], + ['quiz', 'quizzes'], + ['radius', 'radii'], + ['roof', ['roofs', 'rooves']], + ['rose', 'roses'], + ['sandwich', 'sandwiches'], + ['scarf', ['scarfs', 'scarves']], + ['schema', 'schemas'], //schemata + ['selfie', 'selfies'], + ['series', 'series'], + ['service', 'services'], + ['sheriff', 'sheriffs'], + ['shoe', 'shoes'], + ['spy', 'spies'], + ['staff', 'staves'], + ['story', 'stories'], + ['stratum', 'strata'], + ['suitcase', 'suitcases'], + ['syllabus', 'syllabi'], + ['tag', 'tags'], + ['thief', ['thiefs', 'thieves']], + ['tooth', 'teeth'], + ['tree', 'trees'], + ['waltz', 'waltzes'], + ['wife', 'wives'], // test casing: if the first letter was uppercase, it should remain so - array('Man', 'Men'), - array('GrandChild', 'GrandChildren'), - array('SubTree', 'SubTrees'), - ); + ['Man', 'Men'], + ['GrandChild', 'GrandChildren'], + ['SubTree', 'SubTrees'], + ]; } /** @@ -300,9 +300,9 @@ public function testSingularize($plural, $singular) public function testPluralize($plural, $singular) { $single = Inflector::pluralize($plural); - if (is_string($singular) && is_array($single)) { + if (\is_string($singular) && \is_array($single)) { $this->fail("--- Expected\n`string`: ".$singular."\n+++ Actual\n`array`: ".implode(', ', $single)); - } elseif (is_array($singular) && is_string($single)) { + } elseif (\is_array($singular) && \is_string($single)) { $this->fail("--- Expected\n`array`: ".implode(', ', $singular)."\n+++ Actual\n`string`: ".$single); } From 2f8040ee843324b07f73af75ff02dd00844842b9 Mon Sep 17 00:00:00 2001 From: Alex Rock Ancelet Date: Fri, 25 Jan 2019 22:54:04 +0100 Subject: [PATCH 352/495] Create new PHPUnit assertions for the WebTestCase --- .../FrameworkBundle/Test/KernelTestCase.php | 7 +- ...ait.php => TestCaseSetUpTearDownTrait.php} | 39 +- .../Test/WebTestAssertions.php | 383 ++++++++++++++++++ .../FrameworkBundle/Test/WebTestCase.php | 12 +- .../Form/Test/TestCaseSetUpTearDownTrait.php | 10 +- .../Test/TestCaseSetUpTearDownTrait.php | 10 +- 6 files changed, 438 insertions(+), 23 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Test/{KernelShutdownOnTearDownTrait.php => TestCaseSetUpTearDownTrait.php} (53%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php index 666831b041590..e794b2b61d1b1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php @@ -23,7 +23,7 @@ */ abstract class KernelTestCase extends TestCase { - use KernelShutdownOnTearDownTrait; + use TestCaseSetUpTearDownTrait; protected static $class; @@ -37,6 +37,11 @@ abstract class KernelTestCase extends TestCase */ protected static $container; + protected function doTearDown(): void + { + static::ensureKernelShutdown(); + } + /** * @return string The Kernel class name * diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/TestCaseSetUpTearDownTrait.php similarity index 53% rename from src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php rename to src/Symfony/Bundle/FrameworkBundle/Test/TestCaseSetUpTearDownTrait.php index bc23a39cfad67..8fc0997913f9c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/TestCaseSetUpTearDownTrait.php @@ -13,31 +13,60 @@ use PHPUnit\Framework\TestCase; -// Auto-adapt to PHPUnit 8 that added a `void` return-type to the tearDown method +// Auto-adapt to PHPUnit 8 that added a `void` return-type to the setUp/tearDown methods if ((new \ReflectionMethod(TestCase::class, 'tearDown'))->hasReturnType()) { /** * @internal */ - trait KernelShutdownOnTearDownTrait + trait TestCaseSetUpTearDownTrait { + private function doSetUp(): void + { + } + + private function doTearDown(): void + { + } + + protected function setUp(): void + { + $this->doSetUp(); + } + protected function tearDown(): void { - static::ensureKernelShutdown(); + $this->doTearDown(); } } } else { /** * @internal */ - trait KernelShutdownOnTearDownTrait + trait TestCaseSetUpTearDownTrait { + private function doSetUp(): void + { + } + + private function doTearDown(): void + { + } + + /** + * @return void + */ + protected function setUp() + { + $this->doSetUp(); + } + /** * @return void */ protected function tearDown() { - static::ensureKernelShutdown(); + $this->doTearDown(); } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php new file mode 100644 index 0000000000000..dbc6ef65ff75d --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php @@ -0,0 +1,383 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Test; + +use PHPUnit\Framework\Assert; +use Symfony\Bundle\FrameworkBundle\Client; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Ideas borrowed from Laravel Dusk's assertions. + * + * @see https://laravel.com/docs/5.7/dusk#available-assertions + */ +trait WebTestAssertions +{ + /** @var Client|null */ + protected static $client; + + public static function assertResponseIsSuccessful(): void + { + $response = static::getResponse(); + + Assert::assertTrue( + $response->isSuccessful(), + sprintf('Response was expected to be successful, but actual HTTP code is %d.', $response->getStatusCode()) + ); + } + + public static function assertHttpCodeEquals(int $expectedCode): void + { + Assert::assertSame( + $expectedCode, + $code = static::getResponse()->getStatusCode(), + sprintf('Response code "%s" does not match actual HTTP code "%s".', $expectedCode, $code) + ); + } + + public static function assertResponseHasHeader(string $headerName): void + { + Assert::assertTrue( + static::getResponse()->headers->has($headerName), + sprintf('Header "%s" was not found in the Response.', $headerName) + ); + } + + public static function assertResponseNotHasHeader(string $headerName): void + { + Assert::assertFalse( + static::getResponse()->headers->has($headerName), + sprintf('Header "%s" was not expected to be found in the Response.', $headerName) + ); + } + + public static function assertResponseHeaderEquals(string $headerName, $expectedValue): void + { + Assert::assertSame( + $expectedValue, + $value = static::getResponse()->headers->get($headerName, null, true), + sprintf('Header "%s" with value "%s" does not equal actual value "%s".', $headerName, $expectedValue, $value) + ); + } + + public static function assertResponseHeaderNotEquals(string $headerName, $expectedValue): void + { + Assert::assertNotSame( + $expectedValue, + $value = static::getResponse()->headers->get($headerName, null, true), + sprintf('Header "%s" with value "%s" was not expected to equal actual value "%s".', $headerName, $expectedValue, $value) + ); + } + + public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null): void + { + $response = static::getResponse(); + + Assert::assertTrue( + $response->isRedirect(), + sprintf('Response was expected to be a redirection, but actual HTTP code is %s.', $response->getStatusCode()) + ); + + if ($expectedCode) { + static::assertHttpCodeEquals($expectedCode); + } + + if (null !== $expectedLocation) { + Assert::assertSame( + $expectedLocation, + $location = $response->headers->get('Location'), + sprintf('Location "%s" does not match actual redirection URL "%s".', $expectedLocation, $location) + ); + } + } + + public static function assertPageTitleEquals(string $expectedTitle): void + { + $titleNode = static::getCrawler()->filter('title'); + + Assert::assertSame(1, $count = $titleNode->count(), sprintf('There must be one tag in the current page but there is actually %s.', $count)); + + Assert::assertEquals( + $expectedTitle, + trim($title = $titleNode->text()), + sprintf('Expected title "%s" does not equal actual title "%s".', $expectedTitle, $title) + ); + } + + public static function assertPageTitleContains(string $expectedTitle): void + { + $titleNode = static::getCrawler()->filter('title'); + + Assert::assertSame(1, $count = $titleNode->count(), sprintf('There must be one <title> tag in the current page but there is actually %s.', $count)); + + Assert::assertContains( + $expectedTitle, + trim($title = $titleNode->text()), + sprintf('Expected title "%s" does not contain "%s".', $expectedTitle, $title) + ); + } + + public static function assertClientHasCookie(string $name, string $path = '/', string $domain = null): void + { + static::getClientForAssertion(); + + Assert::assertNotNull( + static::$client->getCookieJar()->get($name, $path, $domain), + sprintf('Did not find expected cookie "%s".', $name) + ); + } + + public static function assertClientNotHasCookie(string $name): void + { + static::getClientForAssertion(); + + $cookie = static::$client->getCookieJar()->get($name); + + Assert::assertNull( + $cookie, + sprintf('Cookie "%s" was not expected to be set.', $name) + ); + } + + public static function assertClientCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + { + static::getClientForAssertion(); + + $cookie = static::$client->getCookieJar()->get($name, $path, $domain); + + Assert::assertNotNull( + $cookie, + sprintf('Did not find expected cookie "%s".', $name) + ); + Assert::assertSame( + $expectedValue, + $value = $cookie->getValue(), + sprintf('Cookie name "%s" with value "%s" does not match actual value "%s".', $name, $expectedValue, $value) + ); + } + + public static function assertClientRawCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + { + static::getClientForAssertion(); + + $cookie = static::$client->getCookieJar()->get($name, $path, $domain); + + Assert::assertNotNull( + $cookie, + sprintf('Did not find expected cookie "%s".', $name) + ); + Assert::assertSame( + $expectedValue, + $value = $cookie->getRawValue(), + sprintf('Cookie name "%s" with raw value "%s" does not match actual value "%s".', $name, $expectedValue, $value) + ); + } + + public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null): void + { + $cookie = static::getResponseCookieFromClient($name, $path, $domain); + + Assert::assertNotNull( + $cookie, + sprintf('Did not find expected cookie "%s".', $name) + ); + } + + public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null): void + { + $cookie = static::getResponseCookieFromClient($name, $path, $domain); + + Assert::assertNull( + $cookie, + sprintf('Cookie "%s" was not expected to be set.', $name) + ); + } + + public static function assertResponseCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + { + $cookie = static::getResponseCookieFromClient($name, $path, $domain); + + Assert::assertNotNull( + $cookie, + sprintf('Did not find expected cookie "%s".', $name) + ); + Assert::assertSame( + $expectedValue, + $value = $cookie->getValue(), + sprintf('Cookie name "%s" with value "%s" does not match actual value "%s".', $name, $expectedValue, $value) + ); + } + + public static function assertResponseCookieValueNotEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + { + $cookie = static::getResponseCookieFromClient($name, $path, $domain); + + Assert::assertNotNull( + $cookie, + sprintf('Did not find expected cookie "%s".', $name) + ); + Assert::assertNotSame( + $expectedValue, + $value = $cookie->getValue(), + sprintf('Cookie name "%s" with value "%s" was not expected to be equal to actual value "%s".', $name, $expectedValue, $value) + ); + } + + public static function assertSelectorExists(string $selector): void + { + $nodes = static::getCrawler()->filter($selector); + + Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); + } + + public static function assertSelectorNotExists(string $selector): void + { + $nodes = static::getCrawler()->filter($selector); + + Assert::assertEquals(0, $count = $nodes->count(), sprintf('Selector "%s" resolves to "%s" nodes where it expected 0.', $selector, $count)); + } + + public static function assertSelectorContainsText(string $selector, string $text): void + { + $nodes = static::getCrawler()->filter($selector); + + Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); + + Assert::assertContains($text, $nodes->text(), sprintf('Selector "%s" does not contain text "%s".', $selector, $text)); + } + + public static function assertSelectorNotContainsText(string $selector, string $text): void + { + $nodes = static::getCrawler()->filter($selector); + + Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); + + Assert::assertNotContains($text, $nodes->text(), sprintf('Selector "%s" was expected to not contain text "%s".', $selector, $text)); + } + + public static function assertInputValueEquals(string $fieldName, string $expectedValue): void + { + $inputNode = static::getCrawler()->filter("input[name=\"$fieldName\"]"); + + Assert::assertGreaterThan(0, $inputNode->count(), sprintf('Input with name "%s" not found on the page.', $fieldName)); + + Assert::assertEquals( + $expectedValue, + $value = $inputNode->getNode(0)->getAttribute('value'), + sprintf('Expected value "%s" for the "%s" input does not equal the actual value "%s".', $value, $fieldName, $value) + ); + } + + public static function assertInputValueNotEquals(string $fieldName, string $expectedValue): void + { + $inputNode = static::getCrawler()->filter("input[name=\"$fieldName\"]"); + + Assert::assertGreaterThan(0, $inputNode->count(), sprintf('Input with name "%s" not found on the page.', $fieldName)); + + Assert::assertNotEquals( + $expectedValue, + $value = $inputNode->getNode(0)->getAttribute('value'), + sprintf('Expected value "%s" for the "%s" input was expected to not equal the actual value "%s".', $value, $fieldName, $value) + ); + } + + public static function assertRouteEquals($expectedRoute, array $parameters = []): void + { + $request = static::checkRequestAvailable(); + + Assert::assertSame( + $expectedRoute, + $route = $request->attributes->get('_route'), + sprintf('Expected route name "%s" does not match the actual value "%s".', $expectedRoute, $route) + ); + + if (\count($parameters)) { + foreach ($parameters as $key => $expectedValue) { + static::assertRequestAttributeValueEquals($key, $expectedValue); + } + } + } + + public static function assertRequestAttributeValueEquals(string $key, $expectedValue): void + { + $request = static::checkRequestAvailable(); + + Assert::assertSame( + $expectedValue, + $value = $request->attributes->get($key), + sprintf('Expected request attribute "%s" value "%s" does not match actual value "%s".', $key, $expectedValue, $value) + ); + } + + protected static function getResponseCookieFromClient(string $name, string $path = '/', string $domain = null): ?Cookie + { + $cookies = static::getResponse()->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) use ($name, $path, $domain) { + return + $cookie->getName() === $name + && $cookie->getPath() === $path + && $cookie->getDomain() === $domain + ; + }); + + return reset($filteredCookies) ?: null; + } + + private static function getClientForAssertion(): Client + { + if (!static::$client instanceof Client) { + static::fail(\sprintf( + 'A client must be set to make assertions on it. Did you forget to call "%s::createClient"?', + static::class + )); + } + + return static::$client; + } + + private static function getCrawler(): Crawler + { + $client = static::getClientForAssertion(); + + if (!$client->getCrawler()) { + static::fail('A client must have a crawler to make assertions. Did you forget to make an HTTP request?'); + } + + return $client->getCrawler(); + } + + private static function getResponse(): Response + { + $client = static::getClientForAssertion(); + + if (!$client->getResponse()) { + static::fail('A client must have an HTTP Response to make assertions. Did you forget to make an HTTP request?'); + } + + return $client->getResponse(); + } + + private static function checkRequestAvailable(): Request + { + $client = static::getClientForAssertion(); + + if (!$client->getRequest()) { + static::fail('A client must have an HTTP Request to make assertions. Did you forget to make an HTTP request?'); + } + + return $client->getRequest(); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php index 5334d583610c8..cf6ab72cc59af 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php @@ -21,6 +21,16 @@ */ abstract class WebTestCase extends KernelTestCase { + use WebTestAssertions; + + protected function doTearDown(): void + { + parent::doTearDown(); + if (static::$client) { + static::$client = null; + } + } + /** * Creates a KernelBrowser. * @@ -44,6 +54,6 @@ protected static function createClient(array $options = [], array $server = []) $client->setServerParameters($server); - return $client; + return static::$client = $client; } } diff --git a/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php b/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php index 30d41059b2efe..c7d785e0a844b 100644 --- a/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php +++ b/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php @@ -45,17 +45,11 @@ protected function tearDown(): void */ trait TestCaseSetUpTearDownTrait { - /** - * @return void - */ - private function doSetUp() + private function doSetUp(): void { } - /** - * @return void - */ - private function doTearDown() + private function doTearDown(): void { } diff --git a/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php b/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php index be05bbb33f7c3..ad8d38c97f48d 100644 --- a/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php +++ b/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php @@ -45,17 +45,11 @@ protected function tearDown(): void */ trait TestCaseSetUpTearDownTrait { - /** - * @return void - */ - private function doSetUp() + private function doSetUp(): void { } - /** - * @return void - */ - private function doTearDown() + private function doTearDown(): void { } From ec1ded898a387fda980318b1c9e6e126f5be7912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= <dunglas@gmail.com> Date: Wed, 27 Jun 2018 11:46:32 +0200 Subject: [PATCH 353/495] [Validator] Add a HaveIBeenPwned password validator --- .../Validator/Constraints/NotPwned.php | 33 ++++ .../Constraints/NotPwnedValidator.php | 90 +++++++++++ .../Tests/Constraints/NotPwnedTest.php | 28 ++++ .../Constraints/NotPwnedValidatorTest.php | 145 ++++++++++++++++++ src/Symfony/Component/Validator/composer.json | 1 + 5 files changed, 297 insertions(+) create mode 100644 src/Symfony/Component/Validator/Constraints/NotPwned.php create mode 100644 src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php diff --git a/src/Symfony/Component/Validator/Constraints/NotPwned.php b/src/Symfony/Component/Validator/Constraints/NotPwned.php new file mode 100644 index 0000000000000..9872076b73546 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/NotPwned.php @@ -0,0 +1,33 @@ +<?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\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; + +/** + * Checks if a password has been leaked in a data breach. + * + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Kévin Dunglas <dunglas@gmail.com> + */ +class NotPwned extends Constraint +{ + const PWNED_ERROR = 'd9bcdbfe-a9d6-4bfa-a8ff-da5fd93e0f6d'; + + protected static $errorNames = [self::PWNED_ERROR => 'PWNED_ERROR']; + + public $message = 'This password has been leaked in a data breach, it must not be used. Please use another password.'; + public $threshold = 1; + public $skipOnError = false; +} diff --git a/src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php b/src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php new file mode 100644 index 0000000000000..d0beffb4f285b --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php @@ -0,0 +1,90 @@ +<?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\Component\Validator\Constraints; + +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * Checks if a password has been leaked in a data breach using haveibeenpwned.com's API. + * Use a k-anonymity model to protect the password being searched for. + * + * @see https://haveibeenpwned.com/API/v2#SearchingPwnedPasswordsByRange + * + * @author Kévin Dunglas <dunglas@gmail.com> + */ +class NotPwnedValidator extends ConstraintValidator +{ + private const RANGE_API = 'https://api.pwnedpasswords.com/range/%s'; + + private $httpClient; + + public function __construct(HttpClientInterface $httpClient = null) + { + if (null === $httpClient && !class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('The "%s" class requires the "HttpClient" component. Try running "composer require symfony/http-client".', self::class)); + } + + $this->httpClient = $httpClient ?? HttpClient::create(); + } + + /** + * {@inheritdoc} + * + * @throws ExceptionInterface + */ + public function validate($value, Constraint $constraint) + { + if (!$constraint instanceof NotPwned) { + throw new UnexpectedTypeException($constraint, NotPwned::class); + } + + if (null !== $value && !is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { + throw new UnexpectedTypeException($value, 'string'); + } + + $value = (string) $value; + if ('' === $value) { + return; + } + + $hash = strtoupper(sha1($value)); + $hashPrefix = substr($hash, 0, 5); + $url = sprintf(self::RANGE_API, $hashPrefix); + + try { + $result = $this->httpClient->request('GET', $url)->getContent(); + } catch (ExceptionInterface $e) { + if ($constraint->skipOnError) { + return; + } + + throw $e; + } + + foreach (explode("\r\n", $result) as $line) { + list($hashSuffix, $count) = explode(':', $line); + + if ($hashPrefix.$hashSuffix === $hash && $constraint->threshold <= (int) $count) { + $this->context->buildViolation($constraint->message) + ->setCode(NotPwned::PWNED_ERROR) + ->addViolation(); + + return; + } + } + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php new file mode 100644 index 0000000000000..7d312d828190b --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php @@ -0,0 +1,28 @@ +<?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\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\NotPwned; + +/** + * @author Kévin Dunglas <dunglas@gmail.com> + */ +class NotPwnedTest extends TestCase +{ + public function testDefaultValues() + { + $constraint = new NotPwned(); + $this->assertSame(1, $constraint->threshold); + $this->assertFalse($constraint->skipOnError); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php new file mode 100644 index 0000000000000..845ddbde3959f --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php @@ -0,0 +1,145 @@ +<?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\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Luhn; +use Symfony\Component\Validator\Constraints\NotPwned; +use Symfony\Component\Validator\Constraints\NotPwnedValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * @author Kévin Dunglas <dunglas@gmail.com> + */ +class NotPwnedValidatorTest extends ConstraintValidatorTestCase +{ + private const PASSWORD_TRIGGERING_AN_ERROR = 'apiError'; + private const PASSWORD_TRIGGERING_AN_ERROR_RANGE_URL = 'https://api.pwnedpasswords.com/range/3EF27'; // https://api.pwnedpasswords.com/range/3EF27 is the range for the value "apiError" + private const PASSWORD_LEAKED = 'maman'; + private const PASSWORD_NOT_LEAKED = ']<0585"%sb^5aa$w6!b38",,72?dp3r4\45b28Hy'; + + private const RETURN = [ + '35E033023A46402F94CFB4F654C5BFE44A1:1', + '35F079CECCC31812288257CD770AA7968D7:53', + '36039744C253F9B2A4E90CBEDB02EBFB82D:5', // this is the matching line, password: maman + '3686792BBC66A72D40D928ED15621124CFE:7', + '36EEC709091B810AA240179A44317ED415C:2', + ]; + + protected function createValidator() + { + $httpClientStub = $this->createMock(HttpClientInterface::class); + $httpClientStub->method('request')->will( + $this->returnCallback(function (string $method, string $url): ResponseInterface { + if (self::PASSWORD_TRIGGERING_AN_ERROR_RANGE_URL === $url) { + throw new class('Problem contacting the Have I been Pwned API.') extends \Exception implements ServerExceptionInterface { + public function getResponse(): ResponseInterface + { + throw new \RuntimeException('Not implemented'); + } + }; + } + + $responseStub = $this->createMock(ResponseInterface::class); + $responseStub + ->method('getContent') + ->willReturn(implode("\r\n", self::RETURN)); + + return $responseStub; + }) + ); + + // Pass HttpClient::create() instead of this mock to run the tests against the real API + return new NotPwnedValidator($httpClientStub); + } + + public function testNullIsValid() + { + $this->validator->validate(null, new NotPwned()); + + $this->assertNoViolation(); + } + + public function testEmptyStringIsValid() + { + $this->validator->validate('', new NotPwned()); + + $this->assertNoViolation(); + } + + public function testInvalidPassword() + { + $constraint = new NotPwned(); + $this->validator->validate(self::PASSWORD_LEAKED, $constraint); + + $this->buildViolation($constraint->message) + ->setCode(NotPwned::PWNED_ERROR) + ->assertRaised(); + } + + public function testThresholdReached() + { + $constraint = new NotPwned(['threshold' => 3]); + $this->validator->validate(self::PASSWORD_LEAKED, $constraint); + + $this->buildViolation($constraint->message) + ->setCode(NotPwned::PWNED_ERROR) + ->assertRaised(); + } + + public function testThresholdNotReached() + { + $this->validator->validate(self::PASSWORD_LEAKED, new NotPwned(['threshold' => 10])); + + $this->assertNoViolation(); + } + + public function testValidPassword() + { + $this->validator->validate(self::PASSWORD_NOT_LEAKED, new NotPwned()); + + $this->assertNoViolation(); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException + */ + public function testInvalidConstraint() + { + $this->validator->validate(null, new Luhn()); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException + */ + public function testInvalidValue() + { + $this->validator->validate([], new NotPwned()); + } + + /** + * @expectedException \Symfony\Contracts\HttpClient\Exception\ExceptionInterface + * @expectedExceptionMessage Problem contacting the Have I been Pwned API. + */ + public function testApiError() + { + $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotPwned()); + } + + public function testApiErrorSkipped() + { + $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotPwned(['skipOnError' => true])); + $this->assertTrue(true); // No exception have been thrown + } +} diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index c17fd098f5743..8cba722fc1c9f 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -22,6 +22,7 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { + "symfony/http-client": "^4.3", "symfony/http-foundation": "~4.1", "symfony/http-kernel": "~3.4|~4.0", "symfony/var-dumper": "~3.4|~4.0", From fefe62c4d04516a818bd5c031422ad95bd162748 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 1 Apr 2019 18:49:08 +0200 Subject: [PATCH 354/495] updated CHANGELOG --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 0a1aac70ed580..70528f35117e9 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added `NotPwned` constraint * added options `iban` and `ibanPropertyPath` to Bic constraint * added UATP cards support to `CardSchemeValidator` * added option `allowNull` to NotBlank constraint From 4f91020c8df64b6e4609c9ee1a317789a4498cdd Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 1 Apr 2019 07:28:23 +0200 Subject: [PATCH 355/495] added PHPUnit assertions in various components --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Test/WebTestAssertions.php | 359 +++++------------- .../FrameworkBundle/Test/WebTestCase.php | 8 +- .../Tests/Test/WebTestCaseTest.php | 288 ++++++++++++++ .../Bundle/FrameworkBundle/composer.json | 3 +- src/Symfony/Component/BrowserKit/CHANGELOG.md | 1 + .../Constraint/BrowserCookieValueSame.php | 75 ++++ .../Test/Constraint/BrowserHasCookie.php | 65 ++++ .../Constraint/BrowserCookieValueSameTest.php | 54 +++ .../Test/Constraint/BrowserHasCookieTest.php | 84 ++++ src/Symfony/Component/DomCrawler/CHANGELOG.md | 2 + .../CrawlerSelectorAttributeValueSame.php | 62 +++ .../Test/Constraint/CrawlerSelectorExists.php | 53 +++ .../CrawlerSelectorTextContains.php | 60 +++ .../Constraint/CrawlerSelectorTextSame.php | 60 +++ .../CrawlerSelectorAttributeValueSameTest.php | 38 ++ .../Constraint/CrawlerSelectorExistsTest.php | 39 ++ .../CrawlerSelectorTextContainsTest.php | 38 ++ .../CrawlerSelectorTextSameTest.php | 38 ++ .../Form/Test/TestCaseSetUpTearDownTrait.php | 10 +- .../Component/HttpFoundation/CHANGELOG.md | 2 + .../Constraint/RequestAttributeValueSame.php | 54 +++ .../Constraint/ResponseCookieValueSame.php | 85 +++++ .../Test/Constraint/ResponseHasCookie.php | 77 ++++ .../Test/Constraint/ResponseHasHeader.php | 53 +++ .../Test/Constraint/ResponseHeaderSame.php | 55 +++ .../Test/Constraint/ResponseIsRedirected.php | 56 +++ .../Test/Constraint/ResponseIsSuccessful.php | 56 +++ .../Constraint/ResponseStatusCodeSame.php | 63 +++ .../RequestAttributeValueSameTest.php | 41 ++ .../ResponseCookieValueSameTest.php | 44 +++ .../Test/Constraint/ResponseHasCookieTest.php | 42 ++ .../Test/Constraint/ResponseHasHeaderTest.php | 39 ++ .../Constraint/ResponseHeaderSameTest.php | 39 ++ .../Constraint/ResponseIsRedirectedTest.php | 39 ++ .../Constraint/ResponseIsSuccessfulTest.php | 39 ++ .../Constraint/ResponseStatusCodeSameTest.php | 41 ++ .../Test/TestCaseSetUpTearDownTrait.php | 10 +- 38 files changed, 1906 insertions(+), 267 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php create mode 100644 src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php create mode 100644 src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php create mode 100644 src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php create mode 100644 src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php create mode 100644 src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php create mode 100644 src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php create mode 100644 src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php create mode 100644 src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php create mode 100644 src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php create mode 100644 src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php create mode 100644 src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php create mode 100644 src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php create mode 100644 src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index ac3d97189822f..3d19141469a67 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added `WebTestAssertions` trait (included by default in `WebTestCase`) * renamed `Client` to `KernelBrowser` * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will be mandatory in 5.0. diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php index dbc6ef65ff75d..25eac6fe0ab38 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php @@ -11,12 +11,15 @@ namespace Symfony\Bundle\FrameworkBundle\Test; -use PHPUnit\Framework\Assert; -use Symfony\Bundle\FrameworkBundle\Client; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; +use Symfony\Component\BrowserKit\Test\Constraint as BrowserKitConstraint; use Symfony\Component\DomCrawler\Crawler; -use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\DomCrawler\Test\Constraint as DomCrawlerConstraint; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint as ResponseConstraint; /** * Ideas borrowed from Laravel Dusk's assertions. @@ -25,324 +28,168 @@ */ trait WebTestAssertions { - /** @var Client|null */ - protected static $client; - - public static function assertResponseIsSuccessful(): void + public static function assertResponseIsSuccessful(string $message = ''): void { - $response = static::getResponse(); - - Assert::assertTrue( - $response->isSuccessful(), - sprintf('Response was expected to be successful, but actual HTTP code is %d.', $response->getStatusCode()) - ); + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseIsSuccessful(), $message); } - public static function assertHttpCodeEquals(int $expectedCode): void + public static function assertResponseStatusCodeSame(int $expectedCode, string $message = ''): void { - Assert::assertSame( - $expectedCode, - $code = static::getResponse()->getStatusCode(), - sprintf('Response code "%s" does not match actual HTTP code "%s".', $expectedCode, $code) - ); + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseStatusCodeSame($expectedCode), $message); } - public static function assertResponseHasHeader(string $headerName): void + public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null, string $message = ''): void { - Assert::assertTrue( - static::getResponse()->headers->has($headerName), - sprintf('Header "%s" was not found in the Response.', $headerName) - ); - } + $constraint = new ResponseConstraint\ResponseIsRedirected(); + if ($expectedLocation) { + $constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseHeaderSame('Location', $expectedLocation)); + } + if ($expectedCode) { + $constraint = LogicalAnd::fromConstraints($constraint, new ResponseConstraint\ResponseStatusCodeSame($expectedCode)); + } - public static function assertResponseNotHasHeader(string $headerName): void - { - Assert::assertFalse( - static::getResponse()->headers->has($headerName), - sprintf('Header "%s" was not expected to be found in the Response.', $headerName) - ); + self::assertThat(static::getResponse(), $constraint, $message); } - public static function assertResponseHeaderEquals(string $headerName, $expectedValue): void + public static function assertResponseHasHeader(string $headerName, string $message = ''): void { - Assert::assertSame( - $expectedValue, - $value = static::getResponse()->headers->get($headerName, null, true), - sprintf('Header "%s" with value "%s" does not equal actual value "%s".', $headerName, $expectedValue, $value) - ); + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHasHeader($headerName), $message); } - public static function assertResponseHeaderNotEquals(string $headerName, $expectedValue): void + public static function assertResponseNotHasHeader(string $headerName, string $message = ''): void { - Assert::assertNotSame( - $expectedValue, - $value = static::getResponse()->headers->get($headerName, null, true), - sprintf('Header "%s" with value "%s" was not expected to equal actual value "%s".', $headerName, $expectedValue, $value) - ); + self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasHeader($headerName)), $message); } - public static function assertResponseRedirects(string $expectedLocation = null, int $expectedCode = null): void + public static function assertResponseHeaderSame(string $headerName, string $expectedValue, string $message = ''): void { - $response = static::getResponse(); - - Assert::assertTrue( - $response->isRedirect(), - sprintf('Response was expected to be a redirection, but actual HTTP code is %s.', $response->getStatusCode()) - ); - - if ($expectedCode) { - static::assertHttpCodeEquals($expectedCode); - } - - if (null !== $expectedLocation) { - Assert::assertSame( - $expectedLocation, - $location = $response->headers->get('Location'), - sprintf('Location "%s" does not match actual redirection URL "%s".', $expectedLocation, $location) - ); - } + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue), $message); } - public static function assertPageTitleEquals(string $expectedTitle): void + public static function assertResponseHeaderNotSame(string $headerName, string $expectedValue, string $message = ''): void { - $titleNode = static::getCrawler()->filter('title'); - - Assert::assertSame(1, $count = $titleNode->count(), sprintf('There must be one <title> tag in the current page but there is actually %s.', $count)); - - Assert::assertEquals( - $expectedTitle, - trim($title = $titleNode->text()), - sprintf('Expected title "%s" does not equal actual title "%s".', $expectedTitle, $title) - ); + self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHeaderSame($headerName, $expectedValue)), $message); } - public static function assertPageTitleContains(string $expectedTitle): void + public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void { - $titleNode = static::getCrawler()->filter('title'); - - Assert::assertSame(1, $count = $titleNode->count(), sprintf('There must be one <title> tag in the current page but there is actually %s.', $count)); - - Assert::assertContains( - $expectedTitle, - trim($title = $titleNode->text()), - sprintf('Expected title "%s" does not contain "%s".', $expectedTitle, $title) - ); + self::assertThat(static::getResponse(), new ResponseConstraint\ResponseHasCookie($name, $path, $domain), $message); } - public static function assertClientHasCookie(string $name, string $path = '/', string $domain = null): void + public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void { - static::getClientForAssertion(); - - Assert::assertNotNull( - static::$client->getCookieJar()->get($name, $path, $domain), - sprintf('Did not find expected cookie "%s".', $name) - ); + self::assertThat(static::getResponse(), new LogicalNot(new ResponseConstraint\ResponseHasCookie($name, $path, $domain)), $message); } - public static function assertClientNotHasCookie(string $name): void + public static function assertResponseCookieValueSame(string $name, string $expectedValue, string $path = '/', string $domain = null, string $message = ''): void { - static::getClientForAssertion(); - - $cookie = static::$client->getCookieJar()->get($name); - - Assert::assertNull( - $cookie, - sprintf('Cookie "%s" was not expected to be set.', $name) - ); + self::assertThat(static::getResponse(), LogicalAnd::fromConstraints( + new ResponseConstraint\ResponseHasCookie($name, $path, $domain), + new ResponseConstraint\ResponseCookieValueSame($name, $expectedValue, $path, $domain) + ), $message); } - public static function assertClientCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + public static function assertBrowserHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void { - static::getClientForAssertion(); - - $cookie = static::$client->getCookieJar()->get($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertSame( - $expectedValue, - $value = $cookie->getValue(), - sprintf('Cookie name "%s" with value "%s" does not match actual value "%s".', $name, $expectedValue, $value) - ); + self::assertThat(static::getClient(), new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), $message); } - public static function assertClientRawCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + public static function assertBrowserNotHasCookie(string $name, string $path = '/', string $domain = null, string $message = ''): void { - static::getClientForAssertion(); - - $cookie = static::$client->getCookieJar()->get($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertSame( - $expectedValue, - $value = $cookie->getRawValue(), - sprintf('Cookie name "%s" with raw value "%s" does not match actual value "%s".', $name, $expectedValue, $value) - ); + self::assertThat(static::getClient(), new LogicalNot(new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain)), $message); } - public static function assertResponseHasCookie(string $name, string $path = '/', string $domain = null): void + public static function assertBrowserCookieValueSame(string $name, string $expectedValue, bool $raw = false, string $path = '/', string $domain = null, string $message = ''): void { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); + self::assertThat(static::getClient(), LogicalAnd::fromConstraints( + new BrowserKitConstraint\BrowserHasCookie($name, $path, $domain), + new BrowserKitConstraint\BrowserCookieValueSame($name, $expectedValue, $raw, $path, $domain) + ), $message); } - public static function assertResponseNotHasCookie(string $name, string $path = '/', string $domain = null): void + public static function assertSelectorExists(string $selector, string $message = ''): void { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNull( - $cookie, - sprintf('Cookie "%s" was not expected to be set.', $name) - ); + self::assertThat(static::getCrawler(), new DomCrawlerConstraint\CrawlerSelectorExists($selector), $message); } - public static function assertResponseCookieValueEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + public static function assertSelectorNotExists(string $selector, string $message = ''): void { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertSame( - $expectedValue, - $value = $cookie->getValue(), - sprintf('Cookie name "%s" with value "%s" does not match actual value "%s".', $name, $expectedValue, $value) - ); + self::assertThat(static::getCrawler(), new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorExists($selector)), $message); } - public static function assertResponseCookieValueNotEquals(string $name, $expectedValue, string $path = '/', string $domain = null): void + public static function assertSelectorTextContains(string $selector, string $text, string $message = ''): void { - $cookie = static::getResponseCookieFromClient($name, $path, $domain); - - Assert::assertNotNull( - $cookie, - sprintf('Did not find expected cookie "%s".', $name) - ); - Assert::assertNotSame( - $expectedValue, - $value = $cookie->getValue(), - sprintf('Cookie name "%s" with value "%s" was not expected to be equal to actual value "%s".', $name, $expectedValue, $value) - ); + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists($selector), + new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text) + ), $message); } - public static function assertSelectorExists(string $selector): void + public static function assertSelectorTextSame(string $selector, string $text, string $message = ''): void { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists($selector), + new DomCrawlerConstraint\CrawlerSelectorTextSame($selector, $text) + ), $message); } - public static function assertSelectorNotExists(string $selector): void + public static function assertSelectorTextNotContains(string $selector, string $text, string $message = ''): void { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertEquals(0, $count = $nodes->count(), sprintf('Selector "%s" resolves to "%s" nodes where it expected 0.', $selector, $count)); + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists($selector), + new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorTextContains($selector, $text)) + ), $message); } - public static function assertSelectorContainsText(string $selector, string $text): void + public static function assertPageTitleSame(string $expectedTitle, string $message = ''): void { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); - - Assert::assertContains($text, $nodes->text(), sprintf('Selector "%s" does not contain text "%s".', $selector, $text)); + self::assertSelectorTextSame('title', $expectedTitle, $message); } - public static function assertSelectorNotContainsText(string $selector, string $text): void + public static function assertPageTitleContains(string $expectedTitle, string $message = ''): void { - $nodes = static::getCrawler()->filter($selector); - - Assert::assertGreaterThan(0, $nodes->count(), sprintf('Selector "%s" does not resolve to any node.', $selector)); - - Assert::assertNotContains($text, $nodes->text(), sprintf('Selector "%s" was expected to not contain text "%s".', $selector, $text)); + self::assertSelectorTextContains('title', $expectedTitle, $message); } - public static function assertInputValueEquals(string $fieldName, string $expectedValue): void + public static function assertInputValueSame(string $fieldName, string $expectedValue, string $message = ''): void { - $inputNode = static::getCrawler()->filter("input[name=\"$fieldName\"]"); - - Assert::assertGreaterThan(0, $inputNode->count(), sprintf('Input with name "%s" not found on the page.', $fieldName)); - - Assert::assertEquals( - $expectedValue, - $value = $inputNode->getNode(0)->getAttribute('value'), - sprintf('Expected value "%s" for the "%s" input does not equal the actual value "%s".', $value, $fieldName, $value) - ); + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"), + new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue) + ), $message); } - public static function assertInputValueNotEquals(string $fieldName, string $expectedValue): void + public static function assertInputValueNotSame(string $fieldName, string $expectedValue, string $message = ''): void { - $inputNode = static::getCrawler()->filter("input[name=\"$fieldName\"]"); - - Assert::assertGreaterThan(0, $inputNode->count(), sprintf('Input with name "%s" not found on the page.', $fieldName)); - - Assert::assertNotEquals( - $expectedValue, - $value = $inputNode->getNode(0)->getAttribute('value'), - sprintf('Expected value "%s" for the "%s" input was expected to not equal the actual value "%s".', $value, $fieldName, $value) - ); + self::assertThat(static::getCrawler(), LogicalAnd::fromConstraints( + new DomCrawlerConstraint\CrawlerSelectorExists("input[name=\"$fieldName\"]"), + new LogicalNot(new DomCrawlerConstraint\CrawlerSelectorAttributeValueSame("input[name=\"$fieldName\"]", 'value', $expectedValue)) + ), $message); } - public static function assertRouteEquals($expectedRoute, array $parameters = []): void + public static function assertRequestAttributeValueSame(string $name, string $expectedValue, string $message = ''): void { - $request = static::checkRequestAvailable(); - - Assert::assertSame( - $expectedRoute, - $route = $request->attributes->get('_route'), - sprintf('Expected route name "%s" does not match the actual value "%s".', $expectedRoute, $route) - ); - - if (\count($parameters)) { - foreach ($parameters as $key => $expectedValue) { - static::assertRequestAttributeValueEquals($key, $expectedValue); - } - } + self::assertThat(static::getRequest(), new ResponseConstraint\RequestAttributeValueSame($name, $expectedValue), $message); } - public static function assertRequestAttributeValueEquals(string $key, $expectedValue): void + public static function assertRouteSame($expectedRoute, array $parameters = [], string $message = ''): void { - $request = static::checkRequestAvailable(); - - Assert::assertSame( - $expectedValue, - $value = $request->attributes->get($key), - sprintf('Expected request attribute "%s" value "%s" does not match actual value "%s".', $key, $expectedValue, $value) - ); - } - - protected static function getResponseCookieFromClient(string $name, string $path = '/', string $domain = null): ?Cookie - { - $cookies = static::getResponse()->headers->getCookies(); - - $filteredCookies = array_filter($cookies, function (Cookie $cookie) use ($name, $path, $domain) { - return - $cookie->getName() === $name - && $cookie->getPath() === $path - && $cookie->getDomain() === $domain - ; - }); + $constraint = new ResponseConstraint\RequestAttributeValueSame('_route', $expectedRoute); + $constraints = []; + foreach ($parameters as $key => $value) { + $constraints[] = new ResponseConstraint\RequestAttributeValueSame($key, $value); + } + if ($constraints) { + $constraint = LogicalAnd::fromConstraints($constraint, ...$constraints); + } - return reset($filteredCookies) ?: null; + self::assertThat(static::getRequest(), $constraint, $message); } - private static function getClientForAssertion(): Client + private static function getClient(): KernelBrowser { - if (!static::$client instanceof Client) { - static::fail(\sprintf( - 'A client must be set to make assertions on it. Did you forget to call "%s::createClient"?', - static::class - )); + if (!static::$client instanceof KernelBrowser) { + static::fail(\sprintf('A client must be set to make assertions on it. Did you forget to call "%s::createClient"?', __CLASS__)); } return static::$client; @@ -350,34 +197,28 @@ private static function getClientForAssertion(): Client private static function getCrawler(): Crawler { - $client = static::getClientForAssertion(); - - if (!$client->getCrawler()) { + if (!$crawler = static::getClient()->getCrawler()) { static::fail('A client must have a crawler to make assertions. Did you forget to make an HTTP request?'); } - return $client->getCrawler(); + return $crawler; } private static function getResponse(): Response { - $client = static::getClientForAssertion(); - - if (!$client->getResponse()) { + if (!$response = static::getClient()->getResponse()) { static::fail('A client must have an HTTP Response to make assertions. Did you forget to make an HTTP request?'); } - return $client->getResponse(); + return $response; } - private static function checkRequestAvailable(): Request + private static function getRequest(): Request { - $client = static::getClientForAssertion(); - - if (!$client->getRequest()) { + if (!$request = static::getClient()->getRequest()) { static::fail('A client must have an HTTP Request to make assertions. Did you forget to make an HTTP request?'); } - return $client->getRequest(); + return $request; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php index cf6ab72cc59af..aa2b12ea296ec 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php @@ -23,12 +23,14 @@ abstract class WebTestCase extends KernelTestCase { use WebTestAssertions; + /** @var Client|null */ + protected static $client; + protected function doTearDown(): void { parent::doTearDown(); - if (static::$client) { - static::$client = null; - } + + static::$client = null; } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php new file mode 100644 index 0000000000000..92f200be1fab7 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php @@ -0,0 +1,288 @@ +<?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\Bundle\FrameworkBundle\Tests\Test; + +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\KernelBrowser; +use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertions; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; +use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\HttpFoundation\Cookie as HttpFoundationCookie; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +class WebTestCaseTest extends TestCase +{ + public function testAssertResponseIsSuccessful() + { + $this->getResponseTester(new Response())->assertResponseIsSuccessful(); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage("Failed asserting that the Response is successful.\nHTTP/1.0 404 Not Found"); + $this->getResponseTester(new Response('', 404))->assertResponseIsSuccessful(); + } + + public function testAssertResponseStatusCodeSame() + { + $this->getResponseTester(new Response())->assertResponseStatusCodeSame(200); + $this->getResponseTester(new Response('', 404))->assertResponseStatusCodeSame(404); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage("Failed asserting that the Response status code is 200.\nHTTP/1.0 404 Not Found"); + $this->getResponseTester(new Response('', 404))->assertResponseStatusCodeSame(200); + } + + public function testAssertResponseRedirects() + { + $this->getResponseTester(new Response('', 301))->assertResponseRedirects(); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage("Failed asserting that the Response is redirected.\nHTTP/1.0 200 OK"); + $this->getResponseTester(new Response())->assertResponseRedirects(); + } + + public function testAssertResponseRedirectsWithLocation() + { + $this->getResponseTester(new Response('', 301, ['Location' => 'https://example.com/']))->assertResponseRedirects('https://example.com/'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('is redirected and has header "Location" with value "https://example.com/".'); + $this->getResponseTester(new Response('', 301))->assertResponseRedirects('https://example.com/'); + } + + public function testAssertResponseRedirectsWithStatusCode() + { + $this->getResponseTester(new Response('', 302))->assertResponseRedirects(null, 302); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('is redirected and status code is 301.'); + $this->getResponseTester(new Response('', 302))->assertResponseRedirects(null, 301); + } + + public function testAssertResponseRedirectsWithLocationAndStatusCode() + { + $this->getResponseTester(new Response('', 302, ['Location' => 'https://example.com/']))->assertResponseRedirects('https://example.com/', 302); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('is redirected and has header "Location" with value "https://example.com/" and status code is 301.'); + $this->getResponseTester(new Response('', 302))->assertResponseRedirects('https://example.com/', 301); + } + + public function testAssertResponseHasHeader() + { + $this->getResponseTester(new Response())->assertResponseHasHeader('Date'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response has header "X-Date".'); + $this->getResponseTester(new Response())->assertResponseHasHeader('X-Date'); + } + + public function testAssertResponseNotHasHeader() + { + $this->getResponseTester(new Response())->assertResponseNotHasHeader('X-Date'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response does not have header "Date".'); + $this->getResponseTester(new Response())->assertResponseNotHasHeader('Date'); + } + + public function testAssertResponseHeaderSame() + { + $this->getResponseTester(new Response())->assertResponseHeaderSame('Cache-Control', 'no-cache, private'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response has header "Cache-Control" with value "public".'); + $this->getResponseTester(new Response())->assertResponseHeaderSame('Cache-Control', 'public'); + } + + public function testAssertResponseHeaderNotSame() + { + $this->getResponseTester(new Response())->assertResponseHeaderNotSame('Cache-Control', 'public'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response does not have header "Cache-Control" with value "no-cache, private".'); + $this->getResponseTester(new Response())->assertResponseHeaderNotSame('Cache-Control', 'no-cache, private'); + } + + public function testAssertResponseHasCookie() + { + $response = new Response(); + $response->headers->setCookie(HttpFoundationCookie::create('foo', 'bar')); + + $this->getResponseTester($response)->assertResponseHasCookie('foo'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response has cookie "bar".'); + $this->getResponseTester($response)->assertResponseHasCookie('bar'); + } + + public function testAssertResponseNotHasCookie() + { + $response = new Response(); + $response->headers->setCookie(HttpFoundationCookie::create('foo', 'bar')); + + $this->getResponseTester($response)->assertResponseNotHasCookie('bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Response does not have cookie "foo".'); + $this->getResponseTester($response)->assertResponseNotHasCookie('foo'); + } + + public function testAssertResponseCookieValueSame() + { + $response = new Response(); + $response->headers->setCookie(HttpFoundationCookie::create('foo', 'bar')); + + $this->getResponseTester($response)->assertResponseCookieValueSame('foo', 'bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('has cookie "bar" and has cookie "bar" with value "bar".'); + $this->getResponseTester($response)->assertResponseCookieValueSame('bar', 'bar'); + } + + public function testAssertBrowserHasCookie() + { + $this->getClientTester()->assertBrowserHasCookie('foo', '/path'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Browser has cookie "bar".'); + $this->getClientTester()->assertBrowserHasCookie('bar'); + } + + public function testAssertBrowserNotHasCookie() + { + $this->getClientTester()->assertBrowserNotHasCookie('bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Browser does not have cookie "foo" with path "/path".'); + $this->getClientTester()->assertBrowserNotHasCookie('foo', '/path'); + } + + public function testAssertBrowserCookieValueSame() + { + $this->getClientTester()->assertBrowserCookieValueSame('foo', 'bar', false, '/path'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('has cookie "foo" with path "/path" and has cookie "foo" with path "/path" with value "babar".'); + $this->getClientTester()->assertBrowserCookieValueSame('foo', 'babar', false, '/path'); + } + + public function testAssertSelectorExists() + { + $this->getCrawlerTester(new Crawler('<html><body><h1>'))->assertSelectorExists('body > h1'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "body > h1".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertSelectorExists('body > h1'); + } + + public function testAssertSelectorNotExists() + { + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertSelectorNotExists('body > h1'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('does not match selector "body > h1".'); + $this->getCrawlerTester(new Crawler('<html><body><h1>'))->assertSelectorNotExists('body > h1'); + } + + public function testAssertSelectorTextNotContains() + { + $this->getCrawlerTester(new Crawler('<html><body><h1>Foo'))->assertSelectorTextNotContains('body > h1', 'Bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "body > h1" and does not have a node matching selector "body > h1" with content containing "Foo".'); + $this->getCrawlerTester(new Crawler('<html><body><h1>Foo'))->assertSelectorTextNotContains('body > h1', 'Foo'); + } + + public function testAssertPageTitleSame() + { + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleSame('Foo'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "title" and has a node matching selector "title" with content "Bar".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleSame('Bar'); + } + + public function testAssertPageTitleContains() + { + $this->getCrawlerTester(new Crawler('<html><head><title>Foobar'))->assertPageTitleContains('Foo'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "title" and has a node matching selector "title" with content containing "Bar".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertPageTitleContains('Bar'); + } + + public function testAssertInputValueSame() + { + $this->getCrawlerTester(new Crawler('<html><body><form><input type="text" name="username" value="Fabien">'))->assertInputValueSame('username', 'Fabien'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "input[name="password"]" and has a node matching selector "input[name="password"]" with attribute "value" of value "pa$$".'); + $this->getCrawlerTester(new Crawler('<html><head><title>Foo'))->assertInputValueSame('password', 'pa$$'); + } + + public function testAssertInputValueNotSame() + { + $this->getCrawlerTester(new Crawler('<html><body><input type="text" name="username" value="Helene">'))->assertInputValueNotSame('username', 'Fabien'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('matches selector "input[name="password"]" and does not have a node matching selector "input[name="password"]" with attribute "value" of value "pa$$".'); + $this->getCrawlerTester(new Crawler('<html><body><form><input type="text" name="password" value="pa$$">'))->assertInputValueNotSame('password', 'pa$$'); + } + + public function testAssertRequestAttributeValueSame() + { + $this->getRequestTester()->assertRequestAttributeValueSame('foo', 'bar'); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Request has attribute "foo" with value "baz".'); + $this->getRequestTester()->assertRequestAttributeValueSame('foo', 'baz'); + } + + public function testAssertRouteSame() + { + $this->getRequestTester()->assertRouteSame('homepage', ['foo' => 'bar']); + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage('Failed asserting that the Request has attribute "_route" with value "articles".'); + $this->getRequestTester()->assertRouteSame('articles'); + } + + private function getResponseTester(Response $response): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $client->expects($this->any())->method('getResponse')->will($this->returnValue($response)); + + return $this->getTester($client); + } + + private function getCrawlerTester(Crawler $crawler): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $client->expects($this->any())->method('getCrawler')->will($this->returnValue($crawler)); + + return $this->getTester($client); + } + + private function getClientTester(): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $jar = new CookieJar(); + $jar->set(new Cookie('foo', 'bar', null, '/path', 'example.com')); + $client->expects($this->any())->method('getCookieJar')->will($this->returnValue($jar)); + + return $this->getTester($client); + } + + private function getRequestTester(): WebTestCase + { + $client = $this->createMock(KernelBrowser::class); + $request = new Request(); + $request->attributes->set('foo', 'bar'); + $request->attributes->set('_route', 'homepage'); + $client->expects($this->any())->method('getRequest')->will($this->returnValue($request)); + + return $this->getTester($client); + } + + private function getTester(KernelBrowser $client): WebTestCase + { + return new class($client) extends WebTestCase { + use WebTestAssertions; + + protected static $client; + + public function __construct(KernelBrowser $client) + { + static::$client = $client; + } + }; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 3e406515a9f0a..1b8ffc1e665dc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -36,7 +36,7 @@ "symfony/browser-kit": "^4.3", "symfony/console": "^4.3", "symfony/css-selector": "~3.4|~4.0", - "symfony/dom-crawler": "~3.4|~4.0", + "symfony/dom-crawler": "^4.3", "symfony/polyfill-intl-icu": "~1.0", "symfony/security": "~3.4|~4.0", "symfony/form": "^4.3", @@ -72,6 +72,7 @@ "symfony/browser-kit": "<4.3", "symfony/console": "<4.3", "symfony/dotenv": "<4.2", + "symfony/dom-crawler": "<4.3", "symfony/form": "<4.3", "symfony/messenger": "<4.3", "symfony/property-info": "<3.4", diff --git a/src/Symfony/Component/BrowserKit/CHANGELOG.md b/src/Symfony/Component/BrowserKit/CHANGELOG.md index b966974d8d716..323166a3d6cc5 100644 --- a/src/Symfony/Component/BrowserKit/CHANGELOG.md +++ b/src/Symfony/Component/BrowserKit/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * Added PHPUnit constraints: `BrowserCookieValueSame` and `BrowserHasCookie` * Added `HttpBrowser`, an implementation of a browser with the HttpClient component * Renamed `Client` to `AbstractBrowser` * Marked `Response` final. diff --git a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php new file mode 100644 index 0000000000000..f3103242c2109 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserCookieValueSame.php @@ -0,0 +1,75 @@ +<?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\Component\BrowserKit\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\BrowserKit\AbstractBrowser; + +final class BrowserCookieValueSame extends Constraint +{ + private $name; + private $value; + private $raw; + private $path; + private $domain; + + public function __construct(string $name, string $value, bool $raw = false, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + $this->value = $value; + $this->raw = $raw; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + $str .= sprintf(' with %svalue "%s"', $this->raw ? 'raw ' : '', $this->value); + + return $str; + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function matches($browser): bool + { + $cookie = $browser->getCookieJar()->get($this->name, $this->path, $this->domain); + if (!$cookie) { + return false; + } + + return $this->value === ($this->raw ? $cookie->getRawValue() : $cookie->getValue()); + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function failureDescription($browser): string + { + return 'the Browser '.$this->toString(); + } +} diff --git a/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php new file mode 100644 index 0000000000000..2b84a5e9b9bd7 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Test/Constraint/BrowserHasCookie.php @@ -0,0 +1,65 @@ +<?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\Component\BrowserKit\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\BrowserKit\AbstractBrowser; + +final class BrowserHasCookie extends Constraint +{ + private $name; + private $path; + private $domain; + + public function __construct(string $name, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + + return $str; + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function matches($browser): bool + { + return null !== $browser->getCookieJar()->get($this->name, $this->path, $this->domain); + } + + /** + * @param AbstractBrowser $browser + * + * {@inheritdoc} + */ + protected function failureDescription($browser): string + { + return 'the Browser '.$this->toString(); + } +} diff --git a/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php new file mode 100644 index 0000000000000..ea27473cdb660 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserCookieValueSameTest.php @@ -0,0 +1,54 @@ +<?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\Component\BrowserKit\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\BrowserKit\AbstractBrowser; +use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\Test\Constraint\BrowserCookieValueSame; + +class BrowserCookieValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserCookieValueSame('foo', 'bar', false, '/path'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserCookieValueSame('foo', 'bar', true, '/path'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserCookieValueSame('foo', 'babar', false, '/path'); + $this->assertFalse($constraint->evaluate($browser, '', true)); + + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"foo\" with path \"/path\" with value \"babar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + private function getBrowser(): AbstractBrowser + { + $browser = $this->createMock(AbstractBrowser::class); + $jar = new CookieJar(); + $jar->set(new Cookie('foo', 'bar', null, '/path', 'example.com')); + $browser->expects($this->any())->method('getCookieJar')->will($this->returnValue($jar)); + + return $browser; + } +} diff --git a/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php new file mode 100644 index 0000000000000..2f40c0257f683 --- /dev/null +++ b/src/Symfony/Component/BrowserKit/Tests/Test/Constraint/BrowserHasCookieTest.php @@ -0,0 +1,84 @@ +<?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\Component\BrowserKit\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\BrowserKit\AbstractBrowser; +use Symfony\Component\BrowserKit\Cookie; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\Test\Constraint\BrowserHasCookie; + +class BrowserHasCookieTest extends TestCase +{ + public function testConstraint(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserHasCookie('foo', '/path'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserHasCookie('foo', '/path', 'example.com'); + $this->assertTrue($constraint->evaluate($browser, '', true)); + $constraint = new BrowserHasCookie('bar'); + $this->assertFalse($constraint->evaluate($browser, '', true)); + + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"bar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + public function testConstraintWithWrongPath(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserHasCookie('foo', '/other'); + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"foo\" with path \"/other\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + public function testConstraintWithWrongDomain(): void + { + $browser = $this->getBrowser(); + $constraint = new BrowserHasCookie('foo', '/path', 'example.org'); + try { + $constraint->evaluate($browser); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Browser has cookie \"foo\" with path \"/path\" for domain \"example.org\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } + + private function getBrowser(): AbstractBrowser + { + $browser = $this->createMock(AbstractBrowser::class); + $jar = new CookieJar(); + $jar->set(new Cookie('foo', 'bar', null, '/path', 'example.com')); + $browser->expects($this->any())->method('getCookieJar')->will($this->returnValue($jar)); + + return $browser; + } +} diff --git a/src/Symfony/Component/DomCrawler/CHANGELOG.md b/src/Symfony/Component/DomCrawler/CHANGELOG.md index fae5bd3f1d915..4b79e96f7c2b9 100644 --- a/src/Symfony/Component/DomCrawler/CHANGELOG.md +++ b/src/Symfony/Component/DomCrawler/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- +* Added PHPUnit constraints: `CrawlerSelectorAttributeValueSame`, `CrawlerSelectorExists`, `CrawlerSelectorTextContains`` + and `CrawlerSelectorTextSame` * Added return of element name (`_name`) in `extract()` method. * Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php new file mode 100644 index 0000000000000..962b6bf0b1dc4 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorAttributeValueSame.php @@ -0,0 +1,62 @@ +<?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\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorAttributeValueSame extends Constraint +{ + private $selector; + private $attribute; + private $expectedText; + + public function __construct(string $selector, string $attribute, string $expectedText) + { + $this->selector = $selector; + $this->attribute = $attribute; + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has a node matching selector "%s" with attribute "%s" of value "%s"', $this->selector, $this->attribute, $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return $this->expectedText === trim($crawler->getNode(0)->getAttribute($this->attribute)); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php new file mode 100644 index 0000000000000..112b772b13e87 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorExists.php @@ -0,0 +1,53 @@ +<?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\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorExists extends Constraint +{ + private $selector; + + public function __construct(string $selector) + { + $this->selector = $selector; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('matches selector "%s"', $this->selector); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + return 0 < \count($crawler->filter($this->selector)); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php new file mode 100644 index 0000000000000..260ec57b07504 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextContains.php @@ -0,0 +1,60 @@ +<?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\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorTextContains extends Constraint +{ + private $selector; + private $expectedText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has a node matching selector "%s" with content containing "%s"', $this->selector, $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return false !== \mb_strpos($crawler->text(), $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php new file mode 100644 index 0000000000000..30271f01917a2 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Test/Constraint/CrawlerSelectorTextSame.php @@ -0,0 +1,60 @@ +<?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\Component\DomCrawler\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\DomCrawler\Crawler; + +final class CrawlerSelectorTextSame extends Constraint +{ + private $selector; + private $expectedText; + + public function __construct(string $selector, string $expectedText) + { + $this->selector = $selector; + $this->expectedText = $expectedText; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has a node matching selector "%s" with content "%s"', $this->selector, $this->expectedText); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function matches($crawler): bool + { + $crawler = $crawler->filter($this->selector); + if (!\count($crawler)) { + return false; + } + + return $this->expectedText === trim($crawler->text()); + } + + /** + * @param Crawler $crawler + * + * {@inheritdoc} + */ + protected function failureDescription($crawler): string + { + return 'the Crawler '.$this->toString(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php new file mode 100644 index 0000000000000..9a3716d64f5f4 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorAttributeValueSameTest.php @@ -0,0 +1,38 @@ +<?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\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorAttributeValueSame; + +class CrawlerSelectorAttributeValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorAttributeValueSame('input[name="username"]', 'value', 'Fabien'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><body><form><input type="text" name="username" value="Fabien">'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>Bar')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"input[name=\"username\"]\" with attribute \"value\" of value \"Fabien\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php new file mode 100644 index 0000000000000..f80bd66706ef2 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorExistsTest.php @@ -0,0 +1,39 @@ +<?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\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorExists; + +class CrawlerSelectorExistsTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorExists('title'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>'), '', true)); + $constraint = new CrawlerSelectorExists('h1'); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler matches selector \"h1\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php new file mode 100644 index 0000000000000..d61647c38823d --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextContainsTest.php @@ -0,0 +1,38 @@ +<?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\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorTextContains; + +class CrawlerSelectorTextContainsTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorTextContains('title', 'Foo'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>Foobar'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>Bar')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"title\" with content containing \"Foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php new file mode 100644 index 0000000000000..f394abbc26e91 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Test/Constraint/CrawlerSelectorTextSameTest.php @@ -0,0 +1,38 @@ +<?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\Component\DomCrawler\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Test\Constraint\CrawlerSelectorTextSame; + +class CrawlerSelectorTextSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new CrawlerSelectorTextSame('title', 'Foo'); + $this->assertTrue($constraint->evaluate(new Crawler('<html><head><title>Foo'), '', true)); + $this->assertFalse($constraint->evaluate(new Crawler('<html><head><title>Bar'), '', true)); + + try { + $constraint->evaluate(new Crawler('<html><head><title>Bar')); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Crawler has a node matching selector \"title\" with content \"Foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php b/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php index c7d785e0a844b..30d41059b2efe 100644 --- a/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php +++ b/src/Symfony/Component/Form/Test/TestCaseSetUpTearDownTrait.php @@ -45,11 +45,17 @@ protected function tearDown(): void */ trait TestCaseSetUpTearDownTrait { - private function doSetUp(): void + /** + * @return void + */ + private function doSetUp() { } - private function doTearDown(): void + /** + * @return void + */ + private function doTearDown() { } diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 5ce8df848b1a0..17a0dcc721d00 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * added PHPUnit constraints: `RequestAttributeValueSame`, `ResponseCookieValueSame`, `ResponseHasCookie`, + `ResponseHasHeader`, `ResponseHeaderSame`, `ResponseIsRedirected`, `ResponseIsSuccessful`, and `ResponseStatusCodeSame` * deprecated `MimeTypeGuesserInterface` and `ExtensionGuesserInterface` in favor of `Symfony\Component\Mime\MimeTypesInterface`. * deprecated `MimeType` and `MimeTypeExtensionGuesser` in favor of `Symfony\Component\Mime\MimeTypes`. * deprecated `FileBinaryMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileBinaryMimeTypeGuesser`. diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php new file mode 100644 index 0000000000000..2d105627860ef --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/RequestAttributeValueSame.php @@ -0,0 +1,54 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; + +final class RequestAttributeValueSame extends Constraint +{ + private $name; + private $value; + + public function __construct(string $name, string $value) + { + $this->name = $name; + $this->value = $value; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has attribute "%s" with value "%s"', $this->name, $this->value); + } + + /** + * @param Request $request + * + * {@inheritdoc} + */ + protected function matches($request): bool + { + return $this->value === $request->attributes->get($this->name); + } + + /** + * @param Request $request + * + * {@inheritdoc} + */ + protected function failureDescription($request): string + { + return 'the Request '.$this->toString(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php new file mode 100644 index 0000000000000..554e1a1602dd6 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseCookieValueSame.php @@ -0,0 +1,85 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseCookieValueSame extends Constraint +{ + private $name; + private $value; + private $path; + private $domain; + + public function __construct(string $name, string $value, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->value = $value; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + $str .= sprintf(' with value "%s"', $this->value); + + return $str; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + $cookie = $this->getCookie($response); + if (!$cookie) { + return false; + } + + return $this->value === $cookie->getValue(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + protected function getCookie(Response $response): ?Cookie + { + $cookies = $response->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) { + return $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain; + }); + + return reset($filteredCookies) ?: null; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php new file mode 100644 index 0000000000000..bd792b0d876b2 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasCookie.php @@ -0,0 +1,77 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHasCookie extends Constraint +{ + private $name; + private $path; + private $domain; + + public function __construct(string $name, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + + return $str; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return null !== $this->getCookie($response); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + protected function getCookie(Response $response): ?Cookie + { + $cookies = $response->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) { + return $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain; + }); + + return reset($filteredCookies) ?: null; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php new file mode 100644 index 0000000000000..68ad8273fd568 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHasHeader.php @@ -0,0 +1,53 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHasHeader extends Constraint +{ + private $headerName; + + public function __construct(string $headerName) + { + $this->headerName = $headerName; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s"', $this->headerName); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->headers->has($this->headerName); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php new file mode 100644 index 0000000000000..acdea71d154ec --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseHeaderSame.php @@ -0,0 +1,55 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHeaderSame extends Constraint +{ + private $headerName; + private $expectedValue; + + public function __construct(string $headerName, string $expectedValue) + { + $this->headerName = $headerName; + $this->expectedValue = $expectedValue; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->expectedValue === $response->headers->get($this->headerName, null, true); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php new file mode 100644 index 0000000000000..8c4b883f0b076 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsRedirected.php @@ -0,0 +1,56 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsRedirected extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is redirected'; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->isRedirect(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php new file mode 100644 index 0000000000000..9c665589072b7 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseIsSuccessful.php @@ -0,0 +1,56 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsSuccessful extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is successful'; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->isSuccessful(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php new file mode 100644 index 0000000000000..72bb000b8592c --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Test/Constraint/ResponseStatusCodeSame.php @@ -0,0 +1,63 @@ +<?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\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseStatusCodeSame extends Constraint +{ + private $statusCode; + + public function __construct(int $statusCode) + { + $this->statusCode = $statusCode; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'status code is '.$this->statusCode; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->statusCode === $response->getStatusCode(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php new file mode 100644 index 0000000000000..eca8aed263e21 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php @@ -0,0 +1,41 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Test\Constraint\RequestAttributeValueSame; + +class RequestAttributeValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $request = new Request(); + $request->attributes->set('foo', 'bar'); + $constraint = new RequestAttributeValueSame('foo', 'bar'); + $this->assertTrue($constraint->evaluate($request, '', true)); + $constraint = new RequestAttributeValueSame('bar', 'foo'); + $this->assertFalse($constraint->evaluate($request, '', true)); + + try { + $constraint->evaluate($request); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Request has attribute \"bar\" with value \"foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php new file mode 100644 index 0000000000000..778879c328f0d --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php @@ -0,0 +1,44 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseCookieValueSame; + +class ResponseCookieValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $response = new Response(); + $response->headers->setCookie(Cookie::create('foo', 'bar', 0, '/path')); + $constraint = new ResponseCookieValueSame('foo', 'bar', '/path'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseCookieValueSame('foo', 'bar', '/path'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseCookieValueSame('foo', 'babar', '/path'); + $this->assertFalse($constraint->evaluate($response, '', true)); + + try { + $constraint->evaluate($response); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has cookie \"foo\" with path \"/path\" with value \"babar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php new file mode 100644 index 0000000000000..05ca95fb4656d --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasCookieTest.php @@ -0,0 +1,42 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasCookie; + +class ResponseHasCookieTest extends TestCase +{ + public function testConstraint(): void + { + $response = new Response(); + $response->headers->setCookie(Cookie::create('foo', 'bar')); + $constraint = new ResponseHasCookie('foo'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseHasCookie('bar'); + $this->assertFalse($constraint->evaluate($response, '', true)); + + try { + $constraint->evaluate($response); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has cookie \"bar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php new file mode 100644 index 0000000000000..7b811a64a2bcc --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHasHeaderTest.php @@ -0,0 +1,39 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasHeader; + +class ResponseHasHeaderTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseHasHeader('Date'); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $constraint = new ResponseHasHeader('X-Date'); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has header \"X-Date\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php new file mode 100644 index 0000000000000..d527f35de8c28 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseHeaderSameTest.php @@ -0,0 +1,39 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHeaderSame; + +class ResponseHeaderSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseHeaderSame('Cache-Control', 'no-cache, private'); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $constraint = new ResponseHeaderSame('Cache-Control', 'public'); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has header \"Cache-Control\" with value \"public\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php new file mode 100644 index 0000000000000..a3a460636a280 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php @@ -0,0 +1,39 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsRedirected; + +class ResponseIsRedirectedTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseIsRedirected(); + + $this->assertTrue($constraint->evaluate(new Response('', 301), '', true)); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response is redirected.\nHTTP/1.0 200 OK", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php new file mode 100644 index 0000000000000..0c99a5e484f56 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php @@ -0,0 +1,39 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsSuccessful; + +class ResponseIsSuccessfulTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseIsSuccessful(); + + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $this->assertFalse($constraint->evaluate(new Response('', 404), '', true)); + + try { + $constraint->evaluate(new Response('', 404)); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response is successful.\nHTTP/1.0 404 Not Found", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php new file mode 100644 index 0000000000000..3e15e90673a78 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php @@ -0,0 +1,41 @@ +<?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\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseStatusCodeSame; + +class ResponseStatusCodeSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseStatusCodeSame(200); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $this->assertFalse($constraint->evaluate(new Response('', 404), '', true)); + $constraint = new ResponseStatusCodeSame(404); + $this->assertTrue($constraint->evaluate(new Response('', 404), '', true)); + + $constraint = new ResponseStatusCodeSame(200); + try { + $constraint->evaluate(new Response('', 404)); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response status code is 200.\nHTTP/1.0 404 Not Found", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php b/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php index ad8d38c97f48d..be05bbb33f7c3 100644 --- a/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php +++ b/src/Symfony/Component/Validator/Test/TestCaseSetUpTearDownTrait.php @@ -45,11 +45,17 @@ protected function tearDown(): void */ trait TestCaseSetUpTearDownTrait { - private function doSetUp(): void + /** + * @return void + */ + private function doSetUp() { } - private function doTearDown(): void + /** + * @return void + */ + private function doTearDown() { } From dcba01d2123be30a6dc95e2350a6affebb499246 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto <yonelceruto@gmail.com> Date: Mon, 1 Apr 2019 16:27:30 -0400 Subject: [PATCH 356/495] Add file links for described classes --- .../Resources/config/console.xml | 1 + .../Component/Form/Command/DebugCommand.php | 7 ++- .../Console/Descriptor/TextDescriptor.php | 50 ++++++++++++++++--- .../Form/Console/Helper/DescriptorHelper.php | 5 +- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index f753b214192da..050144e5a8b24 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -160,6 +160,7 @@ <argument type="collection" /> <!-- All services form types are stored here by FormPass --> <argument type="collection" /> <!-- All type extensions are stored here by FormPass --> <argument type="collection" /> <!-- All type guessers are stored here by FormPass --> + <argument type="service" id="debug.file_link_formatter" on-invalid="null" /> <tag name="console.command" command="debug:form" /> </service> </services> diff --git a/src/Symfony/Component/Form/Command/DebugCommand.php b/src/Symfony/Component/Form/Command/DebugCommand.php index 3a86e2669192c..5aed307f44cdd 100644 --- a/src/Symfony/Component/Form/Command/DebugCommand.php +++ b/src/Symfony/Component/Form/Command/DebugCommand.php @@ -22,6 +22,7 @@ use Symfony\Component\Form\Extension\Core\CoreExtension; use Symfony\Component\Form\FormRegistryInterface; use Symfony\Component\Form\FormTypeInterface; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; /** * A console command for retrieving information about form types. @@ -37,8 +38,9 @@ class DebugCommand extends Command private $types; private $extensions; private $guessers; + private $fileLinkFormatter; - public function __construct(FormRegistryInterface $formRegistry, array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], array $types = [], array $extensions = [], array $guessers = []) + public function __construct(FormRegistryInterface $formRegistry, array $namespaces = ['Symfony\Component\Form\Extension\Core\Type'], array $types = [], array $extensions = [], array $guessers = [], FileLinkFormatter $fileLinkFormatter = null) { parent::__construct(); @@ -47,6 +49,7 @@ public function __construct(FormRegistryInterface $formRegistry, array $namespac $this->types = $types; $this->extensions = $extensions; $this->guessers = $guessers; + $this->fileLinkFormatter = $fileLinkFormatter; } /** @@ -145,7 +148,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - $helper = new DescriptorHelper(); + $helper = new DescriptorHelper($this->fileLinkFormatter); $options['format'] = $input->getOption('format'); $options['show_deprecated'] = $input->getOption('show-deprecated'); $helper->describe($io, $object, $options); diff --git a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php index da0fc652f6d21..176be3cd7b8df 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php @@ -14,6 +14,7 @@ use Symfony\Component\Console\Helper\Dumper; use Symfony\Component\Console\Helper\TableSeparator; use Symfony\Component\Form\ResolvedFormTypeInterface; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\OptionsResolver\OptionsResolver; /** @@ -23,11 +24,20 @@ */ class TextDescriptor extends Descriptor { + private $fileLinkFormatter; + + public function __construct(FileLinkFormatter $fileLinkFormatter = null) + { + $this->fileLinkFormatter = $fileLinkFormatter; + } + protected function describeDefaults(array $options) { if ($options['core_types']) { $this->output->section('Built-in form types (Symfony\Component\Form\Extension\Core\Type)'); - $shortClassNames = array_map(function ($fqcn) { return \array_slice(explode('\\', $fqcn), -1)[0]; }, $options['core_types']); + $shortClassNames = array_map(function ($fqcn) { + return $this->formatClassLink($fqcn, \array_slice(explode('\\', $fqcn), -1)[0]); + }, $options['core_types']); for ($i = 0, $loopsMax = \count($shortClassNames); $i * 5 < $loopsMax; ++$i) { $this->output->writeln(' '.implode(', ', \array_slice($shortClassNames, $i * 5, 5))); } @@ -35,18 +45,18 @@ protected function describeDefaults(array $options) if ($options['service_types']) { $this->output->section('Service form types'); - $this->output->listing($options['service_types']); + $this->output->listing(array_map([$this, 'formatClassLink'], $options['service_types'])); } if (!$options['show_deprecated']) { if ($options['extensions']) { $this->output->section('Type extensions'); - $this->output->listing($options['extensions']); + $this->output->listing(array_map([$this, 'formatClassLink'], $options['extensions'])); } if ($options['guessers']) { $this->output->section('Type guessers'); - $this->output->listing($options['guessers']); + $this->output->listing(array_map([$this, 'formatClassLink'], $options['guessers'])); } } } @@ -82,12 +92,12 @@ protected function describeResolvedFormType(ResolvedFormTypeInterface $resolvedF if ($this->parents) { $this->output->section('Parent types'); - $this->output->listing($this->parents); + $this->output->listing(array_map([$this, 'formatClassLink'], $this->parents)); } if ($this->extensions) { $this->output->section('Type extensions'); - $this->output->listing($this->extensions); + $this->output->listing(array_map([$this, 'formatClassLink'], $this->extensions)); } } @@ -178,4 +188,32 @@ private function normalizeAndSortOptionsColumns(array $options) return $options; } + + private function formatClassLink(string $class, string $text = null): string + { + if (null === $text) { + $text = $class; + } + + if ('' === $fileLink = $this->getFileLink($class)) { + return $text; + } + + return sprintf('<href=%s>%s</>', $fileLink, $text); + } + + private function getFileLink(string $class): string + { + if (null === $this->fileLinkFormatter) { + return ''; + } + + try { + $r = new \ReflectionClass($class); + } catch (\ReflectionException $e) { + return ''; + } + + return (string) $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine()); + } } diff --git a/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php b/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php index e850324c01712..355fb95989a36 100644 --- a/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php +++ b/src/Symfony/Component/Form/Console/Helper/DescriptorHelper.php @@ -14,6 +14,7 @@ use Symfony\Component\Console\Helper\DescriptorHelper as BaseDescriptorHelper; use Symfony\Component\Form\Console\Descriptor\JsonDescriptor; use Symfony\Component\Form\Console\Descriptor\TextDescriptor; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; /** * @author Yonel Ceruto <yonelceruto@gmail.com> @@ -22,10 +23,10 @@ */ class DescriptorHelper extends BaseDescriptorHelper { - public function __construct() + public function __construct(FileLinkFormatter $fileLinkFormatter = null) { $this - ->register('txt', new TextDescriptor()) + ->register('txt', new TextDescriptor($fileLinkFormatter)) ->register('json', new JsonDescriptor()) ; } From 05e2e1e08896f7c8afd37029539705676699cad2 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto <yonelceruto@gmail.com> Date: Mon, 1 Apr 2019 18:40:03 -0400 Subject: [PATCH 357/495] Add template file link --- .../Bridge/Twig/Command/DebugCommand.php | 40 +++++++++++++++---- .../TwigBundle/Resources/config/console.xml | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Command/DebugCommand.php b/src/Symfony/Bridge/Twig/Command/DebugCommand.php index 0c1e462fcfafe..e197f4c4bcbcc 100644 --- a/src/Symfony/Bridge/Twig/Command/DebugCommand.php +++ b/src/Symfony/Bridge/Twig/Command/DebugCommand.php @@ -19,6 +19,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Finder\Finder; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Twig\Environment; use Twig\Loader\ChainLoader; use Twig\Loader\FilesystemLoader; @@ -38,8 +39,9 @@ class DebugCommand extends Command private $twigDefaultPath; private $rootDir; private $filesystemLoaders; + private $fileLinkFormatter; - public function __construct(Environment $twig, string $projectDir = null, array $bundlesMetadata = [], string $twigDefaultPath = null, string $rootDir = null) + public function __construct(Environment $twig, string $projectDir = null, array $bundlesMetadata = [], string $twigDefaultPath = null, string $rootDir = null, FileLinkFormatter $fileLinkFormatter = null) { parent::__construct(); @@ -48,6 +50,7 @@ public function __construct(Environment $twig, string $projectDir = null, array $this->bundlesMetadata = $bundlesMetadata; $this->twigDefaultPath = $twigDefaultPath; $this->rootDir = $rootDir; + $this->fileLinkFormatter = $fileLinkFormatter; } protected function configure() @@ -105,16 +108,28 @@ protected function execute(InputInterface $input, OutputInterface $output) private function displayPathsText(SymfonyStyle $io, string $name) { - $files = $this->findTemplateFiles($name); + $file = new \ArrayIterator($this->findTemplateFiles($name)); $paths = $this->getLoaderPaths($name); $io->section('Matched File'); - if ($files) { - $io->success(array_shift($files)); + if ($file->valid()) { + if ($fileLink = $this->getFileLink($file->key())) { + $io->block($file->current(), 'OK', sprintf('fg=black;bg=green;href=%s', $fileLink), ' ', true); + } else { + $io->success($file->current()); + } + $file->next(); - if ($files) { + if ($file->valid()) { $io->section('Overridden Files'); - $io->listing($files); + do { + if ($fileLink = $this->getFileLink($file->key())) { + $io->text(sprintf('* <href=%s>%s</>', $fileLink, $file->current())); + } else { + $io->text(sprintf('* %s', $file->current())); + } + $file->next(); + } while ($file->valid()); } } else { $alternatives = []; @@ -453,9 +468,9 @@ private function findTemplateFiles(string $name): array if (is_file($filename)) { if (false !== $realpath = realpath($filename)) { - $files[] = $this->getRelativePath($realpath); + $files[$realpath] = $this->getRelativePath($realpath); } else { - $files[] = $this->getRelativePath($filename); + $files[$filename] = $this->getRelativePath($filename); } } } @@ -563,4 +578,13 @@ private function getFilesystemLoaders(): array return $this->filesystemLoaders; } + + private function getFileLink(string $absolutePath): string + { + if (null === $this->fileLinkFormatter) { + return ''; + } + + return (string) $this->fileLinkFormatter->format($absolutePath, 1); + } } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml index 25b21d7587c95..03e75a405f50d 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/console.xml @@ -13,6 +13,7 @@ <argument>%kernel.bundles_metadata%</argument> <argument>%twig.default_path%</argument> <argument>%kernel.root_dir%</argument> + <argument type="service" id="debug.file_link_formatter" on-invalid="null" /> <tag name="console.command" command="debug:twig" /> </service> From c3477badbcb517df3be95d6294a9d740dd0d7cac Mon Sep 17 00:00:00 2001 From: Roland Franssen <franssen.roland@gmail.com> Date: Sun, 25 Nov 2018 08:41:16 +0100 Subject: [PATCH 358/495] [EventDispatcher] Split events across requests --- .../Resources/config/collectors.xml | 1 + .../Resources/config/debug.xml | 1 + .../Debug/TraceableEventDispatcher.php | 53 +++++++++++++------ .../TraceableEventDispatcherInterface.php | 9 +++- .../Component/EventDispatcher/composer.json | 1 + .../DataCollector/EventDataCollector.php | 13 +++-- 6 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml index c745949b43116..17df61db1c13a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/collectors.xml @@ -28,6 +28,7 @@ <service id="data_collector.events" class="Symfony\Component\HttpKernel\DataCollector\EventDataCollector"> <tag name="data_collector" template="@WebProfiler/Collector/events.html.twig" id="events" priority="290" /> <argument type="service" id="debug.event_dispatcher" on-invalid="ignore" /> + <argument type="service" id="request_stack" on-invalid="ignore" /> </service> <service id="data_collector.logger" class="Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector"> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml index 9b39912087110..abd0733e0cbd3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug.xml @@ -12,6 +12,7 @@ <argument type="service" id="debug.event_dispatcher.inner" /> <argument type="service" id="debug.stopwatch" /> <argument type="service" id="logger" on-invalid="null" /> + <argument type="service" id="request_stack" on-invalid="null" /> </service> <service id="debug.controller_resolver" decorates="controller_resolver" class="Symfony\Component\HttpKernel\Controller\TraceableControllerResolver"> diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index e0a161ebde478..e5b79276c62c9 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -13,10 +13,12 @@ use Psr\EventDispatcher\StoppableEventInterface; use Psr\Log\LoggerInterface; +use Symfony\Component\BrowserKit\Request; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; @@ -36,14 +38,17 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface private $dispatcher; private $wrappedListeners; private $orphanedEvents; + private $requestStack; + private $currentRequestHash = ''; - public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null) + public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null) { $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); $this->stopwatch = $stopwatch; $this->logger = $logger; $this->wrappedListeners = []; $this->orphanedEvents = []; + $this->requestStack = $requestStack; } /** @@ -133,6 +138,7 @@ public function dispatch($event/*, string $eventName = null*/) $this->callStack = new \SplObjectStorage(); } + $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; $eventName = 1 < \func_num_args() ? \func_get_arg(1) : null; if (\is_object($event)) { @@ -168,6 +174,7 @@ public function dispatch($event/*, string $eventName = null*/) $this->afterDispatch($eventName, $event); } } finally { + $this->currentRequestHash = $currentRequestHash; $this->postProcess($eventName); } @@ -176,18 +183,22 @@ public function dispatch($event/*, string $eventName = null*/) /** * {@inheritdoc} + * + * @param Request|null $request The request to get listeners for */ - public function getCalledListeners() + public function getCalledListeners(/* Request $request = null */) { if (null === $this->callStack) { return []; } + $hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null; $called = []; foreach ($this->callStack as $listener) { - list($eventName) = $this->callStack->getInfo(); - - $called[] = $listener->getInfo($eventName); + list($eventName, $requestHash) = $this->callStack->getInfo(); + if (null === $hash || $hash === $requestHash) { + $called[] = $listener->getInfo($eventName); + } } return $called; @@ -195,8 +206,10 @@ public function getCalledListeners() /** * {@inheritdoc} + * + * @param Request|null $request The request to get listeners for */ - public function getNotCalledListeners() + public function getNotCalledListeners(/* Request $request = null */) { try { $allListeners = $this->getListeners(); @@ -209,13 +222,15 @@ public function getNotCalledListeners() return []; } + $hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null; $notCalled = []; foreach ($allListeners as $eventName => $listeners) { foreach ($listeners as $listener) { $called = false; if (null !== $this->callStack) { foreach ($this->callStack as $calledListener) { - if ($calledListener->getWrappedListener() === $listener) { + list(, $requestHash) = $this->callStack->getInfo(); + if ((null === $hash || $hash === $requestHash) && $calledListener->getWrappedListener() === $listener) { $called = true; break; @@ -237,15 +252,27 @@ public function getNotCalledListeners() return $notCalled; } - public function getOrphanedEvents(): array + /** + * @param Request|null $request The request to get orphaned events for + */ + public function getOrphanedEvents(/* Request $request = null */): array { - return $this->orphanedEvents; + if (1 <= \func_num_args() && null !== $request = \func_get_arg(0)) { + return $this->orphanedEvents[spl_object_hash($request)] ?? []; + } + + if (!$this->orphanedEvents) { + return []; + } + + return array_merge(...array_values($this->orphanedEvents)); } public function reset() { $this->callStack = null; $this->orphanedEvents = []; + $this->currentRequestHash = ''; } /** @@ -298,7 +325,7 @@ protected function postDispatch($eventName, Event $event) private function preProcess($eventName) { if (!$this->dispatcher->hasListeners($eventName)) { - $this->orphanedEvents[] = $eventName; + $this->orphanedEvents[$this->currentRequestHash][] = $eventName; return; } @@ -309,7 +336,7 @@ private function preProcess($eventName) $this->wrappedListeners[$eventName][] = $wrappedListener; $this->dispatcher->removeListener($eventName, $listener); $this->dispatcher->addListener($eventName, $wrappedListener, $priority); - $this->callStack->attach($wrappedListener, [$eventName]); + $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]); } } @@ -334,10 +361,6 @@ private function postProcess($eventName) if (null !== $this->logger) { $this->logger->debug('Notified event "{event}" to listener "{listener}".', $context); } - - if (!isset($this->called[$eventName])) { - $this->called[$eventName] = new \SplObjectStorage(); - } } else { $this->callStack->detach($listener); } diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php index cd4d7470afed2..4fedb9a413a3b 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php @@ -12,6 +12,7 @@ namespace Symfony\Component\EventDispatcher\Debug; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\Service\ResetInterface; /** @@ -24,14 +25,18 @@ interface TraceableEventDispatcherInterface extends EventDispatcherInterface, Re /** * Gets the called listeners. * + * @param Request|null $request The request to get listeners for + * * @return array An array of called listeners */ - public function getCalledListeners(); + public function getCalledListeners(/* Request $request = null */); /** * Gets the not called listeners. * + * @param Request|null $request The request to get listeners for + * * @return array An array of not called listeners */ - public function getNotCalledListeners(); + public function getNotCalledListeners(/* Request $request = null */); } diff --git a/src/Symfony/Component/EventDispatcher/composer.json b/src/Symfony/Component/EventDispatcher/composer.json index 163149f412beb..6677e2b74f636 100644 --- a/src/Symfony/Component/EventDispatcher/composer.json +++ b/src/Symfony/Component/EventDispatcher/composer.json @@ -23,6 +23,7 @@ "symfony/dependency-injection": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/config": "~3.4|~4.0", + "symfony/http-foundation": "^3.4|^4.0", "symfony/stopwatch": "~3.4|~4.0", "psr/log": "~1.0" }, diff --git a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php index 8e84c6acf6973..d918ddf786634 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.php @@ -14,6 +14,7 @@ use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; use Symfony\Contracts\Service\ResetInterface; @@ -26,10 +27,13 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInterface { protected $dispatcher; + private $requestStack; + private $currentRequest; - public function __construct(EventDispatcherInterface $dispatcher = null) + public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null) { $this->dispatcher = $dispatcher; + $this->requestStack = $requestStack; } /** @@ -37,6 +41,7 @@ public function __construct(EventDispatcherInterface $dispatcher = null) */ public function collect(Request $request, Response $response, \Exception $exception = null) { + $this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null; $this->data = [ 'called_listeners' => [], 'not_called_listeners' => [], @@ -56,12 +61,12 @@ public function reset() public function lateCollect() { if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { - $this->setCalledListeners($this->dispatcher->getCalledListeners()); - $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners()); + $this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest)); + $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest)); } if ($this->dispatcher instanceof TraceableEventDispatcher) { - $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents()); + $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest)); } $this->data = $this->cloneVar($this->data); From 0b21268bf567c4dc1856086ddcdbf4ea21ac1b2f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Tue, 2 Apr 2019 12:03:40 +0200 Subject: [PATCH 359/495] [HttpClient][Contracts] rename "raw_headers" to "response_headers" --- .../BrowserKit/Tests/HttpBrowserTest.php | 2 +- .../HttpClient/CachingHttpClient.php | 2 +- .../Component/HttpClient/CurlHttpClient.php | 18 +++++----- .../Exception/HttpExceptionTrait.php | 2 +- .../Component/HttpClient/HttpClientTrait.php | 14 ++++---- .../Component/HttpClient/NativeHttpClient.php | 34 +++++++++---------- .../HttpClient/Response/CurlResponse.php | 4 +-- .../HttpClient/Response/MockResponse.php | 14 ++++---- .../HttpClient/Response/NativeResponse.php | 2 +- .../HttpClient/Response/ResponseTrait.php | 8 ++--- .../Exception/HttpExceptionTraitTest.php | 2 +- .../HttpClient/Tests/HttpClientTraitTest.php | 2 +- .../HttpClient/Tests/MockHttpClientTest.php | 12 +++---- .../HttpClient/ResponseInterface.php | 2 +- .../HttpClient/Test/HttpClientTestCase.php | 12 +++---- 15 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php index be1996d1713fb..266dd9a7ebe98 100644 --- a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php @@ -36,7 +36,7 @@ public function __construct(array $server = [], History $history = null, CookieJ return new MockResponse($this->nextResponse->getContent(), [ 'http_code' => $this->nextResponse->getStatusCode(), - 'raw_headers' => $this->nextResponse->getHeaders(), + 'response_headers' => $this->nextResponse->getHeaders(), ]); }); parent::__construct($client); diff --git a/src/Symfony/Component/HttpClient/CachingHttpClient.php b/src/Symfony/Component/HttpClient/CachingHttpClient.php index 0135a268b6035..7e7001cf3316d 100644 --- a/src/Symfony/Component/HttpClient/CachingHttpClient.php +++ b/src/Symfony/Component/HttpClient/CachingHttpClient.php @@ -97,7 +97,7 @@ public function request(string $method, string $url, array $options = []): Respo $response = $this->cache->handle($request); $response = new MockResponse($response->getContent(), [ 'http_code' => $response->getStatusCode(), - 'raw_headers' => $response->headers->allPreserveCase(), + 'response_headers' => $response->headers->allPreserveCase(), ]); return MockResponse::fromRequest($method, $url, $options, $response); diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 01148fab1eb8f..39a5fde78f38f 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -74,8 +74,8 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections return; } - curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $rawHeaders) use ($multi) { - return self::handlePush($parent, $pushed, $rawHeaders, $multi); + curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi) { + return self::handlePush($parent, $pushed, $requestHeaders, $multi); }); } @@ -191,7 +191,7 @@ public function request(string $method, string $url, array $options = []): Respo $curlopts[CURLOPT_ENCODING] = ''; // Enable HTTP compression } - foreach ($options['raw_headers'] as $header) { + foreach ($options['request_headers'] as $header) { if (':' === $header[-2] && \strlen($header) - 2 === strpos($header, ': ')) { // curl requires a special syntax to send empty headers $curlopts[CURLOPT_HTTPHEADER][] = substr_replace($header, ';', -2); @@ -282,11 +282,11 @@ public function __destruct() } } - private static function handlePush($parent, $pushed, array $rawHeaders, \stdClass $multi): int + private static function handlePush($parent, $pushed, array $requestHeaders, \stdClass $multi): int { $headers = []; - foreach ($rawHeaders as $h) { + foreach ($requestHeaders as $h) { if (false !== $i = strpos($h, ':', 1)) { $headers[substr($h, 0, $i)] = substr($h, 1 + $i); } @@ -348,12 +348,12 @@ private static function createRedirectResolver(array $options, string $host): \C $redirectHeaders = []; if (0 < $options['max_redirects']) { $redirectHeaders['host'] = $host; - $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) { return 0 !== stripos($h, 'Host:'); }); if (isset($options['headers']['authorization']) || isset($options['headers']['cookie'])) { - $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + $redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) { return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); }); } @@ -361,8 +361,8 @@ private static function createRedirectResolver(array $options, string $host): \C return static function ($ch, string $location) use ($redirectHeaders) { if ($redirectHeaders && $host = parse_url($location, PHP_URL_HOST)) { - $rawHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; - curl_setopt($ch, CURLOPT_HTTPHEADER, $rawHeaders); + $requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; + curl_setopt($ch, CURLOPT_HTTPHEADER, $requestHeaders); } $url = self::parseUrl(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)); diff --git a/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php b/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php index 31a976c93c828..3278af9be0d8e 100644 --- a/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php +++ b/src/Symfony/Component/HttpClient/Exception/HttpExceptionTrait.php @@ -31,7 +31,7 @@ public function __construct(ResponseInterface $response) $httpCodeFound = false; $isJson = false; - foreach (array_reverse($response->getInfo('raw_headers')) as $h) { + foreach (array_reverse($response->getInfo('response_headers')) as $h) { if (0 === strpos($h, 'HTTP/')) { if ($httpCodeFound) { break; diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 9a45d420b98eb..5fc2ca65f53c9 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -53,12 +53,12 @@ private static function prepareRequest(?string $method, ?string $url, array $opt $options['peer_fingerprint'] = self::normalizePeerFingerprint($options['peer_fingerprint']); } - // Compute raw headers - $rawHeaders = $headers = []; + // Compute request headers + $requestHeaders = $headers = []; foreach ($options['headers'] as $name => $values) { foreach ($values as $value) { - $rawHeaders[] = $name.': '.$headers[$name][] = $value = (string) $value; + $requestHeaders[] = $name.': '.$headers[$name][] = $value = (string) $value; if (\strlen($value) !== strcspn($value, "\r\n\0")) { throw new InvalidArgumentException(sprintf('Invalid header value: CR/LF/NUL found in "%s".', $value)); @@ -95,14 +95,14 @@ private static function prepareRequest(?string $method, ?string $url, array $opt if (null !== $url) { // Merge auth with headers if (($options['auth_basic'] ?? false) && !($headers['authorization'] ?? false)) { - $rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth_basic']); + $requestHeaders[] = 'authorization: '.$headers['authorization'][] = 'Basic '.base64_encode($options['auth_basic']); } // Merge bearer with headers if (($options['auth_bearer'] ?? false) && !($headers['authorization'] ?? false)) { - $rawHeaders[] = 'authorization: '.$headers['authorization'][] = 'Bearer '.$options['auth_bearer']; + $requestHeaders[] = 'authorization: '.$headers['authorization'][] = 'Bearer '.$options['auth_bearer']; } - $options['raw_headers'] = $rawHeaders; + $options['request_headers'] = $requestHeaders; unset($options['auth_basic'], $options['auth_bearer']); // Parse base URI @@ -128,7 +128,7 @@ private static function prepareRequest(?string $method, ?string $url, array $opt */ private static function mergeDefaultOptions(array $options, array $defaultOptions, bool $allowExtraOptions = false): array { - unset($options['raw_headers'], $defaultOptions['raw_headers']); + unset($options['request_headers'], $defaultOptions['request_headers']); $options['headers'] = self::normalizeHeaders($options['headers'] ?? []); diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index bea3fe755b068..d120dbc83b7b7 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -77,12 +77,12 @@ public function request(string $method, string $url, array $options = []): Respo $options['body'] = self::getBodyAsString($options['body']); if ('' !== $options['body'] && 'POST' === $method && !isset($options['headers']['content-type'])) { - $options['raw_headers'][] = 'content-type: application/x-www-form-urlencoded'; + $options['request_headers'][] = 'content-type: application/x-www-form-urlencoded'; } if ($gzipEnabled = \extension_loaded('zlib') && !isset($options['headers']['accept-encoding'])) { // gzip is the most widely available algo, no need to deal with deflate - $options['raw_headers'][] = 'accept-encoding: gzip'; + $options['request_headers'][] = 'accept-encoding: gzip'; } if ($options['peer_fingerprint']) { @@ -94,7 +94,7 @@ public function request(string $method, string $url, array $options = []): Respo } $info = [ - 'raw_headers' => [], + 'response_headers' => [], 'url' => $url, 'error' => null, 'http_method' => $method, @@ -159,7 +159,7 @@ public function request(string $method, string $url, array $options = []): Respo [$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress); if (!isset($options['headers']['host'])) { - $options['raw_headers'][] = 'host: '.$host.$port; + $options['request_headers'][] = 'host: '.$host.$port; } $context = [ @@ -203,7 +203,7 @@ public function request(string $method, string $url, array $options = []): Respo $resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress); $context = stream_context_create($context, ['notification' => $notification]); - self::configureHeadersAndProxy($context, $host, $options['raw_headers'], $proxy, $noProxy); + self::configureHeadersAndProxy($context, $host, $options['request_headers'], $proxy, $noProxy); return new NativeResponse($this->multi, $context, implode('', $url), $options, $gzipEnabled, $info, $resolveRedirect, $onProgress); } @@ -326,12 +326,12 @@ private static function createRedirectResolver(array $options, string $host, ?ar $redirectHeaders = []; if (0 < $maxRedirects = $options['max_redirects']) { $redirectHeaders = ['host' => $host]; - $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) { return 0 !== stripos($h, 'Host:'); }); if (isset($options['headers']['authorization']) || isset($options['headers']['cookie'])) { - $redirectHeaders['no_auth'] = array_filter($options['raw_headers'], static function ($h) { + $redirectHeaders['no_auth'] = array_filter($options['request_headers'], static function ($h) { return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); }); } @@ -376,36 +376,36 @@ private static function createRedirectResolver(array $options, string $host, ?ar if (false !== (parse_url($location, PHP_URL_HOST) ?? false)) { // Authorization and Cookie headers MUST NOT follow except for the initial host name - $rawHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; - $rawHeaders[] = 'host: '.$host.$port; - self::configureHeadersAndProxy($context, $host, $rawHeaders, $proxy, $noProxy); + $requestHeaders = $redirectHeaders['host'] === $host ? $redirectHeaders['with_auth'] : $redirectHeaders['no_auth']; + $requestHeaders[] = 'host: '.$host.$port; + self::configureHeadersAndProxy($context, $host, $requestHeaders, $proxy, $noProxy); } return implode('', $url); }; } - private static function configureHeadersAndProxy($context, string $host, array $rawHeaders, ?array $proxy, array $noProxy) + private static function configureHeadersAndProxy($context, string $host, array $requestHeaders, ?array $proxy, array $noProxy) { if (null === $proxy) { - return stream_context_set_option($context, 'http', 'header', $rawHeaders); + return stream_context_set_option($context, 'http', 'header', $requestHeaders); } // Matching "no_proxy" should follow the behavior of curl foreach ($noProxy as $rule) { if ('*' === $rule) { - return stream_context_set_option($context, 'http', 'header', $rawHeaders); + return stream_context_set_option($context, 'http', 'header', $requestHeaders); } if ($host === $rule) { - return stream_context_set_option($context, 'http', 'header', $rawHeaders); + return stream_context_set_option($context, 'http', 'header', $requestHeaders); } $rule = '.'.ltrim($rule, '.'); if (substr($host, -\strlen($rule)) === $rule) { - return stream_context_set_option($context, 'http', 'header', $rawHeaders); + return stream_context_set_option($context, 'http', 'header', $requestHeaders); } } @@ -413,9 +413,9 @@ private static function configureHeadersAndProxy($context, string $host, array $ stream_context_set_option($context, 'http', 'request_fulluri', true); if (null !== $proxy['auth']) { - $rawHeaders[] = 'Proxy-Authorization: '.$proxy['auth']; + $requestHeaders[] = 'Proxy-Authorization: '.$proxy['auth']; } - return stream_context_set_option($context, 'http', 'header', $rawHeaders); + return stream_context_set_option($context, 'http', 'header', $requestHeaders); } } diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 5f16ba2b9dd9c..8c52ba501bdb8 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -48,7 +48,7 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string $info = &$this->info; $headers = &$this->headers; - if (!$info['raw_headers']) { + if (!$info['response_headers']) { // Used to keep track of what we're waiting for curl_setopt($ch, CURLOPT_PRIVATE, 'headers'); } @@ -257,7 +257,7 @@ private static function parseHeaderLine($ch, string $data, array &$info, array & if ("\r\n" !== $data) { // Regular header line: add it to the list - self::addRawHeaders([substr($data, 0, -2)], $info, $headers); + self::addResponseHeaders([substr($data, 0, -2)], $info, $headers); if (0 === strpos($data, 'HTTP') && 300 <= $info['http_code'] && $info['http_code'] < 400) { if (curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) { diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 9c63f0052ebdd..1e7581a5c1f53 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -37,26 +37,26 @@ class MockResponse implements ResponseInterface * yielding an empty string simulates a timeout, * exceptions are turned to TransportException * - * @see ResponseInterface::getInfo() for possible info, e.g. "raw_headers" + * @see ResponseInterface::getInfo() for possible info, e.g. "response_headers" */ public function __construct($body = '', array $info = []) { $this->body = \is_iterable($body) ? $body : (string) $body; $this->info = $info + $this->info; - if (!isset($info['raw_headers'])) { + if (!isset($info['response_headers'])) { return; } - $rawHeaders = []; + $responseHeaders = []; - foreach ($info['raw_headers'] as $k => $v) { + foreach ($info['response_headers'] as $k => $v) { foreach ((array) $v as $v) { - $rawHeaders[] = (\is_string($k) ? $k.': ' : '').$v; + $responseHeaders[] = (\is_string($k) ? $k.': ' : '').$v; } } - $this->info['raw_headers'] = $rawHeaders; + $this->info['response_headers'] = $responseHeaders; } /** @@ -239,7 +239,7 @@ private static function readResponse(self $response, array $options, ResponseInt // populate info related to headers $info = $mock->getInfo() ?: []; $response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode(false) ?: 200; - $response->addRawHeaders($info['raw_headers'] ?? [], $response->info, $response->headers); + $response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers); $dlSize = (int) ($response->headers['content-length'][0] ?? 0); $response->info = [ diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 4071a9f9185e0..2ab498a731ea7 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -111,7 +111,7 @@ private function open(): void // Send request and follow redirects when needed $this->info['fopen_time'] = microtime(true); $this->handle = $h = fopen($url, 'r', false, $this->context); - self::addRawHeaders($http_response_header, $this->info, $this->headers); + self::addResponseHeaders($http_response_header, $this->info, $this->headers); $url = ($this->resolveRedirect)($this->multi, $this->headers['location'][0] ?? null, $this->context); } while (null !== $url); } catch (\Throwable $e) { diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index cc8c7b439ffa9..b42aa6f188e85 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -43,7 +43,7 @@ trait ResponseTrait private $content; private $info = [ - 'raw_headers' => [], + 'response_headers' => [], 'http_code' => 0, 'error' => null, ]; @@ -187,9 +187,9 @@ abstract protected static function perform(\stdClass $multi, array &$responses): */ abstract protected static function select(\stdClass $multi, float $timeout): int; - private static function addRawHeaders(array $rawHeaders, array &$info, array &$headers): void + private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers): void { - foreach ($rawHeaders as $h) { + foreach ($responseHeaders as $h) { if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([12345]\d\d) .*#', $h, $m)) { $headers = []; $info['http_code'] = (int) $m[1]; @@ -197,7 +197,7 @@ private static function addRawHeaders(array $rawHeaders, array &$info, array &$h $headers[strtolower($m[0])][] = ltrim($m[1]); } - $info['raw_headers'][] = $h; + $info['response_headers'][] = $h; } if (!$info['http_code']) { diff --git a/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php b/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php index 4993bae71a278..8aa88527cebb8 100644 --- a/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Exception/HttpExceptionTraitTest.php @@ -38,7 +38,7 @@ public function testParseError(string $mimeType, string $json): void ->will($this->returnValueMap([ ['http_code', 400], ['url', 'http://example.com'], - ['raw_headers', [ + ['response_headers', [ 'HTTP/1.1 400 Bad Request', 'Content-Type: '.$mimeType, ]], diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php index 37ab4c5622529..5c35bdd320aa4 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -169,7 +169,7 @@ public function testAuthBearerOption() { [, $options] = self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foobar'], HttpClientInterface::OPTIONS_DEFAULTS); $this->assertSame('Bearer foobar', $options['headers']['authorization'][0]); - $this->assertSame('authorization: Bearer foobar', $options['raw_headers'][0]); + $this->assertSame('authorization: Bearer foobar', $options['request_headers'][0]); } /** diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index 1484526e18cf9..e719428c81581 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -73,7 +73,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface case 'testGetRequest': array_unshift($headers, 'HTTP/1.1 200 OK'); - $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); $headers = [ 'Host: localhost:8057', @@ -81,7 +81,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface 'Content-Type: application/json', ]; - $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); break; case 'testDnsError': @@ -100,7 +100,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface case 'testBadRequestBody': case 'testOnProgressCancel': case 'testOnProgressError': - $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); break; case 'testTimeoutOnAccess': @@ -113,15 +113,15 @@ protected function getHttpClient(string $testCase): HttpClientInterface break; case 'testResolve': - $responses[] = new MockResponse($body, ['raw_headers' => $headers]); - $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); $responses[] = $client->request('GET', 'http://symfony.com:8057/'); break; case 'testTimeoutOnStream': case 'testUncheckedTimeoutThrows': $body = ['<1>', '', '<2>']; - $responses[] = new MockResponse($body, ['raw_headers' => $headers]); + $responses[] = new MockResponse($body, ['response_headers' => $headers]); break; } diff --git a/src/Symfony/Contracts/HttpClient/ResponseInterface.php b/src/Symfony/Contracts/HttpClient/ResponseInterface.php index 03cc6a2be29c0..6751184b87a90 100644 --- a/src/Symfony/Contracts/HttpClient/ResponseInterface.php +++ b/src/Symfony/Contracts/HttpClient/ResponseInterface.php @@ -79,7 +79,7 @@ public function toArray(bool $throw = true): array; * another, as the request/response progresses. * * The following info MUST be returned: - * - raw_headers - an array modelled after the special $http_response_header variable + * - response_headers - an array modelled after the special $http_response_header variable * - redirect_count - the number of redirects followed while executing the request * - redirect_url - the resolved location of redirect responses, null otherwise * - start_time - the time when the request was sent or 0.0 when it's pending diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 400f8dc6b2e8e..fb3a547519b02 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -41,15 +41,15 @@ public function testGetRequest() 'user_data' => $data = new \stdClass(), ]); - $this->assertSame([], $response->getInfo('raw_headers')); + $this->assertSame([], $response->getInfo('response_headers')); $this->assertSame($data, $response->getInfo()['user_data']); $this->assertSame(200, $response->getStatusCode()); $info = $response->getInfo(); $this->assertNull($info['error']); $this->assertSame(0, $info['redirect_count']); - $this->assertSame('HTTP/1.1 200 OK', $info['raw_headers'][0]); - $this->assertSame('Host: localhost:8057', $info['raw_headers'][1]); + $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]); + $this->assertSame('Host: localhost:8057', $info['response_headers'][1]); $this->assertSame('http://localhost:8057/', $info['url']); $headers = $response->getHeaders(); @@ -105,7 +105,7 @@ public function testHttpVersion() ]); $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('raw_headers')[0]); + $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('response_headers')[0]); $body = $response->toArray(); @@ -252,7 +252,7 @@ public function testRedirects() 'Content-Type: application/json', ]; - $filteredHeaders = array_values(array_filter($response->getInfo('raw_headers'), function ($h) { + $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) { return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true) && 'Content-Encoding: gzip' !== $h; })); @@ -326,7 +326,7 @@ public function testMaxRedirects() 'Content-Type: application/json', ]; - $filteredHeaders = array_values(array_filter($response->getInfo('raw_headers'), function ($h) { + $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) { return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true); })); From 2ae30a7e3da762113ab3dd4488156e08802b5682 Mon Sep 17 00:00:00 2001 From: Valentin Udaltsov <udaltsov.valentin@gmail.com> Date: Wed, 3 Apr 2019 11:22:11 +0300 Subject: [PATCH 360/495] Rename WebTestAssertions -> WebTestAssertionsTrait --- .../{WebTestAssertions.php => WebTestAssertionsTrait.php} | 2 +- src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php | 2 +- .../Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Test/{WebTestAssertions.php => WebTestAssertionsTrait.php} (99%) diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertionsTrait.php similarity index 99% rename from src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php rename to src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertionsTrait.php index 25eac6fe0ab38..ce6c514518d76 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertions.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestAssertionsTrait.php @@ -26,7 +26,7 @@ * * @see https://laravel.com/docs/5.7/dusk#available-assertions */ -trait WebTestAssertions +trait WebTestAssertionsTrait { public static function assertResponseIsSuccessful(string $message = ''): void { diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php index aa2b12ea296ec..417556578b7b7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/WebTestCase.php @@ -21,7 +21,7 @@ */ abstract class WebTestCase extends KernelTestCase { - use WebTestAssertions; + use WebTestAssertionsTrait; /** @var Client|null */ protected static $client; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php index 92f200be1fab7..e43edabe6d542 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Test/WebTestCaseTest.php @@ -14,7 +14,7 @@ use PHPUnit\Framework\AssertionFailedError; use PHPUnit\Framework\TestCase; use Symfony\Bundle\FrameworkBundle\KernelBrowser; -use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertions; +use Symfony\Bundle\FrameworkBundle\Test\WebTestAssertionsTrait; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\BrowserKit\Cookie; use Symfony\Component\BrowserKit\CookieJar; @@ -275,7 +275,7 @@ private function getRequestTester(): WebTestCase private function getTester(KernelBrowser $client): WebTestCase { return new class($client) extends WebTestCase { - use WebTestAssertions; + use WebTestAssertionsTrait; protected static $client; From f1a26b9aea8cad10990bada36c6415d18aa4fdd9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Sun, 24 Mar 2019 20:39:17 +0100 Subject: [PATCH 361/495] [FrameworkBundle] change the way http clients are configured by leveraging ScopingHttpClient --- .../DependencyInjection/Configuration.php | 343 +++++++++++------- .../FrameworkExtension.php | 42 +-- .../Resources/config/schema/symfony-1.0.xsd | 43 ++- .../DependencyInjection/ConfigurationTest.php | 2 +- .../php/http_client_default_options.php | 4 +- .../php/http_client_full_default_options.php | 3 - .../http_client_override_default_options.php | 8 +- .../xml/http_client_default_options.xml | 7 +- .../xml/http_client_full_default_options.xml | 4 - .../http_client_override_default_options.xml | 8 +- .../yml/http_client_default_options.yml | 4 +- .../yml/http_client_full_default_options.yml | 3 - .../http_client_override_default_options.yml | 7 +- .../FrameworkExtensionTest.php | 28 +- .../HttpClient/Response/MockResponse.php | 4 +- .../HttpFoundation/ResponseHeaderBag.php | 3 +- .../Component/HttpKernel/HttpClientKernel.php | 12 +- 17 files changed, 306 insertions(+), 219 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 1b23702913404..b30d86169b43b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -17,12 +17,12 @@ use Symfony\Bundle\FullStack; use Symfony\Component\Asset\Package; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; -use Symfony\Component\Config\Definition\Builder\NodeBuilder; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\Form\Form; use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpClient\HttpClientTrait; use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\Store\SemaphoreStore; @@ -43,6 +43,8 @@ */ class Configuration implements ConfigurationInterface { + use HttpClientTrait; + private $debug; /** @@ -1232,144 +1234,231 @@ private function addRobotsIndexSection(ArrayNodeDefinition $rootNode) private function addHttpClientSection(ArrayNodeDefinition $rootNode) { - $subNode = $rootNode + $rootNode ->children() ->arrayNode('http_client') ->info('HTTP Client configuration') ->{!class_exists(FullStack::class) && class_exists(HttpClient::class) ? 'canBeDisabled' : 'canBeEnabled'}() - ->fixXmlConfig('client') - ->children(); - - $this->addHttpClientOptionsSection($subNode); - - $subNode = $subNode - ->arrayNode('clients') + ->fixXmlConfig('scoped_client') + ->children() + ->integerNode('max_host_connections') + ->info('The maximum number of connections to a single host.') + ->end() + ->arrayNode('default_options') + ->fixXmlConfig('header') + ->children() + ->arrayNode('headers') + ->info('Associative array: header => value(s).') + ->useAttributeAsKey('name') + ->normalizeKeys(false) + ->variablePrototype()->end() + ->end() + ->integerNode('max_redirects') + ->info('The maximum number of redirects to follow.') + ->end() + ->scalarNode('http_version') + ->info('The default HTTP version, typically 1.1 or 2.0, leave to null for the best version.') + ->end() + ->arrayNode('resolve') + ->info('Associative array: domain => IP.') + ->useAttributeAsKey('host') + ->beforeNormalization() + ->always(function ($config) { + if (!\is_array($config)) { + return []; + } + if (!isset($config['host'])) { + return $config; + } + + return [$config['host'] => $config['value']]; + }) + ->end() + ->normalizeKeys(false) + ->scalarPrototype()->end() + ->end() + ->scalarNode('proxy') + ->info('The URL of the proxy to pass requests through or null for automatic detection.') + ->end() + ->scalarNode('no_proxy') + ->info('A comma separated list of hosts that do not require a proxy to be reached.') + ->end() + ->floatNode('timeout') + ->info('Defaults to "default_socket_timeout" ini parameter.') + ->end() + ->scalarNode('bindto') + ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.') + ->end() + ->booleanNode('verify_peer') + ->info('Indicates if the peer should be verified in a SSL/TLS context.') + ->end() + ->booleanNode('verify_host') + ->info('Indicates if the host should exist as a certificate common name.') + ->end() + ->scalarNode('cafile') + ->info('A certificate authority file.') + ->end() + ->scalarNode('capath') + ->info('A directory that contains multiple certificate authority files.') + ->end() + ->scalarNode('local_cert') + ->info('A PEM formatted certificate file.') + ->end() + ->scalarNode('local_pk') + ->info('A private key file.') + ->end() + ->scalarNode('passphrase') + ->info('The passphrase used to encrypt the "local_pk" file.') + ->end() + ->scalarNode('ciphers') + ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)') + ->end() + ->arrayNode('peer_fingerprint') + ->info('Associative array: hashing algorithm => hash(es).') + ->normalizeKeys(false) + ->children() + ->variableNode('sha1')->end() + ->variableNode('pin-sha256')->end() + ->variableNode('md5')->end() + ->end() + ->end() + ->end() + ->end() + ->arrayNode('scoped_clients') ->useAttributeAsKey('name') ->normalizeKeys(false) ->arrayPrototype() - ->children(); + ->fixXmlConfig('header') + ->beforeNormalization() + ->always() + ->then(function ($config) { + $config = \is_array($config) ? $config : ['base_uri' => $config]; - $this->addHttpClientOptionsSection($subNode); + if (!isset($config['scope']) && isset($config['base_uri'])) { + $config['scope'] = preg_quote(implode('', self::resolveUrl(self::parseUrl('.'), self::parseUrl($config['base_uri'])))); + } - $subNode = $subNode + return $config; + }) ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ; - } - - private function addHttpClientOptionsSection(NodeBuilder $rootNode) - { - $rootNode - ->integerNode('max_host_connections') - ->info('The maximum number of connections to a single host.') - ->end() - ->arrayNode('default_options') - ->fixXmlConfig('header') - ->children() - ->scalarNode('auth_basic') - ->info('An HTTP Basic authentication "username:password".') - ->end() - ->scalarNode('auth_bearer') - ->info('A token enabling HTTP Bearer authorization.') - ->end() - ->arrayNode('query') - ->info('Associative array of query string values merged with URL parameters.') - ->useAttributeAsKey('key') - ->beforeNormalization() - ->always(function ($config) { - if (!\is_array($config)) { - return []; - } - if (!isset($config['key'])) { - return $config; - } + ->validate() + ->ifTrue(function ($v) { return !isset($v['scope']); }) + ->thenInvalid('either "scope" or "base_uri" should be defined.') + ->end() + ->validate() + ->ifTrue(function ($v) { return isset($v['query']) && !isset($v['base_uri']); }) + ->thenInvalid('"query" applies to "base_uri" but no base URI is defined.') + ->end() + ->children() + ->scalarNode('scope') + ->info('The regular expression that the request URL must match before adding the other options. When none is provided, the base URI is used instead.') + ->cannotBeEmpty() + ->end() + ->scalarNode('base_uri') + ->info('The URI to resolve relative URLs, following rules in RFC 3985, section 2.') + ->cannotBeEmpty() + ->end() + ->scalarNode('auth_basic') + ->info('An HTTP Basic authentication "username:password".') + ->end() + ->scalarNode('auth_bearer') + ->info('A token enabling HTTP Bearer authorization.') + ->end() + ->arrayNode('query') + ->info('Associative array of query string values merged with the base URI.') + ->useAttributeAsKey('key') + ->beforeNormalization() + ->always(function ($config) { + if (!\is_array($config)) { + return []; + } + if (!isset($config['key'])) { + return $config; + } - return [$config['key'] => $config['value']]; - }) - ->end() - ->normalizeKeys(false) - ->scalarPrototype()->end() - ->end() - ->arrayNode('headers') - ->info('Associative array: header => value(s).') - ->useAttributeAsKey('name') - ->normalizeKeys(false) - ->variablePrototype()->end() - ->end() - ->integerNode('max_redirects') - ->info('The maximum number of redirects to follow.') - ->end() - ->scalarNode('http_version') - ->info('The default HTTP version, typically 1.1 or 2.0. Leave to null for the best version.') - ->end() - ->scalarNode('base_uri') - ->info('The URI to resolve relative URLs, following rules in RFC 3986, section 2.') - ->end() - ->arrayNode('resolve') - ->info('Associative array: domain => IP.') - ->useAttributeAsKey('host') - ->beforeNormalization() - ->always(function ($config) { - if (!\is_array($config)) { - return []; - } - if (!isset($config['host'])) { - return $config; - } + return [$config['key'] => $config['value']]; + }) + ->end() + ->normalizeKeys(false) + ->scalarPrototype()->end() + ->end() + ->arrayNode('headers') + ->info('Associative array: header => value(s).') + ->useAttributeAsKey('name') + ->normalizeKeys(false) + ->variablePrototype()->end() + ->end() + ->integerNode('max_redirects') + ->info('The maximum number of redirects to follow.') + ->end() + ->scalarNode('http_version') + ->info('The default HTTP version, typically 1.1 or 2.0, leave to null for the best version.') + ->end() + ->arrayNode('resolve') + ->info('Associative array: domain => IP.') + ->useAttributeAsKey('host') + ->beforeNormalization() + ->always(function ($config) { + if (!\is_array($config)) { + return []; + } + if (!isset($config['host'])) { + return $config; + } - return [$config['host'] => $config['value']]; - }) - ->end() - ->normalizeKeys(false) - ->scalarPrototype()->end() - ->end() - ->scalarNode('proxy') - ->info('The URL of the proxy to pass requests through or null for automatic detection.') - ->end() - ->scalarNode('no_proxy') - ->info('A comma separated list of hosts that do not require a proxy to be reached.') - ->end() - ->floatNode('timeout') - ->info('Defaults to "default_socket_timeout" ini parameter.') - ->end() - ->scalarNode('bindto') - ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.') - ->end() - ->booleanNode('verify_peer') - ->info('Indicates if the peer should be verified in a SSL/TLS context.') - ->end() - ->booleanNode('verify_host') - ->info('Indicates if the host should exist as a certificate common name.') - ->end() - ->scalarNode('cafile') - ->info('A certificate authority file.') - ->end() - ->scalarNode('capath') - ->info('A directory that contains multiple certificate authority files.') - ->end() - ->scalarNode('local_cert') - ->info('A PEM formatted certificate file.') - ->end() - ->scalarNode('local_pk') - ->info('A private key file.') - ->end() - ->scalarNode('passphrase') - ->info('The passphrase used to encrypt the "local_pk" file.') - ->end() - ->scalarNode('ciphers') - ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC4-SHA:TLS13-AES-128-GCM-SHA256"...)') - ->end() - ->arrayNode('peer_fingerprint') - ->info('Associative array: hashing algorithm => hash(es).') - ->normalizeKeys(false) - ->children() - ->variableNode('sha1')->end() - ->variableNode('pin-sha256')->end() - ->variableNode('md5')->end() + return [$config['host'] => $config['value']]; + }) + ->end() + ->normalizeKeys(false) + ->scalarPrototype()->end() + ->end() + ->scalarNode('proxy') + ->info('The URL of the proxy to pass requests through or null for automatic detection.') + ->end() + ->scalarNode('no_proxy') + ->info('A comma separated list of hosts that do not require a proxy to be reached.') + ->end() + ->floatNode('timeout') + ->info('Defaults to "default_socket_timeout" ini parameter.') + ->end() + ->scalarNode('bindto') + ->info('A network interface name, IP address, a host name or a UNIX socket to bind to.') + ->end() + ->booleanNode('verify_peer') + ->info('Indicates if the peer should be verified in a SSL/TLS context.') + ->end() + ->booleanNode('verify_host') + ->info('Indicates if the host should exist as a certificate common name.') + ->end() + ->scalarNode('cafile') + ->info('A certificate authority file.') + ->end() + ->scalarNode('capath') + ->info('A directory that contains multiple certificate authority files.') + ->end() + ->scalarNode('local_cert') + ->info('A PEM formatted certificate file.') + ->end() + ->scalarNode('local_pk') + ->info('A private key file.') + ->end() + ->scalarNode('passphrase') + ->info('The passphrase used to encrypt the "local_pk" file.') + ->end() + ->scalarNode('ciphers') + ->info('A list of SSL/TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...)') + ->end() + ->arrayNode('peer_fingerprint') + ->info('Associative array: hashing algorithm => hash(es).') + ->normalizeKeys(false) + ->children() + ->variableNode('sha1')->end() + ->variableNode('pin-sha256')->end() + ->variableNode('md5')->end() + ->end() + ->end() + ->end() + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 71c02ad80e3ad..3b59605d16609 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -61,8 +61,8 @@ use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\HttpClient\HttpClient; -use Symfony\Component\HttpClient\HttpClientTrait; use Symfony\Component\HttpClient\Psr18Client; +use Symfony\Component\HttpClient\ScopingHttpClient; use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; @@ -117,7 +117,6 @@ use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand; use Symfony\Component\Yaml\Yaml; use Symfony\Contracts\Cache\CacheInterface; -use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\Service\ResetInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; @@ -1803,42 +1802,23 @@ private function registerHttpClientConfiguration(array $config, ContainerBuilder $loader->load('http_client.xml'); - $merger = new class() { - use HttpClientTrait; - - public function merge(array $options, array $defaultOptions) - { - try { - [, $mergedOptions] = $this->prepareRequest(null, null, $options, $defaultOptions); - - foreach ($mergedOptions as $k => $v) { - if (!isset($options[$k]) && !isset($defaultOptions[$k])) { - // Remove options added by prepareRequest() - unset($mergedOptions[$k]); - } - } - - return $mergedOptions; - } catch (TransportExceptionInterface $e) { - throw new InvalidArgumentException($e->getMessage(), 0, $e); - } - } - }; - - $defaultOptions = $merger->merge($config['default_options'] ?? [], []); - $container->getDefinition('http_client')->setArguments([$defaultOptions, $config['max_host_connections'] ?? 6]); + $container->getDefinition('http_client')->setArguments([$config['default_options'] ?? [], $config['max_host_connections'] ?? 6]); if (!$hasPsr18 = interface_exists(ClientInterface::class)) { $container->removeDefinition('psr18.http_client'); $container->removeAlias(ClientInterface::class); } - foreach ($config['clients'] as $name => $clientConfig) { - $options = $merger->merge($clientConfig['default_options'] ?? [], $defaultOptions); + foreach ($config['scoped_clients'] as $name => $scopeConfig) { + if ('http_client' === $name) { + throw new InvalidArgumentException(sprintf('Invalid scope name: "%s" is reserved.', $name)); + } + + $scope = $scopeConfig['scope']; + unset($scopeConfig['scope']); - $container->register($name, HttpClientInterface::class) - ->setFactory([HttpClient::class, 'create']) - ->setArguments([$options, $clientConfig['max_host_connections'] ?? $config['max_host_connections'] ?? 6]); + $container->register($name, ScopingHttpClient::class) + ->setArguments([new Reference('http_client'), [$scope => $scopeConfig], $scope]); $container->registerAliasForArgument($name, HttpClientInterface::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 0415fa9559c54..38e60f6516846 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -458,30 +458,55 @@ <xsd:complexType name="http_client"> <xsd:sequence> - <xsd:element name="default-options" type="http_client_options" minOccurs="0" /> - <xsd:element name="client" type="http_client_client" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="default-options" type="http_client_default_options" minOccurs="0" /> + <xsd:element name="scoped-client" type="http_client_scope_options" minOccurs="0" maxOccurs="unbounded" /> </xsd:sequence> <xsd:attribute name="enabled" type="xsd:boolean" /> <xsd:attribute name="max-host-connections" type="xsd:integer" /> </xsd:complexType> - <xsd:complexType name="http_client_options" mixed="true"> + <xsd:complexType name="http_client_default_options" mixed="true"> <xsd:choice maxOccurs="unbounded"> - <xsd:element name="query" type="http_query" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="resolve" type="http_resolve" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="header" type="http_header" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="peer-fingerprint" type="fingerprint" minOccurs="0" maxOccurs="unbounded" /> </xsd:choice> + <xsd:attribute name="max-redirects" type="xsd:integer" /> + <xsd:attribute name="http-version" type="xsd:string" /> <xsd:attribute name="proxy" type="xsd:string" /> + <xsd:attribute name="no-proxy" type="xsd:string" /> <xsd:attribute name="timeout" type="xsd:float" /> <xsd:attribute name="bindto" type="xsd:string" /> <xsd:attribute name="verify-peer" type="xsd:boolean" /> + <xsd:attribute name="verify-host" type="xsd:boolean" /> + <xsd:attribute name="cafile" type="xsd:string" /> + <xsd:attribute name="capath" type="xsd:string" /> + <xsd:attribute name="local-cert" type="xsd:string" /> + <xsd:attribute name="local-pk" type="xsd:string" /> + <xsd:attribute name="passphrase" type="xsd:string" /> + <xsd:attribute name="ciphers" type="xsd:string" /> + + </xsd:complexType> + + <xsd:complexType name="http_client_scope_options" mixed="true"> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="query" type="http_query" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="resolve" type="http_resolve" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="header" type="http_header" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="peer-fingerprint" type="fingerprint" minOccurs="0" maxOccurs="unbounded" /> + </xsd:choice> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="scope" type="xsd:string" /> + <xsd:attribute name="base-uri" type="xsd:string" /> <xsd:attribute name="auth-basic" type="xsd:string" /> <xsd:attribute name="auth-bearer" type="xsd:string" /> <xsd:attribute name="max-redirects" type="xsd:integer" /> <xsd:attribute name="http-version" type="xsd:string" /> - <xsd:attribute name="base-uri" type="xsd:string" /> + <xsd:attribute name="proxy" type="xsd:string" /> <xsd:attribute name="no-proxy" type="xsd:string" /> + <xsd:attribute name="timeout" type="xsd:float" /> + <xsd:attribute name="bindto" type="xsd:string" /> + <xsd:attribute name="verify-peer" type="xsd:boolean" /> <xsd:attribute name="verify-host" type="xsd:boolean" /> <xsd:attribute name="cafile" type="xsd:string" /> <xsd:attribute name="capath" type="xsd:string" /> @@ -491,14 +516,6 @@ <xsd:attribute name="ciphers" type="xsd:string" /> </xsd:complexType> - <xsd:complexType name="http_client_client"> - <xsd:sequence> - <xsd:element name="default-options" type="http_client_options" minOccurs="0" /> - </xsd:sequence> - <xsd:attribute name="name" type="xsd:string" /> - <xsd:attribute name="max-host-connections" type="xsd:integer" /> - </xsd:complexType> - <xsd:complexType name="fingerprint"> <xsd:choice maxOccurs="unbounded"> <xsd:element name="pin-sha256" type="xsd:string" minOccurs="0" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index bc1ee582fc081..aa0a2fc921853 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -336,7 +336,7 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'disallow_search_engine_index' => true, 'http_client' => [ 'enabled' => !class_exists(FullStack::class) && class_exists(HttpClient::class), - 'clients' => [], + 'scoped_clients' => [], ], 'mailer' => [ 'dsn' => 'smtp://null', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_default_options.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_default_options.php index bd36ab1f03d15..5f71a92847f34 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_default_options.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_default_options.php @@ -4,9 +4,9 @@ 'http_client' => [ 'max_host_connections' => 4, 'default_options' => null, - 'clients' => [ + 'scoped_clients' => [ 'foo' => [ - 'default_options' => null, + 'base_uri' => 'http://example.com', ], ], ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_full_default_options.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_full_default_options.php index 59e7f85d03c23..04a227c24cb14 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_full_default_options.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_full_default_options.php @@ -3,12 +3,9 @@ $container->loadFromExtension('framework', [ 'http_client' => [ 'default_options' => [ - 'auth_basic' => 'foo:bar', - 'query' => ['foo' => 'bar', 'bar' => 'baz'], 'headers' => ['X-powered' => 'PHP'], 'max_redirects' => 2, 'http_version' => '2.0', - 'base_uri' => 'http://example.com', 'resolve' => ['localhost' => '127.0.0.1'], 'proxy' => 'proxy.org', 'timeout' => 3.5, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php index 26b76359da3fb..8ba8dd7b92ec8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/http_client_override_default_options.php @@ -6,12 +6,10 @@ 'default_options' => [ 'headers' => ['foo' => 'bar'], ], - 'clients' => [ + 'scoped_clients' => [ 'foo' => [ - 'max_host_connections' => 5, - 'default_options' => [ - 'headers' => ['bar' => 'baz'], - ], + 'base_uri' => 'http://example.com', + 'headers' => ['bar' => 'baz'], ], ], ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_default_options.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_default_options.xml index 5a16c54914c3a..c00eb314415b9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_default_options.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_default_options.xml @@ -8,9 +8,10 @@ <framework:config> <framework:http-client max-host-connections="4"> <framework:default-options /> - <framework:client name="foo"> - <framework:default-options /> - </framework:client> + <framework:scoped-client + name="foo" + base-uri="http://example.com" + /> </framework:http-client> </framework:config> </container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_full_default_options.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_full_default_options.xml index 6f889ba6e8715..2ea78874d2176 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_full_default_options.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_full_default_options.xml @@ -12,10 +12,8 @@ bindto="127.0.0.1" timeout="3.5" verify-peer="true" - auth-basic="foo:bar" max-redirects="2" http-version="2.0" - base-uri="http://example.com" verify-host="true" cafile="/etc/ssl/cafile" capath="/etc/ssl" @@ -24,8 +22,6 @@ passphrase="password123456" ciphers="RC4-SHA:TLS13-AES-128-GCM-SHA256" > - <framework:query key="foo">bar</framework:query> - <framework:query key="bar">baz</framework:query> <framework:header name="X-powered">PHP</framework:header> <framework:resolve host="localhost">127.0.0.1</framework:resolve> <framework:peer-fingerprint> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml index 085b4721cc7d8..8dd84123ca4b5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/http_client_override_default_options.xml @@ -10,11 +10,9 @@ <framework:default-options> <framework:header name="foo">bar</framework:header> </framework:default-options> - <framework:client name="foo" max-host-connections="5"> - <framework:default-options> - <framework:header name="bar">baz</framework:header> - </framework:default-options> - </framework:client> + <framework:scoped-client name="foo" base-uri="http://example.com"> + <framework:header name="bar">baz</framework:header> + </framework:scoped-client> </framework:http-client> </framework:config> </container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_default_options.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_default_options.yml index 4abf1b897380d..6828f8ec231fb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_default_options.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_default_options.yml @@ -2,6 +2,6 @@ framework: http_client: max_host_connections: 4 default_options: ~ - clients: + scoped_clients: foo: - default_options: ~ + base_uri: http://example.com diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_full_default_options.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_full_default_options.yml index 3d18286820e05..5993be1778fe6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_full_default_options.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_full_default_options.yml @@ -1,13 +1,10 @@ framework: http_client: default_options: - auth_basic: foo:bar - query: {'foo': 'bar', 'bar': 'baz'} headers: X-powered: PHP max_redirects: 2 http_version: 2.0 - base_uri: 'http://example.com' resolve: {'localhost': '127.0.0.1'} proxy: proxy.org timeout: 3.5 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml index 9a3d69e3585b4..1528a313d64e3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/http_client_override_default_options.yml @@ -3,8 +3,7 @@ framework: max_host_connections: 4 default_options: headers: {'foo': 'bar'} - clients: + scoped_clients: foo: - max_host_connections: 5 - default_options: - headers: {'bar': 'baz'} + base_uri: http://example.com + headers: {'bar': 'baz'} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index e62651a40fced..acc7fbad156e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -35,6 +35,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpClient\ScopingHttpClient; use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage; @@ -53,7 +54,6 @@ use Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader; use Symfony\Component\Validator\Validation; use Symfony\Component\Workflow; -use Symfony\Contracts\HttpClient\HttpClientInterface; abstract class FrameworkExtensionTest extends TestCase { @@ -1406,25 +1406,34 @@ public function testHttpClientDefaultOptions() $this->assertTrue($container->hasDefinition('http_client'), '->registerHttpClientConfiguration() loads http_client.xml'); $defaultOptions = [ - 'query' => [], 'headers' => [], 'resolve' => [], ]; $this->assertSame([$defaultOptions, 4], $container->getDefinition('http_client')->getArguments()); $this->assertTrue($container->hasDefinition('foo'), 'should have the "foo" service.'); - $this->assertSame(HttpClientInterface::class, $container->getDefinition('foo')->getClass()); - $this->assertSame([$defaultOptions, 4], $container->getDefinition('foo')->getArguments()); + $this->assertSame(ScopingHttpClient::class, $container->getDefinition('foo')->getClass()); } public function testHttpClientOverrideDefaultOptions() { $container = $this->createContainerFromFile('http_client_override_default_options'); - $this->assertSame(['foo' => ['bar']], $container->getDefinition('http_client')->getArgument(0)['headers']); + $this->assertSame(['foo' => 'bar'], $container->getDefinition('http_client')->getArgument(0)['headers']); $this->assertSame(4, $container->getDefinition('http_client')->getArgument(1)); - $this->assertSame(['bar' => ['baz'], 'foo' => ['bar']], $container->getDefinition('foo')->getArgument(0)['headers']); - $this->assertSame(5, $container->getDefinition('foo')->getArgument(1)); + + $expected = [ + 'http\://example\.com/' => [ + 'base_uri' => 'http://example.com', + 'headers' => [ + 'bar' => 'baz', + ], + 'query' => [], + 'resolve' => [], + ], + ]; + + $this->assertSame($expected, $container->getDefinition('foo')->getArgument(1)); } public function testHttpClientFullDefaultOptions() @@ -1433,12 +1442,9 @@ public function testHttpClientFullDefaultOptions() $defaultOptions = $container->getDefinition('http_client')->getArgument(0); - $this->assertSame('foo:bar', $defaultOptions['auth_basic']); - $this->assertSame(['foo' => 'bar', 'bar' => 'baz'], $defaultOptions['query']); - $this->assertSame(['x-powered' => ['PHP']], $defaultOptions['headers']); + $this->assertSame(['X-powered' => 'PHP'], $defaultOptions['headers']); $this->assertSame(2, $defaultOptions['max_redirects']); $this->assertSame(2.0, (float) $defaultOptions['http_version']); - $this->assertSame('http://example.com', $defaultOptions['base_uri']); $this->assertSame(['localhost' => '127.0.0.1'], $defaultOptions['resolve']); $this->assertSame('proxy.org', $defaultOptions['proxy']); $this->assertSame(3.5, $defaultOptions['timeout']); diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 1e7581a5c1f53..9ca47e6624290 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -240,7 +240,7 @@ private static function readResponse(self $response, array $options, ResponseInt $info = $mock->getInfo() ?: []; $response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode(false) ?: 200; $response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers); - $dlSize = (int) ($response->headers['content-length'][0] ?? 0); + $dlSize = isset($response->headers['content-encoding']) ? 0 : (int) ($response->headers['content-length'][0] ?? 0); $response->info = [ 'start_time' => $response->info['start_time'], @@ -282,7 +282,7 @@ private static function readResponse(self $response, array $options, ResponseInt // "notify" completion $onProgress($offset, $dlSize, $response->info); - if (isset($response->headers['content-length']) && $offset !== $dlSize) { + if ($dlSize && $offset !== $dlSize) { throw new TransportException(sprintf('Transfer closed with %s bytes remaining to read.', $dlSize - $offset)); } } diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php index 9e07221933096..cf44d0eceba8e 100644 --- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php @@ -122,8 +122,7 @@ public function set($key, $values, $replace = true) parent::set($key, $values, $replace); // ensure the cache-control header has sensible defaults - if (\in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'], true)) { - $computed = $this->computeCacheControlValue(); + if (\in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'], true) && '' !== $computed = $this->computeCacheControlValue()) { $this->headers['cache-control'] = [$computed]; $this->headerNames['cache-control'] = 'Cache-Control'; $this->computedCacheControl = $this->parseCacheControl($computed); diff --git a/src/Symfony/Component/HttpKernel/HttpClientKernel.php b/src/Symfony/Component/HttpKernel/HttpClientKernel.php index 29a6a97cefe22..2c04e670cc05f 100644 --- a/src/Symfony/Component/HttpKernel/HttpClientKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpClientKernel.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\Mime\Part\AbstractPart; use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\Multipart\FormDataPart; @@ -60,7 +61,16 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ $this->logger->debug(sprintf('Response: %s %s', $response->getStatusCode(), $request->getUri())); - return new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); + $response = new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); + + $response->headers = new class($response->headers->all()) extends ResponseHeaderBag { + protected function computeCacheControlValue() + { + return $this->getCacheControlHeader(); // preserve the original value + } + }; + + return $response; } private function getBody(Request $request): ?AbstractPart From f455d1bd976054352136cc0f465dabdff92fff8e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Tue, 12 Feb 2019 11:56:23 +0100 Subject: [PATCH 362/495] [DI] Add support for "wither" methods - for greater immutable services --- .../Console/Descriptor/XmlDescriptor.php | 3 + .../Compiler/AnalyzeServiceReferencesPass.php | 34 +++++++++- .../Compiler/AutowireRequiredMethodsPass.php | 16 ++++- .../DependencyInjection/ContainerBuilder.php | 28 ++++++-- .../DependencyInjection/Definition.php | 11 +-- .../DependencyInjection/Dumper/PhpDumper.php | 33 +++++++-- .../DependencyInjection/Dumper/XmlDumper.php | 3 + .../Loader/XmlFileLoader.php | 2 +- .../Loader/YamlFileLoader.php | 4 +- .../schema/dic/services/services-1.0.xsd | 1 + .../AutowireRequiredMethodsPassTest.php | 22 ++++++ .../Tests/ContainerBuilderTest.php | 19 ++++++ .../Tests/DefinitionTest.php | 6 ++ .../Tests/Dumper/PhpDumperTest.php | 25 +++++++ .../Fixtures/includes/autowiring_classes.php | 33 +++++++++ .../Tests/Fixtures/php/services_wither.php | 68 +++++++++++++++++++ 16 files changed, 286 insertions(+), 22 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index db0f346ebd72d..956e0ce44a32c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -348,6 +348,9 @@ private function getContainerDefinitionDocument(Definition $definition, string $ foreach ($calls as $callData) { $callsXML->appendChild($callXML = $dom->createElement('call')); $callXML->setAttribute('method', $callData[0]); + if ($callData[2] ?? false) { + $callXML->setAttribute('returns-clone', 'true'); + } } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php index 2dafb5378946e..d10ee4575bfe8 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php @@ -140,11 +140,41 @@ protected function processValue($value, $isRoot = false) $this->byConstructor = true; $this->processValue($value->getFactory()); $this->processValue($value->getArguments()); + + $properties = $value->getProperties(); + $setters = $value->getMethodCalls(); + + // Any references before a "wither" are part of the constructor-instantiation graph + $lastWitherIndex = null; + foreach ($setters as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + + if (null !== $lastWitherIndex) { + $this->processValue($properties); + $setters = $properties = []; + + foreach ($value->getMethodCalls() as $k => $call) { + if (null === $lastWitherIndex) { + $setters[] = $call; + continue; + } + + if ($lastWitherIndex === $k) { + $lastWitherIndex = null; + } + + $this->processValue($call); + } + } + $this->byConstructor = $byConstructor; if (!$this->onlyConstructorArguments) { - $this->processValue($value->getProperties()); - $this->processValue($value->getMethodCalls()); + $this->processValue($properties); + $this->processValue($setters); $this->processValue($value->getConfigurator()); } $this->lazy = $lazy; diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowireRequiredMethodsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowireRequiredMethodsPass.php index efb9df7b94318..20d31135a73ce 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowireRequiredMethodsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowireRequiredMethodsPass.php @@ -35,6 +35,7 @@ protected function processValue($value, $isRoot = false) } $alreadyCalledMethods = []; + $withers = []; foreach ($value->getMethodCalls() as list($method)) { $alreadyCalledMethods[strtolower($method)] = true; @@ -50,7 +51,11 @@ protected function processValue($value, $isRoot = false) while (true) { if (false !== $doc = $r->getDocComment()) { if (false !== stripos($doc, '@required') && preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@required(?:\s|\*/$)#i', $doc)) { - $value->addMethodCall($reflectionMethod->name); + if (preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@return\s++static[\s\*]#i', $doc)) { + $withers[] = [$reflectionMethod->name, [], true]; + } else { + $value->addMethodCall($reflectionMethod->name, []); + } break; } if (false === stripos($doc, '@inheritdoc') || !preg_match('#(?:^/\*\*|\n\s*+\*)\s*+(?:\{@inheritdoc\}|@inheritdoc)(?:\s|\*/$)#i', $doc)) { @@ -65,6 +70,15 @@ protected function processValue($value, $isRoot = false) } } + if ($withers) { + // Prepend withers to prevent creating circular loops + $setters = $value->getMethodCalls(); + $value->setMethodCalls($withers); + foreach ($setters as $call) { + $value->addMethodCall($call[0], $call[1], $call[2] ?? false); + } + } + return $value; } } diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 943df8d314f11..6da41d35afdaf 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1139,8 +1139,15 @@ private function createService(Definition $definition, array &$inlineServices, $ } } - if ($tryProxy || !$definition->isLazy()) { - // share only if proxying failed, or if not a proxy + $lastWitherIndex = null; + foreach ($definition->getMethodCalls() as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + + if (null === $lastWitherIndex && ($tryProxy || !$definition->isLazy())) { + // share only if proxying failed, or if not a proxy, and if no withers are found $this->shareService($definition, $service, $id, $inlineServices); } @@ -1149,8 +1156,13 @@ private function createService(Definition $definition, array &$inlineServices, $ $service->$name = $value; } - foreach ($definition->getMethodCalls() as $call) { - $this->callMethod($service, $call, $inlineServices); + foreach ($definition->getMethodCalls() as $k => $call) { + $service = $this->callMethod($service, $call, $inlineServices); + + if ($lastWitherIndex === $k && ($tryProxy || !$definition->isLazy())) { + // share only if proxying failed, or if not a proxy, and this is the last wither + $this->shareService($definition, $service, $id, $inlineServices); + } } if ($callable = $definition->getConfigurator()) { @@ -1568,16 +1580,18 @@ private function callMethod($service, $call, array &$inlineServices) { foreach (self::getServiceConditionals($call[1]) as $s) { if (!$this->has($s)) { - return; + return $service; } } foreach (self::getInitializedConditionals($call[1]) as $s) { if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) { - return; + return $service; } } - $service->{$call[0]}(...$this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices)); + $result = $service->{$call[0]}(...$this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices)); + + return empty($call[2]) ? $service : $result; } /** diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index b79a8c9a8273b..857176c44f08e 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -330,7 +330,7 @@ public function setMethodCalls(array $calls = []) { $this->calls = []; foreach ($calls as $call) { - $this->addMethodCall($call[0], $call[1]); + $this->addMethodCall($call[0], $call[1], $call[2] ?? false); } return $this; @@ -339,19 +339,20 @@ public function setMethodCalls(array $calls = []) /** * Adds a method to call after service initialization. * - * @param string $method The method name to call - * @param array $arguments An array of arguments to pass to the method call + * @param string $method The method name to call + * @param array $arguments An array of arguments to pass to the method call + * @param bool $returnsClone Whether the call returns the service instance or not * * @return $this * * @throws InvalidArgumentException on empty $method param */ - public function addMethodCall($method, array $arguments = []) + public function addMethodCall($method, array $arguments = []/*, bool $returnsClone = false*/) { if (empty($method)) { throw new InvalidArgumentException('Method name cannot be empty.'); } - $this->calls[] = [$method, $arguments]; + $this->calls[] = 2 < \func_num_args() && \func_get_arg(2) ? [$method, $arguments, true] : [$method, $arguments]; return $this; } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 4cf663b3dd234..1c4bcf23c0670 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -506,7 +506,14 @@ private function addServiceInstance(string $id, Definition $definition, bool $is $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition); $instantiation = ''; - if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id])) { + $lastWitherIndex = null; + foreach ($definition->getMethodCalls() as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + + if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex) { $instantiation = sprintf('$this->%s[\'%s\'] = %s', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $id, $isSimpleInstance ? '' : '$instance'); } elseif (!$isSimpleInstance) { $instantiation = '$instance'; @@ -563,16 +570,32 @@ private function isTrivialInstance(Definition $definition): bool return true; } - private function addServiceMethodCalls(Definition $definition, string $variableName = 'instance'): string + private function addServiceMethodCalls(Definition $definition, string $variableName, ?string $sharedNonLazyId): string { + $lastWitherIndex = null; + foreach ($definition->getMethodCalls() as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + $calls = ''; - foreach ($definition->getMethodCalls() as $call) { + foreach ($definition->getMethodCalls() as $k => $call) { $arguments = []; foreach ($call[1] as $value) { $arguments[] = $this->dumpValue($value); } - $calls .= $this->wrapServiceConditionals($call[1], sprintf(" \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments))); + $witherAssignation = ''; + + if ($call[2] ?? false) { + if (null !== $sharedNonLazyId && $lastWitherIndex === $k) { + $witherAssignation = sprintf('$this->%s[\'%s\'] = ', $definition->isPublic() ? 'services' : 'privates', $sharedNonLazyId); + } + $witherAssignation .= sprintf('$%s = ', $variableName); + } + + $calls .= $this->wrapServiceConditionals($call[1], sprintf(" %s\$%s->%s(%s);\n", $witherAssignation, $variableName, $call[0], implode(', ', $arguments))); } return $calls; @@ -814,7 +837,7 @@ private function addInlineService(string $id, Definition $definition, Definition } $code .= $this->addServiceProperties($inlineDef, $name); - $code .= $this->addServiceMethodCalls($inlineDef, $name); + $code .= $this->addServiceMethodCalls($inlineDef, $name, !$this->getProxyDumper()->isProxyCandidate($inlineDef) && $inlineDef->isShared() && !isset($this->singleUsePrivateIds[$id]) ? $id : null); $code .= $this->addServiceConfigurator($inlineDef, $name); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index eb56becd8da09..79b316336de97 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -84,6 +84,9 @@ private function addMethodCalls(array $methodcalls, \DOMElement $parent) if (\count($methodcall[1])) { $this->convertParameters($methodcall[1], 'argument', $call); } + if ($methodcall[2] ?? false) { + $call->setAttribute('returns-clone', 'true'); + } $parent->appendChild($call); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index b5e076888fb1e..c29bf1dd1d40d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -337,7 +337,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) } foreach ($this->getChildren($service, 'call') as $call) { - $definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument', $file)); + $definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument', $file), XmlUtils::phpize($call->getAttribute('returns-clone'))); } $tags = $this->getChildren($service, 'tag'); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 06fcbb4a91af1..a03cb6118b52a 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -463,15 +463,17 @@ private function parseDefinition($id, $service, $file, array $defaults) if (isset($call['method'])) { $method = $call['method']; $args = isset($call['arguments']) ? $this->resolveServices($call['arguments'], $file) : []; + $returnsClone = $call['returns_clone'] ?? false; } else { $method = $call[0]; $args = isset($call[1]) ? $this->resolveServices($call[1], $file) : []; + $returnsClone = $call[2] ?? false; } if (!\is_array($args)) { throw new InvalidArgumentException(sprintf('The second parameter for function call "%s" must be an array of its arguments for service "%s" in %s. Check your YAML syntax.', $method, $id, $file)); } - $definition->addMethodCall($method, $args); + $definition->addMethodCall($method, $args, $returnsClone); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd index b14ffc8dcd212..6db5d0b7a482e 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd +++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd @@ -243,6 +243,7 @@ <xsd:element name="argument" type="argument" maxOccurs="unbounded" /> </xsd:choice> <xsd:attribute name="method" type="xsd:string" /> + <xsd:attribute name="returns-clone" type="boolean" /> </xsd:complexType> <xsd:simpleType name="parameter_type"> diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireRequiredMethodsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireRequiredMethodsPassTest.php index 644b32d20465e..653e27ea53e81 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireRequiredMethodsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowireRequiredMethodsPassTest.php @@ -77,4 +77,26 @@ public function testExplicitMethodInjection() ); $this->assertEquals([], $methodCalls[0][1]); } + + public function testWitherInjection() + { + $container = new ContainerBuilder(); + $container->register(Foo::class); + + $container + ->register('wither', Wither::class) + ->setAutowired(true); + + (new ResolveClassPass())->process($container); + (new AutowireRequiredMethodsPass())->process($container); + + $methodCalls = $container->getDefinition('wither')->getMethodCalls(); + + $expected = [ + ['withFoo1', [], true], + ['withFoo2', [], true], + ['setFoo', []], + ]; + $this->assertSame($expected, $methodCalls); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index e6c0b264557f9..42aa565bc8ba7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Tests; +require_once __DIR__.'/Fixtures/includes/autowiring_classes.php'; require_once __DIR__.'/Fixtures/includes/classes.php'; require_once __DIR__.'/Fixtures/includes/ProjectExtension.php'; @@ -36,6 +37,8 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\DependencyInjection\Tests\Compiler\Foo; +use Symfony\Component\DependencyInjection\Tests\Compiler\Wither; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy; @@ -1565,6 +1568,22 @@ public function testDecoratedSelfReferenceInvolvingPrivateServices() $this->assertSame(['service_container'], array_keys($container->getDefinitions())); } + + public function testWither() + { + $container = new ContainerBuilder(); + $container->register(Foo::class); + + $container + ->register('wither', Wither::class) + ->setPublic(true) + ->setAutowired(true); + + $container->compile(); + + $wither = $container->get('wither'); + $this->assertInstanceOf(Foo::class, $wither->foo); + } } class FooClass diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index 3462726943037..c46479896483e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -95,10 +95,16 @@ public function testMethodCalls() $this->assertEquals([['foo', ['foo']]], $def->getMethodCalls(), '->getMethodCalls() returns the methods to call'); $this->assertSame($def, $def->addMethodCall('bar', ['bar']), '->addMethodCall() implements a fluent interface'); $this->assertEquals([['foo', ['foo']], ['bar', ['bar']]], $def->getMethodCalls(), '->addMethodCall() adds a method to call'); + $this->assertSame($def, $def->addMethodCall('foobar', ['foobar'], true), '->addMethodCall() implements a fluent interface with third parameter'); + $this->assertEquals([['foo', ['foo']], ['bar', ['bar']], ['foobar', ['foobar'], true]], $def->getMethodCalls(), '->addMethodCall() adds a method to call'); $this->assertTrue($def->hasMethodCall('bar'), '->hasMethodCall() returns true if first argument is a method to call registered'); $this->assertFalse($def->hasMethodCall('no_registered'), '->hasMethodCall() returns false if first argument is not a method to call registered'); $this->assertSame($def, $def->removeMethodCall('bar'), '->removeMethodCall() implements a fluent interface'); + $this->assertTrue($def->hasMethodCall('foobar'), '->hasMethodCall() returns true if first argument is a method to call registered'); + $this->assertSame($def, $def->removeMethodCall('foobar'), '->removeMethodCall() implements a fluent interface'); $this->assertEquals([['foo', ['foo']]], $def->getMethodCalls(), '->removeMethodCall() removes a method to call'); + $this->assertSame($def, $def->setMethodCalls([['foobar', ['foobar'], true]]), '->setMethodCalls() implements a fluent interface with third parameter'); + $this->assertEquals([['foobar', ['foobar'], true]], $def->getMethodCalls(), '->addMethodCall() adds a method to call'); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 828439969ef3d..481947de57db1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -30,6 +30,8 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\DependencyInjection\Tests\Compiler\Foo; +use Symfony\Component\DependencyInjection\Tests\Compiler\Wither; use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator; use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber; @@ -37,6 +39,7 @@ use Symfony\Component\DependencyInjection\Variable; use Symfony\Component\ExpressionLanguage\Expression; +require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php'; require_once __DIR__.'/../Fixtures/includes/classes.php'; class PhpDumperTest extends TestCase @@ -1170,6 +1173,28 @@ public function testServiceLocatorArgument() $container->set('foo5', $foo5 = new \stdClass()); $this->assertSame($foo5, $locator->get('foo5')); } + + public function testWither() + { + $container = new ContainerBuilder(); + $container->register(Foo::class); + + $container + ->register('wither', Wither::class) + ->setPublic(true) + ->setAutowired(true); + + $container->compile(); + $dumper = new PhpDumper($container); + $dump = $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Service_Wither']); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_wither.php', $dump); + eval('?>'.$dump); + + $container = new \Symfony_DI_PhpDumper_Service_Wither(); + + $wither = $container->get('wither'); + $this->assertInstanceOf(Foo::class, $wither->foo); + } } class Rot13EnvVarProcessor implements EnvVarProcessorInterface diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index a2f8721683b6c..504ed26da3a23 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -278,6 +278,39 @@ public function setChildMethodWithoutDocBlock(A $a) } } +class Wither +{ + public $foo; + + /** + * @required + */ + public function setFoo(Foo $foo) + { + } + + /** + * @required + * @return static + */ + public function withFoo1(Foo $foo) + { + return $this->withFoo2($foo); + } + + /** + * @required + * @return static + */ + public function withFoo2(Foo $foo) + { + $new = clone $this; + $new->foo = $foo; + + return $new; + } +} + class SetterInjectionParent { /** @required*/ diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither.php new file mode 100644 index 0000000000000..c8a0d035886e4 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither.php @@ -0,0 +1,68 @@ +<?php + +use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; + +/** + * This class has been auto-generated + * by the Symfony Dependency Injection Component. + * + * @final since Symfony 3.3 + */ +class Symfony_DI_PhpDumper_Service_Wither extends Container +{ + private $parameters; + private $targetDirs = []; + + public function __construct() + { + $this->services = $this->privates = []; + $this->methodMap = [ + 'wither' => 'getWitherService', + ]; + + $this->aliases = []; + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function getRemovedIds() + { + return [ + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\Tests\\Compiler\\Foo' => true, + ]; + } + + /** + * Gets the public 'wither' shared autowired service. + * + * @return \Symfony\Component\DependencyInjection\Tests\Compiler\Wither + */ + protected function getWitherService() + { + $instance = new \Symfony\Component\DependencyInjection\Tests\Compiler\Wither(); + + $a = new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo(); + + $instance = $instance->withFoo1($a); + $this->services['wither'] = $instance = $instance->withFoo2($a); + $instance->setFoo($a); + + return $instance; + } +} From 847a9bb86d012c09cd0669e5d157d5d8e0e094c5 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 3 Apr 2019 11:22:52 +0200 Subject: [PATCH 363/495] [Cache] add logs on early-recomputation and locking --- src/Symfony/Component/Cache/LockRegistry.php | 7 ++++++- src/Symfony/Component/Cache/Traits/ContractsTrait.php | 7 ++++--- src/Symfony/Contracts/Cache/CacheTrait.php | 9 +++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php index 81f7db459f00a..eee7948aab0b0 100644 --- a/src/Symfony/Component/Cache/LockRegistry.php +++ b/src/Symfony/Component/Cache/LockRegistry.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache; +use Psr\Log\LoggerInterface; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; @@ -75,7 +76,7 @@ public static function setFiles(array $files): array return $previousFiles; } - public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null) + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null) { $key = self::$files ? crc32($item->getKey()) % \count(self::$files) : -1; @@ -87,6 +88,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s try { // race to get the lock in non-blocking mode if (flock($lock, LOCK_EX | LOCK_NB)) { + $logger && $logger->info('Lock acquired, now computing item "{key}"', ['key' => $item->getKey()]); self::$lockedFiles[$key] = true; $value = $callback($item, $save); @@ -103,6 +105,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s return $value; } // if we failed the race, retry locking in blocking mode to wait for the winner + $logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]); flock($lock, LOCK_SH); } finally { flock($lock, LOCK_UN); @@ -114,6 +117,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s try { $value = $pool->get($item->getKey(), $signalingCallback, 0); + $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]); $save = false; return $value; @@ -121,6 +125,7 @@ public static function compute(callable $callback, ItemInterface $item, bool &$s if ($signalingException !== $e) { throw $e; } + $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]); } } } diff --git a/src/Symfony/Component/Cache/Traits/ContractsTrait.php b/src/Symfony/Component/Cache/Traits/ContractsTrait.php index bd7be08dd5e8e..c91c14d90fa6b 100644 --- a/src/Symfony/Component/Cache/Traits/ContractsTrait.php +++ b/src/Symfony/Component/Cache/Traits/ContractsTrait.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Traits; +use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; @@ -40,7 +41,7 @@ trait ContractsTrait public function setCallbackWrapper(?callable $callbackWrapper): callable { $previousWrapper = $this->callbackWrapper; - $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata) { + $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) { return $callback($item, $save); }; @@ -82,13 +83,13 @@ function (CacheItem $item, float $startTime, ?array &$metadata) { try { $value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { $setMetadata($item, $startTime, $metadata); - }); + }, $this->logger ?? null); $setMetadata($item, $startTime, $metadata); return $value; } finally { $this->callbackWrapper = $callbackWrapper; } - }, $beta, $metadata); + }, $beta, $metadata, $this->logger ?? null); } } diff --git a/src/Symfony/Contracts/Cache/CacheTrait.php b/src/Symfony/Contracts/Cache/CacheTrait.php index 918d5559b70c9..7bbdef087e46f 100644 --- a/src/Symfony/Contracts/Cache/CacheTrait.php +++ b/src/Symfony/Contracts/Cache/CacheTrait.php @@ -13,6 +13,7 @@ use Psr\Cache\CacheItemPoolInterface; use Psr\Cache\InvalidArgumentException; +use Psr\Log\LoggerInterface; /** * An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes. @@ -37,7 +38,7 @@ public function delete(string $key): bool return $this->deleteItem($key); } - private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null) + private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null) { if (0 > $beta = $beta ?? 1.0) { throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', \get_class($this), $beta)) extends \InvalidArgumentException implements InvalidArgumentException { @@ -52,9 +53,13 @@ private function doGet(CacheItemPoolInterface $pool, string $key, callable $call $expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false; $ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false; - if ($recompute = $ctime && $expiry && $expiry <= microtime(true) - $ctime / 1000 * $beta * log(random_int(1, PHP_INT_MAX) / PHP_INT_MAX)) { + if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, PHP_INT_MAX) / PHP_INT_MAX)) { // force applying defaultLifetime to expiry $item->expiresAt(null); + $this->logger && $this->logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ + 'key' => $key, + 'delta' => sprintf('%.1f', $expiry - $now), + ]); } } From 2b9b8e5707c618ebbcde82f883c92533ebdceb6f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 3 Apr 2019 10:23:58 +0200 Subject: [PATCH 364/495] [HttpClient] Add ScopingHttpClient::forBaseUri() + tweak MockHttpClient --- .../Component/HttpClient/MockHttpClient.php | 12 +++++---- .../HttpClient/Response/MockResponse.php | 4 +++ .../HttpClient/ScopingHttpClient.php | 11 ++++++++ .../Tests/ScopingHttpClientTest.php | 27 +++++++++++-------- 4 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/HttpClient/MockHttpClient.php b/src/Symfony/Component/HttpClient/MockHttpClient.php index 1d3d7b8b68172..41bb20b299f16 100644 --- a/src/Symfony/Component/HttpClient/MockHttpClient.php +++ b/src/Symfony/Component/HttpClient/MockHttpClient.php @@ -31,16 +31,16 @@ class MockHttpClient implements HttpClientInterface private $baseUri; /** - * @param callable|ResponseInterface|ResponseInterface[]|iterable $responseFactory + * @param callable|ResponseInterface|ResponseInterface[]|iterable|null $responseFactory */ - public function __construct($responseFactory, string $baseUri = null) + public function __construct($responseFactory = null, string $baseUri = null) { if ($responseFactory instanceof ResponseInterface) { $responseFactory = [$responseFactory]; } - if (!\is_callable($responseFactory) && !$responseFactory instanceof \Iterator) { - $responseFactory = (function () use ($responseFactory) { + if (null !== $responseFactory && !\is_callable($responseFactory) && !$responseFactory instanceof \Iterator) { + $responseFactory = (static function () use ($responseFactory) { yield from $responseFactory; })(); } @@ -57,7 +57,9 @@ public function request(string $method, string $url, array $options = []): Respo [$url, $options] = $this->prepareRequest($method, $url, $options, ['base_uri' => $this->baseUri], true); $url = implode('', $url); - if (\is_callable($this->responseFactory)) { + if (null === $this->responseFactory) { + $response = new MockResponse(); + } elseif (\is_callable($this->responseFactory)) { $response = ($this->responseFactory)($method, $url, $options); } elseif (!$this->responseFactory->valid()) { throw new TransportException('The response factory iterator passed to MockHttpClient is empty.'); diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 1e7581a5c1f53..10b087467eaa8 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -111,6 +111,10 @@ public static function fromRequest(string $method, string $url, array $options, $response->info['user_data'] = $options['user_data'] ?? null; $response->info['url'] = $url; + if ($mock instanceof self) { + $mock->requestOptions = $response->requestOptions; + } + self::writeRequest($response, $options, $mock); $response->body[] = [$options, $mock]; diff --git a/src/Symfony/Component/HttpClient/ScopingHttpClient.php b/src/Symfony/Component/HttpClient/ScopingHttpClient.php index 5c8a0c411f1ab..5b1da579bc0b5 100644 --- a/src/Symfony/Component/HttpClient/ScopingHttpClient.php +++ b/src/Symfony/Component/HttpClient/ScopingHttpClient.php @@ -38,6 +38,17 @@ public function __construct(HttpClientInterface $client, array $defaultOptionsBy $this->defaultRegexp = $defaultRegexp; } + public static function forBaseUri(HttpClientInterface $client, string $baseUri, array $defaultOptions = [], $regexp = null): self + { + if (null === $regexp) { + $regexp = preg_quote(implode('', self::resolveUrl(self::parseUrl('.'), self::parseUrl($baseUri)))); + } + + $defaultOptions['base_uri'] = $baseUri; + + return new self($client, [$regexp => $defaultOptions], $regexp); + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php index 9ab34c2b1f6f8..7fe9104442327 100644 --- a/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php @@ -14,14 +14,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\Exception\InvalidArgumentException; use Symfony\Component\HttpClient\MockHttpClient; -use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Component\HttpClient\ScopingHttpClient; class ScopingHttpClientTest extends TestCase { public function testRelativeUrl() { - $mockClient = new MockHttpClient([]); + $mockClient = new MockHttpClient(); $client = new ScopingHttpClient($mockClient, []); $this->expectException(InvalidArgumentException::class); @@ -30,7 +29,7 @@ public function testRelativeUrl() public function testRelativeUrlWithDefaultRegexp() { - $mockClient = new MockHttpClient(new MockResponse()); + $mockClient = new MockHttpClient(); $client = new ScopingHttpClient($mockClient, ['.*' => ['base_uri' => 'http://example.com']], '.*'); $this->assertSame('http://example.com/foo', $client->request('GET', '/foo')->getInfo('url')); @@ -41,7 +40,7 @@ public function testRelativeUrlWithDefaultRegexp() */ public function testMatchingUrls(string $regexp, string $url, array $options) { - $mockClient = new MockHttpClient(new MockResponse()); + $mockClient = new MockHttpClient(); $client = new ScopingHttpClient($mockClient, $options); $response = $client->request('GET', $url); @@ -69,13 +68,7 @@ public function testMatchingUrlsAndOptions() '.*' => ['headers' => ['content-type' => 'text/html']], ]; - $mockResponses = [ - new MockResponse(), - new MockResponse(), - new MockResponse(), - ]; - - $mockClient = new MockHttpClient($mockResponses); + $mockClient = new MockHttpClient(); $client = new ScopingHttpClient($mockClient, $defaultOptions); $response = $client->request('GET', 'http://example.com/foo-bar', ['json' => ['url' => 'http://example.com']]); @@ -93,4 +86,16 @@ public function testMatchingUrlsAndOptions() $this->assertEquals($requestOptions['headers']['x-app'][0], 'unit-test'); $this->assertEquals($requestOptions['headers']['content-type'][0], 'text/html'); } + + public function testForBaseUri() + { + $client = ScopingHttpClient::forBaseUri(new MockHttpClient(), 'http://example.com/foo'); + + $response = $client->request('GET', '/bar'); + $this->assertSame('http://example.com/foo', implode('', $response->getRequestOptions()['base_uri'])); + $this->assertSame('http://example.com/bar', $response->getInfo('url')); + + $response = $client->request('GET', 'http://foo.bar/'); + $this->assertNull($response->getRequestOptions()['base_uri']); + } } From e9fca21d6b4ef494a0104f1f5fd81272f7b08cc7 Mon Sep 17 00:00:00 2001 From: nicoweb <weblefevre@gmail.com> Date: Mon, 11 Mar 2019 17:20:18 +0100 Subject: [PATCH 365/495] [RouterDebugCommand] add link to Controllers --- .../Command/RouterDebugCommand.php | 7 ++- .../Console/Descriptor/TextDescriptor.php | 44 +++++++++++++++++-- .../Console/Helper/DescriptorHelper.php | 5 ++- .../Resources/config/console.xml | 1 + 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php index ec8d53b06ca80..bad3fa0598a56 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/RouterDebugCommand.php @@ -19,6 +19,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\Routing\RouterInterface; @@ -34,12 +35,14 @@ class RouterDebugCommand extends Command { protected static $defaultName = 'debug:router'; private $router; + private $fileLinkFormatter; - public function __construct(RouterInterface $router) + public function __construct(RouterInterface $router, FileLinkFormatter $fileLinkFormatter = null) { parent::__construct(); $this->router = $router; + $this->fileLinkFormatter = $fileLinkFormatter; } /** @@ -74,7 +77,7 @@ protected function execute(InputInterface $input, OutputInterface $output) { $io = new SymfonyStyle($input, $output); $name = $input->getArgument('name'); - $helper = new DescriptorHelper(); + $helper = new DescriptorHelper($this->fileLinkFormatter); $routes = $this->router->getRouteCollection(); if ($name) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 1861916896161..a69dbfd3d21d4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -24,6 +24,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -34,6 +35,13 @@ */ class TextDescriptor extends Descriptor { + private $fileLinkFormatter; + + public function __construct(FileLinkFormatter $fileLinkFormatter = null) + { + $this->fileLinkFormatter = $fileLinkFormatter; + } + /** * {@inheritdoc} */ @@ -48,17 +56,18 @@ protected function describeRouteCollection(RouteCollection $routes, array $optio $tableRows = []; foreach ($routes->all() as $name => $route) { + $controller = $route->getDefault('_controller'); + $row = [ $name, $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY', $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY', '' !== $route->getHost() ? $route->getHost() : 'ANY', - $route->getPath(), + $this->formatControllerLink($controller, $route->getPath()), ]; if ($showControllers) { - $controller = $route->getDefault('_controller'); - $row[] = $controller ? $this->formatCallable($controller) : ''; + $row[] = $controller ? $this->formatControllerLink($controller, $this->formatCallable($controller)) : ''; } $tableRows[] = $row; @@ -514,6 +523,35 @@ private function formatRouterConfig(array $config): string return trim($configAsString); } + private function formatControllerLink($controller, string $anchorText): string + { + if (null === $this->fileLinkFormatter) { + return $anchorText; + } + + try { + if (\is_array($controller)) { + $r = new \ReflectionMethod($controller); + } elseif ($controller instanceof \Closure) { + $r = new \ReflectionFunction($controller); + } elseif (method_exists($controller, '__invoke')) { + $r = new \ReflectionMethod($controller, '__invoke'); + } elseif (!\is_string($controller)) { + return $anchorText; + } elseif (false !== strpos($controller, '::')) { + $r = new \ReflectionMethod($controller); + } else { + $r = new \ReflectionFunction($controller); + } + } catch (\ReflectionException $e) { + return $anchorText; + } + + $fileLink = $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine()); + + return sprintf('<href=%s>%s</>', $fileLink, $anchorText); + } + private function formatCallable($callable): string { if (\is_array($callable)) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php b/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php index 475c22ca31e80..1f17c999424d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Helper/DescriptorHelper.php @@ -16,6 +16,7 @@ use Symfony\Bundle\FrameworkBundle\Console\Descriptor\TextDescriptor; use Symfony\Bundle\FrameworkBundle\Console\Descriptor\XmlDescriptor; use Symfony\Component\Console\Helper\DescriptorHelper as BaseDescriptorHelper; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; /** * @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com> @@ -24,10 +25,10 @@ */ class DescriptorHelper extends BaseDescriptorHelper { - public function __construct() + public function __construct(FileLinkFormatter $fileLinkFormatter = null) { $this - ->register('txt', new TextDescriptor()) + ->register('txt', new TextDescriptor($fileLinkFormatter)) ->register('xml', new XmlDescriptor()) ->register('json', new JsonDescriptor()) ->register('md', new MarkdownDescriptor()) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 050144e5a8b24..7b79664c1f8f5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -111,6 +111,7 @@ <service id="console.command.router_debug" class="Symfony\Bundle\FrameworkBundle\Command\RouterDebugCommand"> <argument type="service" id="router" /> + <argument type="service" id="debug.file_link_formatter" on-invalid="null" /> <tag name="console.command" command="debug:router" /> </service> From 3e7a47c0bf15b42b12f898a52cb7c26f2bee7a68 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 3 Apr 2019 12:06:15 +0200 Subject: [PATCH 366/495] [FrameworkBundle] fix HttpClient integration --- .../DependencyInjection/Configuration.php | 15 ++++++++++++--- .../DependencyInjection/FrameworkExtension.php | 5 ----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index b30d86169b43b..076a70c818768 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -43,8 +43,6 @@ */ class Configuration implements ConfigurationInterface { - use HttpClientTrait; - private $debug; /** @@ -1332,10 +1330,21 @@ private function addHttpClientSection(ArrayNodeDefinition $rootNode) ->beforeNormalization() ->always() ->then(function ($config) { + if (!trait_exists(HttpClientTrait::class)) { + throw new LogicException('HttpClient support cannot be enabled as the component is not installed. Try running "composer require symfony/http-client".'); + } + $config = \is_array($config) ? $config : ['base_uri' => $config]; if (!isset($config['scope']) && isset($config['base_uri'])) { - $config['scope'] = preg_quote(implode('', self::resolveUrl(self::parseUrl('.'), self::parseUrl($config['base_uri'])))); + $urlResolver = new class() { + use HttpClientTrait { + resolveUrl as public; + parseUrl as public; + } + }; + + $config['scope'] = preg_quote(implode('', $urlResolver->resolveUrl($urlResolver->parseUrl('.'), $urlResolver->parseUrl($config['base_uri'])))); } return $config; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3b59605d16609..4831af368e879 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -60,7 +60,6 @@ use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\FormTypeInterface; -use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpClient\Psr18Client; use Symfony\Component\HttpClient\ScopingHttpClient; use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface; @@ -1796,10 +1795,6 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con private function registerHttpClientConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader) { - if (!class_exists(HttpClient::class)) { - throw new LogicException('HttpClient support cannot be enabled as the component is not installed. Try running "composer require symfony/http-client".'); - } - $loader->load('http_client.xml'); $container->getDefinition('http_client')->setArguments([$config['default_options'] ?? [], $config['max_host_connections'] ?? 6]); From 23cb83f726e5905b49c4901b149dfdd2d08375c1 Mon Sep 17 00:00:00 2001 From: Zan Baldwin <hello@zanbaldwin.com> Date: Mon, 18 Feb 2019 14:13:45 +0000 Subject: [PATCH 367/495] [DependencyInjection] Invokable Factory Services --- .../Component/DependencyInjection/Definition.php | 8 ++++++-- .../DependencyInjection/Loader/XmlFileLoader.php | 4 ++-- .../DependencyInjection/Loader/YamlFileLoader.php | 5 ++++- .../DependencyInjection/Tests/DefinitionTest.php | 4 ++++ .../Tests/Fixtures/xml/services6.xml | 3 +++ .../Tests/Fixtures/yaml/bad_factory_syntax.yml | 6 ++++++ .../Tests/Fixtures/yaml/services14.yml | 1 + .../Tests/Fixtures/yaml/services6.yml | 1 + .../Tests/Loader/XmlFileLoaderTest.php | 1 + .../Tests/Loader/YamlFileLoaderTest.php | 12 ++++++++++++ 10 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_factory_syntax.yml diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index b79a8c9a8273b..57b328d419e6b 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -95,7 +95,7 @@ public function setChanges(array $changes) /** * Sets a factory. * - * @param string|array $factory A PHP function or an array containing a class/Reference and a method to call + * @param string|array|Reference $factory A PHP function, reference or an array containing a class/Reference and a method to call * * @return $this */ @@ -105,6 +105,8 @@ public function setFactory($factory) if (\is_string($factory) && false !== strpos($factory, '::')) { $factory = explode('::', $factory, 2); + } elseif ($factory instanceof Reference) { + $factory = [$factory, '__invoke']; } $this->factory = $factory; @@ -782,7 +784,7 @@ public function getDeprecationMessage($id) /** * Sets a configurator to call after the service is fully initialized. * - * @param string|array $configurator A PHP callable + * @param string|array|Reference $configurator A PHP function, reference or an array containing a class/Reference and a method to call * * @return $this */ @@ -792,6 +794,8 @@ public function setConfigurator($configurator) if (\is_string($configurator) && false !== strpos($configurator, '::')) { $configurator = explode('::', $configurator, 2); + } elseif ($configurator instanceof Reference) { + $configurator = [$configurator, '__invoke']; } $this->configurator = $configurator; diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 6f672bdc7f6bc..25777a62acf94 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -317,7 +317,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $class = $factory->hasAttribute('class') ? $factory->getAttribute('class') : null; } - $definition->setFactory([$class, $factory->getAttribute('method')]); + $definition->setFactory([$class, $factory->getAttribute('method') ?: '__invoke']); } } @@ -332,7 +332,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $class = $configurator->getAttribute('class'); } - $definition->setConfigurator([$class, $configurator->getAttribute('method')]); + $definition->setConfigurator([$class, $configurator->getAttribute('method') ?: '__invoke']); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 06fcbb4a91af1..93080a420a166 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -571,12 +571,15 @@ private function parseDefinition($id, $service, $file, array $defaults) * * @throws InvalidArgumentException When errors occur * - * @return string|array A parsed callable + * @return string|array|Reference A parsed callable */ private function parseCallable($callable, $parameter, $id, $file) { if (\is_string($callable)) { if ('' !== $callable && '@' === $callable[0]) { + if (false === strpos($callable, ':')) { + return [$this->resolveServices($callable, $file), '__invoke']; + } throw new InvalidArgumentException(sprintf('The value of the "%s" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $parameter, $id, $callable, substr($callable, 1))); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index 3462726943037..4308301823fcd 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; class DefinitionTest extends TestCase { @@ -35,6 +36,9 @@ public function testSetGetFactory() $def->setFactory('Foo::bar'); $this->assertEquals(['Foo', 'bar'], $def->getFactory(), '->setFactory() converts string static method call to the array'); + + $def->setFactory($ref = new Reference('baz')); + $this->assertSame([$ref, '__invoke'], $def->getFactory(), '->setFactory() converts service reference to class invoke call'); $this->assertSame(['factory' => true], $def->getChanges()); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml index c85b7a7c01efb..cab8939a50add 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml @@ -59,6 +59,9 @@ <service id="new_factory4" class="BazClass"> <factory method="getInstance" /> </service> + <service id="new_factory5" class="FooBarClass"> + <factory service="baz" /> + </service> <service id="alias_for_foo" alias="foo" /> <service id="another_alias_for_foo" alias="foo" public="false" /> <service id="0" class="FooClass" /> diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_factory_syntax.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_factory_syntax.yml new file mode 100644 index 0000000000000..aa728d3c59471 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/bad_factory_syntax.yml @@ -0,0 +1,6 @@ +services: + factory: + class: Baz + invalid_factory: + class: FooBarClass + factory: '@factory:method' diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services14.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services14.yml index 4c188c5fbc7b0..5d64a6537bbbf 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services14.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services14.yml @@ -1,3 +1,4 @@ services: factory: { class: FooBarClass, factory: baz:getClass} factory_with_static_call: { class: FooBarClass, factory: FooBacFactory::createFooBar} + invokable_factory: { class: FooBarClass, factory: '@factory' } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml index 1ee6c6ec740eb..2a82b181ea85d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml @@ -34,6 +34,7 @@ services: new_factory2: { class: FooBarClass, factory: ['@baz', getClass]} new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]} new_factory4: { class: BazClass, factory: [~, getInstance]} + new_factory5: { class: FooBarClass, factory: '@baz' } Acme\WithShortCutArgs: [foo, '@baz'] alias_for_foo: '@foo' another_alias_for_foo: diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 20c80258e2686..6f04a519a2014 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -268,6 +268,7 @@ public function testLoadServices() $this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag'); $this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag'); $this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class'); + $this->assertEquals([new Reference('baz'), '__invoke'], $services['new_factory5']->getFactory(), '->load() accepts service reference as invokable factory'); $aliases = $container->getAliases(); $this->assertArrayHasKey('alias_for_foo', $aliases, '->load() parses <service> elements'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 7870a521a9dbe..afbb4485d01ad 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Loader\IniFileLoader; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; @@ -158,6 +159,7 @@ public function testLoadServices() $this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag'); $this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag'); $this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class'); + $this->assertEquals([new Reference('baz'), '__invoke'], $services['new_factory5']->getFactory(), '->load() accepts service reference as invokable factory'); $this->assertEquals(['foo', new Reference('baz')], $services['Acme\WithShortCutArgs']->getArguments(), '->load() parses short service definition'); $aliases = $container->getAliases(); @@ -196,6 +198,16 @@ public function testLoadFactoryShortSyntax() $this->assertEquals([new Reference('baz'), 'getClass'], $services['factory']->getFactory(), '->load() parses the factory tag with service:method'); $this->assertEquals(['FooBacFactory', 'createFooBar'], $services['factory_with_static_call']->getFactory(), '->load() parses the factory tag with Class::method'); + $this->assertEquals([new Reference('factory'), '__invoke'], $services['invokable_factory']->getFactory(), '->load() parses string service reference'); + } + + public function testFactorySyntaxError() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The value of the "factory" option for the "invalid_factory" service must be the id of the service without the "@" prefix (replace "@factory:method" with "factory:method").'); + $loader->load('bad_factory_syntax.yml'); } public function testLoadConfiguratorShortSyntax() From b9ac645d8bfa6ad01ed2a8340161db784e15019f Mon Sep 17 00:00:00 2001 From: neghmurken <pierre.bobiet@knplabs.com> Date: Thu, 11 Oct 2018 00:18:00 +0200 Subject: [PATCH 368/495] Locale aware service registration --- UPGRADE-4.3.md | 1 + UPGRADE-5.0.md | 1 + .../Bundle/FrameworkBundle/CHANGELOG.md | 5 +- .../Compiler/UnusedTagsPass.php | 1 + .../FrameworkExtension.php | 3 + .../FrameworkBundle/FrameworkBundle.php | 2 + .../Resources/config/services.xml | 6 + .../Resources/config/translation.xml | 7 +- src/Symfony/Component/HttpKernel/CHANGELOG.md | 4 +- .../RegisterLocaleAwareServicesPass.php | 58 +++++++++ .../EventListener/LocaleAwareListener.php | 76 +++++++++++ .../EventListener/TranslatorListener.php | 4 +- .../RegisterLocaleAwareServicesPassTest.php | 59 +++++++++ .../EventListener/LocaleAwareListenerTest.php | 119 ++++++++++++++++++ .../EventListener/TranslatorListenerTest.php | 3 + 15 files changed, 339 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/HttpKernel/DependencyInjection/RegisterLocaleAwareServicesPass.php create mode 100644 src/Symfony/Component/HttpKernel/EventListener/LocaleAwareListener.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleAwareListenerTest.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index ba8ab75cb2965..110e58ed65935 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -86,6 +86,7 @@ HttpKernel * Renamed `GetResponseForControllerResultEvent` to `ViewEvent` * Renamed `GetResponseForExceptionEvent` to `ExceptionEvent` * Renamed `PostResponseEvent` to `TerminateEvent` + * Deprecated `TranslatorListener` in favor of `LocaleAwareListener` Messenger --------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 00a819543d2e7..7c4a38aba253e 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -232,6 +232,7 @@ HttpKernel * Removed `GetResponseForControllerResultEvent`, use `ViewEvent` instead * Removed `GetResponseForExceptionEvent`, use `ExceptionEvent` instead * Removed `PostResponseEvent`, use `TerminateEvent` instead + * Removed `TranslatorListener` in favor of `LocaleAwareListener` Messenger --------- diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 3d19141469a67..d38ddc7e6d88f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -4,13 +4,14 @@ CHANGELOG 4.3.0 ----- - * added `WebTestAssertions` trait (included by default in `WebTestCase`) - * renamed `Client` to `KernelBrowser` + * Added `WebTestAssertionsTrait` (included by default in `WebTestCase`) + * Renamed `Client` to `KernelBrowser` * Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will be mandatory in 5.0. * Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead * Added the ability to specify a custom `serializer` option for each transport under`framework.messenger.transports`. + * Added the `RegisterLocaleAwareServicesPass` and configured the `LocaleAwareListener` * [BC Break] When using Messenger, the default transport changed from using Symfony's serializer service to use `PhpSerializer`, which uses PHP's native `serialize()` and `unserialize()` functions. To use the diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index 2e433cdc6c9f6..efeafad5f06e0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -40,6 +40,7 @@ class UnusedTagsPass implements CompilerPassInterface 'kernel.event_listener', 'kernel.event_subscriber', 'kernel.fragment_renderer', + 'kernel.locale_aware', 'messenger.bus', 'messenger.receiver', 'messenger.message_handler', diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 4831af368e879..f3491d35695b7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -119,6 +119,7 @@ use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\Service\ResetInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; +use Symfony\Contracts\Translation\LocaleAwareInterface; /** * FrameworkExtension. @@ -370,6 +371,8 @@ public function load(array $configs, ContainerBuilder $container) ->addTag('kernel.cache_warmer'); $container->registerForAutoconfiguration(EventSubscriberInterface::class) ->addTag('kernel.event_subscriber'); + $container->registerForAutoconfiguration(LocaleAwareInterface::class) + ->addTag('kernel.locale_aware'); $container->registerForAutoconfiguration(ResetInterface::class) ->addTag('kernel.reset', ['method' => 'reset']); diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index c7b37222ae20e..97b4ef28a6646 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -41,6 +41,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass; use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass; use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass; +use Symfony\Component\HttpKernel\DependencyInjection\RegisterLocaleAwareServicesPass; use Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass; use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; use Symfony\Component\HttpKernel\KernelEvents; @@ -121,6 +122,7 @@ public function build(ContainerBuilder $container) $this->addCompilerPassIfExists($container, FormPass::class); $container->addCompilerPass(new WorkflowGuardListenerPass()); $container->addCompilerPass(new ResettableServicePass()); + $container->addCompilerPass(new RegisterLocaleAwareServicesPass()); $container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32); $container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING); $this->addCompilerPassIfExists($container, AddMimeTypeGuesserPass::class); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index 7f4f5890fa899..7455ae8833de3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -112,5 +112,11 @@ <argument type="service_locator" /> </service> <service id="Symfony\Component\DependencyInjection\ReverseContainer" alias="reverse_container" /> + + <service id="locale_aware_listener" class="Symfony\Component\HttpKernel\EventListener\LocaleAwareListener"> + <argument type="collection" /> <!-- locale aware services --> + <argument type="service" id="request_stack" /> + <tag name="kernel.event_subscriber" /> + </service> </services> </container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml index 8853914f65261..a9d5a85d202e8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/translation.xml @@ -19,6 +19,7 @@ <call method="setConfigCacheFactory"> <argument type="service" id="config_cache_factory" /> </call> + <tag name="kernel.locale_aware" /> </service> <service id="Symfony\Component\Translation\TranslatorInterface" alias="translator" /> <service id="Symfony\Contracts\Translation\TranslatorInterface" alias="translator" /> @@ -140,11 +141,5 @@ <tag name="kernel.cache_warmer" /> <argument type="service" id="Psr\Container\ContainerInterface" /> </service> - - <service id="translator_listener" class="Symfony\Component\HttpKernel\EventListener\TranslatorListener"> - <argument type="service" id="translator" /> - <argument type="service" id="request_stack" /> - <tag name="kernel.event_subscriber" /> - </service> </services> </container> diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 310f9818d85de..06193a00b3395 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -8,7 +8,9 @@ CHANGELOG * `KernelInterface` doesn't extend `Serializable` anymore * deprecated the `Kernel::serialize()` and `unserialize()` methods * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` - * made `Symfony\Component\HttpKernel\EventListenerLocaleListener` set the default locale early + * made `Symfony\Component\HttpKernel\EventListener\LocaleListener` set the default locale early + * deprecated `TranslatorListener` in favor of `LocaleAwareListener` + * added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener` * made `FileLinkFormatter` final and not implement `Serializable` anymore * the base `DataCollector` doesn't implement `Serializable` anymore, you should store all the serialized state in the data property instead diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterLocaleAwareServicesPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterLocaleAwareServicesPass.php new file mode 100644 index 0000000000000..0efb164b72207 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterLocaleAwareServicesPass.php @@ -0,0 +1,58 @@ +<?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\Component\HttpKernel\DependencyInjection; + +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Register all services that have the "kernel.locale_aware" tag into the listener. + * + * @author Pierre Bobiet <pierrebobiet@gmail.com> + */ +class RegisterLocaleAwareServicesPass implements CompilerPassInterface +{ + private $listenerServiceId; + private $localeAwareTag; + + public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware') + { + $this->listenerServiceId = $listenerServiceId; + $this->localeAwareTag = $localeAwareTag; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->listenerServiceId)) { + return; + } + + $services = []; + + foreach ($container->findTaggedServiceIds($this->localeAwareTag) as $id => $tags) { + $services[] = new Reference($id); + } + + if (!$services) { + $container->removeDefinition($this->listenerServiceId); + + return; + } + + $container + ->getDefinition($this->listenerServiceId) + ->setArgument(0, new IteratorArgument($services)) + ; + } +} diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleAwareListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleAwareListener.php new file mode 100644 index 0000000000000..325b8cbc0d569 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleAwareListener.php @@ -0,0 +1,76 @@ +<?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\Component\HttpKernel\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +/** + * Pass the current locale to the provided services. + * + * @author Pierre Bobiet <pierrebobiet@gmail.com> + */ +class LocaleAwareListener implements EventSubscriberInterface +{ + private $localeAwareServices; + private $requestStack; + + /** + * @param LocaleAwareInterface[] $localeAwareServices + */ + public function __construct(iterable $localeAwareServices, RequestStack $requestStack) + { + $this->localeAwareServices = $localeAwareServices; + $this->requestStack = $requestStack; + } + + public function onKernelRequest(RequestEvent $event): void + { + $this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale()); + } + + public function onKernelFinishRequest(FinishRequestEvent $event): void + { + if (null === $parentRequest = $this->requestStack->getParentRequest()) { + $this->setLocale($event->getRequest()->getDefaultLocale()); + + return; + } + + $this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale()); + } + + public static function getSubscribedEvents() + { + return [ + // must be registered after the Locale listener + KernelEvents::REQUEST => [['onKernelRequest', 15]], + KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]], + ]; + } + + private function setLocale(string $locale, ?string $defaultLocale = null): void + { + foreach ($this->localeAwareServices as $service) { + try { + $service->setLocale($locale); + } catch (\InvalidArgumentException $e) { + $service->setLocale($defaultLocale); + } + } + } +} diff --git a/src/Symfony/Component/HttpKernel/EventListener/TranslatorListener.php b/src/Symfony/Component/HttpKernel/EventListener/TranslatorListener.php index 4d022f750c6fb..d28eee2b1ad21 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/TranslatorListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/TranslatorListener.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpKernel\EventListener; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3 and will be removed in 5.0, use LocaleAwareListener instead.', TranslatorListener::class), E_USER_DEPRECATED); + use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -25,7 +27,7 @@ * * @author Fabien Potencier <fabien@symfony.com> * - * @final since Symfony 4.3 + * @deprecated since Symfony 4.3, use LocaleAwareListener instead */ class TranslatorListener implements EventSubscriberInterface { diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php new file mode 100644 index 0000000000000..aa3c6aa0c46c5 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php @@ -0,0 +1,59 @@ +<?php + +namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpKernel\DependencyInjection\RegisterLocaleAwareServicesPass; +use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +class RegisterLocaleAwareServicesPassTest extends TestCase +{ + public function testCompilerPass() + { + $container = new ContainerBuilder(); + + $container->register('locale_aware_listener', LocaleAwareListener::class) + ->setPublic(true) + ->setArguments([null, null]); + + $container->register('some_locale_aware_service', LocaleAwareInterface::class) + ->setPublic(true) + ->addTag('kernel.locale_aware'); + + $container->register('another_locale_aware_service', LocaleAwareInterface::class) + ->setPublic(true) + ->addTag('kernel.locale_aware'); + + $container->addCompilerPass(new RegisterLocaleAwareServicesPass()); + $container->compile(); + + $this->assertEquals( + [ + new IteratorArgument([ + 0 => new Reference('some_locale_aware_service'), + 1 => new Reference('another_locale_aware_service'), + ]), + null, + ], + $container->getDefinition('locale_aware_listener')->getArguments() + ); + } + + public function testListenerUnregisteredWhenNoLocaleAwareServices() + { + $container = new ContainerBuilder(); + + $container->register('locale_aware_listener', LocaleAwareListener::class) + ->setPublic(true) + ->setArguments([null, null]); + + $container->addCompilerPass(new RegisterLocaleAwareServicesPass()); + $container->compile(); + + $this->assertFalse($container->hasDefinition('locale_aware_listener')); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleAwareListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleAwareListenerTest.php new file mode 100644 index 0000000000000..489b02151c9d9 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleAwareListenerTest.php @@ -0,0 +1,119 @@ +<?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\Component\HttpKernel\Tests\EventListener; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +class LocaleAwareListenerTest extends TestCase +{ + private $listener; + private $localeAwareService; + private $requestStack; + + protected function setUp() + { + $this->localeAwareService = $this->getMockBuilder(LocaleAwareInterface::class)->getMock(); + $this->requestStack = new RequestStack(); + $this->listener = new LocaleAwareListener(new \ArrayIterator([$this->localeAwareService]), $this->requestStack); + } + + public function testLocaleIsSetInOnKernelRequest() + { + $this->localeAwareService + ->expects($this->once()) + ->method('setLocale') + ->with($this->equalTo('fr')); + + $event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); + $this->listener->onKernelRequest($event); + } + + public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest() + { + $this->localeAwareService + ->expects($this->at(0)) + ->method('setLocale') + ->will($this->throwException(new \InvalidArgumentException())); + $this->localeAwareService + ->expects($this->at(1)) + ->method('setLocale') + ->with($this->equalTo('en')); + + $event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); + $this->listener->onKernelRequest($event); + } + + public function testLocaleIsSetInOnKernelFinishRequestWhenParentRequestExists() + { + $this->localeAwareService + ->expects($this->once()) + ->method('setLocale') + ->with($this->equalTo('fr')); + + $this->requestStack->push($this->createRequest('fr')); + $this->requestStack->push($subRequest = $this->createRequest('de')); + + $event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST); + $this->listener->onKernelFinishRequest($event); + } + + public function testLocaleIsSetToDefaultOnKernelFinishRequestWhenParentRequestDoesNotExist() + { + $this->localeAwareService + ->expects($this->once()) + ->method('setLocale') + ->with($this->equalTo('en')); + + $this->requestStack->push($subRequest = $this->createRequest('de')); + + $event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST); + $this->listener->onKernelFinishRequest($event); + } + + public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest() + { + $this->localeAwareService + ->expects($this->at(0)) + ->method('setLocale') + ->will($this->throwException(new \InvalidArgumentException())); + $this->localeAwareService + ->expects($this->at(1)) + ->method('setLocale') + ->with($this->equalTo('en')); + + $this->requestStack->push($this->createRequest('fr')); + $this->requestStack->push($subRequest = $this->createRequest('de')); + + $event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST); + $this->listener->onKernelFinishRequest($event); + } + + private function createHttpKernel() + { + return $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + } + + private function createRequest($locale) + { + $request = new Request(); + $request->setLocale($locale); + + return $request; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/TranslatorListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/TranslatorListenerTest.php index 3fecf9aab3bac..1627a2b191906 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/TranslatorListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/TranslatorListenerTest.php @@ -19,6 +19,9 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Contracts\Translation\LocaleAwareInterface; +/** + * @group legacy + */ class TranslatorListenerTest extends TestCase { private $listener; From 4050ec42576ab3b5c01c7773e4fbed4552f4ea50 Mon Sep 17 00:00:00 2001 From: Titouan Galopin <galopintitouan@gmail.com> Date: Sat, 24 Nov 2018 11:19:23 +0100 Subject: [PATCH 369/495] [DomCrawler] Optionally use html5-php to parse HTML --- composer.json | 2 + .../Controller/SessionController.php | 10 +- .../Controller/LocalizedController.php | 4 +- src/Symfony/Component/DomCrawler/CHANGELOG.md | 2 + src/Symfony/Component/DomCrawler/Crawler.php | 103 ++++++++--- ...rawlerTest.php => AbstractCrawlerTest.php} | 164 +++++++----------- .../Tests/Html5ParserCrawlerTest.php | 22 +++ .../Tests/NativeParserCrawlerTest.php | 70 ++++++++ .../Component/DomCrawler/composer.json | 6 +- 9 files changed, 246 insertions(+), 137 deletions(-) rename src/Symfony/Component/DomCrawler/Tests/{CrawlerTest.php => AbstractCrawlerTest.php} (94%) create mode 100644 src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php create mode 100644 src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php diff --git a/composer.json b/composer.json index 56c224e216378..62a7f751dccaf 100644 --- a/composer.json +++ b/composer.json @@ -101,6 +101,7 @@ "doctrine/orm": "~2.4,>=2.4.5", "doctrine/reflection": "~1.0", "doctrine/doctrine-bundle": "~1.4", + "masterminds/html5": "^2.6", "monolog/monolog": "~1.11", "nyholm/psr7": "^1.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", @@ -112,6 +113,7 @@ "phpdocumentor/reflection-docblock": "^3.0|^4.0" }, "conflict": { + "masterminds/html5": "<2.6", "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", "phpdocumentor/type-resolver": "<0.3.0", "phpunit/phpunit": "<5.4.3" diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php index e4d8560835988..0d9464d7dfab4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php @@ -28,19 +28,19 @@ public function welcomeAction(Request $request, $name = null) // new session case if (!$session->has('name')) { if (!$name) { - return new Response('You are new here and gave no name.'); + return new Response('<html><body>You are new here and gave no name.</body></html>'); } // remember name $session->set('name', $name); - return new Response(sprintf('Hello %s, nice to meet you.', $name)); + return new Response(sprintf('<html><body>Hello %s, nice to meet you.</body></html>', $name)); } // existing session $name = $session->get('name'); - return new Response(sprintf('Welcome back %s, nice to meet you.', $name)); + return new Response(sprintf('<html><body>Welcome back %s, nice to meet you.</body></html>', $name)); } public function cacheableAction() @@ -55,7 +55,7 @@ public function logoutAction(Request $request) { $request->getSession()->invalidate(); - return new Response('Session cleared.'); + return new Response('<html><body>Session cleared.</body></html>'); } public function setFlashAction(Request $request, $message) @@ -76,6 +76,6 @@ public function showFlashAction(Request $request) $output = 'No flash was set.'; } - return new Response($output); + return new Response('<html><body>'.$output.'</body></html>'); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php index 3bf2a7767c833..269827e2df5f2 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/FormLoginBundle/Controller/LocalizedController.php @@ -54,11 +54,11 @@ public function secureAction() public function profileAction() { - return new Response('Profile'); + return new Response('<html><body>Profile</body></html>'); } public function homepageAction() { - return new Response('Homepage'); + return new Response('<html><body>Homepage</body></html>'); } } diff --git a/src/Symfony/Component/DomCrawler/CHANGELOG.md b/src/Symfony/Component/DomCrawler/CHANGELOG.md index fae5bd3f1d915..8c1bbc5fbe160 100644 --- a/src/Symfony/Component/DomCrawler/CHANGELOG.md +++ b/src/Symfony/Component/DomCrawler/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * Added return of element name (`_name`) in `extract()` method. * Added ability to return a default value in `text()` and `html()` instead of throwing an exception when node is empty. +* When available, the [html5-php library](https://github.com/Masterminds/html5-php) is used to + parse HTML added to a Crawler for better support of HTML5 tags. 4.2.0 ----- diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 760d3df38856e..b41fdbaa496cc 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DomCrawler; +use Masterminds\HTML5; use Symfony\Component\CssSelector\CssSelectorConverter; /** @@ -55,15 +56,29 @@ class Crawler implements \Countable, \IteratorAggregate private $isHtml = true; /** - * @param mixed $node A Node to use as the base for the crawling - * @param string $uri The current URI - * @param string $baseHref The base href value + * @var HTML5|null */ - public function __construct($node = null, string $uri = null, string $baseHref = null) + private $html5Parser; + + /** + * @param mixed $node A Node to use as the base for the crawling + * @param string $uri The current URI + * @param string $baseHref The base href value + * @param bool|null $useHtml5Parser Whether the Crawler should use the HTML5 parser or the native DOM parser + */ + public function __construct($node = null, string $uri = null, string $baseHref = null, bool $useHtml5Parser = null) { $this->uri = $uri; $this->baseHref = $baseHref ?: $uri; + if ($useHtml5Parser && !class_exists(HTML5::class)) { + throw new \LogicException('Using the DomCrawler HTML5 parser requires the html5-php library. Try running "composer require masterminds/html5".'); + } + + if ($useHtml5Parser ?? class_exists(HTML5::class)) { + $this->html5Parser = new HTML5(['disable_html_ns' => true]); + } + $this->add($node); } @@ -183,29 +198,7 @@ public function addContent($content, $type = null) */ public function addHtmlContent($content, $charset = 'UTF-8') { - $internalErrors = libxml_use_internal_errors(true); - $disableEntities = libxml_disable_entity_loader(true); - - $dom = new \DOMDocument('1.0', $charset); - $dom->validateOnParse = true; - - set_error_handler(function () { throw new \Exception(); }); - - try { - // Convert charset to HTML-entities to work around bugs in DOMDocument::loadHTML() - $content = mb_convert_encoding($content, 'HTML-ENTITIES', $charset); - } catch (\Exception $e) { - } - - restore_error_handler(); - - if ('' !== trim($content)) { - @$dom->loadHTML($content); - } - - libxml_use_internal_errors($internalErrors); - libxml_disable_entity_loader($disableEntities); - + $dom = null !== $this->html5Parser ? $this->parseHtml5($content, $charset) : $this->parseXhtml($content, $charset); $this->addDocument($dom); $base = $this->filterRelativeXPath('descendant-or-self::base')->extract(['href']); @@ -608,6 +601,15 @@ public function html(/* $default = null */) throw new \InvalidArgumentException('The current node list is empty.'); } + if (null !== $this->html5Parser) { + $html = ''; + foreach ($this->getNode(0)->childNodes as $child) { + $html .= $this->html5Parser->saveHTML($child); + } + + return $html; + } + $html = ''; foreach ($this->getNode(0)->childNodes as $child) { $html .= $child->ownerDocument->saveHTML($child); @@ -1112,6 +1114,53 @@ protected function sibling($node, $siblingDir = 'nextSibling') return $nodes; } + private function parseHtml5(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument + { + return $this->html5Parser->parse($this->convertToHtmlEntities($htmlContent, $charset), [], $charset); + } + + private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DOMDocument + { + $htmlContent = $this->convertToHtmlEntities($htmlContent, $charset); + + $internalErrors = libxml_use_internal_errors(true); + $disableEntities = libxml_disable_entity_loader(true); + + $dom = new \DOMDocument('1.0', $charset); + $dom->validateOnParse = true; + + if ('' !== trim($htmlContent)) { + @$dom->loadHTML($htmlContent); + } + + libxml_use_internal_errors($internalErrors); + libxml_disable_entity_loader($disableEntities); + + return $dom; + } + + /** + * Convert charset to HTML-entities to ensure valid parsing. + */ + private function convertToHtmlEntities(string $htmlContent, string $charset = 'UTF-8'): string + { + set_error_handler(function () { throw new \Exception(); }); + + try { + return mb_convert_encoding($htmlContent, 'HTML-ENTITIES', $charset); + } catch (\Exception $e) { + try { + $htmlContent = iconv($charset, 'UTF-8', $htmlContent); + $htmlContent = mb_convert_encoding($htmlContent, 'HTML-ENTITIES', 'UTF-8'); + } catch (\Exception $e) { + } + + return $htmlContent; + } finally { + restore_error_handler(); + } + } + /** * @throws \InvalidArgumentException */ diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php similarity index 94% rename from src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php rename to src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php index dac52ff5624ce..e77cb8cdf87ae 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php @@ -14,41 +14,50 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DomCrawler\Crawler; -class CrawlerTest extends TestCase +abstract class AbstractCrawlerTest extends TestCase { + /** + * @param mixed $node + * @param string|null $uri + * @param string|null $baseHref + * + * @return Crawler + */ + abstract public function createCrawler($node = null, string $uri = null, string $baseHref = null); + public function testConstructor() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $this->assertCount(0, $crawler, '__construct() returns an empty crawler'); $doc = new \DOMDocument(); $node = $doc->createElement('test'); - $crawler = new Crawler($node); + $crawler = $this->createCrawler($node); $this->assertCount(1, $crawler, '__construct() takes a node as a first argument'); } public function testGetUri() { $uri = 'http://symfony.com'; - $crawler = new Crawler(null, $uri); + $crawler = $this->createCrawler(null, $uri); $this->assertEquals($uri, $crawler->getUri()); } public function testGetBaseHref() { $baseHref = 'http://symfony.com'; - $crawler = new Crawler(null, null, $baseHref); + $crawler = $this->createCrawler(null, null, $baseHref); $this->assertEquals($baseHref, $crawler->getBaseHref()); } public function testAdd() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->add($this->createDomDocument()); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMDocument'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->add($this->createNodeList()); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMNodeList'); @@ -56,15 +65,15 @@ public function testAdd() foreach ($this->createNodeList() as $node) { $list[] = $node; } - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->add($list); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from an array of nodes'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->add($this->createNodeList()->item(0)); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMNode'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->add('<html><body>Foo</body></html>'); $this->assertEquals('Foo', $crawler->filterXPath('//body')->text(), '->add() adds nodes from a string'); } @@ -74,7 +83,7 @@ public function testAdd() */ public function testAddInvalidType() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->add(1); } @@ -90,7 +99,7 @@ public function testAddMultipleDocumentNode() public function testAddHtmlContent() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addHtmlContent('<html><div class="foo"></html>', 'UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addHtmlContent() adds nodes from an HTML string'); @@ -98,7 +107,7 @@ public function testAddHtmlContent() public function testAddHtmlContentWithBaseTag() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addHtmlContent('<html><head><base href="http://symfony.com"></head><a href="/contact"></a></html>', 'UTF-8'); @@ -111,7 +120,7 @@ public function testAddHtmlContentWithBaseTag() */ public function testAddHtmlContentCharset() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addHtmlContent('<html><div class="foo">Tiếng Việt</html>', 'UTF-8'); $this->assertEquals('Tiếng Việt', $crawler->filterXPath('//div')->text()); @@ -119,61 +128,27 @@ public function testAddHtmlContentCharset() public function testAddHtmlContentInvalidBaseTag() { - $crawler = new Crawler(null, 'http://symfony.com'); - + $crawler = $this->createCrawler(null, 'http://symfony.com'); $crawler->addHtmlContent('<html><head><base target="_top"></head><a href="/contact"></a></html>', 'UTF-8'); $this->assertEquals('http://symfony.com/contact', current($crawler->filterXPath('//a')->links())->getUri(), '->addHtmlContent() correctly handles a non-existent base tag href attribute'); } - public function testAddHtmlContentUnsupportedCharset() - { - $crawler = new Crawler(); - $crawler->addHtmlContent(file_get_contents(__DIR__.'/Fixtures/windows-1250.html'), 'Windows-1250'); - - $this->assertEquals('Žťčýů', $crawler->filterXPath('//p')->text()); - } - /** * @requires extension mbstring */ public function testAddHtmlContentCharsetGbk() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); //gbk encode of <html><p>中文</p></html> $crawler->addHtmlContent(base64_decode('PGh0bWw+PHA+1tDOxDwvcD48L2h0bWw+'), 'gbk'); $this->assertEquals('中文', $crawler->filterXPath('//p')->text()); } - public function testAddHtmlContentWithErrors() - { - $internalErrors = libxml_use_internal_errors(true); - - $crawler = new Crawler(); - $crawler->addHtmlContent(<<<'EOF' -<!DOCTYPE html> -<html> - <head> - </head> - <body> - <nav><a href="#"><a href="#"></nav> - </body> -</html> -EOF - , 'UTF-8'); - - $errors = libxml_get_errors(); - $this->assertCount(1, $errors); - $this->assertEquals("Tag nav invalid\n", $errors[0]->message); - - libxml_clear_errors(); - libxml_use_internal_errors($internalErrors); - } - public function testAddXmlContent() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addXmlContent('<html><div class="foo"></div></html>', 'UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addXmlContent() adds nodes from an XML string'); @@ -181,62 +156,39 @@ public function testAddXmlContent() public function testAddXmlContentCharset() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addXmlContent('<html><div class="foo">Tiếng Việt</div></html>', 'UTF-8'); $this->assertEquals('Tiếng Việt', $crawler->filterXPath('//div')->text()); } - public function testAddXmlContentWithErrors() - { - $internalErrors = libxml_use_internal_errors(true); - - $crawler = new Crawler(); - $crawler->addXmlContent(<<<'EOF' -<!DOCTYPE html> -<html> - <head> - </head> - <body> - <nav><a href="#"><a href="#"></nav> - </body> -</html> -EOF - , 'UTF-8'); - - $this->assertGreaterThan(1, libxml_get_errors()); - - libxml_clear_errors(); - libxml_use_internal_errors($internalErrors); - } - public function testAddContent() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><div class="foo"></html>', 'text/html; charset=UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><div class="foo"></html>', 'text/html; charset=UTF-8; dir=RTL'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string with extended content type'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><div class="foo"></html>'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() uses text/html as the default type'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><div class="foo"></div></html>', 'text/xml; charset=UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><div class="foo"></div></html>', 'text/xml'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('foo bar', 'text/plain'); $this->assertCount(0, $crawler, '->addContent() does nothing if the type is not (x|ht)ml'); - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><span>中文</span></html>'); $this->assertEquals('中文', $crawler->filterXPath('//span')->text(), '->addContent() guess wrong charset'); } @@ -246,14 +198,14 @@ public function testAddContent() */ public function testAddContentNonUtf8() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent(iconv('UTF-8', 'SJIS', '<html><head><meta charset="Shift_JIS"></head><body>日本語</body></html>')); $this->assertEquals('日本語', $crawler->filterXPath('//body')->text(), '->addContent() can recognize "Shift_JIS" in html5 meta charset tag'); } public function testAddDocument() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addDocument($this->createDomDocument()); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addDocument() adds nodes from a \DOMDocument'); @@ -261,7 +213,7 @@ public function testAddDocument() public function testAddNodeList() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addNodeList($this->createNodeList()); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodeList() adds nodes from a \DOMNodeList'); @@ -274,7 +226,7 @@ public function testAddNodes() $list[] = $node; } - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addNodes($list); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNodes() adds nodes from an array of nodes'); @@ -282,7 +234,7 @@ public function testAddNodes() public function testAddNode() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addNode($this->createNodeList()->item(0)); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addNode() adds nodes from a \DOMNode'); @@ -293,7 +245,7 @@ public function testClear() $doc = new \DOMDocument(); $node = $doc->createElement('test'); - $crawler = new Crawler($node); + $crawler = $this->createCrawler($node); $crawler->clear(); $this->assertCount(0, $crawler, '->clear() removes all the nodes from the crawler'); } @@ -361,7 +313,7 @@ public function testAttr() public function testMissingAttrValueIsNull() { - $crawler = new Crawler(); + $crawler = $this->createCrawler(); $crawler->addContent('<html><div non-empty-attr="sample value" empty-attr=""></div></html>', 'text/html; charset=UTF-8'); $div = $crawler->filterXPath('//div'); @@ -647,7 +599,7 @@ public function testFilterWithMultipleNamespaces() public function testFilterWithDefaultNamespaceOnly() { - $crawler = new Crawler('<?xml version="1.0" encoding="UTF-8"?> + $crawler = $this->createCrawler('<?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>http://localhost/foo</loc> @@ -731,7 +683,7 @@ public function testSelectButtonWithSingleQuotesInNameAttribute() </html> HTML; - $crawler = new Crawler($html); + $crawler = $this->createCrawler($html); $this->assertCount(1, $crawler->selectButton('Click \'Here\'')); } @@ -752,7 +704,7 @@ public function testSelectButtonWithDoubleQuotesInNameAttribute() </html> HTML; - $crawler = new Crawler($html); + $crawler = $this->createCrawler($html); $this->assertCount(1, $crawler->selectButton('Click "Here"')); } @@ -824,7 +776,7 @@ public function testSelectLinkAndLinkFiltered() </html> HTML; - $crawler = new Crawler($html); + $crawler = $this->createCrawler($html); $filtered = $crawler->filterXPath("descendant-or-self::*[@id = 'login-form']"); $this->assertCount(0, $filtered->selectLink('Login')); @@ -841,7 +793,7 @@ public function testSelectLinkAndLinkFiltered() public function testChaining() { - $crawler = new Crawler('<div name="a"><div name="b"><div name="c"></div></div></div>'); + $crawler = $this->createCrawler('<div name="a"><div name="b"><div name="c"></div></div></div>'); $this->assertEquals('a', $crawler->filterXPath('//div')->filterXPath('div')->filterXPath('div')->attr('name')); } @@ -1000,7 +952,7 @@ public function testChildren() } try { - $crawler = new Crawler('<p></p>'); + $crawler = $this->createCrawler('<p></p>'); $crawler->filter('p')->children(); $this->assertTrue(true, '->children() does not trigger a notice if the node has no children'); } catch (\PHPUnit\Framework\Error\Notice $e) { @@ -1029,7 +981,7 @@ public function testFilteredChildren() </html> HTML; - $crawler = new Crawler($html); + $crawler = $this->createCrawler($html); $foo = $crawler->filter('#foo'); $this->assertEquals(3, $foo->children()->count()); @@ -1066,7 +1018,7 @@ public function testParents() */ public function testBaseTag($baseValue, $linkValue, $expectedUri, $currentUri = null, $description = '') { - $crawler = new Crawler('<html><base href="'.$baseValue.'"><a href="'.$linkValue.'"></a></html>', $currentUri); + $crawler = $this->createCrawler('<html><base href="'.$baseValue.'"><a href="'.$linkValue.'"></a></html>', $currentUri); $this->assertEquals($expectedUri, $crawler->filterXPath('//a')->link()->getUri(), $description); } @@ -1086,7 +1038,7 @@ public function getBaseTagData() */ public function testBaseTagWithForm($baseValue, $actionValue, $expectedUri, $currentUri = null, $description = null) { - $crawler = new Crawler('<html><base href="'.$baseValue.'"><form method="post" action="'.$actionValue.'"><button type="submit" name="submit"/></form></html>', $currentUri); + $crawler = $this->createCrawler('<html><base href="'.$baseValue.'"><form method="post" action="'.$actionValue.'"><button type="submit" name="submit"/></form></html>', $currentUri); $this->assertEquals($expectedUri, $crawler->filterXPath('//button')->form()->getUri(), $description); } @@ -1104,7 +1056,7 @@ public function getBaseTagWithFormData() public function testCountOfNestedElements() { - $crawler = new Crawler('<html><body><ul><li>List item 1<ul><li>Sublist item 1</li><li>Sublist item 2</ul></li></ul></body></html>'); + $crawler = $this->createCrawler('<html><body><ul><li>List item 1<ul><li>Sublist item 1</li><li>Sublist item 2</ul></li></ul></body></html>'); $this->assertCount(1, $crawler->filter('li:contains("List item 1")')); } @@ -1151,7 +1103,7 @@ public function testEvaluateReturnsACrawlerIfXPathExpressionEvaluatesToANode() */ public function testEvaluateThrowsAnExceptionIfDocumentIsEmpty() { - (new Crawler())->evaluate('//form/input[1]'); + $this->createCrawler()->evaluate('//form/input[1]'); } /** @@ -1210,6 +1162,14 @@ public function testInheritedClassCallChildrenWithoutArgument() $crawlerChild->children(); } + public function testAddHtmlContentUnsupportedCharset() + { + $crawler = $this->createCrawler(); + $crawler->addHtmlContent(file_get_contents(__DIR__.'/Fixtures/windows-1250.html'), 'Windows-1250'); + + $this->assertEquals('Žťčýů', $crawler->filterXPath('//p')->text()); + } + public function createTestCrawler($uri = null) { $dom = new \DOMDocument(); @@ -1259,7 +1219,7 @@ public function createTestCrawler($uri = null) </html> '); - return new Crawler($dom, $uri); + return $this->createCrawler($dom, $uri); } protected function createTestXmlCrawler($uri = null) @@ -1276,7 +1236,7 @@ protected function createTestXmlCrawler($uri = null) <media:category label="Music" scheme="http://gdata.youtube.com/schemas/2007/categories.cat">Music</media:category> </entry>'; - return new Crawler($xml, $uri); + return $this->createCrawler($xml, $uri); } protected function createDomDocument() diff --git a/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php new file mode 100644 index 0000000000000..eec97e865acbd --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php @@ -0,0 +1,22 @@ +<?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\Component\DomCrawler\Tests; + +use Symfony\Component\DomCrawler\Crawler; + +class Html5ParserCrawlerTest extends AbstractCrawlerTest +{ + public function createCrawler($node = null, string $uri = null, string $baseHref = null) + { + return new Crawler($node, $uri, $baseHref, true); + } +} diff --git a/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php new file mode 100644 index 0000000000000..5a5a65b352017 --- /dev/null +++ b/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php @@ -0,0 +1,70 @@ +<?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\Component\DomCrawler\Tests; + +use Symfony\Component\DomCrawler\Crawler; + +class NativeParserCrawlerTest extends AbstractCrawlerTest +{ + public function createCrawler($node = null, string $uri = null, string $baseHref = null) + { + return new Crawler($node, $uri, $baseHref, false); + } + + public function testAddHtmlContentWithErrors() + { + $internalErrors = libxml_use_internal_errors(true); + + $crawler = $this->createCrawler(); + $crawler->addHtmlContent(<<<'EOF' +<!DOCTYPE html> +<html> + <head> + </head> + <body> + <nav><a href="#"><a href="#"></nav> + </body> +</html> +EOF + , 'UTF-8'); + + $errors = libxml_get_errors(); + $this->assertCount(1, $errors); + $this->assertEquals("Tag nav invalid\n", $errors[0]->message); + + libxml_clear_errors(); + libxml_use_internal_errors($internalErrors); + } + + public function testAddXmlContentWithErrors() + { + $internalErrors = libxml_use_internal_errors(true); + + $crawler = $this->createCrawler(); + $crawler->addXmlContent(<<<'EOF' +<!DOCTYPE html> +<html> + <head> + </head> + <body> + <nav><a href="#"><a href="#"></nav> + </body> +</html> +EOF + , 'UTF-8'); + + $this->assertGreaterThan(1, libxml_get_errors()); + + libxml_clear_errors(); + libxml_use_internal_errors($internalErrors); + } +} diff --git a/src/Symfony/Component/DomCrawler/composer.json b/src/Symfony/Component/DomCrawler/composer.json index b3173484c1e7d..31ddb55009e8b 100644 --- a/src/Symfony/Component/DomCrawler/composer.json +++ b/src/Symfony/Component/DomCrawler/composer.json @@ -21,7 +21,11 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/css-selector": "~3.4|~4.0" + "symfony/css-selector": "~3.4|~4.0", + "masterminds/html5": "^2.6" + }, + "conflict": { + "masterminds/html5": "<2.6" }, "suggest": { "symfony/css-selector": "" From 757ae748b7d80a1e3c5b5308e46b1417651d9f6c Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Wed, 3 Apr 2019 15:17:57 +0200 Subject: [PATCH 370/495] fixed typo --- src/Symfony/Component/DomCrawler/Crawler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index b41fdbaa496cc..590462238b4be 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -1140,7 +1140,7 @@ private function parseXhtml(string $htmlContent, string $charset = 'UTF-8'): \DO } /** - * Convert charset to HTML-entities to ensure valid parsing. + * Converts charset to HTML-entities to ensure valid parsing. */ private function convertToHtmlEntities(string $htmlContent, string $charset = 'UTF-8'): string { From fc5b0cf570d8c74859cfd89a6b6c8b704478c4b5 Mon Sep 17 00:00:00 2001 From: Ryan Weaver <ryan@thatsquality.com> Date: Thu, 28 Mar 2019 09:09:33 -0400 Subject: [PATCH 371/495] [Messenger] Adding MessageCountAwareInterface to get transport message count --- src/Symfony/Component/Messenger/CHANGELOG.md | 2 + .../AmqpExt/AmqpExtIntegrationTest.php | 18 ++++++++ .../Transport/Doctrine/ConnectionTest.php | 7 +++ .../Doctrine/DoctrineIntegrationTest.php | 40 +++++++++++++++++ .../Transport/AmqpExt/AmqpReceiver.php | 11 ++++- .../Transport/AmqpExt/AmqpTransport.php | 11 ++++- .../Transport/AmqpExt/Connection.php | 8 ++++ .../Transport/Doctrine/Connection.php | 44 +++++++++++++------ .../Transport/Doctrine/DoctrineReceiver.php | 11 ++++- .../Receiver/MessageCountAwareInterface.php | 28 ++++++++++++ 10 files changed, 164 insertions(+), 16 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Transport/Receiver/MessageCountAwareInterface.php diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index d8be5f33f36f8..f2de05282acc1 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * Added optional `MessageCountAwareInterface` that receivers can implement + to give information about how many messages are waiting to be processed. * [BC BREAK] The `Envelope::__construct()` signature changed: you can no longer pass an unlimited number of stamps as the second, third, fourth, arguments etc: stamps are now an array passed to the diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php index b2ebfe4ab5043..d3737007291ec 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php @@ -167,6 +167,24 @@ public function testItReceivesSignals() , $process->getOutput()); } + public function testItCountsMessagesInQueue() + { + $serializer = $this->createSerializer(); + + $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); + $connection->setup(); + $connection->queue()->purge(); + + $sender = new AmqpSender($connection, $serializer); + + $sender->send($first = new Envelope(new DummyMessage('First'))); + $sender->send($second = new Envelope(new DummyMessage('Second'))); + $sender->send($second = new Envelope(new DummyMessage('Third'))); + + sleep(1); // give amqp a moment to have the messages ready + $this->assertSame(3, $connection->countMessagesInQueue()); + } + private function waitForOutput(Process $process, string $output, $timeoutInSeconds = 10) { $timedOutTime = time() + $timeoutInSeconds; diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php index 26878e3647bfe..3d8bf82b53eb9 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -37,6 +37,9 @@ public function testGetAMessageWillChangeItsStatus() $queryBuilder ->method('getSQL') ->willReturn(''); + $queryBuilder + ->method('getParameters') + ->willReturn([]); $driverConnection ->method('prepare') ->willReturn($stmt); @@ -54,6 +57,9 @@ public function testGetWithNoPendingMessageWillReturnNull() $driverConnection = $this->getDBALConnectionMock(); $stmt = $this->getStatementMock(false); + $queryBuilder + ->method('getParameters') + ->willReturn([]); $driverConnection->expects($this->once()) ->method('createQueryBuilder') ->willReturn($queryBuilder); @@ -119,6 +125,7 @@ private function getQueryBuilderMock() $queryBuilder->method('orderBy')->willReturn($queryBuilder); $queryBuilder->method('setMaxResults')->willReturn($queryBuilder); $queryBuilder->method('setParameter')->willReturn($queryBuilder); + $queryBuilder->method('setParameters')->willReturn($queryBuilder); return $queryBuilder; } diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index ffcde2039306d..bc826832c593b 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -100,6 +100,46 @@ public function testItRetrieveTheFirstAvailableMessage() $this->assertEquals('{"message": "Hi available"}', $encoded['body']); } + public function testItCountMessages() + { + // insert messages + // one currently handled + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi handled"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'delivered_at' => Connection::formatDateTime(\DateTime::createFromFormat('U.u', microtime(true))), + ]); + // one available later + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi delayed"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime((new \DateTime())->modify('+1 minute')), + ]); + // one available + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi available"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')), + ]); + // another available + $this->driverConnection->insert('messenger_messages', [ + 'body' => '{"message": "Hi available"}', + 'headers' => json_encode(['type' => DummyMessage::class]), + 'queue_name' => 'default', + 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), + 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')), + ]); + + $this->assertSame(2, $this->connection->getMessageCount()); + } + public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout() { $twoHoursAgo = new \DateTime('now'); diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index 9f1e25a40267a..e81b6b9431120 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -15,6 +15,7 @@ use Symfony\Component\Messenger\Exception\LogicException; use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -26,7 +27,7 @@ * * @experimental in 4.2 */ -class AmqpReceiver implements ReceiverInterface +class AmqpReceiver implements ReceiverInterface, MessageCountAwareInterface { private $serializer; private $connection; @@ -87,6 +88,14 @@ public function reject(Envelope $envelope): void $this->rejectAmqpEnvelope($this->findAmqpEnvelope($envelope)); } + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + return $this->connection->countMessagesInQueue(); + } + private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope): void { try { diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php index 586e16c4d86dd..91c9fe45c0c3a 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpTransport.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Transport\AmqpExt; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; use Symfony\Component\Messenger\Transport\SetupableTransportInterface; @@ -22,7 +23,7 @@ * * @experimental in 4.2 */ -class AmqpTransport implements TransportInterface, SetupableTransportInterface +class AmqpTransport implements TransportInterface, SetupableTransportInterface, MessageCountAwareInterface { private $serializer; private $connection; @@ -75,6 +76,14 @@ public function setup(): void $this->connection->setup(); } + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + return ($this->receiver ?? $this->getReceiver())->getMessageCount(); + } + private function getReceiver() { return $this->receiver = new AmqpReceiver($this->connection, $this->serializer); diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 4dad0735b93e9..512193a5e98d6 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -184,6 +184,14 @@ public function publish(string $body, array $headers = [], int $delay = 0): void $this->exchange()->publish($body, $this->queueConfiguration['routing_key'] ?? null, $flags, $attributes); } + /** + * Returns an approximate count of the messages in a queue. + */ + public function countMessagesInQueue(): int + { + return $this->queue()->declareQueue(); + } + /** * @throws \AMQPException */ diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index faf6b8919b19a..f73b756d9ebdb 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -14,6 +14,7 @@ use Doctrine\DBAL\Connection as DBALConnection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Schema\Schema; use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer; use Doctrine\DBAL\Types\Type; @@ -128,25 +129,14 @@ public function get(): ?array { $this->driverConnection->beginTransaction(); try { - $query = $this->driverConnection->createQueryBuilder() - ->select('m.*') - ->from($this->configuration['table_name'], 'm') - ->where('m.delivered_at is null OR m.delivered_at < :redeliver_limit') - ->andWhere('m.available_at <= :now') - ->andWhere('m.queue_name = :queue_name') + $query = $this->createAvailableMessagesQueryBuilder() ->orderBy('available_at', 'ASC') ->setMaxResults(1); - $now = \DateTime::createFromFormat('U.u', microtime(true)); - $redeliverLimit = (clone $now)->modify(sprintf('-%d seconds', $this->configuration['redeliver_timeout'])); // use SELECT ... FOR UPDATE to lock table $doctrineEnvelope = $this->executeQuery( $query->getSQL().' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL(), - [ - ':now' => self::formatDateTime($now), - ':queue_name' => $this->configuration['queue_name'], - ':redeliver_limit' => self::formatDateTime($redeliverLimit), - ] + $query->getParameters() )->fetch(); if (false === $doctrineEnvelope) { @@ -161,6 +151,7 @@ public function get(): ?array ->update($this->configuration['table_name']) ->set('delivered_at', ':delivered_at') ->where('id = :id'); + $now = \DateTime::createFromFormat('U.u', microtime(true)); $this->executeQuery($queryBuilder->getSQL(), [ ':id' => $doctrineEnvelope['id'], ':delivered_at' => self::formatDateTime($now), @@ -200,6 +191,33 @@ public function setup(): void $synchronizer->updateSchema($this->getSchema(), true); } + public function getMessageCount(): int + { + $queryBuilder = $this->createAvailableMessagesQueryBuilder() + ->select('COUNT(m.id) as message_count') + ->setMaxResults(1); + + return $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters())->fetchColumn(); + } + + private function createAvailableMessagesQueryBuilder(): QueryBuilder + { + $now = \DateTime::createFromFormat('U.u', microtime(true)); + $redeliverLimit = (clone $now)->modify(sprintf('-%d seconds', $this->configuration['redeliver_timeout'])); + + return $this->driverConnection->createQueryBuilder() + ->select('m.*') + ->from($this->configuration['table_name'], 'm') + ->where('m.delivered_at is null OR m.delivered_at < :redeliver_limit') + ->andWhere('m.available_at <= :now') + ->andWhere('m.queue_name = :queue_name') + ->setParameters([ + ':now' => self::formatDateTime($now), + ':queue_name' => $this->configuration['queue_name'], + ':redeliver_limit' => self::formatDateTime($redeliverLimit), + ]); + } + private function executeQuery(string $sql, array $parameters = []) { $stmt = null; diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php index 3198e143dca84..65f2eacdc89b4 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/DoctrineReceiver.php @@ -16,6 +16,7 @@ use Symfony\Component\Messenger\Exception\LogicException; use Symfony\Component\Messenger\Exception\MessageDecodingFailedException; use Symfony\Component\Messenger\Exception\TransportException; +use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Component\Messenger\Transport\Serialization\PhpSerializer; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -25,7 +26,7 @@ * * @experimental in 4.3 */ -class DoctrineReceiver implements ReceiverInterface +class DoctrineReceiver implements ReceiverInterface, MessageCountAwareInterface { private $connection; private $serializer; @@ -81,6 +82,14 @@ public function reject(Envelope $envelope): void $this->connection->reject($this->findDoctrineReceivedStamp($envelope)->getId()); } + /** + * {@inheritdoc} + */ + public function getMessageCount(): int + { + return $this->connection->getMessageCount(); + } + private function findDoctrineReceivedStamp(Envelope $envelope): DoctrineReceivedStamp { /** @var DoctrineReceivedStamp|null $doctrineReceivedStamp */ diff --git a/src/Symfony/Component/Messenger/Transport/Receiver/MessageCountAwareInterface.php b/src/Symfony/Component/Messenger/Transport/Receiver/MessageCountAwareInterface.php new file mode 100644 index 0000000000000..69f66e6084dd5 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/Receiver/MessageCountAwareInterface.php @@ -0,0 +1,28 @@ +<?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\Component\Messenger\Transport\Receiver; + +/** + * @author Samuel Roze <samuel.roze@gmail.com> + * @author Ryan Weaver <ryan@symfonycasts.com> + * + * @experimental in 4.3 + */ +interface MessageCountAwareInterface +{ + /** + * Returns the number of messages waiting to be handled. + * + * In some systems, this may be an approximate number. + */ + public function getMessageCount(): int; +} From 5e61b75893ec64581dc71be8e7d5dd21d11d89db Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Wed, 3 Apr 2019 17:53:54 +0200 Subject: [PATCH 372/495] [Twig] removed TemplatedEmail::template() --- src/Symfony/Bridge/Twig/Mime/BodyRenderer.php | 27 ----- .../Bridge/Twig/Mime/TemplatedEmail.php | 20 +--- .../Bridge/Twig/Tests/Mime/RendererTest.php | 108 +----------------- .../Twig/Tests/Mime/TemplatedEmailTest.php | 3 - 4 files changed, 7 insertions(+), 151 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php index e9b04b71ab734..df2c9f91c3cf2 100644 --- a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php +++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php @@ -50,10 +50,6 @@ public function render(Message $message): void 'email' => new WrappedTemplatedEmail($this->twig, $message), ]); - if ($template = $message->getTemplate()) { - $this->renderFull($message, $template, $vars); - } - if ($template = $message->getTextTemplate()) { $message->text($this->twig->render($template, $vars)); } @@ -68,29 +64,6 @@ public function render(Message $message): void } } - private function renderFull(TemplatedEmail $message, string $template, array $vars): void - { - $template = $this->twig->load($template); - - if ($template->hasBlock('subject', $vars)) { - $message->subject($template->renderBlock('subject', $vars)); - } - - if ($template->hasBlock('text', $vars)) { - $message->text($template->renderBlock('text', $vars)); - } - - if ($template->hasBlock('html', $vars)) { - $message->html($template->renderBlock('html', $vars)); - } - - if ($template->hasBlock('config', $vars)) { - // we discard the output as we're only interested - // in the side effect of calling email methods - $template->renderBlock('config', $vars); - } - } - private function convertHtmlToText(string $html): string { if (null !== $this->converter) { diff --git a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php index d840e268c4847..e487055706892 100644 --- a/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php +++ b/src/Symfony/Bridge/Twig/Mime/TemplatedEmail.php @@ -20,21 +20,10 @@ */ class TemplatedEmail extends Email { - private $template; private $htmlTemplate; private $textTemplate; private $context = []; - /** - * @return $this - */ - public function template(?string $template) - { - $this->template = $template; - - return $this; - } - /** * @return $this */ @@ -55,11 +44,6 @@ public function htmlTemplate(?string $template) return $this; } - public function getTemplate(): ?string - { - return $this->template; - } - public function getTextTemplate(): ?string { return $this->textTemplate; @@ -90,7 +74,7 @@ public function getContext(): array */ public function __serialize(): array { - return [$this->template, $this->htmlTemplate, $this->textTemplate, $this->context, parent::__serialize()]; + return [$this->htmlTemplate, $this->textTemplate, $this->context, parent::__serialize()]; } /** @@ -98,7 +82,7 @@ public function __serialize(): array */ public function __unserialize(array $data): void { - [$this->template, $this->htmlTemplate, $this->textTemplate, $this->context, $parentData] = $data; + [$this->htmlTemplate, $this->textTemplate, $this->context, $parentData] = $data; parent::__unserialize($parentData); } diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php index 3c30821bb45e4..3c40e6d7ee049 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/RendererTest.php @@ -15,9 +15,6 @@ use Symfony\Bridge\Twig\Mime\BodyRenderer; use Symfony\Bridge\Twig\Mime\TemplatedEmail; use Symfony\Component\Mime\Part\Multipart\AlternativePart; -use Symfony\Component\Mime\Part\Multipart\MixedPart; -use Symfony\Component\Mime\Part\Multipart\RelatedPart; -use Symfony\Component\Mime\Part\TextPart; use Twig\Environment; use Twig\Loader\ArrayLoader; @@ -25,13 +22,13 @@ class RendererTest extends TestCase { public function testRenderTextOnly(): void { - $email = $this->prepareEmail(null, 'Text', null); + $email = $this->prepareEmail('Text', null); $this->assertEquals('Text', $email->getBody()->bodyToString()); } public function testRenderHtmlOnly(): void { - $email = $this->prepareEmail(null, null, '<b>HTML</b>'); + $email = $this->prepareEmail(null, '<b>HTML</b>'); $body = $email->getBody(); $this->assertInstanceOf(AlternativePart::class, $body); $this->assertEquals('HTML', $body->getParts()[0]->bodyToString()); @@ -40,7 +37,7 @@ public function testRenderHtmlOnly(): void public function testRenderHtmlOnlyWithTextSet(): void { - $email = $this->prepareEmail(null, null, '<b>HTML</b>'); + $email = $this->prepareEmail(null, '<b>HTML</b>'); $email->text('Text'); $body = $email->getBody(); $this->assertInstanceOf(AlternativePart::class, $body); @@ -50,108 +47,16 @@ public function testRenderHtmlOnlyWithTextSet(): void public function testRenderTextAndHtml(): void { - $email = $this->prepareEmail(null, 'Text', '<b>HTML</b>'); + $email = $this->prepareEmail('Text', '<b>HTML</b>'); $body = $email->getBody(); $this->assertInstanceOf(AlternativePart::class, $body); $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); $this->assertEquals('<b>HTML</b>', $body->getParts()[1]->bodyToString()); } - public function testRenderFullOnly(): void - { - $email = $this->prepareEmail(<<<EOF -{% block subject %}Subject{% endblock %} -{% block text %}Text{% endblock %} -{% block html %}<b>HTML</b>{% endblock %} -EOF - , null, null); - $body = $email->getBody(); - $this->assertInstanceOf(AlternativePart::class, $body); - $this->assertEquals('Subject', $email->getSubject()); - $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); - $this->assertEquals('<b>HTML</b>', $body->getParts()[1]->bodyToString()); - } - - public function testRenderFullOnlyWithTextOnly(): void - { - $email = $this->prepareEmail(<<<EOF -{% block text %}Text{% endblock %} -EOF - , null, null); - $body = $email->getBody(); - $this->assertInstanceOf(TextPart::class, $body); - $this->assertEquals('', $email->getSubject()); - $this->assertEquals('Text', $body->bodyToString()); - } - - public function testRenderFullOnlyWithHtmlOnly(): void - { - $email = $this->prepareEmail(<<<EOF -{% block html %}<b>HTML</b>{% endblock %} -EOF - , null, null); - $body = $email->getBody(); - $this->assertInstanceOf(AlternativePart::class, $body); - $this->assertEquals('', $email->getSubject()); - $this->assertEquals('HTML', $body->getParts()[0]->bodyToString()); - $this->assertEquals('<b>HTML</b>', $body->getParts()[1]->bodyToString()); - } - - public function testRenderFullAndText(): void - { - $email = $this->prepareEmail(<<<EOF -{% block text %}Text full{% endblock %} -{% block html %}<b>HTML</b>{% endblock %} -EOF - , 'Text', null); - $body = $email->getBody(); - $this->assertInstanceOf(AlternativePart::class, $body); - $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); - $this->assertEquals('<b>HTML</b>', $body->getParts()[1]->bodyToString()); - } - - public function testRenderFullAndHtml(): void - { - $email = $this->prepareEmail(<<<EOF -{% block text %}Text full{% endblock %} -{% block html %}<b>HTML</b>{% endblock %} -EOF - , null, '<i>HTML</i>'); - $body = $email->getBody(); - $this->assertInstanceOf(AlternativePart::class, $body); - $this->assertEquals('Text full', $body->getParts()[0]->bodyToString()); - $this->assertEquals('<i>HTML</i>', $body->getParts()[1]->bodyToString()); - } - - public function testRenderHtmlWithEmbeddedImages(): void - { - $email = $this->prepareEmail(null, null, '<img src="{{ email.image("image.jpg") }}" />'); - $body = $email->getBody(); - $this->assertInstanceOf(RelatedPart::class, $body); - $this->assertInstanceOf(AlternativePart::class, $body->getParts()[0]); - $this->assertStringMatchesFormat('<img src=3D"cid:%s@symfony" />', $body->getParts()[0]->getParts()[1]->bodyToString()); - $this->assertEquals('Some image data', base64_decode($body->getParts()[1]->bodyToString())); - } - - public function testRenderFullWithAttachments(): void - { - $email = $this->prepareEmail(<<<EOF -{% block text %}Text{% endblock %} -{% block config %} - {% do email.attach('document.txt') %} -{% endblock %} -EOF - , null, null); - $body = $email->getBody(); - $this->assertInstanceOf(MixedPart::class, $body); - $this->assertEquals('Text', $body->getParts()[0]->bodyToString()); - $this->assertEquals('Some text document...', base64_decode($body->getParts()[1]->bodyToString())); - } - - private function prepareEmail(?string $full, ?string $text, ?string $html): TemplatedEmail + private function prepareEmail(?string $text, ?string $html): TemplatedEmail { $twig = new Environment(new ArrayLoader([ - 'full' => $full, 'text' => $text, 'html' => $html, 'document.txt' => 'Some text document...', @@ -159,9 +64,6 @@ private function prepareEmail(?string $full, ?string $text, ?string $html): Temp ])); $renderer = new BodyRenderer($twig); $email = (new TemplatedEmail())->to('fabien@symfony.com')->from('helene@symfony.com'); - if (null !== $full) { - $email->template('full'); - } if (null !== $text) { $email->textTemplate('text'); } diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php index f5d9235a6d503..999ca4d078d58 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/TemplatedEmailTest.php @@ -13,9 +13,6 @@ public function test() $email->context($context = ['product' => 'Symfony']); $this->assertEquals($context, $email->getContext()); - $email->template($template = 'full'); - $this->assertEquals($template, $email->getTemplate()); - $email->textTemplate($template = 'text'); $this->assertEquals($template, $email->getTextTemplate()); From b2f3b53253ea1772d6680037a28a1b8efd3ff1a2 Mon Sep 17 00:00:00 2001 From: Vincent Touzet <vincent.touzet@gmail.com> Date: Wed, 3 Apr 2019 23:16:34 +0200 Subject: [PATCH 373/495] [Messenger] Setup the doctrine transport when consuming --- .../Tests/Transport/Doctrine/ConnectionTest.php | 13 +++++++++++-- .../Transport/Doctrine/DoctrineIntegrationTest.php | 13 +++++++++++++ .../Messenger/Transport/Doctrine/Connection.php | 11 ++++++++--- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php index 3d8bf82b53eb9..4eb9823ce5aa1 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -15,6 +15,7 @@ use Doctrine\DBAL\Driver\Statement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer; use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Transport\Doctrine\Connection; @@ -25,6 +26,7 @@ public function testGetAMessageWillChangeItsStatus() { $queryBuilder = $this->getQueryBuilderMock(); $driverConnection = $this->getDBALConnectionMock(); + $schemaSynchronizer = $this->getSchemaSynchronizerMock(); $stmt = $this->getStatementMock([ 'id' => 1, 'body' => '{"message":"Hi"}', @@ -44,7 +46,7 @@ public function testGetAMessageWillChangeItsStatus() ->method('prepare') ->willReturn($stmt); - $connection = new Connection([], $driverConnection); + $connection = new Connection([], $driverConnection, $schemaSynchronizer); $doctrineEnvelope = $connection->get(); $this->assertEquals(1, $doctrineEnvelope['id']); $this->assertEquals('{"message":"Hi"}', $doctrineEnvelope['body']); @@ -55,6 +57,7 @@ public function testGetWithNoPendingMessageWillReturnNull() { $queryBuilder = $this->getQueryBuilderMock(); $driverConnection = $this->getDBALConnectionMock(); + $schemaSynchronizer = $this->getSchemaSynchronizerMock(); $stmt = $this->getStatementMock(false); $queryBuilder @@ -68,7 +71,7 @@ public function testGetWithNoPendingMessageWillReturnNull() $driverConnection->expects($this->never()) ->method('update'); - $connection = new Connection([], $driverConnection); + $connection = new Connection([], $driverConnection, $schemaSynchronizer); $doctrineEnvelope = $connection->get(); $this->assertNull($doctrineEnvelope); } @@ -142,6 +145,12 @@ private function getStatementMock($expectedResult) return $stmt; } + private function getSchemaSynchronizerMock() + { + return $this->getMockBuilder(SchemaSynchronizer::class) + ->getMock(); + } + /** * @dataProvider buildConfigurationProvider */ diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index bc826832c593b..08ae0d799eda8 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -164,4 +164,17 @@ public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout() $this->assertEquals('{"message": "Hi requeued"}', $next['body']); $this->connection->reject($next['id']); } + + public function testTheTransportIsSetupOnGet() + { + // If the table does not exist and we call the get (i.e run messenger:consume) the table must be setup + // so first delete the tables + $this->driverConnection->exec('DROP TABLE messenger_messages'); + + $this->assertNull($this->connection->get()); + + $this->connection->send('the body', ['my' => 'header']); + $envelope = $this->connection->get(); + $this->assertEquals('the body', $envelope['body']); + } } diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index ad3ab192d5bd1..701794f0b3df5 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -16,6 +16,7 @@ use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer; use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer; use Doctrine\DBAL\Types\Type; use Symfony\Component\Messenger\Exception\InvalidArgumentException; @@ -50,11 +51,13 @@ class Connection */ private $configuration = []; private $driverConnection; + private $schemaSynchronizer; - public function __construct(array $configuration, DBALConnection $driverConnection) + public function __construct(array $configuration, DBALConnection $driverConnection, SchemaSynchronizer $schemaSynchronizer = null) { $this->configuration = array_replace_recursive(self::DEFAULT_OPTIONS, $configuration); $this->driverConnection = $driverConnection; + $this->schemaSynchronizer = $schemaSynchronizer ?? new SingleDatabaseSynchronizer($this->driverConnection); } public function getConfiguration(): array @@ -127,6 +130,9 @@ public function send(string $body, array $headers, int $delay = 0): void public function get(): ?array { + if ($this->configuration['auto_setup']) { + $this->setup(); + } $this->driverConnection->beginTransaction(); try { $query = $this->createAvailableMessagesQueryBuilder() @@ -187,8 +193,7 @@ public function reject(string $id): bool public function setup(): void { - $synchronizer = new SingleDatabaseSynchronizer($this->driverConnection); - $synchronizer->updateSchema($this->getSchema(), true); + $this->schemaSynchronizer->updateSchema($this->getSchema(), true); } public function getMessageCount(): int From fc6ba7efad0e5dbe34eab3a4d893090e0a460004 Mon Sep 17 00:00:00 2001 From: Anton Chernikov <anton_ch1989@mail.ru> Date: Tue, 12 Mar 2019 19:10:19 +0300 Subject: [PATCH 374/495] [HttpClient] logger integration --- .../Component/HttpClient/CurlHttpClient.php | 11 +++++++++-- src/Symfony/Component/HttpClient/HttpClient.php | 16 +++++++++++++--- .../Component/HttpClient/NativeHttpClient.php | 8 +++++++- src/Symfony/Component/HttpClient/composer.json | 3 ++- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 39a5fde78f38f..e863febe2c782 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpClient; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Response\CurlResponse; use Symfony\Component\HttpClient\Response\ResponseStream; @@ -34,6 +36,7 @@ final class CurlHttpClient implements HttpClientInterface private $defaultOptions = self::OPTIONS_DEFAULTS; private $multi; + private $logger; /** * @param array $defaultOptions Default requests' options @@ -41,8 +44,10 @@ final class CurlHttpClient implements HttpClientInterface * * @see HttpClientInterface::OPTIONS_DEFAULTS for available options */ - public function __construct(array $defaultOptions = [], int $maxHostConnections = 6) + public function __construct(array $defaultOptions = [], LoggerInterface $logger = null, int $maxHostConnections = 6) { + $this->logger = $logger ?? new NullLogger(); + if ($defaultOptions) { [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } @@ -86,6 +91,7 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections */ public function request(string $method, string $url, array $options = []): ResponseInterface { + $this->logger->notice('Making a request', ['url' => $url, 'method' => $method, 'client' => static::class]); [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); $scheme = $url['scheme']; $authority = $url['authority']; @@ -103,6 +109,7 @@ public function request(string $method, string $url, array $options = []): Respo ]; if ('GET' === $method && !$options['body'] && $expectedHeaders === $pushedHeaders) { + $this->logger->debug('Creating pushed response'); // Reinitialize the pushed response with request's options $pushedResponse->__construct($this->multi, $url, $options); @@ -156,7 +163,7 @@ public function request(string $method, string $url, array $options = []): Respo // DNS cache removals require curl 7.42 or higher // On lower versions, we have to create a new multi handle curl_multi_close($this->multi->handle); - $this->multi->handle = (new self())->multi->handle; + $this->multi->handle = (new self([], $this->logger))->multi->handle; } foreach ($options['resolve'] as $host => $ip) { diff --git a/src/Symfony/Component/HttpClient/HttpClient.php b/src/Symfony/Component/HttpClient/HttpClient.php index 6d680d9b49837..3e44ca0d67913 100644 --- a/src/Symfony/Component/HttpClient/HttpClient.php +++ b/src/Symfony/Component/HttpClient/HttpClient.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpClient; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -28,12 +30,20 @@ final class HttpClient * * @see HttpClientInterface::OPTIONS_DEFAULTS for available options */ - public static function create(array $defaultOptions = [], int $maxHostConnections = 6): HttpClientInterface + public static function create(array $defaultOptions = [], LoggerInterface $logger = null, int $maxHostConnections = 6): HttpClientInterface { + if (null === $logger) { + $logger = new NullLogger(); + } + if (\extension_loaded('curl')) { - return new CurlHttpClient($defaultOptions, $maxHostConnections); + $logger->debug('Curl extension is enabled. Creating client.', ['client' => CurlHttpClient::class]); + + return new CurlHttpClient($defaultOptions, $logger, $maxHostConnections); } - return new NativeHttpClient($defaultOptions, $maxHostConnections); + $logger->debug('Curl extension is disabled. Creating client.', ['client' => NativeHttpClient::class]); + + return new NativeHttpClient($defaultOptions, $logger, $maxHostConnections); } } diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index d120dbc83b7b7..ab8ba31a09be2 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpClient; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Response\NativeResponse; use Symfony\Component\HttpClient\Response\ResponseStream; @@ -34,6 +36,7 @@ final class NativeHttpClient implements HttpClientInterface private $defaultOptions = self::OPTIONS_DEFAULTS; private $multi; + private $logger; /** * @param array $defaultOptions Default requests' options @@ -41,8 +44,10 @@ final class NativeHttpClient implements HttpClientInterface * * @see HttpClientInterface::OPTIONS_DEFAULTS for available options */ - public function __construct(array $defaultOptions = [], int $maxHostConnections = 6) + public function __construct(array $defaultOptions = [], LoggerInterface $logger = null, int $maxHostConnections = 6) { + $this->logger = $logger ?? new NullLogger(); + if ($defaultOptions) { [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } @@ -68,6 +73,7 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections */ public function request(string $method, string $url, array $options = []): ResponseInterface { + $this->logger->notice('Making a request', ['url' => $url, 'method' => $method, 'client' => static::class]); [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); if ($options['bindto'] && file_exists($options['bindto'])) { diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index 803b424d3d339..b310f269c31b9 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -21,7 +21,8 @@ "require": { "php": "^7.1.3", "symfony/contracts": "^1.1", - "symfony/polyfill-php73": "^1.11" + "symfony/polyfill-php73": "^1.11", + "psr/log": "~1.0" }, "require-dev": { "nyholm/psr7": "^1.0", From f7ec2d388a58c3c8a22b05b1c90a5ad463c10839 Mon Sep 17 00:00:00 2001 From: Ryan Weaver <ryan@thatsquality.com> Date: Thu, 4 Apr 2019 07:32:05 -0400 Subject: [PATCH 375/495] fixing unused variable names --- .../Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php index d3737007291ec..04f2b09ff4cb5 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php @@ -177,9 +177,9 @@ public function testItCountsMessagesInQueue() $sender = new AmqpSender($connection, $serializer); - $sender->send($first = new Envelope(new DummyMessage('First'))); - $sender->send($second = new Envelope(new DummyMessage('Second'))); - $sender->send($second = new Envelope(new DummyMessage('Third'))); + $sender->send(new Envelope(new DummyMessage('First'))); + $sender->send(new Envelope(new DummyMessage('Second'))); + $sender->send(new Envelope(new DummyMessage('Third'))); sleep(1); // give amqp a moment to have the messages ready $this->assertSame(3, $connection->countMessagesInQueue()); From 26d15c8bbe253e97bb029390a3c41ae975b271c2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Thu, 4 Apr 2019 16:02:57 +0200 Subject: [PATCH 376/495] [HttpClient] log requests, responses and pushes when they happen --- .../Resources/config/http_client.xml | 4 ++ .../Component/HttpClient/CurlHttpClient.php | 56 +++++++++++++------ .../Component/HttpClient/HttpClient.php | 17 ++---- .../Component/HttpClient/NativeHttpClient.php | 18 +++--- .../HttpClient/Response/CurlResponse.php | 30 +++++++--- .../HttpClient/Response/NativeResponse.php | 14 ++++- .../HttpClient/Response/ResponseTrait.php | 4 ++ .../HttpClient/Tests/CurlHttpClientTest.php | 49 ++++++++++++++++ .../Component/HttpClient/composer.json | 4 +- .../Component/HttpKernel/HttpClientKernel.php | 10 +--- 10 files changed, 144 insertions(+), 62 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml index c21d115828fa5..bf7b7b9f64055 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml @@ -6,9 +6,13 @@ <services> <service id="http_client" class="Symfony\Contracts\HttpClient\HttpClientInterface"> + <tag name="monolog.logger" channel="http_client" /> <factory class="Symfony\Component\HttpClient\HttpClient" method="create" /> <argument type="collection" /> <!-- default options --> <argument /> <!-- max host connections --> + <call method="setLogger"> + <argument type="service" id="logger" on-invalid="ignore" /> + </call> </service> <service id="Symfony\Contracts\HttpClient\HttpClientInterface" alias="http_client" /> diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index e863febe2c782..f7cb71577f2a7 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -11,8 +11,9 @@ namespace Symfony\Component\HttpClient; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Response\CurlResponse; use Symfony\Component\HttpClient\Response\ResponseStream; @@ -30,24 +31,23 @@ * * @experimental in 4.3 */ -final class CurlHttpClient implements HttpClientInterface +final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface { use HttpClientTrait; + use LoggerAwareTrait; private $defaultOptions = self::OPTIONS_DEFAULTS; private $multi; - private $logger; /** * @param array $defaultOptions Default requests' options * @param int $maxHostConnections The maximum number of connections to a single host + * @param int $maxPendingPushes The maximum number of pushed responses to accept in the queue * * @see HttpClientInterface::OPTIONS_DEFAULTS for available options */ - public function __construct(array $defaultOptions = [], LoggerInterface $logger = null, int $maxHostConnections = 6) + public function __construct(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50) { - $this->logger = $logger ?? new NullLogger(); - if ($defaultOptions) { [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } @@ -70,7 +70,7 @@ public function __construct(array $defaultOptions = [], LoggerInterface $logger ]; // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/bug.php?id=77535 - if (\PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) { + if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) { return; } @@ -79,8 +79,10 @@ public function __construct(array $defaultOptions = [], LoggerInterface $logger return; } - curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi) { - return self::handlePush($parent, $pushed, $requestHeaders, $multi); + $logger = &$this->logger; + + curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes, &$logger) { + return self::handlePush($parent, $pushed, $requestHeaders, $multi, $maxPendingPushes, $logger); }); } @@ -91,7 +93,6 @@ public function __construct(array $defaultOptions = [], LoggerInterface $logger */ public function request(string $method, string $url, array $options = []): ResponseInterface { - $this->logger->notice('Making a request', ['url' => $url, 'method' => $method, 'client' => static::class]); [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); $scheme = $url['scheme']; $authority = $url['authority']; @@ -109,14 +110,19 @@ public function request(string $method, string $url, array $options = []): Respo ]; if ('GET' === $method && !$options['body'] && $expectedHeaders === $pushedHeaders) { - $this->logger->debug('Creating pushed response'); + $this->logger && $this->logger->info(sprintf('Connecting request to pushed response: %s %s', $method, $url)); + // Reinitialize the pushed response with request's options - $pushedResponse->__construct($this->multi, $url, $options); + $pushedResponse->__construct($this->multi, $url, $options, $this->logger); return $pushedResponse; } + + $this->logger && $this->logger->info(sprintf('Rejecting pushed response for "%s": authorization headers don\'t match the request', $url)); } + $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, $url)); + $curlopts = [ CURLOPT_URL => $url, CURLOPT_USERAGENT => 'Symfony HttpClient/Curl', @@ -163,7 +169,7 @@ public function request(string $method, string $url, array $options = []): Respo // DNS cache removals require curl 7.42 or higher // On lower versions, we have to create a new multi handle curl_multi_close($this->multi->handle); - $this->multi->handle = (new self([], $this->logger))->multi->handle; + $this->multi->handle = (new self())->multi->handle; } foreach ($options['resolve'] as $host => $ip) { @@ -262,7 +268,7 @@ public function request(string $method, string $url, array $options = []): Respo } } - return new CurlResponse($this->multi, $ch, $options, $method, self::createRedirectResolver($options, $host)); + return new CurlResponse($this->multi, $ch, $options, $this->logger, $method, self::createRedirectResolver($options, $host)); } /** @@ -289,9 +295,10 @@ public function __destruct() } } - private static function handlePush($parent, $pushed, array $requestHeaders, \stdClass $multi): int + private static function handlePush($parent, $pushed, array $requestHeaders, \stdClass $multi, int $maxPendingPushes, ?LoggerInterface $logger): int { $headers = []; + $origin = curl_getinfo($parent, CURLINFO_EFFECTIVE_URL); foreach ($requestHeaders as $h) { if (false !== $i = strpos($h, ':', 1)) { @@ -299,20 +306,33 @@ private static function handlePush($parent, $pushed, array $requestHeaders, \std } } - if ('GET' !== $headers[':method'] || isset($headers['range'])) { + if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path']) || 'GET' !== $headers[':method'] || isset($headers['range'])) { + $logger && $logger->info(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); + return CURL_PUSH_DENY; } $url = $headers[':scheme'].'://'.$headers[':authority']; + if ($maxPendingPushes <= \count($multi->pushedResponses)) { + $logger && $logger->info(sprintf('Rejecting pushed response from "%s" for "%s": the queue is full', $origin, $url)); + + return CURL_PUSH_DENY; + } + // curl before 7.65 doesn't validate the pushed ":authority" header, // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, // ignoring domains mentioned as alt-name in the certificate for now (same as curl). - if (0 !== strpos(curl_getinfo($parent, CURLINFO_EFFECTIVE_URL), $url.'/')) { + if (0 !== strpos($origin, $url.'/')) { + $logger && $logger->info(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); + return CURL_PUSH_DENY; } - $multi->pushedResponses[$url.$headers[':path']] = [ + $url .= $headers[':path']; + $logger && $logger->info(sprintf('Queueing pushed response: %s', $url)); + + $multi->pushedResponses[$url] = [ new CurlResponse($multi, $pushed), [ $headers['authorization'] ?? null, diff --git a/src/Symfony/Component/HttpClient/HttpClient.php b/src/Symfony/Component/HttpClient/HttpClient.php index 3e44ca0d67913..25d3f6f87425c 100644 --- a/src/Symfony/Component/HttpClient/HttpClient.php +++ b/src/Symfony/Component/HttpClient/HttpClient.php @@ -11,8 +11,6 @@ namespace Symfony\Component\HttpClient; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use Symfony\Contracts\HttpClient\HttpClientInterface; /** @@ -27,23 +25,16 @@ final class HttpClient /** * @param array $defaultOptions Default requests' options * @param int $maxHostConnections The maximum number of connections to a single host + * @param int $maxPendingPushes The maximum number of pushed responses to accept in the queue * * @see HttpClientInterface::OPTIONS_DEFAULTS for available options */ - public static function create(array $defaultOptions = [], LoggerInterface $logger = null, int $maxHostConnections = 6): HttpClientInterface + public static function create(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50): HttpClientInterface { - if (null === $logger) { - $logger = new NullLogger(); - } - if (\extension_loaded('curl')) { - $logger->debug('Curl extension is enabled. Creating client.', ['client' => CurlHttpClient::class]); - - return new CurlHttpClient($defaultOptions, $logger, $maxHostConnections); + return new CurlHttpClient($defaultOptions, $maxHostConnections, $maxPendingPushes); } - $logger->debug('Curl extension is disabled. Creating client.', ['client' => NativeHttpClient::class]); - - return new NativeHttpClient($defaultOptions, $logger, $maxHostConnections); + return new NativeHttpClient($defaultOptions, $maxHostConnections); } } diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index ab8ba31a09be2..0549fccc49c54 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -11,8 +11,8 @@ namespace Symfony\Component\HttpClient; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Response\NativeResponse; use Symfony\Component\HttpClient\Response\ResponseStream; @@ -30,13 +30,13 @@ * * @experimental in 4.3 */ -final class NativeHttpClient implements HttpClientInterface +final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterface { use HttpClientTrait; + use LoggerAwareTrait; private $defaultOptions = self::OPTIONS_DEFAULTS; private $multi; - private $logger; /** * @param array $defaultOptions Default requests' options @@ -44,10 +44,8 @@ final class NativeHttpClient implements HttpClientInterface * * @see HttpClientInterface::OPTIONS_DEFAULTS for available options */ - public function __construct(array $defaultOptions = [], LoggerInterface $logger = null, int $maxHostConnections = 6) + public function __construct(array $defaultOptions = [], int $maxHostConnections = 6) { - $this->logger = $logger ?? new NullLogger(); - if ($defaultOptions) { [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } @@ -73,7 +71,6 @@ public function __construct(array $defaultOptions = [], LoggerInterface $logger */ public function request(string $method, string $url, array $options = []): ResponseInterface { - $this->logger->notice('Making a request', ['url' => $url, 'method' => $method, 'client' => static::class]); [$url, $options] = self::prepareRequest($method, $url, $options, $this->defaultOptions); if ($options['bindto'] && file_exists($options['bindto'])) { @@ -211,7 +208,10 @@ public function request(string $method, string $url, array $options = []): Respo $context = stream_context_create($context, ['notification' => $notification]); self::configureHeadersAndProxy($context, $host, $options['request_headers'], $proxy, $noProxy); - return new NativeResponse($this->multi, $context, implode('', $url), $options, $gzipEnabled, $info, $resolveRedirect, $onProgress); + $url = implode('', $url); + $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, $url)); + + return new NativeResponse($this->multi, $context, $url, $options, $gzipEnabled, $info, $resolveRedirect, $onProgress, $this->logger); } /** diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 8c52ba501bdb8..39e256785d341 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpClient\Response; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -29,7 +30,7 @@ final class CurlResponse implements ResponseInterface /** * @internal */ - public function __construct(\stdClass $multi, $ch, array $options = null, string $method = 'GET', callable $resolveRedirect = null) + public function __construct(\stdClass $multi, $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null) { $this->multi = $multi; @@ -41,6 +42,7 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string } $this->id = $id = (int) $ch; + $this->logger = $logger; $this->timeout = $options['timeout'] ?? null; $this->info['http_method'] = $method; $this->info['user_data'] = $options['user_data'] ?? null; @@ -64,8 +66,8 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string $content = ($options['buffer'] ?? true) ? $content : null; } - curl_setopt($ch, CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, &$headers, $options, $multi, $id, &$location, $resolveRedirect): int { - return self::parseHeaderLine($ch, $data, $info, $headers, $options, $multi, $id, $location, $resolveRedirect); + curl_setopt($ch, CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, &$headers, $options, $multi, $id, &$location, $resolveRedirect, $logger): int { + return self::parseHeaderLine($ch, $data, $info, $headers, $options, $multi, $id, $location, $resolveRedirect, $logger); }); if (null === $options) { @@ -103,7 +105,9 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string throw new TransportException($response->info['error']); } - if (\in_array(curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) { + $waitFor = curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE); + + if (\in_array($waitFor, ['headers', 'destruct'], true)) { try { if (\defined('CURLOPT_STREAM_WEIGHT')) { curl_setopt($ch, CURLOPT_STREAM_WEIGHT, 32); @@ -115,6 +119,8 @@ public function __construct(\stdClass $multi, $ch, array $options = null, string $response->close(); throw $e; } + } elseif ('content' === $waitFor && ($response->multi->handlesActivity[$response->id][0] ?? null) instanceof FirstChunk) { + self::stream([$response])->current(); } curl_setopt($ch, CURLOPT_HEADERFUNCTION, null); @@ -156,8 +162,8 @@ public function getInfo(string $type = null) public function __destruct() { try { - if (null === $this->timeout || isset($this->info['url'])) { - return; // pushed response + if (null === $this->timeout) { + return; // Unused pushed response } if ('content' === $waitFor = curl_getinfo($this->handle, CURLINFO_PRIVATE)) { @@ -171,7 +177,13 @@ public function __destruct() $this->close(); // Clear local caches when the only remaining handles are about pushed responses - if (\count($this->multi->openHandles) === \count($this->multi->pushedResponses)) { + if (!$this->multi->openHandles) { + if ($this->logger) { + foreach ($this->multi->pushedResponses as $url => $response) { + $this->logger->info(sprintf('Unused pushed response: %s', $url)); + } + } + $this->multi->pushedResponses = []; // Schedule DNS cache eviction for the next request $this->multi->dnsCache[2] = $this->multi->dnsCache[2] ?: $this->multi->dnsCache[1]; @@ -249,7 +261,7 @@ protected static function select(\stdClass $multi, float $timeout): int /** * Parses header lines as curl yields them to us. */ - private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, \stdClass $multi, int $id, ?string &$location, ?callable $resolveRedirect): int + private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, \stdClass $multi, int $id, ?string &$location, ?callable $resolveRedirect, ?LoggerInterface $logger): int { if (!\in_array($waitFor = @curl_getinfo($ch, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) { return \strlen($data); // Ignore HTTP trailers @@ -306,6 +318,8 @@ private static function parseHeaderLine($ch, string $data, array &$info, array & } curl_setopt($ch, CURLOPT_PRIVATE, 'content'); + } elseif (null !== $info['redirect_url'] && $logger) { + $logger->info(sprintf('Redirecting: %s %s', $info['http_code'], $info['redirect_url'])); } return \strlen($data); diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 2ab498a731ea7..6c3330a1638e4 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpClient\Response; +use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -35,12 +36,13 @@ final class NativeResponse implements ResponseInterface /** * @internal */ - public function __construct(\stdClass $multi, $context, string $url, $options, bool $gzipEnabled, array &$info, callable $resolveRedirect, ?callable $onProgress) + public function __construct(\stdClass $multi, $context, string $url, $options, bool $gzipEnabled, array &$info, callable $resolveRedirect, ?callable $onProgress, ?LoggerInterface $logger) { $this->multi = $multi; $this->id = (int) $context; $this->context = $context; $this->url = $url; + $this->logger = $logger; $this->timeout = $options['timeout']; $this->info = &$info; $this->resolveRedirect = $resolveRedirect; @@ -107,13 +109,19 @@ private function open(): void $this->info['start_time'] = microtime(true); $url = $this->url; - do { + while (true) { // Send request and follow redirects when needed $this->info['fopen_time'] = microtime(true); $this->handle = $h = fopen($url, 'r', false, $this->context); self::addResponseHeaders($http_response_header, $this->info, $this->headers); $url = ($this->resolveRedirect)($this->multi, $this->headers['location'][0] ?? null, $this->context); - } while (null !== $url); + + if (null === $url) { + break; + } + + $this->logger && $this->logger->info(sprintf('Redirecting: %s %s', $this->info['http_code'], $url ?? $this->url)); + } } catch (\Throwable $e) { $this->close(); $this->multi->handlesActivity[$this->id][] = null; diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index b42aa6f188e85..734359f08d375 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -30,6 +30,7 @@ */ trait ResponseTrait { + private $logger; private $headers = []; /** @@ -299,6 +300,9 @@ public static function stream(iterable $responses, float $timeout = null): \Gene } elseif ($chunk instanceof ErrorChunk) { unset($responses[$j]); $isTimeout = true; + } elseif ($chunk instanceof FirstChunk && $response->logger) { + $info = $response->getInfo(); + $response->logger->info(sprintf('Response: %s %s', $info['http_code'], $info['url'])); } yield $response => $chunk; diff --git a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php index 476dc729762f1..b5e82732bc7cd 100644 --- a/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpClient\Tests; +use Psr\Log\AbstractLogger; use Symfony\Component\HttpClient\CurlHttpClient; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; @@ -24,4 +25,52 @@ protected function getHttpClient(string $testCase): HttpClientInterface { return new CurlHttpClient(); } + + /** + * @requires PHP 7.2.17 + * @requires extension curl 7.61 + */ + public function testHttp2Push() + { + if (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304) { + $this->markTestSkipped('PHP 7.3.0 to 7.3.3 don\'t support HTTP/2 PUSH'); + } + + if (!\defined('CURLMOPT_PUSHFUNCTION') || !(CURL_VERSION_HTTP2 & curl_version()['features'])) { + $this->markTestSkipped('curl is not compiled with support for HTTP/2 PUSH'); + } + + $logger = new class() extends AbstractLogger { + public $logs = []; + + public function log($level, $message, array $context = []) + { + $this->logs[] = $message; + } + }; + + $client = new CurlHttpClient(); + $client->setLogger($logger); + + $index = $client->request('GET', 'https://http2-push.io'); + $index->getContent(); + + $css = $client->request('GET', 'https://http2-push.io/css/style.css'); + $js = $client->request('GET', 'https://http2-push.io/js/http2-push.js'); + + $css->getHeaders(); + $js->getHeaders(); + + $expected = [ + 'Request: GET https://http2-push.io/', + 'Queueing pushed response: https://http2-push.io/css/style.css', + 'Queueing pushed response: https://http2-push.io/js/http2-push.js', + 'Response: 200 https://http2-push.io/', + 'Connecting request to pushed response: GET https://http2-push.io/css/style.css', + 'Connecting request to pushed response: GET https://http2-push.io/js/http2-push.js', + 'Response: 200 https://http2-push.io/css/style.css', + 'Response: 200 https://http2-push.io/js/http2-push.js', + ]; + $this->assertSame($expected, $logger->logs); + } } diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index b310f269c31b9..0469bb41ddebd 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -20,9 +20,9 @@ }, "require": { "php": "^7.1.3", + "psr/log": "^1.0", "symfony/contracts": "^1.1", - "symfony/polyfill-php73": "^1.11", - "psr/log": "~1.0" + "symfony/polyfill-php73": "^1.11" }, "require-dev": { "nyholm/psr7": "^1.0", diff --git a/src/Symfony/Component/HttpKernel/HttpClientKernel.php b/src/Symfony/Component/HttpKernel/HttpClientKernel.php index 2c04e670cc05f..f60a84eabe257 100644 --- a/src/Symfony/Component/HttpKernel/HttpClientKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpClientKernel.php @@ -11,8 +11,6 @@ namespace Symfony\Component\HttpKernel; -use Psr\Log\LoggerInterface; -use Psr\Log\NullLogger; use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -31,22 +29,18 @@ final class HttpClientKernel implements HttpKernelInterface { private $client; - private $logger; - public function __construct(HttpClientInterface $client = null, LoggerInterface $logger = null) + public function __construct(HttpClientInterface $client = null) { if (!class_exists(HttpClient::class)) { throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); } $this->client = $client ?? HttpClient::create(); - $this->logger = $logger ?? new NullLogger(); } public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { - $this->logger->debug(sprintf('Request: %s %s', $request->getMethod(), $request->getUri())); - $headers = $this->getHeaders($request); $body = ''; if (null !== $part = $this->getBody($request)) { @@ -59,8 +53,6 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ 'max_redirects' => 0, ] + $request->attributes->get('http_client_options', [])); - $this->logger->debug(sprintf('Response: %s %s', $response->getStatusCode(), $request->getUri())); - $response = new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); $response->headers = new class($response->headers->all()) extends ResponseHeaderBag { From 098a7ac1af42e068d4cc5dd647ff82c24502c6c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Fri, 5 Apr 2019 15:04:18 +0200 Subject: [PATCH 377/495] [HttpClient] Adjust logger messages and levels --- .../Component/HttpClient/CurlHttpClient.php | 14 +++++++------- .../Component/HttpClient/HttpClientTrait.php | 9 +++++++-- .../Component/HttpClient/Response/CurlResponse.php | 4 ++-- .../HttpClient/Response/NativeResponse.php | 2 +- .../HttpClient/Response/ResponseTrait.php | 2 +- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index f7cb71577f2a7..a6761e23e8a27 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -110,7 +110,7 @@ public function request(string $method, string $url, array $options = []): Respo ]; if ('GET' === $method && !$options['body'] && $expectedHeaders === $pushedHeaders) { - $this->logger && $this->logger->info(sprintf('Connecting request to pushed response: %s %s', $method, $url)); + $this->logger && $this->logger->debug(sprintf('Connecting request to pushed response: "%s %s"', $method, $url)); // Reinitialize the pushed response with request's options $pushedResponse->__construct($this->multi, $url, $options, $this->logger); @@ -118,10 +118,10 @@ public function request(string $method, string $url, array $options = []): Respo return $pushedResponse; } - $this->logger && $this->logger->info(sprintf('Rejecting pushed response for "%s": authorization headers don\'t match the request', $url)); + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response for "%s": authorization headers don\'t match the request', $url)); } - $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, $url)); + $this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, $url)); $curlopts = [ CURLOPT_URL => $url, @@ -307,7 +307,7 @@ private static function handlePush($parent, $pushed, array $requestHeaders, \std } if (!isset($headers[':method']) || !isset($headers[':scheme']) || !isset($headers[':authority']) || !isset($headers[':path']) || 'GET' !== $headers[':method'] || isset($headers['range'])) { - $logger && $logger->info(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); + $logger && $logger->debug(sprintf('Rejecting pushed response from "%s": pushed headers are invalid', $origin)); return CURL_PUSH_DENY; } @@ -315,7 +315,7 @@ private static function handlePush($parent, $pushed, array $requestHeaders, \std $url = $headers[':scheme'].'://'.$headers[':authority']; if ($maxPendingPushes <= \count($multi->pushedResponses)) { - $logger && $logger->info(sprintf('Rejecting pushed response from "%s" for "%s": the queue is full', $origin, $url)); + $logger && $logger->debug(sprintf('Rejecting pushed response from "%s" for "%s": the queue is full', $origin, $url)); return CURL_PUSH_DENY; } @@ -324,13 +324,13 @@ private static function handlePush($parent, $pushed, array $requestHeaders, \std // but this is a MUST in the HTTP/2 RFC; let's restrict pushes to the original host, // ignoring domains mentioned as alt-name in the certificate for now (same as curl). if (0 !== strpos($origin, $url.'/')) { - $logger && $logger->info(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); + $logger && $logger->debug(sprintf('Rejecting pushed response from "%s": server is not authoritative for "%s"', $origin, $url)); return CURL_PUSH_DENY; } $url .= $headers[':path']; - $logger && $logger->info(sprintf('Queueing pushed response: %s', $url)); + $logger && $logger->debug(sprintf('Queueing pushed response: "%s"', $url)); $multi->pushedResponses[$url] = [ new CurlResponse($multi, $pushed), diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 5fc2ca65f53c9..678d9d05b48a5 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -34,8 +34,13 @@ trait HttpClientTrait */ private static function prepareRequest(?string $method, ?string $url, array $options, array $defaultOptions = [], bool $allowExtraOptions = false): array { - if (null !== $method && \strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) { - throw new InvalidArgumentException(sprintf('Invalid HTTP method "%s", only uppercase letters are accepted.', $method)); + if (null !== $method) { + if (\strlen($method) !== strspn($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) { + throw new InvalidArgumentException(sprintf('Invalid HTTP method "%s", only uppercase letters are accepted.', $method)); + } + if (!$method) { + throw new InvalidArgumentException('The HTTP method can not be empty.'); + } } $options = self::mergeDefaultOptions($options, $defaultOptions, $allowExtraOptions); diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 39e256785d341..b98a2cb8ff15e 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -180,7 +180,7 @@ public function __destruct() if (!$this->multi->openHandles) { if ($this->logger) { foreach ($this->multi->pushedResponses as $url => $response) { - $this->logger->info(sprintf('Unused pushed response: %s', $url)); + $this->logger->debug(sprintf('Unused pushed response: "%s"', $url)); } } @@ -319,7 +319,7 @@ private static function parseHeaderLine($ch, string $data, array &$info, array & curl_setopt($ch, CURLOPT_PRIVATE, 'content'); } elseif (null !== $info['redirect_url'] && $logger) { - $logger->info(sprintf('Redirecting: %s %s', $info['http_code'], $info['redirect_url'])); + $logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url'])); } return \strlen($data); diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 6c3330a1638e4..b6652f75a05f7 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -120,7 +120,7 @@ private function open(): void break; } - $this->logger && $this->logger->info(sprintf('Redirecting: %s %s', $this->info['http_code'], $url ?? $this->url)); + $this->logger && $this->logger->info(sprintf('Redirecting: "%s %s"', $this->info['http_code'], $url ?? $this->url)); } } catch (\Throwable $e) { $this->close(); diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 734359f08d375..fc557ea90fcf2 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -302,7 +302,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene $isTimeout = true; } elseif ($chunk instanceof FirstChunk && $response->logger) { $info = $response->getInfo(); - $response->logger->info(sprintf('Response: %s %s', $info['http_code'], $info['url'])); + $response->logger->info(sprintf('Response: "%s %s"', $info['http_code'], $info['url'])); } yield $response => $chunk; From 8f81f55a46c55c987fdfdaae6b71221d4c0323aa Mon Sep 17 00:00:00 2001 From: Vincent Touzet <vincent.touzet@gmail.com> Date: Wed, 3 Apr 2019 22:17:05 +0200 Subject: [PATCH 378/495] [Messenger] test DoctrineTransport on travis and appveyor --- .../Doctrine/DoctrineIntegrationTest.php | 29 ++++++++++++------- .../Transport/Doctrine/Connection.php | 8 ++--- src/Symfony/Component/Messenger/composer.json | 2 +- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index bc826832c593b..7397c69b839dc 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -17,22 +17,31 @@ use Symfony\Component\Messenger\Transport\Doctrine\Connection; /** - * @requires pdo_mysql + * @requires extension pdo_sqlite */ class DoctrineIntegrationTest extends TestCase { private $driverConnection; private $connection; - protected function setUp() + /** + * @after + */ + public function cleanup() { - parent::setUp(); + @unlink(sys_get_temp_dir().'/symfony.messenger.sqlite'); + } - if (!getenv('MESSENGER_DOCTRINE_DSN')) { - $this->markTestSkipped('The "MESSENGER_DOCTRINE_DSN" environment variable is required.'); + /** + * @before + */ + public function createConnection() + { + if ($dsn = getenv('MESSENGER_DOCTRINE_DSN')) { + $this->driverConnection = DriverManager::getConnection(['url' => $dsn]); + } else { + $this->driverConnection = DriverManager::getConnection(['pdo' => new \PDO('sqlite:'.sys_get_temp_dir().'/symfony.messenger.sqlite')]); } - $dsn = getenv('MESSENGER_DOCTRINE_DSN'); - $this->driverConnection = DriverManager::getConnection(['url' => $dsn]); $this->connection = new Connection([], $this->driverConnection); // call send to auto-setup the table $this->connection->setup(); @@ -62,7 +71,7 @@ public function testSendWithDelay() $available_at = new \DateTime($available_at); - $now = \DateTime::createFromFormat('U.u', microtime(true)); + $now = new \DateTime(); $now->modify('+60 seconds'); $this->assertGreaterThan($now, $available_at); } @@ -77,7 +86,7 @@ public function testItRetrieveTheFirstAvailableMessage() 'queue_name' => 'default', 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), - 'delivered_at' => Connection::formatDateTime(\DateTime::createFromFormat('U.u', microtime(true))), + 'delivered_at' => Connection::formatDateTime(new \DateTime()), ]); // one available later $this->driverConnection->insert('messenger_messages', [ @@ -110,7 +119,7 @@ public function testItCountMessages() 'queue_name' => 'default', 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')), - 'delivered_at' => Connection::formatDateTime(\DateTime::createFromFormat('U.u', microtime(true))), + 'delivered_at' => Connection::formatDateTime(new \DateTime()), ]); // one available later $this->driverConnection->insert('messenger_messages', [ diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index ad3ab192d5bd1..e9477ff79848c 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -103,7 +103,7 @@ public static function buildConfiguration($dsn, array $options = []) */ public function send(string $body, array $headers, int $delay = 0): void { - $now = (\DateTime::createFromFormat('U.u', microtime(true))); + $now = new \DateTime(); $availableAt = (clone $now)->modify(sprintf('+%d seconds', $delay / 1000)); $queryBuilder = $this->driverConnection->createQueryBuilder() @@ -151,7 +151,7 @@ public function get(): ?array ->update($this->configuration['table_name']) ->set('delivered_at', ':delivered_at') ->where('id = :id'); - $now = \DateTime::createFromFormat('U.u', microtime(true)); + $now = new \DateTime(); $this->executeQuery($queryBuilder->getSQL(), [ ':id' => $doctrineEnvelope['id'], ':delivered_at' => self::formatDateTime($now), @@ -202,7 +202,7 @@ public function getMessageCount(): int private function createAvailableMessagesQueryBuilder(): QueryBuilder { - $now = \DateTime::createFromFormat('U.u', microtime(true)); + $now = new \DateTime(); $redeliverLimit = (clone $now)->modify(sprintf('-%d seconds', $this->configuration['redeliver_timeout'])); return $this->driverConnection->createQueryBuilder() @@ -268,6 +268,6 @@ private function getSchema(): Schema public static function formatDateTime(\DateTimeInterface $dateTime) { - return $dateTime->format('Y-m-d\TH:i:s.uZ'); + return $dateTime->format('Y-m-d\TH:i:s'); } } diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index d3adb0271dd37..02d25efd5fc4f 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -20,7 +20,7 @@ "psr/log": "~1.0" }, "require-dev": { - "doctrine/dbal": "~2.4", + "doctrine/dbal": "^2.5", "psr/cache": "~1.0", "symfony/console": "~3.4|~4.0", "symfony/dependency-injection": "~3.4.19|^4.1.8", From fe759205c532dc27dbea683f750a2381bc9105db Mon Sep 17 00:00:00 2001 From: Gary PEGEOT <garypegeot@gmail.com> Date: Mon, 5 Nov 2018 15:32:44 +0000 Subject: [PATCH 379/495] Add a "null://" transport --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Resources/config/messenger.xml | 4 + .../InMemoryTransportFactoryTest.php | 62 ++++++++++++ .../Tests/Transport/InMemoryTransportTest.php | 69 ++++++++++++++ .../Messenger/Transport/InMemoryTransport.php | 95 +++++++++++++++++++ .../Transport/InMemoryTransportFactory.php | 27 ++++++ 6 files changed, 258 insertions(+) create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php create mode 100644 src/Symfony/Component/Messenger/Transport/InMemoryTransport.php create mode 100644 src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index d38ddc7e6d88f..981823fd07f10 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -29,6 +29,7 @@ CHANGELOG * Added support for PHP files with translations in translation commands. * Added support for boolean container parameters within routes. * Added the `messenger:setup-transports` command to setup messenger transports + * Added a `InMemoryTransport` to Messenger. Use it with a DSN starting with `in-memory://`. 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index 1720ea72e71aa..75e1f8d5af88b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -70,6 +70,10 @@ <tag name="messenger.transport_factory" /> </service> + <service id="messenger.transport.in_memory.factory" class="Symfony\Component\Messenger\Transport\InMemoryTransportFactory"> + <tag name="messenger.transport_factory" /> + </service> + <!-- retry --> <service id="messenger.retry_strategy_locator"> <tag name="container.service_locator" /> diff --git a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php new file mode 100644 index 0000000000000..fd4cb9c04b001 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php @@ -0,0 +1,62 @@ +<?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\Component\Messenger\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Transport\InMemoryTransport; +use Symfony\Component\Messenger\Transport\InMemoryTransportFactory; +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +/** + * @internal + * + * @author Gary PEGEOT <garypegeot@gmail.com> + */ +class InMemoryTransportFactoryTest extends TestCase +{ + /** + * @var InMemoryTransportFactory + */ + private $factory; + + protected function setUp() + { + $this->factory = new InMemoryTransportFactory(); + } + + /** + * @param string $dsn + * @param bool $expected + * + * @dataProvider provideDSN + */ + public function testSupports(string $dsn, bool $expected = true) + { + $this->assertSame($expected, $this->factory->supports($dsn, []), 'InMemoryTransportFactory::supports returned unexpected result.'); + } + + public function testCreateTransport() + { + /** @var SerializerInterface $serializer */ + $serializer = $this->createMock(SerializerInterface::class); + + $this->assertInstanceOf(InMemoryTransport::class, $this->factory->createTransport('in-memory://', [], $serializer)); + } + + public function provideDSN(): array + { + return [ + 'Supported' => ['in-memory://foo'], + 'Unsupported' => ['amqp://bar', false], + ]; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php new file mode 100644 index 0000000000000..8b5634b3f616a --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php @@ -0,0 +1,69 @@ +<?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\Component\Messenger\Tests\Transport; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Transport\InMemoryTransport; + +/** + * @internal + * + * @author Gary PEGEOT <garypegeot@gmail.com> + */ +class InMemoryTransportTest extends TestCase +{ + /** + * @var InMemoryTransport + */ + private $transport; + + protected function setUp() + { + $this->transport = new InMemoryTransport(); + } + + public function testSend() + { + $envelope = new Envelope(new \stdClass()); + $this->transport->send($envelope); + $this->assertSame([$envelope], $this->transport->get()); + } + + public function testAck() + { + $envelope = new Envelope(new \stdClass()); + $this->transport->ack($envelope); + $this->assertSame([$envelope], $this->transport->getAcknowledged()); + } + + public function testReject() + { + $envelope = new Envelope(new \stdClass()); + $this->transport->reject($envelope); + $this->assertSame([$envelope], $this->transport->getRejected()); + } + + public function testReset() + { + $envelope = new Envelope(new \stdClass()); + $this->transport->send($envelope); + $this->transport->ack($envelope); + $this->transport->reject($envelope); + + $this->transport->reset(); + + $this->assertEmpty($this->transport->get(), 'Should be empty after reset'); + $this->assertEmpty($this->transport->getAcknowledged(), 'Should be empty after reset'); + $this->assertEmpty($this->transport->getRejected(), 'Should be empty after reset'); + } +} diff --git a/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php b/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php new file mode 100644 index 0000000000000..a21d67bd1982b --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php @@ -0,0 +1,95 @@ +<?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\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Envelope; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Transport that stay in memory. Useful for testing purpose. + * + * @author Gary PEGEOT <garypegeot@gmail.com> + * + * @experimental in 4.3 + */ +class InMemoryTransport implements TransportInterface, ResetInterface +{ + /** + * @var Envelope[] + */ + private $sent = []; + + /** + * @var Envelope[] + */ + private $acknowledged = []; + + /** + * @var Envelope[] + */ + private $rejected = []; + + /** + * {@inheritdoc} + */ + public function get(): iterable + { + return $this->sent; + } + + /** + * {@inheritdoc} + */ + public function ack(Envelope $envelope): void + { + $this->acknowledged[] = $envelope; + } + + /** + * {@inheritdoc} + */ + public function reject(Envelope $envelope): void + { + $this->rejected[] = $envelope; + } + + /** + * {@inheritdoc} + */ + public function send(Envelope $envelope): Envelope + { + $this->sent[] = $envelope; + + return $envelope; + } + + public function reset() + { + $this->sent = $this->rejected = $this->acknowledged = []; + } + + /** + * @return Envelope[] + */ + public function getAcknowledged(): array + { + return $this->acknowledged; + } + + /** + * @return Envelope[] + */ + public function getRejected(): array + { + return $this->rejected; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php b/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php new file mode 100644 index 0000000000000..78f1d18da3f0a --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php @@ -0,0 +1,27 @@ +<?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\Component\Messenger\Transport; + +use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; + +class InMemoryTransportFactory implements TransportFactoryInterface +{ + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface + { + return new InMemoryTransport(); + } + + public function supports(string $dsn, array $options): bool + { + return 0 === strpos($dsn, 'in-memory://'); + } +} From 4fc603327d0164f36d4f48f66293de2fb2dccbfc Mon Sep 17 00:00:00 2001 From: Amrouche Hamza <hamza@les-tilleuls.coop> Date: Sat, 6 Apr 2019 11:23:31 +0200 Subject: [PATCH 380/495] minor: remove the logger as it seems uneeded --- src/Symfony/Component/HttpClient/CachingHttpClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/CachingHttpClient.php b/src/Symfony/Component/HttpClient/CachingHttpClient.php index 7e7001cf3316d..143c5cdc03e25 100644 --- a/src/Symfony/Component/HttpClient/CachingHttpClient.php +++ b/src/Symfony/Component/HttpClient/CachingHttpClient.php @@ -46,7 +46,7 @@ public function __construct(HttpClientInterface $client, StoreInterface $store, } $this->client = $client; - $kernel = new HttpClientKernel($client, $logger); + $kernel = new HttpClientKernel($client); $this->cache = new HttpCache($kernel, $store, null, $defaultOptions); unset($defaultOptions['debug']); From 8f8c82e009e885848876562598d8f06d163c2e88 Mon Sep 17 00:00:00 2001 From: Samuel ROZE <samuel.roze@gmail.com> Date: Sat, 6 Apr 2019 11:16:32 +0200 Subject: [PATCH 381/495] Make the in-memory transport resettable --- .../Resources/config/messenger.xml | 1 + .../InMemoryTransportFactoryTest.php | 12 ++++++++++ .../Transport/InMemoryTransportFactory.php | 22 +++++++++++++++++-- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml index 75e1f8d5af88b..4f677d40918a8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml @@ -72,6 +72,7 @@ <service id="messenger.transport.in_memory.factory" class="Symfony\Component\Messenger\Transport\InMemoryTransportFactory"> <tag name="messenger.transport_factory" /> + <tag name="kernel.reset" method="reset" /> </service> <!-- retry --> diff --git a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php index fd4cb9c04b001..856c865f1ea31 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Messenger\Tests\Transport; use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Transport\InMemoryTransport; use Symfony\Component\Messenger\Transport\InMemoryTransportFactory; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -52,6 +54,16 @@ public function testCreateTransport() $this->assertInstanceOf(InMemoryTransport::class, $this->factory->createTransport('in-memory://', [], $serializer)); } + public function testResetCreatedTransports() + { + $transport = $this->factory->createTransport('in-memory://', [], $this->createMock(SerializerInterface::class)); + $transport->send(Envelope::wrap(new DummyMessage('Hello.'))); + + $this->assertCount(1, $transport->get()); + $this->factory->reset(); + $this->assertCount(0, $transport->get()); + } + public function provideDSN(): array { return [ diff --git a/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php b/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php index 78f1d18da3f0a..e7088e67052ca 100644 --- a/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php +++ b/src/Symfony/Component/Messenger/Transport/InMemoryTransportFactory.php @@ -12,16 +12,34 @@ namespace Symfony\Component\Messenger\Transport; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; +use Symfony\Contracts\Service\ResetInterface; -class InMemoryTransportFactory implements TransportFactoryInterface +/** + * @author Gary PEGEOT <garypegeot@gmail.com> + * + * @experimental in 4.3 + */ +class InMemoryTransportFactory implements TransportFactoryInterface, ResetInterface { + /** + * @var InMemoryTransport[] + */ + private $createdTransports = []; + public function createTransport(string $dsn, array $options, SerializerInterface $serializer): TransportInterface { - return new InMemoryTransport(); + return $this->createdTransports[] = new InMemoryTransport(); } public function supports(string $dsn, array $options): bool { return 0 === strpos($dsn, 'in-memory://'); } + + public function reset() + { + foreach ($this->createdTransports as $transport) { + $transport->reset(); + } + } } From 292021b1468b0f45e54f07c677c7ec2f47c644a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 11:31:31 +0200 Subject: [PATCH 382/495] [Messenger] Fixed DIC config when the messenger is not installed --- .../FrameworkBundle/DependencyInjection/FrameworkExtension.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index f3491d35695b7..5ef5ed7b5d269 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -280,6 +280,7 @@ public function load(array $configs, ContainerBuilder $container) } else { $container->removeDefinition('console.command.messenger_consume_messages'); $container->removeDefinition('console.command.messenger_debug'); + $container->removeDefinition('console.command.messenger_stop_workers'); $container->removeDefinition('console.command.messenger_setup_transports'); } From 45fd75ea20805d5dbe64b474a7b3191ef1e84f55 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Sat, 6 Apr 2019 11:37:23 +0200 Subject: [PATCH 383/495] fixed CS --- src/Symfony/Component/Messenger/Transport/InMemoryTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php b/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php index a21d67bd1982b..fbd75e9d9647f 100644 --- a/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php +++ b/src/Symfony/Component/Messenger/Transport/InMemoryTransport.php @@ -15,7 +15,7 @@ use Symfony\Contracts\Service\ResetInterface; /** - * Transport that stay in memory. Useful for testing purpose. + * Transport that stays in memory. Useful for testing purpose. * * @author Gary PEGEOT <garypegeot@gmail.com> * From 3151b54b7a2289a56aa0bcf85331a72ce67a050e Mon Sep 17 00:00:00 2001 From: Guillaume Gammelin <guillaume.gammelin@comalia.com> Date: Mon, 28 Jan 2019 16:06:43 +0100 Subject: [PATCH 384/495] [messenger] AMQP configurable routing key & multiple queues --- src/Symfony/Component/Messenger/CHANGELOG.md | 5 + .../AmqpExt/AmqpExtIntegrationTest.php | 10 +- .../AmqpExt/AmqpReceivedStampTest.php | 31 +++ .../Transport/AmqpExt/AmqpReceiverTest.php | 17 +- .../AmqpExt/AmqpRoutingKeyStampTest.php | 24 ++ .../Transport/AmqpExt/AmqpSenderTest.php | 16 ++ .../Transport/AmqpExt/AmqpTransportTest.php | 3 +- .../Transport/AmqpExt/ConnectionTest.php | 262 ++++++++++++------ .../Transport/AmqpExt/AmqpReceivedStamp.php | 9 +- .../Transport/AmqpExt/AmqpReceiver.php | 34 ++- .../Transport/AmqpExt/AmqpRoutingKeyStamp.php | 34 +++ .../Transport/AmqpExt/AmqpSender.php | 6 +- .../Transport/AmqpExt/Connection.php | 171 +++++++----- 13 files changed, 455 insertions(+), 167 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceivedStampTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php create mode 100644 src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index f2de05282acc1..c2a30754cd5fb 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -18,6 +18,9 @@ CHANGELOG changed: a required 3rd `SerializerInterface` argument was added. * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to explicitly handle messages synchronously. + * Added `AmqpRoutingKeyStamp` allowing to provide a routing key on message publishing. + * Removed publishing with a `routing_key` option from queue configuration, for + AMQP. Use exchange `default_publish_routing_key` or `AmqpRoutingKeyStamp` instead. * Added optional parameter `prefetch_count` in connection configuration, to setup channel prefetch count. * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` @@ -71,6 +74,8 @@ CHANGELOG only. Pass the `auto_setup` connection option to control this. * Added a `SetupTransportsCommand` command to setup the transports * Added a Doctrine transport. For example, use the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) + * Added `AmqpRoutingKeyStamp` allowing to provide a routing key on message publishing. + * Deprecated publishing with a routing key from queue configuration, use exchange configuration instead. 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php index 04f2b09ff4cb5..0addadd6442b6 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpExtIntegrationTest.php @@ -49,7 +49,7 @@ public function testItSendsAndReceivesMessages() $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); $connection->setup(); - $connection->queue()->purge(); + $connection->purgeQueues(); $sender = new AmqpSender($connection, $serializer); $receiver = new AmqpReceiver($connection, $serializer); @@ -79,7 +79,7 @@ public function testRetryAndDelay() $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); $connection->setup(); - $connection->queue()->purge(); + $connection->purgeQueues(); $sender = new AmqpSender($connection, $serializer); $receiver = new AmqpReceiver($connection, $serializer); @@ -126,7 +126,7 @@ public function testItReceivesSignals() $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); $connection->setup(); - $connection->queue()->purge(); + $connection->purgeQueues(); $sender = new AmqpSender($connection, $serializer); $sender->send(new Envelope(new DummyMessage('Hello'))); @@ -173,7 +173,7 @@ public function testItCountsMessagesInQueue() $connection = Connection::fromDsn(getenv('MESSENGER_AMQP_DSN')); $connection->setup(); - $connection->queue()->purge(); + $connection->purgeQueues(); $sender = new AmqpSender($connection, $serializer); @@ -182,7 +182,7 @@ public function testItCountsMessagesInQueue() $sender->send(new Envelope(new DummyMessage('Third'))); sleep(1); // give amqp a moment to have the messages ready - $this->assertSame(3, $connection->countMessagesInQueue()); + $this->assertSame(3, $connection->countMessagesInQueues()); } private function waitForOutput(Process $process, string $output, $timeoutInSeconds = 10) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceivedStampTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceivedStampTest.php new file mode 100644 index 0000000000000..79d53feee2c52 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceivedStampTest.php @@ -0,0 +1,31 @@ +<?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\Component\Messenger\Tests\Transport\AmqpExt; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp; + +/** + * @requires extension amqp + */ +class AmqpReceivedStampTest extends TestCase +{ + public function testStamp() + { + $amqpEnvelope = $this->createMock(\AMQPEnvelope::class); + + $stamp = new AmqpReceivedStamp($amqpEnvelope, 'queueName'); + + $this->assertSame($amqpEnvelope, $stamp->getAmqpEnvelope()); + $this->assertSame('queueName', $stamp->getQueueName()); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php index 7a20fd2042799..617250f2aa087 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpReceiverTest.php @@ -36,7 +36,8 @@ public function testItReturnsTheDecodedMessageToTheHandler() $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($amqpEnvelope); + $connection->method('getQueueNames')->willReturn(['queueName']); + $connection->method('get')->with('queueName')->willReturn($amqpEnvelope); $receiver = new AmqpReceiver($connection, $serializer); $actualEnvelopes = iterator_to_array($receiver->get()); @@ -52,11 +53,12 @@ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() $serializer = $this->createMock(SerializerInterface::class); $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($amqpEnvelope); - $connection->method('ack')->with($amqpEnvelope)->willThrowException(new \AMQPException()); + $connection->method('getQueueNames')->willReturn(['queueName']); + $connection->method('get')->with('queueName')->willReturn($amqpEnvelope); + $connection->method('ack')->with($amqpEnvelope, 'queueName')->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->ack(new Envelope(new \stdClass(), [new AmqpReceivedStamp($amqpEnvelope)])); + $receiver->ack(new Envelope(new \stdClass(), [new AmqpReceivedStamp($amqpEnvelope, 'queueName')])); } /** @@ -67,11 +69,12 @@ public function testItThrowsATransportExceptionIfItCannotRejectMessage() $serializer = $this->createMock(SerializerInterface::class); $amqpEnvelope = $this->createAMQPEnvelope(); $connection = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); - $connection->method('get')->willReturn($amqpEnvelope); - $connection->method('nack')->with($amqpEnvelope, AMQP_NOPARAM)->willThrowException(new \AMQPException()); + $connection->method('getQueueNames')->willReturn(['queueName']); + $connection->method('get')->with('queueName')->willReturn($amqpEnvelope); + $connection->method('nack')->with($amqpEnvelope, 'queueName', AMQP_NOPARAM)->willThrowException(new \AMQPException()); $receiver = new AmqpReceiver($connection, $serializer); - $receiver->reject(new Envelope(new \stdClass(), [new AmqpReceivedStamp($amqpEnvelope)])); + $receiver->reject(new Envelope(new \stdClass(), [new AmqpReceivedStamp($amqpEnvelope, 'queueName')])); } private function createAMQPEnvelope() diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php new file mode 100644 index 0000000000000..895e41b2620e9 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php @@ -0,0 +1,24 @@ +<?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\Component\Messenger\Tests\Transport\AmqpExt; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpRoutingKeyStamp; + +class AmqpRoutingKeyStampTest extends TestCase +{ + public function testStamp() + { + $stamp = new AmqpRoutingKeyStamp('routing_key'); + $this->assertSame('routing_key', $stamp->getRoutingKey()); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php index 14fee16ca6589..178d86a516860 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpRoutingKeyStamp; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpSender; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -38,6 +39,21 @@ public function testItSendsTheEncodedMessage() $sender->send($envelope); } + public function testItSendsTheEncodedMessageUsingARoutingKey() + { + $envelope = (new Envelope(new DummyMessage('Oy')))->with(new AmqpRoutingKeyStamp('rk')); + $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; + + $serializer = $this->createMock(SerializerInterface::class); + $serializer->method('encode')->with($envelope)->willReturn($encoded); + + $connection = $this->createMock(Connection::class); + $connection->expects($this->once())->method('publish')->with($encoded['body'], $encoded['headers'], 0, 'rk'); + + $sender = new AmqpSender($connection, $serializer); + $sender->send($envelope); + } + public function testItSendsTheEncodedMessageWithoutHeaders() { $envelope = new Envelope(new DummyMessage('Oy')); diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php index b3e8b5729dd70..4afdabca69224 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpTransportTest.php @@ -45,7 +45,8 @@ public function testReceivesMessages() $amqpEnvelope->method('getHeaders')->willReturn(['my' => 'header']); $serializer->method('decode')->with(['body' => 'body', 'headers' => ['my' => 'header']])->willReturn(new Envelope($decodedMessage)); - $connection->method('get')->willReturn($amqpEnvelope); + $connection->method('getQueueNames')->willReturn(['queueName']); + $connection->method('get')->with('queueName')->willReturn($amqpEnvelope); $envelopes = iterator_to_array($transport->get()); $this->assertSame($decodedMessage, $envelopes[0]->getMessage()); diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index 100aeb78e882d..a2de20b6208ed 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -40,7 +40,7 @@ public function testItGetsParametersFromTheDsn() ], [ 'name' => 'messages', ], [ - 'name' => 'messages', + 'messages' => [], ]), Connection::fromDsn('amqp://localhost/%2f/messages') ); @@ -58,9 +58,9 @@ public function testOverrideOptionsViaQueryParameters() ], [ 'name' => 'exchangeName', ], [ - 'name' => 'queue', + 'queueName' => [], ]), - Connection::fromDsn('amqp://guest:password@redis:1234/%2f/queue?exchange[name]=exchangeName') + Connection::fromDsn('amqp://guest:password@redis:1234/%2f/queue?exchange[name]=exchangeName&queues[queueName]') ); } @@ -77,9 +77,9 @@ public function testOptionsAreTakenIntoAccountAndOverwrittenByDsn() ], [ 'name' => 'exchangeName', ], [ - 'name' => 'queueName', + 'queueName' => [], ]), - Connection::fromDsn('amqp://guest:password@redis:1234/%2f/queue?exchange[name]=exchangeName&queue[name]=queueName', [ + Connection::fromDsn('amqp://guest:password@redis:1234/%2f/queue?exchange[name]=exchangeName&queues[queueName]', [ 'persistent' => 'true', 'exchange' => ['name' => 'toBeOverwritten'], ]) @@ -89,10 +89,10 @@ public function testOptionsAreTakenIntoAccountAndOverwrittenByDsn() public function testSetsParametersOnTheQueueAndExchange() { $factory = new TestAmqpFactory( - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), - $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), - $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) ); $amqpQueue->expects($this->once())->method('setArguments')->with([ @@ -110,17 +110,19 @@ public function testSetsParametersOnTheQueueAndExchange() ]); $dsn = 'amqp://localhost/%2f/messages?'. - 'queue[arguments][x-dead-letter-exchange]=dead-exchange&'. - 'queue[arguments][x-message-ttl]=100&'. - 'queue[arguments][x-delay]=100&'. - 'queue[arguments][x-expires]=150&' + 'queues[messages][arguments][x-dead-letter-exchange]=dead-exchange&'. + 'queues[messages][arguments][x-message-ttl]=100&'. + 'queues[messages][arguments][x-delay]=100&'. + 'queues[messages][arguments][x-expires]=150&' ; $connection = Connection::fromDsn($dsn, [ - 'queue' => [ - 'arguments' => [ - 'x-max-length' => '200', - 'x-max-length-bytes' => '300', - 'x-max-priority' => '4', + 'queues' => [ + 'messages' => [ + 'arguments' => [ + 'x-max-length' => '200', + 'x-max-length-bytes' => '300', + 'x-max-priority' => '4', + ], ], ], 'exchange' => [ @@ -135,20 +137,23 @@ public function testSetsParametersOnTheQueueAndExchange() public function invalidQueueArgumentsDataProvider(): iterable { $baseDsn = 'amqp://localhost/%2f/messages'; - yield [$baseDsn.'?queue[arguments][x-delay]=not-a-number', []]; - yield [$baseDsn.'?queue[arguments][x-expires]=not-a-number', []]; - yield [$baseDsn.'?queue[arguments][x-max-length]=not-a-number', []]; - yield [$baseDsn.'?queue[arguments][x-max-length-bytes]=not-a-number', []]; - yield [$baseDsn.'?queue[arguments][x-max-priority]=not-a-number', []]; - yield [$baseDsn.'?queue[arguments][x-message-ttl]=not-a-number', []]; - - // Ensure the exception is thrown when the arguments are passed via the array options - yield [$baseDsn, ['queue' => ['arguments' => ['x-delay' => 'not-a-number']]]]; - yield [$baseDsn, ['queue' => ['arguments' => ['x-expires' => 'not-a-number']]]]; - yield [$baseDsn, ['queue' => ['arguments' => ['x-max-length' => 'not-a-number']]]]; - yield [$baseDsn, ['queue' => ['arguments' => ['x-max-length-bytes' => 'not-a-number']]]]; - yield [$baseDsn, ['queue' => ['arguments' => ['x-max-priority' => 'not-a-number']]]]; - yield [$baseDsn, ['queue' => ['arguments' => ['x-message-ttl' => 'not-a-number']]]]; + + return [ + [$baseDsn.'?queues[messages][arguments][x-delay]=not-a-number', []], + [$baseDsn.'?queues[messages][arguments][x-expires]=not-a-number', []], + [$baseDsn.'?queues[messages][arguments][x-max-length]=not-a-number', []], + [$baseDsn.'?queues[messages][arguments][x-max-length-bytes]=not-a-number', []], + [$baseDsn.'?queues[messages][arguments][x-max-priority]=not-a-number', []], + [$baseDsn.'?queues[messages][arguments][x-message-ttl]=not-a-number', []], + + // Ensure the exception is thrown when the arguments are passed via the array options + [$baseDsn, ['queues' => ['messages' => ['arguments' => ['x-delay' => 'not-a-number']]]]], + [$baseDsn, ['queues' => ['messages' => ['arguments' => ['x-expires' => 'not-a-number']]]]], + [$baseDsn, ['queues' => ['messages' => ['arguments' => ['x-max-length' => 'not-a-number']]]]], + [$baseDsn, ['queues' => ['messages' => ['arguments' => ['x-max-length-bytes' => 'not-a-number']]]]], + [$baseDsn, ['queues' => ['messages' => ['arguments' => ['x-max-priority' => 'not-a-number']]]]], + [$baseDsn, ['queues' => ['messages' => ['arguments' => ['x-message-ttl' => 'not-a-number']]]]], + ]; } /** @@ -165,10 +170,10 @@ public function testFromDsnWithInvalidValueOnQueueArguments(string $dsn, array $ public function testItUsesANormalConnectionByDefault() { $factory = new TestAmqpFactory( - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), - $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), - $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) ); // makes sure the channel looks connected, so it's not re-created @@ -182,10 +187,10 @@ public function testItUsesANormalConnectionByDefault() public function testItAllowsToUseAPersistentConnection() { $factory = new TestAmqpFactory( - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), - $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), - $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) ); // makes sure the channel looks connected, so it's not re-created @@ -196,49 +201,65 @@ public function testItAllowsToUseAPersistentConnection() $connection->publish('body'); } - public function testItSetupsTheConnectionByDefault() + public function testItSetupsTheConnectionWithDefaults() { $factory = new TestAmqpFactory( - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), - $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), - $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) ); $amqpExchange->method('getName')->willReturn('exchange_name'); $amqpExchange->expects($this->once())->method('declareExchange'); + $amqpExchange->expects($this->once())->method('publish')->with('body', null, AMQP_NOPARAM, ['headers' => []]); $amqpQueue->expects($this->once())->method('declareQueue'); - $amqpQueue->expects($this->once())->method('bind')->with('exchange_name', 'my_key'); + $amqpQueue->expects($this->once())->method('bind')->with('exchange_name', null); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', [], $factory); + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', [], $factory); $connection->publish('body'); } - public function testItCanDisableTheSetup() + public function testItSetupsTheConnection() { - $factory = new TestAmqpFactory( - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(), - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(), - $amqpQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(), - $amqpExchange = $this->getMockBuilder(\AMQPExchange::class)->disableOriginalConstructor()->getMock() - ); + $amqpConnection = $this->createMock(\AMQPConnection::class); + $amqpChannel = $this->createMock(\AMQPChannel::class); + $amqpExchange = $this->createMock(\AMQPExchange::class); + $amqpQueue0 = $this->createMock(\AMQPQueue::class); + $amqpQueue1 = $this->createMock(\AMQPQueue::class); - $amqpExchange->method('getName')->willReturn('exchange_name'); - $amqpExchange->expects($this->never())->method('declareExchange'); - $amqpQueue->expects($this->never())->method('declareQueue'); - $amqpQueue->expects($this->never())->method('bind'); + $factory = $this->createMock(AmqpFactory::class); + $factory->method('createConnection')->willReturn($amqpConnection); + $factory->method('createChannel')->willReturn($amqpChannel); + $factory->method('createExchange')->willReturn($amqpExchange); + $factory->method('createQueue')->will($this->onConsecutiveCalls($amqpQueue0, $amqpQueue1)); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', ['auto_setup' => 'false'], $factory); - $connection->publish('body'); + $amqpExchange->method('getName')->willReturn('exchange_name'); + $amqpExchange->expects($this->once())->method('declareExchange'); + $amqpExchange->expects($this->once())->method('publish')->with('body', 'routing_key', AMQP_NOPARAM, ['headers' => []]); + $amqpQueue0->expects($this->once())->method('declareQueue'); + $amqpQueue0->expects($this->exactly(2))->method('bind')->withConsecutive( + ['exchange_name', 'binding_key0'], + ['exchange_name', 'binding_key1'] + ); + $amqpQueue1->expects($this->once())->method('declareQueue'); + $amqpQueue1->expects($this->exactly(2))->method('bind')->withConsecutive( + ['exchange_name', 'binding_key2'], + ['exchange_name', 'binding_key3'] + ); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key', ['auto_setup' => false], $factory); - $connection->publish('body'); + $dsn = 'amqp://localhost/%2f/messages?'. + 'exchange[default_publish_routing_key]=routing_key&'. + 'queues[queue0][binding_keys][0]=binding_key0&'. + 'queues[queue0][binding_keys][1]=binding_key1&'. + 'queues[queue1][binding_keys][0]=binding_key2&'. + 'queues[queue1][binding_keys][1]=binding_key3'; - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[routing_key]=my_key&auto_setup=false', [], $factory); + $connection = Connection::fromDsn($dsn, [], $factory); $connection->publish('body'); } - public function testPublishWithQueueOptions() + public function testItCanDisableTheSetup() { $factory = new TestAmqpFactory( $amqpConnection = $this->createMock(\AMQPConnection::class), @@ -246,14 +267,20 @@ public function testPublishWithQueueOptions() $amqpQueue = $this->createMock(\AMQPQueue::class), $amqpExchange = $this->createMock(\AMQPExchange::class) ); - $headers = [ - 'type' => '*', - ]; - $amqpExchange->expects($this->once())->method('publish') - ->with('body', null, 1, ['delivery_mode' => 2, 'headers' => ['token' => 'uuid', 'type' => '*']]); - $connection = Connection::fromDsn('amqp://localhost/%2f/messages?queue[attributes][delivery_mode]=2&queue[attributes][headers][token]=uuid&queue[flags]=1', [], $factory); - $connection->publish('body', $headers); + $amqpExchange->method('getName')->willReturn('exchange_name'); + $amqpExchange->expects($this->never())->method('declareExchange'); + $amqpQueue->expects($this->never())->method('declareQueue'); + $amqpQueue->expects($this->never())->method('bind'); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', ['auto_setup' => 'false'], $factory); + $connection->publish('body'); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', ['auto_setup' => false], $factory); + $connection->publish('body'); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?auto_setup=false', [], $factory); + $connection->publish('body'); } public function testSetChannelPrefetchWhenSetup() @@ -277,11 +304,11 @@ public function testSetChannelPrefetchWhenSetup() public function testItDelaysTheMessage() { - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(); - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(); - $delayQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(); + $amqpConnection = $this->createMock(\AMQPConnection::class); + $amqpChannel = $this->createMock(\AMQPChannel::class); + $delayQueue = $this->createMock(\AMQPQueue::class); - $factory = $this->getMockBuilder(AmqpFactory::class)->getMock(); + $factory = $this->createMock(AmqpFactory::class); $factory->method('createConnection')->willReturn($amqpConnection); $factory->method('createChannel')->willReturn($amqpChannel); $factory->method('createQueue')->willReturn($delayQueue); @@ -314,11 +341,11 @@ public function testItDelaysTheMessage() public function testItDelaysTheMessageWithADifferentRoutingKeyAndTTLs() { - $amqpConnection = $this->getMockBuilder(\AMQPConnection::class)->disableOriginalConstructor()->getMock(); - $amqpChannel = $this->getMockBuilder(\AMQPChannel::class)->disableOriginalConstructor()->getMock(); - $delayQueue = $this->getMockBuilder(\AMQPQueue::class)->disableOriginalConstructor()->getMock(); + $amqpConnection = $this->createMock(\AMQPConnection::class); + $amqpChannel = $this->createMock(\AMQPChannel::class); + $delayQueue = $this->createMock(\AMQPQueue::class); - $factory = $this->getMockBuilder(AmqpFactory::class)->getMock(); + $factory = $this->createMock(AmqpFactory::class); $factory->method('createConnection')->willReturn($amqpConnection); $factory->method('createChannel')->willReturn($amqpChannel); $factory->method('createQueue')->willReturn($delayQueue); @@ -375,6 +402,83 @@ public function testObfuscatePasswordInDsn() $connection = Connection::fromDsn('amqp://user:secretpassword@localhost/%2f/messages', [], $factory); $connection->channel(); } + + public function testItCanPublishWithTheDefaultRoutingKey() + { + $factory = new TestAmqpFactory( + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) + ); + + $amqpExchange->expects($this->once())->method('publish')->with('body', 'routing_key'); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?exchange[default_publish_routing_key]=routing_key', [], $factory); + $connection->publish('body'); + } + + public function testItCanPublishWithASuppliedRoutingKey() + { + $factory = new TestAmqpFactory( + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) + ); + + $amqpExchange->expects($this->once())->method('publish')->with('body', 'routing_key'); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages?exchange[default_publish_routing_key]=default_routing_key', [], $factory); + $connection->publish('body', [], 0, 'routing_key'); + } + + public function testItDelaysTheMessageWithTheInitialSuppliedRoutingKeyAsArgument() + { + $amqpConnection = $this->createMock(\AMQPConnection::class); + $amqpChannel = $this->createMock(\AMQPChannel::class); + $delayQueue = $this->createMock(\AMQPQueue::class); + + $factory = $this->createMock(AmqpFactory::class); + $factory->method('createConnection')->willReturn($amqpConnection); + $factory->method('createChannel')->willReturn($amqpChannel); + $factory->method('createQueue')->willReturn($delayQueue); + $factory->method('createExchange')->will($this->onConsecutiveCalls( + $delayExchange = $this->createMock(\AMQPExchange::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) + )); + + $amqpExchange->expects($this->once())->method('setName')->with('messages'); + $amqpExchange->method('getName')->willReturn('messages'); + + $delayExchange->expects($this->once())->method('setName')->with('delay'); + $delayExchange->expects($this->once())->method('declareExchange'); + $delayExchange->method('getName')->willReturn('delay'); + + $connectionOptions = [ + 'retry' => [ + 'dead_routing_key' => 'my_dead_routing_key', + ], + ]; + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', $connectionOptions, $factory); + + $delayQueue->expects($this->once())->method('setName')->with('delay_queue_120000'); + $delayQueue->expects($this->once())->method('setArguments')->with([ + 'x-message-ttl' => 120000, + 'x-dead-letter-exchange' => 'messages', + ]); + $delayQueue->expects($this->once())->method('setArgument')->with( + 'x-dead-letter-routing-key', + 'routing_key' + ); + + $delayQueue->expects($this->once())->method('declareQueue'); + $delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_120000'); + + $delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_120000', AMQP_NOPARAM, ['headers' => []]); + $connection->publish('{}', [], 120000, 'routing_key'); + } } class TestAmqpFactory extends AmqpFactory diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php index 9ed3dc30a3664..78ccb08add591 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceivedStamp.php @@ -21,14 +21,21 @@ class AmqpReceivedStamp implements StampInterface { private $amqpEnvelope; + private $queueName; - public function __construct(\AMQPEnvelope $amqpEnvelope) + public function __construct(\AMQPEnvelope $amqpEnvelope, string $queueName) { $this->amqpEnvelope = $amqpEnvelope; + $this->queueName = $queueName; } public function getAmqpEnvelope(): \AMQPEnvelope { return $this->amqpEnvelope; } + + public function getQueueName(): string + { + return $this->queueName; + } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index e81b6b9431120..43cfaa814ecf9 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -42,9 +42,16 @@ public function __construct(Connection $connection, SerializerInterface $seriali * {@inheritdoc} */ public function get(): iterable + { + foreach ($this->connection->getQueueNames() as $queueName) { + yield from $this->getEnvelope($queueName); + } + } + + private function getEnvelope(string $queueName): iterable { try { - $amqpEnvelope = $this->connection->get(); + $amqpEnvelope = $this->connection->get($queueName); } catch (\AMQPException $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } @@ -60,12 +67,12 @@ public function get(): iterable ]); } catch (MessageDecodingFailedException $exception) { // invalid message of some type - $this->rejectAmqpEnvelope($amqpEnvelope); + $this->rejectAmqpEnvelope($amqpEnvelope, $queueName); throw $exception; } - yield $envelope->with(new AmqpReceivedStamp($amqpEnvelope)); + yield $envelope->with(new AmqpReceivedStamp($amqpEnvelope, $queueName)); } /** @@ -74,7 +81,11 @@ public function get(): iterable public function ack(Envelope $envelope): void { try { - $this->connection->ack($this->findAmqpEnvelope($envelope)); + /* @var AmqpReceivedStamp $amqpReceivedStamp */ + $this->connection->ack( + $this->findAmqpEnvelope($envelope, $amqpReceivedStamp), + $amqpReceivedStamp->getQueueName() + ); } catch (\AMQPException $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } @@ -85,7 +96,11 @@ public function ack(Envelope $envelope): void */ public function reject(Envelope $envelope): void { - $this->rejectAmqpEnvelope($this->findAmqpEnvelope($envelope)); + /* @var AmqpReceivedStamp $amqpReceivedStamp */ + $this->rejectAmqpEnvelope( + $this->findAmqpEnvelope($envelope, $amqpReceivedStamp), + $amqpReceivedStamp->getQueueName() + ); } /** @@ -93,21 +108,20 @@ public function reject(Envelope $envelope): void */ public function getMessageCount(): int { - return $this->connection->countMessagesInQueue(); + return $this->connection->countMessagesInQueues(); } - private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope): void + private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, string $queueName): void { try { - $this->connection->nack($amqpEnvelope, AMQP_NOPARAM); + $this->connection->nack($amqpEnvelope, $queueName, AMQP_NOPARAM); } catch (\AMQPException $exception) { throw new TransportException($exception->getMessage(), 0, $exception); } } - private function findAmqpEnvelope(Envelope $envelope): \AMQPEnvelope + private function findAmqpEnvelope(Envelope $envelope, AmqpReceivedStamp &$amqpReceivedStamp = null): \AMQPEnvelope { - /** @var AmqpReceivedStamp|null $amqpReceivedStamp */ $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); if (null === $amqpReceivedStamp) { diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php new file mode 100644 index 0000000000000..b9f2aa2d81765 --- /dev/null +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php @@ -0,0 +1,34 @@ +<?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\Component\Messenger\Transport\AmqpExt; + +use Symfony\Component\Messenger\Stamp\StampInterface; + +/** + * @author Guillaume Gammelin <ggammelin@gmail.com> + * + * @experimental in 4.3 + */ +final class AmqpRoutingKeyStamp implements StampInterface +{ + private $routingKey; + + public function __construct(string $routingKey) + { + $this->routingKey = $routingKey; + } + + public function getRoutingKey(): string + { + return $this->routingKey; + } +} diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php index 021a6bfaf8b51..d53ecb3b8979e 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php @@ -51,7 +51,11 @@ public function send(Envelope $envelope): Envelope } try { - $this->connection->publish($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay); + /** @var $routingKeyStamp AmqpRoutingKeyStamp */ + $routingKeyStamp = $envelope->last(AmqpRoutingKeyStamp::class); + $routingKey = $routingKeyStamp ? $routingKeyStamp->getRoutingKey() : null; + + $this->connection->publish($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay, $routingKey); } catch (\AMQPException $e) { throw new TransportException($e->getMessage(), 0, $e); } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 512193a5e98d6..50d5d35a12132 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -35,7 +35,7 @@ class Connection private $connectionConfiguration; private $exchangeConfiguration; - private $queueConfiguration; + private $queuesConfiguration; private $amqpFactory; /** @@ -49,9 +49,9 @@ class Connection private $amqpExchange; /** - * @var \AMQPQueue|null + * @var \AMQPQueue[]|null */ - private $amqpQueue; + private $amqpQueues = []; /** * @var \AMQPExchange|null @@ -68,14 +68,14 @@ class Connection * * vhost: Virtual Host to use with the AMQP service * * user: Username to use to connect the the AMQP service * * password: Password to use the connect to the AMQP service - * * queue: - * * name: Name of the queue - * * routing_key: The routing key (if any) to use to push the messages to + * * queues[name]: An array of queues, keyed by the name + * * binding_keys: The binding keys (if any) to bind to this queue * * flags: Queue flags (Default: AMQP_DURABLE) * * arguments: Extra arguments * * exchange: * * name: Name of the exchange * * type: Type of exchange (Default: fanout) + * * default_publish_routing_key: Routing key to use when publishing, if none is specified on the message * * flags: Exchange flags (Default: AMQP_DURABLE) * * arguments: Extra arguments * * delay: @@ -86,7 +86,7 @@ class Connection * * loop_sleep: Amount of micro-seconds to wait if no message are available (Default: 200000) * * prefetch_count: set channel prefetch count */ - public function __construct(array $connectionConfiguration, array $exchangeConfiguration, array $queueConfiguration, AmqpFactory $amqpFactory = null) + public function __construct(array $connectionConfiguration, array $exchangeConfiguration, array $queuesConfiguration, AmqpFactory $amqpFactory = null) { $this->connectionConfiguration = array_replace_recursive([ 'delay' => [ @@ -96,7 +96,7 @@ public function __construct(array $connectionConfiguration, array $exchangeConfi ], ], $connectionConfiguration); $this->exchangeConfiguration = $exchangeConfiguration; - $this->queueConfiguration = $queueConfiguration; + $this->queuesConfiguration = $queuesConfiguration; $this->amqpFactory = $amqpFactory ?: new AmqpFactory(); } @@ -107,17 +107,17 @@ public static function fromDsn(string $dsn, array $options = [], AmqpFactory $am } $pathParts = isset($parsedUrl['path']) ? explode('/', trim($parsedUrl['path'], '/')) : []; + $exchangeName = $pathParts[1] ?? 'messages'; + parse_str($parsedUrl['query'] ?? '', $parsedQuery); + $amqpOptions = array_replace_recursive([ 'host' => $parsedUrl['host'] ?? 'localhost', 'port' => $parsedUrl['port'] ?? 5672, 'vhost' => isset($pathParts[0]) ? urldecode($pathParts[0]) : '/', - 'queue' => [ - 'name' => $queueName = $pathParts[1] ?? 'messages', - ], 'exchange' => [ - 'name' => $queueName, + 'name' => $exchangeName, ], - ], $options); + ], $options, $parsedQuery); if (isset($parsedUrl['user'])) { $amqpOptions['login'] = $parsedUrl['user']; @@ -127,21 +127,26 @@ public static function fromDsn(string $dsn, array $options = [], AmqpFactory $am $amqpOptions['password'] = $parsedUrl['pass']; } - if (isset($parsedUrl['query'])) { - parse_str($parsedUrl['query'], $parsedQuery); - - $amqpOptions = array_replace_recursive($amqpOptions, $parsedQuery); + if (!isset($amqpOptions['queues'])) { + $amqpOptions['queues'][$exchangeName] = []; } $exchangeOptions = $amqpOptions['exchange']; - $queueOptions = $amqpOptions['queue']; - unset($amqpOptions['queue'], $amqpOptions['exchange']); + $queuesOptions = $amqpOptions['queues']; + unset($amqpOptions['queues'], $amqpOptions['exchange']); - if (\is_array($queueOptions['arguments'] ?? false)) { - $queueOptions['arguments'] = self::normalizeQueueArguments($queueOptions['arguments']); - } + $queuesOptions = array_map(function ($queueOptions) { + if (!\is_array($queueOptions)) { + $queueOptions = []; + } + if (\is_array($queueOptions['arguments'] ?? false)) { + $queueOptions['arguments'] = self::normalizeQueueArguments($queueOptions['arguments']); + } - return new self($amqpOptions, $exchangeOptions, $queueOptions, $amqpFactory); + return $queueOptions; + }, $queuesOptions); + + return new self($amqpOptions, $exchangeOptions, $queuesOptions, $amqpFactory); } private static function normalizeQueueArguments(array $arguments): array @@ -166,10 +171,10 @@ private static function normalizeQueueArguments(array $arguments): array * * @throws \AMQPException */ - public function publish(string $body, array $headers = [], int $delay = 0): void + public function publish(string $body, array $headers = [], int $delay = 0, string $routingKey = null): void { if (0 !== $delay) { - $this->publishWithDelay($body, $headers, $delay); + $this->publishWithDelay($body, $headers, $delay, $routingKey); return; } @@ -178,37 +183,50 @@ public function publish(string $body, array $headers = [], int $delay = 0): void $this->setup(); } - $flags = $this->queueConfiguration['flags'] ?? AMQP_NOPARAM; - $attributes = $this->getAttributes($headers); + // TODO - allow flag & attributes to be configured on the message - $this->exchange()->publish($body, $this->queueConfiguration['routing_key'] ?? null, $flags, $attributes); + $this->exchange()->publish( + $body, + $routingKey ?? $this->getDefaultPublishRoutingKey(), + AMQP_NOPARAM, + [ + 'headers' => $headers, + ] + ); } /** - * Returns an approximate count of the messages in a queue. + * Returns an approximate count of the messages in defined queues. */ - public function countMessagesInQueue(): int + public function countMessagesInQueues(): int { - return $this->queue()->declareQueue(); + return array_sum(array_map(function ($queueName) { + return $this->queue($queueName)->declareQueue(); + }, $this->getQueueNames())); } /** * @throws \AMQPException */ - private function publishWithDelay(string $body, array $headers = [], int $delay) + private function publishWithDelay(string $body, array $headers, int $delay, ?string $exchangeRoutingKey) { if ($this->shouldSetup()) { - $this->setupDelay($delay); + $this->setupDelay($delay, $exchangeRoutingKey); } - $routingKey = $this->getRoutingKeyForDelay($delay); - $flags = $this->queueConfiguration['flags'] ?? AMQP_NOPARAM; - $attributes = $this->getAttributes($headers); + // TODO - allow flag & attributes to be configured on the message - $this->getDelayExchange()->publish($body, $routingKey, $flags, $attributes); + $this->getDelayExchange()->publish( + $body, + $this->getRoutingKeyForDelay($delay), + AMQP_NOPARAM, + [ + 'headers' => $headers, + ] + ); } - private function setupDelay(int $delay) + private function setupDelay(int $delay, ?string $routingKey) { if (!$this->channel()->isConnected()) { $this->clear(); @@ -217,7 +235,7 @@ private function setupDelay(int $delay) $exchange = $this->getDelayExchange(); $exchange->declareExchange(); - $queue = $this->createDelayQueue($delay); + $queue = $this->createDelayQueue($delay, $routingKey); $queue->declareQueue(); $queue->bind($exchange->getName(), $this->getRoutingKeyForDelay($delay)); } @@ -242,7 +260,7 @@ private function getDelayExchange(): \AMQPExchange * which is the original exchange, resulting on it being put back into * the original queue. */ - private function createDelayQueue(int $delay) + private function createDelayQueue(int $delay, ?string $routingKey) { $delayConfiguration = $this->connectionConfiguration['delay']; @@ -253,9 +271,10 @@ private function createDelayQueue(int $delay) 'x-dead-letter-exchange' => $this->exchange()->getName(), ]); - if (isset($this->queueConfiguration['routing_key'])) { + $routingKey = $routingKey ?? $this->getDefaultPublishRoutingKey(); + if (null !== $routingKey) { // after being released from to DLX, this routing key will be used - $queue->setArgument('x-dead-letter-routing-key', $this->queueConfiguration['routing_key']); + $queue->setArgument('x-dead-letter-routing-key', $routingKey); } return $queue; @@ -267,18 +286,18 @@ private function getRoutingKeyForDelay(int $delay): string } /** - * Waits and gets a message from the configured queue. + * Gets a message from the specified queue. * * @throws \AMQPException */ - public function get(): ?\AMQPEnvelope + public function get(string $queueName): ?\AMQPEnvelope { if ($this->shouldSetup()) { $this->setup(); } try { - if (false !== $message = $this->queue()->get()) { + if (false !== $message = $this->queue($queueName)->get()) { return $message; } } catch (\AMQPQueueException $e) { @@ -295,14 +314,14 @@ public function get(): ?\AMQPEnvelope return null; } - public function ack(\AMQPEnvelope $message): bool + public function ack(\AMQPEnvelope $message, string $queueName): bool { - return $this->queue()->ack($message->getDeliveryTag()); + return $this->queue($queueName)->ack($message->getDeliveryTag()); } - public function nack(\AMQPEnvelope $message, int $flags = AMQP_NOPARAM): bool + public function nack(\AMQPEnvelope $message, string $queueName, int $flags = AMQP_NOPARAM): bool { - return $this->queue()->nack($message->getDeliveryTag(), $flags); + return $this->queue($queueName)->nack($message->getDeliveryTag(), $flags); } public function setup(): void @@ -313,10 +332,25 @@ public function setup(): void $this->exchange()->declareExchange(); - $this->queue()->declareQueue(); - $this->queue()->bind($this->exchange()->getName(), $this->queueConfiguration['routing_key'] ?? null); + foreach ($this->queuesConfiguration as $queueName => $queueConfig) { + $this->queue($queueName)->declareQueue(); + foreach ($queueConfig['binding_keys'] ?? [null] as $bindingKey) { + $this->queue($queueName)->bind($this->exchange()->getName(), $bindingKey); + } + } + } + + /** + * @return string[] + */ + public function getQueueNames(): array + { + return array_keys($this->queuesConfiguration); } + /** + * @internal + */ public function channel(): \AMQPChannel { if (null === $this->amqpChannel) { @@ -341,22 +375,26 @@ public function channel(): \AMQPChannel return $this->amqpChannel; } - public function queue(): \AMQPQueue + private function queue(string $queueName): \AMQPQueue { - if (null === $this->amqpQueue) { - $this->amqpQueue = $this->amqpFactory->createQueue($this->channel()); - $this->amqpQueue->setName($this->queueConfiguration['name']); - $this->amqpQueue->setFlags($this->queueConfiguration['flags'] ?? AMQP_DURABLE); + if (!isset($this->amqpQueues[$queueName])) { + $queueConfig = $this->queuesConfiguration[$queueName]; + + $amqpQueue = $this->amqpFactory->createQueue($this->channel()); + $amqpQueue->setName($queueName); + $amqpQueue->setFlags($queueConfig['flags'] ?? AMQP_DURABLE); - if (isset($this->queueConfiguration['arguments'])) { - $this->amqpQueue->setArguments($this->queueConfiguration['arguments']); + if (isset($queueConfig['arguments'])) { + $amqpQueue->setArguments($queueConfig['arguments']); } + + $this->amqpQueues[$queueName] = $amqpQueue; } - return $this->amqpQueue; + return $this->amqpQueues[$queueName]; } - public function exchange(): \AMQPExchange + private function exchange(): \AMQPExchange { if (null === $this->amqpExchange) { $this->amqpExchange = $this->amqpFactory->createExchange($this->channel()); @@ -380,7 +418,7 @@ public function getConnectionConfiguration(): array private function clear(): void { $this->amqpChannel = null; - $this->amqpQueue = null; + $this->amqpQueues = []; $this->amqpExchange = null; } @@ -397,8 +435,15 @@ private function shouldSetup(): bool return true; } - private function getAttributes(array $headers): array + private function getDefaultPublishRoutingKey(): ?string { - return array_merge_recursive($this->queueConfiguration['attributes'] ?? [], ['headers' => $headers]); + return $this->exchangeConfiguration['default_publish_routing_key'] ?? null; + } + + public function purgeQueues() + { + foreach ($this->getQueueNames() as $queueName) { + $this->queue($queueName)->purge(); + } } } From 4b61602d5195f3c9599c367a2844e4607cba178f Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Sat, 6 Apr 2019 11:45:29 +0200 Subject: [PATCH 385/495] removed unneeded tags --- .../Messenger/Tests/Transport/InMemoryTransportFactoryTest.php | 2 -- .../Messenger/Tests/Transport/InMemoryTransportTest.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php index 856c865f1ea31..fd6bebc3b69d3 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportFactoryTest.php @@ -19,8 +19,6 @@ use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; /** - * @internal - * * @author Gary PEGEOT <garypegeot@gmail.com> */ class InMemoryTransportFactoryTest extends TestCase diff --git a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php index 8b5634b3f616a..5d9c8b70088bf 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/InMemoryTransportTest.php @@ -16,8 +16,6 @@ use Symfony\Component\Messenger\Transport\InMemoryTransport; /** - * @internal - * * @author Gary PEGEOT <garypegeot@gmail.com> */ class InMemoryTransportTest extends TestCase From a12b35989220a0351fe2566254fb91d5b947b523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 13:10:58 +0200 Subject: [PATCH 386/495] [Workflow] Fixed Guard Listener usage of RoleHierarchyInterface --- .../Component/Workflow/EventListener/GuardListener.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Workflow/EventListener/GuardListener.php b/src/Symfony/Component/Workflow/EventListener/GuardListener.php index a1795b8f47b02..669d394a43f9d 100644 --- a/src/Symfony/Component/Workflow/EventListener/GuardListener.php +++ b/src/Symfony/Component/Workflow/EventListener/GuardListener.php @@ -97,10 +97,10 @@ private function getVariables(GuardEvent $event): array } if (null !== $this->roleHierarchy && method_exists($this->roleHierarchy, 'getReachableRoleNames')) { - $roleNames = $this->roleHierarchy->getReachableRoleNames($roles); + $roleNames = $this->roleHierarchy->getReachableRoleNames($roleNames); $roles = array_map(function (string $role) { return new Role($role, false); }, $roleNames); } elseif (null !== $this->roleHierarchy) { - $roles = $this->roleHierarchy->getReachableRoles($token->getRoles(false)); + $roles = $this->roleHierarchy->getReachableRoles($roles); $roleNames = array_map(function (Role $role) { return $role->getRole(); }, $roles); } From 76fd9c35b70db958370da39d88a0d7bd278a8b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 12:03:51 +0200 Subject: [PATCH 387/495] [Workflow] Fixed initial places when no places are configured I introduced a BC break in #30468 and this PR fix it. With the full stack framework, when one does not configure the initial_place(s) the DIC set `[]` for the initial values. So it removes the initials values guessed in `Definition::addPlace()` --- src/Symfony/Component/Workflow/Definition.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index dd0c0626cf785..1ecbc0dfb56e0 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -94,7 +94,7 @@ public function getMetadataStore(): MetadataStoreInterface private function setInitialPlaces($places = null) { - if (null === $places) { + if (!$places) { return; } From a515635f18bab7f9f84def7abe71f427d579399c Mon Sep 17 00:00:00 2001 From: Samuel ROZE <samuel.roze@gmail.com> Date: Sat, 6 Apr 2019 11:43:17 +0200 Subject: [PATCH 388/495] Simply code and rename "configuration" to "options" --- src/Symfony/Component/Messenger/CHANGELOG.md | 9 ++- .../Transport/AmqpExt/AmqpReceiver.php | 21 +++--- .../Transport/AmqpExt/Connection.php | 72 ++++++++----------- 3 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index c2a30754cd5fb..20a8fff7b4b5c 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -19,8 +19,12 @@ CHANGELOG * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to explicitly handle messages synchronously. * Added `AmqpRoutingKeyStamp` allowing to provide a routing key on message publishing. - * Removed publishing with a `routing_key` option from queue configuration, for + * [BC BREAK] Removed publishing with a `routing_key` option from queue configuration, for AMQP. Use exchange `default_publish_routing_key` or `AmqpRoutingKeyStamp` instead. + * [BC BREAK] Changed the `queue` option in the AMQP transport DSN to be `queues[name]`. You can + therefore name the queue but also configure `binding_keys`, `flags` and `arguments`. + * [BC BREAK] The methods `get`, `ack`, `nack` and `queue` of the AMQP `Connection` + have a new argument: the queue name. * Added optional parameter `prefetch_count` in connection configuration, to setup channel prefetch count. * New classes: `RoutableMessageBus`, `AddBusNameStampMiddleware` @@ -74,8 +78,7 @@ CHANGELOG only. Pass the `auto_setup` connection option to control this. * Added a `SetupTransportsCommand` command to setup the transports * Added a Doctrine transport. For example, use the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) - * Added `AmqpRoutingKeyStamp` allowing to provide a routing key on message publishing. - * Deprecated publishing with a routing key from queue configuration, use exchange configuration instead. + * [BC BREAK] The `getConnectionConfiguration` method on Amqp's `Connection` has been removed. 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php index 43cfaa814ecf9..5bc0324489e64 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpReceiver.php @@ -81,10 +81,11 @@ private function getEnvelope(string $queueName): iterable public function ack(Envelope $envelope): void { try { - /* @var AmqpReceivedStamp $amqpReceivedStamp */ + $stamp = $this->findAmqpStamp($envelope); + $this->connection->ack( - $this->findAmqpEnvelope($envelope, $amqpReceivedStamp), - $amqpReceivedStamp->getQueueName() + $stamp->getAmqpEnvelope(), + $stamp->getQueueName() ); } catch (\AMQPException $exception) { throw new TransportException($exception->getMessage(), 0, $exception); @@ -96,10 +97,11 @@ public function ack(Envelope $envelope): void */ public function reject(Envelope $envelope): void { - /* @var AmqpReceivedStamp $amqpReceivedStamp */ + $stamp = $this->findAmqpStamp($envelope); + $this->rejectAmqpEnvelope( - $this->findAmqpEnvelope($envelope, $amqpReceivedStamp), - $amqpReceivedStamp->getQueueName() + $stamp->getAmqpEnvelope(), + $stamp->getQueueName() ); } @@ -120,14 +122,13 @@ private function rejectAmqpEnvelope(\AMQPEnvelope $amqpEnvelope, string $queueNa } } - private function findAmqpEnvelope(Envelope $envelope, AmqpReceivedStamp &$amqpReceivedStamp = null): \AMQPEnvelope + private function findAmqpStamp(Envelope $envelope): AmqpReceivedStamp { $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class); - if (null === $amqpReceivedStamp) { - throw new LogicException('No AmqpReceivedStamp found on the Envelope.'); + throw new LogicException('No "AmqpReceivedStamp" stamp found on the Envelope.'); } - return $amqpReceivedStamp->getAmqpEnvelope(); + return $amqpReceivedStamp; } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 50d5d35a12132..1c7a33430bb9f 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -33,9 +33,9 @@ class Connection 'x-message-ttl', ]; - private $connectionConfiguration; - private $exchangeConfiguration; - private $queuesConfiguration; + private $connectionOptions; + private $exchangeOptions; + private $queuesOptions; private $amqpFactory; /** @@ -86,17 +86,17 @@ class Connection * * loop_sleep: Amount of micro-seconds to wait if no message are available (Default: 200000) * * prefetch_count: set channel prefetch count */ - public function __construct(array $connectionConfiguration, array $exchangeConfiguration, array $queuesConfiguration, AmqpFactory $amqpFactory = null) + public function __construct(array $connectionOptions, array $exchangeOptions, array $queuesOptions, AmqpFactory $amqpFactory = null) { - $this->connectionConfiguration = array_replace_recursive([ + $this->connectionOptions = array_replace_recursive([ 'delay' => [ 'routing_key_pattern' => 'delay_%delay%', 'exchange_name' => 'delay', 'queue_name_pattern' => 'delay_queue_%delay%', ], - ], $connectionConfiguration); - $this->exchangeConfiguration = $exchangeConfiguration; - $this->queuesConfiguration = $queuesConfiguration; + ], $connectionOptions); + $this->exchangeOptions = $exchangeOptions; + $this->queuesOptions = $queuesOptions; $this->amqpFactory = $amqpFactory ?: new AmqpFactory(); } @@ -183,8 +183,6 @@ public function publish(string $body, array $headers = [], int $delay = 0, strin $this->setup(); } - // TODO - allow flag & attributes to be configured on the message - $this->exchange()->publish( $body, $routingKey ?? $this->getDefaultPublishRoutingKey(), @@ -214,8 +212,6 @@ private function publishWithDelay(string $body, array $headers, int $delay, ?str $this->setupDelay($delay, $exchangeRoutingKey); } - // TODO - allow flag & attributes to be configured on the message - $this->getDelayExchange()->publish( $body, $this->getRoutingKeyForDelay($delay), @@ -244,7 +240,7 @@ private function getDelayExchange(): \AMQPExchange { if (null === $this->amqpDelayExchange) { $this->amqpDelayExchange = $this->amqpFactory->createExchange($this->channel()); - $this->amqpDelayExchange->setName($this->connectionConfiguration['delay']['exchange_name']); + $this->amqpDelayExchange->setName($this->connectionOptions['delay']['exchange_name']); $this->amqpDelayExchange->setType(AMQP_EX_TYPE_DIRECT); } @@ -262,10 +258,8 @@ private function getDelayExchange(): \AMQPExchange */ private function createDelayQueue(int $delay, ?string $routingKey) { - $delayConfiguration = $this->connectionConfiguration['delay']; - $queue = $this->amqpFactory->createQueue($this->channel()); - $queue->setName(str_replace('%delay%', $delay, $delayConfiguration['queue_name_pattern'])); + $queue->setName(str_replace('%delay%', $delay, $this->connectionOptions['delay']['queue_name_pattern'])); $queue->setArguments([ 'x-message-ttl' => $delay, 'x-dead-letter-exchange' => $this->exchange()->getName(), @@ -282,7 +276,7 @@ private function createDelayQueue(int $delay, ?string $routingKey) private function getRoutingKeyForDelay(int $delay): string { - return str_replace('%delay%', $delay, $this->connectionConfiguration['delay']['routing_key_pattern']); + return str_replace('%delay%', $delay, $this->connectionOptions['delay']['routing_key_pattern']); } /** @@ -332,7 +326,7 @@ public function setup(): void $this->exchange()->declareExchange(); - foreach ($this->queuesConfiguration as $queueName => $queueConfig) { + foreach ($this->queuesOptions as $queueName => $queueConfig) { $this->queue($queueName)->declareQueue(); foreach ($queueConfig['binding_keys'] ?? [null] as $bindingKey) { $this->queue($queueName)->bind($this->exchange()->getName(), $bindingKey); @@ -345,40 +339,37 @@ public function setup(): void */ public function getQueueNames(): array { - return array_keys($this->queuesConfiguration); + return array_keys($this->queuesOptions); } - /** - * @internal - */ public function channel(): \AMQPChannel { if (null === $this->amqpChannel) { - $connection = $this->amqpFactory->createConnection($this->connectionConfiguration); - $connectMethod = 'true' === ($this->connectionConfiguration['persistent'] ?? 'false') ? 'pconnect' : 'connect'; + $connection = $this->amqpFactory->createConnection($this->connectionOptions); + $connectMethod = 'true' === ($this->connectionOptions['persistent'] ?? 'false') ? 'pconnect' : 'connect'; try { $connection->{$connectMethod}(); } catch (\AMQPConnectionException $e) { - $credentials = $this->connectionConfiguration; + $credentials = $this->connectionOptions; $credentials['password'] = '********'; throw new \AMQPException(sprintf('Could not connect to the AMQP server. Please verify the provided DSN. (%s)', json_encode($credentials)), 0, $e); } $this->amqpChannel = $this->amqpFactory->createChannel($connection); - if (isset($this->connectionConfiguration['prefetch_count'])) { - $this->amqpChannel->setPrefetchCount($this->connectionConfiguration['prefetch_count']); + if (isset($this->connectionOptions['prefetch_count'])) { + $this->amqpChannel->setPrefetchCount($this->connectionOptions['prefetch_count']); } } return $this->amqpChannel; } - private function queue(string $queueName): \AMQPQueue + public function queue(string $queueName): \AMQPQueue { if (!isset($this->amqpQueues[$queueName])) { - $queueConfig = $this->queuesConfiguration[$queueName]; + $queueConfig = $this->queuesOptions[$queueName]; $amqpQueue = $this->amqpFactory->createQueue($this->channel()); $amqpQueue->setName($queueName); @@ -394,27 +385,22 @@ private function queue(string $queueName): \AMQPQueue return $this->amqpQueues[$queueName]; } - private function exchange(): \AMQPExchange + public function exchange(): \AMQPExchange { if (null === $this->amqpExchange) { $this->amqpExchange = $this->amqpFactory->createExchange($this->channel()); - $this->amqpExchange->setName($this->exchangeConfiguration['name']); - $this->amqpExchange->setType($this->exchangeConfiguration['type'] ?? AMQP_EX_TYPE_FANOUT); - $this->amqpExchange->setFlags($this->exchangeConfiguration['flags'] ?? AMQP_DURABLE); + $this->amqpExchange->setName($this->exchangeOptions['name']); + $this->amqpExchange->setType($this->exchangeOptions['type'] ?? AMQP_EX_TYPE_FANOUT); + $this->amqpExchange->setFlags($this->exchangeOptions['flags'] ?? AMQP_DURABLE); - if (isset($this->exchangeConfiguration['arguments'])) { - $this->amqpExchange->setArguments($this->exchangeConfiguration['arguments']); + if (isset($this->exchangeOptions['arguments'])) { + $this->amqpExchange->setArguments($this->exchangeOptions['arguments']); } } return $this->amqpExchange; } - public function getConnectionConfiguration(): array - { - return $this->connectionConfiguration; - } - private function clear(): void { $this->amqpChannel = null; @@ -424,11 +410,11 @@ private function clear(): void private function shouldSetup(): bool { - if (!\array_key_exists('auto_setup', $this->connectionConfiguration)) { + if (!\array_key_exists('auto_setup', $this->connectionOptions)) { return true; } - if (\in_array($this->connectionConfiguration['auto_setup'], [false, 'false'], true)) { + if (\in_array($this->connectionOptions['auto_setup'], [false, 'false'], true)) { return false; } @@ -437,7 +423,7 @@ private function shouldSetup(): bool private function getDefaultPublishRoutingKey(): ?string { - return $this->exchangeConfiguration['default_publish_routing_key'] ?? null; + return $this->exchangeOptions['default_publish_routing_key'] ?? null; } public function purgeQueues() From e6e4cde5fcb176de989a7526088ae9fc75bd1312 Mon Sep 17 00:00:00 2001 From: Jonas Elfering <jonas.elfering@web.de> Date: Tue, 29 Jan 2019 14:21:02 +0100 Subject: [PATCH 389/495] Ensure message is handled only once per handler Add check to ensure that a message is only handled once per handler Add try...catch to run all handlers before throwing exception --- .../ChainedHandlerFailedException.php | 61 +++++++++++++++++ .../Middleware/HandleMessageMiddleware.php | 33 +++++++++- .../Messenger/Stamp/HandledStamp.php | 21 +++--- .../MessageHandlerFailingFirstTimes.php | 39 +++++++++++ .../HandleMessageMiddlewareTest.php | 38 +++++++++-- .../Messenger/Tests/RetryIntegrationTest.php | 65 +++++++++++++++++++ src/Symfony/Component/Messenger/Worker.php | 5 ++ 7 files changed, 246 insertions(+), 16 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php create mode 100644 src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php create mode 100644 src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php diff --git a/src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php b/src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php new file mode 100644 index 0000000000000..e8f360dd85d7a --- /dev/null +++ b/src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php @@ -0,0 +1,61 @@ +<?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. + */ + +declare(strict_types=1); + +namespace Symfony\Component\Messenger\Exception; + +use Symfony\Component\Messenger\Envelope; + +class ChainedHandlerFailedException extends \RuntimeException implements ExceptionInterface +{ + /** + * @var \Throwable[] + */ + private $nested; + + /** + * @var Envelope + */ + private $envelope; + + public function __construct(Envelope $envelope, \Throwable ...$nested) + { + parent::__construct($this->constructMessage($nested)); + $this->envelope = $envelope; + $this->nested = $nested; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + /** + * @return \Throwable[] + */ + public function getNestedExceptions(): array + { + return $this->nested; + } + + /** + * @param \Throwable[] $nested + * + * @return string + */ + private function constructMessage(array $nested): string + { + return 1 === \count($nested) ? + $nested[0]->getMessage() : + sprintf('%d MessageHandler failed. First one failed with Message: %s', \count($nested), $nested[0]->getMessage()); + } +} diff --git a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php index ed47ac6389128..c0662ec2915c9 100644 --- a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\ChainedHandlerFailedException; use Symfony\Component\Messenger\Exception\NoHandlerForMessageException; use Symfony\Component\Messenger\Handler\HandlersLocatorInterface; use Symfony\Component\Messenger\Stamp\HandledStamp; @@ -52,10 +53,21 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope 'class' => \get_class($message), ]; + $exceptions = []; foreach ($this->handlersLocator->getHandlers($envelope) as $alias => $handler) { - $handledStamp = HandledStamp::fromCallable($handler, $handler($message), \is_string($alias) ? $alias : null); - $envelope = $envelope->with($handledStamp); - $this->logger->info('Message "{class}" handled by "{handler}"', $context + ['handler' => $handledStamp->getCallableName()]); + $alias = \is_string($alias) ? $alias : null; + + if ($this->messageHasAlreadyBeenHandled($envelope, $handler, $alias)) { + continue; + } + + try { + $handledStamp = HandledStamp::fromCallable($handler, $handler($message), $alias); + $envelope = $envelope->with($handledStamp); + $this->logger->info('Message "{class}" handled by "{handler}"', $context + ['handler' => $handledStamp->getCallableName()]); + } catch (\Throwable $e) { + $exceptions[] = $e; + } } if (null === $handler) { @@ -66,6 +78,21 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope $this->logger->info('No handler for message "{class}"', $context); } + if (\count($exceptions)) { + throw new ChainedHandlerFailedException($envelope, ...$exceptions); + } + return $stack->next()->handle($envelope, $stack); } + + private function messageHasAlreadyBeenHandled(Envelope $envelope, callable $handler, ?string $alias): bool + { + $some = array_filter($envelope + ->all(HandledStamp::class), function (HandledStamp $stamp) use ($handler, $alias) { + return $stamp->getCallableName() === HandledStamp::getNameFromCallable($handler) && + $stamp->getHandlerAlias() === $alias; + }); + + return \count($some) > 0; + } } diff --git a/src/Symfony/Component/Messenger/Stamp/HandledStamp.php b/src/Symfony/Component/Messenger/Stamp/HandledStamp.php index 0cd480765ecb8..491aa64472ebd 100644 --- a/src/Symfony/Component/Messenger/Stamp/HandledStamp.php +++ b/src/Symfony/Component/Messenger/Stamp/HandledStamp.php @@ -40,33 +40,38 @@ public function __construct($result, string $callableName, string $handlerAlias /** * @param mixed $result The returned value of the message handler */ - public static function fromCallable(callable $handler, $result, string $handlerAlias = null): self + public static function fromCallable(callable $handler, $result, ?string $handlerAlias = null): self + { + return new self($result, self::getNameFromCallable($handler), $handlerAlias); + } + + public static function getNameFromCallable(callable $handler): string { if (\is_array($handler)) { if (\is_object($handler[0])) { - return new self($result, \get_class($handler[0]).'::'.$handler[1], $handlerAlias); + return \get_class($handler[0]).'::'.$handler[1]; } - return new self($result, $handler[0].'::'.$handler[1], $handlerAlias); + return $handler[0].'::'.$handler[1]; } if (\is_string($handler)) { - return new self($result, $handler, $handlerAlias); + return $handler; } if ($handler instanceof \Closure) { $r = new \ReflectionFunction($handler); if (false !== strpos($r->name, '{closure}')) { - return new self($result, 'Closure', $handlerAlias); + return 'Closure'; } if ($class = $r->getClosureScopeClass()) { - return new self($result, $class->name.'::'.$r->name, $handlerAlias); + return $class->name.'::'.$r->name; } - return new self($result, $r->name, $handlerAlias); + return $r->name; } - return new self($result, \get_class($handler).'::__invoke', $handlerAlias); + return \get_class($handler).'::__invoke'; } /** diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php b/src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php new file mode 100644 index 0000000000000..d315cb0836206 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php @@ -0,0 +1,39 @@ +<?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\Component\Messenger\Tests\Fixtures; + +class MessageHandlerFailingFirstTimes +{ + private $remainingFailures; + + private $called = 0; + + public function __construct(int $throwExceptionOnFirstTries = 0) + { + $this->remainingFailures = $throwExceptionOnFirstTries; + } + + public function __invoke(DummyMessage $message) + { + if ($this->remainingFailures > 0) { + --$this->remainingFailures; + throw new \Exception('Handler should throw Exception.'); + } + + ++$this->called; + } + + public function getTimesCalledWithoutThrowing(): int + { + return $this->called; + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php index 953124fb9b77d..20b8667f4ed5c 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Tests\Middleware; use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Exception\ChainedHandlerFailedException; use Symfony\Component\Messenger\Handler\HandlersLocator; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; use Symfony\Component\Messenger\Middleware\StackMiddleware; @@ -40,7 +41,7 @@ public function testItCallsTheHandlerAndNextMiddleware() /** * @dataProvider itAddsHandledStampsProvider */ - public function testItAddsHandledStamps(array $handlers, array $expectedStamps) + public function testItAddsHandledStamps(array $handlers, array $expectedStamps, bool $nextIsCalled) { $message = new DummyMessage('Hey'); $envelope = new Envelope($message); @@ -49,7 +50,11 @@ public function testItAddsHandledStamps(array $handlers, array $expectedStamps) DummyMessage::class => $handlers, ])); - $envelope = $middleware->handle($envelope, $this->getStackMock()); + try { + $envelope = $middleware->handle($envelope, $this->getStackMock($nextIsCalled)); + } catch (ChainedHandlerFailedException $e) { + $envelope = $e->getEnvelope(); + } $this->assertEquals($expectedStamps, $envelope->all(HandledStamp::class)); } @@ -64,17 +69,22 @@ public function itAddsHandledStampsProvider() $second->method('__invoke')->willReturn(null); $secondClass = \get_class($second); + $failing = $this->createPartialMock(\stdClass::class, ['__invoke']); + $failing->method('__invoke')->will($this->throwException(new \Exception('handler failed.'))); + yield 'A stamp is added' => [ [$first], [new HandledStamp('first result', $firstClass.'::__invoke')], + true, ]; yield 'A stamp is added per handler' => [ - [$first, $second], + ['first' => $first, 'second' => $second], [ - new HandledStamp('first result', $firstClass.'::__invoke'), - new HandledStamp(null, $secondClass.'::__invoke'), + new HandledStamp('first result', $firstClass.'::__invoke', 'first'), + new HandledStamp(null, $secondClass.'::__invoke', 'second'), ], + true, ]; yield 'Yielded locator alias is used' => [ @@ -83,6 +93,24 @@ public function itAddsHandledStampsProvider() new HandledStamp('first result', $firstClass.'::__invoke', 'first_alias'), new HandledStamp(null, $secondClass.'::__invoke'), ], + true, + ]; + + yield 'It tries all handlers' => [ + ['first' => $first, 'failing' => $failing, 'second' => $second], + [ + new HandledStamp('first result', $firstClass.'::__invoke', 'first'), + new HandledStamp(null, $secondClass.'::__invoke', 'second'), + ], + false, + ]; + + yield 'It ignores duplicated handler' => [ + [$first, $first], + [ + new HandledStamp('first result', $firstClass.'::__invoke'), + ], + true, ]; } diff --git a/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php new file mode 100644 index 0000000000000..136642885b6e6 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php @@ -0,0 +1,65 @@ +<?php + +declare(strict_types=1); + +/* + * 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\Component\Messenger\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\Handler\HandlersLocator; +use Symfony\Component\Messenger\MessageBus; +use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; +use Symfony\Component\Messenger\Middleware\SendMessageMiddleware; +use Symfony\Component\Messenger\Retry\MultiplierRetryStrategy; +use Symfony\Component\Messenger\Stamp\SentStamp; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; +use Symfony\Component\Messenger\Tests\Fixtures\MessageHandlerFailingFirstTimes; +use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; +use Symfony\Component\Messenger\Transport\Sender\SendersLocator; +use Symfony\Component\Messenger\Worker; + +class RetryIntegrationTest extends TestCase +{ + public function testRetryMechanism() + { + $apiMessage = new DummyMessage('API'); + + $receiver = $this->createMock(ReceiverInterface::class); + $receiver->method('get') + ->willReturn([ + new Envelope($apiMessage, [ + new SentStamp('Some\Sender', 'sender_alias'), + ]), + ]); + + $senderLocator = new SendersLocator([], ['*' => true]); + + $handler = new MessageHandlerFailingFirstTimes(); + $throwingHandler = new MessageHandlerFailingFirstTimes(1); + $handlerLocator = new HandlersLocator([ + DummyMessage::class => [ + 'handler' => $handler, + 'throwing' => $throwingHandler, + ], + ]); + + $bus = new MessageBus([new SendMessageMiddleware($senderLocator), new HandleMessageMiddleware($handlerLocator)]); + + $worker = new Worker(['receiverName' => $receiver], $bus, ['receiverName' => new MultiplierRetryStrategy()]); + $worker->run([], function () use ($worker) { + $worker->stop(); + }); + + $this->assertSame(1, $handler->getTimesCalledWithoutThrowing()); + $this->assertSame(1, $throwingHandler->getTimesCalledWithoutThrowing()); + } +} diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index 1e7f539f6ce40..ee10a2ee71aaf 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -15,6 +15,7 @@ use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; +use Symfony\Component\Messenger\Exception\ChainedHandlerFailedException; use Symfony\Component\Messenger\Exception\LogicException; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; use Symfony\Component\Messenger\Retry\RetryStrategyInterface; @@ -123,6 +124,10 @@ private function handleMessage(Envelope $envelope, ReceiverInterface $receiver, try { $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp())); } catch (\Throwable $throwable) { + if ($throwable instanceof ChainedHandlerFailedException) { + $envelope = $throwable->getEnvelope(); + } + $shouldRetry = $this->shouldRetry($throwable, $envelope, $retryStrategy); $this->dispatchEvent(new WorkerMessageFailedEvent($envelope, $receiverName, $throwable, $shouldRetry)); From 2e5e910229808c94bec147820701c763d2ad41bd Mon Sep 17 00:00:00 2001 From: Samuel ROZE <samuel.roze@gmail.com> Date: Sat, 6 Apr 2019 12:33:50 +0200 Subject: [PATCH 390/495] Rename exception, add change log and a few other things --- src/Symfony/Component/Messenger/CHANGELOG.md | 1 + .../ChainedHandlerFailedException.php | 61 ------------------- .../Exception/HandlerFailedException.php | 52 ++++++++++++++++ .../Middleware/HandleMessageMiddleware.php | 4 +- ... DummyMessageHandlerFailingFirstTimes.php} | 2 +- .../HandleMessageMiddlewareTest.php | 4 +- .../Messenger/Tests/RetryIntegrationTest.php | 8 +-- src/Symfony/Component/Messenger/Worker.php | 4 +- 8 files changed, 63 insertions(+), 73 deletions(-) delete mode 100644 src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php create mode 100644 src/Symfony/Component/Messenger/Exception/HandlerFailedException.php rename src/Symfony/Component/Messenger/Tests/Fixtures/{MessageHandlerFailingFirstTimes.php => DummyMessageHandlerFailingFirstTimes.php} (95%) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 20a8fff7b4b5c..03b4864520d4d 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -79,6 +79,7 @@ CHANGELOG * Added a `SetupTransportsCommand` command to setup the transports * Added a Doctrine transport. For example, use the `doctrine://default` DSN (this uses the `default` Doctrine entity manager) * [BC BREAK] The `getConnectionConfiguration` method on Amqp's `Connection` has been removed. + * [BC BREAK] A `HandlerFailedException` exception will be thrown if one or more handler fails. 4.2.0 ----- diff --git a/src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php b/src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php deleted file mode 100644 index e8f360dd85d7a..0000000000000 --- a/src/Symfony/Component/Messenger/Exception/ChainedHandlerFailedException.php +++ /dev/null @@ -1,61 +0,0 @@ -<?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. - */ - -declare(strict_types=1); - -namespace Symfony\Component\Messenger\Exception; - -use Symfony\Component\Messenger\Envelope; - -class ChainedHandlerFailedException extends \RuntimeException implements ExceptionInterface -{ - /** - * @var \Throwable[] - */ - private $nested; - - /** - * @var Envelope - */ - private $envelope; - - public function __construct(Envelope $envelope, \Throwable ...$nested) - { - parent::__construct($this->constructMessage($nested)); - $this->envelope = $envelope; - $this->nested = $nested; - } - - public function getEnvelope(): Envelope - { - return $this->envelope; - } - - /** - * @return \Throwable[] - */ - public function getNestedExceptions(): array - { - return $this->nested; - } - - /** - * @param \Throwable[] $nested - * - * @return string - */ - private function constructMessage(array $nested): string - { - return 1 === \count($nested) ? - $nested[0]->getMessage() : - sprintf('%d MessageHandler failed. First one failed with Message: %s', \count($nested), $nested[0]->getMessage()); - } -} diff --git a/src/Symfony/Component/Messenger/Exception/HandlerFailedException.php b/src/Symfony/Component/Messenger/Exception/HandlerFailedException.php new file mode 100644 index 0000000000000..d0abb7cd4f156 --- /dev/null +++ b/src/Symfony/Component/Messenger/Exception/HandlerFailedException.php @@ -0,0 +1,52 @@ +<?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\Component\Messenger\Exception; + +use Symfony\Component\Messenger\Envelope; + +class HandlerFailedException extends RuntimeException +{ + private $exceptions; + private $envelope; + + /** + * @param \Throwable[] $exceptions + */ + public function __construct(Envelope $envelope, array $exceptions) + { + $firstFailure = current($exceptions); + + parent::__construct( + 1 === \count($exceptions) + ? $firstFailure->getMessage() + : sprintf('%d handlers failed. First failure is: "%s"', \count($exceptions), $firstFailure->getMessage()), + $firstFailure->getCode(), + $firstFailure + ); + + $this->envelope = $envelope; + $this->exceptions = $exceptions; + } + + public function getEnvelope(): Envelope + { + return $this->envelope; + } + + /** + * @return \Throwable[] + */ + public function getNestedExceptions(): array + { + return $this->exceptions; + } +} diff --git a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php index c0662ec2915c9..4fc8f6dfcfdd0 100644 --- a/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/HandleMessageMiddleware.php @@ -14,7 +14,7 @@ use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\ChainedHandlerFailedException; +use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\Exception\NoHandlerForMessageException; use Symfony\Component\Messenger\Handler\HandlersLocatorInterface; use Symfony\Component\Messenger\Stamp\HandledStamp; @@ -79,7 +79,7 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope } if (\count($exceptions)) { - throw new ChainedHandlerFailedException($envelope, ...$exceptions); + throw new HandlerFailedException($envelope, $exceptions); } return $stack->next()->handle($envelope, $stack); diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageHandlerFailingFirstTimes.php similarity index 95% rename from src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php rename to src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageHandlerFailingFirstTimes.php index d315cb0836206..2e9744538473c 100644 --- a/src/Symfony/Component/Messenger/Tests/Fixtures/MessageHandlerFailingFirstTimes.php +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/DummyMessageHandlerFailingFirstTimes.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Messenger\Tests\Fixtures; -class MessageHandlerFailingFirstTimes +class DummyMessageHandlerFailingFirstTimes { private $remainingFailures; diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php index 20b8667f4ed5c..cd15957f1b0f2 100644 --- a/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php +++ b/src/Symfony/Component/Messenger/Tests/Middleware/HandleMessageMiddlewareTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Messenger\Tests\Middleware; use Symfony\Component\Messenger\Envelope; -use Symfony\Component\Messenger\Exception\ChainedHandlerFailedException; +use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\Handler\HandlersLocator; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; use Symfony\Component\Messenger\Middleware\StackMiddleware; @@ -52,7 +52,7 @@ public function testItAddsHandledStamps(array $handlers, array $expectedStamps, try { $envelope = $middleware->handle($envelope, $this->getStackMock($nextIsCalled)); - } catch (ChainedHandlerFailedException $e) { + } catch (HandlerFailedException $e) { $envelope = $e->getEnvelope(); } diff --git a/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php index 136642885b6e6..00346bbc703c2 100644 --- a/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/RetryIntegrationTest.php @@ -1,7 +1,5 @@ <?php -declare(strict_types=1); - /* * This file is part of the Symfony package. * @@ -22,7 +20,7 @@ use Symfony\Component\Messenger\Retry\MultiplierRetryStrategy; use Symfony\Component\Messenger\Stamp\SentStamp; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -use Symfony\Component\Messenger\Tests\Fixtures\MessageHandlerFailingFirstTimes; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessageHandlerFailingFirstTimes; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; use Symfony\Component\Messenger\Transport\Sender\SendersLocator; use Symfony\Component\Messenger\Worker; @@ -43,8 +41,8 @@ public function testRetryMechanism() $senderLocator = new SendersLocator([], ['*' => true]); - $handler = new MessageHandlerFailingFirstTimes(); - $throwingHandler = new MessageHandlerFailingFirstTimes(1); + $handler = new DummyMessageHandlerFailingFirstTimes(); + $throwingHandler = new DummyMessageHandlerFailingFirstTimes(1); $handlerLocator = new HandlersLocator([ DummyMessage::class => [ 'handler' => $handler, diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index ee10a2ee71aaf..39fa5a910bd8c 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -15,7 +15,7 @@ use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent; use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent; use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent; -use Symfony\Component\Messenger\Exception\ChainedHandlerFailedException; +use Symfony\Component\Messenger\Exception\HandlerFailedException; use Symfony\Component\Messenger\Exception\LogicException; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; use Symfony\Component\Messenger\Retry\RetryStrategyInterface; @@ -124,7 +124,7 @@ private function handleMessage(Envelope $envelope, ReceiverInterface $receiver, try { $envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp())); } catch (\Throwable $throwable) { - if ($throwable instanceof ChainedHandlerFailedException) { + if ($throwable instanceof HandlerFailedException) { $envelope = $throwable->getEnvelope(); } From c336696a0681214238c6196f71fce81cac42d6f1 Mon Sep 17 00:00:00 2001 From: Dmytro <bbbara10@gmail.com> Date: Wed, 13 Mar 2019 13:58:13 +0200 Subject: [PATCH 391/495] [PropertyAccess] Allow to disable exception on invalid property path when using PropertyAccess::getValue() --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../DependencyInjection/Configuration.php | 1 + .../FrameworkExtension.php | 1 + .../Resources/config/property_access.xml | 1 + .../Resources/config/schema/symfony-1.0.xsd | 1 + .../DependencyInjection/ConfigurationTest.php | 1 + .../Fixtures/php/property_accessor.php | 1 + .../Fixtures/xml/property_accessor.xml | 2 +- .../Fixtures/yml/property_accessor.yml | 1 + .../FrameworkExtensionTest.php | 2 + .../Component/PropertyAccess/CHANGELOG.md | 7 ++++ .../PropertyAccess/PropertyAccessor.php | 19 +++++---- .../PropertyAccessorBuilder.php | 40 ++++++++++++++++++- .../Tests/PropertyAccessorTest.php | 30 ++++++++++++++ 14 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 981823fd07f10..79aded380fe3c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -30,6 +30,7 @@ CHANGELOG * Added support for boolean container parameters within routes. * Added the `messenger:setup-transports` command to setup messenger transports * Added a `InMemoryTransport` to Messenger. Use it with a DSN starting with `in-memory://`. + * Added `framework.property_access.throw_exception_on_invalid_property_path` config option. 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 076a70c818768..698ef88e021f4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -903,6 +903,7 @@ private function addPropertyAccessSection(ArrayNodeDefinition $rootNode) ->children() ->booleanNode('magic_call')->defaultFalse()->end() ->booleanNode('throw_exception_on_invalid_index')->defaultFalse()->end() + ->booleanNode('throw_exception_on_invalid_property_path')->defaultTrue()->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 5ef5ed7b5d269..afca88af956d5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1361,6 +1361,7 @@ private function registerPropertyAccessConfiguration(array $config, ContainerBui ->getDefinition('property_accessor') ->replaceArgument(0, $config['magic_call']) ->replaceArgument(1, $config['throw_exception_on_invalid_index']) + ->replaceArgument(3, $config['throw_exception_on_invalid_property_path']) ; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml index 4fb4f2ff98abc..424f9f682d796 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_access.xml @@ -11,6 +11,7 @@ <argument /> <!-- magicCall, set by the extension --> <argument /> <!-- throwExceptionOnInvalidIndex, set by the extension --> <argument type="service" id="cache.property_access" on-invalid="ignore" /> + <argument /> <!-- throwExceptionOnInvalidPropertyPath, set by the extension --> </service> <service id="Symfony\Component\PropertyAccess\PropertyAccessorInterface" alias="property_accessor" /> </services> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 38e60f6516846..5a807403a01ad 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -233,6 +233,7 @@ <xsd:complexType name="property_access"> <xsd:attribute name="magic-call" type="xsd:boolean" /> <xsd:attribute name="throw-exception-on-invalid-index" type="xsd:boolean" /> + <xsd:attribute name="throw-exception-on-invalid-property-path" type="xsd:boolean" /> </xsd:complexType> <xsd:complexType name="serializer"> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index aa0a2fc921853..a9d7d0a63bf6c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -249,6 +249,7 @@ protected static function getBundleDefaultConfig() 'property_access' => [ 'magic_call' => false, 'throw_exception_on_invalid_index' => false, + 'throw_exception_on_invalid_property_path' => true, ], 'property_info' => [ 'enabled' => !class_exists(FullStack::class), diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php index b5b060c1baa43..8f431f8735d89 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/property_accessor.php @@ -4,5 +4,6 @@ 'property_access' => [ 'magic_call' => true, 'throw_exception_on_invalid_index' => true, + 'throw_exception_on_invalid_property_path' => false, ], ]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml index 95ddef8288e38..07e33ae3e8d96 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/property_accessor.xml @@ -7,6 +7,6 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> - <framework:property-access magic-call="true" throw-exception-on-invalid-index="true" /> + <framework:property-access magic-call="true" throw-exception-on-invalid-index="true" throw-exception-on-invalid-property-path="false"/> </framework:config> </container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml index b5fd2718ab112..ea527c9821116 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/property_accessor.yml @@ -2,3 +2,4 @@ framework: property_access: magic_call: true throw_exception_on_invalid_index: true + throw_exception_on_invalid_property_path: false diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index acc7fbad156e7..1b8a785a303db 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -80,6 +80,7 @@ public function testPropertyAccessWithDefaultValue() $def = $container->getDefinition('property_accessor'); $this->assertFalse($def->getArgument(0)); $this->assertFalse($def->getArgument(1)); + $this->assertTrue($def->getArgument(3)); } public function testPropertyAccessWithOverriddenValues() @@ -88,6 +89,7 @@ public function testPropertyAccessWithOverriddenValues() $def = $container->getDefinition('property_accessor'); $this->assertTrue($def->getArgument(0)); $this->assertTrue($def->getArgument(1)); + $this->assertFalse($def->getArgument(3)); } public function testPropertyAccessCache() diff --git a/src/Symfony/Component/PropertyAccess/CHANGELOG.md b/src/Symfony/Component/PropertyAccess/CHANGELOG.md index 970f3545b5702..0a012bb47620d 100644 --- a/src/Symfony/Component/PropertyAccess/CHANGELOG.md +++ b/src/Symfony/Component/PropertyAccess/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +4.3.0 +----- + +* added a `$throwExceptionOnInvalidPropertyPath` argument to the PropertyAccessor constructor. +* added `enableExceptionOnInvalidPropertyPath()`, `disableExceptionOnInvalidPropertyPath()` and + `isExceptionOnInvalidPropertyPath()` methods to `PropertyAccessorBuilder` + 4.0.0 ----- diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index db9c6b84652ea..891cc5e75ea46 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -56,6 +56,7 @@ class PropertyAccessor implements PropertyAccessorInterface */ private $magicCall; private $ignoreInvalidIndices; + private $ignoreInvalidProperty; /** * @var CacheItemPoolInterface @@ -70,11 +71,12 @@ class PropertyAccessor implements PropertyAccessorInterface * Should not be used by application code. Use * {@link PropertyAccess::createPropertyAccessor()} instead. */ - public function __construct(bool $magicCall = false, bool $throwExceptionOnInvalidIndex = false, CacheItemPoolInterface $cacheItemPool = null) + public function __construct(bool $magicCall = false, bool $throwExceptionOnInvalidIndex = false, CacheItemPoolInterface $cacheItemPool = null, bool $throwExceptionOnInvalidPropertyPath = true) { $this->magicCall = $magicCall; $this->ignoreInvalidIndices = !$throwExceptionOnInvalidIndex; $this->cacheItemPool = $cacheItemPool instanceof NullAdapter ? null : $cacheItemPool; // Replace the NullAdapter by the null value + $this->ignoreInvalidProperty = !$throwExceptionOnInvalidPropertyPath; } /** @@ -87,7 +89,7 @@ public function getValue($objectOrArray, $propertyPath) ]; if (\is_object($objectOrArray) && false === strpbrk((string) $propertyPath, '.[')) { - return $this->readProperty($zval, $propertyPath)[self::VALUE]; + return $this->readProperty($zval, $propertyPath, $this->ignoreInvalidProperty)[self::VALUE]; } $propertyPath = $this->getPropertyPath($propertyPath); @@ -313,7 +315,7 @@ private function readPropertiesUntil($zval, PropertyPathInterface $propertyPath, $zval = $this->readIndex($zval, $property); } else { - $zval = $this->readProperty($zval, $property); + $zval = $this->readProperty($zval, $property, $this->ignoreInvalidProperty); } // the final value of the path must not be validated @@ -372,14 +374,15 @@ private function readIndex($zval, $index) /** * Reads the a property from an object. * - * @param array $zval The array containing the object to read from - * @param string $property The property to read + * @param array $zval The array containing the object to read from + * @param string $property The property to read + * @param bool $ignoreInvalidProperty Whether to ignore invalid property or throw an exception * * @return array The array containing the value of the property * - * @throws NoSuchPropertyException if the property does not exist or is not public + * @throws NoSuchPropertyException If $ignoreInvalidProperty is false and the property does not exist or is not public */ - private function readProperty($zval, $property) + private function readProperty($zval, $property, bool $ignoreInvalidProperty = false) { if (!\is_object($zval[self::VALUE])) { throw new NoSuchPropertyException(sprintf('Cannot read property "%s" from an array. Maybe you intended to write the property path as "[%1$s]" instead.', $property)); @@ -411,7 +414,7 @@ private function readProperty($zval, $property) } elseif (self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]) { // we call the getter and hope the __call do the job $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}(); - } else { + } elseif (!$ignoreInvalidProperty) { throw new NoSuchPropertyException($access[self::ACCESS_NAME]); } diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php b/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php index 1db6a1dba23ed..a300bdc6f5c36 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessorBuilder.php @@ -22,6 +22,7 @@ class PropertyAccessorBuilder { private $magicCall = false; private $throwExceptionOnInvalidIndex = false; + private $throwExceptionOnInvalidPropertyPath = true; /** * @var CacheItemPoolInterface|null @@ -97,6 +98,43 @@ public function isExceptionOnInvalidIndexEnabled() return $this->throwExceptionOnInvalidIndex; } + /** + * Enables exceptions when reading a non-existing property. + * + * This has no influence on writing non-existing indices with PropertyAccessorInterface::setValue() + * which are always created on-the-fly. + * + * @return $this + */ + public function enableExceptionOnInvalidPropertyPath() + { + $this->throwExceptionOnInvalidPropertyPath = true; + + return $this; + } + + /** + * Disables exceptions when reading a non-existing index. + * + * Instead, null is returned when calling PropertyAccessorInterface::getValue() on a non-existing index. + * + * @return $this + */ + public function disableExceptionOnInvalidPropertyPath() + { + $this->throwExceptionOnInvalidPropertyPath = false; + + return $this; + } + + /** + * @return bool whether an exception is thrown or null is returned when reading a non-existing property + */ + public function isExceptionOnInvalidPropertyPath() + { + return $this->throwExceptionOnInvalidPropertyPath; + } + /** * Sets a cache system. * @@ -128,6 +166,6 @@ public function getCacheItemPool() */ public function getPropertyAccessor() { - return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool); + return new PropertyAccessor($this->magicCall, $this->throwExceptionOnInvalidIndex, $this->cacheItemPool, $this->throwExceptionOnInvalidPropertyPath); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index 2a7dd8a83192b..d0cbccf1ec63c 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\PropertyAccess\Exception\NoSuchIndexException; +use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessor; use Symfony\Component\PropertyAccess\Tests\Fixtures\ReturnTyped; use Symfony\Component\PropertyAccess\Tests\Fixtures\TestClass; @@ -100,6 +101,16 @@ public function testGetValueThrowsExceptionIfPropertyNotFound($objectOrArray, $p $this->propertyAccessor->getValue($objectOrArray, $path); } + /** + * @dataProvider getPathsWithMissingProperty + */ + public function testGetValueReturnsNullIfPropertyNotFoundAndExceptionIsDisabled($objectOrArray, $path) + { + $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()->disableExceptionOnInvalidPropertyPath()->getPropertyAccessor(); + + $this->assertNull($this->propertyAccessor->getValue($objectOrArray, $path), $path); + } + /** * @dataProvider getPathsWithMissingIndex */ @@ -618,6 +629,25 @@ public function testAnonymousClassRead() $this->assertEquals($value, $propertyAccessor->getValue($obj, 'foo')); } + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException + */ + public function testAnonymousClassReadThrowExceptionOnInvalidPropertyPath() + { + $obj = $this->generateAnonymousClass('bar'); + + $this->propertyAccessor->getValue($obj, 'invalid_property'); + } + + public function testAnonymousClassReadReturnsNullOnInvalidPropertyWithDisabledException() + { + $obj = $this->generateAnonymousClass('bar'); + + $this->propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()->disableExceptionOnInvalidPropertyPath()->getPropertyAccessor(); + + $this->assertNull($this->propertyAccessor->getValue($obj, 'invalid_property')); + } + public function testAnonymousClassWrite() { $value = 'bar'; From 40f25121c3964a8ce72c05727d45954012a910f5 Mon Sep 17 00:00:00 2001 From: Thomas Calvet <calvet.thomas@gmail.com> Date: Thu, 2 Nov 2017 13:33:12 +0100 Subject: [PATCH 392/495] [DoctrineBridge] Add decimal form type --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 2 + .../Bridge/Doctrine/Form/Type/DecimalType.php | 57 +++++++++++ .../Bridge/Doctrine/Tests/Fixtures/Price.php | 36 +++++++ .../Tests/Form/Type/DecimalTypeTest.php | 96 +++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 49dfd9bfbce6e..78a2ba9510b2e 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -17,6 +17,7 @@ use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\MappingException as LegacyMappingException; +use Symfony\Bridge\Doctrine\Form\Type\DecimalType; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; @@ -75,6 +76,7 @@ public function guessType($class, $property) case 'time_immutable': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE); case Type::DECIMAL: + return new TypeGuess(DecimalType::class, array(), Guess::HIGH_CONFIDENCE); case Type::FLOAT: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE); case Type::INTEGER: diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php new file mode 100644 index 0000000000000..9956c3de10d33 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php @@ -0,0 +1,57 @@ +<?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\Bridge\Doctrine\Form\Type; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\FormBuilderInterface; + +class DecimalType extends AbstractType +{ + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->addModelTransformer(new CallbackTransformer(function ($value) { + if (null === $value) { + return null; + } + + if (!is_string($value)) { + throw new TransformationFailedException('Expected a string.'); + } + + return $value; + }, function ($value) { + if (null === $value) { + return null; + } + + if (!is_int($value) && !is_float($value)) { + throw new TransformationFailedException('Expected an int or a float.'); + } + + return (string) $value; + })); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return NumberType::class; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php new file mode 100644 index 0000000000000..bd7c645766af6 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php @@ -0,0 +1,36 @@ +<?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\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\ORM\Mapping\Entity; +use Doctrine\ORM\Mapping\Id; +use Doctrine\ORM\Mapping\Column; + +/** @Entity */ +class Price +{ + /** @Id @Column(type="integer") */ + public $id; + + /** @Column(type="decimal") */ + public $value; + + /** + * @param int $id + * @param float $value + */ + public function __construct(int $id, float $value) + { + $this->id = $id; + $this->value = $value; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php new file mode 100644 index 0000000000000..b7601b1a9466e --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php @@ -0,0 +1,96 @@ +<?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\Bridge\Doctrine\Tests\Form\Type; + +use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Tools\SchemaTool; +use Symfony\Bridge\Doctrine\Form\Type\DecimalType; +use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Tests\Fixtures\Price; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\Tests\Extension\Core\Type\BaseTypeTest; + +class DecimalTypeTest extends BaseTypeTest +{ + /** + * @var string + */ + const TESTED_TYPE = DecimalType::class; + + /** + * @var EntityManager + */ + private $em; + + protected function setUp() + { + $this->em = DoctrineTestHelper::createTestEntityManager(); + + parent::setUp(); + + $schemaTool = new SchemaTool($this->em); + $classes = array( + $this->em->getClassMetadata(Price::class) + ); + + try { + $schemaTool->dropSchema($classes); + } catch (\Exception $e) { + } + + try { + $schemaTool->createSchema($classes); + } catch (\Exception $e) { + } + } + + protected function tearDown() + { + parent::tearDown(); + + $this->em = null; + } + + public function testSubmitWithSameStringValue() + { + $price = new Price(1, 1.23); + $this->em->persist($price); + $this->em->flush(); + + $this->em->refresh($price); + + $this->assertInternalType('string', $price->value); + $stringValue = $price->value; + + $formBuilder = $this->factory->createBuilder(FormType::class, $price, array( + 'data_class' => Price::class + )); + $formBuilder->add('value', static::TESTED_TYPE); + + $form = $formBuilder->getForm(); + $form->submit(array( + 'value' => $stringValue + )); + + $this->assertSame($stringValue, $price->value); + + $unitOfWork = $this->em->getUnitOfWork(); + $unitOfWork->computeChangeSets(); + + $this->assertSame(array(), $unitOfWork->getEntityChangeSet($price)); + } + + public function testSubmitNull($expected = null, $norm = null, $view = null) + { + parent::testSubmitNull($expected, $norm, ''); + } +} From fb2b37a8f3dc1131938bc25cdcdebd944d284f51 Mon Sep 17 00:00:00 2001 From: Thomas Calvet <calvet.thomas@gmail.com> Date: Tue, 13 Mar 2018 16:10:41 +0100 Subject: [PATCH 393/495] add force_full_scale option to handle all cases --- .../NumberToStringTransformer.php | 91 ++++++++++++++++ .../Bridge/Doctrine/Form/Type/DecimalType.php | 37 +++---- .../Bridge/Doctrine/Tests/Fixtures/Price.php | 10 +- .../Tests/Form/Type/DecimalTypeTest.php | 103 ++++++++++++++++-- 4 files changed, 205 insertions(+), 36 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php new file mode 100644 index 0000000000000..803df3c1d9935 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php @@ -0,0 +1,91 @@ +<?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\Bridge\Doctrine\Form\DataTransformer; + +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; + +class NumberToStringTransformer implements DataTransformerInterface +{ + /** + * @var bool + */ + private $forceFullScale; + + /** + * @var int|null + */ + private $scale; + + /** + * @param bool $forceFullScale + * @param int|null $scale + */ + public function __construct($forceFullScale = false, $scale = null) + { + $this->forceFullScale = $forceFullScale; + $this->scale = $scale; + } + + /** + * @param mixed $value + * + * @return string|null + */ + public function transform($value) + { + if (null === $value) { + return null; + } + + if (!is_string($value)) { + throw new TransformationFailedException('Expected a string.'); + } + + return $value; + } + + /** + * @param mixed $value + * + * @return string|null + */ + public function reverseTransform($value) + { + if (null === $value) { + return null; + } + + if (is_string($value)) { + return $value; + } + + $valueIsInt = is_int($value); + if (!$valueIsInt && !is_float($value)) { + throw new TransformationFailedException('Expected an int or a float.'); + } + + if ($this->forceFullScale && is_int($this->scale)) { + if ($valueIsInt) { + $value = floatval($value); + } + + return number_format($value, $this->scale, '.', ''); + } + + try { + return (string) $value; + } catch (\Exception $e) { + throw new TransformationFailedException(); + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php index 9956c3de10d33..6c67aacd4bcbb 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php @@ -11,11 +11,11 @@ namespace Symfony\Bridge\Doctrine\Form\Type; +use Symfony\Bridge\Doctrine\Form\DataTransformer\NumberToStringTransformer; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\CallbackTransformer; -use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\Type\NumberType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; class DecimalType extends AbstractType { @@ -24,27 +24,20 @@ class DecimalType extends AbstractType */ public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->addModelTransformer(new CallbackTransformer(function ($value) { - if (null === $value) { - return null; - } - - if (!is_string($value)) { - throw new TransformationFailedException('Expected a string.'); - } - - return $value; - }, function ($value) { - if (null === $value) { - return null; - } - - if (!is_int($value) && !is_float($value)) { - throw new TransformationFailedException('Expected an int or a float.'); - } + $builder->addModelTransformer(new NumberToStringTransformer($options['force_full_scale'], $options['scale'])); + } - return (string) $value; - })); + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'force_full_scale' => false + )); + $resolver->setAllowedTypes('force_full_scale', array( + 'boolean' + )); } /** diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php index bd7c645766af6..3601d30d03fa2 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php @@ -21,8 +21,11 @@ class Price /** @Id @Column(type="integer") */ public $id; - /** @Column(type="decimal") */ - public $value; + /** @Column(type="decimal", scale=2) */ + public $doesNotPreserveFullScaleValue; + + /** @Column(type="string") */ + public $preserveFullScaleValueSimulation; /** * @param int $id @@ -31,6 +34,7 @@ class Price public function __construct(int $id, float $value) { $this->id = $id; - $this->value = $value; + $this->doesNotPreserveFullScaleValue = $value; + $this->preserveFullScaleValueSimulation = number_format($value, 2, '.', ''); } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php index b7601b1a9466e..f2ae341107941 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php @@ -60,33 +60,114 @@ protected function tearDown() $this->em = null; } - public function testSubmitWithSameStringValue() + // On some platforms, fetched decimal values are rounded (the full scale is not preserved) + // eg : on SQLite, inserted float value 4.50 will be fetched as string value "4.5" + public function testSubmitWithSameStringValueOnAPlatformThatDoesNotPreserveFullScaleValueWithoutForceFullScale() { - $price = new Price(1, 1.23); - $this->em->persist($price); + $fullScalePrice = new Price(1, 1.23); + $nonFullScalePrice = new Price(2, 4.50); + $this->em->persist($fullScalePrice); + $this->em->persist($nonFullScalePrice); $this->em->flush(); - $this->em->refresh($price); + $this->em->refresh($fullScalePrice); + $this->em->refresh($nonFullScalePrice); - $this->assertInternalType('string', $price->value); - $stringValue = $price->value; + $this->assertInternalType('string', $fullScalePrice->doesNotPreserveFullScaleValue); + $fullScalePriceStringValue = $fullScalePrice->doesNotPreserveFullScaleValue; - $formBuilder = $this->factory->createBuilder(FormType::class, $price, array( + $formBuilder = $this->factory->createBuilder(FormType::class, $fullScalePrice, array( 'data_class' => Price::class )); - $formBuilder->add('value', static::TESTED_TYPE); + $formBuilder->add('doesNotPreserveFullScaleValue', static::TESTED_TYPE, array( + 'force_full_scale' => false + )); + + $form = $formBuilder->getForm(); + $form->submit(array( + 'doesNotPreserveFullScaleValue' => $fullScalePriceStringValue + )); + + $this->assertSame($fullScalePriceStringValue, $fullScalePrice->doesNotPreserveFullScaleValue); + + $this->assertInternalType('string', $nonFullScalePrice->doesNotPreserveFullScaleValue); + $nonFullScalePriceStringValue = $nonFullScalePrice->doesNotPreserveFullScaleValue; + + $formBuilder = $this->factory->createBuilder(FormType::class, $nonFullScalePrice, array( + 'data_class' => Price::class + )); + $formBuilder->add('doesNotPreserveFullScaleValue', static::TESTED_TYPE, array( + 'force_full_scale' => false + )); + + $form = $formBuilder->getForm(); + $form->submit(array( + 'doesNotPreserveFullScaleValue' => $nonFullScalePriceStringValue + )); + + $this->assertSame($nonFullScalePriceStringValue, $nonFullScalePrice->doesNotPreserveFullScaleValue); + + $unitOfWork = $this->em->getUnitOfWork(); + $unitOfWork->computeChangeSets(); + + $this->assertSame(array(), $unitOfWork->getEntityChangeSet($fullScalePrice)); + $this->assertSame(array(), $unitOfWork->getEntityChangeSet($nonFullScalePrice)); + } + + // On some platforms, fetched decimal values are not rounded at all (the full scale is preserved) + // eg : on PostgreSQL, inserted float value 4.50 will be fetched as string value "4.50" + public function testSubmitWithSameStringValueOnAPlatformThatPreserveFullScaleValueWithForceFullScale() + { + $fullScalePrice = new Price(1, 1.23); + $nonFullScalePrice = new Price(2, 4.50); + $this->em->persist($fullScalePrice); + $this->em->persist($nonFullScalePrice); + $this->em->flush(); + + $this->em->refresh($fullScalePrice); + $this->em->refresh($nonFullScalePrice); + + $this->assertInternalType('string', $fullScalePrice->preserveFullScaleValueSimulation); + $fullScalePriceStringValue = $fullScalePrice->preserveFullScaleValueSimulation; + + $formBuilder = $this->factory->createBuilder(FormType::class, $fullScalePrice, array( + 'data_class' => Price::class + )); + $formBuilder->add('preserveFullScaleValueSimulation', static::TESTED_TYPE, array( + 'force_full_scale' => true, + 'scale' => 2 + )); + + $form = $formBuilder->getForm(); + $form->submit(array( + 'preserveFullScaleValueSimulation' => $fullScalePriceStringValue + )); + + $this->assertSame($fullScalePriceStringValue, $fullScalePrice->preserveFullScaleValueSimulation); + + $this->assertInternalType('string', $nonFullScalePrice->preserveFullScaleValueSimulation); + $nonFullScalePriceStringValue = $nonFullScalePrice->preserveFullScaleValueSimulation; + + $formBuilder = $this->factory->createBuilder(FormType::class, $nonFullScalePrice, array( + 'data_class' => Price::class + )); + $formBuilder->add('preserveFullScaleValueSimulation', static::TESTED_TYPE, array( + 'force_full_scale' => true, + 'scale' => 2 + )); $form = $formBuilder->getForm(); $form->submit(array( - 'value' => $stringValue + 'preserveFullScaleValueSimulation' => $nonFullScalePriceStringValue )); - $this->assertSame($stringValue, $price->value); + $this->assertSame($nonFullScalePriceStringValue, $nonFullScalePrice->preserveFullScaleValueSimulation); $unitOfWork = $this->em->getUnitOfWork(); $unitOfWork->computeChangeSets(); - $this->assertSame(array(), $unitOfWork->getEntityChangeSet($price)); + $this->assertSame(array(), $unitOfWork->getEntityChangeSet($fullScalePrice)); + $this->assertSame(array(), $unitOfWork->getEntityChangeSet($nonFullScalePrice)); } public function testSubmitNull($expected = null, $norm = null, $view = null) From 73708a61b6af18f41b8a398645c31e7ca688205c Mon Sep 17 00:00:00 2001 From: Jules Pietri <heah@heahprod.com> Date: Sat, 23 Mar 2019 20:20:32 +0100 Subject: [PATCH 394/495] [Workflow] Changed initial_places to initial_marking, added property instead of type --- UPGRADE-4.3.md | 21 +++++---- UPGRADE-5.0.md | 43 ++++++++++++++++++- .../DependencyInjection/Configuration.php | 25 +++++++++-- .../FrameworkExtension.php | 12 ++++-- .../Resources/config/schema/symfony-1.0.xsd | 5 ++- .../Fixtures/php/workflow-legacy.php | 2 - ...low_legacy_with_arguments_and_service.php} | 0 ...workflow_legacy_with_type_and_service.php} | 2 +- .../php/workflow_with_guard_expression.php | 5 +-- ...th_multiple_transitions_with_same_name.php | 5 +-- .../workflow_with_property_and_service.php | 32 ++++++++++++++ ...flow_with_support_and_support_strategy.php | 4 +- ...w_without_support_and_support_strategy.php | 6 +-- .../Fixtures/php/workflows.php | 10 +---- .../php/workflows_explicitly_enabled.php | 2 +- ...ows_explicitly_enabled_named_workflows.php | 2 +- .../Fixtures/xml/workflow-legacy.xml | 4 +- ...low_legacy_with_arguments_and_service.xml} | 0 ...workflow_legacy_with_type_and_service.xml} | 2 +- .../xml/workflow_with_guard_expression.xml | 4 +- ...th_multiple_transitions_with_same_name.xml | 2 +- .../workflow_with_property_and_service.xml | 21 +++++++++ ...flow_with_support_and_support_strategy.xml | 3 +- ...w_without_support_and_support_strategy.xml | 3 +- .../Fixtures/xml/workflows.xml | 18 ++++---- .../xml/workflows_explicitly_enabled.xml | 3 +- ...ows_explicitly_enabled_named_workflows.xml | 2 +- ...low_legacy_with_arguments_and_service.yml} | 0 ...workflow_legacy_with_type_and_service.yml} | 2 +- .../yml/workflow_with_guard_expression.yml | 18 ++++---- ...th_multiple_transitions_with_same_name.yml | 4 +- .../workflow_with_property_and_service.yml | 17 ++++++++ ...flow_with_support_and_support_strategy.yml | 3 +- ...w_without_support_and_support_strategy.yml | 3 +- .../Fixtures/yml/workflows.yml | 8 +--- .../yml/workflows_explicitly_enabled.yml | 2 +- ...ows_explicitly_enabled_named_workflows.yml | 2 +- .../FrameworkExtensionTest.php | 15 ++++++- 38 files changed, 214 insertions(+), 98 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/{workflow_with_arguments_and_service.php => workflow_legacy_with_arguments_and_service.php} (100%) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/{workflow_with_type_and_service.php => workflow_legacy_with_type_and_service.php} (94%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{workflow_with_arguments_and_service.xml => workflow_legacy_with_arguments_and_service.xml} (100%) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{workflow_with_type_and_service.xml => workflow_legacy_with_type_and_service.xml} (91%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/{workflow_with_arguments_and_service.yml => workflow_legacy_with_arguments_and_service.yml} (100%) rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/{workflow_with_type_and_service.yml => workflow_legacy_with_type_and_service.yml} (92%) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 110e58ed65935..aeb2b1181fca8 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -166,11 +166,6 @@ Workflow initial_places: [draft] ``` -Yaml ----- - - * Using a mapping inside a multi-line string is deprecated and will throw a `ParseException` in 5.0. - Workflow -------- @@ -202,19 +197,22 @@ Workflow ```yaml framework: workflows: + type: workflow article: marking_store: type: multiple + arguments: states ``` After: ```yaml framework: workflows: + type: workflow article: marking_store: type: method - + property: states ``` * `SingleStateMarkingStore` is deprecated. Use `MethodMarkingStore` instead. @@ -225,16 +223,21 @@ Workflow workflows: article: marking_store: - type: single + arguments: state ``` After: ```yaml framework: workflows: + type: state_machine article: marking_store: type: method - arguments: - - true + property: state ``` + +Yaml +---- + + * Using a mapping inside a multi-line string is deprecated and will throw a `ParseException` in 5.0. diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 7c4a38aba253e..70bfdf3542f2d 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -388,8 +388,47 @@ Workflow * `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead. * `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`. * Removed support of `initial_place`. Use `initial_places` instead. - * `MultipleStateMarkingStore` has been removed. - * `SingleStateMarkingStore` has been removed. + * `MultipleStateMarkingStore` has been removed. Use `MethodMarkingStore` instead. + + Before: + ```yaml + framework: + workflows: + type: workflow + article: + marking_store: + type: multiple + arguments: states + ``` + + After: + ```yaml + framework: + workflows: + type: workflow + article: + marking_store: + property: states + ``` + * `SingleStateMarkingStore` has been removed. Use `MethodMarkingStore` instead. + + Before: + ```yaml + framework: + workflows: + article: + marking_store: + arguments: state + ``` + + After: + ```yaml + framework: + workflows: + article: + marking_store: + property: state + ``` Yaml ---- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 698ef88e021f4..8a7062c4b601a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -233,7 +233,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) $workflows = []; } - if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_places', 'places', 'transitions']))) { + if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_marking', 'places', 'transitions']))) { $workflows = $workflows['workflows']; } @@ -258,9 +258,17 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->arrayNode('workflows') ->useAttributeAsKey('name') ->prototype('array') + ->beforeNormalization() + ->always(function ($v) { + if (isset($v['initial_place'])) { + $v['initial_marking'] = [$v['initial_place']]; + } + + return $v; + }) + ->end() ->fixXmlConfig('support') ->fixXmlConfig('place') - ->fixXmlConfig('initial_place') ->fixXmlConfig('transition') ->children() ->arrayNode('audit_trail') @@ -274,9 +282,11 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->fixXmlConfig('argument') ->children() ->enumNode('type') + ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3. Use "method" instead as it will be the only option in Symfony 5.0.') ->values(['multiple_state', 'single_state', 'method']) ->end() ->arrayNode('arguments') + ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3. Use "property" instead.') ->beforeNormalization() ->ifString() ->then(function ($v) { return [$v]; }) @@ -285,6 +295,9 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->prototype('scalar') ->end() ->end() + ->scalarNode('property') + ->defaultNull() + ->end() ->scalarNode('service') ->cannotBeEmpty() ->end() @@ -297,6 +310,10 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->ifTrue(function ($v) { return !empty($v['arguments']) && isset($v['service']); }) ->thenInvalid('"arguments" and "service" cannot be used together.') ->end() + ->validate() + ->ifTrue(function ($v) { return !empty($v['property']) && isset($v['service']); }) + ->thenInvalid('"property" and "service" cannot be used together.') + ->end() ->end() ->arrayNode('supports') ->beforeNormalization() @@ -315,10 +332,10 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->cannotBeEmpty() ->end() ->scalarNode('initial_place') - ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3, use the "initial_places" configuration key instead.') + ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3, use the "initial_marking" configuration key instead.') ->defaultNull() ->end() - ->arrayNode('initial_places') + ->arrayNode('initial_marking') ->beforeNormalization() ->ifTrue(function ($v) { return !\is_array($v); }) ->then(function ($v) { return [$v]; }) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index afca88af956d5..e10af2e17826a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -631,14 +631,14 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ // Create places $places = array_column($workflow['places'], 'name'); - $initialPlaces = $workflow['initial_places'] ?? $workflow['initial_place'] ?? []; + $initialMarking = $workflow['initial_marking'] ?? $workflow['initial_place'] ?? []; // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); $definitionDefinition->addArgument($places); $definitionDefinition->addArgument($transitions); - $definitionDefinition->addArgument($initialPlaces); + $definitionDefinition->addArgument($initialMarking); $definitionDefinition->addArgument($metadataStoreDefinition); // Create MarkingStore @@ -647,6 +647,12 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ foreach ($workflow['marking_store']['arguments'] as $argument) { $markingStoreDefinition->addArgument($argument); } + if ('method' === $workflow['marking_store']['type']) { + $markingStoreDefinition->setArguments([ + 'state_machine' === $type, //single state + $workflow['marking_store']['property'] ?? 'marking', + ]); + } } elseif (isset($workflow['marking_store']['service'])) { $markingStoreDefinition = new Reference($workflow['marking_store']['service']); } @@ -686,7 +692,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ ->addTransitions(array_map(function (Reference $ref) use ($container): Workflow\Transition { return $container->get((string) $ref); }, $transitions)) - ->setInitialPlace($initialPlaces) + ->setInitialPlace($initialMarking) ->build() ; $validator->validate($realDefinition, $name); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 5a807403a01ad..9d71b403ddb39 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -279,7 +279,7 @@ <xsd:complexType name="workflow"> <xsd:sequence> - <xsd:element name="initial-place" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /> + <xsd:element name="initial-marking" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="marking-store" type="marking_store" minOccurs="0" maxOccurs="1" /> <xsd:element name="support" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="place" type="place" minOccurs="0" maxOccurs="unbounded" /> @@ -289,6 +289,7 @@ <xsd:attribute name="name" type="xsd:string" /> <xsd:attribute name="type" type="workflow_type" /> <xsd:attribute name="initial-place" type="xsd:string" /> + <xsd:attribute name="initial-marking" type="xsd:string" /> <xsd:attribute name="support-strategy" type="xsd:string" /> <xsd:attribute name="enabled" type="xsd:boolean" /> </xsd:complexType> @@ -304,12 +305,14 @@ </xsd:sequence> <xsd:attribute name="type" type="marking_store_type" /> <xsd:attribute name="service" type="xsd:string" /> + <xsd:attribute name="property" type="xsd:string" /> </xsd:complexType> <xsd:simpleType name="marking_store_type"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="multiple_state" /> <xsd:enumeration value="single_state" /> + <xsd:enumeration value="method" /> </xsd:restriction> </xsd:simpleType> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php index e7d8919315da9..729fe03f337ae 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php @@ -1,7 +1,5 @@ <?php -use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest; - $container->loadFromExtension('framework', [ 'workflows' => [ 'legacy' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_arguments_and_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_legacy_with_arguments_and_service.php similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_arguments_and_service.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_legacy_with_arguments_and_service.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_type_and_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_legacy_with_type_and_service.php similarity index 94% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_type_and_service.php rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_legacy_with_type_and_service.php index eca1e29c45b4a..15189349bd83d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_type_and_service.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_legacy_with_type_and_service.php @@ -6,7 +6,7 @@ 'workflows' => [ 'my_workflow' => [ 'marking_store' => [ - 'type' => 'multiple_state', + 'type' => 'method', 'service' => 'workflow_service', ], 'supports' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php index 03b6a0b79b0cb..2037b5f904f69 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_guard_expression.php @@ -6,13 +6,10 @@ 'workflows' => [ 'article' => [ 'type' => 'workflow', - 'marking_store' => [ - 'type' => 'multiple_state', - ], 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_places' => ['draft'], + 'initial_marking' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php index 613a38c6c0ebe..35a9df3730b2a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_multiple_transitions_with_same_name.php @@ -6,13 +6,10 @@ 'workflows' => [ 'article' => [ 'type' => 'workflow', - 'marking_store' => [ - 'type' => 'multiple_state', - ], 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_places' => ['draft'], + 'initial_marking' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php new file mode 100644 index 0000000000000..4129332d00e30 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php @@ -0,0 +1,32 @@ +<?php + +use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest; + +$container->loadFromExtension('framework', [ + 'workflows' => [ + 'my_workflow' => [ + 'type' => 'workflow', + 'marking_store' => [ + 'property' => 'states', + 'service' => 'workflow_service', + ], + 'supports' => [ + FrameworkExtensionTest::class, + ], + 'places' => [ + 'first', + 'last', + ], + 'transitions' => [ + 'go' => [ + 'from' => [ + 'first', + ], + 'to' => [ + 'last', + ], + ], + ], + ], + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_support_and_support_strategy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_support_and_support_strategy.php index 4b38093a3d1d0..063755b130d34 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_support_and_support_strategy.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_support_and_support_strategy.php @@ -5,9 +5,7 @@ $container->loadFromExtension('framework', [ 'workflows' => [ 'my_workflow' => [ - 'marking_store' => [ - 'type' => 'multiple_state', - ], + 'type' => 'workflow', 'supports' => [ FrameworkExtensionTest::class, ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_without_support_and_support_strategy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_without_support_and_support_strategy.php index dd2a92dc2613b..5eef5cc4d0827 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_without_support_and_support_strategy.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_without_support_and_support_strategy.php @@ -1,13 +1,9 @@ <?php -use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest; - $container->loadFromExtension('framework', [ 'workflows' => [ 'my_workflow' => [ - 'marking_store' => [ - 'type' => 'multiple_state', - ], + 'type' => 'workflow', 'places' => [ 'first', 'last', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php index 17a0e1fa4a7eb..7c7f7ed0b45f2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows.php @@ -6,13 +6,10 @@ 'workflows' => [ 'article' => [ 'type' => 'workflow', - 'marking_store' => [ - 'type' => 'multiple_state', - ], 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_places' => ['draft'], + 'initial_marking' => ['draft'], 'places' => [ 'draft', 'wait_for_journalist', @@ -41,13 +38,10 @@ ], ], 'pull_request' => [ - 'marking_store' => [ - 'type' => 'single_state', - ], 'supports' => [ FrameworkExtensionTest::class, ], - 'initial_places' => ['start'], + 'initial_marking' => 'start', 'metadata' => [ 'title' => 'workflow title', ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php index 1c8190bd09d5c..e6f261f8f2f7a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled.php @@ -6,7 +6,7 @@ 'foo' => [ 'type' => 'workflow', 'supports' => ['Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest'], - 'initial_places' => ['bar'], + 'initial_marking' => ['bar'], 'places' => ['bar', 'baz'], 'transitions' => [ 'bar_baz' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php index 6faae44f45ced..e4bc05a66f46f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflows_explicitly_enabled_named_workflows.php @@ -6,7 +6,7 @@ 'workflows' => [ 'type' => 'workflow', 'supports' => ['Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest'], - 'initial_places' => ['bar'], + 'initial_marking' => ['bar'], 'places' => ['bar', 'baz'], 'transitions' => [ 'bar_baz' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml index d1339d5f65cc1..b59bd6c29f955 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml @@ -9,8 +9,8 @@ <framework:config> <framework:workflow name="legacy" type="workflow" initial-place="draft"> <framework:support>stdClass</framework:support> - <framework:place name="draft"></framework:place> - <framework:place name="published"></framework:place> + <framework:place name="draft" /> + <framework:place name="published" /> <framework:transition name="publish"> <framework:from>draft</framework:from> <framework:to>published</framework:to> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_arguments_and_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_legacy_with_arguments_and_service.xml similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_arguments_and_service.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_legacy_with_arguments_and_service.xml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_type_and_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_legacy_with_type_and_service.xml similarity index 91% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_type_and_service.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_legacy_with_type_and_service.xml index 8b4bf305a85cd..e137f9b4b041b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_type_and_service.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_legacy_with_type_and_service.xml @@ -8,7 +8,7 @@ <framework:config> <framework:workflow name="my_workflow"> - <framework:marking-store type="multiple_state" service="workflow_service" /> + <framework:marking-store type="method" service="workflow_service" /> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place name="first" /> <framework:place name="last" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml index 32c33db5b812a..e310c0d11dd17 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml @@ -8,8 +8,8 @@ <framework:config> <framework:workflow name="article" type="workflow"> - <framework:initial-place>draft</framework:initial-place> - <framework:marking-store type="multiple_state"> + <framework:initial-marking>draft</framework:initial-marking> + <framework:marking-store> <framework:argument>a</framework:argument> <framework:argument>a</framework:argument> </framework:marking-store> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml index ffc316c99e70a..5cb7d75e88001 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml @@ -8,7 +8,7 @@ <framework:config> <framework:workflow name="article" type="workflow"> - <framework:initial-place>draft</framework:initial-place> + <framework:initial-marking>draft</framework:initial-marking> <framework:marking-store type="multiple_state"> <framework:argument>a</framework:argument> <framework:argument>a</framework:argument> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml new file mode 100644 index 0000000000000..2b2de8c368f5f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" ?> + +<container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:framework="http://symfony.com/schema/dic/symfony" + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + + <framework:config> + <framework:workflow name="my_workflow"> + <framework:marking-store property="multiple_state" service="workflow_service" /> + <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> + <framework:place name="first" /> + <framework:place name="last" /> + <framework:transition name="foobar"> + <framework:from>a</framework:from> + <framework:to>a</framework:to> + </framework:transition> + </framework:workflow> + </framework:config> +</container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_support_and_support_strategy.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_support_and_support_strategy.xml index f3ff577b808d6..54a346ebda198 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_support_and_support_strategy.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_support_and_support_strategy.xml @@ -7,8 +7,7 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> - <framework:workflow name="my_workflow" support-strategy="foobar"> - <framework:marking-store type="multiple_state"/> + <framework:workflow name="my_workflow" support-strategy="foobar" type="workflow"> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place name="first" /> <framework:place name="last" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_without_support_and_support_strategy.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_without_support_and_support_strategy.xml index 3529c50ceed80..c6ee7d77b5c6a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_without_support_and_support_strategy.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_without_support_and_support_strategy.xml @@ -7,8 +7,7 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> - <framework:workflow name="my_workflow"> - <framework:marking-store type="multiple_state"/> + <framework:workflow name="my_workflow" type="workflow"> <framework:place name="first" /> <framework:place name="last" /> <framework:transition name="foobar"> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml index da5cd4c758200..e0340d54183bc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml @@ -8,18 +8,18 @@ <framework:config> <framework:workflow name="article" type="workflow"> - <framework:initial-place>draft</framework:initial-place> + <framework:initial-marking>draft</framework:initial-marking> <framework:marking-store type="multiple_state"> <framework:argument>a</framework:argument> <framework:argument>a</framework:argument> </framework:marking-store> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> - <framework:place name="draft"></framework:place> - <framework:place name="wait_for_journalist"></framework:place> - <framework:place name="approved_by_journalist"></framework:place> - <framework:place name="wait_for_spellchecker"></framework:place> - <framework:place name="approved_by_spellchecker"></framework:place> - <framework:place name="published"></framework:place> + <framework:place name="draft" /> + <framework:place name="wait_for_journalist" /> + <framework:place name="approved_by_journalist" /> + <framework:place name="wait_for_spellchecker" /> + <framework:place name="approved_by_spellchecker" /> + <framework:place name="published" /> <framework:transition name="request_review"> <framework:from>draft</framework:from> <framework:to>wait_for_journalist</framework:to> @@ -40,8 +40,8 @@ </framework:transition> </framework:workflow> - <framework:workflow name="pull_request" initial-place="start"> - <framework:marking-store type="single_state"/> + <framework:workflow name="pull_request"> + <framework:initial-marking>start</framework:initial-marking> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place name="start"> <framework:metadata> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml index b564c6ff7644a..bb544d8979bb2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled.xml @@ -6,8 +6,7 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> - <framework:workflow enabled="true" name="foo" type="workflow"> - <framework:initial-place>bar</framework:initial-place> + <framework:workflow enabled="true" name="foo" type="workflow" initial-marking="start"> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place>bar</framework:place> <framework:place>baz</framework:place> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml index b218480fe68a7..41fd29a1f27d9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows_explicitly_enabled_named_workflows.xml @@ -7,7 +7,7 @@ <framework:config> <framework:workflow enabled="true" name="workflows" type="workflow"> - <framework:initial-place>bar</framework:initial-place> + <framework:initial-marking>bar</framework:initial-marking> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place>bar</framework:place> <framework:place>baz</framework:place> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_arguments_and_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_legacy_with_arguments_and_service.yml similarity index 100% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_arguments_and_service.yml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_legacy_with_arguments_and_service.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_type_and_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_legacy_with_type_and_service.yml similarity index 92% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_type_and_service.yml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_legacy_with_type_and_service.yml index 000ba10dfb8d2..33ee68b1bc810 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_type_and_service.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_legacy_with_type_and_service.yml @@ -2,7 +2,7 @@ framework: workflows: my_workflow: marking_store: - type: multiple_state + type: method service: workflow_service supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml index 433771601c3d7..80a85a307b738 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_guard_expression.yml @@ -2,18 +2,16 @@ framework: workflows: article: type: workflow - marking_store: - type: multiple_state supports: - - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_places: [draft] + - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + initial_marking: [draft] places: - - draft - - wait_for_journalist - - approved_by_journalist - - wait_for_spellchecker - - approved_by_spellchecker - - published + - draft + - wait_for_journalist + - approved_by_journalist + - wait_for_spellchecker + - approved_by_spellchecker + - published transitions: request_review: from: [draft] diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml index fee71c2645693..12df7b79e7c4f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_multiple_transitions_with_same_name.yml @@ -2,11 +2,9 @@ framework: workflows: article: type: workflow - marking_store: - type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_places: [draft] + initial_marking: [draft] places: - draft - wait_for_journalist diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml new file mode 100644 index 0000000000000..520c689aac724 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml @@ -0,0 +1,17 @@ +framework: + workflows: + my_workflow: + marking_store: + property: state + service: workflow_service + supports: + - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest + places: + - first + - last + transitions: + go: + from: + - first + to: + - last diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_support_and_support_strategy.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_support_and_support_strategy.yml index 743708485ce65..de0b36d8fa491 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_support_and_support_strategy.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_support_and_support_strategy.yml @@ -1,8 +1,7 @@ framework: workflows: my_workflow: - marking_store: - type: multiple_state + type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest support_strategy: foobar diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_without_support_and_support_strategy.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_without_support_and_support_strategy.yml index 6dc848d936b21..de74adbe59b20 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_without_support_and_support_strategy.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_without_support_and_support_strategy.yml @@ -1,8 +1,7 @@ framework: workflows: my_workflow: - marking_store: - type: multiple_state + type: workflow places: - first - last diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml index 894d5dcde207c..225106383d1fd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows.yml @@ -2,11 +2,9 @@ framework: workflows: article: type: workflow - marking_store: - type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_places: [draft] + initial_marking: [draft] places: # simple format - draft @@ -29,11 +27,9 @@ framework: from: [approved_by_journalist, approved_by_spellchecker] to: [published] pull_request: - marking_store: - type: single_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_places: [start] + initial_marking: start metadata: title: workflow title places: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml index d1545374705d3..bee231736b233 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled.yml @@ -6,7 +6,7 @@ framework: type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_places: [bar] + initial_marking: [bar] places: - bar - baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml index bb468254aca0b..c0462c9ab8c9d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflows_explicitly_enabled_named_workflows.yml @@ -5,7 +5,7 @@ framework: type: workflow supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - initial_places: [bar] + initial_marking: [bar] places: - bar - baz diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 1b8a785a303db..332ac8162d49e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -307,12 +307,23 @@ public function testWorkflowAreValidated() } /** + * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException + * @expectedExceptionMessage "property" and "service" cannot be used together. + */ + public function testWorkflowCannotHaveBothPropertyAndService() + { + $this->createContainerFromFile('workflow_with_property_and_service'); + } + + /** + * @legacy + * * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException * @expectedExceptionMessage "type" and "service" cannot be used together. */ public function testWorkflowCannotHaveBothTypeAndService() { - $this->createContainerFromFile('workflow_with_type_and_service'); + $this->createContainerFromFile('workflow_legacy_with_type_and_service'); } /** @@ -339,7 +350,7 @@ public function testWorkflowShouldHaveOneOfSupportsAndSupportStrategy() */ public function testWorkflowCannotHaveBothArgumentsAndService() { - $this->createContainerFromFile('workflow_with_arguments_and_service'); + $this->createContainerFromFile('workflow_legacy_with_arguments_and_service'); } public function testWorkflowMultipleTransitionsWithSameName() From 87839cfaf94e3a6b426036b7ab63b80ef89a6fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 14:37:18 +0200 Subject: [PATCH 395/495] [Workflow] Finished integration of initial_marking + deprecated support for workflow + single state markin store --- .../DependencyInjection/Configuration.php | 15 ++-- .../FrameworkExtension.php | 14 ++-- .../Fixtures/php/workflow-legacy.php | 8 +- .../workflow_with_property_and_service.php | 32 -------- .../Fixtures/xml/workflow-legacy.xml | 5 +- .../xml/workflow_with_guard_expression.xml | 4 - ...th_multiple_transitions_with_same_name.xml | 4 - .../workflow_with_property_and_service.xml | 21 ------ .../Fixtures/xml/workflows.xml | 5 +- .../Fixtures/yml/workflow-legacy.yml | 6 +- .../workflow_with_property_and_service.yml | 17 ----- .../FrameworkExtensionTest.php | 25 +++---- .../PhpFrameworkExtensionTest.php | 73 +------------------ 13 files changed, 43 insertions(+), 186 deletions(-) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 8a7062c4b601a..a398054c5f1c4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -282,8 +282,15 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->fixXmlConfig('argument') ->children() ->enumNode('type') - ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3. Use "method" instead as it will be the only option in Symfony 5.0.') ->values(['multiple_state', 'single_state', 'method']) + ->validate() + ->ifTrue(function ($v) { return 'method' !== $v; }) + ->then(function ($v) { + @trigger_error('Passing something else than "method" has been deprecated in Symfony 4.3.', E_USER_DEPRECATED); + + return $v; + }) + ->end() ->end() ->arrayNode('arguments') ->setDeprecated('The "%path%.%node%" configuration key has been deprecated in Symfony 4.3. Use "property" instead.') @@ -296,7 +303,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->end() ->end() ->scalarNode('property') - ->defaultNull() + ->defaultValue('marking') ->end() ->scalarNode('service') ->cannotBeEmpty() @@ -310,10 +317,6 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->ifTrue(function ($v) { return !empty($v['arguments']) && isset($v['service']); }) ->thenInvalid('"arguments" and "service" cannot be used together.') ->end() - ->validate() - ->ifTrue(function ($v) { return !empty($v['property']) && isset($v['service']); }) - ->thenInvalid('"property" and "service" cannot be used together.') - ->end() ->end() ->arrayNode('supports') ->beforeNormalization() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index e10af2e17826a..a4e33ba7443f0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -644,14 +644,15 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ // Create MarkingStore if (isset($workflow['marking_store']['type'])) { $markingStoreDefinition = new ChildDefinition('workflow.marking_store.'.$workflow['marking_store']['type']); - foreach ($workflow['marking_store']['arguments'] as $argument) { - $markingStoreDefinition->addArgument($argument); - } if ('method' === $workflow['marking_store']['type']) { $markingStoreDefinition->setArguments([ 'state_machine' === $type, //single state - $workflow['marking_store']['property'] ?? 'marking', + $workflow['marking_store']['property'], ]); + } else { + foreach ($workflow['marking_store']['arguments'] as $argument) { + $markingStoreDefinition->addArgument($argument); + } } } elseif (isset($workflow['marking_store']['service'])) { $markingStoreDefinition = new Reference($workflow['marking_store']['service']); @@ -676,10 +677,6 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ case 'state_machine' === $workflow['type']: $validator = new Workflow\Validator\StateMachineValidator(); break; - case 'method' === ($workflow['marking_store']['type'] ?? null): - $singlePlace = $workflow['marking_store']['arguments'][0] ?? false; - $validator = new Workflow\Validator\WorkflowValidator($singlePlace); - break; case 'single_state' === ($workflow['marking_store']['type'] ?? null): $validator = new Workflow\Validator\WorkflowValidator(true); break; @@ -687,6 +684,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $ $validator = new Workflow\Validator\WorkflowValidator(false); break; } + if ($validator) { $realDefinition = (new Workflow\DefinitionBuilder($places)) ->addTransitions(array_map(function (Reference $ref) use ($container): Workflow\Transition { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php index 729fe03f337ae..cad94fc773b87 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow-legacy.php @@ -3,7 +3,13 @@ $container->loadFromExtension('framework', [ 'workflows' => [ 'legacy' => [ - 'type' => 'workflow', + 'type' => 'state_machine', + 'marking_store' => [ + 'type' => 'single_state', + 'arguments' => [ + 'state', + ], + ], 'supports' => [ stdClass::class, ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php deleted file mode 100644 index 4129332d00e30..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow_with_property_and_service.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest; - -$container->loadFromExtension('framework', [ - 'workflows' => [ - 'my_workflow' => [ - 'type' => 'workflow', - 'marking_store' => [ - 'property' => 'states', - 'service' => 'workflow_service', - ], - 'supports' => [ - FrameworkExtensionTest::class, - ], - 'places' => [ - 'first', - 'last', - ], - 'transitions' => [ - 'go' => [ - 'from' => [ - 'first', - ], - 'to' => [ - 'last', - ], - ], - ], - ], - ], -]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml index b59bd6c29f955..5a46d24d0df08 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow-legacy.xml @@ -7,7 +7,10 @@ http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> <framework:config> - <framework:workflow name="legacy" type="workflow" initial-place="draft"> + <framework:workflow name="legacy" type="state_machine" initial-place="draft"> + <framework:marking-store type="single_state"> + <framework:argument>state</framework:argument> + </framework:marking-store> <framework:support>stdClass</framework:support> <framework:place name="draft" /> <framework:place name="published" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml index e310c0d11dd17..ffc12c4d0d420 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_guard_expression.xml @@ -9,10 +9,6 @@ <framework:config> <framework:workflow name="article" type="workflow"> <framework:initial-marking>draft</framework:initial-marking> - <framework:marking-store> - <framework:argument>a</framework:argument> - <framework:argument>a</framework:argument> - </framework:marking-store> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place>draft</framework:place> <framework:place>wait_for_journalist</framework:place> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml index 5cb7d75e88001..db79f9323c47e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_multiple_transitions_with_same_name.xml @@ -9,10 +9,6 @@ <framework:config> <framework:workflow name="article" type="workflow"> <framework:initial-marking>draft</framework:initial-marking> - <framework:marking-store type="multiple_state"> - <framework:argument>a</framework:argument> - <framework:argument>a</framework:argument> - </framework:marking-store> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place name="draft" /> <framework:place name="wait_for_journalist" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml deleted file mode 100644 index 2b2de8c368f5f..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow_with_property_and_service.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" ?> - -<container xmlns="http://symfony.com/schema/dic/services" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:framework="http://symfony.com/schema/dic/symfony" - xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd - http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - <framework:config> - <framework:workflow name="my_workflow"> - <framework:marking-store property="multiple_state" service="workflow_service" /> - <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> - <framework:place name="first" /> - <framework:place name="last" /> - <framework:transition name="foobar"> - <framework:from>a</framework:from> - <framework:to>a</framework:to> - </framework:transition> - </framework:workflow> - </framework:config> -</container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml index e0340d54183bc..0c6a638df45cc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml @@ -9,10 +9,7 @@ <framework:config> <framework:workflow name="article" type="workflow"> <framework:initial-marking>draft</framework:initial-marking> - <framework:marking-store type="multiple_state"> - <framework:argument>a</framework:argument> - <framework:argument>a</framework:argument> - </framework:marking-store> + <framework:marking-store type="method" property="state" /> <framework:support>Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest</framework:support> <framework:place name="draft" /> <framework:place name="wait_for_journalist" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml index 7ff70074d400c..19f51dc9f4119 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow-legacy.yml @@ -1,7 +1,11 @@ framework: workflows: legacy: - type: workflow + type: state_machine + marking_store: + type: single_state + arguments: + - state initial_place: draft supports: - stdClass diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml deleted file mode 100644 index 520c689aac724..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow_with_property_and_service.yml +++ /dev/null @@ -1,17 +0,0 @@ -framework: - workflows: - my_workflow: - marking_store: - property: state - service: workflow_service - supports: - - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest - places: - - first - - last - transitions: - go: - from: - - first - to: - - last diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 332ac8162d49e..7085327e5c054 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -275,15 +275,18 @@ public function testWorkflows() $this->assertGreaterThan(0, \count($registryDefinition->getMethodCalls())); } + /** + * @group legacy + */ public function testWorkflowLegacy() { $container = $this->createContainerFromFile('workflow-legacy'); - $this->assertTrue($container->hasDefinition('workflow.legacy'), 'Workflow is registered as a service'); - $this->assertSame('workflow.abstract', $container->getDefinition('workflow.legacy')->getParent()); - $this->assertTrue($container->hasDefinition('workflow.legacy.definition'), 'Workflow definition is registered as a service'); + $this->assertTrue($container->hasDefinition('state_machine.legacy'), 'Workflow is registered as a service'); + $this->assertSame('state_machine.abstract', $container->getDefinition('state_machine.legacy')->getParent()); + $this->assertTrue($container->hasDefinition('state_machine.legacy.definition'), 'Workflow definition is registered as a service'); - $workflowDefinition = $container->getDefinition('workflow.legacy.definition'); + $workflowDefinition = $container->getDefinition('state_machine.legacy.definition'); $this->assertSame(['draft'], $workflowDefinition->getArgument(2)); @@ -307,17 +310,6 @@ public function testWorkflowAreValidated() } /** - * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException - * @expectedExceptionMessage "property" and "service" cannot be used together. - */ - public function testWorkflowCannotHaveBothPropertyAndService() - { - $this->createContainerFromFile('workflow_with_property_and_service'); - } - - /** - * @legacy - * * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException * @expectedExceptionMessage "type" and "service" cannot be used together. */ @@ -347,6 +339,7 @@ public function testWorkflowShouldHaveOneOfSupportsAndSupportStrategy() /** * @expectedException \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException * @expectedExceptionMessage "arguments" and "service" cannot be used together. + * @group legacy */ public function testWorkflowCannotHaveBothArgumentsAndService() { @@ -423,7 +416,7 @@ public function testWorkflowMultipleTransitionsWithSameName() ], $container->getDefinition($transitions[4])->getArguments()); } - public function testGuardExpressions() + public function testWorkflowGuardExpressions() { $container = $this->createContainerFromFile('workflow_with_guard_expression'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php index 19bad8e825a0a..259ada2f390f4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php @@ -89,78 +89,8 @@ public function testWorkflowValidationStateMachine() } /** - * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException - * @expectedExceptionMessage The marking store of workflow "article" can not store many places. But the transition "a_to_b" has too many output (2). Only one is accepted. + * @group legacy */ - public function testWorkflowValidationMethodSingle() - { - $this->createContainerFromClosure(function ($container) { - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'article' => [ - 'type' => 'workflow', - 'marking_store' => [ - 'type' => 'method', - 'arguments' => [ - true, - ], - ], - 'supports' => [ - __CLASS__, - ], - 'places' => [ - 'a', - 'b', - 'c', - ], - 'transitions' => [ - 'a_to_b' => [ - 'from' => ['a'], - 'to' => ['b', 'c'], - ], - ], - ], - ], - ]); - }); - } - - public function testWorkflowValidationMethodNotSingle() - { - $this->createContainerFromClosure(function ($container) { - $container->loadFromExtension('framework', [ - 'workflows' => [ - 'article' => [ - 'type' => 'workflow', - 'marking_store' => [ - 'type' => 'method', - 'arguments' => [ - false, - ], - ], - 'supports' => [ - __CLASS__, - ], - 'places' => [ - 'a', - 'b', - 'c', - ], - 'transitions' => [ - 'a_to_b' => [ - 'from' => ['a'], - 'to' => ['b', 'c'], - ], - ], - ], - ], - ]); - }); - - // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) - $this->addToAssertionCount(1); - } - public function testWorkflowValidationMultipleState() { $this->createContainerFromClosure(function ($container) { @@ -197,6 +127,7 @@ public function testWorkflowValidationMultipleState() /** * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException * @expectedExceptionMessage The marking store of workflow "article" can not store many places. But the transition "a_to_b" has too many output (2). Only one is accepted. + * @group legacy */ public function testWorkflowValidationSingleState() { From 039353546f570ca14ceecde1b21ace42ccbcc28b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 15:32:53 +0200 Subject: [PATCH 396/495] [Workflow] Deprecate worflow and single state marking --- UPGRADE-4.3.md | 23 +++++++++++++ UPGRADE-5.0.md | 21 ++++++++++++ .../DependencyInjection/Configuration.php | 10 ++++++ .../PhpFrameworkExtensionTest.php | 34 +++++++++++++++++++ 4 files changed, 88 insertions(+) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index aeb2b1181fca8..020f3a40181cb 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -237,6 +237,29 @@ Workflow property: state ``` + * Using a workflow with a single state marking is deprecated. Use a state machine instead. + + Before: + ```yaml + framework: + workflows: + article: + type: workflow + marking_store: + type: single_state + ``` + + After: + ```yaml + framework: + workflows: + article: + type: state_machine + marking_store: + # type: single_state # Since the single_state marking store is deprecated, use method instead + type: method + ``` + Yaml ---- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 70bfdf3542f2d..68001974bb92c 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -430,6 +430,27 @@ Workflow property: state ``` + + * Support for using a workflow with a single state marking is dropped. Use a state machine instead. + + Before: + ```yaml + framework: + workflows: + article: + type: workflow + marking_store: + type: single_state + ``` + + After: + ```yaml + framework: + workflows: + article: + type: state_machine + ``` + Yaml ---- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index a398054c5f1c4..f50c951a3e983 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -474,6 +474,16 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) }) ->thenInvalid('"supports" or "support_strategy" should be configured.') ->end() + ->validate() + ->ifTrue(function ($v) { + return 'workflow' === $v['type'] && 'single_state' === ($v['marking_store']['type'] ?? false); + }) + ->then(function ($v) { + @trigger_error('Using a workflow with type=workflow and a marking_store=single_state is deprecated since Symfony 4.3. Use type=state_machine instead.', E_USER_DEPRECATED); + + return $v; + }) + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php index 259ada2f390f4..a67a35844769f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php @@ -88,6 +88,40 @@ public function testWorkflowValidationStateMachine() }); } + /** + * @group legacy + * @expectedDeprecation Using a workflow with type=workflow and a marking_store=single_state is deprecated since Symfony 4.3. Use type=state_machine instead. + */ + public function testWorkflowDeprecateWorkflowSingleState() + { + $this->createContainerFromClosure(function ($container) { + $container->loadFromExtension('framework', [ + 'workflows' => [ + 'article' => [ + 'type' => 'workflow', + 'marking_store' => [ + 'type' => 'single_state', + ], + 'supports' => [ + __CLASS__, + ], + 'places' => [ + 'a', + 'b', + 'c', + ], + 'transitions' => [ + 'a_to_b' => [ + 'from' => ['a'], + 'to' => ['b'], + ], + ], + ], + ], + ]); + }); + } + /** * @group legacy */ From 2f648b04ae2580c04bd3af5d442d18c374f615bd Mon Sep 17 00:00:00 2001 From: Javier Eguiluz <javier.eguiluz@gmail.com> Date: Sat, 6 Apr 2019 16:05:38 +0200 Subject: [PATCH 397/495] Renamed NotPwned to NotCompromisedPassword --- src/Symfony/Component/Validator/CHANGELOG.md | 2 +- ...otPwned.php => NotCompromisedPassword.php} | 6 ++-- ...hp => NotCompromisedPasswordValidator.php} | 8 ++--- ...est.php => NotCompromisedPasswordTest.php} | 6 ++-- ...> NotCompromisedPasswordValidatorTest.php} | 30 +++++++++---------- 5 files changed, 26 insertions(+), 26 deletions(-) rename src/Symfony/Component/Validator/Constraints/{NotPwned.php => NotCompromisedPassword.php} (75%) rename src/Symfony/Component/Validator/Constraints/{NotPwnedValidator.php => NotCompromisedPasswordValidator.php} (89%) rename src/Symfony/Component/Validator/Tests/Constraints/{NotPwnedTest.php => NotCompromisedPasswordTest.php} (76%) rename src/Symfony/Component/Validator/Tests/Constraints/{NotPwnedValidatorTest.php => NotCompromisedPasswordValidatorTest.php} (81%) diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index 70528f35117e9..c44c49bee8c33 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.3.0 ----- - * added `NotPwned` constraint + * added `NotCompromisedPassword` constraint * added options `iban` and `ibanPropertyPath` to Bic constraint * added UATP cards support to `CardSchemeValidator` * added option `allowNull` to NotBlank constraint diff --git a/src/Symfony/Component/Validator/Constraints/NotPwned.php b/src/Symfony/Component/Validator/Constraints/NotCompromisedPassword.php similarity index 75% rename from src/Symfony/Component/Validator/Constraints/NotPwned.php rename to src/Symfony/Component/Validator/Constraints/NotCompromisedPassword.php index 9872076b73546..d38cab1a92a21 100644 --- a/src/Symfony/Component/Validator/Constraints/NotPwned.php +++ b/src/Symfony/Component/Validator/Constraints/NotCompromisedPassword.php @@ -21,11 +21,11 @@ * * @author Kévin Dunglas <dunglas@gmail.com> */ -class NotPwned extends Constraint +class NotCompromisedPassword extends Constraint { - const PWNED_ERROR = 'd9bcdbfe-a9d6-4bfa-a8ff-da5fd93e0f6d'; + const COMPROMISED_PASSWORD_ERROR = 'd9bcdbfe-a9d6-4bfa-a8ff-da5fd93e0f6d'; - protected static $errorNames = [self::PWNED_ERROR => 'PWNED_ERROR']; + protected static $errorNames = [self::COMPROMISED_PASSWORD_ERROR => 'COMPROMISED_PASSWORD_ERROR']; public $message = 'This password has been leaked in a data breach, it must not be used. Please use another password.'; public $threshold = 1; diff --git a/src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php similarity index 89% rename from src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php rename to src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php index d0beffb4f285b..7abdbf23b26e8 100644 --- a/src/Symfony/Component/Validator/Constraints/NotPwnedValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php @@ -26,7 +26,7 @@ * * @author Kévin Dunglas <dunglas@gmail.com> */ -class NotPwnedValidator extends ConstraintValidator +class NotCompromisedPasswordValidator extends ConstraintValidator { private const RANGE_API = 'https://api.pwnedpasswords.com/range/%s'; @@ -48,8 +48,8 @@ public function __construct(HttpClientInterface $httpClient = null) */ public function validate($value, Constraint $constraint) { - if (!$constraint instanceof NotPwned) { - throw new UnexpectedTypeException($constraint, NotPwned::class); + if (!$constraint instanceof NotCompromisedPassword) { + throw new UnexpectedTypeException($constraint, NotCompromisedPassword::class); } if (null !== $value && !is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { @@ -80,7 +80,7 @@ public function validate($value, Constraint $constraint) if ($hashPrefix.$hashSuffix === $hash && $constraint->threshold <= (int) $count) { $this->context->buildViolation($constraint->message) - ->setCode(NotPwned::PWNED_ERROR) + ->setCode(NotCompromisedPassword::COMPROMISED_PASSWORD_ERROR) ->addViolation(); return; diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordTest.php similarity index 76% rename from src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php rename to src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordTest.php index 7d312d828190b..4ae9b8e852b06 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordTest.php @@ -12,16 +12,16 @@ namespace Symfony\Component\Validator\Tests\Constraints; use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraints\NotPwned; +use Symfony\Component\Validator\Constraints\NotCompromisedPassword; /** * @author Kévin Dunglas <dunglas@gmail.com> */ -class NotPwnedTest extends TestCase +class NotCompromisedPasswordTest extends TestCase { public function testDefaultValues() { - $constraint = new NotPwned(); + $constraint = new NotCompromisedPassword(); $this->assertSame(1, $constraint->threshold); $this->assertFalse($constraint->skipOnError); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php similarity index 81% rename from src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php rename to src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php index 845ddbde3959f..d80ed94b52d6d 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotPwnedValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php @@ -12,8 +12,8 @@ namespace Symfony\Component\Validator\Tests\Constraints; use Symfony\Component\Validator\Constraints\Luhn; -use Symfony\Component\Validator\Constraints\NotPwned; -use Symfony\Component\Validator\Constraints\NotPwnedValidator; +use Symfony\Component\Validator\Constraints\NotCompromisedPassword; +use Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -22,7 +22,7 @@ /** * @author Kévin Dunglas <dunglas@gmail.com> */ -class NotPwnedValidatorTest extends ConstraintValidatorTestCase +class NotCompromisedPasswordValidatorTest extends ConstraintValidatorTestCase { private const PASSWORD_TRIGGERING_AN_ERROR = 'apiError'; private const PASSWORD_TRIGGERING_AN_ERROR_RANGE_URL = 'https://api.pwnedpasswords.com/range/3EF27'; // https://api.pwnedpasswords.com/range/3EF27 is the range for the value "apiError" @@ -61,53 +61,53 @@ public function getResponse(): ResponseInterface ); // Pass HttpClient::create() instead of this mock to run the tests against the real API - return new NotPwnedValidator($httpClientStub); + return new NotCompromisedPasswordValidator($httpClientStub); } public function testNullIsValid() { - $this->validator->validate(null, new NotPwned()); + $this->validator->validate(null, new NotCompromisedPassword()); $this->assertNoViolation(); } public function testEmptyStringIsValid() { - $this->validator->validate('', new NotPwned()); + $this->validator->validate('', new NotCompromisedPassword()); $this->assertNoViolation(); } public function testInvalidPassword() { - $constraint = new NotPwned(); + $constraint = new NotCompromisedPassword(); $this->validator->validate(self::PASSWORD_LEAKED, $constraint); $this->buildViolation($constraint->message) - ->setCode(NotPwned::PWNED_ERROR) + ->setCode(NotCompromisedPassword::COMPROMISED_PASSWORD_ERROR) ->assertRaised(); } public function testThresholdReached() { - $constraint = new NotPwned(['threshold' => 3]); + $constraint = new NotCompromisedPassword(['threshold' => 3]); $this->validator->validate(self::PASSWORD_LEAKED, $constraint); $this->buildViolation($constraint->message) - ->setCode(NotPwned::PWNED_ERROR) + ->setCode(NotCompromisedPassword::COMPROMISED_PASSWORD_ERROR) ->assertRaised(); } public function testThresholdNotReached() { - $this->validator->validate(self::PASSWORD_LEAKED, new NotPwned(['threshold' => 10])); + $this->validator->validate(self::PASSWORD_LEAKED, new NotCompromisedPassword(['threshold' => 10])); $this->assertNoViolation(); } public function testValidPassword() { - $this->validator->validate(self::PASSWORD_NOT_LEAKED, new NotPwned()); + $this->validator->validate(self::PASSWORD_NOT_LEAKED, new NotCompromisedPassword()); $this->assertNoViolation(); } @@ -125,7 +125,7 @@ public function testInvalidConstraint() */ public function testInvalidValue() { - $this->validator->validate([], new NotPwned()); + $this->validator->validate([], new NotCompromisedPassword()); } /** @@ -134,12 +134,12 @@ public function testInvalidValue() */ public function testApiError() { - $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotPwned()); + $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotCompromisedPassword()); } public function testApiErrorSkipped() { - $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotPwned(['skipOnError' => true])); + $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotCompromisedPassword(['skipOnError' => true])); $this->assertTrue(true); // No exception have been thrown } } From 3f257346472a815f850fb65cbc81dd82e0b9f55a Mon Sep 17 00:00:00 2001 From: Bernhard Schussek <b.schussek@cwd.at> Date: Sat, 6 Apr 2019 15:14:18 +0200 Subject: [PATCH 398/495] Added new option "input" to NumberType --- src/Symfony/Bridge/Doctrine/CHANGELOG.md | 5 + .../NumberToStringTransformer.php | 91 --------- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 3 +- .../Bridge/Doctrine/Form/Type/DecimalType.php | 50 ----- .../Bridge/Doctrine/Tests/Fixtures/Price.php | 40 ---- .../Tests/Form/Type/DecimalTypeTest.php | 177 ------------------ src/Symfony/Component/Form/CHANGELOG.md | 1 + .../StringToFloatTransformer.php | 65 +++++++ .../Form/Extension/Core/Type/NumberType.php | 8 +- .../StringToFloatTransformerTest.php | 104 ++++++++++ .../Extension/Core/Type/NumberTypeTest.php | 64 ++++++- 11 files changed, 243 insertions(+), 365 deletions(-) delete mode 100644 src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php delete mode 100644 src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php delete mode 100644 src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php create mode 100644 src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php create mode 100644 src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index c333361d4a37f..6b617825c9190 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * changed guessing of DECIMAL to set the `input` option of `NumberType` to string + 4.2.0 ----- diff --git a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php b/src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php deleted file mode 100644 index 803df3c1d9935..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Form/DataTransformer/NumberToStringTransformer.php +++ /dev/null @@ -1,91 +0,0 @@ -<?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\Bridge\Doctrine\Form\DataTransformer; - -use Symfony\Component\Form\DataTransformerInterface; -use Symfony\Component\Form\Exception\TransformationFailedException; - -class NumberToStringTransformer implements DataTransformerInterface -{ - /** - * @var bool - */ - private $forceFullScale; - - /** - * @var int|null - */ - private $scale; - - /** - * @param bool $forceFullScale - * @param int|null $scale - */ - public function __construct($forceFullScale = false, $scale = null) - { - $this->forceFullScale = $forceFullScale; - $this->scale = $scale; - } - - /** - * @param mixed $value - * - * @return string|null - */ - public function transform($value) - { - if (null === $value) { - return null; - } - - if (!is_string($value)) { - throw new TransformationFailedException('Expected a string.'); - } - - return $value; - } - - /** - * @param mixed $value - * - * @return string|null - */ - public function reverseTransform($value) - { - if (null === $value) { - return null; - } - - if (is_string($value)) { - return $value; - } - - $valueIsInt = is_int($value); - if (!$valueIsInt && !is_float($value)) { - throw new TransformationFailedException('Expected an int or a float.'); - } - - if ($this->forceFullScale && is_int($this->scale)) { - if ($valueIsInt) { - $value = floatval($value); - } - - return number_format($value, $this->scale, '.', ''); - } - - try { - return (string) $value; - } catch (\Exception $e) { - throw new TransformationFailedException(); - } - } -} diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 78a2ba9510b2e..34fb04aed283e 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -17,7 +17,6 @@ use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\MappingException as LegacyMappingException; -use Symfony\Bridge\Doctrine\Form\Type\DecimalType; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; @@ -76,7 +75,7 @@ public function guessType($class, $property) case 'time_immutable': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\TimeType', ['input' => 'datetime_immutable'], Guess::HIGH_CONFIDENCE); case Type::DECIMAL: - return new TypeGuess(DecimalType::class, array(), Guess::HIGH_CONFIDENCE); + return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', ['input' => 'string'], Guess::MEDIUM_CONFIDENCE); case Type::FLOAT: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\NumberType', [], Guess::MEDIUM_CONFIDENCE); case Type::INTEGER: diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php deleted file mode 100644 index 6c67aacd4bcbb..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DecimalType.php +++ /dev/null @@ -1,50 +0,0 @@ -<?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\Bridge\Doctrine\Form\Type; - -use Symfony\Bridge\Doctrine\Form\DataTransformer\NumberToStringTransformer; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\NumberType; -use Symfony\Component\Form\FormBuilderInterface; -use Symfony\Component\OptionsResolver\OptionsResolver; - -class DecimalType extends AbstractType -{ - /** - * {@inheritdoc} - */ - public function buildForm(FormBuilderInterface $builder, array $options) - { - $builder->addModelTransformer(new NumberToStringTransformer($options['force_full_scale'], $options['scale'])); - } - - /** - * {@inheritdoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setDefaults(array( - 'force_full_scale' => false - )); - $resolver->setAllowedTypes('force_full_scale', array( - 'boolean' - )); - } - - /** - * {@inheritdoc} - */ - public function getParent() - { - return NumberType::class; - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php deleted file mode 100644 index 3601d30d03fa2..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Price.php +++ /dev/null @@ -1,40 +0,0 @@ -<?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\Bridge\Doctrine\Tests\Fixtures; - -use Doctrine\ORM\Mapping\Entity; -use Doctrine\ORM\Mapping\Id; -use Doctrine\ORM\Mapping\Column; - -/** @Entity */ -class Price -{ - /** @Id @Column(type="integer") */ - public $id; - - /** @Column(type="decimal", scale=2) */ - public $doesNotPreserveFullScaleValue; - - /** @Column(type="string") */ - public $preserveFullScaleValueSimulation; - - /** - * @param int $id - * @param float $value - */ - public function __construct(int $id, float $value) - { - $this->id = $id; - $this->doesNotPreserveFullScaleValue = $value; - $this->preserveFullScaleValueSimulation = number_format($value, 2, '.', ''); - } -} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php deleted file mode 100644 index f2ae341107941..0000000000000 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/DecimalTypeTest.php +++ /dev/null @@ -1,177 +0,0 @@ -<?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\Bridge\Doctrine\Tests\Form\Type; - -use Doctrine\ORM\EntityManager; -use Doctrine\ORM\Tools\SchemaTool; -use Symfony\Bridge\Doctrine\Form\Type\DecimalType; -use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; -use Symfony\Bridge\Doctrine\Tests\Fixtures\Price; -use Symfony\Component\Form\Extension\Core\Type\FormType; -use Symfony\Component\Form\Tests\Extension\Core\Type\BaseTypeTest; - -class DecimalTypeTest extends BaseTypeTest -{ - /** - * @var string - */ - const TESTED_TYPE = DecimalType::class; - - /** - * @var EntityManager - */ - private $em; - - protected function setUp() - { - $this->em = DoctrineTestHelper::createTestEntityManager(); - - parent::setUp(); - - $schemaTool = new SchemaTool($this->em); - $classes = array( - $this->em->getClassMetadata(Price::class) - ); - - try { - $schemaTool->dropSchema($classes); - } catch (\Exception $e) { - } - - try { - $schemaTool->createSchema($classes); - } catch (\Exception $e) { - } - } - - protected function tearDown() - { - parent::tearDown(); - - $this->em = null; - } - - // On some platforms, fetched decimal values are rounded (the full scale is not preserved) - // eg : on SQLite, inserted float value 4.50 will be fetched as string value "4.5" - public function testSubmitWithSameStringValueOnAPlatformThatDoesNotPreserveFullScaleValueWithoutForceFullScale() - { - $fullScalePrice = new Price(1, 1.23); - $nonFullScalePrice = new Price(2, 4.50); - $this->em->persist($fullScalePrice); - $this->em->persist($nonFullScalePrice); - $this->em->flush(); - - $this->em->refresh($fullScalePrice); - $this->em->refresh($nonFullScalePrice); - - $this->assertInternalType('string', $fullScalePrice->doesNotPreserveFullScaleValue); - $fullScalePriceStringValue = $fullScalePrice->doesNotPreserveFullScaleValue; - - $formBuilder = $this->factory->createBuilder(FormType::class, $fullScalePrice, array( - 'data_class' => Price::class - )); - $formBuilder->add('doesNotPreserveFullScaleValue', static::TESTED_TYPE, array( - 'force_full_scale' => false - )); - - $form = $formBuilder->getForm(); - $form->submit(array( - 'doesNotPreserveFullScaleValue' => $fullScalePriceStringValue - )); - - $this->assertSame($fullScalePriceStringValue, $fullScalePrice->doesNotPreserveFullScaleValue); - - $this->assertInternalType('string', $nonFullScalePrice->doesNotPreserveFullScaleValue); - $nonFullScalePriceStringValue = $nonFullScalePrice->doesNotPreserveFullScaleValue; - - $formBuilder = $this->factory->createBuilder(FormType::class, $nonFullScalePrice, array( - 'data_class' => Price::class - )); - $formBuilder->add('doesNotPreserveFullScaleValue', static::TESTED_TYPE, array( - 'force_full_scale' => false - )); - - $form = $formBuilder->getForm(); - $form->submit(array( - 'doesNotPreserveFullScaleValue' => $nonFullScalePriceStringValue - )); - - $this->assertSame($nonFullScalePriceStringValue, $nonFullScalePrice->doesNotPreserveFullScaleValue); - - $unitOfWork = $this->em->getUnitOfWork(); - $unitOfWork->computeChangeSets(); - - $this->assertSame(array(), $unitOfWork->getEntityChangeSet($fullScalePrice)); - $this->assertSame(array(), $unitOfWork->getEntityChangeSet($nonFullScalePrice)); - } - - // On some platforms, fetched decimal values are not rounded at all (the full scale is preserved) - // eg : on PostgreSQL, inserted float value 4.50 will be fetched as string value "4.50" - public function testSubmitWithSameStringValueOnAPlatformThatPreserveFullScaleValueWithForceFullScale() - { - $fullScalePrice = new Price(1, 1.23); - $nonFullScalePrice = new Price(2, 4.50); - $this->em->persist($fullScalePrice); - $this->em->persist($nonFullScalePrice); - $this->em->flush(); - - $this->em->refresh($fullScalePrice); - $this->em->refresh($nonFullScalePrice); - - $this->assertInternalType('string', $fullScalePrice->preserveFullScaleValueSimulation); - $fullScalePriceStringValue = $fullScalePrice->preserveFullScaleValueSimulation; - - $formBuilder = $this->factory->createBuilder(FormType::class, $fullScalePrice, array( - 'data_class' => Price::class - )); - $formBuilder->add('preserveFullScaleValueSimulation', static::TESTED_TYPE, array( - 'force_full_scale' => true, - 'scale' => 2 - )); - - $form = $formBuilder->getForm(); - $form->submit(array( - 'preserveFullScaleValueSimulation' => $fullScalePriceStringValue - )); - - $this->assertSame($fullScalePriceStringValue, $fullScalePrice->preserveFullScaleValueSimulation); - - $this->assertInternalType('string', $nonFullScalePrice->preserveFullScaleValueSimulation); - $nonFullScalePriceStringValue = $nonFullScalePrice->preserveFullScaleValueSimulation; - - $formBuilder = $this->factory->createBuilder(FormType::class, $nonFullScalePrice, array( - 'data_class' => Price::class - )); - $formBuilder->add('preserveFullScaleValueSimulation', static::TESTED_TYPE, array( - 'force_full_scale' => true, - 'scale' => 2 - )); - - $form = $formBuilder->getForm(); - $form->submit(array( - 'preserveFullScaleValueSimulation' => $nonFullScalePriceStringValue - )); - - $this->assertSame($nonFullScalePriceStringValue, $nonFullScalePrice->preserveFullScaleValueSimulation); - - $unitOfWork = $this->em->getUnitOfWork(); - $unitOfWork->computeChangeSets(); - - $this->assertSame(array(), $unitOfWork->getEntityChangeSet($fullScalePrice)); - $this->assertSame(array(), $unitOfWork->getEntityChangeSet($nonFullScalePrice)); - } - - public function testSubmitNull($expected = null, $norm = null, $view = null) - { - parent::testSubmitNull($expected, $norm, ''); - } -} diff --git a/src/Symfony/Component/Form/CHANGELOG.md b/src/Symfony/Component/Form/CHANGELOG.md index 0d3d468586f6b..ae21b1de9d590 100644 --- a/src/Symfony/Component/Form/CHANGELOG.md +++ b/src/Symfony/Component/Form/CHANGELOG.md @@ -47,6 +47,7 @@ CHANGELOG * dispatch `PostSubmitEvent` on `form.post_submit` * dispatch `PreSetDataEvent` on `form.pre_set_data` * dispatch `PostSetDataEvent` on `form.post_set_data` + * added an `input` option to `NumberType` 4.2.0 ----- diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php new file mode 100644 index 0000000000000..27e60b4306336 --- /dev/null +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/StringToFloatTransformer.php @@ -0,0 +1,65 @@ +<?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\Component\Form\Extension\Core\DataTransformer; + +use Symfony\Component\Form\DataTransformerInterface; +use Symfony\Component\Form\Exception\TransformationFailedException; + +class StringToFloatTransformer implements DataTransformerInterface +{ + private $scale; + + public function __construct(int $scale = null) + { + $this->scale = $scale; + } + + /** + * @param mixed $value + * + * @return float|null + */ + public function transform($value) + { + if (null === $value) { + return null; + } + + if (!\is_string($value) || !is_numeric($value)) { + throw new TransformationFailedException('Expected a numeric string.'); + } + + return (float) $value; + } + + /** + * @param mixed $value + * + * @return string|null + */ + public function reverseTransform($value) + { + if (null === $value) { + return null; + } + + if (!\is_int($value) && !\is_float($value)) { + throw new TransformationFailedException('Expected a numeric.'); + } + + if ($this->scale > 0) { + return number_format((float) $value, $this->scale, '.', ''); + } + + return (string) $value; + } +} diff --git a/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php b/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php index a0257f0269628..4c1f1fd71f16b 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/NumberType.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Extension\Core\DataTransformer\NumberToLocalizedStringTransformer; +use Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; @@ -33,6 +34,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) $options['rounding_mode'], $options['html5'] ? 'en' : null )); + + if ('string' === $options['input']) { + $builder->addModelTransformer(new StringToFloatTransformer($options['scale'])); + } } /** @@ -56,6 +61,7 @@ public function configureOptions(OptionsResolver $resolver) 'grouping' => false, 'rounding_mode' => NumberToLocalizedStringTransformer::ROUND_HALF_UP, 'compound' => false, + 'input' => 'number', 'html5' => false, ]); @@ -68,7 +74,7 @@ public function configureOptions(OptionsResolver $resolver) NumberToLocalizedStringTransformer::ROUND_UP, NumberToLocalizedStringTransformer::ROUND_CEILING, ]); - + $resolver->setAllowedValues('input', ['number', 'string']); $resolver->setAllowedTypes('scale', ['null', 'int']); $resolver->setAllowedTypes('html5', 'bool'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php new file mode 100644 index 0000000000000..5726a217da3d9 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/StringToFloatTransformerTest.php @@ -0,0 +1,104 @@ +<?php + +/* + * This file is part of the symfony/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\Component\Form\Tests\Extension\Core\DataTransformer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\Extension\Core\DataTransformer\StringToFloatTransformer; + +class StringToFloatTransformerTest extends TestCase +{ + private $transformer; + + protected function setUp() + { + $this->transformer = new StringToFloatTransformer(); + } + + protected function tearDown() + { + $this->transformer = null; + } + + public function provideTransformations(): array + { + return [ + [null, null], + ['1', 1.], + ['1.', 1.], + ['1.0', 1.], + ['1.23', 1.23], + ]; + } + + /** + * @dataProvider provideTransformations + */ + public function testTransform($from, $to): void + { + $transformer = new StringToFloatTransformer(); + + $this->assertSame($to, $transformer->transform($from)); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testFailIfTransformingANonString(): void + { + $transformer = new StringToFloatTransformer(); + $transformer->transform(1.0); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testFailIfTransformingANonNumericString(): void + { + $transformer = new StringToFloatTransformer(); + $transformer->transform('foobar'); + } + + public function provideReverseTransformations(): array + { + return [ + [null, null], + [1, '1'], + [1., '1'], + [1.0, '1'], + [1.23, '1.23'], + [1, '1.000', 3], + [1.0, '1.000', 3], + [1.23, '1.230', 3], + [1.2344, '1.234', 3], + [1.2345, '1.235', 3], + ]; + } + + /** + * @dataProvider provideReverseTransformations + */ + public function testReverseTransform($from, $to, int $scale = null): void + { + $transformer = new StringToFloatTransformer($scale); + + $this->assertSame($to, $transformer->reverseTransform($from)); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testFailIfReverseTransformingANonNumeric(): void + { + $transformer = new StringToFloatTransformer(); + $transformer->reverseTransform('foobar'); + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php index 1ab6c8e9fbc76..91b15ca7609ea 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/NumberTypeTest.php @@ -27,7 +27,7 @@ protected function setUp() \Locale::setDefault('de_DE'); } - public function testDefaultFormatting() + public function testDefaultFormatting(): void { $form = $this->factory->create(static::TESTED_TYPE); $form->setData('12345.67890'); @@ -35,7 +35,7 @@ public function testDefaultFormatting() $this->assertSame('12345,679', $form->createView()->vars['value']); } - public function testDefaultFormattingWithGrouping() + public function testDefaultFormattingWithGrouping(): void { $form = $this->factory->create(static::TESTED_TYPE, null, ['grouping' => true]); $form->setData('12345.67890'); @@ -43,7 +43,7 @@ public function testDefaultFormattingWithGrouping() $this->assertSame('12.345,679', $form->createView()->vars['value']); } - public function testDefaultFormattingWithScale() + public function testDefaultFormattingWithScale(): void { $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2]); $form->setData('12345.67890'); @@ -51,7 +51,23 @@ public function testDefaultFormattingWithScale() $this->assertSame('12345,68', $form->createView()->vars['value']); } - public function testDefaultFormattingWithRounding() + public function testDefaultFormattingWithScaleFloat(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2]); + $form->setData(12345.67890); + + $this->assertSame('12345,68', $form->createView()->vars['value']); + } + + public function testDefaultFormattingWithScaleAndStringInput(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 2, 'input' => 'string']); + $form->setData('12345.67890'); + + $this->assertSame('12345,68', $form->createView()->vars['value']); + } + + public function testDefaultFormattingWithRounding(): void { $form = $this->factory->create(static::TESTED_TYPE, null, ['scale' => 0, 'rounding_mode' => \NumberFormatter::ROUND_UP]); $form->setData('12345.54321'); @@ -76,6 +92,46 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = '10', $expectedD $this->assertSame($expectedData, $form->getData()); } + public function testSubmitNumericInput(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'number']); + $form->submit('1,234'); + + $this->assertSame(1.234, $form->getData()); + $this->assertSame(1.234, $form->getNormData()); + $this->assertSame('1,234', $form->getViewData()); + } + + public function testSubmitNumericInputWithScale(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'number', 'scale' => 2]); + $form->submit('1,234'); + + $this->assertSame(1.23, $form->getData()); + $this->assertSame(1.23, $form->getNormData()); + $this->assertSame('1,23', $form->getViewData()); + } + + public function testSubmitStringInput(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'string']); + $form->submit('1,234'); + + $this->assertSame('1.234', $form->getData()); + $this->assertSame(1.234, $form->getNormData()); + $this->assertSame('1,234', $form->getViewData()); + } + + public function testSubmitStringInputWithScale(): void + { + $form = $this->factory->create(static::TESTED_TYPE, null, ['input' => 'string', 'scale' => 2]); + $form->submit('1,234'); + + $this->assertSame('1.23', $form->getData()); + $this->assertSame(1.23, $form->getNormData()); + $this->assertSame('1,23', $form->getViewData()); + } + public function testIgnoresDefaultLocaleToRenderHtml5NumberWidgets() { $form = $this->factory->create(static::TESTED_TYPE, null, [ From 9bbdab68efa4e5a995f775eea320de53d0522c17 Mon Sep 17 00:00:00 2001 From: Titouan Galopin <galopintitouan@gmail.com> Date: Sat, 6 Apr 2019 14:57:24 +0200 Subject: [PATCH 399/495] [DomCrawler] Improve Crawler HTML5 parser need detection --- src/Symfony/Component/DomCrawler/Crawler.php | 25 +++---- .../DomCrawler/Tests/AbstractCrawlerTest.php | 73 +++++++++---------- .../Tests/Html5ParserCrawlerTest.php | 14 +++- .../Tests/NativeParserCrawlerTest.php | 10 +-- 4 files changed, 59 insertions(+), 63 deletions(-) diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 590462238b4be..4efbbf9b2d880 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -61,24 +61,15 @@ class Crawler implements \Countable, \IteratorAggregate private $html5Parser; /** - * @param mixed $node A Node to use as the base for the crawling - * @param string $uri The current URI - * @param string $baseHref The base href value - * @param bool|null $useHtml5Parser Whether the Crawler should use the HTML5 parser or the native DOM parser + * @param mixed $node A Node to use as the base for the crawling + * @param string $uri The current URI + * @param string $baseHref The base href value */ - public function __construct($node = null, string $uri = null, string $baseHref = null, bool $useHtml5Parser = null) + public function __construct($node = null, string $uri = null, string $baseHref = null) { $this->uri = $uri; $this->baseHref = $baseHref ?: $uri; - if ($useHtml5Parser && !class_exists(HTML5::class)) { - throw new \LogicException('Using the DomCrawler HTML5 parser requires the html5-php library. Try running "composer require masterminds/html5".'); - } - - if ($useHtml5Parser ?? class_exists(HTML5::class)) { - $this->html5Parser = new HTML5(['disable_html_ns' => true]); - } - $this->add($node); } @@ -198,6 +189,13 @@ public function addContent($content, $type = null) */ public function addHtmlContent($content, $charset = 'UTF-8') { + // Use HTML5 parser if the content is HTML5 and the library is available + if (!$this->html5Parser + && class_exists(HTML5::class) + && '<!doctype html>' === strtolower(substr(ltrim($content), 0, 15))) { + $this->html5Parser = new HTML5(['disable_html_ns' => true]); + } + $dom = null !== $this->html5Parser ? $this->parseHtml5($content, $charset) : $this->parseXhtml($content, $charset); $this->addDocument($dom); @@ -1219,6 +1217,7 @@ private function createSubCrawler($nodes) $crawler->isHtml = $this->isHtml; $crawler->document = $this->document; $crawler->namespaces = $this->namespaces; + $crawler->html5Parser = $this->html5Parser; return $crawler; } diff --git a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php index e77cb8cdf87ae..bc9777235c11a 100644 --- a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php @@ -16,14 +16,12 @@ abstract class AbstractCrawlerTest extends TestCase { - /** - * @param mixed $node - * @param string|null $uri - * @param string|null $baseHref - * - * @return Crawler - */ - abstract public function createCrawler($node = null, string $uri = null, string $baseHref = null); + abstract public function getDoctype(): string; + + protected function createCrawler($node = null, string $uri = null, string $baseHref = null) + { + return new Crawler($node, $uri, $baseHref); + } public function testConstructor() { @@ -74,7 +72,7 @@ public function testAdd() $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->add() adds nodes from a \DOMNode'); $crawler = $this->createCrawler(); - $crawler->add('<html><body>Foo</body></html>'); + $crawler->add($this->getDoctype().'<html><body>Foo</body></html>'); $this->assertEquals('Foo', $crawler->filterXPath('//body')->text(), '->add() adds nodes from a string'); } @@ -94,13 +92,13 @@ public function testAddInvalidType() public function testAddMultipleDocumentNode() { $crawler = $this->createTestCrawler(); - $crawler->addHtmlContent('<html><div class="foo"></html>', 'UTF-8'); + $crawler->addHtmlContent($this->getDoctype().'<html><div class="foo"></html>', 'UTF-8'); } public function testAddHtmlContent() { $crawler = $this->createCrawler(); - $crawler->addHtmlContent('<html><div class="foo"></html>', 'UTF-8'); + $crawler->addHtmlContent($this->getDoctype().'<html><div class="foo"></html>', 'UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addHtmlContent() adds nodes from an HTML string'); } @@ -108,8 +106,7 @@ public function testAddHtmlContent() public function testAddHtmlContentWithBaseTag() { $crawler = $this->createCrawler(); - - $crawler->addHtmlContent('<html><head><base href="http://symfony.com"></head><a href="/contact"></a></html>', 'UTF-8'); + $crawler->addHtmlContent($this->getDoctype().'<html><head><base href="http://symfony.com"></head><a href="/contact"></a></html>', 'UTF-8'); $this->assertEquals('http://symfony.com', $crawler->filterXPath('//base')->attr('href'), '->addHtmlContent() adds nodes from an HTML string'); $this->assertEquals('http://symfony.com/contact', $crawler->filterXPath('//a')->link()->getUri(), '->addHtmlContent() adds nodes from an HTML string'); @@ -121,7 +118,7 @@ public function testAddHtmlContentWithBaseTag() public function testAddHtmlContentCharset() { $crawler = $this->createCrawler(); - $crawler->addHtmlContent('<html><div class="foo">Tiếng Việt</html>', 'UTF-8'); + $crawler->addHtmlContent($this->getDoctype().'<html><div class="foo">Tiếng Việt</html>', 'UTF-8'); $this->assertEquals('Tiếng Việt', $crawler->filterXPath('//div')->text()); } @@ -129,7 +126,7 @@ public function testAddHtmlContentCharset() public function testAddHtmlContentInvalidBaseTag() { $crawler = $this->createCrawler(null, 'http://symfony.com'); - $crawler->addHtmlContent('<html><head><base target="_top"></head><a href="/contact"></a></html>', 'UTF-8'); + $crawler->addHtmlContent($this->getDoctype().'<html><head><base target="_top"></head><a href="/contact"></a></html>', 'UTF-8'); $this->assertEquals('http://symfony.com/contact', current($crawler->filterXPath('//a')->links())->getUri(), '->addHtmlContent() correctly handles a non-existent base tag href attribute'); } @@ -141,7 +138,7 @@ public function testAddHtmlContentCharsetGbk() { $crawler = $this->createCrawler(); //gbk encode of <html><p>中文</p></html> - $crawler->addHtmlContent(base64_decode('PGh0bWw+PHA+1tDOxDwvcD48L2h0bWw+'), 'gbk'); + $crawler->addHtmlContent($this->getDoctype().base64_decode('PGh0bWw+PHA+1tDOxDwvcD48L2h0bWw+'), 'gbk'); $this->assertEquals('中文', $crawler->filterXPath('//p')->text()); } @@ -149,7 +146,7 @@ public function testAddHtmlContentCharsetGbk() public function testAddXmlContent() { $crawler = $this->createCrawler(); - $crawler->addXmlContent('<html><div class="foo"></div></html>', 'UTF-8'); + $crawler->addXmlContent($this->getDoctype().'<html><div class="foo"></div></html>', 'UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addXmlContent() adds nodes from an XML string'); } @@ -157,7 +154,7 @@ public function testAddXmlContent() public function testAddXmlContentCharset() { $crawler = $this->createCrawler(); - $crawler->addXmlContent('<html><div class="foo">Tiếng Việt</div></html>', 'UTF-8'); + $crawler->addXmlContent($this->getDoctype().'<html><div class="foo">Tiếng Việt</div></html>', 'UTF-8'); $this->assertEquals('Tiếng Việt', $crawler->filterXPath('//div')->text()); } @@ -165,23 +162,23 @@ public function testAddXmlContentCharset() public function testAddContent() { $crawler = $this->createCrawler(); - $crawler->addContent('<html><div class="foo"></html>', 'text/html; charset=UTF-8'); + $crawler->addContent($this->getDoctype().'<html><div class="foo"></html>', 'text/html; charset=UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string'); $crawler = $this->createCrawler(); - $crawler->addContent('<html><div class="foo"></html>', 'text/html; charset=UTF-8; dir=RTL'); + $crawler->addContent($this->getDoctype().'<html><div class="foo"></html>', 'text/html; charset=UTF-8; dir=RTL'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an HTML string with extended content type'); $crawler = $this->createCrawler(); - $crawler->addContent('<html><div class="foo"></html>'); + $crawler->addContent($this->getDoctype().'<html><div class="foo"></html>'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() uses text/html as the default type'); $crawler = $this->createCrawler(); - $crawler->addContent('<html><div class="foo"></div></html>', 'text/xml; charset=UTF-8'); + $crawler->addContent($this->getDoctype().'<html><div class="foo"></div></html>', 'text/xml; charset=UTF-8'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string'); $crawler = $this->createCrawler(); - $crawler->addContent('<html><div class="foo"></div></html>', 'text/xml'); + $crawler->addContent($this->getDoctype().'<html><div class="foo"></div></html>', 'text/xml'); $this->assertEquals('foo', $crawler->filterXPath('//div')->attr('class'), '->addContent() adds nodes from an XML string'); $crawler = $this->createCrawler(); @@ -189,7 +186,7 @@ public function testAddContent() $this->assertCount(0, $crawler, '->addContent() does nothing if the type is not (x|ht)ml'); $crawler = $this->createCrawler(); - $crawler->addContent('<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><span>中文</span></html>'); + $crawler->addContent($this->getDoctype().'<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><span>中文</span></html>'); $this->assertEquals('中文', $crawler->filterXPath('//span')->text(), '->addContent() guess wrong charset'); } @@ -199,7 +196,7 @@ public function testAddContent() public function testAddContentNonUtf8() { $crawler = $this->createCrawler(); - $crawler->addContent(iconv('UTF-8', 'SJIS', '<html><head><meta charset="Shift_JIS"></head><body>日本語</body></html>')); + $crawler->addContent(iconv('UTF-8', 'SJIS', $this->getDoctype().'<html><head><meta charset="Shift_JIS"></head><body>日本語</body></html>')); $this->assertEquals('日本語', $crawler->filterXPath('//body')->text(), '->addContent() can recognize "Shift_JIS" in html5 meta charset tag'); } @@ -314,7 +311,7 @@ public function testAttr() public function testMissingAttrValueIsNull() { $crawler = $this->createCrawler(); - $crawler->addContent('<html><div non-empty-attr="sample value" empty-attr=""></div></html>', 'text/html; charset=UTF-8'); + $crawler->addContent($this->getDoctype().'<html><div non-empty-attr="sample value" empty-attr=""></div></html>', 'text/html; charset=UTF-8'); $div = $crawler->filterXPath('//div'); $this->assertEquals('sample value', $div->attr('non-empty-attr'), '->attr() reads non-empty attributes correctly'); @@ -670,7 +667,6 @@ public function testSelectButton() public function testSelectButtonWithSingleQuotesInNameAttribute() { $html = <<<'HTML' -<!DOCTYPE html> <html lang="en"> <body> <div id="action"> @@ -683,7 +679,7 @@ public function testSelectButtonWithSingleQuotesInNameAttribute() </html> HTML; - $crawler = $this->createCrawler($html); + $crawler = $this->createCrawler($this->getDoctype().$html); $this->assertCount(1, $crawler->selectButton('Click \'Here\'')); } @@ -691,7 +687,6 @@ public function testSelectButtonWithSingleQuotesInNameAttribute() public function testSelectButtonWithDoubleQuotesInNameAttribute() { $html = <<<'HTML' -<!DOCTYPE html> <html lang="en"> <body> <div id="action"> @@ -704,7 +699,7 @@ public function testSelectButtonWithDoubleQuotesInNameAttribute() </html> HTML; - $crawler = $this->createCrawler($html); + $crawler = $this->createCrawler($this->getDoctype().$html); $this->assertCount(1, $crawler->selectButton('Click "Here"')); } @@ -763,7 +758,6 @@ public function testImage() public function testSelectLinkAndLinkFiltered() { $html = <<<'HTML' -<!DOCTYPE html> <html lang="en"> <body> <div id="action"> @@ -776,7 +770,7 @@ public function testSelectLinkAndLinkFiltered() </html> HTML; - $crawler = $this->createCrawler($html); + $crawler = $this->createCrawler($this->getDoctype().$html); $filtered = $crawler->filterXPath("descendant-or-self::*[@id = 'login-form']"); $this->assertCount(0, $filtered->selectLink('Login')); @@ -793,7 +787,7 @@ public function testSelectLinkAndLinkFiltered() public function testChaining() { - $crawler = $this->createCrawler('<div name="a"><div name="b"><div name="c"></div></div></div>'); + $crawler = $this->createCrawler($this->getDoctype().'<div name="a"><div name="b"><div name="c"></div></div></div>'); $this->assertEquals('a', $crawler->filterXPath('//div')->filterXPath('div')->filterXPath('div')->attr('name')); } @@ -965,7 +959,6 @@ public function testChildren() public function testFilteredChildren() { $html = <<<'HTML' -<!DOCTYPE html> <html lang="en"> <body> <div id="foo"> @@ -981,7 +974,7 @@ public function testFilteredChildren() </html> HTML; - $crawler = $this->createCrawler($html); + $crawler = $this->createCrawler($this->getDoctype().$html); $foo = $crawler->filter('#foo'); $this->assertEquals(3, $foo->children()->count()); @@ -1018,7 +1011,7 @@ public function testParents() */ public function testBaseTag($baseValue, $linkValue, $expectedUri, $currentUri = null, $description = '') { - $crawler = $this->createCrawler('<html><base href="'.$baseValue.'"><a href="'.$linkValue.'"></a></html>', $currentUri); + $crawler = $this->createCrawler($this->getDoctype().'<html><base href="'.$baseValue.'"><a href="'.$linkValue.'"></a></html>', $currentUri); $this->assertEquals($expectedUri, $crawler->filterXPath('//a')->link()->getUri(), $description); } @@ -1038,7 +1031,7 @@ public function getBaseTagData() */ public function testBaseTagWithForm($baseValue, $actionValue, $expectedUri, $currentUri = null, $description = null) { - $crawler = $this->createCrawler('<html><base href="'.$baseValue.'"><form method="post" action="'.$actionValue.'"><button type="submit" name="submit"/></form></html>', $currentUri); + $crawler = $this->createCrawler($this->getDoctype().'<html><base href="'.$baseValue.'"><form method="post" action="'.$actionValue.'"><button type="submit" name="submit"/></form></html>', $currentUri); $this->assertEquals($expectedUri, $crawler->filterXPath('//button')->form()->getUri(), $description); } @@ -1113,7 +1106,7 @@ public function testEvaluateThrowsAnExceptionIfDocumentIsEmpty() public function testInheritedClassCallChildrenWithoutArgument() { $dom = new \DOMDocument(); - $dom->loadHTML(' + $dom->loadHTML($this->getDoctype().' <html> <body> <a href="foo">Foo</a> @@ -1165,7 +1158,7 @@ public function testInheritedClassCallChildrenWithoutArgument() public function testAddHtmlContentUnsupportedCharset() { $crawler = $this->createCrawler(); - $crawler->addHtmlContent(file_get_contents(__DIR__.'/Fixtures/windows-1250.html'), 'Windows-1250'); + $crawler->addHtmlContent($this->getDoctype().file_get_contents(__DIR__.'/Fixtures/windows-1250.html'), 'Windows-1250'); $this->assertEquals('Žťčýů', $crawler->filterXPath('//p')->text()); } @@ -1173,7 +1166,7 @@ public function testAddHtmlContentUnsupportedCharset() public function createTestCrawler($uri = null) { $dom = new \DOMDocument(); - $dom->loadHTML(' + $dom->loadHTML($this->getDoctype().' <html> <body> <a href="foo">Foo</a> diff --git a/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php index eec97e865acbd..8ada3794d7ed7 100644 --- a/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php @@ -11,12 +11,18 @@ namespace Symfony\Component\DomCrawler\Tests; -use Symfony\Component\DomCrawler\Crawler; - class Html5ParserCrawlerTest extends AbstractCrawlerTest { - public function createCrawler($node = null, string $uri = null, string $baseHref = null) + public function getDoctype(): string + { + return '<!DOCTYPE html>'; + } + + public function testAddHtml5() { - return new Crawler($node, $uri, $baseHref, true); + // Ensure a bug specific to the DOM extension is fixed (see https://github.com/symfony/symfony/issues/28596) + $crawler = $this->createCrawler(); + $crawler->add($this->getDoctype().'<html><body><h1><p>Foo</p></h1></body></html>'); + $this->assertEquals('Foo', $crawler->filterXPath('//h1')->text(), '->add() adds nodes from a string'); } } diff --git a/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php index 5a5a65b352017..a17562f735580 100644 --- a/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php @@ -11,13 +11,11 @@ namespace Symfony\Component\DomCrawler\Tests; -use Symfony\Component\DomCrawler\Crawler; - class NativeParserCrawlerTest extends AbstractCrawlerTest { - public function createCrawler($node = null, string $uri = null, string $baseHref = null) + public function getDoctype(): string { - return new Crawler($node, $uri, $baseHref, false); + return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'; } public function testAddHtmlContentWithErrors() @@ -26,7 +24,7 @@ public function testAddHtmlContentWithErrors() $crawler = $this->createCrawler(); $crawler->addHtmlContent(<<<'EOF' -<!DOCTYPE html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> </head> @@ -51,7 +49,7 @@ public function testAddXmlContentWithErrors() $crawler = $this->createCrawler(); $crawler->addXmlContent(<<<'EOF' -<!DOCTYPE html> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> </head> From 62ab7751544fa1d0d99e991d1fc8e9032170f8d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 15:51:37 +0200 Subject: [PATCH 400/495] [Workflow] The TransitionEvent is able to modify the context --- src/Symfony/Component/Workflow/CHANGELOG.md | 1 + .../Component/Workflow/Event/TransitionEvent.php | 11 +++++++++++ src/Symfony/Component/Workflow/Tests/Subject.php | 10 +++++++++- .../Component/Workflow/Tests/WorkflowTest.php | 16 ++++++++++++++++ src/Symfony/Component/Workflow/Workflow.php | 9 ++++++--- 5 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Workflow/CHANGELOG.md b/src/Symfony/Component/Workflow/CHANGELOG.md index c3869c0424391..5a32b915e50e7 100644 --- a/src/Symfony/Component/Workflow/CHANGELOG.md +++ b/src/Symfony/Component/Workflow/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * Trigger `entered` event for subject entering in the Workflow for the first time. * Added a context to `Workflow::apply()`. The `MethodMarkingStore` could be used to leverage this feature. + * The `TransitionEvent` is able to modify the context. * Add style to transitions by declaring metadata: use Symfony\Component\Workflow\Definition; diff --git a/src/Symfony/Component/Workflow/Event/TransitionEvent.php b/src/Symfony/Component/Workflow/Event/TransitionEvent.php index d45583fc1ebb1..424518453d361 100644 --- a/src/Symfony/Component/Workflow/Event/TransitionEvent.php +++ b/src/Symfony/Component/Workflow/Event/TransitionEvent.php @@ -13,4 +13,15 @@ class TransitionEvent extends Event { + private $context; + + public function setContext(array $context) + { + $this->context = $context; + } + + public function getContext(): array + { + return $this->context; + } } diff --git a/src/Symfony/Component/Workflow/Tests/Subject.php b/src/Symfony/Component/Workflow/Tests/Subject.php index fafb167ee7e4b..944cb228d66df 100644 --- a/src/Symfony/Component/Workflow/Tests/Subject.php +++ b/src/Symfony/Component/Workflow/Tests/Subject.php @@ -5,10 +5,12 @@ final class Subject { private $marking; + private $context; public function __construct($marking = null) { $this->marking = $marking; + $this->context = []; } public function getMarking() @@ -16,8 +18,14 @@ public function getMarking() return $this->marking; } - public function setMarking($marking) + public function setMarking($marking, array $context = []) { $this->marking = $marking; + $this->context = $context; + } + + public function getContext(): array + { + return $this->context; } } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 8762656a4550d..eb49b8d5fd742 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -7,6 +7,7 @@ use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Event\Event; use Symfony\Component\Workflow\Event\GuardEvent; +use Symfony\Component\Workflow\Event\TransitionEvent; use Symfony\Component\Workflow\Exception\NotEnabledTransitionException; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; @@ -418,6 +419,21 @@ public function testApplyWithEventDispatcher() $this->assertSame($eventNameExpected, $eventDispatcher->dispatchedEvents); } + public function testApplyWithContext() + { + $definition = $this->createComplexWorkflowDefinition(); + $subject = new Subject(); + $eventDispatcher = new EventDispatcher(); + $eventDispatcher->addListener('workflow.transition', function (TransitionEvent $event) { + $event->setContext(array_merge($event->getContext(), ['user' => 'admin'])); + }); + $workflow = new Workflow($definition, new MethodMarkingStore(), $eventDispatcher); + + $workflow->apply($subject, 't1', ['foo' => 'bar']); + + $this->assertSame(['foo' => 'bar', 'user' => 'admin'], $subject->getContext()); + } + public function testEventName() { $definition = $this->createComplexWorkflowDefinition(); diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 188d69e7d3c25..e3df8cb0d072d 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -176,7 +176,7 @@ public function apply($subject, $transitionName, array $context = []) $this->leave($subject, $transition, $marking); - $this->transition($subject, $transition, $marking); + $context = $this->transition($subject, $transition, $marking, $context); $this->enter($subject, $transition, $marking); @@ -308,17 +308,20 @@ private function leave($subject, Transition $transition, Marking $marking): void } } - private function transition($subject, Transition $transition, Marking $marking): void + private function transition($subject, Transition $transition, Marking $marking, array $context): array { if (null === $this->dispatcher) { - return; + return $context; } $event = new TransitionEvent($subject, $marking, $transition, $this); + $event->setContext($context); $this->dispatcher->dispatch($event, WorkflowEvents::TRANSITION); $this->dispatcher->dispatch($event, sprintf('workflow.%s.transition', $this->name)); $this->dispatcher->dispatch($event, sprintf('workflow.%s.transition.%s', $this->name, $transition->getName())); + + return $event->getContext(); } private function enter($subject, Transition $transition, Marking $marking): void From 997270f7ac8709068fb90ddfafc666d6557b4982 Mon Sep 17 00:00:00 2001 From: David Maicher <mail@dmaicher.de> Date: Sat, 6 Apr 2019 16:24:02 +0200 Subject: [PATCH 401/495] [Serializer] provide new ObjectPropertyListExtractorInterface --- .../Extractor/ObjectPropertyListExtractor.php | 39 ++++++++++++ .../ObjectPropertyListExtractorInterface.php | 28 +++++++++ .../ObjectPropertyListExtractorTest.php | 61 +++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php create mode 100644 src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php create mode 100644 src/Symfony/Component/Serializer/Tests/Extractor/ObjectPropertyListExtractorTest.php diff --git a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php new file mode 100644 index 0000000000000..8424a2ae730df --- /dev/null +++ b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php @@ -0,0 +1,39 @@ +<?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\Component\Serializer\Extractor; + +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; + +/** + * @author David Maicher <mail@dmaicher.de> + */ +class ObjectPropertyListExtractor implements ObjectPropertyListExtractorInterface +{ + private $propertyListExtractor; + private $objectClassResolver; + + public function __construct(PropertyListExtractorInterface $propertyListExtractor, ?callable $objectClassResolver = null) + { + $this->propertyListExtractor = $propertyListExtractor; + $this->objectClassResolver = $objectClassResolver; + } + + /** + * {@inheritdoc} + */ + public function getProperties($object, array $context = []) + { + $class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); + + return $this->propertyListExtractor->getProperties($class, $context); + } +} diff --git a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php new file mode 100644 index 0000000000000..d422e79f82b84 --- /dev/null +++ b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php @@ -0,0 +1,28 @@ +<?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\Component\Serializer\Extractor; + +/** + * @author David Maicher <mail@dmaicher.de> + */ +interface ObjectPropertyListExtractorInterface +{ + /** + * Gets the list of properties available for the given object. + * + * @param object $object + * @param array $context + * + * @return string[]|null + */ + public function getProperties($object, array $context = []); +} diff --git a/src/Symfony/Component/Serializer/Tests/Extractor/ObjectPropertyListExtractorTest.php b/src/Symfony/Component/Serializer/Tests/Extractor/ObjectPropertyListExtractorTest.php new file mode 100644 index 0000000000000..9701628e9008e --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Extractor/ObjectPropertyListExtractorTest.php @@ -0,0 +1,61 @@ +<?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\Component\Serializer\Tests\Extractor; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; +use Symfony\Component\Serializer\Extractor\ObjectPropertyListExtractor; + +class ObjectPropertyListExtractorTest extends TestCase +{ + public function testGetPropertiesWithoutObjectClassResolver(): void + { + $object = new \stdClass(); + $context = ['bar' => true]; + $properties = ['prop1', 'prop2']; + + $propertyListExtractor = $this->createMock(PropertyListExtractorInterface::class); + $propertyListExtractor->expects($this->once()) + ->method('getProperties') + ->with(\get_class($object), $context) + ->willReturn($properties); + + $this->assertSame( + $properties, + (new ObjectPropertyListExtractor($propertyListExtractor))->getProperties($object, $context) + ); + } + + public function testGetPropertiesWithObjectClassResolver(): void + { + $object = new \stdClass(); + $classResolver = function ($objectArg) use ($object): string { + $this->assertSame($object, $objectArg); + + return 'foo'; + }; + + $context = ['bar' => true]; + $properties = ['prop1', 'prop2']; + + $propertyListExtractor = $this->createMock(PropertyListExtractorInterface::class); + $propertyListExtractor->expects($this->once()) + ->method('getProperties') + ->with('foo', $context) + ->willReturn($properties); + + $this->assertSame( + $properties, + (new ObjectPropertyListExtractor($propertyListExtractor, $classResolver))->getProperties($object, $context) + ); + } +} From c97686656642ed49d162d71fd195118fabf02830 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera <pol.dellaiera@protonmail.com> Date: Sat, 6 Apr 2019 16:33:16 +0200 Subject: [PATCH 402/495] [symfony/HttpKernel] Throws an error when the generated class name is invalid. --- src/Symfony/Component/HttpKernel/Kernel.php | 9 ++++++++- .../Component/HttpKernel/Tests/KernelTest.php | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 5cc15dbbf9b90..0dcdc717d9b22 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -442,14 +442,21 @@ protected function build(ContainerBuilder $container) /** * Gets the container class. * + * @throws \InvalidArgumentException If the generated classname is invalid + * * @return string The container class */ protected function getContainerClass() { $class = \get_class($this); $class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).str_replace('.', '_', ContainerBuilder::hash($class)) : $class; + $class = $this->name.str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; + + if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $class)) { + throw new \InvalidArgumentException(sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment)); + } - return $this->name.str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; + return $class; } /** diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index 1b66de40ffaf6..5be4fc8d83585 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -64,6 +64,20 @@ public function testClone() $this->assertNull($clone->getContainer()); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The environment "test.env" contains invalid characters, it can only contain characters allowed in PHP class names. + */ + public function testClassNameValidityGetter() + { + // We check the classname that will be generated by using a $env that + // contains invalid characters. + $env = 'test.env'; + $kernel = new KernelForTest($env, false); + + $kernel->boot(); + } + public function testInitializeContainerClearsOldContainers() { $fs = new Filesystem(); From a2f99757f1fa338e982deecc9ec6dc2b6922eb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 16:34:59 +0200 Subject: [PATCH 403/495] [Workflow] Added workflow_transition_blockers twig function --- src/Symfony/Bridge/Twig/CHANGELOG.md | 1 + .../Bridge/Twig/Extension/WorkflowExtension.php | 9 +++++++++ .../Twig/Tests/Extension/WorkflowExtensionTest.php | 13 +++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 35752fff125a3..3b806c47fb2b0 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * added the `form_parent()` function that allows to reliably retrieve the parent form in Twig templates + * added the `workflow_transition_blockers()` function 4.2.0 ----- diff --git a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php index 05c236a1648da..85b4f7a4d73cd 100644 --- a/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @@ -13,6 +13,7 @@ use Symfony\Component\Workflow\Registry; use Symfony\Component\Workflow\Transition; +use Symfony\Component\Workflow\TransitionBlockerList; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; @@ -38,6 +39,7 @@ public function getFunctions() new TwigFunction('workflow_has_marked_place', [$this, 'hasMarkedPlace']), new TwigFunction('workflow_marked_places', [$this, 'getMarkedPlaces']), new TwigFunction('workflow_metadata', [$this, 'getMetadata']), + new TwigFunction('workflow_transition_blockers', [$this, 'buildTransitionBlockerList']), ]; } @@ -120,6 +122,13 @@ public function getMetadata($subject, string $key, $metadataSubject = null, stri ; } + public function buildTransitionBlockerList($subject, string $transitionName, string $name = null): TransitionBlockerList + { + $workflow = $this->workflowRegistry->get($subject, $name); + + return $workflow->buildTransitionBlockerList($subject, $transitionName); + } + public function getName() { return 'workflow'; diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php index 32f4e82dad1c8..3e948bae3f50e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @@ -20,6 +20,7 @@ use Symfony\Component\Workflow\SupportStrategy\ClassInstanceSupportStrategy; use Symfony\Component\Workflow\SupportStrategy\InstanceOfSupportStrategy; use Symfony\Component\Workflow\Transition; +use Symfony\Component\Workflow\TransitionBlockerList; use Symfony\Component\Workflow\Workflow; class WorkflowExtensionTest extends TestCase @@ -110,6 +111,18 @@ public function testGetMetadata() $this->assertNull($this->extension->getMetadata($subject, 'not found')); $this->assertNull($this->extension->getMetadata($subject, 'not found', $this->t1)); } + + public function testbuildTransitionBlockerList() + { + if (!class_exists(TransitionBlockerList::class)) { + $this->markTestSkipped('This test requires symfony/workflow:4.1.'); + } + $subject = new Subject(); + + $list = $this->extension->buildTransitionBlockerList($subject, 't1'); + $this->assertInstanceOf(TransitionBlockerList::class, $list); + $this->assertTrue($list->isEmpty()); + } } final class Subject From aecca9778e3ef42e3c2c7794243ca8cd6c13c00d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= <jeremy@derusse.com> Date: Fri, 5 Apr 2019 19:29:13 +0200 Subject: [PATCH 404/495] Use FormUrlEncoded when posting non-binary data --- .../Component/BrowserKit/HttpBrowser.php | 35 +++++++---- .../BrowserKit/Tests/HttpBrowserTest.php | 60 +++++++++++++++++++ 2 files changed, 85 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/BrowserKit/HttpBrowser.php b/src/Symfony/Component/BrowserKit/HttpBrowser.php index cb13c738d38f9..7492e58907cb7 100644 --- a/src/Symfony/Component/BrowserKit/HttpBrowser.php +++ b/src/Symfony/Component/BrowserKit/HttpBrowser.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpClient\HttpClient; use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; use Symfony\Component\Mime\Part\Multipart\FormDataPart; use Symfony\Component\Mime\Part\TextPart; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -43,13 +44,10 @@ public function __construct(HttpClientInterface $client = null, History $history protected function doRequest($request) { $headers = $this->getHeaders($request); - $body = ''; - if (null !== $part = $this->getBody($request)) { - $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); - $body = $part->bodyToIterable(); - } + [$body, $extraHeaders] = $this->getBodyAndExtraHeaders($request); + $response = $this->client->request($request->getMethod(), $request->getUri(), [ - 'headers' => $headers, + 'headers' => array_merge($headers, $extraHeaders), 'body' => $body, 'max_redirects' => 0, ]); @@ -57,10 +55,13 @@ protected function doRequest($request) return new Response($response->getContent(false), $response->getStatusCode(), $response->getHeaders(false)); } - private function getBody(Request $request): ?AbstractPart + /** + * @return array [$body, $headers] + */ + private function getBodyAndExtraHeaders(Request $request): array { if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { - return null; + return ['', []]; } if (!class_exists(AbstractPart::class)) { @@ -68,19 +69,33 @@ private function getBody(Request $request): ?AbstractPart } if (null !== $content = $request->getContent()) { - return new TextPart($content, 'utf-8', 'plain', '8bit'); + $part = new TextPart($content, 'utf-8', 'plain', '8bit'); + + return [$part->bodyToString(), $part->getPreparedHeaders()->toArray()]; } $fields = $request->getParameters(); + $hasFile = false; foreach ($request->getFiles() as $name => $file) { if (!isset($file['tmp_name'])) { continue; } + $hasFile = true; $fields[$name] = DataPart::fromPath($file['tmp_name'], $file['name']); } - return new FormDataPart($fields); + if ($hasFile) { + $part = new FormDataPart($fields); + + return [$part->bodyToIterable(), $part->getPreparedHeaders()->toArray()]; + } + + if (empty($fields)) { + return ['', []]; + } + + return [http_build_query($fields, '', '&', PHP_QUERY_RFC1738), ['Content-Type' => 'application/x-www-form-urlencoded']]; } private function getHeaders(Request $request): array diff --git a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php index 266dd9a7ebe98..cd3b2c60b6ffd 100644 --- a/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/HttpBrowserTest.php @@ -17,6 +17,8 @@ use Symfony\Component\BrowserKit\Response; use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\Response\MockResponse; +use Symfony\Contracts\HttpClient\HttpClientInterface; +use Symfony\Contracts\HttpClient\ResponseInterface; class SpecialHttpResponse extends Response { @@ -112,4 +114,62 @@ public function testGetInternalResponse() $this->assertNotInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getInternalResponse()); $this->assertInstanceOf('Symfony\Component\BrowserKit\Tests\SpecialHttpResponse', $client->getResponse()); } + + /** + * @dataProvider validContentTypes + */ + public function testRequestHeaders(array $request, array $exepectedCall) + { + $client = $this->createMock(HttpClientInterface::class); + $client + ->expects($this->once()) + ->method('request') + ->with(...$exepectedCall) + ->willReturn($this->createMock(ResponseInterface::class)); + + $browser = new HttpBrowser($client); + $browser->request(...$request); + } + + public function validContentTypes() + { + $defaultHeaders = ['user-agent' => 'Symfony BrowserKit', 'host' => 'example.com']; + yield 'GET/HEAD' => [ + ['GET', 'http://example.com/', ['key' => 'value']], + ['GET', 'http://example.com/', ['headers' => $defaultHeaders, 'body' => '', 'max_redirects' => 0]], + ]; + yield 'empty form' => [ + ['POST', 'http://example.com/'], + ['POST', 'http://example.com/', ['headers' => $defaultHeaders, 'body' => '', 'max_redirects' => 0]], + ]; + yield 'form' => [ + ['POST', 'http://example.com/', ['key' => 'value', 'key2' => 'value']], + ['POST', 'http://example.com/', ['headers' => $defaultHeaders + ['Content-Type' => 'application/x-www-form-urlencoded'], 'body' => 'key=value&key2=value', 'max_redirects' => 0]], + ]; + yield 'content' => [ + ['POST', 'http://example.com/', [], [], [], 'content'], + ['POST', 'http://example.com/', ['headers' => $defaultHeaders + ['Content-Type: text/plain; charset=utf-8', 'Content-Transfer-Encoding: 8bit'], 'body' => 'content', 'max_redirects' => 0]], + ]; + } + + public function testMultiPartRequest() + { + $client = $this->createMock(HttpClientInterface::class); + $client + ->expects($this->once()) + ->method('request') + ->with('POST', 'http://example.com/', $this->callback(function ($options) { + $this->assertContains('Content-Type: multipart/form-data', implode('', $options['headers'])); + $this->assertInstanceOf('\Generator', $options['body']); + $this->assertContains('my_file', implode('', iterator_to_array($options['body']))); + + return true; + })) + ->willReturn($this->createMock(ResponseInterface::class)); + + $browser = new HttpBrowser($client); + $path = tempnam(sys_get_temp_dir(), 'http'); + file_put_contents($path, 'my_file'); + $browser->request('POST', 'http://example.com/', [], ['file' => ['tmp_name' => $path, 'name' => 'foo']]); + } } From 8ac712b29db0bb6a709e54e228955f879c296a5d Mon Sep 17 00:00:00 2001 From: Titouan Galopin <galopintitouan@gmail.com> Date: Sat, 6 Apr 2019 15:53:27 +0200 Subject: [PATCH 405/495] [Validator] Wire NotCompromisedPassword in FrameworkBundle and handle non UTF-8 password --- .../Resources/config/validator.xml | 6 ++ .../NotCompromisedPasswordValidator.php | 8 +- .../NotCompromisedPasswordValidatorTest.php | 79 +++++++++++++------ 3 files changed, 68 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml index 4fd3da7a633ea..95e35d54ce2ee 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml @@ -61,6 +61,12 @@ <tag name="validator.constraint_validator" alias="Symfony\Component\Validator\Constraints\EmailValidator" /> </service> + <service id="validator.not_compromised_password" class="Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator"> + <argument type="service" id="http_client" on-invalid="null" /> + <argument>%kernel.charset%</argument> + <tag name="validator.constraint_validator" alias="Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator" /> + </service> + <service id="validator.property_info_loader" class="Symfony\Component\Validator\Mapping\Loader\PropertyInfoLoader"> <argument type="service" id="property_info" /> <argument type="service" id="property_info" /> diff --git a/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php index 7abdbf23b26e8..a432e90fc04e2 100644 --- a/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php @@ -31,14 +31,16 @@ class NotCompromisedPasswordValidator extends ConstraintValidator private const RANGE_API = 'https://api.pwnedpasswords.com/range/%s'; private $httpClient; + private $charset; - public function __construct(HttpClientInterface $httpClient = null) + public function __construct(HttpClientInterface $httpClient = null, string $charset = 'UTF-8') { if (null === $httpClient && !class_exists(HttpClient::class)) { throw new \LogicException(sprintf('The "%s" class requires the "HttpClient" component. Try running "composer require symfony/http-client".', self::class)); } $this->httpClient = $httpClient ?? HttpClient::create(); + $this->charset = $charset; } /** @@ -61,6 +63,10 @@ public function validate($value, Constraint $constraint) return; } + if ('UTF-8' !== $this->charset) { + $value = mb_convert_encoding($value, 'UTF-8', $this->charset); + } + $hash = strtoupper(sha1($value)); $hashPrefix = substr($hash, 0, 5); $url = sprintf(self::RANGE_API, $hashPrefix); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php index d80ed94b52d6d..3ea3f821e0ac7 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php @@ -28,40 +28,22 @@ class NotCompromisedPasswordValidatorTest extends ConstraintValidatorTestCase private const PASSWORD_TRIGGERING_AN_ERROR_RANGE_URL = 'https://api.pwnedpasswords.com/range/3EF27'; // https://api.pwnedpasswords.com/range/3EF27 is the range for the value "apiError" private const PASSWORD_LEAKED = 'maman'; private const PASSWORD_NOT_LEAKED = ']<0585"%sb^5aa$w6!b38",,72?dp3r4\45b28Hy'; + private const PASSWORD_NON_UTF8_LEAKED = 'мама'; + private const PASSWORD_NON_UTF8_NOT_LEAKED = 'м<в0dp3r4\45b28Hy'; private const RETURN = [ '35E033023A46402F94CFB4F654C5BFE44A1:1', '35F079CECCC31812288257CD770AA7968D7:53', - '36039744C253F9B2A4E90CBEDB02EBFB82D:5', // this is the matching line, password: maman + '36039744C253F9B2A4E90CBEDB02EBFB82D:5', // UTF-8 leaked password: maman + '273CA8A2A78C9B2D724144F4FAF4D221C86:6', // ISO-8859-5 leaked password: мама '3686792BBC66A72D40D928ED15621124CFE:7', '36EEC709091B810AA240179A44317ED415C:2', ]; protected function createValidator() { - $httpClientStub = $this->createMock(HttpClientInterface::class); - $httpClientStub->method('request')->will( - $this->returnCallback(function (string $method, string $url): ResponseInterface { - if (self::PASSWORD_TRIGGERING_AN_ERROR_RANGE_URL === $url) { - throw new class('Problem contacting the Have I been Pwned API.') extends \Exception implements ServerExceptionInterface { - public function getResponse(): ResponseInterface - { - throw new \RuntimeException('Not implemented'); - } - }; - } - - $responseStub = $this->createMock(ResponseInterface::class); - $responseStub - ->method('getContent') - ->willReturn(implode("\r\n", self::RETURN)); - - return $responseStub; - }) - ); - - // Pass HttpClient::create() instead of this mock to run the tests against the real API - return new NotCompromisedPasswordValidator($httpClientStub); + // Pass HttpClient::create() instead of the mock to run the tests against the real API + return new NotCompromisedPasswordValidator($this->createHttpClientStub()); } public function testNullIsValid() @@ -112,6 +94,29 @@ public function testValidPassword() $this->assertNoViolation(); } + public function testNonUtf8CharsetValid() + { + $validator = new NotCompromisedPasswordValidator($this->createHttpClientStub(), 'ISO-8859-5'); + $validator->validate(mb_convert_encoding(self::PASSWORD_NON_UTF8_NOT_LEAKED, 'ISO-8859-5', 'UTF-8'), new NotCompromisedPassword()); + + $this->assertNoViolation(); + } + + public function testNonUtf8CharsetInvalid() + { + $constraint = new NotCompromisedPassword(); + + $this->context = $this->createContext(); + + $validator = new NotCompromisedPasswordValidator($this->createHttpClientStub(), 'ISO-8859-5'); + $validator->initialize($this->context); + $validator->validate(mb_convert_encoding(self::PASSWORD_NON_UTF8_LEAKED, 'ISO-8859-5', 'UTF-8'), $constraint); + + $this->buildViolation($constraint->message) + ->setCode(NotCompromisedPassword::COMPROMISED_PASSWORD_ERROR) + ->assertRaised(); + } + /** * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException */ @@ -142,4 +147,30 @@ public function testApiErrorSkipped() $this->validator->validate(self::PASSWORD_TRIGGERING_AN_ERROR, new NotCompromisedPassword(['skipOnError' => true])); $this->assertTrue(true); // No exception have been thrown } + + private function createHttpClientStub(): HttpClientInterface + { + $httpClientStub = $this->createMock(HttpClientInterface::class); + $httpClientStub->method('request')->will( + $this->returnCallback(function (string $method, string $url): ResponseInterface { + if (self::PASSWORD_TRIGGERING_AN_ERROR_RANGE_URL === $url) { + throw new class('Problem contacting the Have I been Pwned API.') extends \Exception implements ServerExceptionInterface { + public function getResponse(): ResponseInterface + { + throw new \RuntimeException('Not implemented'); + } + }; + } + + $responseStub = $this->createMock(ResponseInterface::class); + $responseStub + ->method('getContent') + ->willReturn(implode("\r\n", self::RETURN)); + + return $responseStub; + }) + ); + + return $httpClientStub; + } } From 07d90f987ed064da501b974d5f2af38709ed5237 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet <stof@notk.org> Date: Sat, 6 Apr 2019 19:22:14 +0200 Subject: [PATCH 406/495] Move doctrine/collections to an optional dep in doctrine-bridge The EntityType does not need to convert the array to a collection if the project does not care about using doctrine/collections. So this can become an optional dependency. --- src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php | 3 ++- src/Symfony/Bridge/Doctrine/composer.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 327e7abb05600..cd3534d51253f 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Form\Type; +use Doctrine\Common\Collections\Collection; use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\Common\Persistence\ObjectManager; use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader; @@ -107,7 +108,7 @@ public function __construct(ManagerRegistry $registry) public function buildForm(FormBuilderInterface $builder, array $options) { - if ($options['multiple']) { + if ($options['multiple'] && interface_exists(Collection::class)) { $builder ->addEventSubscriber(new MergeDoctrineCollectionListener()) ->addViewTransformer(new CollectionToArrayTransformer(), true) diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 849d2069adb98..819af8522046f 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -17,7 +17,6 @@ ], "require": { "php": "^7.1.3", - "doctrine/collections": "~1.0", "doctrine/event-manager": "~1.0", "doctrine/persistence": "~1.0", "symfony/contracts": "^1.0", @@ -39,6 +38,7 @@ "symfony/translation": "~3.4|~4.0", "doctrine/annotations": "~1.0", "doctrine/cache": "~1.6", + "doctrine/collections": "~1.0", "doctrine/data-fixtures": "1.0.*", "doctrine/dbal": "~2.4", "doctrine/orm": "^2.4.5", From 31b3a55787ea03746371d296f5d63fa11cfde0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois-Xavier=20de=20Guillebon?= <fx@gensdeconfiance.fr> Date: Sat, 6 Apr 2019 16:34:11 +0200 Subject: [PATCH 407/495] Add comments when dumping po files --- .../Translation/Dumper/PoFileDumper.php | 23 +++++++++++++++++++ .../Tests/Dumper/PoFileDumperTest.php | 21 ++++++++++++++++- .../Translation/Tests/fixtures/resources.po | 13 +++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Dumper/PoFileDumper.php b/src/Symfony/Component/Translation/Dumper/PoFileDumper.php index 0f7e6fa834bc2..5f60086285f91 100644 --- a/src/Symfony/Component/Translation/Dumper/PoFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/PoFileDumper.php @@ -39,6 +39,18 @@ public function formatCatalogue(MessageCatalogue $messages, $domain, array $opti } else { $newLine = true; } + $metadata = $messages->getMetadata($source, $domain); + + if (isset($metadata['comments'])) { + $output .= $this->formatComments($metadata['comments']); + } + if (isset($metadata['flags'])) { + $output .= $this->formatComments(implode(',', (array) $metadata['flags']), ','); + } + if (isset($metadata['sources'])) { + $output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':'); + } + $output .= sprintf('msgid "%s"'."\n", $this->escape($source)); $output .= sprintf('msgstr "%s"'."\n", $this->escape($target)); } @@ -58,4 +70,15 @@ private function escape($str) { return addcslashes($str, "\0..\37\42\134"); } + + private function formatComments($comments, string $prefix = ''): ?string + { + $output = null; + + foreach ((array) $comments as $comment) { + $output .= sprintf('#%s %s'."\n", $prefix, $comment); + } + + return $output; + } } diff --git a/src/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php b/src/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php index 960ec2df6500c..46df869f89e6a 100644 --- a/src/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php +++ b/src/Symfony/Component/Translation/Tests/Dumper/PoFileDumperTest.php @@ -20,7 +20,26 @@ class PoFileDumperTest extends TestCase public function testFormatCatalogue() { $catalogue = new MessageCatalogue('en'); - $catalogue->add(['foo' => 'bar', 'bar' => 'foo']); + $catalogue->add(['foo' => 'bar', 'bar' => 'foo', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo']); + $catalogue->setMetadata('foo_bar', [ + 'comments' => [ + 'Comment 1', + 'Comment 2', + ], + 'flags' => [ + 'fuzzy', + 'another', + ], + 'sources' => [ + 'src/file_1', + 'src/file_2:50', + ], + ]); + $catalogue->setMetadata('bar_foo', [ + 'comments' => 'Comment', + 'flags' => 'fuzzy', + 'sources' => 'src/file_1', + ]); $dumper = new PoFileDumper(); diff --git a/src/Symfony/Component/Translation/Tests/fixtures/resources.po b/src/Symfony/Component/Translation/Tests/fixtures/resources.po index a20e619828ce6..68e0f2d7e0882 100644 --- a/src/Symfony/Component/Translation/Tests/fixtures/resources.po +++ b/src/Symfony/Component/Translation/Tests/fixtures/resources.po @@ -9,3 +9,16 @@ msgstr "bar" msgid "bar" msgstr "foo" + +# Comment 1 +# Comment 2 +#, fuzzy,another +#: src/file_1 src/file_2:50 +msgid "foo_bar" +msgstr "foobar" + +# Comment +#, fuzzy +#: src/file_1 +msgid "bar_foo" +msgstr "barfoo" From 6e0785f8c52af4c0fe9c6b5264a9f66b483d0d6a Mon Sep 17 00:00:00 2001 From: error56 <46536532+error56@users.noreply.github.com> Date: Sat, 6 Apr 2019 18:09:06 +0200 Subject: [PATCH 408/495] [Profiler] Update ProfilerController.php --- .../Controller/ProfilerController.php | 45 +++++++------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index 35cf31fbf99e9..2dc1c62436a8a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -54,11 +54,7 @@ public function __construct(UrlGeneratorInterface $generator, Profiler $profiler */ public function homeAction() { - if (null === $this->profiler) { - throw new NotFoundHttpException('The profiler must be enabled.'); - } - - $this->profiler->disable(); + $this->denyAccessIfProfilerDisabled(); return new RedirectResponse($this->generator->generate('_profiler_search_results', ['token' => 'empty', 'limit' => 10]), 302, ['Content-Type' => 'text/html']); } @@ -75,11 +71,7 @@ public function homeAction() */ public function panelAction(Request $request, $token) { - if (null === $this->profiler) { - throw new NotFoundHttpException('The profiler must be enabled.'); - } - - $this->profiler->disable(); + $this->denyAccessIfProfilerDisabled(); if (null !== $this->cspHandler) { $this->cspHandler->disableCsp(); @@ -170,11 +162,7 @@ public function toolbarAction(Request $request, $token) */ public function searchBarAction(Request $request) { - if (null === $this->profiler) { - throw new NotFoundHttpException('The profiler must be enabled.'); - } - - $this->profiler->disable(); + $this->denyAccessIfProfilerDisabled(); if (null !== $this->cspHandler) { $this->cspHandler->disableCsp(); @@ -231,11 +219,7 @@ public function searchBarAction(Request $request) */ public function searchResultsAction(Request $request, $token) { - if (null === $this->profiler) { - throw new NotFoundHttpException('The profiler must be enabled.'); - } - - $this->profiler->disable(); + $this->denyAccessIfProfilerDisabled(); if (null !== $this->cspHandler) { $this->cspHandler->disableCsp(); @@ -276,11 +260,7 @@ public function searchResultsAction(Request $request, $token) */ public function searchAction(Request $request) { - if (null === $this->profiler) { - throw new NotFoundHttpException('The profiler must be enabled.'); - } - - $this->profiler->disable(); + $this->denyAccessIfProfilerDisabled(); $ip = preg_replace('/[^:\d\.]/', '', $request->query->get('ip')); $method = $request->query->get('method'); @@ -331,11 +311,7 @@ public function searchAction(Request $request) */ public function phpinfoAction() { - if (null === $this->profiler) { - throw new NotFoundHttpException('The profiler must be enabled.'); - } - - $this->profiler->disable(); + $this->denyAccessIfProfilerDisabled(); if (null !== $this->cspHandler) { $this->cspHandler->disableCsp(); @@ -394,6 +370,15 @@ protected function getTemplateManager() return $this->templateManager; } + + private function denyAccessIfProfilerDisabled() + { + if (null === $this->profiler) { + throw new NotFoundHttpException('The profiler must be enabled.'); + } + + $this->profiler->disable(); + } private function renderWithCspNonces(Request $request, $template, $variables, $code = 200, $headers = ['Content-Type' => 'text/html']) { From a5246589cfce82b66782b8da44abb82aa240fe0e Mon Sep 17 00:00:00 2001 From: Remon van de Kamp <rpkamp@gmail.com> Date: Sat, 20 Oct 2018 17:47:06 +0200 Subject: [PATCH 409/495] Improve Translator caching --- .../FrameworkExtension.php | 26 ++++++++++++++----- .../FrameworkExtensionTest.php | 22 ++++++++++++++++ .../Tests/Translation/TranslatorTest.php | 25 ++++++++++++++++++ .../Translation/Translator.php | 19 ++++++++++++++ .../Component/Translation/Translator.php | 5 +++- 5 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 670033be015bf..d3998bc758243 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1075,6 +1075,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder // Discover translation directories $dirs = []; $transPaths = []; + $nonExistingDirs = []; if (class_exists('Symfony\Component\Validator\Validation')) { $r = new \ReflectionClass('Symfony\Component\Validator\Validation'); @@ -1093,18 +1094,21 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $defaultDir = $container->getParameterBag()->resolveValue($config['default_path']); $rootDir = $container->getParameter('kernel.root_dir'); foreach ($container->getParameter('kernel.bundles_metadata') as $name => $bundle) { - if ($container->fileExists($dir = $bundle['path'].'/Resources/translations')) { + if (\is_dir($dir = $bundle['path'].'/Resources/translations')) { $dirs[] = $dir; + } else { + $nonExistingDirs[] = $dir; } - if ($container->fileExists($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) { + if (\is_dir($dir = $rootDir.sprintf('/Resources/%s/translations', $name))) { @trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED); - $dirs[] = $dir; + } else { + $nonExistingDirs[] = $dir; } } foreach ($config['paths'] as $dir) { - if ($container->fileExists($dir)) { + if (\is_dir($dir)) { $dirs[] = $transPaths[] = $dir; } else { throw new \UnexpectedValueException(sprintf('%s defined in translator.paths does not exist or is not a directory', $dir)); @@ -1119,15 +1123,20 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $container->getDefinition('console.command.translation_update')->replaceArgument(6, $transPaths); } - if ($container->fileExists($defaultDir)) { + if (\is_dir($defaultDir)) { $dirs[] = $defaultDir; + } else { + $nonExistingDirs[] = $defaultDir; } - if ($container->fileExists($dir = $rootDir.'/Resources/translations')) { + + if (\is_dir($dir = $rootDir.'/Resources/translations')) { if ($dir !== $defaultDir) { @trigger_error(sprintf('Translations directory "%s" is deprecated since Symfony 4.2, use "%s" instead.', $dir, $defaultDir), E_USER_DEPRECATED); } $dirs[] = $dir; + } else { + $nonExistingDirs[] = $dir; } // Register translation resources @@ -1154,7 +1163,10 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $options = array_merge( $translator->getArgument(4), - ['resource_files' => $files] + [ + 'resource_files' => $files, + 'scanned_directories' => \array_merge($dirs, $nonExistingDirs), + ] ); $translator->replaceArgument(4, $options); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index ddd9d64286ff5..de674c1082c39 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -25,6 +25,8 @@ use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\ProxyAdapter; use Symfony\Component\Cache\Adapter\RedisAdapter; +use Symfony\Component\Config\Resource\DirectoryResource; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass; @@ -800,6 +802,26 @@ public function testTranslator() $calls = $container->getDefinition('translator.default')->getMethodCalls(); $this->assertEquals(['fr'], $calls[1][1][0]); + + $nonExistingDirectories = array_filter( + $options['scanned_directories'], + function ($directory) { + return !file_exists($directory); + } + ); + + $this->assertNotEmpty($nonExistingDirectories, 'FrameworkBundle should pass non existing directories to Translator'); + + $resources = $container->getResources(); + foreach ($resources as $resource) { + if ($resource instanceof DirectoryResource) { + $this->assertNotContains('translations', $resource->getResource()); + } + + if ($resource instanceof FileExistenceResource) { + $this->assertNotContains('translations', $resource->getResource()); + } + } } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php index 6b276ca0b9b02..9e15e4ba41039 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/TranslatorTest.php @@ -14,6 +14,8 @@ use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; use Symfony\Bundle\FrameworkBundle\Translation\Translator; +use Symfony\Component\Config\Resource\DirectoryResource; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Translation\Formatter\MessageFormatter; use Symfony\Component\Translation\MessageCatalogue; @@ -223,6 +225,29 @@ public function getDebugModeAndCacheDirCombinations() ]; } + public function testCatalogResourcesAreAddedForScannedDirectories() + { + $loader = new \Symfony\Component\Translation\Loader\YamlFileLoader(); + $resourceFiles = [ + 'fr' => [ + __DIR__.'/../Fixtures/Resources/translations/messages.fr.yml', + ], + ]; + + /** @var Translator $translator */ + $translator = $this->getTranslator($loader, [ + 'resource_files' => $resourceFiles, + 'scanned_directories' => [__DIR__, '/tmp/I/sure/hope/this/does/not/exist'], + ], 'yml'); + + $catalogue = $translator->getCatalogue('fr'); + + $resources = $catalogue->getResources(); + + $this->assertEquals(new DirectoryResource(__DIR__), $resources[1]); + $this->assertEquals(new FileExistenceResource('/tmp/I/sure/hope/this/does/not/exist'), $resources[2]); + } + protected function getCatalogue($locale, $messages, $resources = []) { $catalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php index e0d0243281bb8..a32e32f898333 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php @@ -12,6 +12,8 @@ namespace Symfony\Bundle\FrameworkBundle\Translation; use Psr\Container\ContainerInterface; +use Symfony\Component\Config\Resource\DirectoryResource; +use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; use Symfony\Component\Translation\Exception\InvalidArgumentException; use Symfony\Component\Translation\Formatter\MessageFormatterInterface; @@ -31,6 +33,7 @@ class Translator extends BaseTranslator implements WarmableInterface 'cache_dir' => null, 'debug' => false, 'resource_files' => [], + 'scanned_directories' => [], ]; /** @@ -48,6 +51,11 @@ class Translator extends BaseTranslator implements WarmableInterface private $resourceFiles; + /** + * @var string[] + */ + private $scannedDirectories; + /** * Constructor. * @@ -78,6 +86,7 @@ public function __construct(ContainerInterface $container, MessageFormatterInter $this->options = array_merge($this->options, $options); $this->resourceLocales = array_keys($this->options['resource_files']); $this->resourceFiles = $this->options['resource_files']; + $this->scannedDirectories = $this->options['scanned_directories']; parent::__construct($defaultLocale, $formatter, $this->options['cache_dir'], $this->options['debug']); } @@ -120,6 +129,16 @@ protected function initializeCatalogue($locale) parent::initializeCatalogue($locale); } + protected function doLoadCatalogue($locale): void + { + parent::doLoadCatalogue($locale); + + foreach ($this->scannedDirectories as $directory) { + $resourceClass = file_exists($directory) ? DirectoryResource::class : FileExistenceResource::class; + $this->catalogues[$locale]->addResource(new $resourceClass($directory)); + } + } + protected function initialize() { if ($this->resourceFiles) { diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 8a2b2dd9d0c60..f5ce39ef0dd55 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -395,7 +395,10 @@ private function getCatalogueCachePath($locale) return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php'; } - private function doLoadCatalogue($locale): void + /** + * @internal + */ + protected function doLoadCatalogue($locale): void { $this->catalogues[$locale] = new MessageCatalogue($locale); From 69f0a0b3bf439354b5f097c2f12e0de353341665 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Sat, 6 Apr 2019 20:38:25 +0200 Subject: [PATCH 410/495] Removed undefined variable. --- src/Symfony/Component/HttpClient/NativeHttpClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index 0549fccc49c54..a24c69965430f 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -201,7 +201,7 @@ public function request(string $method, string $url, array $options = []): Respo ]; $proxy = self::getProxy($options['proxy'], $url); - $noProxy = $noProxy ?? $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? ''; + $noProxy = $_SERVER['no_proxy'] ?? $_SERVER['NO_PROXY'] ?? ''; $noProxy = $noProxy ? preg_split('/[\s,]+/', $noProxy) : []; $resolveRedirect = self::createRedirectResolver($options, $host, $proxy, $noProxy, $info, $onProgress); From 1546c0dfa0755fed2ad7b84be2f7ef24ed66f0e4 Mon Sep 17 00:00:00 2001 From: jewome62 <jewome62@gmail.com> Date: Sat, 6 Apr 2019 17:45:16 +0200 Subject: [PATCH 411/495] [Serializer] Add datetimezone normalizer --- src/Symfony/Component/Serializer/CHANGELOG.md | 1 + .../Normalizer/DateTimeZoneNormalizer.php | 79 ++++++++++++++++++ .../Normalizer/DateTimeZoneNormalizerTest.php | 81 +++++++++++++++++++ 3 files changed, 161 insertions(+) create mode 100644 src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php create mode 100644 src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeZoneNormalizerTest.php diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index 57e4ed1fd7c2a..fc4ab8b0a3b7d 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * added the list of constraint violations' parameters in `ConstraintViolationListNormalizer` + * added support for serializing `DateTimeZone` objects 4.2.0 ----- diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php new file mode 100644 index 0000000000000..8d589d71c6cca --- /dev/null +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeZoneNormalizer.php @@ -0,0 +1,79 @@ +<?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\Component\Serializer\Normalizer; + +use Symfony\Component\Serializer\Exception\InvalidArgumentException; +use Symfony\Component\Serializer\Exception\NotNormalizableValueException; + +/** + * Normalizes a {@see \DateTimeZone} object to a timezone string. + * + * @author Jérôme Desjardins <jewome62@gmail.com> + */ +class DateTimeZoneNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface +{ + /** + * {@inheritdoc} + * + * @throws InvalidArgumentException + */ + public function normalize($object, $format = null, array $context = []) + { + if (!$object instanceof \DateTimeZone) { + throw new InvalidArgumentException('The object must be an instance of "\DateTimeZone".'); + } + + return $object->getName(); + } + + /** + * {@inheritdoc} + */ + public function supportsNormalization($data, $format = null) + { + return $data instanceof \DateTimeZone; + } + + /** + * {@inheritdoc} + * + * @throws NotNormalizableValueException + */ + public function denormalize($data, $class, $format = null, array $context = []) + { + if ('' === $data || null === $data) { + throw new NotNormalizableValueException('The data is either an empty string or null, you should pass a string that can be parsed as a DateTimeZone.'); + } + + try { + return new \DateTimeZone($data); + } catch (\Exception $e) { + throw new NotNormalizableValueException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + */ + public function supportsDenormalization($data, $type, $format = null) + { + return \DateTimeZone::class === $type; + } + + /** + * {@inheritdoc} + */ + public function hasCacheableSupportsMethod(): bool + { + return __CLASS__ === \get_class($this); + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeZoneNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeZoneNormalizerTest.php new file mode 100644 index 0000000000000..6f2486d3db5f8 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/DateTimeZoneNormalizerTest.php @@ -0,0 +1,81 @@ +<?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\Component\Serializer\Tests\Normalizer; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\Normalizer\DateTimeZoneNormalizer; + +/** + * @author Jérôme Desjardins <jewome62@gmail.com> + */ +class DateTimeZoneNormalizerTest extends TestCase +{ + /** + * @var DateTimeZoneNormalizer + */ + private $normalizer; + + protected function setUp() + { + $this->normalizer = new DateTimeZoneNormalizer(); + } + + public function testSupportsNormalization() + { + $this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeZone('UTC'))); + $this->assertFalse($this->normalizer->supportsNormalization(new \DateTimeImmutable())); + $this->assertFalse($this->normalizer->supportsNormalization(new \stdClass())); + } + + public function testNormalize() + { + $this->assertEquals('UTC', $this->normalizer->normalize(new \DateTimeZone('UTC'))); + $this->assertEquals('Asia/Tokyo', $this->normalizer->normalize(new \DateTimeZone('Asia/Tokyo'))); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\InvalidArgumentException + */ + public function testNormalizeBadObjectTypeThrowsException() + { + $this->normalizer->normalize(new \stdClass()); + } + + public function testSupportsDenormalization() + { + $this->assertTrue($this->normalizer->supportsDenormalization(null, \DateTimeZone::class)); + $this->assertFalse($this->normalizer->supportsDenormalization(null, \DateTimeImmutable::class)); + $this->assertFalse($this->normalizer->supportsDenormalization(null, \stdClass::class)); + } + + public function testDenormalize() + { + $this->assertEquals(new \DateTimeZone('UTC'), $this->normalizer->denormalize('UTC', \DateTimeZone::class, null)); + $this->assertEquals(new \DateTimeZone('Asia/Tokyo'), $this->normalizer->denormalize('Asia/Tokyo', \DateTimeZone::class, null)); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\NotNormalizableValueException + */ + public function testDenormalizeNullTimeZoneThrowsException() + { + $this->normalizer->denormalize(null, \DateTimeZone::class, null); + } + + /** + * @expectedException \Symfony\Component\Serializer\Exception\NotNormalizableValueException + */ + public function testDenormalizeBadTimeZoneThrowsException() + { + $this->normalizer->denormalize('Jupiter/Europa', \DateTimeZone::class, null); + } +} From 536e53f1846394089b5f06e11572e6ff3cc2dfb0 Mon Sep 17 00:00:00 2001 From: Javier Spagnoletti <phansys@gmail.com> Date: Tue, 4 Apr 2017 01:17:01 -0300 Subject: [PATCH 412/495] =?UTF-8?q?[Validator]=C2=A0add=20new=20`Timezone`?= =?UTF-8?q?=20validation=20constraint.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Symfony/Component/Validator/CHANGELOG.md | 1 + .../Validator/Constraints/Timezone.php | 51 ++++ .../Constraints/TimezoneValidator.php | 92 ++++++ .../Resources/translations/validators.de.xlf | 4 + .../Resources/translations/validators.en.xlf | 4 + .../Resources/translations/validators.es.xlf | 4 + .../Resources/translations/validators.fr.xlf | 4 + .../Tests/Constraints/TimezoneTest.php | 63 ++++ .../Constraints/TimezoneValidatorTest.php | 274 ++++++++++++++++++ 9 files changed, 497 insertions(+) create mode 100644 src/Symfony/Component/Validator/Constraints/Timezone.php create mode 100644 src/Symfony/Component/Validator/Constraints/TimezoneValidator.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/TimezoneTest.php create mode 100644 src/Symfony/Component/Validator/Tests/Constraints/TimezoneValidatorTest.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index c44c49bee8c33..237dc68147b84 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.3.0 ----- + * added `Timezone` constraint * added `NotCompromisedPassword` constraint * added options `iban` and `ibanPropertyPath` to Bic constraint * added UATP cards support to `CardSchemeValidator` diff --git a/src/Symfony/Component/Validator/Constraints/Timezone.php b/src/Symfony/Component/Validator/Constraints/Timezone.php new file mode 100644 index 0000000000000..b7323fb874118 --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/Timezone.php @@ -0,0 +1,51 @@ +<?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\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\ConstraintDefinitionException; + +/** + * @Annotation + * @Target({"PROPERTY", "METHOD", "ANNOTATION"}) + * + * @author Javier Spagnoletti <phansys@gmail.com> + * @author Hugo Hamon <hugohamon@neuf.fr> + */ +class Timezone extends Constraint +{ + public const TIMEZONE_IDENTIFIER_ERROR = '5ce113e6-5e64-4ea2-90fe-d2233956db13'; + public const TIMEZONE_IDENTIFIER_IN_ZONE_ERROR = 'b57767b1-36c0-40ac-a3d7-629420c775b8'; + public const TIMEZONE_IDENTIFIER_IN_COUNTRY_ERROR = 'c4a22222-dc92-4fc0-abb0-d95b268c7d0b'; + + public $zone = \DateTimeZone::ALL; + public $countryCode; + public $message = 'This value is not a valid timezone.'; + + protected static $errorNames = [ + self::TIMEZONE_IDENTIFIER_ERROR => 'TIMEZONE_IDENTIFIER_ERROR', + self::TIMEZONE_IDENTIFIER_IN_ZONE_ERROR => 'TIMEZONE_IDENTIFIER_IN_ZONE_ERROR', + self::TIMEZONE_IDENTIFIER_IN_COUNTRY_ERROR => 'TIMEZONE_IDENTIFIER_IN_COUNTRY_ERROR', + ]; + + /** + * {@inheritdoc} + */ + public function __construct(array $options = null) + { + parent::__construct($options); + + if ($this->countryCode && \DateTimeZone::PER_COUNTRY !== $this->zone) { + throw new ConstraintDefinitionException('The option "countryCode" can only be used when "zone" option is configured with `\DateTimeZone::PER_COUNTRY`.'); + } + } +} diff --git a/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php b/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php new file mode 100644 index 0000000000000..14b1668bb595b --- /dev/null +++ b/src/Symfony/Component/Validator/Constraints/TimezoneValidator.php @@ -0,0 +1,92 @@ +<?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\Component\Validator\Constraints; + +use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; + +/** + * Validates whether a value is a valid timezone identifier. + * + * @author Javier Spagnoletti <phansys@gmail.com> + * @author Hugo Hamon <hugohamon@neuf.fr> + */ +class TimezoneValidator extends ConstraintValidator +{ + /** + * {@inheritdoc} + */ + public function validate($value, Constraint $constraint) + { + if (!$constraint instanceof Timezone) { + throw new UnexpectedTypeException($constraint, Timezone::class); + } + + if (null === $value || '' === $value) { + return; + } + + if (!is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { + throw new UnexpectedValueException($value, 'string'); + } + + $value = (string) $value; + + // @see: https://bugs.php.net/bug.php?id=75928 + if ($constraint->countryCode) { + $timezoneIds = \DateTimeZone::listIdentifiers($constraint->zone, $constraint->countryCode); + } else { + $timezoneIds = \DateTimeZone::listIdentifiers($constraint->zone); + } + + if ($timezoneIds && \in_array($value, $timezoneIds, true)) { + return; + } + + if ($constraint->countryCode) { + $code = Timezone::TIMEZONE_IDENTIFIER_IN_COUNTRY_ERROR; + } elseif (\DateTimeZone::ALL !== $constraint->zone) { + $code = Timezone::TIMEZONE_IDENTIFIER_IN_ZONE_ERROR; + } else { + $code = Timezone::TIMEZONE_IDENTIFIER_ERROR; + } + + $this->context->buildViolation($constraint->message) + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode($code) + ->addViolation(); + } + + /** + * {@inheritdoc} + */ + public function getDefaultOption() + { + return 'zone'; + } + + /** + * {@inheritdoc} + */ + protected function formatValue($value, $format = 0) + { + $value = parent::formatValue($value, $format); + + if (!$value || \DateTimeZone::PER_COUNTRY === $value) { + return $value; + } + + return array_search($value, (new \ReflectionClass(\DateTimeZone::class))->getConstants(), true) ?: $value; + } +} diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index 2fc62d942e8e8..64543d5e8de2f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -354,6 +354,10 @@ <source>This collection should contain only unique elements.</source> <target>Diese Sammlung darf keine doppelten Elemente enthalten.</target> </trans-unit> + <trans-unit id="92"> + <source>This value is not a valid timezone.</source> + <target>Dieser Wert ist keine gültige Zeitzone.</target> + </trans-unit> </body> </file> </xliff> diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 39c47e1275c5c..d74b0fefcafac 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -354,6 +354,10 @@ <source>This collection should contain only unique elements.</source> <target>This collection should contain only unique elements.</target> </trans-unit> + <trans-unit id="92"> + <source>This value is not a valid timezone.</source> + <target>This value is not a valid timezone.</target> + </trans-unit> </body> </file> </xliff> diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 69ab34e8b29ce..2fcdc44f3e4ec 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -330,6 +330,10 @@ <source>This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}.</source> <target>Este Código de Identificación Bancaria (BIC) no está asociado con el IBAN {{ iban }}.</target> </trans-unit> + <trans-unit id="92"> + <source>This value is not a valid timezone.</source> + <target>Este valor no es una zona horaria válida.</target> + </trans-unit> </body> </file> </xliff> diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index 7b1799d53315c..b802c0950eb21 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -334,6 +334,10 @@ <source>This value should be valid JSON.</source> <target>Cette valeur doit être un JSON valide.</target> </trans-unit> + <trans-unit id="92"> + <source>This value is not a valid timezone.</source> + <target>Cette valeur n'est pas un fuseau horaire valide.</target> + </trans-unit> </body> </file> </xliff> diff --git a/src/Symfony/Component/Validator/Tests/Constraints/TimezoneTest.php b/src/Symfony/Component/Validator/Tests/Constraints/TimezoneTest.php new file mode 100644 index 0000000000000..b7ca37486ed91 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/TimezoneTest.php @@ -0,0 +1,63 @@ +<?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\Component\Validator\Tests\Constraints; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Validator\Constraints\Timezone; + +/** + * @author Javier Spagnoletti <phansys@gmail.com> + */ +class TimezoneTest extends TestCase +{ + public function testValidTimezoneConstraints() + { + $constraint = new Timezone(); + + $constraint = new Timezone([ + 'message' => 'myMessage', + 'zone' => \DateTimeZone::PER_COUNTRY, + 'countryCode' => 'AR', + ]); + + $constraint = new Timezone([ + 'message' => 'myMessage', + 'zone' => \DateTimeZone::ALL, + ]); + + // Make an assertion in order to avoid this test to be marked as risky + $this->assertInstanceOf(Timezone::class, $constraint); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testExceptionForGroupedTimezonesByCountryWithWrongTimezone() + { + $constraint = new Timezone([ + 'message' => 'myMessage', + 'zone' => \DateTimeZone::ALL, + 'countryCode' => 'AR', + ]); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testExceptionForGroupedTimezonesByCountryWithoutTimezone() + { + $constraint = new Timezone([ + 'message' => 'myMessage', + 'countryCode' => 'AR', + ]); + } +} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/TimezoneValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/TimezoneValidatorTest.php new file mode 100644 index 0000000000000..e18bab86fe670 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Constraints/TimezoneValidatorTest.php @@ -0,0 +1,274 @@ +<?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\Component\Validator\Tests\Constraints; + +use Symfony\Component\Validator\Constraints\Timezone; +use Symfony\Component\Validator\Constraints\TimezoneValidator; +use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; + +/** + * @author Javier Spagnoletti <phansys@gmail.com> + * @author Hugo Hamon <hugohamon@neuf.fr> + */ +class TimezoneValidatorTest extends ConstraintValidatorTestCase +{ + protected function createValidator(): TimezoneValidator + { + return new TimezoneValidator(); + } + + public function testNullIsValid() + { + $this->validator->validate(null, new Timezone()); + + $this->assertNoViolation(); + } + + public function testEmptyStringIsValid() + { + $this->validator->validate('', new Timezone()); + + $this->assertNoViolation(); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\UnexpectedValueException + */ + public function testExpectsStringCompatibleType() + { + $this->validator->validate(new \stdClass(), new Timezone()); + } + + /** + * @dataProvider getValidTimezones + */ + public function testValidTimezones(string $timezone) + { + $this->validator->validate($timezone, new Timezone()); + + $this->assertNoViolation(); + } + + public function getValidTimezones(): iterable + { + yield ['America/Argentina/Buenos_Aires']; + yield ['America/Barbados']; + yield ['America/Toronto']; + yield ['Antarctica/Syowa']; + yield ['Africa/Douala']; + yield ['Atlantic/Canary']; + yield ['Asia/Gaza']; + yield ['Australia/Sydney']; + yield ['Europe/Copenhagen']; + yield ['Europe/Paris']; + yield ['Pacific/Noumea']; + yield ['UTC']; + } + + /** + * @dataProvider getValidGroupedTimezones + */ + public function testValidGroupedTimezones(string $timezone, int $zone) + { + $constraint = new Timezone([ + 'zone' => $zone, + ]); + + $this->validator->validate($timezone, $constraint); + + $this->assertNoViolation(); + } + + public function getValidGroupedTimezones(): iterable + { + yield ['America/Argentina/Cordoba', \DateTimeZone::AMERICA]; + yield ['America/Barbados', \DateTimeZone::AMERICA]; + yield ['Africa/Cairo', \DateTimeZone::AFRICA]; + yield ['Atlantic/Cape_Verde', \DateTimeZone::ATLANTIC]; + yield ['Europe/Bratislava', \DateTimeZone::EUROPE]; + yield ['Indian/Christmas', \DateTimeZone::INDIAN]; + yield ['Pacific/Kiritimati', \DateTimeZone::ALL]; + yield ['Pacific/Kiritimati', \DateTimeZone::ALL_WITH_BC]; + yield ['Pacific/Kiritimati', \DateTimeZone::PACIFIC]; + yield ['Arctic/Longyearbyen', \DateTimeZone::ARCTIC]; + yield ['Asia/Beirut', \DateTimeZone::ASIA]; + yield ['Atlantic/Bermuda', \DateTimeZone::ASIA | \DateTimeZone::ATLANTIC]; + yield ['Atlantic/Azores', \DateTimeZone::ATLANTIC | \DateTimeZone::ASIA]; + } + + /** + * @dataProvider getInvalidTimezones + */ + public function testInvalidTimezoneWithoutZone(string $timezone) + { + $constraint = new Timezone([ + 'message' => 'myMessage', + ]); + + $this->validator->validate($timezone, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', sprintf('"%s"', $timezone)) + ->setCode(Timezone::TIMEZONE_IDENTIFIER_ERROR) + ->assertRaised(); + } + + public function getInvalidTimezones(): iterable + { + yield ['Buenos_Aires/Argentina/America']; + yield ['Mayotte/Indian']; + yield ['foobar']; + } + + /** + * @dataProvider getInvalidGroupedTimezones + */ + public function testInvalidGroupedTimezones(string $timezone, int $zone) + { + $constraint = new Timezone([ + 'zone' => $zone, + 'message' => 'myMessage', + ]); + + $this->validator->validate($timezone, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', sprintf('"%s"', $timezone)) + ->setCode(Timezone::TIMEZONE_IDENTIFIER_IN_ZONE_ERROR) + ->assertRaised(); + } + + public function getInvalidGroupedTimezones(): iterable + { + yield ['Antarctica/McMurdo', \DateTimeZone::AMERICA]; + yield ['America/Barbados', \DateTimeZone::ANTARCTICA]; + yield ['Europe/Kiev', \DateTimeZone::ARCTIC]; + yield ['Asia/Ho_Chi_Minh', \DateTimeZone::INDIAN]; + yield ['Asia/Ho_Chi_Minh', \DateTimeZone::INDIAN | \DateTimeZone::ANTARCTICA]; + } + + /** + * @dataProvider getValidGroupedTimezonesByCountry + */ + public function testValidGroupedTimezonesByCountry(string $timezone, string $country) + { + $constraint = new Timezone([ + 'zone' => \DateTimeZone::PER_COUNTRY, + 'countryCode' => $country, + ]); + + $this->validator->validate($timezone, $constraint); + + $this->assertNoViolation(); + } + + public function getValidGroupedTimezonesByCountry(): iterable + { + yield ['America/Argentina/Cordoba', 'AR']; + yield ['America/Barbados', 'BB']; + yield ['Africa/Cairo', 'EG']; + yield ['Arctic/Longyearbyen', 'SJ']; + yield ['Asia/Beirut', 'LB']; + yield ['Atlantic/Azores', 'PT']; + yield ['Atlantic/Bermuda', 'BM']; + yield ['Atlantic/Cape_Verde', 'CV']; + yield ['Australia/Sydney', 'AU']; + yield ['Australia/Melbourne', 'AU']; + yield ['Europe/Bratislava', 'SK']; + yield ['Europe/Paris', 'FR']; + yield ['Europe/Madrid', 'ES']; + yield ['Europe/Monaco', 'MC']; + yield ['Indian/Christmas', 'CX']; + yield ['Pacific/Kiritimati', 'KI']; + yield ['Pacific/Kiritimati', 'KI']; + yield ['Pacific/Kiritimati', 'KI']; + } + + /** + * @dataProvider getInvalidGroupedTimezonesByCountry + */ + public function testInvalidGroupedTimezonesByCountry(string $timezone, string $invalidCountryCode) + { + $constraint = new Timezone([ + 'message' => 'myMessage', + 'zone' => \DateTimeZone::PER_COUNTRY, + 'countryCode' => $invalidCountryCode, + ]); + + $this->validator->validate($timezone, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', sprintf('"%s"', $timezone)) + ->setCode(Timezone::TIMEZONE_IDENTIFIER_IN_COUNTRY_ERROR) + ->assertRaised(); + } + + public function getInvalidGroupedTimezonesByCountry(): iterable + { + yield ['America/Argentina/Cordoba', 'FR']; + yield ['America/Barbados', 'PT']; + yield ['Europe/Bern', 'FR']; + } + + /** + * @dataProvider getDeprecatedTimezones + */ + public function testDeprecatedTimezonesAreValidWithBC(string $timezone) + { + $constraint = new Timezone([ + 'zone' => \DateTimeZone::ALL_WITH_BC, + ]); + + $this->validator->validate($timezone, $constraint); + + $this->assertNoViolation(); + } + + /** + * @dataProvider getDeprecatedTimezones + */ + public function testDeprecatedTimezonesAreInvalidWithoutBC(string $timezone) + { + $constraint = new Timezone([ + 'message' => 'myMessage', + ]); + + $this->validator->validate($timezone, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', sprintf('"%s"', $timezone)) + ->setCode(Timezone::TIMEZONE_IDENTIFIER_ERROR) + ->assertRaised(); + } + + public function getDeprecatedTimezones(): iterable + { + yield ['America/Buenos_Aires']; + yield ['America/Montreal']; + yield ['Australia/ACT']; + yield ['Australia/LHI']; + yield ['Australia/Queensland']; + yield ['Canada/Eastern']; + yield ['Canada/Central']; + yield ['Canada/Mountain']; + yield ['Canada/Pacific']; + yield ['CET']; + yield ['CST6CDT']; + yield ['Etc/GMT']; + yield ['Etc/Greenwich']; + yield ['Etc/UCT']; + yield ['Etc/Universal']; + yield ['Etc/UTC']; + yield ['Etc/Zulu']; + yield ['US/Pacific']; + } +} From 0d704b4f79c99b15c57e02835fae563ef14c3a08 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto <yonelceruto@gmail.com> Date: Sat, 6 Apr 2019 20:51:34 +0200 Subject: [PATCH 413/495] Remove unused import --- .../Component/HttpKernel/Debug/TraceableEventDispatcher.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php index 6bd45caa7a02a..6c96afdff3908 100644 --- a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher; -use Symfony\Component\EventDispatcher\Event; use Symfony\Component\HttpKernel\KernelEvents; /** From 05e488f41813e851a47518a74af384becc35c3e3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Sat, 6 Apr 2019 20:58:31 +0200 Subject: [PATCH 414/495] fixed CS --- .../WebProfilerBundle/Controller/ProfilerController.php | 2 +- src/Symfony/Component/Form/FormInterface.php | 6 +++--- .../Component/Ldap/Adapter/EntryManagerInterface.php | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index 2dc1c62436a8a..16284c42b3801 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -370,7 +370,7 @@ protected function getTemplateManager() return $this->templateManager; } - + private function denyAccessIfProfilerDisabled() { if (null === $this->profiler) { diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php index 5ed0376ed6008..b73927f3bcaaf 100644 --- a/src/Symfony/Component/Form/FormInterface.php +++ b/src/Symfony/Component/Form/FormInterface.php @@ -113,11 +113,11 @@ public function getErrors($deep = false, $flatten = true); * @return $this * * @throws Exception\AlreadySubmittedException If the form has already been submitted - * @throws Exception\LogicException If the view data does not match the expected type - * according to {@link FormConfigInterface::getDataClass}. + * @throws Exception\LogicException if the view data does not match the expected type + * according to {@link FormConfigInterface::getDataClass} * @throws Exception\RuntimeException If listeners try to call setData in a cycle or if * the form inherits data from its parent - * @throws Exception\TransformationFailedException If the synchronization failed. + * @throws Exception\TransformationFailedException if the synchronization failed */ public function setData($modelData); diff --git a/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php b/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php index 06ef4ddeec763..2ca5706ca0a62 100644 --- a/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php +++ b/src/Symfony/Component/Ldap/Adapter/EntryManagerInterface.php @@ -23,6 +23,7 @@ * @author Kevin Schuurmans <kevin.schuurmans@freshheads.com> * * The move() methods must be added to the interface in Symfony 5.0 + * * @method void move(Entry $entry, string $newParent) Moves an entry on the Ldap server */ interface EntryManagerInterface From 56fa5740239329e94f1e07a191e9f31c11596df0 Mon Sep 17 00:00:00 2001 From: Samuel ROZE <samuel.roze@gmail.com> Date: Sat, 6 Apr 2019 17:20:27 +0200 Subject: [PATCH 415/495] Uses an `AmqpStamp` to provide flags and attributes --- src/Symfony/Component/Messenger/CHANGELOG.md | 4 +- .../AmqpExt/AmqpRoutingKeyStampTest.php | 24 ------------ .../Transport/AmqpExt/AmqpSenderTest.php | 6 +-- .../Tests/Transport/AmqpExt/AmqpStampTest.php | 37 +++++++++++++++++++ .../Transport/AmqpExt/ConnectionTest.php | 26 ++++++++++++- .../Transport/AmqpExt/AmqpSender.php | 11 +++--- ...{AmqpRoutingKeyStamp.php => AmqpStamp.php} | 21 +++++++++-- .../Transport/AmqpExt/Connection.php | 34 +++++++++++------ 8 files changed, 113 insertions(+), 50 deletions(-) delete mode 100644 src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php create mode 100644 src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpStampTest.php rename src/Symfony/Component/Messenger/Transport/AmqpExt/{AmqpRoutingKeyStamp.php => AmqpStamp.php} (51%) diff --git a/src/Symfony/Component/Messenger/CHANGELOG.md b/src/Symfony/Component/Messenger/CHANGELOG.md index 03b4864520d4d..b16eac2d86285 100644 --- a/src/Symfony/Component/Messenger/CHANGELOG.md +++ b/src/Symfony/Component/Messenger/CHANGELOG.md @@ -18,9 +18,9 @@ CHANGELOG changed: a required 3rd `SerializerInterface` argument was added. * Added a new `SyncTransport` along with `ForceCallHandlersStamp` to explicitly handle messages synchronously. - * Added `AmqpRoutingKeyStamp` allowing to provide a routing key on message publishing. + * Added `AmqpStamp` allowing to provide a routing key, flags and attributes on message publishing. * [BC BREAK] Removed publishing with a `routing_key` option from queue configuration, for - AMQP. Use exchange `default_publish_routing_key` or `AmqpRoutingKeyStamp` instead. + AMQP. Use exchange `default_publish_routing_key` or `AmqpStamp` instead. * [BC BREAK] Changed the `queue` option in the AMQP transport DSN to be `queues[name]`. You can therefore name the queue but also configure `binding_keys`, `flags` and `arguments`. * [BC BREAK] The methods `get`, `ack`, `nack` and `queue` of the AMQP `Connection` diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php deleted file mode 100644 index 895e41b2620e9..0000000000000 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpRoutingKeyStampTest.php +++ /dev/null @@ -1,24 +0,0 @@ -<?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\Component\Messenger\Tests\Transport\AmqpExt; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Messenger\Transport\AmqpExt\AmqpRoutingKeyStamp; - -class AmqpRoutingKeyStampTest extends TestCase -{ - public function testStamp() - { - $stamp = new AmqpRoutingKeyStamp('routing_key'); - $this->assertSame('routing_key', $stamp->getRoutingKey()); - } -} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php index 178d86a516860..95380a9e55b76 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpSenderTest.php @@ -14,8 +14,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; -use Symfony\Component\Messenger\Transport\AmqpExt\AmqpRoutingKeyStamp; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpSender; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpStamp; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface; @@ -41,14 +41,14 @@ public function testItSendsTheEncodedMessage() public function testItSendsTheEncodedMessageUsingARoutingKey() { - $envelope = (new Envelope(new DummyMessage('Oy')))->with(new AmqpRoutingKeyStamp('rk')); + $envelope = (new Envelope(new DummyMessage('Oy')))->with($stamp = new AmqpStamp('rk')); $encoded = ['body' => '...', 'headers' => ['type' => DummyMessage::class]]; $serializer = $this->createMock(SerializerInterface::class); $serializer->method('encode')->with($envelope)->willReturn($encoded); $connection = $this->createMock(Connection::class); - $connection->expects($this->once())->method('publish')->with($encoded['body'], $encoded['headers'], 0, 'rk'); + $connection->expects($this->once())->method('publish')->with($encoded['body'], $encoded['headers'], 0, $stamp); $sender = new AmqpSender($connection, $serializer); $sender->send($envelope); diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpStampTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpStampTest.php new file mode 100644 index 0000000000000..d9605808f62fe --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/AmqpStampTest.php @@ -0,0 +1,37 @@ +<?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\Component\Messenger\Tests\Transport\AmqpExt; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpStamp; + +/** + * @requires extension amqp + */ +class AmqpStampTest extends TestCase +{ + public function testRoutingKeyOnly() + { + $stamp = new AmqpStamp('routing_key'); + $this->assertSame('routing_key', $stamp->getRoutingKey()); + $this->assertSame(AMQP_NOPARAM, $stamp->getFlags()); + $this->assertSame([], $stamp->getAttributes()); + } + + public function testFlagsAndAttributes() + { + $stamp = new AmqpStamp(null, AMQP_DURABLE, ['delivery_mode' => 'unknown']); + $this->assertNull($stamp->getRoutingKey()); + $this->assertSame(AMQP_DURABLE, $stamp->getFlags()); + $this->assertSame(['delivery_mode' => 'unknown'], $stamp->getAttributes()); + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php index a2de20b6208ed..e6bd2059e297d 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/AmqpExt/ConnectionTest.php @@ -13,7 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Messenger\Exception\InvalidArgumentException; +use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpFactory; +use Symfony\Component\Messenger\Transport\AmqpExt\AmqpStamp; use Symfony\Component\Messenger\Transport\AmqpExt\Connection; /** @@ -430,7 +432,7 @@ public function testItCanPublishWithASuppliedRoutingKey() $amqpExchange->expects($this->once())->method('publish')->with('body', 'routing_key'); $connection = Connection::fromDsn('amqp://localhost/%2f/messages?exchange[default_publish_routing_key]=default_routing_key', [], $factory); - $connection->publish('body', [], 0, 'routing_key'); + $connection->publish('body', [], 0, new AmqpStamp('routing_key')); } public function testItDelaysTheMessageWithTheInitialSuppliedRoutingKeyAsArgument() @@ -477,7 +479,27 @@ public function testItDelaysTheMessageWithTheInitialSuppliedRoutingKeyAsArgument $delayQueue->expects($this->once())->method('bind')->with('delay', 'delay_120000'); $delayExchange->expects($this->once())->method('publish')->with('{}', 'delay_120000', AMQP_NOPARAM, ['headers' => []]); - $connection->publish('{}', [], 120000, 'routing_key'); + $connection->publish('{}', [], 120000, new AmqpStamp('routing_key')); + } + + public function testItCanPublishWithCustomFlagsAndAttributes() + { + $factory = new TestAmqpFactory( + $amqpConnection = $this->createMock(\AMQPConnection::class), + $amqpChannel = $this->createMock(\AMQPChannel::class), + $amqpQueue = $this->createMock(\AMQPQueue::class), + $amqpExchange = $this->createMock(\AMQPExchange::class) + ); + + $amqpExchange->expects($this->once())->method('publish')->with( + 'body', + 'routing_key', + AMQP_IMMEDIATE, + ['delivery_mode' => 2, 'headers' => ['type' => DummyMessage::class]] + ); + + $connection = Connection::fromDsn('amqp://localhost/%2f/messages', [], $factory); + $connection->publish('body', ['type' => DummyMessage::class], 0, new AmqpStamp('routing_key', AMQP_IMMEDIATE, ['delivery_mode' => 2])); } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php index d53ecb3b8979e..b873312a6736c 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpSender.php @@ -51,11 +51,12 @@ public function send(Envelope $envelope): Envelope } try { - /** @var $routingKeyStamp AmqpRoutingKeyStamp */ - $routingKeyStamp = $envelope->last(AmqpRoutingKeyStamp::class); - $routingKey = $routingKeyStamp ? $routingKeyStamp->getRoutingKey() : null; - - $this->connection->publish($encodedMessage['body'], $encodedMessage['headers'] ?? [], $delay, $routingKey); + $this->connection->publish( + $encodedMessage['body'], + $encodedMessage['headers'] ?? [], + $delay, + $envelope->last(AmqpStamp::class) + ); } catch (\AMQPException $e) { throw new TransportException($e->getMessage(), 0, $e); } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpStamp.php similarity index 51% rename from src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php rename to src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpStamp.php index b9f2aa2d81765..d7a00c09b4436 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpRoutingKeyStamp.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/AmqpStamp.php @@ -15,20 +15,35 @@ /** * @author Guillaume Gammelin <ggammelin@gmail.com> + * @author Samuel Roze <samuel.roze@gmail.com> * * @experimental in 4.3 */ -final class AmqpRoutingKeyStamp implements StampInterface +final class AmqpStamp implements StampInterface { private $routingKey; + private $flags; + private $attributes; - public function __construct(string $routingKey) + public function __construct(string $routingKey = null, int $flags = AMQP_NOPARAM, array $attributes = []) { $this->routingKey = $routingKey; + $this->flags = $flags; + $this->attributes = $attributes; } - public function getRoutingKey(): string + public function getRoutingKey(): ?string { return $this->routingKey; } + + public function getFlags(): int + { + return $this->flags; + } + + public function getAttributes(): array + { + return $this->attributes; + } } diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 1c7a33430bb9f..ea9ba1f02af56 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -171,10 +171,10 @@ private static function normalizeQueueArguments(array $arguments): array * * @throws \AMQPException */ - public function publish(string $body, array $headers = [], int $delay = 0, string $routingKey = null): void + public function publish(string $body, array $headers = [], int $delay = 0, AmqpStamp $amqpStamp = null): void { if (0 !== $delay) { - $this->publishWithDelay($body, $headers, $delay, $routingKey); + $this->publishWithDelay($body, $headers, $delay, $amqpStamp); return; } @@ -183,13 +183,14 @@ public function publish(string $body, array $headers = [], int $delay = 0, strin $this->setup(); } - $this->exchange()->publish( + $this->publishOnExchange( + $this->exchange(), $body, - $routingKey ?? $this->getDefaultPublishRoutingKey(), - AMQP_NOPARAM, + (null !== $amqpStamp ? $amqpStamp->getRoutingKey() : null) ?? $this->getDefaultPublishRoutingKey(), [ 'headers' => $headers, - ] + ], + $amqpStamp ); } @@ -206,19 +207,30 @@ public function countMessagesInQueues(): int /** * @throws \AMQPException */ - private function publishWithDelay(string $body, array $headers, int $delay, ?string $exchangeRoutingKey) + private function publishWithDelay(string $body, array $headers, int $delay, AmqpStamp $amqpStamp = null) { if ($this->shouldSetup()) { - $this->setupDelay($delay, $exchangeRoutingKey); + $this->setupDelay($delay, null !== $amqpStamp ? $amqpStamp->getRoutingKey() : null); } - $this->getDelayExchange()->publish( + $this->publishOnExchange( + $this->getDelayExchange(), $body, $this->getRoutingKeyForDelay($delay), - AMQP_NOPARAM, [ 'headers' => $headers, - ] + ], + $amqpStamp + ); + } + + private function publishOnExchange(\AMQPExchange $exchange, string $body, string $routingKey = null, array $attributes = [], AmqpStamp $amqpStamp = null) + { + $exchange->publish( + $body, + $routingKey, + $amqpStamp ? $amqpStamp->getFlags() : AMQP_NOPARAM, + array_merge($amqpStamp ? $amqpStamp->getAttributes() : [], $attributes) ); } From 9a2787e89a432e1b3b6c6a4fd861a33eb683aef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 21:16:20 +0200 Subject: [PATCH 416/495] [Validator] Add an option to disable NotCompromisedPasswordValidator --- .../DependencyInjection/Configuration.php | 4 ++++ .../DependencyInjection/FrameworkExtension.php | 5 +++++ .../FrameworkBundle/Resources/config/validator.xml | 1 + .../Constraints/NotCompromisedPasswordValidator.php | 8 +++++++- .../NotCompromisedPasswordValidatorTest.php | 11 +++++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index f50c951a3e983..15636fb1e616e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -834,6 +834,10 @@ private function addValidationSection(ArrayNodeDefinition $rootNode) ->end() ->end() ->end() + ->booleanNode('disable_not_compromised_password') + ->defaultFalse() + ->info('Disable NotCompromisedPassword Validator: the value will always be valid.') + ->end() ->arrayNode('auto_mapping') ->useAttributeAsKey('namespace') ->normalizeKeys(false) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a4e33ba7443f0..765abe077d1ed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1229,6 +1229,11 @@ private function registerValidationConfiguration(array $config, ContainerBuilder if (!$propertyInfoEnabled || !$config['auto_mapping'] || !class_exists(PropertyInfoLoader::class)) { $container->removeDefinition('validator.property_info_loader'); } + + $container + ->getDefinition('validator.not_compromised_password') + ->setArgument(2, $config['disable_not_compromised_password']) + ; } private function registerValidatorMapping(ContainerBuilder $container, array $config, array &$files) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml index 95e35d54ce2ee..3c018ade2faf4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml @@ -64,6 +64,7 @@ <service id="validator.not_compromised_password" class="Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator"> <argument type="service" id="http_client" on-invalid="null" /> <argument>%kernel.charset%</argument> + <argument type="constant">false</argument> <tag name="validator.constraint_validator" alias="Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator" /> </service> diff --git a/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php index a432e90fc04e2..c248ef8b5c570 100644 --- a/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php @@ -32,8 +32,9 @@ class NotCompromisedPasswordValidator extends ConstraintValidator private $httpClient; private $charset; + private $disabled; - public function __construct(HttpClientInterface $httpClient = null, string $charset = 'UTF-8') + public function __construct(HttpClientInterface $httpClient = null, string $charset = 'UTF-8', bool $disabled = false) { if (null === $httpClient && !class_exists(HttpClient::class)) { throw new \LogicException(sprintf('The "%s" class requires the "HttpClient" component. Try running "composer require symfony/http-client".', self::class)); @@ -41,6 +42,7 @@ public function __construct(HttpClientInterface $httpClient = null, string $char $this->httpClient = $httpClient ?? HttpClient::create(); $this->charset = $charset; + $this->disabled = $disabled; } /** @@ -54,6 +56,10 @@ public function validate($value, Constraint $constraint) throw new UnexpectedTypeException($constraint, NotCompromisedPassword::class); } + if ($this->disabled) { + return; + } + if (null !== $value && !is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { throw new UnexpectedTypeException($value, 'string'); } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php index 3ea3f821e0ac7..8f0ecd2ecf5c2 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotCompromisedPasswordValidatorTest.php @@ -60,6 +60,17 @@ public function testEmptyStringIsValid() $this->assertNoViolation(); } + public function testInvalidPasswordButDisabled() + { + $r = new \ReflectionProperty($this->validator, 'disabled'); + $r->setAccessible(true); + $r->setValue($this->validator, true); + + $this->validator->validate(self::PASSWORD_LEAKED, new NotCompromisedPassword()); + + $this->assertNoViolation(); + } + public function testInvalidPassword() { $constraint = new NotCompromisedPassword(); From 7628972285e58d7ec45943ac0f402f85376ed7c4 Mon Sep 17 00:00:00 2001 From: David Maicher <mail@dmaicher.de> Date: Sat, 6 Apr 2019 21:18:18 +0200 Subject: [PATCH 417/495] [Serializer] add return type hints for ObjectPropertyListExtractorInterface --- .../Serializer/Extractor/ObjectPropertyListExtractor.php | 2 +- .../Extractor/ObjectPropertyListExtractorInterface.php | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php index 8424a2ae730df..922094f8cb45a 100644 --- a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php +++ b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php @@ -30,7 +30,7 @@ public function __construct(PropertyListExtractorInterface $propertyListExtracto /** * {@inheritdoc} */ - public function getProperties($object, array $context = []) + public function getProperties($object, array $context = []): ?array { $class = $this->objectClassResolver ? ($this->objectClassResolver)($object) : \get_class($object); diff --git a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php index d422e79f82b84..1dd9b8b99a7d3 100644 --- a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php +++ b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php @@ -20,9 +20,8 @@ interface ObjectPropertyListExtractorInterface * Gets the list of properties available for the given object. * * @param object $object - * @param array $context * * @return string[]|null */ - public function getProperties($object, array $context = []); + public function getProperties($object, array $context = []): ?array; } From 6b57ea996cc165d7d041311e52ebf1647da1cb99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= <jeremy@derusse.com> Date: Sat, 6 Apr 2019 21:19:32 +0200 Subject: [PATCH 418/495] Use env variable to create anytype of lock store --- .../Component/Lock/Store/StoreFactory.php | 22 ++++++- .../Lock/Tests/Store/StoreFactoryTest.php | 58 +++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php diff --git a/src/Symfony/Component/Lock/Store/StoreFactory.php b/src/Symfony/Component/Lock/Store/StoreFactory.php index 5f97a8715df34..a7c8168d8d562 100644 --- a/src/Symfony/Component/Lock/Store/StoreFactory.php +++ b/src/Symfony/Component/Lock/Store/StoreFactory.php @@ -11,9 +11,11 @@ namespace Symfony\Component\Lock\Store; +use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Traits\RedisClusterProxy; use Symfony\Component\Cache\Traits\RedisProxy; use Symfony\Component\Lock\Exception\InvalidArgumentException; +use Symfony\Component\Lock\StoreInterface; /** * StoreFactory create stores and connections. @@ -23,9 +25,9 @@ class StoreFactory { /** - * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|\Memcached|\Zookeeper $connection + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|\Memcached|\Zookeeper|string $connection Connection or DSN or Store short name * - * @return RedisStore|MemcachedStore|ZookeeperStore + * @return StoreInterface */ public static function createStore($connection) { @@ -45,7 +47,21 @@ public static function createStore($connection) if ($connection instanceof \Zookeeper) { return new ZookeeperStore($connection); } + if (!\is_string($connection)) { + throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', \get_class($connection))); + } - throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', \get_class($connection))); + switch (true) { + case 'flock' === $connection: + return new FlockStore(); + case 0 === strpos($connection, 'flock://'): + return new FlockStore(substr($connection, 8)); + case 'semaphore' === $connection: + return new SemaphoreStore(); + case preg_match('#^[a-z]++://#', $connection): + return static::createStore(AbstractAdapter::createConnection($connection)); + default: + throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', $connection)); + } } } diff --git a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php new file mode 100644 index 0000000000000..cd93a8cc9f8ad --- /dev/null +++ b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php @@ -0,0 +1,58 @@ +<?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\Component\Lock\Tests\Store; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Traits\RedisProxy; +use Symfony\Component\Lock\Store\FlockStore; +use Symfony\Component\Lock\Store\MemcachedStore; +use Symfony\Component\Lock\Store\RedisStore; +use Symfony\Component\Lock\Store\SemaphoreStore; +use Symfony\Component\Lock\Store\StoreFactory; +use Symfony\Component\Lock\Store\ZookeeperStore; + +/** + * @author Jérémy Derussé <jeremy@derusse.com> + */ +class StoreFactoryTest extends TestCase +{ + /** + * @dataProvider validConnections + */ + public function testCreateStore($connection, string $expectedStoreClass) + { + $store = StoreFactory::createStore($connection); + + $this->assertInstanceOf($expectedStoreClass, $store); + } + + public function validConnections() + { + if (\class_exists(\Redis::class)) { + yield [$this->createMock(\Redis::class), RedisStore::class]; + } + yield [$this->createMock(RedisProxy::class), RedisStore::class]; + yield [$this->createMock(\Predis\Client::class), RedisStore::class]; + if (\class_exists(\Memcached::class)) { + yield [$this->createMock(\Memcached::class), MemcachedStore::class]; + } + if (\class_exists(\Zookeeper::class)) { + yield [$this->createMock(\Zookeeper::class), ZookeeperStore::class]; + } + yield ['flock', FlockStore::class]; + yield ['flock:///tmp', FlockStore::class]; + yield ['semaphore', SemaphoreStore::class]; + if (\class_exists(\Memcached::class)) { + yield ['memcached://server.com', MemcachedStore::class]; + } + } +} From 44d9fbe9952bb6e89556cd2e97eeb7a3b8145d3a Mon Sep 17 00:00:00 2001 From: dFayet <d.fayet@ohwee.fr> Date: Sat, 6 Apr 2019 21:48:09 +0200 Subject: [PATCH 419/495] Fix graph text color --- .../WebProfilerBundle/Resources/views/Collector/time.css.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.css.twig index 9575178058fd8..ca46eafb9a0e1 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.css.twig @@ -53,7 +53,7 @@ font-size: 12px; line-height: 12px; font-weight: normal; - color: var(--color-text); + fill: var(--color-text); } .timeline-graph .timeline-label .timeline-sublabel { From faf629386ea64b90f4f683c405d3e6c5b3025a14 Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@sensiolabs.de> Date: Sat, 6 Apr 2019 22:23:29 +0200 Subject: [PATCH 420/495] drop not needed "constant" type argument --- .../Bundle/FrameworkBundle/Resources/config/validator.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml index 3c018ade2faf4..4100735230929 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/validator.xml @@ -64,7 +64,7 @@ <service id="validator.not_compromised_password" class="Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator"> <argument type="service" id="http_client" on-invalid="null" /> <argument>%kernel.charset%</argument> - <argument type="constant">false</argument> + <argument>false</argument> <tag name="validator.constraint_validator" alias="Symfony\Component\Validator\Constraints\NotCompromisedPasswordValidator" /> </service> From de12e2382e37f9111aec079f433a99129ef68b82 Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@sensiolabs.de> Date: Sat, 6 Apr 2019 23:02:44 +0200 Subject: [PATCH 421/495] throw UnexpectedValueException instead --- .../Validator/Constraints/NotCompromisedPasswordValidator.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php index c248ef8b5c570..20ecdd381a100 100644 --- a/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotCompromisedPasswordValidator.php @@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -61,7 +62,7 @@ public function validate($value, Constraint $constraint) } if (null !== $value && !is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { - throw new UnexpectedTypeException($value, 'string'); + throw new UnexpectedValueException($value, 'string'); } $value = (string) $value; From 50c22b3d58e3d96ecb5015b01462af84e66acbe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= <lyrixx@lyrixx.info> Date: Sat, 6 Apr 2019 23:28:55 +0200 Subject: [PATCH 422/495] Fixed tests --- .../Tests/DependencyInjection/ConfigurationTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index a9d7d0a63bf6c..c2455606b9727 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -234,6 +234,7 @@ protected static function getBundleDefaultConfig() 'paths' => [], ], 'auto_mapping' => [], + 'disable_not_compromised_password' => false, ], 'annotations' => [ 'cache' => 'php_array', From 0c2a2bf536ec39b65c9e98927a67a0cabbe76920 Mon Sep 17 00:00:00 2001 From: tiecoders <a.hannachi@tiecoders.com> Date: Sun, 7 Apr 2019 01:25:14 +0200 Subject: [PATCH 423/495] ASSET-PathPackage-Enhancement - Use parent getUrl method instead of duplicating code. --- src/Symfony/Component/Asset/PathPackage.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Symfony/Component/Asset/PathPackage.php b/src/Symfony/Component/Asset/PathPackage.php index 1fd9926b31ead..e3cc56c0f7113 100644 --- a/src/Symfony/Component/Asset/PathPackage.php +++ b/src/Symfony/Component/Asset/PathPackage.php @@ -53,11 +53,7 @@ public function __construct(string $basePath, VersionStrategyInterface $versionS */ public function getUrl($path) { - if ($this->isAbsoluteUrl($path)) { - return $path; - } - - $versionedPath = $this->getVersionStrategy()->applyVersion($path); + $versionedPath = parent::getUrl($path); // if absolute or begins with /, we're done if ($this->isAbsoluteUrl($versionedPath) || ($versionedPath && '/' === $versionedPath[0])) { From fec4beaffc8496b97b0182ad274f38fe0a634a16 Mon Sep 17 00:00:00 2001 From: sez-open <soufian.ez_zantar@open-groupe.com> Date: Mon, 11 Mar 2019 19:17:50 +0100 Subject: [PATCH 424/495] fix debug:autowiringcommand --- .../Command/DebugAutowiringCommand.php | 12 +++++++++ .../Functional/DebugAutowiringCommandTest.php | 25 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php index 34fd44cb629c5..ac692ee62990c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/DebugAutowiringCommand.php @@ -100,6 +100,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $hasAlias = []; $all = $input->getOption('all'); $previousId = '-'; + $serviceIdsNb = 0; foreach ($serviceIds as $serviceId) { $text = []; if (0 !== strpos($serviceId, $previousId)) { @@ -127,11 +128,22 @@ protected function execute(InputInterface $input, OutputInterface $output) $serviceLine .= ' - <fg=magenta>deprecated</>'; } } elseif (!$all) { + ++$serviceIdsNb; continue; } $text[] = $serviceLine; $io->text($text); } + + $io->newLine(); + + if (0 < $serviceIdsNb) { + $io->text(sprintf('%s more concrete service%s would be displayed when adding the "--all" option.', $serviceIdsNb, $serviceIdsNb > 1 ? 's' : '')); + } + if ($all) { + $io->text('Pro-tip: use interfaces in your type-hints instead of classes to benefit from the dependency inversion principle.'); + } + $io->newLine(); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/DebugAutowiringCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/DebugAutowiringCommandTest.php index 1c64fbe6eeb5b..c468a2a4da70c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/DebugAutowiringCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/DebugAutowiringCommandTest.php @@ -72,4 +72,29 @@ public function testSearchNoResults() $this->assertContains('No autowirable classes or interfaces found matching "foo_fake"', $tester->getErrorOutput()); $this->assertEquals(1, $tester->getStatusCode()); } + + public function testSearchNotAliasedService() + { + static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']); + + $application = new Application(static::$kernel); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(['command' => 'debug:autowiring', 'search' => 'redirect']); + + $this->assertContains(' more concrete service would be displayed when adding the "--all" option.', $tester->getDisplay()); + } + + public function testSearchNotAliasedServiceWithAll() + { + static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']); + + $application = new Application(static::$kernel); + $application->setAutoExit(false); + + $tester = new ApplicationTester($application); + $tester->run(['command' => 'debug:autowiring', 'search' => 'redirect', '--all' => true]); + $this->assertContains('Pro-tip: use interfaces in your type-hints instead of classes to benefit from the dependency inversion principle.', $tester->getDisplay()); + } } From e2dbe634890982bcd52d2dc3c9c5370cb0624950 Mon Sep 17 00:00:00 2001 From: Vincent Touzet <vincent.touzet@gmail.com> Date: Sun, 7 Apr 2019 09:39:29 +0200 Subject: [PATCH 425/495] [Messenger] DoctrineTransport - Use InvalidArgumentException instead of TransportException during configuration checks --- .../Messenger/Tests/Transport/Doctrine/ConnectionTest.php | 4 ++-- .../Component/Messenger/Transport/Doctrine/Connection.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php index 4eb9823ce5aa1..8c4e8fcce9cce 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -213,7 +213,7 @@ public function buildConfigurationProvider() } /** - * @expectedException \Symfony\Component\Messenger\Exception\TransportException + * @expectedException \Symfony\Component\Messenger\Exception\InvalidArgumentException */ public function testItThrowsAnExceptionIfAnExtraOptionsInDefined() { @@ -221,7 +221,7 @@ public function testItThrowsAnExceptionIfAnExtraOptionsInDefined() } /** - * @expectedException \Symfony\Component\Messenger\Exception\TransportException + * @expectedException \Symfony\Component\Messenger\Exception\InvalidArgumentException */ public function testItThrowsAnExceptionIfAnExtraOptionsInDefinedInDSN() { diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 3191033f8e977..385bba2899140 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -87,13 +87,13 @@ public static function buildConfiguration($dsn, array $options = []) // check for extra keys in options $optionsExtraKeys = array_diff(array_keys($options), array_keys($configuration)); if (0 < \count($optionsExtraKeys)) { - throw new TransportException(sprintf('Unknown option found : [%s]. Allowed options are [%s]', implode(', ', $optionsExtraKeys), implode(', ', self::DEFAULT_OPTIONS))); + throw new InvalidArgumentException(sprintf('Unknown option found : [%s]. Allowed options are [%s]', implode(', ', $optionsExtraKeys), implode(', ', self::DEFAULT_OPTIONS))); } // check for extra keys in options $queryExtraKeys = array_diff(array_keys($query), array_keys($configuration)); if (0 < \count($queryExtraKeys)) { - throw new TransportException(sprintf('Unknown option found in DSN: [%s]. Allowed options are [%s]', implode(', ', $queryExtraKeys), implode(', ', self::DEFAULT_OPTIONS))); + throw new InvalidArgumentException(sprintf('Unknown option found in DSN: [%s]. Allowed options are [%s]', implode(', ', $queryExtraKeys), implode(', ', self::DEFAULT_OPTIONS))); } return $configuration; From 4c04601036a77a160a9d9dcc3766fd8f75c93bcf Mon Sep 17 00:00:00 2001 From: Anton Chernikov <anton_ch1989@mail.ru> Date: Sun, 3 Mar 2019 16:03:31 +0300 Subject: [PATCH 426/495] [Form] group_by as callback returns array --- .../Factory/DefaultChoiceListFactory.php | 50 ++++++++++--------- .../Factory/DefaultChoiceListFactoryTest.php | 38 ++++++++++++++ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php index 5383f2a78393c..15b1661d909af 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php @@ -63,9 +63,11 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, $index = 0; } - // If $groupBy is a callable, choices are added to the group with the - // name returned by the callable. If the callable returns null, the - // choice is not added to any group + // If $groupBy is a callable returning a string + // choices are added to the group with the name returned by the callable. + // If $groupBy is a callable returning an array + // choices are added to the groups with names returned by the callable + // If the callable returns null, the choice is not added to any group if (\is_callable($groupBy)) { foreach ($choices as $value => $choice) { self::addChoiceViewGroupedBy( @@ -200,9 +202,9 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { - $groupLabel = $groupBy($choice, $keys[$value], $value); + $groupLabels = $groupBy($choice, $keys[$value], $value); - if (null === $groupLabel) { + if (null === $groupLabels) { // If the callable returns null, don't group the choice self::addChoiceView( $choice, @@ -219,25 +221,27 @@ private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label return; } - $groupLabel = (string) $groupLabel; + $groupLabels = \is_array($groupLabels) ? \array_map('strval', $groupLabels) : [(string) $groupLabels]; - // Initialize the group views if necessary. Unnecessarily built group - // views will be cleaned up at the end of createView() - if (!isset($preferredViews[$groupLabel])) { - $preferredViews[$groupLabel] = new ChoiceGroupView($groupLabel); - $otherViews[$groupLabel] = new ChoiceGroupView($groupLabel); - } + foreach ($groupLabels as $groupLabel) { + // Initialize the group views if necessary. Unnecessarily built group + // views will be cleaned up at the end of createView() + if (!isset($preferredViews[$groupLabel])) { + $preferredViews[$groupLabel] = new ChoiceGroupView($groupLabel); + $otherViews[$groupLabel] = new ChoiceGroupView($groupLabel); + } - self::addChoiceView( - $choice, - $value, - $label, - $keys, - $index, - $attr, - $isPreferred, - $preferredViews[$groupLabel]->choices, - $otherViews[$groupLabel]->choices - ); + self::addChoiceView( + $choice, + $value, + $label, + $keys, + $index, + $attr, + $isPreferred, + $preferredViews[$groupLabel]->choices, + $otherViews[$groupLabel]->choices + ); + } } } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php index c520ab1a0de74..5e684687ecf57 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php @@ -77,6 +77,11 @@ public function getGroup($object) return $this->obj1 === $object || $this->obj2 === $object ? 'Group 1' : 'Group 2'; } + public function getGroupArray($object) + { + return $this->obj1 === $object || $this->obj2 === $object ? ['Group 1', 'Group 2'] : ['Group 3']; + } + public function getGroupAsObject($object) { return $this->obj1 === $object || $this->obj2 === $object @@ -462,6 +467,19 @@ public function testCreateViewFlatGroupByAsCallable() $this->assertGroupedView($view); } + public function testCreateViewFlatGroupByAsCallableReturnsArray() + { + $view = $this->factory->createView( + $this->list, + [], + null, // label + null, // index + [$this, 'getGroupArray'] + ); + + $this->assertGroupedViewWithChoiceDuplication($view); + } + public function testCreateViewFlatGroupByObjectThatCanBeCastToString() { $view = $this->factory->createView( @@ -773,6 +791,26 @@ private function assertGroupedView($view) ] ), $view); } + + private function assertGroupedViewWithChoiceDuplication($view) + { + $this->assertEquals(new ChoiceListView( + [ + 'Group 1' => new ChoiceGroupView( + 'Group 1', + [0 => new ChoiceView($this->obj1, '0', 'A'), 2 => new ChoiceView($this->obj2, '1', 'B')] + ), + 'Group 2' => new ChoiceGroupView( + 'Group 2', + [1 => new ChoiceView($this->obj1, '0', 'A'), 3 => new ChoiceView($this->obj2, '1', 'B')] + ), + 'Group 3' => new ChoiceGroupView( + 'Group 3', + [4 => new ChoiceView($this->obj3, '2', 'C'), 5 => new ChoiceView($this->obj4, '3', 'D')] + ), + ], [] + ), $view); + } } class DefaultChoiceListFactoryTest_Castable From 8acf29eaf5eee27ad9366dfc4d3b8965fa65ffcf Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Sat, 6 Apr 2019 15:42:08 +0200 Subject: [PATCH 427/495] There is no OB to flush. --- src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index ec15196c6592c..ff68ab6878a2b 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -86,7 +86,7 @@ case '/timeout-body': echo '<1>'; - ob_flush(); + @ob_flush(); flush(); usleep(500000); echo '<2>'; @@ -97,7 +97,7 @@ sleep(1); while (true) { echo '<1>'; - ob_flush(); + @ob_flush(); flush(); usleep(500); } From 03da3a22b19de7a08841da9aaaea64fcb491d878 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla <mp@webfactory.de> Date: Sat, 6 Apr 2019 13:47:16 +0000 Subject: [PATCH 428/495] Add a `require` env var processor This allows to process .php files, returning the value returned from that file. Leverages the opcache. --- .../DependencyInjection/CHANGELOG.md | 1 + .../DependencyInjection/EnvVarProcessor.php | 9 ++++-- .../RegisterEnvVarProcessorsPassTest.php | 1 + .../Tests/EnvVarProcessorTest.php | 28 +++++++++++++++++++ .../Tests/Fixtures/php/return_foo_string.php | 2 ++ 5 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/return_foo_string.php diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index 3d71d72844d26..bc54b5f38c36e 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -15,6 +15,7 @@ CHANGELOG * added ability to define an index for services in an injected service locator argument * made `ServiceLocator` implement `ServiceProviderInterface` * deprecated support for non-string default env() parameters + * added `%env(require:...)%` processor to `require()` a PHP file and use the value returned from it 4.2.0 ----- diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 834ca51f3c76a..568c91d4f69bd 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -47,6 +47,7 @@ public static function getProvidedTypes() 'default' => 'bool|int|float|string|array', 'string' => 'string', 'trim' => 'string', + 'require' => 'bool|int|float|string|array', ]; } @@ -102,7 +103,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) return '' === $default ? null : $this->container->getParameter($default); } - if ('file' === $prefix) { + if ('file' === $prefix || 'require' === $prefix) { if (!is_scalar($file = $getEnv($name))) { throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.', $name)); } @@ -110,7 +111,11 @@ public function getEnv($prefix, $name, \Closure $getEnv) throw new EnvNotFoundException(sprintf('File "%s" not found (resolved from "%s").', $file, $name)); } - return file_get_contents($file); + if ('file' === $prefix) { + return file_get_contents($file); + } else { + return require $file; + } } if (false !== $i || 'string' !== $prefix) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php index bcb8e2473c924..f18607914e60d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php @@ -45,6 +45,7 @@ public function testSimpleProcessor() 'default' => ['bool', 'int', 'float', 'string', 'array'], 'string' => ['string'], 'trim' => ['string'], + 'require' => ['bool', 'int', 'float', 'string', 'array'], ]; $this->assertSame($expected, $container->getParameterBag()->getProvidedTypes()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index 7192127691546..5aa905d954b2b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -458,4 +458,32 @@ public function validNullables() ['NULL', 'NULL'], ]; } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\EnvNotFoundException + * @expectedExceptionMessage missing-file + */ + public function testRequireMissingFile() + { + $processor = new EnvVarProcessor(new Container()); + + $processor->getEnv('require', '/missing-file', function ($name) { + return $name; + }); + } + + public function testRequireFile() + { + $path = __DIR__.'/Fixtures/php/return_foo_string.php'; + + $processor = new EnvVarProcessor(new Container()); + + $result = $processor->getEnv('require', $path, function ($name) use ($path) { + $this->assertSame($path, $name); + + return $path; + }); + + $this->assertEquals('foo', $result); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/return_foo_string.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/return_foo_string.php new file mode 100644 index 0000000000000..1551646c643a3 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/return_foo_string.php @@ -0,0 +1,2 @@ +<?php + return 'foo'; From 5bf7ad44e172cea2692282d9f7d4099cc4908e49 Mon Sep 17 00:00:00 2001 From: Thomas Calvet <calvet.thomas@gmail.com> Date: Sat, 6 Apr 2019 21:18:10 +0200 Subject: [PATCH 429/495] [Routing][ObjectRouteLoader] Allow invokable route loader services --- src/Symfony/Component/Routing/CHANGELOG.md | 1 + .../Component/Routing/Loader/ObjectRouteLoader.php | 12 ++++++------ .../Routing/Tests/Loader/ObjectRouteLoaderTest.php | 8 ++++++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 4362103f93808..f7439903e04a5 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -11,6 +11,7 @@ CHANGELOG * deprecated implementing `Serializable` for `Route` and `CompiledRoute`; if you serialize them, please ensure your unserialization logic can recover from a failure related to an updated serialization format * exposed `utf8` Route option, defaults "locale" and "format" in configuration loaders and configurators + * added support for invokable route loader services 4.2.0 ----- diff --git a/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php b/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php index 8370d576c5f2c..8f0680f02aa5c 100644 --- a/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php +++ b/src/Symfony/Component/Routing/Loader/ObjectRouteLoader.php @@ -37,25 +37,25 @@ abstract protected function getServiceObject($id); /** * Calls the service that will load the routes. * - * @param mixed $resource Some value that will resolve to a callable + * @param string $resource Some value that will resolve to a callable * @param string|null $type The resource type * * @return RouteCollection */ public function load($resource, $type = null) { + if (!preg_match('/^[^\:]+(?:::?(?:[^\:]+))?$/', $resource)) { + throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the "service" route loader: use the format "service::method" or "service" if your service has an "__invoke" method.', $resource)); + } + if (1 === substr_count($resource, ':')) { $resource = str_replace(':', '::', $resource); @trigger_error(sprintf('Referencing service route loaders with a single colon is deprecated since Symfony 4.1. Use %s instead.', $resource), E_USER_DEPRECATED); } $parts = explode('::', $resource); - if (2 != \count($parts)) { - throw new \InvalidArgumentException(sprintf('Invalid resource "%s" passed to the "service" route loader: use the format "service::method"', $resource)); - } - $serviceString = $parts[0]; - $method = $parts[1]; + $method = $parts[1] ?? '__invoke'; $loaderObject = $this->getServiceObject($serviceString); diff --git a/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php index 0e9289bee467d..62ec5261ab22f 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/ObjectRouteLoaderTest.php @@ -70,7 +70,7 @@ public function testLoadCallsServiceAndReturnsCollection() * @expectedException \InvalidArgumentException * @dataProvider getBadResourceStrings */ - public function testExceptionWithoutSyntax($resourceString) + public function testExceptionWithoutSyntax(string $resourceString): void { $loader = new ObjectRouteLoaderForTest(); $loader->load($resourceString); @@ -79,8 +79,12 @@ public function testExceptionWithoutSyntax($resourceString) public function getBadResourceStrings() { return [ - ['Foo'], ['Foo:Bar:baz'], + ['Foo::Bar::baz'], + ['Foo:'], + ['Foo::'], + [':Foo'], + ['::Foo'], ]; } From 1f66e7b2bec4bd0a58728420bc9d4c2118cdb0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= <jeremy@derusse.com> Date: Sun, 7 Apr 2019 07:56:05 +0200 Subject: [PATCH 430/495] Fix Lock test suite --- .../Component/Lock/Store/StoreFactory.php | 2 +- .../Lock/Tests/Store/StoreFactoryTest.php | 20 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Lock/Store/StoreFactory.php b/src/Symfony/Component/Lock/Store/StoreFactory.php index a7c8168d8d562..b702b81b70e0c 100644 --- a/src/Symfony/Component/Lock/Store/StoreFactory.php +++ b/src/Symfony/Component/Lock/Store/StoreFactory.php @@ -58,7 +58,7 @@ public static function createStore($connection) return new FlockStore(substr($connection, 8)); case 'semaphore' === $connection: return new SemaphoreStore(); - case preg_match('#^[a-z]++://#', $connection): + case \class_exists(AbstractAdapter::class) && preg_match('#^[a-z]++://#', $connection): return static::createStore(AbstractAdapter::createConnection($connection)); default: throw new InvalidArgumentException(sprintf('Unsupported Connection: %s.', $connection)); diff --git a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php index cd93a8cc9f8ad..4edb4d361a450 100644 --- a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Lock\Tests\Store; use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Traits\RedisProxy; use Symfony\Component\Lock\Store\FlockStore; use Symfony\Component\Lock\Store\MemcachedStore; @@ -40,19 +41,24 @@ public function validConnections() if (\class_exists(\Redis::class)) { yield [$this->createMock(\Redis::class), RedisStore::class]; } - yield [$this->createMock(RedisProxy::class), RedisStore::class]; - yield [$this->createMock(\Predis\Client::class), RedisStore::class]; + if (\class_exists(RedisProxy::class)) { + yield [$this->createMock(RedisProxy::class), RedisStore::class]; + } + yield [new \Predis\Client(), RedisStore::class]; if (\class_exists(\Memcached::class)) { - yield [$this->createMock(\Memcached::class), MemcachedStore::class]; + yield [new \Memcached(), MemcachedStore::class]; } if (\class_exists(\Zookeeper::class)) { yield [$this->createMock(\Zookeeper::class), ZookeeperStore::class]; } - yield ['flock', FlockStore::class]; - yield ['flock:///tmp', FlockStore::class]; - yield ['semaphore', SemaphoreStore::class]; - if (\class_exists(\Memcached::class)) { + if (\extension_loaded('sysvsem')) { + yield ['semaphore', SemaphoreStore::class]; + } + if (\class_exists(\Memcached::class) && \class_exists(AbstractAdapter::class)) { yield ['memcached://server.com', MemcachedStore::class]; } + + yield ['flock', FlockStore::class]; + yield ['flock://'.sys_get_temp_dir(), FlockStore::class]; } } From 5b723865b1b077d7e0a2fd54b278312bf831a9b0 Mon Sep 17 00:00:00 2001 From: jewome62 <jewome62@gmail.com> Date: Mon, 18 Mar 2019 22:44:06 +0100 Subject: [PATCH 431/495] [Serializer] Add Support of recursive denormalization on object_to_populate --- src/Symfony/Component/Serializer/CHANGELOG.md | 1 + .../Normalizer/AbstractObjectNormalizer.php | 9 ++++ .../Normalizer/ObjectToPopulateTrait.php | 2 +- .../Fixtures/DeepObjectPopulateChildDummy.php | 22 +++++++++ .../DeepObjectPopulateParentDummy.php | 33 +++++++++++++ .../AbstractObjectNormalizerTest.php | 48 +++++++++++++++++++ 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateChildDummy.php create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateParentDummy.php diff --git a/src/Symfony/Component/Serializer/CHANGELOG.md b/src/Symfony/Component/Serializer/CHANGELOG.md index fc4ab8b0a3b7d..4bfd664f0aa87 100644 --- a/src/Symfony/Component/Serializer/CHANGELOG.md +++ b/src/Symfony/Component/Serializer/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * added the list of constraint violations' parameters in `ConstraintViolationListNormalizer` * added support for serializing `DateTimeZone` objects + * added a `deep_object_to_populate` context option to recursive denormalize on `object_to_populate` object. 4.2.0 ----- diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index b17d1e8c59e10..599f503e42421 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Serializer\Normalizer; use Symfony\Component\PropertyAccess\Exception\InvalidArgumentException; +use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; use Symfony\Component\Serializer\Encoder\JsonEncoder; @@ -38,6 +39,7 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer const SKIP_NULL_VALUES = 'skip_null_values'; const MAX_DEPTH_HANDLER = 'max_depth_handler'; const EXCLUDE_FROM_CACHE_KEY = 'exclude_from_cache_key'; + const DEEP_OBJECT_TO_POPULATE = 'deep_object_to_populate'; private $propertyTypeExtractor; private $typesCache = []; @@ -274,6 +276,13 @@ public function denormalize($data, $class, $format = null, array $context = []) continue; } + if ($context[self::DEEP_OBJECT_TO_POPULATE] ?? $this->defaultContext[self::DEEP_OBJECT_TO_POPULATE] ?? false) { + try { + $context[self::OBJECT_TO_POPULATE] = $this->getAttributeValue($object, $attribute, $format, $context); + } catch (NoSuchPropertyException $e) { + } + } + $value = $this->validateAndDenormalize($class, $attribute, $value, $format, $context); try { $this->setAttributeValue($object, $attribute, $value, $format, $context); diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectToPopulateTrait.php b/src/Symfony/Component/Serializer/Normalizer/ObjectToPopulateTrait.php index 7150a6e6ee383..9d9fc48dd6fb9 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectToPopulateTrait.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectToPopulateTrait.php @@ -26,7 +26,7 @@ trait ObjectToPopulateTrait */ protected function extractObjectToPopulate($class, array $context, $key = null) { - $key = $key ?: 'object_to_populate'; + $key = $key ?? AbstractNormalizer::OBJECT_TO_POPULATE; if (isset($context[$key]) && \is_object($context[$key]) && $context[$key] instanceof $class) { return $context[$key]; diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateChildDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateChildDummy.php new file mode 100644 index 0000000000000..339b25be3566a --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateChildDummy.php @@ -0,0 +1,22 @@ +<?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\Component\Serializer\Tests\Fixtures; + +/** + * @author Jérôme Desjardin <jewome62@gmail.com> + */ +class DeepObjectPopulateChildDummy +{ + public $foo; + + public $bar; +} diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateParentDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateParentDummy.php new file mode 100644 index 0000000000000..4e65ab4307d74 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DeepObjectPopulateParentDummy.php @@ -0,0 +1,33 @@ +<?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\Component\Serializer\Tests\Fixtures; + +/** + * @author Jérôme Desjardin <jewome62@gmail.com> + */ +class DeepObjectPopulateParentDummy +{ + /** + * @var DeepObjectPopulateChildDummy|null + */ + private $child; + + public function setChild(?DeepObjectPopulateChildDummy $child) + { + $this->child = $child; + } + + public function getChild(): ?DeepObjectPopulateChildDummy + { + return $this->child; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index a45009d2330d5..9176f7f82a87d 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -23,6 +23,8 @@ use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\SerializerAwareInterface; use Symfony\Component\Serializer\SerializerInterface; +use Symfony\Component\Serializer\Tests\Fixtures\DeepObjectPopulateChildDummy; +use Symfony\Component\Serializer\Tests\Fixtures\DeepObjectPopulateParentDummy; class AbstractObjectNormalizerTest extends TestCase { @@ -171,6 +173,48 @@ public function testSkipNullValues() $result = $normalizer->normalize($dummy, null, [AbstractObjectNormalizer::SKIP_NULL_VALUES => true]); $this->assertSame(['bar' => 'present'], $result); } + + public function testDeepObjectToPopulate() + { + $child = new DeepObjectPopulateChildDummy(); + $child->bar = 'bar-old'; + $child->foo = 'foo-old'; + + $parent = new DeepObjectPopulateParentDummy(); + $parent->setChild($child); + + $context = [ + AbstractObjectNormalizer::OBJECT_TO_POPULATE => $parent, + AbstractObjectNormalizer::DEEP_OBJECT_TO_POPULATE => true, + ]; + + $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); + $normalizer = new ObjectNormalizer($classMetadataFactory, null, null, new PhpDocExtractor()); + + $newChild = new DeepObjectPopulateChildDummy(); + $newChild->bar = 'bar-new'; + $newChild->foo = 'foo-old'; + + $serializer = $this->getMockBuilder(__NAMESPACE__.'\ObjectSerializerDenormalizer')->getMock(); + $serializer + ->method('supportsDenormalization') + ->with($this->arrayHasKey('bar'), + $this->equalTo(DeepObjectPopulateChildDummy::class), + $this->isNull(), + $this->contains($child)) + ->willReturn(true); + $serializer->method('denormalize')->willReturn($newChild); + + $normalizer->setSerializer($serializer); + $normalizer->denormalize([ + 'child' => [ + 'bar' => 'bar-new', + ], + ], 'Symfony\Component\Serializer\Tests\Fixtures\DeepObjectPopulateParentDummy', null, $context); + + $this->assertSame('bar-new', $parent->getChild()->bar); + $this->assertSame('foo-old', $parent->getChild()->foo); + } } class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer @@ -348,3 +392,7 @@ public function setSerializer(SerializerInterface $serializer) $this->serializer = $serializer; } } + +abstract class ObjectSerializerDenormalizer implements SerializerInterface, DenormalizerInterface +{ +} From 77424c85572d76d52182a04106ba19e3313d8f06 Mon Sep 17 00:00:00 2001 From: Valentin <udaltsov.valentin@gmail.com> Date: Sun, 7 Apr 2019 11:13:09 +0200 Subject: [PATCH 432/495] Refactor DefaultChoiceListFactory --- .../Factory/DefaultChoiceListFactory.php | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php index 5383f2a78393c..3e91caa437402 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/DefaultChoiceListFactory.php @@ -68,7 +68,7 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, // choice is not added to any group if (\is_callable($groupBy)) { foreach ($choices as $value => $choice) { - self::addChoiceViewGroupedBy( + self::addChoiceViewsGroupedByCallable( $groupBy, $choice, (string) $value, @@ -81,9 +81,23 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, $otherViews ); } + + // Remove empty group views that may have been created by + // addChoiceViewsGroupedByCallable() + foreach ($preferredViews as $key => $view) { + if ($view instanceof ChoiceGroupView && 0 === \count($view->choices)) { + unset($preferredViews[$key]); + } + } + + foreach ($otherViews as $key => $view) { + if ($view instanceof ChoiceGroupView && 0 === \count($view->choices)) { + unset($otherViews[$key]); + } + } } else { // Otherwise use the original structure of the choices - self::addChoiceViewsGroupedBy( + self::addChoiceViewsFromStructuredValues( $list->getStructuredValues(), $label, $choices, @@ -96,20 +110,6 @@ public function createView(ChoiceListInterface $list, $preferredChoices = null, ); } - // Remove any empty group view that may have been created by - // addChoiceViewGroupedBy() - foreach ($preferredViews as $key => $view) { - if ($view instanceof ChoiceGroupView && 0 === \count($view->choices)) { - unset($preferredViews[$key]); - } - } - - foreach ($otherViews as $key => $view) { - if ($view instanceof ChoiceGroupView && 0 === \count($view->choices)) { - unset($otherViews[$key]); - } - } - return new ChoiceListView($otherViews, $preferredViews); } @@ -148,9 +148,9 @@ private static function addChoiceView($choice, $value, $label, $keys, &$index, $ } } - private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) + private static function addChoiceViewsFromStructuredValues($values, $label, $choices, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { - foreach ($groupBy as $key => $value) { + foreach ($values as $key => $value) { if (null === $value) { continue; } @@ -160,7 +160,7 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key $preferredViewsForGroup = []; $otherViewsForGroup = []; - self::addChoiceViewsGroupedBy( + self::addChoiceViewsFromStructuredValues( $value, $label, $choices, @@ -198,7 +198,7 @@ private static function addChoiceViewsGroupedBy($groupBy, $label, $choices, $key } } - private static function addChoiceViewGroupedBy($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) + private static function addChoiceViewsGroupedByCallable($groupBy, $choice, $value, $label, $keys, &$index, $attr, $isPreferred, &$preferredViews, &$otherViews) { $groupLabel = $groupBy($choice, $keys[$value], $value); From 388d8f548c6bc78890021e4c9b5f9fadc8759b3a Mon Sep 17 00:00:00 2001 From: Valentin <udaltsov.valentin@gmail.com> Date: Sun, 7 Apr 2019 11:00:56 +0200 Subject: [PATCH 433/495] [Routing] UrlHelper to get absolute URL for a path --- UPGRADE-4.3.md | 7 + UPGRADE-5.0.md | 7 + src/Symfony/Bridge/Twig/CHANGELOG.md | 3 + .../Extension/HttpFoundationExtension.php | 92 ++++------- .../Extension/HttpFoundationExtensionTest.php | 3 + src/Symfony/Bridge/Twig/composer.json | 3 +- .../Resources/config/services.xml | 6 + .../TwigBundle/Resources/config/twig.xml | 3 +- src/Symfony/Bundle/TwigBundle/composer.json | 4 +- .../Component/HttpFoundation/CHANGELOG.md | 1 + .../HttpFoundation/Tests/UrlHelperTest.php | 143 ++++++++++++++++++ .../Component/HttpFoundation/UrlHelper.php | 102 +++++++++++++ 12 files changed, 306 insertions(+), 68 deletions(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/UrlHelperTest.php create mode 100644 src/Symfony/Component/HttpFoundation/UrlHelper.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 020f3a40181cb..4cbf2216238ba 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -145,6 +145,13 @@ Security } ``` +TwigBridge +========== + + * deprecated the `$requestStack` and `$requestContext` arguments of the + `HttpFoundationExtension`, pass a `Symfony\Component\HttpFoundation\UrlHelper` + instance as the only argument instead + Workflow -------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 68001974bb92c..aa448846237f7 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -364,6 +364,13 @@ TwigBundle * The default value (`false`) of the `twig.strict_variables` configuration option has been changed to `%kernel.debug%`. * The `transchoice` tag and filter have been removed, use the `trans` ones instead with a `%count%` parameter. * Removed support for legacy templates directories `src/Resources/views/` and `src/Resources/<BundleName>/views/`, use `templates/` and `templates/bundles/<BundleName>/` instead. + +TwigBridge +---------- + + * removed the `$requestStack` and `$requestContext` arguments of the + `HttpFoundationExtension`, pass a `Symfony\Component\HttpFoundation\UrlHelper` + instance as the only argument instead Validator -------- diff --git a/src/Symfony/Bridge/Twig/CHANGELOG.md b/src/Symfony/Bridge/Twig/CHANGELOG.md index 3b806c47fb2b0..905d242217c3f 100644 --- a/src/Symfony/Bridge/Twig/CHANGELOG.md +++ b/src/Symfony/Bridge/Twig/CHANGELOG.md @@ -6,6 +6,9 @@ CHANGELOG * added the `form_parent()` function that allows to reliably retrieve the parent form in Twig templates * added the `workflow_transition_blockers()` function + * deprecated the `$requestStack` and `$requestContext` arguments of the + `HttpFoundationExtension`, pass a `Symfony\Component\HttpFoundation\UrlHelper` + instance as the only argument instead 4.2.0 ----- diff --git a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php index 82b9a92f7516c..e99c835879d6d 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\UrlHelper; use Symfony\Component\Routing\RequestContext; use Twig\Extension\AbstractExtension; use Twig\TwigFunction; @@ -24,13 +25,34 @@ */ class HttpFoundationExtension extends AbstractExtension { - private $requestStack; - private $requestContext; + private $urlHelper; - public function __construct(RequestStack $requestStack, RequestContext $requestContext = null) + /** + * @param UrlHelper $urlHelper + */ + public function __construct($urlHelper) { - $this->requestStack = $requestStack; - $this->requestContext = $requestContext; + if ($urlHelper instanceof UrlHelper) { + $this->urlHelper = $urlHelper; + + return; + } + + if (!$urlHelper instanceof RequestStack) { + throw new \TypeError(sprintf('The first argument must be an instance of "%s" or an instance of "%s".', UrlHelper::class, RequestStack::class)); + } + + @trigger_error(sprintf('Passing a "%s" instance as the first argument to the "%s" constructor is deprecated since Symfony 4.3, pass a "%s" instance instead.', RequestStack::class, __CLASS__, UrlHelper::class), E_USER_DEPRECATED); + + $requestContext = null; + if (2 === \func_num_args()) { + $requestContext = \func_get_arg(1); + if (!$requestContext instanceof RequestContext) { + throw new \TypeError(sprintf('The second argument must be an instance of "%s".', RequestContext::class)); + } + } + + $this->urlHelper = new UrlHelper($urlHelper, $requestContext); } /** @@ -57,55 +79,7 @@ public function getFunctions() */ public function generateAbsoluteUrl($path) { - if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) { - return $path; - } - - if (!$request = $this->requestStack->getMasterRequest()) { - if (null !== $this->requestContext && '' !== $host = $this->requestContext->getHost()) { - $scheme = $this->requestContext->getScheme(); - $port = ''; - - if ('http' === $scheme && 80 != $this->requestContext->getHttpPort()) { - $port = ':'.$this->requestContext->getHttpPort(); - } elseif ('https' === $scheme && 443 != $this->requestContext->getHttpsPort()) { - $port = ':'.$this->requestContext->getHttpsPort(); - } - - if ('#' === $path[0]) { - $queryString = $this->requestContext->getQueryString(); - $path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path; - } elseif ('?' === $path[0]) { - $path = $this->requestContext->getPathInfo().$path; - } - - if ('/' !== $path[0]) { - $path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path; - } - - return $scheme.'://'.$host.$port.$path; - } - - return $path; - } - - if ('#' === $path[0]) { - $path = $request->getRequestUri().$path; - } elseif ('?' === $path[0]) { - $path = $request->getPathInfo().$path; - } - - if (!$path || '/' !== $path[0]) { - $prefix = $request->getPathInfo(); - $last = \strlen($prefix) - 1; - if ($last !== $pos = strrpos($prefix, '/')) { - $prefix = substr($prefix, 0, $pos).'/'; - } - - return $request->getUriForPath($prefix.$path); - } - - return $request->getSchemeAndHttpHost().$path; + return $this->urlHelper->getAbsoluteUrl($path); } /** @@ -121,15 +95,7 @@ public function generateAbsoluteUrl($path) */ public function generateRelativePath($path) { - if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) { - return $path; - } - - if (!$request = $this->requestStack->getMasterRequest()) { - return $path; - } - - return $request->getRelativeUriForPath($path); + return $this->urlHelper->getRelativePath($path); } /** diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php index 38ee375b94b13..396f433bfda63 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpFoundationExtensionTest.php @@ -17,6 +17,9 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\RequestContext; +/** + * @group legacy + */ class HttpFoundationExtensionTest extends TestCase { /** diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index c083ff32f44b2..2da2a018ea24a 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -26,7 +26,7 @@ "symfony/dependency-injection": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", "symfony/form": "^4.3", - "symfony/http-foundation": "~3.4|~4.0", + "symfony/http-foundation": "~4.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/mime": "~4.3", "symfony/polyfill-intl-icu": "~1.0", @@ -46,6 +46,7 @@ "conflict": { "symfony/console": "<3.4", "symfony/form": "<4.3", + "symfony/http-foundation": "<4.3", "symfony/translation": "<4.2", "symfony/workflow": "<4.3" }, diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml index 7455ae8833de3..01e93f131ae1a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml @@ -63,6 +63,12 @@ <service id="request_stack" class="Symfony\Component\HttpFoundation\RequestStack" public="true" /> <service id="Symfony\Component\HttpFoundation\RequestStack" alias="request_stack" /> + <service id="url_helper" class="Symfony\Component\HttpFoundation\UrlHelper"> + <argument type="service" id="request_stack" /> + <argument type="service" id="router.request_context" on-invalid="ignore" /> + </service> + <service id="Symfony\Component\HttpFoundation\UrlHelper" alias="url_helper" /> + <service id="cache_warmer" class="Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate" public="true"> <argument type="tagged" tag="kernel.cache_warmer" /> <argument>%kernel.debug%</argument> diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 3992bc4d28919..13121a2a189b0 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -108,8 +108,7 @@ </service> <service id="twig.extension.httpfoundation" class="Symfony\Bridge\Twig\Extension\HttpFoundationExtension"> - <argument type="service" id="request_stack" /> - <argument type="service" id="router.request_context" on-invalid="ignore" /> + <argument type="service" id="url_helper" /> </service> <service id="twig.extension.debug" class="Twig\Extension\DebugExtension" /> diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 9c533b20d8310..0690506fa4991 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -18,8 +18,8 @@ "require": { "php": "^7.1.3", "symfony/config": "~4.2", - "symfony/twig-bridge": "^4.2", - "symfony/http-foundation": "~4.1", + "symfony/twig-bridge": "^4.3", + "symfony/http-foundation": "~4.3", "symfony/http-kernel": "~4.1", "symfony/polyfill-ctype": "~1.8", "twig/twig": "~1.34|~2.4" diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index ad4c1bf721a06..54acd6ae10bde 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -10,6 +10,7 @@ CHANGELOG * deprecated `MimeType` and `MimeTypeExtensionGuesser` in favor of `Symfony\Component\Mime\MimeTypes`. * deprecated `FileBinaryMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileBinaryMimeTypeGuesser`. * deprecated `FileinfoMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileinfoMimeTypeGuesser`. + * added `UrlHelper` that allows to get an absolute URL and a relative path for a given path 4.2.0 ----- diff --git a/src/Symfony/Component/HttpFoundation/Tests/UrlHelperTest.php b/src/Symfony/Component/HttpFoundation/Tests/UrlHelperTest.php new file mode 100644 index 0000000000000..9a750bd8a3bb5 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/UrlHelperTest.php @@ -0,0 +1,143 @@ +<?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\Component\HttpFoundation\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\UrlHelper; +use Symfony\Component\Routing\RequestContext; + +class UrlHelperTest extends TestCase +{ + /** + * @dataProvider getGenerateAbsoluteUrlData() + */ + public function testGenerateAbsoluteUrl($expected, $path, $pathinfo) + { + $stack = new RequestStack(); + $stack->push(Request::create($pathinfo)); + $helper = new UrlHelper($stack); + + $this->assertEquals($expected, $helper->getAbsoluteUrl($path)); + } + + public function getGenerateAbsoluteUrlData() + { + return [ + ['http://localhost/foo.png', '/foo.png', '/foo/bar.html'], + ['http://localhost/foo/foo.png', 'foo.png', '/foo/bar.html'], + ['http://localhost/foo/foo.png', 'foo.png', '/foo/bar'], + ['http://localhost/foo/bar/foo.png', 'foo.png', '/foo/bar/'], + + ['http://example.com/baz', 'http://example.com/baz', '/'], + ['https://example.com/baz', 'https://example.com/baz', '/'], + ['//example.com/baz', '//example.com/baz', '/'], + + ['http://localhost/foo/bar?baz', '?baz', '/foo/bar'], + ['http://localhost/foo/bar?baz=1', '?baz=1', '/foo/bar?foo=1'], + ['http://localhost/foo/baz?baz=1', 'baz?baz=1', '/foo/bar?foo=1'], + + ['http://localhost/foo/bar#baz', '#baz', '/foo/bar'], + ['http://localhost/foo/bar?0#baz', '#baz', '/foo/bar?0'], + ['http://localhost/foo/bar?baz=1#baz', '?baz=1#baz', '/foo/bar?foo=1'], + ['http://localhost/foo/baz?baz=1#baz', 'baz?baz=1#baz', '/foo/bar?foo=1'], + ]; + } + + /** + * @dataProvider getGenerateAbsoluteUrlRequestContextData + */ + public function testGenerateAbsoluteUrlWithRequestContext($path, $baseUrl, $host, $scheme, $httpPort, $httpsPort, $expected) + { + if (!class_exists('Symfony\Component\Routing\RequestContext')) { + $this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.'); + } + + $requestContext = new RequestContext($baseUrl, 'GET', $host, $scheme, $httpPort, $httpsPort, $path); + $helper = new UrlHelper(new RequestStack(), $requestContext); + + $this->assertEquals($expected, $helper->getAbsoluteUrl($path)); + } + + /** + * @dataProvider getGenerateAbsoluteUrlRequestContextData + */ + public function testGenerateAbsoluteUrlWithoutRequestAndRequestContext($path) + { + if (!class_exists('Symfony\Component\Routing\RequestContext')) { + $this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.'); + } + + $helper = new UrlHelper(new RequestStack()); + + $this->assertEquals($path, $helper->getAbsoluteUrl($path)); + } + + public function getGenerateAbsoluteUrlRequestContextData() + { + return [ + ['/foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo.png'], + ['foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo/foo.png'], + ['foo.png', '/foo/bar/', 'localhost', 'http', 80, 443, 'http://localhost/foo/bar/foo.png'], + ['/foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo.png'], + ['foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo/foo.png'], + ['foo.png', '/foo/bar/', 'localhost', 'https', 80, 443, 'https://localhost/foo/bar/foo.png'], + ['/foo.png', '/foo', 'localhost', 'http', 443, 80, 'http://localhost:443/foo.png'], + ['/foo.png', '/foo', 'localhost', 'https', 443, 80, 'https://localhost:80/foo.png'], + ]; + } + + public function testGenerateAbsoluteUrlWithScriptFileName() + { + $request = Request::create('http://localhost/app/web/app_dev.php'); + $request->server->set('SCRIPT_FILENAME', '/var/www/app/web/app_dev.php'); + + $stack = new RequestStack(); + $stack->push($request); + $helper = new UrlHelper($stack); + + $this->assertEquals( + 'http://localhost/app/web/bundles/framework/css/structure.css', + $helper->getAbsoluteUrl('/app/web/bundles/framework/css/structure.css') + ); + } + + /** + * @dataProvider getGenerateRelativePathData() + */ + public function testGenerateRelativePath($expected, $path, $pathinfo) + { + if (!method_exists('Symfony\Component\HttpFoundation\Request', 'getRelativeUriForPath')) { + $this->markTestSkipped('Your version of Symfony HttpFoundation is too old.'); + } + + $stack = new RequestStack(); + $stack->push(Request::create($pathinfo)); + $urlHelper = new UrlHelper($stack); + + $this->assertEquals($expected, $urlHelper->getRelativePath($path)); + } + + public function getGenerateRelativePathData() + { + return [ + ['../foo.png', '/foo.png', '/foo/bar.html'], + ['../baz/foo.png', '/baz/foo.png', '/foo/bar.html'], + ['baz/foo.png', 'baz/foo.png', '/foo/bar.html'], + + ['http://example.com/baz', 'http://example.com/baz', '/'], + ['https://example.com/baz', 'https://example.com/baz', '/'], + ['//example.com/baz', '//example.com/baz', '/'], + ]; + } +} diff --git a/src/Symfony/Component/HttpFoundation/UrlHelper.php b/src/Symfony/Component/HttpFoundation/UrlHelper.php new file mode 100644 index 0000000000000..3c06e9321734f --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/UrlHelper.php @@ -0,0 +1,102 @@ +<?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\Component\HttpFoundation; + +use Symfony\Component\Routing\RequestContext; + +/** + * A helper service for manipulating URLs within and outside the request scope. + * + * @author Valentin Udaltsov <udaltsov.valentin@gmail.com> + */ +final class UrlHelper +{ + private $requestStack; + private $requestContext; + + public function __construct(RequestStack $requestStack, ?RequestContext $requestContext = null) + { + $this->requestStack = $requestStack; + $this->requestContext = $requestContext; + } + + public function getAbsoluteUrl(string $path): string + { + if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) { + return $path; + } + + if (null === $request = $this->requestStack->getMasterRequest()) { + return $this->getAbsoluteUrlFromContext($path); + } + + if ('#' === $path[0]) { + $path = $request->getRequestUri().$path; + } elseif ('?' === $path[0]) { + $path = $request->getPathInfo().$path; + } + + if (!$path || '/' !== $path[0]) { + $prefix = $request->getPathInfo(); + $last = \strlen($prefix) - 1; + if ($last !== $pos = strrpos($prefix, '/')) { + $prefix = substr($prefix, 0, $pos).'/'; + } + + return $request->getUriForPath($prefix.$path); + } + + return $request->getSchemeAndHttpHost().$path; + } + + public function getRelativePath(string $path): string + { + if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) { + return $path; + } + + if (null === $request = $this->requestStack->getMasterRequest()) { + return $path; + } + + return $request->getRelativeUriForPath($path); + } + + private function getAbsoluteUrlFromContext(string $path): string + { + if (null === $this->requestContext || '' === $host = $this->requestContext->getHost()) { + return $path; + } + + $scheme = $this->requestContext->getScheme(); + $port = ''; + + if ('http' === $scheme && 80 !== $this->requestContext->getHttpPort()) { + $port = ':'.$this->requestContext->getHttpPort(); + } elseif ('https' === $scheme && 443 !== $this->requestContext->getHttpsPort()) { + $port = ':'.$this->requestContext->getHttpsPort(); + } + + if ('#' === $path[0]) { + $queryString = $this->requestContext->getQueryString(); + $path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path; + } elseif ('?' === $path[0]) { + $path = $this->requestContext->getPathInfo().$path; + } + + if ('/' !== $path[0]) { + $path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path; + } + + return $scheme.'://'.$host.$port.$path; + } +} From 287c39b9ea52cd26a713fb1e7fe17fbf2503938b Mon Sep 17 00:00:00 2001 From: Jules Pietri <heah@heahprod.com> Date: Sun, 7 Apr 2019 11:28:32 +0200 Subject: [PATCH 434/495] [DoctrineBridge] Deprecated implicit optimization in DoctrineChoiceLoader --- src/Symfony/Bridge/Doctrine/CHANGELOG.md | 1 + .../Form/ChoiceList/DoctrineChoiceLoader.php | 14 +++- .../Doctrine/Form/Type/DoctrineType.php | 3 +- .../ChoiceList/DoctrineChoiceLoaderTest.php | 77 +++++++++++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index 6b617825c9190..27cabfa558fd9 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -5,6 +5,7 @@ CHANGELOG ----- * changed guessing of DECIMAL to set the `input` option of `NumberType` to string + * deprecated not passing an `IdReader` to the `DoctrineChoiceLoader` when query can be optimized with a single id field 4.2.0 ----- diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index 0ed66f8c44f41..fd891abb34b09 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -49,9 +49,19 @@ public function __construct(ObjectManager $manager, string $class, IdReader $idR { $classMetadata = $manager->getClassMetadata($class); + if ((5 > \func_num_args() || false !== func_get_arg(4)) && null === $idReader) { + $idReader = new IdReader($manager, $classMetadata); + + if ($idReader->isSingleId()) { + @trigger_error(sprintf('Not explicitly passing an instance of "%s" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0.', IdReader::class, $class), E_USER_DEPRECATED); + } else { + $idReader = null; + } + } + $this->manager = $manager; $this->class = $classMetadata->getName(); - $this->idReader = $idReader ?: new IdReader($manager, $classMetadata); + $this->idReader = $idReader; $this->objectLoader = $objectLoader; } @@ -120,7 +130,7 @@ public function loadChoicesForValues(array $values, $value = null) // Optimize performance in case we have an object loader and // a single-field identifier - $optimize = null === $value || \is_array($value) && $this->idReader === $value[0]; + $optimize = $this->idReader && (null === $value || \is_array($value) && $this->idReader === $value[0]); if ($optimize && !$this->choiceList && $this->objectLoader && $this->idReader->isSingleId()) { $unorderedObjects = $this->objectLoader->getEntitiesByIds($this->idReader->getIdField(), $values); diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index cd3534d51253f..03bf6a0ba509d 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -150,7 +150,8 @@ public function configureOptions(OptionsResolver $resolver) $options['em'], $options['class'], $options['id_reader'], - $entityLoader + $entityLoader, + false ); if (null !== $hash) { diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php index de6f3a3aa970a..2fbb07d7f3406 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php @@ -18,6 +18,7 @@ use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader; use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface; use Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; @@ -393,4 +394,80 @@ public function testLoadChoicesForValuesLoadsOnlyChoicesIfValueIsIdReader() $this->assertSame([$this->obj2], $loader->loadChoicesForValues(['2'], $value)); } + + /** + * @group legacy + * + * @expectedDeprecation Not explicitly passing an instance of "Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0. + */ + public function testLoaderWithoutIdReaderCanBeOptimized() + { + $obj1 = new SingleIntIdEntity('1', 'one'); + $obj2 = new SingleIntIdEntity('2', 'two'); + + $metadata = $this->createMock(ClassMetadata::class); + $metadata->expects($this->once()) + ->method('getIdentifierFieldNames') + ->willReturn(['idField']) + ; + $metadata->expects($this->any()) + ->method('getIdentifierValues') + ->willReturnCallback(function ($obj) use ($obj1, $obj2) { + if ($obj === $obj1) { + return ['idField' => '1']; + } + if ($obj === $obj2) { + return ['idField' => '2']; + } + + return null; + }) + ; + + $this->om = $this->createMock(ObjectManager::class); + $this->om->expects($this->once()) + ->method('getClassMetadata') + ->with(SingleIntIdEntity::class) + ->willReturn($metadata) + ; + $this->om->expects($this->any()) + ->method('contains') + ->with($this->isInstanceOf(SingleIntIdEntity::class)) + ->willReturn(true) + ; + + $loader = new DoctrineChoiceLoader( + $this->om, + SingleIntIdEntity::class, + null, + $this->objectLoader + ); + + $choices = [$obj1, $obj2]; + + $this->idReader->expects($this->any()) + ->method('isSingleId') + ->willReturn(true); + + $this->idReader->expects($this->any()) + ->method('getIdField') + ->willReturn('idField'); + + $this->repository->expects($this->never()) + ->method('findAll'); + + $this->objectLoader->expects($this->once()) + ->method('getEntitiesByIds') + ->with('idField', ['1']) + ->willReturn($choices); + + $this->idReader->expects($this->any()) + ->method('getIdValue') + ->willReturnMap([ + [$obj1, '1'], + [$obj2, '2'], + ]); + + $this->assertSame([$obj1], $loader->loadChoicesForValues(['1'])); + } } From 35bf4203e84dcb8b7d9520d5454a574f7b11169e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Bogusz?= <przemyslaw.bogusz@tubotax.pl> Date: Sun, 27 Jan 2019 00:31:22 +0100 Subject: [PATCH 435/495] [DI] Fix bad error message for unused bind under _defaults --- .../Argument/BoundArgument.php | 14 +++++-- .../Compiler/ResolveBindingsPass.php | 39 +++++++++++++++++-- .../Configurator/DefaultsConfigurator.php | 10 +++++ .../Configurator/InstanceofConfigurator.php | 11 ++++++ .../Configurator/ServiceConfigurator.php | 4 +- .../Configurator/ServicesConfigurator.php | 8 ++-- .../Loader/Configurator/Traits/BindTrait.php | 6 ++- .../Loader/XmlFileLoader.php | 13 ++++++- .../Loader/YamlFileLoader.php | 10 ++++- .../Compiler/ResolveBindingsPassTest.php | 2 +- ...RegisterControllerArgumentLocatorsPass.php | 4 +- 11 files changed, 104 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php index b2fc28d8d56db..4889c8e7cb02d 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php @@ -16,13 +16,19 @@ */ final class BoundArgument implements ArgumentInterface { + const SERVICE_BINDING = 0; + const DEFAULTS_BINDING = 1; + const INSTANCEOF_BINDING = 2; + private static $sequence = 0; private $value; private $identifier; private $used; + private $type; + private $file; - public function __construct($value, bool $trackUsage = true) + public function __construct($value, bool $trackUsage = true, int $type = 0, string $file = null) { $this->value = $value; if ($trackUsage) { @@ -30,6 +36,8 @@ public function __construct($value, bool $trackUsage = true) } else { $this->used = true; } + $this->type = $type; + $this->file = $file; } /** @@ -37,7 +45,7 @@ public function __construct($value, bool $trackUsage = true) */ public function getValues() { - return [$this->value, $this->identifier, $this->used]; + return [$this->value, $this->identifier, $this->used, $this->type, $this->file]; } /** @@ -45,6 +53,6 @@ public function getValues() */ public function setValues(array $values) { - list($this->value, $this->identifier, $this->used) = $values; + list($this->value, $this->identifier, $this->used, $this->type, $this->file) = $values; } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php index db6c588f91c5a..5cee0023060c4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php @@ -37,8 +37,39 @@ public function process(ContainerBuilder $container) try { parent::process($container); - foreach ($this->unusedBindings as list($key, $serviceId)) { - $message = sprintf('Unused binding "%s" in service "%s".', $key, $serviceId); + foreach ($this->unusedBindings as list($key, $serviceId, $bindingType, $file)) { + $argumentType = $argumentName = $message = null; + + if (false !== strpos($key, ' ')) { + list($argumentType, $argumentName) = explode(' ', $key, 2); + } elseif ('$' === $key[0]) { + $argumentName = $key; + } else { + $argumentType = $key; + } + + if ($argumentType) { + $message .= sprintf('of type "%s" ', $argumentType); + } + + if ($argumentName) { + $message .= sprintf('named "%s" ', $argumentName); + } + + if (BoundArgument::DEFAULTS_BINDING === $bindingType) { + $message .= 'under "_defaults"'; + } elseif (BoundArgument::INSTANCEOF_BINDING === $bindingType) { + $message .= 'under "_instanceof"'; + } else { + $message .= sprintf('for service "%s"', $serviceId); + } + + if ($file) { + $message .= sprintf(' in file "%s"', $file); + } + + $message = sprintf('A binding is configured for an argument %s, but no corresponding argument has been found. It may be unused and should be removed, or it may have a typo.', $message); + if ($this->errorMessages) { $message .= sprintf("\nCould be related to%s:", 1 < \count($this->errorMessages) ? ' one of' : ''); } @@ -75,12 +106,12 @@ protected function processValue($value, $isRoot = false) } foreach ($bindings as $key => $binding) { - list($bindingValue, $bindingId, $used) = $binding->getValues(); + list($bindingValue, $bindingId, $used, $bindingType, $file) = $binding->getValues(); if ($used) { $this->usedBindings[$bindingId] = true; unset($this->unusedBindings[$bindingId]); } elseif (!isset($this->usedBindings[$bindingId])) { - $this->unusedBindings[$bindingId] = [$key, $this->currentId]; + $this->unusedBindings[$bindingId] = [$key, $this->currentId, $bindingType, $file]; } if (preg_match('/^(?:(?:array|bool|float|int|string) )?\$/', $key)) { diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php index b928d75860296..b527fd51da153 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/DefaultsConfigurator.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; /** @@ -25,6 +26,15 @@ class DefaultsConfigurator extends AbstractServiceConfigurator use Traits\BindTrait; use Traits\PublicTrait; + private $path; + + public function __construct(ServicesConfigurator $parent, Definition $definition, string $path = null) + { + parent::__construct($parent, $definition, null, []); + + $this->path = $path; + } + /** * Adds a tag for this definition. * diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php index ad9a6872b6800..f75e17614476f 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/InstanceofConfigurator.php @@ -11,6 +11,8 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\DependencyInjection\Definition; + /** * @author Nicolas Grekas <p@tchwork.com> */ @@ -28,6 +30,15 @@ class InstanceofConfigurator extends AbstractServiceConfigurator use Traits\TagTrait; use Traits\BindTrait; + private $path; + + public function __construct(ServicesConfigurator $parent, Definition $definition, string $id, string $path = null) + { + parent::__construct($parent, $definition, $id, []); + + $this->path = $path; + } + /** * Defines an instanceof-conditional to be applied to following service definitions. */ diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php index 8fc60fbd376bd..13584973af5ff 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServiceConfigurator.php @@ -45,12 +45,14 @@ class ServiceConfigurator extends AbstractServiceConfigurator private $container; private $instanceof; private $allowParent; + private $path; - public function __construct(ContainerBuilder $container, array $instanceof, bool $allowParent, ServicesConfigurator $parent, Definition $definition, $id, array $defaultTags) + public function __construct(ContainerBuilder $container, array $instanceof, bool $allowParent, ServicesConfigurator $parent, Definition $definition, $id, array $defaultTags, string $path = null) { $this->container = $container; $this->instanceof = $instanceof; $this->allowParent = $allowParent; + $this->path = $path; parent::__construct($parent, $definition, $id, $defaultTags); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php index 366828ea4cbdc..b693fc2d66e7e 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ServicesConfigurator.php @@ -29,6 +29,7 @@ class ServicesConfigurator extends AbstractConfigurator private $container; private $loader; private $instanceof; + private $path; private $anonymousHash; private $anonymousCount; @@ -38,6 +39,7 @@ public function __construct(ContainerBuilder $container, PhpFileLoader $loader, $this->container = $container; $this->loader = $loader; $this->instanceof = &$instanceof; + $this->path = $path; $this->anonymousHash = ContainerBuilder::hash($path ?: mt_rand()); $this->anonymousCount = &$anonymousCount; $instanceof = []; @@ -48,7 +50,7 @@ public function __construct(ContainerBuilder $container, PhpFileLoader $loader, */ final public function defaults(): DefaultsConfigurator { - return new DefaultsConfigurator($this, $this->defaults = new Definition()); + return new DefaultsConfigurator($this, $this->defaults = new Definition(), $this->path); } /** @@ -58,7 +60,7 @@ final public function instanceof(string $fqcn): InstanceofConfigurator { $this->instanceof[$fqcn] = $definition = new ChildDefinition(''); - return new InstanceofConfigurator($this, $definition, $fqcn); + return new InstanceofConfigurator($this, $definition, $fqcn, $this->path); } /** @@ -90,7 +92,7 @@ final public function set(?string $id, string $class = null): ServiceConfigurato $definition->setBindings($defaults->getBindings()); $definition->setChanges([]); - $configurator = new ServiceConfigurator($this->container, $this->instanceof, $allowParent, $this, $definition, $id, $defaults->getTags()); + $configurator = new ServiceConfigurator($this->container, $this->instanceof, $allowParent, $this, $definition, $id, $defaults->getTags(), $this->path); return null !== $class ? $configurator->class($class) : $configurator; } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php index 5d6c57cb3b9b2..621158fdee277 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php @@ -11,7 +11,10 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; +use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Loader\Configurator\DefaultsConfigurator; +use Symfony\Component\DependencyInjection\Loader\Configurator\InstanceofConfigurator; use Symfony\Component\DependencyInjection\Reference; trait BindTrait @@ -35,7 +38,8 @@ final public function bind($nameOrFqcn, $valueOrRef) throw new InvalidArgumentException(sprintf('Invalid binding for service "%s": named arguments must start with a "$", and FQCN must map to references. Neither applies to binding "%s".', $this->id, $nameOrFqcn)); } $bindings = $this->definition->getBindings(); - $bindings[$nameOrFqcn] = $valueOrRef; + $type = $this instanceof DefaultsConfigurator ? BoundArgument::DEFAULTS_BINDING : ($this instanceof InstanceofConfigurator ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING); + $bindings[$nameOrFqcn] = new BoundArgument($valueOrRef, true, $type, $this->path ?? null); $this->definition->setBindings($bindings); return $this; diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 6a07c613e2cdd..bbe2d5569579b 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -175,9 +175,15 @@ private function getServiceDefaults(\DOMDocument $xml, $file) if (null === $defaultsNode = $xpath->query('//container:services/container:defaults')->item(0)) { return []; } + + $bindings = []; + foreach ($this->getArgumentsAsPhp($defaultsNode, 'bind', $file) as $argument => $value) { + $bindings[$argument] = new BoundArgument($value, true, BoundArgument::DEFAULTS_BINDING, $file); + } + $defaults = [ 'tags' => $this->getChildren($defaultsNode, 'tag'), - 'bind' => array_map(function ($v) { return new BoundArgument($v); }, $this->getArgumentsAsPhp($defaultsNode, 'bind', $file)), + 'bind' => $bindings, ]; foreach ($defaults['tags'] as $tag) { @@ -368,6 +374,11 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) } $bindings = $this->getArgumentsAsPhp($service, 'bind', $file); + $bindingType = $this->isLoadingInstanceof ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING; + foreach ($bindings as $argument => $value) { + $bindings[$argument] = new BoundArgument($value, true, $bindingType, $file); + } + if (isset($defaults['bind'])) { // deep clone, to avoid multiple process of the same instance in the passes $bindings = array_merge(unserialize(serialize($defaults['bind'])), $bindings); diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 198f00d64cb8e..703620c8a67e3 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -284,7 +284,9 @@ private function parseDefaults(array &$content, string $file): array throw new InvalidArgumentException(sprintf('Parameter "bind" in "_defaults" must be an array in %s. Check your YAML syntax.', $file)); } - $defaults['bind'] = array_map(function ($v) { return new BoundArgument($v); }, $this->resolveServices($defaults['bind'], $file)); + foreach ($this->resolveServices($defaults['bind'], $file) as $argument => $value) { + $defaults['bind'][$argument] = new BoundArgument($value, true, BoundArgument::DEFAULTS_BINDING, $file); + } } return $defaults; @@ -534,6 +536,12 @@ private function parseDefinition($id, $service, $file, array $defaults) } $bindings = array_merge($bindings, $this->resolveServices($service['bind'], $file)); + $bindingType = $this->isLoadingInstanceof ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING; + foreach ($bindings as $argument => $value) { + if (!$value instanceof BoundArgument) { + $bindings[$argument] = new BoundArgument($value, true, $bindingType, $file); + } + } } $definition->setBindings($bindings); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php index 7bbecf6207f46..97855e7bd913b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php @@ -50,7 +50,7 @@ public function testProcess() /** * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException - * @expectedExceptionMessage Unused binding "$quz" in service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy". + * @expectedExceptionMessage A binding is configured for an argument named "$quz" for service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy", but no corresponding argument has been found. It may be unused and should be removed, or it may have a typo. */ public function testUnusedBinding() { diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index c5a823cc7ee1e..a3f5012e3268f 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -139,8 +139,8 @@ public function process(ContainerBuilder $container) } elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) { $binding = $bindings[$bindingName]; - list($bindingValue, $bindingId) = $binding->getValues(); - $binding->setValues([$bindingValue, $bindingId, true]); + list($bindingValue, $bindingId, , $bindingType, $bindingFile) = $binding->getValues(); + $binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]); if (!$bindingValue instanceof Reference) { $args[$p->name] = new Reference('.value.'.$container->hash($bindingValue)); From dd93b707cc17722a04ccfe240d7a7837ee183209 Mon Sep 17 00:00:00 2001 From: Tomas <norkunas.tom@gmail.com> Date: Wed, 27 Mar 2019 07:02:36 +0200 Subject: [PATCH 436/495] Use name converter when normalizing constraint violation list --- .../Resources/config/serializer.xml | 2 + .../FrameworkExtensionTest.php | 13 +++++++ .../ConstraintViolationListNormalizer.php | 7 +++- .../ConstraintViolationListNormalizerTest.php | 39 +++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml index 0a06fd1edec39..a4f218ca37352 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml @@ -32,6 +32,8 @@ <!-- Normalizer --> <service id="serializer.normalizer.constraint_violation_list" class="Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer"> + <argument type="collection" /> + <argument type="service" id="serializer.name_converter.metadata_aware" /> <!-- Run before serializer.normalizer.object --> <tag name="serializer.normalizer" priority="-915" /> </service> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index ddd9d64286ff5..21e01a2107232 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -43,6 +43,7 @@ use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader; use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader; use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader; +use Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer; use Symfony\Component\Serializer\Normalizer\DataUriNormalizer; use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; @@ -1176,6 +1177,18 @@ public function testObjectNormalizerRegistered() $this->assertEquals(-1000, $tag[0]['priority']); } + public function testConstraintViolationListNormalizerRegistered() + { + $container = $this->createContainerFromFile('full'); + + $definition = $container->getDefinition('serializer.normalizer.constraint_violation_list'); + $tag = $definition->getTag('serializer.normalizer'); + + $this->assertEquals(ConstraintViolationListNormalizer::class, $definition->getClass()); + $this->assertEquals(-915, $tag[0]['priority']); + $this->assertEquals(new Reference('serializer.name_converter.metadata_aware'), $definition->getArgument(1)); + } + public function testSerializerCacheActivated() { $container = $this->createContainerFromFile('serializer_enabled'); diff --git a/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php index 051ceaf3a385e..649c095ff46a9 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ConstraintViolationListNormalizer.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Serializer\Normalizer; +use Symfony\Component\Serializer\NameConverter\NameConverterInterface; use Symfony\Component\Validator\ConstraintViolationListInterface; /** @@ -30,10 +31,12 @@ class ConstraintViolationListNormalizer implements NormalizerInterface, Cacheabl const TYPE = 'type'; private $defaultContext; + private $nameConverter; - public function __construct($defaultContext = []) + public function __construct($defaultContext = [], NameConverterInterface $nameConverter = null) { $this->defaultContext = $defaultContext; + $this->nameConverter = $nameConverter; } /** @@ -44,7 +47,7 @@ public function normalize($object, $format = null, array $context = []) $violations = []; $messages = []; foreach ($object as $violation) { - $propertyPath = $violation->getPropertyPath(); + $propertyPath = $this->nameConverter ? $this->nameConverter->normalize($violation->getPropertyPath(), null, $format, $context) : $violation->getPropertyPath(); $violationEntry = [ 'propertyPath' => $propertyPath, diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php index 86008f361aef0..24fc7cd2be896 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ConstraintViolationListNormalizerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Serializer\Tests\Normalizer; use PHPUnit\Framework\TestCase; +use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter; use Symfony\Component\Serializer\Normalizer\ConstraintViolationListNormalizer; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\Validator\ConstraintViolationList; @@ -67,4 +68,42 @@ public function testNormalize() $this->assertEquals($expected, $this->normalizer->normalize($list)); } + + public function testNormalizeWithNameConverter() + { + $normalizer = new ConstraintViolationListNormalizer([], new CamelCaseToSnakeCaseNameConverter()); + + $list = new ConstraintViolationList([ + new ConstraintViolation('too short', 'a', [], 'c', 'shortDescription', ''), + new ConstraintViolation('too long', 'b', [], '3', 'product.shortDescription', 'Lorem ipsum dolor sit amet'), + new ConstraintViolation('error', 'b', [], '3', '', ''), + ]); + + $expected = [ + 'type' => 'https://symfony.com/errors/validation', + 'title' => 'Validation Failed', + 'detail' => 'short_description: too short +product.short_description: too long +error', + 'violations' => [ + [ + 'propertyPath' => 'short_description', + 'title' => 'too short', + 'parameters' => [], + ], + [ + 'propertyPath' => 'product.short_description', + 'title' => 'too long', + 'parameters' => [], + ], + [ + 'propertyPath' => '', + 'title' => 'error', + 'parameters' => [], + ], + ], + ]; + + $this->assertEquals($expected, $normalizer->normalize($list)); + } } From 9a2fcc9392c3da4718ae2c4d4a5877a9962a70f8 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla <mp@webfactory.de> Date: Sun, 7 Apr 2019 09:25:36 +0000 Subject: [PATCH 437/495] [HttpKernel] Add a \"short\" trace header format, make header configurable --- src/Symfony/Component/HttpKernel/CHANGELOG.md | 1 + .../HttpKernel/HttpCache/HttpCache.php | 36 ++++++++++++++++-- .../Tests/HttpCache/HttpCacheTest.php | 38 +++++++++++++++++++ .../Tests/HttpCache/HttpCacheTestCase.php | 4 +- .../Component/HttpKernel/composer.json | 1 + 5 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 06193a00b3395..b1a5f5101b41d 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -24,6 +24,7 @@ CHANGELOG * renamed `GetResponseForExceptionEvent` to `ExceptionEvent` * renamed `PostResponseEvent` to `TerminateEvent` * added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance + * added `trace_header` and `trace_level` configuration options to `HttpCache` 4.2.0 ----- diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index 84b01659f99b1..051285aeba60e 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -40,7 +40,14 @@ class HttpCache implements HttpKernelInterface, TerminableInterface * * The available options are: * - * * debug: If true, the traces are added as a HTTP header to ease debugging + * * debug If true, exceptions are thrown when things go wrong. Otherwise, the cache + * will try to carry on and deliver a meaningful response. + * + * * trace_level May be one of 'none', 'short' and 'full'. For 'short', a concise trace of the + * master request will be added as an HTTP header. 'full' will add traces for all + * requests (including ESI subrequests). (default: 'full' if in debug; 'none' otherwise) + * + * * trace_header Header name to use for traces. (default: X-Symfony-Cache) * * * default_ttl The number of seconds that a cache entry should be considered * fresh when no explicit freshness information is provided in @@ -87,7 +94,13 @@ public function __construct(HttpKernelInterface $kernel, StoreInterface $store, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, + 'trace_level' => 'none', + 'trace_header' => 'X-Symfony-Cache', ], $options); + + if (!isset($options['trace_level']) && $this->options['debug']) { + $this->options['trace_level'] = 'full'; + } } /** @@ -110,6 +123,23 @@ public function getTraces() return $this->traces; } + private function addTraces(Response $response) + { + $traceString = null; + + if ('full' === $this->options['trace_level']) { + $traceString = $this->getLog(); + } + + if ('short' === $this->options['trace_level'] && $masterId = array_key_first($this->traces)) { + $traceString = implode('/', $this->traces[$masterId]); + } + + if (null !== $traceString) { + $response->headers->add([$this->options['trace_header'] => $traceString]); + } + } + /** * Returns a log message for the events of the last request processing. * @@ -194,8 +224,8 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ $this->restoreResponseBody($request, $response); - if (HttpKernelInterface::MASTER_REQUEST === $type && $this->options['debug']) { - $response->headers->set('X-Symfony-Cache', $this->getLog()); + if (HttpKernelInterface::MASTER_REQUEST === $type) { + $this->addTraces($response); } if (null !== $this->surrogate) { diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 7b3cac78c734b..d9f1e458f9f38 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -1508,6 +1508,44 @@ public function testUsesOriginalRequestForSurrogate() // Surrogate request $cache->handle($request, HttpKernelInterface::SUB_REQUEST); } + + public function testTraceHeaderNameCanBeChanged() + { + $this->cacheConfig['trace_header'] = 'X-My-Header'; + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertTrue($this->response->headers->has('X-My-Header')); + } + + public function testTraceLevelDefaultsToFullIfDebug() + { + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertTrue($this->response->headers->has('X-Symfony-Cache')); + $this->assertEquals('GET /: miss', $this->response->headers->get('X-Symfony-Cache')); + } + + public function testTraceLevelDefaultsToNoneIfNotDebug() + { + $this->cacheConfig['debug'] = false; + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertFalse($this->response->headers->has('X-Symfony-Cache')); + } + + public function testTraceLevelShort() + { + $this->cacheConfig['trace_level'] = 'short'; + + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertTrue($this->response->headers->has('X-Symfony-Cache')); + $this->assertEquals('miss', $this->response->headers->get('X-Symfony-Cache')); + } } class TestKernel implements HttpKernelInterface diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php index 1eb461744726e..fde389c28f3d3 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php @@ -122,7 +122,9 @@ public function request($method, $uri = '/', $server = [], $cookies = [], $esi = $this->store = new Store(sys_get_temp_dir().'/http_cache'); - $this->cacheConfig['debug'] = true; + if (!isset($this->cacheConfig['debug'])) { + $this->cacheConfig['debug'] = true; + } $this->esi = $esi ? new Esi() : null; $this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index ca818d16707ab..b8348b0fece8c 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -22,6 +22,7 @@ "symfony/http-foundation": "^4.1.1", "symfony/debug": "~3.4|~4.0", "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php73": "^1.9", "psr/log": "~1.0" }, "require-dev": { From b0cdf45464eec1ee93b9b097432eea0feaa18878 Mon Sep 17 00:00:00 2001 From: Joel Wurtz <jwurtz@jolicode.com> Date: Sun, 7 Apr 2019 11:42:45 +0200 Subject: [PATCH 438/495] Set object list extractor as expiremental, and use final for default implementation --- .../Serializer/Extractor/ObjectPropertyListExtractor.php | 4 +++- .../Extractor/ObjectPropertyListExtractorInterface.php | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php index 922094f8cb45a..2ea19d28faa20 100644 --- a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php +++ b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractor.php @@ -15,8 +15,10 @@ /** * @author David Maicher <mail@dmaicher.de> + * + * @experimental in 4.3 */ -class ObjectPropertyListExtractor implements ObjectPropertyListExtractorInterface +final class ObjectPropertyListExtractor implements ObjectPropertyListExtractorInterface { private $propertyListExtractor; private $objectClassResolver; diff --git a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php index 1dd9b8b99a7d3..fd60e1e5066f3 100644 --- a/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php +++ b/src/Symfony/Component/Serializer/Extractor/ObjectPropertyListExtractorInterface.php @@ -13,6 +13,8 @@ /** * @author David Maicher <mail@dmaicher.de> + * + * @experimental in 4.3 */ interface ObjectPropertyListExtractorInterface { From e5de7b3135ee334ce3833746e8df2679522b9a1f Mon Sep 17 00:00:00 2001 From: Peter Bowyer <peter@mapledesign.co.uk> Date: Sun, 7 Apr 2019 14:00:07 +0100 Subject: [PATCH 439/495] [Workflow] Update to `initial_marking` Also merge the two separate `Workflow` sections. --- UPGRADE-4.3.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 4cbf2216238ba..2c792ff47a5e6 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -155,7 +155,7 @@ TwigBridge Workflow -------- - * `initial_place` is deprecated in favour of `initial_places`. + * `initial_place` is deprecated in favour of `initial_marking`. Before: ```yaml @@ -170,12 +170,9 @@ Workflow framework: workflows: article: - initial_places: [draft] + initial_marking: [draft] ``` -Workflow --------- - * `MarkingStoreInterface::setMarking()` will have a third argument in Symfony 5.0. Before: From a234c8913e716f52665381de5e4bb259f997fd35 Mon Sep 17 00:00:00 2001 From: Jules Pietri <heah@heahprod.com> Date: Sun, 7 Apr 2019 12:04:56 +0200 Subject: [PATCH 440/495] [DoctrineBridge] Deprecated using IdReader when optimization is not possible --- UPGRADE-4.3.md | 6 ++ UPGRADE-5.0.md | 3 + src/Symfony/Bridge/Doctrine/CHANGELOG.md | 1 + .../Form/ChoiceList/DoctrineChoiceLoader.php | 13 +++- .../Doctrine/Form/Type/DoctrineType.php | 18 +++-- .../ChoiceList/DoctrineChoiceLoaderTest.php | 71 ++++++++----------- 6 files changed, 58 insertions(+), 54 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 4cbf2216238ba..f67720fae098d 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -38,6 +38,12 @@ DependencyInjection env(NAME): '1.5' ``` +Doctrine Bridge +--------------- + + * Passing an `IdReader` to the `DoctrineChoiceLoader` when the query cannot be optimized with single id field has been deprecated, pass `null` instead + * Not passing an `IdReader` to the `DoctrineChoiceLoader` when the query can be optimized with single id field has been deprecated + EventDispatcher --------------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index aa448846237f7..7e338df2f47f0 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -60,6 +60,9 @@ DoctrineBridge * Deprecated injecting `ClassMetadataFactory` in `DoctrineExtractor`, an instance of `EntityManagerInterface` should be injected instead + * Passing an `IdReader` to the `DoctrineChoiceLoader` when the query cannot be optimized with single id field will throw an exception, pass `null` instead + * Not passing an `IdReader` to the `DoctrineChoiceLoader` when the query can be optimized with single id field will throw an exception + DomCrawler ---------- diff --git a/src/Symfony/Bridge/Doctrine/CHANGELOG.md b/src/Symfony/Bridge/Doctrine/CHANGELOG.md index 27cabfa558fd9..3bcf9a77dfe56 100644 --- a/src/Symfony/Bridge/Doctrine/CHANGELOG.md +++ b/src/Symfony/Bridge/Doctrine/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * changed guessing of DECIMAL to set the `input` option of `NumberType` to string * deprecated not passing an `IdReader` to the `DoctrineChoiceLoader` when query can be optimized with a single id field + * deprecated passing an `IdReader` to the `DoctrineChoiceLoader` when entities have a composite id 4.2.0 ----- diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index fd891abb34b09..cd040d12a9b03 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -42,18 +42,25 @@ class DoctrineChoiceLoader implements ChoiceLoaderInterface * * @param ObjectManager $manager The object manager * @param string $class The class name of the loaded objects - * @param IdReader $idReader The reader for the object IDs + * @param IdReader|null $idReader The reader for the object IDs * @param EntityLoaderInterface|null $objectLoader The objects loader */ public function __construct(ObjectManager $manager, string $class, IdReader $idReader = null, EntityLoaderInterface $objectLoader = null) { $classMetadata = $manager->getClassMetadata($class); + if ($idReader && !$idReader->isSingleId()) { + @trigger_error(sprintf('Passing an instance of "%s" to "%s" with an entity class "%s" that has a composite id is deprecated since Symfony 4.3 and will throw an exception in 5.0.', IdReader::class, __CLASS__, $class), E_USER_DEPRECATED); + + // In Symfony 5.0 + // throw new \InvalidArgumentException(sprintf('The second argument `$idReader` of "%s" must be null when the query cannot be optimized because of composite id fields.', __METHOD__)); + } + if ((5 > \func_num_args() || false !== func_get_arg(4)) && null === $idReader) { $idReader = new IdReader($manager, $classMetadata); if ($idReader->isSingleId()) { - @trigger_error(sprintf('Not explicitly passing an instance of "%s" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0.', IdReader::class, $class), E_USER_DEPRECATED); + @trigger_error(sprintf('Not explicitly passing an instance of "%s" to "%s" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0.', IdReader::class, __CLASS__, $class), E_USER_DEPRECATED); } else { $idReader = null; } @@ -93,7 +100,7 @@ public function loadValuesForChoices(array $choices, $value = null) // Optimize performance for single-field identifiers. We already // know that the IDs are used as values - $optimize = null === $value || \is_array($value) && $value[0] === $this->idReader; + $optimize = $this->idReader && (null === $value || \is_array($value) && $value[0] === $this->idReader); // Attention: This optimization does not check choices for existence if ($optimize && !$this->choiceList && $this->idReader->isSingleId()) { diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 03bf6a0ba509d..88f9cf9101c7d 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -163,13 +163,10 @@ public function configureOptions(OptionsResolver $resolver) }; $choiceName = function (Options $options) { - /** @var IdReader $idReader */ - $idReader = $options['id_reader']; - // If the object has a single-column, numeric ID, use that ID as // field name. We can only use numeric IDs as names, as we cannot // guarantee that a non-numeric ID contains a valid form name - if ($idReader->isIntId()) { + if ($options['id_reader'] instanceof IdReader && $options['id_reader']->isIntId()) { return [__CLASS__, 'createChoiceName']; } @@ -181,12 +178,9 @@ public function configureOptions(OptionsResolver $resolver) // are indexed by an incrementing integer. // Use the ID/incrementing integer as choice value. $choiceValue = function (Options $options) { - /** @var IdReader $idReader */ - $idReader = $options['id_reader']; - // If the entity has a single-column ID, use that ID as value - if ($idReader->isSingleId()) { - return [$idReader, 'getIdValue']; + if ($options['id_reader'] instanceof IdReader && $options['id_reader']->isSingleId()) { + return [$options['id_reader'], 'getIdValue']; } // Otherwise, an incrementing integer is used as value automatically @@ -240,7 +234,11 @@ public function configureOptions(OptionsResolver $resolver) $this->idReaders[$hash] = new IdReader($options['em'], $classMetadata); } - return $this->idReaders[$hash]; + if ($this->idReaders[$hash]->isSingleId()) { + return $this->idReaders[$hash]; + } + + return null; }; $resolver->setDefaults([ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php index 2fbb07d7f3406..5a5fba5afaf57 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php @@ -81,6 +81,11 @@ protected function setUp() $this->idReader = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader') ->disableOriginalConstructor() ->getMock(); + $this->idReader->expects($this->any()) + ->method('isSingleId') + ->willReturn(true) + ; + $this->objectLoader = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface')->getMock(); $this->obj1 = (object) ['name' => 'A']; $this->obj2 = (object) ['name' => 'B']; @@ -151,7 +156,7 @@ public function testLoadValuesForChoices() $loader = new DoctrineChoiceLoader( $this->om, $this->class, - $this->idReader + null ); $choices = [$this->obj1, $this->obj2, $this->obj3]; @@ -189,10 +194,6 @@ public function testLoadValuesForChoicesDoesNotLoadIfSingleIntId() $this->idReader ); - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - $this->repository->expects($this->never()) ->method('findAll'); @@ -215,10 +216,6 @@ public function testLoadValuesForChoicesLoadsIfSingleIntIdAndValueGiven() $choices = [$this->obj1, $this->obj2, $this->obj3]; $value = function (\stdClass $object) { return $object->name; }; - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - $this->repository->expects($this->once()) ->method('findAll') ->willReturn($choices); @@ -239,10 +236,6 @@ public function testLoadValuesForChoicesDoesNotLoadIfValueIsIdReader() $value = [$this->idReader, 'getIdValue']; - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - $this->repository->expects($this->never()) ->method('findAll'); @@ -303,10 +296,6 @@ public function testLoadChoicesForValuesLoadsOnlyChoicesIfSingleIntId() $choices = [$this->obj2, $this->obj3]; - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - $this->idReader->expects($this->any()) ->method('getIdField') ->willReturn('idField'); @@ -343,10 +332,6 @@ public function testLoadChoicesForValuesLoadsAllIfSingleIntIdAndValueGiven() $choices = [$this->obj1, $this->obj2, $this->obj3]; $value = function (\stdClass $object) { return $object->name; }; - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - $this->repository->expects($this->once()) ->method('findAll') ->willReturn($choices); @@ -369,10 +354,6 @@ public function testLoadChoicesForValuesLoadsOnlyChoicesIfValueIsIdReader() $choices = [$this->obj2, $this->obj3]; $value = [$this->idReader, 'getIdValue']; - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - $this->idReader->expects($this->any()) ->method('getIdField') ->willReturn('idField'); @@ -398,7 +379,7 @@ public function testLoadChoicesForValuesLoadsOnlyChoicesIfValueIsIdReader() /** * @group legacy * - * @expectedDeprecation Not explicitly passing an instance of "Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0. + * @expectedDeprecation Not explicitly passing an instance of "Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader" to "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader" when it can optimize single id entity "%s" has been deprecated in 4.3 and will not apply any optimization in 5.0. */ public function testLoaderWithoutIdReaderCanBeOptimized() { @@ -445,14 +426,6 @@ public function testLoaderWithoutIdReaderCanBeOptimized() $choices = [$obj1, $obj2]; - $this->idReader->expects($this->any()) - ->method('isSingleId') - ->willReturn(true); - - $this->idReader->expects($this->any()) - ->method('getIdField') - ->willReturn('idField'); - $this->repository->expects($this->never()) ->method('findAll'); @@ -461,13 +434,29 @@ public function testLoaderWithoutIdReaderCanBeOptimized() ->with('idField', ['1']) ->willReturn($choices); - $this->idReader->expects($this->any()) - ->method('getIdValue') - ->willReturnMap([ - [$obj1, '1'], - [$obj2, '2'], - ]); - $this->assertSame([$obj1], $loader->loadChoicesForValues(['1'])); } + + /** + * @group legacy + * + * @deprecationMessage Passing an instance of "Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader" to "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader" with an entity class "stdClass" that has a composite id is deprecated since Symfony 4.3 and will throw an exception in 5.0. + */ + public function testPassingIdReaderWithoutSingleIdEntity() + { + $idReader = $this->createMock(IdReader::class); + $idReader->expects($this->once()) + ->method('isSingleId') + ->willReturn(false) + ; + + $loader = new DoctrineChoiceLoader( + $this->om, + $this->class, + $idReader, + $this->objectLoader + ); + + $this->assertInstanceOf(DoctrineChoiceLoader::class, $loader); + } } From d412e77a9cf29ae23606b8570a66e81164577faa Mon Sep 17 00:00:00 2001 From: Thomas Calvet <calvet.thomas@gmail.com> Date: Sun, 7 Apr 2019 10:37:59 +0200 Subject: [PATCH 441/495] Prepare for the new serialization mechanism --- UPGRADE-4.3.md | 10 +- UPGRADE-5.0.md | 10 +- .../Form/Tests/Fixtures/CustomArrayObject.php | 14 ++- .../Fixtures/NonTraversableArrayObject.php | 14 ++- .../Tests/Fixtures/TraversableArrayObject.php | 14 ++- .../Component/Routing/CompiledRoute.php | 24 ++-- src/Symfony/Component/Routing/Route.php | 25 ++-- src/Symfony/Component/Security/CHANGELOG.md | 2 +- .../Authentication/Token/AbstractToken.php | 74 ++++++------ .../Authentication/Token/AnonymousToken.php | 8 +- .../Token/PreAuthenticatedToken.php | 8 +- .../Authentication/Token/RememberMeToken.php | 8 +- .../Authentication/Token/SwitchUserToken.php | 8 +- .../Token/UsernamePasswordToken.php | 8 +- .../Core/Exception/AccountStatusException.php | 8 +- .../Exception/AuthenticationException.php | 108 +++++++++--------- ...stomUserMessageAuthenticationException.php | 8 +- .../Exception/UsernameNotFoundException.php | 8 +- .../AuthenticationTrustResolverTest.php | 8 ++ .../Token/AbstractTokenTest.php | 8 +- ...UserMessageAuthenticationExceptionTest.php | 8 +- .../Token/PostAuthenticationGuardToken.php | 8 +- .../Tests/Fixtures/CustomArrayObject.php | 14 ++- 23 files changed, 238 insertions(+), 167 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 020f3a40181cb..2ca3698ac978c 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -115,7 +115,7 @@ Security * The `Firewall::handleRequest()` method is deprecated, use `Firewall::callListeners()` instead. * The `AbstractToken::serialize()`, `AbstractToken::unserialize()`, `AuthenticationException::serialize()` and `AuthenticationException::unserialize()` - methods are now final, use `getState()` and `setState()` instead. + methods are now final, use `__serialize()` and `__unserialize()` instead. Before: ```php @@ -133,15 +133,15 @@ Security After: ```php - protected function getState(): array + public function __serialize(): array { - return [$this->myLocalVar, parent::getState()]; + return [$this->myLocalVar, parent::__serialize()]; } - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->myLocalVar, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } ``` diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 68001974bb92c..c82a3c7abc0e8 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -293,7 +293,7 @@ Security * The `Firewall::handleRequest()` method has been removed, use `Firewall::callListeners()` instead. * `\Serializable` interface has been removed from `AbstractToken` and `AuthenticationException`, thus `serialize()` and `unserialize()` aren't available. - Use `getState()` and `setState()` instead. + Use `__serialize()` and `__unserialize()` instead. Before: ```php @@ -311,15 +311,15 @@ Security After: ```php - protected function getState(): array + public function __serialize(): array { - return [$this->myLocalVar, parent::getState()]; + return [$this->myLocalVar, parent::__serialize()]; } - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->myLocalVar, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } ``` diff --git a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php index 006724014a2a1..47fa14090e26d 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php @@ -58,13 +58,23 @@ public function count() return \count($this->array); } + public function __serialize(): array + { + return $this->array; + } + public function serialize() { - return serialize($this->array); + return serialize($this->__serialize()); + } + + public function __unserialize(array $data): void + { + $this->array = $data; } public function unserialize($serialized) { - $this->array = (array) unserialize((string) $serialized); + $this->__unserialize((array) unserialize((string) $serialized)); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php index 4b18e725ae9e4..cb659f907c15b 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php @@ -53,13 +53,23 @@ public function count() return \count($this->array); } + public function __serialize(): array + { + return $this->array; + } + public function serialize() { - return serialize($this->array); + return serialize($this->__serialize()); + } + + public function __unserialize(array $data): void + { + $this->array = $data; } public function unserialize($serialized) { - $this->array = (array) unserialize((string) $serialized); + $this->__unserialize((array) unserialize((string) $serialized)); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php index b075286f4a70e..ba5ec36e76bd2 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php @@ -58,13 +58,23 @@ public function count() return \count($this->array); } + public function __serialize(): array + { + return $this->array; + } + public function serialize() { - return serialize($this->array); + return serialize($this->__serialize()); + } + + public function __unserialize(array $data): void + { + $this->array = $data; } public function unserialize($serialized) { - $this->array = (array) unserialize((string) $serialized); + $this->__unserialize((array) unserialize((string) $serialized)); } } diff --git a/src/Symfony/Component/Routing/CompiledRoute.php b/src/Symfony/Component/Routing/CompiledRoute.php index b8919c56cc444..06dc87d74015c 100644 --- a/src/Symfony/Component/Routing/CompiledRoute.php +++ b/src/Symfony/Component/Routing/CompiledRoute.php @@ -49,12 +49,9 @@ public function __construct(string $staticPrefix, string $regex, array $tokens, $this->variables = $variables; } - /** - * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore - */ - public function serialize() + public function __serialize(): array { - return serialize([ + return [ 'vars' => $this->variables, 'path_prefix' => $this->staticPrefix, 'path_regex' => $this->regex, @@ -63,16 +60,19 @@ public function serialize() 'host_regex' => $this->hostRegex, 'host_tokens' => $this->hostTokens, 'host_vars' => $this->hostVariables, - ]); + ]; } /** * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore */ - public function unserialize($serialized) + public function serialize() { - $data = unserialize($serialized, ['allowed_classes' => false]); + return serialize($this->__serialize()); + } + public function __unserialize(array $data): void + { $this->variables = $data['vars']; $this->staticPrefix = $data['path_prefix']; $this->regex = $data['path_regex']; @@ -83,6 +83,14 @@ public function unserialize($serialized) $this->hostVariables = $data['host_vars']; } + /** + * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore + */ + public function unserialize($serialized) + { + $this->__unserialize(unserialize($serialized, ['allowed_classes' => false])); + } + /** * Returns the static prefix. * diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 8028d3801228d..178c5d3ac213b 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -62,12 +62,9 @@ public function __construct(string $path, array $defaults = [], array $requireme $this->setCondition($condition); } - /** - * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore - */ - public function serialize() + public function __serialize(): array { - return serialize([ + return [ 'path' => $this->path, 'host' => $this->host, 'defaults' => $this->defaults, @@ -77,15 +74,19 @@ public function serialize() 'methods' => $this->methods, 'condition' => $this->condition, 'compiled' => $this->compiled, - ]); + ]; } /** * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore */ - public function unserialize($serialized) + public function serialize() + { + return serialize($this->__serialize()); + } + + public function __unserialize(array $data): void { - $data = unserialize($serialized); $this->path = $data['path']; $this->host = $data['host']; $this->defaults = $data['defaults']; @@ -102,6 +103,14 @@ public function unserialize($serialized) } } + /** + * @internal since Symfony 4.3, will be removed in Symfony 5 as the class won't implement Serializable anymore + */ + public function unserialize($serialized) + { + $this->__unserialize(unserialize($serialized)); + } + /** * Returns the pattern for the path. * diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index fc6b60a3a1309..525972bdf4166 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -11,7 +11,7 @@ CHANGELOG * The `getRoles()` method of the `TokenInterface` is deprecated. Tokens must implement the `getRoleNames()` method instead and return roles as strings. * Made the `serialize()` and `unserialize()` methods of `AbstractToken` and - `AuthenticationException` final, use `getState()`/`setState()` instead + `AuthenticationException` final, use `__serialize()`/`__unserialize()` instead * `AuthenticationException` doesn't implement `Serializable` anymore * Deprecated the `ListenerInterface`, turn your listeners into callables instead * Deprecated `Firewall::handleRequest()`, use `Firewall::callListeners()` instead diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index b409e4b5635fd..f8f05a1ed80ec 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -142,16 +142,36 @@ public function eraseCredentials() } } + /** + * Returns all the necessary state of the object for serialization purposes. + * + * There is no need to serialize any entry, they should be returned as-is. + * If you extend this method, keep in mind you MUST guarantee parent data is present in the state. + * Here is an example of how to extend this method: + * <code> + * public function __serialize(): array + * { + * return [$this->childAttribute, parent::__serialize()]; + * } + * </code> + * + * @see __unserialize() + */ + public function __serialize(): array + { + return [$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames]; + } + /** * {@inheritdoc} * - * @final since Symfony 4.3, use getState() instead + * @final since Symfony 4.3, use __serialize() instead * - * @internal since Symfony 4.3, use getState() instead + * @internal since Symfony 4.3, use __serialize() instead */ public function serialize() { - $serialized = $this->getState(); + $serialized = $this->__serialize(); if (null === $isCalledFromOverridingMethod = \func_num_args() ? \func_get_arg(0) : null) { $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); @@ -162,56 +182,36 @@ public function serialize() } /** - * {@inheritdoc} - * - * @final since Symfony 4.3, use setState() instead - * - * @internal since Symfony 4.3, use setState() instead - */ - public function unserialize($serialized) - { - $this->setState(\is_array($serialized) ? $serialized : unserialize($serialized)); - } - - /** - * Returns all the necessary state of the object for serialization purposes. + * Restores the object state from an array given by __serialize(). * - * There is no need to serialize any entry, they should be returned as-is. - * If you extend this method, keep in mind you MUST guarantee parent data is present in the state. + * There is no need to unserialize any entry in $data, they are already ready-to-use. + * If you extend this method, keep in mind you MUST pass the parent data to its respective class. * Here is an example of how to extend this method: * <code> - * protected function getState(): array + * public function __unserialize(array $data): void * { - * return [$this->childAttribute, parent::getState()]; + * [$this->childAttribute, $parentData] = $data; + * parent::__unserialize($parentData); * } * </code> * - * @see setState() + * @see __serialize() */ - protected function getState(): array + public function __unserialize(array $data): void { - return [$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames]; + [$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames] = $data; } /** - * Restores the object state from an array given by getState(). + * {@inheritdoc} * - * There is no need to unserialize any entry in $data, they are already ready-to-use. - * If you extend this method, keep in mind you MUST pass the parent data to its respective class. - * Here is an example of how to extend this method: - * <code> - * protected function setState(array $data) - * { - * [$this->childAttribute, $parentData] = $data; - * parent::setState($parentData); - * } - * </code> + * @final since Symfony 4.3, use __unserialize() instead * - * @see getState() + * @internal since Symfony 4.3, use __unserialize() instead */ - protected function setState(array $data) + public function unserialize($serialized) { - [$this->user, $this->authenticated, $this->roles, $this->attributes, $this->roleNames] = $data; + $this->__unserialize(\is_array($serialized) ? $serialized : unserialize($serialized)); } /** diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php index c233c2bd16dc3..b94e8cbb2b953 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AnonymousToken.php @@ -55,17 +55,17 @@ public function getSecret() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->secret, parent::getState()]; + return [$this->secret, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->secret, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php index eb407e50c9c66..3532a8adbac19 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/PreAuthenticatedToken.php @@ -75,17 +75,17 @@ public function eraseCredentials() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->credentials, $this->providerKey, parent::getState()]; + return [$this->credentials, $this->providerKey, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->credentials, $this->providerKey, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php index 40daa68923c05..766201ecf14e0 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/RememberMeToken.php @@ -92,17 +92,17 @@ public function getCredentials() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->secret, $this->providerKey, parent::getState()]; + return [$this->secret, $this->providerKey, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->secret, $this->providerKey, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php index 8e73876306aa9..ec98f04cfe8b2 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/SwitchUserToken.php @@ -44,17 +44,17 @@ public function getOriginalToken(): TokenInterface /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->originalToken, parent::getState()]; + return [$this->originalToken, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->originalToken, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php index 79e5780f09ce6..4c4773578373e 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/UsernamePasswordToken.php @@ -87,17 +87,17 @@ public function eraseCredentials() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->credentials, $this->providerKey, parent::getState()]; + return [$this->credentials, $this->providerKey, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->credentials, $this->providerKey, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php index 4d707c07d1871..f3fa661c31f4e 100644 --- a/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php +++ b/src/Symfony/Component/Security/Core/Exception/AccountStatusException.php @@ -42,17 +42,17 @@ public function setUser(UserInterface $user) /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->user, parent::getState()]; + return [$this->user, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->user, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php index 82f6db65d6099..0caa0563fd83b 100644 --- a/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/AuthenticationException.php @@ -38,16 +38,36 @@ public function setToken(TokenInterface $token) $this->token = $token; } + /** + * Returns all the necessary state of the object for serialization purposes. + * + * There is no need to serialize any entry, they should be returned as-is. + * If you extend this method, keep in mind you MUST guarantee parent data is present in the state. + * Here is an example of how to extend this method: + * <code> + * public function __serialize(): array + * { + * return [$this->childAttribute, parent::__serialize()]; + * } + * </code> + * + * @see __unserialize() + */ + public function __serialize(): array + { + return [$this->token, $this->code, $this->message, $this->file, $this->line]; + } + /** * {@inheritdoc} * - * @final since Symfony 4.3, use getState() instead + * @final since Symfony 4.3, use __serialize() instead * - * @internal since Symfony 4.3, use getState() instead + * @internal since Symfony 4.3, use __serialize() instead */ public function serialize() { - $serialized = $this->getState(); + $serialized = $this->__serialize(); if (null === $isCalledFromOverridingMethod = \func_num_args() ? \func_get_arg(0) : null) { $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); @@ -57,83 +77,69 @@ public function serialize() return $isCalledFromOverridingMethod ? $serialized : serialize($serialized); } + /** + * Restores the object state from an array given by __serialize(). + * + * There is no need to unserialize any entry in $data, they are already ready-to-use. + * If you extend this method, keep in mind you MUST pass the parent data to its respective class. + * Here is an example of how to extend this method: + * <code> + * public function __unserialize(array $data): void + * { + * [$this->childAttribute, $parentData] = $data; + * parent::__unserialize($parentData); + * } + * </code> + * + * @see __serialize() + */ + public function __unserialize(array $data): void + { + [$this->token, $this->code, $this->message, $this->file, $this->line] = $data; + } + /** * {@inheritdoc} * - * @final since Symfony 4.3, use setState() instead + * @final since Symfony 4.3, use __unserialize() instead * - * @internal since Symfony 4.3, use setState() instead + * @internal since Symfony 4.3, use __unserialize() instead */ public function unserialize($serialized) { - $this->setState(\is_array($serialized) ? $serialized : unserialize($serialized)); + $this->__unserialize(\is_array($serialized) ? $serialized : unserialize($serialized)); } + /** + * @internal + */ public function __sleep() { if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { - @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, implement the getState() and setState() methods instead.', $c), E_USER_DEPRECATED); + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, implement the __serialize() and __unserialize() methods instead.', $c), E_USER_DEPRECATED); $this->serialized = $this->serialize(); } else { - $this->serialized = $this->getState(); + $this->serialized = $this->__serialize(); } return ['serialized']; } + /** + * @internal + */ public function __wakeup() { if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) { - @trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, implement the getState() and setState() methods instead.', $c), E_USER_DEPRECATED); + @trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, implement the __serialize() and __unserialize() methods instead.', $c), E_USER_DEPRECATED); $this->unserialize($this->serialized); } else { - $this->setState($this->serialized); + $this->__unserialize($this->serialized); } unset($this->serialized); } - /** - * Returns all the necessary state of the object for serialization purposes. - * - * There is no need to serialize any entry, they should be returned as-is. - * If you extend this method, keep in mind you MUST guarantee parent data is present in the state. - * Here is an example of how to extend this method: - * <code> - * protected function getState(): array - * { - * return [$this->childAttribute, parent::getState()]; - * } - * </code> - * - * @see setState() - */ - protected function getState(): array - { - return [$this->token, $this->code, $this->message, $this->file, $this->line]; - } - - /** - * Restores the object state from an array given by getState(). - * - * There is no need to unserialize any entry in $data, they are already ready-to-use. - * If you extend this method, keep in mind you MUST pass the parent data to its respective class. - * Here is an example of how to extend this method: - * <code> - * protected function setState(array $data) - * { - * [$this->childAttribute, $parentData] = $data; - * parent::setState($parentData); - * } - * </code> - * - * @see getState() - */ - protected function setState(array $data) - { - [$this->token, $this->code, $this->message, $this->file, $this->line] = $data; - } - /** * Message key to be used by the translation component. * diff --git a/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php b/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php index bd1b18eb328f0..b64d267b4868c 100644 --- a/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php +++ b/src/Symfony/Component/Security/Core/Exception/CustomUserMessageAuthenticationException.php @@ -58,17 +58,17 @@ public function getMessageData() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [parent::getState(), $this->messageKey, $this->messageData]; + return [parent::__serialize(), $this->messageKey, $this->messageData]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$parentData, $this->messageKey, $this->messageData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php index 155f80e357bcd..31dd486eec12d 100644 --- a/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UsernameNotFoundException.php @@ -60,17 +60,17 @@ public function getMessageData() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->username, parent::getState()]; + return [$this->username, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->username, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationTrustResolverTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationTrustResolverTest.php index f55f161476f58..940dcaffaa958 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationTrustResolverTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/AuthenticationTrustResolverTest.php @@ -148,10 +148,18 @@ protected function getResolver() class FakeCustomToken implements TokenInterface { + public function __serialize(): array + { + } + public function serialize() { } + public function __unserialize(array $data): void + { + } + public function unserialize($serialized) { } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 188eeb5ab7def..fde5c139a5a69 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -278,15 +278,15 @@ public function __construct(array $roles = [], UserInterface $user = null) } } - protected function getState(): array + public function __serialize(): array { - return [$this->credentials, parent::getState()]; + return [$this->credentials, parent::__serialize()]; } - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->credentials, $parentState] = $data; - parent::setState($parentState); + parent::__unserialize($parentState); } public function getCredentials() diff --git a/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php b/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php index 58eb04efbdce9..9726707506cbb 100644 --- a/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Exception/CustomUserMessageAuthenticationExceptionTest.php @@ -17,16 +17,16 @@ class ChildCustomUserMessageAuthenticationException extends CustomUserMessageAuthenticationException { - protected function getState(): array + public function __serialize(): array { - return [$this->childMember, parent::getState()]; + return [$this->childMember, parent::__serialize()]; } - public function setState(array $data) + public function __unserialize(array $data): void { [$this->childMember, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php b/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php index bde47244a0014..245ce241074e1 100644 --- a/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php +++ b/src/Symfony/Component/Security/Guard/Token/PostAuthenticationGuardToken.php @@ -73,17 +73,17 @@ public function getProviderKey() /** * {@inheritdoc} */ - protected function getState(): array + public function __serialize(): array { - return [$this->providerKey, parent::getState()]; + return [$this->providerKey, parent::__serialize()]; } /** * {@inheritdoc} */ - protected function setState(array $data) + public function __unserialize(array $data): void { [$this->providerKey, $parentData] = $data; - parent::setState($parentData); + parent::__unserialize($parentData); } } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php index 1edf1de0811db..9b5303c167c0b 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php @@ -58,13 +58,23 @@ public function count() return \count($this->array); } + public function __serialize(): array + { + return $this->array; + } + public function serialize() { - return serialize($this->array); + return serialize($this->__serialize()); + } + + public function __unserialize(array $data): void + { + $this->array = $data; } public function unserialize($serialized) { - $this->array = (array) unserialize((string) $serialized); + $this->__unserialize((array) unserialize((string) $serialized)); } } From 0c82173b241723d6183b57a7ab0b369209128007 Mon Sep 17 00:00:00 2001 From: Robin Chalas <robin.chalas@elao.com> Date: Mon, 17 Dec 2018 15:40:40 +0100 Subject: [PATCH 442/495] [Security] Add Argon2idPasswordEncoder --- UPGRADE-4.3.md | 11 ++- UPGRADE-5.0.md | 5 ++ .../Bundle/SecurityBundle/CHANGELOG.md | 3 + .../DependencyInjection/SecurityExtension.php | 19 +++++ .../CompleteConfigurationTest.php | 56 +++++++++++- .../Fixtures/php/argon2id_encoder.php | 14 +++ .../Fixtures/xml/argon2id_encoder.xml | 16 ++++ .../Fixtures/yml/argon2id_encoder.yml | 10 +++ .../UserPasswordEncoderCommandTest.php | 57 ++++++++++++- .../app/PasswordEncode/argon2id.yml | 7 ++ src/Symfony/Component/Security/CHANGELOG.md | 3 + .../Security/Core/Encoder/Argon2Trait.php | 52 ++++++++++++ .../Core/Encoder/Argon2iPasswordEncoder.php | 66 +++++--------- .../Core/Encoder/Argon2idPasswordEncoder.php | 85 +++++++++++++++++++ .../Security/Core/Encoder/EncoderFactory.php | 9 ++ .../Encoder/Argon2iPasswordEncoderTest.php | 2 +- .../Encoder/Argon2idPasswordEncoderTest.php | 65 ++++++++++++++ 17 files changed, 430 insertions(+), 50 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml create mode 100644 src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php create mode 100644 src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php create mode 100644 src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 4cbf2216238ba..9967dda85425e 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -145,8 +145,17 @@ Security } ``` + * Using `Argon2iPasswordEncoder` while only the `argon2id` algorithm is supported + is deprecated, use `Argon2idPasswordEncoder` instead + +SecurityBundle +-------------- + + * Configuring encoders using `argon2i` as algorithm while only `argon2id` is + supported is deprecated, use `argon2id` instead + TwigBridge -========== +---------- * deprecated the `$requestStack` and `$requestContext` arguments of the `HttpFoundationExtension`, pass a `Symfony\Component\HttpFoundation\UrlHelper` diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index aa448846237f7..50eb4861530fd 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -323,6 +323,9 @@ Security } ``` + * Using `Argon2iPasswordEncoder` while only the `argon2id` algorithm is supported + now throws a \LogicException`, use `Argon2idPasswordEncoder` instead + SecurityBundle -------------- @@ -342,6 +345,8 @@ SecurityBundle changed to underscores. Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore). After: `my-cookie` deletes the `my-cookie` cookie (with a dash). + * Configuring encoders using `argon2i` as algorithm while only `argon2id` is supported + now throws a `\LogicException`, use `argon2id` instead Serializer ---------- diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 84219a99f08d1..fd0edcb7dd8e2 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -8,6 +8,9 @@ CHANGELOG option is deprecated and will be disabled in Symfony 5.0. This affects to cookies with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie` name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore). + * Deprecated configuring encoders using `argon2i` as algorithm while only `argon2id` is supported, + use `argon2id` instead + 4.2.0 ----- diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 4d74daa4d48be..b8b3358c020e9 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -29,6 +29,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Controller\UserValueResolver; @@ -570,6 +571,8 @@ private function createEncoder($config, ContainerBuilder $container) } throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.'); + } elseif (\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + @trigger_error('Configuring an encoder based on the "argon2i" algorithm while only "argon2id" is supported is deprecated since Symfony 4.3, use "argon2id" instead.', E_USER_DEPRECATED); } return [ @@ -582,6 +585,22 @@ private function createEncoder($config, ContainerBuilder $container) ]; } + // Argon2id encoder + if ('argon2id' === $config['algorithm']) { + if (!Argon2idPasswordEncoder::isSupported()) { + throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.'); + } + + return [ + 'class' => Argon2idPasswordEncoder::class, + 'arguments' => [ + $config['memory_cost'], + $config['time_cost'], + $config['threads'], + ], + ]; + } + // run-time configured encoder return $config; } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index f9102edfb07bf..5c95500dc3dd3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; +use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; abstract class CompleteConfigurationTest extends TestCase @@ -313,7 +314,7 @@ public function testEncoders() public function testEncodersWithLibsodium() { - if (!Argon2iPasswordEncoder::isSupported()) { + if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { $this->markTestSkipped('Argon2i algorithm is not supported.'); } @@ -364,6 +365,59 @@ public function testEncodersWithLibsodium() ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } + public function testEncodersWithArgon2id() + { + if (!Argon2idPasswordEncoder::isSupported()) { + $this->markTestSkipped('Argon2i algorithm is not supported.'); + } + + $container = $this->getContainer('argon2id_encoder'); + + $this->assertEquals([[ + 'JMS\FooBundle\Entity\User1' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', + 'arguments' => [false], + ], + 'JMS\FooBundle\Entity\User2' => [ + 'algorithm' => 'sha1', + 'encode_as_base64' => false, + 'iterations' => 5, + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'cost' => 13, + 'memory_cost' => null, + 'time_cost' => null, + 'threads' => null, + ], + 'JMS\FooBundle\Entity\User3' => [ + 'algorithm' => 'md5', + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'encode_as_base64' => true, + 'iterations' => 5000, + 'cost' => 13, + 'memory_cost' => null, + 'time_cost' => null, + 'threads' => null, + ], + 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), + 'JMS\FooBundle\Entity\User5' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', + 'arguments' => ['sha1', false, 5, 30], + ], + 'JMS\FooBundle\Entity\User6' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', + 'arguments' => [15], + ], + 'JMS\FooBundle\Entity\User7' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder', + 'arguments' => [256, 1, 2], + ], + ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); + } + public function testRememberMeThrowExceptionsDefault() { $container = $this->getContainer('container1'); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php new file mode 100644 index 0000000000000..df63deb92eb24 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php @@ -0,0 +1,14 @@ +<?php + +$this->load('container1.php', $container); + +$container->loadFromExtension('security', [ + 'encoders' => [ + 'JMS\FooBundle\Entity\User7' => [ + 'algorithm' => 'argon2id', + 'memory_cost' => 256, + 'time_cost' => 1, + 'threads' => 2, + ], + ], +]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml new file mode 100644 index 0000000000000..8bb8fa91c9d51 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:sec="http://symfony.com/schema/dic/security" + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> + + <imports> + <import resource="container1.xml"/> + </imports> + + <sec:config> + <sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="argon2id" memory_cost="256" time_cost="1" threads="2" /> + </sec:config> + +</container> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml new file mode 100644 index 0000000000000..f13de5ff63874 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml @@ -0,0 +1,10 @@ +imports: + - { resource: container1.yml } + +security: + encoders: + JMS\FooBundle\Entity\User7: + algorithm: argon2id + memory_cost: 256 + time_cost: 1 + threads: 2 diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index faec77550b2b2..80d3348124125 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -15,6 +15,7 @@ use Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand; use Symfony\Component\Console\Application as ConsoleApplication; use Symfony\Component\Console\Tester\CommandTester; +use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; @@ -72,7 +73,7 @@ public function testEncodePasswordBcrypt() public function testEncodePasswordArgon2i() { - if (!Argon2iPasswordEncoder::isSupported()) { + if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { $this->markTestSkipped('Argon2i algorithm not available.'); } $this->setupArgon2i(); @@ -85,6 +86,27 @@ public function testEncodePasswordArgon2i() $output = $this->passwordEncoderCommandTester->getDisplay(); $this->assertContains('Password encoding succeeded', $output); + $encoder = new Argon2iPasswordEncoder(); + preg_match('# Encoded password\s+(\$argon2i?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); + $hash = $matches[1]; + $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); + } + + public function testEncodePasswordArgon2id() + { + if (!Argon2idPasswordEncoder::isSupported()) { + $this->markTestSkipped('Argon2i algorithm not available.'); + } + $this->setupArgon2id(); + $this->passwordEncoderCommandTester->execute([ + 'command' => 'security:encode-password', + 'password' => 'password', + 'user-class' => 'Custom\Class\Argon2id\User', + ], ['interactive' => false]); + + $output = $this->passwordEncoderCommandTester->getDisplay(); + $this->assertContains('Password encoding succeeded', $output); + $encoder = new Argon2iPasswordEncoder(); preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); $hash = $matches[1]; @@ -153,8 +175,8 @@ public function testEncodePasswordBcryptOutput() public function testEncodePasswordArgon2iOutput() { - if (!Argon2iPasswordEncoder::isSupported()) { - $this->markTestSkipped('Argon2i algorithm not available.'); + if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + $this->markTestSkipped('Argon2id algorithm not available.'); } $this->setupArgon2i(); @@ -167,6 +189,22 @@ public function testEncodePasswordArgon2iOutput() $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); } + public function testEncodePasswordArgon2idOutput() + { + if (!Argon2idPasswordEncoder::isSupported()) { + $this->markTestSkipped('Argon2id algorithm not available.'); + } + + $this->setupArgon2id(); + $this->passwordEncoderCommandTester->execute([ + 'command' => 'security:encode-password', + 'password' => 'p@ssw0rd', + 'user-class' => 'Custom\Class\Argon2id\User', + ], ['interactive' => false]); + + $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); + } + public function testEncodePasswordNoConfigForGivenUserClass() { if (method_exists($this, 'expectException')) { @@ -259,4 +297,17 @@ private function setupArgon2i() $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); } + + private function setupArgon2id() + { + putenv('COLUMNS='.(119 + \strlen(PHP_EOL))); + $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2id.yml']); + $kernel->boot(); + + $application = new Application($kernel); + + $passwordEncoderCommand = $application->get('security:encode-password'); + + $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml new file mode 100644 index 0000000000000..481262acb7e6c --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml @@ -0,0 +1,7 @@ +imports: + - { resource: config.yml } + +security: + encoders: + Custom\Class\Argon2id\User: + algorithm: argon2id diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index fc6b60a3a1309..c8063c270d3fc 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -19,6 +19,9 @@ CHANGELOG * Dispatch `AuthenticationFailureEvent` on `security.authentication.failure` * Dispatch `InteractiveLoginEvent` on `security.interactive_login` * Dispatch `SwitchUserEvent` on `security.switch_user` + * Added `Argon2idPasswordEncoder` + * Deprecated using `Argon2iPasswordEncoder` while only the `argon2id` algorithm + is supported, use `Argon2idPasswordEncoder` instead 4.2.0 ----- diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php b/src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php new file mode 100644 index 0000000000000..de14becf47378 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php @@ -0,0 +1,52 @@ +<?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\Component\Security\Core\Encoder; + +/** + * @internal + * + * @author Robin Chalas <robin.chalas@gmail.com> + */ +trait Argon2Trait +{ + private $memoryCost; + private $timeCost; + private $threads; + + public function __construct(int $memoryCost = null, int $timeCost = null, int $threads = null) + { + $this->memoryCost = $memoryCost; + $this->timeCost = $timeCost; + $this->threads = $threads; + } + + private function encodePasswordNative(string $raw, int $algorithm) + { + return password_hash($raw, $algorithm, [ + 'memory_cost' => $this->memoryCost ?? \PASSWORD_ARGON2_DEFAULT_MEMORY_COST, + 'time_cost' => $this->timeCost ?? \PASSWORD_ARGON2_DEFAULT_TIME_COST, + 'threads' => $this->threads ?? \PASSWORD_ARGON2_DEFAULT_THREADS, + ]); + } + + private function encodePasswordSodiumFunction(string $raw) + { + $hash = \sodium_crypto_pwhash_str( + $raw, + \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE + ); + \sodium_memzero($raw); + + return $hash; + } +} diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php index 333d3ddb1165a..1694e8fd65c84 100644 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php @@ -21,25 +21,7 @@ */ class Argon2iPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface { - private $config = []; - - /** - * Argon2iPasswordEncoder constructor. - * - * @param int|null $memoryCost memory usage of the algorithm - * @param int|null $timeCost number of iterations - * @param int|null $threads number of parallel threads - */ - public function __construct(int $memoryCost = null, int $timeCost = null, int $threads = null) - { - if (\defined('PASSWORD_ARGON2I')) { - $this->config = [ - 'memory_cost' => $memoryCost ?? \PASSWORD_ARGON2_DEFAULT_MEMORY_COST, - 'time_cost' => $timeCost ?? \PASSWORD_ARGON2_DEFAULT_TIME_COST, - 'threads' => $threads ?? \PASSWORD_ARGON2_DEFAULT_THREADS, - ]; - } - } + use Argon2Trait; public static function isSupported() { @@ -64,10 +46,13 @@ public function encodePassword($raw, $salt) } if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { - return $this->encodePasswordNative($raw); - } - if (\function_exists('sodium_crypto_pwhash_str')) { - return $this->encodePasswordSodiumFunction($raw); + return $this->encodePasswordNative($raw, \PASSWORD_ARGON2I); + } elseif (\function_exists('sodium_crypto_pwhash_str')) { + if (0 === strpos($hash = $this->encodePasswordSodiumFunction($raw), Argon2idPasswordEncoder::HASH_PREFIX)) { + @trigger_error(sprintf('Using "%s" while only the "argon2id" algorithm is supported is deprecated since Symfony 4.3, use "%s" instead.', __CLASS__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); + } + + return $hash; } if (\extension_loaded('libsodium')) { return $this->encodePasswordSodiumExtension($raw); @@ -81,10 +66,20 @@ public function encodePassword($raw, $salt) */ public function isPasswordValid($encoded, $raw, $salt) { - // If $encoded was created via "sodium_crypto_pwhash_str()", the hashing algorithm may be "argon2id" instead of "argon2i". - // In this case, "password_verify()" cannot be used. - if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I') && (false === strpos($encoded, '$argon2id$'))) { - return !$this->isPasswordTooLong($raw) && password_verify($raw, $encoded); + if ($this->isPasswordTooLong($raw)) { + return false; + } + + if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { + // If $encoded was created via "sodium_crypto_pwhash_str()", the hashing algorithm may be "argon2id" instead of "argon2i" + if ($isArgon2id = (0 === strpos($encoded, Argon2idPasswordEncoder::HASH_PREFIX))) { + @trigger_error(sprintf('Calling "%s()" with a password hashed using argon2id is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); + } + + // Remove the right part of the OR in 5.0 + if (\defined('PASSWORD_ARGON2I') || $isArgon2id && \defined('PASSWORD_ARGON2ID')) { + return password_verify($raw, $encoded); + } } if (\function_exists('sodium_crypto_pwhash_str_verify')) { $valid = !$this->isPasswordTooLong($raw) && \sodium_crypto_pwhash_str_verify($encoded, $raw); @@ -102,23 +97,6 @@ public function isPasswordValid($encoded, $raw, $salt) throw new \LogicException('Argon2i algorithm is not supported. Please install the libsodium extension or upgrade to PHP 7.2+.'); } - private function encodePasswordNative($raw) - { - return password_hash($raw, \PASSWORD_ARGON2I, $this->config); - } - - private function encodePasswordSodiumFunction($raw) - { - $hash = \sodium_crypto_pwhash_str( - $raw, - \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, - \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE - ); - \sodium_memzero($raw); - - return $hash; - } - private function encodePasswordSodiumExtension($raw) { $hash = \Sodium\crypto_pwhash_str( diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php new file mode 100644 index 0000000000000..14fa7b4cec791 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php @@ -0,0 +1,85 @@ +<?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\Component\Security\Core\Encoder; + +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\Exception\LogicException; + +/** + * Hashes passwords using the Argon2id algorithm. + * + * @author Robin Chalas <robin.chalas@gmail.com> + * + * @final + */ +class Argon2idPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface +{ + use Argon2Trait; + + /** + * @internal + */ + public const HASH_PREFIX = '$argon2id'; + + public static function isSupported() + { + return \defined('PASSWORD_ARGON2ID') || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13'); + } + + /** + * {@inheritdoc} + */ + public function encodePassword($raw, $salt) + { + if ($this->isPasswordTooLong($raw)) { + throw new BadCredentialsException('Invalid password.'); + } + if (\defined('PASSWORD_ARGON2ID')) { + return $this->encodePasswordNative($raw, \PASSWORD_ARGON2ID); + } + if (\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + $hash = \sodium_crypto_pwhash_str( + $raw, + \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE + ); + \sodium_memzero($raw); + + return $hash; + } + + throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); + } + + /** + * {@inheritdoc} + */ + public function isPasswordValid($encoded, $raw, $salt) + { + if (0 !== strpos($encoded, self::HASH_PREFIX)) { + return false; + } + + if (\defined('PASSWORD_ARGON2ID')) { + return !$this->isPasswordTooLong($raw) && password_verify($raw, $encoded); + } + + if (\function_exists('sodium_crypto_pwhash_str_verify')) { + $valid = !$this->isPasswordTooLong($raw) && \sodium_crypto_pwhash_str_verify($encoded, $raw); + \sodium_memzero($raw); + + return $valid; + } + + throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); + } +} diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index 8695ba3401d72..c5770b1e58226 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -117,6 +117,15 @@ private function getEncoderConfigFromAlgorithm($config) $config['threads'], ], ]; + case 'argon2id': + return [ + 'class' => Argon2idPasswordEncoder::class, + 'arguments' => [ + $config['memory_cost'], + $config['time_cost'], + $config['threads'], + ], + ]; } return [ diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php index 1b033cfacc685..93917c5b59773 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php @@ -23,7 +23,7 @@ class Argon2iPasswordEncoderTest extends TestCase protected function setUp() { - if (!Argon2iPasswordEncoder::isSupported()) { + if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { $this->markTestSkipped('Argon2i algorithm is not supported.'); } } diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php new file mode 100644 index 0000000000000..460777c124f5f --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php @@ -0,0 +1,65 @@ +<?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\Component\Security\Core\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; + +class Argon2idPasswordEncoderTest extends TestCase +{ + protected function setUp() + { + if (!Argon2idPasswordEncoder::isSupported()) { + $this->markTestSkipped('Argon2i algorithm is not supported.'); + } + } + + public function testValidationWithConfig() + { + $encoder = new Argon2idPasswordEncoder(8, 4, 1); + $result = $encoder->encodePassword('password', null); + $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); + $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); + } + + public function testValidation() + { + $encoder = new Argon2idPasswordEncoder(); + $result = $encoder->encodePassword('password', null); + $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); + $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); + } + + /** + * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException + */ + public function testEncodePasswordLength() + { + $encoder = new Argon2idPasswordEncoder(); + $encoder->encodePassword(str_repeat('a', 4097), 'salt'); + } + + public function testCheckPasswordLength() + { + $encoder = new Argon2idPasswordEncoder(); + $result = $encoder->encodePassword(str_repeat('a', 4096), null); + $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 4097), null)); + $this->assertTrue($encoder->isPasswordValid($result, str_repeat('a', 4096), null)); + } + + public function testUserProvidedSaltIsNotUsed() + { + $encoder = new Argon2idPasswordEncoder(); + $result = $encoder->encodePassword('password', 'salt'); + $this->assertTrue($encoder->isPasswordValid($result, 'password', 'anotherSalt')); + } +} From 6b6c24c6187b5fe19b9c0aa230432a846d212081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= <jeremy@derusse.com> Date: Sun, 7 Apr 2019 20:27:31 +0200 Subject: [PATCH 443/495] Allow env processor to resolve `::` --- .../ParameterBag/EnvPlaceholderParameterBag.php | 2 +- .../Tests/ParameterBag/EnvPlaceholderParameterBagTest.php | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php index 200351bf42551..fe27324e54f11 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php @@ -42,7 +42,7 @@ public function get($name) return $placeholder; // return first result } } - if (!preg_match('/^(?:\w++:)*+\w++$/', $env)) { + if (!preg_match('/^(?:\w*+:)*+\w++$/', $env)) { throw new InvalidArgumentException(sprintf('Invalid %s name: only "word" characters are allowed.', $name)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php b/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php index b245823f670d4..999303017c88f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php @@ -194,4 +194,11 @@ public function testGetThrowsOnBadDefaultValue() $bag->get('env(ARRAY_VAR)'); $bag->resolve(); } + + public function testDefaultToNullAllowed() + { + $bag = new EnvPlaceholderParameterBag(); + $bag->resolve(); + $this->assertNotNull($bag->get('env(default::BAR)')); + } } From 4518ac56a10bba9ca941f16a30073a61f14b41fb Mon Sep 17 00:00:00 2001 From: Patrick Landolt <patrick.landolt@artack.ch> Date: Sun, 7 Apr 2019 22:39:37 +0200 Subject: [PATCH 444/495] allow user/pass on dns while using failover/roundrobin and type fix for username/password --- src/Symfony/Component/Mailer/Tests/TransportTest.php | 10 +++++++++- src/Symfony/Component/Mailer/Transport.php | 12 +++++++++++- .../Mailer/Transport/Smtp/EsmtpTransport.php | 4 ++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Mailer/Tests/TransportTest.php b/src/Symfony/Component/Mailer/Tests/TransportTest.php index 4ecec2e66a0f6..0d1f14326256f 100644 --- a/src/Symfony/Component/Mailer/Tests/TransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/TransportTest.php @@ -236,9 +236,11 @@ public function testFromDsnMailchimp() public function testFromDsnFailover() { + $user = 'user'; + $pass = 'pass'; $dispatcher = $this->createMock(EventDispatcherInterface::class); $logger = $this->createMock(LoggerInterface::class); - $transport = Transport::fromDsn('smtp://null || smtp://null || smtp://null', $dispatcher, null, $logger); + $transport = Transport::fromDsn('smtp://example.com || smtp://'.urlencode($user).'@example.com || smtp://'.urlencode($user).':'.urlencode($pass).'@example.com', $dispatcher, null, $logger); $this->assertInstanceOf(Transport\FailoverTransport::class, $transport); $p = new \ReflectionProperty(Transport\RoundRobinTransport::class, 'transports'); $p->setAccessible(true); @@ -247,6 +249,12 @@ public function testFromDsnFailover() foreach ($transports as $transport) { $this->assertProperties($transport, $dispatcher, $logger); } + $this->assertSame('', $transports[0]->getUsername()); + $this->assertSame('', $transports[0]->getPassword()); + $this->assertSame($user, $transports[1]->getUsername()); + $this->assertSame('', $transports[1]->getPassword()); + $this->assertSame($user, $transports[2]->getUsername()); + $this->assertSame($pass, $transports[2]->getPassword()); } public function testFromDsnRoundRobin() diff --git a/src/Symfony/Component/Mailer/Transport.php b/src/Symfony/Component/Mailer/Transport.php index f5202242a35a9..eeb1892fe8b3c 100644 --- a/src/Symfony/Component/Mailer/Transport.php +++ b/src/Symfony/Component/Mailer/Transport.php @@ -171,7 +171,17 @@ private static function createTransport(string $dsn, EventDispatcherInterface $d throw new LogicException(sprintf('The "%s" scheme is not supported for mailer "%s".', $parsedDsn['scheme'], $parsedDsn['host'])); default: if ('smtp' === $parsedDsn['scheme']) { - return new Transport\Smtp\EsmtpTransport($parsedDsn['host'], $parsedDsn['port'] ?? 25, $query['encryption'] ?? null, $query['auth_mode'] ?? null, $dispatcher, $logger); + $transport = new Transport\Smtp\EsmtpTransport($parsedDsn['host'], $parsedDsn['port'] ?? 25, $query['encryption'] ?? null, $query['auth_mode'] ?? null, $dispatcher, $logger); + + if ($user) { + $transport->setUsername($user); + } + + if ($pass) { + $transport->setPassword($pass); + } + + return $transport; } throw new LogicException(sprintf('The "%s" mailer is not supported.', $parsedDsn['host'])); diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php index fc0ee2ca8f618..d3a93debd1dc5 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php @@ -29,8 +29,8 @@ class EsmtpTransport extends SmtpTransport { private $authenticators = []; - private $username; - private $password; + private $username = ''; + private $password = ''; private $authMode; public function __construct(string $host = 'localhost', int $port = 25, string $encryption = null, string $authMode = null, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) From 44eb7a0485b164c9ead530ece635c95bf724dbbf Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@sensiolabs.de> Date: Sun, 7 Apr 2019 22:01:56 +0200 Subject: [PATCH 445/495] fix backwards compatibility breaks --- .../Bridge/Twig/Extension/HttpFoundationExtension.php | 2 +- .../DependencyInjection/Argument/BoundArgument.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php index e99c835879d6d..a72339e1243e1 100644 --- a/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/HttpFoundationExtension.php @@ -47,7 +47,7 @@ public function __construct($urlHelper) $requestContext = null; if (2 === \func_num_args()) { $requestContext = \func_get_arg(1); - if (!$requestContext instanceof RequestContext) { + if (null !== $requestContext && !$requestContext instanceof RequestContext) { throw new \TypeError(sprintf('The second argument must be an instance of "%s".', RequestContext::class)); } } diff --git a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php index 4889c8e7cb02d..2c777a16fae33 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php @@ -53,6 +53,10 @@ public function getValues() */ public function setValues(array $values) { - list($this->value, $this->identifier, $this->used, $this->type, $this->file) = $values; + if (5 === count($values)) { + list($this->value, $this->identifier, $this->used, $this->type, $this->file) = $values; + } else { + list($this->value, $this->identifier, $this->used) = $values; + } } } From 546b1146c4bf5b64cfd7857e0d83ec918b3b14f2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 8 Apr 2019 07:16:00 +0200 Subject: [PATCH 446/495] fixed CS --- .../Component/DependencyInjection/Argument/BoundArgument.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php index 2c777a16fae33..4a0054e20bff7 100644 --- a/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php +++ b/src/Symfony/Component/DependencyInjection/Argument/BoundArgument.php @@ -53,7 +53,7 @@ public function getValues() */ public function setValues(array $values) { - if (5 === count($values)) { + if (5 === \count($values)) { list($this->value, $this->identifier, $this->used, $this->type, $this->file) = $values; } else { list($this->value, $this->identifier, $this->used) = $values; From f539932899a82514f26581037a16e69293bb86c4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Mon, 8 Apr 2019 08:16:24 +0200 Subject: [PATCH 447/495] fixed CS --- UPGRADE-5.0.md | 2 +- .../Core/Encoder/Argon2idPasswordEncoder.php | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 744ef9a2b0456..b163e76678286 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -327,7 +327,7 @@ Security ``` * Using `Argon2iPasswordEncoder` while only the `argon2id` algorithm is supported - now throws a \LogicException`, use `Argon2idPasswordEncoder` instead + now throws a `\LogicException`, use `Argon2idPasswordEncoder` instead SecurityBundle -------------- diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php index 14fa7b4cec791..7dc924bb159f7 100644 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php @@ -46,18 +46,18 @@ public function encodePassword($raw, $salt) if (\defined('PASSWORD_ARGON2ID')) { return $this->encodePasswordNative($raw, \PASSWORD_ARGON2ID); } - if (\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { - $hash = \sodium_crypto_pwhash_str( - $raw, - \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, - \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE - ); - \sodium_memzero($raw); - - return $hash; + if (!\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); } - throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); + $hash = \sodium_crypto_pwhash_str( + $raw, + \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE + ); + \sodium_memzero($raw); + + return $hash; } /** From e991472a7622eb655af94c9354f2ede6f3b82523 Mon Sep 17 00:00:00 2001 From: Niels Keurentjes <niels.keurentjes@omines.com> Date: Sun, 7 Apr 2019 13:47:03 +0200 Subject: [PATCH 448/495] [WebProfiler] Fix Javascript error when using custom stopwatch categories --- .../WebProfilerBundle/Resources/views/Collector/time.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js index 3a057ec604d0d..e21a9425fd9b1 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js @@ -252,11 +252,11 @@ class Legend { } get(category) { - return this.categories.find(element => element.value === category); + return this.categories.find(element => element.value === category) || this.createCategory(category); } getClassname(category) { - return this.classnames[category]; + return this.classnames[category] || ''; } getSectionClassname() { From 4f39339fec120ecc5078d287e0e9b80be1a9765a Mon Sep 17 00:00:00 2001 From: Amrouche Hamza <hamza@les-tilleuls.coop> Date: Sun, 7 Apr 2019 10:47:43 +0200 Subject: [PATCH 449/495] [FrameworkBundle] [TwigBundle] Move the hinclude key away from templating --- .../DependencyInjection/Configuration.php | 3 ++- .../FrameworkExtension.php | 5 ++++ .../Resources/config/schema/symfony-1.0.xsd | 1 + .../DependencyInjection/ConfigurationTest.php | 1 + .../Fixtures/php/template_and_fragments.php | 18 ++++++++++++++ .../Fixtures/xml/template_and_fragments.xml | 24 +++++++++++++++++++ .../Fixtures/yml/template_and_fragments.yml | 12 ++++++++++ .../FrameworkExtensionTest.php | 8 +++++++ 8 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/template_and_fragments.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/template_and_fragments.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/template_and_fragments.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 15636fb1e616e..00d0053dc4cbd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -191,6 +191,7 @@ private function addFragmentsSection(ArrayNodeDefinition $rootNode) ->info('fragments configuration') ->canBeEnabled() ->children() + ->scalarNode('hinclude_default_template')->defaultNull()->end() ->scalarNode('path')->defaultValue('/_fragment')->end() ->end() ->end() @@ -610,7 +611,7 @@ private function addTemplatingSection(ArrayNodeDefinition $rootNode) ->then(function () { return ['enabled' => false, 'engines' => false]; }) ->end() ->children() - ->scalarNode('hinclude_default_template')->defaultNull()->end() + ->scalarNode('hinclude_default_template')->setDeprecated('Setting "templating.hinclude_default_template" is deprecated since Symfony 4.3, use "fragments.hinclude_default_template" instead.')->defaultNull()->end() ->scalarNode('cache')->end() ->arrayNode('form') ->addDefaultsIfNotSet() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 92aca42e31229..338eddb949cbc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -487,6 +487,11 @@ private function registerFragmentsConfiguration(array $config, ContainerBuilder return; } + if ($container->hasParameter('fragment.renderer.hinclude.global_template') && null !== $container->getParameter('fragment.renderer.hinclude.global_template') && null !== $config['hinclude_default_template']) { + throw new \LogicException('You cannot set both "templating.hinclude_default_template" and "fragments.hinclude_default_template", please only use "fragments.hinclude_default_template".'); + } + + $container->setParameter('fragment.renderer.hinclude.global_template', $config['hinclude_default_template']); $loader->load('fragment_listener.xml'); $container->setParameter('fragment.path', $config['path']); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 9d71b403ddb39..478a5059820a5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -69,6 +69,7 @@ <xsd:complexType name="fragments"> <xsd:attribute name="enabled" type="xsd:boolean" /> <xsd:attribute name="path" type="xsd:string" /> + <xsd:attribute name="hinclude-default-template" type="xsd:string" /> </xsd:complexType> <xsd:complexType name="web_link"> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index c2455606b9727..827988669fb8d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -209,6 +209,7 @@ protected static function getBundleDefaultConfig() 'fragments' => [ 'enabled' => false, 'path' => '/_fragment', + 'hinclude_default_template' => null, ], 'profiler' => [ 'enabled' => false, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/template_and_fragments.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/template_and_fragments.php new file mode 100644 index 0000000000000..6fd941d9f46c0 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/template_and_fragments.php @@ -0,0 +1,18 @@ +<?php + +$container->loadFromExtension('framework', [ + 'templating' => [ + 'cache' => '/path/to/cache', + 'engines' => ['php', 'twig'], + 'loader' => ['loader.foo', 'loader.bar'], + 'form' => [ + 'resources' => ['theme1', 'theme2'], + ], + 'hinclude_default_template' => 'global_hinclude_template', + ], + 'assets' => null, + 'fragments' => [ + 'enabled' => true, + 'hinclude_default_template' => 'global_hinclude_template', + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/template_and_fragments.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/template_and_fragments.xml new file mode 100644 index 0000000000000..d253e9f5deeed --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/template_and_fragments.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" ?> +<container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:framework="http://symfony.com/schema/dic/symfony" + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd + http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> + + <framework:config> + <framework:fragments enabled="true" hinclude-default-template="global_hinclude_template"/> + <framework:esi enabled="true" /> + <framework:ssi enabled="true" /> + <framework:assets /> + <framework:templating cache="/path/to/cache" hinclude-default-template="global_hinclude_template"> + <framework:loader>loader.foo</framework:loader> + <framework:loader>loader.bar</framework:loader> + <framework:engine>php</framework:engine> + <framework:engine>twig</framework:engine> + <framework:form> + <framework:resource>theme1</framework:resource> + <framework:resource>theme2</framework:resource> + </framework:form> + </framework:templating> + </framework:config> +</container> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/template_and_fragments.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/template_and_fragments.yml new file mode 100644 index 0000000000000..dbf7b697541e0 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/template_and_fragments.yml @@ -0,0 +1,12 @@ +framework: + fragments: + enabled: true + hinclude_default_template: global_hinclude_template + templating: + engines: [php, twig] + loader: [loader.foo, loader.bar] + cache: /path/to/cache + form: + resources: [theme1, theme2] + hinclude_default_template: global_hinclude_template + assets: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index e3f727030ccc8..8ebe5d97513fb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -159,6 +159,14 @@ public function testEsiDisabled() $this->assertFalse($container->hasDefinition('esi')); } + /** + * @expectedException \LogicException + */ + public function testAmbiguousWhenBothTemplatingAndFragments() + { + $this->createContainerFromFile('template_and_fragments'); + } + public function testSsi() { $container = $this->createContainerFromFile('full'); From bf89907dce83b07c66caceffa7de022e0d4f0ae3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Mon, 8 Apr 2019 16:21:14 +0200 Subject: [PATCH 450/495] [FrameworkBundle] for Psr18HttpClient configuration --- .../Bundle/FrameworkBundle/Resources/config/http_client.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml index bf7b7b9f64055..aa29944c472d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/http_client.xml @@ -16,8 +16,10 @@ </service> <service id="Symfony\Contracts\HttpClient\HttpClientInterface" alias="http_client" /> - <service id="psr18.http_client" class="Symfony\Component\HttpClient\Psr18Client" autowire="true"> + <service id="psr18.http_client" class="Symfony\Component\HttpClient\Psr18Client"> <argument type="service" id="http_client" /> + <argument type="service" id="Psr\Http\Message\ResponseFactoryInterface" on-invalid="ignore" /> + <argument type="service" id="Psr\Http\Message\StreamFactoryInterface" on-invalid="ignore" /> </service> <service id="Psr\Http\Client\ClientInterface" alias="psr18.http_client" /> </services> From fbd439e0bd1f7a0e6fac000a0dc28fad050d6e07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= <theo.fidry@gmail.com> Date: Sun, 7 Apr 2019 14:48:24 +0200 Subject: [PATCH 451/495] [HttpClient] Allow the HTTP_PROXY environment variable lookup with phpdbg --- src/Symfony/Component/HttpClient/NativeHttpClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index a24c69965430f..03eaeac107e51 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -258,7 +258,7 @@ private static function getProxy(?string $proxy, array $url): ?array { if (null === $proxy) { // Ignore HTTP_PROXY except on the CLI to work around httpoxy set of vulnerabilities - $proxy = $_SERVER['http_proxy'] ?? ('cli' === \PHP_SAPI ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; + $proxy = $_SERVER['http_proxy'] ?? (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? $_SERVER['HTTP_PROXY'] ?? null : null) ?? $_SERVER['all_proxy'] ?? $_SERVER['ALL_PROXY'] ?? null; if ('https:' === $url['scheme']) { $proxy = $_SERVER['https_proxy'] ?? $_SERVER['HTTPS_PROXY'] ?? $proxy; From 682855fa7d9eec3f0e13c0e93a0b59cd4d92d4d5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann <christian.flothmann@sensiolabs.de> Date: Mon, 8 Apr 2019 17:29:39 +0200 Subject: [PATCH 452/495] fix tests * use legacy group when using the deprecated `hinclude_default_template` templating config option * conflict with DependencyInjection 4.2 in the HttpKernel component to be able to rely on five values being retrieved from the values of the `BoundArgument` class * let the TwigBundle conflict with versions of FrameworkBundle that do not ship the `url_helper` service --- .../Tests/DependencyInjection/FrameworkExtensionTest.php | 1 + src/Symfony/Bundle/TwigBundle/composer.json | 4 ++-- src/Symfony/Component/HttpKernel/composer.json | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 8ebe5d97513fb..71e719e0b1685 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -160,6 +160,7 @@ public function testEsiDisabled() } /** + * @group legacy * @expectedException \LogicException */ public function testAmbiguousWhenBothTemplatingAndFragments() diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 0690506fa4991..b754470948aa8 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -35,14 +35,14 @@ "symfony/templating": "~3.4|~4.0", "symfony/translation": "^4.2", "symfony/yaml": "~3.4|~4.0", - "symfony/framework-bundle": "~4.1", + "symfony/framework-bundle": "~4.3", "symfony/web-link": "~3.4|~4.0", "doctrine/annotations": "~1.0", "doctrine/cache": "~1.0" }, "conflict": { "symfony/dependency-injection": "<4.1", - "symfony/framework-bundle": "<4.1", + "symfony/framework-bundle": "<4.3", "symfony/translation": "<4.2" }, "autoload": { diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index b8348b0fece8c..3edbf79cc32f7 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -30,7 +30,7 @@ "symfony/config": "~3.4|~4.0", "symfony/console": "~3.4|~4.0", "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.2", + "symfony/dependency-injection": "^4.3", "symfony/dom-crawler": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", @@ -49,7 +49,7 @@ "conflict": { "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.2", + "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" From caad562c11eeb76c7f4b1d39e0c024d41e616a09 Mon Sep 17 00:00:00 2001 From: Mikkel Paulson <git@email.mikkel.ca> Date: Sun, 7 Apr 2019 15:22:28 -0400 Subject: [PATCH 453/495] [Console] Add callback support to Console\Question autocompleter In order to enable more dynamic use cases such as word-by-word autocomplete and path-based autocomplete, update the autocomplete logic of the Question object and its helper to accept a callback function. This function is called on each keystroke and should return an array of possibilities to present to the user. The original logic only accepted an array, which required implementations to anticipate in advance all possible input values. This change is fully backwards-compatible, but reimplements the old behaviour by initializing a "dumb" callback function that always returns the same array regardless of input. --- src/Symfony/Component/Console/CHANGELOG.md | 2 + .../Console/Helper/QuestionHelper.php | 29 +- .../Component/Console/Question/Question.php | 45 ++- .../Tests/Helper/QuestionHelperTest.php | 61 +++++ .../Console/Tests/Question/QuestionTest.php | 257 ++++++++++++++++++ 5 files changed, 375 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/Console/Tests/Question/QuestionTest.php diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index ff7973319c04c..67decd30beae3 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * added support for hyperlinks * added `ProgressBar::iterate()` method that simplify updating the progress bar when iterating + * added `Question::setAutocompleterCallback()` to provide a callback function + that dynamically generates suggestions as the user types 4.2.0 ----- diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index b8b76833a6f3f..75e660a3fb999 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -115,7 +115,7 @@ private function doAsk(OutputInterface $output, Question $question) $this->writePrompt($output, $question); $inputStream = $this->inputStream ?: STDIN; - $autocomplete = $question->getAutocompleterValues(); + $autocomplete = $question->getAutocompleterCallback(); if (null === $autocomplete || !$this->hasSttyAvailable()) { $ret = false; @@ -137,7 +137,7 @@ private function doAsk(OutputInterface $output, Question $question) $ret = trim($ret); } } else { - $ret = trim($this->autocomplete($output, $question, $inputStream, \is_array($autocomplete) ? $autocomplete : iterator_to_array($autocomplete, false))); + $ret = trim($this->autocomplete($output, $question, $inputStream, $autocomplete)); } if ($output instanceof ConsoleSectionOutput) { @@ -194,17 +194,15 @@ protected function writeError(OutputInterface $output, \Exception $error) /** * Autocompletes a question. * - * @param OutputInterface $output - * @param Question $question - * @param resource $inputStream + * @param resource $inputStream */ - private function autocomplete(OutputInterface $output, Question $question, $inputStream, array $autocomplete): string + private function autocomplete(OutputInterface $output, Question $question, $inputStream, callable $autocomplete): string { $ret = ''; $i = 0; $ofs = -1; - $matches = $autocomplete; + $matches = $autocomplete($ret); $numMatches = \count($matches); $sttyMode = shell_exec('stty -g'); @@ -232,7 +230,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu if (0 === $i) { $ofs = -1; - $matches = $autocomplete; + $matches = $autocomplete($ret); $numMatches = \count($matches); } else { $numMatches = 0; @@ -260,18 +258,25 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu } elseif (\ord($c) < 32) { if ("\t" === $c || "\n" === $c) { if ($numMatches > 0 && -1 !== $ofs) { - $ret = $matches[$ofs]; + $ret = (string) $matches[$ofs]; // Echo out remaining chars for current match $output->write(substr($ret, $i)); $i = \strlen($ret); + + $matches = array_filter( + $autocomplete($ret), + function ($match) use ($ret) { + return '' === $ret || 0 === strpos($match, $ret); + } + ); + $numMatches = \count($matches); + $ofs = -1; } if ("\n" === $c) { $output->write($c); break; } - - $numMatches = 0; } continue; @@ -287,7 +292,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu $numMatches = 0; $ofs = 0; - foreach ($autocomplete as $value) { + foreach ($autocomplete($ret) as $value) { // If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle) if (0 === strpos($value, $ret)) { $matches[$numMatches++] = $value; diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php index eac82cfad32e6..9201af2fd5d82 100644 --- a/src/Symfony/Component/Console/Question/Question.php +++ b/src/Symfony/Component/Console/Question/Question.php @@ -25,7 +25,7 @@ class Question private $attempts; private $hidden = false; private $hiddenFallback = true; - private $autocompleterValues; + private $autocompleterCallback; private $validator; private $default; private $normalizer; @@ -81,7 +81,7 @@ public function isHidden() */ public function setHidden($hidden) { - if ($this->autocompleterValues) { + if ($this->autocompleterCallback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } @@ -121,7 +121,9 @@ public function setHiddenFallback($fallback) */ public function getAutocompleterValues() { - return $this->autocompleterValues; + $callback = $this->getAutocompleterCallback(); + + return $callback ? $callback('') : null; } /** @@ -138,17 +140,46 @@ public function setAutocompleterValues($values) { if (\is_array($values)) { $values = $this->isAssoc($values) ? array_merge(array_keys($values), array_values($values)) : array_values($values); - } - if (null !== $values && !\is_array($values) && !$values instanceof \Traversable) { + $callback = static function () use ($values) { + return $values; + }; + } elseif ($values instanceof \Traversable) { + $valueCache = null; + $callback = static function () use ($values, &$valueCache) { + return $valueCache ?? $valueCache = iterator_to_array($values, false); + }; + } elseif (null === $values) { + $callback = null; + } else { throw new InvalidArgumentException('Autocompleter values can be either an array, "null" or a "Traversable" object.'); } - if ($this->hidden) { + return $this->setAutocompleterCallback($callback); + } + + /** + * Gets the callback function used for the autocompleter. + */ + public function getAutocompleterCallback(): ?callable + { + return $this->autocompleterCallback; + } + + /** + * Sets the callback function used for the autocompleter. + * + * The callback is passed the user input as argument and should return an iterable of corresponding suggestions. + * + * @return $this + */ + public function setAutocompleterCallback(callable $callback = null): self + { + if ($this->hidden && null !== $callback) { throw new LogicException('A hidden question cannot use the autocompleter.'); } - $this->autocompleterValues = $values; + $this->autocompleterCallback = $callback; return $this; } diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 69d5470b8c20c..fc0f2293a461d 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -198,6 +198,67 @@ public function testAskWithAutocomplete() $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } + public function testAskWithAutocompleteCallback() + { + if (!$this->hasSttyAvailable()) { + $this->markTestSkipped('`stty` is required to test autocomplete functionality'); + } + + // Po<TAB>Cr<TAB>P<DOWN ARROW><DOWN ARROW><NEWLINE> + $inputStream = $this->getInputStream("Pa\177\177o\tCr\t\033[A\033[A\033[A\n"); + + $dialog = new QuestionHelper(); + $helperSet = new HelperSet([new FormatterHelper()]); + $dialog->setHelperSet($helperSet); + + $question = new Question('What\'s for dinner?'); + + // A simple test callback - return an array containing the words the + // user has already completed, suffixed with all known words. + // + // Eg: If the user inputs "Potato C", the return will be: + // + // ["Potato Carrot ", "Potato Creme ", "Potato Curry ", ...] + // + // No effort is made to avoid irrelevant suggestions, as this is handled + // by the autocomplete function. + $callback = function ($input) { + $knownWords = [ + 'Carrot', + 'Creme', + 'Curry', + 'Parsnip', + 'Pie', + 'Potato', + 'Tart', + ]; + + $inputWords = explode(' ', $input); + $lastInputWord = array_pop($inputWords); + $suggestionBase = $inputWords + ? implode(' ', $inputWords).' ' + : ''; + + return array_map( + function ($word) use ($suggestionBase) { + return $suggestionBase.$word.' '; + }, + $knownWords + ); + }; + + $question->setAutocompleterCallback($callback); + + $this->assertSame( + 'Potato Creme Pie', + $dialog->ask( + $this->createStreamableInputInterfaceMock($inputStream), + $this->createOutputInterface(), + $question + ) + ); + } + public function testAskWithAutocompleteWithNonSequentialKeys() { if (!$this->hasSttyAvailable()) { diff --git a/src/Symfony/Component/Console/Tests/Question/QuestionTest.php b/src/Symfony/Component/Console/Tests/Question/QuestionTest.php new file mode 100644 index 0000000000000..537cd30144e6a --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Question/QuestionTest.php @@ -0,0 +1,257 @@ +<?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\Component\Console\Tests\Question; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Question\Question; + +class QuestionTest extends TestCase +{ + private $question; + + protected function setUp() + { + parent::setUp(); + $this->question = new Question('Test question'); + } + + public function providerTrueFalse() + { + return [[true], [false]]; + } + + public function testGetQuestion() + { + self::assertSame('Test question', $this->question->getQuestion()); + } + + public function testGetDefault() + { + $question = new Question('Test question', 'Default value'); + self::assertSame('Default value', $question->getDefault()); + } + + public function testGetDefaultDefault() + { + self::assertNull($this->question->getDefault()); + } + + /** + * @dataProvider providerTrueFalse + */ + public function testIsSetHidden(bool $hidden) + { + $this->question->setHidden($hidden); + self::assertSame($hidden, $this->question->isHidden()); + } + + public function testIsHiddenDefault() + { + self::assertFalse($this->question->isHidden()); + } + + public function testSetHiddenWithAutocompleterValues() + { + $this->question->setAutocompleterValues(['a', 'b']); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage( + 'A hidden question cannot use the autocompleter.' + ); + + $this->question->setHidden(true); + } + + public function testSetHiddenWithNoAutocompleterValues() + { + $this->question->setAutocompleterValues(['a', 'b']); + $this->question->setAutocompleterValues(null); + + $exception = null; + try { + $this->question->setHidden(true); + } catch (\Exception $exception) { + // Do nothing + } + + $this->assertNull($exception); + } + + /** + * @dataProvider providerTrueFalse + */ + public function testIsSetHiddenFallback(bool $hidden) + { + $this->question->setHiddenFallback($hidden); + self::assertSame($hidden, $this->question->isHiddenFallback()); + } + + public function testIsHiddenFallbackDefault() + { + self::assertTrue($this->question->isHiddenFallback()); + } + + public function providerGetSetAutocompleterValues() + { + return [ + 'array' => [ + ['a', 'b', 'c', 'd'], + ['a', 'b', 'c', 'd'], + ], + 'associative array' => [ + ['a' => 'c', 'b' => 'd'], + ['a', 'b', 'c', 'd'], + ], + 'iterator' => [ + new \ArrayIterator(['a', 'b', 'c', 'd']), + ['a', 'b', 'c', 'd'], + ], + 'null' => [null, null], + ]; + } + + /** + * @dataProvider providerGetSetAutocompleterValues + */ + public function testGetSetAutocompleterValues($values, $expectValues) + { + $this->question->setAutocompleterValues($values); + self::assertSame( + $expectValues, + $this->question->getAutocompleterValues() + ); + } + + public function providerSetAutocompleterValuesInvalid() + { + return [ + ['Potato'], + [new \stdclass()], + [false], + ]; + } + + /** + * @dataProvider providerSetAutocompleterValuesInvalid + */ + public function testSetAutocompleterValuesInvalid($values) + { + self::expectException(InvalidArgumentException::class); + self::expectExceptionMessage( + 'Autocompleter values can be either an array, "null" or a "Traversable" object.' + ); + + $this->question->setAutocompleterValues($values); + } + + public function testSetAutocompleterValuesWhenHidden() + { + $this->question->setHidden(true); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage( + 'A hidden question cannot use the autocompleter.' + ); + + $this->question->setAutocompleterValues(['a', 'b']); + } + + public function testSetAutocompleterValuesWhenNotHidden() + { + $this->question->setHidden(true); + $this->question->setHidden(false); + + $exception = null; + try { + $this->question->setAutocompleterValues(['a', 'b']); + } catch (\Exception $exception) { + // Do nothing + } + + $this->assertNull($exception); + } + + public function testGetAutocompleterValuesDefault() + { + self::assertNull($this->question->getAutocompleterValues()); + } + + public function providerGetSetValidator() + { + return [ + [function ($input) { return $input; }], + [null], + ]; + } + + /** + * @dataProvider providerGetSetValidator + */ + public function testGetSetValidator($callback) + { + $this->question->setValidator($callback); + self::assertSame($callback, $this->question->getValidator()); + } + + public function testGetValidatorDefault() + { + self::assertNull($this->question->getValidator()); + } + + public function providerGetSetMaxAttempts() + { + return [[1], [5], [null]]; + } + + /** + * @dataProvider providerGetSetMaxAttempts + */ + public function testGetSetMaxAttempts($attempts) + { + $this->question->setMaxAttempts($attempts); + self::assertSame($attempts, $this->question->getMaxAttempts()); + } + + public function providerSetMaxAttemptsInvalid() + { + return [['Potato'], [0], [-1]]; + } + + /** + * @dataProvider providerSetMaxAttemptsInvalid + */ + public function testSetMaxAttemptsInvalid($attempts) + { + self::expectException(\InvalidArgumentException::class); + self::expectExceptionMessage('Maximum number of attempts must be a positive value.'); + + $this->question->setMaxAttempts($attempts); + } + + public function testGetMaxAttemptsDefault() + { + self::assertNull($this->question->getMaxAttempts()); + } + + public function testGetSetNormalizer() + { + $normalizer = function ($input) { return $input; }; + $this->question->setNormalizer($normalizer); + self::assertSame($normalizer, $this->question->getNormalizer()); + } + + public function testGetNormalizerDefault() + { + self::assertNull($this->question->getNormalizer()); + } +} From dc95a6fec6d44e1dfcd7ab5895d6e68bf71676bb Mon Sep 17 00:00:00 2001 From: Robin Chalas <robin.chalas@elao.com> Date: Mon, 8 Apr 2019 17:54:59 +0200 Subject: [PATCH 454/495] [Security] Fix argon2 availability checks --- .../DependencyInjection/SecurityExtension.php | 2 +- .../UserPasswordEncoderCommandTest.php | 8 ++-- .../Core/Encoder/Argon2iPasswordEncoder.php | 14 +++---- .../Core/Encoder/Argon2idPasswordEncoder.php | 21 ++++++---- .../Encoder/Argon2iPasswordEncoderTest.php | 41 ++++++++++++++++--- 5 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index b8b3358c020e9..dd7fe75cc8b19 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -571,7 +571,7 @@ private function createEncoder($config, ContainerBuilder $container) } throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.'); - } elseif (\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + } elseif (!\defined('PASSWORD_ARGON2I') && Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { @trigger_error('Configuring an encoder based on the "argon2i" algorithm while only "argon2id" is supported is deprecated since Symfony 4.3, use "argon2id" instead.', E_USER_DEPRECATED); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 80d3348124125..54d355cf0f3a6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -73,7 +73,7 @@ public function testEncodePasswordBcrypt() public function testEncodePasswordArgon2i() { - if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + if (!Argon2iPasswordEncoder::isSupported() || !\defined('PASSWORD_ARGON2I') && Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { $this->markTestSkipped('Argon2i algorithm not available.'); } $this->setupArgon2i(); @@ -95,7 +95,7 @@ public function testEncodePasswordArgon2i() public function testEncodePasswordArgon2id() { if (!Argon2idPasswordEncoder::isSupported()) { - $this->markTestSkipped('Argon2i algorithm not available.'); + $this->markTestSkipped('Argon2id algorithm not available.'); } $this->setupArgon2id(); $this->passwordEncoderCommandTester->execute([ @@ -107,7 +107,7 @@ public function testEncodePasswordArgon2id() $output = $this->passwordEncoderCommandTester->getDisplay(); $this->assertContains('Password encoding succeeded', $output); - $encoder = new Argon2iPasswordEncoder(); + $encoder = new Argon2idPasswordEncoder(); preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); $hash = $matches[1]; $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); @@ -175,7 +175,7 @@ public function testEncodePasswordBcryptOutput() public function testEncodePasswordArgon2iOutput() { - if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + if (!Argon2iPasswordEncoder::isSupported() || !\defined('PASSWORD_ARGON2I') && Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { $this->markTestSkipped('Argon2id algorithm not available.'); } diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php index 1694e8fd65c84..b1add537632c6 100644 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php @@ -48,11 +48,11 @@ public function encodePassword($raw, $salt) if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { return $this->encodePasswordNative($raw, \PASSWORD_ARGON2I); } elseif (\function_exists('sodium_crypto_pwhash_str')) { - if (0 === strpos($hash = $this->encodePasswordSodiumFunction($raw), Argon2idPasswordEncoder::HASH_PREFIX)) { + if (Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { @trigger_error(sprintf('Using "%s" while only the "argon2id" algorithm is supported is deprecated since Symfony 4.3, use "%s" instead.', __CLASS__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); } - return $hash; + return $this->encodePasswordSodiumFunction($raw); } if (\extension_loaded('libsodium')) { return $this->encodePasswordSodiumExtension($raw); @@ -70,12 +70,12 @@ public function isPasswordValid($encoded, $raw, $salt) return false; } - if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { - // If $encoded was created via "sodium_crypto_pwhash_str()", the hashing algorithm may be "argon2id" instead of "argon2i" - if ($isArgon2id = (0 === strpos($encoded, Argon2idPasswordEncoder::HASH_PREFIX))) { - @trigger_error(sprintf('Calling "%s()" with a password hashed using argon2id is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); - } + // If $encoded was created via "sodium_crypto_pwhash_str()", the hashing algorithm may be "argon2id" instead of "argon2i" + if ($isArgon2id = (0 === strpos($encoded, Argon2idPasswordEncoder::HASH_PREFIX))) { + @trigger_error(sprintf('Calling "%s()" with a password hashed using argon2id is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); + } + if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { // Remove the right part of the OR in 5.0 if (\defined('PASSWORD_ARGON2I') || $isArgon2id && \defined('PASSWORD_ARGON2ID')) { return password_verify($raw, $encoded); diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php index 7dc924bb159f7..a201bca36b936 100644 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php @@ -46,18 +46,11 @@ public function encodePassword($raw, $salt) if (\defined('PASSWORD_ARGON2ID')) { return $this->encodePasswordNative($raw, \PASSWORD_ARGON2ID); } - if (!\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + if (!self::isDefaultSodiumAlgorithm()) { throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); } - $hash = \sodium_crypto_pwhash_str( - $raw, - \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, - \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE - ); - \sodium_memzero($raw); - - return $hash; + return $this->encodePasswordSodiumFunction($raw); } /** @@ -82,4 +75,14 @@ public function isPasswordValid($encoded, $raw, $salt) throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); } + + /** + * @internal + */ + public static function isDefaultSodiumAlgorithm() + { + return \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') + && \defined('SODIUM_CRYPTO_PWHASH_ALG_DEFAULT') + && \SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 === \SODIUM_CRYPTO_PWHASH_ALG_DEFAULT; + } } diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php index 93917c5b59773..88f10b446d723 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Core\Tests\Encoder; use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; /** @@ -21,15 +22,12 @@ class Argon2iPasswordEncoderTest extends TestCase { const PASSWORD = 'password'; - protected function setUp() + public function testValidationWithConfig() { - if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { + if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { $this->markTestSkipped('Argon2i algorithm is not supported.'); } - } - public function testValidationWithConfig() - { $encoder = new Argon2iPasswordEncoder(8, 4, 1); $result = $encoder->encodePassword(self::PASSWORD, null); $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, null)); @@ -38,6 +36,10 @@ public function testValidationWithConfig() public function testValidation() { + if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + $this->markTestSkipped('Argon2i algorithm is not supported.'); + } + $encoder = new Argon2iPasswordEncoder(); $result = $encoder->encodePassword(self::PASSWORD, null); $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, null)); @@ -49,12 +51,20 @@ public function testValidation() */ public function testEncodePasswordLength() { + if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + $this->markTestSkipped('Argon2i algorithm is not supported.'); + } + $encoder = new Argon2iPasswordEncoder(); $encoder->encodePassword(str_repeat('a', 4097), 'salt'); } public function testCheckPasswordLength() { + if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + $this->markTestSkipped('Argon2i algorithm is not supported.'); + } + $encoder = new Argon2iPasswordEncoder(); $result = $encoder->encodePassword(str_repeat('a', 4096), null); $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 4097), null)); @@ -63,8 +73,29 @@ public function testCheckPasswordLength() public function testUserProvidedSaltIsNotUsed() { + if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + $this->markTestSkipped('Argon2i algorithm is not supported.'); + } + $encoder = new Argon2iPasswordEncoder(); $result = $encoder->encodePassword(self::PASSWORD, 'salt'); $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, 'anotherSalt')); } + + /** + * @group legacy + * @exectedDeprecation Using "Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder" while only the "argon2id" algorithm is supported is deprecated since Symfony 4.3, use "Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder" instead. + * @exectedDeprecation Calling "Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder::isPasswordValid()" with a password hashed using argon2id is deprecated since Symfony 4.3, use "Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder" instead. + */ + public function testEncodeWithArgon2idSupportOnly() + { + if (!Argon2iPasswordEncoder::isSupported() || !Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + $this->markTestSkipped('Argon2id algorithm not available.'); + } + + $encoder = new Argon2iPasswordEncoder(); + $result = $encoder->encodePassword(self::PASSWORD, null); + $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, null)); + $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); + } } From b9e2046821b13e499b0c16cd15bdbd5be2a2942c Mon Sep 17 00:00:00 2001 From: Denis Brumann <denis.brumann@sensiolabs.de> Date: Mon, 8 Apr 2019 21:51:36 +0200 Subject: [PATCH 455/495] Fixes sprintf unmapped parameter. --- src/Symfony/Component/HttpClient/HttpClientTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 678d9d05b48a5..3c229bfca9ea5 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -294,7 +294,7 @@ private static function jsonEncode($value, int $flags = null, int $maxDepth = 51 $flags = $flags ?? (JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_PRESERVE_ZERO_FRACTION); if (!\is_array($value) && !$value instanceof \JsonSerializable) { - throw new InvalidArgumentException(sprintf('Option "json" must be array or JsonSerializable, %s given.', __CLASS__, \is_object($value) ? \get_class($value) : \gettype($value))); + throw new InvalidArgumentException(sprintf('Option "json" must be array or JsonSerializable, %s given.', \is_object($value) ? \get_class($value) : \gettype($value))); } try { From 529211d7eded6592ba769b105ff663064b0a3201 Mon Sep 17 00:00:00 2001 From: Robin Chalas <robin.chalas@elao.com> Date: Mon, 8 Apr 2019 19:01:45 +0200 Subject: [PATCH 456/495] [Security] Replace Argon2*PasswordEncoder by SodiumPasswordEncoder This reverts commit dc95a6fec6d44e1dfcd7ab5895d6e68bf71676bb. --- UPGRADE-4.3.md | 6 +- UPGRADE-5.0.md | 6 +- .../Bundle/SecurityBundle/CHANGELOG.md | 4 +- .../DependencyInjection/SecurityExtension.php | 21 ++--- .../CompleteConfigurationTest.php | 25 +++--- ...rgon2id_encoder.php => sodium_encoder.php} | 5 +- ...rgon2id_encoder.xml => sodium_encoder.xml} | 2 +- .../Fixtures/yml/argon2id_encoder.yml | 10 --- .../Fixtures/yml/sodium_encoder.yml | 7 ++ .../UserPasswordEncoderCommandTest.php | 45 +++++----- .../app/PasswordEncode/argon2id.yml | 7 -- .../Functional/app/PasswordEncode/sodium.yml | 7 ++ src/Symfony/Component/Security/CHANGELOG.md | 4 +- .../Security/Core/Encoder/Argon2Trait.php | 52 ----------- .../Core/Encoder/Argon2iPasswordEncoder.php | 68 +++++++++----- .../Core/Encoder/Argon2idPasswordEncoder.php | 88 ------------------- .../Security/Core/Encoder/EncoderFactory.php | 16 ++-- .../Core/Encoder/SodiumPasswordEncoder.php | 84 ++++++++++++++++++ .../Encoder/Argon2iPasswordEncoderTest.php | 43 ++------- ...Test.php => SodiumPasswordEncoderTest.php} | 24 ++--- 20 files changed, 223 insertions(+), 301 deletions(-) rename src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/{argon2id_encoder.php => sodium_encoder.php} (57%) rename src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/{argon2id_encoder.xml => sodium_encoder.xml} (89%) delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml delete mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml delete mode 100644 src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php delete mode 100644 src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php create mode 100644 src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php rename src/Symfony/Component/Security/Core/Tests/Encoder/{Argon2idPasswordEncoderTest.php => SodiumPasswordEncoderTest.php} (64%) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 7442600260a8c..1191a75218d7e 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -151,14 +151,12 @@ Security } ``` - * Using `Argon2iPasswordEncoder` while only the `argon2id` algorithm is supported - is deprecated, use `Argon2idPasswordEncoder` instead + * The `Argon2iPasswordEncoder` class has been deprecated, use `SodiumPasswordEncoder` instead. SecurityBundle -------------- - * Configuring encoders using `argon2i` as algorithm while only `argon2id` is - supported is deprecated, use `argon2id` instead + * Configuring encoders using `argon2i` as algorithm has been deprecated, use `sodium` instead. TwigBridge ---------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index b163e76678286..fbcc53cf4ac6b 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -326,8 +326,7 @@ Security } ``` - * Using `Argon2iPasswordEncoder` while only the `argon2id` algorithm is supported - now throws a `\LogicException`, use `Argon2idPasswordEncoder` instead + * The `Argon2iPasswordEncoder` class has been removed, use `SodiumPasswordEncoder` instead. SecurityBundle -------------- @@ -348,8 +347,7 @@ SecurityBundle changed to underscores. Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore). After: `my-cookie` deletes the `my-cookie` cookie (with a dash). - * Configuring encoders using `argon2i` as algorithm while only `argon2id` is supported - now throws a `\LogicException`, use `argon2id` instead + * Configuring encoders using `argon2i` as algorithm is not supported anymore, use `sodium` instead. Serializer ---------- diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index fd0edcb7dd8e2..28bbd1286e021 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -8,9 +8,7 @@ CHANGELOG option is deprecated and will be disabled in Symfony 5.0. This affects to cookies with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie` name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore). - * Deprecated configuring encoders using `argon2i` as algorithm while only `argon2id` is supported, - use `argon2id` instead - + * Deprecated configuring encoders using `argon2i` as algorithm, use `sodium` instead 4.2.0 ----- diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index dd7fe75cc8b19..4519b66a94313 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -29,8 +29,8 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; -use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; +use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Controller\UserValueResolver; use Symfony\Component\Templating\PhpEngine; @@ -565,14 +565,14 @@ private function createEncoder($config, ContainerBuilder $container) // Argon2i encoder if ('argon2i' === $config['algorithm']) { + @trigger_error('Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "sodium" instead.', E_USER_DEPRECATED); + if (!Argon2iPasswordEncoder::isSupported()) { if (\extension_loaded('sodium') && !\defined('SODIUM_CRYPTO_PWHASH_SALTBYTES')) { throw new InvalidConfigurationException('The installed libsodium version does not have support for Argon2i. Use Bcrypt instead.'); } throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.'); - } elseif (!\defined('PASSWORD_ARGON2I') && Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - @trigger_error('Configuring an encoder based on the "argon2i" algorithm while only "argon2id" is supported is deprecated since Symfony 4.3, use "argon2id" instead.', E_USER_DEPRECATED); } return [ @@ -585,19 +585,14 @@ private function createEncoder($config, ContainerBuilder $container) ]; } - // Argon2id encoder - if ('argon2id' === $config['algorithm']) { - if (!Argon2idPasswordEncoder::isSupported()) { - throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.'); + if ('sodium' === $config['algorithm']) { + if (!SodiumPasswordEncoder::isSupported()) { + throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use BCrypt instead.'); } return [ - 'class' => Argon2idPasswordEncoder::class, - 'arguments' => [ - $config['memory_cost'], - $config['time_cost'], - $config['threads'], - ], + 'class' => SodiumPasswordEncoder::class, + 'arguments' => [], ]; } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index 5c95500dc3dd3..0727c79a52139 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -18,8 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; -use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; +use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; abstract class CompleteConfigurationTest extends TestCase { @@ -314,11 +314,11 @@ public function testEncoders() public function testEncodersWithLibsodium() { - if (!Argon2iPasswordEncoder::isSupported() || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); + if (!SodiumPasswordEncoder::isSupported()) { + $this->markTestSkipped('Libsodium is not available.'); } - $container = $this->getContainer('argon2i_encoder'); + $container = $this->getContainer('sodium_encoder'); $this->assertEquals([[ 'JMS\FooBundle\Entity\User1' => [ @@ -359,19 +359,24 @@ public function testEncodersWithLibsodium() 'arguments' => [15], ], 'JMS\FooBundle\Entity\User7' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder', - 'arguments' => [256, 1, 2], + 'class' => 'Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder', + 'arguments' => [], ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } - public function testEncodersWithArgon2id() + /** + * @group legacy + * + * @expectedDeprecation Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "sodium" instead. + */ + public function testEncodersWithArgon2i() { - if (!Argon2idPasswordEncoder::isSupported()) { + if (!Argon2iPasswordEncoder::isSupported()) { $this->markTestSkipped('Argon2i algorithm is not supported.'); } - $container = $this->getContainer('argon2id_encoder'); + $container = $this->getContainer('argon2i_encoder'); $this->assertEquals([[ 'JMS\FooBundle\Entity\User1' => [ @@ -412,7 +417,7 @@ public function testEncodersWithArgon2id() 'arguments' => [15], ], 'JMS\FooBundle\Entity\User7' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder', + 'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder', 'arguments' => [256, 1, 2], ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php similarity index 57% rename from src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php rename to src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php index df63deb92eb24..e32969df2353c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2id_encoder.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php @@ -5,10 +5,7 @@ $container->loadFromExtension('security', [ 'encoders' => [ 'JMS\FooBundle\Entity\User7' => [ - 'algorithm' => 'argon2id', - 'memory_cost' => 256, - 'time_cost' => 1, - 'threads' => 2, + 'algorithm' => 'sodium', ], ], ]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml similarity index 89% rename from src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml rename to src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml index 8bb8fa91c9d51..3fb47213009fc 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/argon2id_encoder.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml @@ -10,7 +10,7 @@ </imports> <sec:config> - <sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="argon2id" memory_cost="256" time_cost="1" threads="2" /> + <sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="sodium" /> </sec:config> </container> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml deleted file mode 100644 index f13de5ff63874..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/argon2id_encoder.yml +++ /dev/null @@ -1,10 +0,0 @@ -imports: - - { resource: container1.yml } - -security: - encoders: - JMS\FooBundle\Entity\User7: - algorithm: argon2id - memory_cost: 256 - time_cost: 1 - threads: 2 diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml new file mode 100644 index 0000000000000..175d945b7d1b5 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml @@ -0,0 +1,7 @@ +imports: + - { resource: container1.yml } + +security: + encoders: + JMS\FooBundle\Entity\User7: + algorithm: sodium diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 54d355cf0f3a6..6685d34948907 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -15,11 +15,11 @@ use Symfony\Bundle\SecurityBundle\Command\UserPasswordEncoderCommand; use Symfony\Component\Console\Application as ConsoleApplication; use Symfony\Component\Console\Tester\CommandTester; -use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder; +use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; /** * Tests UserPasswordEncoderCommand. @@ -71,9 +71,12 @@ public function testEncodePasswordBcrypt() $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); } + /** + * @group legacy + */ public function testEncodePasswordArgon2i() { - if (!Argon2iPasswordEncoder::isSupported() || !\defined('PASSWORD_ARGON2I') && Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + if (!Argon2iPasswordEncoder::isSupported()) { $this->markTestSkipped('Argon2i algorithm not available.'); } $this->setupArgon2i(); @@ -87,30 +90,29 @@ public function testEncodePasswordArgon2i() $this->assertContains('Password encoding succeeded', $output); $encoder = new Argon2iPasswordEncoder(); - preg_match('# Encoded password\s+(\$argon2i?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); + preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); $hash = $matches[1]; $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); } - public function testEncodePasswordArgon2id() + public function testEncodePasswordSodium() { - if (!Argon2idPasswordEncoder::isSupported()) { - $this->markTestSkipped('Argon2id algorithm not available.'); + if (!SodiumPasswordEncoder::isSupported()) { + $this->markTestSkipped('Libsodium is not available.'); } - $this->setupArgon2id(); + $this->setupSodium(); $this->passwordEncoderCommandTester->execute([ 'command' => 'security:encode-password', 'password' => 'password', - 'user-class' => 'Custom\Class\Argon2id\User', + 'user-class' => 'Custom\Class\Sodium\User', ], ['interactive' => false]); $output = $this->passwordEncoderCommandTester->getDisplay(); $this->assertContains('Password encoding succeeded', $output); - $encoder = new Argon2idPasswordEncoder(); - preg_match('# Encoded password\s+(\$argon2id?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); + preg_match('# Encoded password\s+(\$?\$[\w,=\$+\/]+={0,2})\s+#', $output, $matches); $hash = $matches[1]; - $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); + $this->assertTrue((new SodiumPasswordEncoder())->isPasswordValid($hash, 'password', null)); } public function testEncodePasswordPbkdf2() @@ -173,10 +175,13 @@ public function testEncodePasswordBcryptOutput() $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); } + /** + * @group legacy + */ public function testEncodePasswordArgon2iOutput() { - if (!Argon2iPasswordEncoder::isSupported() || !\defined('PASSWORD_ARGON2I') && Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - $this->markTestSkipped('Argon2id algorithm not available.'); + if (!Argon2iPasswordEncoder::isSupported()) { + $this->markTestSkipped('Argon2i algorithm not available.'); } $this->setupArgon2i(); @@ -189,17 +194,17 @@ public function testEncodePasswordArgon2iOutput() $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); } - public function testEncodePasswordArgon2idOutput() + public function testEncodePasswordSodiumOutput() { - if (!Argon2idPasswordEncoder::isSupported()) { - $this->markTestSkipped('Argon2id algorithm not available.'); + if (!SodiumPasswordEncoder::isSupported()) { + $this->markTestSkipped('Libsodium is not available.'); } - $this->setupArgon2id(); + $this->setupSodium(); $this->passwordEncoderCommandTester->execute([ 'command' => 'security:encode-password', 'password' => 'p@ssw0rd', - 'user-class' => 'Custom\Class\Argon2id\User', + 'user-class' => 'Custom\Class\Sodium\User', ], ['interactive' => false]); $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); @@ -298,10 +303,10 @@ private function setupArgon2i() $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); } - private function setupArgon2id() + private function setupSodium() { putenv('COLUMNS='.(119 + \strlen(PHP_EOL))); - $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2id.yml']); + $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'sodium.yml']); $kernel->boot(); $application = new Application($kernel); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml deleted file mode 100644 index 481262acb7e6c..0000000000000 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/argon2id.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: config.yml } - -security: - encoders: - Custom\Class\Argon2id\User: - algorithm: argon2id diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml new file mode 100644 index 0000000000000..1ccc2a10d5f6e --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/sodium.yml @@ -0,0 +1,7 @@ +imports: + - { resource: config.yml } + +security: + encoders: + Custom\Class\Sodium\User: + algorithm: sodium diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 776774e5b6e3a..42aca94dd0738 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -19,9 +19,7 @@ CHANGELOG * Dispatch `AuthenticationFailureEvent` on `security.authentication.failure` * Dispatch `InteractiveLoginEvent` on `security.interactive_login` * Dispatch `SwitchUserEvent` on `security.switch_user` - * Added `Argon2idPasswordEncoder` - * Deprecated using `Argon2iPasswordEncoder` while only the `argon2id` algorithm - is supported, use `Argon2idPasswordEncoder` instead + * deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` instead 4.2.0 ----- diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php b/src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php deleted file mode 100644 index de14becf47378..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2Trait.php +++ /dev/null @@ -1,52 +0,0 @@ -<?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\Component\Security\Core\Encoder; - -/** - * @internal - * - * @author Robin Chalas <robin.chalas@gmail.com> - */ -trait Argon2Trait -{ - private $memoryCost; - private $timeCost; - private $threads; - - public function __construct(int $memoryCost = null, int $timeCost = null, int $threads = null) - { - $this->memoryCost = $memoryCost; - $this->timeCost = $timeCost; - $this->threads = $threads; - } - - private function encodePasswordNative(string $raw, int $algorithm) - { - return password_hash($raw, $algorithm, [ - 'memory_cost' => $this->memoryCost ?? \PASSWORD_ARGON2_DEFAULT_MEMORY_COST, - 'time_cost' => $this->timeCost ?? \PASSWORD_ARGON2_DEFAULT_TIME_COST, - 'threads' => $this->threads ?? \PASSWORD_ARGON2_DEFAULT_THREADS, - ]); - } - - private function encodePasswordSodiumFunction(string $raw) - { - $hash = \sodium_crypto_pwhash_str( - $raw, - \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, - \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE - ); - \sodium_memzero($raw); - - return $hash; - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php index b1add537632c6..d7b53d34b0854 100644 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/Argon2iPasswordEncoder.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Security\Core\Encoder; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Argon2iPasswordEncoder::class, SodiumPasswordEncoder::class), E_USER_DEPRECATED); + use Symfony\Component\Security\Core\Exception\BadCredentialsException; /** @@ -18,10 +20,30 @@ * * @author Zan Baldwin <hello@zanbaldwin.com> * @author Dominik Müller <dominik.mueller@jkweb.ch> + * + * @deprecated since Symfony 4.3, use SodiumPasswordEncoder instead */ class Argon2iPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface { - use Argon2Trait; + private $config = []; + + /** + * Argon2iPasswordEncoder constructor. + * + * @param int|null $memoryCost memory usage of the algorithm + * @param int|null $timeCost number of iterations + * @param int|null $threads number of parallel threads + */ + public function __construct(int $memoryCost = null, int $timeCost = null, int $threads = null) + { + if (\defined('PASSWORD_ARGON2I')) { + $this->config = [ + 'memory_cost' => $memoryCost ?? \PASSWORD_ARGON2_DEFAULT_MEMORY_COST, + 'time_cost' => $timeCost ?? \PASSWORD_ARGON2_DEFAULT_TIME_COST, + 'threads' => $threads ?? \PASSWORD_ARGON2_DEFAULT_THREADS, + ]; + } + } public static function isSupported() { @@ -46,12 +68,9 @@ public function encodePassword($raw, $salt) } if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { - return $this->encodePasswordNative($raw, \PASSWORD_ARGON2I); - } elseif (\function_exists('sodium_crypto_pwhash_str')) { - if (Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - @trigger_error(sprintf('Using "%s" while only the "argon2id" algorithm is supported is deprecated since Symfony 4.3, use "%s" instead.', __CLASS__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); - } - + return $this->encodePasswordNative($raw); + } + if (\function_exists('sodium_crypto_pwhash_str')) { return $this->encodePasswordSodiumFunction($raw); } if (\extension_loaded('libsodium')) { @@ -66,20 +85,10 @@ public function encodePassword($raw, $salt) */ public function isPasswordValid($encoded, $raw, $salt) { - if ($this->isPasswordTooLong($raw)) { - return false; - } - - // If $encoded was created via "sodium_crypto_pwhash_str()", the hashing algorithm may be "argon2id" instead of "argon2i" - if ($isArgon2id = (0 === strpos($encoded, Argon2idPasswordEncoder::HASH_PREFIX))) { - @trigger_error(sprintf('Calling "%s()" with a password hashed using argon2id is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Argon2idPasswordEncoder::class), E_USER_DEPRECATED); - } - - if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I')) { - // Remove the right part of the OR in 5.0 - if (\defined('PASSWORD_ARGON2I') || $isArgon2id && \defined('PASSWORD_ARGON2ID')) { - return password_verify($raw, $encoded); - } + // If $encoded was created via "sodium_crypto_pwhash_str()", the hashing algorithm may be "argon2id" instead of "argon2i". + // In this case, "password_verify()" cannot be used. + if (\PHP_VERSION_ID >= 70200 && \defined('PASSWORD_ARGON2I') && (false === strpos($encoded, '$argon2id$'))) { + return !$this->isPasswordTooLong($raw) && password_verify($raw, $encoded); } if (\function_exists('sodium_crypto_pwhash_str_verify')) { $valid = !$this->isPasswordTooLong($raw) && \sodium_crypto_pwhash_str_verify($encoded, $raw); @@ -97,6 +106,23 @@ public function isPasswordValid($encoded, $raw, $salt) throw new \LogicException('Argon2i algorithm is not supported. Please install the libsodium extension or upgrade to PHP 7.2+.'); } + private function encodePasswordNative($raw) + { + return password_hash($raw, \PASSWORD_ARGON2I, $this->config); + } + + private function encodePasswordSodiumFunction($raw) + { + $hash = \sodium_crypto_pwhash_str( + $raw, + \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE + ); + \sodium_memzero($raw); + + return $hash; + } + private function encodePasswordSodiumExtension($raw) { $hash = \Sodium\crypto_pwhash_str( diff --git a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php deleted file mode 100644 index a201bca36b936..0000000000000 --- a/src/Symfony/Component/Security/Core/Encoder/Argon2idPasswordEncoder.php +++ /dev/null @@ -1,88 +0,0 @@ -<?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\Component\Security\Core\Encoder; - -use Symfony\Component\Security\Core\Exception\BadCredentialsException; -use Symfony\Component\Security\Core\Exception\LogicException; - -/** - * Hashes passwords using the Argon2id algorithm. - * - * @author Robin Chalas <robin.chalas@gmail.com> - * - * @final - */ -class Argon2idPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface -{ - use Argon2Trait; - - /** - * @internal - */ - public const HASH_PREFIX = '$argon2id'; - - public static function isSupported() - { - return \defined('PASSWORD_ARGON2ID') || \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13'); - } - - /** - * {@inheritdoc} - */ - public function encodePassword($raw, $salt) - { - if ($this->isPasswordTooLong($raw)) { - throw new BadCredentialsException('Invalid password.'); - } - if (\defined('PASSWORD_ARGON2ID')) { - return $this->encodePasswordNative($raw, \PASSWORD_ARGON2ID); - } - if (!self::isDefaultSodiumAlgorithm()) { - throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); - } - - return $this->encodePasswordSodiumFunction($raw); - } - - /** - * {@inheritdoc} - */ - public function isPasswordValid($encoded, $raw, $salt) - { - if (0 !== strpos($encoded, self::HASH_PREFIX)) { - return false; - } - - if (\defined('PASSWORD_ARGON2ID')) { - return !$this->isPasswordTooLong($raw) && password_verify($raw, $encoded); - } - - if (\function_exists('sodium_crypto_pwhash_str_verify')) { - $valid = !$this->isPasswordTooLong($raw) && \sodium_crypto_pwhash_str_verify($encoded, $raw); - \sodium_memzero($raw); - - return $valid; - } - - throw new LogicException('Algorithm "argon2id" is not supported. Please install the libsodium extension or upgrade to PHP 7.3+.'); - } - - /** - * @internal - */ - public static function isDefaultSodiumAlgorithm() - { - return \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') - && \defined('SODIUM_CRYPTO_PWHASH_ALG_DEFAULT') - && \SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13 === \SODIUM_CRYPTO_PWHASH_ALG_DEFAULT; - } -} diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index c5770b1e58226..01dd33f053de6 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -108,18 +108,16 @@ private function getEncoderConfigFromAlgorithm($config) 'arguments' => [$config['cost']], ]; - case 'argon2i': + case 'sodium': return [ - 'class' => Argon2iPasswordEncoder::class, - 'arguments' => [ - $config['memory_cost'], - $config['time_cost'], - $config['threads'], - ], + 'class' => SodiumPasswordEncoder::class, + 'arguments' => [], ]; - case 'argon2id': + + /* @deprecated since Symfony 4.3 */ + case 'argon2i': return [ - 'class' => Argon2idPasswordEncoder::class, + 'class' => Argon2iPasswordEncoder::class, 'arguments' => [ $config['memory_cost'], $config['time_cost'], diff --git a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php new file mode 100644 index 0000000000000..febca05dd0f39 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php @@ -0,0 +1,84 @@ +<?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\Component\Security\Core\Encoder; + +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\Exception\LogicException; + +/** + * Hashes passwords using libsodium. + * + * @author Robin Chalas <robin.chalas@gmail.com> + * @author Zan Baldwin <hello@zanbaldwin.com> + * @author Dominik Müller <dominik.mueller@jkweb.ch> + * + * @final + */ +class SodiumPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface +{ + public static function isSupported(): bool + { + if (\class_exists('ParagonIE_Sodium_Compat') && \method_exists('ParagonIE_Sodium_Compat', 'crypto_pwhash_is_available')) { + return \ParagonIE_Sodium_Compat::crypto_pwhash_is_available(); + } + + return \function_exists('sodium_crypto_pwhash_str') || \extension_loaded('libsodium'); + } + + /** + * {@inheritdoc} + */ + public function encodePassword($raw, $salt) + { + if ($this->isPasswordTooLong($raw)) { + throw new BadCredentialsException('Invalid password.'); + } + + if (\function_exists('sodium_crypto_pwhash_str')) { + return \sodium_crypto_pwhash_str( + $raw, + \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE + ); + } + + if (\extension_loaded('libsodium')) { + return \Sodium\crypto_pwhash_str( + $raw, + \Sodium\CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, + \Sodium\CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE + ); + } + + throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.'); + } + + /** + * {@inheritdoc} + */ + public function isPasswordValid($encoded, $raw, $salt) + { + if ($this->isPasswordTooLong($raw)) { + return false; + } + + if (\function_exists('sodium_crypto_pwhash_str_verify')) { + return \sodium_crypto_pwhash_str_verify($encoded, $raw); + } + + if (\extension_loaded('libsodium')) { + return \Sodium\crypto_pwhash_str_verify($encoded, $raw); + } + + throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.'); + } +} diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php index 88f10b446d723..a9991749f01fd 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2iPasswordEncoderTest.php @@ -12,22 +12,26 @@ namespace Symfony\Component\Security\Core\Tests\Encoder; use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; /** * @author Zan Baldwin <hello@zanbaldwin.com> + * + * @group legacy */ class Argon2iPasswordEncoderTest extends TestCase { const PASSWORD = 'password'; - public function testValidationWithConfig() + protected function setUp() { - if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { + if (!Argon2iPasswordEncoder::isSupported()) { $this->markTestSkipped('Argon2i algorithm is not supported.'); } + } + public function testValidationWithConfig() + { $encoder = new Argon2iPasswordEncoder(8, 4, 1); $result = $encoder->encodePassword(self::PASSWORD, null); $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, null)); @@ -36,10 +40,6 @@ public function testValidationWithConfig() public function testValidation() { - if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); - } - $encoder = new Argon2iPasswordEncoder(); $result = $encoder->encodePassword(self::PASSWORD, null); $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, null)); @@ -51,20 +51,12 @@ public function testValidation() */ public function testEncodePasswordLength() { - if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); - } - $encoder = new Argon2iPasswordEncoder(); $encoder->encodePassword(str_repeat('a', 4097), 'salt'); } public function testCheckPasswordLength() { - if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); - } - $encoder = new Argon2iPasswordEncoder(); $result = $encoder->encodePassword(str_repeat('a', 4096), null); $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 4097), null)); @@ -73,29 +65,8 @@ public function testCheckPasswordLength() public function testUserProvidedSaltIsNotUsed() { - if (!Argon2iPasswordEncoder::isSupported() || Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); - } - $encoder = new Argon2iPasswordEncoder(); $result = $encoder->encodePassword(self::PASSWORD, 'salt'); $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, 'anotherSalt')); } - - /** - * @group legacy - * @exectedDeprecation Using "Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder" while only the "argon2id" algorithm is supported is deprecated since Symfony 4.3, use "Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder" instead. - * @exectedDeprecation Calling "Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder::isPasswordValid()" with a password hashed using argon2id is deprecated since Symfony 4.3, use "Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder" instead. - */ - public function testEncodeWithArgon2idSupportOnly() - { - if (!Argon2iPasswordEncoder::isSupported() || !Argon2idPasswordEncoder::isDefaultSodiumAlgorithm()) { - $this->markTestSkipped('Argon2id algorithm not available.'); - } - - $encoder = new Argon2iPasswordEncoder(); - $result = $encoder->encodePassword(self::PASSWORD, null); - $this->assertTrue($encoder->isPasswordValid($result, self::PASSWORD, null)); - $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); - } } diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/SodiumPasswordEncoderTest.php similarity index 64% rename from src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php rename to src/Symfony/Component/Security/Core/Tests/Encoder/SodiumPasswordEncoderTest.php index 460777c124f5f..fe9e5db0eb4cb 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/Argon2idPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/SodiumPasswordEncoderTest.php @@ -12,28 +12,20 @@ namespace Symfony\Component\Security\Core\Tests\Encoder; use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Encoder\Argon2idPasswordEncoder; +use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; -class Argon2idPasswordEncoderTest extends TestCase +class SodiumPasswordEncoderTest extends TestCase { protected function setUp() { - if (!Argon2idPasswordEncoder::isSupported()) { - $this->markTestSkipped('Argon2i algorithm is not supported.'); + if (!SodiumPasswordEncoder::isSupported()) { + $this->markTestSkipped('Libsodium is not available.'); } } - public function testValidationWithConfig() - { - $encoder = new Argon2idPasswordEncoder(8, 4, 1); - $result = $encoder->encodePassword('password', null); - $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); - $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); - } - public function testValidation() { - $encoder = new Argon2idPasswordEncoder(); + $encoder = new SodiumPasswordEncoder(); $result = $encoder->encodePassword('password', null); $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); @@ -44,13 +36,13 @@ public function testValidation() */ public function testEncodePasswordLength() { - $encoder = new Argon2idPasswordEncoder(); + $encoder = new SodiumPasswordEncoder(); $encoder->encodePassword(str_repeat('a', 4097), 'salt'); } public function testCheckPasswordLength() { - $encoder = new Argon2idPasswordEncoder(); + $encoder = new SodiumPasswordEncoder(); $result = $encoder->encodePassword(str_repeat('a', 4096), null); $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 4097), null)); $this->assertTrue($encoder->isPasswordValid($result, str_repeat('a', 4096), null)); @@ -58,7 +50,7 @@ public function testCheckPasswordLength() public function testUserProvidedSaltIsNotUsed() { - $encoder = new Argon2idPasswordEncoder(); + $encoder = new SodiumPasswordEncoder(); $result = $encoder->encodePassword('password', 'salt'); $this->assertTrue($encoder->isPasswordValid($result, 'password', 'anotherSalt')); } From e77108d24ee1fd0915129c2d2b312f2f52ccb4b1 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera <pol.dellaiera@protonmail.com> Date: Mon, 8 Apr 2019 20:49:29 +0200 Subject: [PATCH 457/495] [HttpClient] Add tests - update code style nits. --- .../HttpClient/CachingHttpClient.php | 2 +- .../Component/HttpClient/CurlHttpClient.php | 6 ++- .../Component/HttpClient/HttpClientTrait.php | 3 +- .../Component/HttpClient/HttpOptions.php | 1 + .../Component/HttpClient/MockHttpClient.php | 2 +- .../Component/HttpClient/NativeHttpClient.php | 12 +----- .../HttpClient/Tests/HttpClientTraitTest.php | 38 +++++++++++++++++++ 7 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CachingHttpClient.php b/src/Symfony/Component/HttpClient/CachingHttpClient.php index 143c5cdc03e25..3abf3113beac4 100644 --- a/src/Symfony/Component/HttpClient/CachingHttpClient.php +++ b/src/Symfony/Component/HttpClient/CachingHttpClient.php @@ -71,7 +71,7 @@ public function request(string $method, string $url, array $options = []): Respo $url = implode('', $url); $options['extra']['no_cache'] = $options['extra']['no_cache'] ?? !$options['buffer']; - if ($options['extra']['no_cache'] || !empty($options['body']) || !\in_array($method, ['GET', 'HEAD', 'OPTIONS'])) { + if (!empty($options['body']) || $options['extra']['no_cache'] || !\in_array($method, ['GET', 'HEAD', 'OPTIONS'])) { return $this->client->request($method, $url, $options); } diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index a6761e23e8a27..f59069349e6f1 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -48,6 +48,10 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface */ public function __construct(array $defaultOptions = [], int $maxHostConnections = 6, int $maxPendingPushes = 50) { + if (!\extension_loaded('curl')) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\CurlHttpClient" as the "curl" extension is not installed.'); + } + if ($defaultOptions) { [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } @@ -109,7 +113,7 @@ public function request(string $method, string $url, array $options = []): Respo $options['headers']['range'] ?? null, ]; - if ('GET' === $method && !$options['body'] && $expectedHeaders === $pushedHeaders) { + if ('GET' === $method && $expectedHeaders === $pushedHeaders && !$options['body']) { $this->logger && $this->logger->debug(sprintf('Connecting request to pushed response: "%s %s"', $method, $url)); // Reinitialize the pushed response with request's options diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 3c229bfca9ea5..32e940ac736b9 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpClient; use Symfony\Component\HttpClient\Exception\InvalidArgumentException; -use Symfony\Contracts\HttpClient\HttpClientInterface; /** * Provides the common logic from writing HttpClientInterface implementations. @@ -278,7 +277,7 @@ private static function normalizePeerFingerprint($fingerprint): array $fingerprint[$algo] = 'pin-sha256' === $algo ? (array) $hash : str_replace(':', '', $hash); } } else { - throw new InvalidArgumentException(sprintf('Option "peer_fingerprint" must be string or array, %s given.', \gettype($body))); + throw new InvalidArgumentException(sprintf('Option "peer_fingerprint" must be string or array, %s given.', \gettype($fingerprint))); } return $fingerprint; diff --git a/src/Symfony/Component/HttpClient/HttpOptions.php b/src/Symfony/Component/HttpClient/HttpOptions.php index 85b55f0d08525..60df9ac300a21 100644 --- a/src/Symfony/Component/HttpClient/HttpOptions.php +++ b/src/Symfony/Component/HttpClient/HttpOptions.php @@ -37,6 +37,7 @@ public function toArray(): array public function setAuthBasic(string $user, string $password = '') { $this->options['auth_basic'] = $user; + if ('' !== $password) { $this->options['auth_basic'] .= ':'.$password; } diff --git a/src/Symfony/Component/HttpClient/MockHttpClient.php b/src/Symfony/Component/HttpClient/MockHttpClient.php index 41bb20b299f16..987f04211fbdf 100644 --- a/src/Symfony/Component/HttpClient/MockHttpClient.php +++ b/src/Symfony/Component/HttpClient/MockHttpClient.php @@ -39,7 +39,7 @@ public function __construct($responseFactory = null, string $baseUri = null) $responseFactory = [$responseFactory]; } - if (null !== $responseFactory && !\is_callable($responseFactory) && !$responseFactory instanceof \Iterator) { + if (!$responseFactory instanceof \Iterator && null !== $responseFactory && !\is_callable($responseFactory)) { $responseFactory = (static function () use ($responseFactory) { yield from $responseFactory; })(); diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index 03eaeac107e51..18afa2d13e59d 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -400,17 +400,9 @@ private static function configureHeadersAndProxy($context, string $host, array $ // Matching "no_proxy" should follow the behavior of curl foreach ($noProxy as $rule) { - if ('*' === $rule) { - return stream_context_set_option($context, 'http', 'header', $requestHeaders); - } - - if ($host === $rule) { - return stream_context_set_option($context, 'http', 'header', $requestHeaders); - } - - $rule = '.'.ltrim($rule, '.'); + $dotRule = '.'.ltrim($rule, '.'); - if (substr($host, -\strlen($rule)) === $rule) { + if ('*' === $rule || $host === $rule || substr($host, -\strlen($dotRule)) === $dotRule) { return stream_context_set_option($context, 'http', 'header', $requestHeaders); } } diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php index 5c35bdd320aa4..0a08abec30395 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -215,4 +215,42 @@ public function testPrepareAuthBasic($arg, $result) [, $options] = $this->prepareRequest('POST', 'http://example.com', ['auth_basic' => $arg], HttpClientInterface::OPTIONS_DEFAULTS); $this->assertSame('Basic '.$result, $options['headers']['authorization'][0]); } + + public function provideFingerprints() + { + foreach (['md5', 'sha1', 'sha256'] as $algo) { + $hash = \hash($algo, $algo); + yield [$hash, [$algo => $hash]]; + } + + yield ['AAAA:BBBB:CCCC:DDDD:EEEE:FFFF:GGGG:HHHH:IIII:JJJJ:KKKK', ['pin-sha256' => ['AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKK']]]; + } + + /** + * @dataProvider provideFingerprints + */ + public function testNormalizePeerFingerprint($fingerprint, $expected) + { + self::assertSame($expected, $this->normalizePeerFingerprint($fingerprint)); + } + + /** + * @expectedException \Symfony\Component\HttpClient\Exception\InvalidArgumentException + * @expectedExceptionMessage Cannot auto-detect fingerprint algorithm for "foo". + */ + public function testNormalizePeerFingerprintException() + { + $this->normalizePeerFingerprint('foo'); + } + + /** + * @expectedException \Symfony\Component\HttpClient\Exception\InvalidArgumentException + * @expectedExceptionMessage Option "peer_fingerprint" must be string or array, object given. + */ + public function testNormalizePeerFingerprintTypeException() + { + $fingerprint = new \stdClass(); + + $this->normalizePeerFingerprint($fingerprint); + } } From ff6bc79eba5cc17bf86dc90ec22537bad7b1c522 Mon Sep 17 00:00:00 2001 From: Gregor Harlan <mail@gh01.de> Date: Tue, 9 Apr 2019 01:07:36 +0200 Subject: [PATCH 458/495] Deprecate TreeBuilder::root --- UPGRADE-4.3.md | 1 + UPGRADE-5.0.md | 1 + src/Symfony/Component/Config/CHANGELOG.md | 1 + .../Config/Definition/Builder/TreeBuilder.php | 7 ++++++- .../Tests/Definition/Builder/TreeBuilderTest.php | 10 ++++++++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 1191a75218d7e..873dc682569b1 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -20,6 +20,7 @@ Config ------ * Deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` + * Deprecated the `root()` method in `TreeBuilder`, pass the root node information to the constructor instead DependencyInjection ------------------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index fbcc53cf4ac6b..e90d60b60e3cf 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -25,6 +25,7 @@ Config * The `Processor` class has been made final * Removed `FileLoaderLoadException`, use `LoaderLoadException` instead. * Using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` will throw an exception. + * Removed the `root()` method in `TreeBuilder`, pass the root node information to the constructor instead Console ------- diff --git a/src/Symfony/Component/Config/CHANGELOG.md b/src/Symfony/Component/Config/CHANGELOG.md index 122184021c3bf..4d15e9aedae8b 100644 --- a/src/Symfony/Component/Config/CHANGELOG.md +++ b/src/Symfony/Component/Config/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` * made `Resource\*` classes final and not implement `Serializable` anymore + * deprecated the `root()` method in `TreeBuilder`, pass the root node information to the constructor instead 4.2.0 ----- diff --git a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php index 71e7976da7b8f..9a3b0351d2490 100644 --- a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php +++ b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php @@ -29,7 +29,8 @@ public function __construct(string $name = null, string $type = 'array', NodeBui if (null === $name) { @trigger_error('A tree builder without a root node is deprecated since Symfony 4.2 and will not be supported anymore in 5.0.', E_USER_DEPRECATED); } else { - $this->root($name, $type, $builder); + $builder = $builder ?: new NodeBuilder(); + $this->root = $builder->node($name, $type)->setParent($this); } } @@ -43,9 +44,13 @@ public function __construct(string $name = null, string $type = 'array', NodeBui * @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array') * * @throws \RuntimeException When the node type is not supported + * + * @deprecated since Symfony 4.3, pass the root name to the constructor instead */ public function root($name, $type = 'array', NodeBuilder $builder = null) { + @trigger_error(sprintf('The "%s()" method called for the "%s" configuration is deprecated since Symfony 4.3, pass the root name to the constructor instead.', __METHOD__, $name), E_USER_DEPRECATED); + $builder = $builder ?: new NodeBuilder(); return $this->root = $builder->node($name, $type)->setParent($this); diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php index 0dae83be41d9c..d0e3d2d52d4b5 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/TreeBuilderTest.php @@ -197,4 +197,14 @@ public function testInitializingTreeBuildersWithoutRootNode() { new TreeBuilder(); } + + /** + * @group legacy + * @expectedDeprecation The "Symfony\Component\Config\Definition\Builder\TreeBuilder::root()" method called for the "foo" configuration is deprecated since Symfony 4.3, pass the root name to the constructor instead. + */ + public function testRoot() + { + $builder = new TreeBuilder('foo'); + $builder->root('foo'); + } } From 4693422642b7faa0470b5d97e879445a2299e8c2 Mon Sep 17 00:00:00 2001 From: Mikkel Paulson <mikkel.paulson@lightspeedpos.com> Date: Tue, 9 Apr 2019 14:49:00 -0400 Subject: [PATCH 459/495] Improve test coverage from #30997 Test coverage added in #30997 did a good job of validating previous behaviour, but didn't adequately cover the new callback logic. Added coverage for new methods on the Question object. --- .../Console/Tests/Question/QuestionTest.php | 75 +++++++++++++++---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/Console/Tests/Question/QuestionTest.php b/src/Symfony/Component/Console/Tests/Question/QuestionTest.php index 537cd30144e6a..13c8e362e1457 100644 --- a/src/Symfony/Component/Console/Tests/Question/QuestionTest.php +++ b/src/Symfony/Component/Console/Tests/Question/QuestionTest.php @@ -60,9 +60,11 @@ public function testIsHiddenDefault() self::assertFalse($this->question->isHidden()); } - public function testSetHiddenWithAutocompleterValues() + public function testSetHiddenWithAutocompleterCallback() { - $this->question->setAutocompleterValues(['a', 'b']); + $this->question->setAutocompleterCallback( + function (string $input): array { return []; } + ); $this->expectException(\LogicException::class); $this->expectExceptionMessage( @@ -72,10 +74,12 @@ public function testSetHiddenWithAutocompleterValues() $this->question->setHidden(true); } - public function testSetHiddenWithNoAutocompleterValues() + public function testSetHiddenWithNoAutocompleterCallback() { - $this->question->setAutocompleterValues(['a', 'b']); - $this->question->setAutocompleterValues(null); + $this->question->setAutocompleterCallback( + function (string $input): array { return []; } + ); + $this->question->setAutocompleterCallback(null); $exception = null; try { @@ -154,7 +158,51 @@ public function testSetAutocompleterValuesInvalid($values) $this->question->setAutocompleterValues($values); } - public function testSetAutocompleterValuesWhenHidden() + public function testSetAutocompleterValuesWithTraversable() + { + $question1 = new Question('Test question 1'); + $iterator1 = $this->getMockForAbstractClass(\IteratorAggregate::class); + $iterator1 + ->expects($this->once()) + ->method('getIterator') + ->willReturn(new \ArrayIterator(['Potato'])); + $question1->setAutocompleterValues($iterator1); + + $question2 = new Question('Test question 2'); + $iterator2 = $this->getMockForAbstractClass(\IteratorAggregate::class); + $iterator2 + ->expects($this->once()) + ->method('getIterator') + ->willReturn(new \ArrayIterator(['Carrot'])); + $question2->setAutocompleterValues($iterator2); + + // Call multiple times to verify that Traversable result is cached, and + // that there is no crosstalk between cached copies. + self::assertSame(['Potato'], $question1->getAutocompleterValues()); + self::assertSame(['Carrot'], $question2->getAutocompleterValues()); + self::assertSame(['Potato'], $question1->getAutocompleterValues()); + self::assertSame(['Carrot'], $question2->getAutocompleterValues()); + } + + public function testGetAutocompleterValuesDefault() + { + self::assertNull($this->question->getAutocompleterValues()); + } + + public function testGetSetAutocompleterCallback() + { + $callback = function (string $input): array { return []; }; + + $this->question->setAutocompleterCallback($callback); + self::assertSame($callback, $this->question->getAutocompleterCallback()); + } + + public function testGetAutocompleterCallbackDefault() + { + self::assertNull($this->question->getAutocompleterCallback()); + } + + public function testSetAutocompleterCallbackWhenHidden() { $this->question->setHidden(true); @@ -163,17 +211,21 @@ public function testSetAutocompleterValuesWhenHidden() 'A hidden question cannot use the autocompleter.' ); - $this->question->setAutocompleterValues(['a', 'b']); + $this->question->setAutocompleterCallback( + function (string $input): array { return []; } + ); } - public function testSetAutocompleterValuesWhenNotHidden() + public function testSetAutocompleterCallbackWhenNotHidden() { $this->question->setHidden(true); $this->question->setHidden(false); $exception = null; try { - $this->question->setAutocompleterValues(['a', 'b']); + $this->question->setAutocompleterCallback( + function (string $input): array { return []; } + ); } catch (\Exception $exception) { // Do nothing } @@ -181,11 +233,6 @@ public function testSetAutocompleterValuesWhenNotHidden() $this->assertNull($exception); } - public function testGetAutocompleterValuesDefault() - { - self::assertNull($this->question->getAutocompleterValues()); - } - public function providerGetSetValidator() { return [ From 20f4eb32046fc6f21ac1acc58c5ab157d1d698f2 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" <me@derrabus.de> Date: Sun, 7 Apr 2019 11:02:11 +0200 Subject: [PATCH 460/495] Document the state object that is passed around by the HttpClient. --- .../Component/HttpClient/CurlHttpClient.php | 55 +++++++++---------- .../HttpClient/Internal/ClientState.php | 25 +++++++++ .../HttpClient/Internal/CurlClientState.php | 35 ++++++++++++ .../HttpClient/Internal/DnsCache.php | 39 +++++++++++++ .../HttpClient/Internal/NativeClientState.php | 44 +++++++++++++++ .../HttpClient/Internal/PushedResponse.php | 36 ++++++++++++ .../Component/HttpClient/NativeHttpClient.php | 21 +++---- .../HttpClient/Response/CurlResponse.php | 22 ++++---- .../HttpClient/Response/MockResponse.php | 10 ++-- .../HttpClient/Response/NativeResponse.php | 9 ++- .../HttpClient/Response/ResponseTrait.php | 8 ++- 11 files changed, 240 insertions(+), 64 deletions(-) create mode 100644 src/Symfony/Component/HttpClient/Internal/ClientState.php create mode 100644 src/Symfony/Component/HttpClient/Internal/CurlClientState.php create mode 100644 src/Symfony/Component/HttpClient/Internal/DnsCache.php create mode 100644 src/Symfony/Component/HttpClient/Internal/NativeClientState.php create mode 100644 src/Symfony/Component/HttpClient/Internal/PushedResponse.php diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index f59069349e6f1..e28ade68dc7ef 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -15,6 +15,8 @@ use Psr\Log\LoggerAwareTrait; use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\CurlClientState; +use Symfony\Component\HttpClient\Internal\PushedResponse; use Symfony\Component\HttpClient\Response\CurlResponse; use Symfony\Component\HttpClient\Response\ResponseStream; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -37,6 +39,12 @@ final class CurlHttpClient implements HttpClientInterface, LoggerAwareInterface use LoggerAwareTrait; private $defaultOptions = self::OPTIONS_DEFAULTS; + + /** + * An internal object to share state between the client and its responses. + * + * @var CurlClientState + */ private $multi; /** @@ -56,22 +64,13 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } - $mh = curl_multi_init(); + $this->multi = $multi = new CurlClientState(); // Don't enable HTTP/1.1 pipelining: it forces responses to be sent in order if (\defined('CURLPIPE_MULTIPLEX')) { - curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); + curl_multi_setopt($this->multi->handle, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX); } - curl_multi_setopt($mh, CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : PHP_INT_MAX); - - // Use an internal stdClass object to share state between the client and its responses - $this->multi = $multi = (object) [ - 'openHandles' => [], - 'handlesActivity' => [], - 'handle' => $mh, - 'pushedResponses' => [], - 'dnsCache' => [[], [], []], - ]; + curl_multi_setopt($this->multi->handle, CURLMOPT_MAX_HOST_CONNECTIONS, 0 < $maxHostConnections ? $maxHostConnections : PHP_INT_MAX); // Skip configuring HTTP/2 push when it's unsupported or buggy, see https://bugs.php.net/bug.php?id=77535 if (0 >= $maxPendingPushes || \PHP_VERSION_ID < 70217 || (\PHP_VERSION_ID >= 70300 && \PHP_VERSION_ID < 70304)) { @@ -85,7 +84,7 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections $logger = &$this->logger; - curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes, &$logger) { + curl_multi_setopt($this->multi->handle, CURLMOPT_PUSHFUNCTION, static function ($parent, $pushed, array $requestHeaders) use ($multi, $maxPendingPushes, &$logger) { return self::handlePush($parent, $pushed, $requestHeaders, $multi, $maxPendingPushes, $logger); }); } @@ -103,7 +102,7 @@ public function request(string $method, string $url, array $options = []): Respo $host = parse_url($authority, PHP_URL_HOST); $url = implode('', $url); - if ([$pushedResponse, $pushedHeaders] = $this->multi->pushedResponses[$url] ?? null) { + if ($pushedResponse = $this->multi->pushedResponses[$url] ?? null) { unset($this->multi->pushedResponses[$url]); // Accept pushed responses only if their headers related to authentication match the request $expectedHeaders = [ @@ -113,13 +112,13 @@ public function request(string $method, string $url, array $options = []): Respo $options['headers']['range'] ?? null, ]; - if ('GET' === $method && $expectedHeaders === $pushedHeaders && !$options['body']) { + if ('GET' === $method && $expectedHeaders === $pushedResponse->headers && !$options['body']) { $this->logger && $this->logger->debug(sprintf('Connecting request to pushed response: "%s %s"', $method, $url)); // Reinitialize the pushed response with request's options - $pushedResponse->__construct($this->multi, $url, $options, $this->logger); + $pushedResponse->response->__construct($this->multi, $url, $options, $this->logger); - return $pushedResponse; + return $pushedResponse->response; } $this->logger && $this->logger->debug(sprintf('Rejecting pushed response for "%s": authorization headers don\'t match the request', $url)); @@ -159,14 +158,14 @@ public function request(string $method, string $url, array $options = []): Respo } // curl's resolve feature varies by host:port but ours varies by host only, let's handle this with our own DNS map - if (isset($this->multi->dnsCache[0][$host])) { - $options['resolve'] += [$host => $this->multi->dnsCache[0][$host]]; + if (isset($this->multi->dnsCache->hostnames[$host])) { + $options['resolve'] += [$host => $this->multi->dnsCache->hostnames[$host]]; } - if ($options['resolve'] || $this->multi->dnsCache[2]) { + if ($options['resolve'] || $this->multi->dnsCache->evictions) { // First reset any old DNS cache entries then add the new ones - $resolve = $this->multi->dnsCache[2]; - $this->multi->dnsCache[2] = []; + $resolve = $this->multi->dnsCache->evictions; + $this->multi->dnsCache->evictions = []; $port = parse_url($authority, PHP_URL_PORT) ?: ('http:' === $scheme ? 80 : 443); if ($resolve && 0x072a00 > curl_version()['version_number']) { @@ -178,8 +177,8 @@ public function request(string $method, string $url, array $options = []): Respo foreach ($options['resolve'] as $host => $ip) { $resolve[] = null === $ip ? "-$host:$port" : "$host:$port:$ip"; - $this->multi->dnsCache[0][$host] = $ip; - $this->multi->dnsCache[1]["-$host:$port"] = "-$host:$port"; + $this->multi->dnsCache->hostnames[$host] = $ip; + $this->multi->dnsCache->removals["-$host:$port"] = "-$host:$port"; } $curlopts[CURLOPT_RESOLVE] = $resolve; @@ -299,7 +298,7 @@ public function __destruct() } } - private static function handlePush($parent, $pushed, array $requestHeaders, \stdClass $multi, int $maxPendingPushes, ?LoggerInterface $logger): int + private static function handlePush($parent, $pushed, array $requestHeaders, CurlClientState $multi, int $maxPendingPushes, ?LoggerInterface $logger): int { $headers = []; $origin = curl_getinfo($parent, CURLINFO_EFFECTIVE_URL); @@ -336,15 +335,15 @@ private static function handlePush($parent, $pushed, array $requestHeaders, \std $url .= $headers[':path']; $logger && $logger->debug(sprintf('Queueing pushed response: "%s"', $url)); - $multi->pushedResponses[$url] = [ + $multi->pushedResponses[$url] = new PushedResponse( new CurlResponse($multi, $pushed), [ $headers['authorization'] ?? null, $headers['cookie'] ?? null, $headers['x-requested-with'] ?? null, null, - ], - ]; + ] + ); return CURL_PUSH_OK; } diff --git a/src/Symfony/Component/HttpClient/Internal/ClientState.php b/src/Symfony/Component/HttpClient/Internal/ClientState.php new file mode 100644 index 0000000000000..c316e7b078920 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Internal/ClientState.php @@ -0,0 +1,25 @@ +<?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\Component\HttpClient\Internal; + +/** + * Internal representation of the client state. + * + * @author Alexander M. Turek <me@derrabus.de> + * + * @internal + */ +class ClientState +{ + public $handlesActivity = []; + public $openHandles = []; +} diff --git a/src/Symfony/Component/HttpClient/Internal/CurlClientState.php b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php new file mode 100644 index 0000000000000..1c2e6c8eed48d --- /dev/null +++ b/src/Symfony/Component/HttpClient/Internal/CurlClientState.php @@ -0,0 +1,35 @@ +<?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\Component\HttpClient\Internal; + +/** + * Internal representation of the cURL client's state. + * + * @author Alexander M. Turek <me@derrabus.de> + * + * @internal + */ +final class CurlClientState extends ClientState +{ + /** @var resource */ + public $handle; + /** @var PushedResponse[] */ + public $pushedResponses = []; + /** @var DnsCache */ + public $dnsCache; + + public function __construct() + { + $this->handle = curl_multi_init(); + $this->dnsCache = new DnsCache(); + } +} diff --git a/src/Symfony/Component/HttpClient/Internal/DnsCache.php b/src/Symfony/Component/HttpClient/Internal/DnsCache.php new file mode 100644 index 0000000000000..bd23f77f8a057 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Internal/DnsCache.php @@ -0,0 +1,39 @@ +<?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\Component\HttpClient\Internal; + +/** + * Cache for resolved DNS queries. + * + * @author Alexander M. Turek <me@derrabus.de> + * + * @internal + */ +final class DnsCache +{ + /** + * Resolved hostnames (hostname => IP address). + * + * @var string[] + */ + public $hostnames = []; + + /** + * @var string[] + */ + public $removals = []; + + /** + * @var string[] + */ + public $evictions = []; +} diff --git a/src/Symfony/Component/HttpClient/Internal/NativeClientState.php b/src/Symfony/Component/HttpClient/Internal/NativeClientState.php new file mode 100644 index 0000000000000..e82ce4c853d21 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Internal/NativeClientState.php @@ -0,0 +1,44 @@ +<?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\Component\HttpClient\Internal; + +use Symfony\Component\HttpClient\Response\NativeResponse; + +/** + * Internal representation of the native client's state. + * + * @author Alexander M. Turek <me@derrabus.de> + * + * @internal + */ +final class NativeClientState extends ClientState +{ + /** @var int */ + public $id; + /** @var NativeResponse[] */ + public $pendingResponses = []; + /** @var int */ + public $maxHostConnections = PHP_INT_MAX; + /** @var int */ + public $responseCount = 0; + /** @var string[] */ + public $dnsCache = []; + /** @var resource[] */ + public $handles = []; + /** @var bool */ + public $sleep = false; + + public function __construct() + { + $this->id = random_int(PHP_INT_MIN, PHP_INT_MAX); + } +} diff --git a/src/Symfony/Component/HttpClient/Internal/PushedResponse.php b/src/Symfony/Component/HttpClient/Internal/PushedResponse.php new file mode 100644 index 0000000000000..632f0c41d0556 --- /dev/null +++ b/src/Symfony/Component/HttpClient/Internal/PushedResponse.php @@ -0,0 +1,36 @@ +<?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\Component\HttpClient\Internal; + +use Symfony\Component\HttpClient\Response\CurlResponse; + +/** + * A pushed response with headers. + * + * @author Alexander M. Turek <me@derrabus.de> + * + * @internal + */ +final class PushedResponse +{ + /** @var CurlResponse */ + public $response; + + /** @var string[] */ + public $headers; + + public function __construct(CurlResponse $response, array $headers) + { + $this->response = $response; + $this->headers = $headers; + } +} diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index 18afa2d13e59d..829d9ceb546cf 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerAwareTrait; use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\NativeClientState; use Symfony\Component\HttpClient\Response\NativeResponse; use Symfony\Component\HttpClient\Response\ResponseStream; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -36,6 +37,8 @@ final class NativeHttpClient implements HttpClientInterface, LoggerAwareInterfac use LoggerAwareTrait; private $defaultOptions = self::OPTIONS_DEFAULTS; + + /** @var NativeClientState */ private $multi; /** @@ -50,18 +53,8 @@ public function __construct(array $defaultOptions = [], int $maxHostConnections [, $this->defaultOptions] = self::prepareRequest(null, null, $defaultOptions, self::OPTIONS_DEFAULTS); } - // Use an internal stdClass object to share state between the client and its responses - $this->multi = (object) [ - 'openHandles' => [], - 'handlesActivity' => [], - 'pendingResponses' => [], - 'maxHostConnections' => 0 < $maxHostConnections ? $maxHostConnections : PHP_INT_MAX, - 'responseCount' => 0, - 'dnsCache' => [], - 'handles' => [], - 'sleep' => false, - 'id' => random_int(PHP_INT_MIN, PHP_INT_MAX), - ]; + $this->multi = new NativeClientState(); + $this->multi->maxHostConnections = 0 < $maxHostConnections ? $maxHostConnections : PHP_INT_MAX; } /** @@ -292,7 +285,7 @@ private static function getProxy(?string $proxy, array $url): ?array /** * Resolves the IP of the host using the local DNS cache if possible. */ - private static function dnsResolve(array $url, \stdClass $multi, array &$info, ?\Closure $onProgress): array + private static function dnsResolve(array $url, NativeClientState $multi, array &$info, ?\Closure $onProgress): array { if ($port = parse_url($url['authority'], PHP_URL_PORT) ?: '') { $info['primary_port'] = $port; @@ -343,7 +336,7 @@ private static function createRedirectResolver(array $options, string $host, ?ar } } - return static function (\stdClass $multi, ?string $location, $context) use ($redirectHeaders, $proxy, $noProxy, &$info, $maxRedirects, $onProgress): ?string { + return static function (NativeClientState $multi, ?string $location, $context) use ($redirectHeaders, $proxy, $noProxy, &$info, $maxRedirects, $onProgress): ?string { if (null === $location || $info['http_code'] < 300 || 400 <= $info['http_code']) { $info['redirect_url'] = null; diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index b98a2cb8ff15e..2a4cd5546ae8a 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\CurlClientState; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -26,11 +27,12 @@ final class CurlResponse implements ResponseInterface use ResponseTrait; private static $performing = false; + private $multi; /** * @internal */ - public function __construct(\stdClass $multi, $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null) + public function __construct(CurlClientState $multi, $ch, array $options = null, LoggerInterface $logger = null, string $method = 'GET', callable $resolveRedirect = null) { $this->multi = $multi; @@ -186,8 +188,8 @@ public function __destruct() $this->multi->pushedResponses = []; // Schedule DNS cache eviction for the next request - $this->multi->dnsCache[2] = $this->multi->dnsCache[2] ?: $this->multi->dnsCache[1]; - $this->multi->dnsCache[1] = $this->multi->dnsCache[0] = []; + $this->multi->dnsCache->evictions = $this->multi->dnsCache->evictions ?: $this->multi->dnsCache->removals; + $this->multi->dnsCache->removals = $this->multi->dnsCache->hostnames = []; } } } @@ -195,7 +197,7 @@ public function __destruct() /** * {@inheritdoc} */ - protected function close(): void + private function close(): void { unset($this->multi->openHandles[$this->id], $this->multi->handlesActivity[$this->id]); curl_multi_remove_handle($this->multi->handle, $this->handle); @@ -213,7 +215,7 @@ protected function close(): void /** * {@inheritdoc} */ - protected static function schedule(self $response, array &$runningResponses): void + private static function schedule(self $response, array &$runningResponses): void { if (isset($runningResponses[$i = (int) $response->multi->handle])) { $runningResponses[$i][1][$response->id] = $response; @@ -231,7 +233,7 @@ protected static function schedule(self $response, array &$runningResponses): vo /** * {@inheritdoc} */ - protected static function perform(\stdClass $multi, array &$responses = null): void + private static function perform(CurlClientState $multi, array &$responses = null): void { if (self::$performing) { return; @@ -253,7 +255,7 @@ protected static function perform(\stdClass $multi, array &$responses = null): v /** * {@inheritdoc} */ - protected static function select(\stdClass $multi, float $timeout): int + private static function select(CurlClientState $multi, float $timeout): int { return curl_multi_select($multi->handle, $timeout); } @@ -261,7 +263,7 @@ protected static function select(\stdClass $multi, float $timeout): int /** * Parses header lines as curl yields them to us. */ - private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, \stdClass $multi, int $id, ?string &$location, ?callable $resolveRedirect, ?LoggerInterface $logger): int + private static function parseHeaderLine($ch, string $data, array &$info, array &$headers, ?array $options, CurlClientState $multi, int $id, ?string &$location, ?callable $resolveRedirect, ?LoggerInterface $logger): int { if (!\in_array($waitFor = @curl_getinfo($ch, CURLINFO_PRIVATE), ['headers', 'destruct'], true)) { return \strlen($data); // Ignore HTTP trailers @@ -295,11 +297,11 @@ private static function parseHeaderLine($ch, string $data, array &$info, array & $info['redirect_url'] = $resolveRedirect($ch, $location); $url = parse_url($location ?? ':'); - if (isset($url['host']) && null !== $ip = $multi->dnsCache[0][$url['host'] = strtolower($url['host'])] ?? null) { + if (isset($url['host']) && null !== $ip = $multi->dnsCache->hostnames[$url['host'] = strtolower($url['host'])] ?? null) { // Populate DNS cache for redirects if needed $port = $url['port'] ?? ('http' === ($url['scheme'] ?? parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL), PHP_URL_SCHEME)) ? 80 : 443); curl_setopt($ch, CURLOPT_RESOLVE, ["{$url['host']}:$port:$ip"]); - $multi->dnsCache[1]["-{$url['host']}:$port"] = "-{$url['host']}:$port"; + $multi->dnsCache->removals["-{$url['host']}:$port"] = "-{$url['host']}:$port"; } } diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 2eed8b9b88275..df38c7e5bb2ce 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\InvalidArgumentException; use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\ClientState; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -130,10 +131,7 @@ protected static function schedule(self $response, array &$runningResponses): vo throw new InvalidArgumentException('MockResponse instances must be issued by MockHttpClient before processing.'); } - $multi = self::$mainMulti ?? self::$mainMulti = (object) [ - 'handlesActivity' => [], - 'openHandles' => [], - ]; + $multi = self::$mainMulti ?? self::$mainMulti = new ClientState(); if (!isset($runningResponses[0])) { $runningResponses[0] = [$multi, []]; @@ -145,7 +143,7 @@ protected static function schedule(self $response, array &$runningResponses): vo /** * {@inheritdoc} */ - protected static function perform(\stdClass $multi, array &$responses): void + protected static function perform(ClientState $multi, array &$responses): void { foreach ($responses as $response) { $id = $response->id; @@ -185,7 +183,7 @@ protected static function perform(\stdClass $multi, array &$responses): void /** * {@inheritdoc} */ - protected static function select(\stdClass $multi, float $timeout): int + protected static function select(ClientState $multi, float $timeout): int { return 42; } diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index b6652f75a05f7..037dd5da889bc 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -14,6 +14,7 @@ use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\NativeClientState; use Symfony\Contracts\HttpClient\ResponseInterface; /** @@ -32,11 +33,12 @@ final class NativeResponse implements ResponseInterface private $remaining; private $buffer; private $inflate; + private $multi; /** * @internal */ - public function __construct(\stdClass $multi, $context, string $url, $options, bool $gzipEnabled, array &$info, callable $resolveRedirect, ?callable $onProgress, ?LoggerInterface $logger) + public function __construct(NativeClientState $multi, $context, string $url, $options, bool $gzipEnabled, array &$info, callable $resolveRedirect, ?callable $onProgress, ?LoggerInterface $logger) { $this->multi = $multi; $this->id = (int) $context; @@ -193,7 +195,7 @@ private static function schedule(self $response, array &$runningResponses): void /** * {@inheritdoc} */ - private static function perform(\stdClass $multi, array &$responses = null): void + private static function perform(NativeClientState $multi, array &$responses = null): void { // List of native handles for stream_select() if (null !== $responses) { @@ -283,6 +285,7 @@ private static function perform(\stdClass $multi, array &$responses = null): voi if ($multi->pendingResponses && \count($multi->handles) < $multi->maxHostConnections) { // Open the next pending request - this is a blocking operation so we do only one of them + /** @var self $response */ $response = array_shift($multi->pendingResponses); $response->open(); $responses[$response->id] = $response; @@ -305,7 +308,7 @@ private static function perform(\stdClass $multi, array &$responses = null): voi /** * {@inheritdoc} */ - private static function select(\stdClass $multi, float $timeout): int + private static function select(NativeClientState $multi, float $timeout): int { $_ = []; diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index fc557ea90fcf2..98e96ea0a64ea 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -20,6 +20,7 @@ use Symfony\Component\HttpClient\Exception\RedirectionException; use Symfony\Component\HttpClient\Exception\ServerException; use Symfony\Component\HttpClient\Exception\TransportException; +use Symfony\Component\HttpClient\Internal\ClientState; /** * Implements the common logic for response classes. @@ -49,7 +50,7 @@ trait ResponseTrait 'error' => null, ]; - private $multi; + /** @var resource */ private $handle; private $id; private $timeout; @@ -181,12 +182,12 @@ abstract protected static function schedule(self $response, array &$runningRespo /** * Performs all pending non-blocking operations. */ - abstract protected static function perform(\stdClass $multi, array &$responses): void; + abstract protected static function perform(ClientState $multi, array &$responses): void; /** * Waits for network activity. */ - abstract protected static function select(\stdClass $multi, float $timeout): int; + abstract protected static function select(ClientState $multi, float $timeout): int; private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers): void { @@ -254,6 +255,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene $timeoutMax = 0; $timeoutMin = $timeout ?? INF; + /** @var ClientState $multi */ foreach ($runningResponses as $i => [$multi]) { $responses = &$runningResponses[$i][1]; self::perform($multi, $responses); From 5c210e6fd5544bc018225abd6be7c942c6d6b213 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm <tobias.nyholm@gmail.com> Date: Mon, 8 Apr 2019 20:16:33 +0200 Subject: [PATCH 461/495] [Cache] Added command for list all available cache pools --- .../Bundle/FrameworkBundle/CHANGELOG.md | 1 + .../Command/CachePoolListCommand.php | 62 +++++++++++++++++++ .../Resources/config/console.xml | 5 ++ .../Functional/CachePoolListCommandTest.php | 53 ++++++++++++++++ .../DependencyInjection/CachePoolPass.php | 4 ++ 5 files changed, 125 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Command/CachePoolListCommand.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolListCommandTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 79aded380fe3c..f1fbb2a8950bd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -31,6 +31,7 @@ CHANGELOG * Added the `messenger:setup-transports` command to setup messenger transports * Added a `InMemoryTransport` to Messenger. Use it with a DSN starting with `in-memory://`. * Added `framework.property_access.throw_exception_on_invalid_property_path` config option. + * Added `cache:pool:list` command to list all available cache pools. 4.2.0 ----- diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolListCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolListCommand.php new file mode 100644 index 0000000000000..4f399ab61556a --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CachePoolListCommand.php @@ -0,0 +1,62 @@ +<?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\Bundle\FrameworkBundle\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * List available cache pools. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +final class CachePoolListCommand extends Command +{ + protected static $defaultName = 'cache:pool:list'; + + private $poolNames; + + public function __construct(array $poolNames) + { + parent::__construct(); + + $this->poolNames = $poolNames; + } + + /** + * {@inheritdoc} + */ + protected function configure() + { + $this + ->setDescription('List available cache pools') + ->setHelp(<<<'EOF' +The <info>%command.name%</info> command lists all available cache pools. +EOF + ) + ; + } + + /** + * {@inheritdoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $io = new SymfonyStyle($input, $output); + + $io->table(['Pool name'], array_map(function ($pool) { + return [$pool]; + }, $this->poolNames)); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml index 7b79664c1f8f5..1c74220bf8417 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.xml @@ -48,6 +48,11 @@ <tag name="console.command" command="cache:pool:delete" /> </service> + <service id="console.command.cache_pool_list" class="Symfony\Bundle\FrameworkBundle\Command\CachePoolListCommand"> + <argument /> <!-- Pool names --> + <tag name="console.command" command="cache:pool:list" /> + </service> + <service id="console.command.cache_warmup" class="Symfony\Bundle\FrameworkBundle\Command\CacheWarmupCommand"> <argument type="service" id="cache_warmer" /> <tag name="console.command" command="cache:warmup" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolListCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolListCommandTest.php new file mode 100644 index 0000000000000..15e7994e46002 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/CachePoolListCommandTest.php @@ -0,0 +1,53 @@ +<?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\Bundle\FrameworkBundle\Tests\Functional; + +use Symfony\Bundle\FrameworkBundle\Command\CachePoolListCommand; +use Symfony\Bundle\FrameworkBundle\Console\Application; +use Symfony\Component\Console\Tester\CommandTester; + +/** + * @group functional + */ +class CachePoolListCommandTest extends WebTestCase +{ + protected function setUp() + { + static::bootKernel(['test_case' => 'CachePools', 'root_config' => 'config.yml']); + } + + public function testListPools() + { + $tester = $this->createCommandTester(['cache.app', 'cache.system']); + $tester->execute([]); + + $this->assertSame(0, $tester->getStatusCode(), 'cache:pool:list exits with 0 in case of success'); + $this->assertContains('cache.app', $tester->getDisplay()); + $this->assertContains('cache.system', $tester->getDisplay()); + } + + public function testEmptyList() + { + $tester = $this->createCommandTester([]); + $tester->execute([]); + + $this->assertSame(0, $tester->getStatusCode(), 'cache:pool:list exits with 0 in case of success'); + } + + private function createCommandTester(array $poolNames) + { + $application = new Application(static::$kernel); + $application->add(new CachePoolListCommand($poolNames)); + + return new CommandTester($application->find('cache:pool:list')); + } +} diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php index b1af39755e0d6..1c69e10c942a2 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php @@ -136,6 +136,10 @@ public function process(ContainerBuilder $container) $clearer->addTag($this->cacheSystemClearerTag); } } + + if ($container->hasDefinition('console.command.cache_pool_list')) { + $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($pools)); + } } private function getNamespace($seed, $id) From 601adf5de715281d2f615fd82739fd192e66f465 Mon Sep 17 00:00:00 2001 From: Giso Stallenberg <gisostallenberg@gmail.com> Date: Tue, 9 Apr 2019 23:54:10 +0200 Subject: [PATCH 462/495] [HttpClient] Do not allow setting both json and body --- src/Symfony/Component/HttpClient/HttpClientTrait.php | 4 ++++ .../Component/HttpClient/Tests/HttpClientTraitTest.php | 9 +++++++++ .../Component/HttpClient/Tests/ScopingHttpClientTest.php | 4 +++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 32e940ac736b9..abf7d86c80016 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -45,7 +45,11 @@ private static function prepareRequest(?string $method, ?string $url, array $opt $options = self::mergeDefaultOptions($options, $defaultOptions, $allowExtraOptions); if (isset($options['json'])) { + if (isset($options['body']) && '' !== $options['body']) { + throw new InvalidArgumentException('Define either the "json" or the "body" option, setting both is not supported.'); + } $options['body'] = self::jsonEncode($options['json']); + unset($options['json']); $options['headers']['content-type'] = $options['headers']['content-type'] ?? ['application/json']; } diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php index 0a08abec30395..5a55ec424e3c2 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -199,6 +199,15 @@ public function testSetAuthBasicAndBearerOptions() self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foo', 'auth_basic' => 'foo:bar'], HttpClientInterface::OPTIONS_DEFAULTS); } + /** + * @expectedException \Symfony\Component\HttpClient\Exception\InvalidArgumentException + * @expectedExceptionMessage Define either the "json" or the "body" option, setting both is not supported + */ + public function testSetJSONAndBodyOptions() + { + self::prepareRequest('POST', 'http://example.com', ['json' => ['foo' => 'bar'], 'body' => '<html/>'], HttpClientInterface::OPTIONS_DEFAULTS); + } + public function providePrepareAuthBasic() { yield ['foo:bar', 'Zm9vOmJhcg==']; diff --git a/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php index 7fe9104442327..e4dbcf6c9a14b 100644 --- a/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/ScopingHttpClientTest.php @@ -73,7 +73,9 @@ public function testMatchingUrlsAndOptions() $response = $client->request('GET', 'http://example.com/foo-bar', ['json' => ['url' => 'http://example.com']]); $requestOptions = $response->getRequestOptions(); - $this->assertEquals($requestOptions['json']['url'], 'http://example.com'); + $this->assertEquals($requestOptions['headers']['content-type'][0], 'application/json'); + $requestJson = json_decode($requestOptions['body'], true); + $this->assertEquals($requestJson['url'], 'http://example.com'); $this->assertEquals($requestOptions['headers']['x-app'][0], $defaultOptions['.*/foo-bar']['headers']['x-app']); $response = $client->request('GET', 'http://example.com/bar-foo', ['headers' => ['x-app' => 'unit-test']]); From e6455ea2d86f9fb336cfb37fa2eb7e1b60833cee Mon Sep 17 00:00:00 2001 From: Thomas Calvet <calvet.thomas@gmail.com> Date: Mon, 8 Apr 2019 14:17:08 +0200 Subject: [PATCH 463/495] [Security][TokenInterface] Prepare for the new serialization mechanism --- UPGRADE-4.3.md | 2 ++ UPGRADE-5.0.md | 2 ++ src/Symfony/Component/Security/CHANGELOG.md | 1 + .../Security/Core/Authentication/Token/TokenInterface.php | 4 +++- 4 files changed, 8 insertions(+), 1 deletion(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 873dc682569b1..9e19ba0dcbd94 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -153,6 +153,8 @@ Security ``` * The `Argon2iPasswordEncoder` class has been deprecated, use `SodiumPasswordEncoder` instead. + * Not implementing the methods `__serialize` and `__unserialize` in classes implementing + the `TokenInterface` is deprecated SecurityBundle -------------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index e90d60b60e3cf..bac52753634aa 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -328,6 +328,8 @@ Security ``` * The `Argon2iPasswordEncoder` class has been removed, use `SodiumPasswordEncoder` instead. + * Classes implementing the `TokenInterface` must implement the two new methods + `__serialize` and `__unserialize` SecurityBundle -------------- diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 42aca94dd0738..69f4c6301acb0 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -20,6 +20,7 @@ CHANGELOG * Dispatch `InteractiveLoginEvent` on `security.interactive_login` * Dispatch `SwitchUserEvent` on `security.switch_user` * deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` instead + * Added methods `__serialize` and `__unserialize` to the `TokenInterface` 4.2.0 ----- diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php b/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php index 4d8c2522abd6d..80ddca19db9c1 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php @@ -19,7 +19,9 @@ * @author Fabien Potencier <fabien@symfony.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com> * - * @method string[] getRoleNames() The associated roles - not implementing it is deprecated since Symfony 4.3 + * @method array __serialize() Returns all the necessary state of the object for serialization purposes - not implementing it is deprecated since Symfony 4.3 + * @method void __unserialize(array $data) Restores the object state from an array given by __serialize() - not implementing it is deprecated since Symfony 4.3 + * @method string[] getRoleNames() The associated roles - not implementing it is deprecated since Symfony 4.3 */ interface TokenInterface extends \Serializable { From 8e45fc043ec74ebc2d112b1ce3196b452a11b4a3 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm <tobias.nyholm@gmail.com> Date: Wed, 10 Apr 2019 16:52:01 +0200 Subject: [PATCH 464/495] [Dotenv] Deprecate useage of \"putenv\" --- UPGRADE-4.3.md | 6 +++ src/Symfony/Component/Dotenv/CHANGELOG.md | 5 ++ src/Symfony/Component/Dotenv/Dotenv.php | 26 ++++++++- src/Symfony/Component/Dotenv/README.md | 2 +- .../Component/Dotenv/Tests/DotenvTest.php | 53 ++++++++++++------- 5 files changed, 71 insertions(+), 21 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 873dc682569b1..85358cfbf66b4 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -45,6 +45,12 @@ Doctrine Bridge * Passing an `IdReader` to the `DoctrineChoiceLoader` when the query cannot be optimized with single id field has been deprecated, pass `null` instead * Not passing an `IdReader` to the `DoctrineChoiceLoader` when the query can be optimized with single id field has been deprecated +Dotenv +------ + + * First parameter of `Dontenv::__construct()` will change from `true` to `false` in Symfony 5.0. A deprecation warning + will be triggered if no parameter is used. Use `$usePutenv=true` to upgrade without breaking changes. + EventDispatcher --------------- diff --git a/src/Symfony/Component/Dotenv/CHANGELOG.md b/src/Symfony/Component/Dotenv/CHANGELOG.md index 3d3546f76c63d..296f029e7a9ac 100644 --- a/src/Symfony/Component/Dotenv/CHANGELOG.md +++ b/src/Symfony/Component/Dotenv/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.3.0 +----- + + * deprecated use of `putenv()` but default. This feature will be opted-in with a constructor argument to `Dotenv`. + 4.2.0 ----- diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 697e09ec0b443..e980544f73c1b 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -35,6 +35,21 @@ final class Dotenv private $data; private $end; private $values; + private $usePutenv = true; + + /** + * @var bool If we should use `putenv()` to define environment variables + * or not. Since Symfony 5.0 the default value is false + * because `putenv()` is not thread safe. + */ + public function __construct(bool $usePutenv = true) + { + if (0 === \func_num_args()) { + @trigger_error(sprintf('The default value of "$usePutenv" argument of "%s\'s constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly.', __METHOD__), E_USER_DEPRECATED); + } + + $this->usePutenv = $usePutenv; + } /** * Loads one or several .env files. @@ -126,7 +141,10 @@ public function populate(array $values, bool $overrideExistingVars = false): voi continue; } - putenv("$name=$value"); + if ($this->usePutenv) { + putenv("$name=$value"); + } + $_ENV[$name] = $value; if ($notHttpName) { $_SERVER[$name] = $value; @@ -140,7 +158,11 @@ public function populate(array $values, bool $overrideExistingVars = false): voi if ($updateLoadedVars) { unset($loadedVars['']); $loadedVars = implode(',', array_keys($loadedVars)); - putenv('SYMFONY_DOTENV_VARS='.$_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars); + $_ENV['SYMFONY_DOTENV_VARS'] = $_SERVER['SYMFONY_DOTENV_VARS'] = $loadedVars; + + if ($this->usePutenv) { + putenv('SYMFONY_DOTENV_VARS='.$loadedVars); + } } } diff --git a/src/Symfony/Component/Dotenv/README.md b/src/Symfony/Component/Dotenv/README.md index 244ed7700a14e..38dde84bc4d95 100644 --- a/src/Symfony/Component/Dotenv/README.md +++ b/src/Symfony/Component/Dotenv/README.md @@ -2,7 +2,7 @@ Dotenv Component ================ Symfony Dotenv parses `.env` files to make environment variables stored in them -accessible via `getenv()`, `$_ENV`, or `$_SERVER`. +accessible via `$_ENV`, `$_SERVER` and optionally `getenv()`. Resources --------- diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 36c0af252094a..8d308c415925c 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -22,7 +22,7 @@ class DotenvTest extends TestCase */ public function testParseWithFormatError($data, $error) { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); try { $dotenv->parse($data); @@ -62,7 +62,7 @@ public function getEnvDataWithFormatErrors() */ public function testParse($data, $expected) { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $this->assertSame($expected, $dotenv->parse($data)); } @@ -193,7 +193,7 @@ public function testLoad() file_put_contents($path1, 'FOO=BAR'); file_put_contents($path2, 'BAR=BAZ'); - (new Dotenv())->load($path1, $path2); + (new Dotenv(true))->load($path1, $path2); $foo = getenv('FOO'); $bar = getenv('BAR'); @@ -224,7 +224,7 @@ public function testLoadEnv() // .env file_put_contents($path, 'FOO=BAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('BAR', getenv('FOO')); $this->assertSame('dev', getenv('TEST_APP_ENV')); @@ -232,33 +232,33 @@ public function testLoadEnv() $_SERVER['TEST_APP_ENV'] = 'local'; file_put_contents("$path.local", 'FOO=localBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('localBAR', getenv('FOO')); // special case for test $_SERVER['TEST_APP_ENV'] = 'test'; - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('BAR', getenv('FOO')); // .env.dev unset($_SERVER['TEST_APP_ENV']); file_put_contents("$path.dev", 'FOO=devBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('devBAR', getenv('FOO')); // .env.dev.local file_put_contents("$path.dev.local", 'FOO=devlocalBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('devlocalBAR', getenv('FOO')); // .env.dist unlink($path); file_put_contents("$path.dist", 'BAR=distBAR'); - (new DotEnv())->loadEnv($path, 'TEST_APP_ENV'); + (new Dotenv(true))->loadEnv($path, 'TEST_APP_ENV'); $this->assertSame('distBAR', getenv('BAR')); putenv('FOO'); @@ -290,7 +290,7 @@ public function testOverload() file_put_contents($path1, 'FOO=BAR'); file_put_contents($path2, 'BAR=BAZ'); - (new Dotenv())->overload($path1, $path2); + (new Dotenv(true))->overload($path1, $path2); $foo = getenv('FOO'); $bar = getenv('BAR'); @@ -310,7 +310,7 @@ public function testOverload() */ public function testLoadDirectory() { - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->load(__DIR__); } @@ -318,7 +318,7 @@ public function testServerSuperglobalIsNotOverriden() { $originalValue = $_SERVER['argc']; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['argc' => 'new_value']); $this->assertSame($originalValue, $_SERVER['argc']); @@ -329,7 +329,7 @@ public function testEnvVarIsNotOverriden() putenv('TEST_ENV_VAR=original_value'); $_SERVER['TEST_ENV_VAR'] = 'original_value'; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['TEST_ENV_VAR' => 'new_value']); $this->assertSame('original_value', getenv('TEST_ENV_VAR')); @@ -339,7 +339,7 @@ public function testHttpVarIsPartiallyOverriden() { $_SERVER['HTTP_TEST_ENV_VAR'] = 'http_value'; - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['HTTP_TEST_ENV_VAR' => 'env_value']); $this->assertSame('env_value', getenv('HTTP_TEST_ENV_VAR')); @@ -351,7 +351,7 @@ public function testEnvVarIsOverriden() { putenv('TEST_ENV_VAR_OVERRIDEN=original_value'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['TEST_ENV_VAR_OVERRIDEN' => 'new_value'], true); $this->assertSame('new_value', getenv('TEST_ENV_VAR_OVERRIDEN')); @@ -373,7 +373,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() unset($_SERVER['DATABASE_URL']); putenv('DATABASE_URL'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['APP_DEBUG' => '1', 'DATABASE_URL' => 'mysql://root@localhost/db']); $this->assertSame('APP_DEBUG,DATABASE_URL', getenv('SYMFONY_DOTENV_VARS')); @@ -390,7 +390,7 @@ public function testMemorizingLoadedVarsNamesInSpecialVar() unset($_SERVER['DATABASE_URL']); putenv('DATABASE_URL'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['APP_DEBUG' => '0', 'DATABASE_URL' => 'mysql://root@localhost/db']); $dotenv->populate(['DATABASE_URL' => 'sqlite:///somedb.sqlite']); @@ -406,7 +406,7 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() putenv('BAZ=baz'); putenv('DOCUMENT_ROOT=/var/www'); - $dotenv = new Dotenv(); + $dotenv = new Dotenv(true); $dotenv->populate(['FOO' => 'foo1', 'BAR' => 'bar1', 'BAZ' => 'baz1', 'DOCUMENT_ROOT' => '/boot']); $this->assertSame('foo1', getenv('FOO')); @@ -414,4 +414,21 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() $this->assertSame('baz1', getenv('BAZ')); $this->assertSame('/var/www', getenv('DOCUMENT_ROOT')); } + + /** + * @group legacy + * @expectedDeprecation The default value of "$usePutenv" argument of "%s's constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly. + */ + public function testDeprecationWarning() + { + new Dotenv(); + } + + public function testNoDeprecationWarning() + { + $dotenv = new Dotenv(true); + $this->assertInstanceOf(Dotenv::class, $dotenv); + $dotenv = new Dotenv(false); + $this->assertInstanceOf(Dotenv::class, $dotenv); + } } From ccbb171312ccde082603781bb1d863b0169d3186 Mon Sep 17 00:00:00 2001 From: Patrick Landolt <patrick.landolt@artack.ch> Date: Mon, 8 Apr 2019 17:57:55 +0200 Subject: [PATCH 465/495] fixed roundrobin dead transport which should recover --- .../Tests/Transport/FailoverTransportTest.php | 63 +++++++++++++++++++ .../Transport/RoundRobinTransportTest.php | 29 +++++++-- .../Mailer/Transport/RoundRobinTransport.php | 9 +++ 3 files changed, 96 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php index dc3bc21a7dc44..031dc32edb94c 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php @@ -64,6 +64,69 @@ public function testSendOneDead() $t->send(new RawMessage('')); } + public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->once())->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->exactly(5))->method('send'); + $t = new FailoverTransport([$t1, $t2], 40); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + } + + public function testSendOneDeadAndRecoveryWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->at(1))->method('send'); + $t1->expects($this->exactly(3))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send'); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->at(2))->method('send'); + $t2->expects($this->at(3))->method('send')->will($this->throwException(new TransportException())); + $t2->expects($this->exactly(4))->method('send'); + $t = new FailoverTransport([$t1, $t2], 6); + $t->send(new RawMessage('')); // t1>fail - t2>sent + sleep(4); + $t->send(new RawMessage('')); // t2>sent + sleep(4); + $t->send(new RawMessage('')); // t2>sent + sleep(4); + $t->send(new RawMessage('')); // t2>fail - t1>sent + sleep(4); + $t->send(new RawMessage('')); // t1>sent + } + + public function testSendAllDeadWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t1->expects($this->once())->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send'); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->at(2))->method('send')->will($this->throwException(new TransportException())); + $t2->expects($this->exactly(3))->method('send'); + $t = new FailoverTransport([$t1, $t2], 40); + $t->send(new RawMessage('')); + sleep(4); + $t->send(new RawMessage('')); + sleep(4); + $this->expectException(TransportException::class); + $this->expectExceptionMessage('All transports failed.'); + $t->send(new RawMessage('')); + } + public function testSendOneDeadButRecover() { $t1 = $this->createMock(TransportInterface::class); diff --git a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php index b27a3e7949845..7acbe9c483743 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php @@ -64,16 +64,35 @@ public function testSendOneDead() $t->send(new RawMessage('')); } - public function testSendOneDeadButRecover() + public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() { $t1 = $this->createMock(TransportInterface::class); - $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); - $t1->expects($this->at(1))->method('send'); + $t1->expects($this->exactly(4))->method('send'); $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); $t2->expects($this->once())->method('send'); - $t = new RoundRobinTransport([$t1, $t2], 1); + $t = new RoundRobinTransport([$t1, $t2], 60); $t->send(new RawMessage('')); - sleep(2); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + $t->send(new RawMessage('')); + } + + public function testSendOneDeadAndRecoveryWithinRetryPeriod() + { + $t1 = $this->createMock(TransportInterface::class); + $t1->expects($this->exactly(3))->method('send'); + $t2 = $this->createMock(TransportInterface::class); + $t2->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); + $t2->expects($this->at(1))->method('send'); + $t2->expects($this->exactly(2))->method('send'); + $t = new RoundRobinTransport([$t1, $t2], 3); + $t->send(new RawMessage('')); + sleep(5); + $t->send(new RawMessage('')); + sleep(5); + $t->send(new RawMessage('')); + sleep(5); $t->send(new RawMessage('')); } } diff --git a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php index 22b1ba9714347..e585e3635e6a4 100644 --- a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php +++ b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php @@ -66,11 +66,20 @@ protected function getNextTransport(): ?TransportInterface if (!$this->isTransportDead($transport)) { break; } + if ((microtime(true) - $this->deadTransports[$transport]) > $this->retryPeriod) { $this->deadTransports->detach($transport); break; } + + if ($transport) { + $this->transports[] = $transport; + } + + if ($this->deadTransports->count() >= \count($this->transports)) { + return null; + } } if ($transport) { From 5d4d4e7a712cd222965e4e891a6c7737fb3b0cbb Mon Sep 17 00:00:00 2001 From: Fabien Potencier <fabien@potencier.org> Date: Wed, 10 Apr 2019 09:39:31 +0200 Subject: [PATCH 466/495] fixed roundrobin dead transport which should recover --- .../Tests/Transport/FailoverTransportTest.php | 45 ++++++++++--------- .../Transport/RoundRobinTransportTest.php | 32 ++++++++++--- .../Mailer/Transport/RoundRobinTransport.php | 21 +++++---- 3 files changed, 63 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php index 031dc32edb94c..9243263fdd0ed 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/FailoverTransportTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Exception\TransportException; use Symfony\Component\Mailer\Transport\FailoverTransport; +use Symfony\Component\Mailer\Transport\RoundRobinTransport; use Symfony\Component\Mailer\Transport\TransportInterface; use Symfony\Component\Mime\RawMessage; @@ -36,8 +37,11 @@ public function testSendFirstWork() $t2->expects($this->never())->method('send'); $t = new FailoverTransport([$t1, $t2]); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); } public function testSendAllDead() @@ -50,6 +54,7 @@ public function testSendAllDead() $this->expectException(TransportException::class); $this->expectExceptionMessage('All transports failed.'); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1, $t2]); } public function testSendOneDead() @@ -60,27 +65,11 @@ public function testSendOneDead() $t2->expects($this->exactly(3))->method('send'); $t = new FailoverTransport([$t1, $t2]); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1]); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1]); $t->send(new RawMessage('')); - } - - public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() - { - $t1 = $this->createMock(TransportInterface::class); - $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); - $t1->expects($this->once())->method('send'); - $t2 = $this->createMock(TransportInterface::class); - $t2->expects($this->exactly(5))->method('send'); - $t = new FailoverTransport([$t1, $t2], 40); - $t->send(new RawMessage('')); - sleep(4); - $t->send(new RawMessage('')); - sleep(4); - $t->send(new RawMessage('')); - sleep(4); - $t->send(new RawMessage('')); - sleep(4); - $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1]); } public function testSendOneDeadAndRecoveryWithinRetryPeriod() @@ -88,23 +77,26 @@ public function testSendOneDeadAndRecoveryWithinRetryPeriod() $t1 = $this->createMock(TransportInterface::class); $t1->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); $t1->expects($this->at(1))->method('send'); - $t1->expects($this->exactly(3))->method('send'); $t2 = $this->createMock(TransportInterface::class); $t2->expects($this->at(0))->method('send'); $t2->expects($this->at(1))->method('send'); $t2->expects($this->at(2))->method('send'); $t2->expects($this->at(3))->method('send')->will($this->throwException(new TransportException())); - $t2->expects($this->exactly(4))->method('send'); $t = new FailoverTransport([$t1, $t2], 6); $t->send(new RawMessage('')); // t1>fail - t2>sent + $this->assertTransports($t, 0, [$t1]); sleep(4); $t->send(new RawMessage('')); // t2>sent + $this->assertTransports($t, 0, [$t1]); sleep(4); $t->send(new RawMessage('')); // t2>sent + $this->assertTransports($t, 0, [$t1]); sleep(4); $t->send(new RawMessage('')); // t2>fail - t1>sent + $this->assertTransports($t, 1, [$t2]); sleep(4); $t->send(new RawMessage('')); // t1>sent + $this->assertTransports($t, 1, [$t2]); } public function testSendAllDeadWithinRetryPeriod() @@ -143,4 +135,15 @@ public function testSendOneDeadButRecover() sleep(1); $t->send(new RawMessage('')); } + + private function assertTransports(RoundRobinTransport $transport, int $cursor, array $deadTransports) + { + $p = new \ReflectionProperty(RoundRobinTransport::class, 'cursor'); + $p->setAccessible(true); + $this->assertSame($cursor, $p->getValue($transport)); + + $p = new \ReflectionProperty(RoundRobinTransport::class, 'deadTransports'); + $p->setAccessible(true); + $this->assertSame($deadTransports, iterator_to_array($p->getValue($transport))); + } } diff --git a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php index 7acbe9c483743..4b2316da5d00c 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/RoundRobinTransportTest.php @@ -36,8 +36,11 @@ public function testSendAlternate() $t2->expects($this->once())->method('send'); $t = new RoundRobinTransport([$t1, $t2]); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); } public function testSendAllDead() @@ -50,6 +53,7 @@ public function testSendAllDead() $this->expectException(TransportException::class); $this->expectExceptionMessage('All transports failed.'); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, [$t1, $t2]); } public function testSendOneDead() @@ -60,8 +64,11 @@ public function testSendOneDead() $t2->expects($this->exactly(3))->method('send'); $t = new RoundRobinTransport([$t1, $t2]); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1]); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1]); $t->send(new RawMessage('')); + $this->assertTransports($t, 0, [$t1]); } public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() @@ -69,13 +76,16 @@ public function testSendOneDeadAndRecoveryNotWithinRetryPeriod() $t1 = $this->createMock(TransportInterface::class); $t1->expects($this->exactly(4))->method('send'); $t2 = $this->createMock(TransportInterface::class); - $t2->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); - $t2->expects($this->once())->method('send'); + $t2->expects($this->once())->method('send')->will($this->throwException(new TransportException())); $t = new RoundRobinTransport([$t1, $t2], 60); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, [$t2]); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, [$t2]); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, [$t2]); } public function testSendOneDeadAndRecoveryWithinRetryPeriod() @@ -85,14 +95,26 @@ public function testSendOneDeadAndRecoveryWithinRetryPeriod() $t2 = $this->createMock(TransportInterface::class); $t2->expects($this->at(0))->method('send')->will($this->throwException(new TransportException())); $t2->expects($this->at(1))->method('send'); - $t2->expects($this->exactly(2))->method('send'); $t = new RoundRobinTransport([$t1, $t2], 3); $t->send(new RawMessage('')); - sleep(5); + $this->assertTransports($t, 1, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, [$t2]); sleep(5); $t->send(new RawMessage('')); - sleep(5); + $this->assertTransports($t, 0, []); $t->send(new RawMessage('')); + $this->assertTransports($t, 1, []); + } + + private function assertTransports(RoundRobinTransport $transport, int $cursor, array $deadTransports) + { + $p = new \ReflectionProperty($transport, 'cursor'); + $p->setAccessible(true); + $this->assertSame($cursor, $p->getValue($transport)); + + $p = new \ReflectionProperty($transport, 'deadTransports'); + $p->setAccessible(true); + $this->assertSame($deadTransports, iterator_to_array($p->getValue($transport))); } } diff --git a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php index e585e3635e6a4..928b6c06ad8bd 100644 --- a/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php +++ b/src/Symfony/Component/Mailer/Transport/RoundRobinTransport.php @@ -29,6 +29,7 @@ class RoundRobinTransport implements TransportInterface private $deadTransports; private $transports = []; private $retryPeriod; + private $cursor = 0; /** * @param TransportInterface[] $transports @@ -62,7 +63,10 @@ public function send(RawMessage $message, SmtpEnvelope $envelope = null): ?SentM */ protected function getNextTransport(): ?TransportInterface { - while ($transport = array_shift($this->transports)) { + $cursor = $this->cursor; + while (true) { + $transport = $this->transports[$cursor]; + if (!$this->isTransportDead($transport)) { break; } @@ -73,18 +77,12 @@ protected function getNextTransport(): ?TransportInterface break; } - if ($transport) { - $this->transports[] = $transport; - } - - if ($this->deadTransports->count() >= \count($this->transports)) { + if ($this->cursor === $cursor = $this->moveCursor($cursor)) { return null; } } - if ($transport) { - $this->transports[] = $transport; - } + $this->cursor = $this->moveCursor($cursor); return $transport; } @@ -93,4 +91,9 @@ protected function isTransportDead(TransportInterface $transport): bool { return $this->deadTransports->contains($transport); } + + private function moveCursor(int $cursor): int + { + return ++$cursor >= \count($this->transports) ? 0 : $cursor; + } } From e0c452823720a4db56829fa5949bae9b03b2a8a2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 10 Apr 2019 22:28:30 +0200 Subject: [PATCH 467/495] [Dotenv] fix typos --- UPGRADE-4.3.md | 4 ++-- UPGRADE-5.0.md | 5 +++++ src/Symfony/Component/Dotenv/CHANGELOG.md | 2 +- src/Symfony/Component/Dotenv/Dotenv.php | 8 ++++---- src/Symfony/Component/Dotenv/README.md | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 2b422af3d110d..7af29f15e3315 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -48,8 +48,8 @@ Doctrine Bridge Dotenv ------ - * First parameter of `Dontenv::__construct()` will change from `true` to `false` in Symfony 5.0. A deprecation warning - will be triggered if no parameter is used. Use `$usePutenv=true` to upgrade without breaking changes. + * First parameter of `Dotenv::__construct()` will change from `true` to `false` in Symfony 5.0. A deprecation warning + is triggered if no parameter is used. Use `$usePutenv = true` to upgrade without breaking changes. EventDispatcher --------------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index bac52753634aa..5c1013d9336e6 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -70,6 +70,11 @@ DomCrawler * The `Crawler::children()` method has a new `$selector` argument. +Dotenv +------ + + * First parameter `$usePutenv` of `Dotenv::__construct()` now default to `false`. + EventDispatcher --------------- diff --git a/src/Symfony/Component/Dotenv/CHANGELOG.md b/src/Symfony/Component/Dotenv/CHANGELOG.md index 296f029e7a9ac..e6e74c945bb40 100644 --- a/src/Symfony/Component/Dotenv/CHANGELOG.md +++ b/src/Symfony/Component/Dotenv/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGELOG 4.3.0 ----- - * deprecated use of `putenv()` but default. This feature will be opted-in with a constructor argument to `Dotenv`. + * deprecated use of `putenv()` by default. This feature will be opted-in with a constructor argument to `Dotenv` 4.2.0 ----- diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index e980544f73c1b..e5b2a318abe19 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -38,13 +38,13 @@ final class Dotenv private $usePutenv = true; /** - * @var bool If we should use `putenv()` to define environment variables - * or not. Since Symfony 5.0 the default value is false - * because `putenv()` is not thread safe. + * @var bool If `putenv()` should be used to define environment variables or not. + * Beware that `putenv()` is not thread safe and this setting will default + * to `false` in Symfony 5.0. */ public function __construct(bool $usePutenv = true) { - if (0 === \func_num_args()) { + if (!\func_num_args()) { @trigger_error(sprintf('The default value of "$usePutenv" argument of "%s\'s constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly.', __METHOD__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Dotenv/README.md b/src/Symfony/Component/Dotenv/README.md index 38dde84bc4d95..c21223b04e42e 100644 --- a/src/Symfony/Component/Dotenv/README.md +++ b/src/Symfony/Component/Dotenv/README.md @@ -2,7 +2,7 @@ Dotenv Component ================ Symfony Dotenv parses `.env` files to make environment variables stored in them -accessible via `$_ENV`, `$_SERVER` and optionally `getenv()`. +accessible via `$_SERVER`, `$_ENV` and optionally `getenv()`. Resources --------- From e871a6a83a03caf9b357e4c8a5b7a989e2dd459f Mon Sep 17 00:00:00 2001 From: Quynh Xuan Nguyen <seriquynh@gmail.com> Date: Thu, 11 Apr 2019 08:29:28 +0700 Subject: [PATCH 468/495] Improve Dotenv messages --- UPGRADE-4.3.md | 6 +++--- src/Symfony/Component/Dotenv/Dotenv.php | 2 +- src/Symfony/Component/Dotenv/Tests/DotenvTest.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 7af29f15e3315..0a5228587700d 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -48,8 +48,8 @@ Doctrine Bridge Dotenv ------ - * First parameter of `Dotenv::__construct()` will change from `true` to `false` in Symfony 5.0. A deprecation warning - is triggered if no parameter is used. Use `$usePutenv = true` to upgrade without breaking changes. + * First parameter of `Dotenv::__construct()` will be changed from `true` to `false` in Symfony 5.0. A deprecation warning + is triggered if no parameter is provided. Use `$usePutenv = true` to upgrade without breaking changes. EventDispatcher --------------- @@ -170,7 +170,7 @@ SecurityBundle TwigBridge ---------- - * deprecated the `$requestStack` and `$requestContext` arguments of the + * deprecated the `$requestStack` and `$requestContext` arguments of the `HttpFoundationExtension`, pass a `Symfony\Component\HttpFoundation\UrlHelper` instance as the only argument instead diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index e5b2a318abe19..2f699ce860faa 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -45,7 +45,7 @@ final class Dotenv public function __construct(bool $usePutenv = true) { if (!\func_num_args()) { - @trigger_error(sprintf('The default value of "$usePutenv" argument of "%s\'s constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly.', __METHOD__), E_USER_DEPRECATED); + @trigger_error(sprintf('The default value of "$usePutenv" argument of "%s" will be changed from "true" to "false" in Symfony 5.0. You should define its value explicitly.', __METHOD__), E_USER_DEPRECATED); } $this->usePutenv = $usePutenv; diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 8d308c415925c..ded78faaa78b2 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -417,7 +417,7 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar() /** * @group legacy - * @expectedDeprecation The default value of "$usePutenv" argument of "%s's constructor will change from "true" to "false" in Symfony 5.0, you should define its value explicitly. + * @expectedDeprecation The default value of "$usePutenv" argument of "%s" will be changed from "true" to "false" in Symfony 5.0. You should define its value explicitly. */ public function testDeprecationWarning() { From 526cad6909ceb06d6c1543129068445fd7d7d027 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera <pol.dellaiera@protonmail.com> Date: Wed, 10 Apr 2019 22:08:15 +0200 Subject: [PATCH 469/495] Make sure that logged URL is the same as the one which is requested. --- src/Symfony/Component/HttpClient/NativeHttpClient.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index 18afa2d13e59d..6ca9f6cce1719 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -159,6 +159,8 @@ public function request(string $method, string $url, array $options = []): Respo $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; } + $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, implode('', $url))); + [$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress); if (!isset($options['headers']['host'])) { @@ -208,10 +210,7 @@ public function request(string $method, string $url, array $options = []): Respo $context = stream_context_create($context, ['notification' => $notification]); self::configureHeadersAndProxy($context, $host, $options['request_headers'], $proxy, $noProxy); - $url = implode('', $url); - $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, $url)); - - return new NativeResponse($this->multi, $context, $url, $options, $gzipEnabled, $info, $resolveRedirect, $onProgress, $this->logger); + return new NativeResponse($this->multi, $context, implode('', $url), $options, $gzipEnabled, $info, $resolveRedirect, $onProgress, $this->logger); } /** From 3a680402cedcb55764eeaec06d20f42e3795118c Mon Sep 17 00:00:00 2001 From: Dennis Haarbrink <dennis@nonmagna.nl> Date: Thu, 11 Apr 2019 10:19:52 +0200 Subject: [PATCH 470/495] #30998 Fix deprecated setCircularReferenceHandler call --- .../DependencyInjection/FrameworkExtension.php | 5 ++++- .../Tests/DependencyInjection/FrameworkExtensionTest.php | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index b390f2978113b..218290bf36dff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1398,7 +1398,10 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder } if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) { - $container->getDefinition('serializer.normalizer.object')->addMethodCall('setCircularReferenceHandler', [new Reference($config['circular_reference_handler'])]); + $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments(); + $context = ($arguments[6] ?? []) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])]; + $container->getDefinition('serializer.normalizer.object')->setArgument(5, null); + $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context); } if ($config['max_depth_handler'] ?? false) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 862786c9b8b80..bb5308583b651 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -1066,8 +1066,8 @@ public function testSerializerEnabled() $this->assertNull($container->getDefinition('serializer.mapping.class_metadata_factory')->getArgument(1)); $this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.name_converter.metadata_aware')->getArgument(1)); $this->assertEquals(new Reference('property_info', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), $container->getDefinition('serializer.normalizer.object')->getArgument(3)); - $this->assertEquals(['setCircularReferenceHandler', [new Reference('my.circular.reference.handler')]], $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[0]); - $this->assertEquals(['setMaxDepthHandler', [new Reference('my.max.depth.handler')]], $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[1]); + $this->assertArrayHasKey('circular_reference_handler', $container->getDefinition('serializer.normalizer.object')->getArgument(6)); + $this->assertEquals(['setMaxDepthHandler', [new Reference('my.max.depth.handler')]], $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[0]); } public function testRegisterSerializerExtractor() From 027bd1288490e43e585b803ae18f5ac251c5e42d Mon Sep 17 00:00:00 2001 From: rubenrua <rubenrua@gmail.com> Date: Wed, 10 Apr 2019 16:55:13 +0200 Subject: [PATCH 471/495] CS Fixes: Not double split with one array argument Keep to use the same CS in all the Symfony code base. Use: ```php $resolver->setDefaults([ 'compound' => false ]); ``` Instead of: ```php $resolver->setDefaults( [ 'compound' => false, ] ); ``` Keep the double split when the method has two or more arguments. I miss a PSR with this rule. --- .../Factory/DefaultChoiceListFactoryTest.php | 8 ++------ .../Form/Tests/Extension/Core/Type/ChoiceTypeTest.php | 11 +++++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php index c57a466ec54c4..79118d93b0792 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php @@ -95,9 +95,7 @@ protected function setUp() $this->obj2 = (object) ['label' => 'B', 'index' => 'x', 'value' => 'b', 'preferred' => true, 'group' => 'Group 1', 'attr' => ['attr1' => 'value1']]; $this->obj3 = (object) ['label' => 'C', 'index' => 'y', 'value' => 1, 'preferred' => true, 'group' => 'Group 2', 'attr' => ['attr2' => 'value2']]; $this->obj4 = (object) ['label' => 'D', 'index' => 'z', 'value' => 2, 'preferred' => false, 'group' => 'Group 2', 'attr' => []]; - $this->list = new ArrayChoiceList( - ['A' => $this->obj1, 'B' => $this->obj2, 'C' => $this->obj3, 'D' => $this->obj4] - ); + $this->list = new ArrayChoiceList(['A' => $this->obj1, 'B' => $this->obj2, 'C' => $this->obj3, 'D' => $this->obj4]); $this->factory = new DefaultChoiceListFactory(); } @@ -111,9 +109,7 @@ public function testCreateFromChoicesEmpty() public function testCreateFromChoicesFlat() { - $list = $this->factory->createListFromChoices( - ['A' => $this->obj1, 'B' => $this->obj2, 'C' => $this->obj3, 'D' => $this->obj4] - ); + $list = $this->factory->createListFromChoices(['A' => $this->obj1, 'B' => $this->obj2, 'C' => $this->obj3, 'D' => $this->obj4]); $this->assertObjectListWithGeneratedValues($list); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index 4a7f006f6f2ec..741c3ce85f790 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -1841,12 +1841,11 @@ public function testCustomChoiceTypeDoesNotInheritChoiceLabels() { $builder = $this->factory->createBuilder(); $builder->add('choice', static::TESTED_TYPE, [ - 'choices' => [ - '1' => '1', - '2' => '2', - ], - ] - ); + 'choices' => [ + '1' => '1', + '2' => '2', + ], + ]); $builder->add('subChoice', 'Symfony\Component\Form\Tests\Fixtures\ChoiceSubType'); $form = $builder->getForm(); From 1c73f9cfedad7fb7eb6ab0b1230d0219685ead0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= <postmaster@greg0ire.fr> Date: Tue, 4 Sep 2018 23:36:01 +0200 Subject: [PATCH 472/495] [PhpUnitBridge] Url encoded deprecations helper config --- .../PhpUnit/DeprecationErrorHandler.php | 236 ++++++-------- .../DeprecationErrorHandler/Configuration.php | 208 +++++++++++++ .../DeprecationErrorHandler/Deprecation.php | 291 ++++++++++++++++++ .../ConfigurationTest.php | 195 ++++++++++++ .../DeprecationTest.php | 60 ++++ .../DeprecationErrorHandler/default.phpt | 2 +- .../{regexp.phpt => deprecated_regexp.phpt} | 0 .../eval_not_self.phpt | 24 ++ .../fake_vendor/acme/lib/SomeService.php | 14 + .../acme/outdated-lib/outdated_file.php | 7 + .../lagging_vendor.phpt | 38 +++ .../Tests/DeprecationErrorHandler/quiet.phpt | 39 +++ .../self_on_non_vendor.phpt | 74 +++++ .../shutdown_deprecations.phpt | 2 +- .../weak_vendors_on_eval_d_deprecation.phpt | 3 +- .../weak_vendors_on_non_vendor.phpt | 4 +- .../weak_vendors_on_phar_deprecation.phpt | 5 +- .../weak_vendors_on_vendor.phpt | 6 +- 18 files changed, 1049 insertions(+), 159 deletions(-) create mode 100644 src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php create mode 100644 src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/ConfigurationTest.php create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php rename src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/{regexp.phpt => deprecated_regexp.phpt} (100%) create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/eval_not_self.phpt create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/lib/SomeService.php create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/outdated-lib/outdated_file.php create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/lagging_vendor.phpt create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/quiet.phpt create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/self_on_non_vendor.phpt diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 20118f921b149..9289b5e942065 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -11,6 +11,9 @@ namespace Symfony\Bridge\PhpUnit; +use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration; +use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation; + /** * Catch deprecation notices and print a summary report at the end of the test suite. * @@ -18,23 +21,30 @@ */ class DeprecationErrorHandler { - const MODE_WEAK = 'weak'; + /** + * @deprecated since Symfony 4.3, use max[self]=0 instead + */ const MODE_WEAK_VENDORS = 'weak_vendors'; + const MODE_DISABLED = 'disabled'; + const MODE_WEAK = 'max[total]=999999&verbose=0'; + const MODE_STRICT = 'max[total]=0'; - private $mode = false; - private $resolvedMode = false; + private $mode; + private $configuration; private $deprecations = [ 'unsilencedCount' => 0, - 'remainingCount' => 0, + 'remaining selfCount' => 0, 'legacyCount' => 0, 'otherCount' => 0, - 'remaining vendorCount' => 0, + 'remaining directCount' => 0, + 'remaining indirectCount' => 0, 'unsilenced' => [], - 'remaining' => [], + 'remaining self' => [], 'legacy' => [], 'other' => [], - 'remaining vendor' => [], + 'remaining direct' => [], + 'remaining indirect' => [], ]; private static $isRegistered = false; @@ -43,13 +53,16 @@ class DeprecationErrorHandler /** * Registers and configures the deprecation handler. * - * The following reporting modes are supported: - * - use "weak" to hide the deprecation report but keep a global count; - * - use "weak_vendors" to fail only on deprecations triggered in your own code; - * - use "/some-regexp/" to stop the test suite whenever a deprecation - * message matches the given regular expression; - * - use a number to define the upper bound of allowed deprecations, - * making the test suite fail whenever more notices are triggered. + * The mode is a query string with options: + * - "disabled" to disable the deprecation handler + * - "verbose" to enable/disable displaying the deprecation report + * - "max" to configure the number of deprecations to allow before exiting with a non-zero + * status code; it's an array with keys "total", "self", "direct" and "indirect" + * + * The default mode is "max[total]=0&verbose=1". + * + * The mode can alternatively be "/some-regexp/" to stop the test suite whenever + * a deprecation message matches the given regular expression. * * @param int|string|false $mode The reporting mode, defaults to not allowing any deprecations */ @@ -108,76 +121,41 @@ public static function collectDeprecations($outputFile) */ public function handleError($type, $msg, $file, $line, $context = []) { - if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || self::MODE_DISABLED === $mode = $this->getMode()) { + if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || !$this->getConfiguration()->isEnabled()) { $ErrorHandler = self::$utilPrefix.'ErrorHandler'; return $ErrorHandler::handleError($type, $msg, $file, $line, $context); } - $trace = debug_backtrace(); + $deprecation = new Deprecation($msg, debug_backtrace(), $file); $group = 'other'; - $isVendor = self::MODE_WEAK_VENDORS === $mode && self::inVendors($file); - $i = \count($trace); - while (1 < $i && (!isset($trace[--$i]['class']) || ('ReflectionMethod' === $trace[$i]['class'] || 0 === strpos($trace[$i]['class'], 'PHPUnit_') || 0 === strpos($trace[$i]['class'], 'PHPUnit\\')))) { - // No-op - } - - if (isset($trace[$i]['object']) || isset($trace[$i]['class'])) { - if (isset($trace[$i]['class']) && 0 === strpos($trace[$i]['class'], 'Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor')) { - $parsedMsg = unserialize($msg); - $msg = $parsedMsg['deprecation']; - $class = $parsedMsg['class']; - $method = $parsedMsg['method']; - // If the deprecation has been triggered via - // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest() - // then we need to use the serialized information to determine - // if the error has been triggered from vendor code. - $isVendor = self::MODE_WEAK_VENDORS === $mode && isset($parsedMsg['triggering_file']) && self::inVendors($parsedMsg['triggering_file']); - } else { - $class = isset($trace[$i]['object']) ? \get_class($trace[$i]['object']) : $trace[$i]['class']; - $method = $trace[$i]['function']; - } - - $Test = self::$utilPrefix.'Test'; + if ($deprecation->originatesFromAnObject()) { + $class = $deprecation->originatingClass(); + $method = $deprecation->originatingMethod(); if (0 !== error_reporting()) { $group = 'unsilenced'; - } elseif (0 === strpos($method, 'testLegacy') - || 0 === strpos($method, 'provideLegacy') - || 0 === strpos($method, 'getLegacy') - || strpos($class, '\Legacy') - || \in_array('legacy', $Test::getGroups($class, $method), true) - ) { + } elseif ($deprecation->isLegacy(self::$utilPrefix)) { $group = 'legacy'; - } elseif ($isVendor) { - $group = 'remaining vendor'; + } elseif (!$deprecation->isSelf()) { + $group = $deprecation->isIndirect() ? 'remaining indirect' : 'remaining direct'; } else { - $group = 'remaining'; + $group = 'remaining self'; } - if (isset($mode[0]) && '/' === $mode[0] && preg_match($mode, $msg)) { - $e = new \Exception($msg); - $r = new \ReflectionProperty($e, 'trace'); - $r->setAccessible(true); - $r->setValue($e, \array_slice($trace, 1, $i)); - - echo "\n".ucfirst($group).' deprecation triggered by '.$class.'::'.$method.':'; - echo "\n".$msg; - echo "\nStack trace:"; - echo "\n".str_replace(' '.getcwd().\DIRECTORY_SEPARATOR, ' ', $e->getTraceAsString()); - echo "\n"; + if ($this->getConfiguration()->shouldDisplayStackTrace($msg)) { + echo "\n".ucfirst($group).' '.$deprecation->toString(); exit(1); } - - if ('legacy' !== $group && self::MODE_WEAK !== $mode) { + if ('legacy' !== $group) { $ref = &$this->deprecations[$group][$msg]['count']; ++$ref; $ref = &$this->deprecations[$group][$msg][$class.'::'.$method]; ++$ref; } - } elseif (self::MODE_WEAK !== $mode) { + } else { $ref = &$this->deprecations[$group][$msg]['count']; ++$ref; } @@ -190,9 +168,9 @@ public function handleError($type, $msg, $file, $line, $context = []) */ public function shutdown() { - $mode = $this->getMode(); + $configuration = $this->getConfiguration(); - if (isset($mode[0]) && '/' === $mode[0]) { + if ($configuration->isInRegexMode()) { return; } @@ -200,28 +178,22 @@ public function shutdown() restore_error_handler(); if ($currErrorHandler !== [$this, 'handleError']) { - echo "\n", self::colorize('THE ERROR HANDLER HAS CHANGED!', true, $mode), "\n"; - } - - $groups = ['unsilenced', 'remaining']; - - if (self::MODE_WEAK_VENDORS === $mode) { - $groups[] = 'remaining vendor'; + echo "\n", self::colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n"; } - array_push($groups, 'legacy', 'other'); + $groups = ['unsilenced', 'remaining self', 'remaining direct', 'remaining indirect', 'legacy', 'other']; - $this->displayDeprecations($groups, $mode); + $this->displayDeprecations($groups, $configuration); // store failing status - $isFailing = self::MODE_WEAK !== $mode && $mode < $this->deprecations['unsilencedCount'] + $this->deprecations['remainingCount'] + $this->deprecations['otherCount']; + $isFailing = !$configuration->tolerates($this->deprecations); // reset deprecations array foreach ($this->deprecations as $group => $arrayOrInt) { $this->deprecations[$group] = \is_int($arrayOrInt) ? 0 : []; } - register_shutdown_function(function () use ($isFailing, $groups, $mode) { + register_shutdown_function(function () use ($isFailing, $groups, $configuration) { foreach ($this->deprecations as $group => $arrayOrInt) { if (0 < (\is_int($arrayOrInt) ? $arrayOrInt : \count($arrayOrInt))) { echo "Shutdown-time deprecations:\n"; @@ -229,85 +201,55 @@ public function shutdown() } } - $this->displayDeprecations($groups, $mode); + $this->displayDeprecations($groups, $configuration); - if ($isFailing || self::MODE_WEAK !== $mode && $mode < $this->deprecations['unsilencedCount'] + $this->deprecations['remainingCount'] + $this->deprecations['otherCount']) { + if ($isFailing || !$configuration->tolerates($this->deprecations)) { exit(1); } }); } - private function getMode() + private function getConfiguration() { - if (false !== $this->resolvedMode) { - return $this->resolvedMode; + if (null !== $this->configuration) { + return $this->configuration; } - if (false === $mode = $this->mode) { $mode = getenv('SYMFONY_DEPRECATIONS_HELPER'); } - - if (self::MODE_DISABLED !== $mode - && self::MODE_WEAK !== $mode - && self::MODE_WEAK_VENDORS !== $mode - && (!isset($mode[0]) || '/' !== $mode[0]) - ) { - $mode = preg_match('/^[1-9][0-9]*$/', $mode) ? (int) $mode : 0; + if ('strict' === $mode) { + return $this->configuration = Configuration::inStrictMode(); } - - return $this->resolvedMode = $mode; - } - - /** - * @param string $path - * - * @return bool - */ - private static function inVendors($path) - { - /** @var string[] absolute paths to vendor directories */ - static $vendors; - - if (null === $vendors) { - foreach (get_declared_classes() as $class) { - if ('C' !== $class[0] || 0 !== strpos($class, 'ComposerAutoloaderInit')) { - continue; - } - - $r = new \ReflectionClass($class); - $v = \dirname(\dirname($r->getFileName())); - - if (file_exists($v.'/composer/installed.json')) { - $vendors[] = $v; - } - } + if (self::MODE_DISABLED === $mode) { + return $this->configuration = Configuration::inDisabledMode(); } - - $realPath = realpath($path); - - if (false === $realPath && '-' !== $path && 'Standard input code' !== $path) { - return true; + if ('weak' === $mode) { + return $this->configuration = Configuration::inWeakMode(); + } + if (self::MODE_WEAK_VENDORS === $mode) { + echo sprintf('Setting SYMFONY_DEPRECATIONS_HELPER to "%s" is deprecated in favor of "max[self]=0"', $mode).PHP_EOL; + exit(1); + } + if (isset($mode[0]) && '/' === $mode[0]) { + return $this->configuration = Configuration::fromRegex($mode); } - foreach ($vendors as $vendor) { - if (0 === strpos($realPath, $vendor) && false !== strpbrk(substr($realPath, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) { - return true; - } + if (preg_match('/^[1-9][0-9]*$/', (string) $mode)) { + return $this->configuration = Configuration::fromNumber($mode); } - return false; + return $this->configuration = Configuration::fromUrlEncodedString((string) $mode); } /** * @param string $str * @param bool $red - * @param mixed $mode * * @return string */ - private static function colorize($str, $red, $mode) + private static function colorize($str, $red) { - if (!self::hasColorSupport() || self::MODE_WEAK === $mode) { + if (!self::hasColorSupport()) { return $str; } @@ -317,36 +259,36 @@ private static function colorize($str, $red, $mode) } /** - * @param string[] $groups - * @param mixed $mode + * @param string[] $groups + * @param Configuration $configuration */ - private function displayDeprecations($groups, $mode) + private function displayDeprecations($groups, $configuration) { $cmp = function ($a, $b) { return $b['count'] - $a['count']; }; foreach ($groups as $group) { - if (!$this->deprecations[$group.'Count']) { - continue; - } + if ($this->deprecations[$group.'Count']) { + echo "\n", self::colorize( + sprintf('%s deprecation notices (%d)', ucfirst($group), $this->deprecations[$group.'Count']), + 'legacy' !== $group && 'remaining indirect' !== $group + ), "\n"; - echo "\n", self::colorize( - sprintf('%s deprecation notices (%d)', ucfirst($group), $this->deprecations[$group.'Count']), - 'legacy' !== $group && 'remaining vendor' !== $group, - $mode - ), "\n"; - - uasort($this->deprecations[$group], $cmp); + if (!$configuration->verboseOutput()) { + continue; + } + uasort($this->deprecations[$group], $cmp); - foreach ($this->deprecations[$group] as $msg => $notices) { - echo "\n ", $notices['count'], 'x: ', $msg, "\n"; + foreach ($this->deprecations[$group] as $msg => $notices) { + echo "\n ", $notices['count'], 'x: ', $msg, "\n"; - arsort($notices); + arsort($notices); - foreach ($notices as $method => $count) { - if ('count' !== $method) { - echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n"; + foreach ($notices as $method => $count) { + if ('count' !== $method) { + echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n"; + } } } } diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php new file mode 100644 index 0000000000000..069f815963b5d --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php @@ -0,0 +1,208 @@ +<?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\Bridge\PhpUnit\DeprecationErrorHandler; + +/** + * @internal + */ +class Configuration +{ + const GROUPS = ['total', 'indirect', 'direct', 'self']; + + /** + * @var int[] + */ + private $thresholds; + + /** + * @var string + */ + private $regex; + + /** + * @var bool + */ + private $enabled = true; + + /** + * @var bool + */ + private $verboseOutput = true; + + /** + * @param int[] $thresholds A hash associating groups to thresholds + * @param string $regex Will be matched against messages, to decide + * whether to display a stack trace + * @param bool $verboseOutput + */ + private function __construct(array $thresholds = [], $regex = '', $verboseOutput = true) + { + foreach ($thresholds as $group => $threshold) { + if (!\in_array($group, self::GROUPS, true)) { + throw new \InvalidArgumentException(sprintf('Unrecognized threshold "%s", expected one of "%s"', $group, implode('", "', self::GROUPS))); + } + if (!is_numeric($threshold)) { + throw new \InvalidArgumentException(sprintf('Threshold for group "%s" has invalid value "%s"', $group, $threshold)); + } + $this->thresholds[$group] = (int) $threshold; + } + if (isset($this->thresholds['direct'])) { + $this->thresholds += [ + 'self' => $this->thresholds['direct'], + ]; + } + if (isset($this->thresholds['indirect'])) { + $this->thresholds += [ + 'direct' => $this->thresholds['indirect'], + 'self' => $this->thresholds['indirect'], + ]; + } + foreach (self::GROUPS as $group) { + if (!isset($this->thresholds[$group])) { + $this->thresholds[$group] = 999999; + } + } + $this->regex = $regex; + $this->verboseOutput = $verboseOutput; + } + + /** + * @return bool + */ + public function isEnabled() + { + return $this->enabled; + } + + /** + * @param mixed[] $deprecations + * + * @return bool + */ + public function tolerates(array $deprecations) + { + $deprecationCounts = array_filter($deprecations, function ($key) { + return false !== strpos($key, 'Count') && false === strpos($key, 'legacy'); + }, ARRAY_FILTER_USE_KEY); + + if (array_sum($deprecationCounts) > $this->thresholds['total']) { + return false; + } + foreach (['self', 'direct', 'indirect'] as $deprecationType) { + if ($deprecationCounts['remaining '.$deprecationType.'Count'] > $this->thresholds[$deprecationType]) { + return false; + } + } + + return true; + } + + /** + * @param string $message + * + * @return bool + */ + public function shouldDisplayStackTrace($message) + { + return '' !== $this->regex && preg_match($this->regex, $message); + } + + /** + * @return bool + */ + public function isInRegexMode() + { + return '' !== $this->regex; + } + + /** + * @return bool + */ + public function verboseOutput() + { + return $this->verboseOutput; + } + + /** + * @param string $serializedConfiguration an encoded string, for instance + * max[total]=1234&max[indirect]=42 + * + * @return self + */ + public static function fromUrlEncodedString(string $serializedConfiguration) + { + parse_str($serializedConfiguration, $normalizedConfiguration); + foreach (array_keys($normalizedConfiguration) as $key) { + if (!\in_array($key, ['max', 'disabled', 'verbose'], true)) { + throw new \InvalidArgumentException(sprintf('Unknown configuration option "%s"', $key)); + } + } + + if (isset($normalizedConfiguration['disabled'])) { + return self::inDisabledMode(); + } + + $verboseOutput = true; + if (isset($normalizedConfiguration['verbose'])) { + $verboseOutput = (bool) $normalizedConfiguration['verbose']; + } + + return new self( + $normalizedConfiguration['max'] ?? [], + '', + $verboseOutput + ); + } + + /** + * @return self + */ + public static function inDisabledMode() + { + $configuration = new self(); + $configuration->enabled = false; + + return $configuration; + } + + /** + * @return self + */ + public static function inStrictMode() + { + return new self(['total' => 0]); + } + + /** + * @return self + */ + public static function inWeakMode() + { + return new self([], '', false); + } + + /** + * @return self + */ + public static function fromNumber(int $upperBound) + { + return new self(['total' => $upperBound]); + } + + /** + * @return self + */ + public static function fromRegex(string $regex) + { + return new self([], $regex); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php new file mode 100644 index 0000000000000..e267a3b8db46b --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php @@ -0,0 +1,291 @@ +<?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\Bridge\PhpUnit\DeprecationErrorHandler; + +use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor; + +/** + * @internal + */ +class Deprecation +{ + /** + * @var array + */ + private $trace; + + /** + * @var string + */ + private $message; + + /** + * @var ?string + */ + private $originClass; + + /** + * @var ?string + */ + private $originMethod; + + /** + * @var bool + */ + private $self; + + /** @var string[] absolute paths to vendor directories */ + private static $vendors; + + /** + * @param string $message + * @param string $file + */ + public function __construct($message, array $trace, $file) + { + $this->trace = $trace; + $this->message = $message; + $i = \count($trace); + while (1 < $i && $this->lineShouldBeSkipped($trace[--$i])) { + // No-op + } + $line = $trace[$i]; + $this->self = !$this->pathOriginatesFromVendor($file); + if (isset($line['object']) || isset($line['class'])) { + if (isset($line['class']) && 0 === strpos($line['class'], SymfonyTestsListenerFor::class)) { + $parsedMsg = unserialize($this->message); + $this->message = $parsedMsg['deprecation']; + $this->originClass = $parsedMsg['class']; + $this->originMethod = $parsedMsg['method']; + // If the deprecation has been triggered via + // \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest() + // then we need to use the serialized information to determine + // if the error has been triggered from vendor code. + $this->self = isset($parsedMsg['triggering_file']) + && $this->pathOriginatesFromVendor($parsedMsg['triggering_file']); + + return; + } + $this->originClass = isset($line['object']) ? \get_class($line['object']) : $line['class']; + $this->originMethod = $line['function']; + } + } + + /** + * @return bool + */ + private function lineShouldBeSkipped(array $line) + { + if (!isset($line['class'])) { + return true; + } + $class = $line['class']; + + return 'ReflectionMethod' === $class || 0 === strpos($class, 'PHPUnit_') || 0 === strpos($class, 'PHPUnit\\'); + } + + /** + * @return bool + */ + public function originatesFromAnObject() + { + return isset($this->originClass); + } + + /** + * @return bool + */ + public function isSelf() + { + return $this->self; + } + + /** + * @return string + */ + public function originatingClass() + { + if (null === $this->originClass) { + throw new \LogicException('Check with originatesFromAnObject() before calling this method'); + } + + return $this->originClass; + } + + /** + * @return string + */ + public function originatingMethod() + { + if (null === $this->originMethod) { + throw new \LogicException('Check with originatesFromAnObject() before calling this method'); + } + + return $this->originMethod; + } + + /** + * @param string $utilPrefix + * + * @return bool + */ + public function isLegacy($utilPrefix) + { + $test = $utilPrefix.'Test'; + $class = $this->originatingClass(); + $method = $this->originatingMethod(); + + return 0 === strpos($method, 'testLegacy') + || 0 === strpos($method, 'provideLegacy') + || 0 === strpos($method, 'getLegacy') + || strpos($class, '\Legacy') + || \in_array('legacy', $test::getGroups($class, $method), true); + } + + /** + * Tells whether both the calling package and the called package are vendor + * packages. + * + * @return bool + */ + public function isIndirect() + { + $erroringFile = $erroringPackage = null; + foreach ($this->trace as $line) { + if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) { + continue; + } + if (!isset($line['file'])) { + continue; + } + $file = $line['file']; + if ('-' === $file || 'Standard input code' === $file || !realpath($file)) { + continue; + } + if (!$this->pathOriginatesFromVendor($file)) { + return false; + } + if (null !== $erroringFile && null !== $erroringPackage) { + $package = $this->getPackage($file); + if ('composer' !== $package && $package !== $erroringPackage) { + return true; + } + continue; + } + $erroringFile = $file; + $erroringPackage = $this->getPackage($file); + } + + return false; + } + + /** + * pathOriginatesFromVendor() should always be called prior to calling this method. + * + * @param string $path + * + * @return string + */ + private function getPackage($path) + { + $path = realpath($path) ?: $path; + foreach (self::getVendors() as $vendorRoot) { + if (0 === strpos($path, $vendorRoot)) { + $relativePath = substr($path, \strlen($vendorRoot) + 1); + $vendor = strstr($relativePath, \DIRECTORY_SEPARATOR, true); + if (false === $vendor) { + throw new \RuntimeException(sprintf('Could not find directory separator "%s" in path "%s"', \DIRECTORY_SEPARATOR, $relativePath)); + } + + return rtrim($vendor.'/'.strstr(substr( + $relativePath, + \strlen($vendor) + 1 + ), \DIRECTORY_SEPARATOR, true), '/'); + } + } + + throw new \RuntimeException(sprintf('No vendors found for path "%s"', $path)); + } + + /** + * @return string[] an array of paths + */ + private static function getVendors() + { + if (null === self::$vendors) { + self::$vendors = []; + foreach (get_declared_classes() as $class) { + if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { + $r = new \ReflectionClass($class); + $v = \dirname(\dirname($r->getFileName())); + if (file_exists($v.'/composer/installed.json')) { + self::$vendors[] = $v; + } + } + } + } + + return self::$vendors; + } + + /** + * @param string $path + * + * @return bool + */ + private function pathOriginatesFromVendor($path) + { + $realPath = realpath($path); + if (false === $realPath && '-' !== $path && 'Standard input code' !== $path) { + return true; + } + foreach (self::getVendors() as $vendor) { + if (0 === strpos($realPath, $vendor) && false !== strpbrk(substr($realPath, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) { + return true; + } + } + + return false; + } + + /** + * @return string + */ + public function toString() + { + $exception = new \Exception($this->message); + $reflection = new \ReflectionProperty($exception, 'trace'); + $reflection->setAccessible(true); + $reflection->setValue($exception, $this->trace); + + return 'deprecation triggered by '.$this->originatingClass().'::'.$this->originatingMethod().':'. + "\n".$this->message. + "\nStack trace:". + "\n".str_replace(' '.getcwd().\DIRECTORY_SEPARATOR, ' ', $exception->getTraceAsString()). + "\n"; + } + + private function getPackageFromLine(array $line) + { + if (!isset($line['file'])) { + return 'internal function'; + } + if (!$this->pathOriginatesFromVendor($line['file'])) { + return 'source code'; + } + try { + return $this->getPackage($line['file']); + } catch (\RuntimeException $e) { + return 'unknown'; + } + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/ConfigurationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/ConfigurationTest.php new file mode 100644 index 0000000000000..39e792cd3a2cb --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/ConfigurationTest.php @@ -0,0 +1,195 @@ +<?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\Bridge\PhpUnit\Tests\DeprecationErrorHandler; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Configuration; + +class ConfigurationTest extends TestCase +{ + public function testItThrowsOnStringishValue() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('hi'); + Configuration::fromUrlEncodedString('hi'); + } + + public function testItThrowsOnUnknownConfigurationOption() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('min'); + Configuration::fromUrlEncodedString('min[total]=42'); + } + + public function testItThrowsOnUnknownThreshold() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('deep'); + Configuration::fromUrlEncodedString('max[deep]=42'); + } + + public function testItThrowsOnStringishThreshold() + { + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('forty-two'); + Configuration::fromUrlEncodedString('max[total]=forty-two'); + } + + public function testItNoticesExceededTotalThreshold() + { + $configuration = Configuration::fromUrlEncodedString('max[total]=3'); + $this->assertTrue($configuration->tolerates([ + 'unsilencedCount' => 1, + 'remaining selfCount' => 0, + 'legacyCount' => 1, + 'otherCount' => 0, + 'remaining directCount' => 1, + 'remaining indirectCount' => 1, + ])); + $this->assertFalse($configuration->tolerates([ + 'unsilencedCount' => 1, + 'remaining selfCount' => 1, + 'legacyCount' => 1, + 'otherCount' => 0, + 'remaining directCount' => 1, + 'remaining indirectCount' => 1, + ])); + } + + public function testItNoticesExceededSelfThreshold() + { + $configuration = Configuration::fromUrlEncodedString('max[self]=1'); + $this->assertTrue($configuration->tolerates([ + 'unsilencedCount' => 1234, + 'remaining selfCount' => 1, + 'legacyCount' => 23, + 'otherCount' => 13, + 'remaining directCount' => 124, + 'remaining indirectCount' => 3244, + ])); + $this->assertFalse($configuration->tolerates([ + 'unsilencedCount' => 1234, + 'remaining selfCount' => 2, + 'legacyCount' => 23, + 'otherCount' => 13, + 'remaining directCount' => 124, + 'remaining indirectCount' => 3244, + ])); + } + + public function testItNoticesExceededDirectThreshold() + { + $configuration = Configuration::fromUrlEncodedString('max[direct]=1&max[self]=999999'); + $this->assertTrue($configuration->tolerates([ + 'unsilencedCount' => 1234, + 'remaining selfCount' => 123, + 'legacyCount' => 23, + 'otherCount' => 13, + 'remaining directCount' => 1, + 'remaining indirectCount' => 3244, + ])); + $this->assertFalse($configuration->tolerates([ + 'unsilencedCount' => 1234, + 'remaining selfCount' => 124, + 'legacyCount' => 23, + 'otherCount' => 13, + 'remaining directCount' => 2, + 'remaining indirectCount' => 3244, + ])); + } + + public function testItNoticesExceededIndirectThreshold() + { + $configuration = Configuration::fromUrlEncodedString('max[indirect]=1&max[direct]=999999&max[self]=999999'); + $this->assertTrue($configuration->tolerates([ + 'unsilencedCount' => 1234, + 'remaining selfCount' => 123, + 'legacyCount' => 23, + 'otherCount' => 13, + 'remaining directCount' => 1234, + 'remaining indirectCount' => 1, + ])); + $this->assertFalse($configuration->tolerates([ + 'unsilencedCount' => 1234, + 'remaining selfCount' => 124, + 'legacyCount' => 23, + 'otherCount' => 13, + 'remaining directCount' => 2324, + 'remaining indirectCount' => 2, + ])); + } + + public function testIndirectThresholdIsUsedAsADefaultForDirectAndSelfThreshold() + { + $configuration = Configuration::fromUrlEncodedString('max[indirect]=1'); + $this->assertTrue($configuration->tolerates([ + 'unsilencedCount' => 0, + 'remaining selfCount' => 1, + 'legacyCount' => 0, + 'otherCount' => 0, + 'remaining directCount' => 0, + 'remaining indirectCount' => 0, + ])); + $this->assertFalse($configuration->tolerates([ + 'unsilencedCount' => 0, + 'remaining selfCount' => 2, + 'legacyCount' => 0, + 'otherCount' => 0, + 'remaining directCount' => 0, + 'remaining indirectCount' => 0, + ])); + $this->assertTrue($configuration->tolerates([ + 'unsilencedCount' => 0, + 'remaining selfCount' => 0, + 'legacyCount' => 0, + 'otherCount' => 0, + 'remaining directCount' => 1, + 'remaining indirectCount' => 0, + ])); + $this->assertFalse($configuration->tolerates([ + 'unsilencedCount' => 0, + 'remaining selfCount' => 0, + 'legacyCount' => 0, + 'otherCount' => 0, + 'remaining directCount' => 2, + 'remaining indirectCount' => 0, + ])); + } + + public function testItCanTellWhetherToDisplayAStackTrace() + { + $configuration = Configuration::fromUrlEncodedString(''); + $this->assertFalse($configuration->shouldDisplayStackTrace('interesting')); + + $configuration = Configuration::fromRegex('/^interesting/'); + $this->assertFalse($configuration->shouldDisplayStackTrace('uninteresting')); + $this->assertTrue($configuration->shouldDisplayStackTrace('interesting')); + } + + public function testItCanBeDisabled() + { + $configuration = Configuration::fromUrlEncodedString('disabled'); + $this->assertFalse($configuration->isEnabled()); + } + + public function testItCanBeShushed() + { + $configuration = Configuration::fromUrlEncodedString('verbose'); + $this->assertFalse($configuration->verboseOutput()); + } + + public function testOutputIsNotVerboseInWeakMode() + { + $configuration = Configuration::inWeakMode(); + $this->assertFalse($configuration->verboseOutput()); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php new file mode 100644 index 0000000000000..92bad71e08498 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php @@ -0,0 +1,60 @@ +<?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\Bridge\PhpUnit\Tests\DeprecationErrorHandler; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\DeprecationErrorHandler\Deprecation; + +class DeprecationTest extends TestCase +{ + public function testItCanDetermineTheClassWhereTheDeprecationHappened() + { + $deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__); + $this->assertTrue($deprecation->originatesFromAnObject()); + $this->assertSame(self::class, $deprecation->originatingClass()); + $this->assertSame(__FUNCTION__, $deprecation->originatingMethod()); + } + + public function testItCanTellWhetherItIsInternal() + { + $deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__); + $this->assertTrue($deprecation->isSelf()); + } + + public function testLegacyTestMethodIsDetectedAsSuch() + { + $deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__); + $this->assertTrue($deprecation->isLegacy('whatever')); + } + + public function testItCanBeConvertedToAString() + { + $deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__); + $this->assertContains('💩', $deprecation->toString()); + $this->assertContains(__FUNCTION__, $deprecation->toString()); + } + + public function testItRulesOutFilesOutsideVendorsAsIndirect() + { + $deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__); + $this->assertFalse($deprecation->isIndirect()); + } + + /** + * This method is here to simulate the extra level from the piece of code + * triggering an error to the error handler + */ + public function debugBacktrace(): array + { + return debug_backtrace(); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt index 7a0595a7ddebc..e9f7bec9664c6 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/default.phpt @@ -73,7 +73,7 @@ Unsilenced deprecation notices (3) 1x: unsilenced bar deprecation 1x in FooTestCase::testNonLegacyBar -Remaining deprecation notices (1) +Remaining self deprecation notices (1) 1x: silenced bar deprecation 1x in FooTestCase::testNonLegacyBar diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/regexp.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/deprecated_regexp.phpt similarity index 100% rename from src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/regexp.phpt rename to src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/deprecated_regexp.phpt diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/eval_not_self.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/eval_not_self.phpt new file mode 100644 index 0000000000000..8d823feb2c97e --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/eval_not_self.phpt @@ -0,0 +1,24 @@ +--TEST-- +Test eval()'d deprecation is not considered as self +--FILE-- +<?php + +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0'); +putenv('ANSICON'); +putenv('ConEmuANSI'); +putenv('TERM'); + +$vendor = __DIR__; +while (!file_exists($vendor.'/vendor')) { + $vendor = dirname($vendor); +} +define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php'); +require PHPUNIT_COMPOSER_INSTALL; +require_once __DIR__.'/../../bootstrap.php'; +eval("@trigger_error('who knows where I come from?', E_USER_DEPRECATED);"); + +?> +--EXPECTF-- +Other deprecation notices (1) + + 1x: who knows where I come from? diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/lib/SomeService.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/lib/SomeService.php new file mode 100644 index 0000000000000..6a354103ff3ce --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/lib/SomeService.php @@ -0,0 +1,14 @@ +<?php + +namespace acme\lib; + +class SomeService +{ + public function deprecatedApi() + { + @trigger_error( + __FUNCTION__.' is deprecated! You should stop relying on it!', + E_USER_DEPRECATED + ); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/outdated-lib/outdated_file.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/outdated-lib/outdated_file.php new file mode 100644 index 0000000000000..73d8d6a5782dc --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/fake_vendor/acme/outdated-lib/outdated_file.php @@ -0,0 +1,7 @@ +<?php +/* We have not caught up on the deprecations yet and still call the other lib + in a deprecated way. */ + +include __DIR__.'/../lib/SomeService.php'; +$defraculator = new \acme\lib\SomeService(); +$defraculator->deprecatedApi(); diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/lagging_vendor.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/lagging_vendor.phpt new file mode 100644 index 0000000000000..37488e1d160ec --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/lagging_vendor.phpt @@ -0,0 +1,38 @@ +--TEST-- +Test DeprecationErrorHandler in weak vendors mode on vendor file +--FILE-- +<?php + +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0&max[direct]=0'); +putenv('ANSICON'); +putenv('ConEmuANSI'); +putenv('TERM'); + +$vendor = __DIR__; +while (!file_exists($vendor.'/vendor')) { + $vendor = dirname($vendor); +} +define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php'); +require PHPUNIT_COMPOSER_INSTALL; +require_once __DIR__.'/../../bootstrap.php'; +eval(<<<'EOPHP' +namespace PHPUnit\Util; + +class Test +{ + public static function getGroups() + { + return array(); + } +} +EOPHP +); +require __DIR__.'/fake_vendor/autoload.php'; +require __DIR__.'/fake_vendor/acme/outdated-lib/outdated_file.php'; + +?> +--EXPECTF-- +Remaining indirect deprecation notices (1) + + 1x: deprecatedApi is deprecated! You should stop relying on it! + 1x in SomeService::deprecatedApi from acme\lib diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/quiet.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/quiet.phpt new file mode 100644 index 0000000000000..b7e22a711df20 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/quiet.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test DeprecationErrorHandler with quiet output +--FILE-- +<?php + +putenv('SYMFONY_DEPRECATIONS_HELPER=verbose=0'); +putenv('ANSICON'); +putenv('ConEmuANSI'); +putenv('TERM'); + +$vendor = __DIR__; +while (!file_exists($vendor.'/vendor')) { + $vendor = dirname($vendor); +} +define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php'); +require PHPUNIT_COMPOSER_INSTALL; +require_once __DIR__.'/../../bootstrap.php'; + +@trigger_error('root deprecation', E_USER_DEPRECATED); + +class FooTestCase +{ + public function testLegacyFoo() + { + @trigger_error('silenced foo deprecation', E_USER_DEPRECATED); + trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED); + } +} + +$foo = new FooTestCase(); +$foo->testLegacyFoo(); + +?> +--EXPECTF-- +Unsilenced deprecation notices (1) + +Legacy deprecation notices (1) + +Other deprecation notices (1) diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/self_on_non_vendor.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/self_on_non_vendor.phpt new file mode 100644 index 0000000000000..cb21ea8c21bd1 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/self_on_non_vendor.phpt @@ -0,0 +1,74 @@ +--TEST-- +Test DeprecationErrorHandler with no self deprecations on self deprecation +--FILE-- +<?php + +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0'); +putenv('ANSICON'); +putenv('ConEmuANSI'); +putenv('TERM'); + +$vendor = __DIR__; +while (!file_exists($vendor.'/vendor')) { + $vendor = dirname($vendor); +} +define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php'); +require PHPUNIT_COMPOSER_INSTALL; +require_once __DIR__.'/../../bootstrap.php'; + +@trigger_error('root deprecation', E_USER_DEPRECATED); + +eval(<<<'EOPHP' +namespace PHPUnit\Util; + +class Test +{ + public static function getGroups() + { + return array(); + } +} +EOPHP +); + +class FooTestCase +{ + public function testLegacyFoo() + { + @trigger_error('silenced foo deprecation', E_USER_DEPRECATED); + trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED); + trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED); + } + + public function testNonLegacyBar() + { + @trigger_error('silenced bar deprecation', E_USER_DEPRECATED); + trigger_error('unsilenced bar deprecation', E_USER_DEPRECATED); + } +} + +$foo = new FooTestCase(); +$foo->testLegacyFoo(); +$foo->testNonLegacyBar(); + +?> +--EXPECTF-- +Unsilenced deprecation notices (3) + + 2x: unsilenced foo deprecation + 2x in FooTestCase::testLegacyFoo + + 1x: unsilenced bar deprecation + 1x in FooTestCase::testNonLegacyBar + +Remaining self deprecation notices (1) + + 1x: silenced bar deprecation + 1x in FooTestCase::testNonLegacyBar + +Legacy deprecation notices (1) + +Other deprecation notices (1) + + 1x: root deprecation + diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/shutdown_deprecations.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/shutdown_deprecations.phpt index fddeed6085dea..46e9691085aac 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/shutdown_deprecations.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/shutdown_deprecations.phpt @@ -73,7 +73,7 @@ Unsilenced deprecation notices (3) 1x: unsilenced bar deprecation 1x in FooTestCase::testNonLegacyBar -Remaining deprecation notices (1) +Remaining self deprecation notices (1) 1x: silenced bar deprecation 1x in FooTestCase::testNonLegacyBar diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_eval_d_deprecation.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_eval_d_deprecation.phpt index 8390d16332fa1..ab513b646c15d 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_eval_d_deprecation.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_eval_d_deprecation.phpt @@ -3,7 +3,7 @@ Test DeprecationErrorHandler in weak vendors mode on eval()'d deprecation --FILE-- <?php -putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors'); +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0'); putenv('ANSICON'); putenv('ConEmuANSI'); putenv('TERM'); @@ -19,7 +19,6 @@ eval("@trigger_error('who knows where I come from?', E_USER_DEPRECATED);"); ?> --EXPECTF-- - Other deprecation notices (1) 1x: who knows where I come from? diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_non_vendor.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_non_vendor.phpt index e20c7adf6ba1f..4068a392b2c9f 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_non_vendor.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_non_vendor.phpt @@ -3,7 +3,7 @@ Test DeprecationErrorHandler in weak vendors mode on a non vendor file --FILE-- <?php -putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors'); +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0'); putenv('ANSICON'); putenv('ConEmuANSI'); putenv('TERM'); @@ -61,7 +61,7 @@ Unsilenced deprecation notices (3) 1x: unsilenced bar deprecation 1x in FooTestCase::testNonLegacyBar -Remaining deprecation notices (1) +Remaining self deprecation notices (1) 1x: silenced bar deprecation 1x in FooTestCase::testNonLegacyBar diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_phar_deprecation.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_phar_deprecation.phpt index 7a583f95337d9..3926b47f420f7 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_phar_deprecation.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_phar_deprecation.phpt @@ -1,10 +1,10 @@ --TEST-- -Test DeprecationErrorHandler in weak vendors mode on eval()'d deprecation +Test deprecations coming from a phar are not considered self deprecations The phar can be regenerated by running php src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/generate_phar.php --FILE-- <?php -putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors'); +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0'); putenv('ANSICON'); putenv('ConEmuANSI'); putenv('TERM'); @@ -21,7 +21,6 @@ include 'phar://deprecation.phar/deprecation.php'; ?> --EXPECTF-- - Other deprecation notices (1) 1x: I come from… afar! :D diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt index 68e233df7d0d9..cb707610574eb 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/weak_vendors_on_vendor.phpt @@ -1,9 +1,9 @@ --TEST-- -Test DeprecationErrorHandler in weak vendors mode on vendor file +Test DeprecationErrorHandler with no self deprecations on vendor deprecation --FILE-- <?php -putenv('SYMFONY_DEPRECATIONS_HELPER=weak_vendors'); +putenv('SYMFONY_DEPRECATIONS_HELPER=max[self]=0'); putenv('ANSICON'); putenv('ConEmuANSI'); putenv('TERM'); @@ -28,7 +28,7 @@ Unsilenced deprecation notices (3) 1x: unsilenced bar deprecation 1x in FooTestCase::testNonLegacyBar -Remaining vendor deprecation notices (1) +Remaining direct deprecation notices (1) 1x: silenced bar deprecation 1x in FooTestCase::testNonLegacyBar From b11585e31f8d461b2fb5407ed10a0de4abc420d2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Fri, 12 Apr 2019 15:46:34 +0200 Subject: [PATCH 473/495] [PhpUnitBridge] fixes --- src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php | 6 ++++-- .../PhpUnit/DeprecationErrorHandler/Configuration.php | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 9289b5e942065..542588c55adf8 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -227,8 +227,10 @@ private function getConfiguration() return $this->configuration = Configuration::inWeakMode(); } if (self::MODE_WEAK_VENDORS === $mode) { - echo sprintf('Setting SYMFONY_DEPRECATIONS_HELPER to "%s" is deprecated in favor of "max[self]=0"', $mode).PHP_EOL; - exit(1); + ++$this->deprecations['remaining selfCount']; + $msg = sprintf('Setting SYMFONY_DEPRECATIONS_HELPER to "%s" is deprecated in favor of "max[self]=0"', $mode); + $ref = &$this->deprecations['remaining self'][$msg]['count']; + ++$ref; } if (isset($mode[0]) && '/' === $mode[0]) { return $this->configuration = Configuration::fromRegex($mode); diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php index 069f815963b5d..20e8127a83340 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php @@ -16,8 +16,6 @@ */ class Configuration { - const GROUPS = ['total', 'indirect', 'direct', 'self']; - /** * @var int[] */ @@ -46,9 +44,11 @@ class Configuration */ private function __construct(array $thresholds = [], $regex = '', $verboseOutput = true) { + $groups = ['total', 'indirect', 'direct', 'self']; + foreach ($thresholds as $group => $threshold) { - if (!\in_array($group, self::GROUPS, true)) { - throw new \InvalidArgumentException(sprintf('Unrecognized threshold "%s", expected one of "%s"', $group, implode('", "', self::GROUPS))); + if (!\in_array($group, $groups, true)) { + throw new \InvalidArgumentException(sprintf('Unrecognized threshold "%s", expected one of "%s"', $group, implode('", "', $groups))); } if (!is_numeric($threshold)) { throw new \InvalidArgumentException(sprintf('Threshold for group "%s" has invalid value "%s"', $group, $threshold)); @@ -66,7 +66,7 @@ private function __construct(array $thresholds = [], $regex = '', $verboseOutput 'self' => $this->thresholds['indirect'], ]; } - foreach (self::GROUPS as $group) { + foreach ($groups as $group) { if (!isset($this->thresholds[$group])) { $this->thresholds[$group] = 999999; } From 2f73c2f66b54b376647b605ebd4fbd7f399b0ff9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Fri, 12 Apr 2019 15:55:35 +0200 Subject: [PATCH 474/495] fix --- src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index 542588c55adf8..a393868e9469c 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -231,6 +231,7 @@ private function getConfiguration() $msg = sprintf('Setting SYMFONY_DEPRECATIONS_HELPER to "%s" is deprecated in favor of "max[self]=0"', $mode); $ref = &$this->deprecations['remaining self'][$msg]['count']; ++$ref; + $mode = 'max[self]=0'; } if (isset($mode[0]) && '/' === $mode[0]) { return $this->configuration = Configuration::fromRegex($mode); From b34738bba672d412cdfcd87e3c12b640aebbb3c8 Mon Sep 17 00:00:00 2001 From: Amrouche Hamza <hamza@les-tilleuls.coop> Date: Fri, 12 Apr 2019 15:32:58 +0200 Subject: [PATCH 475/495] [PhpUnitBridge] ClockMock does not mock gmdate() --- src/Symfony/Bridge/PhpUnit/ClockMock.php | 15 ++++++++++++++- .../Bridge/PhpUnit/Tests/ClockMockTest.php | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/ClockMock.php b/src/Symfony/Bridge/PhpUnit/ClockMock.php index 14b482c87440d..10c7d8780ccc8 100644 --- a/src/Symfony/Bridge/PhpUnit/ClockMock.php +++ b/src/Symfony/Bridge/PhpUnit/ClockMock.php @@ -79,11 +79,20 @@ public static function date($format, $timestamp = null) return \date($format, $timestamp); } + public static function gmdate($format, $timestamp = null) + { + if (null === $timestamp) { + $timestamp = self::time(); + } + + return \gmdate($format, $timestamp); + } + public static function register($class) { $self = \get_called_class(); - $mockedNs = array(substr($class, 0, strrpos($class, '\\'))); + $mockedNs = [substr($class, 0, strrpos($class, '\\'))]; if (0 < strpos($class, '\\Tests\\')) { $ns = str_replace('\\Tests\\', '\\', $class); $mockedNs[] = substr($ns, 0, strrpos($ns, '\\')); @@ -122,6 +131,10 @@ function date(\$format, \$timestamp = null) return \\$self::date(\$format, \$timestamp); } +function gmdate(\$format, \$timestamp = null) +{ + return \\$self::gmdate(\$format, \$timestamp); +} EOPHP ); } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ClockMockTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ClockMockTest.php index 4c77e99f5e20f..5b92ccd8507e4 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/ClockMockTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/ClockMockTest.php @@ -62,4 +62,11 @@ public function testDate() { $this->assertSame('1234567890', date('U')); } + + public function testGmDate() + { + ClockMock::withClockMock(1555075769); + + $this->assertSame('1555075769', gmdate('U')); + } } From 770c7ddec42d797bfd7b312601594f89e46ff915 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Fri, 12 Apr 2019 16:49:44 +0200 Subject: [PATCH 476/495] [PhpUnitBridge] CS fix --- src/Symfony/Bridge/PhpUnit/ClockMock.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/ClockMock.php b/src/Symfony/Bridge/PhpUnit/ClockMock.php index 10c7d8780ccc8..534d906c1239f 100644 --- a/src/Symfony/Bridge/PhpUnit/ClockMock.php +++ b/src/Symfony/Bridge/PhpUnit/ClockMock.php @@ -92,7 +92,7 @@ public static function register($class) { $self = \get_called_class(); - $mockedNs = [substr($class, 0, strrpos($class, '\\'))]; + $mockedNs = array(substr($class, 0, strrpos($class, '\\'))); if (0 < strpos($class, '\\Tests\\')) { $ns = str_replace('\\Tests\\', '\\', $class); $mockedNs[] = substr($ns, 0, strrpos($ns, '\\')); From 08577f43984f532bedb5eb643ae993c11997ca09 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Fri, 12 Apr 2019 17:26:05 +0200 Subject: [PATCH 477/495] [PhpUnitBridge] fix PHP 5.5 support --- .../PhpUnit/DeprecationErrorHandler/Configuration.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php index 20e8127a83340..44f0341205aa7 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Configuration.php @@ -138,7 +138,7 @@ public function verboseOutput() * * @return self */ - public static function fromUrlEncodedString(string $serializedConfiguration) + public static function fromUrlEncodedString($serializedConfiguration) { parse_str($serializedConfiguration, $normalizedConfiguration); foreach (array_keys($normalizedConfiguration) as $key) { @@ -157,7 +157,7 @@ public static function fromUrlEncodedString(string $serializedConfiguration) } return new self( - $normalizedConfiguration['max'] ?? [], + isset($normalizedConfiguration['max']) ? $normalizedConfiguration['max'] : [], '', $verboseOutput ); @@ -193,7 +193,7 @@ public static function inWeakMode() /** * @return self */ - public static function fromNumber(int $upperBound) + public static function fromNumber($upperBound) { return new self(['total' => $upperBound]); } @@ -201,7 +201,7 @@ public static function fromNumber(int $upperBound) /** * @return self */ - public static function fromRegex(string $regex) + public static function fromRegex($regex) { return new self([], $regex); } From 9ae73b11a60655fe62f0473bd9257a78c0f09578 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rokas=20Mikalk=C4=97nas?= <rokas.mikalkenas@nfq.lt> Date: Sat, 13 Apr 2019 00:07:37 +0300 Subject: [PATCH 478/495] Missing use statement added in UniqueValidator. --- src/Symfony/Component/Validator/Constraints/UniqueValidator.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php index 72403b59bdc23..ce98cd73477c1 100644 --- a/src/Symfony/Component/Validator/Constraints/UniqueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UniqueValidator.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; /** From d6b67d469a8767d88d5745b11b711c644e340ffc Mon Sep 17 00:00:00 2001 From: Roland Franssen <franssen.roland@gmail.com> Date: Fri, 12 Oct 2018 21:48:56 +0200 Subject: [PATCH 479/495] [Intl] Simplify API --- UPGRADE-4.3.md | 9 + UPGRADE-5.0.md | 9 + .../Form/Extension/Core/Type/CountryType.php | 6 +- .../Form/Extension/Core/Type/CurrencyType.php | 6 +- .../Form/Extension/Core/Type/LanguageType.php | 6 +- .../Form/Extension/Core/Type/LocaleType.php | 6 +- src/Symfony/Component/Form/composer.json | 3 +- src/Symfony/Component/Intl/CHANGELOG.md | 9 + src/Symfony/Component/Intl/Currencies.php | 117 +++ .../Data/Provider/CurrencyDataProvider.php | 2 +- .../Data/Provider/LanguageDataProvider.php | 2 +- .../Intl/Data/Provider/LocaleDataProvider.php | 2 +- .../Intl/Data/Provider/RegionDataProvider.php | 2 +- .../Intl/Data/Provider/ScriptDataProvider.php | 2 +- src/Symfony/Component/Intl/Intl.php | 22 +- src/Symfony/Component/Intl/Languages.php | 79 ++ src/Symfony/Component/Intl/Locales.php | 68 ++ .../Intl/NumberFormatter/NumberFormatter.php | 10 +- src/Symfony/Component/Intl/Regions.php | 60 ++ src/Symfony/Component/Intl/ResourceBundle.php | 76 ++ .../Intl/ResourceBundle/CurrencyBundle.php | 2 +- .../CurrencyBundleInterface.php | 2 + .../Intl/ResourceBundle/LanguageBundle.php | 2 +- .../LanguageBundleInterface.php | 2 + .../Intl/ResourceBundle/LocaleBundle.php | 2 +- .../ResourceBundle/LocaleBundleInterface.php | 2 + .../Intl/ResourceBundle/RegionBundle.php | 2 +- .../ResourceBundle/RegionBundleInterface.php | 2 + .../ResourceBundleInterface.php | 2 + src/Symfony/Component/Intl/Scripts.php | 60 ++ .../Component/Intl/Tests/CurrenciesTest.php | 789 +++++++++++++++ .../AbstractCurrencyDataProviderTest.php | 2 + .../Provider/AbstractDataProviderTest.php | 2 + .../AbstractLanguageDataProviderTest.php | 2 + .../AbstractLocaleDataProviderTest.php | 2 + .../AbstractRegionDataProviderTest.php | 2 + .../AbstractScriptDataProviderTest.php | 1 + .../Json/JsonCurrencyDataProviderTest.php | 1 + .../Json/JsonLanguageDataProviderTest.php | 1 + .../Json/JsonLocaleDataProviderTest.php | 1 + .../Json/JsonRegionDataProviderTest.php | 1 + .../Json/JsonScriptDataProviderTest.php | 1 + src/Symfony/Component/Intl/Tests/IntlTest.php | 13 + .../Component/Intl/Tests/LanguagesTest.php | 918 ++++++++++++++++++ .../Component/Intl/Tests/LocalesTest.php | 87 ++ .../Component/Intl/Tests/RegionsTest.php | 346 +++++++ .../Intl/Tests/ResourceBundleTestCase.php | 751 ++++++++++++++ .../Component/Intl/Tests/ScriptsTest.php | 277 ++++++ .../Component/Validator/Constraints/Bic.php | 4 +- .../Validator/Constraints/BicValidator.php | 6 +- .../Validator/Constraints/Country.php | 4 +- .../Constraints/CountryValidator.php | 7 +- .../Validator/Constraints/Currency.php | 4 +- .../Constraints/CurrencyValidator.php | 7 +- .../Validator/Constraints/Language.php | 4 +- .../Constraints/LanguageValidator.php | 7 +- .../Validator/Constraints/Locale.php | 4 +- .../Validator/Constraints/LocaleValidator.php | 5 +- src/Symfony/Component/Validator/composer.json | 4 +- 59 files changed, 3767 insertions(+), 60 deletions(-) create mode 100644 src/Symfony/Component/Intl/Currencies.php create mode 100644 src/Symfony/Component/Intl/Languages.php create mode 100644 src/Symfony/Component/Intl/Locales.php create mode 100644 src/Symfony/Component/Intl/Regions.php create mode 100644 src/Symfony/Component/Intl/ResourceBundle.php create mode 100644 src/Symfony/Component/Intl/Scripts.php create mode 100644 src/Symfony/Component/Intl/Tests/CurrenciesTest.php create mode 100644 src/Symfony/Component/Intl/Tests/LanguagesTest.php create mode 100644 src/Symfony/Component/Intl/Tests/LocalesTest.php create mode 100644 src/Symfony/Component/Intl/Tests/RegionsTest.php create mode 100644 src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php create mode 100644 src/Symfony/Component/Intl/Tests/ScriptsTest.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 7442600260a8c..d0bd5cefe5ea4 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -94,6 +94,15 @@ HttpKernel * Renamed `PostResponseEvent` to `TerminateEvent` * Deprecated `TranslatorListener` in favor of `LocaleAwareListener` +Intl +---- + + * Deprecated `ResourceBundle` namespace + * Deprecated `Intl::getCurrencyBundle()`, use `Currencies` instead + * Deprecated `Intl::getLanguageBundle()`, use `Languages` or `Scripts` instead + * Deprecated `Intl::getLocaleBundle()`, use `Locales` instead + * Deprecated `Intl::getRegionBundle()`, use `Regions` instead + Messenger --------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index b163e76678286..e8c479c6bc332 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -237,6 +237,15 @@ HttpKernel * Removed `PostResponseEvent`, use `TerminateEvent` instead * Removed `TranslatorListener` in favor of `LocaleAwareListener` +Intl +---- + + * Removed `ResourceBundle` namespace + * Removed `Intl::getLanguageBundle()`, use `Languages` or `Scripts` instead + * Removed `Intl::getCurrencyBundle()`, use `Currencies` instead + * Removed `Intl::getLocaleBundle()`, use `Locales` instead + * Removed `Intl::getRegionBundle()`, use `Regions` instead + Messenger --------- diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index 2373dee5ff908..ff50c2fb00fef 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getRegionBundle()->getCountryNames($choiceTranslationLocale)); + return array_flip(Regions::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getRegionBundle()->getCountryNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Regions::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php index 134d568e4d174..486bdc7b20206 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Currencies; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getCurrencyBundle()->getCurrencyNames($choiceTranslationLocale)); + return array_flip(Currencies::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getCurrencyBundle()->getCurrencyNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Currencies::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php index 88761598ab84b..4a0cbe1f8f459 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Languages; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getLanguageBundle()->getLanguageNames($choiceTranslationLocale)); + return array_flip(Languages::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getLanguageBundle()->getLanguageNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Languages::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index 853f98a928c25..41e016df1008b 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -15,7 +15,7 @@ use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\Loader\IntlCallbackChoiceLoader; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Locales; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) $choiceTranslationLocale = $options['choice_translation_locale']; return new IntlCallbackChoiceLoader(function () use ($choiceTranslationLocale) { - return array_flip(Intl::getLocaleBundle()->getLocaleNames($choiceTranslationLocale)); + return array_flip(Locales::getNames($choiceTranslationLocale)); }); }, 'choice_translation_domain' => false, @@ -83,7 +83,7 @@ public function loadChoiceList($value = null) return $this->choiceList; } - return $this->choiceList = new ArrayChoiceList(array_flip(Intl::getLocaleBundle()->getLocaleNames()), $value); + return $this->choiceList = new ArrayChoiceList(array_flip(Locales::getNames()), $value); } /** diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index 6de2563a7bb09..d448e77e5a7fe 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.1.3", "symfony/event-dispatcher": "^4.3", - "symfony/intl": "~3.4|~4.0", + "symfony/intl": "^4.3", "symfony/options-resolver": "~4.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", @@ -43,6 +43,7 @@ "symfony/doctrine-bridge": "<3.4", "symfony/framework-bundle": "<3.4", "symfony/http-kernel": "<4.3", + "symfony/intl": "<4.3", "symfony/translation": "<4.2", "symfony/twig-bridge": "<3.4.5|<4.0.5,>=4.0" }, diff --git a/src/Symfony/Component/Intl/CHANGELOG.md b/src/Symfony/Component/Intl/CHANGELOG.md index 4a61ee7178fab..7c8d46745533d 100644 --- a/src/Symfony/Component/Intl/CHANGELOG.md +++ b/src/Symfony/Component/Intl/CHANGELOG.md @@ -1,6 +1,15 @@ CHANGELOG ========= +4.3.0 +----- + + * deprecated `ResourceBundle` namespace + * added `Currencies` in favor of `Intl::getCurrencyBundle()` + * added `Languages` and `Scripts` in favor of `Intl::getLanguageBundle()` + * added `Locales` in favor of `Intl::getLocaleBundle()` + * added `Regions` in favor of `Intl::getRegionBundle()` + 4.2.0 ----- diff --git a/src/Symfony/Component/Intl/Currencies.php b/src/Symfony/Component/Intl/Currencies.php new file mode 100644 index 0000000000000..5d6a4b06cce63 --- /dev/null +++ b/src/Symfony/Component/Intl/Currencies.php @@ -0,0 +1,117 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to currency-related ICU data. + * + * @author Bernhard Schussek <bschussek@gmail.com> + * @author Roland Franssen <franssen.roland@gmail.com> + */ +final class Currencies extends ResourceBundle +{ + private const INDEX_SYMBOL = 0; + private const INDEX_NAME = 1; + private const INDEX_FRACTION_DIGITS = 0; + private const INDEX_ROUNDING_INCREMENT = 1; + + /** + * @return string[] + */ + public static function getCurrencyCodes(): array + { + return self::readEntry(['Currencies'], 'meta'); + } + + public static function exists(string $currency): bool + { + try { + self::readEntry(['Names', $currency, self::INDEX_NAME]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $currency, string $displayLocale = null): string + { + return self::readEntry(['Names', $currency, self::INDEX_NAME], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames(string $displayLocale = null): array + { + // ==================================================================== + // For reference: It is NOT possible to return names indexed by + // numeric code here, because some numeric codes map to multiple + // 3-letter codes (e.g. 32 => "ARA", "ARP", "ARS") + // ==================================================================== + + $names = self::readEntry(['Names'], $displayLocale); + + if ($names instanceof \Traversable) { + $names = iterator_to_array($names); + } + + array_walk($names, function (&$value) { + $value = $value[self::INDEX_NAME]; + }); + + return self::asort($names, $displayLocale); + } + + public static function getSymbol(string $currency, string $displayLocale = null): string + { + return self::readEntry(['Names', $currency, self::INDEX_SYMBOL], $displayLocale); + } + + public static function getFractionDigits(string $currency): int + { + try { + return self::readEntry(['Meta', $currency, self::INDEX_FRACTION_DIGITS], 'meta'); + } catch (MissingResourceException $e) { + return self::readEntry(['Meta', 'DEFAULT', self::INDEX_FRACTION_DIGITS], 'meta'); + } + } + + /** + * @return float|int + */ + public static function getRoundingIncrement(string $currency) + { + try { + return self::readEntry(['Meta', $currency, self::INDEX_ROUNDING_INCREMENT], 'meta'); + } catch (MissingResourceException $e) { + return self::readEntry(['Meta', 'DEFAULT', self::INDEX_ROUNDING_INCREMENT], 'meta'); + } + } + + public static function getNumericCode(string $currency): int + { + return self::readEntry(['Alpha3ToNumeric', $currency], 'meta'); + } + + public static function forNumericCode(int $numericCode): array + { + return self::readEntry(['NumericToAlpha3', (string) $numericCode], 'meta'); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::CURRENCY_DIR; + } +} diff --git a/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php index 61814dfda3058..d4ee9af69b206 100644 --- a/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/CurrencyDataProvider.php @@ -20,7 +20,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class CurrencyDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php index 60a364b6447b0..b507f25b8f0d0 100644 --- a/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/LanguageDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class LanguageDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php index f42be225bcc5b..216ede8810f00 100644 --- a/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/LocaleDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class LocaleDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php index f45cae16a1f18..bf6a634aa200a 100644 --- a/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/RegionDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class RegionDataProvider { diff --git a/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php b/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php index 43651cae591d0..9f1ed1711f186 100644 --- a/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php +++ b/src/Symfony/Component/Intl/Data/Provider/ScriptDataProvider.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class ScriptDataProvider { diff --git a/src/Symfony/Component/Intl/Intl.php b/src/Symfony/Component/Intl/Intl.php index 70fc55697a841..7d121971e880d 100644 --- a/src/Symfony/Component/Intl/Intl.php +++ b/src/Symfony/Component/Intl/Intl.php @@ -113,14 +113,18 @@ public static function isExtensionLoaded() * Returns the bundle containing currency information. * * @return CurrencyBundleInterface The currency resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Currencies} instead. */ public static function getCurrencyBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Currencies::class), E_USER_DEPRECATED); + if (null === self::$currencyBundle) { self::$currencyBundle = new CurrencyBundle( self::getDataDirectory().'/'.self::CURRENCY_DIR, self::getEntryReader(), - self::getLocaleBundle() + self::$localeBundle ?? self::$localeBundle = new LocaleBundle(self::getDataDirectory().'/'.self::LOCALE_DIR, self::getEntryReader()) ); } @@ -131,14 +135,18 @@ public static function getCurrencyBundle() * Returns the bundle containing language information. * * @return LanguageBundleInterface The language resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Languages} or {@see Scripts} instead. */ public static function getLanguageBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" or "%s" instead.', __METHOD__, Languages::class, Scripts::class), E_USER_DEPRECATED); + if (null === self::$languageBundle) { self::$languageBundle = new LanguageBundle( self::getDataDirectory().'/'.self::LANGUAGE_DIR, self::getEntryReader(), - self::getLocaleBundle(), + self::$localeBundle ?? self::$localeBundle = new LocaleBundle(self::getDataDirectory().'/'.self::LOCALE_DIR, self::getEntryReader()), new ScriptDataProvider( self::getDataDirectory().'/'.self::SCRIPT_DIR, self::getEntryReader() @@ -153,9 +161,13 @@ public static function getLanguageBundle() * Returns the bundle containing locale information. * * @return LocaleBundleInterface The locale resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Locales} instead. */ public static function getLocaleBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Locales::class), E_USER_DEPRECATED); + if (null === self::$localeBundle) { self::$localeBundle = new LocaleBundle( self::getDataDirectory().'/'.self::LOCALE_DIR, @@ -170,14 +182,18 @@ public static function getLocaleBundle() * Returns the bundle containing region information. * * @return RegionBundleInterface The region resource bundle + * + * @deprecated since Symfony 4.3, to be removed in 5.0. Use {@see Regions} instead. */ public static function getRegionBundle() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.3, use "%s" instead.', __METHOD__, Regions::class), E_USER_DEPRECATED); + if (null === self::$regionBundle) { self::$regionBundle = new RegionBundle( self::getDataDirectory().'/'.self::REGION_DIR, self::getEntryReader(), - self::getLocaleBundle() + self::$localeBundle ?? self::$localeBundle = new LocaleBundle(self::getDataDirectory().'/'.self::LOCALE_DIR, self::getEntryReader()) ); } diff --git a/src/Symfony/Component/Intl/Languages.php b/src/Symfony/Component/Intl/Languages.php new file mode 100644 index 0000000000000..64d85a6ade3ec --- /dev/null +++ b/src/Symfony/Component/Intl/Languages.php @@ -0,0 +1,79 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to language-related ICU data. + * + * @author Bernhard Schussek <bschussek@gmail.com> + * @author Roland Franssen <franssen.roland@gmail.com> + */ +final class Languages extends ResourceBundle +{ + /** + * Returns all available languages. + * + * Languages are returned as lowercase ISO 639-1 two-letter language codes. + * For languages that don't have a two-letter code, the ISO 639-2 + * three-letter code is used instead. + * + * A full table of ISO 639 language codes can be found here: + * http://www-01.sil.org/iso639-3/codes.asp + * + * @return string[] an array of canonical ISO 639 language codes + */ + public static function getLanguageCodes(): array + { + return self::readEntry(['Languages'], 'meta'); + } + + public static function exists(string $language): bool + { + try { + self::readEntry(['Names', $language]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $language, string $displayLocale = null): string + { + return self::readEntry(['Names', $language], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames(string $displayLocale = null): array + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + /** + * Returns the ISO 639-2 three-letter code of a language. + * + * @throws MissingResourceException if the language has no corresponding three-letter code + */ + public static function getAlpha3Code(string $language): string + { + return self::readEntry(['Alpha2ToAlpha3', $language], 'meta'); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::LANGUAGE_DIR; + } +} diff --git a/src/Symfony/Component/Intl/Locales.php b/src/Symfony/Component/Intl/Locales.php new file mode 100644 index 0000000000000..980c8f8b6b679 --- /dev/null +++ b/src/Symfony/Component/Intl/Locales.php @@ -0,0 +1,68 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to locale-related ICU data. + * + * @author Bernhard Schussek <bschussek@gmail.com> + * @author Roland Franssen <franssen.roland@gmail.com> + */ +final class Locales extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getLocales(): array + { + return self::readEntry(['Locales'], 'meta'); + } + + /** + * @return string[] + */ + public static function getAliases(): array + { + return self::readEntry(['Aliases'], 'meta'); + } + + public static function exists(string $locale): bool + { + try { + self::readEntry(['Names', $locale]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $locale, string $displayLocale = null): string + { + return self::readEntry(['Names', $locale], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames($displayLocale = null) + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::LOCALE_DIR; + } +} diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index c668d9a3c13ca..9f644ef8cd6ae 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Intl\NumberFormatter; +use Symfony\Component\Intl\Currencies; use Symfony\Component\Intl\Exception\MethodArgumentNotImplementedException; use Symfony\Component\Intl\Exception\MethodArgumentValueNotImplementedException; use Symfony\Component\Intl\Exception\MethodNotImplementedException; use Symfony\Component\Intl\Exception\NotImplementedException; use Symfony\Component\Intl\Globals\IntlGlobals; -use Symfony\Component\Intl\Intl; use Symfony\Component\Intl\Locale\Locale; /** @@ -318,8 +318,8 @@ public function formatCurrency($value, $currency) return $this->format($value); } - $symbol = Intl::getCurrencyBundle()->getCurrencySymbol($currency, 'en'); - $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency); + $symbol = Currencies::getSymbol($currency, 'en'); + $fractionDigits = Currencies::getFractionDigits($currency); $value = $this->roundCurrency($value, $currency); @@ -682,8 +682,8 @@ protected function resetError() */ private function roundCurrency($value, $currency) { - $fractionDigits = Intl::getCurrencyBundle()->getFractionDigits($currency); - $roundingIncrement = Intl::getCurrencyBundle()->getRoundingIncrement($currency); + $fractionDigits = Currencies::getFractionDigits($currency); + $roundingIncrement = Currencies::getRoundingIncrement($currency); // Round with the formatter rounding mode $value = $this->round($value, $fractionDigits); diff --git a/src/Symfony/Component/Intl/Regions.php b/src/Symfony/Component/Intl/Regions.php new file mode 100644 index 0000000000000..b3606c0b30197 --- /dev/null +++ b/src/Symfony/Component/Intl/Regions.php @@ -0,0 +1,60 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to region-related ICU data. + * + * @author Bernhard Schussek <bschussek@gmail.com> + * @author Roland Franssen <franssen.roland@gmail.com> + */ +final class Regions extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getRegionCodes(): array + { + return self::readEntry(['Regions'], 'meta'); + } + + public static function exists(string $region): bool + { + try { + self::readEntry(['Names', $region]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $region, string $displayLocale = null): string + { + return self::readEntry(['Names', $region], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames($displayLocale = null) + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::REGION_DIR; + } +} diff --git a/src/Symfony/Component/Intl/ResourceBundle.php b/src/Symfony/Component/Intl/ResourceBundle.php new file mode 100644 index 0000000000000..46115838cdb7a --- /dev/null +++ b/src/Symfony/Component/Intl/ResourceBundle.php @@ -0,0 +1,76 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Data\Bundle\Reader\BufferedBundleReader; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReader; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleEntryReaderInterface; +use Symfony\Component\Intl\Data\Bundle\Reader\JsonBundleReader; + +/** + * @author Roland Franssen <franssen.roland@gmail.com> + * + * @internal + */ +abstract class ResourceBundle +{ + private static $entryReader; + + abstract protected static function getPath(): string; + + /** + * Reads an entry from a resource bundle. + * + * @see BundleEntryReaderInterface::readEntry() + * + * @param string[] $indices The indices to read from the bundle + * @param string $locale The locale to read + * @param bool $fallback Whether to merge the value with the value from + * the fallback locale (e.g. "en" for "en_GB"). + * Only applicable if the result is multivalued + * (i.e. array or \ArrayAccess) or cannot be found + * in the requested locale. + * + * @return mixed returns an array or {@link \ArrayAccess} instance for + * complex data and a scalar value for simple data + */ + final protected static function readEntry(array $indices, string $locale = null, bool $fallback = true) + { + if (null === self::$entryReader) { + self::$entryReader = new BundleEntryReader(new BufferedBundleReader( + new JsonBundleReader(), + Intl::BUFFER_SIZE + )); + + $localeAliases = self::$entryReader->readEntry(Intl::getDataDirectory().'/'.Intl::LOCALE_DIR, 'meta', ['Aliases']); + self::$entryReader->setLocaleAliases($localeAliases instanceof \Traversable ? iterator_to_array($localeAliases) : $localeAliases); + } + + return self::$entryReader->readEntry(static::getPath(), $locale ?? \Locale::getDefault(), $indices, $fallback); + } + + final protected static function asort(iterable $list, string $locale = null): array + { + if ($list instanceof \Traversable) { + $list = iterator_to_array($list); + } + + $collator = new \Collator($locale ?? \Locale::getDefault()); + $collator->asort($list); + + return $list; + } + + private function __construct() + { + } +} diff --git a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php index 86e020570f7ac..b7ea33ea58574 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php @@ -21,7 +21,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class CurrencyBundle extends CurrencyDataProvider implements CurrencyBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php index eb82f6849e6a4..421973b9fed31 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to currency-related ICU data. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface CurrencyBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php index b2fbde3fe5430..eabd94821db2c 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php @@ -22,7 +22,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class LanguageBundle extends LanguageDataProvider implements LanguageBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php index aa0c3e0f2c0b6..ab2c1805d145b 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to language-related ICU data. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface LanguageBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php index 078b1de2ddd8e..19acc41782cf2 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php @@ -19,7 +19,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class LocaleBundle extends LocaleDataProvider implements LocaleBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php index 6fa4e5c0abbf5..f7791adcbfec7 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to locale-related ICU data. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface LocaleBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php b/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php index b5717a000f205..4cb34c2a09dda 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php @@ -21,7 +21,7 @@ * * @author Bernhard Schussek <bschussek@gmail.com> * - * @internal + * @internal to be removed in 5.0. */ class RegionBundle extends RegionDataProvider implements RegionBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php index 12d0dd240824c..a417dbb3812da 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/RegionBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to region-related ICU data. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface RegionBundleInterface extends ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php b/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php index 5c4c97483da94..37ef2648bddc9 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php +++ b/src/Symfony/Component/Intl/ResourceBundle/ResourceBundleInterface.php @@ -15,6 +15,8 @@ * Gives access to ICU data. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, to be removed in 5.0. */ interface ResourceBundleInterface { diff --git a/src/Symfony/Component/Intl/Scripts.php b/src/Symfony/Component/Intl/Scripts.php new file mode 100644 index 0000000000000..b01ff848efb97 --- /dev/null +++ b/src/Symfony/Component/Intl/Scripts.php @@ -0,0 +1,60 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to script-related ICU data. + * + * @author Bernhard Schussek <bschussek@gmail.com> + * @author Roland Franssen <franssen.roland@gmail.com> + */ +final class Scripts extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getScriptCodes(): array + { + return self::readEntry(['Scripts'], 'meta'); + } + + public static function exists(string $script): bool + { + try { + self::readEntry(['Names', $script]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $script, string $displayLocale = null): string + { + return self::readEntry(['Names', $script], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames($displayLocale = null) + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::SCRIPT_DIR; + } +} diff --git a/src/Symfony/Component/Intl/Tests/CurrenciesTest.php b/src/Symfony/Component/Intl/Tests/CurrenciesTest.php new file mode 100644 index 0000000000000..1f1a4e567b7a8 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/CurrenciesTest.php @@ -0,0 +1,789 @@ +<?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\Component\Intl\Tests; + +use Symfony\Component\Intl\Currencies; +use Symfony\Component\Intl\Locale; + +/** + * @group intl-data + */ +class CurrenciesTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $currencies = [ + 'ADP', + 'AED', + 'AFA', + 'AFN', + 'ALK', + 'ALL', + 'AMD', + 'ANG', + 'AOA', + 'AOK', + 'AON', + 'AOR', + 'ARA', + 'ARL', + 'ARM', + 'ARP', + 'ARS', + 'ATS', + 'AUD', + 'AWG', + 'AZM', + 'AZN', + 'BAD', + 'BAM', + 'BAN', + 'BBD', + 'BDT', + 'BEC', + 'BEF', + 'BEL', + 'BGL', + 'BGM', + 'BGN', + 'BGO', + 'BHD', + 'BIF', + 'BMD', + 'BND', + 'BOB', + 'BOL', + 'BOP', + 'BOV', + 'BRB', + 'BRC', + 'BRE', + 'BRL', + 'BRN', + 'BRR', + 'BRZ', + 'BSD', + 'BTN', + 'BUK', + 'BWP', + 'BYB', + 'BYN', + 'BYR', + 'BZD', + 'CAD', + 'CDF', + 'CHE', + 'CHF', + 'CHW', + 'CLE', + 'CLF', + 'CLP', + 'CNH', + 'CNX', + 'CNY', + 'COP', + 'COU', + 'CRC', + 'CSD', + 'CSK', + 'CUC', + 'CUP', + 'CVE', + 'CYP', + 'CZK', + 'DDM', + 'DEM', + 'DJF', + 'DKK', + 'DOP', + 'DZD', + 'ECS', + 'ECV', + 'EEK', + 'EGP', + 'ERN', + 'ESA', + 'ESB', + 'ESP', + 'ETB', + 'EUR', + 'FIM', + 'FJD', + 'FKP', + 'FRF', + 'GBP', + 'GEK', + 'GEL', + 'GHC', + 'GHS', + 'GIP', + 'GMD', + 'GNF', + 'GNS', + 'GQE', + 'GRD', + 'GTQ', + 'GWE', + 'GWP', + 'GYD', + 'HKD', + 'HNL', + 'HRD', + 'HRK', + 'HTG', + 'HUF', + 'IDR', + 'IEP', + 'ILP', + 'ILR', + 'ILS', + 'INR', + 'IQD', + 'IRR', + 'ISJ', + 'ISK', + 'ITL', + 'JMD', + 'JOD', + 'JPY', + 'KES', + 'KGS', + 'KHR', + 'KMF', + 'KPW', + 'KRH', + 'KRO', + 'KRW', + 'KWD', + 'KYD', + 'KZT', + 'LAK', + 'LBP', + 'LKR', + 'LRD', + 'LSL', + 'LTL', + 'LTT', + 'LUC', + 'LUF', + 'LUL', + 'LVL', + 'LVR', + 'LYD', + 'MAD', + 'MAF', + 'MCF', + 'MDC', + 'MDL', + 'MGA', + 'MGF', + 'MKD', + 'MKN', + 'MLF', + 'MMK', + 'MNT', + 'MOP', + 'MRO', + 'MRU', + 'MTL', + 'MTP', + 'MUR', + 'MVP', + 'MVR', + 'MWK', + 'MXN', + 'MXP', + 'MXV', + 'MYR', + 'MZE', + 'MZM', + 'MZN', + 'NAD', + 'NGN', + 'NIC', + 'NIO', + 'NLG', + 'NOK', + 'NPR', + 'NZD', + 'OMR', + 'PAB', + 'PEI', + 'PEN', + 'PES', + 'PGK', + 'PHP', + 'PKR', + 'PLN', + 'PLZ', + 'PTE', + 'PYG', + 'QAR', + 'RHD', + 'ROL', + 'RON', + 'RSD', + 'RUB', + 'RUR', + 'RWF', + 'SAR', + 'SBD', + 'SCR', + 'SDD', + 'SDG', + 'SDP', + 'SEK', + 'SGD', + 'SHP', + 'SIT', + 'SKK', + 'SLL', + 'SOS', + 'SRD', + 'SRG', + 'SSP', + 'STD', + 'STN', + 'SUR', + 'SVC', + 'SYP', + 'SZL', + 'THB', + 'TJR', + 'TJS', + 'TMM', + 'TMT', + 'TND', + 'TOP', + 'TPE', + 'TRL', + 'TRY', + 'TTD', + 'TWD', + 'TZS', + 'UAH', + 'UAK', + 'UGS', + 'UGX', + 'USD', + 'USN', + 'USS', + 'UYI', + 'UYP', + 'UYU', + 'UYW', + 'UZS', + 'VEB', + 'VEF', + 'VES', + 'VND', + 'VNN', + 'VUV', + 'WST', + 'XAF', + 'XCD', + 'XEU', + 'XFO', + 'XFU', + 'XOF', + 'XPF', + 'XRE', + 'YDD', + 'YER', + 'YUD', + 'YUM', + 'YUN', + 'YUR', + 'ZAL', + 'ZAR', + 'ZMK', + 'ZMW', + 'ZRN', + 'ZRZ', + 'ZWD', + 'ZWL', + 'ZWR', + ]; + + private static $alpha3ToNumeric = [ + 'AFA' => 4, + 'ALK' => 8, + 'ALL' => 8, + 'DZD' => 12, + 'ADP' => 20, + 'AON' => 24, + 'AOK' => 24, + 'AZM' => 31, + 'ARA' => 32, + 'ARP' => 32, + 'ARS' => 32, + 'AUD' => 36, + 'ATS' => 40, + 'BSD' => 44, + 'BHD' => 48, + 'BDT' => 50, + 'AMD' => 51, + 'BBD' => 52, + 'BEF' => 56, + 'BMD' => 60, + 'BTN' => 64, + 'BOB' => 68, + 'BOP' => 68, + 'BAD' => 70, + 'BWP' => 72, + 'BRN' => 76, + 'BRE' => 76, + 'BRC' => 76, + 'BRB' => 76, + 'BZD' => 84, + 'SBD' => 90, + 'BND' => 96, + 'BGL' => 100, + 'MMK' => 104, + 'BUK' => 104, + 'BIF' => 108, + 'BYB' => 112, + 'KHR' => 116, + 'CAD' => 124, + 'CVE' => 132, + 'KYD' => 136, + 'LKR' => 144, + 'CLP' => 152, + 'CNY' => 156, + 'COP' => 170, + 'KMF' => 174, + 'ZRZ' => 180, + 'ZRN' => 180, + 'CRC' => 188, + 'HRK' => 191, + 'HRD' => 191, + 'CUP' => 192, + 'CYP' => 196, + 'CSK' => 200, + 'CZK' => 203, + 'DKK' => 208, + 'DOP' => 214, + 'ECS' => 218, + 'SVC' => 222, + 'GQE' => 226, + 'ETB' => 230, + 'ERN' => 232, + 'EEK' => 233, + 'FKP' => 238, + 'FJD' => 242, + 'FIM' => 246, + 'FRF' => 250, + 'DJF' => 262, + 'GEK' => 268, + 'GMD' => 270, + 'DEM' => 276, + 'DDM' => 278, + 'GHC' => 288, + 'GIP' => 292, + 'GRD' => 300, + 'GTQ' => 320, + 'GNS' => 324, + 'GNF' => 324, + 'GYD' => 328, + 'HTG' => 332, + 'HNL' => 340, + 'HKD' => 344, + 'HUF' => 348, + 'ISJ' => 352, + 'ISK' => 352, + 'INR' => 356, + 'IDR' => 360, + 'IRR' => 364, + 'IQD' => 368, + 'IEP' => 372, + 'ILP' => 376, + 'ILR' => 376, + 'ILS' => 376, + 'ITL' => 380, + 'JMD' => 388, + 'JPY' => 392, + 'KZT' => 398, + 'JOD' => 400, + 'KES' => 404, + 'KPW' => 408, + 'KRW' => 410, + 'KWD' => 414, + 'KGS' => 417, + 'LAK' => 418, + 'LBP' => 422, + 'LSL' => 426, + 'LVR' => 428, + 'LVL' => 428, + 'LRD' => 430, + 'LYD' => 434, + 'LTL' => 440, + 'LTT' => 440, + 'LUF' => 442, + 'MOP' => 446, + 'MGF' => 450, + 'MWK' => 454, + 'MYR' => 458, + 'MVR' => 462, + 'MLF' => 466, + 'MTL' => 470, + 'MTP' => 470, + 'MRO' => 478, + 'MUR' => 480, + 'MXP' => 484, + 'MXN' => 484, + 'MNT' => 496, + 'MDL' => 498, + 'MAD' => 504, + 'MZE' => 508, + 'MZM' => 508, + 'OMR' => 512, + 'NAD' => 516, + 'NPR' => 524, + 'NLG' => 528, + 'ANG' => 532, + 'AWG' => 533, + 'VUV' => 548, + 'NZD' => 554, + 'NIC' => 558, + 'NIO' => 558, + 'NGN' => 566, + 'NOK' => 578, + 'PKR' => 586, + 'PAB' => 590, + 'PGK' => 598, + 'PYG' => 600, + 'PEI' => 604, + 'PES' => 604, + 'PEN' => 604, + 'PHP' => 608, + 'PLZ' => 616, + 'PTE' => 620, + 'GWP' => 624, + 'GWE' => 624, + 'TPE' => 626, + 'QAR' => 634, + 'ROL' => 642, + 'RUB' => 643, + 'RWF' => 646, + 'SHP' => 654, + 'STD' => 678, + 'SAR' => 682, + 'SCR' => 690, + 'SLL' => 694, + 'SGD' => 702, + 'SKK' => 703, + 'VND' => 704, + 'SIT' => 705, + 'SOS' => 706, + 'ZAR' => 710, + 'ZWD' => 716, + 'RHD' => 716, + 'YDD' => 720, + 'ESP' => 724, + 'SSP' => 728, + 'SDD' => 736, + 'SDP' => 736, + 'SRG' => 740, + 'SZL' => 748, + 'SEK' => 752, + 'CHF' => 756, + 'SYP' => 760, + 'TJR' => 762, + 'THB' => 764, + 'TOP' => 776, + 'TTD' => 780, + 'AED' => 784, + 'TND' => 788, + 'TRL' => 792, + 'TMM' => 795, + 'UGX' => 800, + 'UGS' => 800, + 'UAK' => 804, + 'MKD' => 807, + 'RUR' => 810, + 'SUR' => 810, + 'EGP' => 818, + 'GBP' => 826, + 'TZS' => 834, + 'USD' => 840, + 'UYP' => 858, + 'UYU' => 858, + 'UZS' => 860, + 'VEB' => 862, + 'WST' => 882, + 'YER' => 886, + 'YUN' => 890, + 'YUD' => 890, + 'YUM' => 891, + 'CSD' => 891, + 'ZMK' => 894, + 'TWD' => 901, + 'UYW' => 927, + 'VES' => 928, + 'MRU' => 929, + 'STN' => 930, + 'CUC' => 931, + 'ZWL' => 932, + 'BYN' => 933, + 'TMT' => 934, + 'ZWR' => 935, + 'GHS' => 936, + 'VEF' => 937, + 'SDG' => 938, + 'UYI' => 940, + 'RSD' => 941, + 'MZN' => 943, + 'AZN' => 944, + 'RON' => 946, + 'CHE' => 947, + 'CHW' => 948, + 'TRY' => 949, + 'XAF' => 950, + 'XCD' => 951, + 'XOF' => 952, + 'XPF' => 953, + 'XEU' => 954, + 'ZMW' => 967, + 'SRD' => 968, + 'MGA' => 969, + 'COU' => 970, + 'AFN' => 971, + 'TJS' => 972, + 'AOA' => 973, + 'BYR' => 974, + 'BGN' => 975, + 'CDF' => 976, + 'BAM' => 977, + 'EUR' => 978, + 'MXV' => 979, + 'UAH' => 980, + 'GEL' => 981, + 'AOR' => 982, + 'ECV' => 983, + 'BOV' => 984, + 'PLN' => 985, + 'BRL' => 986, + 'BRR' => 987, + 'LUL' => 988, + 'LUC' => 989, + 'CLF' => 990, + 'ZAL' => 991, + 'BEL' => 992, + 'BEC' => 993, + 'ESB' => 995, + 'ESA' => 996, + 'USN' => 997, + 'USS' => 998, + ]; + + public function testGetCurrencies() + { + $this->assertSame(self::$currencies, Currencies::getCurrencyCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $names = Currencies::getNames($displayLocale); + + $keys = array_keys($names); + + sort($keys); + + $this->assertSame(self::$currencies, $keys); + + // Names should be sorted + $sortedNames = $names; + $collator = new \Collator($displayLocale); + $collator->asort($names); + + $this->assertSame($sortedNames, $names); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Currencies::getNames('de_AT'), Currencies::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Currencies::getNames($ofLocale), Currencies::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $expected = Currencies::getNames($displayLocale); + $actual = []; + + foreach ($expected as $currency => $name) { + $actual[$currency] = Currencies::getName($currency, $displayLocale); + } + + $this->assertSame($expected, $actual); + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $expected = Currencies::getNames('de_AT'); + $actual = []; + + foreach ($expected as $currency => $name) { + $actual[$currency] = Currencies::getName($currency); + } + + $this->assertSame($expected, $actual); + } + + /** + * @dataProvider provideLocales + */ + public function testGetSymbol($displayLocale) + { + $currencies = Currencies::getCurrencyCodes(); + + foreach ($currencies as $currency) { + $this->assertGreaterThan(0, mb_strlen(Currencies::getSymbol($currency, $displayLocale))); + } + } + + public function provideCurrencies() + { + return array_map( + function ($currency) { return [$currency]; }, + self::$currencies + ); + } + + /** + * @dataProvider provideCurrencies + */ + public function testGetFractionDigits($currency) + { + $this->assertInternalType('numeric', Currencies::getFractionDigits($currency)); + } + + /** + * @dataProvider provideCurrencies + */ + public function testGetRoundingIncrement($currency) + { + $this->assertInternalType('numeric', Currencies::getRoundingIncrement($currency)); + } + + public function provideCurrenciesWithNumericEquivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_keys(self::$alpha3ToNumeric) + ); + } + + /** + * @dataProvider provideCurrenciesWithNumericEquivalent + */ + public function testGetNumericCode($currency) + { + $this->assertSame(self::$alpha3ToNumeric[$currency], Currencies::getNumericCode($currency)); + } + + public function provideCurrenciesWithoutNumericEquivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_diff(self::$currencies, array_keys(self::$alpha3ToNumeric)) + ); + } + + /** + * @dataProvider provideCurrenciesWithoutNumericEquivalent + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNumericCodeFailsIfNoNumericEquivalent($currency) + { + Currencies::getNumericCode($currency); + } + + public function provideValidNumericCodes() + { + $numericToAlpha3 = $this->getNumericToAlpha3Mapping(); + + return array_map( + function ($numeric, $alpha3) { return [$numeric, $alpha3]; }, + array_keys($numericToAlpha3), + $numericToAlpha3 + ); + } + + /** + * @dataProvider provideValidNumericCodes + */ + public function testForNumericCode($numeric, $expected) + { + $actual = Currencies::forNumericCode($numeric); + + // Make sure that a different array order doesn't break the test + sort($actual); + sort($expected); + + $this->assertSame($expected, $actual); + } + + public function provideInvalidNumericCodes() + { + $validNumericCodes = array_keys($this->getNumericToAlpha3Mapping()); + $invalidNumericCodes = array_diff(range(0, 1000), $validNumericCodes); + + return array_map( + function ($value) { return [$value]; }, + $invalidNumericCodes + ); + } + + /** + * @dataProvider provideInvalidNumericCodes + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testForNumericCodeFailsIfInvalidNumericCode($currency) + { + Currencies::forNumericCode($currency); + } + + private function getNumericToAlpha3Mapping() + { + $numericToAlpha3 = []; + + foreach (self::$alpha3ToNumeric as $alpha3 => $numeric) { + if (!isset($numericToAlpha3[$numeric])) { + $numericToAlpha3[$numeric] = []; + } + + $numericToAlpha3[$numeric][] = $alpha3; + } + + return $numericToAlpha3; + } +} diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php index 428f6f89b0045..65140b9d2bd20 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractCurrencyDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> + * + * @group legacy */ abstract class AbstractCurrencyDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php index d0ef4d273b45a..b61f97c7a403c 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractDataProviderTest.php @@ -18,6 +18,8 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> + * + * @group legacy */ abstract class AbstractDataProviderTest extends TestCase { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php index 310fe791608f9..580b7ed951165 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLanguageDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> + * + * @group legacy */ abstract class AbstractLanguageDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php index aeca40cdbd6cd..0fe89266002a9 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractLocaleDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> + * + * @group legacy */ abstract class AbstractLocaleDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php index 1f5febb2b86bf..0e0325cdb784c 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractRegionDataProviderTest.php @@ -17,6 +17,8 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> + * + * @group legacy */ abstract class AbstractRegionDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php index db4b81ebdb13f..669bbfa3459bb 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/AbstractScriptDataProviderTest.php @@ -18,6 +18,7 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> * @group intl-data + * @group legacy */ abstract class AbstractScriptDataProviderTest extends AbstractDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php index 1baca128d687f..ff12edb44126b 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonCurrencyDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> * @group intl-data + * @group legacy */ class JsonCurrencyDataProviderTest extends AbstractCurrencyDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php index ba4c0ee08c143..74049ab53e13f 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLanguageDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> * @group intl-data + * @group legacy */ class JsonLanguageDataProviderTest extends AbstractLanguageDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php index 2e5e803b1d443..ba00439bdcea0 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonLocaleDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> * @group intl-data + * @group legacy */ class JsonLocaleDataProviderTest extends AbstractLocaleDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php index c3dba262475ca..9bb3bba48917d 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonRegionDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> * @group intl-data + * @group legacy */ class JsonRegionDataProviderTest extends AbstractRegionDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php index ec1eede660cd8..9648cbaca306f 100644 --- a/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php +++ b/src/Symfony/Component/Intl/Tests/Data/Provider/Json/JsonScriptDataProviderTest.php @@ -19,6 +19,7 @@ /** * @author Bernhard Schussek <bschussek@gmail.com> * @group intl-data + * @group legacy */ class JsonScriptDataProviderTest extends AbstractScriptDataProviderTest { diff --git a/src/Symfony/Component/Intl/Tests/IntlTest.php b/src/Symfony/Component/Intl/Tests/IntlTest.php index de722baf948f3..fd8f294a3841e 100644 --- a/src/Symfony/Component/Intl/Tests/IntlTest.php +++ b/src/Symfony/Component/Intl/Tests/IntlTest.php @@ -24,21 +24,33 @@ public function testIsExtensionLoadedChecksIfIntlExtensionIsLoaded() $this->assertTrue(Intl::isExtensionLoaded()); } + /** + * @group legacy + */ public function testGetCurrencyBundleCreatesTheCurrencyBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\CurrencyBundleInterface', Intl::getCurrencyBundle()); } + /** + * @group legacy + */ public function testGetLanguageBundleCreatesTheLanguageBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LanguageBundleInterface', Intl::getLanguageBundle()); } + /** + * @group legacy + */ public function testGetLocaleBundleCreatesTheLocaleBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\LocaleBundleInterface', Intl::getLocaleBundle()); } + /** + * @group legacy + */ public function testGetRegionBundleCreatesTheRegionBundle() { $this->assertInstanceOf('Symfony\Component\Intl\ResourceBundle\RegionBundleInterface', Intl::getRegionBundle()); @@ -65,6 +77,7 @@ public function testGetDataDirectoryReturnsThePathToIcuData() } /** + * @group legacy * @requires extension intl */ public function testLocaleAliasesAreLoaded() diff --git a/src/Symfony/Component/Intl/Tests/LanguagesTest.php b/src/Symfony/Component/Intl/Tests/LanguagesTest.php new file mode 100644 index 0000000000000..6fa059b29445a --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/LanguagesTest.php @@ -0,0 +1,918 @@ +<?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\Component\Intl\Tests; + +use Symfony\Component\Intl\Languages; +use Symfony\Component\Intl\Locale; + +/** + * @group intl-data + */ +class LanguagesTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $languages = [ + 'aa', + 'ab', + 'ace', + 'ach', + 'ada', + 'ady', + 'ae', + 'aeb', + 'af', + 'afh', + 'agq', + 'ain', + 'ak', + 'akk', + 'akz', + 'ale', + 'aln', + 'alt', + 'am', + 'an', + 'ang', + 'anp', + 'ar', + 'ar_001', + 'arc', + 'arn', + 'aro', + 'arp', + 'arq', + 'ars', + 'arw', + 'ary', + 'arz', + 'as', + 'asa', + 'ase', + 'ast', + 'av', + 'avk', + 'awa', + 'ay', + 'az', + 'az_Arab', + 'ba', + 'bal', + 'ban', + 'bar', + 'bas', + 'bax', + 'bbc', + 'bbj', + 'be', + 'bej', + 'bem', + 'bew', + 'bez', + 'bfd', + 'bfq', + 'bg', + 'bgn', + 'bho', + 'bi', + 'bik', + 'bin', + 'bjn', + 'bkm', + 'bla', + 'bm', + 'bn', + 'bo', + 'bpy', + 'bqi', + 'br', + 'bra', + 'brh', + 'brx', + 'bs', + 'bss', + 'bua', + 'bug', + 'bum', + 'byn', + 'byv', + 'ca', + 'cad', + 'car', + 'cay', + 'cch', + 'ccp', + 'ce', + 'ceb', + 'cgg', + 'ch', + 'chb', + 'chg', + 'chk', + 'chm', + 'chn', + 'cho', + 'chp', + 'chr', + 'chy', + 'ckb', + 'co', + 'cop', + 'cps', + 'cr', + 'crh', + 'crs', + 'cs', + 'csb', + 'cu', + 'cv', + 'cy', + 'da', + 'dak', + 'dar', + 'dav', + 'de', + 'de_AT', + 'de_CH', + 'del', + 'den', + 'dgr', + 'din', + 'dje', + 'doi', + 'dsb', + 'dtp', + 'dua', + 'dum', + 'dv', + 'dyo', + 'dyu', + 'dz', + 'dzg', + 'ebu', + 'ee', + 'efi', + 'egl', + 'egy', + 'eka', + 'el', + 'elx', + 'en', + 'en_AU', + 'en_CA', + 'en_GB', + 'en_US', + 'enm', + 'eo', + 'es', + 'es_419', + 'es_ES', + 'es_MX', + 'esu', + 'et', + 'eu', + 'ewo', + 'ext', + 'fa', + 'fa_AF', + 'fan', + 'fat', + 'ff', + 'fi', + 'fil', + 'fit', + 'fj', + 'fo', + 'fon', + 'fr', + 'fr_CA', + 'fr_CH', + 'frc', + 'frm', + 'fro', + 'frp', + 'frr', + 'frs', + 'fur', + 'fy', + 'ga', + 'gaa', + 'gag', + 'gan', + 'gay', + 'gba', + 'gbz', + 'gd', + 'gez', + 'gil', + 'gl', + 'glk', + 'gmh', + 'gn', + 'goh', + 'gom', + 'gon', + 'gor', + 'got', + 'grb', + 'grc', + 'gsw', + 'gu', + 'guc', + 'gur', + 'guz', + 'gv', + 'gwi', + 'ha', + 'hai', + 'hak', + 'haw', + 'he', + 'hi', + 'hif', + 'hil', + 'hit', + 'hmn', + 'ho', + 'hr', + 'hsb', + 'hsn', + 'ht', + 'hu', + 'hup', + 'hy', + 'hz', + 'ia', + 'iba', + 'ibb', + 'id', + 'ie', + 'ig', + 'ii', + 'ik', + 'ilo', + 'inh', + 'io', + 'is', + 'it', + 'iu', + 'izh', + 'ja', + 'jam', + 'jbo', + 'jgo', + 'jmc', + 'jpr', + 'jrb', + 'jut', + 'jv', + 'ka', + 'kaa', + 'kab', + 'kac', + 'kaj', + 'kam', + 'kaw', + 'kbd', + 'kbl', + 'kcg', + 'kde', + 'kea', + 'ken', + 'kfo', + 'kg', + 'kgp', + 'kha', + 'kho', + 'khq', + 'khw', + 'ki', + 'kiu', + 'kj', + 'kk', + 'kkj', + 'kl', + 'kln', + 'km', + 'kmb', + 'kn', + 'ko', + 'koi', + 'kok', + 'kos', + 'kpe', + 'kr', + 'krc', + 'kri', + 'krj', + 'krl', + 'kru', + 'ks', + 'ksb', + 'ksf', + 'ksh', + 'ku', + 'kum', + 'kut', + 'kv', + 'kw', + 'ky', + 'la', + 'lad', + 'lag', + 'lah', + 'lam', + 'lb', + 'lez', + 'lfn', + 'lg', + 'li', + 'lij', + 'liv', + 'lkt', + 'lmo', + 'ln', + 'lo', + 'lol', + 'lou', + 'loz', + 'lrc', + 'lt', + 'ltg', + 'lu', + 'lua', + 'lui', + 'lun', + 'luo', + 'lus', + 'luy', + 'lv', + 'lzh', + 'lzz', + 'mad', + 'maf', + 'mag', + 'mai', + 'mak', + 'man', + 'mas', + 'mde', + 'mdf', + 'mdr', + 'men', + 'mer', + 'mfe', + 'mg', + 'mga', + 'mgh', + 'mgo', + 'mh', + 'mi', + 'mic', + 'min', + 'mk', + 'ml', + 'mn', + 'mnc', + 'mni', + 'moh', + 'mos', + 'mr', + 'mrj', + 'ms', + 'mt', + 'mua', + 'mus', + 'mwl', + 'mwr', + 'mwv', + 'my', + 'mye', + 'myv', + 'mzn', + 'na', + 'nan', + 'nap', + 'naq', + 'nb', + 'nd', + 'nds', + 'nds_NL', + 'ne', + 'new', + 'ng', + 'nia', + 'niu', + 'njo', + 'nl', + 'nl_BE', + 'nmg', + 'nn', + 'nnh', + 'no', + 'nog', + 'non', + 'nov', + 'nqo', + 'nr', + 'nso', + 'nus', + 'nv', + 'nwc', + 'ny', + 'nym', + 'nyn', + 'nyo', + 'nzi', + 'oc', + 'oj', + 'om', + 'or', + 'os', + 'osa', + 'ota', + 'pa', + 'pag', + 'pal', + 'pam', + 'pap', + 'pau', + 'pcd', + 'pcm', + 'pdc', + 'pdt', + 'peo', + 'pfl', + 'phn', + 'pi', + 'pl', + 'pms', + 'pnt', + 'pon', + 'prg', + 'pro', + 'ps', + 'pt', + 'pt_BR', + 'pt_PT', + 'qu', + 'quc', + 'qug', + 'raj', + 'rap', + 'rar', + 'rgn', + 'rif', + 'rm', + 'rn', + 'ro', + 'ro_MD', + 'rof', + 'rom', + 'root', + 'rtm', + 'ru', + 'rue', + 'rug', + 'rup', + 'rw', + 'rwk', + 'sa', + 'sad', + 'sah', + 'sam', + 'saq', + 'sas', + 'sat', + 'saz', + 'sba', + 'sbp', + 'sc', + 'scn', + 'sco', + 'sd', + 'sdc', + 'sdh', + 'se', + 'see', + 'seh', + 'sei', + 'sel', + 'ses', + 'sg', + 'sga', + 'sgs', + 'sh', + 'shi', + 'shn', + 'shu', + 'si', + 'sid', + 'sk', + 'sl', + 'sli', + 'sly', + 'sm', + 'sma', + 'smj', + 'smn', + 'sms', + 'sn', + 'snk', + 'so', + 'sog', + 'sq', + 'sr', + 'sr_ME', + 'srn', + 'srr', + 'ss', + 'ssy', + 'st', + 'stq', + 'su', + 'suk', + 'sus', + 'sux', + 'sv', + 'sw', + 'sw_CD', + 'swb', + 'syc', + 'syr', + 'szl', + 'ta', + 'tcy', + 'te', + 'tem', + 'teo', + 'ter', + 'tet', + 'tg', + 'th', + 'ti', + 'tig', + 'tiv', + 'tk', + 'tkl', + 'tkr', + 'tl', + 'tlh', + 'tli', + 'tly', + 'tmh', + 'tn', + 'to', + 'tog', + 'tpi', + 'tr', + 'tru', + 'trv', + 'ts', + 'tsd', + 'tsi', + 'tt', + 'ttt', + 'tum', + 'tvl', + 'tw', + 'twq', + 'ty', + 'tyv', + 'tzm', + 'udm', + 'ug', + 'uga', + 'uk', + 'umb', + 'ur', + 'uz', + 'vai', + 've', + 'vec', + 'vep', + 'vi', + 'vls', + 'vmf', + 'vo', + 'vot', + 'vro', + 'vun', + 'wa', + 'wae', + 'wal', + 'war', + 'was', + 'wbp', + 'wo', + 'wuu', + 'xal', + 'xh', + 'xmf', + 'xog', + 'yao', + 'yap', + 'yav', + 'ybb', + 'yi', + 'yo', + 'yrl', + 'yue', + 'za', + 'zap', + 'zbl', + 'zea', + 'zen', + 'zgh', + 'zh', + 'zh_Hans', + 'zh_Hant', + 'zu', + 'zun', + 'zza', + ]; + + private static $alpha2ToAlpha3 = [ + 'aa' => 'aar', + 'ab' => 'abk', + 'af' => 'afr', + 'ak' => 'aka', + 'sq' => 'sqi', + 'am' => 'amh', + 'ar' => 'ara', + 'an' => 'arg', + 'hy' => 'hye', + 'as' => 'asm', + 'av' => 'ava', + 'ae' => 'ave', + 'ay' => 'aym', + 'az' => 'aze', + 'ba' => 'bak', + 'bm' => 'bam', + 'eu' => 'eus', + 'be' => 'bel', + 'bn' => 'ben', + 'bi' => 'bis', + 'bo' => 'bod', + 'bs' => 'bos', + 'br' => 'bre', + 'bg' => 'bul', + 'my' => 'mya', + 'ca' => 'cat', + 'cs' => 'ces', + 'ch' => 'cha', + 'ce' => 'che', + 'zh' => 'zho', + 'cu' => 'chu', + 'cv' => 'chv', + 'kw' => 'cor', + 'co' => 'cos', + 'cr' => 'cre', + 'cy' => 'cym', + 'da' => 'dan', + 'de' => 'deu', + 'dv' => 'div', + 'nl' => 'nld', + 'dz' => 'dzo', + 'et' => 'est', + 'el' => 'ell', + 'en' => 'eng', + 'eo' => 'epo', + 'ik' => 'ipk', + 'ee' => 'ewe', + 'fo' => 'fao', + 'fa' => 'fas', + 'fj' => 'fij', + 'fi' => 'fin', + 'fr' => 'fra', + 'fy' => 'fry', + 'ff' => 'ful', + 'om' => 'orm', + 'ka' => 'kat', + 'gd' => 'gla', + 'ga' => 'gle', + 'gl' => 'glg', + 'gv' => 'glv', + 'gn' => 'grn', + 'gu' => 'guj', + 'ht' => 'hat', + 'ha' => 'hau', + 'he' => 'heb', + 'hz' => 'her', + 'hi' => 'hin', + 'ho' => 'hmo', + 'hr' => 'hrv', + 'hu' => 'hun', + 'ig' => 'ibo', + 'is' => 'isl', + 'io' => 'ido', + 'ii' => 'iii', + 'iu' => 'iku', + 'ie' => 'ile', + 'ia' => 'ina', + 'id' => 'ind', + 'it' => 'ita', + 'jv' => 'jav', + 'ja' => 'jpn', + 'kl' => 'kal', + 'kn' => 'kan', + 'ks' => 'kas', + 'kr' => 'kau', + 'kk' => 'kaz', + 'mn' => 'mon', + 'km' => 'khm', + 'ki' => 'kik', + 'rw' => 'kin', + 'ky' => 'kir', + 'ku' => 'kur', + 'kg' => 'kon', + 'kv' => 'kom', + 'ko' => 'kor', + 'kj' => 'kua', + 'lo' => 'lao', + 'la' => 'lat', + 'lv' => 'lav', + 'li' => 'lim', + 'ln' => 'lin', + 'lt' => 'lit', + 'lb' => 'ltz', + 'lu' => 'lub', + 'lg' => 'lug', + 'mk' => 'mkd', + 'mh' => 'mah', + 'ml' => 'mal', + 'mi' => 'mri', + 'mr' => 'mar', + 'ms' => 'msa', + 'mg' => 'mlg', + 'mt' => 'mlt', + 'na' => 'nau', + 'nv' => 'nav', + 'nr' => 'nbl', + 'nd' => 'nde', + 'ng' => 'ndo', + 'ne' => 'nep', + 'nn' => 'nno', + 'nb' => 'nob', + 'ny' => 'nya', + 'oc' => 'oci', + 'oj' => 'oji', + 'or' => 'ori', + 'os' => 'oss', + 'pa' => 'pan', + 'ps' => 'pus', + 'pi' => 'pli', + 'pl' => 'pol', + 'pt' => 'por', + 'qu' => 'que', + 'rm' => 'roh', + 'ro' => 'ron', + 'rn' => 'run', + 'ru' => 'rus', + 'sg' => 'sag', + 'sa' => 'san', + 'sr' => 'srp', + 'si' => 'sin', + 'sk' => 'slk', + 'sl' => 'slv', + 'se' => 'sme', + 'sm' => 'smo', + 'sn' => 'sna', + 'sd' => 'snd', + 'so' => 'som', + 'st' => 'sot', + 'es' => 'spa', + 'sc' => 'srd', + 'ss' => 'ssw', + 'su' => 'sun', + 'sw' => 'swa', + 'sv' => 'swe', + 'ty' => 'tah', + 'ta' => 'tam', + 'tt' => 'tat', + 'te' => 'tel', + 'tg' => 'tgk', + 'th' => 'tha', + 'ti' => 'tir', + 'to' => 'ton', + 'tn' => 'tsn', + 'ts' => 'tso', + 'tk' => 'tuk', + 'tr' => 'tur', + 'ug' => 'uig', + 'uk' => 'ukr', + 'ur' => 'urd', + 'uz' => 'uzb', + 've' => 'ven', + 'vi' => 'vie', + 'vo' => 'vol', + 'wa' => 'wln', + 'wo' => 'wol', + 'xh' => 'xho', + 'yi' => 'yid', + 'yo' => 'yor', + 'za' => 'zha', + 'zu' => 'zul', + ]; + + public function testGetLanguages() + { + $this->assertEquals(self::$languages, Languages::getLanguageCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $languages = array_keys(Languages::getNames($displayLocale)); + + sort($languages); + + $this->assertNotEmpty($languages); + $this->assertEmpty(array_diff($languages, self::$languages)); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Languages::getNames('de_AT'), Languages::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Languages::getNames($ofLocale), Languages::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Languages::getNames($displayLocale); + + foreach ($names as $language => $name) { + $this->assertSame($name, Languages::getName($language, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $names = Languages::getNames('de_AT'); + + foreach ($names as $language => $name) { + $this->assertSame($name, Languages::getName($language)); + } + } + + public function provideLanguagesWithAlpha3Equivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_keys(self::$alpha2ToAlpha3) + ); + } + + /** + * @dataProvider provideLanguagesWithAlpha3Equivalent + */ + public function testGetAlpha3Code($language) + { + $this->assertSame(self::$alpha2ToAlpha3[$language], Languages::getAlpha3Code($language)); + } + + public function provideLanguagesWithoutAlpha3Equivalent() + { + return array_map( + function ($value) { return [$value]; }, + array_diff(self::$languages, array_keys(self::$alpha2ToAlpha3)) + ); + } + + /** + * @dataProvider provideLanguagesWithoutAlpha3Equivalent + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetAlpha3CodeFailsIfNoAlpha3Equivalent($language) + { + Languages::getAlpha3Code($language); + } +} diff --git a/src/Symfony/Component/Intl/Tests/LocalesTest.php b/src/Symfony/Component/Intl/Tests/LocalesTest.php new file mode 100644 index 0000000000000..e7ffbd2ca9a42 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/LocalesTest.php @@ -0,0 +1,87 @@ +<?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\Component\Intl\Tests; + +use Symfony\Component\Intl\Locale; +use Symfony\Component\Intl\Locales; + +/** + * @group intl-data + */ +class LocalesTest extends ResourceBundleTestCase +{ + public function testGetLocales() + { + $this->assertSame($this->getLocales(), Locales::getLocales()); + } + + public function testGetLocaleAliases() + { + $this->assertSame($this->getLocaleAliases(), Locales::getAliases()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $locales = array_keys(Locales::getNames($displayLocale)); + + sort($locales); + + // We can't assert on exact list of locale, as there's too many variations. + // The best we can do is to make sure getNames() returns a subset of what getLocales() returns. + $this->assertNotEmpty($locales); + $this->assertEmpty(array_diff($locales, $this->getLocales())); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Locales::getNames('de_AT'), Locales::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Locales::getNames($ofLocale), Locales::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Locales::getNames($displayLocale); + + foreach ($names as $locale => $name) { + $this->assertSame($name, Locales::getName($locale, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $names = Locales::getNames('de_AT'); + + foreach ($names as $locale => $name) { + $this->assertSame($name, Locales::getName($locale)); + } + } +} diff --git a/src/Symfony/Component/Intl/Tests/RegionsTest.php b/src/Symfony/Component/Intl/Tests/RegionsTest.php new file mode 100644 index 0000000000000..80d4ca98bf638 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/RegionsTest.php @@ -0,0 +1,346 @@ +<?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\Component\Intl\Tests; + +use Symfony\Component\Intl\Locale; +use Symfony\Component\Intl\Regions; + +/** + * @group intl-data + */ +class RegionsTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $territories = [ + 'AC', + 'AD', + 'AE', + 'AF', + 'AG', + 'AI', + 'AL', + 'AM', + 'AO', + 'AQ', + 'AR', + 'AS', + 'AT', + 'AU', + 'AW', + 'AX', + 'AZ', + 'BA', + 'BB', + 'BD', + 'BE', + 'BF', + 'BG', + 'BH', + 'BI', + 'BJ', + 'BL', + 'BM', + 'BN', + 'BO', + 'BQ', + 'BR', + 'BS', + 'BT', + 'BW', + 'BY', + 'BZ', + 'CA', + 'CC', + 'CD', + 'CF', + 'CG', + 'CH', + 'CI', + 'CK', + 'CL', + 'CM', + 'CN', + 'CO', + 'CR', + 'CU', + 'CV', + 'CW', + 'CX', + 'CY', + 'CZ', + 'DE', + 'DG', + 'DJ', + 'DK', + 'DM', + 'DO', + 'DZ', + 'EA', + 'EC', + 'EE', + 'EG', + 'EH', + 'ER', + 'ES', + 'ET', + 'FI', + 'FJ', + 'FK', + 'FM', + 'FO', + 'FR', + 'GA', + 'GB', + 'GD', + 'GE', + 'GF', + 'GG', + 'GH', + 'GI', + 'GL', + 'GM', + 'GN', + 'GP', + 'GQ', + 'GR', + 'GS', + 'GT', + 'GU', + 'GW', + 'GY', + 'HK', + 'HN', + 'HR', + 'HT', + 'HU', + 'IC', + 'ID', + 'IE', + 'IL', + 'IM', + 'IN', + 'IO', + 'IQ', + 'IR', + 'IS', + 'IT', + 'JE', + 'JM', + 'JO', + 'JP', + 'KE', + 'KG', + 'KH', + 'KI', + 'KM', + 'KN', + 'KP', + 'KR', + 'KW', + 'KY', + 'KZ', + 'LA', + 'LB', + 'LC', + 'LI', + 'LK', + 'LR', + 'LS', + 'LT', + 'LU', + 'LV', + 'LY', + 'MA', + 'MC', + 'MD', + 'ME', + 'MF', + 'MG', + 'MH', + 'MK', + 'ML', + 'MM', + 'MN', + 'MO', + 'MP', + 'MQ', + 'MR', + 'MS', + 'MT', + 'MU', + 'MV', + 'MW', + 'MX', + 'MY', + 'MZ', + 'NA', + 'NC', + 'NE', + 'NF', + 'NG', + 'NI', + 'NL', + 'NO', + 'NP', + 'NR', + 'NU', + 'NZ', + 'OM', + 'PA', + 'PE', + 'PF', + 'PG', + 'PH', + 'PK', + 'PL', + 'PM', + 'PN', + 'PR', + 'PS', + 'PT', + 'PW', + 'PY', + 'QA', + 'RE', + 'RO', + 'RS', + 'RU', + 'RW', + 'SA', + 'SB', + 'SC', + 'SD', + 'SE', + 'SG', + 'SH', + 'SI', + 'SJ', + 'SK', + 'SL', + 'SM', + 'SN', + 'SO', + 'SR', + 'SS', + 'ST', + 'SV', + 'SX', + 'SY', + 'SZ', + 'TA', + 'TC', + 'TD', + 'TF', + 'TG', + 'TH', + 'TJ', + 'TK', + 'TL', + 'TM', + 'TN', + 'TO', + 'TR', + 'TT', + 'TV', + 'TW', + 'TZ', + 'UA', + 'UG', + 'UM', + 'US', + 'UY', + 'UZ', + 'VA', + 'VC', + 'VE', + 'VG', + 'VI', + 'VN', + 'VU', + 'WF', + 'WS', + 'XA', + 'XB', + 'XK', + 'YE', + 'YT', + 'ZA', + 'ZM', + 'ZW', + ]; + + public function testGetRegions() + { + $this->assertSame(self::$territories, Regions::getRegionCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $countries = array_keys(Regions::getNames($displayLocale)); + + sort($countries); + + $this->assertSame(self::$territories, $countries); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Regions::getNames('de_AT'), Regions::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Regions::getNames($ofLocale), Regions::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Regions::getNames($displayLocale); + + foreach ($names as $country => $name) { + $this->assertSame($name, Regions::getName($country, $displayLocale)); + } + } + + /** + * @requires extension intl + */ + public function testLocaleAliasesAreLoaded() + { + \Locale::setDefault('zh_TW'); + $countryNameZhTw = Regions::getName('AD'); + + \Locale::setDefault('zh_Hant_TW'); + $countryNameHantZhTw = Regions::getName('AD'); + + \Locale::setDefault('zh'); + $countryNameZh = Regions::getName('AD'); + + $this->assertSame($countryNameZhTw, $countryNameHantZhTw, 'zh_TW is an alias to zh_Hant_TW'); + $this->assertNotSame($countryNameZh, $countryNameZhTw, 'zh_TW does not fall back to zh'); + } +} diff --git a/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php b/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php new file mode 100644 index 0000000000000..3e460985896c7 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php @@ -0,0 +1,751 @@ +<?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\Component\Intl\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Intl\Locale; + +abstract class ResourceBundleTestCase extends TestCase +{ + // Include the locales statically so that the data providers are decoupled + // from the Intl class. Otherwise tests will fail if the intl extension is + // not loaded, because it is NOT possible to skip the execution of data + // providers. + + private static $locales = [ + 'af', + 'af_NA', + 'af_ZA', + 'ak', + 'ak_GH', + 'am', + 'am_ET', + 'ar', + 'ar_001', + 'ar_AE', + 'ar_BH', + 'ar_DJ', + 'ar_DZ', + 'ar_EG', + 'ar_EH', + 'ar_ER', + 'ar_IL', + 'ar_IQ', + 'ar_JO', + 'ar_KM', + 'ar_KW', + 'ar_LB', + 'ar_LY', + 'ar_MA', + 'ar_MR', + 'ar_OM', + 'ar_PS', + 'ar_QA', + 'ar_SA', + 'ar_SD', + 'ar_SO', + 'ar_SS', + 'ar_SY', + 'ar_TD', + 'ar_TN', + 'ar_YE', + 'as', + 'as_IN', + 'az', + 'az_AZ', + 'az_Cyrl', + 'az_Cyrl_AZ', + 'az_Latn', + 'az_Latn_AZ', + 'be', + 'be_BY', + 'bg', + 'bg_BG', + 'bm', + 'bm_ML', + 'bn', + 'bn_BD', + 'bn_IN', + 'bo', + 'bo_CN', + 'bo_IN', + 'br', + 'br_FR', + 'bs', + 'bs_BA', + 'bs_Cyrl', + 'bs_Cyrl_BA', + 'bs_Latn', + 'bs_Latn_BA', + 'ca', + 'ca_AD', + 'ca_ES', + 'ca_FR', + 'ca_IT', + 'ce', + 'ce_RU', + 'cs', + 'cs_CZ', + 'cy', + 'cy_GB', + 'da', + 'da_DK', + 'da_GL', + 'de', + 'de_AT', + 'de_BE', + 'de_CH', + 'de_DE', + 'de_IT', + 'de_LI', + 'de_LU', + 'dz', + 'dz_BT', + 'ee', + 'ee_GH', + 'ee_TG', + 'el', + 'el_CY', + 'el_GR', + 'en', + 'en_001', + 'en_150', + 'en_AE', + 'en_AG', + 'en_AI', + 'en_AS', + 'en_AT', + 'en_AU', + 'en_BB', + 'en_BE', + 'en_BI', + 'en_BM', + 'en_BS', + 'en_BW', + 'en_BZ', + 'en_CA', + 'en_CC', + 'en_CH', + 'en_CK', + 'en_CM', + 'en_CX', + 'en_CY', + 'en_DE', + 'en_DG', + 'en_DK', + 'en_DM', + 'en_ER', + 'en_FI', + 'en_FJ', + 'en_FK', + 'en_FM', + 'en_GB', + 'en_GD', + 'en_GG', + 'en_GH', + 'en_GI', + 'en_GM', + 'en_GU', + 'en_GY', + 'en_HK', + 'en_IE', + 'en_IL', + 'en_IM', + 'en_IN', + 'en_IO', + 'en_JE', + 'en_JM', + 'en_KE', + 'en_KI', + 'en_KN', + 'en_KY', + 'en_LC', + 'en_LR', + 'en_LS', + 'en_MG', + 'en_MH', + 'en_MO', + 'en_MP', + 'en_MS', + 'en_MT', + 'en_MU', + 'en_MW', + 'en_MY', + 'en_NA', + 'en_NF', + 'en_NG', + 'en_NH', + 'en_NL', + 'en_NR', + 'en_NU', + 'en_NZ', + 'en_PG', + 'en_PH', + 'en_PK', + 'en_PN', + 'en_PR', + 'en_PW', + 'en_RH', + 'en_RW', + 'en_SB', + 'en_SC', + 'en_SD', + 'en_SE', + 'en_SG', + 'en_SH', + 'en_SI', + 'en_SL', + 'en_SS', + 'en_SX', + 'en_SZ', + 'en_TC', + 'en_TK', + 'en_TO', + 'en_TT', + 'en_TV', + 'en_TZ', + 'en_UG', + 'en_UM', + 'en_US', + 'en_US_POSIX', + 'en_VC', + 'en_VG', + 'en_VI', + 'en_VU', + 'en_WS', + 'en_ZA', + 'en_ZM', + 'en_ZW', + 'eo', + 'eo_001', + 'es', + 'es_419', + 'es_AR', + 'es_BO', + 'es_BR', + 'es_BZ', + 'es_CL', + 'es_CO', + 'es_CR', + 'es_CU', + 'es_DO', + 'es_EA', + 'es_EC', + 'es_ES', + 'es_GQ', + 'es_GT', + 'es_HN', + 'es_IC', + 'es_MX', + 'es_NI', + 'es_PA', + 'es_PE', + 'es_PH', + 'es_PR', + 'es_PY', + 'es_SV', + 'es_US', + 'es_UY', + 'es_VE', + 'et', + 'et_EE', + 'eu', + 'eu_ES', + 'fa', + 'fa_AF', + 'fa_IR', + 'ff', + 'ff_CM', + 'ff_GN', + 'ff_Latn', + 'ff_Latn_BF', + 'ff_Latn_CM', + 'ff_Latn_GH', + 'ff_Latn_GM', + 'ff_Latn_GN', + 'ff_Latn_GW', + 'ff_Latn_LR', + 'ff_Latn_MR', + 'ff_Latn_NE', + 'ff_Latn_NG', + 'ff_Latn_SL', + 'ff_Latn_SN', + 'ff_MR', + 'ff_SN', + 'fi', + 'fi_FI', + 'fo', + 'fo_DK', + 'fo_FO', + 'fr', + 'fr_BE', + 'fr_BF', + 'fr_BI', + 'fr_BJ', + 'fr_BL', + 'fr_CA', + 'fr_CD', + 'fr_CF', + 'fr_CG', + 'fr_CH', + 'fr_CI', + 'fr_CM', + 'fr_DJ', + 'fr_DZ', + 'fr_FR', + 'fr_GA', + 'fr_GF', + 'fr_GN', + 'fr_GP', + 'fr_GQ', + 'fr_HT', + 'fr_KM', + 'fr_LU', + 'fr_MA', + 'fr_MC', + 'fr_MF', + 'fr_MG', + 'fr_ML', + 'fr_MQ', + 'fr_MR', + 'fr_MU', + 'fr_NC', + 'fr_NE', + 'fr_PF', + 'fr_PM', + 'fr_RE', + 'fr_RW', + 'fr_SC', + 'fr_SN', + 'fr_SY', + 'fr_TD', + 'fr_TG', + 'fr_TN', + 'fr_VU', + 'fr_WF', + 'fr_YT', + 'fy', + 'fy_NL', + 'ga', + 'ga_IE', + 'gd', + 'gd_GB', + 'gl', + 'gl_ES', + 'gu', + 'gu_IN', + 'gv', + 'gv_IM', + 'ha', + 'ha_GH', + 'ha_NE', + 'ha_NG', + 'he', + 'he_IL', + 'hi', + 'hi_IN', + 'hr', + 'hr_BA', + 'hr_HR', + 'hu', + 'hu_HU', + 'hy', + 'hy_AM', + 'ia', + 'ia_001', + 'id', + 'id_ID', + 'ig', + 'ig_NG', + 'ii', + 'ii_CN', + 'in', + 'in_ID', + 'is', + 'is_IS', + 'it', + 'it_CH', + 'it_IT', + 'it_SM', + 'it_VA', + 'iw', + 'iw_IL', + 'ja', + 'ja_JP', + 'ja_JP_TRADITIONAL', + 'jv', + 'jv_ID', + 'ka', + 'ka_GE', + 'ki', + 'ki_KE', + 'kk', + 'kk_KZ', + 'kl', + 'kl_GL', + 'km', + 'km_KH', + 'kn', + 'kn_IN', + 'ko', + 'ko_KP', + 'ko_KR', + 'ks', + 'ks_IN', + 'ku', + 'ku_TR', + 'kw', + 'kw_GB', + 'ky', + 'ky_KG', + 'lb', + 'lb_LU', + 'lg', + 'lg_UG', + 'ln', + 'ln_AO', + 'ln_CD', + 'ln_CF', + 'ln_CG', + 'lo', + 'lo_LA', + 'lt', + 'lt_LT', + 'lu', + 'lu_CD', + 'lv', + 'lv_LV', + 'mg', + 'mg_MG', + 'mi', + 'mi_NZ', + 'mk', + 'mk_MK', + 'ml', + 'ml_IN', + 'mn', + 'mn_MN', + 'mo', + 'mr', + 'mr_IN', + 'ms', + 'ms_BN', + 'ms_MY', + 'ms_SG', + 'mt', + 'mt_MT', + 'my', + 'my_MM', + 'nb', + 'nb_NO', + 'nb_SJ', + 'nd', + 'nd_ZW', + 'ne', + 'ne_IN', + 'ne_NP', + 'nl', + 'nl_AW', + 'nl_BE', + 'nl_BQ', + 'nl_CW', + 'nl_NL', + 'nl_SR', + 'nl_SX', + 'nn', + 'nn_NO', + 'no', + 'no_NO', + 'no_NO_NY', + 'om', + 'om_ET', + 'om_KE', + 'or', + 'or_IN', + 'os', + 'os_GE', + 'os_RU', + 'pa', + 'pa_Arab', + 'pa_Arab_PK', + 'pa_Guru', + 'pa_Guru_IN', + 'pa_IN', + 'pa_PK', + 'pl', + 'pl_PL', + 'ps', + 'ps_AF', + 'ps_PK', + 'pt', + 'pt_AO', + 'pt_BR', + 'pt_CH', + 'pt_CV', + 'pt_GQ', + 'pt_GW', + 'pt_LU', + 'pt_MO', + 'pt_MZ', + 'pt_PT', + 'pt_ST', + 'pt_TL', + 'qu', + 'qu_BO', + 'qu_EC', + 'qu_PE', + 'rm', + 'rm_CH', + 'rn', + 'rn_BI', + 'ro', + 'ro_MD', + 'ro_RO', + 'ru', + 'ru_BY', + 'ru_KG', + 'ru_KZ', + 'ru_MD', + 'ru_RU', + 'ru_UA', + 'rw', + 'rw_RW', + 'sd', + 'sd_PK', + 'se', + 'se_FI', + 'se_NO', + 'se_SE', + 'sg', + 'sg_CF', + 'sh', + 'sh_BA', + 'sh_CS', + 'sh_YU', + 'si', + 'si_LK', + 'sk', + 'sk_SK', + 'sl', + 'sl_SI', + 'sn', + 'sn_ZW', + 'so', + 'so_DJ', + 'so_ET', + 'so_KE', + 'so_SO', + 'sq', + 'sq_AL', + 'sq_MK', + 'sq_XK', + 'sr', + 'sr_BA', + 'sr_CS', + 'sr_Cyrl', + 'sr_Cyrl_BA', + 'sr_Cyrl_CS', + 'sr_Cyrl_ME', + 'sr_Cyrl_RS', + 'sr_Cyrl_XK', + 'sr_Cyrl_YU', + 'sr_Latn', + 'sr_Latn_BA', + 'sr_Latn_CS', + 'sr_Latn_ME', + 'sr_Latn_RS', + 'sr_Latn_XK', + 'sr_Latn_YU', + 'sr_ME', + 'sr_RS', + 'sr_XK', + 'sr_YU', + 'sv', + 'sv_AX', + 'sv_FI', + 'sv_SE', + 'sw', + 'sw_CD', + 'sw_KE', + 'sw_TZ', + 'sw_UG', + 'ta', + 'ta_IN', + 'ta_LK', + 'ta_MY', + 'ta_SG', + 'te', + 'te_IN', + 'tg', + 'tg_TJ', + 'th', + 'th_TH', + 'th_TH_TRADITIONAL', + 'ti', + 'ti_ER', + 'ti_ET', + 'tk', + 'tk_TM', + 'tl', + 'tl_PH', + 'to', + 'to_TO', + 'tr', + 'tr_CY', + 'tr_TR', + 'tt', + 'tt_RU', + 'ug', + 'ug_CN', + 'uk', + 'uk_UA', + 'ur', + 'ur_IN', + 'ur_PK', + 'uz', + 'uz_AF', + 'uz_Arab', + 'uz_Arab_AF', + 'uz_Cyrl', + 'uz_Cyrl_UZ', + 'uz_Latn', + 'uz_Latn_UZ', + 'uz_UZ', + 'vi', + 'vi_VN', + 'wo', + 'wo_SN', + 'xh', + 'xh_ZA', + 'yi', + 'yi_001', + 'yo', + 'yo_BJ', + 'yo_NG', + 'zh', + 'zh_CN', + 'zh_HK', + 'zh_Hans', + 'zh_Hans_CN', + 'zh_Hans_HK', + 'zh_Hans_MO', + 'zh_Hans_SG', + 'zh_Hant', + 'zh_Hant_HK', + 'zh_Hant_MO', + 'zh_Hant_TW', + 'zh_MO', + 'zh_SG', + 'zh_TW', + 'zu', + 'zu_ZA', + ]; + + private static $localeAliases = [ + 'az_AZ' => 'az_Latn_AZ', + 'bs_BA' => 'bs_Latn_BA', + 'en_NH' => 'en_VU', + 'en_RH' => 'en_ZW', + 'ff_CM' => 'ff_Latn_CM', + 'ff_GN' => 'ff_Latn_GN', + 'ff_MR' => 'ff_Latn_MR', + 'ff_SN' => 'ff_Latn_SN', + 'in' => 'id', + 'in_ID' => 'id_ID', + 'iw' => 'he', + 'iw_IL' => 'he_IL', + 'mo' => 'ro', + 'no' => 'nb', + 'no_NO' => 'nb_NO', + 'no_NO_NY' => 'nn_NO', + 'pa_IN' => 'pa_Guru_IN', + 'pa_PK' => 'pa_Arab_PK', + 'sh' => 'sr_Latn', + 'sh_BA' => 'sr_Latn_BA', + 'sh_CS' => 'sr_Latn_RS', + 'sh_YU' => 'sr_Latn_RS', + 'sr_BA' => 'sr_Cyrl_BA', + 'sr_CS' => 'sr_Cyrl_RS', + 'sr_Cyrl_CS' => 'sr_Cyrl_RS', + 'sr_Cyrl_YU' => 'sr_Cyrl_RS', + 'sr_Latn_CS' => 'sr_Latn_RS', + 'sr_Latn_YU' => 'sr_Latn_RS', + 'sr_ME' => 'sr_Latn_ME', + 'sr_RS' => 'sr_Cyrl_RS', + 'sr_XK' => 'sr_Cyrl_XK', + 'sr_YU' => 'sr_Cyrl_RS', + 'tl' => 'fil', + 'tl_PH' => 'fil_PH', + 'uz_AF' => 'uz_Arab_AF', + 'uz_UZ' => 'uz_Latn_UZ', + 'zh_CN' => 'zh_Hans_CN', + 'zh_HK' => 'zh_Hant_HK', + 'zh_MO' => 'zh_Hant_MO', + 'zh_SG' => 'zh_Hans_SG', + 'zh_TW' => 'zh_Hant_TW', + ]; + + private static $rootLocales; + + protected function setUp() + { + Locale::setDefault('en'); + Locale::setDefaultFallback('en'); + } + + public function provideLocales() + { + return array_map( + function ($locale) { return [$locale]; }, + $this->getLocales() + ); + } + + public function provideLocaleAliases() + { + return array_map( + function ($alias, $ofLocale) { return [$alias, $ofLocale]; }, + array_keys($this->getLocaleAliases()), + $this->getLocaleAliases() + ); + } + + public function provideRootLocales() + { + return array_map( + function ($locale) { return [$locale]; }, + $this->getRootLocales() + ); + } + + protected function getLocales() + { + return self::$locales; + } + + protected function getLocaleAliases() + { + return self::$localeAliases; + } + + protected function getRootLocales() + { + if (null === self::$rootLocales) { + self::$rootLocales = array_filter($this->getLocales(), function ($locale) { + // no locales for which fallback is possible (e.g "en_GB") + return false === strpos($locale, '_'); + }); + } + + return self::$rootLocales; + } +} diff --git a/src/Symfony/Component/Intl/Tests/ScriptsTest.php b/src/Symfony/Component/Intl/Tests/ScriptsTest.php new file mode 100644 index 0000000000000..5b404fda85aaa --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/ScriptsTest.php @@ -0,0 +1,277 @@ +<?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\Component\Intl\Tests; + +use Symfony\Component\Intl\Locale; +use Symfony\Component\Intl\Scripts; + +/** + * @group intl-data + */ +class ScriptsTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + protected static $scripts = [ + 'Adlm', + 'Afak', + 'Aghb', + 'Ahom', + 'Arab', + 'Armi', + 'Armn', + 'Avst', + 'Bali', + 'Bamu', + 'Bass', + 'Batk', + 'Beng', + 'Bhks', + 'Blis', + 'Bopo', + 'Brah', + 'Brai', + 'Bugi', + 'Buhd', + 'Cakm', + 'Cans', + 'Cari', + 'Cham', + 'Cher', + 'Cirt', + 'Copt', + 'Cprt', + 'Cyrl', + 'Cyrs', + 'Deva', + 'Dogr', + 'Dsrt', + 'Dupl', + 'Egyd', + 'Egyh', + 'Egyp', + 'Elba', + 'Elym', + 'Ethi', + 'Geok', + 'Geor', + 'Glag', + 'Gong', + 'Gonm', + 'Goth', + 'Gran', + 'Grek', + 'Gujr', + 'Guru', + 'Hanb', + 'Hang', + 'Hani', + 'Hano', + 'Hans', + 'Hant', + 'Hatr', + 'Hebr', + 'Hira', + 'Hluw', + 'Hmng', + 'Hmnp', + 'Hrkt', + 'Hung', + 'Inds', + 'Ital', + 'Jamo', + 'Java', + 'Jpan', + 'Jurc', + 'Kali', + 'Kana', + 'Khar', + 'Khmr', + 'Khoj', + 'Knda', + 'Kore', + 'Kpel', + 'Kthi', + 'Lana', + 'Laoo', + 'Latf', + 'Latg', + 'Latn', + 'Lepc', + 'Limb', + 'Lina', + 'Linb', + 'Lisu', + 'Loma', + 'Lyci', + 'Lydi', + 'Mahj', + 'Maka', + 'Mand', + 'Mani', + 'Marc', + 'Maya', + 'Medf', + 'Mend', + 'Merc', + 'Mero', + 'Mlym', + 'Modi', + 'Mong', + 'Moon', + 'Mroo', + 'Mtei', + 'Mult', + 'Mymr', + 'Nand', + 'Narb', + 'Nbat', + 'Newa', + 'Nkgb', + 'Nkoo', + 'Nshu', + 'Ogam', + 'Olck', + 'Orkh', + 'Orya', + 'Osge', + 'Osma', + 'Palm', + 'Pauc', + 'Perm', + 'Phag', + 'Phli', + 'Phlp', + 'Phlv', + 'Phnx', + 'Plrd', + 'Prti', + 'Qaag', + 'Rjng', + 'Rohg', + 'Roro', + 'Runr', + 'Samr', + 'Sara', + 'Sarb', + 'Saur', + 'Sgnw', + 'Shaw', + 'Shrd', + 'Sidd', + 'Sind', + 'Sinh', + 'Sogd', + 'Sogo', + 'Sora', + 'Soyo', + 'Sund', + 'Sylo', + 'Syrc', + 'Syre', + 'Syrj', + 'Syrn', + 'Tagb', + 'Takr', + 'Tale', + 'Talu', + 'Taml', + 'Tang', + 'Tavt', + 'Telu', + 'Teng', + 'Tfng', + 'Tglg', + 'Thaa', + 'Thai', + 'Tibt', + 'Tirh', + 'Ugar', + 'Vaii', + 'Visp', + 'Wara', + 'Wcho', + 'Wole', + 'Xpeo', + 'Xsux', + 'Yiii', + 'Zanb', + 'Zinh', + 'Zmth', + 'Zsye', + 'Zsym', + 'Zxxx', + 'Zyyy', + 'Zzzz', + ]; + + public function testGetScripts() + { + $this->assertSame(self::$scripts, Scripts::getScriptCodes()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $scripts = array_keys(Scripts::getNames($displayLocale)); + + sort($scripts); + + // We can't assert on exact list of scripts, as there's too many variations between locales. + // The best we can do is to make sure getNames() returns a subset of what getScripts() returns. + $this->assertNotEmpty($scripts); + $this->assertEmpty(array_diff($scripts, self::$scripts)); + } + + public function testGetNamesDefaultLocale() + { + Locale::setDefault('de_AT'); + + $this->assertSame(Scripts::getNames('de_AT'), Scripts::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Scripts::getNames($ofLocale), Scripts::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Scripts::getNames($displayLocale); + + foreach ($names as $script => $name) { + $this->assertSame($name, Scripts::getName($script, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + Locale::setDefault('de_AT'); + + $names = Scripts::getNames('de_AT'); + + foreach ($names as $script => $name) { + $this->assertSame($name, Scripts::getName($script)); + } + } +} diff --git a/src/Symfony/Component/Validator/Constraints/Bic.php b/src/Symfony/Component/Validator/Constraints/Bic.php index c0eeade9a9d48..bd782f4c38934 100644 --- a/src/Symfony/Component/Validator/Constraints/Bic.php +++ b/src/Symfony/Component/Validator/Constraints/Bic.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -47,7 +47,7 @@ class Bic extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Regions::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index 3036d200e0668..3bbed7bfd0f20 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; use Symfony\Component\PropertyAccess\PropertyAccessor; @@ -105,8 +105,8 @@ public function validate($value, Constraint $constraint) } // @deprecated since Symfony 4.2, will throw in 5.0 - if (class_exists(Intl::class)) { - $validCountryCode = isset(Intl::getRegionBundle()->getCountryNames()[substr($canonicalize, 4, 2)]); + if (class_exists(Regions::class)) { + $validCountryCode = Regions::exists(substr($canonicalize, 4, 2)); } else { $validCountryCode = ctype_alpha(substr($canonicalize, 4, 2)); // throw new LogicException('The "symfony/intl" component is required to use the Bic constraint.'); diff --git a/src/Symfony/Component/Validator/Constraints/Country.php b/src/Symfony/Component/Validator/Constraints/Country.php index 09e1996d5bcb8..adedb665b6467 100644 --- a/src/Symfony/Component/Validator/Constraints/Country.php +++ b/src/Symfony/Component/Validator/Constraints/Country.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -33,7 +33,7 @@ class Country extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Regions::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/CountryValidator.php b/src/Symfony/Component/Validator/Constraints/CountryValidator.php index ad5dc36a9ab54..057420f7bcbed 100644 --- a/src/Symfony/Component/Validator/Constraints/CountryValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CountryValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Regions; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\LogicException; @@ -42,14 +42,13 @@ public function validate($value, Constraint $constraint) throw new UnexpectedValueException($value, 'string'); } - if (!class_exists(Intl::class)) { + if (!class_exists(Regions::class)) { throw new LogicException('The "symfony/intl" component is required to use the Country constraint.'); } $value = (string) $value; - $countries = Intl::getRegionBundle()->getCountryNames(); - if (!isset($countries[$value])) { + if (!Regions::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Country::NO_SUCH_COUNTRY_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/Currency.php b/src/Symfony/Component/Validator/Constraints/Currency.php index 4f9d7d26fc444..73ea29488f561 100644 --- a/src/Symfony/Component/Validator/Constraints/Currency.php +++ b/src/Symfony/Component/Validator/Constraints/Currency.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Currencies; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -34,7 +34,7 @@ class Currency extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Currencies::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php index 44e5df246cb89..cc25aa738e32d 100644 --- a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Currencies; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\LogicException; @@ -43,14 +43,13 @@ public function validate($value, Constraint $constraint) throw new UnexpectedValueException($value, 'string'); } - if (!class_exists(Intl::class)) { + if (!class_exists(Currencies::class)) { throw new LogicException('The "symfony/intl" component is required to use the Currency constraint.'); } $value = (string) $value; - $currencies = Intl::getCurrencyBundle()->getCurrencyNames(); - if (!isset($currencies[$value])) { + if (!Currencies::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Currency::NO_SUCH_CURRENCY_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/Language.php b/src/Symfony/Component/Validator/Constraints/Language.php index ce01bba15f09f..47b9389557b50 100644 --- a/src/Symfony/Component/Validator/Constraints/Language.php +++ b/src/Symfony/Component/Validator/Constraints/Language.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Languages; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -33,7 +33,7 @@ class Language extends Constraint public function __construct($options = null) { - if (!class_exists(Intl::class)) { + if (!class_exists(Languages::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/LanguageValidator.php b/src/Symfony/Component/Validator/Constraints/LanguageValidator.php index 22ddb0fe53459..b193ceda84107 100644 --- a/src/Symfony/Component/Validator/Constraints/LanguageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LanguageValidator.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Languages; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\LogicException; @@ -42,14 +42,13 @@ public function validate($value, Constraint $constraint) throw new UnexpectedValueException($value, 'string'); } - if (!class_exists(Intl::class)) { + if (!class_exists(Languages::class)) { throw new LogicException('The "symfony/intl" component is required to use the Language constraint.'); } $value = (string) $value; - $languages = Intl::getLanguageBundle()->getLanguageNames(); - if (!isset($languages[$value])) { + if (!Languages::exists($value)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Language::NO_SUCH_LANGUAGE_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/Locale.php b/src/Symfony/Component/Validator/Constraints/Locale.php index 0e4ccf69ce319..d56db7cf212f7 100644 --- a/src/Symfony/Component/Validator/Constraints/Locale.php +++ b/src/Symfony/Component/Validator/Constraints/Locale.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Validator\Constraints; -use Symfony\Component\Intl\Intl; +use Symfony\Component\Intl\Locales; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\LogicException; @@ -38,7 +38,7 @@ public function __construct($options = null) @trigger_error('The "canonicalize" option with value "false" is deprecated since Symfony 4.1, set it to "true" instead.', E_USER_DEPRECATED); } - if (!class_exists(Intl::class)) { + if (!class_exists(Locales::class)) { // throw new LogicException(sprintf('The "symfony/intl" component is required to use the "%s" constraint.', __CLASS__)); @trigger_error(sprintf('Using the "%s" constraint without the "symfony/intl" component installed is deprecated since Symfony 4.2.', __CLASS__), E_USER_DEPRECATED); } diff --git a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php index d4bca35a70375..244d0f554ba09 100644 --- a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php @@ -12,6 +12,7 @@ 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\UnexpectedTypeException; @@ -46,10 +47,8 @@ public function validate($value, Constraint $constraint) if ($constraint->canonicalize) { $value = \Locale::canonicalize($value); } - $localeBundle = Intl::getLocaleBundle(); - $locales = $localeBundle->getLocaleNames(); - if (!isset($locales[$value]) && !\in_array($value, $localeBundle->getAliases(), true)) { + if (!Locales::exists($value) && !\in_array($value, Locales::getAliases(), true)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($inputValue)) ->setCode(Locale::NO_SUCH_LOCALE_ERROR) diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 9813a88563afc..b6eae402a8009 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -26,7 +26,7 @@ "symfony/http-foundation": "~4.1", "symfony/http-kernel": "~3.4|~4.0", "symfony/var-dumper": "~3.4|~4.0", - "symfony/intl": "~4.1", + "symfony/intl": "^4.3", "symfony/yaml": "~3.4|~4.0", "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", @@ -43,7 +43,7 @@ "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0", "symfony/dependency-injection": "<3.4", "symfony/http-kernel": "<3.4", - "symfony/intl": "<4.1", + "symfony/intl": "<4.3", "symfony/translation": "<4.2", "symfony/yaml": "<3.4" }, From f1d3bc0e62d5ffb762f8a417f7a7110629a9a74d Mon Sep 17 00:00:00 2001 From: Yonel Ceruto <yonelceruto@gmail.com> Date: Thu, 11 Apr 2019 18:07:48 -0400 Subject: [PATCH 480/495] Show all option normalizers on debug:form command --- .../Form/Console/Descriptor/Descriptor.php | 2 +- .../Console/Descriptor/JsonDescriptor.php | 2 +- .../Console/Descriptor/TextDescriptor.php | 2 +- .../Form/Tests/Command/DebugCommandTest.php | 44 ++++++++++--------- .../default_option_with_normalizer.txt | 40 +++++++++-------- .../Fixtures/Descriptor/deprecated_option.txt | 2 +- ...verridden_option_with_default_closures.txt | 3 +- .../required_option_with_allowed_values.txt | 42 ++++++++++-------- src/Symfony/Component/Form/composer.json | 2 +- 9 files changed, 74 insertions(+), 65 deletions(-) diff --git a/src/Symfony/Component/Form/Console/Descriptor/Descriptor.php b/src/Symfony/Component/Form/Console/Descriptor/Descriptor.php index 7add269e308a0..e209e34d53061 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/Descriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/Descriptor.php @@ -120,7 +120,7 @@ protected function getOptionDefinition(OptionsResolver $optionsResolver, $option 'lazy' => 'getLazyClosures', 'allowedTypes' => 'getAllowedTypes', 'allowedValues' => 'getAllowedValues', - 'normalizer' => 'getNormalizer', + 'normalizers' => 'getNormalizers', 'deprecationMessage' => 'getDeprecationMessage', ]; diff --git a/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php index 18a288b444dd6..62d035e0246a9 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php @@ -87,7 +87,7 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio } } } - $data['has_normalizer'] = isset($definition['normalizer']); + $data['has_normalizer'] = isset($definition['normalizers']); $this->writeData($data, $options); } diff --git a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php index 176be3cd7b8df..219bd69c62c8f 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php @@ -118,7 +118,7 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio 'Default' => 'default', 'Allowed types' => 'allowedTypes', 'Allowed values' => 'allowedValues', - 'Normalizer' => 'normalizer', + 'Normalizers' => 'normalizers', ]; $rows = []; foreach ($map as $label => $name) { diff --git a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php index 71dedf67eaa48..16434073a548f 100644 --- a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php @@ -164,27 +164,29 @@ public function testDebugCustomFormTypeOption() Symfony\Component\Form\Tests\Command\FooType (foo) ================================================== - ---------------- -----------------------------------------------------------%s - Required true %w - ---------------- -----------------------------------------------------------%s - Default - %w - ---------------- -----------------------------------------------------------%s - Allowed types [ %w - "string" %w - ] %w - ---------------- -----------------------------------------------------------%s - Allowed values [ %w - "bar", %w - "baz" %w - ] %w - ---------------- -----------------------------------------------------------%s - Normalizer Closure(Options $options, $value) { %w - class: "Symfony\Component\Form\Tests\Command\FooType" %w - this: Symfony\Component\Form\Tests\Command\FooType { …} %w - file: "%s"%w - line: "%d to %d"%w - } %w - ---------------- -----------------------------------------------------------%s + ---------------- -----------%s + Required true %s + ---------------- -----------%s + Default - %s + ---------------- -----------%s + Allowed types [ %s + "string"%s + ] %s + ---------------- -----------%s + Allowed values [ %s + "bar", %s + "baz" %s + ] %s + ---------------- -----------%s + Normalizers [ %s + Closure(%s + class:%s + this: %s + file: %s + line: %s + } %s + ] %s + ---------------- -----------%s TXT , $tester->getDisplay(true)); diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt index 1824c46a7e5f8..d02b0c02ae3a2 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt @@ -2,22 +2,26 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain) ================================================================================= - ---------------- --------------------%s - Required false %s - ---------------- --------------------%s - Default true %s - ---------------- --------------------%s - Allowed types [ %s - "null", %s - "bool", %s - "string" %s - ] %s - ---------------- --------------------%s - Allowed values - %s - ---------------- --------------------%s - Normalizer Closure%s{%A - file: "%s%eExtension%eCore%eType%eChoiceType.php"%w - line: %s - } %s - ---------------- --------------------%s + ---------------- -----------%s + Required false %s + ---------------- -----------%s + Default true %s + ---------------- -----------%s + Allowed types [ %s + "null", %s + "bool", %s + "string"%s + ] %s + ---------------- -----------%s + Allowed values - %s + ---------------- -----------%s + Normalizers [ %s + Closure(%s + class:%s + this: %s + file: %s + line: %s + } %s + ] %s + ---------------- -----------%s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/deprecated_option.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/deprecated_option.txt index 1ad6c50e4acd5..e607f20b73755 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/deprecated_option.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/deprecated_option.txt @@ -14,5 +14,5 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (bar) --------------------- ----------------------------------- Allowed values - --------------------- ----------------------------------- - Normalizer - + Normalizers - --------------------- ----------------------------------- \ No newline at end of file diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt index 780a4e5cb3589..b184d75a448e2 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt @@ -1,4 +1,3 @@ - Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data) ==================================================================== @@ -22,6 +21,6 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data) ---------------- ----------------------%s Allowed values - %s ---------------- ----------------------%s - Normalizer - %s + Normalizers - %s ---------------- ----------------------%s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt index ca203a285b2c2..b42c10f5bd790 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt +++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt @@ -2,23 +2,27 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo) ============================================================= - ---------------- --------------------%s - Required true %s - ---------------- --------------------%s - Default - %s - ---------------- --------------------%s - Allowed types [ %s - "string" %s - ] %s - ---------------- --------------------%s - Allowed values [ %s - "bar", %s - "baz" %s - ] %s - ---------------- --------------------%s - Normalizer Closure%s{%A - file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w - line: %s - } %s - ---------------- --------------------%s + ---------------- -----------%s + Required true %s + ---------------- -----------%s + Default - %s + ---------------- -----------%s + Allowed types [ %s + "string"%s + ] %s + ---------------- -----------%s + Allowed values [ %s + "bar", %s + "baz" %s + ] %s + ---------------- -----------%s + Normalizers [ %s + Closure(%s + class:%s + this: %s + file: %s + line: %s + } %s + ] %s + ---------------- -----------%s diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index d448e77e5a7fe..8e2f0989dfa46 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -19,7 +19,7 @@ "php": "^7.1.3", "symfony/event-dispatcher": "^4.3", "symfony/intl": "^4.3", - "symfony/options-resolver": "~4.2", + "symfony/options-resolver": "~4.3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", "symfony/property-access": "~3.4|~4.0" From 70b448d120f53609e8be3542b354193196cda1ce Mon Sep 17 00:00:00 2001 From: Ryan Weaver <ryan@thatsquality.com> Date: Sun, 7 Apr 2019 03:44:13 -0400 Subject: [PATCH 481/495] Reorganizing messenger serializer config and replacing base64_encode with addslashes --- .../DependencyInjection/Configuration.php | 29 +++++++++++-------- .../FrameworkExtension.php | 6 ++-- .../Resources/config/schema/symfony-1.0.xsd | 12 +++++--- .../DependencyInjection/ConfigurationTest.php | 10 ++++--- .../Fixtures/php/messenger.php | 1 - .../Fixtures/php/messenger_routing.php | 4 ++- .../Fixtures/php/messenger_transport.php | 10 ++++--- .../Fixtures/php/messenger_transports.php | 4 ++- .../Fixtures/xml/messenger_routing.xml | 2 +- .../Fixtures/xml/messenger_transport.xml | 13 +++++---- .../Fixtures/xml/messenger_transports.xml | 2 +- .../Fixtures/yml/messenger.yml | 1 - .../Fixtures/yml/messenger_routing.yml | 3 +- .../Fixtures/yml/messenger_transport.yml | 11 +++---- .../Fixtures/yml/messenger_transports.yml | 3 +- .../Serialization/PhpSerializerTest.php | 6 ++-- .../Transport/Serialization/PhpSerializer.php | 10 +++---- 17 files changed, 73 insertions(+), 54 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 00d0053dc4cbd..d8b98a6319fb3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1143,20 +1143,25 @@ function ($a) { ->end() ->end() ->end() - ->scalarNode('default_serializer') - ->defaultValue('messenger.transport.native_php_serializer') - ->info('Service id to use as the default serializer for the transports.') - ->end() - ->arrayNode('symfony_serializer') + ->arrayNode('serializer') ->addDefaultsIfNotSet() ->children() - ->scalarNode('format')->defaultValue('json')->info('Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default).')->end() - ->arrayNode('context') - ->normalizeKeys(false) - ->useAttributeAsKey('name') - ->defaultValue([]) - ->info('Context array for the messenger.transport.symfony_serializer service (which is not the serializer used by default).') - ->prototype('variable')->end() + ->scalarNode('default_serializer') + ->defaultValue('messenger.transport.native_php_serializer') + ->info('Service id to use as the default serializer for the transports.') + ->end() + ->arrayNode('symfony_serializer') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('format')->defaultValue('json')->info('Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default).')->end() + ->arrayNode('context') + ->normalizeKeys(false) + ->useAttributeAsKey('name') + ->defaultValue([]) + ->info('Context array for the messenger.transport.symfony_serializer service (which is not the serializer used by default).') + ->prototype('variable')->end() + ->end() + ->end() ->end() ->end() ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index b6ffff5f07ead..c085f57e6686f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1692,9 +1692,9 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder $container->removeDefinition('messenger.transport.amqp.factory'); } else { $container->getDefinition('messenger.transport.symfony_serializer') - ->replaceArgument(1, $config['symfony_serializer']['format']) - ->replaceArgument(2, $config['symfony_serializer']['context']); - $container->setAlias('messenger.default_serializer', $config['default_serializer']); + ->replaceArgument(1, $config['serializer']['symfony_serializer']['format']) + ->replaceArgument(2, $config['serializer']['symfony_serializer']['context']); + $container->setAlias('messenger.default_serializer', $config['serializer']['default_serializer']); } $senderAliases = []; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 478a5059820a5..fcba6ef6ce362 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -407,10 +407,7 @@ <xsd:complexType name="messenger"> <xsd:sequence> - <xsd:element name="default-serializer" type="xsd:string" minOccurs="0" /> - <xsd:element name="symfony-serializer" type="messenger_symfony_serializer" minOccurs="0" /> - <xsd:element name="encoder" type="xsd:string" minOccurs="0" /> - <xsd:element name="decoder" type="xsd:string" minOccurs="0" /> + <xsd:element name="serializer" type="messenger_serializer" minOccurs="0" /> <xsd:element name="routing" type="messenger_routing" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="transport" type="messenger_transport" minOccurs="0" maxOccurs="unbounded" /> <xsd:element name="bus" type="messenger_bus" minOccurs="0" maxOccurs="unbounded" /> @@ -418,6 +415,13 @@ <xsd:attribute name="default-bus" type="xsd:string" /> </xsd:complexType> + <xsd:complexType name="messenger_serializer"> + <xsd:sequence> + <xsd:element name="symfony-serializer" type="messenger_symfony_serializer" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="default-serializer" type="xsd:string" /> + </xsd:complexType> + <xsd:complexType name="messenger_symfony_serializer"> <xsd:sequence> <xsd:element name="context" type="metadata" minOccurs="0" maxOccurs="unbounded" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php index 827988669fb8d..bd3ba1c18d8c0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php @@ -328,10 +328,12 @@ class_exists(SemaphoreStore::class) && SemaphoreStore::isSupported() ? 'semaphor 'enabled' => !class_exists(FullStack::class) && interface_exists(MessageBusInterface::class), 'routing' => [], 'transports' => [], - 'default_serializer' => 'messenger.transport.native_php_serializer', - 'symfony_serializer' => [ - 'format' => 'json', - 'context' => [], + 'serializer' => [ + 'default_serializer' => 'messenger.transport.native_php_serializer', + 'symfony_serializer' => [ + 'format' => 'json', + 'context' => [], + ], ], 'default_bus' => null, 'buses' => ['messenger.bus.default' => ['default_middleware' => true, 'middleware' => []]], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php index c74b64f3ffb1d..1160dfc573a7c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger.php @@ -5,7 +5,6 @@ $container->loadFromExtension('framework', [ 'messenger' => [ - 'default_serializer' => false, 'routing' => [ FooMessage::class => ['sender.bar', 'sender.biz'], BarMessage::class => 'sender.foo', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php index 6e0b7c61f1297..c8bddb1e8fcec 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_routing.php @@ -3,7 +3,9 @@ $container->loadFromExtension('framework', [ 'serializer' => true, 'messenger' => [ - 'default_serializer' => 'messenger.transport.symfony_serializer', + 'serializer' => [ + 'default_serializer' => 'messenger.transport.symfony_serializer', + ], 'routing' => [ 'Symfony\Component\Messenger\Tests\Fixtures\DummyMessage' => ['amqp', 'audit'], 'Symfony\Component\Messenger\Tests\Fixtures\SecondMessage' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php index 6a1c729fd460b..7baab29dc57ce 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transport.php @@ -3,10 +3,12 @@ $container->loadFromExtension('framework', [ 'serializer' => true, 'messenger' => [ - 'default_serializer' => 'messenger.transport.symfony_serializer', - 'symfony_serializer' => [ - 'format' => 'csv', - 'context' => ['enable_max_depth' => true], + 'serializer' => [ + 'default_serializer' => 'messenger.transport.symfony_serializer', + 'symfony_serializer' => [ + 'format' => 'csv', + 'context' => ['enable_max_depth' => true], + ], ], 'transports' => [ 'default' => 'amqp://localhost/%2f/messages', diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php index a326c505e62b2..b655644e0dff5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_transports.php @@ -3,7 +3,9 @@ $container->loadFromExtension('framework', [ 'serializer' => true, 'messenger' => [ - 'default_serializer' => 'messenger.transport.symfony_serializer', + 'serializer' => [ + 'default_serializer' => 'messenger.transport.symfony_serializer', + ], 'transports' => [ 'default' => 'amqp://localhost/%2f/messages', 'customised' => [ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml index 6231a7a82e98a..2b895cb6e6b86 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_routing.xml @@ -8,7 +8,7 @@ <framework:config> <framework:serializer enabled="true" /> <framework:messenger> - <framework:default-serializer>messenger.transport.symfony_serializer</framework:default-serializer> + <framework:serializer default-serializer="messenger.transport.symfony_serializer" /> <framework:routing message-class="Symfony\Component\Messenger\Tests\Fixtures\DummyMessage"> <framework:sender service="amqp" /> <framework:sender service="audit" /> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml index 82a85aedcc849..e5e60a39823a6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transport.xml @@ -8,12 +8,13 @@ <framework:config> <framework:serializer enabled="true" /> <framework:messenger> - <framework:default-serializer>messenger.transport.symfony_serializer</framework:default-serializer> - <framework:symfony-serializer format="csv"> - <framework:context> - <framework:enable_max_depth>true</framework:enable_max_depth> - </framework:context> - </framework:symfony-serializer> + <framework:serializer default-serializer="messenger.transport.symfony_serializer"> + <framework:symfony-serializer format="csv"> + <framework:context> + <framework:enable_max_depth>true</framework:enable_max_depth> + </framework:context> + </framework:symfony-serializer> + </framework:serializer> <framework:transport name="default" dsn="amqp://localhost/%2f/messages" /> </framework:messenger> </framework:config> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml index 70cdb69a8ada4..411c0c29e5b50 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_transports.xml @@ -8,7 +8,7 @@ <framework:config> <framework:serializer enabled="true" /> <framework:messenger> - <framework:default-serializer>messenger.transport.symfony_serializer</framework:default-serializer> + <framework:serializer default-serializer="messenger.transport.symfony_serializer" /> <framework:transport name="default" dsn="amqp://localhost/%2f/messages" /> <framework:transport name="customised" dsn="amqp://localhost/%2f/messages?exchange_name=exchange_name" serializer="messenger.transport.native_php_serializer"> <framework:options> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml index 42df49ea4d1cb..7f038af11fdff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger.yml @@ -1,6 +1,5 @@ framework: messenger: - default_serializer: false routing: 'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\FooMessage': ['sender.bar', 'sender.biz'] 'Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Messenger\BarMessage': 'sender.foo' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml index 4481a16d46033..84b6e2c0047ed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_routing.yml @@ -1,7 +1,8 @@ framework: serializer: true messenger: - default_serializer: messenger.transport.symfony_serializer + serializer: + default_serializer: messenger.transport.symfony_serializer routing: 'Symfony\Component\Messenger\Tests\Fixtures\DummyMessage': [amqp, audit] 'Symfony\Component\Messenger\Tests\Fixtures\SecondMessage': diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml index 8740f37bd6ec1..b51feb73bce95 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transport.yml @@ -1,10 +1,11 @@ framework: serializer: true messenger: - default_serializer: messenger.transport.symfony_serializer - symfony_serializer: - format: csv - context: - enable_max_depth: true + serializer: + default_serializer: messenger.transport.symfony_serializer + symfony_serializer: + format: csv + context: + enable_max_depth: true transports: default: 'amqp://localhost/%2f/messages' diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml index 48ff8c6c82364..409e410986840 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_transports.yml @@ -1,7 +1,8 @@ framework: serializer: true messenger: - default_serializer: messenger.transport.symfony_serializer + serializer: + default_serializer: messenger.transport.symfony_serializer transports: default: 'amqp://localhost/%2f/messages' customised: diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php index 53905a053d1a5..6e508365e500a 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php @@ -25,7 +25,9 @@ public function testEncodedIsDecodable() $envelope = new Envelope(new DummyMessage('Hello')); - $this->assertEquals($envelope, $serializer->decode($serializer->encode($envelope))); + $encoded = $serializer->encode($envelope); + $this->assertNotContains("\0", $encoded['body'], 'Does not contain the binary characters'); + $this->assertEquals($envelope, $serializer->decode($encoded)); } public function testDecodingFailsWithMissingBodyKey() @@ -58,7 +60,7 @@ public function testDecodingFailsWithBadClass() $serializer = new PhpSerializer(); $serializer->decode([ - 'body' => base64_encode('O:13:"ReceivedSt0mp":0:{}'), + 'body' => 'O:13:"ReceivedSt0mp":0:{}', ]); } } diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php index 6a27529c5592d..a916bf795c21d 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php @@ -30,11 +30,7 @@ public function decode(array $encodedEnvelope): Envelope throw new MessageDecodingFailedException('Encoded envelope should have at least a "body".'); } - $serializeEnvelope = base64_decode($encodedEnvelope['body']); - - if (false === $serializeEnvelope) { - throw new MessageDecodingFailedException('The "body" key could not be base64 decoded.'); - } + $serializeEnvelope = stripslashes($encodedEnvelope['body']); return $this->safelyUnserialize($serializeEnvelope); } @@ -44,8 +40,10 @@ public function decode(array $encodedEnvelope): Envelope */ public function encode(Envelope $envelope): array { + $body = addslashes(serialize($envelope)); + return [ - 'body' => base64_encode(serialize($envelope)), + 'body' => $body, ]; } From 8f699541f5021b9160b8b1f6be9545891e8f98f6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Mon, 15 Apr 2019 19:24:46 +0200 Subject: [PATCH 482/495] [HttpClient] fix too high timeout in test --- src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index fb3a547519b02..b898ba55c6c95 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -541,7 +541,7 @@ public function testResolve() $response = null; $this->expectException(TransportExceptionInterface::class); - $client->request('GET', 'http://symfony.com:8057/'); + $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 3]); } public function testTimeoutOnAccess() From 6a94dea5cdc299c9ddddddae5adc967c537da736 Mon Sep 17 00:00:00 2001 From: Chris Tanaskoski <chris@devristo.com> Date: Tue, 9 Apr 2019 17:31:33 +0200 Subject: [PATCH 483/495] [BrowserKit] Fixed BC-break introduced by rename of Client to Browser --- .../Component/BrowserKit/AbstractBrowser.php | 712 +---------------- src/Symfony/Component/BrowserKit/Client.php | 724 +++++++++++++++++- .../BrowserKit/Tests/AbstractBrowserTest.php | 23 +- 3 files changed, 740 insertions(+), 719 deletions(-) diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php index fd6dc27a0d4f6..f58a8756bb48b 100644 --- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php @@ -11,12 +11,6 @@ namespace Symfony\Component\BrowserKit; -use Symfony\Component\BrowserKit\Exception\BadMethodCallException; -use Symfony\Component\DomCrawler\Crawler; -use Symfony\Component\DomCrawler\Form; -use Symfony\Component\DomCrawler\Link; -use Symfony\Component\Process\PhpProcess; - /** * Simulates a browser. * @@ -30,710 +24,6 @@ * * @author Fabien Potencier <fabien@symfony.com> */ -abstract class AbstractBrowser +abstract class AbstractBrowser extends Client { - protected $history; - protected $cookieJar; - protected $server = []; - protected $internalRequest; - protected $request; - protected $internalResponse; - protected $response; - protected $crawler; - protected $insulated = false; - protected $redirect; - protected $followRedirects = true; - protected $followMetaRefresh = false; - - private $maxRedirects = -1; - private $redirectCount = 0; - private $redirects = []; - private $isMainRequest = true; - - /** - * @param array $server The server parameters (equivalent of $_SERVER) - * @param History $history A History instance to store the browser history - * @param CookieJar $cookieJar A CookieJar instance to store the cookies - */ - public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) - { - $this->setServerParameters($server); - $this->history = $history ?: new History(); - $this->cookieJar = $cookieJar ?: new CookieJar(); - } - - /** - * Sets whether to automatically follow redirects or not. - * - * @param bool $followRedirect Whether to follow redirects - */ - public function followRedirects($followRedirect = true) - { - $this->followRedirects = (bool) $followRedirect; - } - - /** - * Sets whether to automatically follow meta refresh redirects or not. - */ - public function followMetaRefresh(bool $followMetaRefresh = true) - { - $this->followMetaRefresh = $followMetaRefresh; - } - - /** - * Returns whether client automatically follows redirects or not. - * - * @return bool - */ - public function isFollowingRedirects() - { - return $this->followRedirects; - } - - /** - * Sets the maximum number of redirects that crawler can follow. - * - * @param int $maxRedirects - */ - public function setMaxRedirects($maxRedirects) - { - $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects; - $this->followRedirects = -1 != $this->maxRedirects; - } - - /** - * Returns the maximum number of redirects that crawler can follow. - * - * @return int - */ - public function getMaxRedirects() - { - return $this->maxRedirects; - } - - /** - * Sets the insulated flag. - * - * @param bool $insulated Whether to insulate the requests or not - * - * @throws \RuntimeException When Symfony Process Component is not installed - */ - public function insulate($insulated = true) - { - if ($insulated && !class_exists('Symfony\\Component\\Process\\Process')) { - throw new \LogicException('Unable to isolate requests as the Symfony Process Component is not installed.'); - } - - $this->insulated = (bool) $insulated; - } - - /** - * Sets server parameters. - * - * @param array $server An array of server parameters - */ - public function setServerParameters(array $server) - { - $this->server = array_merge([ - 'HTTP_USER_AGENT' => 'Symfony BrowserKit', - ], $server); - } - - /** - * Sets single server parameter. - * - * @param string $key A key of the parameter - * @param string $value A value of the parameter - */ - public function setServerParameter($key, $value) - { - $this->server[$key] = $value; - } - - /** - * Gets single server parameter for specified key. - * - * @param string $key A key of the parameter to get - * @param string $default A default value when key is undefined - * - * @return string A value of the parameter - */ - public function getServerParameter($key, $default = '') - { - return isset($this->server[$key]) ? $this->server[$key] : $default; - } - - public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler - { - $this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest'); - - try { - return $this->request($method, $uri, $parameters, $files, $server, $content, $changeHistory); - } finally { - unset($this->server['HTTP_X_REQUESTED_WITH']); - } - } - - /** - * Returns the History instance. - * - * @return History A History instance - */ - public function getHistory() - { - return $this->history; - } - - /** - * Returns the CookieJar instance. - * - * @return CookieJar A CookieJar instance - */ - public function getCookieJar() - { - return $this->cookieJar; - } - - /** - * Returns the current Crawler instance. - * - * @return Crawler A Crawler instance - */ - public function getCrawler() - { - if (null === $this->crawler) { - @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); - // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - return $this->crawler; - } - - /** - * Returns the current BrowserKit Response instance. - * - * @return Response A BrowserKit Response instance - */ - public function getInternalResponse() - { - if (null === $this->internalResponse) { - @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); - // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - return $this->internalResponse; - } - - /** - * Returns the current origin response instance. - * - * The origin response is the response instance that is returned - * by the code that handles requests. - * - * @return object A response instance - * - * @see doRequest() - */ - public function getResponse() - { - if (null === $this->response) { - @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); - // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - return $this->response; - } - - /** - * Returns the current BrowserKit Request instance. - * - * @return Request A BrowserKit Request instance - */ - public function getInternalRequest() - { - if (null === $this->internalRequest) { - @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); - // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - return $this->internalRequest; - } - - /** - * Returns the current origin Request instance. - * - * The origin request is the request instance that is sent - * to the code that handles requests. - * - * @return object A Request instance - * - * @see doRequest() - */ - public function getRequest() - { - if (null === $this->request) { - @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', __METHOD__), E_USER_DEPRECATED); - // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - return $this->request; - } - - /** - * Clicks on a given link. - * - * @return Crawler - */ - public function click(Link $link) - { - if ($link instanceof Form) { - return $this->submit($link); - } - - return $this->request($link->getMethod(), $link->getUri()); - } - - /** - * Clicks the first link (or clickable image) that contains the given text. - * - * @param string $linkText The text of the link or the alt attribute of the clickable image - */ - public function clickLink(string $linkText): Crawler - { - if (null === $this->crawler) { - throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - return $this->click($this->crawler->selectLink($linkText)->link()); - } - - /** - * Submits a form. - * - * @param Form $form A Form instance - * @param array $values An array of form field values - * @param array $serverParameters An array of server parameters - * - * @return Crawler - */ - public function submit(Form $form, array $values = []/*, array $serverParameters = []*/) - { - if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { - @trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); - } - - $form->setValues($values); - $serverParameters = 2 < \func_num_args() ? func_get_arg(2) : []; - - return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles(), $serverParameters); - } - - /** - * Finds the first form that contains a button with the given content and - * uses it to submit the given form field values. - * - * @param string $button The text content, id, value or name of the form <button> or <input type="submit"> - * @param array $fieldValues Use this syntax: ['my_form[name]' => '...', 'my_form[email]' => '...'] - * @param string $method The HTTP method used to submit the form - * @param array $serverParameters These values override the ones stored in $_SERVER (HTTP headers must include a HTTP_ prefix as PHP does) - */ - public function submitForm(string $button, array $fieldValues = [], string $method = 'POST', array $serverParameters = []): Crawler - { - if (null === $this->crawler) { - throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); - } - - $buttonNode = $this->crawler->selectButton($button); - $form = $buttonNode->form($fieldValues, $method); - - return $this->submit($form, [], $serverParameters); - } - - /** - * Calls a URI. - * - * @param string $method The request method - * @param string $uri The URI to fetch - * @param array $parameters The Request parameters - * @param array $files The files - * @param array $server The server parameters (HTTP headers are referenced with a HTTP_ prefix as PHP does) - * @param string $content The raw body data - * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload()) - * - * @return Crawler - */ - public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true) - { - if ($this->isMainRequest) { - $this->redirectCount = 0; - } else { - ++$this->redirectCount; - } - - $originalUri = $uri; - - $uri = $this->getAbsoluteUri($uri); - - $server = array_merge($this->server, $server); - - if (!empty($server['HTTP_HOST']) && null === parse_url($originalUri, PHP_URL_HOST)) { - $uri = preg_replace('{^(https?\://)'.preg_quote($this->extractHost($uri)).'}', '${1}'.$server['HTTP_HOST'], $uri); - } - - if (isset($server['HTTPS']) && null === parse_url($originalUri, PHP_URL_SCHEME)) { - $uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri); - } - - if (!$this->history->isEmpty()) { - $server['HTTP_REFERER'] = $this->history->current()->getUri(); - } - - if (empty($server['HTTP_HOST'])) { - $server['HTTP_HOST'] = $this->extractHost($uri); - } - - $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME); - - $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content); - - $this->request = $this->filterRequest($this->internalRequest); - - if (true === $changeHistory) { - $this->history->add($this->internalRequest); - } - - if ($this->insulated) { - $this->response = $this->doRequestInProcess($this->request); - } else { - $this->response = $this->doRequest($this->request); - } - - $this->internalResponse = $this->filterResponse($this->response); - - $this->cookieJar->updateFromResponse($this->internalResponse, $uri); - - $status = $this->internalResponse->getStatusCode(); - - if ($status >= 300 && $status < 400) { - $this->redirect = $this->internalResponse->getHeader('Location'); - } else { - $this->redirect = null; - } - - if ($this->followRedirects && $this->redirect) { - $this->redirects[serialize($this->history->current())] = true; - - return $this->crawler = $this->followRedirect(); - } - - $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type')); - - // Check for meta refresh redirect - if ($this->followMetaRefresh && null !== $redirect = $this->getMetaRefreshUrl()) { - $this->redirect = $redirect; - $this->redirects[serialize($this->history->current())] = true; - $this->crawler = $this->followRedirect(); - } - - return $this->crawler; - } - - /** - * Makes a request in another process. - * - * @param object $request An origin request instance - * - * @return object An origin response instance - * - * @throws \RuntimeException When processing returns exit code - */ - protected function doRequestInProcess($request) - { - $deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec'); - putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile); - $_ENV['SYMFONY_DEPRECATIONS_SERIALIZE'] = $deprecationsFile; - $process = new PhpProcess($this->getScript($request), null, null); - $process->run(); - - if (file_exists($deprecationsFile)) { - $deprecations = file_get_contents($deprecationsFile); - unlink($deprecationsFile); - foreach ($deprecations ? unserialize($deprecations) : [] as $deprecation) { - if ($deprecation[0]) { - @trigger_error($deprecation[1], E_USER_DEPRECATED); - } else { - @trigger_error($deprecation[1], E_USER_DEPRECATED); - } - } - } - - if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) { - throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput())); - } - - return unserialize($process->getOutput()); - } - - /** - * Makes a request. - * - * @param object $request An origin request instance - * - * @return object An origin response instance - */ - abstract protected function doRequest($request); - - /** - * Returns the script to execute when the request must be insulated. - * - * @param object $request An origin request instance - * - * @throws \LogicException When this abstract class is not implemented - */ - protected function getScript($request) - { - throw new \LogicException('To insulate requests, you need to override the getScript() method.'); - } - - /** - * Filters the BrowserKit request to the origin one. - * - * @param Request $request The BrowserKit Request to filter - * - * @return object An origin request instance - */ - protected function filterRequest(Request $request) - { - return $request; - } - - /** - * Filters the origin response to the BrowserKit one. - * - * @param object $response The origin response to filter - * - * @return Response An BrowserKit Response instance - */ - protected function filterResponse($response) - { - return $response; - } - - /** - * Creates a crawler. - * - * This method returns null if the DomCrawler component is not available. - * - * @param string $uri A URI - * @param string $content Content for the crawler to use - * @param string $type Content type - * - * @return Crawler|null - */ - protected function createCrawlerFromContent($uri, $content, $type) - { - if (!class_exists('Symfony\Component\DomCrawler\Crawler')) { - return; - } - - $crawler = new Crawler(null, $uri); - $crawler->addContent($content, $type); - - return $crawler; - } - - /** - * Goes back in the browser history. - * - * @return Crawler - */ - public function back() - { - do { - $request = $this->history->back(); - } while (\array_key_exists(serialize($request), $this->redirects)); - - return $this->requestFromRequest($request, false); - } - - /** - * Goes forward in the browser history. - * - * @return Crawler - */ - public function forward() - { - do { - $request = $this->history->forward(); - } while (\array_key_exists(serialize($request), $this->redirects)); - - return $this->requestFromRequest($request, false); - } - - /** - * Reloads the current browser. - * - * @return Crawler - */ - public function reload() - { - return $this->requestFromRequest($this->history->current(), false); - } - - /** - * Follow redirects? - * - * @return Crawler - * - * @throws \LogicException If request was not a redirect - */ - public function followRedirect() - { - if (empty($this->redirect)) { - throw new \LogicException('The request was not redirected.'); - } - - if (-1 !== $this->maxRedirects) { - if ($this->redirectCount > $this->maxRedirects) { - $this->redirectCount = 0; - throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects)); - } - } - - $request = $this->internalRequest; - - if (\in_array($this->internalResponse->getStatusCode(), [301, 302, 303])) { - $method = 'GET'; - $files = []; - $content = null; - } else { - $method = $request->getMethod(); - $files = $request->getFiles(); - $content = $request->getContent(); - } - - if ('GET' === strtoupper($method)) { - // Don't forward parameters for GET request as it should reach the redirection URI - $parameters = []; - } else { - $parameters = $request->getParameters(); - } - - $server = $request->getServer(); - $server = $this->updateServerFromUri($server, $this->redirect); - - $this->isMainRequest = false; - - $response = $this->request($method, $this->redirect, $parameters, $files, $server, $content); - - $this->isMainRequest = true; - - return $response; - } - - /** - * @see https://dev.w3.org/html5/spec-preview/the-meta-element.html#attr-meta-http-equiv-refresh - */ - private function getMetaRefreshUrl(): ?string - { - $metaRefresh = $this->getCrawler()->filter('head meta[http-equiv="refresh"]'); - foreach ($metaRefresh->extract(['content']) as $content) { - if (preg_match('/^\s*0\s*;\s*URL\s*=\s*(?|\'([^\']++)|"([^"]++)|([^\'"].*))/i', $content, $m)) { - return str_replace("\t\r\n", '', rtrim($m[1])); - } - } - - return null; - } - - /** - * Restarts the client. - * - * It flushes history and all cookies. - */ - public function restart() - { - $this->cookieJar->clear(); - $this->history->clear(); - } - - /** - * Takes a URI and converts it to absolute if it is not already absolute. - * - * @param string $uri A URI - * - * @return string An absolute URI - */ - protected function getAbsoluteUri($uri) - { - // already absolute? - if (0 === strpos($uri, 'http://') || 0 === strpos($uri, 'https://')) { - return $uri; - } - - if (!$this->history->isEmpty()) { - $currentUri = $this->history->current()->getUri(); - } else { - $currentUri = sprintf('http%s://%s/', - isset($this->server['HTTPS']) ? 's' : '', - isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost' - ); - } - - // protocol relative URL - if (0 === strpos($uri, '//')) { - return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri; - } - - // anchor or query string parameters? - if (!$uri || '#' == $uri[0] || '?' == $uri[0]) { - return preg_replace('/[#?].*?$/', '', $currentUri).$uri; - } - - if ('/' !== $uri[0]) { - $path = parse_url($currentUri, PHP_URL_PATH); - - if ('/' !== substr($path, -1)) { - $path = substr($path, 0, strrpos($path, '/') + 1); - } - - $uri = $path.$uri; - } - - return preg_replace('#^(.*?//[^/]+)\/.*$#', '$1', $currentUri).$uri; - } - - /** - * Makes a request from a Request object directly. - * - * @param Request $request A Request instance - * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload()) - * - * @return Crawler - */ - protected function requestFromRequest(Request $request, $changeHistory = true) - { - return $this->request($request->getMethod(), $request->getUri(), $request->getParameters(), $request->getFiles(), $request->getServer(), $request->getContent(), $changeHistory); - } - - private function updateServerFromUri($server, $uri) - { - $server['HTTP_HOST'] = $this->extractHost($uri); - $scheme = parse_url($uri, PHP_URL_SCHEME); - $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme; - unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']); - - return $server; - } - - private function extractHost($uri) - { - $host = parse_url($uri, PHP_URL_HOST); - - if ($port = parse_url($uri, PHP_URL_PORT)) { - return $host.':'.$port; - } - - return $host; - } } diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index ddeaa25f3fa38..536383b382e40 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -11,8 +11,728 @@ namespace Symfony\Component\BrowserKit; -@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Client::class, AbstractBrowser::class), E_USER_DEPRECATED); +use Symfony\Component\BrowserKit\Exception\BadMethodCallException; +use Symfony\Component\DomCrawler\Crawler; +use Symfony\Component\DomCrawler\Form; +use Symfony\Component\DomCrawler\Link; +use Symfony\Component\Process\PhpProcess; -abstract class Client extends AbstractBrowser +/** + * Client simulates a browser. + * + * To make the actual request, you need to implement the doRequest() method. + * + * If you want to be able to run requests in their own process (insulated flag), + * you need to also implement the getScript() method. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @deprecated since Symfony 4.3, use "\Symfony\Component\BrowserKit\AbstractBrowser" instead + */ +abstract class Client { + protected $history; + protected $cookieJar; + protected $server = []; + protected $internalRequest; + protected $request; + protected $internalResponse; + protected $response; + protected $crawler; + protected $insulated = false; + protected $redirect; + protected $followRedirects = true; + protected $followMetaRefresh = false; + + private $maxRedirects = -1; + private $redirectCount = 0; + private $redirects = []; + private $isMainRequest = true; + + /** + * @param array $server The server parameters (equivalent of $_SERVER) + * @param History $history A History instance to store the browser history + * @param CookieJar $cookieJar A CookieJar instance to store the cookies + */ + public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) + { + $this->setServerParameters($server); + $this->history = $history ?: new History(); + $this->cookieJar = $cookieJar ?: new CookieJar(); + } + + /** + * Sets whether to automatically follow redirects or not. + * + * @param bool $followRedirect Whether to follow redirects + */ + public function followRedirects($followRedirect = true) + { + $this->followRedirects = (bool) $followRedirect; + } + + /** + * Sets whether to automatically follow meta refresh redirects or not. + */ + public function followMetaRefresh(bool $followMetaRefresh = true) + { + $this->followMetaRefresh = $followMetaRefresh; + } + + /** + * Returns whether client automatically follows redirects or not. + * + * @return bool + */ + public function isFollowingRedirects() + { + return $this->followRedirects; + } + + /** + * Sets the maximum number of redirects that crawler can follow. + * + * @param int $maxRedirects + */ + public function setMaxRedirects($maxRedirects) + { + $this->maxRedirects = $maxRedirects < 0 ? -1 : $maxRedirects; + $this->followRedirects = -1 != $this->maxRedirects; + } + + /** + * Returns the maximum number of redirects that crawler can follow. + * + * @return int + */ + public function getMaxRedirects() + { + return $this->maxRedirects; + } + + /** + * Sets the insulated flag. + * + * @param bool $insulated Whether to insulate the requests or not + * + * @throws \RuntimeException When Symfony Process Component is not installed + */ + public function insulate($insulated = true) + { + if ($insulated && !class_exists('Symfony\\Component\\Process\\Process')) { + throw new \LogicException('Unable to isolate requests as the Symfony Process Component is not installed.'); + } + + $this->insulated = (bool) $insulated; + } + + /** + * Sets server parameters. + * + * @param array $server An array of server parameters + */ + public function setServerParameters(array $server) + { + $this->server = array_merge([ + 'HTTP_USER_AGENT' => 'Symfony BrowserKit', + ], $server); + } + + /** + * Sets single server parameter. + * + * @param string $key A key of the parameter + * @param string $value A value of the parameter + */ + public function setServerParameter($key, $value) + { + $this->server[$key] = $value; + } + + /** + * Gets single server parameter for specified key. + * + * @param string $key A key of the parameter to get + * @param string $default A default value when key is undefined + * + * @return string A value of the parameter + */ + public function getServerParameter($key, $default = '') + { + return isset($this->server[$key]) ? $this->server[$key] : $default; + } + + public function xmlHttpRequest(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true): Crawler + { + $this->setServerParameter('HTTP_X_REQUESTED_WITH', 'XMLHttpRequest'); + + try { + return $this->request($method, $uri, $parameters, $files, $server, $content, $changeHistory); + } finally { + unset($this->server['HTTP_X_REQUESTED_WITH']); + } + } + + /** + * Returns the History instance. + * + * @return History A History instance + */ + public function getHistory() + { + return $this->history; + } + + /** + * Returns the CookieJar instance. + * + * @return CookieJar A CookieJar instance + */ + public function getCookieJar() + { + return $this->cookieJar; + } + + /** + * Returns the current Crawler instance. + * + * @return Crawler A Crawler instance + */ + public function getCrawler() + { + if (null === $this->crawler) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', \get_class($this).'::'.__FUNCTION__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->crawler; + } + + /** + * Returns the current BrowserKit Response instance. + * + * @return Response A BrowserKit Response instance + */ + public function getInternalResponse() + { + if (null === $this->internalResponse) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', \get_class($this).'::'.__FUNCTION__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->internalResponse; + } + + /** + * Returns the current origin response instance. + * + * The origin response is the response instance that is returned + * by the code that handles requests. + * + * @return object A response instance + * + * @see doRequest() + */ + public function getResponse() + { + if (null === $this->response) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', \get_class($this).'::'.__FUNCTION__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->response; + } + + /** + * Returns the current BrowserKit Request instance. + * + * @return Request A BrowserKit Request instance + */ + public function getInternalRequest() + { + if (null === $this->internalRequest) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', \get_class($this).'::'.__FUNCTION__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->internalRequest; + } + + /** + * Returns the current origin Request instance. + * + * The origin request is the request instance that is sent + * to the code that handles requests. + * + * @return object A Request instance + * + * @see doRequest() + */ + public function getRequest() + { + if (null === $this->request) { + @trigger_error(sprintf('Calling the "%s()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0.', \get_class($this).'::'.__FUNCTION__), E_USER_DEPRECATED); + // throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->request; + } + + /** + * Clicks on a given link. + * + * @return Crawler + */ + public function click(Link $link) + { + if ($link instanceof Form) { + return $this->submit($link); + } + + return $this->request($link->getMethod(), $link->getUri()); + } + + /** + * Clicks the first link (or clickable image) that contains the given text. + * + * @param string $linkText The text of the link or the alt attribute of the clickable image + */ + public function clickLink(string $linkText): Crawler + { + if (null === $this->crawler) { + throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + return $this->click($this->crawler->selectLink($linkText)->link()); + } + + /** + * Submits a form. + * + * @param Form $form A Form instance + * @param array $values An array of form field values + * @param array $serverParameters An array of server parameters + * + * @return Crawler + */ + public function submit(Form $form, array $values = []/*, array $serverParameters = []*/) + { + if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { + @trigger_error(sprintf('The "%s()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2.', \get_class($this).'::'.__FUNCTION__), E_USER_DEPRECATED); + } + + $form->setValues($values); + $serverParameters = 2 < \func_num_args() ? func_get_arg(2) : []; + + return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles(), $serverParameters); + } + + /** + * Finds the first form that contains a button with the given content and + * uses it to submit the given form field values. + * + * @param string $button The text content, id, value or name of the form <button> or <input type="submit"> + * @param array $fieldValues Use this syntax: ['my_form[name]' => '...', 'my_form[email]' => '...'] + * @param string $method The HTTP method used to submit the form + * @param array $serverParameters These values override the ones stored in $_SERVER (HTTP headers must include a HTTP_ prefix as PHP does) + */ + public function submitForm(string $button, array $fieldValues = [], string $method = 'POST', array $serverParameters = []): Crawler + { + if (null === $this->crawler) { + throw new BadMethodCallException(sprintf('The "request()" method must be called before "%s()".', __METHOD__)); + } + + $buttonNode = $this->crawler->selectButton($button); + $form = $buttonNode->form($fieldValues, $method); + + return $this->submit($form, [], $serverParameters); + } + + /** + * Calls a URI. + * + * @param string $method The request method + * @param string $uri The URI to fetch + * @param array $parameters The Request parameters + * @param array $files The files + * @param array $server The server parameters (HTTP headers are referenced with a HTTP_ prefix as PHP does) + * @param string $content The raw body data + * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload()) + * + * @return Crawler + */ + public function request(string $method, string $uri, array $parameters = [], array $files = [], array $server = [], string $content = null, bool $changeHistory = true) + { + if ($this->isMainRequest) { + $this->redirectCount = 0; + } else { + ++$this->redirectCount; + } + + $originalUri = $uri; + + $uri = $this->getAbsoluteUri($uri); + + $server = array_merge($this->server, $server); + + if (!empty($server['HTTP_HOST']) && null === parse_url($originalUri, PHP_URL_HOST)) { + $uri = preg_replace('{^(https?\://)'.preg_quote($this->extractHost($uri)).'}', '${1}'.$server['HTTP_HOST'], $uri); + } + + if (isset($server['HTTPS']) && null === parse_url($originalUri, PHP_URL_SCHEME)) { + $uri = preg_replace('{^'.parse_url($uri, PHP_URL_SCHEME).'}', $server['HTTPS'] ? 'https' : 'http', $uri); + } + + if (!$this->history->isEmpty()) { + $server['HTTP_REFERER'] = $this->history->current()->getUri(); + } + + if (empty($server['HTTP_HOST'])) { + $server['HTTP_HOST'] = $this->extractHost($uri); + } + + $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME); + + $this->internalRequest = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content); + + $this->request = $this->filterRequest($this->internalRequest); + + if (true === $changeHistory) { + $this->history->add($this->internalRequest); + } + + if ($this->insulated) { + $this->response = $this->doRequestInProcess($this->request); + } else { + $this->response = $this->doRequest($this->request); + } + + $this->internalResponse = $this->filterResponse($this->response); + + $this->cookieJar->updateFromResponse($this->internalResponse, $uri); + + $status = $this->internalResponse->getStatusCode(); + + if ($status >= 300 && $status < 400) { + $this->redirect = $this->internalResponse->getHeader('Location'); + } else { + $this->redirect = null; + } + + if ($this->followRedirects && $this->redirect) { + $this->redirects[serialize($this->history->current())] = true; + + return $this->crawler = $this->followRedirect(); + } + + $this->crawler = $this->createCrawlerFromContent($this->internalRequest->getUri(), $this->internalResponse->getContent(), $this->internalResponse->getHeader('Content-Type')); + + // Check for meta refresh redirect + if ($this->followMetaRefresh && null !== $redirect = $this->getMetaRefreshUrl()) { + $this->redirect = $redirect; + $this->redirects[serialize($this->history->current())] = true; + $this->crawler = $this->followRedirect(); + } + + return $this->crawler; + } + + /** + * Makes a request in another process. + * + * @param object $request An origin request instance + * + * @return object An origin response instance + * + * @throws \RuntimeException When processing returns exit code + */ + protected function doRequestInProcess($request) + { + $deprecationsFile = tempnam(sys_get_temp_dir(), 'deprec'); + putenv('SYMFONY_DEPRECATIONS_SERIALIZE='.$deprecationsFile); + $_ENV['SYMFONY_DEPRECATIONS_SERIALIZE'] = $deprecationsFile; + $process = new PhpProcess($this->getScript($request), null, null); + $process->run(); + + if (file_exists($deprecationsFile)) { + $deprecations = file_get_contents($deprecationsFile); + unlink($deprecationsFile); + foreach ($deprecations ? unserialize($deprecations) : [] as $deprecation) { + if ($deprecation[0]) { + @trigger_error($deprecation[1], E_USER_DEPRECATED); + } else { + @trigger_error($deprecation[1], E_USER_DEPRECATED); + } + } + } + + if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) { + throw new \RuntimeException(sprintf('OUTPUT: %s ERROR OUTPUT: %s', $process->getOutput(), $process->getErrorOutput())); + } + + return unserialize($process->getOutput()); + } + + /** + * Makes a request. + * + * @param object $request An origin request instance + * + * @return object An origin response instance + */ + abstract protected function doRequest($request); + + /** + * Returns the script to execute when the request must be insulated. + * + * @param object $request An origin request instance + * + * @throws \LogicException When this abstract class is not implemented + */ + protected function getScript($request) + { + throw new \LogicException('To insulate requests, you need to override the getScript() method.'); + } + + /** + * Filters the BrowserKit request to the origin one. + * + * @param Request $request The BrowserKit Request to filter + * + * @return object An origin request instance + */ + protected function filterRequest(Request $request) + { + return $request; + } + + /** + * Filters the origin response to the BrowserKit one. + * + * @param object $response The origin response to filter + * + * @return Response An BrowserKit Response instance + */ + protected function filterResponse($response) + { + return $response; + } + + /** + * Creates a crawler. + * + * This method returns null if the DomCrawler component is not available. + * + * @param string $uri A URI + * @param string $content Content for the crawler to use + * @param string $type Content type + * + * @return Crawler|null + */ + protected function createCrawlerFromContent($uri, $content, $type) + { + if (!class_exists('Symfony\Component\DomCrawler\Crawler')) { + return; + } + + $crawler = new Crawler(null, $uri); + $crawler->addContent($content, $type); + + return $crawler; + } + + /** + * Goes back in the browser history. + * + * @return Crawler + */ + public function back() + { + do { + $request = $this->history->back(); + } while (\array_key_exists(serialize($request), $this->redirects)); + + return $this->requestFromRequest($request, false); + } + + /** + * Goes forward in the browser history. + * + * @return Crawler + */ + public function forward() + { + do { + $request = $this->history->forward(); + } while (\array_key_exists(serialize($request), $this->redirects)); + + return $this->requestFromRequest($request, false); + } + + /** + * Reloads the current browser. + * + * @return Crawler + */ + public function reload() + { + return $this->requestFromRequest($this->history->current(), false); + } + + /** + * Follow redirects? + * + * @return Crawler + * + * @throws \LogicException If request was not a redirect + */ + public function followRedirect() + { + if (empty($this->redirect)) { + throw new \LogicException('The request was not redirected.'); + } + + if (-1 !== $this->maxRedirects) { + if ($this->redirectCount > $this->maxRedirects) { + $this->redirectCount = 0; + throw new \LogicException(sprintf('The maximum number (%d) of redirections was reached.', $this->maxRedirects)); + } + } + + $request = $this->internalRequest; + + if (\in_array($this->internalResponse->getStatusCode(), [301, 302, 303])) { + $method = 'GET'; + $files = []; + $content = null; + } else { + $method = $request->getMethod(); + $files = $request->getFiles(); + $content = $request->getContent(); + } + + if ('GET' === strtoupper($method)) { + // Don't forward parameters for GET request as it should reach the redirection URI + $parameters = []; + } else { + $parameters = $request->getParameters(); + } + + $server = $request->getServer(); + $server = $this->updateServerFromUri($server, $this->redirect); + + $this->isMainRequest = false; + + $response = $this->request($method, $this->redirect, $parameters, $files, $server, $content); + + $this->isMainRequest = true; + + return $response; + } + + /** + * @see https://dev.w3.org/html5/spec-preview/the-meta-element.html#attr-meta-http-equiv-refresh + */ + private function getMetaRefreshUrl(): ?string + { + $metaRefresh = $this->getCrawler()->filter('head meta[http-equiv="refresh"]'); + foreach ($metaRefresh->extract(['content']) as $content) { + if (preg_match('/^\s*0\s*;\s*URL\s*=\s*(?|\'([^\']++)|"([^"]++)|([^\'"].*))/i', $content, $m)) { + return str_replace("\t\r\n", '', rtrim($m[1])); + } + } + + return null; + } + + /** + * Restarts the client. + * + * It flushes history and all cookies. + */ + public function restart() + { + $this->cookieJar->clear(); + $this->history->clear(); + } + + /** + * Takes a URI and converts it to absolute if it is not already absolute. + * + * @param string $uri A URI + * + * @return string An absolute URI + */ + protected function getAbsoluteUri($uri) + { + // already absolute? + if (0 === strpos($uri, 'http://') || 0 === strpos($uri, 'https://')) { + return $uri; + } + + if (!$this->history->isEmpty()) { + $currentUri = $this->history->current()->getUri(); + } else { + $currentUri = sprintf('http%s://%s/', + isset($this->server['HTTPS']) ? 's' : '', + isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost' + ); + } + + // protocol relative URL + if (0 === strpos($uri, '//')) { + return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri; + } + + // anchor or query string parameters? + if (!$uri || '#' == $uri[0] || '?' == $uri[0]) { + return preg_replace('/[#?].*?$/', '', $currentUri).$uri; + } + + if ('/' !== $uri[0]) { + $path = parse_url($currentUri, PHP_URL_PATH); + + if ('/' !== substr($path, -1)) { + $path = substr($path, 0, strrpos($path, '/') + 1); + } + + $uri = $path.$uri; + } + + return preg_replace('#^(.*?//[^/]+)\/.*$#', '$1', $currentUri).$uri; + } + + /** + * Makes a request from a Request object directly. + * + * @param Request $request A Request instance + * @param bool $changeHistory Whether to update the history or not (only used internally for back(), forward(), and reload()) + * + * @return Crawler + */ + protected function requestFromRequest(Request $request, $changeHistory = true) + { + return $this->request($request->getMethod(), $request->getUri(), $request->getParameters(), $request->getFiles(), $request->getServer(), $request->getContent(), $changeHistory); + } + + private function updateServerFromUri($server, $uri) + { + $server['HTTP_HOST'] = $this->extractHost($uri); + $scheme = parse_url($uri, PHP_URL_SCHEME); + $server['HTTPS'] = null === $scheme ? $server['HTTPS'] : 'https' == $scheme; + unset($server['HTTP_IF_NONE_MATCH'], $server['HTTP_IF_MODIFIED_SINCE']); + + return $server; + } + + private function extractHost($uri) + { + $host = parse_url($uri, PHP_URL_HOST); + + if ($port = parse_url($uri, PHP_URL_PORT)) { + return $host.':'.$port; + } + + return $host; + } } diff --git a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php index 02daf6f9b561d..0d492e92344de 100644 --- a/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/AbstractBrowserTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\BrowserKit\AbstractBrowser; +use Symfony\Component\BrowserKit\Client; use Symfony\Component\BrowserKit\CookieJar; use Symfony\Component\BrowserKit\History; use Symfony\Component\BrowserKit\Response; @@ -80,6 +81,16 @@ public function getBrowser(array $server = [], History $history = null, CookieJa return new TestClient($server, $history, $cookieJar); } + /** + * @group legacy + */ + public function testAbstractBrowserIsAClient() + { + $browser = $this->getBrowser(); + + $this->assertInstanceOf(Client::class, $browser); + } + public function testGetHistory() { $client = $this->getBrowser([], $history = new History()); @@ -102,7 +113,7 @@ public function testGetRequest() /** * @group legacy - * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\AbstractBrowser::getRequest()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. + * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\Tests\%s::getRequest()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. */ public function testGetRequestNull() { @@ -140,7 +151,7 @@ public function testGetResponse() /** * @group legacy - * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\AbstractBrowser::getResponse()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. + * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\Tests\%s::getResponse()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. */ public function testGetResponseNull() { @@ -161,7 +172,7 @@ public function testGetInternalResponse() /** * @group legacy - * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\AbstractBrowser::getInternalResponse()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. + * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\Tests\%s::getInternalResponse()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. */ public function testGetInternalResponseNull() { @@ -189,7 +200,7 @@ public function testGetCrawler() /** * @group legacy - * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\AbstractBrowser::getCrawler()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. + * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\Tests\%s::getCrawler()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. */ public function testGetCrawlerNull() { @@ -894,7 +905,7 @@ public function testInternalRequest() /** * @group legacy - * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\AbstractBrowser::getInternalRequest()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. + * @expectedDeprecation Calling the "Symfony\Component\BrowserKit\Tests\%s::getInternalRequest()" method before the "request()" one is deprecated since Symfony 4.1 and will throw an exception in 5.0. */ public function testInternalRequestNull() { @@ -904,7 +915,7 @@ public function testInternalRequestNull() /** * @group legacy - * @expectedDeprecation The "Symfony\Component\BrowserKit\AbstractBrowser::submit()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2. + * @expectedDeprecation The "Symfony\Component\BrowserKit\Tests\ClassThatInheritClient::submit()" method will have a new "array $serverParameters = []" argument in version 5.0, not defining it is deprecated since Symfony 4.2. */ public function testInheritedClassCallSubmitWithTwoArguments() { From 0cdb808f1c3fac7030a78ecd9fa4f5ebb3d80907 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Tue, 16 Apr 2019 15:41:08 +0200 Subject: [PATCH 484/495] [VarDumper] add caster for WeakReference instances of PHP 7.4 --- .../Component/VarDumper/Caster/ReflectionCaster.php | 7 +++++++ src/Symfony/Component/VarDumper/Caster/SplCaster.php | 7 +++++++ src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php | 2 ++ 3 files changed, 16 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index c686962dbdd58..8dfe7ea5ad749 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -280,6 +280,13 @@ public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub return $a; } + public static function castReference(\ReflectionReference $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); + + return $a; + } + public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, $isNested) { self::addMap($a, $c, [ diff --git a/src/Symfony/Component/VarDumper/Caster/SplCaster.php b/src/Symfony/Component/VarDumper/Caster/SplCaster.php index a223adb7f2cae..37260b5b97584 100644 --- a/src/Symfony/Component/VarDumper/Caster/SplCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/SplCaster.php @@ -188,6 +188,13 @@ public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub return $a; } + public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); + + return $a; + } + private static function castSplArray($c, array $a, Stub $stub, $isNested) { $prefix = Caster::PREFIX_VIRTUAL; diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index e2393c4dbe5ee..5582d24c3abac 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -38,6 +38,7 @@ abstract class AbstractCloner implements ClonerInterface 'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'], 'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'], 'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'], + 'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'], 'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'], 'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'], @@ -109,6 +110,7 @@ abstract class AbstractCloner implements ClonerInterface 'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'], 'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], 'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'], + 'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'], 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], 'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'], From 28f7961c55aa4e23c6d1352ed24340cfd3ed0ab1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Wed, 17 Apr 2019 11:28:15 +0200 Subject: [PATCH 485/495] [Security] Add NativePasswordEncoder --- UPGRADE-4.3.md | 2 +- .../Bundle/SecurityBundle/CHANGELOG.md | 3 +- .../DependencyInjection/MainConfiguration.php | 12 ++- .../DependencyInjection/SecurityExtension.php | 27 ++++-- .../CompleteConfigurationTest.php | 56 ++++++++++-- .../Fixtures/php/container1.php | 9 ++ .../Fixtures/php/sodium_encoder.php | 2 + .../Fixtures/xml/container1.xml | 4 + .../Fixtures/xml/sodium_encoder.xml | 2 +- .../Fixtures/yml/container1.yml | 7 ++ .../Fixtures/yml/sodium_encoder.yml | 2 + src/Symfony/Component/Security/CHANGELOG.md | 5 +- .../Security/Core/Encoder/EncoderFactory.php | 19 +++- .../Core/Encoder/NativePasswordEncoder.php | 90 +++++++++++++++++++ .../Core/Encoder/SodiumPasswordEncoder.php | 43 +++++---- .../Encoder/NativePasswordEncoderTest.php | 70 +++++++++++++++ 16 files changed, 314 insertions(+), 39 deletions(-) create mode 100644 src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php create mode 100644 src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index 5205e9ac939ed..c52cb7436c351 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -174,7 +174,7 @@ Security SecurityBundle -------------- - * Configuring encoders using `argon2i` as algorithm has been deprecated, use `sodium` instead. + * Configuring encoders using `argon2i` as algorithm has been deprecated, use `auto` instead. TwigBridge ---------- diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 28bbd1286e021..e26a56b788847 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -4,11 +4,12 @@ CHANGELOG 4.3.0 ----- + * Added new encoder types: `auto` (recommended), `native` and `sodium` * The normalization of the cookie names configured in the `logout.delete_cookies` option is deprecated and will be disabled in Symfony 5.0. This affects to cookies with dashes in their names. For example, starting from Symfony 5.0, the `my-cookie` name will delete `my-cookie` (with a dash) instead of `my_cookie` (with an underscore). - * Deprecated configuring encoders using `argon2i` as algorithm, use `sodium` instead + * Deprecated configuring encoders using `argon2i` as algorithm, use `auto` instead 4.2.0 ----- diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 60de7afc598d0..eda62ed9ac715 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -394,9 +394,10 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode) ->children() ->arrayNode('encoders') ->example([ - 'App\Entity\User1' => 'bcrypt', + 'App\Entity\User1' => 'auto', 'App\Entity\User2' => [ - 'algorithm' => 'bcrypt', + 'algorithm' => 'auto', + 'time_cost' => 8, 'cost' => 13, ], ]) @@ -416,11 +417,14 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode) ->integerNode('cost') ->min(4) ->max(31) - ->defaultValue(13) + ->defaultNull() ->end() ->scalarNode('memory_cost')->defaultNull()->end() ->scalarNode('time_cost')->defaultNull()->end() - ->scalarNode('threads')->defaultNull()->end() + ->scalarNode('threads') + ->defaultNull() + ->setDeprecated('The "%path%.%node%" configuration key has no effect since Symfony 4.3 and will be removed in 5.0.') + ->end() ->scalarNode('id')->end() ->end() ->end() diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 4519b66a94313..0463e9011dd92 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -30,6 +30,7 @@ use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; +use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Controller\UserValueResolver; @@ -559,20 +560,20 @@ private function createEncoder($config, ContainerBuilder $container) if ('bcrypt' === $config['algorithm']) { return [ 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', - 'arguments' => [$config['cost']], + 'arguments' => [$config['cost'] ?? 13], ]; } // Argon2i encoder if ('argon2i' === $config['algorithm']) { - @trigger_error('Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "sodium" instead.', E_USER_DEPRECATED); + @trigger_error('Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "auto" instead.', E_USER_DEPRECATED); if (!Argon2iPasswordEncoder::isSupported()) { if (\extension_loaded('sodium') && !\defined('SODIUM_CRYPTO_PWHASH_SALTBYTES')) { - throw new InvalidConfigurationException('The installed libsodium version does not have support for Argon2i. Use Bcrypt instead.'); + throw new InvalidConfigurationException('The installed libsodium version does not have support for Argon2i. Use "auto" instead.'); } - throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use BCrypt instead.'); + throw new InvalidConfigurationException('Argon2i algorithm is not supported. Install the libsodium extension or use "auto" instead.'); } return [ @@ -585,14 +586,28 @@ private function createEncoder($config, ContainerBuilder $container) ]; } + if ('native' === $config['algorithm']) { + return [ + 'class' => NativePasswordEncoder::class, + 'arguments' => [ + $config['time_cost'], + (($config['memory_cost'] ?? 0) << 10) ?: null, + $config['cost'], + ], + ]; + } + if ('sodium' === $config['algorithm']) { if (!SodiumPasswordEncoder::isSupported()) { - throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use BCrypt instead.'); + throw new InvalidConfigurationException('Libsodium is not available. Install the sodium extension or use "auto" instead.'); } return [ 'class' => SodiumPasswordEncoder::class, - 'arguments' => [], + 'arguments' => [ + $config['time_cost'], + (($config['memory_cost'] ?? 0) << 10) ?: null, + ], ]; } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index 0727c79a52139..1405ef4bd8fe1 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -283,7 +283,7 @@ public function testEncoders() 'hash_algorithm' => 'sha512', 'key_length' => 40, 'ignore_case' => false, - 'cost' => 13, + 'cost' => null, 'memory_cost' => null, 'time_cost' => null, 'threads' => null, @@ -295,7 +295,7 @@ public function testEncoders() 'ignore_case' => false, 'encode_as_base64' => true, 'iterations' => 5000, - 'cost' => 13, + 'cost' => null, 'memory_cost' => null, 'time_cost' => null, 'threads' => null, @@ -309,6 +309,22 @@ public function testEncoders() 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', 'arguments' => [15], ], + 'JMS\FooBundle\Entity\User7' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', + 'arguments' => [8, 102400, 15], + ], + 'JMS\FooBundle\Entity\User8' => [ + 'algorithm' => 'auto', + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'encode_as_base64' => true, + 'iterations' => 5000, + 'cost' => null, + 'memory_cost' => null, + 'time_cost' => null, + 'threads' => null, + ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } @@ -332,7 +348,7 @@ public function testEncodersWithLibsodium() 'hash_algorithm' => 'sha512', 'key_length' => 40, 'ignore_case' => false, - 'cost' => 13, + 'cost' => null, 'memory_cost' => null, 'time_cost' => null, 'threads' => null, @@ -344,7 +360,7 @@ public function testEncodersWithLibsodium() 'ignore_case' => false, 'encode_as_base64' => true, 'iterations' => 5000, - 'cost' => 13, + 'cost' => null, 'memory_cost' => null, 'time_cost' => null, 'threads' => null, @@ -360,7 +376,19 @@ public function testEncodersWithLibsodium() ], 'JMS\FooBundle\Entity\User7' => [ 'class' => 'Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder', - 'arguments' => [], + 'arguments' => [8, 128 * 1024 * 1024], + ], + 'JMS\FooBundle\Entity\User8' => [ + 'algorithm' => 'auto', + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'encode_as_base64' => true, + 'iterations' => 5000, + 'cost' => null, + 'memory_cost' => null, + 'time_cost' => null, + 'threads' => null, ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } @@ -368,7 +396,7 @@ public function testEncodersWithLibsodium() /** * @group legacy * - * @expectedDeprecation Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "sodium" instead. + * @expectedDeprecation Configuring an encoder with "argon2i" as algorithm is deprecated since Symfony 4.3, use "auto" instead. */ public function testEncodersWithArgon2i() { @@ -390,7 +418,7 @@ public function testEncodersWithArgon2i() 'hash_algorithm' => 'sha512', 'key_length' => 40, 'ignore_case' => false, - 'cost' => 13, + 'cost' => null, 'memory_cost' => null, 'time_cost' => null, 'threads' => null, @@ -402,7 +430,7 @@ public function testEncodersWithArgon2i() 'ignore_case' => false, 'encode_as_base64' => true, 'iterations' => 5000, - 'cost' => 13, + 'cost' => null, 'memory_cost' => null, 'time_cost' => null, 'threads' => null, @@ -420,6 +448,18 @@ public function testEncodersWithArgon2i() 'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder', 'arguments' => [256, 1, 2], ], + 'JMS\FooBundle\Entity\User8' => [ + 'algorithm' => 'auto', + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'encode_as_base64' => true, + 'iterations' => 5000, + 'cost' => null, + 'memory_cost' => null, + 'time_cost' => null, + 'threads' => null, + ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php index f420d4d8af637..06afe665d24ae 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php @@ -25,6 +25,15 @@ 'algorithm' => 'bcrypt', 'cost' => 15, ], + 'JMS\FooBundle\Entity\User7' => [ + 'algorithm' => 'native', + 'time_cost' => 8, + 'memory_cost' => 100, + 'cost' => 15, + ], + 'JMS\FooBundle\Entity\User8' => [ + 'algorithm' => 'auto', + ], ], 'providers' => [ 'default' => [ diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php index e32969df2353c..5fdef4b8046fa 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/sodium_encoder.php @@ -6,6 +6,8 @@ 'encoders' => [ 'JMS\FooBundle\Entity\User7' => [ 'algorithm' => 'sodium', + 'time_cost' => 8, + 'memory_cost' => 128 * 1024, ], ], ]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml index 97631ae318f4b..9a3cae7159a2b 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml @@ -18,6 +18,10 @@ <encoder class="JMS\FooBundle\Entity\User6" algorithm="bcrypt" cost="15" /> + <encoder class="JMS\FooBundle\Entity\User7" algorithm="native" time-cost="8" memory-cost="100" cost="15" /> + + <encoder class="JMS\FooBundle\Entity\User8" algorithm="auto" /> + <provider name="default"> <memory> <user name="foo" password="foo" roles="ROLE_USER" /> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml index 3fb47213009fc..11682f7c950fc 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/sodium_encoder.xml @@ -10,7 +10,7 @@ </imports> <sec:config> - <sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="sodium" /> + <sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="sodium" time-cost="8" memory-cost="131072" /> </sec:config> </container> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml index 9a1535ebb2c9a..a51b0c49cafb3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml @@ -18,6 +18,13 @@ security: JMS\FooBundle\Entity\User6: algorithm: bcrypt cost: 15 + JMS\FooBundle\Entity\User7: + algorithm: native + time_cost: 8 + memory_cost: 100 + cost: 15 + JMS\FooBundle\Entity\User8: + algorithm: auto providers: default: diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml index 175d945b7d1b5..2d70ef0d9b42a 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/sodium_encoder.yml @@ -5,3 +5,5 @@ security: encoders: JMS\FooBundle\Entity\User7: algorithm: sodium + time_cost: 8 + memory_cost: 131072 diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 69f4c6301acb0..5dc78560733f7 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG 4.3.0 ----- + * Added methods `__serialize` and `__unserialize` to the `TokenInterface` + * Added `SodiumPasswordEncoder` and `NativePasswordEncoder` * The `Role` and `SwitchUserRole` classes are deprecated and will be removed in 5.0. Use strings for roles instead. * The `getReachableRoles()` method of the `RoleHierarchyInterface` is deprecated and will be removed in 5.0. @@ -19,8 +21,7 @@ CHANGELOG * Dispatch `AuthenticationFailureEvent` on `security.authentication.failure` * Dispatch `InteractiveLoginEvent` on `security.interactive_login` * Dispatch `SwitchUserEvent` on `security.switch_user` - * deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` instead - * Added methods `__serialize` and `__unserialize` to the `TokenInterface` + * Deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` 4.2.0 ----- diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index 01dd33f053de6..7d87c6f904ef0 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -84,6 +84,10 @@ private function createEncoder(array $config) private function getEncoderConfigFromAlgorithm($config) { + if ('auto' === $config['algorithm']) { + $config['algorithm'] = SodiumPasswordEncoder::isSupported() ? 'sodium' : 'native'; + } + switch ($config['algorithm']) { case 'plaintext': return [ @@ -108,10 +112,23 @@ private function getEncoderConfigFromAlgorithm($config) 'arguments' => [$config['cost']], ]; + case 'native': + return [ + 'class' => NativePasswordEncoder::class, + 'arguments' => [ + $config['time_cost'] ?? null, + (($config['memory_cost'] ?? 0) << 10) ?: null, + $config['cost'] ?? null, + ], + ]; + case 'sodium': return [ 'class' => SodiumPasswordEncoder::class, - 'arguments' => [], + 'arguments' => [ + $config['time_cost'] ?? null, + (($config['memory_cost'] ?? 0) << 10) ?: null, + ], ]; /* @deprecated since Symfony 4.3 */ diff --git a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php new file mode 100644 index 0000000000000..a99d064eeb3e2 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php @@ -0,0 +1,90 @@ +<?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\Component\Security\Core\Encoder; + +use Symfony\Component\Security\Core\Exception\BadCredentialsException; + +/** + * Hashes passwords using password_hash(). + * + * @author Elnur Abdurrakhimov <elnur@elnur.pro> + * @author Terje Bråten <terje@braten.be> + * @author Nicolas Grekas <p@tchwork.com> + */ +final class NativePasswordEncoder implements PasswordEncoderInterface, SelfSaltingEncoderInterface +{ + private const MAX_PASSWORD_LENGTH = 4096; + + private $algo; + private $options; + + public function __construct(int $opsLimit = null, int $memLimit = null, int $cost = null) + { + $cost = $cost ?? 13; + $opsLimit = $opsLimit ?? max(6, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE : 6); + $memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024); + + if (2 > $opsLimit) { + throw new \InvalidArgumentException('$opsLimit must be 2 or greater.'); + } + + if (10 * 1024 > $memLimit) { + throw new \InvalidArgumentException('$memLimit must be 10k or greater.'); + } + + if ($cost < 4 || 31 < $cost) { + throw new \InvalidArgumentException('$cost must be in the range of 4-31.'); + } + + $this->algo = \defined('PASSWORD_ARGON2I') ? max(PASSWORD_DEFAULT, \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : PASSWORD_ARGON2I) : PASSWORD_DEFAULT; + $this->options = [ + 'cost' => $cost, + 'time_cost' => $opsLimit, + 'memory_cost' => $memLimit >> 10, + 'threads' => 1, + ]; + } + + /** + * {@inheritdoc} + */ + public function encodePassword($raw, $salt) + { + if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) { + throw new BadCredentialsException('Invalid password.'); + } + + // Ignore $salt, the auto-generated one is always the best + + $encoded = password_hash($raw, $this->algo, $this->options); + + if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) { + // BCrypt encodes only the first 72 chars + throw new BadCredentialsException('Invalid password.'); + } + + return $encoded; + } + + /** + * {@inheritdoc} + */ + public function isPasswordValid($encoded, $raw, $salt) + { + if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) { + // BCrypt encodes only the first 72 chars + return false; + } + + return \strlen($raw) <= self::MAX_PASSWORD_LENGTH && password_verify($raw, $encoded); + } +} diff --git a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php index febca05dd0f39..96fbdca173324 100644 --- a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php @@ -20,11 +20,32 @@ * @author Robin Chalas <robin.chalas@gmail.com> * @author Zan Baldwin <hello@zanbaldwin.com> * @author Dominik Müller <dominik.mueller@jkweb.ch> - * - * @final */ -class SodiumPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface +final class SodiumPasswordEncoder implements PasswordEncoderInterface, SelfSaltingEncoderInterface { + private const MAX_PASSWORD_LENGTH = 4096; + + private $opsLimit; + private $memLimit; + + public function __construct(int $opsLimit = null, int $memLimit = null) + { + if (!self::isSupported()) { + throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.'); + } + + $this->opsLimit = $opsLimit ?? max(6, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_MODERATE : 6); + $this->memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 2014); + + if (2 > $this->opsLimit) { + throw new \InvalidArgumentException('$opsLimit must be 2 or greater.'); + } + + if (10 * 1024 > $this->memLimit) { + throw new \InvalidArgumentException('$memLimit must be 10k or greater.'); + } + } + public static function isSupported(): bool { if (\class_exists('ParagonIE_Sodium_Compat') && \method_exists('ParagonIE_Sodium_Compat', 'crypto_pwhash_is_available')) { @@ -39,24 +60,16 @@ public static function isSupported(): bool */ public function encodePassword($raw, $salt) { - if ($this->isPasswordTooLong($raw)) { + if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) { throw new BadCredentialsException('Invalid password.'); } if (\function_exists('sodium_crypto_pwhash_str')) { - return \sodium_crypto_pwhash_str( - $raw, - \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, - \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE - ); + return \sodium_crypto_pwhash_str($raw, $this->opsLimit, $this->memLimit); } if (\extension_loaded('libsodium')) { - return \Sodium\crypto_pwhash_str( - $raw, - \Sodium\CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE, - \Sodium\CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE - ); + return \Sodium\crypto_pwhash_str($raw, $this->opsLimit, $this->memLimit); } throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.'); @@ -67,7 +80,7 @@ public function encodePassword($raw, $salt) */ public function isPasswordValid($encoded, $raw, $salt) { - if ($this->isPasswordTooLong($raw)) { + if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) { return false; } diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php new file mode 100644 index 0000000000000..681b91a1eeec5 --- /dev/null +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/NativePasswordEncoderTest.php @@ -0,0 +1,70 @@ +<?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\Component\Security\Core\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; + +/** + * @author Elnur Abdurrakhimov <elnur@elnur.pro> + */ +class NativePasswordEncoderTest extends TestCase +{ + /** + * @expectedException \InvalidArgumentException + */ + public function testCostBelowRange() + { + new NativePasswordEncoder(null, null, 3); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testCostAboveRange() + { + new NativePasswordEncoder(null, null, 32); + } + + /** + * @dataProvider validRangeData + */ + public function testCostInRange($cost) + { + $this->assertInstanceOf(NativePasswordEncoder::class, new NativePasswordEncoder(null, null, $cost)); + } + + public function validRangeData() + { + $costs = range(4, 31); + array_walk($costs, function (&$cost) { $cost = [$cost]; }); + + return $costs; + } + + public function testValidation() + { + $encoder = new NativePasswordEncoder(); + $result = $encoder->encodePassword('password', null); + $this->assertTrue($encoder->isPasswordValid($result, 'password', null)); + $this->assertFalse($encoder->isPasswordValid($result, 'anotherPassword', null)); + } + + public function testCheckPasswordLength() + { + $encoder = new NativePasswordEncoder(null, null, 4); + $result = password_hash(str_repeat('a', 72), PASSWORD_BCRYPT, ['cost' => 4]); + + $this->assertFalse($encoder->isPasswordValid($result, str_repeat('a', 73), 'salt')); + $this->assertTrue($encoder->isPasswordValid($result, str_repeat('a', 72), 'salt')); + } +} From e197398d2ff76698eda9c021e8fda0f1d4157587 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Thu, 18 Apr 2019 17:20:05 +0200 Subject: [PATCH 486/495] [Security] deprecate BCryptPasswordEncoder in favor of NativePasswordEncoder --- UPGRADE-4.3.md | 3 +- UPGRADE-5.0.md | 3 +- .../Command/UserPasswordEncoderCommand.php | 2 +- .../DependencyInjection/SecurityExtension.php | 2 + .../CompleteConfigurationTest.php | 70 +++++++++++++------ .../Fixtures/php/bcrypt_encoder.php | 12 ++++ .../Fixtures/php/container1.php | 6 +- .../Fixtures/xml/bcrypt_encoder.xml | 16 +++++ .../Fixtures/xml/container1.xml | 6 +- .../Fixtures/yml/bcrypt_encoder.yml | 8 +++ .../Fixtures/yml/container1.yml | 5 +- .../UserPasswordEncoderCommandTest.php | 43 ++++++++++-- .../Functional/app/PasswordEncode/bcrypt.yml | 7 ++ .../Functional/app/PasswordEncode/config.yml | 4 +- src/Symfony/Component/Security/CHANGELOG.md | 3 +- .../Core/Encoder/BCryptPasswordEncoder.php | 4 ++ .../Security/Core/Encoder/EncoderFactory.php | 1 + .../Encoder/BCryptPasswordEncoderTest.php | 2 + 18 files changed, 151 insertions(+), 46 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml diff --git a/UPGRADE-4.3.md b/UPGRADE-4.3.md index c52cb7436c351..3f5f22164dfaa 100644 --- a/UPGRADE-4.3.md +++ b/UPGRADE-4.3.md @@ -168,13 +168,14 @@ Security ``` * The `Argon2iPasswordEncoder` class has been deprecated, use `SodiumPasswordEncoder` instead. + * The `BCryptPasswordEncoder` class has been deprecated, use `NativePasswordEncoder` instead. * Not implementing the methods `__serialize` and `__unserialize` in classes implementing the `TokenInterface` is deprecated SecurityBundle -------------- - * Configuring encoders using `argon2i` as algorithm has been deprecated, use `auto` instead. + * Configuring encoders using `argon2i` or `bcrypt` as algorithm has been deprecated, use `auto` instead. TwigBridge ---------- diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 2036cabcd90fe..7c409d4630d2d 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -342,6 +342,7 @@ Security ``` * The `Argon2iPasswordEncoder` class has been removed, use `SodiumPasswordEncoder` instead. + * The `BCryptPasswordEncoder` class has been removed, use `NativePasswordEncoder` instead. * Classes implementing the `TokenInterface` must implement the two new methods `__serialize` and `__unserialize` @@ -364,7 +365,7 @@ SecurityBundle changed to underscores. Before: `my-cookie` deleted the `my_cookie` cookie (with an underscore). After: `my-cookie` deletes the `my-cookie` cookie (with a dash). - * Configuring encoders using `argon2i` as algorithm is not supported anymore, use `sodium` instead. + * Configuring encoders using `argon2i` or `bcrypt` as algorithm is not supported anymore, use `auto` instead. Serializer ---------- diff --git a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php index 15f59f47540f2..84ad3e4c8b92e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php +++ b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php @@ -70,7 +70,7 @@ protected function configure() security: encoders: Symfony\Component\Security\Core\User\User: plaintext - App\Entity\User: bcrypt + App\Entity\User: auto </comment> If you execute the command non-interactively, the first available configured diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 0463e9011dd92..af4260f04c428 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -558,6 +558,8 @@ private function createEncoder($config, ContainerBuilder $container) // bcrypt encoder if ('bcrypt' === $config['algorithm']) { + @trigger_error('Configuring an encoder with "bcrypt" as algorithm is deprecated since Symfony 4.3, use "auto" instead.', E_USER_DEPRECATED); + return [ 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', 'arguments' => [$config['cost'] ?? 13], diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index 1405ef4bd8fe1..ef318946ce66c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -306,14 +306,10 @@ public function testEncoders() 'arguments' => ['sha1', false, 5, 30], ], 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', - 'arguments' => [15], - ], - 'JMS\FooBundle\Entity\User7' => [ 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', 'arguments' => [8, 102400, 15], ], - 'JMS\FooBundle\Entity\User8' => [ + 'JMS\FooBundle\Entity\User7' => [ 'algorithm' => 'auto', 'hash_algorithm' => 'sha512', 'key_length' => 40, @@ -371,25 +367,13 @@ public function testEncodersWithLibsodium() 'arguments' => ['sha1', false, 5, 30], ], 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', - 'arguments' => [15], + 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', + 'arguments' => [8, 102400, 15], ], 'JMS\FooBundle\Entity\User7' => [ 'class' => 'Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder', 'arguments' => [8, 128 * 1024 * 1024], ], - 'JMS\FooBundle\Entity\User8' => [ - 'algorithm' => 'auto', - 'hash_algorithm' => 'sha512', - 'key_length' => 40, - 'ignore_case' => false, - 'encode_as_base64' => true, - 'iterations' => 5000, - 'cost' => null, - 'memory_cost' => null, - 'time_cost' => null, - 'threads' => null, - ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } @@ -441,15 +425,42 @@ public function testEncodersWithArgon2i() 'arguments' => ['sha1', false, 5, 30], ], 'JMS\FooBundle\Entity\User6' => [ - 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', - 'arguments' => [15], + 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', + 'arguments' => [8, 102400, 15], ], 'JMS\FooBundle\Entity\User7' => [ 'class' => 'Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder', 'arguments' => [256, 1, 2], ], - 'JMS\FooBundle\Entity\User8' => [ - 'algorithm' => 'auto', + ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); + } + + /** + * @group legacy + */ + public function testEncodersWithBCrypt() + { + $container = $this->getContainer('bcrypt_encoder'); + + $this->assertEquals([[ + 'JMS\FooBundle\Entity\User1' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder', + 'arguments' => [false], + ], + 'JMS\FooBundle\Entity\User2' => [ + 'algorithm' => 'sha1', + 'encode_as_base64' => false, + 'iterations' => 5, + 'hash_algorithm' => 'sha512', + 'key_length' => 40, + 'ignore_case' => false, + 'cost' => null, + 'memory_cost' => null, + 'time_cost' => null, + 'threads' => null, + ], + 'JMS\FooBundle\Entity\User3' => [ + 'algorithm' => 'md5', 'hash_algorithm' => 'sha512', 'key_length' => 40, 'ignore_case' => false, @@ -460,6 +471,19 @@ public function testEncodersWithArgon2i() 'time_cost' => null, 'threads' => null, ], + 'JMS\FooBundle\Entity\User4' => new Reference('security.encoder.foo'), + 'JMS\FooBundle\Entity\User5' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder', + 'arguments' => ['sha1', false, 5, 30], + ], + 'JMS\FooBundle\Entity\User6' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\NativePasswordEncoder', + 'arguments' => [8, 102400, 15], + ], + 'JMS\FooBundle\Entity\User7' => [ + 'class' => 'Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder', + 'arguments' => [15], + ], ]], $container->getDefinition('security.encoder_factory.generic')->getArguments()); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php new file mode 100644 index 0000000000000..1afad79e4fca3 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php @@ -0,0 +1,12 @@ +<?php + +$this->load('container1.php', $container); + +$container->loadFromExtension('security', [ + 'encoders' => [ + 'JMS\FooBundle\Entity\User7' => [ + 'algorithm' => 'bcrypt', + 'cost' => 15, + ], + ], +]); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php index 06afe665d24ae..3c9e6104eecc3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/container1.php @@ -22,16 +22,12 @@ 'key_length' => 30, ], 'JMS\FooBundle\Entity\User6' => [ - 'algorithm' => 'bcrypt', - 'cost' => 15, - ], - 'JMS\FooBundle\Entity\User7' => [ 'algorithm' => 'native', 'time_cost' => 8, 'memory_cost' => 100, 'cost' => 15, ], - 'JMS\FooBundle\Entity\User8' => [ + 'JMS\FooBundle\Entity\User7' => [ 'algorithm' => 'auto', ], ], diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml new file mode 100644 index 0000000000000..a98400c5f043a --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/bcrypt_encoder.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:sec="http://symfony.com/schema/dic/security" + xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> + + <imports> + <import resource="container1.xml"/> + </imports> + + <sec:config> + <sec:encoder class="JMS\FooBundle\Entity\User7" algorithm="bcrypt" cost="15" /> + </sec:config> + +</container> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml index 9a3cae7159a2b..c919a7f276732 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml @@ -16,11 +16,9 @@ <encoder class="JMS\FooBundle\Entity\User5" algorithm="pbkdf2" hash-algorithm="sha1" encode-as-base64="false" iterations="5" key-length="30" /> - <encoder class="JMS\FooBundle\Entity\User6" algorithm="bcrypt" cost="15" /> + <encoder class="JMS\FooBundle\Entity\User6" algorithm="native" time-cost="8" memory-cost="100" cost="15" /> - <encoder class="JMS\FooBundle\Entity\User7" algorithm="native" time-cost="8" memory-cost="100" cost="15" /> - - <encoder class="JMS\FooBundle\Entity\User8" algorithm="auto" /> + <encoder class="JMS\FooBundle\Entity\User7" algorithm="auto" /> <provider name="default"> <memory> diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml new file mode 100644 index 0000000000000..3f1a526215204 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/bcrypt_encoder.yml @@ -0,0 +1,8 @@ +imports: + - { resource: container1.yml } + +security: + encoders: + JMS\FooBundle\Entity\User7: + algorithm: bcrypt + cost: 15 diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml index a51b0c49cafb3..03b9aaf6ef5b9 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/yml/container1.yml @@ -16,14 +16,11 @@ security: iterations: 5 key_length: 30 JMS\FooBundle\Entity\User6: - algorithm: bcrypt - cost: 15 - JMS\FooBundle\Entity\User7: algorithm: native time_cost: 8 memory_cost: 100 cost: 15 - JMS\FooBundle\Entity\User8: + JMS\FooBundle\Entity\User7: algorithm: auto providers: diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 15cea530d50ef..7e90562246228 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Security\Core\Encoder\Argon2iPasswordEncoder; use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; +use Symfony\Component\Security\Core\Encoder\NativePasswordEncoder; use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder; use Symfony\Component\Security\Core\Encoder\SodiumPasswordEncoder; @@ -54,8 +55,12 @@ public function testEncodeNoPasswordNoInteraction() $this->assertEquals($statusCode, 1); } + /** + * @group legacy + */ public function testEncodePasswordBcrypt() { + $this->setupBcrypt(); $this->passwordEncoderCommandTester->execute([ 'command' => 'security:encode-password', 'password' => 'password', @@ -95,6 +100,23 @@ public function testEncodePasswordArgon2i() $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); } + public function testEncodePasswordNative() + { + $this->passwordEncoderCommandTester->execute([ + 'command' => 'security:encode-password', + 'password' => 'password', + 'user-class' => 'Custom\Class\Native\User', + ], ['interactive' => false]); + + $output = $this->passwordEncoderCommandTester->getDisplay(); + $this->assertContains('Password encoding succeeded', $output); + + $encoder = new NativePasswordEncoder(); + preg_match('# Encoded password\s{1,}([\w+\/$.,=]+={0,2})\s+#', $output, $matches); + $hash = $matches[1]; + $this->assertTrue($encoder->isPasswordValid($hash, 'password', null)); + } + public function testEncodePasswordSodium() { if (!SodiumPasswordEncoder::isSupported()) { @@ -162,12 +184,12 @@ public function testEncodePasswordEmptySaltOutput() $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); } - public function testEncodePasswordBcryptOutput() + public function testEncodePasswordNativeOutput() { $this->passwordEncoderCommandTester->execute([ 'command' => 'security:encode-password', 'password' => 'p@ssw0rd', - 'user-class' => 'Custom\Class\Bcrypt\User', + 'user-class' => 'Custom\Class\Native\User', ], ['interactive' => false]); $this->assertNotContains(' Generated salt ', $this->passwordEncoderCommandTester->getDisplay()); @@ -233,8 +255,8 @@ public function testEncodePasswordAsksNonProvidedUserClass() ], ['decorated' => false]); $this->assertContains(<<<EOTXT - For which user class would you like to encode a password? [Custom\Class\Bcrypt\User]: - [0] Custom\Class\Bcrypt\User + For which user class would you like to encode a password? [Custom\Class\Native\User]: + [0] Custom\Class\Native\User [1] Custom\Class\Pbkdf2\User [2] Custom\Class\Test\User [3] Symfony\Component\Security\Core\User\User @@ -301,6 +323,19 @@ private function setupArgon2i() $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); } + private function setupBcrypt() + { + putenv('COLUMNS='.(119 + \strlen(PHP_EOL))); + $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'bcrypt.yml']); + $kernel->boot(); + + $application = new Application($kernel); + + $passwordEncoderCommand = $application->get('security:encode-password'); + + $this->passwordEncoderCommandTester = new CommandTester($passwordEncoderCommand); + } + private function setupSodium() { putenv('COLUMNS='.(119 + \strlen(PHP_EOL))); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml new file mode 100644 index 0000000000000..1928c0400b722 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/bcrypt.yml @@ -0,0 +1,7 @@ +imports: + - { resource: config.yml } + +security: + encoders: + Custom\Class\Bcrypt\User: + algorithm: bcrypt diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml index 82416b095748e..9ae5433246561 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/PasswordEncode/config.yml @@ -4,8 +4,8 @@ imports: security: encoders: Symfony\Component\Security\Core\User\User: plaintext - Custom\Class\Bcrypt\User: - algorithm: bcrypt + Custom\Class\Native\User: + algorithm: native cost: 10 Custom\Class\Pbkdf2\User: algorithm: pbkdf2 diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md index 5dc78560733f7..f7b868fcbadea 100644 --- a/src/Symfony/Component/Security/CHANGELOG.md +++ b/src/Symfony/Component/Security/CHANGELOG.md @@ -21,7 +21,8 @@ CHANGELOG * Dispatch `AuthenticationFailureEvent` on `security.authentication.failure` * Dispatch `InteractiveLoginEvent` on `security.interactive_login` * Dispatch `SwitchUserEvent` on `security.switch_user` - * Deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` + * Deprecated `Argon2iPasswordEncoder`, use `SodiumPasswordEncoder` instead + * Deprecated `BCryptPasswordEncoder`, use `NativePasswordEncoder` instead 4.2.0 ----- diff --git a/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php index 7855552af61a1..d14949465c0ee 100644 --- a/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/BCryptPasswordEncoder.php @@ -11,11 +11,15 @@ namespace Symfony\Component\Security\Core\Encoder; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', BCryptPasswordEncoder::class, NativePasswordEncoder::class), E_USER_DEPRECATED); + use Symfony\Component\Security\Core\Exception\BadCredentialsException; /** * @author Elnur Abdurrakhimov <elnur@elnur.pro> * @author Terje Bråten <terje@braten.be> + * + * @deprecated since Symfony 4.3, use NativePasswordEncoder instead */ class BCryptPasswordEncoder extends BasePasswordEncoder implements SelfSaltingEncoderInterface { diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index 7d87c6f904ef0..150190dc4c161 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -106,6 +106,7 @@ private function getEncoderConfigFromAlgorithm($config) ], ]; + /* @deprecated since Symfony 4.3 */ case 'bcrypt': return [ 'class' => BCryptPasswordEncoder::class, diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php index 7f9dbe7f33fd8..4e8fcde7b0692 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/BCryptPasswordEncoderTest.php @@ -16,6 +16,8 @@ /** * @author Elnur Abdurrakhimov <elnur@elnur.pro> + * + * @group legacy */ class BCryptPasswordEncoderTest extends TestCase { From 6c3c199b4e5d31dec7176f70c105202b2a0c27c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= <postmaster@greg0ire.fr> Date: Thu, 18 Apr 2019 21:14:54 +0200 Subject: [PATCH 487/495] Treat undefined env var as strict mode An undefined SYMFONY_DEPRECATION_HELPER environment variable translates to false, and that was previously interpreted as 0, which means strict mode. This restores backwards compatibility with the previous behavior, which got broken in 1c73f9cfedad7fb7eb6ab0b1230d0219685ead0f . --- src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index a393868e9469c..0d5b78d497abe 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -241,6 +241,10 @@ private function getConfiguration() return $this->configuration = Configuration::fromNumber($mode); } + if (!$mode) { + return $this->configuration = Configuration::fromNumber(0); + } + return $this->configuration = Configuration::fromUrlEncodedString((string) $mode); } From 4bea1981ff115d65dc561d08dbb9197c99f07770 Mon Sep 17 00:00:00 2001 From: Roland Franssen <franssen.roland@gmail.com> Date: Mon, 1 Oct 2018 10:53:57 +0200 Subject: [PATCH 488/495] [Intl] Add Timezones --- src/Symfony/Component/Intl/CHANGELOG.md | 1 + .../Data/Generator/TimezoneDataGenerator.php | 158 ++++++ src/Symfony/Component/Intl/Intl.php | 5 + .../Intl/Resources/bin/update-data.php | 7 + .../Intl/Resources/data/timezones/af.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/am.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ar.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/as.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/az.json | 429 +++++++++++++++ .../Intl/Resources/data/timezones/be.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/bg.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/bn.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/bo.json | 4 + .../Intl/Resources/data/timezones/br.json | 334 +++++++++++ .../Intl/Resources/data/timezones/bs.json | 433 +++++++++++++++ .../Resources/data/timezones/bs_Cyrl.json | 425 ++++++++++++++ .../Intl/Resources/data/timezones/ca.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ce.json | 427 +++++++++++++++ .../Intl/Resources/data/timezones/cs.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/cy.json | 429 +++++++++++++++ .../Intl/Resources/data/timezones/da.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/de.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/de_CH.json | 7 + .../Intl/Resources/data/timezones/dz.json | 354 ++++++++++++ .../Intl/Resources/data/timezones/ee.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/el.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/en.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/en_001.json | 4 + .../Intl/Resources/data/timezones/en_150.json | 4 + .../Intl/Resources/data/timezones/en_AE.json | 4 + .../Intl/Resources/data/timezones/en_AU.json | 77 +++ .../Intl/Resources/data/timezones/en_BW.json | 4 + .../Intl/Resources/data/timezones/en_CA.json | 4 + .../Intl/Resources/data/timezones/en_CM.json | 4 + .../Intl/Resources/data/timezones/en_ER.json | 4 + .../Intl/Resources/data/timezones/en_GB.json | 9 + .../Intl/Resources/data/timezones/en_GH.json | 4 + .../Intl/Resources/data/timezones/en_GM.json | 4 + .../Intl/Resources/data/timezones/en_GU.json | 4 + .../Intl/Resources/data/timezones/en_GY.json | 4 + .../Intl/Resources/data/timezones/en_HK.json | 4 + .../Intl/Resources/data/timezones/en_IE.json | 4 + .../Intl/Resources/data/timezones/en_IN.json | 4 + .../Intl/Resources/data/timezones/en_KE.json | 4 + .../Intl/Resources/data/timezones/en_LR.json | 4 + .../Intl/Resources/data/timezones/en_LS.json | 4 + .../Intl/Resources/data/timezones/en_MG.json | 4 + .../Intl/Resources/data/timezones/en_MH.json | 4 + .../Intl/Resources/data/timezones/en_MO.json | 4 + .../Intl/Resources/data/timezones/en_MP.json | 4 + .../Intl/Resources/data/timezones/en_MU.json | 4 + .../Intl/Resources/data/timezones/en_MW.json | 4 + .../Intl/Resources/data/timezones/en_MY.json | 4 + .../Intl/Resources/data/timezones/en_NA.json | 4 + .../Intl/Resources/data/timezones/en_NG.json | 4 + .../Intl/Resources/data/timezones/en_NZ.json | 4 + .../Intl/Resources/data/timezones/en_RH.json | 4 + .../Intl/Resources/data/timezones/en_RW.json | 4 + .../Intl/Resources/data/timezones/en_SD.json | 4 + .../Intl/Resources/data/timezones/en_SG.json | 4 + .../Intl/Resources/data/timezones/en_SL.json | 4 + .../Intl/Resources/data/timezones/en_SS.json | 4 + .../Intl/Resources/data/timezones/en_SZ.json | 4 + .../Intl/Resources/data/timezones/en_TZ.json | 4 + .../Intl/Resources/data/timezones/en_UG.json | 4 + .../Intl/Resources/data/timezones/en_ZA.json | 4 + .../Intl/Resources/data/timezones/en_ZM.json | 4 + .../Intl/Resources/data/timezones/en_ZW.json | 4 + .../Intl/Resources/data/timezones/es.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/es_419.json | 59 ++ .../Intl/Resources/data/timezones/es_AR.json | 4 + .../Intl/Resources/data/timezones/es_BO.json | 4 + .../Intl/Resources/data/timezones/es_CL.json | 4 + .../Intl/Resources/data/timezones/es_CO.json | 4 + .../Intl/Resources/data/timezones/es_EC.json | 4 + .../Intl/Resources/data/timezones/es_MX.json | 49 ++ .../Intl/Resources/data/timezones/es_PE.json | 4 + .../Intl/Resources/data/timezones/es_US.json | 61 +++ .../Intl/Resources/data/timezones/es_UY.json | 4 + .../Intl/Resources/data/timezones/es_VE.json | 4 + .../Intl/Resources/data/timezones/et.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/eu.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/fa.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/fi.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/fo.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/fr.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/fr_CA.json | 334 +++++++++++ .../Intl/Resources/data/timezones/fr_GF.json | 4 + .../Intl/Resources/data/timezones/fy.json | 427 +++++++++++++++ .../Intl/Resources/data/timezones/ga.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/gd.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/gl.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/gu.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ha.json | 206 +++++++ .../Intl/Resources/data/timezones/ha_NE.json | 206 +++++++ .../Intl/Resources/data/timezones/he.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/hi.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/hr.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/hu.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/hy.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/ia.json | 228 ++++++++ .../Intl/Resources/data/timezones/id.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ig.json | 188 +++++++ .../Intl/Resources/data/timezones/ii.json | 4 + .../Intl/Resources/data/timezones/in.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/is.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/it.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/iw.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ja.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/jv.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/ka.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/kk.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/km.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/kn.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ko.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ko_KP.json | 7 + .../Intl/Resources/data/timezones/ks.json | 425 ++++++++++++++ .../Intl/Resources/data/timezones/ky.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/lb.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ln.json | 4 + .../Intl/Resources/data/timezones/lo.json | 430 +++++++++++++++ .../Intl/Resources/data/timezones/lt.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/lv.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/meta.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/mi.json | 188 +++++++ .../Intl/Resources/data/timezones/mk.json | 432 +++++++++++++++ .../Intl/Resources/data/timezones/ml.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/mn.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/mo.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/mr.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ms.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/mt.json | 40 ++ .../Intl/Resources/data/timezones/my.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/nb.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ne.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/ne_IN.json | 4 + .../Intl/Resources/data/timezones/nl.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/nl_SR.json | 4 + .../Intl/Resources/data/timezones/nn.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/no.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/om.json | 4 + .../Intl/Resources/data/timezones/or.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/os.json | 98 ++++ .../Intl/Resources/data/timezones/pa.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/pl.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ps.json | 405 ++++++++++++++ .../Intl/Resources/data/timezones/ps_PK.json | 13 + .../Intl/Resources/data/timezones/pt.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/pt_AO.json | 4 + .../Intl/Resources/data/timezones/pt_CV.json | 4 + .../Intl/Resources/data/timezones/pt_GW.json | 4 + .../Intl/Resources/data/timezones/pt_MO.json | 4 + .../Intl/Resources/data/timezones/pt_MZ.json | 4 + .../Intl/Resources/data/timezones/pt_PT.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/pt_ST.json | 4 + .../Intl/Resources/data/timezones/pt_TL.json | 4 + .../Intl/Resources/data/timezones/qu.json | 83 +++ .../Intl/Resources/data/timezones/qu_BO.json | 4 + .../Intl/Resources/data/timezones/qu_EC.json | 4 + .../Intl/Resources/data/timezones/rm.json | 4 + .../Intl/Resources/data/timezones/ro.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ru.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/rw.json | 4 + .../Intl/Resources/data/timezones/sd.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/se.json | 97 ++++ .../Intl/Resources/data/timezones/se_FI.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/sh.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/si.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/sk.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/sl.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/so.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/sq.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/sr.json | 433 +++++++++++++++ .../Resources/data/timezones/sr_Latn.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/sv.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/sw.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ta.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ta_MY.json | 4 + .../Intl/Resources/data/timezones/ta_SG.json | 4 + .../Intl/Resources/data/timezones/te.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/tg.json | 188 +++++++ .../Intl/Resources/data/timezones/th.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ti.json | 4 + .../Intl/Resources/data/timezones/tk.json | 428 +++++++++++++++ .../Intl/Resources/data/timezones/tl.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/to.json | 432 +++++++++++++++ .../Intl/Resources/data/timezones/tr.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/tt.json | 188 +++++++ .../Intl/Resources/data/timezones/ug.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/uk.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/ur.json | 431 +++++++++++++++ .../Intl/Resources/data/timezones/ur_IN.json | 132 +++++ .../Intl/Resources/data/timezones/uz.json | 428 +++++++++++++++ .../Resources/data/timezones/uz_Arab.json | 4 + .../Resources/data/timezones/uz_Cyrl.json | 422 ++++++++++++++ .../Intl/Resources/data/timezones/vi.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/wo.json | 188 +++++++ .../Intl/Resources/data/timezones/yi.json | 4 + .../Intl/Resources/data/timezones/yo.json | 188 +++++++ .../Intl/Resources/data/timezones/yo_BJ.json | 188 +++++++ .../Intl/Resources/data/timezones/zh.json | 433 +++++++++++++++ .../Intl/Resources/data/timezones/zh_HK.json | 116 ++++ .../Resources/data/timezones/zh_Hans_SG.json | 4 + .../Resources/data/timezones/zh_Hant.json | 433 +++++++++++++++ .../Resources/data/timezones/zh_Hant_HK.json | 116 ++++ .../Intl/Resources/data/timezones/zh_SG.json | 4 + .../Intl/Resources/data/timezones/zu.json | 431 +++++++++++++++ .../Component/Intl/Tests/TimezonesTest.php | 518 ++++++++++++++++++ src/Symfony/Component/Intl/Timezones.php | 59 ++ 209 files changed, 49335 insertions(+) create mode 100644 src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/af.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/am.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ar.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/as.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/az.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/be.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/bg.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/bn.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/bo.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/br.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/bs.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/bs_Cyrl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ca.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ce.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/cs.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/cy.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/da.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/de.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/de_CH.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/dz.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ee.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/el.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_001.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_150.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_AE.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_AU.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_BW.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_CA.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_CM.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_ER.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_GB.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_GH.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_GM.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_GU.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_GY.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_HK.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_IE.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_IN.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_KE.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_LR.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_LS.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MH.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MO.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MP.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MU.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MW.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_MY.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_NA.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_NG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_NZ.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_RH.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_RW.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_SD.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_SG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_SL.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_SS.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_SZ.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_TZ.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_UG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_ZA.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_ZM.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/en_ZW.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_419.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_AR.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_BO.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_CL.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_CO.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_EC.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_MX.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_PE.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_US.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_UY.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/es_VE.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/et.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/eu.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fa.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fi.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fo.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fr.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fr_CA.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fr_GF.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/fy.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ga.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/gd.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/gl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/gu.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ha.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ha_NE.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/he.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/hi.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/hr.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/hu.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/hy.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ia.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/id.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ig.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ii.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/in.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/is.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/it.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/iw.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ja.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/jv.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ka.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/kk.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/km.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/kn.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ko.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ko_KP.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ks.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ky.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/lb.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ln.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/lo.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/lt.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/lv.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/meta.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/mi.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/mk.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ml.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/mn.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/mo.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/mr.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ms.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/mt.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/my.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/nb.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ne.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ne_IN.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/nl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/nl_SR.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/nn.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/no.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/om.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/or.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/os.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pa.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ps.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ps_PK.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_AO.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_CV.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_GW.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_MO.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_MZ.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_PT.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_ST.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/pt_TL.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/qu.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/qu_BO.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/qu_EC.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/rm.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ro.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ru.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/rw.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sd.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/se.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/se_FI.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sh.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/si.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sk.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/so.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sq.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sr.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sr_Latn.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sv.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/sw.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ta.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ta_MY.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ta_SG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/te.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/tg.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/th.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ti.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/tk.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/tl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/to.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/tr.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/tt.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ug.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/uk.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ur.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/ur_IN.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/uz.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/uz_Arab.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/uz_Cyrl.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/vi.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/wo.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/yi.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/yo.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/yo_BJ.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zh.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zh_HK.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zh_Hans_SG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant_HK.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zh_SG.json create mode 100644 src/Symfony/Component/Intl/Resources/data/timezones/zu.json create mode 100644 src/Symfony/Component/Intl/Tests/TimezonesTest.php create mode 100644 src/Symfony/Component/Intl/Timezones.php diff --git a/src/Symfony/Component/Intl/CHANGELOG.md b/src/Symfony/Component/Intl/CHANGELOG.md index 7c8d46745533d..adc1405631d7a 100644 --- a/src/Symfony/Component/Intl/CHANGELOG.md +++ b/src/Symfony/Component/Intl/CHANGELOG.md @@ -9,6 +9,7 @@ CHANGELOG * added `Languages` and `Scripts` in favor of `Intl::getLanguageBundle()` * added `Locales` in favor of `Intl::getLocaleBundle()` * added `Regions` in favor of `Intl::getRegionBundle()` + * added `Timezones` 4.2.0 ----- diff --git a/src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php new file mode 100644 index 0000000000000..3f2412ff0b269 --- /dev/null +++ b/src/Symfony/Component/Intl/Data/Generator/TimezoneDataGenerator.php @@ -0,0 +1,158 @@ +<?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\Component\Intl\Data\Generator; + +use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; +use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; +use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle; +use Symfony\Component\Intl\Data\Util\LocaleScanner; + +/** + * The rule for compiling the zone bundle. + * + * @author Roland Franssen <franssen.roland@gmail.com> + * + * @internal + */ +class TimezoneDataGenerator extends AbstractDataGenerator +{ + /** + * Collects all available zone codes. + * + * @var string[] + */ + private $zoneCodes = []; + + /** + * {@inheritdoc} + */ + protected function scanLocales(LocaleScanner $scanner, $sourceDir) + { + return $scanner->scanLocales($sourceDir.'/zone'); + } + + /** + * {@inheritdoc} + */ + protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir) + { + $compiler->compile($sourceDir.'/zone', $tempDir); + $compiler->compile($sourceDir.'/misc/timezoneTypes.txt', $tempDir); + $compiler->compile($sourceDir.'/misc/metaZones.txt', $tempDir); + } + + /** + * {@inheritdoc} + */ + protected function preGenerate() + { + $this->zoneCodes = []; + } + + /** + * {@inheritdoc} + */ + protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale) + { + $localeBundle = $reader->read($tempDir, $displayLocale); + + if (isset($localeBundle['zoneStrings']) && null !== $localeBundle['zoneStrings']) { + $data = [ + 'Version' => $localeBundle['Version'], + 'Names' => self::generateZones( + $reader->read($tempDir, 'timezoneTypes'), + $reader->read($tempDir, 'metaZones'), + $reader->read($tempDir, 'root'), + $localeBundle + ), + ]; + + $this->zoneCodes = array_merge($this->zoneCodes, array_keys($data['Names'])); + + return $data; + } + } + + /** + * {@inheritdoc} + */ + protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) + { + } + + /** + * {@inheritdoc} + */ + protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir) + { + $rootBundle = $reader->read($tempDir, 'root'); + + $this->zoneCodes = array_unique($this->zoneCodes); + + sort($this->zoneCodes); + + $data = [ + 'Version' => $rootBundle['Version'], + 'Zones' => $this->zoneCodes, + ]; + + return $data; + } + + private static function generateZones(ArrayAccessibleResourceBundle $typeBundle, ArrayAccessibleResourceBundle $metaBundle, ArrayAccessibleResourceBundle $rootBundle, ArrayAccessibleResourceBundle $localeBundle): array + { + $available = []; + foreach ($typeBundle['typeMap']['timezone'] as $zone => $_) { + if ('Etc:Unknown' === $zone || preg_match('~^Etc:GMT[-+]\d+$~', $zone)) { + continue; + } + + $available[$zone] = true; + } + + $metazones = []; + foreach ($metaBundle['metazoneInfo'] as $zone => $info) { + foreach ($info as $metazone) { + $metazones[$zone] = $metazone->get(0); + } + } + + $zones = []; + foreach (array_keys($available) as $zone) { + // lg: long generic, e.g. "Central European Time" + // ls: long specific (not DST), e.g. "Central European Standard Time" + // ld: long DST, e.g. "Central European Summer Time" + // ec: example city, e.g. "Amsterdam" + $name = $localeBundle['zoneStrings'][$zone]['lg'] ?? $rootBundle['zoneStrings'][$zone]['lg'] ?? $localeBundle['zoneStrings'][$zone]['ls'] ?? $rootBundle['zoneStrings'][$zone]['ls'] ?? null; + $city = $localeBundle['zoneStrings'][$zone]['ec'] ?? $rootBundle['zoneStrings'][$zone]['ec'] ?? null; + + if (null === $name && isset($metazones[$zone])) { + $meta = 'meta:'.$metazones[$zone]; + $name = $localeBundle['zoneStrings'][$meta]['lg'] ?? $rootBundle['zoneStrings'][$meta]['lg'] ?? $localeBundle['zoneStrings'][$meta]['ls'] ?? $rootBundle['zoneStrings'][$meta]['ls'] ?? null; + } + if (null === $city && 0 !== strrpos($zone, 'Etc:') && false !== $i = strrpos($zone, ':')) { + $city = str_replace('_', ' ', substr($zone, $i + 1)); + } + if (null === $name) { + continue; + } + if (null !== $city) { + $name .= ' ('.$city.')'; + } + + $id = str_replace(':', '/', $zone); + $zones[$id] = $name; + } + + return $zones; + } +} diff --git a/src/Symfony/Component/Intl/Intl.php b/src/Symfony/Component/Intl/Intl.php index 7d121971e880d..e3763b7f52c60 100644 --- a/src/Symfony/Component/Intl/Intl.php +++ b/src/Symfony/Component/Intl/Intl.php @@ -64,6 +64,11 @@ final class Intl */ const REGION_DIR = 'regions'; + /** + * The directory name of the zone data. + */ + public const TIMEZONE_DIR = 'timezones'; + /** * @var ResourceBundle\CurrencyBundleInterface */ diff --git a/src/Symfony/Component/Intl/Resources/bin/update-data.php b/src/Symfony/Component/Intl/Resources/bin/update-data.php index d6e25af474569..b683d99308934 100644 --- a/src/Symfony/Component/Intl/Resources/bin/update-data.php +++ b/src/Symfony/Component/Intl/Resources/bin/update-data.php @@ -20,6 +20,7 @@ use Symfony\Component\Intl\Data\Generator\LocaleDataGenerator; use Symfony\Component\Intl\Data\Generator\RegionDataGenerator; use Symfony\Component\Intl\Data\Generator\ScriptDataGenerator; +use Symfony\Component\Intl\Data\Generator\TimezoneDataGenerator; use Symfony\Component\Intl\Data\Provider\LanguageDataProvider; use Symfony\Component\Intl\Data\Provider\RegionDataProvider; use Symfony\Component\Intl\Data\Provider\ScriptDataProvider; @@ -195,6 +196,7 @@ $targetDir.'/'.Intl::LOCALE_DIR, $targetDir.'/'.Intl::REGION_DIR, $targetDir.'/'.Intl::SCRIPT_DIR, + $targetDir.'/'.Intl::TIMEZONE_DIR, ]); } @@ -256,6 +258,11 @@ // //$filesystem->remove($txtDir); +echo "Generating zone data...\n"; + +$generator = new TimezoneDataGenerator($compiler, Intl::TIMEZONE_DIR); +$generator->generateData($config); + echo "Resource bundle compilation complete.\n"; $gitInfo = <<<GIT_INFO diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/af.json b/src/Symfony/Component/Intl/Resources/data/timezones/af.json new file mode 100644 index 0000000000000..8f411dd7dbb1a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/af.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Greenwich-tyd (Abidjan)", + "Africa\/Accra": "Greenwich-tyd (Accra)", + "Africa\/Addis_Ababa": "Oos-Afrika-tyd (Addis Abeba)", + "Africa\/Algiers": "Sentraal-Europese tyd (Algiers)", + "Africa\/Asmera": "Oos-Afrika-tyd (Asmara)", + "Africa\/Bamako": "Greenwich-tyd (Bamako)", + "Africa\/Bangui": "Wes-Afrika-tyd (Bangui)", + "Africa\/Banjul": "Greenwich-tyd (Banjul)", + "Africa\/Bissau": "Greenwich-tyd (Bissau)", + "Africa\/Blantyre": "Sentraal-Afrika-tyd (Blantyre)", + "Africa\/Brazzaville": "Wes-Afrika-tyd (Brazzaville)", + "Africa\/Bujumbura": "Sentraal-Afrika-tyd (Bujumbura)", + "Africa\/Cairo": "Oos-Europese tyd (Kaïro)", + "Africa\/Casablanca": "Wes-Europese tyd (Casablanca)", + "Africa\/Ceuta": "Sentraal-Europese tyd (Ceuta)", + "Africa\/Conakry": "Greenwich-tyd (Conakry)", + "Africa\/Dakar": "Greenwich-tyd (Dakar)", + "Africa\/Dar_es_Salaam": "Oos-Afrika-tyd (Dar es Salaam)", + "Africa\/Djibouti": "Oos-Afrika-tyd (Djiboeti)", + "Africa\/Douala": "Wes-Afrika-tyd (Douala)", + "Africa\/El_Aaiun": "Wes-Europese tyd (El Aaiun)", + "Africa\/Freetown": "Greenwich-tyd (Freetown)", + "Africa\/Gaborone": "Sentraal-Afrika-tyd (Gaborone)", + "Africa\/Harare": "Sentraal-Afrika-tyd (Harare)", + "Africa\/Johannesburg": "Suid-Afrika-standaardtyd (Johannesburg)", + "Africa\/Juba": "Oos-Afrika-tyd (Juba)", + "Africa\/Kampala": "Oos-Afrika-tyd (Kampala)", + "Africa\/Khartoum": "Sentraal-Afrika-tyd (Kartoem)", + "Africa\/Kigali": "Sentraal-Afrika-tyd (Kigali)", + "Africa\/Kinshasa": "Wes-Afrika-tyd (Kinshasa)", + "Africa\/Lagos": "Wes-Afrika-tyd (Lagos)", + "Africa\/Libreville": "Wes-Afrika-tyd (Libreville)", + "Africa\/Lome": "Greenwich-tyd (Lome)", + "Africa\/Luanda": "Wes-Afrika-tyd (Luanda)", + "Africa\/Lubumbashi": "Sentraal-Afrika-tyd (Lubumbashi)", + "Africa\/Lusaka": "Sentraal-Afrika-tyd (Lusaka)", + "Africa\/Malabo": "Wes-Afrika-tyd (Malabo)", + "Africa\/Maputo": "Sentraal-Afrika-tyd (Maputo)", + "Africa\/Maseru": "Suid-Afrika-standaardtyd (Maseru)", + "Africa\/Mbabane": "Suid-Afrika-standaardtyd (Mbabane)", + "Africa\/Mogadishu": "Oos-Afrika-tyd (Mogadisjoe)", + "Africa\/Monrovia": "Greenwich-tyd (Monrovia)", + "Africa\/Nairobi": "Oos-Afrika-tyd (Nairobi)", + "Africa\/Ndjamena": "Wes-Afrika-tyd (Ndjamena)", + "Africa\/Niamey": "Wes-Afrika-tyd (Niamey)", + "Africa\/Nouakchott": "Greenwich-tyd (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich-tyd (Ouagadougou)", + "Africa\/Porto-Novo": "Wes-Afrika-tyd (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich-tyd (São Tomé)", + "Africa\/Tripoli": "Oos-Europese tyd (Tripoli)", + "Africa\/Tunis": "Sentraal-Europese tyd (Tunis)", + "Africa\/Windhoek": "Sentraal-Afrika-tyd (Windhoek)", + "America\/Adak": "Hawaii-Aleoete-tyd (Adak)", + "America\/Anchorage": "Alaska-tyd (Anchorage)", + "America\/Anguilla": "Atlantiese tyd (Anguilla)", + "America\/Antigua": "Atlantiese tyd (Antigua)", + "America\/Araguaina": "Brasilia-tyd (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentinië-tyd (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinië-tyd (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinië-tyd (Salta)", + "America\/Argentina\/San_Juan": "Argentinië-tyd (San Juan)", + "America\/Argentina\/San_Luis": "Wes-Argentinië-tyd (San Luis)", + "America\/Argentina\/Tucuman": "Argentinië-tyd (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentinië-tyd (Ushuaia)", + "America\/Aruba": "Atlantiese tyd (Aruba)", + "America\/Asuncion": "Paraguay-tyd (Asunción)", + "America\/Bahia": "Brasilia-tyd (Bahia)", + "America\/Bahia_Banderas": "Noord-Amerikaanse sentrale tyd (Bahia Banderas)", + "America\/Barbados": "Atlantiese tyd (Barbados)", + "America\/Belem": "Brasilia-tyd (Belem)", + "America\/Belize": "Noord-Amerikaanse sentrale tyd (Belize)", + "America\/Blanc-Sablon": "Atlantiese tyd (Blanc-Sablon)", + "America\/Boa_Vista": "Amasone-tyd (Boa Vista)", + "America\/Bogota": "Colombië-tyd (Bogota)", + "America\/Boise": "Noord-Amerikaanse bergtyd (Boise)", + "America\/Buenos_Aires": "Argentinië-tyd (Buenos Aires)", + "America\/Cambridge_Bay": "Noord-Amerikaanse bergtyd (Cambridgebaai)", + "America\/Campo_Grande": "Amasone-tyd (Campo Grande)", + "America\/Cancun": "Noord-Amerikaanse oostelike tyd (Cancun)", + "America\/Caracas": "Venezuela-tyd (Caracas)", + "America\/Catamarca": "Argentinië-tyd (Catamarca)", + "America\/Cayenne": "Frans-Guiana-tyd (Cayenne)", + "America\/Cayman": "Noord-Amerikaanse oostelike tyd (Kaaiman)", + "America\/Chicago": "Noord-Amerikaanse sentrale tyd (Chicago)", + "America\/Chihuahua": "Meksikaanse Pasifiese tyd (Chihuahua)", + "America\/Coral_Harbour": "Noord-Amerikaanse oostelike tyd (Atikokan)", + "America\/Cordoba": "Argentinië-tyd (Cordoba)", + "America\/Costa_Rica": "Noord-Amerikaanse sentrale tyd (Costa Rica)", + "America\/Creston": "Noord-Amerikaanse bergtyd (Creston)", + "America\/Cuiaba": "Amasone-tyd (Cuiaba)", + "America\/Curacao": "Atlantiese tyd (Curaçao)", + "America\/Danmarkshavn": "Greenwich-tyd (Danmarkshavn)", + "America\/Dawson": "Pasifiese tyd (Dawson)", + "America\/Dawson_Creek": "Noord-Amerikaanse bergtyd (Dawson Creek)", + "America\/Denver": "Noord-Amerikaanse bergtyd (Denver)", + "America\/Detroit": "Noord-Amerikaanse oostelike tyd (Detroit)", + "America\/Dominica": "Atlantiese tyd (Dominica)", + "America\/Edmonton": "Noord-Amerikaanse bergtyd (Edmonton)", + "America\/El_Salvador": "Noord-Amerikaanse sentrale tyd (El Salvador)", + "America\/Fort_Nelson": "Noord-Amerikaanse bergtyd (Fort Nelson)", + "America\/Fortaleza": "Brasilia-tyd (Fortaleza)", + "America\/Glace_Bay": "Atlantiese tyd (Glacebaai)", + "America\/Godthab": "Wes-Groenland-tyd (Nuuk)", + "America\/Goose_Bay": "Atlantiese tyd (Goosebaai)", + "America\/Grand_Turk": "Noord-Amerikaanse oostelike tyd (Grand Turk)", + "America\/Grenada": "Atlantiese tyd (Grenada)", + "America\/Guadeloupe": "Atlantiese tyd (Guadeloupe)", + "America\/Guatemala": "Noord-Amerikaanse sentrale tyd (Guatemala)", + "America\/Guayaquil": "Ecuador-tyd (Guayaquil)", + "America\/Guyana": "Guyana-tyd (Guyana)", + "America\/Halifax": "Atlantiese tyd (Halifax)", + "America\/Havana": "Kuba-tyd (Havana)", + "America\/Hermosillo": "Meksikaanse Pasifiese tyd (Hermosillo)", + "America\/Indiana\/Knox": "Noord-Amerikaanse sentrale tyd (Knox, Indiana)", + "America\/Indiana\/Marengo": "Noord-Amerikaanse oostelike tyd (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Noord-Amerikaanse oostelike tyd (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Noord-Amerikaanse sentrale tyd (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Noord-Amerikaanse oostelike tyd (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Noord-Amerikaanse oostelike tyd (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Noord-Amerikaanse oostelike tyd (Winamac, Indiana)", + "America\/Indianapolis": "Noord-Amerikaanse oostelike tyd (Indianapolis)", + "America\/Inuvik": "Noord-Amerikaanse bergtyd (Inuvik)", + "America\/Iqaluit": "Noord-Amerikaanse oostelike tyd (Iqaluit)", + "America\/Jamaica": "Noord-Amerikaanse oostelike tyd (Jamaika)", + "America\/Jujuy": "Argentinië-tyd (Jujuy)", + "America\/Juneau": "Alaska-tyd (Juneau)", + "America\/Kentucky\/Monticello": "Noord-Amerikaanse oostelike tyd (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantiese tyd (Kralendijk)", + "America\/La_Paz": "Bolivia-tyd (La Paz)", + "America\/Lima": "Peru-tyd (Lima)", + "America\/Los_Angeles": "Pasifiese tyd (Los Angeles)", + "America\/Louisville": "Noord-Amerikaanse oostelike tyd (Louisville)", + "America\/Lower_Princes": "Atlantiese tyd (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilia-tyd (Maceio)", + "America\/Managua": "Noord-Amerikaanse sentrale tyd (Managua)", + "America\/Manaus": "Amasone-tyd (Manaus)", + "America\/Marigot": "Atlantiese tyd (Marigot)", + "America\/Martinique": "Atlantiese tyd (Martinique)", + "America\/Matamoros": "Noord-Amerikaanse sentrale tyd (Matamoros)", + "America\/Mazatlan": "Meksikaanse Pasifiese tyd (Mazatlan)", + "America\/Mendoza": "Argentinië-tyd (Mendoza)", + "America\/Menominee": "Noord-Amerikaanse sentrale tyd (Menominee)", + "America\/Merida": "Noord-Amerikaanse sentrale tyd (Merida)", + "America\/Metlakatla": "Alaska-tyd (Metlakatla)", + "America\/Mexico_City": "Noord-Amerikaanse sentrale tyd (Meksikostad)", + "America\/Miquelon": "Sint-Pierre en Miquelon-tyd (Miquelon)", + "America\/Moncton": "Atlantiese tyd (Moncton)", + "America\/Monterrey": "Noord-Amerikaanse sentrale tyd (Monterrey)", + "America\/Montevideo": "Uruguay-tyd (Montevideo)", + "America\/Montserrat": "Atlantiese tyd (Montserrat)", + "America\/Nassau": "Noord-Amerikaanse oostelike tyd (Nassau)", + "America\/New_York": "Noord-Amerikaanse oostelike tyd (New York)", + "America\/Nipigon": "Noord-Amerikaanse oostelike tyd (Nipigon)", + "America\/Nome": "Alaska-tyd (Nome)", + "America\/Noronha": "Fernando de Noronha-tyd (Noronha)", + "America\/North_Dakota\/Beulah": "Noord-Amerikaanse sentrale tyd (Beulah, Noord-Dakota)", + "America\/North_Dakota\/Center": "Noord-Amerikaanse sentrale tyd (Center, Noord-Dakota)", + "America\/North_Dakota\/New_Salem": "Noord-Amerikaanse sentrale tyd (New Salem, Noord-Dakota)", + "America\/Ojinaga": "Noord-Amerikaanse bergtyd (Ojinaga)", + "America\/Panama": "Noord-Amerikaanse oostelike tyd (Panama)", + "America\/Pangnirtung": "Noord-Amerikaanse oostelike tyd (Pangnirtung)", + "America\/Paramaribo": "Suriname-tyd (Paramaribo)", + "America\/Phoenix": "Noord-Amerikaanse bergtyd (Phoenix)", + "America\/Port-au-Prince": "Noord-Amerikaanse oostelike tyd (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantiese tyd (Port of Spain)", + "America\/Porto_Velho": "Amasone-tyd (Porto Velho)", + "America\/Puerto_Rico": "Atlantiese tyd (Puerto Rico)", + "America\/Punta_Arenas": "Chili-tyd (Punta Arenas)", + "America\/Rainy_River": "Noord-Amerikaanse sentrale tyd (Rainyrivier)", + "America\/Rankin_Inlet": "Noord-Amerikaanse sentrale tyd (Rankin Inlet)", + "America\/Recife": "Brasilia-tyd (Recife)", + "America\/Regina": "Noord-Amerikaanse sentrale tyd (Regina)", + "America\/Resolute": "Noord-Amerikaanse sentrale tyd (Resolute)", + "America\/Santa_Isabel": "Noordwes-Meksiko-tyd (Santa Isabel)", + "America\/Santarem": "Brasilia-tyd (Santarem)", + "America\/Santiago": "Chili-tyd (Santiago)", + "America\/Santo_Domingo": "Atlantiese tyd (Santo Domingo)", + "America\/Sao_Paulo": "Brasilia-tyd (Sao Paulo)", + "America\/Scoresbysund": "Oos-Groenland-tyd (Ittoqqortoormiit)", + "America\/Sitka": "Alaska-tyd (Sitka)", + "America\/St_Barthelemy": "Atlantiese tyd (Sint Barthélemy)", + "America\/St_Johns": "Newfoundland-tyd (Sint John’s)", + "America\/St_Kitts": "Atlantiese tyd (Sint Kitts)", + "America\/St_Lucia": "Atlantiese tyd (Sint Lucia)", + "America\/St_Thomas": "Atlantiese tyd (Sint Thomas)", + "America\/St_Vincent": "Atlantiese tyd (Sint Vincent)", + "America\/Swift_Current": "Noord-Amerikaanse sentrale tyd (Swift Current)", + "America\/Tegucigalpa": "Noord-Amerikaanse sentrale tyd (Tegucigalpa)", + "America\/Thule": "Atlantiese tyd (Thule)", + "America\/Thunder_Bay": "Noord-Amerikaanse oostelike tyd (Thunderbaai)", + "America\/Tijuana": "Pasifiese tyd (Tijuana)", + "America\/Toronto": "Noord-Amerikaanse oostelike tyd (Toronto)", + "America\/Tortola": "Atlantiese tyd (Tortola)", + "America\/Vancouver": "Pasifiese tyd (Vancouver)", + "America\/Whitehorse": "Pasifiese tyd (Whitehorse)", + "America\/Winnipeg": "Noord-Amerikaanse sentrale tyd (Winnipeg)", + "America\/Yakutat": "Alaska-tyd (Yakutat)", + "America\/Yellowknife": "Noord-Amerikaanse bergtyd (Yellowknife)", + "Antarctica\/Casey": "Westelike Australiese tyd (Casey)", + "Antarctica\/Davis": "Davis-tyd (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville-tyd (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie-eiland-tyd (Macquarie)", + "Antarctica\/Mawson": "Mawson-tyd (Mawson)", + "Antarctica\/McMurdo": "Nieu-Seeland-tyd (McMurdo)", + "Antarctica\/Palmer": "Chili-tyd (Palmer)", + "Antarctica\/Rothera": "Rothera-tyd (Rothera)", + "Antarctica\/Syowa": "Syowa-tyd (Syowa)", + "Antarctica\/Troll": "Greenwich-tyd (Troll)", + "Antarctica\/Vostok": "Wostok-tyd (Wostok)", + "Arctic\/Longyearbyen": "Sentraal-Europese tyd (Longyearbyen)", + "Asia\/Aden": "Arabiese tyd (Aden)", + "Asia\/Almaty": "Oos-Kazakstan-tyd (Almaty)", + "Asia\/Amman": "Oos-Europese tyd (Amman)", + "Asia\/Anadyr": "Anadyr-tyd (Anadyr)", + "Asia\/Aqtau": "Wes-Kazakstan-tyd (Aqtau)", + "Asia\/Aqtobe": "Wes-Kazakstan-tyd (Aqtobe)", + "Asia\/Ashgabat": "Turkmenistan-tyd (Asjchabad)", + "Asia\/Atyrau": "Wes-Kazakstan-tyd (Atyrau)", + "Asia\/Baghdad": "Arabiese tyd (Bagdad)", + "Asia\/Bahrain": "Arabiese tyd (Bahrein)", + "Asia\/Baku": "Aserbeidjan-tyd (Bakoe)", + "Asia\/Bangkok": "Indosjina-tyd (Bangkok)", + "Asia\/Beirut": "Oos-Europese tyd (Beiroet)", + "Asia\/Bishkek": "Kirgistan-tyd (Bisjkek)", + "Asia\/Brunei": "Broenei Darussalam-tyd (Broenei)", + "Asia\/Calcutta": "Indië-standaardtyd (Kolkata)", + "Asia\/Chita": "Jakoetsk-tyd (Chita)", + "Asia\/Choibalsan": "Choibalsan-tyd (Choibalsan)", + "Asia\/Colombo": "Indië-standaardtyd (Colombo)", + "Asia\/Damascus": "Oos-Europese tyd (Damaskus)", + "Asia\/Dhaka": "Bangladesj-tyd (Dhaka)", + "Asia\/Dili": "Oos-Timor-tyd (Dili)", + "Asia\/Dubai": "Persiese Golf-standaardtyd (Doebai)", + "Asia\/Dushanbe": "Tadjikistan-tyd (Dushanbe)", + "Asia\/Famagusta": "Oos-Europese tyd (Famagusta)", + "Asia\/Gaza": "Oos-Europese tyd (Gaza)", + "Asia\/Hebron": "Oos-Europese tyd (Hebron)", + "Asia\/Hong_Kong": "Hongkong-tyd (Hongkong)", + "Asia\/Hovd": "Hovd-tyd (Hovd)", + "Asia\/Irkutsk": "Irkutsk-tyd (Irkutsk)", + "Asia\/Jakarta": "Wes-Indonesië-tyd (Djakarta)", + "Asia\/Jayapura": "Oos-Indonesië-tyd (Jayapura)", + "Asia\/Jerusalem": "Israel-tyd (Jerusalem)", + "Asia\/Kabul": "Afganistan-tyd (Kaboel)", + "Asia\/Kamchatka": "Petropavlovsk-Kamchatski-tyd (Kamtsjatka)", + "Asia\/Karachi": "Pakistan-tyd (Karatsji)", + "Asia\/Katmandu": "Nepal-tyd (Katmandoe)", + "Asia\/Khandyga": "Jakoetsk-tyd (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk-tyd (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Maleisië-tyd (Koeala-Loempoer)", + "Asia\/Kuching": "Maleisië-tyd (Kuching)", + "Asia\/Kuwait": "Arabiese tyd (Koeweit)", + "Asia\/Macau": "China-tyd (Macau)", + "Asia\/Magadan": "Magadan-tyd (Magadan)", + "Asia\/Makassar": "Sentraal-Indonesiese tyd (Makassar)", + "Asia\/Manila": "Filippynse tyd (Manila)", + "Asia\/Muscat": "Persiese Golf-standaardtyd (Muskat)", + "Asia\/Nicosia": "Oos-Europese tyd (Nicosia)", + "Asia\/Novokuznetsk": "Krasnojarsk-tyd (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk-tyd (Novosibirsk)", + "Asia\/Omsk": "Omsk-tyd (Omsk)", + "Asia\/Oral": "Wes-Kazakstan-tyd (Oral)", + "Asia\/Phnom_Penh": "Indosjina-tyd (Phnom Penh)", + "Asia\/Pontianak": "Wes-Indonesië-tyd (Pontianak)", + "Asia\/Pyongyang": "Koreaanse tyd (Pyongyang)", + "Asia\/Qatar": "Arabiese tyd (Katar)", + "Asia\/Qostanay": "Oos-Kazakstan-tyd (Qostanay)", + "Asia\/Qyzylorda": "Wes-Kazakstan-tyd (Qyzylorda)", + "Asia\/Rangoon": "Mianmar-tyd (Yangon)", + "Asia\/Riyadh": "Arabiese tyd (Riaad)", + "Asia\/Saigon": "Indosjina-tyd (Ho Tsji Minhstad)", + "Asia\/Sakhalin": "Sakhalin-tyd (Sakhalin)", + "Asia\/Samarkand": "Oesbekistan-tyd (Samarkand)", + "Asia\/Seoul": "Koreaanse tyd (Seoel)", + "Asia\/Shanghai": "China-tyd (Shanghai)", + "Asia\/Singapore": "Singapoer-standaardtyd (Singapoer)", + "Asia\/Srednekolymsk": "Magadan-tyd (Srednekolymsk)", + "Asia\/Taipei": "Taipei-tyd (Taipei)", + "Asia\/Tashkent": "Oesbekistan-tyd (Tashkent)", + "Asia\/Tbilisi": "Georgië-tyd (Tbilisi)", + "Asia\/Tehran": "Iran-tyd (Tehran)", + "Asia\/Thimphu": "Bhoetan-tyd (Thimphu)", + "Asia\/Tokyo": "Japan-tyd (Tokio)", + "Asia\/Ulaanbaatar": "Ulaanbaatar-tyd (Ulaanbaatar)", + "Asia\/Ust-Nera": "Wladiwostok-tyd (Ust-Nera)", + "Asia\/Vientiane": "Indosjina-tyd (Vientiane)", + "Asia\/Vladivostok": "Wladiwostok-tyd (Wladiwostok)", + "Asia\/Yakutsk": "Jakoetsk-tyd (Jakoetsk)", + "Asia\/Yekaterinburg": "Jekaterinburg-tyd (Jekaterinburg)", + "Asia\/Yerevan": "Armenië-tyd (Yerevan)", + "Atlantic\/Azores": "Asore-tyd (Asore)", + "Atlantic\/Bermuda": "Atlantiese tyd (Bermuda)", + "Atlantic\/Canary": "Wes-Europese tyd (Kanarie)", + "Atlantic\/Cape_Verde": "Kaap Verde-tyd (Kaap Verde)", + "Atlantic\/Faeroe": "Wes-Europese tyd (Faroe)", + "Atlantic\/Madeira": "Wes-Europese tyd (Madeira)", + "Atlantic\/Reykjavik": "Greenwich-tyd (Reykjavik)", + "Atlantic\/South_Georgia": "Suid-Georgië-tyd (Suid-Georgië)", + "Atlantic\/St_Helena": "Greenwich-tyd (Sint Helena)", + "Atlantic\/Stanley": "Falklandeilande-tyd (Stanley)", + "Australia\/Adelaide": "Sentraal-Australiese tyd (Adelaide)", + "Australia\/Brisbane": "Oostelike Australiese tyd (Brisbane)", + "Australia\/Broken_Hill": "Sentraal-Australiese tyd (Broken Hill)", + "Australia\/Currie": "Oostelike Australiese tyd (Currie)", + "Australia\/Darwin": "Sentraal-Australiese tyd (Darwin)", + "Australia\/Eucla": "Sentraal-westelike Australiese tyd (Eucla)", + "Australia\/Hobart": "Oostelike Australiese tyd (Hobart)", + "Australia\/Lindeman": "Oostelike Australiese tyd (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe-tyd (Lord Howe)", + "Australia\/Melbourne": "Oostelike Australiese tyd (Melbourne)", + "Australia\/Perth": "Westelike Australiese tyd (Perth)", + "Australia\/Sydney": "Oostelike Australiese tyd (Sydney)", + "CST6CDT": "Noord-Amerikaanse sentrale tyd", + "EST5EDT": "Noord-Amerikaanse oostelike tyd", + "Etc\/GMT": "Greenwich-tyd", + "Etc\/UTC": "Gekoördineerde universele tyd", + "Europe\/Amsterdam": "Sentraal-Europese tyd (Amsterdam)", + "Europe\/Andorra": "Sentraal-Europese tyd (Andorra)", + "Europe\/Astrakhan": "Moskou-tyd (Astrakhan)", + "Europe\/Athens": "Oos-Europese tyd (Athene)", + "Europe\/Belgrade": "Sentraal-Europese tyd (Belgrade)", + "Europe\/Berlin": "Sentraal-Europese tyd (Berlyn)", + "Europe\/Bratislava": "Sentraal-Europese tyd (Bratislava)", + "Europe\/Brussels": "Sentraal-Europese tyd (Brussel)", + "Europe\/Bucharest": "Oos-Europese tyd (Boekarest)", + "Europe\/Budapest": "Sentraal-Europese tyd (Boedapest)", + "Europe\/Busingen": "Sentraal-Europese tyd (Busingen)", + "Europe\/Chisinau": "Oos-Europese tyd (Chisinau)", + "Europe\/Copenhagen": "Sentraal-Europese tyd (Kopenhagen)", + "Europe\/Dublin": "Greenwich-tyd (Dublin)", + "Europe\/Gibraltar": "Sentraal-Europese tyd (Gibraltar)", + "Europe\/Guernsey": "Greenwich-tyd (Guernsey)", + "Europe\/Helsinki": "Oos-Europese tyd (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich-tyd (Eiland Man)", + "Europe\/Jersey": "Greenwich-tyd (Jersey)", + "Europe\/Kaliningrad": "Oos-Europese tyd (Kaliningrad)", + "Europe\/Kiev": "Oos-Europese tyd (Kiëf)", + "Europe\/Lisbon": "Wes-Europese tyd (Lissabon)", + "Europe\/Ljubljana": "Sentraal-Europese tyd (Ljubljana)", + "Europe\/London": "Greenwich-tyd (Londen)", + "Europe\/Luxembourg": "Sentraal-Europese tyd (Luxemburg)", + "Europe\/Madrid": "Sentraal-Europese tyd (Madrid)", + "Europe\/Malta": "Sentraal-Europese tyd (Malta)", + "Europe\/Mariehamn": "Oos-Europese tyd (Mariehamn)", + "Europe\/Minsk": "Moskou-tyd (Minsk)", + "Europe\/Monaco": "Sentraal-Europese tyd (Monaco)", + "Europe\/Moscow": "Moskou-tyd (Moskou)", + "Europe\/Oslo": "Sentraal-Europese tyd (Oslo)", + "Europe\/Paris": "Sentraal-Europese tyd (Parys)", + "Europe\/Podgorica": "Sentraal-Europese tyd (Podgorica)", + "Europe\/Prague": "Sentraal-Europese tyd (Praag)", + "Europe\/Riga": "Oos-Europese tyd (Riga)", + "Europe\/Rome": "Sentraal-Europese tyd (Rome)", + "Europe\/Samara": "Samara-tyd (Samara)", + "Europe\/San_Marino": "Sentraal-Europese tyd (San Marino)", + "Europe\/Sarajevo": "Sentraal-Europese tyd (Sarajevo)", + "Europe\/Saratov": "Moskou-tyd (Saratof)", + "Europe\/Simferopol": "Moskou-tyd (Simferopol)", + "Europe\/Skopje": "Sentraal-Europese tyd (Skopje)", + "Europe\/Sofia": "Oos-Europese tyd (Sofia)", + "Europe\/Stockholm": "Sentraal-Europese tyd (Stockholm)", + "Europe\/Tallinn": "Oos-Europese tyd (Tallinn)", + "Europe\/Tirane": "Sentraal-Europese tyd (Tirane)", + "Europe\/Ulyanovsk": "Moskou-tyd (Ulyanovsk)", + "Europe\/Uzhgorod": "Oos-Europese tyd (Uzhgorod)", + "Europe\/Vaduz": "Sentraal-Europese tyd (Vaduz)", + "Europe\/Vatican": "Sentraal-Europese tyd (Vatikaanstad)", + "Europe\/Vienna": "Sentraal-Europese tyd (Wene)", + "Europe\/Vilnius": "Oos-Europese tyd (Vilnius)", + "Europe\/Volgograd": "Wolgograd-tyd (Wolgograd)", + "Europe\/Warsaw": "Sentraal-Europese tyd (Warskou)", + "Europe\/Zagreb": "Sentraal-Europese tyd (Zagreb)", + "Europe\/Zaporozhye": "Oos-Europese tyd (Zaporozhye)", + "Europe\/Zurich": "Sentraal-Europese tyd (Zürich)", + "Indian\/Antananarivo": "Oos-Afrika-tyd (Antananarivo)", + "Indian\/Chagos": "Indiese Oseaan-tyd (Chagos)", + "Indian\/Christmas": "Christmaseiland-tyd (Christmas)", + "Indian\/Cocos": "Kokoseilande-tyd (Kokos)", + "Indian\/Comoro": "Oos-Afrika-tyd (Comore)", + "Indian\/Kerguelen": "Franse Suider- en Antarktiese tyd (Kerguelen)", + "Indian\/Mahe": "Seychelle-tyd (Mahe)", + "Indian\/Maldives": "Maledive-tyd (Maledive)", + "Indian\/Mauritius": "Mauritius-tyd (Mauritius)", + "Indian\/Mayotte": "Oos-Afrika-tyd (Mayotte)", + "Indian\/Reunion": "Réunion-tyd (Réunion)", + "MST7MDT": "Noord-Amerikaanse bergtyd", + "PST8PDT": "Pasifiese tyd", + "Pacific\/Apia": "Apia-tyd (Apia)", + "Pacific\/Auckland": "Nieu-Seeland-tyd (Auckland)", + "Pacific\/Bougainville": "Papoea-Nieu-Guinee-tyd (Bougainville)", + "Pacific\/Chatham": "Chatham-tyd (Chatham)", + "Pacific\/Easter": "Paaseiland-tyd (Paas)", + "Pacific\/Efate": "Vanuatu-tyd (Efate)", + "Pacific\/Enderbury": "Fenikseilande-tyd (Enderbury)", + "Pacific\/Fakaofo": "Tokelau-tyd (Fakaofo)", + "Pacific\/Fiji": "Fidji-tyd (Fidji)", + "Pacific\/Funafuti": "Tuvalu-tyd (Funafuti)", + "Pacific\/Galapagos": "Galapagos-tyd (Galapagos)", + "Pacific\/Gambier": "Gambier-tyd (Gambier)", + "Pacific\/Guadalcanal": "Salomonseilande-tyd (Guadalcanal)", + "Pacific\/Guam": "Chamorro-standaardtyd (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleoete-tyd (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleoete-tyd (Johnston)", + "Pacific\/Kiritimati": "Line-eilande-tyd (Kiritimati)", + "Pacific\/Kosrae": "Kosrae-tyd (Kosrae)", + "Pacific\/Kwajalein": "Marshalleilande-tyd (Kwajalein)", + "Pacific\/Majuro": "Marshalleilande-tyd (Majuro)", + "Pacific\/Marquesas": "Marquesas-tyd (Marquesas)", + "Pacific\/Midway": "Samoa-tyd (Midway)", + "Pacific\/Nauru": "Nauru-tyd (Nauru)", + "Pacific\/Niue": "Niue-tyd (Niue)", + "Pacific\/Norfolk": "Norfolkeiland-tyd (Norfolk)", + "Pacific\/Noumea": "Nieu-Kaledonië-tyd (Nouméa)", + "Pacific\/Pago_Pago": "Samoa-tyd (Pago Pago)", + "Pacific\/Palau": "Palau-tyd (Palau)", + "Pacific\/Pitcairn": "Pitcairn-tyd (Pitcairn)", + "Pacific\/Ponape": "Ponape-tyd (Pohnpei)", + "Pacific\/Port_Moresby": "Papoea-Nieu-Guinee-tyd (Port Moresby)", + "Pacific\/Rarotonga": "Cookeilande-tyd (Rarotonga)", + "Pacific\/Saipan": "Chamorro-standaardtyd (Saipan)", + "Pacific\/Tahiti": "Tahiti-tyd (Tahiti)", + "Pacific\/Tarawa": "Gilberteilande-tyd (Tarawa)", + "Pacific\/Tongatapu": "Tonga-tyd (Tongatapu)", + "Pacific\/Truk": "Chuuk-tyd (Chuuk)", + "Pacific\/Wake": "Wake-eiland-tyd (Wake)", + "Pacific\/Wallis": "Wallis en Futuna-tyd (Mata-Utu)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/am.json b/src/Symfony/Component/Intl/Resources/data/timezones/am.json new file mode 100644 index 0000000000000..5e6312306143a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/am.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.18", + "Names": { + "Africa\/Abidjan": "ግሪንዊች ማዕከላዊ ሰዓት (አቢጃን)", + "Africa\/Accra": "ግሪንዊች ማዕከላዊ ሰዓት (አክራ)", + "Africa\/Addis_Ababa": "የምስራቅ አፍሪካ ሰዓት (አዲስ አበባ)", + "Africa\/Algiers": "የመካከለኛው አውሮፓ ሰዓት (አልጀርስ)", + "Africa\/Asmera": "የምስራቅ አፍሪካ ሰዓት (አስመራ)", + "Africa\/Bamako": "ግሪንዊች ማዕከላዊ ሰዓት (ባማኮ)", + "Africa\/Bangui": "የምዕራብ አፍሪካ ሰዓት (ባንጉኢ)", + "Africa\/Banjul": "ግሪንዊች ማዕከላዊ ሰዓት (ባንጁል)", + "Africa\/Bissau": "ግሪንዊች ማዕከላዊ ሰዓት (ቢሳኦ)", + "Africa\/Blantyre": "የመካከለኛው አፍሪካ ሰዓት (ብላንታየር)", + "Africa\/Brazzaville": "የምዕራብ አፍሪካ ሰዓት (ብራዛቪል)", + "Africa\/Bujumbura": "የመካከለኛው አፍሪካ ሰዓት (ቡጁምብራ)", + "Africa\/Cairo": "የምስራቃዊ አውሮፓ ሰዓት (ካይሮ)", + "Africa\/Casablanca": "የምዕራባዊ አውሮፓ ሰዓት (ካዛብላንካ)", + "Africa\/Ceuta": "የመካከለኛው አውሮፓ ሰዓት (ሲኡታ)", + "Africa\/Conakry": "ግሪንዊች ማዕከላዊ ሰዓት (ኮናክሬ)", + "Africa\/Dakar": "ግሪንዊች ማዕከላዊ ሰዓት (ዳካር)", + "Africa\/Dar_es_Salaam": "የምስራቅ አፍሪካ ሰዓት (ዳሬ ሰላም)", + "Africa\/Djibouti": "የምስራቅ አፍሪካ ሰዓት (ጅቡቲ)", + "Africa\/Douala": "የምዕራብ አፍሪካ ሰዓት (ዱአላ)", + "Africa\/El_Aaiun": "የምዕራባዊ አውሮፓ ሰዓት (ኤል አዩአን)", + "Africa\/Freetown": "ግሪንዊች ማዕከላዊ ሰዓት (ፍሪታውን)", + "Africa\/Gaborone": "የመካከለኛው አፍሪካ ሰዓት (ጋቦሮን)", + "Africa\/Harare": "የመካከለኛው አፍሪካ ሰዓት (ሃራሬ)", + "Africa\/Johannesburg": "የደቡብ አፍሪካ መደበኛ ሰዓት (ጆሃንስበርግ)", + "Africa\/Juba": "የምስራቅ አፍሪካ ሰዓት (ጁባ)", + "Africa\/Kampala": "የምስራቅ አፍሪካ ሰዓት (ካምፓላ)", + "Africa\/Khartoum": "የመካከለኛው አፍሪካ ሰዓት (ካርቱም)", + "Africa\/Kigali": "የመካከለኛው አፍሪካ ሰዓት (ኪጋሊ)", + "Africa\/Kinshasa": "የምዕራብ አፍሪካ ሰዓት (ኪንሻሳ)", + "Africa\/Lagos": "የምዕራብ አፍሪካ ሰዓት (ሌጎስ)", + "Africa\/Libreville": "የምዕራብ አፍሪካ ሰዓት (ሊበርቪል)", + "Africa\/Lome": "ግሪንዊች ማዕከላዊ ሰዓት (ሎሜ)", + "Africa\/Luanda": "የምዕራብ አፍሪካ ሰዓት (ሉአንዳ)", + "Africa\/Lubumbashi": "የመካከለኛው አፍሪካ ሰዓት (ሉቡምባሺ)", + "Africa\/Lusaka": "የመካከለኛው አፍሪካ ሰዓት (ሉሳካ)", + "Africa\/Malabo": "የምዕራብ አፍሪካ ሰዓት (ማላቡ)", + "Africa\/Maputo": "የመካከለኛው አፍሪካ ሰዓት (ማፑቱ)", + "Africa\/Maseru": "የደቡብ አፍሪካ መደበኛ ሰዓት (ማሴሩ)", + "Africa\/Mbabane": "የደቡብ አፍሪካ መደበኛ ሰዓት (ምባባኔ)", + "Africa\/Mogadishu": "የምስራቅ አፍሪካ ሰዓት (ሞቃዲሹ)", + "Africa\/Monrovia": "ግሪንዊች ማዕከላዊ ሰዓት (ሞንሮቪያ)", + "Africa\/Nairobi": "የምስራቅ አፍሪካ ሰዓት (ናይሮቢ)", + "Africa\/Ndjamena": "የምዕራብ አፍሪካ ሰዓት (ንጃሜና)", + "Africa\/Niamey": "የምዕራብ አፍሪካ ሰዓት (ኒያሜይ)", + "Africa\/Nouakchott": "ግሪንዊች ማዕከላዊ ሰዓት (ኑአክቾት)", + "Africa\/Ouagadougou": "ግሪንዊች ማዕከላዊ ሰዓት (ኡጋዱጉ)", + "Africa\/Porto-Novo": "የምዕራብ አፍሪካ ሰዓት (ፖርቶ - ኖቮ)", + "Africa\/Sao_Tome": "ግሪንዊች ማዕከላዊ ሰዓት (ሳኦ ቶሜ)", + "Africa\/Tripoli": "የምስራቃዊ አውሮፓ ሰዓት (ትሪፖሊ)", + "Africa\/Tunis": "የመካከለኛው አውሮፓ ሰዓት (ቱኒዝ)", + "Africa\/Windhoek": "የመካከለኛው አፍሪካ ሰዓት (ዊንድሆክ)", + "America\/Adak": "የሃዋይ አሌኡት ሰዓት አቆጣጠር (አዳክ)", + "America\/Anchorage": "የአላስካ ሰዓት አቆጣጠር (አንኮራጅ)", + "America\/Anguilla": "የአትላንቲክ የሰዓት አቆጣጠር (አንጉይላ)", + "America\/Antigua": "የአትላንቲክ የሰዓት አቆጣጠር (አንቲጓ)", + "America\/Araguaina": "የብራዚላዊ ሰዓት አቆጣጠር (አራጉየና)", + "America\/Argentina\/La_Rioja": "የአርጀንቲና የሰዓት አቆጣጠር (ላ ሪኦጃ)", + "America\/Argentina\/Rio_Gallegos": "የአርጀንቲና የሰዓት አቆጣጠር (ሪዮ ጋሌጎስ)", + "America\/Argentina\/Salta": "የአርጀንቲና የሰዓት አቆጣጠር (ሳልታ)", + "America\/Argentina\/San_Juan": "የአርጀንቲና የሰዓት አቆጣጠር (ሳን ጁአን)", + "America\/Argentina\/San_Luis": "የአርጀንቲና ምስራቃዊ ሰዓት አቆጣጠር (ሳን ሊውስ)", + "America\/Argentina\/Tucuman": "የአርጀንቲና የሰዓት አቆጣጠር (ቱኩማን)", + "America\/Argentina\/Ushuaia": "የአርጀንቲና የሰዓት አቆጣጠር (ኡሹአኢ)", + "America\/Aruba": "የአትላንቲክ የሰዓት አቆጣጠር (አሩባ)", + "America\/Asuncion": "የፓራጓይ ሰዓት (አሱንሲዮን)", + "America\/Bahia": "የብራዚላዊ ሰዓት አቆጣጠር (ባሂአ)", + "America\/Bahia_Banderas": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ባሂያ ባንደራስ)", + "America\/Barbados": "የአትላንቲክ የሰዓት አቆጣጠር (ባርቤዶስ)", + "America\/Belem": "የብራዚላዊ ሰዓት አቆጣጠር (ቤለም)", + "America\/Belize": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ቤሊዝ)", + "America\/Blanc-Sablon": "የአትላንቲክ የሰዓት አቆጣጠር (ብላንክ- ሳብሎን)", + "America\/Boa_Vista": "የአማዞን ሰዓት አቆጣጠር (ቦአ ቪስታ)", + "America\/Bogota": "የኮሎምቢያ ሰዓት (ቦጎታ)", + "America\/Boise": "የተራራ የሰዓት አቆጣጠር (ቦይዝ)", + "America\/Buenos_Aires": "የአርጀንቲና የሰዓት አቆጣጠር (ቦነስ አይረስ)", + "America\/Cambridge_Bay": "የተራራ የሰዓት አቆጣጠር (ካምብሪጅ ቤይ)", + "America\/Campo_Grande": "የአማዞን ሰዓት አቆጣጠር (ካምፖ ግራንዴ)", + "America\/Cancun": "ምስራቃዊ ሰዓት አቆጣጠር (ካንኩን)", + "America\/Caracas": "የቬኔዝዌላ ሰዓት (ካራካስ)", + "America\/Catamarca": "የአርጀንቲና የሰዓት አቆጣጠር (ካታማርካ)", + "America\/Cayenne": "የፈረንሳይ ጉያና ሰዓት (ካይንኤ)", + "America\/Cayman": "ምስራቃዊ ሰዓት አቆጣጠር (ካይማን)", + "America\/Chicago": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ቺካጎ)", + "America\/Chihuahua": "የሜክሲኮ ፓሲፊክ ሰዓት አቆጣጠር (ቺሁዋውአ)", + "America\/Coral_Harbour": "ምስራቃዊ ሰዓት አቆጣጠር (አቲኮካን)", + "America\/Cordoba": "የአርጀንቲና የሰዓት አቆጣጠር (ኮርዶባ)", + "America\/Costa_Rica": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ኮስታሪካ)", + "America\/Creston": "የተራራ የሰዓት አቆጣጠር (ክረስተን)", + "America\/Cuiaba": "የአማዞን ሰዓት አቆጣጠር (ኩየአባ)", + "America\/Curacao": "የአትላንቲክ የሰዓት አቆጣጠር (ኩራሳዎ)", + "America\/Danmarkshavn": "ግሪንዊች ማዕከላዊ ሰዓት (ዳንማርክሻቭን)", + "America\/Dawson": "የፓስፊክ ሰዓት አቆጣጠር (ዳውሰን)", + "America\/Dawson_Creek": "የተራራ የሰዓት አቆጣጠር (ዳውሰን ክሬክ)", + "America\/Denver": "የተራራ የሰዓት አቆጣጠር (ዴንቨር)", + "America\/Detroit": "ምስራቃዊ ሰዓት አቆጣጠር (ዲትሮይት)", + "America\/Dominica": "የአትላንቲክ የሰዓት አቆጣጠር (ዶሜኒካ)", + "America\/Edmonton": "የተራራ የሰዓት አቆጣጠር (ኤድመንተን)", + "America\/El_Salvador": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ኤልሳልቫዶር)", + "America\/Fort_Nelson": "የተራራ የሰዓት አቆጣጠር (ፎርት ኔልሰን)", + "America\/Fortaleza": "የብራዚላዊ ሰዓት አቆጣጠር (ፎርታሌዛ)", + "America\/Glace_Bay": "የአትላንቲክ የሰዓት አቆጣጠር (ግሌስ ቤይ)", + "America\/Godthab": "የምዕራብ ግሪንላንድ ሰዓት (ጋድታብ)", + "America\/Goose_Bay": "የአትላንቲክ የሰዓት አቆጣጠር (ጉዝ ቤይ)", + "America\/Grand_Turk": "ምስራቃዊ ሰዓት አቆጣጠር (ግራንድ ተርክ)", + "America\/Grenada": "የአትላንቲክ የሰዓት አቆጣጠር (ግሬናዳ)", + "America\/Guadeloupe": "የአትላንቲክ የሰዓት አቆጣጠር (ጕዳሉፕ)", + "America\/Guatemala": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ጓቲማላ)", + "America\/Guayaquil": "የኢኳዶር ሰዓት (ጉያኩይል)", + "America\/Guyana": "የጉያና ሰዓት (ጉያና)", + "America\/Halifax": "የአትላንቲክ የሰዓት አቆጣጠር (ሃሊፋክስ)", + "America\/Havana": "ኩባ ሰዓት (ሃቫና)", + "America\/Hermosillo": "የሜክሲኮ ፓሲፊክ ሰዓት አቆጣጠር (ኸርሞዚሎ)", + "America\/Indiana\/Knox": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ኖክስ, ኢንዲያና)", + "America\/Indiana\/Marengo": "ምስራቃዊ ሰዓት አቆጣጠር (ማሬንጎ, ኢንዲያና)", + "America\/Indiana\/Petersburg": "ምስራቃዊ ሰዓት አቆጣጠር (ፒተርስበርግ, ኢንዲያና)", + "America\/Indiana\/Tell_City": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ቴል ከተማ, ኢንዲያና)", + "America\/Indiana\/Vevay": "ምስራቃዊ ሰዓት አቆጣጠር (ቪቫይ, ኢንዲያና)", + "America\/Indiana\/Vincennes": "ምስራቃዊ ሰዓት አቆጣጠር (ቪንቼንስ, ኢንዲያና)", + "America\/Indiana\/Winamac": "ምስራቃዊ ሰዓት አቆጣጠር (ዊናማክ, ኢንዲያና)", + "America\/Indianapolis": "ምስራቃዊ ሰዓት አቆጣጠር (ኢንዲያናፖሊስ)", + "America\/Inuvik": "የተራራ የሰዓት አቆጣጠር (ኢኑቪክ)", + "America\/Iqaluit": "ምስራቃዊ ሰዓት አቆጣጠር (ኢኳሊውት)", + "America\/Jamaica": "ምስራቃዊ ሰዓት አቆጣጠር (ጃማይካ)", + "America\/Jujuy": "የአርጀንቲና የሰዓት አቆጣጠር (ጁጁይ)", + "America\/Juneau": "የአላስካ ሰዓት አቆጣጠር (ጁኒዩ)", + "America\/Kentucky\/Monticello": "ምስራቃዊ ሰዓት አቆጣጠር (ሞንቲሴሎ, ኪንታኪ)", + "America\/Kralendijk": "የአትላንቲክ የሰዓት አቆጣጠር (ክራለንዲይክ)", + "America\/La_Paz": "የቦሊቪያ ሰዓት (ላ ፓዝ)", + "America\/Lima": "የፔሩ ሰዓት (ሊማ)", + "America\/Los_Angeles": "የፓስፊክ ሰዓት አቆጣጠር (ሎስ አንጀለስ)", + "America\/Louisville": "ምስራቃዊ ሰዓት አቆጣጠር (ሊውስቪል)", + "America\/Lower_Princes": "የአትላንቲክ የሰዓት አቆጣጠር (የታችኛው ልዑል ሩብ)", + "America\/Maceio": "የብራዚላዊ ሰዓት አቆጣጠር (ሜሲኦ)", + "America\/Managua": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ማናጉአ)", + "America\/Manaus": "የአማዞን ሰዓት አቆጣጠር (ማናኡስ)", + "America\/Marigot": "የአትላንቲክ የሰዓት አቆጣጠር (ማርጎት)", + "America\/Martinique": "የአትላንቲክ የሰዓት አቆጣጠር (ማርቲኒክ)", + "America\/Matamoros": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ማታሞሮስ)", + "America\/Mazatlan": "የሜክሲኮ ፓሲፊክ ሰዓት አቆጣጠር (ማዛትላን)", + "America\/Mendoza": "የአርጀንቲና የሰዓት አቆጣጠር (ሜንዶዛ)", + "America\/Menominee": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ሜኖሚኒ)", + "America\/Merida": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ሜሪዳ)", + "America\/Metlakatla": "የአላስካ ሰዓት አቆጣጠር (መትላካትላ)", + "America\/Mexico_City": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ሜክሲኮ ከተማ)", + "America\/Miquelon": "ቅዱስ የፒዬር እና ሚኴሎን ሰዓት (ሚኮውሎን)", + "America\/Moncton": "የአትላንቲክ የሰዓት አቆጣጠር (ሞንክቶን)", + "America\/Monterrey": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ሞንተርሬይ)", + "America\/Montevideo": "የኡራጓይ ሰዓት (ሞንቴቪድዮ)", + "America\/Montserrat": "የአትላንቲክ የሰዓት አቆጣጠር (ሞንትሴራት)", + "America\/Nassau": "ምስራቃዊ ሰዓት አቆጣጠር (ናሳው)", + "America\/New_York": "ምስራቃዊ ሰዓት አቆጣጠር (ኒውዮርክ)", + "America\/Nipigon": "ምስራቃዊ ሰዓት አቆጣጠር (ኒፒጎን)", + "America\/Nome": "የአላስካ ሰዓት አቆጣጠር (ኖሜ)", + "America\/Noronha": "የኖሮንሃ ሰዓት አቆጣጠር (ኖሮኛ)", + "America\/North_Dakota\/Beulah": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ቤኡላህ, ሰሜን ዳኮታ)", + "America\/North_Dakota\/Center": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (መካከለኛ, ሰሜን ዳኮታ)", + "America\/North_Dakota\/New_Salem": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (አዲስ ሳሌም, ሰሜን ዳኮታ)", + "America\/Ojinaga": "የተራራ የሰዓት አቆጣጠር (ኦዪናጋ)", + "America\/Panama": "ምስራቃዊ ሰዓት አቆጣጠር (ፓናማ)", + "America\/Pangnirtung": "ምስራቃዊ ሰዓት አቆጣጠር (ፓንግኒርተንግ)", + "America\/Paramaribo": "የሱሪናም ሰዓት (ፓራማሪቦ)", + "America\/Phoenix": "የተራራ የሰዓት አቆጣጠር (ፊኒክስ)", + "America\/Port-au-Prince": "ምስራቃዊ ሰዓት አቆጣጠር (ፖርት ኦ ፕሪንስ)", + "America\/Port_of_Spain": "የአትላንቲክ የሰዓት አቆጣጠር (የእስፔን ወደብ)", + "America\/Porto_Velho": "የአማዞን ሰዓት አቆጣጠር (ፔትሮ ቬልሆ)", + "America\/Puerto_Rico": "የአትላንቲክ የሰዓት አቆጣጠር (ፖርቶሪኮ)", + "America\/Punta_Arenas": "የቺሊ ሰዓት (ፑንታ አሬናስ)", + "America\/Rainy_River": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ሬኒ ሪቨር)", + "America\/Rankin_Inlet": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ራንኪን ኢንሌት)", + "America\/Recife": "የብራዚላዊ ሰዓት አቆጣጠር (ረሲፍ)", + "America\/Regina": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ረጂና)", + "America\/Resolute": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ሪዞሊዩት)", + "America\/Santa_Isabel": "ሰሜናዊ ምእራብ የሜክሲኮ ሰዓት አቆጣጠር (ሳንታ ኢዛቤል)", + "America\/Santarem": "የብራዚላዊ ሰዓት አቆጣጠር (ሳንታሬም)", + "America\/Santiago": "የቺሊ ሰዓት (ሳንቲያጎ)", + "America\/Santo_Domingo": "የአትላንቲክ የሰዓት አቆጣጠር (ሳንቶ ዶሚንጎ)", + "America\/Sao_Paulo": "የብራዚላዊ ሰዓት አቆጣጠር (ሳኦ ፖሎ)", + "America\/Scoresbysund": "የምስራቅ ግሪንላንድ ሰዓት (ስኮርስባይሰንድ)", + "America\/Sitka": "የአላስካ ሰዓት አቆጣጠር (ሲትካ)", + "America\/St_Barthelemy": "የአትላንቲክ የሰዓት አቆጣጠር (ቅድስት ቤርተሎሜ)", + "America\/St_Johns": "የኒውፋውንድላንድ የሰዓት አቆጣጠር (ቅዱስ ዮሐንስ)", + "America\/St_Kitts": "የአትላንቲክ የሰዓት አቆጣጠር (ቅዱስ ኪትስ)", + "America\/St_Lucia": "የአትላንቲክ የሰዓት አቆጣጠር (ቅድስት ሉሲያ)", + "America\/St_Thomas": "የአትላንቲክ የሰዓት አቆጣጠር (ቅዱስ ቶማስ)", + "America\/St_Vincent": "የአትላንቲክ የሰዓት አቆጣጠር (ቅዱስ ቪንሰንት)", + "America\/Swift_Current": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (የሐዋላ ገንዘብ)", + "America\/Tegucigalpa": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ቴጉሲጋልፓ)", + "America\/Thule": "የአትላንቲክ የሰዓት አቆጣጠር (ቱሌ)", + "America\/Thunder_Bay": "ምስራቃዊ ሰዓት አቆጣጠር (ተንደር ቤይ)", + "America\/Tijuana": "የፓስፊክ ሰዓት አቆጣጠር (ቲጁአና)", + "America\/Toronto": "ምስራቃዊ ሰዓት አቆጣጠር (ቶሮንቶ)", + "America\/Tortola": "የአትላንቲክ የሰዓት አቆጣጠር (ቶርቶላ)", + "America\/Vancouver": "የፓስፊክ ሰዓት አቆጣጠር (ቫንኮቨር)", + "America\/Whitehorse": "የፓስፊክ ሰዓት አቆጣጠር (ኋይትሆርስ)", + "America\/Winnipeg": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር (ዊኒፔግ)", + "America\/Yakutat": "የአላስካ ሰዓት አቆጣጠር (ያኩታት)", + "America\/Yellowknife": "የተራራ የሰዓት አቆጣጠር (የሎውናይፍ)", + "Antarctica\/Casey": "የምስራቃዊ አውስትራሊያ ሰዓት አቆጣጠር (ካዚይ)", + "Antarctica\/Davis": "የዴቪስ ሰዓት (ዳቪስ)", + "Antarctica\/DumontDUrville": "የዱሞንት-ዱርቪል ሰዓት (ደሞንት ዲኡርቪል)", + "Antarctica\/Macquarie": "የማከሪ ደሴት ሰዓት (ማከሪ)", + "Antarctica\/Mawson": "የማውሰን ሰዓት (ናውሰን)", + "Antarctica\/McMurdo": "የኒው ዚላንድ ሰዓት (ማክመርዶ)", + "Antarctica\/Palmer": "የቺሊ ሰዓት (ፓልመር)", + "Antarctica\/Rothera": "የሮቴራ ሰዓት (ሮቴራ)", + "Antarctica\/Syowa": "የሲዮዋ ሰዓት (ስዮዋ)", + "Antarctica\/Troll": "ግሪንዊች ማዕከላዊ ሰዓት (ትሮል)", + "Antarctica\/Vostok": "የቮስቶክ ሰዓት (ቭስቶክ)", + "Arctic\/Longyearbyen": "የመካከለኛው አውሮፓ ሰዓት (ሎንግይርባየን)", + "Asia\/Aden": "የዓረቢያ ሰዓት (ኤደን)", + "Asia\/Almaty": "የምስራቅ ካዛኪስታን ሰዓት (አልማትይ)", + "Asia\/Amman": "የምስራቃዊ አውሮፓ ሰዓት (አማን)", + "Asia\/Anadyr": "የአናድይር ሰዓት አቆጣጠር (አናድይር)", + "Asia\/Aqtau": "የምዕራብ ካዛኪስታን ሰዓት (አኩታኡ)", + "Asia\/Aqtobe": "የምዕራብ ካዛኪስታን ሰዓት (አኩቶቤ)", + "Asia\/Ashgabat": "የቱርክመኒስታን ሰዓት (አሽጋባት)", + "Asia\/Atyrau": "የምዕራብ ካዛኪስታን ሰዓት (አትይራኡ)", + "Asia\/Baghdad": "የዓረቢያ ሰዓት (ባግዳድ)", + "Asia\/Bahrain": "የዓረቢያ ሰዓት (ባህሬን)", + "Asia\/Baku": "የአዘርባጃን ሰዓት (ባኩ)", + "Asia\/Bangkok": "የኢንዶቻይና ሰዓት (ባንኮክ)", + "Asia\/Beirut": "የምስራቃዊ አውሮፓ ሰዓት (ቤሩት)", + "Asia\/Bishkek": "የኪርጊስታን ሰዓት (ቢሽኬክ)", + "Asia\/Brunei": "የብሩኔይ ዳሩሳላም ሰዓት (ብሩናይ)", + "Asia\/Calcutta": "የህንድ መደበኛ ሰዓት (ኮልካታ)", + "Asia\/Chita": "ያኩትስክ የሰዓት አቆጣጠር (ቺታ)", + "Asia\/Choibalsan": "የቾይባልሳ ሰዓት አቆጣጠር (ቾይባልሳን)", + "Asia\/Colombo": "የህንድ መደበኛ ሰዓት (ኮሎምቦ)", + "Asia\/Damascus": "የምስራቃዊ አውሮፓ ሰዓት (ደማስቆ)", + "Asia\/Dhaka": "የባንግላዴሽ ሰዓት (ዳካ)", + "Asia\/Dili": "የምስራቅ ቲሞር ሰዓት (ዲሊ)", + "Asia\/Dubai": "የባህረሰላጤ መደበኛ ሰዓት (ዱባይ)", + "Asia\/Dushanbe": "የታጂኪስታን ሰዓት (ደሻንቤ)", + "Asia\/Famagusta": "የምስራቃዊ አውሮፓ ሰዓት (ፋማጉስታ)", + "Asia\/Gaza": "የምስራቃዊ አውሮፓ ሰዓት (ጋዛ)", + "Asia\/Hebron": "የምስራቃዊ አውሮፓ ሰዓት (ኬብሮን)", + "Asia\/Hong_Kong": "የሆንግ ኮንግ ሰዓት (ሆንግ ኮንግ)", + "Asia\/Hovd": "የሆቭድ ሰዓት አቆጣጠር (ሆቭድ)", + "Asia\/Irkutsk": "የኢርኩትስክ ሰዓት አቆጣጠር (ኢርኩትስክ)", + "Asia\/Jakarta": "የምዕራባዊ ኢንዶኔዢያ ሰዓት (ጃካርታ)", + "Asia\/Jayapura": "የምስራቃዊ ኢንዶኔዢያ ሰዓት (ጃያፑራ)", + "Asia\/Jerusalem": "የእስራኤል ሰዓት (እየሩሳሌም)", + "Asia\/Kabul": "የአፍጋኒስታን ሰዓት (ካቡል)", + "Asia\/Kamchatka": "የካምቻትካ ሰዓት አቆጣጠር (ካምቻትካ)", + "Asia\/Karachi": "የፓኪስታን ሰዓት (ካራቺ)", + "Asia\/Katmandu": "የኔፓል ሰዓት (ካትማንዱ)", + "Asia\/Khandyga": "ያኩትስክ የሰዓት አቆጣጠር (ካንዲጋ)", + "Asia\/Krasnoyarsk": "የክራስኖያርስክ ሰዓት አቆጣጠር (ክራስኖያርስክ)", + "Asia\/Kuala_Lumpur": "የማሌይዢያ ሰዓት (ኩዋላ ላምፑር)", + "Asia\/Kuching": "የማሌይዢያ ሰዓት (ኩቺንግ)", + "Asia\/Kuwait": "የዓረቢያ ሰዓት (ኩዌት)", + "Asia\/Macau": "የቻይና ሰዓት (ማካኡ)", + "Asia\/Magadan": "የማጋዳን የሰዓት አቆጣጠር (ማጋዳን)", + "Asia\/Makassar": "የመካከለኛው ኢንዶኔዢያ ሰዓት (ማካሳር)", + "Asia\/Manila": "የፊሊፒን ሰዓት (ማኒላ)", + "Asia\/Muscat": "የባህረሰላጤ መደበኛ ሰዓት (ሙስካት)", + "Asia\/Nicosia": "የምስራቃዊ አውሮፓ ሰዓት (ኒኮሲአ)", + "Asia\/Novokuznetsk": "የክራስኖያርስክ ሰዓት አቆጣጠር (ኖቮኩትዝኔክ)", + "Asia\/Novosibirsk": "የኖቮሲብሪስክ የሰዓት አቆጣጠር (ኖቮሲቢሪስክ)", + "Asia\/Omsk": "የኦምስክ የሰዓት አቆጣጠር (ኦምስክ)", + "Asia\/Oral": "የምዕራብ ካዛኪስታን ሰዓት (ኦራል)", + "Asia\/Phnom_Penh": "የኢንዶቻይና ሰዓት (ፍኖም ፔንህ)", + "Asia\/Pontianak": "የምዕራባዊ ኢንዶኔዢያ ሰዓት (ፖንቲአናክ)", + "Asia\/Pyongyang": "የኮሪያ ሰዓት (ፕዮንግያንግ)", + "Asia\/Qatar": "የዓረቢያ ሰዓት (ኳታር)", + "Asia\/Qostanay": "የምስራቅ ካዛኪስታን ሰዓት (Qostanay)", + "Asia\/Qyzylorda": "የምዕራብ ካዛኪስታን ሰዓት (ኩይዚሎርዳ)", + "Asia\/Rangoon": "የሚያንማር ሰዓት (ያንጎን)", + "Asia\/Riyadh": "የዓረቢያ ሰዓት (ሪያድ)", + "Asia\/Saigon": "የኢንዶቻይና ሰዓት (ሆ ቺ ሚንህ ከተማ)", + "Asia\/Sakhalin": "የሳክሃሊን ሰዓት አቆጣጠር (ሳክሃሊን)", + "Asia\/Samarkand": "የኡዝቤኪስታን ሰዓት (ሳማርካንድ)", + "Asia\/Seoul": "የኮሪያ ሰዓት (ሴኦል)", + "Asia\/Shanghai": "የቻይና ሰዓት (ሻንጋይ)", + "Asia\/Singapore": "የሲንጋፒር መደበኛ ሰዓት (ሲንጋፖር)", + "Asia\/Srednekolymsk": "የማጋዳን የሰዓት አቆጣጠር (ስሬድኔስኮልምስክ)", + "Asia\/Taipei": "የታይፔይ ሰዓት (ታይፓይ)", + "Asia\/Tashkent": "የኡዝቤኪስታን ሰዓት (ታሽኬንት)", + "Asia\/Tbilisi": "የጂዮርጂያ ሰዓት (ትብሊሲ)", + "Asia\/Tehran": "የኢራን ሰዓት (ቴህራን)", + "Asia\/Thimphu": "የቡታን ሰዓት (ቲምፉ)", + "Asia\/Tokyo": "የጃፓን ሰዓት (ቶኪዮ)", + "Asia\/Ulaanbaatar": "የኡላን ባቶር ጊዜ (ኡላአንባአታር)", + "Asia\/Ust-Nera": "የቭላዲቮስቶክ የሰዓት አቆጣጠር (ኡስት-ኔራ)", + "Asia\/Vientiane": "የኢንዶቻይና ሰዓት (ቬንቲአን)", + "Asia\/Vladivostok": "የቭላዲቮስቶክ የሰዓት አቆጣጠር (ቭላዲቮስቶክ)", + "Asia\/Yakutsk": "ያኩትስክ የሰዓት አቆጣጠር (ያኩትስክ)", + "Asia\/Yekaterinburg": "የየካተሪንበርግ ሰዓት አቆጣጠር (የካተሪንበርግ)", + "Asia\/Yerevan": "የአርመኒያ ሰዓት (ይሬቫን)", + "Atlantic\/Azores": "የአዞረስ ሰዓት (አዞረስ)", + "Atlantic\/Bermuda": "የአትላንቲክ የሰዓት አቆጣጠር (ቤርሙዳ)", + "Atlantic\/Canary": "የምዕራባዊ አውሮፓ ሰዓት (ካናሪ)", + "Atlantic\/Cape_Verde": "የኬፕ ቨርዴ ሰዓት (ኬፕ ቬርደ)", + "Atlantic\/Faeroe": "የምዕራባዊ አውሮፓ ሰዓት (ፋሮእ)", + "Atlantic\/Madeira": "የምዕራባዊ አውሮፓ ሰዓት (ማዴራ)", + "Atlantic\/Reykjavik": "ግሪንዊች ማዕከላዊ ሰዓት (ሬይክጃቪክ)", + "Atlantic\/South_Georgia": "የደቡብ ጂዮርጂያ ሰዓት (ደቡብ ጆርጂያ)", + "Atlantic\/St_Helena": "ግሪንዊች ማዕከላዊ ሰዓት (ቅድስት ሄለና)", + "Atlantic\/Stanley": "የፋልክላንድ ደሴቶች ሰዓት (ስታንሌይ)", + "Australia\/Adelaide": "የመካከለኛው አውስትራሊያ ሰዓት አቆጣጠር (አዴሌእድ)", + "Australia\/Brisbane": "የምዕራባዊ አውስትራሊያ የሰዓት አቆጣጠር (ብሪስቤን)", + "Australia\/Broken_Hill": "የመካከለኛው አውስትራሊያ ሰዓት አቆጣጠር (ብሮክን ሂል)", + "Australia\/Currie": "የምዕራባዊ አውስትራሊያ የሰዓት አቆጣጠር (ከሪ)", + "Australia\/Darwin": "የመካከለኛው አውስትራሊያ ሰዓት አቆጣጠር (ዳርዊን)", + "Australia\/Eucla": "የአውስትራሊያ መካከለኛ ምስራቃዊ ሰዓት አቆጣጠር (ኡክላ)", + "Australia\/Hobart": "የምዕራባዊ አውስትራሊያ የሰዓት አቆጣጠር (ሆባርት)", + "Australia\/Lindeman": "የምዕራባዊ አውስትራሊያ የሰዓት አቆጣጠር (ሊንድማን)", + "Australia\/Lord_Howe": "የሎርድ ሆዌ የሰዓት አቆጣጠር (ሎርድ ሆዊ)", + "Australia\/Melbourne": "የምዕራባዊ አውስትራሊያ የሰዓት አቆጣጠር (ሜልቦርን)", + "Australia\/Perth": "የምስራቃዊ አውስትራሊያ ሰዓት አቆጣጠር (ፐርዝ)", + "Australia\/Sydney": "የምዕራባዊ አውስትራሊያ የሰዓት አቆጣጠር (ሲድኒ)", + "CST6CDT": "የሰሜን አሜሪካ የመካከለኛ ሰዓት አቆጣጠር", + "EST5EDT": "ምስራቃዊ ሰዓት አቆጣጠር", + "Etc\/GMT": "ግሪንዊች ማዕከላዊ ሰዓት", + "Etc\/UTC": "የተቀነባበረ ሁለገብ ሰዓት", + "Europe\/Amsterdam": "የመካከለኛው አውሮፓ ሰዓት (አምስተርዳም)", + "Europe\/Andorra": "የመካከለኛው አውሮፓ ሰዓት (አንዶራ)", + "Europe\/Astrakhan": "የሞስኮ ሰዓት አቆጣጠር (አስትራክሃን)", + "Europe\/Athens": "የምስራቃዊ አውሮፓ ሰዓት (አቴንስ)", + "Europe\/Belgrade": "የመካከለኛው አውሮፓ ሰዓት (ቤልግሬድ)", + "Europe\/Berlin": "የመካከለኛው አውሮፓ ሰዓት (በርሊን)", + "Europe\/Bratislava": "የመካከለኛው አውሮፓ ሰዓት (ብራቲስላቫ)", + "Europe\/Brussels": "የመካከለኛው አውሮፓ ሰዓት (ብራሰልስ)", + "Europe\/Bucharest": "የምስራቃዊ አውሮፓ ሰዓት (ቡካሬስት)", + "Europe\/Budapest": "የመካከለኛው አውሮፓ ሰዓት (ቡዳፔስት)", + "Europe\/Busingen": "የመካከለኛው አውሮፓ ሰዓት (ቡሲንገን)", + "Europe\/Chisinau": "የምስራቃዊ አውሮፓ ሰዓት (ቺስናኡ)", + "Europe\/Copenhagen": "የመካከለኛው አውሮፓ ሰዓት (ኮፐንሃገን)", + "Europe\/Dublin": "ግሪንዊች ማዕከላዊ ሰዓት (ደብሊን)", + "Europe\/Gibraltar": "የመካከለኛው አውሮፓ ሰዓት (ጂብራልታር)", + "Europe\/Guernsey": "ግሪንዊች ማዕከላዊ ሰዓት (ጉርነሲ)", + "Europe\/Helsinki": "የምስራቃዊ አውሮፓ ሰዓት (ሄልሲንኪ)", + "Europe\/Isle_of_Man": "ግሪንዊች ማዕከላዊ ሰዓት (አይስል ኦፍ ማን)", + "Europe\/Jersey": "ግሪንዊች ማዕከላዊ ሰዓት (ጀርሲ)", + "Europe\/Kaliningrad": "የምስራቃዊ አውሮፓ ሰዓት (ካሊኒንግራድ)", + "Europe\/Kiev": "የምስራቃዊ አውሮፓ ሰዓት (ኪየቭ)", + "Europe\/Lisbon": "የምዕራባዊ አውሮፓ ሰዓት (ሊዝበን)", + "Europe\/Ljubljana": "የመካከለኛው አውሮፓ ሰዓት (ልጁብልጃና)", + "Europe\/London": "ግሪንዊች ማዕከላዊ ሰዓት (ለንደን)", + "Europe\/Luxembourg": "የመካከለኛው አውሮፓ ሰዓት (ሉክሰምበርግ)", + "Europe\/Madrid": "የመካከለኛው አውሮፓ ሰዓት (ማድሪድ)", + "Europe\/Malta": "የመካከለኛው አውሮፓ ሰዓት (ማልታ)", + "Europe\/Mariehamn": "የምስራቃዊ አውሮፓ ሰዓት (ሜሪሃምን)", + "Europe\/Minsk": "የሞስኮ ሰዓት አቆጣጠር (ሚንስክ)", + "Europe\/Monaco": "የመካከለኛው አውሮፓ ሰዓት (ሞናኮ)", + "Europe\/Moscow": "የሞስኮ ሰዓት አቆጣጠር (ሞስኮ)", + "Europe\/Oslo": "የመካከለኛው አውሮፓ ሰዓት (ኦስሎ)", + "Europe\/Paris": "የመካከለኛው አውሮፓ ሰዓት (ፓሪስ)", + "Europe\/Podgorica": "የመካከለኛው አውሮፓ ሰዓት (ፖድጎሪካ)", + "Europe\/Prague": "የመካከለኛው አውሮፓ ሰዓት (ፕራግ)", + "Europe\/Riga": "የምስራቃዊ አውሮፓ ሰዓት (ሪጋ)", + "Europe\/Rome": "የመካከለኛው አውሮፓ ሰዓት (ሮም)", + "Europe\/Samara": "የሳማራ ሰዓት አቆጣጠር (ሳማራ)", + "Europe\/San_Marino": "የመካከለኛው አውሮፓ ሰዓት (ሳን ማሪኖ)", + "Europe\/Sarajevo": "የመካከለኛው አውሮፓ ሰዓት (ሳሪየቮ)", + "Europe\/Saratov": "የሞስኮ ሰዓት አቆጣጠር (ሳራቶቭ)", + "Europe\/Simferopol": "የሞስኮ ሰዓት አቆጣጠር (ሲምፈሮፖል)", + "Europe\/Skopje": "የመካከለኛው አውሮፓ ሰዓት (ስኮፕየ)", + "Europe\/Sofia": "የምስራቃዊ አውሮፓ ሰዓት (ሶፊያ)", + "Europe\/Stockholm": "የመካከለኛው አውሮፓ ሰዓት (ስቶክሆልም)", + "Europe\/Tallinn": "የምስራቃዊ አውሮፓ ሰዓት (ታሊን)", + "Europe\/Tirane": "የመካከለኛው አውሮፓ ሰዓት (ቴራን)", + "Europe\/Ulyanovsk": "የሞስኮ ሰዓት አቆጣጠር (ኡልያኖቭስክ)", + "Europe\/Uzhgorod": "የምስራቃዊ አውሮፓ ሰዓት (ኡዝጎሮድ)", + "Europe\/Vaduz": "የመካከለኛው አውሮፓ ሰዓት (ቫዱዝ)", + "Europe\/Vatican": "የመካከለኛው አውሮፓ ሰዓት (ቫቲካን)", + "Europe\/Vienna": "የመካከለኛው አውሮፓ ሰዓት (ቪየና)", + "Europe\/Vilnius": "የምስራቃዊ አውሮፓ ሰዓት (ቪሊነስ)", + "Europe\/Volgograd": "የቮልጎራድ የሰዓት አቆጣጠር (ቮልጎራድ)", + "Europe\/Warsaw": "የመካከለኛው አውሮፓ ሰዓት (ዋርሶው)", + "Europe\/Zagreb": "የመካከለኛው አውሮፓ ሰዓት (ዛግሬብ)", + "Europe\/Zaporozhye": "የምስራቃዊ አውሮፓ ሰዓት (ዛፖሮዚይ)", + "Europe\/Zurich": "የመካከለኛው አውሮፓ ሰዓት (ዙሪክ)", + "Indian\/Antananarivo": "የምስራቅ አፍሪካ ሰዓት (አንታናናሪቮ)", + "Indian\/Chagos": "የህንድ ውቅያኖስ ሰዓት (ቻጎስ)", + "Indian\/Christmas": "የገና ደሴት ሰዓት (ገና)", + "Indian\/Cocos": "የኮኮስ ደሴቶች ሰዓት (ኮኮስ)", + "Indian\/Comoro": "የምስራቅ አፍሪካ ሰዓት (ኮሞሮ)", + "Indian\/Kerguelen": "የፈረንሳይ ደቡባዊ እና አንታርክቲክ ሰዓት (ኬርጉለን)", + "Indian\/Mahe": "የሴሸልስ ሰዓት (ማሄ)", + "Indian\/Maldives": "የማልዲቭስ ሰዓት (ማልዲቨ)", + "Indian\/Mauritius": "የማውሪሺየስ ሰዓት (ሞሪሽየስ)", + "Indian\/Mayotte": "የምስራቅ አፍሪካ ሰዓት (ማዮቴ)", + "Indian\/Reunion": "የሬዩኒየን ሰዓት (ሬዩኒየን)", + "MST7MDT": "የተራራ የሰዓት አቆጣጠር", + "PST8PDT": "የፓስፊክ ሰዓት አቆጣጠር", + "Pacific\/Apia": "የአፒያ ሰዓት (አፒአ)", + "Pacific\/Auckland": "የኒው ዚላንድ ሰዓት (ኦክላንድ)", + "Pacific\/Bougainville": "የፓፗ ኒው ጊኒ ሰዓት (ቦጌይንቪል)", + "Pacific\/Chatham": "የቻታም ሰዓት (ቻታም)", + "Pacific\/Easter": "የኢስተር ደሴት ሰዓት (ፋሲካ)", + "Pacific\/Efate": "የቫኗቱ ሰዓት (ኢፋቴ)", + "Pacific\/Enderbury": "የፊኒክስ ደሴቶች ሰዓት (ኢንደርበሪ)", + "Pacific\/Fakaofo": "የቶኬላው ሰዓት (ፋካኦፎ)", + "Pacific\/Fiji": "የፊጂ ሰዓት (ፊጂ)", + "Pacific\/Funafuti": "የቱቫሉ ሰዓት (ፈናፉቲ)", + "Pacific\/Galapagos": "የጋላፓጎስ ሰዓት (ጋላፓጎስ)", + "Pacific\/Gambier": "የጋምቢየር ሰዓት (ጋምቢየር)", + "Pacific\/Guadalcanal": "የሰለሞን ደሴቶች ሰዓት (ጉዋዳልካናል)", + "Pacific\/Guam": "የቻሞሮ መደበኛ ሰዓት (ጉአም)", + "Pacific\/Honolulu": "የሃዋይ አሌኡት ሰዓት አቆጣጠር (ሆኖሉሉ)", + "Pacific\/Johnston": "የሃዋይ አሌኡት ሰዓት አቆጣጠር (ጆንስተን)", + "Pacific\/Kiritimati": "የላይን ደሴቶች ሰዓት (ኪሪቲማቲ)", + "Pacific\/Kosrae": "የኮስራኤ ሰዓት (ኮስሬ)", + "Pacific\/Kwajalein": "የማርሻል ደሴቶች ሰዓት (ክዋጃሊን)", + "Pacific\/Majuro": "የማርሻል ደሴቶች ሰዓት (ማጁሩ)", + "Pacific\/Marquesas": "የማርኴሳስ ሰዓት (ማርክዌሳስ)", + "Pacific\/Midway": "የሳሞዋ ሰዓት (ሚድወይ)", + "Pacific\/Nauru": "የናውሩ ሰዓት (ናውሩ)", + "Pacific\/Niue": "የኒዩዌ ሰዓት (ኒዌ)", + "Pacific\/Norfolk": "የኖርፎልክ ደሴቶች ሰዓት (ኖርፎልክ)", + "Pacific\/Noumea": "የኒው ካሌዶኒያ ሰዓት (ናኦሚአ)", + "Pacific\/Pago_Pago": "የሳሞዋ ሰዓት (ፓጎ ፓጎ)", + "Pacific\/Palau": "የፓላው ሰዓት (ፓላው)", + "Pacific\/Pitcairn": "የፒትካይርን ሰዓት (ፒትከይርን)", + "Pacific\/Ponape": "የፖናፔ ሰዓት (ፖህንፔ)", + "Pacific\/Port_Moresby": "የፓፗ ኒው ጊኒ ሰዓት (ፖርት ሞሬስባይ)", + "Pacific\/Rarotonga": "የኩክ ደሴቶች ሰዓት (ራሮቶንጋ)", + "Pacific\/Saipan": "የቻሞሮ መደበኛ ሰዓት (ሴይፓን)", + "Pacific\/Tahiti": "የታሂቲ ሰዓት (ታሂቲ)", + "Pacific\/Tarawa": "የጂልበርት ደሴቶች ሰዓት (ታራዋ)", + "Pacific\/Tongatapu": "የቶንጋ ሰዓት (ቶንጋታፑ)", + "Pacific\/Truk": "የቹክ ሰዓት (ቹክ)", + "Pacific\/Wake": "የዌክ ደሴት ሰዓት (ዋኬ)", + "Pacific\/Wallis": "የዋሊስ እና ፉቱና ሰዓት (ዋሊስ)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ar.json b/src/Symfony/Component/Intl/Resources/data/timezones/ar.json new file mode 100644 index 0000000000000..4524944e1e7e5 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ar.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.22", + "Names": { + "Africa\/Abidjan": "توقيت غرينتش (أبيدجان)", + "Africa\/Accra": "توقيت غرينتش (أكرا)", + "Africa\/Addis_Ababa": "توقيت شرق أفريقيا (أديس أبابا)", + "Africa\/Algiers": "توقيت وسط أوروبا (الجزائر)", + "Africa\/Asmera": "توقيت شرق أفريقيا (أسمرة)", + "Africa\/Bamako": "توقيت غرينتش (باماكو)", + "Africa\/Bangui": "توقيت غرب أفريقيا (بانغوي)", + "Africa\/Banjul": "توقيت غرينتش (بانجول)", + "Africa\/Bissau": "توقيت غرينتش (بيساو)", + "Africa\/Blantyre": "توقيت وسط أفريقيا (بلانتاير)", + "Africa\/Brazzaville": "توقيت غرب أفريقيا (برازافيل)", + "Africa\/Bujumbura": "توقيت وسط أفريقيا (بوجومبورا)", + "Africa\/Cairo": "توقيت شرق أوروبا (القاهرة)", + "Africa\/Casablanca": "توقيت غرب أوروبا (الدار البيضاء)", + "Africa\/Ceuta": "توقيت وسط أوروبا (سيتا)", + "Africa\/Conakry": "توقيت غرينتش (كوناكري)", + "Africa\/Dakar": "توقيت غرينتش (داكار)", + "Africa\/Dar_es_Salaam": "توقيت شرق أفريقيا (دار السلام)", + "Africa\/Djibouti": "توقيت شرق أفريقيا (جيبوتي)", + "Africa\/Douala": "توقيت غرب أفريقيا (دوالا)", + "Africa\/El_Aaiun": "توقيت غرب أوروبا (العيون)", + "Africa\/Freetown": "توقيت غرينتش (فري تاون)", + "Africa\/Gaborone": "توقيت وسط أفريقيا (غابورون)", + "Africa\/Harare": "توقيت وسط أفريقيا (هراري)", + "Africa\/Johannesburg": "توقيت جنوب أفريقيا (جوهانسبرغ)", + "Africa\/Juba": "توقيت شرق أفريقيا (جوبا)", + "Africa\/Kampala": "توقيت شرق أفريقيا (كامبالا)", + "Africa\/Khartoum": "توقيت وسط أفريقيا (الخرطوم)", + "Africa\/Kigali": "توقيت وسط أفريقيا (كيغالي)", + "Africa\/Kinshasa": "توقيت غرب أفريقيا (كينشاسا)", + "Africa\/Lagos": "توقيت غرب أفريقيا (لاغوس)", + "Africa\/Libreville": "توقيت غرب أفريقيا (ليبرفيل)", + "Africa\/Lome": "توقيت غرينتش (لومي)", + "Africa\/Luanda": "توقيت غرب أفريقيا (لواندا)", + "Africa\/Lubumbashi": "توقيت وسط أفريقيا (لومبباشا)", + "Africa\/Lusaka": "توقيت وسط أفريقيا (لوساكا)", + "Africa\/Malabo": "توقيت غرب أفريقيا (مالابو)", + "Africa\/Maputo": "توقيت وسط أفريقيا (مابوتو)", + "Africa\/Maseru": "توقيت جنوب أفريقيا (ماسيرو)", + "Africa\/Mbabane": "توقيت جنوب أفريقيا (مباباني)", + "Africa\/Mogadishu": "توقيت شرق أفريقيا (مقديشيو)", + "Africa\/Monrovia": "توقيت غرينتش (مونروفيا)", + "Africa\/Nairobi": "توقيت شرق أفريقيا (نيروبي)", + "Africa\/Ndjamena": "توقيت غرب أفريقيا (نجامينا)", + "Africa\/Niamey": "توقيت غرب أفريقيا (نيامي)", + "Africa\/Nouakchott": "توقيت غرينتش (نواكشوط)", + "Africa\/Ouagadougou": "توقيت غرينتش (واغادوغو)", + "Africa\/Porto-Novo": "توقيت غرب أفريقيا (بورتو نوفو)", + "Africa\/Sao_Tome": "توقيت غرينتش (ساو تومي)", + "Africa\/Tripoli": "توقيت شرق أوروبا (طرابلس)", + "Africa\/Tunis": "توقيت وسط أوروبا (تونس)", + "Africa\/Windhoek": "توقيت وسط أفريقيا (ويندهوك)", + "America\/Adak": "توقيت هاواي ألوتيان (أداك)", + "America\/Anchorage": "توقيت ألاسكا (أنشوراج)", + "America\/Anguilla": "توقيت الأطلسي (أنغويلا)", + "America\/Antigua": "توقيت الأطلسي (أنتيغوا)", + "America\/Araguaina": "توقيت برازيليا (أروجوانيا)", + "America\/Argentina\/La_Rioja": "توقيت الأرجنتين (لا ريوجا)", + "America\/Argentina\/Rio_Gallegos": "توقيت الأرجنتين (ريو جالييوس)", + "America\/Argentina\/Salta": "توقيت الأرجنتين (سالطا)", + "America\/Argentina\/San_Juan": "توقيت الأرجنتين (سان خوان)", + "America\/Argentina\/San_Luis": "توقيت غرب الأرجنتين (سان لويس)", + "America\/Argentina\/Tucuman": "توقيت الأرجنتين (تاكمان)", + "America\/Argentina\/Ushuaia": "توقيت الأرجنتين (أشوا)", + "America\/Aruba": "توقيت الأطلسي (أروبا)", + "America\/Asuncion": "توقيت باراغواي (أسونسيون)", + "America\/Bahia": "توقيت برازيليا (باهيا)", + "America\/Bahia_Banderas": "التوقيت المركزي لأمريكا الشمالية (باهيا بانديراس)", + "America\/Barbados": "توقيت الأطلسي (بربادوس)", + "America\/Belem": "توقيت برازيليا (بلم)", + "America\/Belize": "التوقيت المركزي لأمريكا الشمالية (بليز)", + "America\/Blanc-Sablon": "توقيت الأطلسي (بلانك-سابلون)", + "America\/Boa_Vista": "توقيت الأمازون (باو فيستا)", + "America\/Bogota": "توقيت كولومبيا (بوغوتا)", + "America\/Boise": "التوقيت الجبلي لأمريكا الشمالية (بويس)", + "America\/Buenos_Aires": "توقيت الأرجنتين (بوينوس أيرس)", + "America\/Cambridge_Bay": "التوقيت الجبلي لأمريكا الشمالية (كامبرديج باي)", + "America\/Campo_Grande": "توقيت الأمازون (كومبو جراند)", + "America\/Cancun": "التوقيت الشرقي لأمريكا الشمالية (كانكون)", + "America\/Caracas": "توقيت فنزويلا (كاراكاس)", + "America\/Catamarca": "توقيت الأرجنتين (كاتاماركا)", + "America\/Cayenne": "توقيت غويانا الفرنسية (كايين)", + "America\/Cayman": "التوقيت الشرقي لأمريكا الشمالية (كايمان)", + "America\/Chicago": "التوقيت المركزي لأمريكا الشمالية (شيكاغو)", + "America\/Chihuahua": "توقيت المحيط الهادي للمكسيك (تشيواوا)", + "America\/Coral_Harbour": "التوقيت الشرقي لأمريكا الشمالية (كورال هاربر)", + "America\/Cordoba": "توقيت الأرجنتين (كوردوبا)", + "America\/Costa_Rica": "التوقيت المركزي لأمريكا الشمالية (كوستاريكا)", + "America\/Creston": "التوقيت الجبلي لأمريكا الشمالية (كريستون)", + "America\/Cuiaba": "توقيت الأمازون (كيابا)", + "America\/Curacao": "توقيت الأطلسي (كوراساو)", + "America\/Danmarkshavn": "توقيت غرينتش (دانمرك شافن)", + "America\/Dawson": "توقيت المحيط الهادي (داوسان)", + "America\/Dawson_Creek": "التوقيت الجبلي لأمريكا الشمالية (داوسن كريك)", + "America\/Denver": "التوقيت الجبلي لأمريكا الشمالية (دنفر)", + "America\/Detroit": "التوقيت الشرقي لأمريكا الشمالية (ديترويت)", + "America\/Dominica": "توقيت الأطلسي (دومينيكا)", + "America\/Edmonton": "التوقيت الجبلي لأمريكا الشمالية (ايدمونتون)", + "America\/El_Salvador": "التوقيت المركزي لأمريكا الشمالية (السلفادور)", + "America\/Fort_Nelson": "التوقيت الجبلي لأمريكا الشمالية (فورت نيلسون)", + "America\/Fortaleza": "توقيت برازيليا (فورتاليزا)", + "America\/Glace_Bay": "توقيت الأطلسي (جلاس باي)", + "America\/Godthab": "توقيت غرب غرينلاند (غودثاب)", + "America\/Goose_Bay": "توقيت الأطلسي (جوس باي)", + "America\/Grand_Turk": "التوقيت الشرقي لأمريكا الشمالية (غراند ترك)", + "America\/Grenada": "توقيت الأطلسي (غرينادا)", + "America\/Guadeloupe": "توقيت الأطلسي (غوادلوب)", + "America\/Guatemala": "التوقيت المركزي لأمريكا الشمالية (غواتيمالا)", + "America\/Guayaquil": "توقيت الإكوادور (غواياكويل)", + "America\/Guyana": "توقيت غيانا (غيانا)", + "America\/Halifax": "توقيت الأطلسي (هاليفاكس)", + "America\/Havana": "توقيت كوبا (هافانا)", + "America\/Hermosillo": "توقيت المحيط الهادي للمكسيك (هيرموسيلو)", + "America\/Indiana\/Knox": "التوقيت المركزي لأمريكا الشمالية (كونكس)", + "America\/Indiana\/Marengo": "التوقيت الشرقي لأمريكا الشمالية (مارنجو)", + "America\/Indiana\/Petersburg": "التوقيت الشرقي لأمريكا الشمالية (بيترسبرغ)", + "America\/Indiana\/Tell_City": "التوقيت المركزي لأمريكا الشمالية (مدينة تل، إنديانا)", + "America\/Indiana\/Vevay": "التوقيت الشرقي لأمريكا الشمالية (فيفاي)", + "America\/Indiana\/Vincennes": "التوقيت الشرقي لأمريكا الشمالية (فينسينس)", + "America\/Indiana\/Winamac": "التوقيت الشرقي لأمريكا الشمالية (ويناماك)", + "America\/Indianapolis": "التوقيت الشرقي لأمريكا الشمالية (إنديانابوليس)", + "America\/Inuvik": "التوقيت الجبلي لأمريكا الشمالية (اينوفيك)", + "America\/Iqaluit": "التوقيت الشرقي لأمريكا الشمالية (اكويلت)", + "America\/Jamaica": "التوقيت الشرقي لأمريكا الشمالية (جامايكا)", + "America\/Jujuy": "توقيت الأرجنتين (جوجو)", + "America\/Juneau": "توقيت ألاسكا (جوني)", + "America\/Kentucky\/Monticello": "التوقيت الشرقي لأمريكا الشمالية (مونتيسيلو)", + "America\/Kralendijk": "توقيت الأطلسي (كرالنديك)", + "America\/La_Paz": "توقيت بوليفيا (لا باز)", + "America\/Lima": "توقيت بيرو (ليما)", + "America\/Los_Angeles": "توقيت المحيط الهادي (لوس انجلوس)", + "America\/Louisville": "التوقيت الشرقي لأمريكا الشمالية (لويس فيل)", + "America\/Lower_Princes": "توقيت الأطلسي (حي الأمير السفلي)", + "America\/Maceio": "توقيت برازيليا (ماشيو)", + "America\/Managua": "التوقيت المركزي لأمريكا الشمالية (ماناغوا)", + "America\/Manaus": "توقيت الأمازون (ماناوس)", + "America\/Marigot": "توقيت الأطلسي (ماريغوت)", + "America\/Martinique": "توقيت الأطلسي (المارتينيك)", + "America\/Matamoros": "التوقيت المركزي لأمريكا الشمالية (ماتاموروس)", + "America\/Mazatlan": "توقيت المحيط الهادي للمكسيك (مازاتلان)", + "America\/Mendoza": "توقيت الأرجنتين (ميندوزا)", + "America\/Menominee": "التوقيت المركزي لأمريكا الشمالية (مينوميني)", + "America\/Merida": "التوقيت المركزي لأمريكا الشمالية (ميريدا)", + "America\/Metlakatla": "توقيت ألاسكا (ميتلاكاتلا)", + "America\/Mexico_City": "التوقيت المركزي لأمريكا الشمالية (مكسيكو سيتي)", + "America\/Miquelon": "توقيت سانت بيير وميكولون (مكويلون)", + "America\/Moncton": "توقيت الأطلسي (وينكتون)", + "America\/Monterrey": "التوقيت المركزي لأمريكا الشمالية (مونتيري)", + "America\/Montevideo": "توقيت أوروغواي (مونتفيديو)", + "America\/Montserrat": "توقيت الأطلسي (مونتسيرات)", + "America\/Nassau": "التوقيت الشرقي لأمريكا الشمالية (ناسو)", + "America\/New_York": "التوقيت الشرقي لأمريكا الشمالية (نيويورك)", + "America\/Nipigon": "التوقيت الشرقي لأمريكا الشمالية (نيبيجون)", + "America\/Nome": "توقيت ألاسكا (نوم)", + "America\/Noronha": "توقيت فيرناندو دي نورونها (نوروناه)", + "America\/North_Dakota\/Beulah": "التوقيت المركزي لأمريكا الشمالية (بيولا، داكوتا الشمالية)", + "America\/North_Dakota\/Center": "التوقيت المركزي لأمريكا الشمالية (سنتر)", + "America\/North_Dakota\/New_Salem": "التوقيت المركزي لأمريكا الشمالية (نيو ساليم)", + "America\/Ojinaga": "التوقيت الجبلي لأمريكا الشمالية (أوجيناجا)", + "America\/Panama": "التوقيت الشرقي لأمريكا الشمالية (بنما)", + "America\/Pangnirtung": "التوقيت الشرقي لأمريكا الشمالية (بانجينتينج)", + "America\/Paramaribo": "توقيت سورينام (باراماريبو)", + "America\/Phoenix": "التوقيت الجبلي لأمريكا الشمالية (فينكس)", + "America\/Port-au-Prince": "التوقيت الشرقي لأمريكا الشمالية (بورت أو برنس)", + "America\/Port_of_Spain": "توقيت الأطلسي (بورت أوف سبين)", + "America\/Porto_Velho": "توقيت الأمازون (بورتو فيلو)", + "America\/Puerto_Rico": "توقيت الأطلسي (بورتوريكو)", + "America\/Punta_Arenas": "توقيت تشيلي (بونتا أريناز)", + "America\/Rainy_River": "التوقيت المركزي لأمريكا الشمالية (راني ريفر)", + "America\/Rankin_Inlet": "التوقيت المركزي لأمريكا الشمالية (رانكن انلت)", + "America\/Recife": "توقيت برازيليا (ريسيف)", + "America\/Regina": "التوقيت المركزي لأمريكا الشمالية (ريجينا)", + "America\/Resolute": "التوقيت المركزي لأمريكا الشمالية (ريزولوت)", + "America\/Santa_Isabel": "توقيت شمال غرب المكسيك (سانتا إيزابيل)", + "America\/Santarem": "توقيت برازيليا (سانتاريم)", + "America\/Santiago": "توقيت تشيلي (سانتياغو)", + "America\/Santo_Domingo": "توقيت الأطلسي (سانتو دومينغو)", + "America\/Sao_Paulo": "توقيت برازيليا (ساو باولو)", + "America\/Scoresbysund": "توقيت شرق غرينلاند (سكورسبيسند)", + "America\/Sitka": "توقيت ألاسكا (سيتكا)", + "America\/St_Barthelemy": "توقيت الأطلسي (سانت بارتيليمي)", + "America\/St_Johns": "توقيت نيوفاوندلاند (سانت جونس)", + "America\/St_Kitts": "توقيت الأطلسي (سانت كيتس)", + "America\/St_Lucia": "توقيت الأطلسي (سانت لوشيا)", + "America\/St_Thomas": "توقيت الأطلسي (سانت توماس)", + "America\/St_Vincent": "توقيت الأطلسي (سانت فنسنت)", + "America\/Swift_Current": "التوقيت المركزي لأمريكا الشمالية (سوفت كارنت)", + "America\/Tegucigalpa": "التوقيت المركزي لأمريكا الشمالية (تيغوسيغالبا)", + "America\/Thule": "توقيت الأطلسي (ثيل)", + "America\/Thunder_Bay": "التوقيت الشرقي لأمريكا الشمالية (ثندر باي)", + "America\/Tijuana": "توقيت المحيط الهادي (تيخوانا)", + "America\/Toronto": "التوقيت الشرقي لأمريكا الشمالية (تورونتو)", + "America\/Tortola": "توقيت الأطلسي (تورتولا)", + "America\/Vancouver": "توقيت المحيط الهادي (فانكوفر)", + "America\/Whitehorse": "توقيت المحيط الهادي (وايت هورس)", + "America\/Winnipeg": "التوقيت المركزي لأمريكا الشمالية (وينيبيج)", + "America\/Yakutat": "توقيت ألاسكا (ياكوتات)", + "America\/Yellowknife": "التوقيت الجبلي لأمريكا الشمالية (يلونيف)", + "Antarctica\/Casey": "توقيت غرب أستراليا (كاساي)", + "Antarctica\/Davis": "توقيت دافيز (دافيز)", + "Antarctica\/DumontDUrville": "توقيت دي مونت دو روفيل (دي مونت دو روفيل)", + "Antarctica\/Macquarie": "توقيت ماكواري (ماكواري)", + "Antarctica\/Mawson": "توقيت ماوسون (ماوسون)", + "Antarctica\/McMurdo": "توقيت نيوزيلندا (ماك موردو)", + "Antarctica\/Palmer": "توقيت تشيلي (بالمير)", + "Antarctica\/Rothera": "توقيت روثيرا (روثيرا)", + "Antarctica\/Syowa": "توقيت سايووا (سايووا)", + "Antarctica\/Troll": "توقيت غرينتش (ترول)", + "Antarctica\/Vostok": "توقيت فوستوك (فوستوك)", + "Arctic\/Longyearbyen": "توقيت وسط أوروبا (لونجيربين)", + "Asia\/Aden": "التوقيت العربي (عدن)", + "Asia\/Almaty": "توقيت شرق كازاخستان (ألماتي)", + "Asia\/Amman": "توقيت شرق أوروبا (عمان)", + "Asia\/Anadyr": "توقيت أنادير (أندير)", + "Asia\/Aqtau": "توقيت غرب كازاخستان (أكتاو)", + "Asia\/Aqtobe": "توقيت غرب كازاخستان (أكتوب)", + "Asia\/Ashgabat": "توقيت تركمانستان (عشق آباد)", + "Asia\/Atyrau": "توقيت غرب كازاخستان (أتيراو)", + "Asia\/Baghdad": "التوقيت العربي (بغداد)", + "Asia\/Bahrain": "التوقيت العربي (البحرين)", + "Asia\/Baku": "توقيت أذربيجان (باكو)", + "Asia\/Bangkok": "توقيت الهند الصينية (بانكوك)", + "Asia\/Beirut": "توقيت شرق أوروبا (بيروت)", + "Asia\/Bishkek": "توقيت قيرغيزستان (بشكيك)", + "Asia\/Brunei": "توقيت بروناي (بروناي)", + "Asia\/Calcutta": "توقيت الهند (كالكتا)", + "Asia\/Chita": "توقيت ياكوتسك (تشيتا)", + "Asia\/Choibalsan": "توقيت شويبالسان (تشوبالسان)", + "Asia\/Colombo": "توقيت الهند (كولومبو)", + "Asia\/Damascus": "توقيت شرق أوروبا (دمشق)", + "Asia\/Dhaka": "توقيت بنغلاديش (دكا)", + "Asia\/Dili": "توقيت تيمور الشرقية (ديلي)", + "Asia\/Dubai": "توقيت الخليج (دبي)", + "Asia\/Dushanbe": "توقيت طاجكستان (دوشانبي)", + "Asia\/Famagusta": "توقيت شرق أوروبا (فاماغوستا)", + "Asia\/Gaza": "توقيت شرق أوروبا (غزة)", + "Asia\/Hebron": "توقيت شرق أوروبا (هيبرون (مدينة الخليل))", + "Asia\/Hong_Kong": "توقيت هونغ كونغ (هونغ كونغ)", + "Asia\/Hovd": "توقيت هوفد (هوفد)", + "Asia\/Irkutsk": "توقيت إركوتسك (ايركيتسك)", + "Asia\/Jakarta": "توقيت غرب إندونيسيا (جاكرتا)", + "Asia\/Jayapura": "توقيت شرق إندونيسيا (جايابيورا)", + "Asia\/Jerusalem": "توقيت إسرائيل (القدس)", + "Asia\/Kabul": "توقيت أفغانستان (كابول)", + "Asia\/Kamchatka": "توقيت كامشاتكا (كامتشاتكا)", + "Asia\/Karachi": "توقيت باكستان (كراتشي)", + "Asia\/Katmandu": "توقيت نيبال (كاتماندو)", + "Asia\/Khandyga": "توقيت ياكوتسك (خانديجا)", + "Asia\/Krasnoyarsk": "توقيت كراسنويارسك (كراسنويارسك)", + "Asia\/Kuala_Lumpur": "توقيت ماليزيا (كوالا لامبور)", + "Asia\/Kuching": "توقيت ماليزيا (كيشينج)", + "Asia\/Kuwait": "التوقيت العربي (الكويت)", + "Asia\/Macau": "توقيت الصين (ماكاو)", + "Asia\/Magadan": "توقيت ماغادان (مجادن)", + "Asia\/Makassar": "توقيت وسط إندونيسيا (ماكسار)", + "Asia\/Manila": "توقيت الفيلبين (مانيلا)", + "Asia\/Muscat": "توقيت الخليج (مسقط)", + "Asia\/Nicosia": "توقيت شرق أوروبا (نيقوسيا)", + "Asia\/Novokuznetsk": "توقيت كراسنويارسك (نوفوكوزنتسك)", + "Asia\/Novosibirsk": "توقيت نوفوسيبيرسك (نوفوسبيرسك)", + "Asia\/Omsk": "توقيت أومسك (أومسك)", + "Asia\/Oral": "توقيت غرب كازاخستان (أورال)", + "Asia\/Phnom_Penh": "توقيت الهند الصينية (بنوم بنه)", + "Asia\/Pontianak": "توقيت غرب إندونيسيا (بونتيانك)", + "Asia\/Pyongyang": "توقيت كوريا (بيونغ يانغ)", + "Asia\/Qatar": "التوقيت العربي (قطر)", + "Asia\/Qostanay": "توقيت شرق كازاخستان (قوستاناي)", + "Asia\/Qyzylorda": "توقيت غرب كازاخستان (كيزيلوردا)", + "Asia\/Rangoon": "توقيت ميانمار (رانغون)", + "Asia\/Riyadh": "التوقيت العربي (الرياض)", + "Asia\/Saigon": "توقيت الهند الصينية (مدينة هو تشي منة)", + "Asia\/Sakhalin": "توقيت ساخالين (سكالين)", + "Asia\/Samarkand": "توقيت أوزبكستان (سمرقند)", + "Asia\/Seoul": "توقيت كوريا (سول)", + "Asia\/Shanghai": "توقيت الصين (شنغهاي)", + "Asia\/Singapore": "توقيت سنغافورة (سنغافورة)", + "Asia\/Srednekolymsk": "توقيت ماغادان (سريدنكوليمسك)", + "Asia\/Taipei": "توقيت تايبيه (تايبيه)", + "Asia\/Tashkent": "توقيت أوزبكستان (طشقند)", + "Asia\/Tbilisi": "توقيت جورجيا (تبليسي)", + "Asia\/Tehran": "توقيت إيران (طهران)", + "Asia\/Thimphu": "توقيت بوتان (تيمفو)", + "Asia\/Tokyo": "توقيت اليابان (طوكيو)", + "Asia\/Ulaanbaatar": "توقيت أولان باتور (آلانباتار)", + "Asia\/Ust-Nera": "توقيت فلاديفوستوك (أوست نيرا)", + "Asia\/Vientiane": "توقيت الهند الصينية (فيانتيان)", + "Asia\/Vladivostok": "توقيت فلاديفوستوك (فلاديفوستك)", + "Asia\/Yakutsk": "توقيت ياكوتسك (ياكتسك)", + "Asia\/Yekaterinburg": "توقيت يكاترينبورغ (يكاترنبيرج)", + "Asia\/Yerevan": "توقيت أرمينيا (يريفان)", + "Atlantic\/Azores": "توقيت أزورس (أزورس)", + "Atlantic\/Bermuda": "توقيت الأطلسي (برمودا)", + "Atlantic\/Canary": "توقيت غرب أوروبا (كناري)", + "Atlantic\/Cape_Verde": "توقيت الرأس الأخضر (الرأس الأخضر)", + "Atlantic\/Faeroe": "توقيت غرب أوروبا (فارو)", + "Atlantic\/Madeira": "توقيت غرب أوروبا (ماديرا)", + "Atlantic\/Reykjavik": "توقيت غرينتش (ريكيافيك)", + "Atlantic\/South_Georgia": "توقيت جنوب جورجيا (جورجيا الجنوبية)", + "Atlantic\/St_Helena": "توقيت غرينتش (سانت هيلينا)", + "Atlantic\/Stanley": "توقيت جزر فوكلاند (استانلي)", + "Australia\/Adelaide": "توقيت وسط أستراليا (أديليد)", + "Australia\/Brisbane": "توقيت شرق أستراليا (برسيبان)", + "Australia\/Broken_Hill": "توقيت وسط أستراليا (بروكن هيل)", + "Australia\/Currie": "توقيت شرق أستراليا (كوري)", + "Australia\/Darwin": "توقيت وسط أستراليا (دارون)", + "Australia\/Eucla": "توقيت غرب وسط أستراليا (أوكلا)", + "Australia\/Hobart": "توقيت شرق أستراليا (هوبارت)", + "Australia\/Lindeman": "توقيت شرق أستراليا (ليندمان)", + "Australia\/Lord_Howe": "توقيت لورد هاو (لورد هاو)", + "Australia\/Melbourne": "توقيت شرق أستراليا (ميلبورن)", + "Australia\/Perth": "توقيت غرب أستراليا (برثا)", + "Australia\/Sydney": "توقيت شرق أستراليا (سيدني)", + "CST6CDT": "التوقيت المركزي لأمريكا الشمالية", + "EST5EDT": "التوقيت الشرقي لأمريكا الشمالية", + "Etc\/GMT": "توقيت غرينتش", + "Etc\/UTC": "التوقيت العالمي المنسق", + "Europe\/Amsterdam": "توقيت وسط أوروبا (أمستردام)", + "Europe\/Andorra": "توقيت وسط أوروبا (أندورا)", + "Europe\/Astrakhan": "توقيت موسكو (أستراخان)", + "Europe\/Athens": "توقيت شرق أوروبا (أثينا)", + "Europe\/Belgrade": "توقيت وسط أوروبا (بلغراد)", + "Europe\/Berlin": "توقيت وسط أوروبا (برلين)", + "Europe\/Bratislava": "توقيت وسط أوروبا (براتيسلافا)", + "Europe\/Brussels": "توقيت وسط أوروبا (بروكسل)", + "Europe\/Bucharest": "توقيت شرق أوروبا (بوخارست)", + "Europe\/Budapest": "توقيت وسط أوروبا (بودابست)", + "Europe\/Busingen": "توقيت وسط أوروبا (بوسنغن)", + "Europe\/Chisinau": "توقيت شرق أوروبا (تشيسيناو)", + "Europe\/Copenhagen": "توقيت وسط أوروبا (كوبنهاغن)", + "Europe\/Dublin": "توقيت غرينتش (دبلن)", + "Europe\/Gibraltar": "توقيت وسط أوروبا (جبل طارق)", + "Europe\/Guernsey": "توقيت غرينتش (غيرنزي)", + "Europe\/Helsinki": "توقيت شرق أوروبا (هلسنكي)", + "Europe\/Isle_of_Man": "توقيت غرينتش (جزيرة مان)", + "Europe\/Jersey": "توقيت غرينتش (جيرسي)", + "Europe\/Kaliningrad": "توقيت شرق أوروبا (كالينجراد)", + "Europe\/Kiev": "توقيت شرق أوروبا (كييف)", + "Europe\/Lisbon": "توقيت غرب أوروبا (لشبونة)", + "Europe\/Ljubljana": "توقيت وسط أوروبا (ليوبليانا)", + "Europe\/London": "توقيت غرينتش (لندن)", + "Europe\/Luxembourg": "توقيت وسط أوروبا (لوكسمبورغ)", + "Europe\/Madrid": "توقيت وسط أوروبا (مدريد)", + "Europe\/Malta": "توقيت وسط أوروبا (مالطة)", + "Europe\/Mariehamn": "توقيت شرق أوروبا (ماريهامن)", + "Europe\/Minsk": "توقيت موسكو (مينسك)", + "Europe\/Monaco": "توقيت وسط أوروبا (موناكو)", + "Europe\/Moscow": "توقيت موسكو (موسكو)", + "Europe\/Oslo": "توقيت وسط أوروبا (أوسلو)", + "Europe\/Paris": "توقيت وسط أوروبا (باريس)", + "Europe\/Podgorica": "توقيت وسط أوروبا (بودغوريكا)", + "Europe\/Prague": "توقيت وسط أوروبا (براغ)", + "Europe\/Riga": "توقيت شرق أوروبا (ريغا)", + "Europe\/Rome": "توقيت وسط أوروبا (روما)", + "Europe\/Samara": "توقيت سامارا (سمراء)", + "Europe\/San_Marino": "توقيت وسط أوروبا (سان مارينو)", + "Europe\/Sarajevo": "توقيت وسط أوروبا (سراييفو)", + "Europe\/Saratov": "توقيت موسكو (ساراتوف)", + "Europe\/Simferopol": "توقيت موسكو (سيمفروبول)", + "Europe\/Skopje": "توقيت وسط أوروبا (سكوبي)", + "Europe\/Sofia": "توقيت شرق أوروبا (صوفيا)", + "Europe\/Stockholm": "توقيت وسط أوروبا (ستوكهولم)", + "Europe\/Tallinn": "توقيت شرق أوروبا (تالين)", + "Europe\/Tirane": "توقيت وسط أوروبا (تيرانا)", + "Europe\/Ulyanovsk": "توقيت موسكو (أوليانوفسك)", + "Europe\/Uzhgorod": "توقيت شرق أوروبا (أوزجرود)", + "Europe\/Vaduz": "توقيت وسط أوروبا (فادوز)", + "Europe\/Vatican": "توقيت وسط أوروبا (الفاتيكان)", + "Europe\/Vienna": "توقيت وسط أوروبا (فيينا)", + "Europe\/Vilnius": "توقيت شرق أوروبا (فيلنيوس)", + "Europe\/Volgograd": "توقيت فولغوغراد (فولوجراد)", + "Europe\/Warsaw": "توقيت وسط أوروبا (وارسو)", + "Europe\/Zagreb": "توقيت وسط أوروبا (زغرب)", + "Europe\/Zaporozhye": "توقيت شرق أوروبا (زابوروزي)", + "Europe\/Zurich": "توقيت وسط أوروبا (زيورخ)", + "Indian\/Antananarivo": "توقيت شرق أفريقيا (أنتاناناريفو)", + "Indian\/Chagos": "توقيت المحيط الهندي (تشاغوس)", + "Indian\/Christmas": "توقيت جزر الكريسماس (كريسماس)", + "Indian\/Cocos": "توقيت جزر كوكوس (كوكوس)", + "Indian\/Comoro": "توقيت شرق أفريقيا (جزر القمر)", + "Indian\/Kerguelen": "توقيت المقاطعات الفرنسية الجنوبية والأنتارتيكية (كيرغويلين)", + "Indian\/Mahe": "توقيت سيشل (ماهي)", + "Indian\/Maldives": "توقيت جزر المالديف (المالديف)", + "Indian\/Mauritius": "توقيت موريشيوس (موريشيوس)", + "Indian\/Mayotte": "توقيت شرق أفريقيا (مايوت)", + "Indian\/Reunion": "توقيت روينيون (ريونيون)", + "MST7MDT": "التوقيت الجبلي لأمريكا الشمالية", + "PST8PDT": "توقيت المحيط الهادي", + "Pacific\/Apia": "توقيت آبيا (أبيا)", + "Pacific\/Auckland": "توقيت نيوزيلندا (أوكلاند)", + "Pacific\/Bougainville": "توقيت بابوا غينيا الجديدة (بوغانفيل)", + "Pacific\/Chatham": "توقيت تشاتام (تشاثام)", + "Pacific\/Easter": "توقيت جزيرة استر (استر)", + "Pacific\/Efate": "توقيت فانواتو (إيفات)", + "Pacific\/Enderbury": "توقيت جزر فينكس (اندربيرج)", + "Pacific\/Fakaofo": "توقيت توكيلاو (فاكاوفو)", + "Pacific\/Fiji": "توقيت فيجي (فيجي)", + "Pacific\/Funafuti": "توقيت توفالو (فونافوتي)", + "Pacific\/Galapagos": "توقيت غلاباغوس (جلاباجوس)", + "Pacific\/Gambier": "توقيت جامبير (جامبير)", + "Pacific\/Guadalcanal": "توقيت جزر سليمان (غوادالكانال)", + "Pacific\/Guam": "توقيت تشامورو (غوام)", + "Pacific\/Honolulu": "توقيت هاواي ألوتيان (هونولولو)", + "Pacific\/Johnston": "توقيت هاواي ألوتيان (جونستون)", + "Pacific\/Kiritimati": "توقيت جزر لاين (كيريتي ماتي)", + "Pacific\/Kosrae": "توقيت كوسرا (كوسرا)", + "Pacific\/Kwajalein": "توقيت جزر مارشال (كواجالين)", + "Pacific\/Majuro": "توقيت جزر مارشال (ماجورو)", + "Pacific\/Marquesas": "توقيت ماركيساس (ماركيساس)", + "Pacific\/Midway": "توقيت ساموا (ميدواي)", + "Pacific\/Nauru": "توقيت ناورو (ناورو)", + "Pacific\/Niue": "توقيت نيوي (نيوي)", + "Pacific\/Norfolk": "توقيت جزيرة نورفولك (نورفولك)", + "Pacific\/Noumea": "توقيت كاليدونيا الجديدة (نوميا)", + "Pacific\/Pago_Pago": "توقيت ساموا (باغو باغو)", + "Pacific\/Palau": "توقيت بالاو (بالاو)", + "Pacific\/Pitcairn": "توقيت بيتكيرن (بيتكيرن)", + "Pacific\/Ponape": "توقيت بونابي (باناب)", + "Pacific\/Port_Moresby": "توقيت بابوا غينيا الجديدة (بور مورسبي)", + "Pacific\/Rarotonga": "توقيت جزر كووك (راروتونغا)", + "Pacific\/Saipan": "توقيت تشامورو (سايبان)", + "Pacific\/Tahiti": "توقيت تاهيتي (تاهيتي)", + "Pacific\/Tarawa": "توقيت جزر جيلبرت (تاراوا)", + "Pacific\/Tongatapu": "توقيت تونغا (تونغاتابو)", + "Pacific\/Truk": "توقيت شوك (ترك)", + "Pacific\/Wake": "توقيت جزيرة ويك (واك)", + "Pacific\/Wallis": "توقيت واليس و فوتونا (واليس)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/as.json b/src/Symfony/Component/Intl/Resources/data/timezones/as.json new file mode 100644 index 0000000000000..6debd39fd9834 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/as.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "গ্ৰীণউইচ মান সময় (আবিডজান)", + "Africa\/Accra": "গ্ৰীণউইচ মান সময় (এক্ৰা)", + "Africa\/Addis_Ababa": "পূব আফ্ৰিকাৰ সময় (আদ্দিছ আবাবা)", + "Africa\/Algiers": "মধ্য ইউৰোপীয় সময় (আলজিয়াৰ্ছ)", + "Africa\/Asmera": "পূব আফ্ৰিকাৰ সময় (আস্মাৰা)", + "Africa\/Bamako": "গ্ৰীণউইচ মান সময় (বামাকো)", + "Africa\/Bangui": "পশ্চিম আফ্ৰিকাৰ সময় (বাংগুই)", + "Africa\/Banjul": "গ্ৰীণউইচ মান সময় (বেঞ্জুল)", + "Africa\/Bissau": "গ্ৰীণউইচ মান সময় (বিছাউ)", + "Africa\/Blantyre": "মধ্য আফ্ৰিকাৰ সময় (ব্লাণ্টায়াৰ)", + "Africa\/Brazzaville": "পশ্চিম আফ্ৰিকাৰ সময় (ব্ৰাজাভিলে)", + "Africa\/Bujumbura": "মধ্য আফ্ৰিকাৰ সময় (বুজুম্বুৰা)", + "Africa\/Cairo": "প্ৰাচ্য ইউৰোপীয় সময় (কাইৰো)", + "Africa\/Casablanca": "পাশ্চাত্য ইউৰোপীয় সময় (কাছাব্লাংকা)", + "Africa\/Ceuta": "মধ্য ইউৰোপীয় সময় (চেউটা)", + "Africa\/Conakry": "গ্ৰীণউইচ মান সময় (কোনাক্ৰী)", + "Africa\/Dakar": "গ্ৰীণউইচ মান সময় (ডাকাৰ)", + "Africa\/Dar_es_Salaam": "পূব আফ্ৰিকাৰ সময় (ডাৰ এছ ছালাম)", + "Africa\/Djibouti": "পূব আফ্ৰিকাৰ সময় (জিবুটি)", + "Africa\/Douala": "পশ্চিম আফ্ৰিকাৰ সময় (ডুৱালা)", + "Africa\/El_Aaiun": "পাশ্চাত্য ইউৰোপীয় সময় (এল আইয়ুন)", + "Africa\/Freetown": "গ্ৰীণউইচ মান সময় (ফ্ৰিটাউন)", + "Africa\/Gaborone": "মধ্য আফ্ৰিকাৰ সময় (গাবোৰোণ)", + "Africa\/Harare": "মধ্য আফ্ৰিকাৰ সময় (হাৰাৰে)", + "Africa\/Johannesburg": "দক্ষিণ আফ্ৰিকাৰ মান সময় (জোহান্সবাৰ্গ)", + "Africa\/Juba": "পূব আফ্ৰিকাৰ সময় (জুবা)", + "Africa\/Kampala": "পূব আফ্ৰিকাৰ সময় (কাম্পালা)", + "Africa\/Khartoum": "মধ্য আফ্ৰিকাৰ সময় (খাৰ্টুম)", + "Africa\/Kigali": "মধ্য আফ্ৰিকাৰ সময় (কিগালী)", + "Africa\/Kinshasa": "পশ্চিম আফ্ৰিকাৰ সময় (কিংচাছা)", + "Africa\/Lagos": "পশ্চিম আফ্ৰিকাৰ সময় (লাগোছ)", + "Africa\/Libreville": "পশ্চিম আফ্ৰিকাৰ সময় (লিব্ৰিভিলে)", + "Africa\/Lome": "গ্ৰীণউইচ মান সময় (লোম)", + "Africa\/Luanda": "পশ্চিম আফ্ৰিকাৰ সময় (লুৱাণ্ডা)", + "Africa\/Lubumbashi": "মধ্য আফ্ৰিকাৰ সময় (লুবুম্বাচি)", + "Africa\/Lusaka": "মধ্য আফ্ৰিকাৰ সময় (লুছাকা)", + "Africa\/Malabo": "পশ্চিম আফ্ৰিকাৰ সময় (মালাবো)", + "Africa\/Maputo": "মধ্য আফ্ৰিকাৰ সময় (মাপুটো)", + "Africa\/Maseru": "দক্ষিণ আফ্ৰিকাৰ মান সময় (মাছেৰু)", + "Africa\/Mbabane": "দক্ষিণ আফ্ৰিকাৰ মান সময় (এম্বাবেন)", + "Africa\/Mogadishu": "পূব আফ্ৰিকাৰ সময় (মোগাদিচু)", + "Africa\/Monrovia": "গ্ৰীণউইচ মান সময় (মোনৰোভিয়া)", + "Africa\/Nairobi": "পূব আফ্ৰিকাৰ সময় (নাইৰোবি)", + "Africa\/Ndjamena": "পশ্চিম আফ্ৰিকাৰ সময় (নেদজামেনা)", + "Africa\/Niamey": "পশ্চিম আফ্ৰিকাৰ সময় (নিয়ামী)", + "Africa\/Nouakchott": "গ্ৰীণউইচ মান সময় (নৌআকচোট)", + "Africa\/Ouagadougou": "গ্ৰীণউইচ মান সময় (ঔগাডোগো)", + "Africa\/Porto-Novo": "পশ্চিম আফ্ৰিকাৰ সময় (পোৰ্টো-নোভো)", + "Africa\/Sao_Tome": "গ্ৰীণউইচ মান সময় (চাও টোমে)", + "Africa\/Tripoli": "প্ৰাচ্য ইউৰোপীয় সময় (ত্ৰিপোলি)", + "Africa\/Tunis": "মধ্য ইউৰোপীয় সময় (টুনিছ)", + "Africa\/Windhoek": "মধ্য আফ্ৰিকাৰ সময় (ৱিণ্ডহোক)", + "America\/Adak": "হাৱাই-এলিউশ্বনৰ সময় (আডাক)", + "America\/Anchorage": "আলাস্কাৰ সময় (এংকোৰেজ)", + "America\/Anguilla": "আটলাণ্টিক সময় (এনগুইলা)", + "America\/Antigua": "আটলাণ্টিক সময় (এণ্টিগুৱা)", + "America\/Araguaina": "ব্ৰাজিলিয়াৰ সময় (আৰাগায়েনা)", + "America\/Argentina\/La_Rioja": "আৰ্জেণ্টিনাৰ সময় (লা ৰিওজা)", + "America\/Argentina\/Rio_Gallegos": "আৰ্জেণ্টিনাৰ সময় (ৰিঅ’ গালেগোছ)", + "America\/Argentina\/Salta": "আৰ্জেণ্টিনাৰ সময় (ছাল্টা)", + "America\/Argentina\/San_Juan": "আৰ্জেণ্টিনাৰ সময় (ছেন জুৱান)", + "America\/Argentina\/San_Luis": "পাশ্চাত্য আৰ্জেণ্টিনাৰ সময় (ছেন লুইচ)", + "America\/Argentina\/Tucuman": "আৰ্জেণ্টিনাৰ সময় (টুকুমন)", + "America\/Argentina\/Ushuaia": "আৰ্জেণ্টিনাৰ সময় (উচুআইয়া)", + "America\/Aruba": "আটলাণ্টিক সময় (আৰুবা)", + "America\/Asuncion": "পাৰাগুৱেৰ সময় (আছুনচিয়ন)", + "America\/Bahia": "ব্ৰাজিলিয়াৰ সময় (বাহিয়া)", + "America\/Bahia_Banderas": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (বাহিয়া বান্দেৰাছ)", + "America\/Barbados": "আটলাণ্টিক সময় (বাৰ্বাডোচ)", + "America\/Belem": "ব্ৰাজিলিয়াৰ সময় (বেলেম)", + "America\/Belize": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (বেলিজ)", + "America\/Blanc-Sablon": "আটলাণ্টিক সময় (ব্লাংক-ছেবলোন)", + "America\/Boa_Vista": "আমাজনৰ সময় (বোৱা ভিষ্টা)", + "America\/Bogota": "কলম্বিয়াৰ সময় (বোগোটা)", + "America\/Boise": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ব’ইজে)", + "America\/Buenos_Aires": "আৰ্জেণ্টিনাৰ সময় (বুনছ আয়াৰ্ছ)", + "America\/Cambridge_Bay": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (কেমব্ৰিজ উপসাগৰ)", + "America\/Campo_Grande": "আমাজনৰ সময় (কেম্পো গ্ৰেণ্ডে)", + "America\/Cancun": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (কেনকুন)", + "America\/Caracas": "ভেনিজুৱেলাৰ সময় (কাৰাকাছ)", + "America\/Catamarca": "আৰ্জেণ্টিনাৰ সময় (কাটামাৰ্কা)", + "America\/Cayenne": "ফ্ৰান্স গয়ানাৰ সময় (কেয়েন)", + "America\/Cayman": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (কেইমেন)", + "America\/Chicago": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (চিকাগো)", + "America\/Chihuahua": "মেক্সিকোৰ প্ৰশান্ত সময় (চিহুআহুৱা)", + "America\/Coral_Harbour": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (আটিকোকান)", + "America\/Cordoba": "আৰ্জেণ্টিনাৰ সময় (কোৰ্ডোবা)", + "America\/Costa_Rica": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (কোষ্টা ৰিকা)", + "America\/Creston": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ক্ৰেষ্টন)", + "America\/Cuiaba": "আমাজনৰ সময় (কুইআবা)", + "America\/Curacao": "আটলাণ্টিক সময় (কুৰাকাও)", + "America\/Danmarkshavn": "গ্ৰীণউইচ মান সময় (ডেনমাৰ্কশ্বন)", + "America\/Dawson": "উত্তৰ আমেৰিকাৰ প্ৰশান্ত সময় (ডাওছন)", + "America\/Dawson_Creek": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ডাওছন ক্ৰীক)", + "America\/Denver": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ডেনভাৰ)", + "America\/Detroit": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (ডেট্ৰোইট)", + "America\/Dominica": "আটলাণ্টিক সময় (ডমিনিকা)", + "America\/Edmonton": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (এডমণ্টন)", + "America\/El_Salvador": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (এল ছেলভেড’ৰ)", + "America\/Fort_Nelson": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ফ’ৰ্ট নেলছন)", + "America\/Fortaleza": "ব্ৰাজিলিয়াৰ সময় (ফোৰ্টালেজা)", + "America\/Glace_Bay": "আটলাণ্টিক সময় (গ্লেচ উপসাগৰ)", + "America\/Godthab": "পশ্চিম গ্ৰীণলেণ্ডৰ সময় (নুক)", + "America\/Goose_Bay": "আটলাণ্টিক সময় (গুছ উপসাগৰ)", + "America\/Grand_Turk": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (গ্ৰেণ্ড টাৰ্ক)", + "America\/Grenada": "আটলাণ্টিক সময় (গ্ৰেনাডা)", + "America\/Guadeloupe": "আটলাণ্টিক সময় (গুৱাডেলুপ)", + "America\/Guatemala": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (গুৱাটেমালা)", + "America\/Guayaquil": "ইকুৱেডৰৰ সময় (গায়াকুইল)", + "America\/Guyana": "গায়ানাৰ সময় (গায়ানা)", + "America\/Halifax": "আটলাণ্টিক সময় (হেলিফেক্স)", + "America\/Havana": "কিউবাৰ সময় (হাভানা)", + "America\/Hermosillo": "মেক্সিকোৰ প্ৰশান্ত সময় (হাৰ্মোছিল্লো)", + "America\/Indiana\/Knox": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (নক্স, ইণ্ডিয়ানা)", + "America\/Indiana\/Marengo": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (মাৰেংগো, ইণ্ডিয়ানা)", + "America\/Indiana\/Petersburg": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (পিটাৰ্ছবাৰ্গ, ইণ্ডিয়ানা)", + "America\/Indiana\/Tell_City": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (টেল চিটী, ইণ্ডিয়ানা)", + "America\/Indiana\/Vevay": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (ভেভে, ইণ্ডিয়ানা)", + "America\/Indiana\/Vincennes": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (ভিনচেনেছ, ইণ্ডিয়ানা)", + "America\/Indiana\/Winamac": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (উইনামেক, ইণ্ডিয়ানা)", + "America\/Indianapolis": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (ইণ্ডিয়ানাপ’লিছ)", + "America\/Inuvik": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ইনুভিক)", + "America\/Iqaluit": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (ইকালুইট)", + "America\/Jamaica": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (জামাইকা)", + "America\/Jujuy": "আৰ্জেণ্টিনাৰ সময় (জুজুই)", + "America\/Juneau": "আলাস্কাৰ সময় (জুনেউ)", + "America\/Kentucky\/Monticello": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (মণ্টিচেলো, কেণ্টুকী)", + "America\/Kralendijk": "আটলাণ্টিক সময় (ক্ৰালেণ্ডিজিক)", + "America\/La_Paz": "বলিভিয়াৰ সময় (লা পাজ)", + "America\/Lima": "পেৰুৰ সময় (লিমা)", + "America\/Los_Angeles": "উত্তৰ আমেৰিকাৰ প্ৰশান্ত সময় (লছ এঞ্জেলছ্)", + "America\/Louisville": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (লুইছভিলে)", + "America\/Lower_Princes": "আটলাণ্টিক সময় (ল’ৱাৰ প্ৰিন্সেছ কোৱাৰ্টাৰ)", + "America\/Maceio": "ব্ৰাজিলিয়াৰ সময় (মেচিও)", + "America\/Managua": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (মানাগুৱা)", + "America\/Manaus": "আমাজনৰ সময় (মানাছ)", + "America\/Marigot": "আটলাণ্টিক সময় (মেৰিগোট)", + "America\/Martinique": "আটলাণ্টিক সময় (মাৰ্টিনিক)", + "America\/Matamoros": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (মাটামোৰোছ)", + "America\/Mazatlan": "মেক্সিকোৰ প্ৰশান্ত সময় (মাজাট্‌লান)", + "America\/Mendoza": "আৰ্জেণ্টিনাৰ সময় (মেণ্ডোজা)", + "America\/Menominee": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (মেনোমিনী)", + "America\/Merida": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (মেৰিডা)", + "America\/Metlakatla": "আলাস্কাৰ সময় (মেটলাকাট্‌লা)", + "America\/Mexico_City": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (মেক্সিকো চিটী)", + "America\/Miquelon": "ছেইণ্ট পিয়েৰে আৰু মিকিউৱেলনৰ সময় (মিকিউৱেলন)", + "America\/Moncton": "আটলাণ্টিক সময় (মন্‌কটন)", + "America\/Monterrey": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (মণ্টেৰেৰী)", + "America\/Montevideo": "উৰুগুৱেৰ সময় (মণ্টেভিডিঅ’)", + "America\/Montserrat": "আটলাণ্টিক সময় (মণ্টছেৰাট)", + "America\/Nassau": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (নাছাউ)", + "America\/New_York": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (নিউ ইয়ৰ্ক)", + "America\/Nipigon": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (নিপিগন)", + "America\/Nome": "আলাস্কাৰ সময় (নোম)", + "America\/Noronha": "ফাৰ্নাণ্ডো ডে নোৰোন্‌হাৰ সময় (নোৰোন্‌হা)", + "America\/North_Dakota\/Beulah": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (বেউলাহ, উত্তৰ ডাকোটা)", + "America\/North_Dakota\/Center": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (চেণ্টাৰ, উত্তৰ ডাকোটা)", + "America\/North_Dakota\/New_Salem": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (নিউ ছালেম, উত্তৰ ডাকোটা)", + "America\/Ojinaga": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (অ’জিনাগা)", + "America\/Panama": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (পানামা)", + "America\/Pangnirtung": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (পাংনিৰ্টুংগ)", + "America\/Paramaribo": "ছুৰিনামৰ সময় (পাৰামাৰিবো)", + "America\/Phoenix": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (ফিনিক্স)", + "America\/Port-au-Prince": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (প’ৰ্ট-ঔ-প্ৰিন্স)", + "America\/Port_of_Spain": "আটলাণ্টিক সময় (প’ৰ্ট অৱ স্পেইন)", + "America\/Porto_Velho": "আমাজনৰ সময় (পোৰ্টো ভেল্‌হো)", + "America\/Puerto_Rico": "আটলাণ্টিক সময় (পুৱেৰ্টো ৰিকো)", + "America\/Punta_Arenas": "চিলিৰ সময় (পুণ্টা এৰিনাছ)", + "America\/Rainy_River": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (ৰেইনী নদী)", + "America\/Rankin_Inlet": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (ৰেংকিন ইনলেট)", + "America\/Recife": "ব্ৰাজিলিয়াৰ সময় (ৰেচাইফ)", + "America\/Regina": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (ৰেজিনা)", + "America\/Resolute": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (ৰিজ’লিউট)", + "America\/Santa_Isabel": "উত্তৰ-পশ্চিম মেক্সিকোৰ সময় (Santa Isabel)", + "America\/Santarem": "ব্ৰাজিলিয়াৰ সময় (ছেণ্টাৰেম)", + "America\/Santiago": "চিলিৰ সময় (ছেণ্টিয়াগো)", + "America\/Santo_Domingo": "আটলাণ্টিক সময় (ছাণ্টো ডোমিংগো)", + "America\/Sao_Paulo": "ব্ৰাজিলিয়াৰ সময় (ছাও পাউলো)", + "America\/Scoresbysund": "পূব গ্ৰীণলেণ্ডৰ সময় (ইটোকোৰ্টোৰমিট)", + "America\/Sitka": "আলাস্কাৰ সময় (ছিট্‌‌কা)", + "America\/St_Barthelemy": "আটলাণ্টিক সময় (ছেইণ্ট বাৰ্থলেমে)", + "America\/St_Johns": "নিউফাউণ্ডলেণ্ডৰ সময় (ছেইণ্ট জনচ্)", + "America\/St_Kitts": "আটলাণ্টিক সময় (ছেইণ্ট কিটছ)", + "America\/St_Lucia": "আটলাণ্টিক সময় (ছেইণ্ট লুচিয়া)", + "America\/St_Thomas": "আটলাণ্টিক সময় (ছেইণ্ট থমাছ)", + "America\/St_Vincent": "আটলাণ্টিক সময় (ছেইণ্ট ভিনচেণ্ট)", + "America\/Swift_Current": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (ছুইফ্ট কাৰেণ্ট)", + "America\/Tegucigalpa": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (টেগুচিগাল্পা)", + "America\/Thule": "আটলাণ্টিক সময় (থ্যুলে)", + "America\/Thunder_Bay": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (থাণ্ডাৰ উপসাগৰ)", + "America\/Tijuana": "উত্তৰ আমেৰিকাৰ প্ৰশান্ত সময় (তিজুৱানা)", + "America\/Toronto": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময় (ট’ৰ’ণ্টো)", + "America\/Tortola": "আটলাণ্টিক সময় (টোৰ্টোলা)", + "America\/Vancouver": "উত্তৰ আমেৰিকাৰ প্ৰশান্ত সময় (ভেনকুভেৰ)", + "America\/Whitehorse": "উত্তৰ আমেৰিকাৰ প্ৰশান্ত সময় (হোৱাইটহৰ্চ)", + "America\/Winnipeg": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময় (ৱিনিপেগ)", + "America\/Yakutat": "আলাস্কাৰ সময় (য়াকুটাট)", + "America\/Yellowknife": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময় (য়েল্লোনাইফ)", + "Antarctica\/Casey": "পাশ্চাত্য অষ্ট্ৰেলিয়াৰ সময় (কেছী)", + "Antarctica\/Davis": "ডেভিছৰ সময় (ডেভিছ)", + "Antarctica\/DumontDUrville": "ডুমোণ্ট-ডি আৰ্ভিলৰ সময় (ডুমোণ্ট ডি আৰ্ভিলৰ)", + "Antarctica\/Macquarie": "মেক্‌কুৱেৰী দ্বীপৰ সময় (মেক্‌কুৱেৰী)", + "Antarctica\/Mawson": "মাউছনৰ সময় (মাউছন)", + "Antarctica\/McMurdo": "নিউজিলেণ্ডৰ সময় (মেকমুৰ্ডু)", + "Antarctica\/Palmer": "চিলিৰ সময় (পামৰ)", + "Antarctica\/Rothera": "ৰোথেৰাৰ সময় (ৰোথেৰা)", + "Antarctica\/Syowa": "স্বোৱা সময় (স্বোৱা)", + "Antarctica\/Troll": "গ্ৰীণউইচ মান সময় (ট্ৰোল)", + "Antarctica\/Vostok": "ভোষ্টকৰ সময় (ভোষ্টক)", + "Arctic\/Longyearbyen": "মধ্য ইউৰোপীয় সময় (লংগেইৰবায়েন)", + "Asia\/Aden": "আৰবীয় সময় (আদেন)", + "Asia\/Almaty": "পূব কাজাখস্তানৰ সময় (আলমাটি)", + "Asia\/Amman": "প্ৰাচ্য ইউৰোপীয় সময় (আম্মান)", + "Asia\/Aqtau": "পশ্চিম কাজাখস্তানৰ সময় (এক্যোট্যাও)", + "Asia\/Aqtobe": "পশ্চিম কাজাখস্তানৰ সময় (এক্যোটব)", + "Asia\/Ashgabat": "তুৰ্কমেনিস্তানৰ সময় (আশ্ব্গা‌বাট)", + "Asia\/Atyrau": "পশ্চিম কাজাখস্তানৰ সময় (এটৰাউ)", + "Asia\/Baghdad": "আৰবীয় সময় (বাগদাদ)", + "Asia\/Bahrain": "আৰবীয় সময় (বাহৰেইন)", + "Asia\/Baku": "আজেৰবাইজানৰ সময় (বাকু)", + "Asia\/Bangkok": "ইণ্ডোচাইনাৰ সময় (বেংকক)", + "Asia\/Beirut": "প্ৰাচ্য ইউৰোপীয় সময় (বেইৰুট)", + "Asia\/Bishkek": "কিৰ্গিজস্তানৰ সময় (বিশ্ব্‌কেক)", + "Asia\/Brunei": "ব্ৰুনেই ডাৰুছালেমৰ সময় (ব্ৰুনেই)", + "Asia\/Calcutta": "ভাৰতীয় মান সময় (কলকাতা)", + "Asia\/Chita": "য়াকুত্স্কৰ সময় (চিটা)", + "Asia\/Choibalsan": "কোইবাল্ছনৰ সময় (কোইবাল্ছন)", + "Asia\/Colombo": "ভাৰতীয় মান সময় (কলম্বো)", + "Asia\/Damascus": "প্ৰাচ্য ইউৰোপীয় সময় (ডামাস্কাছ)", + "Asia\/Dhaka": "বাংলাদেশৰ সময় (ঢাকা)", + "Asia\/Dili": "পূব তিমোৰৰ সময় (ডিলি)", + "Asia\/Dubai": "উপসাগৰীয় মান সময় (ডুবাই)", + "Asia\/Dushanbe": "তাজিকিস্তানৰ সময় (ডুছানবে)", + "Asia\/Famagusta": "প্ৰাচ্য ইউৰোপীয় সময় (ফামাগুস্তা)", + "Asia\/Gaza": "প্ৰাচ্য ইউৰোপীয় সময় (গাজা)", + "Asia\/Hebron": "প্ৰাচ্য ইউৰোপীয় সময় (হেব্ৰোন)", + "Asia\/Hong_Kong": "হং কঙৰ সময় (হং কং)", + "Asia\/Hovd": "হোভ্‌ডৰ সময় (হোভ্‌ড)", + "Asia\/Irkutsk": "ইৰ্কুটস্কৰ সময় (ইৰ্কুত্স্ক)", + "Asia\/Jakarta": "পাশ্চাত্য ইণ্ডোনেচিয়াৰ সময় (জাকাৰ্টা)", + "Asia\/Jayapura": "প্ৰাচ্য ইণ্ডোনেচিয়াৰ সময় (জায়াপুৰা)", + "Asia\/Jerusalem": "ইজৰাইলৰ সময় (জেৰুজালেম)", + "Asia\/Kabul": "আফগানিস্তানৰ সময় (কাবুল)", + "Asia\/Karachi": "পাকিস্তানৰ সময় (কৰাচী)", + "Asia\/Katmandu": "নেপালৰ সময় (কাঠমাণ্ডু)", + "Asia\/Khandyga": "য়াকুত্স্কৰ সময় (খাণ্ডিগা)", + "Asia\/Krasnoyarsk": "ক্ৰাছনোয়াৰ্স্কৰ সময় (ক্ৰাছনোয়াৰ্স্ক)", + "Asia\/Kuala_Lumpur": "মালয়েচিয়াৰ সময় (কুৱালালুমপুৰ)", + "Asia\/Kuching": "মালয়েচিয়াৰ সময় (কুচিং)", + "Asia\/Kuwait": "আৰবীয় সময় (কুৱেইট)", + "Asia\/Macau": "চীনৰ সময় (মাকাও)", + "Asia\/Magadan": "মাগাদানৰ সময় (মাগাদান)", + "Asia\/Makassar": "মধ্য ইণ্ডোনেচিয়াৰ সময় (মাকাছাৰ)", + "Asia\/Manila": "ফিলিপাইনৰ সময় (মানিলা)", + "Asia\/Muscat": "উপসাগৰীয় মান সময় (মুস্কেট)", + "Asia\/Nicosia": "প্ৰাচ্য ইউৰোপীয় সময় (নিকোছিয়া)", + "Asia\/Novokuznetsk": "ক্ৰাছনোয়াৰ্স্কৰ সময় (নোভোকুজনেত্স্ক)", + "Asia\/Novosibirsk": "নভোছিবিৰ্স্কৰ সময় (নোভোছিবিৰ্স্ক)", + "Asia\/Omsk": "ওমস্কৰ সময় (ওমস্ক)", + "Asia\/Oral": "পশ্চিম কাজাখস্তানৰ সময় (অ’ৰেল)", + "Asia\/Phnom_Penh": "ইণ্ডোচাইনাৰ সময় (নোম পেন্‌হ)", + "Asia\/Pontianak": "পাশ্চাত্য ইণ্ডোনেচিয়াৰ সময় (পোণ্টিয়াংক)", + "Asia\/Pyongyang": "কোৰিয়াৰ সময় (প্যংয়াং)", + "Asia\/Qatar": "আৰবীয় সময় (কাটাৰ)", + "Asia\/Qostanay": "পূব কাজাখস্তানৰ সময় (ক’ষ্টেনী)", + "Asia\/Qyzylorda": "পশ্চিম কাজাখস্তানৰ সময় (কেজিলোৰ্ডা)", + "Asia\/Rangoon": "ম্যানমাৰৰ সময় (য়াঙোন)", + "Asia\/Riyadh": "আৰবীয় সময় (ৰিয়াধ)", + "Asia\/Saigon": "ইণ্ডোচাইনাৰ সময় (হো চি মিন চিটী)", + "Asia\/Sakhalin": "ছাখালিনৰ সময় (ছাখালিন)", + "Asia\/Samarkand": "উজবেকিস্তানৰ সময় (ছামাৰকাণ্ড)", + "Asia\/Seoul": "কোৰিয়াৰ সময় (ছিউল)", + "Asia\/Shanghai": "চীনৰ সময় (ছাংহাই)", + "Asia\/Singapore": "ছিংগাপুৰৰ মান সময় (ছিংগাপুৰ)", + "Asia\/Srednekolymsk": "মাগাদানৰ সময় (স্ৰেডনিকোলিমস্ক)", + "Asia\/Taipei": "টাইপেইৰ সময় (টাইপেই)", + "Asia\/Tashkent": "উজবেকিস্তানৰ সময় (তাছকেণ্ট)", + "Asia\/Tbilisi": "জৰ্জিয়াৰ সময় (টিবলিচি)", + "Asia\/Tehran": "ইৰানৰ সময় (তেহৰান)", + "Asia\/Thimphu": "ভুটানৰ সময় (থিম্ফু)", + "Asia\/Tokyo": "জাপানৰ সময় (টকিঅ’)", + "Asia\/Ulaanbaatar": "উলানবাটাৰৰ সময় (উলানবাটাৰ)", + "Asia\/Ust-Nera": "ভ্লাডিভোষ্টোকৰ সময় (উষ্ট-নেৰা)", + "Asia\/Vientiane": "ইণ্ডোচাইনাৰ সময় (ভিয়েণ্টিয়ান)", + "Asia\/Vladivostok": "ভ্লাডিভোষ্টোকৰ সময় (ভ্লাডিভোষ্টক)", + "Asia\/Yakutsk": "য়াকুত্স্কৰ সময় (য়াকুত্স্ক)", + "Asia\/Yekaterinburg": "য়েকাটেৰিণবাৰ্গৰ সময় (য়েকাটেৰিণবাৰ্গ)", + "Asia\/Yerevan": "আৰ্মেনিয়াৰ সময় (য়েৰেভান)", + "Atlantic\/Azores": "আজোৰেছ সময় (এজোৰেছ)", + "Atlantic\/Bermuda": "আটলাণ্টিক সময় (বাৰ্মুডা)", + "Atlantic\/Canary": "পাশ্চাত্য ইউৰোপীয় সময় (কেনেৰী)", + "Atlantic\/Cape_Verde": "কেপ ভাৰ্দেৰ সময় (কেপ ভাৰ্দে)", + "Atlantic\/Faeroe": "পাশ্চাত্য ইউৰোপীয় সময় (ফাৰো)", + "Atlantic\/Madeira": "পাশ্চাত্য ইউৰোপীয় সময় (মাডেৰা)", + "Atlantic\/Reykjavik": "গ্ৰীণউইচ মান সময় (ৰেইকজাভিক)", + "Atlantic\/South_Georgia": "দক্ষিণ জৰ্জিয়াৰ সময় (দক্ষিণ জৰ্জিয়া)", + "Atlantic\/St_Helena": "গ্ৰীণউইচ মান সময় (ছেইণ্ট হেলেনা)", + "Atlantic\/Stanley": "ফকলেণ্ড দ্বীপপুঞ্জৰ সময় (ষ্টেন্‌লী)", + "Australia\/Adelaide": "মধ্য অষ্ট্ৰেলিয়াৰ সময় (এডিলেইড)", + "Australia\/Brisbane": "প্ৰাচ্য অষ্ট্ৰেলিয়াৰ সময় (ব্ৰিচবেন)", + "Australia\/Broken_Hill": "মধ্য অষ্ট্ৰেলিয়াৰ সময় (ব্ৰোকেন হিল)", + "Australia\/Currie": "প্ৰাচ্য অষ্ট্ৰেলিয়াৰ সময় (ক্যুৰি)", + "Australia\/Darwin": "মধ্য অষ্ট্ৰেলিয়াৰ সময় (ডাৰউইন)", + "Australia\/Eucla": "অষ্ট্ৰেলিয়াৰ কেন্দ্ৰীয় পাশ্চাত্য সময় (ইউক্লা)", + "Australia\/Hobart": "প্ৰাচ্য অষ্ট্ৰেলিয়াৰ সময় (হোবাৰ্ট)", + "Australia\/Lindeman": "প্ৰাচ্য অষ্ট্ৰেলিয়াৰ সময় (লিণ্ডমান)", + "Australia\/Lord_Howe": "লৰ্ড হাওৰ সময় (লৰ্ড হাও)", + "Australia\/Melbourne": "প্ৰাচ্য অষ্ট্ৰেলিয়াৰ সময় (মেলব’ৰ্ণ)", + "Australia\/Perth": "পাশ্চাত্য অষ্ট্ৰেলিয়াৰ সময় (পাৰ্থ)", + "Australia\/Sydney": "প্ৰাচ্য অষ্ট্ৰেলিয়াৰ সময় (চিডনী)", + "CST6CDT": "উত্তৰ আমেৰিকাৰ কেন্দ্ৰীয় সময়", + "EST5EDT": "উত্তৰ আমেৰিকাৰ প্ৰাচ্য সময়", + "Etc\/GMT": "গ্ৰীণউইচ মান সময়", + "Etc\/UTC": "সমন্বিত সাৰ্বজনীন সময়", + "Europe\/Amsterdam": "মধ্য ইউৰোপীয় সময় (আমষ্টাৰডাম)", + "Europe\/Andorra": "মধ্য ইউৰোপীয় সময় (আন্দোৰা)", + "Europe\/Astrakhan": "মস্কোৰ সময় (আষ্ট্ৰাখান)", + "Europe\/Athens": "প্ৰাচ্য ইউৰোপীয় সময় (এথেন্স)", + "Europe\/Belgrade": "মধ্য ইউৰোপীয় সময় (বেলগ্ৰেড)", + "Europe\/Berlin": "মধ্য ইউৰোপীয় সময় (বাৰ্লিন)", + "Europe\/Bratislava": "মধ্য ইউৰোপীয় সময় (ব্ৰাটিছলাভা)", + "Europe\/Brussels": "মধ্য ইউৰোপীয় সময় (ব্ৰুছলেছ)", + "Europe\/Bucharest": "প্ৰাচ্য ইউৰোপীয় সময় (বুচাৰেষ্ট)", + "Europe\/Budapest": "মধ্য ইউৰোপীয় সময় (বুডাপেষ্ট)", + "Europe\/Busingen": "মধ্য ইউৰোপীয় সময় (বুছিনজেন)", + "Europe\/Chisinau": "প্ৰাচ্য ইউৰোপীয় সময় (চিছিনাউ)", + "Europe\/Copenhagen": "মধ্য ইউৰোপীয় সময় (কোপেনহাগেন)", + "Europe\/Dublin": "গ্ৰীণউইচ মান সময় (ডাবলিন)", + "Europe\/Gibraltar": "মধ্য ইউৰোপীয় সময় (জিব্ৰাল্টৰ)", + "Europe\/Guernsey": "গ্ৰীণউইচ মান সময় (গোৰেনচি)", + "Europe\/Helsinki": "প্ৰাচ্য ইউৰোপীয় সময় (হেলছিংকি)", + "Europe\/Isle_of_Man": "গ্ৰীণউইচ মান সময় (আইল অফ মেন)", + "Europe\/Jersey": "গ্ৰীণউইচ মান সময় (জাৰ্চি)", + "Europe\/Kaliningrad": "প্ৰাচ্য ইউৰোপীয় সময় (কালিনিনগ্ৰাড)", + "Europe\/Kiev": "প্ৰাচ্য ইউৰোপীয় সময় (কিভ)", + "Europe\/Lisbon": "পাশ্চাত্য ইউৰোপীয় সময় (লিছবন)", + "Europe\/Ljubljana": "মধ্য ইউৰোপীয় সময় (ল্যুবেলজানা)", + "Europe\/London": "গ্ৰীণউইচ মান সময় (লণ্ডন)", + "Europe\/Luxembourg": "মধ্য ইউৰোপীয় সময় (লাক্সেমবাৰ্গ)", + "Europe\/Madrid": "মধ্য ইউৰোপীয় সময় (মাদ্ৰিদ)", + "Europe\/Malta": "মধ্য ইউৰোপীয় সময় (মাল্টা)", + "Europe\/Mariehamn": "প্ৰাচ্য ইউৰোপীয় সময় (মাৰিয়াহেম)", + "Europe\/Minsk": "মস্কোৰ সময় (মিংস্ক)", + "Europe\/Monaco": "মধ্য ইউৰোপীয় সময় (মোনাকো)", + "Europe\/Moscow": "মস্কোৰ সময় (মস্কো)", + "Europe\/Oslo": "মধ্য ইউৰোপীয় সময় (ওস্লো)", + "Europe\/Paris": "মধ্য ইউৰোপীয় সময় (পেৰিছ)", + "Europe\/Podgorica": "মধ্য ইউৰোপীয় সময় (পোডগোৰিকা)", + "Europe\/Prague": "মধ্য ইউৰোপীয় সময় (প্ৰাগ)", + "Europe\/Riga": "প্ৰাচ্য ইউৰোপীয় সময় (ৰিগা)", + "Europe\/Rome": "মধ্য ইউৰোপীয় সময় (ৰোম)", + "Europe\/San_Marino": "মধ্য ইউৰোপীয় সময় (চান মাৰিনো)", + "Europe\/Sarajevo": "মধ্য ইউৰোপীয় সময় (ছাৰাজেভো)", + "Europe\/Saratov": "মস্কোৰ সময় (ছাৰাটোভ)", + "Europe\/Simferopol": "মস্কোৰ সময় (ছিম্ফেৰোপোল)", + "Europe\/Skopje": "মধ্য ইউৰোপীয় সময় (স্কোপ্জে)", + "Europe\/Sofia": "প্ৰাচ্য ইউৰোপীয় সময় (ছোফিয়া)", + "Europe\/Stockholm": "মধ্য ইউৰোপীয় সময় (ষ্টকহোম)", + "Europe\/Tallinn": "প্ৰাচ্য ইউৰোপীয় সময় (তেলিন)", + "Europe\/Tirane": "মধ্য ইউৰোপীয় সময় (টাইৰেন)", + "Europe\/Ulyanovsk": "মস্কোৰ সময় (উল্যানোভ্‌স্ক)", + "Europe\/Uzhgorod": "প্ৰাচ্য ইউৰোপীয় সময় (উজ্গোৰোড)", + "Europe\/Vaduz": "মধ্য ইউৰোপীয় সময় (ভাদুজ)", + "Europe\/Vatican": "মধ্য ইউৰোপীয় সময় (ভেটিকান)", + "Europe\/Vienna": "মধ্য ইউৰোপীয় সময় (ভিয়েনা)", + "Europe\/Vilnius": "প্ৰাচ্য ইউৰোপীয় সময় (ভিলনিয়াছ)", + "Europe\/Volgograd": "ভোল্গোগ্ৰাডৰ সময় (ভোল্গোগ্ৰাড)", + "Europe\/Warsaw": "মধ্য ইউৰোপীয় সময় (ৱাৰছাও)", + "Europe\/Zagreb": "মধ্য ইউৰোপীয় সময় (জাগ্ৰেব)", + "Europe\/Zaporozhye": "প্ৰাচ্য ইউৰোপীয় সময় (জাপোৰোজাই)", + "Europe\/Zurich": "মধ্য ইউৰোপীয় সময় (জুৰিখ)", + "Indian\/Antananarivo": "পূব আফ্ৰিকাৰ সময় (এণ্টানানাৰিভো)", + "Indian\/Chagos": "ভাৰত মহাসাগৰীয় সময় (চাগোছ)", + "Indian\/Christmas": "খ্ৰীষ্টমাছ দ্বীপৰ সময় (খ্ৰীষ্টমাছ)", + "Indian\/Cocos": "কোকোছ দ্বীপপুঞ্জৰ সময় (কোকোছ)", + "Indian\/Comoro": "পূব আফ্ৰিকাৰ সময় (কোমোৰো)", + "Indian\/Kerguelen": "দক্ষিণ ফ্ৰান্স আৰু এণ্টাৰ্কটিক সময় (কেৰগুলেন)", + "Indian\/Mahe": "ছিচিলিছৰ সময় (মাহে)", + "Indian\/Maldives": "মালদ্বীপৰ সময় (মালদ্বীপ)", + "Indian\/Mauritius": "মৰিছাছৰ সময় (মৰিছাছ)", + "Indian\/Mayotte": "পূব আফ্ৰিকাৰ সময় (মায়োট্টে)", + "Indian\/Reunion": "ৰিইউনিয়নৰ সময় (ৰিইউনিয়ন)", + "MST7MDT": "উত্তৰ আমেৰিকাৰ পৰ্ব্বতীয় সময়", + "PST8PDT": "উত্তৰ আমেৰিকাৰ প্ৰশান্ত সময়", + "Pacific\/Apia": "আপিয়াৰ সময় (আপিয়া)", + "Pacific\/Auckland": "নিউজিলেণ্ডৰ সময় (অকলেণ্ড)", + "Pacific\/Bougainville": "পাপুৱা নিউ গিনিৰ সময় (বোগেইনভিলে)", + "Pacific\/Chatham": "চাথামৰ সময় (চাথাম)", + "Pacific\/Easter": "ইষ্টাৰ দ্বীপৰ সময় (ইষ্টাৰ)", + "Pacific\/Efate": "ভানাটুৰ সময় (এফেট)", + "Pacific\/Enderbury": "ফিনিক্স দ্বীপপুঞ্জৰ সময় (এণ্ডৰবাৰী)", + "Pacific\/Fakaofo": "টোকেলাউৰ সময় (ফাকাওফো)", + "Pacific\/Fiji": "ফিজিৰ সময় (ফিজি)", + "Pacific\/Funafuti": "টুভালাউৰ সময় (ফুনাফুটি)", + "Pacific\/Galapagos": "গালাপাগোছৰ সময় (গালাপাগোছ)", + "Pacific\/Gambier": "গেম্বিয়াৰ সময় (গেম্বিয়াৰ)", + "Pacific\/Guadalcanal": "চোলোমোন দ্বীপপুঞ্জৰ সময় (গুৱাডলকানাল)", + "Pacific\/Guam": "চামোৰোৰ মান সময় (গুৱাম)", + "Pacific\/Honolulu": "হাৱাই-এলিউশ্বনৰ সময় (Honolulu)", + "Pacific\/Johnston": "হাৱাই-এলিউশ্বনৰ সময় (জনষ্টন)", + "Pacific\/Kiritimati": "লাইন দ্বীপপুঞ্জৰ সময় (কিৰিটিমাটি)", + "Pacific\/Kosrae": "কোছৰায়ে সময় (কোছৰায়ে)", + "Pacific\/Kwajalein": "মাৰ্শ্বাল দ্বীপপুঞ্জৰ সময় (কোৱাজালিন)", + "Pacific\/Majuro": "মাৰ্শ্বাল দ্বীপপুঞ্জৰ সময় (মাজুৰো)", + "Pacific\/Marquesas": "মাৰ্কছেছৰ সময় (মাৰ্কছাছ)", + "Pacific\/Midway": "ছামোৱাৰ সময় (মিডৱে)", + "Pacific\/Nauru": "নাউৰুৰ সময় (নাৰু)", + "Pacific\/Niue": "নিয়ুৰ সময় (নিয়ো)", + "Pacific\/Norfolk": "ন’ৰফ’ক দ্বীপৰ সময় (ন’ৰফ’ক)", + "Pacific\/Noumea": "নিউ কেলিডোনিয়াৰ সময় (নউমিয়া)", + "Pacific\/Pago_Pago": "ছামোৱাৰ সময় (পাগো পাগো)", + "Pacific\/Palau": "পালাউৰ সময় (পালাউ)", + "Pacific\/Pitcairn": "পিটকেইৰ্ণৰ সময় (পিটকেইৰ্ণ)", + "Pacific\/Ponape": "পোনাপেৰ সময় (পোনপেই)", + "Pacific\/Port_Moresby": "পাপুৱা নিউ গিনিৰ সময় (প’ৰ্ট মোৰেছ্‌বি)", + "Pacific\/Rarotonga": "কুক দ্বীপপুঞ্জৰ সময় (ৰাৰোটোঙ্গা)", + "Pacific\/Saipan": "চামোৰোৰ মান সময় (ছাইপান)", + "Pacific\/Tahiti": "তাহিতিৰ সময় (তাহিতি)", + "Pacific\/Tarawa": "গিলবাৰ্ট দ্বীপপুঞ্জৰ সময় (তাৰাৱা)", + "Pacific\/Tongatapu": "টংগাৰ সময় (টংগাটাপু)", + "Pacific\/Truk": "চ্চুকৰ সময় (চ্চুক)", + "Pacific\/Wake": "ৱেক দ্বীপৰ সময় (ৱেক)", + "Pacific\/Wallis": "ৱালিছ আৰু ফুটুনাৰ সময় (ৱালিছ)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/az.json b/src/Symfony/Component/Intl/Resources/data/timezones/az.json new file mode 100644 index 0000000000000..3c2c288c2e02e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/az.json @@ -0,0 +1,429 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Qrinviç Orta Vaxtı (Abican)", + "Africa\/Accra": "Qrinviç Orta Vaxtı (Akkra)", + "Africa\/Addis_Ababa": "Şərqi Afrika Vaxtı (Əddis Əbəbə)", + "Africa\/Algiers": "Mərkəzi Avropa Vaxtı (Əlcəzair)", + "Africa\/Asmera": "Şərqi Afrika Vaxtı (Əsmərə)", + "Africa\/Bamako": "Qrinviç Orta Vaxtı (Bamako)", + "Africa\/Bangui": "Qərbi Afrika Vaxtı (Banqui)", + "Africa\/Banjul": "Qrinviç Orta Vaxtı (Bancul)", + "Africa\/Bissau": "Qrinviç Orta Vaxtı (Bissau)", + "Africa\/Blantyre": "Mərkəzi Afrika Vaxtı (Blantir)", + "Africa\/Brazzaville": "Qərbi Afrika Vaxtı (Brazzavil)", + "Africa\/Bujumbura": "Mərkəzi Afrika Vaxtı (Bujumbura)", + "Africa\/Cairo": "Şərqi Avropa Vaxtı (Qahirə)", + "Africa\/Casablanca": "Qərbi Avropa Vaxtı (Kasablanka)", + "Africa\/Ceuta": "Mərkəzi Avropa Vaxtı (Seuta)", + "Africa\/Conakry": "Qrinviç Orta Vaxtı (Konakri)", + "Africa\/Dakar": "Qrinviç Orta Vaxtı (Dakar)", + "Africa\/Dar_es_Salaam": "Şərqi Afrika Vaxtı (Dar es Salam)", + "Africa\/Djibouti": "Şərqi Afrika Vaxtı (Cibuti)", + "Africa\/Douala": "Qərbi Afrika Vaxtı (Duala)", + "Africa\/El_Aaiun": "Qərbi Avropa Vaxtı (Əl Əyun)", + "Africa\/Freetown": "Qrinviç Orta Vaxtı (Fritaun)", + "Africa\/Gaborone": "Mərkəzi Afrika Vaxtı (Qaboron)", + "Africa\/Harare": "Mərkəzi Afrika Vaxtı (Harare)", + "Africa\/Johannesburg": "Cənubi Afrika Vaxtı (Yohanesburq)", + "Africa\/Juba": "Şərqi Afrika Vaxtı (Juba)", + "Africa\/Kampala": "Şərqi Afrika Vaxtı (Kampala)", + "Africa\/Khartoum": "Mərkəzi Afrika Vaxtı (Xartum)", + "Africa\/Kigali": "Mərkəzi Afrika Vaxtı (Kiqali)", + "Africa\/Kinshasa": "Qərbi Afrika Vaxtı (Kinşasa)", + "Africa\/Lagos": "Qərbi Afrika Vaxtı (Laqos)", + "Africa\/Libreville": "Qərbi Afrika Vaxtı (Librevil)", + "Africa\/Lome": "Qrinviç Orta Vaxtı (Lome)", + "Africa\/Luanda": "Qərbi Afrika Vaxtı (Luanda)", + "Africa\/Lubumbashi": "Mərkəzi Afrika Vaxtı (Lubumbaşi)", + "Africa\/Lusaka": "Mərkəzi Afrika Vaxtı (Lusaka)", + "Africa\/Malabo": "Qərbi Afrika Vaxtı (Malabo)", + "Africa\/Maputo": "Mərkəzi Afrika Vaxtı (Maputo)", + "Africa\/Maseru": "Cənubi Afrika Vaxtı (Maseru)", + "Africa\/Mbabane": "Cənubi Afrika Vaxtı (Mbabane)", + "Africa\/Mogadishu": "Şərqi Afrika Vaxtı (Moqadişu)", + "Africa\/Monrovia": "Qrinviç Orta Vaxtı (Monrovia)", + "Africa\/Nairobi": "Şərqi Afrika Vaxtı (Nairobi)", + "Africa\/Ndjamena": "Qərbi Afrika Vaxtı (Ncamena)", + "Africa\/Niamey": "Qərbi Afrika Vaxtı (Niamey)", + "Africa\/Nouakchott": "Qrinviç Orta Vaxtı (Nouakşot)", + "Africa\/Ouagadougou": "Qrinviç Orta Vaxtı (Uqaduqu)", + "Africa\/Porto-Novo": "Qərbi Afrika Vaxtı (Porto-Novo)", + "Africa\/Sao_Tome": "Qrinviç Orta Vaxtı (San Tom)", + "Africa\/Tripoli": "Şərqi Avropa Vaxtı (Tripoli)", + "Africa\/Tunis": "Mərkəzi Avropa Vaxtı (Tunis)", + "Africa\/Windhoek": "Mərkəzi Afrika Vaxtı (Vindhuk)", + "America\/Adak": "Havay-Aleut Vaxtı (Adak)", + "America\/Anchorage": "Alyaska Vaxtı (Ankorac)", + "America\/Anguilla": "Atlantik Vaxt (Angilya)", + "America\/Antigua": "Atlantik Vaxt (Antiqua)", + "America\/Araguaina": "Braziliya Vaxtı (Araguayna)", + "America\/Argentina\/La_Rioja": "Argentina Vaxtı (Rioxa)", + "America\/Argentina\/Rio_Gallegos": "Argentina Vaxtı (Rio Qalyeqos)", + "America\/Argentina\/Salta": "Argentina Vaxtı (Salta)", + "America\/Argentina\/San_Juan": "Argentina Vaxtı (San Xuan)", + "America\/Argentina\/San_Luis": "Qərbi Argentina Vaxtı (San Luis)", + "America\/Argentina\/Tucuman": "Argentina Vaxtı (Tukuman)", + "America\/Argentina\/Ushuaia": "Argentina Vaxtı (Uşuaya)", + "America\/Aruba": "Atlantik Vaxt (Aruba)", + "America\/Asuncion": "Paraqvay Vaxtı (Asunsion)", + "America\/Bahia": "Braziliya Vaxtı (Bahiya)", + "America\/Bahia_Banderas": "Şimali Mərkəzi Amerika Vaxtı (Bahia Banderas)", + "America\/Barbados": "Atlantik Vaxt (Barbados)", + "America\/Belem": "Braziliya Vaxtı (Belem)", + "America\/Belize": "Şimali Mərkəzi Amerika Vaxtı (Beliz)", + "America\/Blanc-Sablon": "Atlantik Vaxt (Blank-Sablon)", + "America\/Boa_Vista": "Amazon Vaxtı (Boa Vista)", + "America\/Bogota": "Kolumbiya Vaxtı (Boqota)", + "America\/Boise": "Şimali Dağlıq Amerika Vaxtı (Boyse)", + "America\/Buenos_Aires": "Argentina Vaxtı (Buenos Ayres)", + "America\/Cambridge_Bay": "Şimali Dağlıq Amerika Vaxtı (Kembric Körfəzi)", + "America\/Campo_Grande": "Amazon Vaxtı (Kampo Qrande)", + "America\/Cancun": "Şimali Şərqi Amerika Vaxtı (Kankun)", + "America\/Caracas": "Venesuela Vaxtı (Karakas)", + "America\/Catamarca": "Argentina Vaxtı (Katamarka)", + "America\/Cayenne": "Fransız Qvianası Vaxtı (Kayen)", + "America\/Cayman": "Şimali Şərqi Amerika Vaxtı (Kayman)", + "America\/Chicago": "Şimali Mərkəzi Amerika Vaxtı (Cikaqo)", + "America\/Chihuahua": "Meksika Sakit Okean Vaxtı (Çihuahua)", + "America\/Coral_Harbour": "Şimali Şərqi Amerika Vaxtı (Atikokan)", + "America\/Cordoba": "Argentina Vaxtı (Kordoba)", + "America\/Costa_Rica": "Şimali Mərkəzi Amerika Vaxtı (Kosta Rika)", + "America\/Creston": "Şimali Dağlıq Amerika Vaxtı (Kreston)", + "America\/Cuiaba": "Amazon Vaxtı (Kuyaba)", + "America\/Curacao": "Atlantik Vaxt (Kurasao)", + "America\/Danmarkshavn": "Qrinviç Orta Vaxtı (Danmarkşavn)", + "America\/Dawson": "Şimali Amerika Sakit Okean Vaxtı (Douson)", + "America\/Dawson_Creek": "Şimali Dağlıq Amerika Vaxtı (Douson Krik)", + "America\/Denver": "Şimali Dağlıq Amerika Vaxtı (Denver)", + "America\/Detroit": "Şimali Şərqi Amerika Vaxtı (Detroyt)", + "America\/Dominica": "Atlantik Vaxt (Dominika)", + "America\/Edmonton": "Şimali Dağlıq Amerika Vaxtı (Edmondton)", + "America\/El_Salvador": "Şimali Mərkəzi Amerika Vaxtı (Salvador)", + "America\/Fort_Nelson": "Şimali Dağlıq Amerika Vaxtı (Fort Nelson)", + "America\/Fortaleza": "Braziliya Vaxtı (Fortaleza)", + "America\/Glace_Bay": "Atlantik Vaxt (Qleys Körfəzi)", + "America\/Godthab": "Qərbi Qrenlandiya Vaxtı (Nuuk)", + "America\/Goose_Bay": "Atlantik Vaxt (Quz Körfəzi)", + "America\/Grand_Turk": "Şimali Şərqi Amerika Vaxtı (Qrand Turk)", + "America\/Grenada": "Atlantik Vaxt (Qrenada)", + "America\/Guadeloupe": "Atlantik Vaxt (Qvadelupa)", + "America\/Guatemala": "Şimali Mərkəzi Amerika Vaxtı (Qvatemala)", + "America\/Guayaquil": "Ekvador Vaxtı (Quayakil)", + "America\/Guyana": "Qayana Vaxtı (Qayana)", + "America\/Halifax": "Atlantik Vaxt (Halifaks)", + "America\/Havana": "Kuba Vaxtı (Havana)", + "America\/Hermosillo": "Meksika Sakit Okean Vaxtı (Hermosilo)", + "America\/Indiana\/Knox": "Şimali Mərkəzi Amerika Vaxtı (Noks)", + "America\/Indiana\/Marengo": "Şimali Şərqi Amerika Vaxtı (Marenqo)", + "America\/Indiana\/Petersburg": "Şimali Şərqi Amerika Vaxtı (Pitersburq)", + "America\/Indiana\/Tell_City": "Şimali Mərkəzi Amerika Vaxtı (Tell)", + "America\/Indiana\/Vevay": "Şimali Şərqi Amerika Vaxtı (Vivey)", + "America\/Indiana\/Vincennes": "Şimali Şərqi Amerika Vaxtı (Vinsen)", + "America\/Indiana\/Winamac": "Şimali Şərqi Amerika Vaxtı (Vinamak)", + "America\/Indianapolis": "Şimali Şərqi Amerika Vaxtı (İndianapolis)", + "America\/Inuvik": "Şimali Dağlıq Amerika Vaxtı (İnuvik)", + "America\/Iqaluit": "Şimali Şərqi Amerika Vaxtı (İqaluit)", + "America\/Jamaica": "Şimali Şərqi Amerika Vaxtı (Yamayka)", + "America\/Jujuy": "Argentina Vaxtı (Jujuy)", + "America\/Juneau": "Alyaska Vaxtı (Cuno)", + "America\/Kentucky\/Monticello": "Şimali Şərqi Amerika Vaxtı (Montiçello)", + "America\/Kralendijk": "Atlantik Vaxt (Kralendik)", + "America\/La_Paz": "Boliviya Vaxtı (La Pas)", + "America\/Lima": "Peru Vaxtı (Lima)", + "America\/Los_Angeles": "Şimali Amerika Sakit Okean Vaxtı (Los Anceles)", + "America\/Louisville": "Şimali Şərqi Amerika Vaxtı (Luisvil)", + "America\/Lower_Princes": "Atlantik Vaxt (Aşağı Prins Kvartalı)", + "America\/Maceio": "Braziliya Vaxtı (Maseyo)", + "America\/Managua": "Şimali Mərkəzi Amerika Vaxtı (Manaqua)", + "America\/Manaus": "Amazon Vaxtı (Manaus)", + "America\/Marigot": "Atlantik Vaxt (Mariqot)", + "America\/Martinique": "Atlantik Vaxt (Martinik)", + "America\/Matamoros": "Şimali Mərkəzi Amerika Vaxtı (Matamoros)", + "America\/Mazatlan": "Meksika Sakit Okean Vaxtı (Mazaltan)", + "America\/Mendoza": "Argentina Vaxtı (Mendoza)", + "America\/Menominee": "Şimali Mərkəzi Amerika Vaxtı (Menomini)", + "America\/Merida": "Şimali Mərkəzi Amerika Vaxtı (Merida)", + "America\/Metlakatla": "Alyaska Vaxtı (Metlakatla)", + "America\/Mexico_City": "Şimali Mərkəzi Amerika Vaxtı (Mexiko)", + "America\/Miquelon": "Müqəddəs Pyer və Mikelon Vaxtı (Mikelon)", + "America\/Moncton": "Atlantik Vaxt (Monkton)", + "America\/Monterrey": "Şimali Mərkəzi Amerika Vaxtı (Monterey)", + "America\/Montevideo": "Uruqvay Vaxtı (Montevideo)", + "America\/Montserrat": "Atlantik Vaxt (Monserat)", + "America\/Nassau": "Şimali Şərqi Amerika Vaxtı (Nassau)", + "America\/New_York": "Şimali Şərqi Amerika Vaxtı (Nyu York)", + "America\/Nipigon": "Şimali Şərqi Amerika Vaxtı (Nipiqon)", + "America\/Nome": "Alyaska Vaxtı (Nom)", + "America\/Noronha": "Fernando de Noronya Vaxtı (Noronya)", + "America\/North_Dakota\/Beulah": "Şimali Mərkəzi Amerika Vaxtı (Beulah, Şimali Dakota)", + "America\/North_Dakota\/Center": "Şimali Mərkəzi Amerika Vaxtı (Mərkəz, Şimal Dakota)", + "America\/North_Dakota\/New_Salem": "Şimali Mərkəzi Amerika Vaxtı (Nyu Salem)", + "America\/Ojinaga": "Şimali Dağlıq Amerika Vaxtı (Ocinaqa)", + "America\/Panama": "Şimali Şərqi Amerika Vaxtı (Panama)", + "America\/Pangnirtung": "Şimali Şərqi Amerika Vaxtı (Panqnirtanq)", + "America\/Paramaribo": "Surinam Vaxtı (Paramaribo)", + "America\/Phoenix": "Şimali Dağlıq Amerika Vaxtı (Feniks)", + "America\/Port-au-Prince": "Şimali Şərqi Amerika Vaxtı (Port-o-Prins)", + "America\/Port_of_Spain": "Atlantik Vaxt (İspan Limanı)", + "America\/Porto_Velho": "Amazon Vaxtı (Porto Velyo)", + "America\/Puerto_Rico": "Atlantik Vaxt (Puerto Riko)", + "America\/Punta_Arenas": "Çili Vaxtı (Punta Arenas)", + "America\/Rainy_River": "Şimali Mərkəzi Amerika Vaxtı (Reyni Çayı)", + "America\/Rankin_Inlet": "Şimali Mərkəzi Amerika Vaxtı (Rankin Girişi)", + "America\/Recife": "Braziliya Vaxtı (Resif)", + "America\/Regina": "Şimali Mərkəzi Amerika Vaxtı (Recina)", + "America\/Resolute": "Şimali Mərkəzi Amerika Vaxtı (Rezolyut)", + "America\/Santa_Isabel": "Şimal-Qərbi Meksika Vaxtı (Santa Isabel)", + "America\/Santarem": "Braziliya Vaxtı (Santarem)", + "America\/Santiago": "Çili Vaxtı (Santyaqo)", + "America\/Santo_Domingo": "Atlantik Vaxt (Santo Dominqo)", + "America\/Sao_Paulo": "Braziliya Vaxtı (San Paulo)", + "America\/Scoresbysund": "Şərqi Qrenlandiya Vaxtı (Skoresbisund)", + "America\/Sitka": "Alyaska Vaxtı (Sitka)", + "America\/St_Barthelemy": "Atlantik Vaxt (Sent-Bartelemi)", + "America\/St_Johns": "Nyufaundlend Vaxtı (Sent Cons)", + "America\/St_Kitts": "Atlantik Vaxt (San Kits)", + "America\/St_Lucia": "Atlantik Vaxt (San Lüsiya)", + "America\/St_Thomas": "Atlantik Vaxt (San Tomas)", + "America\/St_Vincent": "Atlantik Vaxt (San Vinsent)", + "America\/Swift_Current": "Şimali Mərkəzi Amerika Vaxtı (Svift Kurent)", + "America\/Tegucigalpa": "Şimali Mərkəzi Amerika Vaxtı (Tequsiqalpa)", + "America\/Thule": "Atlantik Vaxt (Tul)", + "America\/Thunder_Bay": "Şimali Şərqi Amerika Vaxtı (İldırım Körfəzi)", + "America\/Tijuana": "Şimali Amerika Sakit Okean Vaxtı (Tixuana)", + "America\/Toronto": "Şimali Şərqi Amerika Vaxtı (Toronto)", + "America\/Tortola": "Atlantik Vaxt (Tortola)", + "America\/Vancouver": "Şimali Amerika Sakit Okean Vaxtı (Vankuver)", + "America\/Whitehorse": "Şimali Amerika Sakit Okean Vaxtı (Uaythors)", + "America\/Winnipeg": "Şimali Mərkəzi Amerika Vaxtı (Vinipeq)", + "America\/Yakutat": "Alyaska Vaxtı (Yakutat)", + "America\/Yellowknife": "Şimali Dağlıq Amerika Vaxtı (Yellounayf)", + "Antarctica\/Casey": "Qərbi Avstraliya Vaxtı (Keysi)", + "Antarctica\/Davis": "Devis Vaxtı (Deyvis)", + "Antarctica\/DumontDUrville": "Dümon-d’Ürvil Vaxtı (Dumont d’Urvil)", + "Antarctica\/Macquarie": "Makari Adası Vaxtı (Makuari)", + "Antarctica\/Mawson": "Mouson Vaxtı (Mouson)", + "Antarctica\/McMurdo": "Yeni Zelandiya Vaxtı (Mak Murdo)", + "Antarctica\/Palmer": "Çili Vaxtı (Palmer)", + "Antarctica\/Rothera": "Rotera Vaxtı (Rothera)", + "Antarctica\/Syowa": "Syova Vaxtı (Syova)", + "Antarctica\/Troll": "Qrinviç Orta Vaxtı (Troll)", + "Antarctica\/Vostok": "Vostok Vaxtı (Vostok)", + "Arctic\/Longyearbyen": "Mərkəzi Avropa Vaxtı (Lonqyir)", + "Asia\/Aden": "Ərəbistan Vaxtı (Aden)", + "Asia\/Almaty": "Şərqi Qazaxıstan Vaxtı (Almatı)", + "Asia\/Amman": "Şərqi Avropa Vaxtı (Amman)", + "Asia\/Aqtau": "Qərbi Qazaxıstan Vaxtı (Aktau)", + "Asia\/Aqtobe": "Qərbi Qazaxıstan Vaxtı (Aqtobe)", + "Asia\/Ashgabat": "Türkmənistan Vaxtı (Aşqabat)", + "Asia\/Atyrau": "Qərbi Qazaxıstan Vaxtı (Atırau)", + "Asia\/Baghdad": "Ərəbistan Vaxtı (Bağdad)", + "Asia\/Bahrain": "Ərəbistan Vaxtı (Bəhreyn)", + "Asia\/Baku": "Azərbaycan Vaxtı (Bakı)", + "Asia\/Bangkok": "Hindçin Vaxtı (Banqkok)", + "Asia\/Beirut": "Şərqi Avropa Vaxtı (Beyrut)", + "Asia\/Bishkek": "Qırğızıstan Vaxtı (Bişkek)", + "Asia\/Brunei": "Brunei Darussalam vaxtı (Brunei)", + "Asia\/Calcutta": "Hindistan Vaxtı (Kolkata)", + "Asia\/Chita": "Yakutsk Vaxtı (Çita)", + "Asia\/Choibalsan": "Çoybalsan Vaxtı (Çoybalsan)", + "Asia\/Colombo": "Hindistan Vaxtı (Kolombo)", + "Asia\/Damascus": "Şərqi Avropa Vaxtı (Dəməşq)", + "Asia\/Dhaka": "Banqladeş Vaxtı (Dəkkə)", + "Asia\/Dili": "Şərqi Timor Vaxtı (Dili)", + "Asia\/Dubai": "Körfəz Vaxtı (Dubay)", + "Asia\/Dushanbe": "Tacikistan Vaxtı (Düşənbə)", + "Asia\/Famagusta": "Şərqi Avropa Vaxtı (Famaqusta)", + "Asia\/Gaza": "Şərqi Avropa Vaxtı (Qəza)", + "Asia\/Hebron": "Şərqi Avropa Vaxtı (Hebron)", + "Asia\/Hong_Kong": "Honq Konq Vaxtı (Honq Konq)", + "Asia\/Hovd": "Hovd Vaxtı (Hovd)", + "Asia\/Irkutsk": "İrkutsk Vaxtı (İrkutsk)", + "Asia\/Jakarta": "Qərbi İndoneziya Vaxtı (Cakarta)", + "Asia\/Jayapura": "Şərqi İndoneziya Vaxtı (Cayapura)", + "Asia\/Jerusalem": "İsrail Vaxtı (Yerusəlim)", + "Asia\/Kabul": "Əfqanıstan Vaxtı (Kabil)", + "Asia\/Karachi": "Pakistan Vaxtı (Karaçi)", + "Asia\/Katmandu": "Nepal vaxtı (Katmandu)", + "Asia\/Khandyga": "Yakutsk Vaxtı (Xandıqa)", + "Asia\/Krasnoyarsk": "Krasnoyarsk Vaxtı (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malayziya Vaxtı (Kuala Lumpur)", + "Asia\/Kuching": "Malayziya Vaxtı (Kuçinq)", + "Asia\/Kuwait": "Ərəbistan Vaxtı (Küveyt)", + "Asia\/Macau": "Çin Vaxtı (Makao)", + "Asia\/Magadan": "Maqadan Vaxtı (Maqadan)", + "Asia\/Makassar": "Mərkəzi İndoneziya Vaxtı (Makasar)", + "Asia\/Manila": "Filippin Vaxtı (Manila)", + "Asia\/Muscat": "Körfəz Vaxtı (Muskat)", + "Asia\/Nicosia": "Şərqi Avropa Vaxtı (Nikosia)", + "Asia\/Novokuznetsk": "Krasnoyarsk Vaxtı (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk Vaxtı (Novosibirsk)", + "Asia\/Omsk": "Omsk Vaxtı (Omsk)", + "Asia\/Oral": "Qərbi Qazaxıstan Vaxtı (Oral)", + "Asia\/Phnom_Penh": "Hindçin Vaxtı (Pnom Pen)", + "Asia\/Pontianak": "Qərbi İndoneziya Vaxtı (Pontianak)", + "Asia\/Pyongyang": "Koreya Vaxtı (Pxenyan)", + "Asia\/Qatar": "Ərəbistan Vaxtı (Qatar)", + "Asia\/Qostanay": "Şərqi Qazaxıstan Vaxtı (Qostanay)", + "Asia\/Qyzylorda": "Qərbi Qazaxıstan Vaxtı (Qızılorda)", + "Asia\/Rangoon": "Myanma Vaxtı (Ranqun)", + "Asia\/Riyadh": "Ərəbistan Vaxtı (Riyad)", + "Asia\/Saigon": "Hindçin Vaxtı (Ho Şi Min)", + "Asia\/Sakhalin": "Saxalin Vaxtı (Saxalin)", + "Asia\/Samarkand": "Özbəkistan Vaxtı (Səmərqənd)", + "Asia\/Seoul": "Koreya Vaxtı (Seul)", + "Asia\/Shanghai": "Çin Vaxtı (Şanxay)", + "Asia\/Singapore": "Sinqapur Vaxtı (Sinqapur)", + "Asia\/Srednekolymsk": "Maqadan Vaxtı (Srednekolımsk)", + "Asia\/Taipei": "Taybey Vaxtı (Taipei)", + "Asia\/Tashkent": "Özbəkistan Vaxtı (Daşkənd)", + "Asia\/Tbilisi": "Gurcüstan Vaxtı (Tbilisi)", + "Asia\/Tehran": "İran Vaxtı (Tehran)", + "Asia\/Thimphu": "Butan Vaxtı (Thimphu)", + "Asia\/Tokyo": "Yaponiya Vaxtı (Tokyo)", + "Asia\/Ulaanbaatar": "Ulanbator Vaxtı (Ulanbator)", + "Asia\/Ust-Nera": "Vladivostok Vaxtı (Ust-Nera)", + "Asia\/Vientiane": "Hindçin Vaxtı (Vyentyan)", + "Asia\/Vladivostok": "Vladivostok Vaxtı (Vladivostok)", + "Asia\/Yakutsk": "Yakutsk Vaxtı (Yakutsk)", + "Asia\/Yekaterinburg": "Yekaterinburq Vaxtı (Yekaterinburq)", + "Asia\/Yerevan": "Ermənistan Vaxtı (Yerevan)", + "Atlantic\/Azores": "Azor Vaxtı (Azor)", + "Atlantic\/Bermuda": "Atlantik Vaxt (Bermud adaları)", + "Atlantic\/Canary": "Qərbi Avropa Vaxtı (Kanar)", + "Atlantic\/Cape_Verde": "Kape Verde Vaxtı (Kape Verde)", + "Atlantic\/Faeroe": "Qərbi Avropa Vaxtı (Farer)", + "Atlantic\/Madeira": "Qərbi Avropa Vaxtı (Madeyra)", + "Atlantic\/Reykjavik": "Qrinviç Orta Vaxtı (Reykyavik)", + "Atlantic\/South_Georgia": "Cənubi Corciya Vaxtı (Cənubi Corciya)", + "Atlantic\/St_Helena": "Qrinviç Orta Vaxtı (Müqəddəs Yelena)", + "Atlantic\/Stanley": "Folklend Adaları Vaxtı (Stenli)", + "Australia\/Adelaide": "Mərkəzi Avstraliya Vaxtı (Adelaida)", + "Australia\/Brisbane": "Şərqi Avstraliya Vaxtı (Brisbeyn)", + "Australia\/Broken_Hill": "Mərkəzi Avstraliya Vaxtı (Broken Hill)", + "Australia\/Currie": "Şərqi Avstraliya Vaxtı (Kuriye)", + "Australia\/Darwin": "Mərkəzi Avstraliya Vaxtı (Darvin)", + "Australia\/Eucla": "Mərkəzi Qərbi Avstraliya Vaxtı (Yukla)", + "Australia\/Hobart": "Şərqi Avstraliya Vaxtı (Hobart)", + "Australia\/Lindeman": "Şərqi Avstraliya Vaxtı (Lindeman)", + "Australia\/Lord_Howe": "Lord Hau Vaxtı (Lord Hau)", + "Australia\/Melbourne": "Şərqi Avstraliya Vaxtı (Melburn)", + "Australia\/Perth": "Qərbi Avstraliya Vaxtı (Perth)", + "Australia\/Sydney": "Şərqi Avstraliya Vaxtı (Sidney)", + "CST6CDT": "Şimali Mərkəzi Amerika Vaxtı", + "EST5EDT": "Şimali Şərqi Amerika Vaxtı", + "Etc\/GMT": "Qrinviç Orta Vaxtı", + "Etc\/UTC": "Koordinasiya edilmiş ümumdünya vaxtı", + "Europe\/Amsterdam": "Mərkəzi Avropa Vaxtı (Amsterdam)", + "Europe\/Andorra": "Mərkəzi Avropa Vaxtı (Andorra)", + "Europe\/Astrakhan": "Moskva Vaxtı (Həştərxan)", + "Europe\/Athens": "Şərqi Avropa Vaxtı (Afina)", + "Europe\/Belgrade": "Mərkəzi Avropa Vaxtı (Belqrad)", + "Europe\/Berlin": "Mərkəzi Avropa Vaxtı (Berlin)", + "Europe\/Bratislava": "Mərkəzi Avropa Vaxtı (Bratislava)", + "Europe\/Brussels": "Mərkəzi Avropa Vaxtı (Brüssel)", + "Europe\/Bucharest": "Şərqi Avropa Vaxtı (Buxarest)", + "Europe\/Budapest": "Mərkəzi Avropa Vaxtı (Budapeşt)", + "Europe\/Busingen": "Mərkəzi Avropa Vaxtı (Busingen)", + "Europe\/Chisinau": "Şərqi Avropa Vaxtı (Kişinyov)", + "Europe\/Copenhagen": "Mərkəzi Avropa Vaxtı (Kopenhagen)", + "Europe\/Dublin": "Qrinviç Orta Vaxtı (Dublin)", + "Europe\/Gibraltar": "Mərkəzi Avropa Vaxtı (Gibraltar)", + "Europe\/Guernsey": "Qrinviç Orta Vaxtı (Gernzey)", + "Europe\/Helsinki": "Şərqi Avropa Vaxtı (Helsinki)", + "Europe\/Isle_of_Man": "Qrinviç Orta Vaxtı (Men Adası)", + "Europe\/Jersey": "Qrinviç Orta Vaxtı (Cersi)", + "Europe\/Kaliningrad": "Şərqi Avropa Vaxtı (Kalininqrad)", + "Europe\/Kiev": "Şərqi Avropa Vaxtı (Kiyev)", + "Europe\/Lisbon": "Qərbi Avropa Vaxtı (Lissabon)", + "Europe\/Ljubljana": "Mərkəzi Avropa Vaxtı (Lyublyana)", + "Europe\/London": "Qrinviç Orta Vaxtı (London)", + "Europe\/Luxembourg": "Mərkəzi Avropa Vaxtı (Lüksemburq)", + "Europe\/Madrid": "Mərkəzi Avropa Vaxtı (Madrid)", + "Europe\/Malta": "Mərkəzi Avropa Vaxtı (Malta)", + "Europe\/Mariehamn": "Şərqi Avropa Vaxtı (Mariham)", + "Europe\/Minsk": "Moskva Vaxtı (Minsk)", + "Europe\/Monaco": "Mərkəzi Avropa Vaxtı (Monako)", + "Europe\/Moscow": "Moskva Vaxtı (Moskva)", + "Europe\/Oslo": "Mərkəzi Avropa Vaxtı (Oslo)", + "Europe\/Paris": "Mərkəzi Avropa Vaxtı (Paris)", + "Europe\/Podgorica": "Mərkəzi Avropa Vaxtı (Podqoritsa)", + "Europe\/Prague": "Mərkəzi Avropa Vaxtı (Praqa)", + "Europe\/Riga": "Şərqi Avropa Vaxtı (Riqa)", + "Europe\/Rome": "Mərkəzi Avropa Vaxtı (Roma)", + "Europe\/Samara": "Samara vaxtı (Samara)", + "Europe\/San_Marino": "Mərkəzi Avropa Vaxtı (San Marino)", + "Europe\/Sarajevo": "Mərkəzi Avropa Vaxtı (Sarayevo)", + "Europe\/Saratov": "Moskva Vaxtı (Saratov)", + "Europe\/Simferopol": "Moskva Vaxtı (Simferopol)", + "Europe\/Skopje": "Mərkəzi Avropa Vaxtı (Skopye)", + "Europe\/Sofia": "Şərqi Avropa Vaxtı (Sofia)", + "Europe\/Stockholm": "Mərkəzi Avropa Vaxtı (Stokholm)", + "Europe\/Tallinn": "Şərqi Avropa Vaxtı (Tallin)", + "Europe\/Tirane": "Mərkəzi Avropa Vaxtı (Tirana)", + "Europe\/Ulyanovsk": "Moskva Vaxtı (Ulyanovsk)", + "Europe\/Uzhgorod": "Şərqi Avropa Vaxtı (Ujqorod)", + "Europe\/Vaduz": "Mərkəzi Avropa Vaxtı (Vaduts)", + "Europe\/Vatican": "Mərkəzi Avropa Vaxtı (Vatikan)", + "Europe\/Vienna": "Mərkəzi Avropa Vaxtı (Vyana)", + "Europe\/Vilnius": "Şərqi Avropa Vaxtı (Vilnyus)", + "Europe\/Volgograd": "Volqoqrad Vaxtı (Volqoqrad)", + "Europe\/Warsaw": "Mərkəzi Avropa Vaxtı (Varşava)", + "Europe\/Zagreb": "Mərkəzi Avropa Vaxtı (Zaqreb)", + "Europe\/Zaporozhye": "Şərqi Avropa Vaxtı (Zaporojye)", + "Europe\/Zurich": "Mərkəzi Avropa Vaxtı (Sürix)", + "Indian\/Antananarivo": "Şərqi Afrika Vaxtı (Antananarivo)", + "Indian\/Chagos": "Hind Okeanı Vaxtı (Çaqos)", + "Indian\/Christmas": "Milad Adası Vaxtı (Milad)", + "Indian\/Cocos": "Kokos Adaları Vaxtı (Kokos)", + "Indian\/Comoro": "Şərqi Afrika Vaxtı (Komoro)", + "Indian\/Kerguelen": "Fransız Cənubi və Antarktik Vaxtı (Kergelen)", + "Indian\/Mahe": "Seyşel Adaları Vaxtı (Mahe)", + "Indian\/Maldives": "Maldiv Vaxtı (Maldiv)", + "Indian\/Mauritius": "Mavriki Vaxtı (Mavriki)", + "Indian\/Mayotte": "Şərqi Afrika Vaxtı (Mayot)", + "Indian\/Reunion": "Reunion Vaxtı (Reunion)", + "MST7MDT": "Şimali Dağlıq Amerika Vaxtı", + "PST8PDT": "Şimali Amerika Sakit Okean Vaxtı", + "Pacific\/Apia": "Apia Vaxtı (Apia)", + "Pacific\/Auckland": "Yeni Zelandiya Vaxtı (Aukland)", + "Pacific\/Bougainville": "Papua Yeni Qvineya Vaxtı (Buqanvil)", + "Pacific\/Chatham": "Çatham Vaxtı (Çatam)", + "Pacific\/Easter": "Pasxa Adası Vaxtı (Pasxa)", + "Pacific\/Efate": "Vanuatu Vaxtı (Efate)", + "Pacific\/Enderbury": "Feniks Adaları Vaxtı (Enderböri)", + "Pacific\/Fakaofo": "Tokelau Vaxtı (Fakaofo)", + "Pacific\/Fiji": "Fici Vaxtı (Fici)", + "Pacific\/Funafuti": "Tuvalu Vaxtı (Funafuti)", + "Pacific\/Galapagos": "Qalapaqos Vaxtı (Qalapaqos)", + "Pacific\/Gambier": "Qambier Vaxtı (Qambiyer)", + "Pacific\/Guadalcanal": "Solomon Adaları Vaxtı (Quadalkanal)", + "Pacific\/Guam": "Çamorro Vaxtı (Quam)", + "Pacific\/Honolulu": "Havay-Aleut Vaxtı (Honolulu)", + "Pacific\/Johnston": "Havay-Aleut Vaxtı (Conston)", + "Pacific\/Kiritimati": "Layn Adaları Vaxtı (Kirimati)", + "Pacific\/Kosrae": "Korse Vaxtı (Kosraye)", + "Pacific\/Kwajalein": "Marşal Adaları Vaxtı (Kvajaleyn)", + "Pacific\/Majuro": "Marşal Adaları Vaxtı (Macuro)", + "Pacific\/Marquesas": "Markesas Vaxtı (Markesas)", + "Pacific\/Midway": "Samoa Vaxtı (Midvey)", + "Pacific\/Nauru": "Nauru Vaxtı (Nauru)", + "Pacific\/Niue": "Niue Vaxtı (Niue)", + "Pacific\/Norfolk": "Norfolk Adası Vaxtı (Norfolk)", + "Pacific\/Noumea": "Yeni Kaledoniya Vaxtı (Noumea)", + "Pacific\/Pago_Pago": "Samoa Vaxtı (Paqo Paqo)", + "Pacific\/Palau": "Palau Vaxtı (Palau)", + "Pacific\/Pitcairn": "Pitkern Vaxtı (Pitkern)", + "Pacific\/Ponape": "Ponape Vaxtı (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Yeni Qvineya Vaxtı (Port Moresbi)", + "Pacific\/Rarotonga": "Kuk Adaları Vaxtı (Rarotonqa)", + "Pacific\/Saipan": "Çamorro Vaxtı (Saipan)", + "Pacific\/Tahiti": "Tahiti Vaxtı (Tahiti)", + "Pacific\/Tarawa": "Gilbert Adaları Vaxtı (Tarava)", + "Pacific\/Tongatapu": "Tonqa Vaxtı (Tonqapatu)", + "Pacific\/Truk": "Çuuk Vaxtı (Çuuk)", + "Pacific\/Wake": "Ueyk Vaxtı (Veyk)", + "Pacific\/Wallis": "Uollis və Futuna Vaxtı (Uollis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/be.json b/src/Symfony/Component/Intl/Resources/data/timezones/be.json new file mode 100644 index 0000000000000..4a5c9a815ec5d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/be.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Час па Грынвічы (Абіджан)", + "Africa\/Accra": "Час па Грынвічы (Акра)", + "Africa\/Addis_Ababa": "Усходнеафрыканскі час (Адыс-Абеба)", + "Africa\/Algiers": "Цэнтральнаеўрапейскі час (Алжыр)", + "Africa\/Asmera": "Усходнеафрыканскі час (Асмара)", + "Africa\/Bamako": "Час па Грынвічы (Бамако)", + "Africa\/Bangui": "Заходнеафрыканскі час (Бангі)", + "Africa\/Banjul": "Час па Грынвічы (Банжул)", + "Africa\/Bissau": "Час па Грынвічы (Бісау)", + "Africa\/Blantyre": "Цэнтральнаафрыканскі час (Блантайр)", + "Africa\/Brazzaville": "Заходнеафрыканскі час (Бразавіль)", + "Africa\/Bujumbura": "Цэнтральнаафрыканскі час (Бужумбура)", + "Africa\/Cairo": "Усходнееўрапейскі час (Каір)", + "Africa\/Casablanca": "Заходнееўрапейскі час (Касабланка)", + "Africa\/Ceuta": "Цэнтральнаеўрапейскі час (Сеўта)", + "Africa\/Conakry": "Час па Грынвічы (Конакры)", + "Africa\/Dakar": "Час па Грынвічы (Дакар)", + "Africa\/Dar_es_Salaam": "Усходнеафрыканскі час (Дар-эс-Салам)", + "Africa\/Djibouti": "Усходнеафрыканскі час (Джыбуці)", + "Africa\/Douala": "Заходнеафрыканскі час (Дуала)", + "Africa\/El_Aaiun": "Заходнееўрапейскі час (Эль-Аюн)", + "Africa\/Freetown": "Час па Грынвічы (Фрытаўн)", + "Africa\/Gaborone": "Цэнтральнаафрыканскі час (Габаронэ)", + "Africa\/Harare": "Цэнтральнаафрыканскі час (Харарэ)", + "Africa\/Johannesburg": "Паўднёваафрыканскі час (Яганэсбург)", + "Africa\/Juba": "Усходнеафрыканскі час (Джуба)", + "Africa\/Kampala": "Усходнеафрыканскі час (Кампала)", + "Africa\/Khartoum": "Цэнтральнаафрыканскі час (Хартум)", + "Africa\/Kigali": "Цэнтральнаафрыканскі час (Кігалі)", + "Africa\/Kinshasa": "Заходнеафрыканскі час (Кіншаса)", + "Africa\/Lagos": "Заходнеафрыканскі час (Лагас)", + "Africa\/Libreville": "Заходнеафрыканскі час (Лібрэвіль)", + "Africa\/Lome": "Час па Грынвічы (Ламэ)", + "Africa\/Luanda": "Заходнеафрыканскі час (Луанда)", + "Africa\/Lubumbashi": "Цэнтральнаафрыканскі час (Лубумбашы)", + "Africa\/Lusaka": "Цэнтральнаафрыканскі час (Лусака)", + "Africa\/Malabo": "Заходнеафрыканскі час (Малаба)", + "Africa\/Maputo": "Цэнтральнаафрыканскі час (Мапуту)", + "Africa\/Maseru": "Паўднёваафрыканскі час (Масеру)", + "Africa\/Mbabane": "Паўднёваафрыканскі час (Мбабанэ)", + "Africa\/Mogadishu": "Усходнеафрыканскі час (Магадыша)", + "Africa\/Monrovia": "Час па Грынвічы (Манровія)", + "Africa\/Nairobi": "Усходнеафрыканскі час (Найробі)", + "Africa\/Ndjamena": "Заходнеафрыканскі час (Нджамена)", + "Africa\/Niamey": "Заходнеафрыканскі час (Ніямей)", + "Africa\/Nouakchott": "Час па Грынвічы (Нуакшот)", + "Africa\/Ouagadougou": "Час па Грынвічы (Уагадугу)", + "Africa\/Porto-Novo": "Заходнеафрыканскі час (Порта-Нова)", + "Africa\/Sao_Tome": "Час па Грынвічы (Сан-Тамэ)", + "Africa\/Tripoli": "Усходнееўрапейскі час (Трыпалі)", + "Africa\/Tunis": "Цэнтральнаеўрапейскі час (Туніс)", + "Africa\/Windhoek": "Цэнтральнаафрыканскі час (Віндхук)", + "America\/Adak": "Гавайска-Алеуцкі час (Адак)", + "America\/Anchorage": "Час Аляскі (Анкарыдж)", + "America\/Anguilla": "Атлантычны час (Ангілья)", + "America\/Antigua": "Атлантычны час (Антыгуа)", + "America\/Araguaina": "Бразільскі час (Арагуаіна)", + "America\/Argentina\/La_Rioja": "Аргенцінскі час (Ла-Рыёха)", + "America\/Argentina\/Rio_Gallegos": "Аргенцінскі час (Рыа-Гальегас)", + "America\/Argentina\/Salta": "Аргенцінскі час (Сальта)", + "America\/Argentina\/San_Juan": "Аргенцінскі час (Сан-Хуан)", + "America\/Argentina\/San_Luis": "Час Заходняй Аргенціны (Сан-Луіс)", + "America\/Argentina\/Tucuman": "Аргенцінскі час (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргенцінскі час (Ушуая)", + "America\/Aruba": "Атлантычны час (Аруба)", + "America\/Asuncion": "Час Парагвая (Асунсьён)", + "America\/Bahia": "Бразільскі час (Баія)", + "America\/Bahia_Banderas": "Паўночнаамерыканскі цэнтральны час (Баія-дэ-Бандэрас)", + "America\/Barbados": "Атлантычны час (Барбадас)", + "America\/Belem": "Бразільскі час (Белен)", + "America\/Belize": "Паўночнаамерыканскі цэнтральны час (Беліз)", + "America\/Blanc-Sablon": "Атлантычны час (Бланк-Саблон)", + "America\/Boa_Vista": "Амазонскі час (Боа-Віста)", + "America\/Bogota": "Калумбійскі час (Багата)", + "America\/Boise": "Паўночнаамерыканскі горны час (Бойсэ)", + "America\/Buenos_Aires": "Аргенцінскі час (Буэнас-Айрэс)", + "America\/Cambridge_Bay": "Паўночнаамерыканскі горны час (Кембрыдж-Бей)", + "America\/Campo_Grande": "Амазонскі час (Кампу-Гранды)", + "America\/Cancun": "Паўночнаамерыканскі ўсходні час (Канкун)", + "America\/Caracas": "Венесуэльскі час (Каракас)", + "America\/Catamarca": "Аргенцінскі час (Катамарка)", + "America\/Cayenne": "Час Французскай Гвіяны (Каена)", + "America\/Cayman": "Паўночнаамерыканскі ўсходні час (Кайманавы астравы)", + "America\/Chicago": "Паўночнаамерыканскі цэнтральны час (Чыкага)", + "America\/Chihuahua": "Мексіканскі ціхаакіянскі час (Чыўаўа)", + "America\/Coral_Harbour": "Паўночнаамерыканскі ўсходні час (Атыкокан)", + "America\/Cordoba": "Аргенцінскі час (Кордава)", + "America\/Costa_Rica": "Паўночнаамерыканскі цэнтральны час (Коста-Рыка)", + "America\/Creston": "Паўночнаамерыканскі горны час (Крэстан)", + "America\/Cuiaba": "Амазонскі час (Куяба)", + "America\/Curacao": "Атлантычны час (Кюрасаа)", + "America\/Danmarkshavn": "Час па Грынвічы (Данмарксхаўн)", + "America\/Dawson": "Ціхаакіянскі час (Доўсан)", + "America\/Dawson_Creek": "Паўночнаамерыканскі горны час (Досан-Крык)", + "America\/Denver": "Паўночнаамерыканскі горны час (Дэнвер)", + "America\/Detroit": "Паўночнаамерыканскі ўсходні час (Дэтройт)", + "America\/Dominica": "Атлантычны час (Дамініка)", + "America\/Edmonton": "Паўночнаамерыканскі горны час (Эдмантан)", + "America\/El_Salvador": "Паўночнаамерыканскі цэнтральны час (Сальвадор)", + "America\/Fort_Nelson": "Паўночнаамерыканскі горны час (Форт-Нельсан)", + "America\/Fortaleza": "Бразільскі час (Фарталеза)", + "America\/Glace_Bay": "Атлантычны час (Глэйс-Бэй)", + "America\/Godthab": "Час Заходняй Грэнландыі (Нук)", + "America\/Goose_Bay": "Атлантычны час (Гус-Бэй)", + "America\/Grand_Turk": "Паўночнаамерыканскі ўсходні час (Гранд-Цёрк)", + "America\/Grenada": "Атлантычны час (Грэнада)", + "America\/Guadeloupe": "Атлантычны час (Гвадэлупа)", + "America\/Guatemala": "Паўночнаамерыканскі цэнтральны час (Гватэмала)", + "America\/Guayaquil": "Эквадорскі час (Гуаякіль)", + "America\/Guyana": "Час Гаяны (Гаяна)", + "America\/Halifax": "Атлантычны час (Галіфакс)", + "America\/Havana": "Час Кубы (Гавана)", + "America\/Hermosillo": "Мексіканскі ціхаакіянскі час (Эрмасілья)", + "America\/Indiana\/Knox": "Паўночнаамерыканскі цэнтральны час (Нокс, Індыяна)", + "America\/Indiana\/Marengo": "Паўночнаамерыканскі ўсходні час (Марэнга, Індыяна)", + "America\/Indiana\/Petersburg": "Паўночнаамерыканскі ўсходні час (Пітэрсберг, Індыяна)", + "America\/Indiana\/Tell_City": "Паўночнаамерыканскі цэнтральны час (Тэл Сіці, Індыяна)", + "America\/Indiana\/Vevay": "Паўночнаамерыканскі ўсходні час (Віві, Індыяна)", + "America\/Indiana\/Vincennes": "Паўночнаамерыканскі ўсходні час (Вінсенс, Індыяна)", + "America\/Indiana\/Winamac": "Паўночнаамерыканскі ўсходні час (Уінамак, Індыяна)", + "America\/Indianapolis": "Паўночнаамерыканскі ўсходні час (Індыянапаліс)", + "America\/Inuvik": "Паўночнаамерыканскі горны час (Інувік)", + "America\/Iqaluit": "Паўночнаамерыканскі ўсходні час (Ікалуіт)", + "America\/Jamaica": "Паўночнаамерыканскі ўсходні час (Ямайка)", + "America\/Jujuy": "Аргенцінскі час (Жужуй)", + "America\/Juneau": "Час Аляскі (Джуна)", + "America\/Kentucky\/Monticello": "Паўночнаамерыканскі ўсходні час (Мантысела, Кентукі)", + "America\/Kralendijk": "Атлантычны час (Кралендэйк)", + "America\/La_Paz": "Балівійскі час (Ла-Пас)", + "America\/Lima": "Перуанскі час (Ліма)", + "America\/Los_Angeles": "Ціхаакіянскі час (Лос-Анджэлес)", + "America\/Louisville": "Паўночнаамерыканскі ўсходні час (Луісвіл)", + "America\/Lower_Princes": "Атлантычны час (Лоўэр Прынсіз Квортэр)", + "America\/Maceio": "Бразільскі час (Масеё)", + "America\/Managua": "Паўночнаамерыканскі цэнтральны час (Манагуа)", + "America\/Manaus": "Амазонскі час (Манаўс)", + "America\/Marigot": "Атлантычны час (Марыго)", + "America\/Martinique": "Атлантычны час (Марцініка)", + "America\/Matamoros": "Паўночнаамерыканскі цэнтральны час (Матаморас)", + "America\/Mazatlan": "Мексіканскі ціхаакіянскі час (Масатлан)", + "America\/Mendoza": "Аргенцінскі час (Мендоса)", + "America\/Menominee": "Паўночнаамерыканскі цэнтральны час (Меноміні)", + "America\/Merida": "Паўночнаамерыканскі цэнтральны час (Мерыда)", + "America\/Metlakatla": "Час Аляскі (Метлакатла)", + "America\/Mexico_City": "Паўночнаамерыканскі цэнтральны час (Мехіка)", + "America\/Miquelon": "Час Сен-П’ер і Мікелон (Мікелон)", + "America\/Moncton": "Атлантычны час (Манктан)", + "America\/Monterrey": "Паўночнаамерыканскі цэнтральны час (Мантэрэй)", + "America\/Montevideo": "Уругвайскі час (Мантэвідэа)", + "America\/Montserrat": "Атлантычны час (Мантсерат)", + "America\/Nassau": "Паўночнаамерыканскі ўсходні час (Насаў)", + "America\/New_York": "Паўночнаамерыканскі ўсходні час (Нью-Ёрк)", + "America\/Nipigon": "Паўночнаамерыканскі ўсходні час (Ніпіган)", + "America\/Nome": "Час Аляскі (Ном)", + "America\/Noronha": "Час Фернанду-ды-Наронья (Наронья)", + "America\/North_Dakota\/Beulah": "Паўночнаамерыканскі цэнтральны час (Б’юла, Паўночная Дакота)", + "America\/North_Dakota\/Center": "Паўночнаамерыканскі цэнтральны час (Сентэр, Паўночная Дакота)", + "America\/North_Dakota\/New_Salem": "Паўночнаамерыканскі цэнтральны час (Нью-Сейлем, Паўночная Дакота)", + "America\/Ojinaga": "Паўночнаамерыканскі горны час (Ахінага)", + "America\/Panama": "Паўночнаамерыканскі ўсходні час (Панама)", + "America\/Pangnirtung": "Паўночнаамерыканскі ўсходні час (Пангніртунг)", + "America\/Paramaribo": "Час Сурынама (Парамарыба)", + "America\/Phoenix": "Паўночнаамерыканскі горны час (Фінікс)", + "America\/Port-au-Prince": "Паўночнаамерыканскі ўсходні час (Порт-о-Прэнс)", + "America\/Port_of_Spain": "Атлантычны час (Порт-оф-Спейн)", + "America\/Porto_Velho": "Амазонскі час (Порту-Велью)", + "America\/Puerto_Rico": "Атлантычны час (Пуэрта-Рыка)", + "America\/Punta_Arenas": "Чылійскі час (Пунта Арэнас)", + "America\/Rainy_River": "Паўночнаамерыканскі цэнтральны час (Рэйні-Рывер)", + "America\/Rankin_Inlet": "Паўночнаамерыканскі цэнтральны час (Ранкін-Інлет)", + "America\/Recife": "Бразільскі час (Рэсіфі)", + "America\/Regina": "Паўночнаамерыканскі цэнтральны час (Рэджайна)", + "America\/Resolute": "Паўночнаамерыканскі цэнтральны час (Рэзальют)", + "America\/Santa_Isabel": "Паўночна-заходні мексіканскі час (Санта-Ісабель)", + "America\/Santarem": "Бразільскі час (Сантарэн)", + "America\/Santiago": "Чылійскі час (Сант’яга)", + "America\/Santo_Domingo": "Атлантычны час (Санта-Дамінга)", + "America\/Sao_Paulo": "Бразільскі час (Сан-Паўлу)", + "America\/Scoresbysund": "Час Усходняй Грэнландыі (Ітакортаарміут)", + "America\/Sitka": "Час Аляскі (Сітка)", + "America\/St_Barthelemy": "Атлантычны час (Сен-Бартэльмі)", + "America\/St_Johns": "Ньюфаўндлендскі час (Сент-Джонс)", + "America\/St_Kitts": "Атлантычны час (Сент-Кітс)", + "America\/St_Lucia": "Атлантычны час (Сент-Люсія)", + "America\/St_Thomas": "Атлантычны час (Сент-Томас)", + "America\/St_Vincent": "Атлантычны час (Сент-Вінсент)", + "America\/Swift_Current": "Паўночнаамерыканскі цэнтральны час (Свіфт-Керэнт)", + "America\/Tegucigalpa": "Паўночнаамерыканскі цэнтральны час (Тэгусігальпа)", + "America\/Thule": "Атлантычны час (Каанаак)", + "America\/Thunder_Bay": "Паўночнаамерыканскі ўсходні час (Тандэр-Бэй)", + "America\/Tijuana": "Ціхаакіянскі час (Тыхуана)", + "America\/Toronto": "Паўночнаамерыканскі ўсходні час (Таронта)", + "America\/Tortola": "Атлантычны час (Тартола)", + "America\/Vancouver": "Ціхаакіянскі час (Ванкувер)", + "America\/Whitehorse": "Ціхаакіянскі час (Уайтхорс)", + "America\/Winnipeg": "Паўночнаамерыканскі цэнтральны час (Вініпег)", + "America\/Yakutat": "Час Аляскі (Якутат)", + "America\/Yellowknife": "Паўночнаамерыканскі горны час (Йелаўнайф)", + "Antarctica\/Casey": "Час заходняй Аўстраліі (Кэйсі)", + "Antarctica\/Davis": "Час станцыі Дэйвіс (Дэйвіс)", + "Antarctica\/DumontDUrville": "Час станцыі Дзюмон-Дзюрвіль (Дзюмон-Дзюрвіль)", + "Antarctica\/Macquarie": "Час вострава Макуоры (Макуоры)", + "Antarctica\/Mawson": "Час станцыі Моўсан (Моўсан)", + "Antarctica\/McMurdo": "Час Новай Зеландыі (Мак-Мерда)", + "Antarctica\/Palmer": "Чылійскі час (Палмер)", + "Antarctica\/Rothera": "Час станцыі Ратэра (Ротэра)", + "Antarctica\/Syowa": "Час станцыі Сёва (Сёва)", + "Antarctica\/Troll": "Час па Грынвічы (Трол)", + "Antarctica\/Vostok": "Час станцыі Васток (Васток)", + "Arctic\/Longyearbyen": "Цэнтральнаеўрапейскі час (Лонгйір)", + "Asia\/Aden": "Час Саудаўскай Аравіі (Адэн)", + "Asia\/Almaty": "Усходнеказахстанскі час (Алматы)", + "Asia\/Amman": "Усходнееўрапейскі час (Аман (горад))", + "Asia\/Aqtau": "Заходнеказахстанскі час (Актау)", + "Asia\/Aqtobe": "Заходнеказахстанскі час (Актабэ)", + "Asia\/Ashgabat": "Час Туркменістана (Ашгабад)", + "Asia\/Atyrau": "Заходнеказахстанскі час (Атырау)", + "Asia\/Baghdad": "Час Саудаўскай Аравіі (Багдад)", + "Asia\/Bahrain": "Час Саудаўскай Аравіі (Бахрэйн)", + "Asia\/Baku": "Час Азербайджана (Баку)", + "Asia\/Bangkok": "Індакітайскі час (Бангкок)", + "Asia\/Beirut": "Усходнееўрапейскі час (Бейрут)", + "Asia\/Bishkek": "Час Кыргызстана (Бішкек)", + "Asia\/Brunei": "Час Брунея (Бруней)", + "Asia\/Calcutta": "Час Індыі (Калькута)", + "Asia\/Chita": "Якуцкі час (Чыта)", + "Asia\/Choibalsan": "Час Чайбалсана (Чайбалсан)", + "Asia\/Colombo": "Час Індыі (Каломба)", + "Asia\/Damascus": "Усходнееўрапейскі час (Дамаск)", + "Asia\/Dhaka": "Час Бангладэш (Дака)", + "Asia\/Dili": "Час Усходняга Тымора (Дылі)", + "Asia\/Dubai": "Час Персідскага заліва (Дубай)", + "Asia\/Dushanbe": "Час Таджыкістана (Душанбэ)", + "Asia\/Famagusta": "Усходнееўрапейскі час (Фамагуста)", + "Asia\/Gaza": "Усходнееўрапейскі час (Газа)", + "Asia\/Hebron": "Усходнееўрапейскі час (Хеўрон)", + "Asia\/Hong_Kong": "Час Ганконга (Ганконг)", + "Asia\/Hovd": "Час Хоўда (Хоўд)", + "Asia\/Irkutsk": "Іркуцкі час (Іркуцк)", + "Asia\/Jakarta": "Заходнеінданезійскі час (Джакарта)", + "Asia\/Jayapura": "Усходнеінданезійскі час (Джаяпура)", + "Asia\/Jerusalem": "Ізраільскі час (Іерусалім)", + "Asia\/Kabul": "Афганістанскі час (Кабул)", + "Asia\/Karachi": "Пакістанскі час (Карачы)", + "Asia\/Katmandu": "Непальскі час (Катманду)", + "Asia\/Khandyga": "Якуцкі час (Хандыга)", + "Asia\/Krasnoyarsk": "Краснаярскі час (Краснаярск)", + "Asia\/Kuala_Lumpur": "Час Малайзіі (Куала-Лумпур)", + "Asia\/Kuching": "Час Малайзіі (Кучынг)", + "Asia\/Kuwait": "Час Саудаўскай Аравіі (Кувейт)", + "Asia\/Macau": "Час Кітая (Макаа)", + "Asia\/Magadan": "Магаданскі час (Магадан)", + "Asia\/Makassar": "Цэнтральнаінданезійскі час (Макасар)", + "Asia\/Manila": "Філіпінскі час (Маніла)", + "Asia\/Muscat": "Час Персідскага заліва (Маскат)", + "Asia\/Nicosia": "Усходнееўрапейскі час (Нікасія)", + "Asia\/Novokuznetsk": "Краснаярскі час (Новакузнецк)", + "Asia\/Novosibirsk": "Новасібірскі час (Новасібірск)", + "Asia\/Omsk": "Омскі час (Омск)", + "Asia\/Oral": "Заходнеказахстанскі час (Уральск)", + "Asia\/Phnom_Penh": "Індакітайскі час (Пнампень)", + "Asia\/Pontianak": "Заходнеінданезійскі час (Пантыянак)", + "Asia\/Pyongyang": "Час Карэі (Пхеньян)", + "Asia\/Qatar": "Час Саудаўскай Аравіі (Катар)", + "Asia\/Qostanay": "Усходнеказахстанскі час (Qostanay)", + "Asia\/Qyzylorda": "Заходнеказахстанскі час (Кзыларда)", + "Asia\/Rangoon": "Час М’янмы (Рангун)", + "Asia\/Riyadh": "Час Саудаўскай Аравіі (Эр-Рыяд)", + "Asia\/Saigon": "Індакітайскі час (Хашымін)", + "Asia\/Sakhalin": "Сахалінскі час (Сахалін)", + "Asia\/Samarkand": "Час Узбекістана (Самарканд)", + "Asia\/Seoul": "Час Карэі (Сеул)", + "Asia\/Shanghai": "Час Кітая (Шанхай)", + "Asia\/Singapore": "Сінгапурскі час (Сінгапур)", + "Asia\/Srednekolymsk": "Магаданскі час (Сярэднекалымск)", + "Asia\/Taipei": "Час Тайбэя (Тайбэй)", + "Asia\/Tashkent": "Час Узбекістана (Ташкент)", + "Asia\/Tbilisi": "Грузінскі час (Тбілісі)", + "Asia\/Tehran": "Іранскі час (Тэгеран)", + "Asia\/Thimphu": "Час Бутана (Тхімпху)", + "Asia\/Tokyo": "Час Японіі (Токіа)", + "Asia\/Ulaanbaatar": "Час Улан-Батара (Улан-Батар)", + "Asia\/Ust-Nera": "Уладзівастоцкі час (Вусць-Нера)", + "Asia\/Vientiane": "Індакітайскі час (В’енцьян)", + "Asia\/Vladivostok": "Уладзівастоцкі час (Уладзівасток)", + "Asia\/Yakutsk": "Якуцкі час (Якуцк)", + "Asia\/Yekaterinburg": "Екацярынбургскі час (Екацярынбург)", + "Asia\/Yerevan": "Час Арменіі (Ерэван)", + "Atlantic\/Azores": "Час Азорскіх астравоў (Азорскія астравы)", + "Atlantic\/Bermuda": "Атлантычны час (Бермудскія астравы)", + "Atlantic\/Canary": "Заходнееўрапейскі час (Канарскія астравы)", + "Atlantic\/Cape_Verde": "Час Каба-Вердэ (Каба-Вердэ)", + "Atlantic\/Faeroe": "Заходнееўрапейскі час (Фарэрскія астравы)", + "Atlantic\/Madeira": "Заходнееўрапейскі час (Мадэйра)", + "Atlantic\/Reykjavik": "Час па Грынвічы (Рэйк’явік)", + "Atlantic\/South_Georgia": "Час Паўднёвай Джорджыі (Паўднёвая Джорджыя)", + "Atlantic\/St_Helena": "Час па Грынвічы (Востраў Святой Алены)", + "Atlantic\/Stanley": "Час Фалклендскіх астравоў (Стэнлі)", + "Australia\/Adelaide": "Час цэнтральнай Аўстраліі (Адэлаіда)", + "Australia\/Brisbane": "Час усходняй Аўстраліі (Брысбен)", + "Australia\/Broken_Hill": "Час цэнтральнай Аўстраліі (Брокен-Хіл)", + "Australia\/Currie": "Час усходняй Аўстраліі (Керы)", + "Australia\/Darwin": "Час цэнтральнай Аўстраліі (Дарвін)", + "Australia\/Eucla": "Цэнтральна-заходні час Аўстраліі (Юкла)", + "Australia\/Hobart": "Час усходняй Аўстраліі (Хобарт)", + "Australia\/Lindeman": "Час усходняй Аўстраліі (Ліндэман)", + "Australia\/Lord_Howe": "Час Лорд-Хау (Лорд-Хау)", + "Australia\/Melbourne": "Час усходняй Аўстраліі (Мельбурн)", + "Australia\/Perth": "Час заходняй Аўстраліі (Перт)", + "Australia\/Sydney": "Час усходняй Аўстраліі (Сідней)", + "CST6CDT": "Паўночнаамерыканскі цэнтральны час", + "EST5EDT": "Паўночнаамерыканскі ўсходні час", + "Etc\/GMT": "Час па Грынвічы", + "Etc\/UTC": "Універсальны каардынаваны час", + "Europe\/Amsterdam": "Цэнтральнаеўрапейскі час (Амстэрдам)", + "Europe\/Andorra": "Цэнтральнаеўрапейскі час (Андора)", + "Europe\/Astrakhan": "Маскоўскі час (Астрахань)", + "Europe\/Athens": "Усходнееўрапейскі час (Афіны)", + "Europe\/Belgrade": "Цэнтральнаеўрапейскі час (Бялград)", + "Europe\/Berlin": "Цэнтральнаеўрапейскі час (Берлін)", + "Europe\/Bratislava": "Цэнтральнаеўрапейскі час (Браціслава)", + "Europe\/Brussels": "Цэнтральнаеўрапейскі час (Брусель)", + "Europe\/Bucharest": "Усходнееўрапейскі час (Бухарэст)", + "Europe\/Budapest": "Цэнтральнаеўрапейскі час (Будапешт)", + "Europe\/Busingen": "Цэнтральнаеўрапейскі час (Бюзінген)", + "Europe\/Chisinau": "Усходнееўрапейскі час (Кішынёў)", + "Europe\/Copenhagen": "Цэнтральнаеўрапейскі час (Капенгаген)", + "Europe\/Dublin": "Час па Грынвічы (Дублін)", + "Europe\/Gibraltar": "Цэнтральнаеўрапейскі час (Гібралтар)", + "Europe\/Guernsey": "Час па Грынвічы (Гернсі)", + "Europe\/Helsinki": "Усходнееўрапейскі час (Хельсінкі)", + "Europe\/Isle_of_Man": "Час па Грынвічы (Востраў Мэн)", + "Europe\/Jersey": "Час па Грынвічы (Джэрсі)", + "Europe\/Kaliningrad": "Усходнееўрапейскі час (Калінінград)", + "Europe\/Kiev": "Усходнееўрапейскі час (Кіеў)", + "Europe\/Lisbon": "Заходнееўрапейскі час (Лісабон)", + "Europe\/Ljubljana": "Цэнтральнаеўрапейскі час (Любляна)", + "Europe\/London": "Час па Грынвічы (Лондан)", + "Europe\/Luxembourg": "Цэнтральнаеўрапейскі час (Люксембург)", + "Europe\/Madrid": "Цэнтральнаеўрапейскі час (Мадрыд)", + "Europe\/Malta": "Цэнтральнаеўрапейскі час (Мальта)", + "Europe\/Mariehamn": "Усходнееўрапейскі час (Марыехамн)", + "Europe\/Minsk": "Маскоўскі час (Мінск)", + "Europe\/Monaco": "Цэнтральнаеўрапейскі час (Манака)", + "Europe\/Moscow": "Маскоўскі час (Масква)", + "Europe\/Oslo": "Цэнтральнаеўрапейскі час (Осла)", + "Europe\/Paris": "Цэнтральнаеўрапейскі час (Парыж)", + "Europe\/Podgorica": "Цэнтральнаеўрапейскі час (Падгорыца)", + "Europe\/Prague": "Цэнтральнаеўрапейскі час (Прага)", + "Europe\/Riga": "Усходнееўрапейскі час (Рыга)", + "Europe\/Rome": "Цэнтральнаеўрапейскі час (Рым)", + "Europe\/San_Marino": "Цэнтральнаеўрапейскі час (Сан-Марына)", + "Europe\/Sarajevo": "Цэнтральнаеўрапейскі час (Сараева)", + "Europe\/Saratov": "Маскоўскі час (Саратаў)", + "Europe\/Simferopol": "Маскоўскі час (Сімферопаль)", + "Europe\/Skopje": "Цэнтральнаеўрапейскі час (Скоп’е)", + "Europe\/Sofia": "Усходнееўрапейскі час (Сафія)", + "Europe\/Stockholm": "Цэнтральнаеўрапейскі час (Стакгольм)", + "Europe\/Tallinn": "Усходнееўрапейскі час (Талін)", + "Europe\/Tirane": "Цэнтральнаеўрапейскі час (Тырана)", + "Europe\/Ulyanovsk": "Маскоўскі час (Ульянаўск)", + "Europe\/Uzhgorod": "Усходнееўрапейскі час (Ужгарад)", + "Europe\/Vaduz": "Цэнтральнаеўрапейскі час (Вадуц)", + "Europe\/Vatican": "Цэнтральнаеўрапейскі час (Ватыкан)", + "Europe\/Vienna": "Цэнтральнаеўрапейскі час (Вена)", + "Europe\/Vilnius": "Усходнееўрапейскі час (Вільнюс)", + "Europe\/Volgograd": "Валгаградскі час (Валгаград)", + "Europe\/Warsaw": "Цэнтральнаеўрапейскі час (Варшава)", + "Europe\/Zagreb": "Цэнтральнаеўрапейскі час (Заграб)", + "Europe\/Zaporozhye": "Усходнееўрапейскі час (Запарожжа)", + "Europe\/Zurich": "Цэнтральнаеўрапейскі час (Цюрых)", + "Indian\/Antananarivo": "Усходнеафрыканскі час (Антананарыву)", + "Indian\/Chagos": "Час Індыйскага акіяна (Чагас)", + "Indian\/Christmas": "Час вострава Каляд (Востраў Каляд)", + "Indian\/Cocos": "Час Какосавых астравоў (Какосавыя астравы)", + "Indian\/Comoro": "Усходнеафрыканскі час (Камор)", + "Indian\/Kerguelen": "Час Французскай паўднёва-антарктычнай тэрыторыі (Кергелен)", + "Indian\/Mahe": "Час Сейшэльскіх астравоў (Маэ)", + "Indian\/Maldives": "Час Мальдываў (Мальдывы)", + "Indian\/Mauritius": "Час Маўрыкія (Маўрыкій)", + "Indian\/Mayotte": "Усходнеафрыканскі час (Маёта)", + "Indian\/Reunion": "Час Рэюньёна (Рэюньён)", + "MST7MDT": "Паўночнаамерыканскі горны час", + "PST8PDT": "Ціхаакіянскі час", + "Pacific\/Apia": "Час Апіі (Апія)", + "Pacific\/Auckland": "Час Новай Зеландыі (Окленд)", + "Pacific\/Bougainville": "Час Папуа-Новай Гвінеі (Бугенвіль)", + "Pacific\/Chatham": "Час Чатэма (Чатэм)", + "Pacific\/Easter": "Час вострава Пасхі (Пасхі востраў)", + "Pacific\/Efate": "Час Вануату (Эфатэ)", + "Pacific\/Enderbury": "Час астравоў Фенікс (Эндэрберы)", + "Pacific\/Fakaofo": "Час Такелау (Факаофа)", + "Pacific\/Fiji": "Час Фіджы (Фіджы)", + "Pacific\/Funafuti": "Час Тувалу (Фунафуці)", + "Pacific\/Galapagos": "Стандартны час Галапагоскіх астравоў (Галапагас)", + "Pacific\/Gambier": "Час астравоў Гамб’е (Астравы Гамб’е)", + "Pacific\/Guadalcanal": "Час Саламонавых астравоў (Гуадалканал)", + "Pacific\/Guam": "Час Чамора (Гуам)", + "Pacific\/Honolulu": "Гавайска-Алеуцкі час (Ганалулу)", + "Pacific\/Johnston": "Гавайска-Алеуцкі час (Джонстан)", + "Pacific\/Kiritimati": "Час астравоў Лайн (Кірыцімаці)", + "Pacific\/Kosrae": "Час астравоў Кусаіе (Кусаіе)", + "Pacific\/Kwajalein": "Час Маршалавых астравоў (Кваджалейн)", + "Pacific\/Majuro": "Час Маршалавых астравоў (Маджура)", + "Pacific\/Marquesas": "Час Маркізскіх астравоў (Маркізскія астравы)", + "Pacific\/Midway": "Час Самоа (Мідуэй)", + "Pacific\/Nauru": "Час Науру (Науру)", + "Pacific\/Niue": "Час Ніуэ (Ніуэ)", + "Pacific\/Norfolk": "Час вострава Норфалк (Норфалк)", + "Pacific\/Noumea": "Час Новай Каледоніі (Нумеа)", + "Pacific\/Pago_Pago": "Час Самоа (Пага-Пага)", + "Pacific\/Palau": "Час Палау (Палау)", + "Pacific\/Pitcairn": "Час вострава Піткэрн (Піткэрн)", + "Pacific\/Ponape": "Час вострава Понпеі (Понпеі)", + "Pacific\/Port_Moresby": "Час Папуа-Новай Гвінеі (Порт-Морсбі)", + "Pacific\/Rarotonga": "Час астравоў Кука (Раратонга)", + "Pacific\/Saipan": "Час Чамора (Сайпан)", + "Pacific\/Tahiti": "Час Таіці (Таіці)", + "Pacific\/Tarawa": "Час астравоў Гілберта (Тарава)", + "Pacific\/Tongatapu": "Час Тонга (Тангатапу)", + "Pacific\/Truk": "Час Чуук (Чуук)", + "Pacific\/Wake": "Час вострава Уэйк (Уэйк)", + "Pacific\/Wallis": "Час астравоў Уоліс і Футуна (Уоліс)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/bg.json b/src/Symfony/Component/Intl/Resources/data/timezones/bg.json new file mode 100644 index 0000000000000..5fe89d12ea05f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/bg.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Средно гринуичко време (Абиджан)", + "Africa\/Accra": "Средно гринуичко време (Акра)", + "Africa\/Addis_Ababa": "Източноафриканско време (Адис Абеба)", + "Africa\/Algiers": "Централноевропейско време (Алжир)", + "Africa\/Asmera": "Източноафриканско време (Асмара)", + "Africa\/Bamako": "Средно гринуичко време (Бамако)", + "Africa\/Bangui": "Западноафриканско време (Бангуи)", + "Africa\/Banjul": "Средно гринуичко време (Банджул)", + "Africa\/Bissau": "Средно гринуичко време (Бисау)", + "Africa\/Blantyre": "Централноафриканско време (Блантайър)", + "Africa\/Brazzaville": "Западноафриканско време (Бразавил)", + "Africa\/Bujumbura": "Централноафриканско време (Бужумбура)", + "Africa\/Cairo": "Източноевропейско време (Кайро)", + "Africa\/Casablanca": "Западноевропейско време (Казабланка)", + "Africa\/Ceuta": "Централноевропейско време (Сеута)", + "Africa\/Conakry": "Средно гринуичко време (Конакри)", + "Africa\/Dakar": "Средно гринуичко време (Дакар)", + "Africa\/Dar_es_Salaam": "Източноафриканско време (Дар ес Салам)", + "Africa\/Djibouti": "Източноафриканско време (Джибути)", + "Africa\/Douala": "Западноафриканско време (Дуала)", + "Africa\/El_Aaiun": "Западноевропейско време (Ел Аюн)", + "Africa\/Freetown": "Средно гринуичко време (Фрийтаун)", + "Africa\/Gaborone": "Централноафриканско време (Габороне)", + "Africa\/Harare": "Централноафриканско време (Хараре)", + "Africa\/Johannesburg": "Южноафриканско време (Йоханесбург)", + "Africa\/Juba": "Източноафриканско време (Джуба)", + "Africa\/Kampala": "Източноафриканско време (Кампала)", + "Africa\/Khartoum": "Централноафриканско време (Хартум)", + "Africa\/Kigali": "Централноафриканско време (Кигали)", + "Africa\/Kinshasa": "Западноафриканско време (Киншаса)", + "Africa\/Lagos": "Западноафриканско време (Лагос)", + "Africa\/Libreville": "Западноафриканско време (Либревил)", + "Africa\/Lome": "Средно гринуичко време (Ломе)", + "Africa\/Luanda": "Западноафриканско време (Луанда)", + "Africa\/Lubumbashi": "Централноафриканско време (Лубумбаши)", + "Africa\/Lusaka": "Централноафриканско време (Лусака)", + "Africa\/Malabo": "Западноафриканско време (Малабо)", + "Africa\/Maputo": "Централноафриканско време (Мапуто)", + "Africa\/Maseru": "Южноафриканско време (Масеру)", + "Africa\/Mbabane": "Южноафриканско време (Мбабане)", + "Africa\/Mogadishu": "Източноафриканско време (Могадишу)", + "Africa\/Monrovia": "Средно гринуичко време (Монровия)", + "Africa\/Nairobi": "Източноафриканско време (Найроби)", + "Africa\/Ndjamena": "Западноафриканско време (Нджамена)", + "Africa\/Niamey": "Западноафриканско време (Ниамей)", + "Africa\/Nouakchott": "Средно гринуичко време (Нуакшот)", + "Africa\/Ouagadougou": "Средно гринуичко време (Уагадугу)", + "Africa\/Porto-Novo": "Западноафриканско време (Порто Ново)", + "Africa\/Sao_Tome": "Средно гринуичко време (Сао Томе)", + "Africa\/Tripoli": "Източноевропейско време (Триполи)", + "Africa\/Tunis": "Централноевропейско време (Тунис)", + "Africa\/Windhoek": "Централноафриканско време (Виндхук)", + "America\/Adak": "Хавайско-алеутско време (Адак)", + "America\/Anchorage": "Аляска (Анкъридж)", + "America\/Anguilla": "Северноамериканско атлантическо време (Ангуила)", + "America\/Antigua": "Северноамериканско атлантическо време (Антигуа)", + "America\/Araguaina": "Бразилско време (Арагуайна)", + "America\/Argentina\/La_Rioja": "Аржентинско време (Ла Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аржентинско време (Рио Галегос)", + "America\/Argentina\/Salta": "Аржентинско време (Салта)", + "America\/Argentina\/San_Juan": "Аржентинско време (Сан Хуан)", + "America\/Argentina\/San_Luis": "Западноаржентинско време (Сан Луис)", + "America\/Argentina\/Tucuman": "Аржентинско време (Тукуман)", + "America\/Argentina\/Ushuaia": "Аржентинско време (Ушуая)", + "America\/Aruba": "Северноамериканско атлантическо време (Аруба)", + "America\/Asuncion": "Парагвайско време (Асунсион)", + "America\/Bahia": "Бразилско време (Баия)", + "America\/Bahia_Banderas": "Северноамериканско централно време (Баия де Бандерас)", + "America\/Barbados": "Северноамериканско атлантическо време (Барбадос)", + "America\/Belem": "Бразилско време (Белем)", + "America\/Belize": "Северноамериканско централно време (Белиз)", + "America\/Blanc-Sablon": "Северноамериканско атлантическо време (Блан-Саблон)", + "America\/Boa_Vista": "Амазонско време (Боа Виста)", + "America\/Bogota": "Колумбийско време (Богота)", + "America\/Boise": "Северноамериканско планинско време (Бойси)", + "America\/Buenos_Aires": "Аржентинско време (Буенос Айрес)", + "America\/Cambridge_Bay": "Северноамериканско планинско време (Кеймбридж Бей)", + "America\/Campo_Grande": "Амазонско време (Кампо Гранде)", + "America\/Cancun": "Северноамериканско източно време (Канкун)", + "America\/Caracas": "Венецуелско време (Каракас)", + "America\/Catamarca": "Аржентинско време (Катамарка)", + "America\/Cayenne": "Френска Гвиана (Кайен)", + "America\/Cayman": "Северноамериканско източно време (Кайманови острови)", + "America\/Chicago": "Северноамериканско централно време (Чикаго)", + "America\/Chihuahua": "Мексиканско тихоокеанско време (Чиуауа)", + "America\/Coral_Harbour": "Северноамериканско източно време (Корал Харбър)", + "America\/Cordoba": "Аржентинско време (Кордоба)", + "America\/Costa_Rica": "Северноамериканско централно време (Коста Рика)", + "America\/Creston": "Северноамериканско планинско време (Крестън)", + "America\/Cuiaba": "Амазонско време (Чуяба)", + "America\/Curacao": "Северноамериканско атлантическо време (Кюрасао)", + "America\/Danmarkshavn": "Средно гринуичко време (Данмарксхавн)", + "America\/Dawson": "Северноамериканско тихоокеанско време (Доусън)", + "America\/Dawson_Creek": "Северноамериканско планинско време (Доусън Крийк)", + "America\/Denver": "Северноамериканско планинско време (Денвър)", + "America\/Detroit": "Северноамериканско източно време (Детройт)", + "America\/Dominica": "Северноамериканско атлантическо време (Доминика)", + "America\/Edmonton": "Северноамериканско планинско време (Едмънтън)", + "America\/El_Salvador": "Северноамериканско централно време (Салвадор)", + "America\/Fort_Nelson": "Северноамериканско планинско време (Форт Нелсън)", + "America\/Fortaleza": "Бразилско време (Форталеза)", + "America\/Glace_Bay": "Северноамериканско атлантическо време (Глейс Бей)", + "America\/Godthab": "Западногренландско време (Нуук)", + "America\/Goose_Bay": "Северноамериканско атлантическо време (Гус Бей)", + "America\/Grand_Turk": "Северноамериканско източно време (Гранд Търк)", + "America\/Grenada": "Северноамериканско атлантическо време (Гренада)", + "America\/Guadeloupe": "Северноамериканско атлантическо време (Гваделупа)", + "America\/Guatemala": "Северноамериканско централно време (Гватемала)", + "America\/Guayaquil": "Еквадорско време (Гуаякил)", + "America\/Guyana": "Гаяна (Гаяна)", + "America\/Halifax": "Северноамериканско атлантическо време (Халифакс)", + "America\/Havana": "Кубинско време (Хавана)", + "America\/Hermosillo": "Мексиканско тихоокеанско време (Ермосильо)", + "America\/Indiana\/Knox": "Северноамериканско централно време (Нокс)", + "America\/Indiana\/Marengo": "Северноамериканско източно време (Маренго)", + "America\/Indiana\/Petersburg": "Северноамериканско източно време (Питърсбърг)", + "America\/Indiana\/Tell_City": "Северноамериканско централно време (Тел Сити)", + "America\/Indiana\/Vevay": "Северноамериканско източно време (Виви)", + "America\/Indiana\/Vincennes": "Северноамериканско източно време (Винсенс)", + "America\/Indiana\/Winamac": "Северноамериканско източно време (Уинамак)", + "America\/Indianapolis": "Северноамериканско източно време (Индианаполис)", + "America\/Inuvik": "Северноамериканско планинско време (Инувик)", + "America\/Iqaluit": "Северноамериканско източно време (Иквалуит)", + "America\/Jamaica": "Северноамериканско източно време (Ямайка)", + "America\/Jujuy": "Аржентинско време (Хухуй)", + "America\/Juneau": "Аляска (Джуно)", + "America\/Kentucky\/Monticello": "Северноамериканско източно време (Монтичело)", + "America\/Kralendijk": "Северноамериканско атлантическо време (Кралендейк)", + "America\/La_Paz": "Боливийско време (Ла Пас)", + "America\/Lima": "Перуанско време (Лима)", + "America\/Los_Angeles": "Северноамериканско тихоокеанско време (Лос Анджелис)", + "America\/Louisville": "Северноамериканско източно време (Луисвил)", + "America\/Lower_Princes": "Северноамериканско атлантическо време (Лоуър принсес куотър)", + "America\/Maceio": "Бразилско време (Масейо)", + "America\/Managua": "Северноамериканско централно време (Манагуа)", + "America\/Manaus": "Амазонско време (Манаус)", + "America\/Marigot": "Северноамериканско атлантическо време (Мариго)", + "America\/Martinique": "Северноамериканско атлантическо време (Мартиника)", + "America\/Matamoros": "Северноамериканско централно време (Матаморос)", + "America\/Mazatlan": "Мексиканско тихоокеанско време (Масатлан)", + "America\/Mendoza": "Аржентинско време (Мендоса)", + "America\/Menominee": "Северноамериканско централно време (Меномини)", + "America\/Merida": "Северноамериканско централно време (Мерида)", + "America\/Metlakatla": "Аляска (Метлакатла)", + "America\/Mexico_City": "Северноамериканско централно време (Мексико Сити)", + "America\/Miquelon": "Сен Пиер и Микелон (Микелон)", + "America\/Moncton": "Северноамериканско атлантическо време (Монктон)", + "America\/Monterrey": "Северноамериканско централно време (Монтерей)", + "America\/Montevideo": "Уругвайско време (Монтевидео)", + "America\/Montserrat": "Северноамериканско атлантическо време (Монтсерат)", + "America\/Nassau": "Северноамериканско източно време (Насау)", + "America\/New_York": "Северноамериканско източно време (Ню Йорк)", + "America\/Nipigon": "Северноамериканско източно време (Нипигон)", + "America\/Nome": "Аляска (Ноум)", + "America\/Noronha": "Фернандо де Нороня (Нороня)", + "America\/North_Dakota\/Beulah": "Северноамериканско централно време (Бюла)", + "America\/North_Dakota\/Center": "Северноамериканско централно време (Сентър)", + "America\/North_Dakota\/New_Salem": "Северноамериканско централно време (Ню Сейлъм)", + "America\/Ojinaga": "Северноамериканско планинско време (Охинага)", + "America\/Panama": "Северноамериканско източно време (Панама)", + "America\/Pangnirtung": "Северноамериканско източно време (Пангниртунг)", + "America\/Paramaribo": "Суринамско време (Парамарибо)", + "America\/Phoenix": "Северноамериканско планинско време (Финикс)", + "America\/Port-au-Prince": "Северноамериканско източно време (Порт-о-Пренс)", + "America\/Port_of_Spain": "Северноамериканско атлантическо време (Порт ъф Спейн)", + "America\/Porto_Velho": "Амазонско време (Порто Вельо)", + "America\/Puerto_Rico": "Северноамериканско атлантическо време (Пуерто Рико)", + "America\/Punta_Arenas": "Чилийско време (Пунта Аренас)", + "America\/Rainy_River": "Северноамериканско централно време (Рейни Ривър)", + "America\/Rankin_Inlet": "Северноамериканско централно време (Ранкин Инлет)", + "America\/Recife": "Бразилско време (Ресифе)", + "America\/Regina": "Северноамериканско централно време (Риджайна)", + "America\/Resolute": "Северноамериканско централно време (Резолют)", + "America\/Santa_Isabel": "Северозападно мексиканско време (Санта Исабел)", + "America\/Santarem": "Бразилско време (Сантарем)", + "America\/Santiago": "Чилийско време (Сантяго)", + "America\/Santo_Domingo": "Северноамериканско атлантическо време (Санто Доминго)", + "America\/Sao_Paulo": "Бразилско време (Сао Пауло)", + "America\/Scoresbysund": "Източногренландско време (Сгорсбисон)", + "America\/Sitka": "Аляска (Ситка)", + "America\/St_Barthelemy": "Северноамериканско атлантическо време (Сен Бартелеми)", + "America\/St_Johns": "Нюфаундлендско време (Сейнт Джонс)", + "America\/St_Kitts": "Северноамериканско атлантическо време (Сейнт Китс)", + "America\/St_Lucia": "Северноамериканско атлантическо време (Сейнт Лусия)", + "America\/St_Thomas": "Северноамериканско атлантическо време (Сейнт Томас)", + "America\/St_Vincent": "Северноамериканско атлантическо време (Сейнт Винсънт)", + "America\/Swift_Current": "Северноамериканско централно време (Суифт Кърент)", + "America\/Tegucigalpa": "Северноамериканско централно време (Тегусигалпа)", + "America\/Thule": "Северноамериканско атлантическо време (Туле)", + "America\/Thunder_Bay": "Северноамериканско източно време (Тъндър Бей)", + "America\/Tijuana": "Северноамериканско тихоокеанско време (Тихуана)", + "America\/Toronto": "Северноамериканско източно време (Торонто)", + "America\/Tortola": "Северноамериканско атлантическо време (Тортола)", + "America\/Vancouver": "Северноамериканско тихоокеанско време (Ванкувър)", + "America\/Whitehorse": "Северноамериканско тихоокеанско време (Уайтхорс)", + "America\/Winnipeg": "Северноамериканско централно време (Уинипег)", + "America\/Yakutat": "Аляска (Якутат)", + "America\/Yellowknife": "Северноамериканско планинско време (Йелоунайф)", + "Antarctica\/Casey": "Западноавстралийско време (Кейси)", + "Antarctica\/Davis": "Дейвис (Дейвис)", + "Antarctica\/DumontDUrville": "Дюмон Дюрвил (Дюмон Дюрвил)", + "Antarctica\/Macquarie": "Маккуори (Маккуори)", + "Antarctica\/Mawson": "Моусън (Моусън)", + "Antarctica\/McMurdo": "Новозеландско време (Макмърдо)", + "Antarctica\/Palmer": "Чилийско време (Палмър)", + "Antarctica\/Rothera": "Ротера (Ротера)", + "Antarctica\/Syowa": "Шова (Шова)", + "Antarctica\/Troll": "Средно гринуичко време (Трол)", + "Antarctica\/Vostok": "Восток (Восток)", + "Arctic\/Longyearbyen": "Централноевропейско време (Лонгирбюен)", + "Asia\/Aden": "Арабско време (Аден)", + "Asia\/Almaty": "Източноказахстанско време (Алмати)", + "Asia\/Amman": "Източноевропейско време (Аман)", + "Asia\/Anadyr": "Анадир време (Анадир)", + "Asia\/Aqtau": "Западноказахстанско време (Актау)", + "Asia\/Aqtobe": "Западноказахстанско време (Актобе)", + "Asia\/Ashgabat": "Туркменистанско време (Ашхабад)", + "Asia\/Atyrau": "Западноказахстанско време (Атърау)", + "Asia\/Baghdad": "Арабско време (Багдад)", + "Asia\/Bahrain": "Арабско време (Бахрейн)", + "Asia\/Baku": "Азербайджанско време (Баку)", + "Asia\/Bangkok": "Индокитайско време (Банкок)", + "Asia\/Beirut": "Източноевропейско време (Бейрут)", + "Asia\/Bishkek": "Киргизстанско време (Бишкек)", + "Asia\/Brunei": "Бруней Даруссалам (Бруней)", + "Asia\/Calcutta": "Индийско време (Колката)", + "Asia\/Chita": "Якутско време (Чита)", + "Asia\/Choibalsan": "Чойбалсанско време (Чойбалсан)", + "Asia\/Colombo": "Индийско време (Коломбо)", + "Asia\/Damascus": "Източноевропейско време (Дамаск)", + "Asia\/Dhaka": "Бангладешко време (Дака)", + "Asia\/Dili": "Източнотиморско време (Дили)", + "Asia\/Dubai": "Персийски залив (Дубай)", + "Asia\/Dushanbe": "Таджикистанско време (Душанбе)", + "Asia\/Famagusta": "Източноевропейско време (Фамагуста)", + "Asia\/Gaza": "Източноевропейско време (Газа)", + "Asia\/Hebron": "Източноевропейско време (Хеброн)", + "Asia\/Hong_Kong": "Хонконгско време (Хонконг)", + "Asia\/Hovd": "Ховдско време (Ховд)", + "Asia\/Irkutsk": "Иркутско време (Иркутск)", + "Asia\/Jakarta": "Западноиндонезийско време (Джакарта)", + "Asia\/Jayapura": "Източноиндонезийско време (Джаяпура)", + "Asia\/Jerusalem": "Израелско време (Йерусалим)", + "Asia\/Kabul": "Афганистанско време (Кабул)", + "Asia\/Kamchatka": "Петропавловск-Камчатски време (Камчатка)", + "Asia\/Karachi": "Пакистанско време (Карачи)", + "Asia\/Katmandu": "Непалско време (Катманду)", + "Asia\/Khandyga": "Якутско време (Хандига)", + "Asia\/Krasnoyarsk": "Красноярско време (Красноярск)", + "Asia\/Kuala_Lumpur": "Малайзийско време (Куала Лумпур)", + "Asia\/Kuching": "Малайзийско време (Кучин)", + "Asia\/Kuwait": "Арабско време (Кувейт)", + "Asia\/Macau": "Китайско време (Макао)", + "Asia\/Magadan": "Магаданско време (Магадан)", + "Asia\/Makassar": "Централноиндонезийско време (Макасар)", + "Asia\/Manila": "Филипинско време (Манила)", + "Asia\/Muscat": "Персийски залив (Мускат)", + "Asia\/Nicosia": "Източноевропейско време (Никозия)", + "Asia\/Novokuznetsk": "Красноярско време (Новокузнецк)", + "Asia\/Novosibirsk": "Новосибирско време (Новосибирск)", + "Asia\/Omsk": "Омско време (Омск)", + "Asia\/Oral": "Западноказахстанско време (Арал)", + "Asia\/Phnom_Penh": "Индокитайско време (Пном Пен)", + "Asia\/Pontianak": "Западноиндонезийско време (Понтианак)", + "Asia\/Pyongyang": "Корейско време (Пхенян)", + "Asia\/Qatar": "Арабско време (Катар)", + "Asia\/Qostanay": "Източноказахстанско време (Qostanay)", + "Asia\/Qyzylorda": "Западноказахстанско време (Къзълорда)", + "Asia\/Rangoon": "Мианмарско време (Рангун)", + "Asia\/Riyadh": "Арабско време (Рияд)", + "Asia\/Saigon": "Индокитайско време (Хошимин)", + "Asia\/Sakhalin": "Сахалинско време (Сахалин)", + "Asia\/Samarkand": "Узбекистанско време (Самарканд)", + "Asia\/Seoul": "Корейско време (Сеул)", + "Asia\/Shanghai": "Китайско време (Шанхай)", + "Asia\/Singapore": "Сингапурско време (Сингапур)", + "Asia\/Srednekolymsk": "Магаданско време (Среднеколимск)", + "Asia\/Taipei": "Тайпе (Тайпе)", + "Asia\/Tashkent": "Узбекистанско време (Ташкент)", + "Asia\/Tbilisi": "Грузинско време (Тбилиси)", + "Asia\/Tehran": "Иранско време (Техеран)", + "Asia\/Thimphu": "Бутанско време (Тхимпху)", + "Asia\/Tokyo": "Японско време (Токио)", + "Asia\/Ulaanbaatar": "Уланбаторско време (Улан Батор)", + "Asia\/Ust-Nera": "Владивостокско време (Уст-Нера)", + "Asia\/Vientiane": "Индокитайско време (Виентян)", + "Asia\/Vladivostok": "Владивостокско време (Владивосток)", + "Asia\/Yakutsk": "Якутско време (Якутск)", + "Asia\/Yekaterinburg": "Екатеринбургско време (Екатеринбург)", + "Asia\/Yerevan": "Арменско време (Ереван)", + "Atlantic\/Azores": "Азорски острови (Азорски острови)", + "Atlantic\/Bermuda": "Северноамериканско атлантическо време (Бермудски острови)", + "Atlantic\/Canary": "Западноевропейско време (Канарски острови)", + "Atlantic\/Cape_Verde": "Кабо Верде (Кабо Верде)", + "Atlantic\/Faeroe": "Западноевропейско време (Фарьорски острови)", + "Atlantic\/Madeira": "Западноевропейско време (Мадейра)", + "Atlantic\/Reykjavik": "Средно гринуичко време (Рейкявик)", + "Atlantic\/South_Georgia": "Южна Джорджия (Южна Джорджия)", + "Atlantic\/St_Helena": "Средно гринуичко време (Света Елена)", + "Atlantic\/Stanley": "Фолклендски острови (Стенли)", + "Australia\/Adelaide": "Централноавстралийско време (Аделаида)", + "Australia\/Brisbane": "Източноавстралийско време (Бризбейн)", + "Australia\/Broken_Hill": "Централноавстралийско време (Броукън Хил)", + "Australia\/Currie": "Източноавстралийско време (Къри)", + "Australia\/Darwin": "Централноавстралийско време (Дарвин)", + "Australia\/Eucla": "Австралия – западно централно време (Юкла)", + "Australia\/Hobart": "Източноавстралийско време (Хобарт)", + "Australia\/Lindeman": "Източноавстралийско време (Линдеман)", + "Australia\/Lord_Howe": "Лорд Хау (Лорд Хау)", + "Australia\/Melbourne": "Източноавстралийско време (Мелбърн)", + "Australia\/Perth": "Западноавстралийско време (Пърт)", + "Australia\/Sydney": "Източноавстралийско време (Сидни)", + "CST6CDT": "Северноамериканско централно време", + "EST5EDT": "Северноамериканско източно време", + "Etc\/GMT": "Средно гринуичко време", + "Etc\/UTC": "Координирано универсално време", + "Europe\/Amsterdam": "Централноевропейско време (Амстердам)", + "Europe\/Andorra": "Централноевропейско време (Андора)", + "Europe\/Astrakhan": "Московско време (Астрахан)", + "Europe\/Athens": "Източноевропейско време (Атина)", + "Europe\/Belgrade": "Централноевропейско време (Белград)", + "Europe\/Berlin": "Централноевропейско време (Берлин)", + "Europe\/Bratislava": "Централноевропейско време (Братислава)", + "Europe\/Brussels": "Централноевропейско време (Брюксел)", + "Europe\/Bucharest": "Източноевропейско време (Букурещ)", + "Europe\/Budapest": "Централноевропейско време (Будапеща)", + "Europe\/Busingen": "Централноевропейско време (Бюзинген)", + "Europe\/Chisinau": "Източноевропейско време (Кишинев)", + "Europe\/Copenhagen": "Централноевропейско време (Копенхаген)", + "Europe\/Dublin": "Средно гринуичко време (Дъблин)", + "Europe\/Gibraltar": "Централноевропейско време (Гибралтар)", + "Europe\/Guernsey": "Средно гринуичко време (Гърнзи)", + "Europe\/Helsinki": "Източноевропейско време (Хелзинки)", + "Europe\/Isle_of_Man": "Средно гринуичко време (остров Ман)", + "Europe\/Jersey": "Средно гринуичко време (Джърси)", + "Europe\/Kaliningrad": "Източноевропейско време (Калининград)", + "Europe\/Kiev": "Източноевропейско време (Киев)", + "Europe\/Lisbon": "Западноевропейско време (Лисабон)", + "Europe\/Ljubljana": "Централноевропейско време (Любляна)", + "Europe\/London": "Средно гринуичко време (Лондон)", + "Europe\/Luxembourg": "Централноевропейско време (Люксембург)", + "Europe\/Madrid": "Централноевропейско време (Мадрид)", + "Europe\/Malta": "Централноевропейско време (Малта)", + "Europe\/Mariehamn": "Източноевропейско време (Мариехамн)", + "Europe\/Minsk": "Московско време (Минск)", + "Europe\/Monaco": "Централноевропейско време (Монако)", + "Europe\/Moscow": "Московско време (Москва)", + "Europe\/Oslo": "Централноевропейско време (Осло)", + "Europe\/Paris": "Централноевропейско време (Париж)", + "Europe\/Podgorica": "Централноевропейско време (Подгорица)", + "Europe\/Prague": "Централноевропейско време (Прага)", + "Europe\/Riga": "Източноевропейско време (Рига)", + "Europe\/Rome": "Централноевропейско време (Рим)", + "Europe\/Samara": "Самара време (Самара)", + "Europe\/San_Marino": "Централноевропейско време (Сан Марино)", + "Europe\/Sarajevo": "Централноевропейско време (Сараево)", + "Europe\/Saratov": "Московско време (Саратов)", + "Europe\/Simferopol": "Московско време (Симферопол)", + "Europe\/Skopje": "Централноевропейско време (Скопие)", + "Europe\/Sofia": "Източноевропейско време (София)", + "Europe\/Stockholm": "Централноевропейско време (Стокхолм)", + "Europe\/Tallinn": "Източноевропейско време (Талин)", + "Europe\/Tirane": "Централноевропейско време (Тирана)", + "Europe\/Ulyanovsk": "Московско време (Уляновск)", + "Europe\/Uzhgorod": "Източноевропейско време (Ужгород)", + "Europe\/Vaduz": "Централноевропейско време (Вадуц)", + "Europe\/Vatican": "Централноевропейско време (Ватикан)", + "Europe\/Vienna": "Централноевропейско време (Виена)", + "Europe\/Vilnius": "Източноевропейско време (Вилнюс)", + "Europe\/Volgograd": "Волгоградско време (Волгоград)", + "Europe\/Warsaw": "Централноевропейско време (Варшава)", + "Europe\/Zagreb": "Централноевропейско време (Загреб)", + "Europe\/Zaporozhye": "Източноевропейско време (Запорожие)", + "Europe\/Zurich": "Централноевропейско време (Цюрих)", + "Indian\/Antananarivo": "Източноафриканско време (Антананариво)", + "Indian\/Chagos": "Индийски океан (Чагос)", + "Indian\/Christmas": "Остров Рождество (Рождество)", + "Indian\/Cocos": "Кокосови острови (Кокосови острови)", + "Indian\/Comoro": "Източноафриканско време (Коморски острови)", + "Indian\/Kerguelen": "Френски южни и антарктически територии (Кергелен)", + "Indian\/Mahe": "Сейшели (Мае)", + "Indian\/Maldives": "Малдивско време (Малдиви)", + "Indian\/Mauritius": "Мавриций (Мавриций)", + "Indian\/Mayotte": "Източноафриканско време (Майот)", + "Indian\/Reunion": "Реюнион (Реюнион)", + "MST7MDT": "Северноамериканско планинско време", + "PST8PDT": "Северноамериканско тихоокеанско време", + "Pacific\/Apia": "Апия (Апия)", + "Pacific\/Auckland": "Новозеландско време (Окланд)", + "Pacific\/Bougainville": "Папуа Нова Гвинея (Бугенвил)", + "Pacific\/Chatham": "Чатъмско време (Чатам)", + "Pacific\/Easter": "Великденски остров (Великденски остров)", + "Pacific\/Efate": "Вануату (Ефате)", + "Pacific\/Enderbury": "Острови Феникс (Ендърбъри)", + "Pacific\/Fakaofo": "Токелау (Факаофо)", + "Pacific\/Fiji": "Фиджийско време (Фиджи)", + "Pacific\/Funafuti": "Тувалу (Фунафути)", + "Pacific\/Galapagos": "Галапагоско време (Галапагос)", + "Pacific\/Gambier": "Гамбие (Гамбие)", + "Pacific\/Guadalcanal": "Соломонови острови (Гуадалканал)", + "Pacific\/Guam": "Чаморско време (Гуам)", + "Pacific\/Honolulu": "Хавайско-алеутско време (Хонолулу)", + "Pacific\/Johnston": "Хавайско-алеутско време (Джонстън)", + "Pacific\/Kiritimati": "Екваториални острови (Киритимати)", + "Pacific\/Kosrae": "Кошрай (Кошрай)", + "Pacific\/Kwajalein": "Маршалови острови (Куаджалин)", + "Pacific\/Majuro": "Маршалови острови (Маджуро)", + "Pacific\/Marquesas": "Маркизки острови (Маркизки острови)", + "Pacific\/Midway": "Самоанско време (Мидуей)", + "Pacific\/Nauru": "Науру (Науру)", + "Pacific\/Niue": "Ниуе (Ниуе)", + "Pacific\/Norfolk": "Норфолкско време (Норфолк)", + "Pacific\/Noumea": "Новокаледонско време (Нумеа)", + "Pacific\/Pago_Pago": "Самоанско време (Паго Паго)", + "Pacific\/Palau": "Палау (Палау)", + "Pacific\/Pitcairn": "Питкерн (Питкерн)", + "Pacific\/Ponape": "Понапе (Понпей)", + "Pacific\/Port_Moresby": "Папуа Нова Гвинея (Порт Морсби)", + "Pacific\/Rarotonga": "Острови Кук (Раротонга)", + "Pacific\/Saipan": "Чаморско време (Сайпан)", + "Pacific\/Tahiti": "Таитянско време (Таити)", + "Pacific\/Tarawa": "Острови Гилбърт (Тарауа)", + "Pacific\/Tongatapu": "Тонга (Тонгатапу)", + "Pacific\/Truk": "Чуюк (Чуюк)", + "Pacific\/Wake": "Остров Уейк (Уейк)", + "Pacific\/Wallis": "Уолис и Футуна (Уолис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/bn.json b/src/Symfony/Component/Intl/Resources/data/timezones/bn.json new file mode 100644 index 0000000000000..908163fefb92d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/bn.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.36", + "Names": { + "Africa\/Abidjan": "গ্রীনিচ মিন টাইম (আবিদজান)", + "Africa\/Accra": "গ্রীনিচ মিন টাইম (আক্রা)", + "Africa\/Addis_Ababa": "পূর্ব আফ্রিকা সময় (আদ্দিস আবাবা)", + "Africa\/Algiers": "মধ্য ইউরোপীয় সময় (আলজিয়ার্স)", + "Africa\/Asmera": "পূর্ব আফ্রিকা সময় (অ্যাসমারাহু)", + "Africa\/Bamako": "গ্রীনিচ মিন টাইম (বাম্যাকো)", + "Africa\/Bangui": "পশ্চিম আফ্রিকা সময় (বাঙ্গুই)", + "Africa\/Banjul": "গ্রীনিচ মিন টাইম (বাঞ্জুল)", + "Africa\/Bissau": "গ্রীনিচ মিন টাইম (বিসোউ)", + "Africa\/Blantyre": "মধ্য আফ্রিকা সময় (ব্ল্যানটায়ের)", + "Africa\/Brazzaville": "পশ্চিম আফ্রিকা সময় (ব্রাজাভিলি)", + "Africa\/Bujumbura": "মধ্য আফ্রিকা সময় (বুজুমবুরহু)", + "Africa\/Cairo": "পূর্ব ইউরোপীয় সময় (কায়রো)", + "Africa\/Casablanca": "পশ্চিম ইউরোপীয় সময় (কাসাব্লাঙ্কা)", + "Africa\/Ceuta": "মধ্য ইউরোপীয় সময় (সেউটা)", + "Africa\/Conakry": "গ্রীনিচ মিন টাইম (কনাক্রি)", + "Africa\/Dakar": "গ্রীনিচ মিন টাইম (ডাকার)", + "Africa\/Dar_es_Salaam": "পূর্ব আফ্রিকা সময় (দার এস সালাম)", + "Africa\/Djibouti": "পূর্ব আফ্রিকা সময় (জিবুটি)", + "Africa\/Douala": "পশ্চিম আফ্রিকা সময় (ডোয়ালা)", + "Africa\/El_Aaiun": "পশ্চিম ইউরোপীয় সময় (এল আহইউন)", + "Africa\/Freetown": "গ্রীনিচ মিন টাইম (ফ্রীটাউন)", + "Africa\/Gaborone": "মধ্য আফ্রিকা সময় (গ্যাবুরনি)", + "Africa\/Harare": "মধ্য আফ্রিকা সময় (হারারে)", + "Africa\/Johannesburg": "দক্ষিণ আফ্রিকা মানক সময় (জোহানেসবার্গ)", + "Africa\/Juba": "পূর্ব আফ্রিকা সময় (জুবা)", + "Africa\/Kampala": "পূর্ব আফ্রিকা সময় (কামপালা)", + "Africa\/Khartoum": "মধ্য আফ্রিকা সময় (খার্তুম)", + "Africa\/Kigali": "মধ্য আফ্রিকা সময় (কিগালি)", + "Africa\/Kinshasa": "পশ্চিম আফ্রিকা সময় (কিনশাসা)", + "Africa\/Lagos": "পশ্চিম আফ্রিকা সময় (লাগোস)", + "Africa\/Libreville": "পশ্চিম আফ্রিকা সময় (লিব্রুভিল)", + "Africa\/Lome": "গ্রীনিচ মিন টাইম (লোমে)", + "Africa\/Luanda": "পশ্চিম আফ্রিকা সময় (লোয়ান্ডা)", + "Africa\/Lubumbashi": "মধ্য আফ্রিকা সময় (লুবুম্বাশি)", + "Africa\/Lusaka": "মধ্য আফ্রিকা সময় (লুসাকা)", + "Africa\/Malabo": "পশ্চিম আফ্রিকা সময় (মালাবো)", + "Africa\/Maputo": "মধ্য আফ্রিকা সময় (মাপুতো)", + "Africa\/Maseru": "দক্ষিণ আফ্রিকা মানক সময় (মাহসুরু)", + "Africa\/Mbabane": "দক্ষিণ আফ্রিকা মানক সময় (অমবাবান)", + "Africa\/Mogadishu": "পূর্ব আফ্রিকা সময় (মাওগাদিসু)", + "Africa\/Monrovia": "গ্রীনিচ মিন টাইম (মনরোভিয়া)", + "Africa\/Nairobi": "পূর্ব আফ্রিকা সময় (নাইরোবি)", + "Africa\/Ndjamena": "পশ্চিম আফ্রিকা সময় (এনজমেনা)", + "Africa\/Niamey": "পশ্চিম আফ্রিকা সময় (নিয়ামে)", + "Africa\/Nouakchott": "গ্রীনিচ মিন টাইম (নোয়াকশট)", + "Africa\/Ouagadougou": "গ্রীনিচ মিন টাইম (ওয়াহগুডোগু)", + "Africa\/Porto-Novo": "পশ্চিম আফ্রিকা সময় (পোর্টো-নোভো)", + "Africa\/Sao_Tome": "গ্রীনিচ মিন টাইম (সাও টোম)", + "Africa\/Tripoli": "পূর্ব ইউরোপীয় সময় (ত্রিপোলি)", + "Africa\/Tunis": "মধ্য ইউরোপীয় সময় (টিউনিস)", + "Africa\/Windhoek": "মধ্য আফ্রিকা সময় (উইনধোক)", + "America\/Adak": "হাওয়াই অ্যালিউটিয়ান সময় (আডাক)", + "America\/Anchorage": "আলাস্কা সময় (এনকোরেজ)", + "America\/Anguilla": "অতলান্তিকের সময় (অ্যাঙ্গুইলা)", + "America\/Antigua": "অতলান্তিকের সময় (অ্যান্টিগুয়া)", + "America\/Araguaina": "ব্রাসিলিয়া সময় (আরাগুয়াইনা)", + "America\/Argentina\/La_Rioja": "আর্জেন্টিনা সময় (লা রিওহা)", + "America\/Argentina\/Rio_Gallegos": "আর্জেন্টিনা সময় (রিও গায়েগোস)", + "America\/Argentina\/Salta": "আর্জেন্টিনা সময় (স্যালটা)", + "America\/Argentina\/San_Juan": "আর্জেন্টিনা সময় (সান জুয়ান)", + "America\/Argentina\/San_Luis": "পশ্চিমি আর্জেন্টিনা সময় (সান লুইস)", + "America\/Argentina\/Tucuman": "আর্জেন্টিনা সময় (টুকুমান)", + "America\/Argentina\/Ushuaia": "আর্জেন্টিনা সময় (উশুয়াইয়া)", + "America\/Aruba": "অতলান্তিকের সময় (এরুবা)", + "America\/Asuncion": "প্যারাগুয়ে সময় (আসুনসিয়ন)", + "America\/Bahia": "ব্রাসিলিয়া সময় (বাহিয়া)", + "America\/Bahia_Banderas": "কেন্দ্রীয় সময় (বাহিয়া বানড্রাস)", + "America\/Barbados": "অতলান্তিকের সময় (বার্বাডোজ)", + "America\/Belem": "ব্রাসিলিয়া সময় (বেলেম)", + "America\/Belize": "কেন্দ্রীয় সময় (বেলিজ)", + "America\/Blanc-Sablon": "অতলান্তিকের সময় (ব্লাঙ্ক-সাব্লোন)", + "America\/Boa_Vista": "অ্যামাজন সময় (বোয়া ভিস্তা)", + "America\/Bogota": "কোলোম্বিয়া সময় (বোগোটা)", + "America\/Boise": "পার্বত্য অঞ্চলের সময় (বয়জি)", + "America\/Buenos_Aires": "আর্জেন্টিনা সময় (বুয়েনোস আয়েরেস)", + "America\/Cambridge_Bay": "পার্বত্য অঞ্চলের সময় (কেমব্রিজ বে)", + "America\/Campo_Grande": "অ্যামাজন সময় (কাম্পো গ্রান্ডে)", + "America\/Cancun": "পূর্বাঞ্চলীয় সময় (ক্যানকুন)", + "America\/Caracas": "ভেনেজুয়েলা সময় (ক্যারাকাস)", + "America\/Catamarca": "আর্জেন্টিনা সময় (ক্যাটামার্কা)", + "America\/Cayenne": "ফরাসি গায়ানা সময় (কাহেন)", + "America\/Cayman": "পূর্বাঞ্চলীয় সময় (কামেন)", + "America\/Chicago": "কেন্দ্রীয় সময় (শিকাগো)", + "America\/Chihuahua": "মেক্সিকান প্রশান্ত মহাসাগরীয় সময় (চিহুয়াহুয়া)", + "America\/Coral_Harbour": "পূর্বাঞ্চলীয় সময় (আটিকোকান)", + "America\/Cordoba": "আর্জেন্টিনা সময় (কর্ডোবা)", + "America\/Costa_Rica": "কেন্দ্রীয় সময় (কোস্টারিকা)", + "America\/Creston": "পার্বত্য অঞ্চলের সময় (ক্রিস্টান)", + "America\/Cuiaba": "অ্যামাজন সময় (কুইয়াবা)", + "America\/Curacao": "অতলান্তিকের সময় (কুরাসাও)", + "America\/Danmarkshavn": "গ্রীনিচ মিন টাইম (ডানমার্কশ্যাভন)", + "America\/Dawson": "প্রশান্ত মহাসাগরীয় অঞ্চলের সময় (ডসোন)", + "America\/Dawson_Creek": "পার্বত্য অঞ্চলের সময় (ডসোন ক্রিক)", + "America\/Denver": "পার্বত্য অঞ্চলের সময় (ডেনভার)", + "America\/Detroit": "পূর্বাঞ্চলীয় সময় (ডেট্রোইট)", + "America\/Dominica": "অতলান্তিকের সময় (ডোমিনিকা)", + "America\/Edmonton": "পার্বত্য অঞ্চলের সময় (এডমন্টোন)", + "America\/El_Salvador": "কেন্দ্রীয় সময় (এল সালভাদোর)", + "America\/Fort_Nelson": "পার্বত্য অঞ্চলের সময় (ফোর্ট নেলসন)", + "America\/Fortaleza": "ব্রাসিলিয়া সময় (ফোর্টালেজা)", + "America\/Glace_Bay": "অতলান্তিকের সময় (গ্লাস বে)", + "America\/Godthab": "পশ্চিম গ্রীনল্যান্ড সময় (নুক)", + "America\/Goose_Bay": "অতলান্তিকের সময় (গুস বে)", + "America\/Grand_Turk": "পূর্বাঞ্চলীয় সময় (গ্র্যান্ড তুর্ক)", + "America\/Grenada": "অতলান্তিকের সময় (গ্রেনাডা)", + "America\/Guadeloupe": "অতলান্তিকের সময় (গুয়াদেলোপ)", + "America\/Guatemala": "কেন্দ্রীয় সময় (গুয়াতেমালা)", + "America\/Guayaquil": "ইকুয়েডর সময় (গোয়াইয়াকিল)", + "America\/Guyana": "গুয়ানা সময় (গায়ানা)", + "America\/Halifax": "অতলান্তিকের সময় (হ্যালিফ্যাক্স)", + "America\/Havana": "কিউবার সময় (হাভানা)", + "America\/Hermosillo": "মেক্সিকান প্রশান্ত মহাসাগরীয় সময় (হারমোসিল্লো)", + "America\/Indiana\/Knox": "কেন্দ্রীয় সময় (নক্স, ইন্ডিয়ানা)", + "America\/Indiana\/Marengo": "পূর্বাঞ্চলীয় সময় (মারেঙ্গো, ইন্ডিয়ানা)", + "America\/Indiana\/Petersburg": "পূর্বাঞ্চলীয় সময় (পিটারর্সবার্গ, ইন্ডিয়ানা)", + "America\/Indiana\/Tell_City": "কেন্দ্রীয় সময় (টেলসিটি, ইন্ডিয়ানা)", + "America\/Indiana\/Vevay": "পূর্বাঞ্চলীয় সময় (ভেভেয়, ইন্ডিয়ানা)", + "America\/Indiana\/Vincennes": "পূর্বাঞ্চলীয় সময় (ভিনসেন্নেস, ইন্ডিয়ানা)", + "America\/Indiana\/Winamac": "পূর্বাঞ্চলীয় সময় (উইনাম্যাক, ইন্ডিয়ানা)", + "America\/Indianapolis": "পূর্বাঞ্চলীয় সময় (ইন্ডিয়ানাপোলিস)", + "America\/Inuvik": "পার্বত্য অঞ্চলের সময় (ইনুভ্যাক)", + "America\/Iqaluit": "পূর্বাঞ্চলীয় সময় (ইকুয়ালুইট)", + "America\/Jamaica": "পূর্বাঞ্চলীয় সময় (জামাইকা)", + "America\/Jujuy": "আর্জেন্টিনা সময় (জুজুই)", + "America\/Juneau": "আলাস্কা সময় (জুনো)", + "America\/Kentucky\/Monticello": "পূর্বাঞ্চলীয় সময় (মন্টিচেলো, কেন্টাকি)", + "America\/Kralendijk": "অতলান্তিকের সময় (ক্রেলেন্ডাজিক)", + "America\/La_Paz": "বোলিভিয়া সময় (লা পাজ)", + "America\/Lima": "পেরু সময় (লিমা)", + "America\/Los_Angeles": "প্রশান্ত মহাসাগরীয় অঞ্চলের সময় (লস অ্যাঞ্জেলেস)", + "America\/Louisville": "পূর্বাঞ্চলীয় সময় (লুইসভিল)", + "America\/Lower_Princes": "অতলান্তিকের সময় (লোয়ার প্রিন্সেস কোয়ার্টার)", + "America\/Maceio": "ব্রাসিলিয়া সময় (মাসেয়ো)", + "America\/Managua": "কেন্দ্রীয় সময় (মানাগুয়া)", + "America\/Manaus": "অ্যামাজন সময় (মানাউস)", + "America\/Marigot": "অতলান্তিকের সময় (মারিগো)", + "America\/Martinique": "অতলান্তিকের সময় (মারটিনিক)", + "America\/Matamoros": "কেন্দ্রীয় সময় (মাতামোরস)", + "America\/Mazatlan": "মেক্সিকান প্রশান্ত মহাসাগরীয় সময় (মাজাটলান)", + "America\/Mendoza": "আর্জেন্টিনা সময় (মেন্ডোজা)", + "America\/Menominee": "কেন্দ্রীয় সময় (মেনোমিনি)", + "America\/Merida": "কেন্দ্রীয় সময় (মেরিডা)", + "America\/Metlakatla": "আলাস্কা সময় (মেটলাকাটলা)", + "America\/Mexico_City": "কেন্দ্রীয় সময় (মেক্সিকো সিটি)", + "America\/Miquelon": "সেন্ট পিয়ের ও মিকেলন সময় (মিকুলন)", + "America\/Moncton": "অতলান্তিকের সময় (মঙ্কটোন)", + "America\/Monterrey": "কেন্দ্রীয় সময় (মন্টেরি)", + "America\/Montevideo": "উরুগুয়ে সময় (মন্টেভিডিও)", + "America\/Montserrat": "অতলান্তিকের সময় (মন্তসেরাত)", + "America\/Nassau": "পূর্বাঞ্চলীয় সময় (নাসাউ)", + "America\/New_York": "পূর্বাঞ্চলীয় সময় (নিউইয়র্ক)", + "America\/Nipigon": "পূর্বাঞ্চলীয় সময় (নিপিগোন)", + "America\/Nome": "আলাস্কা সময় (নোম)", + "America\/Noronha": "ফার্নান্দো ডি নোরোনহা সময় (নরোন্‌হা)", + "America\/North_Dakota\/Beulah": "কেন্দ্রীয় সময় (বেউলা, উত্তর ডাকোটা)", + "America\/North_Dakota\/Center": "কেন্দ্রীয় সময় (মধ্য, উত্তর ডাকোটা)", + "America\/North_Dakota\/New_Salem": "কেন্দ্রীয় সময় (নিউ সালেম, উত্তর ডাকোটা)", + "America\/Ojinaga": "পার্বত্য অঞ্চলের সময় (ওজিনাগা)", + "America\/Panama": "পূর্বাঞ্চলীয় সময় (পানামা)", + "America\/Pangnirtung": "পূর্বাঞ্চলীয় সময় (প্যাঙ্গনির্টুং)", + "America\/Paramaribo": "সুরিনাম সময় (প্যারামেরিবো)", + "America\/Phoenix": "পার্বত্য অঞ্চলের সময় (ফিনিক্স)", + "America\/Port-au-Prince": "পূর্বাঞ্চলীয় সময় (পোর্ট-অহ-প্রিন্স)", + "America\/Port_of_Spain": "অতলান্তিকের সময় (পোর্ট অফ স্পেন)", + "America\/Porto_Velho": "অ্যামাজন সময় (পোর্তো ভেল্‌হো)", + "America\/Puerto_Rico": "অতলান্তিকের সময় (পুয়েরতো রিকো)", + "America\/Punta_Arenas": "চিলি সময় (পুন্টা আরেনাস)", + "America\/Rainy_River": "কেন্দ্রীয় সময় (রেইনি রিভার)", + "America\/Rankin_Inlet": "কেন্দ্রীয় সময় (র‌্যাঙ্কিন ইনলেট)", + "America\/Recife": "ব্রাসিলিয়া সময় (রেসিফে)", + "America\/Regina": "কেন্দ্রীয় সময় (রেজিনা)", + "America\/Resolute": "কেন্দ্রীয় সময় (রেসোলুট)", + "America\/Santa_Isabel": "উত্তরপশ্চিম মেক্সিকোর সময় (সান্তা ইসাবেল)", + "America\/Santarem": "ব্রাসিলিয়া সময় (সেনটুরেম)", + "America\/Santiago": "চিলি সময় (সান্টিয়াগো)", + "America\/Santo_Domingo": "অতলান্তিকের সময় (স্যান্টো ডোমিংগো)", + "America\/Sao_Paulo": "ব্রাসিলিয়া সময় (সাও পাউলো)", + "America\/Scoresbysund": "পূর্ব গ্রীনল্যান্ড সময় (ইটকুয়োরটুরমিট)", + "America\/Sitka": "আলাস্কা সময় (শিটকা)", + "America\/St_Barthelemy": "অতলান্তিকের সময় (সেন্ট.বার্থেলেমি)", + "America\/St_Johns": "নিউফাউন্ডল্যান্ড সময় (সেন্ট জন্স)", + "America\/St_Kitts": "অতলান্তিকের সময় (সেন্ট. কিটস)", + "America\/St_Lucia": "অতলান্তিকের সময় (সেন্ট. লুসিয়া)", + "America\/St_Thomas": "অতলান্তিকের সময় (সেন্ট. থমাস)", + "America\/St_Vincent": "অতলান্তিকের সময় (সেন্ট. ভিনসেন্ট)", + "America\/Swift_Current": "কেন্দ্রীয় সময় (সুইফ্ট কারেন্ট)", + "America\/Tegucigalpa": "কেন্দ্রীয় সময় (তেগুসিগালপা)", + "America\/Thule": "অতলান্তিকের সময় (থুলি)", + "America\/Thunder_Bay": "পূর্বাঞ্চলীয় সময় (থান্ডার বে)", + "America\/Tijuana": "প্রশান্ত মহাসাগরীয় অঞ্চলের সময় (তিজুয়ানা)", + "America\/Toronto": "পূর্বাঞ্চলীয় সময় (টোরন্টো)", + "America\/Tortola": "অতলান্তিকের সময় (টরটোলা)", + "America\/Vancouver": "প্রশান্ত মহাসাগরীয় অঞ্চলের সময় (ভ্যাঙ্কুভার)", + "America\/Whitehorse": "প্রশান্ত মহাসাগরীয় অঞ্চলের সময় (হোয়াইটহর্স)", + "America\/Winnipeg": "কেন্দ্রীয় সময় (উইনিপেগ)", + "America\/Yakutat": "আলাস্কা সময় (ইয়াকুটাট)", + "America\/Yellowknife": "পার্বত্য অঞ্চলের সময় (ইয়েলোনাইফ)", + "Antarctica\/Casey": "পশ্চিমি অস্ট্রেলীয় সময় (কেইসি)", + "Antarctica\/Davis": "ডেভিস সময় (ডেভিস)", + "Antarctica\/DumontDUrville": "ডুমন্ট-দ্য’উরভিলে সময় (ডুমন্ট ডি’উরভিল)", + "Antarctica\/Macquarie": "ম্যাককুরি দ্বীপ সময় (ম্যাককুয়্যারি)", + "Antarctica\/Mawson": "মসন সময় (মসোন)", + "Antarctica\/McMurdo": "নিউজিল্যান্ড সময় (ম্যাকমুর্ডো)", + "Antarctica\/Palmer": "চিলি সময় (পালমার)", + "Antarctica\/Rothera": "রথেরা সময় (রথেরা)", + "Antarctica\/Syowa": "সায়োওয়া সময় (সিওয়া)", + "Antarctica\/Troll": "গ্রীনিচ মিন টাইম (ট্রল)", + "Antarctica\/Vostok": "ভসটক সময় (ভস্টোক)", + "Arctic\/Longyearbyen": "মধ্য ইউরোপীয় সময় (লঞ্জিয়বিয়েঁন)", + "Asia\/Aden": "আরবি সময় (আহদেন)", + "Asia\/Almaty": "পূর্ব কাজাখাস্তান সময় (আলমাটি)", + "Asia\/Amman": "পূর্ব ইউরোপীয় সময় (আম্মান)", + "Asia\/Anadyr": "অনদ্য্র্ সময় (অ্যানাডির)", + "Asia\/Aqtau": "পশ্চিম কাজাখাস্তান সময় (আকটাউ)", + "Asia\/Aqtobe": "পশ্চিম কাজাখাস্তান সময় (আকটোবে)", + "Asia\/Ashgabat": "তুর্কমেনিস্তান সময় (আশগাবাত)", + "Asia\/Atyrau": "পশ্চিম কাজাখাস্তান সময় (অতিরাউ)", + "Asia\/Baghdad": "আরবি সময় (বাগদাদ)", + "Asia\/Bahrain": "আরবি সময় (বাহারিন)", + "Asia\/Baku": "আজারবাইজান সময় (বাকু)", + "Asia\/Bangkok": "ইন্দোচীন সময় (ব্যাংকক)", + "Asia\/Beirut": "পূর্ব ইউরোপীয় সময় (বেইরুট)", + "Asia\/Bishkek": "কিরগিস্তান সময় (বিশকেক)", + "Asia\/Brunei": "ব্রুনেই দারুসসালাম সময় (ব্রুনেই)", + "Asia\/Calcutta": "ভারতীয় মানক সময় (কোলকাতা)", + "Asia\/Chita": "ইয়াকুটাস্ক সময় (চিতা)", + "Asia\/Choibalsan": "চয়বালসন সময় (চোইবাল্‌স্যান)", + "Asia\/Colombo": "ভারতীয় মানক সময় (কলম্বো)", + "Asia\/Damascus": "পূর্ব ইউরোপীয় সময় (দামাস্কাস)", + "Asia\/Dhaka": "বাংলাদেশ সময় (ঢাকা)", + "Asia\/Dili": "পূর্ব টিমর সময় (দিলি)", + "Asia\/Dubai": "উপসাগরীয় মানক সময় (দুবাই)", + "Asia\/Dushanbe": "তাজাখাস্তান সময় (দুশানবে)", + "Asia\/Famagusta": "পূর্ব ইউরোপীয় সময় (ফামাগাস্তা)", + "Asia\/Gaza": "পূর্ব ইউরোপীয় সময় (গাজা)", + "Asia\/Hebron": "পূর্ব ইউরোপীয় সময় (হেব্রোন)", + "Asia\/Hong_Kong": "হং কং সময় (হং কং)", + "Asia\/Hovd": "হোভড সময় (হোভ্ড)", + "Asia\/Irkutsk": "ইরকুটস্ক সময় (ইরকুটস্ক)", + "Asia\/Jakarta": "পশ্চিমী ইন্দোনেশিয়া সময় (জাকার্তা)", + "Asia\/Jayapura": "পূর্ব ইন্দোনেশিয়া সময় (জয়াপুরা)", + "Asia\/Jerusalem": "ইজরায়েল সময় (জেরুজালেম)", + "Asia\/Kabul": "আফগানিস্তান সময় (কাবুল)", + "Asia\/Kamchatka": "পিত্রেপ্যাভলস্ক- ক্যামচ্যাটস্কি সময় (কামচাটকা)", + "Asia\/Karachi": "পাকিস্তান সময় (করাচি)", + "Asia\/Katmandu": "নেপাল সময় (কাঠমান্ডু)", + "Asia\/Khandyga": "ইয়াকুটাস্ক সময় (খানডিয়াগা)", + "Asia\/Krasnoyarsk": "ক্রাসনোয়ার্স্কি সময় (ক্রাসনোইয়ার্স্ক)", + "Asia\/Kuala_Lumpur": "মালয়েশিয়া সময় (কুয়ালালামপুর)", + "Asia\/Kuching": "মালয়েশিয়া সময় (কুচিং)", + "Asia\/Kuwait": "আরবি সময় (কুয়েত)", + "Asia\/Macau": "চীন সময় (ম্যাকাও)", + "Asia\/Magadan": "ম্যাগাডান সময় (ম্যাগাডান)", + "Asia\/Makassar": "কেন্দ্রীয় ইন্দোনেশিয়া সময় (মাকাসসার)", + "Asia\/Manila": "ফিলিপাইন সময় (ম্যানিলা)", + "Asia\/Muscat": "উপসাগরীয় মানক সময় (মাসকট)", + "Asia\/Nicosia": "পূর্ব ইউরোপীয় সময় (নিকোসিয়া)", + "Asia\/Novokuznetsk": "ক্রাসনোয়ার্স্কি সময় (নভকুয়েতস্নক)", + "Asia\/Novosibirsk": "নোভোসিবির্স্ক সময় (নভোসিবির্স্ক)", + "Asia\/Omsk": "ওমস্ক সময় (ওম্স্ক)", + "Asia\/Oral": "পশ্চিম কাজাখাস্তান সময় (ওরাল)", + "Asia\/Phnom_Penh": "ইন্দোচীন সময় (নম পেন)", + "Asia\/Pontianak": "পশ্চিমী ইন্দোনেশিয়া সময় (পন্টিয়ান্যাক)", + "Asia\/Pyongyang": "কোরিয়ান সময় (পিয়ংইয়ং)", + "Asia\/Qatar": "আরবি সময় (কাতার)", + "Asia\/Qostanay": "পূর্ব কাজাখাস্তান সময় (কোস্টানয়)", + "Asia\/Qyzylorda": "পশ্চিম কাজাখাস্তান সময় (কিজিলর্ডা)", + "Asia\/Rangoon": "মায়ানমার সময় (রেঙ্গুন)", + "Asia\/Riyadh": "আরবি সময় (রিয়াধ)", + "Asia\/Saigon": "ইন্দোচীন সময় (হো চি মিন শহর)", + "Asia\/Sakhalin": "সাখালিন সময় (সাখালিন)", + "Asia\/Samarkand": "উজবেকিস্তান সময় (সমরখন্দ)", + "Asia\/Seoul": "কোরিয়ান সময় (সিওল)", + "Asia\/Shanghai": "চীন সময় (সাংহাই)", + "Asia\/Singapore": "সিঙ্গাপুর মানক সময় (সিঙ্গাপুর)", + "Asia\/Srednekolymsk": "ম্যাগাডান সময় (স্রেদনেকোলয়মস্ক)", + "Asia\/Taipei": "তাইপেই সময় (তাইপেই)", + "Asia\/Tashkent": "উজবেকিস্তান সময় (তাসখন্দ)", + "Asia\/Tbilisi": "জর্জিয়া সময় (সিবিলিশি)", + "Asia\/Tehran": "ইরান সময় (তেহেরান)", + "Asia\/Thimphu": "ভুটান সময় (থিম্ফু)", + "Asia\/Tokyo": "জাপান সময় (টোকিও)", + "Asia\/Ulaanbaatar": "উলান বাতোর সময় (উলানবাতার)", + "Asia\/Ust-Nera": "ভ্লাদিভস্তক সময় (উস্ত- নেরা)", + "Asia\/Vientiane": "ইন্দোচীন সময় (ভিয়েনতায়েন)", + "Asia\/Vladivostok": "ভ্লাদিভস্তক সময় (ভ্লাদিভস্তোক)", + "Asia\/Yakutsk": "ইয়াকুটাস্ক সময় (ইয়াকুটস্ক)", + "Asia\/Yekaterinburg": "ইয়েকাতেরিনবুর্গ সময় (ইয়েকাটেরিনবার্গ)", + "Asia\/Yerevan": "আর্মেনিয়া সময় (ইয়েরাভান)", + "Atlantic\/Azores": "এজোরেস সময় (আজোরেস)", + "Atlantic\/Bermuda": "অতলান্তিকের সময় (বারমুডা)", + "Atlantic\/Canary": "পশ্চিম ইউরোপীয় সময় (কানেরি)", + "Atlantic\/Cape_Verde": "কেপ ভার্দ সময় (কেপ ভার্দ)", + "Atlantic\/Faeroe": "পশ্চিম ইউরোপীয় সময় (ফ্যারো)", + "Atlantic\/Madeira": "পশ্চিম ইউরোপীয় সময় (মাডেইরা)", + "Atlantic\/Reykjavik": "গ্রীনিচ মিন টাইম (রিকজাভিক)", + "Atlantic\/South_Georgia": "দক্ষিণ জর্জিয়া সময় (দক্ষিণ জর্জিয়া)", + "Atlantic\/St_Helena": "গ্রীনিচ মিন টাইম (সেন্ট. হেলেনা)", + "Atlantic\/Stanley": "ফকল্যান্ড দ্বীপপুঞ্জ সময় (স্টানলী)", + "Australia\/Adelaide": "কেন্দ্রীয় অস্ট্রেলীয় সময় (এ্যাডেলেইড)", + "Australia\/Brisbane": "পূর্ব অস্ট্রেলীয় সময় (ব্রিসবেন)", + "Australia\/Broken_Hill": "কেন্দ্রীয় অস্ট্রেলীয় সময় (ব্রোকেন হিল)", + "Australia\/Currie": "পূর্ব অস্ট্রেলীয় সময় (কিউরি)", + "Australia\/Darwin": "কেন্দ্রীয় অস্ট্রেলীয় সময় (ডারউইন)", + "Australia\/Eucla": "অস্ট্রেলীয় কেন্দ্রীয় পশ্চিমি সময় (ইউক্লা)", + "Australia\/Hobart": "পূর্ব অস্ট্রেলীয় সময় (হোবার্ট)", + "Australia\/Lindeman": "পূর্ব অস্ট্রেলীয় সময় (লিনডেম্যান)", + "Australia\/Lord_Howe": "লর্ড হাওয়ে সময় (লর্ড হাও)", + "Australia\/Melbourne": "পূর্ব অস্ট্রেলীয় সময় (মেলবোর্ন)", + "Australia\/Perth": "পশ্চিমি অস্ট্রেলীয় সময় (পার্থ)", + "Australia\/Sydney": "পূর্ব অস্ট্রেলীয় সময় (সিডনি)", + "CST6CDT": "কেন্দ্রীয় সময়", + "EST5EDT": "পূর্বাঞ্চলীয় সময়", + "Etc\/GMT": "গ্রীনিচ মিন টাইম", + "Etc\/UTC": "স্থানাংকিত আন্তর্জাতিক সময়", + "Europe\/Amsterdam": "মধ্য ইউরোপীয় সময় (আমস্টারডাম)", + "Europe\/Andorra": "মধ্য ইউরোপীয় সময় (অ্যান্ডোরা)", + "Europe\/Astrakhan": "মস্কো সময় (আসট্রাখান)", + "Europe\/Athens": "পূর্ব ইউরোপীয় সময় (এথেন্স)", + "Europe\/Belgrade": "মধ্য ইউরোপীয় সময় (বেলগ্রেড)", + "Europe\/Berlin": "মধ্য ইউরোপীয় সময় (বার্লিন)", + "Europe\/Bratislava": "মধ্য ইউরোপীয় সময় (ব্রাতিস্লাভা)", + "Europe\/Brussels": "মধ্য ইউরোপীয় সময় (ব্রাসেলস)", + "Europe\/Bucharest": "পূর্ব ইউরোপীয় সময় (বুখারেস্ট)", + "Europe\/Budapest": "মধ্য ইউরোপীয় সময় (বুডাপেস্ট)", + "Europe\/Busingen": "মধ্য ইউরোপীয় সময় (বুসিনগেন)", + "Europe\/Chisinau": "পূর্ব ইউরোপীয় সময় (কিসিনাহু)", + "Europe\/Copenhagen": "মধ্য ইউরোপীয় সময় (কোপেনহেগেন)", + "Europe\/Dublin": "গ্রীনিচ মিন টাইম (ডাবলিন)", + "Europe\/Gibraltar": "মধ্য ইউরোপীয় সময় (জিব্রাল্টার)", + "Europe\/Guernsey": "গ্রীনিচ মিন টাইম (গুয়ার্নসি)", + "Europe\/Helsinki": "পূর্ব ইউরোপীয় সময় (হেলসিঙ্কি)", + "Europe\/Isle_of_Man": "গ্রীনিচ মিন টাইম (আইল অফ ম্যান)", + "Europe\/Jersey": "গ্রীনিচ মিন টাইম (জার্সি)", + "Europe\/Kaliningrad": "পূর্ব ইউরোপীয় সময় (কালিনিঙগ্রাড)", + "Europe\/Kiev": "পূর্ব ইউরোপীয় সময় (কিয়েভ)", + "Europe\/Lisbon": "পশ্চিম ইউরোপীয় সময় (লিসবন)", + "Europe\/Ljubljana": "মধ্য ইউরোপীয় সময় (লুবলিয়ানা)", + "Europe\/London": "গ্রীনিচ মিন টাইম (লন্ডন)", + "Europe\/Luxembourg": "মধ্য ইউরোপীয় সময় (লুক্সেমবার্গ)", + "Europe\/Madrid": "মধ্য ইউরোপীয় সময় (মাদ্রিদ)", + "Europe\/Malta": "মধ্য ইউরোপীয় সময় (মাল্টা)", + "Europe\/Mariehamn": "পূর্ব ইউরোপীয় সময় (মরিয়েহামেন)", + "Europe\/Minsk": "মস্কো সময় (মিন্সক)", + "Europe\/Monaco": "মধ্য ইউরোপীয় সময় (মোনাকো)", + "Europe\/Moscow": "মস্কো সময় (মস্কো)", + "Europe\/Oslo": "মধ্য ইউরোপীয় সময় (অসলো)", + "Europe\/Paris": "মধ্য ইউরোপীয় সময় (প্যারিস)", + "Europe\/Podgorica": "মধ্য ইউরোপীয় সময় (পডগরিত্সা)", + "Europe\/Prague": "মধ্য ইউরোপীয় সময় (প্রাগ)", + "Europe\/Riga": "পূর্ব ইউরোপীয় সময় (রিগা)", + "Europe\/Rome": "মধ্য ইউরোপীয় সময় (রোম)", + "Europe\/Samara": "সামারা সময় (সামারা)", + "Europe\/San_Marino": "মধ্য ইউরোপীয় সময় (সান মেরিনো)", + "Europe\/Sarajevo": "মধ্য ইউরোপীয় সময় (সারাজিভো)", + "Europe\/Saratov": "মস্কো সময় (সারাটোভ)", + "Europe\/Simferopol": "মস্কো সময় (সিমফেরোপোল)", + "Europe\/Skopje": "মধ্য ইউরোপীয় সময় (স্কপয়ে)", + "Europe\/Sofia": "পূর্ব ইউরোপীয় সময় (সোফিয়া)", + "Europe\/Stockholm": "মধ্য ইউরোপীয় সময় (স্টকহোম)", + "Europe\/Tallinn": "পূর্ব ইউরোপীয় সময় (তাহলিন)", + "Europe\/Tirane": "মধ্য ইউরোপীয় সময় (তিরানা)", + "Europe\/Ulyanovsk": "মস্কো সময় (উলিয়ানোভস্ক)", + "Europe\/Uzhgorod": "পূর্ব ইউরোপীয় সময় (উঝগোরোড)", + "Europe\/Vaduz": "মধ্য ইউরোপীয় সময় (ভাদুজ)", + "Europe\/Vatican": "মধ্য ইউরোপীয় সময় (ভাটিকান)", + "Europe\/Vienna": "মধ্য ইউরোপীয় সময় (ভিয়েনা)", + "Europe\/Vilnius": "পূর্ব ইউরোপীয় সময় (ভিলনিওস)", + "Europe\/Volgograd": "ভলগোগ্রাড সময় (ভোল্গোগ্রাদ)", + "Europe\/Warsaw": "মধ্য ইউরোপীয় সময় (ওয়ারশ)", + "Europe\/Zagreb": "মধ্য ইউরোপীয় সময় (জাগ্রেব)", + "Europe\/Zaporozhye": "পূর্ব ইউরোপীয় সময় (জেপোরোজাইয়াই)", + "Europe\/Zurich": "মধ্য ইউরোপীয় সময় (জুরিখ)", + "Indian\/Antananarivo": "পূর্ব আফ্রিকা সময় (আন্তুনানারিভো)", + "Indian\/Chagos": "ভারত মহাসাগরীয় সময় (ছাগোস)", + "Indian\/Christmas": "ক্রিসমাস দ্বীপ সময় (ক্রিসমাস)", + "Indian\/Cocos": "কোকোস দ্বীপপুঞ্জ সময় (কোকোস)", + "Indian\/Comoro": "পূর্ব আফ্রিকা সময় (কোমোরো)", + "Indian\/Kerguelen": "ফরাসি দক্ষিণ এবং আন্টার্কটিক সময় (কার্গুলেন)", + "Indian\/Mahe": "সেশেলস সময় (মাহে)", + "Indian\/Maldives": "মালদ্বীপ সময় (মালদ্বীপ)", + "Indian\/Mauritius": "মরিশাস সময় (মরিশাস)", + "Indian\/Mayotte": "পূর্ব আফ্রিকা সময় (মায়োতো)", + "Indian\/Reunion": "রিইউনিয়ন সময় (রিইউনিয়ন)", + "MST7MDT": "পার্বত্য অঞ্চলের সময়", + "PST8PDT": "প্রশান্ত মহাসাগরীয় অঞ্চলের সময়", + "Pacific\/Apia": "অপিয়া সময় (আপিয়া)", + "Pacific\/Auckland": "নিউজিল্যান্ড সময় (অকল্যান্ড)", + "Pacific\/Bougainville": "পাপুয়া নিউ গিনি সময় (বুগেনভিলে)", + "Pacific\/Chatham": "চ্যাথাম সময় (চ্যাঠাম)", + "Pacific\/Easter": "ইস্টার দ্বীপ সময় (ইস্টার)", + "Pacific\/Efate": "ভানুয়াতু সময় (ইফাতে)", + "Pacific\/Enderbury": "ফোনিক্স দ্বীপপুঞ্জ সময় (এন্ডারবারি)", + "Pacific\/Fakaofo": "টোকেলাউ সময় (ফ্যাকাওফো)", + "Pacific\/Fiji": "ফিজি সময় (ফিজি)", + "Pacific\/Funafuti": "টুভালু সময় (ফুনাফুটি)", + "Pacific\/Galapagos": "গালাপাগোস সময় (গ্যালাপ্যাগোস)", + "Pacific\/Gambier": "গ্যাম্বিয়ার সময় (গাম্বিয়ের)", + "Pacific\/Guadalcanal": "সলোমন দ্বীপপুঞ্জ সময় (গোয়াদালকুনাল)", + "Pacific\/Guam": "চামেরো মানক সময় (গুয়াম)", + "Pacific\/Honolulu": "হাওয়াই অ্যালিউটিয়ান সময় (হনোলুলু)", + "Pacific\/Johnston": "হাওয়াই অ্যালিউটিয়ান সময় (জনস্টন)", + "Pacific\/Kiritimati": "লাইন দ্বীপপুঞ্জ সময় (কিরিতিমাতি)", + "Pacific\/Kosrae": "কোসরেই সময় (কোসরায়)", + "Pacific\/Kwajalein": "মার্শাল দ্বীপপুঞ্জ সময় (কোয়াজালেইন)", + "Pacific\/Majuro": "মার্শাল দ্বীপপুঞ্জ সময় (মাজুরো)", + "Pacific\/Marquesas": "মার্কেসাস সময় (মার্কেসাস)", + "Pacific\/Midway": "সামোয়া সময় (মিডওয়ে)", + "Pacific\/Nauru": "নাউরু সময় (নাউরু)", + "Pacific\/Niue": "নিউই সময় (নিউয়ি)", + "Pacific\/Norfolk": "নরফোক দ্বীপ সময় (নরফক)", + "Pacific\/Noumea": "নিউ ক্যালেডোনিয়া সময় (নুমিয়া)", + "Pacific\/Pago_Pago": "সামোয়া সময় (প্যাগো প্যাগো)", + "Pacific\/Palau": "পালাউ সময় (পালাউ)", + "Pacific\/Pitcairn": "পিটকেয়ার্ন সময় (পিটকেয়ার্ন)", + "Pacific\/Ponape": "পোনাপে সময় (পোনাপে)", + "Pacific\/Port_Moresby": "পাপুয়া নিউ গিনি সময় (পোর্ট মৌরজবি)", + "Pacific\/Rarotonga": "কুক দ্বীপপুঞ্জ সময় (রারউহতুঙ্গা)", + "Pacific\/Saipan": "চামেরো মানক সময় (সাইপান)", + "Pacific\/Tahiti": "তাহিতি সময় (তাহিতি)", + "Pacific\/Tarawa": "গিলবার্ট দ্বীপপুঞ্জ সময় (টারাওয়া)", + "Pacific\/Tongatapu": "টোঙ্গা সময় (টোঙ্গাটাপু)", + "Pacific\/Truk": "চুক সময় (চুক)", + "Pacific\/Wake": "ওয়েক দ্বীপ সময় (ওয়েক)", + "Pacific\/Wallis": "ওয়ালিস এবং ফুটুনা সময় (ওলিস)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/bo.json b/src/Symfony/Component/Intl/Resources/data/timezones/bo.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/bo.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/br.json b/src/Symfony/Component/Intl/Resources/data/timezones/br.json new file mode 100644 index 0000000000000..43c1cb79a9284 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/br.json @@ -0,0 +1,334 @@ +{ + "Version": "2.1.48.86", + "Names": { + "Africa\/Abidjan": "Amzer keitat Greenwich (AKG) (Abidjan)", + "Africa\/Accra": "Amzer keitat Greenwich (AKG) (Accra)", + "Africa\/Addis_Ababa": "eur Afrika ar Reter (Adis Abeba)", + "Africa\/Algiers": "eur Kreizeuropa (Aljer)", + "Africa\/Asmera": "eur Afrika ar Reter (Asmara)", + "Africa\/Bamako": "Amzer keitat Greenwich (AKG) (Bamako)", + "Africa\/Bangui": "eur Afrika ar Cʼhornôg (Bangui)", + "Africa\/Banjul": "Amzer keitat Greenwich (AKG) (Banjul)", + "Africa\/Bissau": "Amzer keitat Greenwich (AKG) (Bissau)", + "Africa\/Blantyre": "eur Kreizafrika (Blantyre)", + "Africa\/Brazzaville": "eur Afrika ar Cʼhornôg (Brazzaville)", + "Africa\/Bujumbura": "eur Kreizafrika (Bujumbura)", + "Africa\/Cairo": "eur Europa ar Reter (Kaero)", + "Africa\/Casablanca": "eur Europa ar Cʼhornôg (Dar el Beida (Casablanca))", + "Africa\/Ceuta": "eur Kreizeuropa (Ceuta)", + "Africa\/Conakry": "Amzer keitat Greenwich (AKG) (Conakry)", + "Africa\/Dakar": "Amzer keitat Greenwich (AKG) (Dakar)", + "Africa\/Dar_es_Salaam": "eur Afrika ar Reter (Dar es Salaam)", + "Africa\/Djibouti": "eur Afrika ar Reter (Djibouti)", + "Africa\/Douala": "eur Afrika ar Cʼhornôg (Douala)", + "Africa\/El_Aaiun": "eur Europa ar Cʼhornôg (LaʼYoun)", + "Africa\/Freetown": "Amzer keitat Greenwich (AKG) (Freetown)", + "Africa\/Gaborone": "eur Kreizafrika (Gaborone)", + "Africa\/Harare": "eur Kreizafrika (Harare)", + "Africa\/Johannesburg": "eur cʼhoañv Suafrika (Johannesburg)", + "Africa\/Juba": "eur Afrika ar Reter (Juba)", + "Africa\/Kampala": "eur Afrika ar Reter (Kampala)", + "Africa\/Khartoum": "eur Kreizafrika (Khartoum)", + "Africa\/Kigali": "eur Kreizafrika (Kigali)", + "Africa\/Kinshasa": "eur Afrika ar Cʼhornôg (Kinshasa)", + "Africa\/Lagos": "eur Afrika ar Cʼhornôg (Lagos)", + "Africa\/Libreville": "eur Afrika ar Cʼhornôg (Libreville)", + "Africa\/Lome": "Amzer keitat Greenwich (AKG) (Lomé)", + "Africa\/Luanda": "eur Afrika ar Cʼhornôg (Luanda)", + "Africa\/Lubumbashi": "eur Kreizafrika (Lubumbashi)", + "Africa\/Lusaka": "eur Kreizafrika (Lusaka)", + "Africa\/Malabo": "eur Afrika ar Cʼhornôg (Malabo)", + "Africa\/Maputo": "eur Kreizafrika (Maputo)", + "Africa\/Maseru": "eur cʼhoañv Suafrika (Maseru)", + "Africa\/Mbabane": "eur cʼhoañv Suafrika (Mbabane)", + "Africa\/Mogadishu": "eur Afrika ar Reter (Muqdisho)", + "Africa\/Monrovia": "Amzer keitat Greenwich (AKG) (Monrovia)", + "Africa\/Nairobi": "eur Afrika ar Reter (Nairobi)", + "Africa\/Ndjamena": "eur Afrika ar Cʼhornôg (NʼDjamena)", + "Africa\/Niamey": "eur Afrika ar Cʼhornôg (Niamey)", + "Africa\/Nouakchott": "Amzer keitat Greenwich (AKG) (Nouakchott)", + "Africa\/Ouagadougou": "Amzer keitat Greenwich (AKG) (Ouagadougou)", + "Africa\/Porto-Novo": "eur Afrika ar Cʼhornôg (Porto-Novo)", + "Africa\/Sao_Tome": "Amzer keitat Greenwich (AKG) (São Tomé)", + "Africa\/Tripoli": "eur Europa ar Reter (Tarabulus (Tripoli))", + "Africa\/Tunis": "eur Kreizeuropa (Tuniz)", + "Africa\/Windhoek": "eur Kreizafrika (Windhoek)", + "America\/Anchorage": "eur Alaska (Anchorage)", + "America\/Araguaina": "eur Brasília (Araguaina)", + "America\/Argentina\/La_Rioja": "eur Arcʼhantina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "eur Arcʼhantina (Rio Gallegos)", + "America\/Argentina\/Salta": "eur Arcʼhantina (Salta)", + "America\/Argentina\/San_Juan": "eur Arcʼhantina (San Juan)", + "America\/Argentina\/San_Luis": "eur Arcʼhantina ar Cʼhornôg (San Luis)", + "America\/Argentina\/Tucuman": "eur Arcʼhantina (Tucuman)", + "America\/Argentina\/Ushuaia": "eur Arcʼhantina (Ushuaia)", + "America\/Asuncion": "eur Paraguay (Asunción)", + "America\/Bahia": "eur Brasília (Bahia)", + "America\/Belem": "eur Brasília (Belém)", + "America\/Boa_Vista": "eur an Amazon (Boa Vista)", + "America\/Bogota": "eur Kolombia (Bogotá)", + "America\/Boise": "eur ar Menezioù (Boise)", + "America\/Buenos_Aires": "eur Arcʼhantina (Buenos Aires)", + "America\/Cambridge_Bay": "eur ar Menezioù (Cambridge Bay)", + "America\/Campo_Grande": "eur an Amazon (Campo Grande)", + "America\/Cancun": "eur ar Reter (Cancun)", + "America\/Caracas": "eur Venezuela (Caracas)", + "America\/Catamarca": "eur Arcʼhantina (Catamarca)", + "America\/Cayenne": "eur Gwiana cʼhall (Cayenne)", + "America\/Cayman": "eur ar Reter (Cayman)", + "America\/Coral_Harbour": "eur ar Reter (Atikokan)", + "America\/Cordoba": "eur Arcʼhantina (Cordoba)", + "America\/Creston": "eur ar Menezioù (Creston)", + "America\/Cuiaba": "eur an Amazon (Cuiaba)", + "America\/Danmarkshavn": "Amzer keitat Greenwich (AKG) (Danmarkshavn)", + "America\/Dawson_Creek": "eur ar Menezioù (Dawson Creek)", + "America\/Denver": "eur ar Menezioù (Denver)", + "America\/Detroit": "eur ar Reter (Detroit)", + "America\/Edmonton": "eur ar Menezioù (Edmonton)", + "America\/Fort_Nelson": "eur ar Menezioù (Fort Nelson)", + "America\/Fortaleza": "eur Brasília (Fortaleza)", + "America\/Godthab": "eur Greunland ar Cʼhornôg (Nuuk (Godthåb))", + "America\/Grand_Turk": "eur ar Reter (Grand Turk)", + "America\/Guayaquil": "eur Ecuador (Guayaquil)", + "America\/Guyana": "eur Guyana (Guyana)", + "America\/Havana": "eur Kuba (La Habana)", + "America\/Indiana\/Marengo": "eur ar Reter (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "eur ar Reter (Petersburg, Indiana)", + "America\/Indiana\/Vevay": "eur ar Reter (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "eur ar Reter (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "eur ar Reter (Winamac, Indiana)", + "America\/Indianapolis": "eur ar Reter (Indianapolis)", + "America\/Inuvik": "eur ar Menezioù (Inuvik)", + "America\/Iqaluit": "eur ar Reter (Iqaluit)", + "America\/Jamaica": "eur ar Reter (Jamaika)", + "America\/Jujuy": "eur Arcʼhantina (Jujuy)", + "America\/Juneau": "eur Alaska (Juneau)", + "America\/Kentucky\/Monticello": "eur ar Reter (Monticello, Kentucky)", + "America\/La_Paz": "eur Bolivia (La Paz)", + "America\/Lima": "eur Perou (Lima)", + "America\/Louisville": "eur ar Reter (Louisville)", + "America\/Maceio": "eur Brasília (Maceio)", + "America\/Manaus": "eur an Amazon (Manaus)", + "America\/Mendoza": "eur Arcʼhantina (Mendoza)", + "America\/Metlakatla": "eur Alaska (Metlakatla)", + "America\/Miquelon": "eur Sant-Pêr-ha-Mikelon (Mikelon)", + "America\/Montevideo": "eur Uruguay (Montevideo)", + "America\/Nassau": "eur ar Reter (Nassau)", + "America\/New_York": "eur ar Reter (New York)", + "America\/Nipigon": "eur ar Reter (Nipigon)", + "America\/Nome": "eur Alaska (Nome)", + "America\/Ojinaga": "eur ar Menezioù (Ojinaga)", + "America\/Panama": "eur ar Reter (Panamá)", + "America\/Pangnirtung": "eur ar Reter (Pangnirtung)", + "America\/Paramaribo": "eur Surinam (Paramaribo)", + "America\/Phoenix": "eur ar Menezioù (Phoenix)", + "America\/Port-au-Prince": "eur ar Reter (Port-au-Prince)", + "America\/Porto_Velho": "eur an Amazon (Porto Velho)", + "America\/Punta_Arenas": "eur Chile (Punta Arenas)", + "America\/Recife": "eur Brasília (Recife)", + "America\/Santa_Isabel": "eur Gwalarn Mecʼhiko (Santa Isabel)", + "America\/Santarem": "eur Brasília (Santarem)", + "America\/Santiago": "eur Chile (Santiago)", + "America\/Sao_Paulo": "eur Brasília (São Paulo)", + "America\/Scoresbysund": "eur Greunland ar Reter (Ittoqqortoormiit)", + "America\/Sitka": "eur Alaska (Sitka)", + "America\/St_Johns": "eur Newfoundland (Saint Johnʼs)", + "America\/Thunder_Bay": "eur ar Reter (Thunder Bay)", + "America\/Toronto": "eur ar Reter (Toronto)", + "America\/Yakutat": "eur Alaska (Yakutat)", + "America\/Yellowknife": "eur ar Menezioù (Yellowknife)", + "Antarctica\/Casey": "eur Aostralia ar Cʼhornôg (Casey)", + "Antarctica\/Macquarie": "eur Enez Macquarie (Macquarie)", + "Antarctica\/McMurdo": "eur Zeland-Nevez (McMurdo)", + "Antarctica\/Palmer": "eur Chile (Palmer)", + "Antarctica\/Troll": "Amzer keitat Greenwich (AKG) (Troll)", + "Arctic\/Longyearbyen": "eur Kreizeuropa (Longyearbyen)", + "Asia\/Aden": "eur Arabia (Aden)", + "Asia\/Almaty": "eur Kazakstan ar Reter (Almaty)", + "Asia\/Amman": "eur Europa ar Reter (Amman)", + "Asia\/Anadyr": "eur Anadyrʼ (Anadyrʼ)", + "Asia\/Aqtau": "eur Kazakstan ar Cʼhornôg (Aqtau)", + "Asia\/Aqtobe": "eur Kazakstan ar Cʼhornôg (Aqtobe)", + "Asia\/Ashgabat": "eur Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "eur Kazakstan ar Cʼhornôg (Atyrau)", + "Asia\/Baghdad": "eur Arabia (Baghdad)", + "Asia\/Bahrain": "eur Arabia (Bahrein)", + "Asia\/Baku": "eur Azerbaidjan (Bakou)", + "Asia\/Bangkok": "eur Indez-Sina (Bangkok)", + "Asia\/Beirut": "eur Europa ar Reter (Bayrut)", + "Asia\/Bishkek": "eur Kyrgyzstan (Bishkek)", + "Asia\/Brunei": "eur Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "eur cʼhoañv India (Calcutta)", + "Asia\/Chita": "eur Yakutsk (Chita)", + "Asia\/Colombo": "eur cʼhoañv India (Kolamba)", + "Asia\/Damascus": "eur Europa ar Reter (Damask)", + "Asia\/Dhaka": "eur Bangladesh (Dhaka)", + "Asia\/Dili": "eur Timor ar Reter (Dili)", + "Asia\/Dubai": "eur cʼhoañv ar Pleg-mor Arab-ha-Pers (Dubai)", + "Asia\/Dushanbe": "eur Tadjikistan (Dushanbe)", + "Asia\/Famagusta": "eur Europa ar Reter (Famagusta)", + "Asia\/Gaza": "eur Europa ar Reter (Gaza)", + "Asia\/Hebron": "eur Europa ar Reter (Hebron)", + "Asia\/Hong_Kong": "eur Hong Kong (Hong Kong)", + "Asia\/Irkutsk": "eur Irkutsk (Irkutsk)", + "Asia\/Jakarta": "eur Indonezia ar Cʼhornôg (Jakarta)", + "Asia\/Jayapura": "eur Indonezia ar Reter (Jayapura)", + "Asia\/Jerusalem": "eur Israel (Jeruzalem)", + "Asia\/Kabul": "eur Afghanistan (Kaboul)", + "Asia\/Karachi": "eur Pakistan (Karachi)", + "Asia\/Katmandu": "eur Nepal (Kathmandu)", + "Asia\/Khandyga": "eur Yakutsk (Khandyga)", + "Asia\/Kuala_Lumpur": "eur Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "eur Malaysia (Kuching)", + "Asia\/Kuwait": "eur Arabia (Koweit)", + "Asia\/Macau": "eur Sina (Macau)", + "Asia\/Manila": "eur ar Filipinez (Manila)", + "Asia\/Muscat": "eur cʼhoañv ar Pleg-mor Arab-ha-Pers (Masqat)", + "Asia\/Nicosia": "eur Europa ar Reter (Levkosía)", + "Asia\/Novosibirsk": "eur Novosibirsk (Novosibirsk)", + "Asia\/Oral": "eur Kazakstan ar Cʼhornôg (Oral)", + "Asia\/Phnom_Penh": "eur Indez-Sina (Phnum Pénh)", + "Asia\/Pontianak": "eur Indonezia ar Cʼhornôg (Pontianak)", + "Asia\/Pyongyang": "eur Korea (Pʼyongyang)", + "Asia\/Qatar": "eur Arabia (Qatar)", + "Asia\/Qostanay": "eur Kazakstan ar Reter (Qostanay)", + "Asia\/Qyzylorda": "eur Kazakstan ar Cʼhornôg (Qyzylorda)", + "Asia\/Rangoon": "eur Myanmar (Yangon)", + "Asia\/Riyadh": "eur Arabia (Riyadh)", + "Asia\/Saigon": "eur Indez-Sina (Kêr Hô-Chi-Minh)", + "Asia\/Sakhalin": "eur Sakhalin (Sakhalin)", + "Asia\/Samarkand": "eur Ouzbekistan (Samarkand)", + "Asia\/Seoul": "eur Korea (Seoul)", + "Asia\/Shanghai": "eur Sina (Shanghai)", + "Asia\/Singapore": "eur cʼhoañv Singapour (Singapour)", + "Asia\/Taipei": "eur Taipei (Taipei)", + "Asia\/Tashkent": "eur Ouzbekistan (Toshkent)", + "Asia\/Tbilisi": "eur Jorjia (Tbilisi)", + "Asia\/Tehran": "eur Iran (Tehran)", + "Asia\/Thimphu": "eur Bhoutan (Thimphu)", + "Asia\/Tokyo": "eur Japan (Tokyo)", + "Asia\/Ulaanbaatar": "eur Ulaanbaatar (Ulaanbaatar)", + "Asia\/Ust-Nera": "eur Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "eur Indez-Sina (Viangchan)", + "Asia\/Vladivostok": "eur Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "eur Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "eur Yekaterinbourg (Yekaterinbourg)", + "Asia\/Yerevan": "eur Armenia (Yerevan)", + "Atlantic\/Azores": "eur an Azorez (Azorez)", + "Atlantic\/Canary": "eur Europa ar Cʼhornôg (Kanariez)", + "Atlantic\/Cape_Verde": "eur ar Cʼhab-Glas (Kab Glas)", + "Atlantic\/Faeroe": "eur Europa ar Cʼhornôg (Faero)", + "Atlantic\/Madeira": "eur Europa ar Cʼhornôg (Madeira)", + "Atlantic\/Reykjavik": "Amzer keitat Greenwich (AKG) (Reykjavík)", + "Atlantic\/South_Georgia": "eur Georgia ar Su (Georgia ar Su)", + "Atlantic\/St_Helena": "Amzer keitat Greenwich (AKG) (Saint Helena)", + "Atlantic\/Stanley": "eur Inizi Falkland (Stanley)", + "Australia\/Adelaide": "eur Kreizaostralia (Adelaide)", + "Australia\/Brisbane": "eur Aostralia ar Reter (Brisbane)", + "Australia\/Broken_Hill": "eur Kreizaostralia (Broken Hill)", + "Australia\/Currie": "eur Aostralia ar Reter (Currie)", + "Australia\/Darwin": "eur Kreizaostralia (Darwin)", + "Australia\/Eucla": "eur Kreizaostralia ar Cʼhornôg (Eucla)", + "Australia\/Hobart": "eur Aostralia ar Reter (Hobart)", + "Australia\/Lindeman": "eur Aostralia ar Reter (Lindeman)", + "Australia\/Melbourne": "eur Aostralia ar Reter (Melbourne)", + "Australia\/Perth": "eur Aostralia ar Cʼhornôg (Perth)", + "Australia\/Sydney": "eur Aostralia ar Reter (Sydney)", + "EST5EDT": "eur ar Reter", + "Etc\/GMT": "Amzer keitat Greenwich (AKG)", + "Europe\/Amsterdam": "eur Kreizeuropa (Amsterdam)", + "Europe\/Andorra": "eur Kreizeuropa (Andorra)", + "Europe\/Astrakhan": "eur Moskov (Astrakhan)", + "Europe\/Athens": "eur Europa ar Reter (Aten)", + "Europe\/Belgrade": "eur Kreizeuropa (Beograd)", + "Europe\/Berlin": "eur Kreizeuropa (Berlin)", + "Europe\/Bratislava": "eur Kreizeuropa (Bratislava)", + "Europe\/Brussels": "eur Kreizeuropa (Brusel)", + "Europe\/Bucharest": "eur Europa ar Reter (Bukarest)", + "Europe\/Budapest": "eur Kreizeuropa (Budapest)", + "Europe\/Busingen": "eur Kreizeuropa (Busingen)", + "Europe\/Chisinau": "eur Europa ar Reter (Chisinau)", + "Europe\/Copenhagen": "eur Kreizeuropa (Kopenhagen)", + "Europe\/Dublin": "Amzer keitat Greenwich (AKG) (Dulenn)", + "Europe\/Gibraltar": "eur Kreizeuropa (Jibraltar)", + "Europe\/Guernsey": "Amzer keitat Greenwich (AKG) (Gwernenez)", + "Europe\/Helsinki": "eur Europa ar Reter (Helsinki)", + "Europe\/Isle_of_Man": "Amzer keitat Greenwich (AKG) (Manav)", + "Europe\/Jersey": "Amzer keitat Greenwich (AKG) (Jerzenez)", + "Europe\/Kaliningrad": "eur Europa ar Reter (Kaliningrad)", + "Europe\/Kiev": "eur Europa ar Reter (Kiev)", + "Europe\/Lisbon": "eur Europa ar Cʼhornôg (Lisboa)", + "Europe\/Ljubljana": "eur Kreizeuropa (Ljubljana)", + "Europe\/London": "Amzer keitat Greenwich (AKG) (Londrez)", + "Europe\/Luxembourg": "eur Kreizeuropa (Luksembourg)", + "Europe\/Madrid": "eur Kreizeuropa (Madrid)", + "Europe\/Malta": "eur Kreizeuropa (Malta)", + "Europe\/Mariehamn": "eur Europa ar Reter (Marjehamn)", + "Europe\/Minsk": "eur Moskov (Mensk)", + "Europe\/Monaco": "eur Kreizeuropa (Monaco)", + "Europe\/Moscow": "eur Moskov (Moskov)", + "Europe\/Oslo": "eur Kreizeuropa (Oslo)", + "Europe\/Paris": "eur Kreizeuropa (Pariz)", + "Europe\/Podgorica": "eur Kreizeuropa (Podgorica)", + "Europe\/Prague": "eur Kreizeuropa (Praha)", + "Europe\/Riga": "eur Europa ar Reter (Riga)", + "Europe\/Rome": "eur Kreizeuropa (Roma)", + "Europe\/San_Marino": "eur Kreizeuropa (San Marino)", + "Europe\/Sarajevo": "eur Kreizeuropa (Sarajevo)", + "Europe\/Saratov": "eur Moskov (Saratov)", + "Europe\/Simferopol": "eur Moskov (Simferopol)", + "Europe\/Skopje": "eur Kreizeuropa (Skopje)", + "Europe\/Sofia": "eur Europa ar Reter (Sofia)", + "Europe\/Stockholm": "eur Kreizeuropa (Stockholm)", + "Europe\/Tallinn": "eur Europa ar Reter (Tallinn)", + "Europe\/Tirane": "eur Kreizeuropa (Tiranë)", + "Europe\/Ulyanovsk": "eur Moskov (Ulyanovsk)", + "Europe\/Uzhgorod": "eur Europa ar Reter (Uzhgorod)", + "Europe\/Vaduz": "eur Kreizeuropa (Vaduz)", + "Europe\/Vatican": "eur Kreizeuropa (Vatikan)", + "Europe\/Vienna": "eur Kreizeuropa (Vienna)", + "Europe\/Vilnius": "eur Europa ar Reter (Vilnius)", + "Europe\/Volgograd": "eur Volgograd (Volgograd)", + "Europe\/Warsaw": "eur Kreizeuropa (Varsovia)", + "Europe\/Zagreb": "eur Kreizeuropa (Zagreb)", + "Europe\/Zaporozhye": "eur Europa ar Reter (Zaporozhye)", + "Europe\/Zurich": "eur Kreizeuropa (Zurich)", + "Indian\/Antananarivo": "eur Afrika ar Reter (Antananarivo)", + "Indian\/Christmas": "eur Enez Christmas (Christmas)", + "Indian\/Cocos": "eur Inizi Kokoz (Kokoz)", + "Indian\/Comoro": "eur Afrika ar Reter (Komorez)", + "Indian\/Kerguelen": "eur Douaroù aostral Frañs hag Antarktika (Kergelenn)", + "Indian\/Mahe": "eur Sechelez (Mahe)", + "Indian\/Maldives": "eur ar Maldivez (Maldivez)", + "Indian\/Mauritius": "eur Moris (Moris)", + "Indian\/Mayotte": "eur Afrika ar Reter (Mayotte)", + "Indian\/Reunion": "eur ar Reünion (Reünion)", + "MST7MDT": "eur ar Menezioù", + "Pacific\/Apia": "eur Apia (Apia)", + "Pacific\/Auckland": "eur Zeland-Nevez (Auckland)", + "Pacific\/Chatham": "eur Chatham (Chatham)", + "Pacific\/Easter": "eur Enez Pask (Enez Pask)", + "Pacific\/Efate": "eur Vanuatu (Efate)", + "Pacific\/Fakaofo": "eur Tokelau (Fakaofo)", + "Pacific\/Fiji": "eur Fidji (Fidji)", + "Pacific\/Funafuti": "eur Tuvalu (Funafuti)", + "Pacific\/Galapagos": "eur Inizi Galápagos (Galápagos)", + "Pacific\/Gambier": "eur Gambier (Gambier)", + "Pacific\/Guadalcanal": "eur Inizi Salomon (Guadalcanal)", + "Pacific\/Kwajalein": "eur Inizi Marshall (Kwajalein)", + "Pacific\/Majuro": "eur Inizi Marshall (Majuro)", + "Pacific\/Marquesas": "eur Inizi Markiz (Markiz)", + "Pacific\/Midway": "eur Samoa (Midway)", + "Pacific\/Nauru": "eur Nauru (Nauru)", + "Pacific\/Niue": "eur Niue (Niue)", + "Pacific\/Norfolk": "eur Enez Norfolk (Norfolk)", + "Pacific\/Noumea": "eur Kaledonia Nevez (Noumea)", + "Pacific\/Pago_Pago": "eur Samoa (Pago Pago)", + "Pacific\/Palau": "eur Palau (Palau)", + "Pacific\/Pitcairn": "eur Pitcairn (Pitcairn)", + "Pacific\/Rarotonga": "eur Inizi Cook (Rarotonga)", + "Pacific\/Tahiti": "eur Tahiti (Tahiti)", + "Pacific\/Tongatapu": "eur Tonga (Tongatapu)", + "Pacific\/Wallis": "eur Wallis ha Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/bs.json b/src/Symfony/Component/Intl/Resources/data/timezones/bs.json new file mode 100644 index 0000000000000..c0bab45f6f118 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/bs.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Griničko vrijeme (Abidjan)", + "Africa\/Accra": "Griničko vrijeme (Accra)", + "Africa\/Addis_Ababa": "Istočnoafričko vrijeme (Addis Ababa)", + "Africa\/Algiers": "Centralnoevropsko vrijeme (Algiers)", + "Africa\/Asmera": "Istočnoafričko vrijeme (Asmara)", + "Africa\/Bamako": "Griničko vrijeme (Bamako)", + "Africa\/Bangui": "Zapadnoafričko vrijeme (Bangui)", + "Africa\/Banjul": "Griničko vrijeme (Banjul)", + "Africa\/Bissau": "Griničko vrijeme (Bissau)", + "Africa\/Blantyre": "Centralnoafričko vrijeme (Blantyre)", + "Africa\/Brazzaville": "Zapadnoafričko vrijeme (Brazzaville)", + "Africa\/Bujumbura": "Centralnoafričko vrijeme (Bujumbura)", + "Africa\/Cairo": "Istočnoevropsko vrijeme (Kairo)", + "Africa\/Casablanca": "Zapadnoevropsko vrijeme (Kazablanka)", + "Africa\/Ceuta": "Centralnoevropsko vrijeme (Ceuta)", + "Africa\/Conakry": "Griničko vrijeme (Conakry)", + "Africa\/Dakar": "Griničko vrijeme (Dakar)", + "Africa\/Dar_es_Salaam": "Istočnoafričko vrijeme (Dar es Salaam)", + "Africa\/Djibouti": "Istočnoafričko vrijeme (Džibuti)", + "Africa\/Douala": "Zapadnoafričko vrijeme (Douala)", + "Africa\/El_Aaiun": "Zapadnoevropsko vrijeme (El Aaiun)", + "Africa\/Freetown": "Griničko vrijeme (Freetown)", + "Africa\/Gaborone": "Centralnoafričko vrijeme (Gaborone)", + "Africa\/Harare": "Centralnoafričko vrijeme (Harare)", + "Africa\/Johannesburg": "Južnoafričko standardno vrijeme (Johannesburg)", + "Africa\/Juba": "Istočnoafričko vrijeme (Juba)", + "Africa\/Kampala": "Istočnoafričko vrijeme (Kampala)", + "Africa\/Khartoum": "Centralnoafričko vrijeme (Kartum)", + "Africa\/Kigali": "Centralnoafričko vrijeme (Kigali)", + "Africa\/Kinshasa": "Zapadnoafričko vrijeme (Kinshasa)", + "Africa\/Lagos": "Zapadnoafričko vrijeme (Lagos)", + "Africa\/Libreville": "Zapadnoafričko vrijeme (Libreville)", + "Africa\/Lome": "Griničko vrijeme (Lome)", + "Africa\/Luanda": "Zapadnoafričko vrijeme (Luanda)", + "Africa\/Lubumbashi": "Centralnoafričko vrijeme (Lubumbashi)", + "Africa\/Lusaka": "Centralnoafričko vrijeme (Lusaka)", + "Africa\/Malabo": "Zapadnoafričko vrijeme (Malabo)", + "Africa\/Maputo": "Centralnoafričko vrijeme (Maputo)", + "Africa\/Maseru": "Južnoafričko standardno vrijeme (Maseru)", + "Africa\/Mbabane": "Južnoafričko standardno vrijeme (Mbabane)", + "Africa\/Mogadishu": "Istočnoafričko vrijeme (Mogadiš)", + "Africa\/Monrovia": "Griničko vrijeme (Monrovia)", + "Africa\/Nairobi": "Istočnoafričko vrijeme (Nairobi)", + "Africa\/Ndjamena": "Zapadnoafričko vrijeme (Ndjamena)", + "Africa\/Niamey": "Zapadnoafričko vrijeme (Niamey)", + "Africa\/Nouakchott": "Griničko vrijeme (Nouakchott)", + "Africa\/Ouagadougou": "Griničko vrijeme (Ouagadougou)", + "Africa\/Porto-Novo": "Zapadnoafričko vrijeme (Porto-Novo)", + "Africa\/Sao_Tome": "Griničko vrijeme (Sao Tome)", + "Africa\/Tripoli": "Istočnoevropsko vrijeme (Tripoli)", + "Africa\/Tunis": "Centralnoevropsko vrijeme (Tunis)", + "Africa\/Windhoek": "Centralnoafričko vrijeme (Windhoek)", + "America\/Adak": "Havajsko-aleućansko vrijeme (Adak)", + "America\/Anchorage": "Aljaskansko vrijeme (Anchorage)", + "America\/Anguilla": "Sjevernoameričko atlantsko vrijeme (Angvila)", + "America\/Antigua": "Sjevernoameričko atlantsko vrijeme (Antigva)", + "America\/Araguaina": "Brazilijsko vrijeme (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentinsko vrijeme (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinsko vrijeme (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinsko vrijeme (Salta)", + "America\/Argentina\/San_Juan": "Argentinsko vrijeme (San Juan)", + "America\/Argentina\/San_Luis": "Zapadnoargentinsko vrijeme (San Luis)", + "America\/Argentina\/Tucuman": "Argentinsko vrijeme (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentinsko vrijeme (Ushuaia)", + "America\/Aruba": "Sjevernoameričko atlantsko vrijeme (Aruba)", + "America\/Asuncion": "Paragvajsko vrijeme (Asuncion)", + "America\/Bahia": "Brazilijsko vrijeme (Bahia)", + "America\/Bahia_Banderas": "Sjevernoameričko centralno vrijeme (Bahia Banderas)", + "America\/Barbados": "Sjevernoameričko atlantsko vrijeme (Barbados)", + "America\/Belem": "Brazilijsko vrijeme (Belem)", + "America\/Belize": "Sjevernoameričko centralno vrijeme (Belize)", + "America\/Blanc-Sablon": "Sjevernoameričko atlantsko vrijeme (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonsko vrijeme (Boa Vista)", + "America\/Bogota": "Kolumbijsko vrijeme (Bogota)", + "America\/Boise": "Sjevernoameričko planinsko vrijeme (Boise)", + "America\/Buenos_Aires": "Argentinsko vrijeme (Buenos Aires)", + "America\/Cambridge_Bay": "Sjevernoameričko planinsko vrijeme (Cambridge Bay)", + "America\/Campo_Grande": "Amazonsko vrijeme (Campo Grande)", + "America\/Cancun": "Sjevernoameričko istočno vrijeme (Cancun)", + "America\/Caracas": "Venecuelansko vrijeme (Caracas)", + "America\/Catamarca": "Argentinsko vrijeme (Catamarca)", + "America\/Cayenne": "Francuskogvajansko vrijeme (Cayenne)", + "America\/Cayman": "Sjevernoameričko istočno vrijeme (Kajman)", + "America\/Chicago": "Sjevernoameričko centralno vrijeme (Chicago)", + "America\/Chihuahua": "Meksičko pacifičko vrijeme (Chihuahua)", + "America\/Coral_Harbour": "Sjevernoameričko istočno vrijeme (Atikokan)", + "America\/Cordoba": "Argentinsko vrijeme (Cordoba)", + "America\/Costa_Rica": "Sjevernoameričko centralno vrijeme (Kostarika)", + "America\/Creston": "Sjevernoameričko planinsko vrijeme (Creston)", + "America\/Cuiaba": "Amazonsko vrijeme (Cuiaba)", + "America\/Curacao": "Sjevernoameričko atlantsko vrijeme (Kurasao)", + "America\/Danmarkshavn": "Griničko vrijeme (Danmarkshavn)", + "America\/Dawson": "Sjevernoameričko pacifičko vrijeme (Dawson)", + "America\/Dawson_Creek": "Sjevernoameričko planinsko vrijeme (Dawson Creek)", + "America\/Denver": "Sjevernoameričko planinsko vrijeme (Denver)", + "America\/Detroit": "Sjevernoameričko istočno vrijeme (Detroit)", + "America\/Dominica": "Sjevernoameričko atlantsko vrijeme (Dominika)", + "America\/Edmonton": "Sjevernoameričko planinsko vrijeme (Edmonton)", + "America\/Eirunepe": "Acre vreme (Eirunepe)", + "America\/El_Salvador": "Sjevernoameričko centralno vrijeme (Salvador)", + "America\/Fort_Nelson": "Sjevernoameričko planinsko vrijeme (Fort Nelson)", + "America\/Fortaleza": "Brazilijsko vrijeme (Fortaleza)", + "America\/Glace_Bay": "Sjevernoameričko atlantsko vrijeme (Glace Bay)", + "America\/Godthab": "Zapadnogrenlandsko vrijeme (Nuuk)", + "America\/Goose_Bay": "Sjevernoameričko atlantsko vrijeme (Goose Bay)", + "America\/Grand_Turk": "Sjevernoameričko istočno vrijeme (Grand Turk)", + "America\/Grenada": "Sjevernoameričko atlantsko vrijeme (Grenada)", + "America\/Guadeloupe": "Sjevernoameričko atlantsko vrijeme (Gvadalupe)", + "America\/Guatemala": "Sjevernoameričko centralno vrijeme (Gvatemala)", + "America\/Guayaquil": "Ekvadorsko vrijeme (Guayaquil)", + "America\/Guyana": "Gvajansko vrijeme (Guyana)", + "America\/Halifax": "Sjevernoameričko atlantsko vrijeme (Halifax)", + "America\/Havana": "Kubansko vrijeme (Havana)", + "America\/Hermosillo": "Meksičko pacifičko vrijeme (Hermosillo)", + "America\/Indiana\/Knox": "Sjevernoameričko centralno vrijeme (Knox, Indiana)", + "America\/Indiana\/Marengo": "Sjevernoameričko istočno vrijeme (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Sjevernoameričko istočno vrijeme (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Sjevernoameričko centralno vrijeme (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Sjevernoameričko istočno vrijeme (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Sjevernoameričko istočno vrijeme (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Sjevernoameričko istočno vrijeme (Winamac, Indiana)", + "America\/Indianapolis": "Sjevernoameričko istočno vrijeme (Indianapolis)", + "America\/Inuvik": "Sjevernoameričko planinsko vrijeme (Inuvik)", + "America\/Iqaluit": "Sjevernoameričko istočno vrijeme (Iqaluit)", + "America\/Jamaica": "Sjevernoameričko istočno vrijeme (Jamajka)", + "America\/Jujuy": "Argentinsko vrijeme (Jujuy)", + "America\/Juneau": "Aljaskansko vrijeme (Juneau)", + "America\/Kentucky\/Monticello": "Sjevernoameričko istočno vrijeme (Monticello, Kentucky)", + "America\/Kralendijk": "Sjevernoameričko atlantsko vrijeme (Kralendijk)", + "America\/La_Paz": "Bolivijsko vrijeme (La Paz)", + "America\/Lima": "Peruansko vrijeme (Lima)", + "America\/Los_Angeles": "Sjevernoameričko pacifičko vrijeme (Los Angeles)", + "America\/Louisville": "Sjevernoameričko istočno vrijeme (Louisville)", + "America\/Lower_Princes": "Sjevernoameričko atlantsko vrijeme (Lower Prince’s Quarter)", + "America\/Maceio": "Brazilijsko vrijeme (Maceio)", + "America\/Managua": "Sjevernoameričko centralno vrijeme (Managua)", + "America\/Manaus": "Amazonsko vrijeme (Manaus)", + "America\/Marigot": "Sjevernoameričko atlantsko vrijeme (Marigot)", + "America\/Martinique": "Sjevernoameričko atlantsko vrijeme (Martinique)", + "America\/Matamoros": "Sjevernoameričko centralno vrijeme (Matamoros)", + "America\/Mazatlan": "Meksičko pacifičko vrijeme (Mazatlan)", + "America\/Mendoza": "Argentinsko vrijeme (Mendoza)", + "America\/Menominee": "Sjevernoameričko centralno vrijeme (Menominee)", + "America\/Merida": "Sjevernoameričko centralno vrijeme (Merida)", + "America\/Metlakatla": "Aljaskansko vrijeme (Metlakatla)", + "America\/Mexico_City": "Sjevernoameričko centralno vrijeme (Mexico City)", + "America\/Miquelon": "Vrijeme na Ostrvima Sveti Petar i Mikelon (Miquelon)", + "America\/Moncton": "Sjevernoameričko atlantsko vrijeme (Moncton)", + "America\/Monterrey": "Sjevernoameričko centralno vrijeme (Monterrey)", + "America\/Montevideo": "Urugvajsko vrijeme (Montevideo)", + "America\/Montserrat": "Sjevernoameričko atlantsko vrijeme (Montserrat)", + "America\/Nassau": "Sjevernoameričko istočno vrijeme (Nassau)", + "America\/New_York": "Sjevernoameričko istočno vrijeme (New York)", + "America\/Nipigon": "Sjevernoameričko istočno vrijeme (Nipigon)", + "America\/Nome": "Aljaskansko vrijeme (Nome)", + "America\/Noronha": "Vrijeme na ostrvu Fernando di Noronja (Noronha)", + "America\/North_Dakota\/Beulah": "Sjevernoameričko centralno vrijeme (Beulah, Sjeverna Dakota)", + "America\/North_Dakota\/Center": "Sjevernoameričko centralno vrijeme (Center, Sjeverna Dakota)", + "America\/North_Dakota\/New_Salem": "Sjevernoameričko centralno vrijeme (New Salem, Sjeverna Dakota)", + "America\/Ojinaga": "Sjevernoameričko planinsko vrijeme (Ojinaga)", + "America\/Panama": "Sjevernoameričko istočno vrijeme (Panama)", + "America\/Pangnirtung": "Sjevernoameričko istočno vrijeme (Pangnirtung)", + "America\/Paramaribo": "Surinamsko vrijeme (Paramaribo)", + "America\/Phoenix": "Sjevernoameričko planinsko vrijeme (Phoenix)", + "America\/Port-au-Prince": "Sjevernoameričko istočno vrijeme (Port-au-Prince)", + "America\/Port_of_Spain": "Sjevernoameričko atlantsko vrijeme (Port of Spain)", + "America\/Porto_Velho": "Amazonsko vrijeme (Porto Velho)", + "America\/Puerto_Rico": "Sjevernoameričko atlantsko vrijeme (Portoriko)", + "America\/Punta_Arenas": "Čileansko vrijeme (Punta Arenas)", + "America\/Rainy_River": "Sjevernoameričko centralno vrijeme (Rainy River)", + "America\/Rankin_Inlet": "Sjevernoameričko centralno vrijeme (Rankin Inlet)", + "America\/Recife": "Brazilijsko vrijeme (Recife)", + "America\/Regina": "Sjevernoameričko centralno vrijeme (Regina)", + "America\/Resolute": "Sjevernoameričko centralno vrijeme (Resolute)", + "America\/Rio_Branco": "Acre vreme (Rio Branco)", + "America\/Santa_Isabel": "Sjeverozapadno meksičko vrijeme (Santa Isabel)", + "America\/Santarem": "Brazilijsko vrijeme (Santarem)", + "America\/Santiago": "Čileansko vrijeme (Santiago)", + "America\/Santo_Domingo": "Sjevernoameričko atlantsko vrijeme (Santo Domingo)", + "America\/Sao_Paulo": "Brazilijsko vrijeme (Sao Paulo)", + "America\/Scoresbysund": "Istočnogrenlandsko vrijeme (Ittoqqortoormiit)", + "America\/Sitka": "Aljaskansko vrijeme (Sitka)", + "America\/St_Barthelemy": "Sjevernoameričko atlantsko vrijeme (St. Barthelemy)", + "America\/St_Johns": "Njufaundlendsko vrijeme (St. John’s)", + "America\/St_Kitts": "Sjevernoameričko atlantsko vrijeme (St. Kitts)", + "America\/St_Lucia": "Sjevernoameričko atlantsko vrijeme (St. Lucia)", + "America\/St_Thomas": "Sjevernoameričko atlantsko vrijeme (St. Thomas)", + "America\/St_Vincent": "Sjevernoameričko atlantsko vrijeme (St. Vincent)", + "America\/Swift_Current": "Sjevernoameričko centralno vrijeme (Swift Current)", + "America\/Tegucigalpa": "Sjevernoameričko centralno vrijeme (Tegucigalpa)", + "America\/Thule": "Sjevernoameričko atlantsko vrijeme (Thule)", + "America\/Thunder_Bay": "Sjevernoameričko istočno vrijeme (Thunder Bay)", + "America\/Tijuana": "Sjevernoameričko pacifičko vrijeme (Tijuana)", + "America\/Toronto": "Sjevernoameričko istočno vrijeme (Toronto)", + "America\/Tortola": "Sjevernoameričko atlantsko vrijeme (Tortola)", + "America\/Vancouver": "Sjevernoameričko pacifičko vrijeme (Vancouver)", + "America\/Whitehorse": "Sjevernoameričko pacifičko vrijeme (Whitehorse)", + "America\/Winnipeg": "Sjevernoameričko centralno vrijeme (Winnipeg)", + "America\/Yakutat": "Aljaskansko vrijeme (Yakutat)", + "America\/Yellowknife": "Sjevernoameričko planinsko vrijeme (Yellowknife)", + "Antarctica\/Casey": "Zapadnoaustralijsko vrijeme (Casey)", + "Antarctica\/Davis": "Vrijeme stanice Davis (Davis)", + "Antarctica\/DumontDUrville": "Vrijeme stanice Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Vrijeme na Ostrvu Makvori (Macquarie)", + "Antarctica\/Mawson": "Vrijeme stanice Mawson (Mawson)", + "Antarctica\/McMurdo": "Novozelandsko vrijeme (McMurdo)", + "Antarctica\/Palmer": "Čileansko vrijeme (Palmer)", + "Antarctica\/Rothera": "Vrijeme stanice Rothera (Rothera)", + "Antarctica\/Syowa": "Vrijeme stanice Syowa (Syowa)", + "Antarctica\/Troll": "Griničko vrijeme (Troll)", + "Antarctica\/Vostok": "Vrijeme stanice Vostok (Vostok)", + "Arctic\/Longyearbyen": "Centralnoevropsko vrijeme (Longyearbyen)", + "Asia\/Aden": "Arabijsko vrijeme (Aden)", + "Asia\/Almaty": "Istočnokazahstansko vrijeme (Almati)", + "Asia\/Amman": "Istočnoevropsko vrijeme (Aman)", + "Asia\/Anadyr": "Anadir vreme (Anadir)", + "Asia\/Aqtau": "Zapadnokazahstansko vrijeme (Aktau)", + "Asia\/Aqtobe": "Zapadnokazahstansko vrijeme (Akutobe)", + "Asia\/Ashgabat": "Turkmenistansko vrijeme (Ašhabad)", + "Asia\/Atyrau": "Zapadnokazahstansko vrijeme (Atyrau)", + "Asia\/Baghdad": "Arabijsko vrijeme (Bagdad)", + "Asia\/Bahrain": "Arabijsko vrijeme (Bahrein)", + "Asia\/Baku": "Azerbejdžansko vrijeme (Baku)", + "Asia\/Bangkok": "Indokinesko vrijeme (Bangkok)", + "Asia\/Beirut": "Istočnoevropsko vrijeme (Bejrut)", + "Asia\/Bishkek": "Kirgistansko vrijeme (Biškek)", + "Asia\/Brunei": "Brunejsko vrijeme (Bruneji)", + "Asia\/Calcutta": "Indijsko standardno vrijeme (Kolkata)", + "Asia\/Chita": "Jakutsko vrijeme (Chita)", + "Asia\/Choibalsan": "Čojbalsansko vrijeme (Čojbalsan)", + "Asia\/Colombo": "Indijsko standardno vrijeme (Kolombo)", + "Asia\/Damascus": "Istočnoevropsko vrijeme (Damask)", + "Asia\/Dhaka": "Bangladeško vrijeme (Daka)", + "Asia\/Dili": "Istočnotimorsko vrijeme (Dili)", + "Asia\/Dubai": "Zalivsko standardno vrijeme (Dubai)", + "Asia\/Dushanbe": "Tadžikistansko vrijeme (Dušanbe)", + "Asia\/Famagusta": "Istočnoevropsko vrijeme (Famagusta)", + "Asia\/Gaza": "Istočnoevropsko vrijeme (Gaza)", + "Asia\/Hebron": "Istočnoevropsko vrijeme (Hebron)", + "Asia\/Hong_Kong": "Hongkonško vrijeme (Hong Kong)", + "Asia\/Hovd": "Hovdsko vrijeme (Hovd)", + "Asia\/Irkutsk": "Irkutsko vrijeme (Irkutsk)", + "Asia\/Jakarta": "Zapadnoindonezijsko vrijeme (Džakarta)", + "Asia\/Jayapura": "Istočnoindonezijsko vrijeme (Džajapura)", + "Asia\/Jerusalem": "Izraelsko vrijeme (Jeruzalem)", + "Asia\/Kabul": "Afganistansko vrijeme (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamčatski vreme (Kamčatka)", + "Asia\/Karachi": "Pakistansko vrijeme (Karači)", + "Asia\/Katmandu": "Nepalsko vrijeme (Katmandu)", + "Asia\/Khandyga": "Jakutsko vrijeme (Handiga)", + "Asia\/Krasnoyarsk": "Krasnojarsko vrijeme (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malezijsko vrijeme (Kuala Lumpur)", + "Asia\/Kuching": "Malezijsko vrijeme (Kučing)", + "Asia\/Kuwait": "Arabijsko vrijeme (Kuvajt)", + "Asia\/Macau": "Kinesko vrijeme (Makau)", + "Asia\/Magadan": "Magadansko vrijeme (Magadan)", + "Asia\/Makassar": "Centralnoindonezijsko vrijeme (Makasar)", + "Asia\/Manila": "Filipinsko vrijeme (Manila)", + "Asia\/Muscat": "Zalivsko standardno vrijeme (Muskat)", + "Asia\/Nicosia": "Istočnoevropsko vrijeme (Nikozija)", + "Asia\/Novokuznetsk": "Krasnojarsko vrijeme (Novokuznjeck)", + "Asia\/Novosibirsk": "Novosibirsko vrijeme (Novosibirsk)", + "Asia\/Omsk": "Omsko vrijeme (Omsk)", + "Asia\/Oral": "Zapadnokazahstansko vrijeme (Oral)", + "Asia\/Phnom_Penh": "Indokinesko vrijeme (Pnom Pen)", + "Asia\/Pontianak": "Zapadnoindonezijsko vrijeme (Pontianak)", + "Asia\/Pyongyang": "Korejsko vrijeme (Pjongjang)", + "Asia\/Qatar": "Arabijsko vrijeme (Katar)", + "Asia\/Qostanay": "Istočnokazahstansko vrijeme (Qostanay)", + "Asia\/Qyzylorda": "Zapadnokazahstansko vrijeme (Kizilorda)", + "Asia\/Rangoon": "Mijanmarsko vrijeme (Rangun)", + "Asia\/Riyadh": "Arabijsko vrijeme (Rijad)", + "Asia\/Saigon": "Indokinesko vrijeme (Ho Ši Min)", + "Asia\/Sakhalin": "Sahalinsko vrijeme (Sahalin)", + "Asia\/Samarkand": "Uzbekistansko vrijeme (Samarkand)", + "Asia\/Seoul": "Korejsko vrijeme (Seul)", + "Asia\/Shanghai": "Kinesko vrijeme (Šangaj)", + "Asia\/Singapore": "Singapursko standardno vrijeme (Singapur)", + "Asia\/Srednekolymsk": "Magadansko vrijeme (Srednekolymsk)", + "Asia\/Taipei": "Tajpejsko vrijeme (Tajpej)", + "Asia\/Tashkent": "Uzbekistansko vrijeme (Taškent)", + "Asia\/Tbilisi": "Gruzijsko vrijeme (Tbilisi)", + "Asia\/Tehran": "Iransko vrijeme (Teheran)", + "Asia\/Thimphu": "Butansko vrijeme (Thimphu)", + "Asia\/Tokyo": "Japansko vrijeme (Tokio)", + "Asia\/Ulaanbaatar": "Ulanbatorsko vrijeme (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostočko vrijeme (Ust-Nera)", + "Asia\/Vientiane": "Indokinesko vrijeme (Vijentijan)", + "Asia\/Vladivostok": "Vladivostočko vrijeme (Vladivostok)", + "Asia\/Yakutsk": "Jakutsko vrijeme (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburško vrijeme (Jekaterinburg)", + "Asia\/Yerevan": "Armensko vrijeme (Jerevan)", + "Atlantic\/Azores": "Azorsko vrijeme (Azori)", + "Atlantic\/Bermuda": "Sjevernoameričko atlantsko vrijeme (Bermuda)", + "Atlantic\/Canary": "Zapadnoevropsko vrijeme (Kanari)", + "Atlantic\/Cape_Verde": "Zelenortsko vrijeme (Kape Verde)", + "Atlantic\/Faeroe": "Zapadnoevropsko vrijeme (Faroe)", + "Atlantic\/Madeira": "Zapadnoevropsko vrijeme (Madeira)", + "Atlantic\/Reykjavik": "Griničko vrijeme (Rejkjavik)", + "Atlantic\/South_Georgia": "Južnodžordžijsko vrijeme (South Georgia)", + "Atlantic\/St_Helena": "Griničko vrijeme (Sveta Helena)", + "Atlantic\/Stanley": "Folklandsko vrijeme (Stanley)", + "Australia\/Adelaide": "Centralnoaustralijsko vrijeme (Adelaide)", + "Australia\/Brisbane": "Istočnoaustralijsko vrijeme (Brisbane)", + "Australia\/Broken_Hill": "Centralnoaustralijsko vrijeme (Broken Hill)", + "Australia\/Currie": "Istočnoaustralijsko vrijeme (Currie)", + "Australia\/Darwin": "Centralnoaustralijsko vrijeme (Darwin)", + "Australia\/Eucla": "Australijsko centralno zapadno vrijeme (Eucla)", + "Australia\/Hobart": "Istočnoaustralijsko vrijeme (Hobart)", + "Australia\/Lindeman": "Istočnoaustralijsko vrijeme (Lindeman)", + "Australia\/Lord_Howe": "Vrijeme na Ostrvu Lord Hau (Lord Hau)", + "Australia\/Melbourne": "Istočnoaustralijsko vrijeme (Melburn)", + "Australia\/Perth": "Zapadnoaustralijsko vrijeme (Pert)", + "Australia\/Sydney": "Istočnoaustralijsko vrijeme (Sidnej)", + "CST6CDT": "Sjevernoameričko centralno vrijeme", + "EST5EDT": "Sjevernoameričko istočno vrijeme", + "Etc\/GMT": "Griničko vrijeme", + "Etc\/UTC": "Koordinirano svjetsko vrijeme", + "Europe\/Amsterdam": "Centralnoevropsko vrijeme (Amsterdam)", + "Europe\/Andorra": "Centralnoevropsko vrijeme (Andora)", + "Europe\/Astrakhan": "Moskovsko vrijeme (Astrahan)", + "Europe\/Athens": "Istočnoevropsko vrijeme (Atina)", + "Europe\/Belgrade": "Centralnoevropsko vrijeme (Beograd)", + "Europe\/Berlin": "Centralnoevropsko vrijeme (Berlin)", + "Europe\/Bratislava": "Centralnoevropsko vrijeme (Bratislava)", + "Europe\/Brussels": "Centralnoevropsko vrijeme (Brisel)", + "Europe\/Bucharest": "Istočnoevropsko vrijeme (Bukurešt)", + "Europe\/Budapest": "Centralnoevropsko vrijeme (Budimpešta)", + "Europe\/Busingen": "Centralnoevropsko vrijeme (Busingen)", + "Europe\/Chisinau": "Istočnoevropsko vrijeme (Kišinjev)", + "Europe\/Copenhagen": "Centralnoevropsko vrijeme (Kopenhagen)", + "Europe\/Dublin": "Griničko vrijeme (Dablin)", + "Europe\/Gibraltar": "Centralnoevropsko vrijeme (Gibraltar)", + "Europe\/Guernsey": "Griničko vrijeme (Gernzi)", + "Europe\/Helsinki": "Istočnoevropsko vrijeme (Helsinki)", + "Europe\/Isle_of_Man": "Griničko vrijeme (Ostrvo Man)", + "Europe\/Jersey": "Griničko vrijeme (Jersey)", + "Europe\/Kaliningrad": "Istočnoevropsko vrijeme (Kalinjingrad)", + "Europe\/Kiev": "Istočnoevropsko vrijeme (Kijev)", + "Europe\/Lisbon": "Zapadnoevropsko vrijeme (Lisabon)", + "Europe\/Ljubljana": "Centralnoevropsko vrijeme (Ljubljana)", + "Europe\/London": "Griničko vrijeme (London)", + "Europe\/Luxembourg": "Centralnoevropsko vrijeme (Luksemburg)", + "Europe\/Madrid": "Centralnoevropsko vrijeme (Madrid)", + "Europe\/Malta": "Centralnoevropsko vrijeme (Malta)", + "Europe\/Mariehamn": "Istočnoevropsko vrijeme (Mariehamn)", + "Europe\/Minsk": "Moskovsko vrijeme (Minsk)", + "Europe\/Monaco": "Centralnoevropsko vrijeme (Monako)", + "Europe\/Moscow": "Moskovsko vrijeme (Moskva)", + "Europe\/Oslo": "Centralnoevropsko vrijeme (Oslo)", + "Europe\/Paris": "Centralnoevropsko vrijeme (Pariz)", + "Europe\/Podgorica": "Centralnoevropsko vrijeme (Podgorica)", + "Europe\/Prague": "Centralnoevropsko vrijeme (Prag)", + "Europe\/Riga": "Istočnoevropsko vrijeme (Riga)", + "Europe\/Rome": "Centralnoevropsko vrijeme (Rim)", + "Europe\/Samara": "Samara vreme (Samara)", + "Europe\/San_Marino": "Centralnoevropsko vrijeme (San Marino)", + "Europe\/Sarajevo": "Centralnoevropsko vrijeme (Sarajevo)", + "Europe\/Saratov": "Moskovsko vrijeme (Saratov)", + "Europe\/Simferopol": "Moskovsko vrijeme (Simferopolj)", + "Europe\/Skopje": "Centralnoevropsko vrijeme (Skoplje)", + "Europe\/Sofia": "Istočnoevropsko vrijeme (Sofija)", + "Europe\/Stockholm": "Centralnoevropsko vrijeme (Štokholm)", + "Europe\/Tallinn": "Istočnoevropsko vrijeme (Talin)", + "Europe\/Tirane": "Centralnoevropsko vrijeme (Tirana)", + "Europe\/Ulyanovsk": "Moskovsko vrijeme (Ulyanovsk)", + "Europe\/Uzhgorod": "Istočnoevropsko vrijeme (Užgorod)", + "Europe\/Vaduz": "Centralnoevropsko vrijeme (Vaduz)", + "Europe\/Vatican": "Centralnoevropsko vrijeme (Vatikan)", + "Europe\/Vienna": "Centralnoevropsko vrijeme (Beč)", + "Europe\/Vilnius": "Istočnoevropsko vrijeme (Vilnius)", + "Europe\/Volgograd": "Volgogradsko vrijeme (Volgograd)", + "Europe\/Warsaw": "Centralnoevropsko vrijeme (Varšava)", + "Europe\/Zagreb": "Centralnoevropsko vrijeme (Zagreb)", + "Europe\/Zaporozhye": "Istočnoevropsko vrijeme (Zaporožje)", + "Europe\/Zurich": "Centralnoevropsko vrijeme (Cirih)", + "Indian\/Antananarivo": "Istočnoafričko vrijeme (Antananarivo)", + "Indian\/Chagos": "Vrijeme na Indijskom okeanu (Chagos)", + "Indian\/Christmas": "Vrijeme na Božićnom Ostrvu (Božićno ostrvo)", + "Indian\/Cocos": "Vrijeme na Ostrvima Kokos (Kokosova ostrva)", + "Indian\/Comoro": "Istočnoafričko vrijeme (Comoro)", + "Indian\/Kerguelen": "Vrijeme na Francuskoj Južnoj Teritoriji i Antarktiku (Kerguelen)", + "Indian\/Mahe": "Sejšelsko vrijeme (Mahe)", + "Indian\/Maldives": "Maldivsko vrijeme (Maldivi)", + "Indian\/Mauritius": "Mauricijsko vrijeme (Mauricijus)", + "Indian\/Mayotte": "Istočnoafričko vrijeme (Mayotte)", + "Indian\/Reunion": "Reunionsko vrijeme (Reunion)", + "MST7MDT": "Sjevernoameričko planinsko vrijeme", + "PST8PDT": "Sjevernoameričko pacifičko vrijeme", + "Pacific\/Apia": "Apijsko vrijeme (Apia)", + "Pacific\/Auckland": "Novozelandsko vrijeme (Auckland)", + "Pacific\/Bougainville": "Vrijeme na Papui Novoj Gvineji (Bougainville)", + "Pacific\/Chatham": "Čatamsko vrijeme (Chatham)", + "Pacific\/Easter": "Uskršnjeostrvsko vrijeme (Easter)", + "Pacific\/Efate": "Vanuatuansko vrijeme (Efate)", + "Pacific\/Enderbury": "Vrijeme na Ostrvima Finiks (Enderbury)", + "Pacific\/Fakaofo": "Vrijeme na Ostrvu Tokelau (Fakaofo)", + "Pacific\/Fiji": "Vrijeme na Fidžiju (Fidži)", + "Pacific\/Funafuti": "Tuvaluansko vrijeme (Funafuti)", + "Pacific\/Galapagos": "Galapagosko vrijeme (Galapagos)", + "Pacific\/Gambier": "Gambijersko vrijeme (Gambier)", + "Pacific\/Guadalcanal": "Vrijeme na Solomonskim ostrvima (Guadalcanal)", + "Pacific\/Guam": "Čamorsko standardno vrijeme (Guam)", + "Pacific\/Honolulu": "Havajsko-aleućansko vrijeme (Honolulu)", + "Pacific\/Johnston": "Havajsko-aleućansko vrijeme (Johnston)", + "Pacific\/Kiritimati": "Vrijeme na Ostrvima Lajn (Kiritimati)", + "Pacific\/Kosrae": "Vrijeme na Ostrvu Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Vrijeme na Maršalovim ostrvima (Kwajalein)", + "Pacific\/Majuro": "Vrijeme na Maršalovim ostrvima (Majuro)", + "Pacific\/Marquesas": "Vrijeme na Ostrvima Markiz (Marquesas)", + "Pacific\/Midway": "Samoansko vrijeme (Midway)", + "Pacific\/Nauru": "Vrijeme na Ostrvu Nauru (Nauru)", + "Pacific\/Niue": "Vrijeme na Ostrvu Niue (Niue)", + "Pacific\/Norfolk": "Norfolško vrijeme (Norfolk)", + "Pacific\/Noumea": "Novokaledonijsko vrijeme (Noumea)", + "Pacific\/Pago_Pago": "Samoansko vrijeme (Pago Pago)", + "Pacific\/Palau": "Vrijeme na Ostrvu Palau (Palau)", + "Pacific\/Pitcairn": "Vrijeme na Ostrvima Pitkern (Pitkern)", + "Pacific\/Ponape": "Vrijeme na Ostrvu Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Vrijeme na Papui Novoj Gvineji (Port Moresby)", + "Pacific\/Rarotonga": "Vrijeme na Kukovim ostrvima (Rarotonga)", + "Pacific\/Saipan": "Čamorsko standardno vrijeme (Saipan)", + "Pacific\/Tahiti": "Tahićansko vrijeme (Tahiti)", + "Pacific\/Tarawa": "Vrijeme na Gilbertovim ostrvima (Tarawa)", + "Pacific\/Tongatapu": "Tongansko vrijeme (Tongatapu)", + "Pacific\/Truk": "Čučko vrijeme (Chuuk)", + "Pacific\/Wake": "Vrijeme na Ostrvu Vejk (Wake)", + "Pacific\/Wallis": "Vrijeme na Ostrvima Valis i Futuna (Valis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/bs_Cyrl.json b/src/Symfony/Component/Intl/Resources/data/timezones/bs_Cyrl.json new file mode 100644 index 0000000000000..a0da4fdd5b21c --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/bs_Cyrl.json @@ -0,0 +1,425 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Гринвич средње време (Абиџан)", + "Africa\/Accra": "Гринвич средње време (Акра)", + "Africa\/Addis_Ababa": "Источно-афричко време (Адис Абеба)", + "Africa\/Algiers": "Средњеевропско време (Алжир)", + "Africa\/Asmera": "Источно-афричко време (Асмера)", + "Africa\/Bamako": "Гринвич средње време (Бамако)", + "Africa\/Bangui": "Западно-афричко време (Бангуи)", + "Africa\/Banjul": "Гринвич средње време (Банжул)", + "Africa\/Bissau": "Гринвич средње време (Бисао)", + "Africa\/Blantyre": "Централно-афричко време (Блантир)", + "Africa\/Brazzaville": "Западно-афричко време (Бразавил)", + "Africa\/Bujumbura": "Централно-афричко време (Буџумбура)", + "Africa\/Cairo": "Источноевропско време (Каиро)", + "Africa\/Casablanca": "Западноевропско време (Казабланка)", + "Africa\/Ceuta": "Средњеевропско време (Сеута)", + "Africa\/Conakry": "Гринвич средње време (Конакри)", + "Africa\/Dakar": "Гринвич средње време (Дакар)", + "Africa\/Dar_es_Salaam": "Источно-афричко време (Дар-ес-Салам)", + "Africa\/Djibouti": "Источно-афричко време (Џибути)", + "Africa\/Douala": "Западно-афричко време (Дуала)", + "Africa\/El_Aaiun": "Западноевропско време (Ел Ајун)", + "Africa\/Freetown": "Гринвич средње време (Фритаун)", + "Africa\/Gaborone": "Централно-афричко време (Габорон)", + "Africa\/Harare": "Централно-афричко време (Хараре)", + "Africa\/Johannesburg": "Јужно-афричко време (Јоханесбург)", + "Africa\/Juba": "Источно-афричко време (Juba)", + "Africa\/Kampala": "Источно-афричко време (Кампала)", + "Africa\/Khartoum": "Централно-афричко време (Картум)", + "Africa\/Kigali": "Централно-афричко време (Кигали)", + "Africa\/Kinshasa": "Западно-афричко време (Киншаса)", + "Africa\/Lagos": "Западно-афричко време (Лагос)", + "Africa\/Libreville": "Западно-афричко време (Либревил)", + "Africa\/Lome": "Гринвич средње време (Ломе)", + "Africa\/Luanda": "Западно-афричко време (Луанда)", + "Africa\/Lubumbashi": "Централно-афричко време (Лумумбаши)", + "Africa\/Lusaka": "Централно-афричко време (Лусака)", + "Africa\/Malabo": "Западно-афричко време (Малабо)", + "Africa\/Maputo": "Централно-афричко време (Мапуто)", + "Africa\/Maseru": "Јужно-афричко време (Масеру)", + "Africa\/Mbabane": "Јужно-афричко време (Мбабане)", + "Africa\/Mogadishu": "Источно-афричко време (Могадиш)", + "Africa\/Monrovia": "Гринвич средње време (Монровија)", + "Africa\/Nairobi": "Источно-афричко време (Најроби)", + "Africa\/Ndjamena": "Западно-афричко време (Нџамена)", + "Africa\/Niamey": "Западно-афричко време (Нијамеј)", + "Africa\/Nouakchott": "Гринвич средње време (Навакшут)", + "Africa\/Ouagadougou": "Гринвич средње време (Уагадугу)", + "Africa\/Porto-Novo": "Западно-афричко време (Порто Ново)", + "Africa\/Sao_Tome": "Гринвич средње време (Сао Томе)", + "Africa\/Tripoli": "Источноевропско време (Триполи)", + "Africa\/Tunis": "Средњеевропско време (Тунис)", + "Africa\/Windhoek": "Централно-афричко време (Виндхук)", + "America\/Adak": "Хавајско-алеутско време (Адак)", + "America\/Anchorage": "Аљашко време (Енкориџ)", + "America\/Anguilla": "Атланско време (Ангвила)", + "America\/Antigua": "Атланско време (Антигва)", + "America\/Araguaina": "Бразилија време (Арагвајана)", + "America\/Argentina\/La_Rioja": "Аргентина време (Ла Риоја)", + "America\/Argentina\/Rio_Gallegos": "Аргентина време (Рио Гелегос)", + "America\/Argentina\/Salta": "Аргентина време (Салта)", + "America\/Argentina\/San_Juan": "Аргентина време (Сан Хуан)", + "America\/Argentina\/San_Luis": "Западна Аргентина време (Сан Луи)", + "America\/Argentina\/Tucuman": "Аргентина време (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентина време (Ушуаија)", + "America\/Aruba": "Атланско време (Аруба)", + "America\/Asuncion": "Парагвај време (Асунсион)", + "America\/Bahia": "Бразилија време (Бахиа)", + "America\/Bahia_Banderas": "Централно време (Bahia Banderas)", + "America\/Barbados": "Атланско време (Барбадос)", + "America\/Belem": "Бразилија време (Белем)", + "America\/Belize": "Централно време (Белизе)", + "America\/Blanc-Sablon": "Атланско време (Бланк-Сејблон)", + "America\/Boa_Vista": "Амазон време (Боа Виста)", + "America\/Bogota": "Колумбија време (Богота)", + "America\/Boise": "Планинско време (Бојзи)", + "America\/Buenos_Aires": "Аргентина време (Буенос Аирес)", + "America\/Cambridge_Bay": "Планинско време (Кембриџ Беј)", + "America\/Campo_Grande": "Амазон време (Кампо Гранде)", + "America\/Cancun": "Источно време (Канкун)", + "America\/Caracas": "Венецуела време (Каракас)", + "America\/Catamarca": "Аргентина време (Катамарка)", + "America\/Cayenne": "Француска Гвајана време (Кајен)", + "America\/Cayman": "Источно време (Кајманска острва)", + "America\/Chicago": "Централно време (Чикаго)", + "America\/Coral_Harbour": "Источно време (Корал Харбур)", + "America\/Cordoba": "Аргентина време (Кордоба)", + "America\/Costa_Rica": "Централно време (Костарика)", + "America\/Creston": "Планинско време (Creston)", + "America\/Cuiaba": "Амазон време (Куиаба)", + "America\/Curacao": "Атланско време (Кирасо)", + "America\/Danmarkshavn": "Гринвич средње време (Данмарксхаген)", + "America\/Dawson": "Пацифичко време (Досон)", + "America\/Dawson_Creek": "Планинско време (Досон Крик)", + "America\/Denver": "Планинско време (Денвер)", + "America\/Detroit": "Источно време (Детроит)", + "America\/Dominica": "Атланско време (Доминика)", + "America\/Edmonton": "Планинско време (Едмонтон)", + "America\/Eirunepe": "Акре време (Еирунепе)", + "America\/El_Salvador": "Централно време (Салвадор)", + "America\/Fort_Nelson": "Планинско време (Fort Nelson)", + "America\/Fortaleza": "Бразилија време (Форталеза)", + "America\/Glace_Bay": "Атланско време (Глејс Беј)", + "America\/Godthab": "Западни Гренланд време (Готхаб)", + "America\/Goose_Bay": "Атланско време (Гус Беј)", + "America\/Grand_Turk": "Источно време (Гранд Турк)", + "America\/Grenada": "Атланско време (Гренада)", + "America\/Guadeloupe": "Атланско време (Гвадалупе)", + "America\/Guatemala": "Централно време (Гватемала)", + "America\/Guayaquil": "Еквадор време (Гвајакил)", + "America\/Guyana": "Гвајана време (Гуана)", + "America\/Halifax": "Атланско време (Халифакс)", + "America\/Havana": "Куба време (Хавана)", + "America\/Indiana\/Knox": "Централно време (Кнокс, Индијана)", + "America\/Indiana\/Marengo": "Источно време (Маренго, Индијана)", + "America\/Indiana\/Petersburg": "Источно време (Петерсбург, Индијана)", + "America\/Indiana\/Tell_City": "Централно време (Тел Сити)", + "America\/Indiana\/Vevay": "Источно време (Вевај, Индијана)", + "America\/Indiana\/Vincennes": "Источно време (Винценес, Индијана)", + "America\/Indiana\/Winamac": "Источно време (Винамак, Индијана)", + "America\/Indianapolis": "Источно време (Индианаполис)", + "America\/Inuvik": "Планинско време (Инувик)", + "America\/Iqaluit": "Источно време (Иквалуит)", + "America\/Jamaica": "Источно време (Јамајка)", + "America\/Jujuy": "Аргентина време (Жужуи)", + "America\/Juneau": "Аљашко време (Жуно)", + "America\/Kentucky\/Monticello": "Источно време (Монтичело, Кентаки)", + "America\/Kralendijk": "Атланско време (Kralendijk)", + "America\/La_Paz": "Боливија време (Ла Паз)", + "America\/Lima": "Перу време (Лима)", + "America\/Los_Angeles": "Пацифичко време (Лос Анђелес)", + "America\/Louisville": "Источно време (Луивиле)", + "America\/Lower_Princes": "Атланско време (Lower Prince’s Quarter)", + "America\/Maceio": "Бразилија време (Масејо)", + "America\/Managua": "Централно време (Манагва)", + "America\/Manaus": "Амазон време (Манаус)", + "America\/Marigot": "Атланско време (Мариго)", + "America\/Martinique": "Атланско време (Мартиник)", + "America\/Matamoros": "Централно време (Matamoros)", + "America\/Mendoza": "Аргентина време (Мендоза)", + "America\/Menominee": "Централно време (Меномини)", + "America\/Merida": "Централно време (Мерида)", + "America\/Metlakatla": "Аљашко време (Metlakatla)", + "America\/Mexico_City": "Централно време (Мексико Сити)", + "America\/Miquelon": "Сен Пјер и Микелон време (Микелон)", + "America\/Moncton": "Атланско време (Монктон)", + "America\/Monterrey": "Централно време (Монтереј)", + "America\/Montevideo": "Уругвај време (Монтевидео)", + "America\/Montserrat": "Атланско време (Монтсерат)", + "America\/Nassau": "Источно време (Насау)", + "America\/New_York": "Источно време (Њујорк)", + "America\/Nipigon": "Источно време (Нипигон)", + "America\/Nome": "Аљашко време (Ном)", + "America\/Noronha": "Фернандо де Нороња време (Нороња)", + "America\/North_Dakota\/Beulah": "Централно време (Бијула, Северна Дакота)", + "America\/North_Dakota\/Center": "Централно време (Центар, Северна Дакота)", + "America\/North_Dakota\/New_Salem": "Централно време (Нови Салем, Северна Даткоа)", + "America\/Ojinaga": "Планинско време (Ojinaga)", + "America\/Panama": "Источно време (Панама)", + "America\/Pangnirtung": "Источно време (Пангниртунг)", + "America\/Paramaribo": "Суринам време (Парамирбо)", + "America\/Phoenix": "Планинско време (Феникс)", + "America\/Port-au-Prince": "Источно време (Порт-о-Пренс)", + "America\/Port_of_Spain": "Атланско време (Порт оф Спејн)", + "America\/Porto_Velho": "Амазон време (Порто Вељо)", + "America\/Puerto_Rico": "Атланско време (Порто Рико)", + "America\/Punta_Arenas": "Чиле време (Punta Arenas)", + "America\/Rainy_River": "Централно време (Рејни Ривер)", + "America\/Rankin_Inlet": "Централно време (Ранкин Инлет)", + "America\/Recife": "Бразилија време (Ресифе)", + "America\/Regina": "Централно време (Регина)", + "America\/Resolute": "Централно време (Ресолут)", + "America\/Rio_Branco": "Акре време (Рио Бранко)", + "America\/Santarem": "Бразилија време (Сантарем)", + "America\/Santiago": "Чиле време (Сантијаго)", + "America\/Santo_Domingo": "Атланско време (Санто Доминго)", + "America\/Sao_Paulo": "Бразилија време (Сао Паоло)", + "America\/Scoresbysund": "Источни Гренланд време (Скорезбисунд)", + "America\/Sitka": "Аљашко време (Sitka)", + "America\/St_Barthelemy": "Атланско време (Св. Бартоломeј)", + "America\/St_Johns": "Њуфаундленд време (Св. Џон)", + "America\/St_Kitts": "Атланско време (Сент Китс)", + "America\/St_Lucia": "Атланско време (Св. Луција)", + "America\/St_Thomas": "Атланско време (Св. Тома)", + "America\/St_Vincent": "Атланско време (Сент Винсент)", + "America\/Swift_Current": "Централно време (Свифт Курент)", + "America\/Tegucigalpa": "Централно време (Тегусигалпа)", + "America\/Thule": "Атланско време (Туле)", + "America\/Thunder_Bay": "Источно време (Тандер Беј)", + "America\/Tijuana": "Пацифичко време (Тихуана)", + "America\/Toronto": "Источно време (Торонто)", + "America\/Tortola": "Атланско време (Тортола)", + "America\/Vancouver": "Пацифичко време (Ванкувер)", + "America\/Whitehorse": "Пацифичко време (Вајтхорс)", + "America\/Winnipeg": "Централно време (Винипег)", + "America\/Yakutat": "Аљашко време (Јакутат)", + "America\/Yellowknife": "Планинско време (Јелоунајф)", + "Antarctica\/Casey": "Аустралијско западно време (Касеј)", + "Antarctica\/Davis": "Дејвис време (Дејвис)", + "Antarctica\/DumontDUrville": "Димон д’Урвил време (Димон д’Урвил)", + "Antarctica\/Macquarie": "Макверијско време (Macquarie)", + "Antarctica\/Mawson": "Мосон време (Мосон)", + "Antarctica\/McMurdo": "Нови Зеланд време (Макмурдо)", + "Antarctica\/Palmer": "Чиле време (Палмер)", + "Antarctica\/Rothera": "Ротера време (Ротера)", + "Antarctica\/Syowa": "Шова време (Шова)", + "Antarctica\/Troll": "Гринвич средње време (Troll)", + "Antarctica\/Vostok": "Восток време (Восток)", + "Arctic\/Longyearbyen": "Средњеевропско време (Лонгјербјен)", + "Asia\/Aden": "Арабијско време (Аден)", + "Asia\/Almaty": "Источно-казахстанско време (Алмати)", + "Asia\/Amman": "Источноевропско време (Аман)", + "Asia\/Anadyr": "Анадир време (Анадир)", + "Asia\/Aqtau": "Западно-казахстанско време (Актау)", + "Asia\/Aqtobe": "Западно-казахстанско време (Акутобе)", + "Asia\/Ashgabat": "Туркменистан време (Ашхабад)", + "Asia\/Atyrau": "Западно-казахстанско време (Atyrau)", + "Asia\/Baghdad": "Арабијско време (Багдад)", + "Asia\/Bahrain": "Арабијско време (Бахреин)", + "Asia\/Baku": "Азербејџан време (Баку)", + "Asia\/Bangkok": "Индокина време (Банкок)", + "Asia\/Beirut": "Источноевропско време (Бејрут)", + "Asia\/Bishkek": "Киргизстан време (Бишкек)", + "Asia\/Brunei": "Брунеј Дарусалум време (Брунеји)", + "Asia\/Calcutta": "Индијско стандардно време (Калкута)", + "Asia\/Chita": "Јакутск време (Chita)", + "Asia\/Choibalsan": "Чојбалсан време (Чојбалсан)", + "Asia\/Colombo": "Индијско стандардно време (Коломбо)", + "Asia\/Damascus": "Источноевропско време (Дамаск)", + "Asia\/Dhaka": "Бангладеш време (Дака)", + "Asia\/Dili": "Источни тимор време (Дили)", + "Asia\/Dubai": "Залив време (Дубаи)", + "Asia\/Dushanbe": "Таџикистан време (Душанбе)", + "Asia\/Famagusta": "Источноевропско време (Famagusta)", + "Asia\/Gaza": "Источноевропско време (Газа)", + "Asia\/Hebron": "Источноевропско време (Hebron)", + "Asia\/Hong_Kong": "Хонг Конг време (Хонг Конг)", + "Asia\/Hovd": "Ховд време (Ховд)", + "Asia\/Irkutsk": "Иркуцк време (Иркуцк)", + "Asia\/Jakarta": "Западно-индонезијско време (Џакарта)", + "Asia\/Jayapura": "Источно-индонезијско време (Џајапура)", + "Asia\/Jerusalem": "Израелско време (Јерусалим)", + "Asia\/Kamchatka": "Петропавловско-камчатско време (Камчатка)", + "Asia\/Karachi": "Пакистан време (Карачи)", + "Asia\/Katmandu": "Непал време (Катманду)", + "Asia\/Khandyga": "Јакутск време (Khandyga)", + "Asia\/Krasnoyarsk": "Краснојарск време (Краснојарск)", + "Asia\/Kuala_Lumpur": "Малезија време (Куала Лумпур)", + "Asia\/Kuching": "Малезија време (Кучинг)", + "Asia\/Kuwait": "Арабијско време (Кувајт)", + "Asia\/Macau": "Кина време (Макау)", + "Asia\/Magadan": "Магадан време (Магадан)", + "Asia\/Makassar": "Централно-индонезијско време (Макасар)", + "Asia\/Manila": "Филипини време (Манила)", + "Asia\/Muscat": "Залив време (Мускат)", + "Asia\/Nicosia": "Источноевропско време (Никозија)", + "Asia\/Novokuznetsk": "Краснојарск време (Novokuznetsk)", + "Asia\/Novosibirsk": "Новосибирск време (Новосибирск)", + "Asia\/Omsk": "Омск време (Омск)", + "Asia\/Oral": "Западно-казахстанско време (Орал)", + "Asia\/Phnom_Penh": "Индокина време (Пном Пен)", + "Asia\/Pontianak": "Западно-индонезијско време (Понтианак)", + "Asia\/Pyongyang": "Кореја време (Пјонгјанг)", + "Asia\/Qatar": "Арабијско време (Катар)", + "Asia\/Qostanay": "Источно-казахстанско време (Qostanay)", + "Asia\/Qyzylorda": "Западно-казахстанско време (Кизилорда)", + "Asia\/Rangoon": "Мијанмар време (Рангун)", + "Asia\/Riyadh": "Арабијско време (Ријад)", + "Asia\/Saigon": "Индокина време (Хо Ши Мин)", + "Asia\/Sakhalin": "Сахалин време (Сахалин)", + "Asia\/Samarkand": "Узбекистан време (Самарканд)", + "Asia\/Seoul": "Кореја време (Сеул)", + "Asia\/Shanghai": "Кина време (Шангај)", + "Asia\/Singapore": "Сингапур стандардно време (Сингапур)", + "Asia\/Srednekolymsk": "Магадан време (Srednekolymsk)", + "Asia\/Taipei": "Таипеи време (Тајпеј)", + "Asia\/Tashkent": "Узбекистан време (Ташкент)", + "Asia\/Tbilisi": "Грузија време (Тбилиси)", + "Asia\/Tehran": "Иран време (Техеран)", + "Asia\/Thimphu": "Бутан време (Тимпу)", + "Asia\/Tokyo": "Јапанско време (Токио)", + "Asia\/Ulaanbaatar": "Улан Батор време (Улан Батор)", + "Asia\/Ust-Nera": "Владивосток време (Ust-Nera)", + "Asia\/Vientiane": "Индокина време (Вијентијан)", + "Asia\/Vladivostok": "Владивосток време (Владивосток)", + "Asia\/Yakutsk": "Јакутск време (Јакутск)", + "Asia\/Yekaterinburg": "Јекатеринбург време (Јекатеринбург)", + "Asia\/Yerevan": "Арменија време (Јереван)", + "Atlantic\/Azores": "Азори време (Азори)", + "Atlantic\/Bermuda": "Атланско време (Бермуда)", + "Atlantic\/Canary": "Западноевропско време (Канарска острва)", + "Atlantic\/Cape_Verde": "Зелениртско време (Зеленортска Острва)", + "Atlantic\/Faeroe": "Западноевропско време (Фарска острва)", + "Atlantic\/Madeira": "Западноевропско време (Мадера)", + "Atlantic\/Reykjavik": "Гринвич средње време (Рејкјавик)", + "Atlantic\/South_Georgia": "Јужна Џорџија време (Јужна Џорџија)", + "Atlantic\/St_Helena": "Гринвич средње време (Св. Јелена)", + "Atlantic\/Stanley": "Фолкландска Острва време (Стенли)", + "Australia\/Adelaide": "Аустралијско централно време (Аделаида)", + "Australia\/Brisbane": "Аустралијско источно време (Бризбејн)", + "Australia\/Broken_Hill": "Аустралијско централно време (Брокен Хил)", + "Australia\/Currie": "Аустралијско источно време (Курие)", + "Australia\/Darwin": "Аустралијско централно време (Дарвин)", + "Australia\/Eucla": "Аустралијско централно западно време (Иукла)", + "Australia\/Hobart": "Аустралијско источно време (Хобарт)", + "Australia\/Lindeman": "Аустралијско источно време (Линдеман)", + "Australia\/Lord_Howe": "Лорд Хов време (Лорд Хов)", + "Australia\/Melbourne": "Аустралијско источно време (Мелбурн)", + "Australia\/Perth": "Аустралијско западно време (Перт)", + "Australia\/Sydney": "Аустралијско источно време (Сиднеј)", + "CST6CDT": "Централно време", + "EST5EDT": "Источно време", + "Etc\/GMT": "Гринвич средње време", + "Europe\/Amsterdam": "Средњеевропско време (Амстердам)", + "Europe\/Andorra": "Средњеевропско време (Андора)", + "Europe\/Astrakhan": "Москва време (Astrakhan)", + "Europe\/Athens": "Источноевропско време (Атина)", + "Europe\/Belgrade": "Средњеевропско време (Београд)", + "Europe\/Berlin": "Средњеевропско време (Берлин)", + "Europe\/Bratislava": "Средњеевропско време (Братислава)", + "Europe\/Brussels": "Средњеевропско време (Брисел)", + "Europe\/Bucharest": "Источноевропско време (Букурешт)", + "Europe\/Budapest": "Средњеевропско време (Будимпешта)", + "Europe\/Busingen": "Средњеевропско време (Busingen)", + "Europe\/Chisinau": "Источноевропско време (Кишињев)", + "Europe\/Copenhagen": "Средњеевропско време (Копенхаген)", + "Europe\/Dublin": "Гринвич средње време (Даблин)", + "Europe\/Gibraltar": "Средњеевропско време (Гибралтар)", + "Europe\/Guernsey": "Гринвич средње време (Гернзи)", + "Europe\/Helsinki": "Источноевропско време (Хелсинки)", + "Europe\/Isle_of_Man": "Гринвич средње време (Острво Ман)", + "Europe\/Jersey": "Гринвич средње време (Џерси)", + "Europe\/Kaliningrad": "Источноевропско време (Калининград)", + "Europe\/Kiev": "Источноевропско време (Кијев)", + "Europe\/Lisbon": "Западноевропско време (Лисабон)", + "Europe\/Ljubljana": "Средњеевропско време (Љубљана)", + "Europe\/London": "Гринвич средње време (Лондон)", + "Europe\/Luxembourg": "Средњеевропско време (Луксембург)", + "Europe\/Madrid": "Средњеевропско време (Мадрид)", + "Europe\/Malta": "Средњеевропско време (Малта)", + "Europe\/Mariehamn": "Источноевропско време (Марихамн)", + "Europe\/Minsk": "Москва време (Минск)", + "Europe\/Monaco": "Средњеевропско време (Монако)", + "Europe\/Moscow": "Москва време (Москва)", + "Europe\/Oslo": "Средњеевропско време (Осло)", + "Europe\/Paris": "Средњеевропско време (Париз)", + "Europe\/Podgorica": "Средњеевропско време (Подгорица)", + "Europe\/Prague": "Средњеевропско време (Праг)", + "Europe\/Riga": "Источноевропско време (Рига)", + "Europe\/Rome": "Средњеевропско време (Рим)", + "Europe\/Samara": "Самара време (Самара)", + "Europe\/San_Marino": "Средњеевропско време (Сан Марино)", + "Europe\/Sarajevo": "Средњеевропско време (Сарајево)", + "Europe\/Saratov": "Москва време (Saratov)", + "Europe\/Simferopol": "Москва време (Симферопол)", + "Europe\/Skopje": "Средњеевропско време (Скопље)", + "Europe\/Sofia": "Источноевропско време (Софија)", + "Europe\/Stockholm": "Средњеевропско време (Стокхолм)", + "Europe\/Tallinn": "Источноевропско време (Талин)", + "Europe\/Tirane": "Средњеевропско време (Тирана)", + "Europe\/Ulyanovsk": "Москва време (Ulyanovsk)", + "Europe\/Uzhgorod": "Источноевропско време (Ужгород)", + "Europe\/Vaduz": "Средњеевропско време (Вадуз)", + "Europe\/Vatican": "Средњеевропско време (Ватикан)", + "Europe\/Vienna": "Средњеевропско време (Беч)", + "Europe\/Vilnius": "Источноевропско време (Виљнус)", + "Europe\/Volgograd": "Волгоград време (Волгоград)", + "Europe\/Warsaw": "Средњеевропско време (Варшава)", + "Europe\/Zagreb": "Средњеевропско време (Загреб)", + "Europe\/Zaporozhye": "Источноевропско време (Запорожје)", + "Europe\/Zurich": "Средњеевропско време (Цирих)", + "Indian\/Antananarivo": "Источно-афричко време (Антананариво)", + "Indian\/Chagos": "Индијско океанско време (Чагос)", + "Indian\/Christmas": "Божићна острва време (Божић)", + "Indian\/Cocos": "Кокос (Келинг) Острва време (Кокос)", + "Indian\/Comoro": "Источно-афричко време (Коморо)", + "Indian\/Kerguelen": "Француско јужно и антарктичко време (Кергелен)", + "Indian\/Mahe": "Сејшели време (Махе)", + "Indian\/Maldives": "Малдиви време (Малдиви)", + "Indian\/Mauritius": "Маурицијус време (Маурицијус)", + "Indian\/Mayotte": "Источно-афричко време (Мајот)", + "Indian\/Reunion": "Реинион време (Реунион)", + "MST7MDT": "Планинско време", + "PST8PDT": "Пацифичко време", + "Pacific\/Auckland": "Нови Зеланд време (Окланд)", + "Pacific\/Bougainville": "Папуа Нова Гвинеја време (Bougainville)", + "Pacific\/Chatham": "Чатам време (Катхам)", + "Pacific\/Easter": "Ускршња острва време (Ускршње острво)", + "Pacific\/Efate": "Вануату време (Ефат)", + "Pacific\/Enderbury": "Феникс острва време (Ендербери)", + "Pacific\/Fakaofo": "Токелау време (Факаофо)", + "Pacific\/Fiji": "Фиџи време (Фиџи)", + "Pacific\/Funafuti": "Тувалу време (Фунафути)", + "Pacific\/Galapagos": "Галапагос време (Галапагос)", + "Pacific\/Gambier": "Гамбијер време (Гамбије)", + "Pacific\/Guadalcanal": "Соломонска Острва време (Гвадалканал)", + "Pacific\/Guam": "Чаморо време (Гуам)", + "Pacific\/Honolulu": "Хавајско-алеутско време (Хонолулу)", + "Pacific\/Johnston": "Хавајско-алеутско време (Џонстон)", + "Pacific\/Kiritimati": "Лине Острва време (Киритимати)", + "Pacific\/Kosrae": "Кошре време (Кошре)", + "Pacific\/Kwajalein": "Маршалска Острва време (Кваџалејин)", + "Pacific\/Majuro": "Маршалска Острва време (Мајуро)", + "Pacific\/Marquesas": "Маркиз време (Маркиз)", + "Pacific\/Midway": "Самоа време (Мидвеј)", + "Pacific\/Nauru": "Науру време (Науру)", + "Pacific\/Niue": "Ниуе време (Ниуе)", + "Pacific\/Norfolk": "Норфолк Острво време (Норфолк)", + "Pacific\/Noumea": "Нова Каледонија време (Нумеа)", + "Pacific\/Pago_Pago": "Самоа време (Паго Паго)", + "Pacific\/Pitcairn": "Питкерн време (Питкаирн)", + "Pacific\/Ponape": "Понапе време (Понапе)", + "Pacific\/Port_Moresby": "Папуа Нова Гвинеја време (Порт Морзби)", + "Pacific\/Rarotonga": "Кукова острва време (Раротонга)", + "Pacific\/Saipan": "Чаморо време (Сајпан)", + "Pacific\/Tahiti": "Тахити време (Тахити)", + "Pacific\/Tarawa": "Гилберт острва време (Тарава)", + "Pacific\/Tongatapu": "Тонга време (Тонгатапу)", + "Pacific\/Truk": "Трук време (Трук)", + "Pacific\/Wake": "Вејк острво време (Вејк)", + "Pacific\/Wallis": "Валис и Футуна Острва време (Валис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ca.json b/src/Symfony/Component/Intl/Resources/data/timezones/ca.json new file mode 100644 index 0000000000000..c65c9ce1455a7 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ca.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Hora del Meridià de Greenwich (Abidjan)", + "Africa\/Accra": "Hora del Meridià de Greenwich (Accra)", + "Africa\/Addis_Ababa": "Hora de l’Àfrica Oriental (Addis Abeba)", + "Africa\/Algiers": "Hora del Centre d’Europa (Alger)", + "Africa\/Asmera": "Hora de l’Àfrica Oriental (Asmara)", + "Africa\/Bamako": "Hora del Meridià de Greenwich (Bamako)", + "Africa\/Bangui": "Hora de l’Àfrica Occidental (Bangui)", + "Africa\/Banjul": "Hora del Meridià de Greenwich (Banjul)", + "Africa\/Bissau": "Hora del Meridià de Greenwich (Bissau)", + "Africa\/Blantyre": "Hora de l’Àfrica Central (Blantyre)", + "Africa\/Brazzaville": "Hora de l’Àfrica Occidental (Brazzaville)", + "Africa\/Bujumbura": "Hora de l’Àfrica Central (Bujumbura)", + "Africa\/Cairo": "Hora de l’Est d’Europa (Caire, el)", + "Africa\/Casablanca": "Hora de l’Oest d’Europa (Casablanca)", + "Africa\/Ceuta": "Hora del Centre d’Europa (Ceuta)", + "Africa\/Conakry": "Hora del Meridià de Greenwich (Conakry)", + "Africa\/Dakar": "Hora del Meridià de Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Hora de l’Àfrica Oriental (Dar es Salaam)", + "Africa\/Djibouti": "Hora de l’Àfrica Oriental (Djibouti)", + "Africa\/Douala": "Hora de l’Àfrica Occidental (Douala)", + "Africa\/El_Aaiun": "Hora de l’Oest d’Europa (Al-aaiun)", + "Africa\/Freetown": "Hora del Meridià de Greenwich (Freetown)", + "Africa\/Gaborone": "Hora de l’Àfrica Central (Gaborone)", + "Africa\/Harare": "Hora de l’Àfrica Central (Harare)", + "Africa\/Johannesburg": "Hora estàndard del sud de l’Àfrica (Johannesburg)", + "Africa\/Juba": "Hora de l’Àfrica Oriental (Juba)", + "Africa\/Kampala": "Hora de l’Àfrica Oriental (Kampala)", + "Africa\/Khartoum": "Hora de l’Àfrica Central (Khartum)", + "Africa\/Kigali": "Hora de l’Àfrica Central (Kigali)", + "Africa\/Kinshasa": "Hora de l’Àfrica Occidental (Kinshasa)", + "Africa\/Lagos": "Hora de l’Àfrica Occidental (Lagos)", + "Africa\/Libreville": "Hora de l’Àfrica Occidental (Libreville)", + "Africa\/Lome": "Hora del Meridià de Greenwich (Lome)", + "Africa\/Luanda": "Hora de l’Àfrica Occidental (Luanda)", + "Africa\/Lubumbashi": "Hora de l’Àfrica Central (Lubumbashi)", + "Africa\/Lusaka": "Hora de l’Àfrica Central (Lusaka)", + "Africa\/Malabo": "Hora de l’Àfrica Occidental (Malabo)", + "Africa\/Maputo": "Hora de l’Àfrica Central (Maputo)", + "Africa\/Maseru": "Hora estàndard del sud de l’Àfrica (Maseru)", + "Africa\/Mbabane": "Hora estàndard del sud de l’Àfrica (Mbabane)", + "Africa\/Mogadishu": "Hora de l’Àfrica Oriental (Muqdiisho)", + "Africa\/Monrovia": "Hora del Meridià de Greenwich (Monrovia)", + "Africa\/Nairobi": "Hora de l’Àfrica Oriental (Nairobi)", + "Africa\/Ndjamena": "Hora de l’Àfrica Occidental (Ndjamena)", + "Africa\/Niamey": "Hora de l’Àfrica Occidental (Niamey)", + "Africa\/Nouakchott": "Hora del Meridià de Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Hora del Meridià de Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Hora de l’Àfrica Occidental (Porto-Novo)", + "Africa\/Sao_Tome": "Hora del Meridià de Greenwich (São Tomé)", + "Africa\/Tripoli": "Hora de l’Est d’Europa (Trípoli)", + "Africa\/Tunis": "Hora del Centre d’Europa (Tunis)", + "Africa\/Windhoek": "Hora de l’Àfrica Central (Windhoek)", + "America\/Adak": "Hora de Hawaii-Aleutianes (Adak)", + "America\/Anchorage": "Hora d’Alaska (Anchorage)", + "America\/Anguilla": "Hora de l’Atlàntic (Anguilla)", + "America\/Antigua": "Hora de l’Atlàntic (Antigua)", + "America\/Araguaina": "Hora de Brasília (Araguaína)", + "America\/Argentina\/La_Rioja": "Hora de l’Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Hora de l’Argentina (Río Gallegos)", + "America\/Argentina\/Salta": "Hora de l’Argentina (Salta)", + "America\/Argentina\/San_Juan": "Hora de l’Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Hora de l’oest de l’Argentina (San Luis)", + "America\/Argentina\/Tucuman": "Hora de l’Argentina (Tucumán)", + "America\/Argentina\/Ushuaia": "Hora de l’Argentina (Ushuaia)", + "America\/Aruba": "Hora de l’Atlàntic (Aruba)", + "America\/Asuncion": "Hora del Paraguai (Asunción)", + "America\/Bahia": "Hora de Brasília (Bahia)", + "America\/Bahia_Banderas": "Hora central d’Amèrica del Nord (Bahía de Banderas)", + "America\/Barbados": "Hora de l’Atlàntic (Barbados)", + "America\/Belem": "Hora de Brasília (Belém)", + "America\/Belize": "Hora central d’Amèrica del Nord (Belize)", + "America\/Blanc-Sablon": "Hora de l’Atlàntic (Blanc Sablon)", + "America\/Boa_Vista": "Hora de l’Amazones (Boa Vista)", + "America\/Bogota": "Hora de Colòmbia (Bogotà)", + "America\/Boise": "Hora de muntanya d’Amèrica del Nord (Boise)", + "America\/Buenos_Aires": "Hora de l’Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Hora de muntanya d’Amèrica del Nord (Cambridge Bay)", + "America\/Campo_Grande": "Hora de l’Amazones (Campo Grande)", + "America\/Cancun": "Hora oriental d’Amèrica del Nord (Cancun)", + "America\/Caracas": "Hora de Veneçuela (Caracas)", + "America\/Catamarca": "Hora de l’Argentina (Catamarca)", + "America\/Cayenne": "Hora de la Guaiana Francesa (Caiena)", + "America\/Cayman": "Hora oriental d’Amèrica del Nord (Caiman)", + "America\/Chicago": "Hora central d’Amèrica del Nord (Chicago)", + "America\/Chihuahua": "Hora del Pacífic de Mèxic (Chihuahua)", + "America\/Coral_Harbour": "Hora oriental d’Amèrica del Nord (Atikokan)", + "America\/Cordoba": "Hora de l’Argentina (Córdoba)", + "America\/Costa_Rica": "Hora central d’Amèrica del Nord (Costa Rica)", + "America\/Creston": "Hora de muntanya d’Amèrica del Nord (Creston)", + "America\/Cuiaba": "Hora de l’Amazones (Cuiabá)", + "America\/Curacao": "Hora de l’Atlàntic (Curaçao)", + "America\/Danmarkshavn": "Hora del Meridià de Greenwich (Danmarkshavn)", + "America\/Dawson": "Hora del Pacífic d’Amèrica del Nord (Dawson)", + "America\/Dawson_Creek": "Hora de muntanya d’Amèrica del Nord (Dawson Creek)", + "America\/Denver": "Hora de muntanya d’Amèrica del Nord (Denver)", + "America\/Detroit": "Hora oriental d’Amèrica del Nord (Detroit)", + "America\/Dominica": "Hora de l’Atlàntic (Dominica)", + "America\/Edmonton": "Hora de muntanya d’Amèrica del Nord (Edmonton)", + "America\/El_Salvador": "Hora central d’Amèrica del Nord (El Salvador)", + "America\/Fort_Nelson": "Hora de muntanya d’Amèrica del Nord (Fort Nelson)", + "America\/Fortaleza": "Hora de Brasília (Fortaleza)", + "America\/Glace_Bay": "Hora de l’Atlàntic (Glace Bay)", + "America\/Godthab": "Hora de l’Oest de Grenlàndia (Nuuk)", + "America\/Goose_Bay": "Hora de l’Atlàntic (Goose Bay)", + "America\/Grand_Turk": "Hora oriental d’Amèrica del Nord (Grand Turk)", + "America\/Grenada": "Hora de l’Atlàntic (Grenada)", + "America\/Guadeloupe": "Hora de l’Atlàntic (Guadeloupe)", + "America\/Guatemala": "Hora central d’Amèrica del Nord (Guatemala)", + "America\/Guayaquil": "Hora de l’Equador (Guayaquil)", + "America\/Guyana": "Hora de Guyana (Guyana)", + "America\/Halifax": "Hora de l’Atlàntic (Halifax)", + "America\/Havana": "Hora de Cuba (Havana)", + "America\/Hermosillo": "Hora del Pacífic de Mèxic (Hermosillo)", + "America\/Indiana\/Knox": "Hora central d’Amèrica del Nord (Knox, Indiana)", + "America\/Indiana\/Marengo": "Hora oriental d’Amèrica del Nord (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Hora oriental d’Amèrica del Nord (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Hora central d’Amèrica del Nord (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Hora oriental d’Amèrica del Nord (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Hora oriental d’Amèrica del Nord (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Hora oriental d’Amèrica del Nord (Winamac, Indiana)", + "America\/Indianapolis": "Hora oriental d’Amèrica del Nord (Indianapolis)", + "America\/Inuvik": "Hora de muntanya d’Amèrica del Nord (Inuvik)", + "America\/Iqaluit": "Hora oriental d’Amèrica del Nord (Iqaluit)", + "America\/Jamaica": "Hora oriental d’Amèrica del Nord (Jamaica)", + "America\/Jujuy": "Hora de l’Argentina (Jujuy)", + "America\/Juneau": "Hora d’Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Hora oriental d’Amèrica del Nord (Monticello, Kentucky)", + "America\/Kralendijk": "Hora de l’Atlàntic (Kralendijk)", + "America\/La_Paz": "Hora de Bolívia (La Paz)", + "America\/Lima": "Hora del Perú (Lima)", + "America\/Los_Angeles": "Hora del Pacífic d’Amèrica del Nord (Los Angeles)", + "America\/Louisville": "Hora oriental d’Amèrica del Nord (Louisville)", + "America\/Lower_Princes": "Hora de l’Atlàntic (Lower Prince’s Quarter)", + "America\/Maceio": "Hora de Brasília (Maceió)", + "America\/Managua": "Hora central d’Amèrica del Nord (Managua)", + "America\/Manaus": "Hora de l’Amazones (Manaus)", + "America\/Marigot": "Hora de l’Atlàntic (Marigot)", + "America\/Martinique": "Hora de l’Atlàntic (Martinica)", + "America\/Matamoros": "Hora central d’Amèrica del Nord (Matamoros)", + "America\/Mazatlan": "Hora del Pacífic de Mèxic (Mazatlán)", + "America\/Mendoza": "Hora de l’Argentina (Mendoza)", + "America\/Menominee": "Hora central d’Amèrica del Nord (Menominee)", + "America\/Merida": "Hora central d’Amèrica del Nord (Mérida)", + "America\/Metlakatla": "Hora d’Alaska (Metlakatla)", + "America\/Mexico_City": "Hora central d’Amèrica del Nord (Ciutat de Mèxic)", + "America\/Miquelon": "Hora de Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "Hora de l’Atlàntic (Moncton)", + "America\/Monterrey": "Hora central d’Amèrica del Nord (Monterrey)", + "America\/Montevideo": "Hora de l’Uruguai (Montevideo)", + "America\/Montserrat": "Hora de l’Atlàntic (Montserrat)", + "America\/Nassau": "Hora oriental d’Amèrica del Nord (Nassau)", + "America\/New_York": "Hora oriental d’Amèrica del Nord (Nova York)", + "America\/Nipigon": "Hora oriental d’Amèrica del Nord (Nipigon)", + "America\/Nome": "Hora d’Alaska (Nome)", + "America\/Noronha": "Hora de Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Hora central d’Amèrica del Nord (Beulah, Dakota del Nord)", + "America\/North_Dakota\/Center": "Hora central d’Amèrica del Nord (Center, Dakota del Nord)", + "America\/North_Dakota\/New_Salem": "Hora central d’Amèrica del Nord (New Salem, Dakota del Nord)", + "America\/Ojinaga": "Hora de muntanya d’Amèrica del Nord (Ojinaga)", + "America\/Panama": "Hora oriental d’Amèrica del Nord (Panamà)", + "America\/Pangnirtung": "Hora oriental d’Amèrica del Nord (Pangnirtung)", + "America\/Paramaribo": "Hora de Surinam (Paramaribo)", + "America\/Phoenix": "Hora de muntanya d’Amèrica del Nord (Phoenix)", + "America\/Port-au-Prince": "Hora oriental d’Amèrica del Nord (Port-au-Prince)", + "America\/Port_of_Spain": "Hora de l’Atlàntic (Port of Spain)", + "America\/Porto_Velho": "Hora de l’Amazones (Porto Velho)", + "America\/Puerto_Rico": "Hora de l’Atlàntic (Puerto Rico)", + "America\/Punta_Arenas": "Hora de Xile (Punta Arenas)", + "America\/Rainy_River": "Hora central d’Amèrica del Nord (Rainy River)", + "America\/Rankin_Inlet": "Hora central d’Amèrica del Nord (Rankin Inlet)", + "America\/Recife": "Hora de Brasília (Recife)", + "America\/Regina": "Hora central d’Amèrica del Nord (Regina)", + "America\/Resolute": "Hora central d’Amèrica del Nord (Resolute)", + "America\/Santa_Isabel": "Hora del nord-oest de Mèxic (Santa Isabel)", + "America\/Santarem": "Hora de Brasília (Santarém)", + "America\/Santiago": "Hora de Xile (Santiago)", + "America\/Santo_Domingo": "Hora de l’Atlàntic (Santo Domingo)", + "America\/Sao_Paulo": "Hora de Brasília (São Paulo)", + "America\/Scoresbysund": "Hora de l’Est de Grenlàndia (Scoresbysund)", + "America\/Sitka": "Hora d’Alaska (Sitka)", + "America\/St_Barthelemy": "Hora de l’Atlàntic (Saint Barthélemy)", + "America\/St_Johns": "Hora de Terranova (Saint John’s)", + "America\/St_Kitts": "Hora de l’Atlàntic (Saint Kitts)", + "America\/St_Lucia": "Hora de l’Atlàntic (Saint Lucia)", + "America\/St_Thomas": "Hora de l’Atlàntic (Saint Thomas)", + "America\/St_Vincent": "Hora de l’Atlàntic (Saint Vincent)", + "America\/Swift_Current": "Hora central d’Amèrica del Nord (Swift Current)", + "America\/Tegucigalpa": "Hora central d’Amèrica del Nord (Tegucigalpa)", + "America\/Thule": "Hora de l’Atlàntic (Thule)", + "America\/Thunder_Bay": "Hora oriental d’Amèrica del Nord (Thunder Bay)", + "America\/Tijuana": "Hora del Pacífic d’Amèrica del Nord (Tijuana)", + "America\/Toronto": "Hora oriental d’Amèrica del Nord (Toronto)", + "America\/Tortola": "Hora de l’Atlàntic (Tortola)", + "America\/Vancouver": "Hora del Pacífic d’Amèrica del Nord (Vancouver)", + "America\/Whitehorse": "Hora del Pacífic d’Amèrica del Nord (Whitehorse)", + "America\/Winnipeg": "Hora central d’Amèrica del Nord (Winnipeg)", + "America\/Yakutat": "Hora d’Alaska (Yakutat)", + "America\/Yellowknife": "Hora de muntanya d’Amèrica del Nord (Yellowknife)", + "Antarctica\/Casey": "Hora d’Austràlia Occidental (Casey)", + "Antarctica\/Davis": "Hora de Davis (Davis)", + "Antarctica\/DumontDUrville": "Hora de Dumont d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Hora de Macquarie (Macquarie)", + "Antarctica\/Mawson": "Hora de Mawson (Mawson)", + "Antarctica\/McMurdo": "Hora de Nova Zelanda (McMurdo)", + "Antarctica\/Palmer": "Hora de Xile (Palmer)", + "Antarctica\/Rothera": "Hora de Rothera (Rothera)", + "Antarctica\/Syowa": "Hora de Syowa (Syowa)", + "Antarctica\/Troll": "Hora del Meridià de Greenwich (Troll)", + "Antarctica\/Vostok": "Hora de Vostok (Vostok)", + "Arctic\/Longyearbyen": "Hora del Centre d’Europa (Longyearbyen)", + "Asia\/Aden": "Hora àrab (Aden)", + "Asia\/Almaty": "Hora de l’est del Kazakhstan (Almaty)", + "Asia\/Amman": "Hora de l’Est d’Europa (Amman)", + "Asia\/Anadyr": "Hora d’Anadyr (Anadyr’)", + "Asia\/Aqtau": "Hora de l’oest del Kazakhstan (Aqtaū)", + "Asia\/Aqtobe": "Hora de l’oest del Kazakhstan (Aqtobe)", + "Asia\/Ashgabat": "Hora del Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Hora de l’oest del Kazakhstan (Atirau)", + "Asia\/Baghdad": "Hora àrab (Bagdad)", + "Asia\/Bahrain": "Hora àrab (Bahrain)", + "Asia\/Baku": "Hora d’Azerbaidjan (Bakú)", + "Asia\/Bangkok": "Hora d’Indoxina (Bangkok)", + "Asia\/Beirut": "Hora de l’Est d’Europa (Beirut)", + "Asia\/Bishkek": "Hora del Kirguizistan (Bixkek)", + "Asia\/Brunei": "Hora de Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Hora de l’Índia (Calcuta)", + "Asia\/Chita": "Hora de Iakutsk (Txità)", + "Asia\/Choibalsan": "Hora de Choibalsan (Choibalsan)", + "Asia\/Colombo": "Hora de l’Índia (Colombo)", + "Asia\/Damascus": "Hora de l’Est d’Europa (Damasc)", + "Asia\/Dhaka": "Hora de Bangla Desh (Dacca)", + "Asia\/Dili": "Hora de Timor Oriental (Dili)", + "Asia\/Dubai": "Hora del Golf (Dubai)", + "Asia\/Dushanbe": "Hora del Tadjikistan (Dushanbe)", + "Asia\/Famagusta": "Hora de l’Est d’Europa (Famagusta)", + "Asia\/Gaza": "Hora de l’Est d’Europa (Gaza)", + "Asia\/Hebron": "Hora de l’Est d’Europa (Hebron)", + "Asia\/Hong_Kong": "Hora de Hong Kong (Hong Kong)", + "Asia\/Hovd": "Hora de Hovd (Hovd)", + "Asia\/Irkutsk": "Hora d’Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Hora de l’oest d’Indonèsia (Jakarta)", + "Asia\/Jayapura": "Hora de l’est d’Indonèsia (Jaipur)", + "Asia\/Jerusalem": "Hora d’Israel (Jerusalem)", + "Asia\/Kabul": "Hora de l’Afganistan (Kābul)", + "Asia\/Kamchatka": "Hora de Kamtxatka (Kamtxatka)", + "Asia\/Karachi": "Hora del Pakistan (Karachi)", + "Asia\/Katmandu": "Hora del Nepal (Katmandú)", + "Asia\/Khandyga": "Hora de Iakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Hora de Krasnoiarsk (Krasnoiarsk)", + "Asia\/Kuala_Lumpur": "Hora de Malàisia (Kuala Lumpur)", + "Asia\/Kuching": "Hora de Malàisia (Kuching)", + "Asia\/Kuwait": "Hora àrab (Kuwait)", + "Asia\/Macau": "Hora de la Xina (Macau)", + "Asia\/Magadan": "Hora de Magadan (Magadan)", + "Asia\/Makassar": "Hora central d’Indonèsia (Makasar)", + "Asia\/Manila": "Hora de Filipines (Manila)", + "Asia\/Muscat": "Hora del Golf (Masqat)", + "Asia\/Nicosia": "Hora de l’Est d’Europa (Nicòsia)", + "Asia\/Novokuznetsk": "Hora de Krasnoiarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Hora de Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Hora d’Omsk (Omsk)", + "Asia\/Oral": "Hora de l’oest del Kazakhstan (Oral)", + "Asia\/Phnom_Penh": "Hora d’Indoxina (Phnom Penh)", + "Asia\/Pontianak": "Hora de l’oest d’Indonèsia (Pontianak)", + "Asia\/Pyongyang": "Hora de Corea (Pyongyang)", + "Asia\/Qatar": "Hora àrab (Qatar)", + "Asia\/Qostanay": "Hora de l’est del Kazakhstan (Kostanai)", + "Asia\/Qyzylorda": "Hora de l’oest del Kazakhstan (Kizil-Orda)", + "Asia\/Rangoon": "Hora de Myanmar (Yangôn)", + "Asia\/Riyadh": "Hora àrab (Al-Riyād)", + "Asia\/Saigon": "Hora d’Indoxina (Ho Chi Minh)", + "Asia\/Sakhalin": "Hora de Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Hora de l’Uzbekistan (Samarcanda)", + "Asia\/Seoul": "Hora de Corea (Seül)", + "Asia\/Shanghai": "Hora de la Xina (Xangai)", + "Asia\/Singapore": "Hora de Singapur (Singapur)", + "Asia\/Srednekolymsk": "Hora de Magadan (Srednekolimsk)", + "Asia\/Taipei": "Hora de Taipei (Taipei)", + "Asia\/Tashkent": "Hora de l’Uzbekistan (Taixkent)", + "Asia\/Tbilisi": "Hora de Geòrgia (Tbilisi)", + "Asia\/Tehran": "Hora d’Iran (Teheran)", + "Asia\/Thimphu": "Hora de Bhutan (Thimbu)", + "Asia\/Tokyo": "Hora del Japó (Tòquio)", + "Asia\/Ulaanbaatar": "Hora d’Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "Hora de Vladivostok (Ust’-Nera)", + "Asia\/Vientiane": "Hora d’Indoxina (Vientiane)", + "Asia\/Vladivostok": "Hora de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Hora de Iakutsk (Jakutsk)", + "Asia\/Yekaterinburg": "Hora d’Ekaterinburg (Jekaterinburg)", + "Asia\/Yerevan": "Hora d’Armènia (Erevan)", + "Atlantic\/Azores": "Hora de les Açores (Açores)", + "Atlantic\/Bermuda": "Hora de l’Atlàntic (Bermudes)", + "Atlantic\/Canary": "Hora de l’Oest d’Europa (Illes Canàries)", + "Atlantic\/Cape_Verde": "Hora de Cap Verd (Cap Verd)", + "Atlantic\/Faeroe": "Hora de l’Oest d’Europa (Illes Fèroe)", + "Atlantic\/Madeira": "Hora de l’Oest d’Europa (Madeira)", + "Atlantic\/Reykjavik": "Hora del Meridià de Greenwich (Reykjavik)", + "Atlantic\/South_Georgia": "Hora de Geòrgia del Sud (Geòrgia del Sud)", + "Atlantic\/St_Helena": "Hora del Meridià de Greenwich (Saint Helena)", + "Atlantic\/Stanley": "Hora de les illes Malvines (Stanley)", + "Australia\/Adelaide": "Hora d’Austràlia Central (Adelaide)", + "Australia\/Brisbane": "Hora d’Austràlia Oriental (Brisbane)", + "Australia\/Broken_Hill": "Hora d’Austràlia Central (Broken Hill)", + "Australia\/Currie": "Hora d’Austràlia Oriental (Currie)", + "Australia\/Darwin": "Hora d’Austràlia Central (Darwin)", + "Australia\/Eucla": "Hora d’Austràlia centre-occidental (Eucla)", + "Australia\/Hobart": "Hora d’Austràlia Oriental (Hobart)", + "Australia\/Lindeman": "Hora d’Austràlia Oriental (Lindeman)", + "Australia\/Lord_Howe": "Hora de Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Hora d’Austràlia Oriental (Melbourne)", + "Australia\/Perth": "Hora d’Austràlia Occidental (Perth)", + "Australia\/Sydney": "Hora d’Austràlia Oriental (Sydney)", + "CST6CDT": "Hora central d’Amèrica del Nord", + "EST5EDT": "Hora oriental d’Amèrica del Nord", + "Etc\/GMT": "Hora del Meridià de Greenwich", + "Etc\/UTC": "Temps universal coordinat", + "Europe\/Amsterdam": "Hora del Centre d’Europa (Amsterdam)", + "Europe\/Andorra": "Hora del Centre d’Europa (Andorra)", + "Europe\/Astrakhan": "Hora de Moscou (Astrakhan)", + "Europe\/Athens": "Hora de l’Est d’Europa (Atenes)", + "Europe\/Belgrade": "Hora del Centre d’Europa (Belgrad)", + "Europe\/Berlin": "Hora del Centre d’Europa (Berlín)", + "Europe\/Bratislava": "Hora del Centre d’Europa (Bratislava)", + "Europe\/Brussels": "Hora del Centre d’Europa (Brussel·les)", + "Europe\/Bucharest": "Hora de l’Est d’Europa (Bucarest)", + "Europe\/Budapest": "Hora del Centre d’Europa (Budapest)", + "Europe\/Busingen": "Hora del Centre d’Europa (Busingen)", + "Europe\/Chisinau": "Hora de l’Est d’Europa (Chisinau)", + "Europe\/Copenhagen": "Hora del Centre d’Europa (Copenhagen)", + "Europe\/Dublin": "Hora del Meridià de Greenwich (Dublín)", + "Europe\/Gibraltar": "Hora del Centre d’Europa (Gibraltar)", + "Europe\/Guernsey": "Hora del Meridià de Greenwich (Guernsey)", + "Europe\/Helsinki": "Hora de l’Est d’Europa (Hèlsinki)", + "Europe\/Isle_of_Man": "Hora del Meridià de Greenwich (Man)", + "Europe\/Jersey": "Hora del Meridià de Greenwich (Jersey)", + "Europe\/Kaliningrad": "Hora de l’Est d’Europa (Kaliningrad)", + "Europe\/Kiev": "Hora de l’Est d’Europa (Kíev)", + "Europe\/Lisbon": "Hora de l’Oest d’Europa (Lisboa)", + "Europe\/Ljubljana": "Hora del Centre d’Europa (Ljubljana)", + "Europe\/London": "Hora del Meridià de Greenwich (Londres)", + "Europe\/Luxembourg": "Hora del Centre d’Europa (Luxemburg)", + "Europe\/Madrid": "Hora del Centre d’Europa (Madrid)", + "Europe\/Malta": "Hora del Centre d’Europa (Malta)", + "Europe\/Mariehamn": "Hora de l’Est d’Europa (Maarianhamina)", + "Europe\/Minsk": "Hora de Moscou (Minsk)", + "Europe\/Monaco": "Hora del Centre d’Europa (Mònaco)", + "Europe\/Moscow": "Hora de Moscou (Moscou)", + "Europe\/Oslo": "Hora del Centre d’Europa (Oslo)", + "Europe\/Paris": "Hora del Centre d’Europa (París)", + "Europe\/Podgorica": "Hora del Centre d’Europa (Podgorica)", + "Europe\/Prague": "Hora del Centre d’Europa (Praga)", + "Europe\/Riga": "Hora de l’Est d’Europa (Riga)", + "Europe\/Rome": "Hora del Centre d’Europa (Roma)", + "Europe\/Samara": "Hora de Samara (Samara)", + "Europe\/San_Marino": "Hora del Centre d’Europa (San Marino)", + "Europe\/Sarajevo": "Hora del Centre d’Europa (Sarajevo)", + "Europe\/Saratov": "Hora de Moscou (Saràtov)", + "Europe\/Simferopol": "Hora de Moscou (Simferopol)", + "Europe\/Skopje": "Hora del Centre d’Europa (Skopje)", + "Europe\/Sofia": "Hora de l’Est d’Europa (Sofia)", + "Europe\/Stockholm": "Hora del Centre d’Europa (Estocolm)", + "Europe\/Tallinn": "Hora de l’Est d’Europa (Tallinn)", + "Europe\/Tirane": "Hora del Centre d’Europa (Tirana)", + "Europe\/Ulyanovsk": "Hora de Moscou (Uliànovsk)", + "Europe\/Uzhgorod": "Hora de l’Est d’Europa (Uzhgorod)", + "Europe\/Vaduz": "Hora del Centre d’Europa (Vaduz)", + "Europe\/Vatican": "Hora del Centre d’Europa (Vaticà)", + "Europe\/Vienna": "Hora del Centre d’Europa (Viena)", + "Europe\/Vilnius": "Hora de l’Est d’Europa (Vílnius)", + "Europe\/Volgograd": "Hora de Volgograd (Volgograd)", + "Europe\/Warsaw": "Hora del Centre d’Europa (Varsòvia)", + "Europe\/Zagreb": "Hora del Centre d’Europa (Zagreb)", + "Europe\/Zaporozhye": "Hora de l’Est d’Europa (Zaporíjia)", + "Europe\/Zurich": "Hora del Centre d’Europa (Zuric)", + "Indian\/Antananarivo": "Hora de l’Àfrica Oriental (Antananarivo)", + "Indian\/Chagos": "Hora de l’oceà Índic (Chagos)", + "Indian\/Christmas": "Hora de Kiritimati (Christmas)", + "Indian\/Cocos": "Hora de les illes Cocos (Cocos)", + "Indian\/Comoro": "Hora de l’Àfrica Oriental (Comoro)", + "Indian\/Kerguelen": "Hora d’Antàrtida i França del Sud (Kerguelen)", + "Indian\/Mahe": "Hora de les Seychelles (Mahe)", + "Indian\/Maldives": "Hora de les Maldives (Maldives)", + "Indian\/Mauritius": "Hora de Maurici (Maurici)", + "Indian\/Mayotte": "Hora de l’Àfrica Oriental (Mayotte)", + "Indian\/Reunion": "Hora de Reunió (Reunió)", + "MST7MDT": "Hora de muntanya d’Amèrica del Nord", + "PST8PDT": "Hora del Pacífic d’Amèrica del Nord", + "Pacific\/Apia": "Hora d’Apia (Apia)", + "Pacific\/Auckland": "Hora de Nova Zelanda (Auckland)", + "Pacific\/Bougainville": "Hora de Papua Nova Guinea (Bougainville)", + "Pacific\/Chatham": "Hora de Chatham (Chatham)", + "Pacific\/Easter": "Hora de l’illa de Pasqua (Illa de Pasqua)", + "Pacific\/Efate": "Hora de Vanatu (Efate)", + "Pacific\/Enderbury": "Hora de les illes Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Hora de Tokelau (Fakaofo)", + "Pacific\/Fiji": "Hora de Fiji (Fiji)", + "Pacific\/Funafuti": "Hora de Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Hora de Galápagos (Galápagos)", + "Pacific\/Gambier": "Hora de Gambier (Gambier)", + "Pacific\/Guadalcanal": "Hora de Salomó (Guadalcanal)", + "Pacific\/Guam": "Hora de Chamorro (Guam)", + "Pacific\/Honolulu": "Hora de Hawaii-Aleutianes (Honolulu)", + "Pacific\/Johnston": "Hora de Hawaii-Aleutianes (Johnston)", + "Pacific\/Kiritimati": "Hora de Line Islands (Kiritimati)", + "Pacific\/Kosrae": "Hora de Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Hora de les illes Marshall (Kwajalein)", + "Pacific\/Majuro": "Hora de les illes Marshall (Majuro)", + "Pacific\/Marquesas": "Hora de les Marqueses (Marqueses)", + "Pacific\/Midway": "Hora de Samoa (Midway)", + "Pacific\/Nauru": "Hora de Nauru (Nauru)", + "Pacific\/Niue": "Hora de Niue (Niue)", + "Pacific\/Norfolk": "Hora de les illes Norfolk (Norfolk)", + "Pacific\/Noumea": "Hora de Nova Caledònia (Nouméa)", + "Pacific\/Pago_Pago": "Hora de Samoa (Pago Pago)", + "Pacific\/Palau": "Hora de Palau (Palau)", + "Pacific\/Pitcairn": "Hora de Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Hora de Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Hora de Papua Nova Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Hora de les illes Cook (Rarotonga)", + "Pacific\/Saipan": "Hora de Chamorro (Saipan)", + "Pacific\/Tahiti": "Hora de Tahití (Tahití)", + "Pacific\/Tarawa": "Hora de les illes Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Hora de Tonga (Tongatapu)", + "Pacific\/Truk": "Hora de Chuuk (Chuuk)", + "Pacific\/Wake": "Hora de Wake (Wake)", + "Pacific\/Wallis": "Hora de Wallis i Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ce.json b/src/Symfony/Component/Intl/Resources/data/timezones/ce.json new file mode 100644 index 0000000000000..7431f74de89e9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ce.json @@ -0,0 +1,427 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "Гринвичица юкъара хан (Абиджан)", + "Africa\/Accra": "Гринвичица юкъара хан (Аккра)", + "Africa\/Addis_Ababa": "Малхбален Африка (Аддис-Абеба)", + "Africa\/Algiers": "Юккъера Европа (Алжир)", + "Africa\/Asmera": "Малхбален Африка (Асмера)", + "Africa\/Bamako": "Гринвичица юкъара хан (Бамако)", + "Africa\/Bangui": "Малхбузен Африка (Банги)", + "Africa\/Banjul": "Гринвичица юкъара хан (Банжул)", + "Africa\/Bissau": "Гринвичица юкъара хан (Бисау)", + "Africa\/Blantyre": "Юккъера Африка (Блантайр)", + "Africa\/Brazzaville": "Малхбузен Африка (Браззавиль)", + "Africa\/Bujumbura": "Юккъера Африка (Бужумбура)", + "Africa\/Cairo": "Малхбален Европа (КъахӀира)", + "Africa\/Casablanca": "Малхбузен Европа (Касабланка)", + "Africa\/Ceuta": "Юккъера Европа (Сеута)", + "Africa\/Conakry": "Гринвичица юкъара хан (Конакри)", + "Africa\/Dakar": "Гринвичица юкъара хан (Дакар)", + "Africa\/Dar_es_Salaam": "Малхбален Африка (Дар-эс-Салам)", + "Africa\/Djibouti": "Малхбален Африка (Джибути)", + "Africa\/Douala": "Малхбузен Африка (Дуала)", + "Africa\/El_Aaiun": "Малхбузен Европа (Эль-Аюн)", + "Africa\/Freetown": "Гринвичица юкъара хан (Фритаун)", + "Africa\/Gaborone": "Юккъера Африка (Габороне)", + "Africa\/Harare": "Юккъера Африка (Хараре)", + "Africa\/Johannesburg": "Къилба Африка (Йоханнесбург)", + "Africa\/Juba": "Малхбален Африка (Джуба)", + "Africa\/Kampala": "Малхбален Африка (Кампала)", + "Africa\/Khartoum": "Юккъера Африка (Хартум)", + "Africa\/Kigali": "Юккъера Африка (Кигали)", + "Africa\/Kinshasa": "Малхбузен Африка (Киншаса)", + "Africa\/Lagos": "Малхбузен Африка (Лагос)", + "Africa\/Libreville": "Малхбузен Африка (Либревиль)", + "Africa\/Lome": "Гринвичица юкъара хан (Ломе)", + "Africa\/Luanda": "Малхбузен Африка (Луанда)", + "Africa\/Lubumbashi": "Юккъера Африка (Лубумбаши)", + "Africa\/Lusaka": "Юккъера Африка (Лусака)", + "Africa\/Malabo": "Малхбузен Африка (Малабо)", + "Africa\/Maputo": "Юккъера Африка (Мапуту)", + "Africa\/Maseru": "Къилба Африка (Масеру)", + "Africa\/Mbabane": "Къилба Африка (Мбабане)", + "Africa\/Mogadishu": "Малхбален Африка (Могадишо)", + "Africa\/Monrovia": "Гринвичица юкъара хан (Монрови)", + "Africa\/Nairobi": "Малхбален Африка (Найроби)", + "Africa\/Ndjamena": "Малхбузен Африка (Нджамена)", + "Africa\/Niamey": "Малхбузен Африка (Ниамей)", + "Africa\/Nouakchott": "Гринвичица юкъара хан (Нуакшот)", + "Africa\/Ouagadougou": "Гринвичица юкъара хан (Уагадугу)", + "Africa\/Porto-Novo": "Малхбузен Африка (Порто-Ново)", + "Africa\/Sao_Tome": "Гринвичица юкъара хан (Сан-Томе)", + "Africa\/Tripoli": "Малхбален Европа (Триполи)", + "Africa\/Tunis": "Юккъера Европа (Тунис)", + "Africa\/Windhoek": "Юккъера Африка (Виндхук)", + "America\/Adak": "Гавайн-алеутийн хан (Адак)", + "America\/Anchorage": "Аляска (Анкоридж)", + "America\/Anguilla": "Атлантикан хан (Ангилья)", + "America\/Antigua": "Атлантикан хан (Антигуа)", + "America\/Araguaina": "Бразили (Арагуаина)", + "America\/Argentina\/La_Rioja": "Аргентина (Ла-Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аргентина (Рио-Гальегос)", + "America\/Argentina\/Salta": "Аргентина (Сальта)", + "America\/Argentina\/San_Juan": "Аргентина (Сан-Хуан)", + "America\/Argentina\/San_Luis": "Малхбузен Аргентина (Сан-Луис)", + "America\/Argentina\/Tucuman": "Аргентина (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентина (Ушуая)", + "America\/Aruba": "Атлантикан хан (Аруба)", + "America\/Asuncion": "Парагвай (Асунсьон)", + "America\/Bahia": "Бразили (Баи)", + "America\/Bahia_Banderas": "Юккъера Америка (Баия-де-Бандерас)", + "America\/Barbados": "Атлантикан хан (Барбадос)", + "America\/Belem": "Бразили (Белен)", + "America\/Belize": "Юккъера Америка (Белиз)", + "America\/Blanc-Sablon": "Атлантикан хан (Бланк-Саблон)", + "America\/Boa_Vista": "Амазонка (Боа-Виста)", + "America\/Bogota": "Колумби (Богота)", + "America\/Boise": "Лаьмнийн хан (АЦШ) (Бойсе)", + "America\/Buenos_Aires": "Аргентина (Буэнос-Айрес)", + "America\/Cambridge_Bay": "Лаьмнийн хан (АЦШ) (Кеймбридж-Бей)", + "America\/Campo_Grande": "Амазонка (Кампу-Гранди)", + "America\/Cancun": "Малхбален Америка (Канкун)", + "America\/Caracas": "Венесуэла (Каракас)", + "America\/Catamarca": "Аргентина (Катамарка)", + "America\/Cayenne": "Французийн Гвиана (Кайенна)", + "America\/Cayman": "Малхбален Америка (Кайман)", + "America\/Chicago": "Юккъера Америка (Чикаго)", + "America\/Chihuahua": "Тийна океанан Мексикан хан (Чиуауа)", + "America\/Coral_Harbour": "Малхбален Америка (Корал-Харбор)", + "America\/Cordoba": "Аргентина (Кордова)", + "America\/Costa_Rica": "Юккъера Америка (Коста-Рика)", + "America\/Creston": "Лаьмнийн хан (АЦШ) (Крестон)", + "America\/Cuiaba": "Амазонка (Куяба)", + "America\/Curacao": "Атлантикан хан (Кюрасао)", + "America\/Danmarkshavn": "Гринвичица юкъара хан (Денмарксхавн)", + "America\/Dawson": "Тийна океанан хан (Доусон)", + "America\/Dawson_Creek": "Лаьмнийн хан (АЦШ) (Доусон-Крик)", + "America\/Denver": "Лаьмнийн хан (АЦШ) (Денвер)", + "America\/Detroit": "Малхбален Америка (Детройт)", + "America\/Dominica": "Атлантикан хан (Доминика)", + "America\/Edmonton": "Лаьмнийн хан (АЦШ) (Эдмонтон)", + "America\/El_Salvador": "Юккъера Америка (Сальвадор)", + "America\/Fort_Nelson": "Лаьмнийн хан (АЦШ) (Форт Нельсон)", + "America\/Fortaleza": "Бразили (Форталеза)", + "America\/Glace_Bay": "Атлантикан хан (Глейс-Бей)", + "America\/Godthab": "Малхбузен Гренланди (Готхоб)", + "America\/Goose_Bay": "Атлантикан хан (Гус-Бей)", + "America\/Grand_Turk": "Малхбален Америка (Гранд Турк)", + "America\/Grenada": "Атлантикан хан (Гренада)", + "America\/Guadeloupe": "Атлантикан хан (Гваделупа)", + "America\/Guatemala": "Юккъера Америка (Гватемала)", + "America\/Guayaquil": "Эквадор (Гуаякиль)", + "America\/Guyana": "Гайана (Гайана)", + "America\/Halifax": "Атлантикан хан (Галифакс)", + "America\/Havana": "Куба (Гавана)", + "America\/Hermosillo": "Тийна океанан Мексикан хан (Эрмосильо)", + "America\/Indiana\/Knox": "Юккъера Америка (Нокс)", + "America\/Indiana\/Marengo": "Малхбален Америка (Маренго)", + "America\/Indiana\/Petersburg": "Малхбален Америка (Петерсбург)", + "America\/Indiana\/Tell_City": "Юккъера Америка (Телл-Сити)", + "America\/Indiana\/Vevay": "Малхбален Америка (Вивэй)", + "America\/Indiana\/Vincennes": "Малхбален Америка (Винсенс)", + "America\/Indiana\/Winamac": "Малхбален Америка (Винамак)", + "America\/Indianapolis": "Малхбален Америка (Индианаполис)", + "America\/Inuvik": "Лаьмнийн хан (АЦШ) (Инувик)", + "America\/Iqaluit": "Малхбален Америка (Икалуит)", + "America\/Jamaica": "Малхбален Америка (Ямайка)", + "America\/Jujuy": "Аргентина (Жужуй)", + "America\/Juneau": "Аляска (Джуно)", + "America\/Kentucky\/Monticello": "Малхбален Америка (Монтиселло)", + "America\/Kralendijk": "Атлантикан хан (Кралендейк)", + "America\/La_Paz": "Боливи (Ла-Пас)", + "America\/Lima": "Перу (Лима)", + "America\/Los_Angeles": "Тийна океанан хан (Лос-Анджелес)", + "America\/Louisville": "Малхбален Америка (Луисвилл)", + "America\/Lower_Princes": "Атлантикан хан (Лоуэр-Принсес-Куортер)", + "America\/Maceio": "Бразили (Масейо)", + "America\/Managua": "Юккъера Америка (Манагуа)", + "America\/Manaus": "Амазонка (Манаус)", + "America\/Marigot": "Атлантикан хан (Мариго)", + "America\/Martinique": "Атлантикан хан (Мартиника)", + "America\/Matamoros": "Юккъера Америка (Матаморос)", + "America\/Mazatlan": "Тийна океанан Мексикан хан (Масатлан)", + "America\/Mendoza": "Аргентина (Мендоса)", + "America\/Menominee": "Юккъера Америка (Меномини)", + "America\/Merida": "Юккъера Америка (Мерида)", + "America\/Metlakatla": "Аляска (Метлакатла)", + "America\/Mexico_City": "Юккъера Америка (Мехико)", + "America\/Miquelon": "Сен-Пьер а, Микелон а (Микелон)", + "America\/Moncton": "Атлантикан хан (Монктон)", + "America\/Monterrey": "Юккъера Америка (Монтеррей)", + "America\/Montevideo": "Уругвай (Монтевидео)", + "America\/Montserrat": "Атлантикан хан (Монсеррат)", + "America\/Nassau": "Малхбален Америка (Нассау)", + "America\/New_York": "Малхбален Америка (Нью-Йорк)", + "America\/Nipigon": "Малхбален Америка (Нипигон)", + "America\/Nome": "Аляска (Ном)", + "America\/Noronha": "Фернанду-ди-Норонья (Норонха)", + "America\/North_Dakota\/Beulah": "Юккъера Америка (Бойла, Къилбаседа Дакота)", + "America\/North_Dakota\/Center": "Юккъера Америка (Юкъ, Къилбаседа Дакота)", + "America\/North_Dakota\/New_Salem": "Юккъера Америка (Нью-Салем)", + "America\/Ojinaga": "Лаьмнийн хан (АЦШ) (Охинага)", + "America\/Panama": "Малхбален Америка (Панама)", + "America\/Pangnirtung": "Малхбален Америка (Пангниртанг)", + "America\/Paramaribo": "Суринам (Парамарибо)", + "America\/Phoenix": "Лаьмнийн хан (АЦШ) (Финикс)", + "America\/Port-au-Prince": "Малхбален Америка (Порт-о-Пренс)", + "America\/Port_of_Spain": "Атлантикан хан (Порт-оф-Спейн)", + "America\/Porto_Velho": "Амазонка (Порту-Велью)", + "America\/Puerto_Rico": "Атлантикан хан (Пуэрто-Рико)", + "America\/Punta_Arenas": "Чили (Пунта-Аренас)", + "America\/Rainy_River": "Юккъера Америка (Рейни-Ривер)", + "America\/Rankin_Inlet": "Юккъера Америка (Ранкин-Инлет)", + "America\/Recife": "Бразили (Ресифи)", + "America\/Regina": "Юккъера Америка (Реджайна)", + "America\/Resolute": "Юккъера Америка (Резолют)", + "America\/Santa_Isabel": "Къилбаседа Американ Мексикан хан (Санта-Изабел)", + "America\/Santarem": "Бразили (Сантарен)", + "America\/Santiago": "Чили (Сантьяго)", + "America\/Santo_Domingo": "Атлантикан хан (Санто-Доминго)", + "America\/Sao_Paulo": "Бразили (Сан-Паулу)", + "America\/Scoresbysund": "Малхбален Гренланди (Скорсбисунн)", + "America\/Sitka": "Аляска (Ситка)", + "America\/St_Barthelemy": "Атлантикан хан (Сен-Бартельми)", + "America\/St_Johns": "Ньюфаундленд (Сент-Джонс)", + "America\/St_Kitts": "Атлантикан хан (Сент-Китс)", + "America\/St_Lucia": "Атлантикан хан (Сент-Люси)", + "America\/St_Thomas": "Атлантикан хан (Сент-Томас)", + "America\/St_Vincent": "Атлантикан хан (Сент-Винсент)", + "America\/Swift_Current": "Юккъера Америка (Свифт-Карент)", + "America\/Tegucigalpa": "Юккъера Америка (Тегусигальпа)", + "America\/Thule": "Атлантикан хан (Туле)", + "America\/Thunder_Bay": "Малхбален Америка (Тандер-Бей)", + "America\/Tijuana": "Тийна океанан хан (Тихуана)", + "America\/Toronto": "Малхбален Америка (Торонто)", + "America\/Tortola": "Атлантикан хан (Тортола)", + "America\/Vancouver": "Тийна океанан хан (Ванкувер)", + "America\/Whitehorse": "Тийна океанан хан (Уайтхорс)", + "America\/Winnipeg": "Юккъера Америка (Виннипег)", + "America\/Yakutat": "Аляска (Якутат)", + "America\/Yellowknife": "Лаьмнийн хан (АЦШ) (Йеллоунайф)", + "Antarctica\/Casey": "Малхбузен Австрали (Кейси)", + "Antarctica\/Davis": "Дейвис (Дейвис)", + "Antarctica\/DumontDUrville": "Дюмон-д’Юрвиль (Дюмон-д’Юрвиль)", + "Antarctica\/Macquarie": "Маккуори (Маккуори)", + "Antarctica\/Mawson": "Моусон (Моусон)", + "Antarctica\/McMurdo": "Керла Зеланди (Мак-Мердо)", + "Antarctica\/Palmer": "Чили (Палмер)", + "Antarctica\/Rothera": "Ротера (Ротера)", + "Antarctica\/Syowa": "Сёва (Сёва)", + "Antarctica\/Troll": "Гринвичица юкъара хан (Тролль)", + "Antarctica\/Vostok": "Восток (Восток)", + "Arctic\/Longyearbyen": "Юккъера Европа (Лонгйир)", + "Asia\/Aden": "СаӀудийн Ӏаьрбийчоь (Аден)", + "Asia\/Almaty": "Малхбален Казахстан (Алма-Ата)", + "Asia\/Amman": "Малхбален Европа (Ӏамман)", + "Asia\/Aqtau": "Малхбузен Казахстан (Актау)", + "Asia\/Aqtobe": "Малхбузен Казахстан (Актобе)", + "Asia\/Ashgabat": "Туркмени (Ашхабад)", + "Asia\/Atyrau": "Малхбузен Казахстан (Атирау)", + "Asia\/Baghdad": "СаӀудийн Ӏаьрбийчоь (БагӀдад)", + "Asia\/Bahrain": "СаӀудийн Ӏаьрбийчоь (Бахрейн)", + "Asia\/Baku": "Азербайджан (Бакох)", + "Asia\/Bangkok": "Индокитай (Бангкок)", + "Asia\/Beirut": "Малхбален Европа (Бейрут)", + "Asia\/Bishkek": "Киргизи (Бишкек)", + "Asia\/Brunei": "Бруней-Даруссалам (Бруней)", + "Asia\/Calcutta": "ХӀинди (Калькутта)", + "Asia\/Chita": "Якутск (Чита)", + "Asia\/Choibalsan": "Чойбалсан (Чойбалсан)", + "Asia\/Colombo": "ХӀинди (Коломбо)", + "Asia\/Damascus": "Малхбален Европа (Димашкъ)", + "Asia\/Dhaka": "Бангладеш (Дакка)", + "Asia\/Dili": "Малхбален Тимор (Дили)", + "Asia\/Dubai": "ГӀажарийн айма (Дубай)", + "Asia\/Dushanbe": "Таджикистан (Душанбе)", + "Asia\/Famagusta": "Малхбален Европа (Фамагуста)", + "Asia\/Gaza": "Малхбален Европа (Газа)", + "Asia\/Hebron": "Малхбален Европа (Хеврон)", + "Asia\/Hong_Kong": "Гонконг (Гонконг)", + "Asia\/Hovd": "Ховд (Ховд)", + "Asia\/Irkutsk": "Иркутск (Иркутск)", + "Asia\/Jakarta": "Малхбузен Индонези (Джакарта)", + "Asia\/Jayapura": "Малхбален Индонези (Джайпур)", + "Asia\/Jerusalem": "Израиль (Къудс-ГӀала)", + "Asia\/Kabul": "ОвхӀан (Кабул)", + "Asia\/Karachi": "Пакистан (Карачи)", + "Asia\/Katmandu": "Непал (Катманду)", + "Asia\/Khandyga": "Якутск (Хандыга)", + "Asia\/Krasnoyarsk": "Красноярск (Красноярск)", + "Asia\/Kuala_Lumpur": "Малайзи (Куала-Лумпур)", + "Asia\/Kuching": "Малайзи (Кучинг)", + "Asia\/Kuwait": "СаӀудийн Ӏаьрбийчоь (Кувейт)", + "Asia\/Macau": "Цийчоь (Макао)", + "Asia\/Magadan": "Магадан (Магадан)", + "Asia\/Makassar": "Юккъера Индонези (Макасар)", + "Asia\/Manila": "Филиппинаш (Манила)", + "Asia\/Muscat": "ГӀажарийн айма (Маскат)", + "Asia\/Nicosia": "Малхбален Европа (Никоси)", + "Asia\/Novokuznetsk": "Красноярск (Новокузнецк)", + "Asia\/Novosibirsk": "Новосибирск (Новосибирск)", + "Asia\/Omsk": "Омск (Омск)", + "Asia\/Oral": "Малхбузен Казахстан (Орал)", + "Asia\/Phnom_Penh": "Индокитай (Пномпень)", + "Asia\/Pontianak": "Малхбузен Индонези (Понтианак)", + "Asia\/Pyongyang": "Корей (Пхеньян)", + "Asia\/Qatar": "СаӀудийн Ӏаьрбийчоь (Катар)", + "Asia\/Qostanay": "Малхбален Казахстан (Qostanay)", + "Asia\/Qyzylorda": "Малхбузен Казахстан (Кызылорда)", + "Asia\/Rangoon": "Мьянма (Рангун)", + "Asia\/Riyadh": "СаӀудийн Ӏаьрбийчоь (Эр-Рияд)", + "Asia\/Saigon": "Индокитай (Хошимин)", + "Asia\/Sakhalin": "Сахалин (Сахалин гӀ-е)", + "Asia\/Samarkand": "Узбекистан (Самарканд)", + "Asia\/Seoul": "Корей (Сеул)", + "Asia\/Shanghai": "Цийчоь (Шанхай)", + "Asia\/Singapore": "Сингапур (Сингапур)", + "Asia\/Srednekolymsk": "Магадан (Среднеколымск)", + "Asia\/Taipei": "Тайвань (Тайбэй)", + "Asia\/Tashkent": "Узбекистан (Ташкент)", + "Asia\/Tbilisi": "Гуьржийчоь (Тбилиси)", + "Asia\/Tehran": "ГӀажарийчоь (ТехӀран)", + "Asia\/Thimphu": "Бутан (Тимпу)", + "Asia\/Tokyo": "Япон (Токио)", + "Asia\/Ulaanbaatar": "Улан-Батор (Улан-Батор)", + "Asia\/Ust-Nera": "Владивосток (Усть-Нера)", + "Asia\/Vientiane": "Индокитай (Вьентьян)", + "Asia\/Vladivostok": "Владивосток (Владивосток)", + "Asia\/Yakutsk": "Якутск (Якутск)", + "Asia\/Yekaterinburg": "Екатеринбург (Екатеринбург)", + "Asia\/Yerevan": "Эрмалойчоь (Ереван)", + "Atlantic\/Azores": "Азоран гӀайренаш (Азоран гӀайренаш)", + "Atlantic\/Bermuda": "Атлантикан хан (Бермудаш)", + "Atlantic\/Canary": "Малхбузен Европа (Канаран гӀайренаш)", + "Atlantic\/Cape_Verde": "Кабо-Верде (Кабо-Верде)", + "Atlantic\/Faeroe": "Малхбузен Европа (Фарерийн гӀайренаш)", + "Atlantic\/Madeira": "Малхбузен Европа (Мадейра, гӀ-е)", + "Atlantic\/Reykjavik": "Гринвичица юкъара хан (Рейкьявик)", + "Atlantic\/South_Georgia": "Къилба Георги (Къилба Джорджи)", + "Atlantic\/St_Helena": "Гринвичица юкъара хан (Езачу Еленин гӀайре)", + "Atlantic\/Stanley": "Фолклендан гӀайренаш (Стэнли)", + "Australia\/Adelaide": "Юккъера Австрали (Аделаида)", + "Australia\/Brisbane": "Малхбален Австрали (Брисбен)", + "Australia\/Broken_Hill": "Юккъера Австрали (Брокен-Хилл)", + "Australia\/Currie": "Малхбален Австрали (Керри)", + "Australia\/Darwin": "Юккъера Австрали (Дарвин)", + "Australia\/Eucla": "Юккъера Австрали, малхбузен хан (Юкла)", + "Australia\/Hobart": "Малхбален Австрали (Хобарт)", + "Australia\/Lindeman": "Малхбален Австрали (Линдеман)", + "Australia\/Lord_Howe": "Лорд-Хау (Лорд-Хау, гӀ-е)", + "Australia\/Melbourne": "Малхбален Австрали (Мельбурн)", + "Australia\/Perth": "Малхбузен Австрали (Перт)", + "Australia\/Sydney": "Малхбален Австрали (Сидней)", + "CST6CDT": "Юккъера Америка", + "EST5EDT": "Малхбален Америка", + "Etc\/GMT": "Гринвичица юкъара хан", + "Europe\/Amsterdam": "Юккъера Европа (Амстердам)", + "Europe\/Andorra": "Юккъера Европа (Андорра)", + "Europe\/Astrakhan": "Москва (Аштаркхне)", + "Europe\/Athens": "Малхбален Европа (Афина)", + "Europe\/Belgrade": "Юккъера Европа (Белград)", + "Europe\/Berlin": "Юккъера Европа (Берлин)", + "Europe\/Bratislava": "Юккъера Европа (Братислава)", + "Europe\/Brussels": "Юккъера Европа (Брюссель)", + "Europe\/Bucharest": "Малхбален Европа (Бухарест)", + "Europe\/Budapest": "Юккъера Европа (Будапешт)", + "Europe\/Busingen": "Юккъера Европа (Бюзинген-ам-Хохрайн)", + "Europe\/Chisinau": "Малхбален Европа (Кишинев)", + "Europe\/Copenhagen": "Юккъера Европа (Копенгаген)", + "Europe\/Dublin": "Гринвичица юкъара хан (Дублин)", + "Europe\/Gibraltar": "Юккъера Европа (Гибралтар)", + "Europe\/Guernsey": "Гринвичица юкъара хан (Гернси)", + "Europe\/Helsinki": "Малхбален Европа (Хельсинки)", + "Europe\/Isle_of_Man": "Гринвичица юкъара хан (Мэн, гӀ-е)", + "Europe\/Jersey": "Гринвичица юкъара хан (Джерси)", + "Europe\/Kaliningrad": "Малхбален Европа (Калининград)", + "Europe\/Kiev": "Малхбален Европа (Киев)", + "Europe\/Lisbon": "Малхбузен Европа (Лиссабон)", + "Europe\/Ljubljana": "Юккъера Европа (Любляна)", + "Europe\/London": "Гринвичица юкъара хан (Лондон)", + "Europe\/Luxembourg": "Юккъера Европа (Люксембург)", + "Europe\/Madrid": "Юккъера Европа (Мадрид)", + "Europe\/Malta": "Юккъера Европа (Мальта)", + "Europe\/Mariehamn": "Малхбален Европа (Мариехамн)", + "Europe\/Minsk": "Москва (Минск)", + "Europe\/Monaco": "Юккъера Европа (Монако)", + "Europe\/Moscow": "Москва (Москва)", + "Europe\/Oslo": "Юккъера Европа (Осло)", + "Europe\/Paris": "Юккъера Европа (Париж)", + "Europe\/Podgorica": "Юккъера Европа (Подгорица)", + "Europe\/Prague": "Юккъера Европа (Прага)", + "Europe\/Riga": "Малхбален Европа (Рига)", + "Europe\/Rome": "Юккъера Европа (Рим)", + "Europe\/San_Marino": "Юккъера Европа (Сан-Марино)", + "Europe\/Sarajevo": "Юккъера Европа (Сараево)", + "Europe\/Saratov": "Москва (Саратов)", + "Europe\/Simferopol": "Москва (Симферополь)", + "Europe\/Skopje": "Юккъера Европа (Скопье)", + "Europe\/Sofia": "Малхбален Европа (Софи)", + "Europe\/Stockholm": "Юккъера Европа (Стокгольм)", + "Europe\/Tallinn": "Малхбален Европа (Таллин)", + "Europe\/Tirane": "Юккъера Европа (Тирана)", + "Europe\/Ulyanovsk": "Москва (Ульяновск)", + "Europe\/Uzhgorod": "Малхбален Европа (Ужгород)", + "Europe\/Vaduz": "Юккъера Европа (Вадуц)", + "Europe\/Vatican": "Юккъера Европа (Ватикан)", + "Europe\/Vienna": "Юккъера Европа (Вена)", + "Europe\/Vilnius": "Малхбален Европа (Вильнюс)", + "Europe\/Volgograd": "Волгоград (Волгоград)", + "Europe\/Warsaw": "Юккъера Европа (Варшава)", + "Europe\/Zagreb": "Юккъера Европа (Загреб)", + "Europe\/Zaporozhye": "Малхбален Европа (Запорожье)", + "Europe\/Zurich": "Юккъера Европа (Цюрих)", + "Indian\/Antananarivo": "Малхбален Африка (Антананариву)", + "Indian\/Chagos": "Индин океан (Чагос)", + "Indian\/Christmas": "Ӏийса пайхамар винчу ден гӀайре (Ӏийса пайхамар винчу ден гӀайре)", + "Indian\/Cocos": "Кокосийн, гӀ-наш (Кокосийн, гӀ-наш)", + "Indian\/Comoro": "Малхбален Африка (Коморийн гӀайренаш)", + "Indian\/Kerguelen": "Французийн къилба а, Антарктидан а хан (Кергелен)", + "Indian\/Mahe": "Сейшелан гӀайренаш (Маэ)", + "Indian\/Maldives": "Мальдиваш (Мальдиваш)", + "Indian\/Mauritius": "Маврики (Маврики)", + "Indian\/Mayotte": "Малхбален Африка (Майорка)", + "Indian\/Reunion": "Реюньон (Реюньон)", + "MST7MDT": "Лаьмнийн хан (АЦШ)", + "PST8PDT": "Тийна океанан хан", + "Pacific\/Apia": "хан Апиа, Самоа (Апи)", + "Pacific\/Auckland": "Керла Зеланди (Окленд)", + "Pacific\/Bougainville": "Папуа – Керла Гвиней (Бугенвиль, гӀ-е)", + "Pacific\/Chatham": "Чатем (Чатем, гӀ-е)", + "Pacific\/Easter": "Мархин гӀайре (Мархин гӀайренаш)", + "Pacific\/Efate": "Вануату (Эфате)", + "Pacific\/Enderbury": "Феникс, гӀ-наш (Эндерберин, гӀ-е)", + "Pacific\/Fakaofo": "Токелау (Факаофо)", + "Pacific\/Fiji": "Фиджи (Фиджи)", + "Pacific\/Funafuti": "Тувалу (Фунафути)", + "Pacific\/Galapagos": "Галапагосан гӀайренаш (Галапагосан гӀайренаш)", + "Pacific\/Gambier": "Гамбье (Гамбьен, гӀ-наш)", + "Pacific\/Guadalcanal": "Соломонан, гӀ-наш (Гвадалканал)", + "Pacific\/Guam": "Чаморро (Гуам)", + "Pacific\/Honolulu": "Гавайн-алеутийн хан (Гонолулу)", + "Pacific\/Johnston": "Гавайн-алеутийн хан (Джонстон)", + "Pacific\/Kiritimati": "Лайн, гӀ-наш (Киритимати)", + "Pacific\/Kosrae": "Косраэ (Косрае)", + "Pacific\/Kwajalein": "Маршалан , гӀ-наш (Кваджалейн)", + "Pacific\/Majuro": "Маршалан , гӀ-наш (Маджуро)", + "Pacific\/Marquesas": "Маркизан, гӀ-наш (Маркизан, гӀ-наш)", + "Pacific\/Midway": "Самоа (Мидуэй, гӀ-наш)", + "Pacific\/Nauru": "Науру (Науру)", + "Pacific\/Niue": "Ниуэ (Ниуэ)", + "Pacific\/Norfolk": "Норфолк (Норфолк)", + "Pacific\/Noumea": "Керла Каледони (Нумеа)", + "Pacific\/Pago_Pago": "Самоа (Паго-Паго)", + "Pacific\/Palau": "Палау (Палау)", + "Pacific\/Pitcairn": "Питкэрн (Питкерн)", + "Pacific\/Ponape": "Понапе, гӀ-наш (Понапе, гӀ-наш)", + "Pacific\/Port_Moresby": "Папуа – Керла Гвиней (Порт-Морсби)", + "Pacific\/Rarotonga": "Кукан, гӀ-наш (Раротонга)", + "Pacific\/Saipan": "Чаморро (Сайпан)", + "Pacific\/Tahiti": "Таити, гӀ-наш (Таити, гӀ-наш)", + "Pacific\/Tarawa": "Гилбертан, гӀ-наш (Тарава)", + "Pacific\/Tongatapu": "Тонга (Тонгатапу)", + "Pacific\/Truk": "Чуук (Трук, гӀ-наш)", + "Pacific\/Wake": "Уэйк, гӀ-е (Уэйк, гӀ-е)", + "Pacific\/Wallis": "Уоллис а, Футуна а (Уоллис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/cs.json b/src/Symfony/Component/Intl/Resources/data/timezones/cs.json new file mode 100644 index 0000000000000..a8b763012e345 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/cs.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.44", + "Names": { + "Africa\/Abidjan": "Greenwichský střední čas (Abidžan)", + "Africa\/Accra": "Greenwichský střední čas (Accra)", + "Africa\/Addis_Ababa": "Východoafrický čas (Addis Abeba)", + "Africa\/Algiers": "Středoevropský čas (Alžír)", + "Africa\/Asmera": "Východoafrický čas (Asmara)", + "Africa\/Bamako": "Greenwichský střední čas (Bamako)", + "Africa\/Bangui": "Západoafrický čas (Bangui)", + "Africa\/Banjul": "Greenwichský střední čas (Banjul)", + "Africa\/Bissau": "Greenwichský střední čas (Bissau)", + "Africa\/Blantyre": "Středoafrický čas (Blantyre)", + "Africa\/Brazzaville": "Západoafrický čas (Brazzaville)", + "Africa\/Bujumbura": "Středoafrický čas (Bujumbura)", + "Africa\/Cairo": "Východoevropský čas (Káhira)", + "Africa\/Casablanca": "Západoevropský čas (Casablanca)", + "Africa\/Ceuta": "Středoevropský čas (Ceuta)", + "Africa\/Conakry": "Greenwichský střední čas (Conakry)", + "Africa\/Dakar": "Greenwichský střední čas (Dakar)", + "Africa\/Dar_es_Salaam": "Východoafrický čas (Dar es Salaam)", + "Africa\/Djibouti": "Východoafrický čas (Džibuti)", + "Africa\/Douala": "Západoafrický čas (Douala)", + "Africa\/El_Aaiun": "Západoevropský čas (El Aaiun)", + "Africa\/Freetown": "Greenwichský střední čas (Freetown)", + "Africa\/Gaborone": "Středoafrický čas (Gaborone)", + "Africa\/Harare": "Středoafrický čas (Harare)", + "Africa\/Johannesburg": "Jihoafrický čas (Johannesburg)", + "Africa\/Juba": "Východoafrický čas (Juba)", + "Africa\/Kampala": "Východoafrický čas (Kampala)", + "Africa\/Khartoum": "Středoafrický čas (Chartúm)", + "Africa\/Kigali": "Středoafrický čas (Kigali)", + "Africa\/Kinshasa": "Západoafrický čas (Kinshasa)", + "Africa\/Lagos": "Západoafrický čas (Lagos)", + "Africa\/Libreville": "Západoafrický čas (Libreville)", + "Africa\/Lome": "Greenwichský střední čas (Lomé)", + "Africa\/Luanda": "Západoafrický čas (Luanda)", + "Africa\/Lubumbashi": "Středoafrický čas (Lubumbashi)", + "Africa\/Lusaka": "Středoafrický čas (Lusaka)", + "Africa\/Malabo": "Západoafrický čas (Malabo)", + "Africa\/Maputo": "Středoafrický čas (Maputo)", + "Africa\/Maseru": "Jihoafrický čas (Maseru)", + "Africa\/Mbabane": "Jihoafrický čas (Mbabane)", + "Africa\/Mogadishu": "Východoafrický čas (Mogadišu)", + "Africa\/Monrovia": "Greenwichský střední čas (Monrovia)", + "Africa\/Nairobi": "Východoafrický čas (Nairobi)", + "Africa\/Ndjamena": "Západoafrický čas (Ndžamena)", + "Africa\/Niamey": "Západoafrický čas (Niamey)", + "Africa\/Nouakchott": "Greenwichský střední čas (Nuakšott)", + "Africa\/Ouagadougou": "Greenwichský střední čas (Ouagadougou)", + "Africa\/Porto-Novo": "Západoafrický čas (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwichský střední čas (Svatý Tomáš)", + "Africa\/Tripoli": "Východoevropský čas (Tripolis)", + "Africa\/Tunis": "Středoevropský čas (Tunis)", + "Africa\/Windhoek": "Středoafrický čas (Windhoek)", + "America\/Adak": "Havajsko-aleutský čas (Adak)", + "America\/Anchorage": "Aljašský čas (Anchorage)", + "America\/Anguilla": "Atlantický čas (Anguilla)", + "America\/Antigua": "Atlantický čas (Antigua)", + "America\/Araguaina": "Brasilijský čas (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentinský čas (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinský čas (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinský čas (Salta)", + "America\/Argentina\/San_Juan": "Argentinský čas (San Juan)", + "America\/Argentina\/San_Luis": "Západoargentinský čas (San Luis)", + "America\/Argentina\/Tucuman": "Argentinský čas (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentinský čas (Ushuaia)", + "America\/Aruba": "Atlantický čas (Aruba)", + "America\/Asuncion": "Paraguayský čas (Asunción)", + "America\/Bahia": "Brasilijský čas (Bahía)", + "America\/Bahia_Banderas": "Severoamerický centrální čas (Bahia Banderas)", + "America\/Barbados": "Atlantický čas (Barbados)", + "America\/Belem": "Brasilijský čas (Belém)", + "America\/Belize": "Severoamerický centrální čas (Belize)", + "America\/Blanc-Sablon": "Atlantický čas (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonský čas (Boa Vista)", + "America\/Bogota": "Kolumbijský čas (Bogotá)", + "America\/Boise": "Severoamerický horský čas (Boise)", + "America\/Buenos_Aires": "Argentinský čas (Buenos Aires)", + "America\/Cambridge_Bay": "Severoamerický horský čas (Cambridge Bay)", + "America\/Campo_Grande": "Amazonský čas (Campo Grande)", + "America\/Cancun": "Severoamerický východní čas (Cancún)", + "America\/Caracas": "Venezuelský čas (Caracas)", + "America\/Catamarca": "Argentinský čas (Catamarca)", + "America\/Cayenne": "Francouzskoguyanský čas (Cayenne)", + "America\/Cayman": "Severoamerický východní čas (Kajmanské ostrovy)", + "America\/Chicago": "Severoamerický centrální čas (Chicago)", + "America\/Chihuahua": "Mexický pacifický čas (Chihuahua)", + "America\/Coral_Harbour": "Severoamerický východní čas (Atikokan)", + "America\/Cordoba": "Argentinský čas (Córdoba)", + "America\/Costa_Rica": "Severoamerický centrální čas (Kostarika)", + "America\/Creston": "Severoamerický horský čas (Creston)", + "America\/Cuiaba": "Amazonský čas (Cuiaba)", + "America\/Curacao": "Atlantický čas (Curaçao)", + "America\/Danmarkshavn": "Greenwichský střední čas (Danmarkshavn)", + "America\/Dawson": "Severoamerický pacifický čas (Dawson)", + "America\/Dawson_Creek": "Severoamerický horský čas (Dawson Creek)", + "America\/Denver": "Severoamerický horský čas (Denver)", + "America\/Detroit": "Severoamerický východní čas (Detroit)", + "America\/Dominica": "Atlantický čas (Dominika)", + "America\/Edmonton": "Severoamerický horský čas (Edmonton)", + "America\/Eirunepe": "Acrejský čas (Eirunepe)", + "America\/El_Salvador": "Severoamerický centrální čas (Salvador)", + "America\/Fort_Nelson": "Severoamerický horský čas (Fort Nelson)", + "America\/Fortaleza": "Brasilijský čas (Fortaleza)", + "America\/Glace_Bay": "Atlantický čas (Glace Bay)", + "America\/Godthab": "Západogrónský čas (Nuuk)", + "America\/Goose_Bay": "Atlantický čas (Goose Bay)", + "America\/Grand_Turk": "Severoamerický východní čas (Grand Turk)", + "America\/Grenada": "Atlantický čas (Grenada)", + "America\/Guadeloupe": "Atlantický čas (Guadeloupe)", + "America\/Guatemala": "Severoamerický centrální čas (Guatemala)", + "America\/Guayaquil": "Ekvádorský čas (Guayaquil)", + "America\/Guyana": "Guyanský čas (Guyana)", + "America\/Halifax": "Atlantický čas (Halifax)", + "America\/Havana": "Kubánský čas (Havana)", + "America\/Hermosillo": "Mexický pacifický čas (Hermosillo)", + "America\/Indiana\/Knox": "Severoamerický centrální čas (Knox, Indiana)", + "America\/Indiana\/Marengo": "Severoamerický východní čas (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Severoamerický východní čas (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Severoamerický centrální čas (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Severoamerický východní čas (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Severoamerický východní čas (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Severoamerický východní čas (Winamac, Indiana)", + "America\/Indianapolis": "Severoamerický východní čas (Indianapolis)", + "America\/Inuvik": "Severoamerický horský čas (Inuvik)", + "America\/Iqaluit": "Severoamerický východní čas (Iqaluit)", + "America\/Jamaica": "Severoamerický východní čas (Jamajka)", + "America\/Jujuy": "Argentinský čas (Jujuy)", + "America\/Juneau": "Aljašský čas (Juneau)", + "America\/Kentucky\/Monticello": "Severoamerický východní čas (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantický čas (Kralendijk)", + "America\/La_Paz": "Bolivijský čas (La Paz)", + "America\/Lima": "Peruánský čas (Lima)", + "America\/Los_Angeles": "Severoamerický pacifický čas (Los Angeles)", + "America\/Louisville": "Severoamerický východní čas (Louisville)", + "America\/Lower_Princes": "Atlantický čas (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilijský čas (Maceio)", + "America\/Managua": "Severoamerický centrální čas (Managua)", + "America\/Manaus": "Amazonský čas (Manaus)", + "America\/Marigot": "Atlantický čas (Marigot)", + "America\/Martinique": "Atlantický čas (Martinik)", + "America\/Matamoros": "Severoamerický centrální čas (Matamoros)", + "America\/Mazatlan": "Mexický pacifický čas (Mazatlán)", + "America\/Mendoza": "Argentinský čas (Mendoza)", + "America\/Menominee": "Severoamerický centrální čas (Menominee)", + "America\/Merida": "Severoamerický centrální čas (Merida)", + "America\/Metlakatla": "Aljašský čas (Metlakatla)", + "America\/Mexico_City": "Severoamerický centrální čas (Ciudad de México)", + "America\/Miquelon": "Pierre-miquelonský čas (Miquelon)", + "America\/Moncton": "Atlantický čas (Moncton)", + "America\/Monterrey": "Severoamerický centrální čas (Monterrey)", + "America\/Montevideo": "Uruguayský čas (Montevideo)", + "America\/Montserrat": "Atlantický čas (Montserrat)", + "America\/Nassau": "Severoamerický východní čas (Nassau)", + "America\/New_York": "Severoamerický východní čas (New York)", + "America\/Nipigon": "Severoamerický východní čas (Nipigon)", + "America\/Nome": "Aljašský čas (Nome)", + "America\/Noronha": "Čas souostroví Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Severoamerický centrální čas (Beulah, Severní Dakota)", + "America\/North_Dakota\/Center": "Severoamerický centrální čas (Center, Severní Dakota)", + "America\/North_Dakota\/New_Salem": "Severoamerický centrální čas (New Salem, Severní Dakota)", + "America\/Ojinaga": "Severoamerický horský čas (Ojinaga)", + "America\/Panama": "Severoamerický východní čas (Panama)", + "America\/Pangnirtung": "Severoamerický východní čas (Pangnirtung)", + "America\/Paramaribo": "Surinamský čas (Paramaribo)", + "America\/Phoenix": "Severoamerický horský čas (Phoenix)", + "America\/Port-au-Prince": "Severoamerický východní čas (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantický čas (Port of Spain)", + "America\/Porto_Velho": "Amazonský čas (Porto Velho)", + "America\/Puerto_Rico": "Atlantický čas (Portoriko)", + "America\/Punta_Arenas": "Chilský čas (Punta Arenas)", + "America\/Rainy_River": "Severoamerický centrální čas (Rainy River)", + "America\/Rankin_Inlet": "Severoamerický centrální čas (Rankin Inlet)", + "America\/Recife": "Brasilijský čas (Recife)", + "America\/Regina": "Severoamerický centrální čas (Regina)", + "America\/Resolute": "Severoamerický centrální čas (Resolute)", + "America\/Rio_Branco": "Acrejský čas (Rio Branco)", + "America\/Santa_Isabel": "Severozápadní mexický čas (Santa Isabel)", + "America\/Santarem": "Brasilijský čas (Santarém)", + "America\/Santiago": "Chilský čas (Santiago)", + "America\/Santo_Domingo": "Atlantický čas (Santo Domingo)", + "America\/Sao_Paulo": "Brasilijský čas (São Paulo)", + "America\/Scoresbysund": "Východogrónský čas (Ittoqqortoormiit)", + "America\/Sitka": "Aljašský čas (Sitka)", + "America\/St_Barthelemy": "Atlantický čas (Svatý Bartoloměj)", + "America\/St_Johns": "Newfoundlandský čas (St. John’s)", + "America\/St_Kitts": "Atlantický čas (Svatý Kryštof)", + "America\/St_Lucia": "Atlantický čas (Svatá Lucie)", + "America\/St_Thomas": "Atlantický čas (Svatý Tomáš (Karibik))", + "America\/St_Vincent": "Atlantický čas (Svatý Vincenc)", + "America\/Swift_Current": "Severoamerický centrální čas (Swift Current)", + "America\/Tegucigalpa": "Severoamerický centrální čas (Tegucigalpa)", + "America\/Thule": "Atlantický čas (Thule)", + "America\/Thunder_Bay": "Severoamerický východní čas (Thunder Bay)", + "America\/Tijuana": "Severoamerický pacifický čas (Tijuana)", + "America\/Toronto": "Severoamerický východní čas (Toronto)", + "America\/Tortola": "Atlantický čas (Tortola)", + "America\/Vancouver": "Severoamerický pacifický čas (Vancouver)", + "America\/Whitehorse": "Severoamerický pacifický čas (Whitehorse)", + "America\/Winnipeg": "Severoamerický centrální čas (Winnipeg)", + "America\/Yakutat": "Aljašský čas (Yakutat)", + "America\/Yellowknife": "Severoamerický horský čas (Yellowknife)", + "Antarctica\/Casey": "Západoaustralský čas (Casey)", + "Antarctica\/Davis": "Čas Davisovy stanice (Davis)", + "Antarctica\/DumontDUrville": "Čas stanice Dumonta d’Urvilla (Dumont d’Urville)", + "Antarctica\/Macquarie": "Čas ostrova Macquarie (Macquarie)", + "Antarctica\/Mawson": "Čas Mawsonovy stanice (Mawson)", + "Antarctica\/McMurdo": "Novozélandský čas (McMurdo)", + "Antarctica\/Palmer": "Chilský čas (Palmer)", + "Antarctica\/Rothera": "Čas Rotherovy stanice (Rothera)", + "Antarctica\/Syowa": "Čas stanice Šówa (Syowa)", + "Antarctica\/Troll": "Greenwichský střední čas (Troll)", + "Antarctica\/Vostok": "Čas stanice Vostok (Vostok)", + "Arctic\/Longyearbyen": "Středoevropský čas (Longyearbyen)", + "Asia\/Aden": "Arabský čas (Aden)", + "Asia\/Almaty": "Východokazachstánský čas (Almaty)", + "Asia\/Amman": "Východoevropský čas (Ammán)", + "Asia\/Anadyr": "Anadyrský čas (Anadyr)", + "Asia\/Aqtau": "Západokazachstánský čas (Aktau)", + "Asia\/Aqtobe": "Západokazachstánský čas (Aktobe)", + "Asia\/Ashgabat": "Turkmenský čas (Ašchabad)", + "Asia\/Atyrau": "Západokazachstánský čas (Atyrau)", + "Asia\/Baghdad": "Arabský čas (Bagdád)", + "Asia\/Bahrain": "Arabský čas (Bahrajn)", + "Asia\/Baku": "Ázerbájdžánský čas (Baku)", + "Asia\/Bangkok": "Indočínský čas (Bangkok)", + "Asia\/Beirut": "Východoevropský čas (Bejrút)", + "Asia\/Bishkek": "Kyrgyzský čas (Biškek)", + "Asia\/Brunei": "Brunejský čas (Brunej)", + "Asia\/Calcutta": "Indický čas (Kalkata)", + "Asia\/Chita": "Jakutský čas (Čita)", + "Asia\/Choibalsan": "Čojbalsanský čas (Čojbalsan)", + "Asia\/Colombo": "Indický čas (Kolombo)", + "Asia\/Damascus": "Východoevropský čas (Damašek)", + "Asia\/Dhaka": "Bangladéšský čas (Dháka)", + "Asia\/Dili": "Východotimorský čas (Dili)", + "Asia\/Dubai": "Standardní čas Perského zálivu (Dubaj)", + "Asia\/Dushanbe": "Tádžický čas (Dušanbe)", + "Asia\/Famagusta": "Východoevropský čas (Famagusta)", + "Asia\/Gaza": "Východoevropský čas (Gaza)", + "Asia\/Hebron": "Východoevropský čas (Hebron)", + "Asia\/Hong_Kong": "Hongkongský čas (Hongkong)", + "Asia\/Hovd": "Hovdský čas (Hovd)", + "Asia\/Irkutsk": "Irkutský čas (Irkutsk)", + "Asia\/Jakarta": "Západoindonéský čas (Jakarta)", + "Asia\/Jayapura": "Východoindonéský čas (Jayapura)", + "Asia\/Jerusalem": "Izraelský čas (Jeruzalém)", + "Asia\/Kabul": "Afghánský čas (Kábul)", + "Asia\/Kamchatka": "Petropavlovsko-kamčatský čas (Kamčatka)", + "Asia\/Karachi": "Pákistánský čas (Karáčí)", + "Asia\/Katmandu": "Nepálský čas (Káthmándú)", + "Asia\/Khandyga": "Jakutský čas (Chandyga)", + "Asia\/Krasnoyarsk": "Krasnojarský čas (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malajský čas (Kuala Lumpur)", + "Asia\/Kuching": "Malajský čas (Kučing)", + "Asia\/Kuwait": "Arabský čas (Kuvajt)", + "Asia\/Macau": "Čínský čas (Macao)", + "Asia\/Magadan": "Magadanský čas (Magadan)", + "Asia\/Makassar": "Středoindonéský čas (Makassar)", + "Asia\/Manila": "Filipínský čas (Manila)", + "Asia\/Muscat": "Standardní čas Perského zálivu (Maskat)", + "Asia\/Nicosia": "Východoevropský čas (Nikósie)", + "Asia\/Novokuznetsk": "Krasnojarský čas (Novokuzněck)", + "Asia\/Novosibirsk": "Novosibirský čas (Novosibirsk)", + "Asia\/Omsk": "Omský čas (Omsk)", + "Asia\/Oral": "Západokazachstánský čas (Uralsk)", + "Asia\/Phnom_Penh": "Indočínský čas (Phnompenh)", + "Asia\/Pontianak": "Západoindonéský čas (Pontianak)", + "Asia\/Pyongyang": "Korejský čas (Pchjongjang)", + "Asia\/Qatar": "Arabský čas (Katar)", + "Asia\/Qostanay": "Východokazachstánský čas (Kostanaj)", + "Asia\/Qyzylorda": "Západokazachstánský čas (Kyzylorda)", + "Asia\/Rangoon": "Myanmarský čas (Rangún)", + "Asia\/Riyadh": "Arabský čas (Rijád)", + "Asia\/Saigon": "Indočínský čas (Ho Či Minovo město)", + "Asia\/Sakhalin": "Sachalinský čas (Sachalin)", + "Asia\/Samarkand": "Uzbecký čas (Samarkand)", + "Asia\/Seoul": "Korejský čas (Soul)", + "Asia\/Shanghai": "Čínský čas (Šanghaj)", + "Asia\/Singapore": "Singapurský čas (Singapur)", + "Asia\/Srednekolymsk": "Magadanský čas (Sredněkolymsk)", + "Asia\/Taipei": "Tchajpejský čas (Tchaj-pej)", + "Asia\/Tashkent": "Uzbecký čas (Taškent)", + "Asia\/Tbilisi": "Gruzínský čas (Tbilisi)", + "Asia\/Tehran": "Íránský čas (Teherán)", + "Asia\/Thimphu": "Bhútánský čas (Thimbú)", + "Asia\/Tokyo": "Japonský čas (Tokio)", + "Asia\/Ulaanbaatar": "Ulánbátarský čas (Ulánbátar)", + "Asia\/Ust-Nera": "Vladivostocký čas (Ust-Nera)", + "Asia\/Vientiane": "Indočínský čas (Vientiane)", + "Asia\/Vladivostok": "Vladivostocký čas (Vladivostok)", + "Asia\/Yakutsk": "Jakutský čas (Jakutsk)", + "Asia\/Yekaterinburg": "Jekatěrinburský čas (Jekatěrinburg)", + "Asia\/Yerevan": "Arménský čas (Jerevan)", + "Atlantic\/Azores": "Azorský čas (Azorské ostrovy)", + "Atlantic\/Bermuda": "Atlantický čas (Bermudy)", + "Atlantic\/Canary": "Západoevropský čas (Kanárské ostrovy)", + "Atlantic\/Cape_Verde": "Kapverdský čas (Kapverdy)", + "Atlantic\/Faeroe": "Západoevropský čas (Faerské ostrovy)", + "Atlantic\/Madeira": "Západoevropský čas (Madeira)", + "Atlantic\/Reykjavik": "Greenwichský střední čas (Reykjavík)", + "Atlantic\/South_Georgia": "Čas Jižní Georgie (Jižní Georgie)", + "Atlantic\/St_Helena": "Greenwichský střední čas (Svatá Helena)", + "Atlantic\/Stanley": "Falklandský čas (Stanley)", + "Australia\/Adelaide": "Středoaustralský čas (Adelaide)", + "Australia\/Brisbane": "Východoaustralský čas (Brisbane)", + "Australia\/Broken_Hill": "Středoaustralský čas (Broken Hill)", + "Australia\/Currie": "Východoaustralský čas (Currie)", + "Australia\/Darwin": "Středoaustralský čas (Darwin)", + "Australia\/Eucla": "Středozápadní australský čas (Eucla)", + "Australia\/Hobart": "Východoaustralský čas (Hobart)", + "Australia\/Lindeman": "Východoaustralský čas (Lindeman)", + "Australia\/Lord_Howe": "Čas ostrova lorda Howa (Lord Howe)", + "Australia\/Melbourne": "Východoaustralský čas (Melbourne)", + "Australia\/Perth": "Západoaustralský čas (Perth)", + "Australia\/Sydney": "Východoaustralský čas (Sydney)", + "CST6CDT": "Severoamerický centrální čas", + "EST5EDT": "Severoamerický východní čas", + "Etc\/GMT": "Greenwichský střední čas", + "Etc\/UTC": "Koordinovaný světový čas", + "Europe\/Amsterdam": "Středoevropský čas (Amsterdam)", + "Europe\/Andorra": "Středoevropský čas (Andorra)", + "Europe\/Astrakhan": "Moskevský čas (Astrachaň)", + "Europe\/Athens": "Východoevropský čas (Athény)", + "Europe\/Belgrade": "Středoevropský čas (Bělehrad)", + "Europe\/Berlin": "Středoevropský čas (Berlín)", + "Europe\/Bratislava": "Středoevropský čas (Bratislava)", + "Europe\/Brussels": "Středoevropský čas (Brusel)", + "Europe\/Bucharest": "Východoevropský čas (Bukurešť)", + "Europe\/Budapest": "Středoevropský čas (Budapešť)", + "Europe\/Busingen": "Středoevropský čas (Busingen)", + "Europe\/Chisinau": "Východoevropský čas (Kišiněv)", + "Europe\/Copenhagen": "Středoevropský čas (Kodaň)", + "Europe\/Dublin": "Greenwichský střední čas (Dublin)", + "Europe\/Gibraltar": "Středoevropský čas (Gibraltar)", + "Europe\/Guernsey": "Greenwichský střední čas (Guernsey)", + "Europe\/Helsinki": "Východoevropský čas (Helsinky)", + "Europe\/Isle_of_Man": "Greenwichský střední čas (Ostrov Man)", + "Europe\/Jersey": "Greenwichský střední čas (Jersey)", + "Europe\/Kaliningrad": "Východoevropský čas (Kaliningrad)", + "Europe\/Kiev": "Východoevropský čas (Kyjev)", + "Europe\/Lisbon": "Západoevropský čas (Lisabon)", + "Europe\/Ljubljana": "Středoevropský čas (Lublaň)", + "Europe\/London": "Greenwichský střední čas (Londýn)", + "Europe\/Luxembourg": "Středoevropský čas (Lucemburk)", + "Europe\/Madrid": "Středoevropský čas (Madrid)", + "Europe\/Malta": "Středoevropský čas (Malta)", + "Europe\/Mariehamn": "Východoevropský čas (Mariehamn)", + "Europe\/Minsk": "Moskevský čas (Minsk)", + "Europe\/Monaco": "Středoevropský čas (Monako)", + "Europe\/Moscow": "Moskevský čas (Moskva)", + "Europe\/Oslo": "Středoevropský čas (Oslo)", + "Europe\/Paris": "Středoevropský čas (Paříž)", + "Europe\/Podgorica": "Středoevropský čas (Podgorica)", + "Europe\/Prague": "Středoevropský čas (Praha)", + "Europe\/Riga": "Východoevropský čas (Riga)", + "Europe\/Rome": "Středoevropský čas (Řím)", + "Europe\/Samara": "Samarský čas (Samara)", + "Europe\/San_Marino": "Středoevropský čas (San Marino)", + "Europe\/Sarajevo": "Středoevropský čas (Sarajevo)", + "Europe\/Saratov": "Moskevský čas (Saratov)", + "Europe\/Simferopol": "Moskevský čas (Simferopol)", + "Europe\/Skopje": "Středoevropský čas (Skopje)", + "Europe\/Sofia": "Východoevropský čas (Sofie)", + "Europe\/Stockholm": "Středoevropský čas (Stockholm)", + "Europe\/Tallinn": "Východoevropský čas (Tallinn)", + "Europe\/Tirane": "Středoevropský čas (Tirana)", + "Europe\/Ulyanovsk": "Moskevský čas (Uljanovsk)", + "Europe\/Uzhgorod": "Východoevropský čas (Užhorod)", + "Europe\/Vaduz": "Středoevropský čas (Vaduz)", + "Europe\/Vatican": "Středoevropský čas (Vatikán)", + "Europe\/Vienna": "Středoevropský čas (Vídeň)", + "Europe\/Vilnius": "Východoevropský čas (Vilnius)", + "Europe\/Volgograd": "Volgogradský čas (Volgograd)", + "Europe\/Warsaw": "Středoevropský čas (Varšava)", + "Europe\/Zagreb": "Středoevropský čas (Záhřeb)", + "Europe\/Zaporozhye": "Východoevropský čas (Záporoží)", + "Europe\/Zurich": "Středoevropský čas (Curych)", + "Indian\/Antananarivo": "Východoafrický čas (Antananarivo)", + "Indian\/Chagos": "Indickooceánský čas (Chagos)", + "Indian\/Christmas": "Čas Vánočního ostrova (Vánoční ostrov)", + "Indian\/Cocos": "Čas Kokosových ostrovů (Kokosové ostrovy)", + "Indian\/Comoro": "Východoafrický čas (Komory)", + "Indian\/Kerguelen": "Čas Francouzských jižních a antarktických území (Kerguelenovy ostrovy)", + "Indian\/Mahe": "Seychelský čas (Mahé)", + "Indian\/Maldives": "Maledivský čas (Maledivy)", + "Indian\/Mauritius": "Mauricijský čas (Mauricius)", + "Indian\/Mayotte": "Východoafrický čas (Mayotte)", + "Indian\/Reunion": "Réunionský čas (Réunion)", + "MST7MDT": "Severoamerický horský čas", + "PST8PDT": "Severoamerický pacifický čas", + "Pacific\/Apia": "Apijský čas (Apia)", + "Pacific\/Auckland": "Novozélandský čas (Auckland)", + "Pacific\/Bougainville": "Čas Papuy-Nové Guiney (Bougainville)", + "Pacific\/Chatham": "Chathamský čas (Chathamské ostrovy)", + "Pacific\/Easter": "Čas Velikonočního ostrova (Velikonoční ostrov)", + "Pacific\/Efate": "Vanuatský čas (Éfaté)", + "Pacific\/Enderbury": "Čas Fénixových ostrovů (Enderbury)", + "Pacific\/Fakaofo": "Tokelauský čas (Fakaofo)", + "Pacific\/Fiji": "Fidžijský čas (Fidži)", + "Pacific\/Funafuti": "Tuvalský čas (Funafuti)", + "Pacific\/Galapagos": "Galapážský čas (Galapágy)", + "Pacific\/Gambier": "Gambierský čas (Gambierovy ostrovy)", + "Pacific\/Guadalcanal": "Čas Šalamounových ostrovů (Guadalcanal)", + "Pacific\/Guam": "Chamorrský čas (Guam)", + "Pacific\/Honolulu": "Havajsko-aleutský čas (Honolulu)", + "Pacific\/Johnston": "Havajsko-aleutský čas (Johnston)", + "Pacific\/Kiritimati": "Čas Rovníkových ostrovů (Kiritimati)", + "Pacific\/Kosrae": "Kosrajský čas (Kosrae)", + "Pacific\/Kwajalein": "Čas Marshallových ostrovů (Kwajalein)", + "Pacific\/Majuro": "Čas Marshallových ostrovů (Majuro)", + "Pacific\/Marquesas": "Markézský čas (Markézy)", + "Pacific\/Midway": "Samojský čas (Midway)", + "Pacific\/Nauru": "Naurský čas (Nauru)", + "Pacific\/Niue": "Niuejský čas (Niue)", + "Pacific\/Norfolk": "Norfolský čas (Norfolk)", + "Pacific\/Noumea": "Novokaledonský čas (Nouméa)", + "Pacific\/Pago_Pago": "Samojský čas (Pago Pago)", + "Pacific\/Palau": "Palauský čas (Palau)", + "Pacific\/Pitcairn": "Čas Pitcairnova ostrova (Pitcairnovy ostrovy)", + "Pacific\/Ponape": "Ponapský čas (Pohnpei)", + "Pacific\/Port_Moresby": "Čas Papuy-Nové Guiney (Port Moresby)", + "Pacific\/Rarotonga": "Čas Cookových ostrovů (Rarotonga)", + "Pacific\/Saipan": "Chamorrský čas (Saipan)", + "Pacific\/Tahiti": "Tahitský čas (Tahiti)", + "Pacific\/Tarawa": "Čas Gilbertových ostrovů (Tarawa)", + "Pacific\/Tongatapu": "Tonžský čas (Tongatapu)", + "Pacific\/Truk": "Chuukský čas (Chuukské ostrovy)", + "Pacific\/Wake": "Čas ostrova Wake (Wake)", + "Pacific\/Wallis": "Čas ostrovů Wallis a Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/cy.json b/src/Symfony/Component/Intl/Resources/data/timezones/cy.json new file mode 100644 index 0000000000000..5271476a859b4 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/cy.json @@ -0,0 +1,429 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Amser Safonol Greenwich (Abidjan)", + "Africa\/Accra": "Amser Safonol Greenwich (Accra)", + "Africa\/Addis_Ababa": "Amser Dwyrain Affrica (Addis Ababa)", + "Africa\/Algiers": "Amser Canolbarth Ewrop (Alger)", + "Africa\/Asmera": "Amser Dwyrain Affrica (Asmera)", + "Africa\/Bamako": "Amser Safonol Greenwich (Bamako)", + "Africa\/Bangui": "Amser Gorllewin Affrica (Bangui)", + "Africa\/Banjul": "Amser Safonol Greenwich (Banjul)", + "Africa\/Bissau": "Amser Safonol Greenwich (Bissau)", + "Africa\/Blantyre": "Amser Canolbarth Affrica (Blantyre)", + "Africa\/Brazzaville": "Amser Gorllewin Affrica (Brazzaville)", + "Africa\/Bujumbura": "Amser Canolbarth Affrica (Bujumbura)", + "Africa\/Cairo": "Amser Dwyrain Ewrop (Cairo)", + "Africa\/Casablanca": "Amser Gorllewin Ewrop (Casablanca)", + "Africa\/Ceuta": "Amser Canolbarth Ewrop (Ceuta)", + "Africa\/Conakry": "Amser Safonol Greenwich (Conakry)", + "Africa\/Dakar": "Amser Safonol Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Amser Dwyrain Affrica (Dar es Salaam)", + "Africa\/Djibouti": "Amser Dwyrain Affrica (Djibouti)", + "Africa\/Douala": "Amser Gorllewin Affrica (Douala)", + "Africa\/El_Aaiun": "Amser Gorllewin Ewrop (El Aaiun)", + "Africa\/Freetown": "Amser Safonol Greenwich (Freetown)", + "Africa\/Gaborone": "Amser Canolbarth Affrica (Gaborone)", + "Africa\/Harare": "Amser Canolbarth Affrica (Harare)", + "Africa\/Johannesburg": "Amser Safonol De Affrica (Johannesburg)", + "Africa\/Juba": "Amser Dwyrain Affrica (Juba)", + "Africa\/Kampala": "Amser Dwyrain Affrica (Kampala)", + "Africa\/Khartoum": "Amser Canolbarth Affrica (Khartoum)", + "Africa\/Kigali": "Amser Canolbarth Affrica (Kigali)", + "Africa\/Kinshasa": "Amser Gorllewin Affrica (Kinshasa)", + "Africa\/Lagos": "Amser Gorllewin Affrica (Lagos)", + "Africa\/Libreville": "Amser Gorllewin Affrica (Libreville)", + "Africa\/Lome": "Amser Safonol Greenwich (Lome)", + "Africa\/Luanda": "Amser Gorllewin Affrica (Luanda)", + "Africa\/Lubumbashi": "Amser Canolbarth Affrica (Lubumbashi)", + "Africa\/Lusaka": "Amser Canolbarth Affrica (Lusaka)", + "Africa\/Malabo": "Amser Gorllewin Affrica (Malabo)", + "Africa\/Maputo": "Amser Canolbarth Affrica (Maputo)", + "Africa\/Maseru": "Amser Safonol De Affrica (Maseru)", + "Africa\/Mbabane": "Amser Safonol De Affrica (Mbabane)", + "Africa\/Mogadishu": "Amser Dwyrain Affrica (Mogadishu)", + "Africa\/Monrovia": "Amser Safonol Greenwich (Monrovia)", + "Africa\/Nairobi": "Amser Dwyrain Affrica (Nairobi)", + "Africa\/Ndjamena": "Amser Gorllewin Affrica (Ndjamena)", + "Africa\/Niamey": "Amser Gorllewin Affrica (Niamey)", + "Africa\/Nouakchott": "Amser Safonol Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Amser Safonol Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Amser Gorllewin Affrica (Porto-Novo)", + "Africa\/Sao_Tome": "Amser Safonol Greenwich (São Tomé)", + "Africa\/Tripoli": "Amser Dwyrain Ewrop (Tripoli)", + "Africa\/Tunis": "Amser Canolbarth Ewrop (Tunis)", + "Africa\/Windhoek": "Amser Canolbarth Affrica (Windhoek)", + "America\/Adak": "Amser Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Amser Alaska (Anchorage)", + "America\/Anguilla": "Amser Cefnfor yr Iwerydd (Anguilla)", + "America\/Antigua": "Amser Cefnfor yr Iwerydd (Antigua)", + "America\/Araguaina": "Amser Brasília (Araguaina)", + "America\/Argentina\/La_Rioja": "Amser yr Ariannin (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Amser yr Ariannin (Rio Gallegos)", + "America\/Argentina\/Salta": "Amser yr Ariannin (Salta)", + "America\/Argentina\/San_Juan": "Amser yr Ariannin (San Juan)", + "America\/Argentina\/San_Luis": "Amser Gorllewin Ariannin (San Luis)", + "America\/Argentina\/Tucuman": "Amser yr Ariannin (Tucumán)", + "America\/Argentina\/Ushuaia": "Amser yr Ariannin (Ushuaia)", + "America\/Aruba": "Amser Cefnfor yr Iwerydd (Aruba)", + "America\/Asuncion": "Amser Paraguay (Asunción)", + "America\/Bahia": "Amser Brasília (Bahia)", + "America\/Bahia_Banderas": "Amser Canolbarth Gogledd America (Bae Banderas)", + "America\/Barbados": "Amser Cefnfor yr Iwerydd (Barbados)", + "America\/Belem": "Amser Brasília (Belém)", + "America\/Belize": "Amser Canolbarth Gogledd America (Belize)", + "America\/Blanc-Sablon": "Amser Cefnfor yr Iwerydd (Blanc-Sablon)", + "America\/Boa_Vista": "Amser Amazonas (Boa Vista)", + "America\/Bogota": "Amser Colombia (Bogotá)", + "America\/Boise": "Amser Mynyddoedd Gogledd America (Boise)", + "America\/Buenos_Aires": "Amser yr Ariannin (Buenos Aires)", + "America\/Cambridge_Bay": "Amser Mynyddoedd Gogledd America (Bae Cambridge)", + "America\/Campo_Grande": "Amser Amazonas (Campo Grande)", + "America\/Cancun": "Amser Dwyrain Gogledd America (Cancún)", + "America\/Caracas": "Amser Venezuela (Caracas)", + "America\/Catamarca": "Amser yr Ariannin (Catamarca)", + "America\/Cayenne": "Amser Guyane Ffrengig (Cayenne)", + "America\/Cayman": "Amser Dwyrain Gogledd America (Cayman)", + "America\/Chicago": "Amser Canolbarth Gogledd America (Chicago)", + "America\/Chihuahua": "Amser Pasiffig Mecsico (Chihuahua)", + "America\/Coral_Harbour": "Amser Dwyrain Gogledd America (Atikokan)", + "America\/Cordoba": "Amser yr Ariannin (Cordoba)", + "America\/Costa_Rica": "Amser Canolbarth Gogledd America (Costa Rica)", + "America\/Creston": "Amser Mynyddoedd Gogledd America (Creston)", + "America\/Cuiaba": "Amser Amazonas (Cuiabá)", + "America\/Curacao": "Amser Cefnfor yr Iwerydd (Curaçao)", + "America\/Danmarkshavn": "Amser Safonol Greenwich (Danmarkshavn)", + "America\/Dawson": "Amser Cefnfor Tawel Gogledd America (Dawson)", + "America\/Dawson_Creek": "Amser Mynyddoedd Gogledd America (Dawson Creek)", + "America\/Denver": "Amser Mynyddoedd Gogledd America (Denver)", + "America\/Detroit": "Amser Dwyrain Gogledd America (Detroit)", + "America\/Dominica": "Amser Cefnfor yr Iwerydd (Dominica)", + "America\/Edmonton": "Amser Mynyddoedd Gogledd America (Edmonton)", + "America\/El_Salvador": "Amser Canolbarth Gogledd America (El Salvador)", + "America\/Fort_Nelson": "Amser Mynyddoedd Gogledd America (Fort Nelson)", + "America\/Fortaleza": "Amser Brasília (Fortaleza)", + "America\/Glace_Bay": "Amser Cefnfor yr Iwerydd (Glace Bay)", + "America\/Godthab": "Amser Gorllewin yr Ynys Las (Nuuk)", + "America\/Goose_Bay": "Amser Cefnfor yr Iwerydd (Goose Bay)", + "America\/Grand_Turk": "Amser Dwyrain Gogledd America (Grand Turk)", + "America\/Grenada": "Amser Cefnfor yr Iwerydd (Grenada)", + "America\/Guadeloupe": "Amser Cefnfor yr Iwerydd (Guadeloupe)", + "America\/Guatemala": "Amser Canolbarth Gogledd America (Guatemala)", + "America\/Guayaquil": "Amser Ecuador (Guayaquil)", + "America\/Guyana": "Amser Guyana (Guyana)", + "America\/Halifax": "Amser Cefnfor yr Iwerydd (Halifax)", + "America\/Havana": "Amser Cuba (Havana)", + "America\/Hermosillo": "Amser Pasiffig Mecsico (Hermosillo)", + "America\/Indiana\/Knox": "Amser Canolbarth Gogledd America (Knox, Indiana)", + "America\/Indiana\/Marengo": "Amser Dwyrain Gogledd America (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Amser Dwyrain Gogledd America (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Amser Canolbarth Gogledd America (Dinas Tell, Indiana)", + "America\/Indiana\/Vevay": "Amser Dwyrain Gogledd America (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Amser Dwyrain Gogledd America (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Amser Dwyrain Gogledd America (Winamac, Indiana)", + "America\/Indianapolis": "Amser Dwyrain Gogledd America (Indianapolis)", + "America\/Inuvik": "Amser Mynyddoedd Gogledd America (Inuvik)", + "America\/Iqaluit": "Amser Dwyrain Gogledd America (Iqaluit)", + "America\/Jamaica": "Amser Dwyrain Gogledd America (Jamaica)", + "America\/Jujuy": "Amser yr Ariannin (Jujuy)", + "America\/Juneau": "Amser Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Amser Dwyrain Gogledd America (Monticello, Kentucky)", + "America\/Kralendijk": "Amser Cefnfor yr Iwerydd (Kralendijk)", + "America\/La_Paz": "Amser Bolivia (La Paz)", + "America\/Lima": "Amser Periw (Lima)", + "America\/Los_Angeles": "Amser Cefnfor Tawel Gogledd America (Los Angeles)", + "America\/Louisville": "Amser Dwyrain Gogledd America (Louisville)", + "America\/Lower_Princes": "Amser Cefnfor yr Iwerydd (Lower Prince’s Quarter)", + "America\/Maceio": "Amser Brasília (Maceio)", + "America\/Managua": "Amser Canolbarth Gogledd America (Managua)", + "America\/Manaus": "Amser Amazonas (Manaus)", + "America\/Marigot": "Amser Cefnfor yr Iwerydd (Marigot)", + "America\/Martinique": "Amser Cefnfor yr Iwerydd (Martinique)", + "America\/Matamoros": "Amser Canolbarth Gogledd America (Matamoros)", + "America\/Mazatlan": "Amser Pasiffig Mecsico (Mazatlan)", + "America\/Mendoza": "Amser yr Ariannin (Mendoza)", + "America\/Menominee": "Amser Canolbarth Gogledd America (Menominee)", + "America\/Merida": "Amser Canolbarth Gogledd America (Merida)", + "America\/Metlakatla": "Amser Alaska (Metlakatla)", + "America\/Mexico_City": "Amser Canolbarth Gogledd America (Dinas Mecsico)", + "America\/Miquelon": "Amser Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "Amser Cefnfor yr Iwerydd (Moncton)", + "America\/Monterrey": "Amser Canolbarth Gogledd America (Monterrey)", + "America\/Montevideo": "Amser Uruguay (Montevideo)", + "America\/Montserrat": "Amser Cefnfor yr Iwerydd (Montserrat)", + "America\/Nassau": "Amser Dwyrain Gogledd America (Nassau)", + "America\/New_York": "Amser Dwyrain Gogledd America (Efrog Newydd)", + "America\/Nipigon": "Amser Dwyrain Gogledd America (Nipigon)", + "America\/Nome": "Amser Alaska (Nome)", + "America\/Noronha": "Amser Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Amser Canolbarth Gogledd America (Beulah, Gogledd Dakota)", + "America\/North_Dakota\/Center": "Amser Canolbarth Gogledd America (Center, Gogledd Dakota)", + "America\/North_Dakota\/New_Salem": "Amser Canolbarth Gogledd America (New Salem, Gogledd Dakota)", + "America\/Ojinaga": "Amser Mynyddoedd Gogledd America (Ojinaga)", + "America\/Panama": "Amser Dwyrain Gogledd America (Panama)", + "America\/Pangnirtung": "Amser Dwyrain Gogledd America (Pangnirtung)", + "America\/Paramaribo": "Amser Suriname (Paramaribo)", + "America\/Phoenix": "Amser Mynyddoedd Gogledd America (Phoenix)", + "America\/Port-au-Prince": "Amser Dwyrain Gogledd America (Port-au-Prince)", + "America\/Port_of_Spain": "Amser Cefnfor yr Iwerydd (Port of Spain)", + "America\/Porto_Velho": "Amser Amazonas (Porto Velho)", + "America\/Puerto_Rico": "Amser Cefnfor yr Iwerydd (Puerto Rico)", + "America\/Punta_Arenas": "Amser Chile (Punta Arenas)", + "America\/Rainy_River": "Amser Canolbarth Gogledd America (Rainy River)", + "America\/Rankin_Inlet": "Amser Canolbarth Gogledd America (Rankin Inlet)", + "America\/Recife": "Amser Brasília (Recife)", + "America\/Regina": "Amser Canolbarth Gogledd America (Regina)", + "America\/Resolute": "Amser Canolbarth Gogledd America (Resolute)", + "America\/Santa_Isabel": "Amser Gogledd Orllewin Mecsico (Santa Isabel)", + "America\/Santarem": "Amser Brasília (Santarem)", + "America\/Santiago": "Amser Chile (Santiago)", + "America\/Santo_Domingo": "Amser Cefnfor yr Iwerydd (Santo Domingo)", + "America\/Sao_Paulo": "Amser Brasília (Sao Paulo)", + "America\/Scoresbysund": "Amser Dwyrain yr Ynys Las (Ittoqqortoormiit)", + "America\/Sitka": "Amser Alaska (Sitka)", + "America\/St_Barthelemy": "Amser Cefnfor yr Iwerydd (St. Barthelemy)", + "America\/St_Johns": "Amser Newfoundland (St. John’s)", + "America\/St_Kitts": "Amser Cefnfor yr Iwerydd (St. Kitts)", + "America\/St_Lucia": "Amser Cefnfor yr Iwerydd (St. Lucia)", + "America\/St_Thomas": "Amser Cefnfor yr Iwerydd (St. Thomas)", + "America\/St_Vincent": "Amser Cefnfor yr Iwerydd (St. Vincent)", + "America\/Swift_Current": "Amser Canolbarth Gogledd America (Swift Current)", + "America\/Tegucigalpa": "Amser Canolbarth Gogledd America (Tegucigalpa)", + "America\/Thule": "Amser Cefnfor yr Iwerydd (Thule)", + "America\/Thunder_Bay": "Amser Dwyrain Gogledd America (Thunder Bay)", + "America\/Tijuana": "Amser Cefnfor Tawel Gogledd America (Tijuana)", + "America\/Toronto": "Amser Dwyrain Gogledd America (Toronto)", + "America\/Tortola": "Amser Cefnfor yr Iwerydd (Tortola)", + "America\/Vancouver": "Amser Cefnfor Tawel Gogledd America (Vancouver)", + "America\/Whitehorse": "Amser Cefnfor Tawel Gogledd America (Whitehorse)", + "America\/Winnipeg": "Amser Canolbarth Gogledd America (Winnipeg)", + "America\/Yakutat": "Amser Alaska (Yakutat)", + "America\/Yellowknife": "Amser Mynyddoedd Gogledd America (Yellowknife)", + "Antarctica\/Casey": "Amser Gorllewin Awstralia (Casey)", + "Antarctica\/Davis": "Amser Davis (Davis)", + "Antarctica\/DumontDUrville": "Amser Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Amser Ynys Macquarie (Macquarie)", + "Antarctica\/Mawson": "Amser Mawson (Mawson)", + "Antarctica\/McMurdo": "Amser Seland Newydd (McMurdo)", + "Antarctica\/Palmer": "Amser Chile (Palmer)", + "Antarctica\/Rothera": "Amser Rothera (Rothera)", + "Antarctica\/Syowa": "Amser Syowa (Syowa)", + "Antarctica\/Troll": "Amser Safonol Greenwich (Troll)", + "Antarctica\/Vostok": "Amser Vostok (Vostok)", + "Arctic\/Longyearbyen": "Amser Canolbarth Ewrop (Longyearbyen)", + "Asia\/Aden": "Amser Arabaidd (Aden)", + "Asia\/Almaty": "Amser Dwyrain Kazakhstan (Almaty)", + "Asia\/Amman": "Amser Dwyrain Ewrop (Amman)", + "Asia\/Aqtau": "Amser Gorllewin Casachstan (Aqtau)", + "Asia\/Aqtobe": "Amser Gorllewin Casachstan (Aqtobe)", + "Asia\/Ashgabat": "Amser Tyrcmenistan (Ashgabat)", + "Asia\/Atyrau": "Amser Gorllewin Casachstan (Atyrau)", + "Asia\/Baghdad": "Amser Arabaidd (Baghdad)", + "Asia\/Bahrain": "Amser Arabaidd (Bahrain)", + "Asia\/Baku": "Amser Aserbaijan (Baku)", + "Asia\/Bangkok": "Amser Indo-Tsieina (Bangkok)", + "Asia\/Beirut": "Amser Dwyrain Ewrop (Beirut)", + "Asia\/Bishkek": "Amser Kyrgyzstan (Bishkek)", + "Asia\/Brunei": "Amser Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Amser India (Kolkata)", + "Asia\/Chita": "Amser Yakutsk (Chita)", + "Asia\/Choibalsan": "Amser Choibalsan (Choibalsan)", + "Asia\/Colombo": "Amser India (Colombo)", + "Asia\/Damascus": "Amser Dwyrain Ewrop (Damascus)", + "Asia\/Dhaka": "Amser Bangladesh (Dhaka)", + "Asia\/Dili": "Amser Dwyrain Timor (Dili)", + "Asia\/Dubai": "Amser Safonol y Gwlff (Dubai)", + "Asia\/Dushanbe": "Amser Tajicistan (Dushanbe)", + "Asia\/Famagusta": "Amser Dwyrain Ewrop (Famagusta)", + "Asia\/Gaza": "Amser Dwyrain Ewrop (Gasa)", + "Asia\/Hebron": "Amser Dwyrain Ewrop (Hebron)", + "Asia\/Hong_Kong": "Amser Hong Kong (Hong Kong)", + "Asia\/Hovd": "Amser Hovd (Hovd)", + "Asia\/Irkutsk": "Amser Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Amser Gorllewin Indonesia (Jakarta)", + "Asia\/Jayapura": "Amser Dwyrain Indonesia (Jayapura)", + "Asia\/Jerusalem": "Amser Israel (Jerwsalem)", + "Asia\/Kabul": "Amser Afghanistan (Kabul)", + "Asia\/Karachi": "Amser Pakistan (Karachi)", + "Asia\/Katmandu": "Amser Nepal (Kathmandu)", + "Asia\/Khandyga": "Amser Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Amser Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Amser Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Amser Malaysia (Kuching)", + "Asia\/Kuwait": "Amser Arabaidd (Kuwait)", + "Asia\/Macau": "Amser Tsieina (Macau)", + "Asia\/Magadan": "Amser Magadan (Magadan)", + "Asia\/Makassar": "Amser Canolbarth Indonesia (Makassar)", + "Asia\/Manila": "Amser Pilipinas (Manila)", + "Asia\/Muscat": "Amser Safonol y Gwlff (Muscat)", + "Asia\/Nicosia": "Amser Dwyrain Ewrop (Nicosia)", + "Asia\/Novokuznetsk": "Amser Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Amser Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Amser Omsk (Omsk)", + "Asia\/Oral": "Amser Gorllewin Casachstan (Oral)", + "Asia\/Phnom_Penh": "Amser Indo-Tsieina (Phnom Penh)", + "Asia\/Pontianak": "Amser Gorllewin Indonesia (Pontianak)", + "Asia\/Pyongyang": "Amser Corea (Pyongyang)", + "Asia\/Qatar": "Amser Arabaidd (Qatar)", + "Asia\/Qostanay": "Amser Dwyrain Kazakhstan (Qostanay)", + "Asia\/Qyzylorda": "Amser Gorllewin Casachstan (Qyzylorda)", + "Asia\/Rangoon": "Amser Myanmar (Yangon)", + "Asia\/Riyadh": "Amser Arabaidd (Riyadh)", + "Asia\/Saigon": "Amser Indo-Tsieina (Dinas Hô Chi Minh)", + "Asia\/Sakhalin": "Amser Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Amser Wsbecistan (Samarkand)", + "Asia\/Seoul": "Amser Corea (Seoul)", + "Asia\/Shanghai": "Amser Tsieina (Shanghai)", + "Asia\/Singapore": "Amser Singapore (Singapore)", + "Asia\/Srednekolymsk": "Amser Magadan (Srednekolymsk)", + "Asia\/Taipei": "Amser Taipei (Taipei)", + "Asia\/Tashkent": "Amser Wsbecistan (Tashkent)", + "Asia\/Tbilisi": "Amser Georgia (Tiflis)", + "Asia\/Tehran": "Amser Iran (Tehran)", + "Asia\/Thimphu": "Amser Bhutan (Thimphu)", + "Asia\/Tokyo": "Amser Siapan (Tokyo)", + "Asia\/Ulaanbaatar": "Amser Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "Amser Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Amser Indo-Tsieina (Vientiane)", + "Asia\/Vladivostok": "Amser Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Amser Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Amser Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Amser Armenia (Yerevan)", + "Atlantic\/Azores": "Amser yr Azores (Azores)", + "Atlantic\/Bermuda": "Amser Cefnfor yr Iwerydd (Bermuda)", + "Atlantic\/Canary": "Amser Gorllewin Ewrop (Yr Ynysoedd Dedwydd)", + "Atlantic\/Cape_Verde": "Amser Cabo Verde (Cabo Verde)", + "Atlantic\/Faeroe": "Amser Gorllewin Ewrop (Ffaro)", + "Atlantic\/Madeira": "Amser Gorllewin Ewrop (Madeira)", + "Atlantic\/Reykjavik": "Amser Safonol Greenwich (Reykjavík)", + "Atlantic\/South_Georgia": "Amser De Georgia (De Georgia)", + "Atlantic\/St_Helena": "Amser Safonol Greenwich (St. Helena)", + "Atlantic\/Stanley": "Amser Ynysoedd Falklands\/Malvinas (Stanley)", + "Australia\/Adelaide": "Amser Canolbarth Awstralia (Adelaide)", + "Australia\/Brisbane": "Amser Dwyrain Awstralia (Brisbane)", + "Australia\/Broken_Hill": "Amser Canolbarth Awstralia (Broken Hill)", + "Australia\/Currie": "Amser Dwyrain Awstralia (Currie)", + "Australia\/Darwin": "Amser Canolbarth Awstralia (Darwin)", + "Australia\/Eucla": "Amser Canolbarth Gorllewin Awstralia (Eucla)", + "Australia\/Hobart": "Amser Dwyrain Awstralia (Hobart)", + "Australia\/Lindeman": "Amser Dwyrain Awstralia (Lindeman)", + "Australia\/Lord_Howe": "Amser yr Arglwydd Howe (Lord Howe)", + "Australia\/Melbourne": "Amser Dwyrain Awstralia (Melbourne)", + "Australia\/Perth": "Amser Gorllewin Awstralia (Perth)", + "Australia\/Sydney": "Amser Dwyrain Awstralia (Sydney)", + "CST6CDT": "Amser Canolbarth Gogledd America", + "EST5EDT": "Amser Dwyrain Gogledd America", + "Etc\/GMT": "Amser Safonol Greenwich", + "Etc\/UTC": "Amser Cyffredniol Cydlynol", + "Europe\/Amsterdam": "Amser Canolbarth Ewrop (Amsterdam)", + "Europe\/Andorra": "Amser Canolbarth Ewrop (Andorra)", + "Europe\/Astrakhan": "Amser Moscfa (Astrakhan)", + "Europe\/Athens": "Amser Dwyrain Ewrop (Athens)", + "Europe\/Belgrade": "Amser Canolbarth Ewrop (Belgrade)", + "Europe\/Berlin": "Amser Canolbarth Ewrop (Berlin)", + "Europe\/Bratislava": "Amser Canolbarth Ewrop (Bratislava)", + "Europe\/Brussels": "Amser Canolbarth Ewrop (Brwsel)", + "Europe\/Bucharest": "Amser Dwyrain Ewrop (Bwcarést)", + "Europe\/Budapest": "Amser Canolbarth Ewrop (Budapest)", + "Europe\/Busingen": "Amser Canolbarth Ewrop (Busingen)", + "Europe\/Chisinau": "Amser Dwyrain Ewrop (Chisinau)", + "Europe\/Copenhagen": "Amser Canolbarth Ewrop (Copenhagen)", + "Europe\/Dublin": "Amser Safonol Greenwich (Dulyn)", + "Europe\/Gibraltar": "Amser Canolbarth Ewrop (Gibraltar)", + "Europe\/Guernsey": "Amser Safonol Greenwich (Ynys y Garn)", + "Europe\/Helsinki": "Amser Dwyrain Ewrop (Helsinki)", + "Europe\/Isle_of_Man": "Amser Safonol Greenwich (Ynys Manaw)", + "Europe\/Jersey": "Amser Safonol Greenwich (Jersey)", + "Europe\/Kaliningrad": "Amser Dwyrain Ewrop (Kaliningrad)", + "Europe\/Kiev": "Amser Dwyrain Ewrop (Kiev)", + "Europe\/Lisbon": "Amser Gorllewin Ewrop (Lisbon)", + "Europe\/Ljubljana": "Amser Canolbarth Ewrop (Ljubljana)", + "Europe\/London": "Amser Safonol Greenwich (Llundain)", + "Europe\/Luxembourg": "Amser Canolbarth Ewrop (Lwcsembwrg)", + "Europe\/Madrid": "Amser Canolbarth Ewrop (Madrid)", + "Europe\/Malta": "Amser Canolbarth Ewrop (Malta)", + "Europe\/Mariehamn": "Amser Dwyrain Ewrop (Mariehamn)", + "Europe\/Minsk": "Amser Moscfa (Minsk)", + "Europe\/Monaco": "Amser Canolbarth Ewrop (Monaco)", + "Europe\/Moscow": "Amser Moscfa (Moscfa)", + "Europe\/Oslo": "Amser Canolbarth Ewrop (Oslo)", + "Europe\/Paris": "Amser Canolbarth Ewrop (Paris)", + "Europe\/Podgorica": "Amser Canolbarth Ewrop (Podgorica)", + "Europe\/Prague": "Amser Canolbarth Ewrop (Prag)", + "Europe\/Riga": "Amser Dwyrain Ewrop (Riga)", + "Europe\/Rome": "Amser Canolbarth Ewrop (Rhufain)", + "Europe\/Samara": "Amser Samara (Samara)", + "Europe\/San_Marino": "Amser Canolbarth Ewrop (San Marino)", + "Europe\/Sarajevo": "Amser Canolbarth Ewrop (Sarajevo)", + "Europe\/Saratov": "Amser Moscfa (Saratov)", + "Europe\/Simferopol": "Amser Moscfa (Simferopol)", + "Europe\/Skopje": "Amser Canolbarth Ewrop (Skopje)", + "Europe\/Sofia": "Amser Dwyrain Ewrop (Sofia)", + "Europe\/Stockholm": "Amser Canolbarth Ewrop (Stockholm)", + "Europe\/Tallinn": "Amser Dwyrain Ewrop (Tallinn)", + "Europe\/Tirane": "Amser Canolbarth Ewrop (Tirane)", + "Europe\/Ulyanovsk": "Amser Moscfa (Ulyanovsk)", + "Europe\/Uzhgorod": "Amser Dwyrain Ewrop (Uzhhorod)", + "Europe\/Vaduz": "Amser Canolbarth Ewrop (Vaduz)", + "Europe\/Vatican": "Amser Canolbarth Ewrop (Y Fatican)", + "Europe\/Vienna": "Amser Canolbarth Ewrop (Fienna)", + "Europe\/Vilnius": "Amser Dwyrain Ewrop (Vilnius)", + "Europe\/Volgograd": "Amser Volgograd (Volgograd)", + "Europe\/Warsaw": "Amser Canolbarth Ewrop (Warsaw)", + "Europe\/Zagreb": "Amser Canolbarth Ewrop (Zagreb)", + "Europe\/Zaporozhye": "Amser Dwyrain Ewrop (Zaporizhzhya)", + "Europe\/Zurich": "Amser Canolbarth Ewrop (Zurich)", + "Indian\/Antananarivo": "Amser Dwyrain Affrica (Antananarivo)", + "Indian\/Chagos": "Amser Cefnfor India (Chagos)", + "Indian\/Christmas": "Amser Ynys Y Nadolig (Ynys y Nadolig)", + "Indian\/Cocos": "Amser Ynysoedd Cocos (Cocos)", + "Indian\/Comoro": "Amser Dwyrain Affrica (Comoro)", + "Indian\/Kerguelen": "Amser Tiroedd Ffrainc yn y De a’r Antarctig (Kerguelen)", + "Indian\/Mahe": "Amser Seychelles (Mahe)", + "Indian\/Maldives": "Amser Y Maldives (Maldives)", + "Indian\/Mauritius": "Amser Mauritius (Mauritius)", + "Indian\/Mayotte": "Amser Dwyrain Affrica (Mayotte)", + "Indian\/Reunion": "Amser Réunion (Réunion)", + "MST7MDT": "Amser Mynyddoedd Gogledd America", + "PST8PDT": "Amser Cefnfor Tawel Gogledd America", + "Pacific\/Apia": "Amser Apia (Apia)", + "Pacific\/Auckland": "Amser Seland Newydd (Auckland)", + "Pacific\/Bougainville": "Amser Papua Guinea Newydd (Bougainville)", + "Pacific\/Chatham": "Amser Chatham (Chatham)", + "Pacific\/Easter": "Amser Ynys y Pasg (Ynys y Pasg)", + "Pacific\/Efate": "Amser Vanuatu (Efate)", + "Pacific\/Enderbury": "Amser Ynysoedd Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Amser Tokelau (Fakaofo)", + "Pacific\/Fiji": "Amser Fiji (Fiji)", + "Pacific\/Funafuti": "Amser Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Amser Galapagos (Galapagos)", + "Pacific\/Gambier": "Amser Gambier (Gambier)", + "Pacific\/Guadalcanal": "Amser Ynysoedd Solomon (Guadalcanal)", + "Pacific\/Guam": "Amser Chamorro (Guam)", + "Pacific\/Honolulu": "Amser Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Amser Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Amser Ynysoedd Line (Kiritimati)", + "Pacific\/Kosrae": "Amser Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Amser Ynysoedd Marshall (Kwajalein)", + "Pacific\/Majuro": "Amser Ynysoedd Marshall (Majuro)", + "Pacific\/Marquesas": "Amser Marquises (Marquesas)", + "Pacific\/Midway": "Amser Samoa (Midway)", + "Pacific\/Nauru": "Amser Nauru (Nauru)", + "Pacific\/Niue": "Amser Niue (Niue)", + "Pacific\/Norfolk": "Amser Ynys Norfolk (Norfolk)", + "Pacific\/Noumea": "Amser Caledonia Newydd (Noumea)", + "Pacific\/Pago_Pago": "Amser Samoa (Pago Pago)", + "Pacific\/Palau": "Amser Palau (Palau)", + "Pacific\/Pitcairn": "Amser Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Amser Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "Amser Papua Guinea Newydd (Port Moresby)", + "Pacific\/Rarotonga": "Amser Ynysoedd Cook (Rarotonga)", + "Pacific\/Saipan": "Amser Chamorro (Saipan)", + "Pacific\/Tahiti": "Amser Tahiti (Tahiti)", + "Pacific\/Tarawa": "Amser Ynysoedd Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Amser Tonga (Tongatapu)", + "Pacific\/Truk": "Amser Chuuk (Chuuk)", + "Pacific\/Wake": "Amser Ynys Wake (Wake)", + "Pacific\/Wallis": "Amser Wallis a Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/da.json b/src/Symfony/Component/Intl/Resources/data/timezones/da.json new file mode 100644 index 0000000000000..cec42a14e461c --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/da.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "GMT (Abidjan)", + "Africa\/Accra": "GMT (Accra)", + "Africa\/Addis_Ababa": "Østafrikansk tid (Addis Abeba)", + "Africa\/Algiers": "Centraleuropæisk tid (Algier)", + "Africa\/Asmera": "Østafrikansk tid (Asmara)", + "Africa\/Bamako": "GMT (Bamako)", + "Africa\/Bangui": "Vestafrikansk tid (Bangui)", + "Africa\/Banjul": "GMT (Banjul)", + "Africa\/Bissau": "GMT (Bissau)", + "Africa\/Blantyre": "Centralafrikansk tid (Blantyre)", + "Africa\/Brazzaville": "Vestafrikansk tid (Brazzaville)", + "Africa\/Bujumbura": "Centralafrikansk tid (Bujumbura)", + "Africa\/Cairo": "Østeuropæisk tid (Cairo)", + "Africa\/Casablanca": "Vesteuropæisk tid (Casablanca)", + "Africa\/Ceuta": "Centraleuropæisk tid (Ceuta)", + "Africa\/Conakry": "GMT (Conakry)", + "Africa\/Dakar": "GMT (Dakar)", + "Africa\/Dar_es_Salaam": "Østafrikansk tid (Dar es Salaam)", + "Africa\/Djibouti": "Østafrikansk tid (Djibouti)", + "Africa\/Douala": "Vestafrikansk tid (Douala)", + "Africa\/El_Aaiun": "Vesteuropæisk tid (El Aaiun)", + "Africa\/Freetown": "GMT (Freetown)", + "Africa\/Gaborone": "Centralafrikansk tid (Gaborone)", + "Africa\/Harare": "Centralafrikansk tid (Harare)", + "Africa\/Johannesburg": "Sydafrikansk tid (Johannesburg)", + "Africa\/Juba": "Østafrikansk tid (Juba)", + "Africa\/Kampala": "Østafrikansk tid (Kampala)", + "Africa\/Khartoum": "Centralafrikansk tid (Khartoum)", + "Africa\/Kigali": "Centralafrikansk tid (Kigali)", + "Africa\/Kinshasa": "Vestafrikansk tid (Kinshasa)", + "Africa\/Lagos": "Vestafrikansk tid (Lagos)", + "Africa\/Libreville": "Vestafrikansk tid (Libreville)", + "Africa\/Lome": "GMT (Lome)", + "Africa\/Luanda": "Vestafrikansk tid (Luanda)", + "Africa\/Lubumbashi": "Centralafrikansk tid (Lubumbashi)", + "Africa\/Lusaka": "Centralafrikansk tid (Lusaka)", + "Africa\/Malabo": "Vestafrikansk tid (Malabo)", + "Africa\/Maputo": "Centralafrikansk tid (Maputo)", + "Africa\/Maseru": "Sydafrikansk tid (Maseru)", + "Africa\/Mbabane": "Sydafrikansk tid (Mbabane)", + "Africa\/Mogadishu": "Østafrikansk tid (Mogadishu)", + "Africa\/Monrovia": "GMT (Monrovia)", + "Africa\/Nairobi": "Østafrikansk tid (Nairobi)", + "Africa\/Ndjamena": "Vestafrikansk tid (Ndjamena)", + "Africa\/Niamey": "Vestafrikansk tid (Niamey)", + "Africa\/Nouakchott": "GMT (Nouakchott)", + "Africa\/Ouagadougou": "GMT (Ouagadougou)", + "Africa\/Porto-Novo": "Vestafrikansk tid (Porto-Novo)", + "Africa\/Sao_Tome": "GMT (São Tomé)", + "Africa\/Tripoli": "Østeuropæisk tid (Tripoli)", + "Africa\/Tunis": "Centraleuropæisk tid (Tunis)", + "Africa\/Windhoek": "Centralafrikansk tid (Windhoek)", + "America\/Adak": "Hawaii-Aleutian-tid (Adak)", + "America\/Anchorage": "Alaska-tid (Anchorage)", + "America\/Anguilla": "Atlantic-tid (Anguilla)", + "America\/Antigua": "Atlantic-tid (Antigua)", + "America\/Araguaina": "Brasiliansk tid (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentisk tid (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentisk tid (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentisk tid (Salta)", + "America\/Argentina\/San_Juan": "Argentisk tid (San Juan)", + "America\/Argentina\/San_Luis": "Vestargentinsk tid (San Luis)", + "America\/Argentina\/Tucuman": "Argentisk tid (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentisk tid (Ushuaia)", + "America\/Aruba": "Atlantic-tid (Aruba)", + "America\/Asuncion": "Paraguayansk tid (Asunción)", + "America\/Bahia": "Brasiliansk tid (Bahia)", + "America\/Bahia_Banderas": "Central-tid (Bahia Banderas)", + "America\/Barbados": "Atlantic-tid (Barbados)", + "America\/Belem": "Brasiliansk tid (Belem)", + "America\/Belize": "Central-tid (Belize)", + "America\/Blanc-Sablon": "Atlantic-tid (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonas-tid (Boa Vista)", + "America\/Bogota": "Colombiansk tid (Bogota)", + "America\/Boise": "Mountain-tid (Boise)", + "America\/Buenos_Aires": "Argentisk tid (Buenos Aires)", + "America\/Cambridge_Bay": "Mountain-tid (Cambridge Bay)", + "America\/Campo_Grande": "Amazonas-tid (Campo Grande)", + "America\/Cancun": "Eastern-tid (Cancun)", + "America\/Caracas": "Venezuelansk tid (Caracas)", + "America\/Catamarca": "Argentisk tid (Catamarca)", + "America\/Cayenne": "Fransk Guyana-tid (Cayenne)", + "America\/Cayman": "Eastern-tid (Caymanøerne)", + "America\/Chicago": "Central-tid (Chicago)", + "America\/Chihuahua": "Mexicansk Pacific-tid (Chihuahua)", + "America\/Coral_Harbour": "Eastern-tid (Atikokan)", + "America\/Cordoba": "Argentisk tid (Cordoba)", + "America\/Costa_Rica": "Central-tid (Costa Rica)", + "America\/Creston": "Mountain-tid (Creston)", + "America\/Cuiaba": "Amazonas-tid (Cuiaba)", + "America\/Curacao": "Atlantic-tid (Curaçao)", + "America\/Danmarkshavn": "GMT (Danmarkshavn)", + "America\/Dawson": "Pacific-tid (Dawson)", + "America\/Dawson_Creek": "Mountain-tid (Dawson Creek)", + "America\/Denver": "Mountain-tid (Denver)", + "America\/Detroit": "Eastern-tid (Detroit)", + "America\/Dominica": "Atlantic-tid (Dominica)", + "America\/Edmonton": "Mountain-tid (Edmonton)", + "America\/Eirunepe": "Acre-tid (Eirunepe)", + "America\/El_Salvador": "Central-tid (El Salvador)", + "America\/Fort_Nelson": "Mountain-tid (Fort Nelson)", + "America\/Fortaleza": "Brasiliansk tid (Fortaleza)", + "America\/Glace_Bay": "Atlantic-tid (Glace Bay)", + "America\/Godthab": "Vestgrønlandsk tid (Nuuk)", + "America\/Goose_Bay": "Atlantic-tid (Goose Bay)", + "America\/Grand_Turk": "Eastern-tid (Grand Turk)", + "America\/Grenada": "Atlantic-tid (Grenada)", + "America\/Guadeloupe": "Atlantic-tid (Guadeloupe)", + "America\/Guatemala": "Central-tid (Guatemala)", + "America\/Guayaquil": "Ecuadoriansk tid (Guayaquil)", + "America\/Guyana": "Guyana-tid (Guyana)", + "America\/Halifax": "Atlantic-tid (Halifax)", + "America\/Havana": "Cubansk tid (Havana)", + "America\/Hermosillo": "Mexicansk Pacific-tid (Hermosillo)", + "America\/Indiana\/Knox": "Central-tid (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern-tid (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern-tid (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Central-tid (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern-tid (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern-tid (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern-tid (Winamac, Indiana)", + "America\/Indianapolis": "Eastern-tid (Indianapolis)", + "America\/Inuvik": "Mountain-tid (Inuvik)", + "America\/Iqaluit": "Eastern-tid (Iqaluit)", + "America\/Jamaica": "Eastern-tid (Jamaica)", + "America\/Jujuy": "Argentisk tid (Jujuy)", + "America\/Juneau": "Alaska-tid (Juneau)", + "America\/Kentucky\/Monticello": "Eastern-tid (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantic-tid (Kralendijk)", + "America\/La_Paz": "Boliviansk tid (La Paz)", + "America\/Lima": "Peruviansk tid (Lima)", + "America\/Los_Angeles": "Pacific-tid (Los Angeles)", + "America\/Louisville": "Eastern-tid (Louisville)", + "America\/Lower_Princes": "Atlantic-tid (Lower Prince’s Quarter)", + "America\/Maceio": "Brasiliansk tid (Maceio)", + "America\/Managua": "Central-tid (Managua)", + "America\/Manaus": "Amazonas-tid (Manaus)", + "America\/Marigot": "Atlantic-tid (Marigot)", + "America\/Martinique": "Atlantic-tid (Martinique)", + "America\/Matamoros": "Central-tid (Matamoros)", + "America\/Mazatlan": "Mexicansk Pacific-tid (Mazatlan)", + "America\/Mendoza": "Argentisk tid (Mendoza)", + "America\/Menominee": "Central-tid (Menominee)", + "America\/Merida": "Central-tid (Merida)", + "America\/Metlakatla": "Alaska-tid (Metlakatla)", + "America\/Mexico_City": "Central-tid (Mexico City)", + "America\/Miquelon": "Saint Pierre- og Miquelon-tid (Miquelon)", + "America\/Moncton": "Atlantic-tid (Moncton)", + "America\/Monterrey": "Central-tid (Monterrey)", + "America\/Montevideo": "Uruguayansk tid (Montevideo)", + "America\/Montserrat": "Atlantic-tid (Montserrat)", + "America\/Nassau": "Eastern-tid (Nassau)", + "America\/New_York": "Eastern-tid (New York)", + "America\/Nipigon": "Eastern-tid (Nipigon)", + "America\/Nome": "Alaska-tid (Nome)", + "America\/Noronha": "Fernando de Noronha-tid (Noronha)", + "America\/North_Dakota\/Beulah": "Central-tid (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Central-tid (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Central-tid (New Salem, North Dakota)", + "America\/Ojinaga": "Mountain-tid (Ojinaga)", + "America\/Panama": "Eastern-tid (Panama)", + "America\/Pangnirtung": "Eastern-tid (Pangnirtung)", + "America\/Paramaribo": "Surinam-tid (Paramaribo)", + "America\/Phoenix": "Mountain-tid (Phoenix)", + "America\/Port-au-Prince": "Eastern-tid (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantic-tid (Port of Spain)", + "America\/Porto_Velho": "Amazonas-tid (Porto Velho)", + "America\/Puerto_Rico": "Atlantic-tid (Puerto Rico)", + "America\/Punta_Arenas": "Chilensk tid (Punta Arenas)", + "America\/Rainy_River": "Central-tid (Rainy River)", + "America\/Rankin_Inlet": "Central-tid (Rankin Inlet)", + "America\/Recife": "Brasiliansk tid (Recife)", + "America\/Regina": "Central-tid (Regina)", + "America\/Resolute": "Central-tid (Resolute)", + "America\/Rio_Branco": "Acre-tid (Rio Branco)", + "America\/Santa_Isabel": "Nordvestmexicansk tid (Santa Isabel)", + "America\/Santarem": "Brasiliansk tid (Santarem)", + "America\/Santiago": "Chilensk tid (Santiago)", + "America\/Santo_Domingo": "Atlantic-tid (Santo Domingo)", + "America\/Sao_Paulo": "Brasiliansk tid (São Paulo)", + "America\/Scoresbysund": "Østgrønlandsk tid (Ittoqqortoormiit)", + "America\/Sitka": "Alaska-tid (Sitka)", + "America\/St_Barthelemy": "Atlantic-tid (Saint-Barthélemy)", + "America\/St_Johns": "Newfoundlandsk tid (St. John’s)", + "America\/St_Kitts": "Atlantic-tid (St. Kitts)", + "America\/St_Lucia": "Atlantic-tid (St. Lucia)", + "America\/St_Thomas": "Atlantic-tid (St. Thomas)", + "America\/St_Vincent": "Atlantic-tid (St. Vincent)", + "America\/Swift_Current": "Central-tid (Swift Current)", + "America\/Tegucigalpa": "Central-tid (Tegucigalpa)", + "America\/Thule": "Atlantic-tid (Thule)", + "America\/Thunder_Bay": "Eastern-tid (Thunder Bay)", + "America\/Tijuana": "Pacific-tid (Tijuana)", + "America\/Toronto": "Eastern-tid (Toronto)", + "America\/Tortola": "Atlantic-tid (Tortola)", + "America\/Vancouver": "Pacific-tid (Vancouver)", + "America\/Whitehorse": "Pacific-tid (Whitehorse)", + "America\/Winnipeg": "Central-tid (Winnipeg)", + "America\/Yakutat": "Alaska-tid (Yakutat)", + "America\/Yellowknife": "Mountain-tid (Yellowknife)", + "Antarctica\/Casey": "Vestaustralsk tid (Casey)", + "Antarctica\/Davis": "Davis-tid (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville-tid (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie-tid (Macquarie)", + "Antarctica\/Mawson": "Mawson-tid (Mawson)", + "Antarctica\/McMurdo": "Newzealandsk tid (McMurdo)", + "Antarctica\/Palmer": "Chilensk tid (Palmer)", + "Antarctica\/Rothera": "Rothera-tid (Rothera)", + "Antarctica\/Syowa": "Syowa-tid (Syowa)", + "Antarctica\/Troll": "GMT (Troll)", + "Antarctica\/Vostok": "Vostok-tid (Vostok)", + "Arctic\/Longyearbyen": "Centraleuropæisk tid (Longyearbyen)", + "Asia\/Aden": "Arabisk tid (Aden)", + "Asia\/Almaty": "Østkasakhstansk tid (Almaty)", + "Asia\/Amman": "Østeuropæisk tid (Amman)", + "Asia\/Anadyr": "Anadyr-tid (Anadyr)", + "Asia\/Aqtau": "Vestkasakhstansk tid (Aktau)", + "Asia\/Aqtobe": "Vestkasakhstansk tid (Aktobe)", + "Asia\/Ashgabat": "Turkmensk tid (Asjkhabad)", + "Asia\/Atyrau": "Vestkasakhstansk tid (Atyrau)", + "Asia\/Baghdad": "Arabisk tid (Bagdad)", + "Asia\/Bahrain": "Arabisk tid (Bahrain)", + "Asia\/Baku": "Aserbajdsjansk tid (Baku)", + "Asia\/Bangkok": "Indokina-tid (Bangkok)", + "Asia\/Beirut": "Østeuropæisk tid (Beirut)", + "Asia\/Bishkek": "Kirgisisk tid (Bisjkek)", + "Asia\/Brunei": "Brunei Darussalam-tid (Brunei)", + "Asia\/Calcutta": "Indisk normaltid (Kolkata)", + "Asia\/Chita": "Jakutsk-tid (Chita)", + "Asia\/Choibalsan": "Tsjojbalsan-tid (Tsjojbalsan)", + "Asia\/Colombo": "Indisk normaltid (Colombo)", + "Asia\/Damascus": "Østeuropæisk tid (Damaskus)", + "Asia\/Dhaka": "Bangladesh-tid (Dhaka)", + "Asia\/Dili": "Østtimor-tid (Dili)", + "Asia\/Dubai": "Golflandene-normaltid (Dubai)", + "Asia\/Dushanbe": "Tadsjikisk tid (Dusjanbe)", + "Asia\/Famagusta": "Østeuropæisk tid (Famagusta)", + "Asia\/Gaza": "Østeuropæisk tid (Gaza)", + "Asia\/Hebron": "Østeuropæisk tid (Hebron)", + "Asia\/Hong_Kong": "Hongkong-tid (Hongkong)", + "Asia\/Hovd": "Hovd-tid (Hovd)", + "Asia\/Irkutsk": "Irkutsk-tid (Irkutsk)", + "Asia\/Jakarta": "Vestindonesisk tid (Jakarta)", + "Asia\/Jayapura": "Østindonesisk tid (Jayapura)", + "Asia\/Jerusalem": "Israelsk tid (Jerusalem)", + "Asia\/Kabul": "Afghansk tid (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamchatski tid (Kamtjatka)", + "Asia\/Karachi": "Pakistansk tid (Karachi)", + "Asia\/Katmandu": "Nepalesisk tid (Katmandu)", + "Asia\/Khandyga": "Jakutsk-tid (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk-tid (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malaysia-tid (Kuala Lumpur)", + "Asia\/Kuching": "Malaysia-tid (Kuching)", + "Asia\/Kuwait": "Arabisk tid (Kuwait)", + "Asia\/Macau": "Kinesisk tid (Macao)", + "Asia\/Magadan": "Magadan-tid (Magadan)", + "Asia\/Makassar": "Centralindonesisk tid (Makassar)", + "Asia\/Manila": "Filippinsk tid (Manila)", + "Asia\/Muscat": "Golflandene-normaltid (Muscat)", + "Asia\/Nicosia": "Østeuropæisk tid (Nicosia)", + "Asia\/Novokuznetsk": "Krasnojarsk-tid (Novokusnetsk)", + "Asia\/Novosibirsk": "Novosibirsk-tid (Novosibirsk)", + "Asia\/Omsk": "Omsk-tid (Omsk)", + "Asia\/Oral": "Vestkasakhstansk tid (Oral)", + "Asia\/Phnom_Penh": "Indokina-tid (Phnom Penh)", + "Asia\/Pontianak": "Vestindonesisk tid (Pontianak)", + "Asia\/Pyongyang": "Koreansk tid (Pyongyang)", + "Asia\/Qatar": "Arabisk tid (Qatar)", + "Asia\/Qostanay": "Østkasakhstansk tid (Qostanay)", + "Asia\/Qyzylorda": "Vestkasakhstansk tid (Kyzylorda)", + "Asia\/Rangoon": "Myanmar-tid (Rangoon)", + "Asia\/Riyadh": "Arabisk tid (Riyadh)", + "Asia\/Saigon": "Indokina-tid (Ho Chi Minh City)", + "Asia\/Sakhalin": "Sakhalin-tid (Sakhalin)", + "Asia\/Samarkand": "Usbekisk tid (Samarkand)", + "Asia\/Seoul": "Koreansk tid (Seoul)", + "Asia\/Shanghai": "Kinesisk tid (Shanghai)", + "Asia\/Singapore": "Singapore-tid (Singapore)", + "Asia\/Srednekolymsk": "Magadan-tid (Srednekolymsk)", + "Asia\/Taipei": "Taipei-tid (Taipei)", + "Asia\/Tashkent": "Usbekisk tid (Tasjkent)", + "Asia\/Tbilisi": "Georgisk tid (Tbilisi)", + "Asia\/Tehran": "Iransk tid (Teheran)", + "Asia\/Thimphu": "Bhutan-tid (Thimphu)", + "Asia\/Tokyo": "Japansk tid (Tokyo)", + "Asia\/Ulaanbaatar": "Ulan Bator-tid (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostok-tid (Ust-Nera)", + "Asia\/Vientiane": "Indokina-tid (Vientiane)", + "Asia\/Vladivostok": "Vladivostok-tid (Vladivostok)", + "Asia\/Yakutsk": "Jakutsk-tid (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburg-tid (Jekaterinburg)", + "Asia\/Yerevan": "Armensk tid (Jerevan)", + "Atlantic\/Azores": "Azorerne-tid (Azorerne)", + "Atlantic\/Bermuda": "Atlantic-tid (Bermuda)", + "Atlantic\/Canary": "Vesteuropæisk tid (De Kanariske Øer)", + "Atlantic\/Cape_Verde": "Kap Verde-tid (Kap Verde)", + "Atlantic\/Faeroe": "Vesteuropæisk tid (Færøerne)", + "Atlantic\/Madeira": "Vesteuropæisk tid (Madeira)", + "Atlantic\/Reykjavik": "GMT (Reykjavik)", + "Atlantic\/South_Georgia": "South Georgia-tid (South Georgia)", + "Atlantic\/St_Helena": "GMT (St. Helena)", + "Atlantic\/Stanley": "Falklandsøerne-tid (Stanley)", + "Australia\/Adelaide": "Centralaustralsk tid (Adelaide)", + "Australia\/Brisbane": "Østaustralsk tid (Brisbane)", + "Australia\/Broken_Hill": "Centralaustralsk tid (Broken Hill)", + "Australia\/Currie": "Østaustralsk tid (Currie)", + "Australia\/Darwin": "Centralaustralsk tid (Darwin)", + "Australia\/Eucla": "Vestlig centralaustralsk tid (Eucla)", + "Australia\/Hobart": "Østaustralsk tid (Hobart)", + "Australia\/Lindeman": "Østaustralsk tid (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe-tid (Lord Howe)", + "Australia\/Melbourne": "Østaustralsk tid (Melbourne)", + "Australia\/Perth": "Vestaustralsk tid (Perth)", + "Australia\/Sydney": "Østaustralsk tid (Sydney)", + "CST6CDT": "Central-tid", + "EST5EDT": "Eastern-tid", + "Etc\/GMT": "GMT", + "Etc\/UTC": "Koordineret universaltid", + "Europe\/Amsterdam": "Centraleuropæisk tid (Amsterdam)", + "Europe\/Andorra": "Centraleuropæisk tid (Andorra)", + "Europe\/Astrakhan": "Moskva-tid (Astrakhan)", + "Europe\/Athens": "Østeuropæisk tid (Athen)", + "Europe\/Belgrade": "Centraleuropæisk tid (Beograd)", + "Europe\/Berlin": "Centraleuropæisk tid (Berlin)", + "Europe\/Bratislava": "Centraleuropæisk tid (Bratislava)", + "Europe\/Brussels": "Centraleuropæisk tid (Bruxelles)", + "Europe\/Bucharest": "Østeuropæisk tid (Bukarest)", + "Europe\/Budapest": "Centraleuropæisk tid (Budapest)", + "Europe\/Busingen": "Centraleuropæisk tid (Busingen)", + "Europe\/Chisinau": "Østeuropæisk tid (Chisinau)", + "Europe\/Copenhagen": "Centraleuropæisk tid (København)", + "Europe\/Dublin": "GMT (Dublin)", + "Europe\/Gibraltar": "Centraleuropæisk tid (Gibraltar)", + "Europe\/Guernsey": "GMT (Guernsey)", + "Europe\/Helsinki": "Østeuropæisk tid (Helsinki)", + "Europe\/Isle_of_Man": "GMT (Isle of Man)", + "Europe\/Jersey": "GMT (Jersey)", + "Europe\/Kaliningrad": "Østeuropæisk tid (Kaliningrad)", + "Europe\/Kiev": "Østeuropæisk tid (Kiev)", + "Europe\/Lisbon": "Vesteuropæisk tid (Lissabon)", + "Europe\/Ljubljana": "Centraleuropæisk tid (Ljubljana)", + "Europe\/London": "GMT (London)", + "Europe\/Luxembourg": "Centraleuropæisk tid (Luxembourg)", + "Europe\/Madrid": "Centraleuropæisk tid (Madrid)", + "Europe\/Malta": "Centraleuropæisk tid (Malta)", + "Europe\/Mariehamn": "Østeuropæisk tid (Mariehamn)", + "Europe\/Minsk": "Moskva-tid (Minsk)", + "Europe\/Monaco": "Centraleuropæisk tid (Monaco)", + "Europe\/Moscow": "Moskva-tid (Moskva)", + "Europe\/Oslo": "Centraleuropæisk tid (Oslo)", + "Europe\/Paris": "Centraleuropæisk tid (Paris)", + "Europe\/Podgorica": "Centraleuropæisk tid (Podgorica)", + "Europe\/Prague": "Centraleuropæisk tid (Prag)", + "Europe\/Riga": "Østeuropæisk tid (Riga)", + "Europe\/Rome": "Centraleuropæisk tid (Rom)", + "Europe\/Samara": "Samara-tid (Samara)", + "Europe\/San_Marino": "Centraleuropæisk tid (San Marino)", + "Europe\/Sarajevo": "Centraleuropæisk tid (Sarajevo)", + "Europe\/Saratov": "Moskva-tid (Saratov)", + "Europe\/Simferopol": "Moskva-tid (Simferopol)", + "Europe\/Skopje": "Centraleuropæisk tid (Skopje)", + "Europe\/Sofia": "Østeuropæisk tid (Sofia)", + "Europe\/Stockholm": "Centraleuropæisk tid (Stockholm)", + "Europe\/Tallinn": "Østeuropæisk tid (Tallinn)", + "Europe\/Tirane": "Centraleuropæisk tid (Tirana)", + "Europe\/Ulyanovsk": "Moskva-tid (Uljanovsk)", + "Europe\/Uzhgorod": "Østeuropæisk tid (Uzjhorod)", + "Europe\/Vaduz": "Centraleuropæisk tid (Vaduz)", + "Europe\/Vatican": "Centraleuropæisk tid (Vatikanet)", + "Europe\/Vienna": "Centraleuropæisk tid (Wien)", + "Europe\/Vilnius": "Østeuropæisk tid (Vilnius)", + "Europe\/Volgograd": "Volgograd-tid (Volgograd)", + "Europe\/Warsaw": "Centraleuropæisk tid (Warszawa)", + "Europe\/Zagreb": "Centraleuropæisk tid (Zagreb)", + "Europe\/Zaporozhye": "Østeuropæisk tid (Zaporizjzja)", + "Europe\/Zurich": "Centraleuropæisk tid (Zürich)", + "Indian\/Antananarivo": "Østafrikansk tid (Antananarivo)", + "Indian\/Chagos": "Indiske Ocean-normaltid (Chagos)", + "Indian\/Christmas": "Juleøen-normaltid (Juleøerne)", + "Indian\/Cocos": "Cocosøerne-normaltid (Cocos)", + "Indian\/Comoro": "Østafrikansk tid (Comorerne)", + "Indian\/Kerguelen": "Franske Sydlige og Antarktiske Territorier-tid (Kerguelen)", + "Indian\/Mahe": "Seychellisk tid (Mahe)", + "Indian\/Maldives": "Maldiverne-tid (Maldiverne)", + "Indian\/Mauritius": "Mauritius-tid (Mauritius)", + "Indian\/Mayotte": "Østafrikansk tid (Mayotte)", + "Indian\/Reunion": "Reunion-tid (Réunion)", + "MST7MDT": "Mountain-tid", + "PST8PDT": "Pacific-tid", + "Pacific\/Apia": "Apia-tid (Apia)", + "Pacific\/Auckland": "Newzealandsk tid (Auckland)", + "Pacific\/Bougainville": "Papua Ny Guinea-tid (Bougainville)", + "Pacific\/Chatham": "Chatham-tid (Chatham)", + "Pacific\/Easter": "Påskeøen-tid (Påskeøen)", + "Pacific\/Efate": "Vanuatu-tid (Efate)", + "Pacific\/Enderbury": "Phoenixøen-tid (Enderbury)", + "Pacific\/Fakaofo": "Tokelau-tid (Fakaofo)", + "Pacific\/Fiji": "Fijiansk tid (Fiji)", + "Pacific\/Funafuti": "Tuvalu-tid (Funafuti)", + "Pacific\/Galapagos": "Galapagos-tid (Galapagos)", + "Pacific\/Gambier": "Gambier-tid (Gambier)", + "Pacific\/Guadalcanal": "Salomonøerne-tid (Guadalcanal)", + "Pacific\/Guam": "Chamorro-tid (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleutian-tid (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleutian-tid (Johnston)", + "Pacific\/Kiritimati": "Linjeøerne-tid (Kiritimati)", + "Pacific\/Kosrae": "Kosrae-tid (Kosrae)", + "Pacific\/Kwajalein": "Marshalløerne-tid (Kwajalein)", + "Pacific\/Majuro": "Marshalløerne-tid (Majuro)", + "Pacific\/Marquesas": "Marquesas-tid (Marquesas)", + "Pacific\/Midway": "Samoansk tid (Midway)", + "Pacific\/Nauru": "Nauru-tid (Nauru)", + "Pacific\/Niue": "Niue-tid (Niue)", + "Pacific\/Norfolk": "Norfolk Island-tid (Norfolk)", + "Pacific\/Noumea": "Ny Kaledonien-tid (Noumea)", + "Pacific\/Pago_Pago": "Samoansk tid (Pago Pago)", + "Pacific\/Palau": "Palau-normaltid (Palau)", + "Pacific\/Pitcairn": "Pitcairn-tid (Pitcairn)", + "Pacific\/Ponape": "Ponape-tid (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Ny Guinea-tid (Port Moresby)", + "Pacific\/Rarotonga": "Cookøerne-tid (Rarotonga)", + "Pacific\/Saipan": "Chamorro-tid (Saipan)", + "Pacific\/Tahiti": "Tahiti-tid (Tahiti)", + "Pacific\/Tarawa": "Gilbertøerne-tid (Tarawa)", + "Pacific\/Tongatapu": "Tongansk tid (Tongatapu)", + "Pacific\/Truk": "Chuuk-tid (Chuuk)", + "Pacific\/Wake": "Wake Island-tid (Wake)", + "Pacific\/Wallis": "Wallis og Futuna-tid (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/de.json b/src/Symfony/Component/Intl/Resources/data/timezones/de.json new file mode 100644 index 0000000000000..8b0bfc468f5fe --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/de.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Mittlere Greenwich-Zeit (Abidjan)", + "Africa\/Accra": "Mittlere Greenwich-Zeit (Accra)", + "Africa\/Addis_Ababa": "Ostafrikanische Zeit (Addis Abeba)", + "Africa\/Algiers": "Mitteleuropäische Zeit (Algier)", + "Africa\/Asmera": "Ostafrikanische Zeit (Asmara)", + "Africa\/Bamako": "Mittlere Greenwich-Zeit (Bamako)", + "Africa\/Bangui": "Westafrikanische Zeit (Bangui)", + "Africa\/Banjul": "Mittlere Greenwich-Zeit (Banjul)", + "Africa\/Bissau": "Mittlere Greenwich-Zeit (Bissau)", + "Africa\/Blantyre": "Zentralafrikanische Zeit (Blantyre)", + "Africa\/Brazzaville": "Westafrikanische Zeit (Brazzaville)", + "Africa\/Bujumbura": "Zentralafrikanische Zeit (Bujumbura)", + "Africa\/Cairo": "Osteuropäische Zeit (Kairo)", + "Africa\/Casablanca": "Westeuropäische Zeit (Casablanca)", + "Africa\/Ceuta": "Mitteleuropäische Zeit (Ceuta)", + "Africa\/Conakry": "Mittlere Greenwich-Zeit (Conakry)", + "Africa\/Dakar": "Mittlere Greenwich-Zeit (Dakar)", + "Africa\/Dar_es_Salaam": "Ostafrikanische Zeit (Daressalam)", + "Africa\/Djibouti": "Ostafrikanische Zeit (Dschibuti)", + "Africa\/Douala": "Westafrikanische Zeit (Douala)", + "Africa\/El_Aaiun": "Westeuropäische Zeit (El Aaiún)", + "Africa\/Freetown": "Mittlere Greenwich-Zeit (Freetown)", + "Africa\/Gaborone": "Zentralafrikanische Zeit (Gaborone)", + "Africa\/Harare": "Zentralafrikanische Zeit (Harare)", + "Africa\/Johannesburg": "Südafrikanische Zeit (Johannesburg)", + "Africa\/Juba": "Ostafrikanische Zeit (Juba)", + "Africa\/Kampala": "Ostafrikanische Zeit (Kampala)", + "Africa\/Khartoum": "Zentralafrikanische Zeit (Khartum)", + "Africa\/Kigali": "Zentralafrikanische Zeit (Kigali)", + "Africa\/Kinshasa": "Westafrikanische Zeit (Kinshasa)", + "Africa\/Lagos": "Westafrikanische Zeit (Lagos)", + "Africa\/Libreville": "Westafrikanische Zeit (Libreville)", + "Africa\/Lome": "Mittlere Greenwich-Zeit (Lomé)", + "Africa\/Luanda": "Westafrikanische Zeit (Luanda)", + "Africa\/Lubumbashi": "Zentralafrikanische Zeit (Lubumbashi)", + "Africa\/Lusaka": "Zentralafrikanische Zeit (Lusaka)", + "Africa\/Malabo": "Westafrikanische Zeit (Malabo)", + "Africa\/Maputo": "Zentralafrikanische Zeit (Maputo)", + "Africa\/Maseru": "Südafrikanische Zeit (Maseru)", + "Africa\/Mbabane": "Südafrikanische Zeit (Mbabane)", + "Africa\/Mogadishu": "Ostafrikanische Zeit (Mogadischu)", + "Africa\/Monrovia": "Mittlere Greenwich-Zeit (Monrovia)", + "Africa\/Nairobi": "Ostafrikanische Zeit (Nairobi)", + "Africa\/Ndjamena": "Westafrikanische Zeit (N’Djamena)", + "Africa\/Niamey": "Westafrikanische Zeit (Niamey)", + "Africa\/Nouakchott": "Mittlere Greenwich-Zeit (Nouakchott)", + "Africa\/Ouagadougou": "Mittlere Greenwich-Zeit (Ouagadougou)", + "Africa\/Porto-Novo": "Westafrikanische Zeit (Porto Novo)", + "Africa\/Sao_Tome": "Mittlere Greenwich-Zeit (São Tomé)", + "Africa\/Tripoli": "Osteuropäische Zeit (Tripolis)", + "Africa\/Tunis": "Mitteleuropäische Zeit (Tunis)", + "Africa\/Windhoek": "Zentralafrikanische Zeit (Windhoek)", + "America\/Adak": "Hawaii-Aleuten-Zeit (Adak)", + "America\/Anchorage": "Alaska-Zeit (Anchorage)", + "America\/Anguilla": "Atlantik-Zeit (Anguilla)", + "America\/Antigua": "Atlantik-Zeit (Antigua)", + "America\/Araguaina": "Brasília-Zeit (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentinische Zeit (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinische Zeit (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinische Zeit (Salta)", + "America\/Argentina\/San_Juan": "Argentinische Zeit (San Juan)", + "America\/Argentina\/San_Luis": "Westargentinische Zeit (San Luis)", + "America\/Argentina\/Tucuman": "Argentinische Zeit (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentinische Zeit (Ushuaia)", + "America\/Aruba": "Atlantik-Zeit (Aruba)", + "America\/Asuncion": "Paraguayanische Zeit (Asunción)", + "America\/Bahia": "Brasília-Zeit (Bahia)", + "America\/Bahia_Banderas": "Nordamerikanische Inlandzeit (Bahia Banderas)", + "America\/Barbados": "Atlantik-Zeit (Barbados)", + "America\/Belem": "Brasília-Zeit (Belem)", + "America\/Belize": "Nordamerikanische Inlandzeit (Belize)", + "America\/Blanc-Sablon": "Atlantik-Zeit (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonas-Zeit (Boa Vista)", + "America\/Bogota": "Kolumbianische Zeit (Bogotá)", + "America\/Boise": "Rocky-Mountain-Zeit (Boise)", + "America\/Buenos_Aires": "Argentinische Zeit (Buenos Aires)", + "America\/Cambridge_Bay": "Rocky-Mountain-Zeit (Cambridge Bay)", + "America\/Campo_Grande": "Amazonas-Zeit (Campo Grande)", + "America\/Cancun": "Nordamerikanische Ostküstenzeit (Cancún)", + "America\/Caracas": "Venezuela-Zeit (Caracas)", + "America\/Catamarca": "Argentinische Zeit (Catamarca)", + "America\/Cayenne": "Französisch-Guayana-Zeit (Cayenne)", + "America\/Cayman": "Nordamerikanische Ostküstenzeit (Kaimaninseln)", + "America\/Chicago": "Nordamerikanische Inlandzeit (Chicago)", + "America\/Chihuahua": "Mexiko Pazifikzone-Zeit (Chihuahua)", + "America\/Coral_Harbour": "Nordamerikanische Ostküstenzeit (Atikokan)", + "America\/Cordoba": "Argentinische Zeit (Córdoba)", + "America\/Costa_Rica": "Nordamerikanische Inlandzeit (Costa Rica)", + "America\/Creston": "Rocky-Mountain-Zeit (Creston)", + "America\/Cuiaba": "Amazonas-Zeit (Cuiaba)", + "America\/Curacao": "Atlantik-Zeit (Curaçao)", + "America\/Danmarkshavn": "Mittlere Greenwich-Zeit (Danmarkshavn)", + "America\/Dawson": "Nordamerikanische Westküstenzeit (Dawson)", + "America\/Dawson_Creek": "Rocky-Mountain-Zeit (Dawson Creek)", + "America\/Denver": "Rocky-Mountain-Zeit (Denver)", + "America\/Detroit": "Nordamerikanische Ostküstenzeit (Detroit)", + "America\/Dominica": "Atlantik-Zeit (Dominica)", + "America\/Edmonton": "Rocky-Mountain-Zeit (Edmonton)", + "America\/Eirunepe": "Acre-Zeit (Eirunepe)", + "America\/El_Salvador": "Nordamerikanische Inlandzeit (El Salvador)", + "America\/Fort_Nelson": "Rocky-Mountain-Zeit (Fort Nelson)", + "America\/Fortaleza": "Brasília-Zeit (Fortaleza)", + "America\/Glace_Bay": "Atlantik-Zeit (Glace Bay)", + "America\/Godthab": "Westgrönland-Zeit (Nuuk)", + "America\/Goose_Bay": "Atlantik-Zeit (Goose Bay)", + "America\/Grand_Turk": "Nordamerikanische Ostküstenzeit (Grand Turk)", + "America\/Grenada": "Atlantik-Zeit (Grenada)", + "America\/Guadeloupe": "Atlantik-Zeit (Guadeloupe)", + "America\/Guatemala": "Nordamerikanische Inlandzeit (Guatemala)", + "America\/Guayaquil": "Ecuadorianische Zeit (Guayaquil)", + "America\/Guyana": "Guyana-Zeit (Guyana)", + "America\/Halifax": "Atlantik-Zeit (Halifax)", + "America\/Havana": "Kubanische Zeit (Havanna)", + "America\/Hermosillo": "Mexiko Pazifikzone-Zeit (Hermosillo)", + "America\/Indiana\/Knox": "Nordamerikanische Inlandzeit (Knox, Indiana)", + "America\/Indiana\/Marengo": "Nordamerikanische Ostküstenzeit (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Nordamerikanische Ostküstenzeit (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Nordamerikanische Inlandzeit (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Nordamerikanische Ostküstenzeit (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Nordamerikanische Ostküstenzeit (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Nordamerikanische Ostküstenzeit (Winamac, Indiana)", + "America\/Indianapolis": "Nordamerikanische Ostküstenzeit (Indianapolis)", + "America\/Inuvik": "Rocky-Mountain-Zeit (Inuvik)", + "America\/Iqaluit": "Nordamerikanische Ostküstenzeit (Iqaluit)", + "America\/Jamaica": "Nordamerikanische Ostküstenzeit (Jamaika)", + "America\/Jujuy": "Argentinische Zeit (Jujuy)", + "America\/Juneau": "Alaska-Zeit (Juneau)", + "America\/Kentucky\/Monticello": "Nordamerikanische Ostküstenzeit (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantik-Zeit (Kralendijk)", + "America\/La_Paz": "Bolivianische Zeit (La Paz)", + "America\/Lima": "Peruanische Zeit (Lima)", + "America\/Los_Angeles": "Nordamerikanische Westküstenzeit (Los Angeles)", + "America\/Louisville": "Nordamerikanische Ostküstenzeit (Louisville)", + "America\/Lower_Princes": "Atlantik-Zeit (Lower Prince’s Quarter)", + "America\/Maceio": "Brasília-Zeit (Maceio)", + "America\/Managua": "Nordamerikanische Inlandzeit (Managua)", + "America\/Manaus": "Amazonas-Zeit (Manaus)", + "America\/Marigot": "Atlantik-Zeit (Marigot)", + "America\/Martinique": "Atlantik-Zeit (Martinique)", + "America\/Matamoros": "Nordamerikanische Inlandzeit (Matamoros)", + "America\/Mazatlan": "Mexiko Pazifikzone-Zeit (Mazatlan)", + "America\/Mendoza": "Argentinische Zeit (Mendoza)", + "America\/Menominee": "Nordamerikanische Inlandzeit (Menominee)", + "America\/Merida": "Nordamerikanische Inlandzeit (Merida)", + "America\/Metlakatla": "Alaska-Zeit (Metlakatla)", + "America\/Mexico_City": "Nordamerikanische Inlandzeit (Mexiko-Stadt)", + "America\/Miquelon": "St.-Pierre-und-Miquelon-Zeit (Miquelon)", + "America\/Moncton": "Atlantik-Zeit (Moncton)", + "America\/Monterrey": "Nordamerikanische Inlandzeit (Monterrey)", + "America\/Montevideo": "Uruguayanische Zeit (Montevideo)", + "America\/Montserrat": "Atlantik-Zeit (Montserrat)", + "America\/Nassau": "Nordamerikanische Ostküstenzeit (Nassau)", + "America\/New_York": "Nordamerikanische Ostküstenzeit (New York)", + "America\/Nipigon": "Nordamerikanische Ostküstenzeit (Nipigon)", + "America\/Nome": "Alaska-Zeit (Nome)", + "America\/Noronha": "Fernando de Noronha-Zeit (Noronha)", + "America\/North_Dakota\/Beulah": "Nordamerikanische Inlandzeit (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Nordamerikanische Inlandzeit (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Nordamerikanische Inlandzeit (New Salem, North Dakota)", + "America\/Ojinaga": "Rocky-Mountain-Zeit (Ojinaga)", + "America\/Panama": "Nordamerikanische Ostküstenzeit (Panama)", + "America\/Pangnirtung": "Nordamerikanische Ostküstenzeit (Pangnirtung)", + "America\/Paramaribo": "Suriname-Zeit (Paramaribo)", + "America\/Phoenix": "Rocky-Mountain-Zeit (Phoenix)", + "America\/Port-au-Prince": "Nordamerikanische Ostküstenzeit (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantik-Zeit (Port of Spain)", + "America\/Porto_Velho": "Amazonas-Zeit (Porto Velho)", + "America\/Puerto_Rico": "Atlantik-Zeit (Puerto Rico)", + "America\/Punta_Arenas": "Chilenische Zeit (Punta Arenas)", + "America\/Rainy_River": "Nordamerikanische Inlandzeit (Rainy River)", + "America\/Rankin_Inlet": "Nordamerikanische Inlandzeit (Rankin Inlet)", + "America\/Recife": "Brasília-Zeit (Recife)", + "America\/Regina": "Nordamerikanische Inlandzeit (Regina)", + "America\/Resolute": "Nordamerikanische Inlandzeit (Resolute)", + "America\/Rio_Branco": "Acre-Zeit (Rio Branco)", + "America\/Santa_Isabel": "Mexiko Nordwestliche Zone-Zeit (Santa Isabel)", + "America\/Santarem": "Brasília-Zeit (Santarem)", + "America\/Santiago": "Chilenische Zeit (Santiago)", + "America\/Santo_Domingo": "Atlantik-Zeit (Santo Domingo)", + "America\/Sao_Paulo": "Brasília-Zeit (São Paulo)", + "America\/Scoresbysund": "Ostgrönland-Zeit (Ittoqqortoormiit)", + "America\/Sitka": "Alaska-Zeit (Sitka)", + "America\/St_Barthelemy": "Atlantik-Zeit (Saint-Barthélemy)", + "America\/St_Johns": "Neufundland-Zeit (St. John’s)", + "America\/St_Kitts": "Atlantik-Zeit (St. Kitts)", + "America\/St_Lucia": "Atlantik-Zeit (St. Lucia)", + "America\/St_Thomas": "Atlantik-Zeit (St. Thomas)", + "America\/St_Vincent": "Atlantik-Zeit (St. Vincent)", + "America\/Swift_Current": "Nordamerikanische Inlandzeit (Swift Current)", + "America\/Tegucigalpa": "Nordamerikanische Inlandzeit (Tegucigalpa)", + "America\/Thule": "Atlantik-Zeit (Thule)", + "America\/Thunder_Bay": "Nordamerikanische Ostküstenzeit (Thunder Bay)", + "America\/Tijuana": "Nordamerikanische Westküstenzeit (Tijuana)", + "America\/Toronto": "Nordamerikanische Ostküstenzeit (Toronto)", + "America\/Tortola": "Atlantik-Zeit (Tortola)", + "America\/Vancouver": "Nordamerikanische Westküstenzeit (Vancouver)", + "America\/Whitehorse": "Nordamerikanische Westküstenzeit (Whitehorse)", + "America\/Winnipeg": "Nordamerikanische Inlandzeit (Winnipeg)", + "America\/Yakutat": "Alaska-Zeit (Yakutat)", + "America\/Yellowknife": "Rocky-Mountain-Zeit (Yellowknife)", + "Antarctica\/Casey": "Westaustralische Zeit (Casey)", + "Antarctica\/Davis": "Davis-Zeit (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville-Zeit (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarieinsel-Zeit (Macquarie)", + "Antarctica\/Mawson": "Mawson-Zeit (Mawson)", + "Antarctica\/McMurdo": "Neuseeland-Zeit (McMurdo)", + "Antarctica\/Palmer": "Chilenische Zeit (Palmer)", + "Antarctica\/Rothera": "Rothera-Zeit (Rothera)", + "Antarctica\/Syowa": "Syowa-Zeit (Syowa)", + "Antarctica\/Troll": "Mittlere Greenwich-Zeit (Troll)", + "Antarctica\/Vostok": "Wostok-Zeit (Wostok)", + "Arctic\/Longyearbyen": "Mitteleuropäische Zeit (Longyearbyen)", + "Asia\/Aden": "Arabische Zeit (Aden)", + "Asia\/Almaty": "Ostkasachische Zeit (Almaty)", + "Asia\/Amman": "Osteuropäische Zeit (Amman)", + "Asia\/Anadyr": "Anadyr Zeit (Anadyr)", + "Asia\/Aqtau": "Westkasachische Zeit (Aqtau)", + "Asia\/Aqtobe": "Westkasachische Zeit (Aktobe)", + "Asia\/Ashgabat": "Turkmenistan-Zeit (Aşgabat)", + "Asia\/Atyrau": "Westkasachische Zeit (Atyrau)", + "Asia\/Baghdad": "Arabische Zeit (Bagdad)", + "Asia\/Bahrain": "Arabische Zeit (Bahrain)", + "Asia\/Baku": "Aserbaidschanische Zeit (Baku)", + "Asia\/Bangkok": "Indochina-Zeit (Bangkok)", + "Asia\/Beirut": "Osteuropäische Zeit (Beirut)", + "Asia\/Bishkek": "Kirgisistan-Zeit (Bischkek)", + "Asia\/Brunei": "Brunei-Darussalam-Zeit (Brunei Darussalam)", + "Asia\/Calcutta": "Indische Zeit (Kalkutta)", + "Asia\/Chita": "Jakutsk-Zeit (Tschita)", + "Asia\/Choibalsan": "Tschoibalsan-Zeit (Tschoibalsan)", + "Asia\/Colombo": "Indische Zeit (Colombo)", + "Asia\/Damascus": "Osteuropäische Zeit (Damaskus)", + "Asia\/Dhaka": "Bangladesch-Zeit (Dhaka)", + "Asia\/Dili": "Osttimor-Zeit (Dili)", + "Asia\/Dubai": "Golf-Zeit (Dubai)", + "Asia\/Dushanbe": "Tadschikistan-Zeit (Duschanbe)", + "Asia\/Famagusta": "Osteuropäische Zeit (Famagusta)", + "Asia\/Gaza": "Osteuropäische Zeit (Gaza)", + "Asia\/Hebron": "Osteuropäische Zeit (Hebron)", + "Asia\/Hong_Kong": "Hongkong-Zeit (Hongkong)", + "Asia\/Hovd": "Chowd-Zeit (Chowd)", + "Asia\/Irkutsk": "Irkutsk-Zeit (Irkutsk)", + "Asia\/Jakarta": "Westindonesische Zeit (Jakarta)", + "Asia\/Jayapura": "Ostindonesische Zeit (Jayapura)", + "Asia\/Jerusalem": "Israelische Zeit (Jerusalem)", + "Asia\/Kabul": "Afghanistan-Zeit (Kabul)", + "Asia\/Kamchatka": "Kamtschatka-Zeit (Kamtschatka)", + "Asia\/Karachi": "Pakistanische Zeit (Karatschi)", + "Asia\/Katmandu": "Nepalesische Zeit (Kathmandu)", + "Asia\/Khandyga": "Jakutsk-Zeit (Chandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk-Zeit (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malaysische Zeit (Kuala Lumpur)", + "Asia\/Kuching": "Malaysische Zeit (Kuching)", + "Asia\/Kuwait": "Arabische Zeit (Kuwait)", + "Asia\/Macau": "Chinesische Zeit (Macau)", + "Asia\/Magadan": "Magadan-Zeit (Magadan)", + "Asia\/Makassar": "Zentralindonesische Zeit (Makassar)", + "Asia\/Manila": "Philippinische Zeit (Manila)", + "Asia\/Muscat": "Golf-Zeit (Maskat)", + "Asia\/Nicosia": "Osteuropäische Zeit (Nikosia)", + "Asia\/Novokuznetsk": "Krasnojarsk-Zeit (Nowokuznetsk)", + "Asia\/Novosibirsk": "Nowosibirsk-Zeit (Nowosibirsk)", + "Asia\/Omsk": "Omsk-Zeit (Omsk)", + "Asia\/Oral": "Westkasachische Zeit (Oral)", + "Asia\/Phnom_Penh": "Indochina-Zeit (Phnom Penh)", + "Asia\/Pontianak": "Westindonesische Zeit (Pontianak)", + "Asia\/Pyongyang": "Koreanische Zeit (Pjöngjang)", + "Asia\/Qatar": "Arabische Zeit (Katar)", + "Asia\/Qostanay": "Ostkasachische Zeit (Qostanay)", + "Asia\/Qyzylorda": "Westkasachische Zeit (Qysylorda)", + "Asia\/Rangoon": "Myanmar-Zeit (Rangun)", + "Asia\/Riyadh": "Arabische Zeit (Riad)", + "Asia\/Saigon": "Indochina-Zeit (Ho-Chi-Minh-Stadt)", + "Asia\/Sakhalin": "Sachalin-Zeit (Sachalin)", + "Asia\/Samarkand": "Usbekistan-Zeit (Samarkand)", + "Asia\/Seoul": "Koreanische Zeit (Seoul)", + "Asia\/Shanghai": "Chinesische Zeit (Shanghai)", + "Asia\/Singapore": "Singapur-Zeit (Singapur)", + "Asia\/Srednekolymsk": "Magadan-Zeit (Srednekolymsk)", + "Asia\/Taipei": "Taipeh-Zeit (Taipeh)", + "Asia\/Tashkent": "Usbekistan-Zeit (Taschkent)", + "Asia\/Tbilisi": "Georgische Zeit (Tiflis)", + "Asia\/Tehran": "Iranische Zeit (Teheran)", + "Asia\/Thimphu": "Bhutan-Zeit (Thimphu)", + "Asia\/Tokyo": "Japanische Zeit (Tokio)", + "Asia\/Ulaanbaatar": "Ulaanbaatar-Zeit (Ulaanbaatar)", + "Asia\/Ust-Nera": "Wladiwostok-Zeit (Ust-Nera)", + "Asia\/Vientiane": "Indochina-Zeit (Vientiane)", + "Asia\/Vladivostok": "Wladiwostok-Zeit (Wladiwostok)", + "Asia\/Yakutsk": "Jakutsk-Zeit (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburg-Zeit (Jekaterinburg)", + "Asia\/Yerevan": "Armenische Zeit (Eriwan)", + "Atlantic\/Azores": "Azoren-Zeit (Azoren)", + "Atlantic\/Bermuda": "Atlantik-Zeit (Bermuda)", + "Atlantic\/Canary": "Westeuropäische Zeit (Kanaren)", + "Atlantic\/Cape_Verde": "Cabo-Verde-Zeit (Cabo Verde)", + "Atlantic\/Faeroe": "Westeuropäische Zeit (Färöer)", + "Atlantic\/Madeira": "Westeuropäische Zeit (Madeira)", + "Atlantic\/Reykjavik": "Mittlere Greenwich-Zeit (Reyk­ja­vík)", + "Atlantic\/South_Georgia": "Südgeorgische Zeit (Südgeorgien)", + "Atlantic\/St_Helena": "Mittlere Greenwich-Zeit (St. Helena)", + "Atlantic\/Stanley": "Falklandinseln-Zeit (Stanley)", + "Australia\/Adelaide": "Zentralaustralische Zeit (Adelaide)", + "Australia\/Brisbane": "Ostaustralische Zeit (Brisbane)", + "Australia\/Broken_Hill": "Zentralaustralische Zeit (Broken Hill)", + "Australia\/Currie": "Ostaustralische Zeit (Currie)", + "Australia\/Darwin": "Zentralaustralische Zeit (Darwin)", + "Australia\/Eucla": "Zentral-\/Westaustralische Zeit (Eucla)", + "Australia\/Hobart": "Ostaustralische Zeit (Hobart)", + "Australia\/Lindeman": "Ostaustralische Zeit (Lindeman)", + "Australia\/Lord_Howe": "Lord-Howe-Zeit (Lord Howe)", + "Australia\/Melbourne": "Ostaustralische Zeit (Melbourne)", + "Australia\/Perth": "Westaustralische Zeit (Perth)", + "Australia\/Sydney": "Ostaustralische Zeit (Sydney)", + "CST6CDT": "Nordamerikanische Inlandzeit", + "EST5EDT": "Nordamerikanische Ostküstenzeit", + "Etc\/GMT": "Mittlere Greenwich-Zeit", + "Etc\/UTC": "Koordinierte Weltzeit", + "Europe\/Amsterdam": "Mitteleuropäische Zeit (Amsterdam)", + "Europe\/Andorra": "Mitteleuropäische Zeit (Andorra)", + "Europe\/Astrakhan": "Moskauer Zeit (Astrachan)", + "Europe\/Athens": "Osteuropäische Zeit (Athen)", + "Europe\/Belgrade": "Mitteleuropäische Zeit (Belgrad)", + "Europe\/Berlin": "Mitteleuropäische Zeit (Berlin)", + "Europe\/Bratislava": "Mitteleuropäische Zeit (Bratislava)", + "Europe\/Brussels": "Mitteleuropäische Zeit (Brüssel)", + "Europe\/Bucharest": "Osteuropäische Zeit (Bukarest)", + "Europe\/Budapest": "Mitteleuropäische Zeit (Budapest)", + "Europe\/Busingen": "Mitteleuropäische Zeit (Büsingen)", + "Europe\/Chisinau": "Osteuropäische Zeit (Kischinau)", + "Europe\/Copenhagen": "Mitteleuropäische Zeit (Kopenhagen)", + "Europe\/Dublin": "Mittlere Greenwich-Zeit (Dublin)", + "Europe\/Gibraltar": "Mitteleuropäische Zeit (Gibraltar)", + "Europe\/Guernsey": "Mittlere Greenwich-Zeit (Guernsey)", + "Europe\/Helsinki": "Osteuropäische Zeit (Helsinki)", + "Europe\/Isle_of_Man": "Mittlere Greenwich-Zeit (Isle of Man)", + "Europe\/Jersey": "Mittlere Greenwich-Zeit (Jersey)", + "Europe\/Kaliningrad": "Osteuropäische Zeit (Kaliningrad)", + "Europe\/Kiev": "Osteuropäische Zeit (Kiew)", + "Europe\/Lisbon": "Westeuropäische Zeit (Lissabon)", + "Europe\/Ljubljana": "Mitteleuropäische Zeit (Ljubljana)", + "Europe\/London": "Mittlere Greenwich-Zeit (London)", + "Europe\/Luxembourg": "Mitteleuropäische Zeit (Luxemburg)", + "Europe\/Madrid": "Mitteleuropäische Zeit (Madrid)", + "Europe\/Malta": "Mitteleuropäische Zeit (Malta)", + "Europe\/Mariehamn": "Osteuropäische Zeit (Mariehamn)", + "Europe\/Minsk": "Moskauer Zeit (Minsk)", + "Europe\/Monaco": "Mitteleuropäische Zeit (Monaco)", + "Europe\/Moscow": "Moskauer Zeit (Moskau)", + "Europe\/Oslo": "Mitteleuropäische Zeit (Oslo)", + "Europe\/Paris": "Mitteleuropäische Zeit (Paris)", + "Europe\/Podgorica": "Mitteleuropäische Zeit (Podgorica)", + "Europe\/Prague": "Mitteleuropäische Zeit (Prag)", + "Europe\/Riga": "Osteuropäische Zeit (Riga)", + "Europe\/Rome": "Mitteleuropäische Zeit (Rom)", + "Europe\/Samara": "Samara-Zeit (Samara)", + "Europe\/San_Marino": "Mitteleuropäische Zeit (San Marino)", + "Europe\/Sarajevo": "Mitteleuropäische Zeit (Sarajevo)", + "Europe\/Saratov": "Moskauer Zeit (Saratow)", + "Europe\/Simferopol": "Moskauer Zeit (Simferopol)", + "Europe\/Skopje": "Mitteleuropäische Zeit (Skopje)", + "Europe\/Sofia": "Osteuropäische Zeit (Sofia)", + "Europe\/Stockholm": "Mitteleuropäische Zeit (Stockholm)", + "Europe\/Tallinn": "Osteuropäische Zeit (Tallinn)", + "Europe\/Tirane": "Mitteleuropäische Zeit (Tirana)", + "Europe\/Ulyanovsk": "Moskauer Zeit (Uljanowsk)", + "Europe\/Uzhgorod": "Osteuropäische Zeit (Uschgorod)", + "Europe\/Vaduz": "Mitteleuropäische Zeit (Vaduz)", + "Europe\/Vatican": "Mitteleuropäische Zeit (Vatikan)", + "Europe\/Vienna": "Mitteleuropäische Zeit (Wien)", + "Europe\/Vilnius": "Osteuropäische Zeit (Vilnius)", + "Europe\/Volgograd": "Wolgograd-Zeit (Wolgograd)", + "Europe\/Warsaw": "Mitteleuropäische Zeit (Warschau)", + "Europe\/Zagreb": "Mitteleuropäische Zeit (Zagreb)", + "Europe\/Zaporozhye": "Osteuropäische Zeit (Saporischja)", + "Europe\/Zurich": "Mitteleuropäische Zeit (Zürich)", + "Indian\/Antananarivo": "Ostafrikanische Zeit (Antananarivo)", + "Indian\/Chagos": "Indischer Ozean-Zeit (Chagos)", + "Indian\/Christmas": "Weihnachtsinsel-Zeit (Weihnachtsinsel)", + "Indian\/Cocos": "Kokosinseln-Zeit (Cocos)", + "Indian\/Comoro": "Ostafrikanische Zeit (Komoren)", + "Indian\/Kerguelen": "Französische Süd- und Antarktisgebiete-Zeit (Kerguelen)", + "Indian\/Mahe": "Seychellen-Zeit (Mahe)", + "Indian\/Maldives": "Malediven-Zeit (Malediven)", + "Indian\/Mauritius": "Mauritius-Zeit (Mauritius)", + "Indian\/Mayotte": "Ostafrikanische Zeit (Mayotte)", + "Indian\/Reunion": "Réunion-Zeit (Réunion)", + "MST7MDT": "Rocky-Mountain-Zeit", + "PST8PDT": "Nordamerikanische Westküstenzeit", + "Pacific\/Apia": "Apia-Zeit (Apia)", + "Pacific\/Auckland": "Neuseeland-Zeit (Auckland)", + "Pacific\/Bougainville": "Papua-Neuguinea-Zeit (Bougainville)", + "Pacific\/Chatham": "Chatham-Zeit (Chatham)", + "Pacific\/Easter": "Osterinsel-Zeit (Osterinsel)", + "Pacific\/Efate": "Vanuatu-Zeit (Efate)", + "Pacific\/Enderbury": "Phoenixinseln-Zeit (Enderbury)", + "Pacific\/Fakaofo": "Tokelau-Zeit (Fakaofo)", + "Pacific\/Fiji": "Fidschi-Zeit (Fidschi)", + "Pacific\/Funafuti": "Tuvalu-Zeit (Funafuti)", + "Pacific\/Galapagos": "Galapagos-Zeit (Galapagos)", + "Pacific\/Gambier": "Gambier-Zeit (Gambier)", + "Pacific\/Guadalcanal": "Salomonen-Zeit (Guadalcanal)", + "Pacific\/Guam": "Chamorro-Zeit (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleuten-Zeit (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleuten-Zeit (Johnston)", + "Pacific\/Kiritimati": "Linieninseln-Zeit (Kiritimati)", + "Pacific\/Kosrae": "Kosrae-Zeit (Kosrae)", + "Pacific\/Kwajalein": "Marshallinseln-Zeit (Kwajalein)", + "Pacific\/Majuro": "Marshallinseln-Zeit (Majuro)", + "Pacific\/Marquesas": "Marquesas-Zeit (Marquesas)", + "Pacific\/Midway": "Samoa-Zeit (Midway)", + "Pacific\/Nauru": "Nauru-Zeit (Nauru)", + "Pacific\/Niue": "Niue-Zeit (Niue)", + "Pacific\/Norfolk": "Norfolkinsel-Zeit (Norfolk)", + "Pacific\/Noumea": "Neukaledonische Zeit (Noumea)", + "Pacific\/Pago_Pago": "Samoa-Zeit (Pago Pago)", + "Pacific\/Palau": "Palau-Zeit (Palau)", + "Pacific\/Pitcairn": "Pitcairninseln-Zeit (Pitcairn)", + "Pacific\/Ponape": "Ponape-Zeit (Pohnpei)", + "Pacific\/Port_Moresby": "Papua-Neuguinea-Zeit (Port Moresby)", + "Pacific\/Rarotonga": "Cookinseln-Zeit (Rarotonga)", + "Pacific\/Saipan": "Chamorro-Zeit (Saipan)", + "Pacific\/Tahiti": "Tahiti-Zeit (Tahiti)", + "Pacific\/Tarawa": "Gilbert-Inseln-Zeit (Tarawa)", + "Pacific\/Tongatapu": "Tonganische Zeit (Tongatapu)", + "Pacific\/Truk": "Chuuk-Zeit (Chuuk)", + "Pacific\/Wake": "Wake-Insel-Zeit (Wake)", + "Pacific\/Wallis": "Wallis-und-Futuna-Zeit (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/de_CH.json b/src/Symfony/Component/Intl/Resources/data/timezones/de_CH.json new file mode 100644 index 0000000000000..176ca7c1123bc --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/de_CH.json @@ -0,0 +1,7 @@ +{ + "Version": "2.1.47.86", + "Names": { + "Asia\/Brunei": "Brunei-Zeit (Brunei)", + "Pacific\/Guadalcanal": "Salomoninseln-Zeit (Guadalcanal)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/dz.json b/src/Symfony/Component/Intl/Resources/data/timezones/dz.json new file mode 100644 index 0000000000000..a1d49c2db7073 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/dz.json @@ -0,0 +1,354 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Abidjan)", + "Africa\/Accra": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Accra)", + "Africa\/Addis_Ababa": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Addis Ababa)", + "Africa\/Algiers": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Algiers)", + "Africa\/Asmera": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Asmara)", + "Africa\/Bamako": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Bamako)", + "Africa\/Bangui": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Bangui)", + "Africa\/Banjul": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Banjul)", + "Africa\/Bissau": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Bissau)", + "Africa\/Blantyre": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Blantyre)", + "Africa\/Brazzaville": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Brazzaville)", + "Africa\/Bujumbura": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Bujumbura)", + "Africa\/Cairo": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཀཱའི་རོ)", + "Africa\/Casablanca": "ནུབ་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Casablanca)", + "Africa\/Ceuta": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Ceuta)", + "Africa\/Conakry": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Conakry)", + "Africa\/Dakar": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (ཌཱ་ཀར)", + "Africa\/Dar_es_Salaam": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Dar es Salaam)", + "Africa\/Djibouti": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Djibouti)", + "Africa\/Douala": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Douala)", + "Africa\/El_Aaiun": "ནུབ་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (El Aaiun)", + "Africa\/Freetown": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Freetown)", + "Africa\/Gaborone": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Gaborone)", + "Africa\/Harare": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Harare)", + "Africa\/Johannesburg": "ལྷོ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Johannesburg)", + "Africa\/Juba": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Juba)", + "Africa\/Kampala": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Kampala)", + "Africa\/Khartoum": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (ཁཱར་ཊུམ)", + "Africa\/Kigali": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Kigali)", + "Africa\/Kinshasa": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Kinshasa)", + "Africa\/Lagos": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Lagos)", + "Africa\/Libreville": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Libreville)", + "Africa\/Lome": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (ལོ་མེ)", + "Africa\/Luanda": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Luanda)", + "Africa\/Lubumbashi": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Lubumbashi)", + "Africa\/Lusaka": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Lusaka)", + "Africa\/Malabo": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Malabo)", + "Africa\/Maputo": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Maputo)", + "Africa\/Maseru": "ལྷོ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Maseru)", + "Africa\/Mbabane": "ལྷོ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Mbabane)", + "Africa\/Mogadishu": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Mogadishu)", + "Africa\/Monrovia": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Monrovia)", + "Africa\/Nairobi": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Nairobi)", + "Africa\/Ndjamena": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Ndjamena)", + "Africa\/Niamey": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Niamey)", + "Africa\/Nouakchott": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Nouakchott)", + "Africa\/Ouagadougou": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Ouagadougou)", + "Africa\/Porto-Novo": "ནུབ་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Porto-Novo)", + "Africa\/Sao_Tome": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Sao Tome)", + "Africa\/Tripoli": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཏྲི་པོ་ལི)", + "Africa\/Tunis": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཊུ་ནིས྄)", + "Africa\/Windhoek": "དབུས་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Windhoek)", + "America\/Adak": "ཧ་ཝའི་-ཨེ་ལིའུ་ཤེན་ཆུ་ཚོད (Adak)", + "America\/Anchorage": "ཨ་ལསི་ཀ་ཆུ་ཚོད (Anchorage)", + "America\/Anguilla": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Anguilla)", + "America\/Antigua": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (ཨན་ཊི་གུ་ཝ་)", + "America\/Araguaina": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Araguaina)", + "America\/Argentina\/La_Rioja": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Rio Gallegos)", + "America\/Argentina\/Salta": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Salta)", + "America\/Argentina\/San_Juan": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (San Juan)", + "America\/Argentina\/San_Luis": "ནུབ་ཕྱོགས་ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (San Luis)", + "America\/Argentina\/Tucuman": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Tucuman)", + "America\/Argentina\/Ushuaia": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Ushuaia)", + "America\/Aruba": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Aruba)", + "America\/Asuncion": "པ་ར་གུ་ཝའི་ཆུ་ཚོད (Asuncion)", + "America\/Bahia": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Bahia)", + "America\/Bahia_Banderas": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Bahia Banderas)", + "America\/Barbados": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (བྷར་བེ་ཌོས)", + "America\/Belem": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Belem)", + "America\/Belize": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (བྷེ་ལིཛ)", + "America\/Blanc-Sablon": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Blanc-Sablon)", + "America\/Boa_Vista": "ཨེ་མ་ཛཱོན་ཆུ་ཚོད (Boa Vista)", + "America\/Bogota": "ཀོ་ལོམ་བྷི་ཡ་ཆུ་ཚོད (བྷོ་ག་ཊ)", + "America\/Boise": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Boise)", + "America\/Buenos_Aires": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Buenos Aires)", + "America\/Cambridge_Bay": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (ཀེམ་བིརིདཆ་ བའེ)", + "America\/Campo_Grande": "ཨེ་མ་ཛཱོན་ཆུ་ཚོད (Campo Grande)", + "America\/Cancun": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Cancun)", + "America\/Caracas": "བེ་ནི་ཛུ་ཝེ་ལ་ཆུ་ཚོད (Caracas)", + "America\/Catamarca": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Catamarca)", + "America\/Cayenne": "ཕིརེནཅ་གི་ཡ་ན་ཆུ་ཚོད (Cayenne)", + "America\/Cayman": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Cayman)", + "America\/Chicago": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (ཅི་ཀཱ་གོ)", + "America\/Coral_Harbour": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (ཨ་ཏི་ཀོ་ཀཱན)", + "America\/Cordoba": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Cordoba)", + "America\/Costa_Rica": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (ཀོས་ཊ་རི་ཀ)", + "America\/Creston": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Creston)", + "America\/Cuiaba": "ཨེ་མ་ཛཱོན་ཆུ་ཚོད (Cuiaba)", + "America\/Curacao": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Curacao)", + "America\/Danmarkshavn": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Danmarkshavn)", + "America\/Dawson": "བྱང་ཨ་མི་རི་ཀ་པེ་སི་ཕིག་ཆུ་ཚོད (དའུ་སཱོན)", + "America\/Dawson_Creek": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (དའུ་སཱོན་ ཀིརིཀ)", + "America\/Denver": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Denver)", + "America\/Detroit": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Detroit)", + "America\/Dominica": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (ཌོ་མི་ནི་ཀ)", + "America\/Edmonton": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (ཨེཌ་མཱོན་ཊོན)", + "America\/El_Salvador": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (ཨེལ་ སཱལ་བ་ཌོ)", + "America\/Fort_Nelson": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Fort Nelson)", + "America\/Fortaleza": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Fortaleza)", + "America\/Glace_Bay": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Glace Bay)", + "America\/Godthab": "ནུབ་ཕྱོགས་གིརིན་ལེནཌ་ཆུ་ཚོད (Nuuk)", + "America\/Goose_Bay": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (གཱུསི་ བའེ)", + "America\/Grand_Turk": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Grand Turk)", + "America\/Grenada": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Grenada)", + "America\/Guadeloupe": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Guadeloupe)", + "America\/Guatemala": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (གྷོ་ཊ་མ་ལ)", + "America\/Guayaquil": "ཨེ་ཀུ་ཌཽ་ཆུ་ཚོད (Guayaquil)", + "America\/Guyana": "གུ་ཡ་ན་ཆུ་ཚོད (Guyana)", + "America\/Halifax": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (ཧ་ལི་ཕེགསི)", + "America\/Havana": "ཀིའུ་བྷ་ཆུ་ཚོད (Havana)", + "America\/Indiana\/Knox": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Knox, Indiana)", + "America\/Indiana\/Marengo": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Tell City, Indiana)", + "America\/Indiana\/Vevay": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Winamac, Indiana)", + "America\/Indianapolis": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Indianapolis)", + "America\/Inuvik": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (ཨི་ནུ་ཝིཀ)", + "America\/Iqaluit": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Iqaluit)", + "America\/Jamaica": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Jamaica)", + "America\/Jujuy": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Jujuy)", + "America\/Juneau": "ཨ་ལསི་ཀ་ཆུ་ཚོད (Juneau)", + "America\/Kentucky\/Monticello": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Monticello, Kentucky)", + "America\/Kralendijk": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Kralendijk)", + "America\/La_Paz": "བྷོ་ལི་བི་ཡ་ཆུ་ཚོད (ལ་པཱཛ྄)", + "America\/Lima": "པ་རུ་ཆུ་ཚོད (Lima)", + "America\/Los_Angeles": "བྱང་ཨ་མི་རི་ཀ་པེ་སི་ཕིག་ཆུ་ཚོད (Los Angeles)", + "America\/Louisville": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Louisville)", + "America\/Lower_Princes": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Lower Prince’s Quarter)", + "America\/Maceio": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Maceio)", + "America\/Managua": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Managua)", + "America\/Manaus": "ཨེ་མ་ཛཱོན་ཆུ་ཚོད (Manaus)", + "America\/Marigot": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Marigot)", + "America\/Martinique": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Martinique)", + "America\/Matamoros": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Matamoros)", + "America\/Mendoza": "ཨར་ཇེན་ཊི་ན་ཆུ་ཚོད (Mendoza)", + "America\/Menominee": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Menominee)", + "America\/Merida": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Merida)", + "America\/Metlakatla": "ཨ་ལསི་ཀ་ཆུ་ཚོད (Metlakatla)", + "America\/Mexico_City": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (མེཀ་སི་ཀོ་ སི་ཊི)", + "America\/Miquelon": "པའི་རི་དང་མི་ཀི་ལཱོན་ཆུ་ཚོད (Miquelon)", + "America\/Moncton": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (མཱོངཀ་ཊོན)", + "America\/Monterrey": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Monterrey)", + "America\/Montevideo": "ཡུ་རུ་གུ་ཝཱའི་ཆུ་ཚོད (Montevideo)", + "America\/Montserrat": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Montserrat)", + "America\/Nassau": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Nassau)", + "America\/New_York": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (New York)", + "America\/Nipigon": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (ནི་པི་གཱོན)", + "America\/Nome": "ཨ་ལསི་ཀ་ཆུ་ཚོད (Nome)", + "America\/Noronha": "ཕར་ནེན་ཌོ་ ཌི་ ནོ་རཱོན་ཧ་ཆུ་ཚོད (Noronha)", + "America\/North_Dakota\/Beulah": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (New Salem, North Dakota)", + "America\/Ojinaga": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Ojinaga)", + "America\/Panama": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (པ་ན་མ)", + "America\/Pangnirtung": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (པེང་ནིར་ཏུང)", + "America\/Paramaribo": "སུ་རི་ནཱམ་ཆུ་ཚོད (Paramaribo)", + "America\/Phoenix": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Phoenix)", + "America\/Port-au-Prince": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (Port-au-Prince)", + "America\/Port_of_Spain": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Port of Spain)", + "America\/Porto_Velho": "ཨེ་མ་ཛཱོན་ཆུ་ཚོད (Porto Velho)", + "America\/Puerto_Rico": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Puerto Rico)", + "America\/Punta_Arenas": "ཅི་ལི་ཆུ་ཚོད (Punta Arenas)", + "America\/Rainy_River": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (རཱེ་ནི་རི་ཝར)", + "America\/Rankin_Inlet": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (རེན་ཀིན་ ཨིན་ལེཊ)", + "America\/Recife": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Recife)", + "America\/Regina": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (རི་ཇི་ན)", + "America\/Resolute": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (རི་སོ་ལིའུཊ)", + "America\/Santarem": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Santarem)", + "America\/Santiago": "ཅི་ལི་ཆུ་ཚོད (སཱན་ཊི་ཡ་གྷོ)", + "America\/Santo_Domingo": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (སཱན་ཊོ་ ཌོ་མིང་གྷོ)", + "America\/Sao_Paulo": "བྲ་ཛི་ལི་ཡ་ཆུ་ཚོད (Sao Paulo)", + "America\/Scoresbysund": "ཤར་ཕྱོགས་གིརིན་ལེནཌ་ཆུ་ཚོད (Ittoqqortoormiit)", + "America\/Sitka": "ཨ་ལསི་ཀ་ཆུ་ཚོད (Sitka)", + "America\/St_Barthelemy": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (St. Barthelemy)", + "America\/St_Johns": "ནིའུ་ཕའུནཌ་ལེནཌ་ཆུ་ཚོད (ཨིསི་ཊེཊ་ ཇཱོནསི་)", + "America\/St_Kitts": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (St. Kitts)", + "America\/St_Lucia": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (St. Lucia)", + "America\/St_Thomas": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (St. Thomas)", + "America\/St_Vincent": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (St. Vincent)", + "America\/Swift_Current": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (སུ་ཨིཕཊ་ཀ་རེནཊ)", + "America\/Tegucigalpa": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (ཊེ་གུ་སི་གཱལ་པ)", + "America\/Thule": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Thule)", + "America\/Thunder_Bay": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (ཐན་ཌར་ བའེ)", + "America\/Tijuana": "བྱང་ཨ་མི་རི་ཀ་པེ་སི་ཕིག་ཆུ་ཚོད (ཏིའུ་ཝ་ན)", + "America\/Toronto": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད (ཊོ་རོན་ཊོ)", + "America\/Tortola": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (Tortola)", + "America\/Vancouver": "བྱང་ཨ་མི་རི་ཀ་པེ་སི་ཕིག་ཆུ་ཚོད (Vancouver)", + "America\/Whitehorse": "བྱང་ཨ་མི་རི་ཀ་པེ་སི་ཕིག་ཆུ་ཚོད (Whitehorse)", + "America\/Winnipeg": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད (Winnipeg)", + "America\/Yakutat": "ཨ་ལསི་ཀ་ཆུ་ཚོད (ཡ་ཀུ་ཏཏ)", + "America\/Yellowknife": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད (Yellowknife)", + "Antarctica\/Casey": "ནུབ་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Casey)", + "Antarctica\/McMurdo": "ནིའུ་ཛི་ལེནཌ་ཆུ་ཚོད (McMurdo)", + "Antarctica\/Palmer": "ཅི་ལི་ཆུ་ཚོད (Palmer)", + "Antarctica\/Troll": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Troll)", + "Arctic\/Longyearbyen": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Longyearbyen)", + "Asia\/Aden": "ཨ་རེ་བྷི་ཡན་ཆུ་ཚོད (Aden)", + "Asia\/Amman": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Amman)", + "Asia\/Baghdad": "ཨ་རེ་བྷི་ཡན་ཆུ་ཚོད (Baghdad)", + "Asia\/Bahrain": "ཨ་རེ་བྷི་ཡན་ཆུ་ཚོད (བྷ་རེན་)", + "Asia\/Baku": "ཨ་ཛར་བྷའི་ཇཱན་ཆུ་ཚོད (Baku)", + "Asia\/Bangkok": "ཨིན་ཌོ་ཅཱའི་ན་ཆུ་ཚོད (Bangkok)", + "Asia\/Beirut": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Beirut)", + "Asia\/Calcutta": "རྒྱ་གར་ཆུ་ཚོད (Kolkata)", + "Asia\/Chita": "ཡ་ཀུཙིཀི་ཆུ་ཚོད (Chita)", + "Asia\/Colombo": "རྒྱ་གར་ཆུ་ཚོད (Colombo)", + "Asia\/Damascus": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Damascus)", + "Asia\/Dhaka": "བངྒ་ལ་དེཤ་ཆུ་ཚོད (Dhaka)", + "Asia\/Dubai": "གཱལཕི་ཆུ་ཚོད (Dubai)", + "Asia\/Famagusta": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Famagusta)", + "Asia\/Gaza": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Gaza)", + "Asia\/Hebron": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Hebron)", + "Asia\/Irkutsk": "ཨར་ཀུཙི་ཆུ་ཚོད (Irkutsk)", + "Asia\/Jakarta": "ནུབ་ཕྱོགས་ཨིན་ཌོ་ནེ་ཤི་ཡ་ཆུ་ཚོད (Jakarta)", + "Asia\/Jayapura": "ཤར་ཕྱོགས་ཨིན་ཌོ་ནེ་ཤི་ཡ་ཆུ་ཚོད (Jayapura)", + "Asia\/Jerusalem": "ཨིས་རེལ་ཆུ་ཚོད (Jerusalem)", + "Asia\/Kabul": "ཨཕ་ག་ནི་ས྄ཏཱནཆུ་ཚོད (Kabul)", + "Asia\/Karachi": "པ་ཀི་ས྄ཏཱན་ཆུ་ཚོད (Karachi)", + "Asia\/Katmandu": "ནེ་པཱལ་ཆུ་ཚོད (Kathmandu)", + "Asia\/Khandyga": "ཡ་ཀུཙིཀི་ཆུ་ཚོད (Khandyga)", + "Asia\/Krasnoyarsk": "ཀརསི་ནོ་ཡརསཀི་ཆུ་ཚོད (Krasnoyarsk)", + "Asia\/Kuwait": "ཨ་རེ་བྷི་ཡན་ཆུ་ཚོད (Kuwait)", + "Asia\/Macau": "རྒྱ་ནག་ཆུ་ཚོད (Macao)", + "Asia\/Magadan": "མ་གྷ་དཱན་ཆུ་ཚོད (Magadan)", + "Asia\/Makassar": "དབུས་ཕྱོགས་ཨིན་ཌོ་ནེ་ཤི་ཡ་ཆུ་ཚོད (Makassar)", + "Asia\/Muscat": "གཱལཕི་ཆུ་ཚོད (Muscat)", + "Asia\/Nicosia": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Nicosia)", + "Asia\/Novokuznetsk": "ཀརསི་ནོ་ཡརསཀི་ཆུ་ཚོད (Novokuznetsk)", + "Asia\/Novosibirsk": "ནོ་བོ་སི་བིརསཀི་ཆུ་ཚོད (Novosibirsk)", + "Asia\/Omsk": "ཨོམསཀི་ཆུ་ཚོད (Omsk)", + "Asia\/Phnom_Penh": "ཨིན་ཌོ་ཅཱའི་ན་ཆུ་ཚོད (Phnom Penh)", + "Asia\/Pontianak": "ནུབ་ཕྱོགས་ཨིན་ཌོ་ནེ་ཤི་ཡ་ཆུ་ཚོད (Pontianak)", + "Asia\/Pyongyang": "ཀོ་རི་ཡ་ཆུ་ཚོད (Pyongyang)", + "Asia\/Qatar": "ཨ་རེ་བྷི་ཡན་ཆུ་ཚོད (Qatar)", + "Asia\/Riyadh": "ཨ་རེ་བྷི་ཡན་ཆུ་ཚོད (Riyadh)", + "Asia\/Saigon": "ཨིན་ཌོ་ཅཱའི་ན་ཆུ་ཚོད (Ho Chi Minh)", + "Asia\/Sakhalin": "ས་ཁ་ལིན་ཆུ་ཚོད (Sakhalin)", + "Asia\/Seoul": "ཀོ་རི་ཡ་ཆུ་ཚོད (Seoul)", + "Asia\/Shanghai": "རྒྱ་ནག་ཆུ་ཚོད (Shanghai)", + "Asia\/Srednekolymsk": "མ་གྷ་དཱན་ཆུ་ཚོད (Srednekolymsk)", + "Asia\/Tbilisi": "ཇཽ་ཇཱ་ཆུ་ཚོད (Tbilisi)", + "Asia\/Tehran": "ཨི་རཱན་ཆུ་ཚོད (Tehran)", + "Asia\/Thimphu": "འབྲུག་ཡུལ་ཆུ་ཚོད (ཐིམ་ཕུག)", + "Asia\/Tokyo": "ཇ་པཱན་ཆུ་ཚོད (Tokyo)", + "Asia\/Ust-Nera": "བ་ལ་ཌི་བོསི་ཏོཀ་ཆུ་ཚོད (Ust-Nera)", + "Asia\/Vientiane": "ཨིན་ཌོ་ཅཱའི་ན་ཆུ་ཚོད (Vientiane)", + "Asia\/Vladivostok": "བ་ལ་ཌི་བོསི་ཏོཀ་ཆུ་ཚོད (Vladivostok)", + "Asia\/Yakutsk": "ཡ་ཀུཙིཀི་ཆུ་ཚོད (Yakutsk)", + "Asia\/Yekaterinburg": "ཡེ་ཀ་ཏེ་རིན་བརག་ཆུ་ཚོད (Yekaterinburg)", + "Asia\/Yerevan": "ཨར་མི་ནི་ཡ་ཆུ་ཚོད (Yerevan)", + "Atlantic\/Azores": "ཨེ་ཛོརས་ཆུ་ཚོད (Azores)", + "Atlantic\/Bermuda": "ཨེཊ་ལེན་ཊིཀ་ཆུ་ཚོད (བར་མུ་ད)", + "Atlantic\/Canary": "ནུབ་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Canary)", + "Atlantic\/Cape_Verde": "ཀེཔ་བཱཌ་ཆུ་ཚོད (Cape Verde)", + "Atlantic\/Faeroe": "ནུབ་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཕཱའེ་རོ་)", + "Atlantic\/Madeira": "ནུབ་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Madeira)", + "Atlantic\/Reykjavik": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Reykjavik)", + "Atlantic\/St_Helena": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (St. Helena)", + "Atlantic\/Stanley": "ཕལཀ་ལེནཌ་ཨཱའི་ལེནཌས་ཆུ་ཚོད (Stanley)", + "Australia\/Adelaide": "དབུས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Adelaide)", + "Australia\/Brisbane": "ཤར་ཕྱོགས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Brisbane)", + "Australia\/Broken_Hill": "དབུས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Broken Hill)", + "Australia\/Currie": "ཤར་ཕྱོགས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Currie)", + "Australia\/Darwin": "དབུས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Darwin)", + "Australia\/Eucla": "བུས་ནུབ་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Eucla)", + "Australia\/Hobart": "ཤར་ཕྱོགས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Hobart)", + "Australia\/Lindeman": "ཤར་ཕྱོགས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Lindeman)", + "Australia\/Melbourne": "ཤར་ཕྱོགས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Melbourne)", + "Australia\/Perth": "ནུབ་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Perth)", + "Australia\/Sydney": "ཤར་ཕྱོགས་ཕྱོགས་ཨཱོས་ཊྲེལ་ལི་ཡ་ཆུ་ཚོད (Sydney)", + "CST6CDT": "བྱང་ཨ་མི་རི་ཀ་དབུས་ཕྱོགས་ཆུ་ཚོད", + "EST5EDT": "བྱང་ཨ་མི་རི་ཀ་ཤར་ཕྱོགས་ཆུ་ཚོད", + "Etc\/GMT": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད", + "Europe\/Amsterdam": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Amsterdam)", + "Europe\/Andorra": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Andorra)", + "Europe\/Astrakhan": "མཽས་ཀོ་ཆུ་ཚོད (Astrakhan)", + "Europe\/Athens": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཨེ་ཐེནས་)", + "Europe\/Belgrade": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Belgrade)", + "Europe\/Berlin": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Berlin)", + "Europe\/Bratislava": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Bratislava)", + "Europe\/Brussels": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Brussels)", + "Europe\/Bucharest": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Bucharest)", + "Europe\/Budapest": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Budapest)", + "Europe\/Busingen": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Busingen)", + "Europe\/Chisinau": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Chisinau)", + "Europe\/Copenhagen": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཀོ་པེན་ཧེ་གེན)", + "Europe\/Dublin": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Dublin)", + "Europe\/Gibraltar": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Gibraltar)", + "Europe\/Guernsey": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Guernsey)", + "Europe\/Helsinki": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཧེལ་སིང་ཀི)", + "Europe\/Isle_of_Man": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Isle of Man)", + "Europe\/Jersey": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (Jersey)", + "Europe\/Kaliningrad": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Kaliningrad)", + "Europe\/Kiev": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Kiev)", + "Europe\/Lisbon": "ནུབ་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Lisbon)", + "Europe\/Ljubljana": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Ljubljana)", + "Europe\/London": "གིརིན་ཝིཆ་ལུ་ཡོད་པའི་ཆུ་ཚོད (London)", + "Europe\/Luxembourg": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Luxembourg)", + "Europe\/Madrid": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Madrid)", + "Europe\/Malta": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Malta)", + "Europe\/Mariehamn": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Mariehamn)", + "Europe\/Minsk": "མཽས་ཀོ་ཆུ་ཚོད (Minsk)", + "Europe\/Monaco": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Monaco)", + "Europe\/Moscow": "མཽས་ཀོ་ཆུ་ཚོད (Moscow)", + "Europe\/Oslo": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Oslo)", + "Europe\/Paris": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Paris)", + "Europe\/Podgorica": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Podgorica)", + "Europe\/Prague": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Prague)", + "Europe\/Riga": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Riga)", + "Europe\/Rome": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Rome)", + "Europe\/San_Marino": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (San Marino)", + "Europe\/Sarajevo": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Sarajevo)", + "Europe\/Saratov": "མཽས་ཀོ་ཆུ་ཚོད (Saratov)", + "Europe\/Simferopol": "མཽས་ཀོ་ཆུ་ཚོད (Simferopol)", + "Europe\/Skopje": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Skopje)", + "Europe\/Sofia": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Sofia)", + "Europe\/Stockholm": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Stockholm)", + "Europe\/Tallinn": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (ཊཱ་ལཱིན)", + "Europe\/Tirane": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Tirane)", + "Europe\/Ulyanovsk": "མཽས་ཀོ་ཆུ་ཚོད (Ulyanovsk)", + "Europe\/Uzhgorod": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Uzhgorod)", + "Europe\/Vaduz": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Vaduz)", + "Europe\/Vatican": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Vatican)", + "Europe\/Vienna": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Vienna)", + "Europe\/Vilnius": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Vilnius)", + "Europe\/Volgograd": "བཱོལ་གོ་གིརེཌ་ཆུ་ཚོད (Volgograd)", + "Europe\/Warsaw": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Warsaw)", + "Europe\/Zagreb": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Zagreb)", + "Europe\/Zaporozhye": "ཤར་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Zaporozhye)", + "Europe\/Zurich": "དབུས་ཕྱོགས་ཡུ་རོ་པེན་ཆུ་ཚོད (Zurich)", + "Indian\/Antananarivo": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Antananarivo)", + "Indian\/Chagos": "རྒྱ་གར་གྱི་རྒྱ་མཚོ་ཆུ་ཚོད (Chagos)", + "Indian\/Christmas": "ཁི་རིསྟ་མེས་མཚོ་གླིང་ཆུ་ཚོད (Christmas)", + "Indian\/Comoro": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Comoro)", + "Indian\/Mahe": "སེ་ཤཱལས་ཆུ་ཚོད (Mahe)", + "Indian\/Maldives": "མཱལ་དིབས་ཆུ་ཚོད (Maldives)", + "Indian\/Mauritius": "མོ་རི་ཤཱས་ཆུ་ཚོད (Mauritius)", + "Indian\/Mayotte": "ཤར་ཕྱོགས་ཨཕ་རི་ཀཱ་ཆུ་ཚོད (Mayotte)", + "Indian\/Reunion": "རི་ཡུ་ནི་ཡཱན་ཆུ་ཚོད (Reunion)", + "MST7MDT": "བྱང་ཨ་མི་རི་ཀ་མའུ་ཊེན་ཆུ་ཚོད", + "PST8PDT": "བྱང་ཨ་མི་རི་ཀ་པེ་སི་ཕིག་ཆུ་ཚོད", + "Pacific\/Auckland": "ནིའུ་ཛི་ལེནཌ་ཆུ་ཚོད (Auckland)", + "Pacific\/Easter": "ཨིསི་ཊར་ཨཱའི་ལེནཌ་ཆུ་ཚོད (Easter)", + "Pacific\/Galapagos": "ག་ལ་པ་གོསི་ཆུ་ཚོད (Galapagos)", + "Pacific\/Honolulu": "ཧ་ཝའི་-ཨེ་ལིའུ་ཤེན་ཆུ་ཚོད (Honolulu)", + "Pacific\/Johnston": "ཧ་ཝའི་-ཨེ་ལིའུ་ཤེན་ཆུ་ཚོད (Johnston)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ee.json b/src/Symfony/Component/Intl/Resources/data/timezones/ee.json new file mode 100644 index 0000000000000..1e2d0c558200e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ee.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "Greenwich gaƒoƒo me (Abidjan)", + "Africa\/Accra": "Greenwich gaƒoƒo me (Accra)", + "Africa\/Addis_Ababa": "East Africa gaƒoƒo me (Addis Ababa)", + "Africa\/Algiers": "Central Europe gaƒoƒo me (Algiers)", + "Africa\/Asmera": "East Africa gaƒoƒo me (Asmara)", + "Africa\/Bamako": "Greenwich gaƒoƒo me (Bamako)", + "Africa\/Bangui": "West Africa gaƒoƒo me (Bangui)", + "Africa\/Banjul": "Greenwich gaƒoƒo me (Banjul)", + "Africa\/Bissau": "Greenwich gaƒoƒo me (Bissau)", + "Africa\/Blantyre": "Central Africa gaƒoƒo me (Blantyre)", + "Africa\/Brazzaville": "West Africa gaƒoƒo me (Brazzaville)", + "Africa\/Bujumbura": "Central Africa gaƒoƒo me (Bujumbura)", + "Africa\/Cairo": "Ɣedzeƒe Europe gaƒoƒome (Cairo)", + "Africa\/Casablanca": "Western Europe gaƒoƒo me (Casablanca)", + "Africa\/Ceuta": "Central Europe gaƒoƒo me (Ceuta)", + "Africa\/Conakry": "Greenwich gaƒoƒo me (Conakry)", + "Africa\/Dakar": "Greenwich gaƒoƒo me (Dakar)", + "Africa\/Dar_es_Salaam": "East Africa gaƒoƒo me (Dar es Salaam)", + "Africa\/Djibouti": "East Africa gaƒoƒo me (Djibouti)", + "Africa\/Douala": "West Africa gaƒoƒo me (Douala)", + "Africa\/El_Aaiun": "Western Europe gaƒoƒo me (El Aaiun)", + "Africa\/Freetown": "Greenwich gaƒoƒo me (Freetown)", + "Africa\/Gaborone": "Central Africa gaƒoƒo me (Gaborone)", + "Africa\/Harare": "Central Africa gaƒoƒo me (Harare)", + "Africa\/Johannesburg": "South Africa nutome gaƒoƒo me (Johannesburg)", + "Africa\/Juba": "East Africa gaƒoƒo me (Juba)", + "Africa\/Kampala": "East Africa gaƒoƒo me (Kampala)", + "Africa\/Khartoum": "Central Africa gaƒoƒo me (Khartoum)", + "Africa\/Kigali": "Central Africa gaƒoƒo me (Kigali)", + "Africa\/Kinshasa": "West Africa gaƒoƒo me (Kinshasa)", + "Africa\/Lagos": "West Africa gaƒoƒo me (Lagos)", + "Africa\/Libreville": "West Africa gaƒoƒo me (Libreville)", + "Africa\/Lome": "Greenwich gaƒoƒo me (Lome)", + "Africa\/Luanda": "West Africa gaƒoƒo me (Luanda)", + "Africa\/Lubumbashi": "Central Africa gaƒoƒo me (Lubumbashi)", + "Africa\/Lusaka": "Central Africa gaƒoƒo me (Lusaka)", + "Africa\/Malabo": "West Africa gaƒoƒo me (Malabo)", + "Africa\/Maputo": "Central Africa gaƒoƒo me (Maputo)", + "Africa\/Maseru": "South Africa nutome gaƒoƒo me (Maseru)", + "Africa\/Mbabane": "South Africa nutome gaƒoƒo me (Mbabane)", + "Africa\/Mogadishu": "East Africa gaƒoƒo me (Mogadishu)", + "Africa\/Monrovia": "Greenwich gaƒoƒo me (Monrovia)", + "Africa\/Nairobi": "East Africa gaƒoƒo me (Nairobi)", + "Africa\/Ndjamena": "West Africa gaƒoƒo me (Ndjamena)", + "Africa\/Niamey": "West Africa gaƒoƒo me (Niamey)", + "Africa\/Nouakchott": "Greenwich gaƒoƒo me (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich gaƒoƒo me (Ouagadougou)", + "Africa\/Porto-Novo": "West Africa gaƒoƒo me (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich gaƒoƒo me (Sao Tome)", + "Africa\/Tripoli": "Ɣedzeƒe Europe gaƒoƒome (Tripoli)", + "Africa\/Tunis": "Central Europe gaƒoƒo me (Tunis)", + "Africa\/Windhoek": "Central Africa gaƒoƒo me (Windhoek)", + "America\/Adak": "Hawaii-Aleutia gaƒoƒo me (Adak)", + "America\/Anchorage": "Alaska gaƒoƒome (Anchorage)", + "America\/Anguilla": "Atlantic gaƒoƒome (Anguilla)", + "America\/Antigua": "Atlantic gaƒoƒome (Antigua)", + "America\/Araguaina": "Brasilia gaƒoƒo me (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentina gaƒoƒo me (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentina gaƒoƒo me (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentina gaƒoƒo me (Salta)", + "America\/Argentina\/San_Juan": "Argentina gaƒoƒo me (San Juan)", + "America\/Argentina\/San_Luis": "Ɣetoɖoƒe Argentina gaƒoƒo me (San Luis)", + "America\/Argentina\/Tucuman": "Argentina gaƒoƒo me (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentina gaƒoƒo me (Ushuaia)", + "America\/Aruba": "Atlantic gaƒoƒome (Aruba)", + "America\/Asuncion": "Paraguay gaƒoƒo me (Asuncion)", + "America\/Bahia": "Brasilia gaƒoƒo me (Bahia)", + "America\/Bahia_Banderas": "Titina America gaƒoƒome (Bahia Banderas)", + "America\/Barbados": "Atlantic gaƒoƒome (Barbados)", + "America\/Belem": "Brasilia gaƒoƒo me (Belem)", + "America\/Belize": "Titina America gaƒoƒome (Belize)", + "America\/Blanc-Sablon": "Atlantic gaƒoƒome (Blanc-Sablon)", + "America\/Boa_Vista": "Amazon gaƒoƒome (Boa Vista)", + "America\/Bogota": "Colombia gaƒoƒo me (Bogota)", + "America\/Boise": "Mountain gaƒoƒo me (Boise)", + "America\/Buenos_Aires": "Argentina gaƒoƒo me (Buenos Aires)", + "America\/Cambridge_Bay": "Mountain gaƒoƒo me (Cambridge Bay)", + "America\/Campo_Grande": "Amazon gaƒoƒome (Campo Grande)", + "America\/Cancun": "Eastern America gaƒoƒo me (Cancun)", + "America\/Caracas": "Venezuela gaƒoƒo me (Caracas)", + "America\/Catamarca": "Argentina gaƒoƒo me (Catamarca)", + "America\/Cayenne": "French Guiana gaƒoƒo me (Cayenne)", + "America\/Cayman": "Eastern America gaƒoƒo me (Cayman)", + "America\/Chicago": "Titina America gaƒoƒome (Chicago)", + "America\/Chihuahua": "Mexican Pacific gaƒoƒo me (Chihuahua)", + "America\/Coral_Harbour": "Eastern America gaƒoƒo me (Atikokan)", + "America\/Cordoba": "Argentina gaƒoƒo me (Cordoba)", + "America\/Costa_Rica": "Titina America gaƒoƒome (Costa Rica)", + "America\/Creston": "Mountain gaƒoƒo me (Creston)", + "America\/Cuiaba": "Amazon gaƒoƒome (Cuiaba)", + "America\/Curacao": "Atlantic gaƒoƒome (Curacao)", + "America\/Danmarkshavn": "Greenwich gaƒoƒo me (Danmarkshavn)", + "America\/Dawson": "Pacific gaƒoƒome (Dawson)", + "America\/Dawson_Creek": "Mountain gaƒoƒo me (Dawson Creek)", + "America\/Denver": "Mountain gaƒoƒo me (Denver)", + "America\/Detroit": "Eastern America gaƒoƒo me (Detroit)", + "America\/Dominica": "Atlantic gaƒoƒome (Dominica)", + "America\/Edmonton": "Mountain gaƒoƒo me (Edmonton)", + "America\/El_Salvador": "Titina America gaƒoƒome (El Salvador)", + "America\/Fort_Nelson": "Mountain gaƒoƒo me (Fort Nelson)", + "America\/Fortaleza": "Brasilia gaƒoƒo me (Fortaleza)", + "America\/Glace_Bay": "Atlantic gaƒoƒome (Glace Bay)", + "America\/Godthab": "West Greenland gaƒoƒo me (Nuuk)", + "America\/Goose_Bay": "Atlantic gaƒoƒome (Goose Bay)", + "America\/Grand_Turk": "Eastern America gaƒoƒo me (Grand Turk)", + "America\/Grenada": "Atlantic gaƒoƒome (Grenada)", + "America\/Guadeloupe": "Atlantic gaƒoƒome (Guadeloupe)", + "America\/Guatemala": "Titina America gaƒoƒome (Guatemala)", + "America\/Guayaquil": "Ecuador gaƒoƒo me (Guayaquil)", + "America\/Guyana": "Guyana gaƒoƒo me (Guyana)", + "America\/Halifax": "Atlantic gaƒoƒome (Halifax)", + "America\/Havana": "Cuba gaƒoƒome (Havana)", + "America\/Hermosillo": "Mexican Pacific gaƒoƒo me (Hermosillo)", + "America\/Indiana\/Knox": "Titina America gaƒoƒome (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern America gaƒoƒo me (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern America gaƒoƒo me (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Titina America gaƒoƒome (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern America gaƒoƒo me (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern America gaƒoƒo me (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern America gaƒoƒo me (Winamac, Indiana)", + "America\/Indianapolis": "Eastern America gaƒoƒo me (Indianapolis)", + "America\/Inuvik": "Mountain gaƒoƒo me (Inuvik)", + "America\/Iqaluit": "Eastern America gaƒoƒo me (Iqaluit)", + "America\/Jamaica": "Eastern America gaƒoƒo me (Jamaica)", + "America\/Jujuy": "Argentina gaƒoƒo me (Jujuy)", + "America\/Juneau": "Alaska gaƒoƒome (Juneau)", + "America\/Kentucky\/Monticello": "Eastern America gaƒoƒo me (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantic gaƒoƒome (Kralendijk)", + "America\/La_Paz": "Bolivia gaƒoƒo me (La Paz)", + "America\/Lima": "Peru gaƒoƒo me (Lima)", + "America\/Los_Angeles": "Pacific gaƒoƒome (Los Angeles)", + "America\/Louisville": "Eastern America gaƒoƒo me (Louisville)", + "America\/Lower_Princes": "Atlantic gaƒoƒome (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilia gaƒoƒo me (Maceio)", + "America\/Managua": "Titina America gaƒoƒome (Managua)", + "America\/Manaus": "Amazon gaƒoƒome (Manaus)", + "America\/Marigot": "Atlantic gaƒoƒome (Marigot)", + "America\/Martinique": "Atlantic gaƒoƒome (Martinique)", + "America\/Matamoros": "Titina America gaƒoƒome (Matamoros)", + "America\/Mazatlan": "Mexican Pacific gaƒoƒo me (Mazatlan)", + "America\/Mendoza": "Argentina gaƒoƒo me (Mendoza)", + "America\/Menominee": "Titina America gaƒoƒome (Menominee)", + "America\/Merida": "Titina America gaƒoƒome (Merida)", + "America\/Metlakatla": "Alaska gaƒoƒome (Metlakatla)", + "America\/Mexico_City": "Titina America gaƒoƒome (Mexico City)", + "America\/Miquelon": "St. Pierre & Miquelon gaƒoƒome (Miquelon)", + "America\/Moncton": "Atlantic gaƒoƒome (Moncton)", + "America\/Monterrey": "Titina America gaƒoƒome (Monterrey)", + "America\/Montevideo": "Uruguay gaƒoƒo me (Montevideo)", + "America\/Montserrat": "Atlantic gaƒoƒome (Montserrat)", + "America\/Nassau": "Eastern America gaƒoƒo me (Nassau)", + "America\/New_York": "Eastern America gaƒoƒo me (New York)", + "America\/Nipigon": "Eastern America gaƒoƒo me (Nipigon)", + "America\/Nome": "Alaska gaƒoƒome (Nome)", + "America\/Noronha": "Fernando de Noronha gaƒoƒo me (Noronha)", + "America\/North_Dakota\/Beulah": "Titina America gaƒoƒome (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Titina America gaƒoƒome (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Titina America gaƒoƒome (New Salem, North Dakota)", + "America\/Ojinaga": "Mountain gaƒoƒo me (Ojinaga)", + "America\/Panama": "Eastern America gaƒoƒo me (Panama)", + "America\/Pangnirtung": "Eastern America gaƒoƒo me (Pangnirtung)", + "America\/Paramaribo": "Suriname gaƒoƒome (Paramaribo)", + "America\/Phoenix": "Mountain gaƒoƒo me (Phoenix)", + "America\/Port-au-Prince": "Eastern America gaƒoƒo me (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantic gaƒoƒome (Port of Spain)", + "America\/Porto_Velho": "Amazon gaƒoƒome (Porto Velho)", + "America\/Puerto_Rico": "Atlantic gaƒoƒome (Puerto Rico)", + "America\/Punta_Arenas": "Chile gaƒoƒo me (Punta Arenas)", + "America\/Rainy_River": "Titina America gaƒoƒome (Rainy River)", + "America\/Rankin_Inlet": "Titina America gaƒoƒome (Rankin Inlet)", + "America\/Recife": "Brasilia gaƒoƒo me (Recife)", + "America\/Regina": "Titina America gaƒoƒome (Regina)", + "America\/Resolute": "Titina America gaƒoƒome (Resolute)", + "America\/Santa_Isabel": "Northwest Mexico gaƒoƒo me (Santa Isabel)", + "America\/Santarem": "Brasilia gaƒoƒo me (Santarem)", + "America\/Santiago": "Chile gaƒoƒo me (Santiago)", + "America\/Santo_Domingo": "Atlantic gaƒoƒome (Santo Domingo)", + "America\/Sao_Paulo": "Brasilia gaƒoƒo me (Sao Paulo)", + "America\/Scoresbysund": "East Greenland gaƒoƒome (Ittoqqortoormiit)", + "America\/Sitka": "Alaska gaƒoƒome (Sitka)", + "America\/St_Barthelemy": "Atlantic gaƒoƒome (St. Barthelemy)", + "America\/St_Johns": "Newfoundland gaƒoƒome (St. John’s)", + "America\/St_Kitts": "Atlantic gaƒoƒome (St. Kitts)", + "America\/St_Lucia": "Atlantic gaƒoƒome (St. Lucia)", + "America\/St_Thomas": "Atlantic gaƒoƒome (St. Thomas)", + "America\/St_Vincent": "Atlantic gaƒoƒome (St. Vincent)", + "America\/Swift_Current": "Titina America gaƒoƒome (Swift Current)", + "America\/Tegucigalpa": "Titina America gaƒoƒome (Tegucigalpa)", + "America\/Thule": "Atlantic gaƒoƒome (Thule)", + "America\/Thunder_Bay": "Eastern America gaƒoƒo me (Thunder Bay)", + "America\/Tijuana": "Pacific gaƒoƒome (Tijuana)", + "America\/Toronto": "Eastern America gaƒoƒo me (Toronto)", + "America\/Tortola": "Atlantic gaƒoƒome (Tortola)", + "America\/Vancouver": "Pacific gaƒoƒome (Vancouver)", + "America\/Whitehorse": "Pacific gaƒoƒome (Whitehorse)", + "America\/Winnipeg": "Titina America gaƒoƒome (Winnipeg)", + "America\/Yakutat": "Alaska gaƒoƒome (Yakutat)", + "America\/Yellowknife": "Mountain gaƒoƒo me (Yellowknife)", + "Antarctica\/Casey": "Western Australia gaƒoƒo me (Casey)", + "Antarctica\/Davis": "Davis gaƒoƒo me (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville gaƒoƒo me (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie Island gaƒoƒo me (Macquarie)", + "Antarctica\/Mawson": "Mawson gaƒoƒo me (Mawson)", + "Antarctica\/McMurdo": "New Zealand gaƒoƒo me (McMurdo)", + "Antarctica\/Palmer": "Chile gaƒoƒo me (Palmer)", + "Antarctica\/Rothera": "Rothera gaƒoƒo me (Rothera)", + "Antarctica\/Syowa": "Syowa gaƒoƒo me (Syowa)", + "Antarctica\/Troll": "Greenwich gaƒoƒo me (Troll)", + "Antarctica\/Vostok": "Vostok gaƒoƒo me (Vostok)", + "Arctic\/Longyearbyen": "Central Europe gaƒoƒo me (Longyearbyen)", + "Asia\/Aden": "Arabia gaƒoƒo me (Aden)", + "Asia\/Almaty": "East Kazakhstan gaƒoƒo me (Almaty)", + "Asia\/Amman": "Ɣedzeƒe Europe gaƒoƒome (Amman)", + "Asia\/Aqtau": "West Kazakhstan gaƒoƒo me (Aqtau)", + "Asia\/Aqtobe": "West Kazakhstan gaƒoƒo me (Aqtobe)", + "Asia\/Ashgabat": "Turkmenistan gaƒoƒo me (Ashgabat)", + "Asia\/Atyrau": "West Kazakhstan gaƒoƒo me (Atyrau)", + "Asia\/Baghdad": "Arabia gaƒoƒo me (Baghdad)", + "Asia\/Bahrain": "Arabia gaƒoƒo me (Bahrain)", + "Asia\/Baku": "Azerbaijan gaƒoƒo me (Baku)", + "Asia\/Bangkok": "Indonesia gaƒoƒo me (Bangkok)", + "Asia\/Beirut": "Ɣedzeƒe Europe gaƒoƒome (Beirut)", + "Asia\/Bishkek": "Kyrgystan gaƒoƒo me (Bishkek)", + "Asia\/Brunei": "Brunei Darussalam gaƒoƒo me (Brunei)", + "Asia\/Calcutta": "India gaƒoƒo me (Kolkata)", + "Asia\/Chita": "Yakutsk gaƒoƒo me (Chita)", + "Asia\/Choibalsan": "Choibalsan gaƒoƒo me (Choibalsan)", + "Asia\/Colombo": "India gaƒoƒo me (Colombo)", + "Asia\/Damascus": "Ɣedzeƒe Europe gaƒoƒome (Damascus)", + "Asia\/Dhaka": "Bangladesh gaƒoƒo me (Dhaka)", + "Asia\/Dili": "East Timor gaƒoƒo me (Dili)", + "Asia\/Dubai": "Gulf nutome gaƒoƒo me (Dubai)", + "Asia\/Dushanbe": "Tajikistan gaƒoƒo me (Dushanbe)", + "Asia\/Famagusta": "Ɣedzeƒe Europe gaƒoƒome (Famagusta)", + "Asia\/Gaza": "Ɣedzeƒe Europe gaƒoƒome (Gaza)", + "Asia\/Hebron": "Ɣedzeƒe Europe gaƒoƒome (Hebron)", + "Asia\/Hong_Kong": "Hong Kong gaƒoƒo me (Hong Kong)", + "Asia\/Hovd": "Hovd gaƒoƒo me (Hovd)", + "Asia\/Irkutsk": "Irkutsk gaƒoƒo me (Irkutsk)", + "Asia\/Jakarta": "Western Indonesia gaƒoƒo me (Jakarta)", + "Asia\/Jayapura": "Eastern Indonesia gaƒoƒo me (Jayapura)", + "Asia\/Jerusalem": "Israel gaƒoƒo me (Jerusalem)", + "Asia\/Kabul": "Afghanistan gaƒoƒo me (Kabul)", + "Asia\/Karachi": "Pakistan gaƒoƒo me (Karachi)", + "Asia\/Katmandu": "Nepal gaƒoƒo me (Kathmandu nutomegaƒoƒome)", + "Asia\/Khandyga": "Yakutsk gaƒoƒo me (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnoyarsk gaƒoƒo me (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malaysia gaƒoƒo me (Kuala Lumpur)", + "Asia\/Kuching": "Malaysia gaƒoƒo me (Kuching)", + "Asia\/Kuwait": "Arabia gaƒoƒo me (Kuwait)", + "Asia\/Macau": "China gaƒoƒo me (Macau)", + "Asia\/Magadan": "Magadan gaƒoƒo me (Magadan)", + "Asia\/Makassar": "Central Indonesia gaƒoƒo me (Makassar)", + "Asia\/Manila": "Philippine gaƒoƒo me (Manila)", + "Asia\/Muscat": "Gulf nutome gaƒoƒo me (Muscat)", + "Asia\/Nicosia": "Ɣedzeƒe Europe gaƒoƒome (Nicosia)", + "Asia\/Novokuznetsk": "Krasnoyarsk gaƒoƒo me (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk gaƒoƒo me (Novosibirsk)", + "Asia\/Omsk": "Omsk gaƒoƒo me (Omsk)", + "Asia\/Oral": "West Kazakhstan gaƒoƒo me (Oral)", + "Asia\/Phnom_Penh": "Indonesia gaƒoƒo me (Phnom Penh)", + "Asia\/Pontianak": "Western Indonesia gaƒoƒo me (Pontianak)", + "Asia\/Pyongyang": "Korea gaƒoƒo me (Pyongyang)", + "Asia\/Qatar": "Arabia gaƒoƒo me (Qatar)", + "Asia\/Qostanay": "East Kazakhstan gaƒoƒo me (Qostanay)", + "Asia\/Qyzylorda": "West Kazakhstan gaƒoƒo me (Qyzylorda)", + "Asia\/Rangoon": "Myanmar gaƒoƒo me (Yangon)", + "Asia\/Riyadh": "Arabia gaƒoƒo me (Riyadh)", + "Asia\/Saigon": "Indonesia gaƒoƒo me (Ho Chi Minh)", + "Asia\/Sakhalin": "Sakhalin gaƒoƒo me (Sakhalin)", + "Asia\/Samarkand": "Uzbekistan gaƒoƒo me (Samarkand)", + "Asia\/Seoul": "Korea gaƒoƒo me (Seoul)", + "Asia\/Shanghai": "China gaƒoƒo me (Shanghai)", + "Asia\/Singapore": "Singapore nutome gaƒoƒo me (Singapore)", + "Asia\/Srednekolymsk": "Magadan gaƒoƒo me (Srednekolymsk)", + "Asia\/Taipei": "Taipei gaƒoƒo me (Taipei)", + "Asia\/Tashkent": "Uzbekistan gaƒoƒo me (Tashkent)", + "Asia\/Tbilisi": "Georgia gaƒoƒo me (Tbilisi)", + "Asia\/Tehran": "Iran gaƒoƒo me (Tehran)", + "Asia\/Thimphu": "Bhutan gaƒoƒo me (Thimphu)", + "Asia\/Tokyo": "Japan gaƒoƒo me (Tokyo)", + "Asia\/Ulaanbaatar": "Ulan Bator gaƒoƒo me (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostok gaƒoƒo me (Ust-Nera)", + "Asia\/Vientiane": "Indonesia gaƒoƒo me (Vientiane)", + "Asia\/Vladivostok": "Vladivostok gaƒoƒo me (Vladivostok)", + "Asia\/Yakutsk": "Yakutsk gaƒoƒo me (Yakutsk)", + "Asia\/Yekaterinburg": "Yekaterinburg gaƒoƒo me (Yekaterinburg)", + "Asia\/Yerevan": "Armenia gaƒoƒo me (Yerevan)", + "Atlantic\/Azores": "Azores gaƒoƒo me (Azores)", + "Atlantic\/Bermuda": "Atlantic gaƒoƒome (Bermuda)", + "Atlantic\/Canary": "Western Europe gaƒoƒo me (Canary)", + "Atlantic\/Cape_Verde": "Cape Verde gaƒoƒo me (Cape Verde)", + "Atlantic\/Faeroe": "Western Europe gaƒoƒo me (Faroe)", + "Atlantic\/Madeira": "Western Europe gaƒoƒo me (Madeira)", + "Atlantic\/Reykjavik": "Greenwich gaƒoƒo me (Reykjavik)", + "Atlantic\/South_Georgia": "South Georgia gaƒoƒo me (South Georgia)", + "Atlantic\/St_Helena": "Greenwich gaƒoƒo me (St. Helena)", + "Atlantic\/Stanley": "Falkland Islands gaƒoƒo me (Stanley)", + "Australia\/Adelaide": "Central Australia gaƒoƒo me (Adelaide)", + "Australia\/Brisbane": "Eastern Australia gaƒoƒo me (Brisbane)", + "Australia\/Broken_Hill": "Central Australia gaƒoƒo me (Broken Hill)", + "Australia\/Currie": "Eastern Australia gaƒoƒo me (Currie)", + "Australia\/Darwin": "Central Australia gaƒoƒo me (Darwin)", + "Australia\/Eucla": "Australian Central Australia ɣetoɖofe gaƒoƒo me (Eucla)", + "Australia\/Hobart": "Eastern Australia gaƒoƒo me (Hobart)", + "Australia\/Lindeman": "Eastern Australia gaƒoƒo me (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe gaƒoƒo me (Lord Howe)", + "Australia\/Melbourne": "Eastern Australia gaƒoƒo me (Melbourne)", + "Australia\/Perth": "Western Australia gaƒoƒo me (Perth)", + "Australia\/Sydney": "Eastern Australia gaƒoƒo me (Sydney)", + "CST6CDT": "Titina America gaƒoƒome", + "EST5EDT": "Eastern America gaƒoƒo me", + "Etc\/GMT": "Greenwich gaƒoƒo me", + "Etc\/UTC": "Xexeme gaƒoƒoɖoanyi me", + "Europe\/Amsterdam": "Central Europe gaƒoƒo me (Amsterdam)", + "Europe\/Andorra": "Central Europe gaƒoƒo me (Andorra)", + "Europe\/Astrakhan": "Moscow gaƒoƒo me (Astrakhan)", + "Europe\/Athens": "Ɣedzeƒe Europe gaƒoƒome (Athens)", + "Europe\/Belgrade": "Central Europe gaƒoƒo me (Belgrade)", + "Europe\/Berlin": "Central Europe gaƒoƒo me (Berlin)", + "Europe\/Bratislava": "Central Europe gaƒoƒo me (Bratislava)", + "Europe\/Brussels": "Central Europe gaƒoƒo me (Brussels)", + "Europe\/Bucharest": "Ɣedzeƒe Europe gaƒoƒome (Bucharest)", + "Europe\/Budapest": "Central Europe gaƒoƒo me (Budapest)", + "Europe\/Busingen": "Central Europe gaƒoƒo me (Busingen)", + "Europe\/Chisinau": "Ɣedzeƒe Europe gaƒoƒome (Chisinau)", + "Europe\/Copenhagen": "Central Europe gaƒoƒo me (Copenhagen)", + "Europe\/Dublin": "Greenwich gaƒoƒo me (Dublin)", + "Europe\/Gibraltar": "Central Europe gaƒoƒo me (Gibraltar)", + "Europe\/Guernsey": "Greenwich gaƒoƒo me (Guernsey)", + "Europe\/Helsinki": "Ɣedzeƒe Europe gaƒoƒome (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich gaƒoƒo me (Isle of Man)", + "Europe\/Jersey": "Greenwich gaƒoƒo me (Jersey)", + "Europe\/Kaliningrad": "Ɣedzeƒe Europe gaƒoƒome (Kaliningrad)", + "Europe\/Kiev": "Ɣedzeƒe Europe gaƒoƒome (Kiev)", + "Europe\/Lisbon": "Western Europe gaƒoƒo me (Lisbon)", + "Europe\/Ljubljana": "Central Europe gaƒoƒo me (Ljubljana)", + "Europe\/London": "Greenwich gaƒoƒo me (London)", + "Europe\/Luxembourg": "Central Europe gaƒoƒo me (Luxembourg)", + "Europe\/Madrid": "Central Europe gaƒoƒo me (Madrid)", + "Europe\/Malta": "Central Europe gaƒoƒo me (Malta)", + "Europe\/Mariehamn": "Ɣedzeƒe Europe gaƒoƒome (Mariehamn)", + "Europe\/Minsk": "Moscow gaƒoƒo me (Minsk)", + "Europe\/Monaco": "Central Europe gaƒoƒo me (Monaco)", + "Europe\/Moscow": "Moscow gaƒoƒo me (Moscow)", + "Europe\/Oslo": "Central Europe gaƒoƒo me (Oslo)", + "Europe\/Paris": "Central Europe gaƒoƒo me (Paris)", + "Europe\/Podgorica": "Central Europe gaƒoƒo me (Podgorica)", + "Europe\/Prague": "Central Europe gaƒoƒo me (Prague)", + "Europe\/Riga": "Ɣedzeƒe Europe gaƒoƒome (Riga)", + "Europe\/Rome": "Central Europe gaƒoƒo me (Rome)", + "Europe\/San_Marino": "Central Europe gaƒoƒo me (San Marino)", + "Europe\/Sarajevo": "Central Europe gaƒoƒo me (Sarajevo)", + "Europe\/Saratov": "Moscow gaƒoƒo me (Saratov)", + "Europe\/Simferopol": "Moscow gaƒoƒo me (Simferopol)", + "Europe\/Skopje": "Central Europe gaƒoƒo me (Skopje)", + "Europe\/Sofia": "Ɣedzeƒe Europe gaƒoƒome (Sofia)", + "Europe\/Stockholm": "Central Europe gaƒoƒo me (Stockholm)", + "Europe\/Tallinn": "Ɣedzeƒe Europe gaƒoƒome (Tallinn)", + "Europe\/Tirane": "Central Europe gaƒoƒo me (Tirane)", + "Europe\/Ulyanovsk": "Moscow gaƒoƒo me (Ulyanovsk)", + "Europe\/Uzhgorod": "Ɣedzeƒe Europe gaƒoƒome (Uzhgorod)", + "Europe\/Vaduz": "Central Europe gaƒoƒo me (Vaduz)", + "Europe\/Vatican": "Central Europe gaƒoƒo me (Vatican)", + "Europe\/Vienna": "Central Europe gaƒoƒo me (Vienna)", + "Europe\/Vilnius": "Ɣedzeƒe Europe gaƒoƒome (Vilnius)", + "Europe\/Volgograd": "Volgograd gaƒoƒo me (Volgograd)", + "Europe\/Warsaw": "Central Europe gaƒoƒo me (Warsaw)", + "Europe\/Zagreb": "Central Europe gaƒoƒo me (Zagreb)", + "Europe\/Zaporozhye": "Ɣedzeƒe Europe gaƒoƒome (Zaporozhye)", + "Europe\/Zurich": "Central Europe gaƒoƒo me (Zurich)", + "Indian\/Antananarivo": "East Africa gaƒoƒo me (Antananarivo)", + "Indian\/Chagos": "Indian Ocean gaƒoƒo me (Chagos)", + "Indian\/Christmas": "Christmas Island gaƒoƒo me (Christmas)", + "Indian\/Cocos": "Cocos Islands gaƒoƒo me (Cocos)", + "Indian\/Comoro": "East Africa gaƒoƒo me (Comoro)", + "Indian\/Kerguelen": "French Southern & Antarctic gaƒoƒo me (Kerguelen)", + "Indian\/Mahe": "Seychelles gaƒoƒo me (Mahe)", + "Indian\/Maldives": "Maldives gaƒoƒo me (Maldives)", + "Indian\/Mauritius": "Mauritius gaƒoƒo me (Mauritius)", + "Indian\/Mayotte": "East Africa gaƒoƒo me (Mayotte)", + "Indian\/Reunion": "Reunion gaƒoƒo me (Reunion)", + "MST7MDT": "Mountain gaƒoƒo me", + "PST8PDT": "Pacific gaƒoƒome", + "Pacific\/Apia": "Apia gaƒoƒo me (Apia)", + "Pacific\/Auckland": "New Zealand gaƒoƒo me (Auckland)", + "Pacific\/Bougainville": "Papua New Guinea gaƒoƒo me (Bougainville)", + "Pacific\/Chatham": "Chatham gaƒoƒo me (Chatham)", + "Pacific\/Easter": "Easter Island gaƒoƒo me (Easter)", + "Pacific\/Efate": "Vanuatu gaƒoƒo me (Efate)", + "Pacific\/Enderbury": "Phoenix Islands gaƒoƒo me (Enderbury)", + "Pacific\/Fakaofo": "Tokelau gaƒoƒo me (Fakaofo)", + "Pacific\/Fiji": "Fiji gaƒoƒo me (Fiji)", + "Pacific\/Funafuti": "Tuvalu gaƒoƒo me (Funafuti)", + "Pacific\/Galapagos": "Galapagos gaƒoƒo me (Galapagos)", + "Pacific\/Gambier": "Gambier gaƒoƒo me (Gambier)", + "Pacific\/Guadalcanal": "Solomon Islands gaƒoƒo me (Guadalcanal)", + "Pacific\/Guam": "Chamorro gaƒoƒo me (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleutia gaƒoƒo me (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleutia gaƒoƒo me (Johnston)", + "Pacific\/Kiritimati": "Line Islands gaƒoƒo me (Kiritimati)", + "Pacific\/Kosrae": "Kosrae gaƒoƒo me (Kosrae)", + "Pacific\/Kwajalein": "Marshall Islands gaƒoƒo me (Kwajalein)", + "Pacific\/Majuro": "Marshall Islands gaƒoƒo me (Majuro)", + "Pacific\/Marquesas": "Marquesas gaƒoƒo me (Marquesas)", + "Pacific\/Midway": "Samoa gaƒoƒo me (Midway)", + "Pacific\/Nauru": "Nauru gaƒoƒo me (Nauru)", + "Pacific\/Niue": "Niue gaƒoƒo me (Niue)", + "Pacific\/Norfolk": "Norfolk Island gaƒoƒo me (Norfolk)", + "Pacific\/Noumea": "New Caledonia gaƒoƒo me (Noumea)", + "Pacific\/Pago_Pago": "Samoa gaƒoƒo me (Pago Pago)", + "Pacific\/Palau": "Palau gaƒoƒo me (Palau)", + "Pacific\/Pitcairn": "Pitcairn gaƒoƒo me (Pitcairn)", + "Pacific\/Ponape": "Ponape gaƒoƒo me (Pohnpei)", + "Pacific\/Port_Moresby": "Papua New Guinea gaƒoƒo me (Port Moresby)", + "Pacific\/Rarotonga": "Cook Islands gaƒoƒo me (Rarotonga)", + "Pacific\/Saipan": "Chamorro gaƒoƒo me (Saipan)", + "Pacific\/Tahiti": "Tahiti gaƒoƒo me (Tahiti)", + "Pacific\/Tarawa": "Gilbert Islands gaƒoƒo me (Tarawa)", + "Pacific\/Tongatapu": "Tonga gaƒoƒo me (Tongatapu)", + "Pacific\/Truk": "Chuuk gaƒoƒo me (Chuuk)", + "Pacific\/Wake": "Wake Island gaƒoƒo me (Wake)", + "Pacific\/Wallis": "Wallis & Futuna gaƒoƒo me (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/el.json b/src/Symfony/Component/Intl/Resources/data/timezones/el.json new file mode 100644 index 0000000000000..31c6f23f555c9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/el.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.49.26", + "Names": { + "Africa\/Abidjan": "Μέση ώρα Γκρίνουιτς (Αμπιτζάν)", + "Africa\/Accra": "Μέση ώρα Γκρίνουιτς (Άκρα)", + "Africa\/Addis_Ababa": "Ώρα Ανατολικής Αφρικής (Αντίς Αμπέμπα)", + "Africa\/Algiers": "Ώρα Κεντρικής Ευρώπης (Αλγέρι)", + "Africa\/Asmera": "Ώρα Ανατολικής Αφρικής (Ασμάρα)", + "Africa\/Bamako": "Μέση ώρα Γκρίνουιτς (Μπαμάκο)", + "Africa\/Bangui": "Ώρα Δυτικής Αφρικής (Μπανγκί)", + "Africa\/Banjul": "Μέση ώρα Γκρίνουιτς (Μπανζούλ)", + "Africa\/Bissau": "Μέση ώρα Γκρίνουιτς (Μπισάου)", + "Africa\/Blantyre": "Ώρα Κεντρικής Αφρικής (Μπλαντάιρ)", + "Africa\/Brazzaville": "Ώρα Δυτικής Αφρικής (Μπραζαβίλ)", + "Africa\/Bujumbura": "Ώρα Κεντρικής Αφρικής (Μπουζουμπούρα)", + "Africa\/Cairo": "Ώρα Ανατολικής Ευρώπης (Κάιρο)", + "Africa\/Casablanca": "Ώρα Δυτικής Ευρώπης (Καζαμπλάνκα)", + "Africa\/Ceuta": "Ώρα Κεντρικής Ευρώπης (Θέουτα)", + "Africa\/Conakry": "Μέση ώρα Γκρίνουιτς (Κόνακρι)", + "Africa\/Dakar": "Μέση ώρα Γκρίνουιτς (Ντακάρ)", + "Africa\/Dar_es_Salaam": "Ώρα Ανατολικής Αφρικής (Νταρ Ες Σαλάμ)", + "Africa\/Djibouti": "Ώρα Ανατολικής Αφρικής (Τζιμπουτί)", + "Africa\/Douala": "Ώρα Δυτικής Αφρικής (Ντουάλα)", + "Africa\/El_Aaiun": "Ώρα Δυτικής Ευρώπης (Ελ Αγιούν)", + "Africa\/Freetown": "Μέση ώρα Γκρίνουιτς (Φρίταουν)", + "Africa\/Gaborone": "Ώρα Κεντρικής Αφρικής (Γκαμπορόνε)", + "Africa\/Harare": "Ώρα Κεντρικής Αφρικής (Χαράρε)", + "Africa\/Johannesburg": "Χειμερινή ώρα Νότιας Αφρικής (Γιοχάνεσμπουργκ)", + "Africa\/Juba": "Ώρα Ανατολικής Αφρικής (Τζούμπα)", + "Africa\/Kampala": "Ώρα Ανατολικής Αφρικής (Καμπάλα)", + "Africa\/Khartoum": "Ώρα Κεντρικής Αφρικής (Χαρτούμ)", + "Africa\/Kigali": "Ώρα Κεντρικής Αφρικής (Κιγκάλι)", + "Africa\/Kinshasa": "Ώρα Δυτικής Αφρικής (Κινσάσα)", + "Africa\/Lagos": "Ώρα Δυτικής Αφρικής (Λάγκος)", + "Africa\/Libreville": "Ώρα Δυτικής Αφρικής (Λιμπρεβίλ)", + "Africa\/Lome": "Μέση ώρα Γκρίνουιτς (Λομέ)", + "Africa\/Luanda": "Ώρα Δυτικής Αφρικής (Λουάντα)", + "Africa\/Lubumbashi": "Ώρα Κεντρικής Αφρικής (Λουμπουμπάσι)", + "Africa\/Lusaka": "Ώρα Κεντρικής Αφρικής (Λουζάκα)", + "Africa\/Malabo": "Ώρα Δυτικής Αφρικής (Μαλάμπο)", + "Africa\/Maputo": "Ώρα Κεντρικής Αφρικής (Μαπούτο)", + "Africa\/Maseru": "Χειμερινή ώρα Νότιας Αφρικής (Μασέρου)", + "Africa\/Mbabane": "Χειμερινή ώρα Νότιας Αφρικής (Μπαμπάνε)", + "Africa\/Mogadishu": "Ώρα Ανατολικής Αφρικής (Μογκαντίσου)", + "Africa\/Monrovia": "Μέση ώρα Γκρίνουιτς (Μονρόβια)", + "Africa\/Nairobi": "Ώρα Ανατολικής Αφρικής (Ναϊρόμπι)", + "Africa\/Ndjamena": "Ώρα Δυτικής Αφρικής (Ντζαμένα)", + "Africa\/Niamey": "Ώρα Δυτικής Αφρικής (Νιαμέι)", + "Africa\/Nouakchott": "Μέση ώρα Γκρίνουιτς (Νουακσότ)", + "Africa\/Ouagadougou": "Μέση ώρα Γκρίνουιτς (Ουαγκαντούγκου)", + "Africa\/Porto-Novo": "Ώρα Δυτικής Αφρικής (Πόρτο-Νόβο)", + "Africa\/Sao_Tome": "Μέση ώρα Γκρίνουιτς (Σάο Τομέ)", + "Africa\/Tripoli": "Ώρα Ανατολικής Ευρώπης (Τρίπολη)", + "Africa\/Tunis": "Ώρα Κεντρικής Ευρώπης (Τύνιδα)", + "Africa\/Windhoek": "Ώρα Κεντρικής Αφρικής (Βίντχουκ)", + "America\/Adak": "Ώρα Χαβάης-Αλεούτιων Νήσων (Άντακ)", + "America\/Anchorage": "Ώρα Αλάσκας (Άνκορατζ)", + "America\/Anguilla": "Ώρα Ατλαντικού (Ανγκουίλα)", + "America\/Antigua": "Ώρα Ατλαντικού (Αντίγκουα)", + "America\/Araguaina": "Ώρα Μπραζίλιας (Αραγκουάινα)", + "America\/Argentina\/La_Rioja": "Ώρα Αργεντινής (Λα Ριόχα)", + "America\/Argentina\/Rio_Gallegos": "Ώρα Αργεντινής (Ρίο Γκαγιέγκος)", + "America\/Argentina\/Salta": "Ώρα Αργεντινής (Σάλτα)", + "America\/Argentina\/San_Juan": "Ώρα Αργεντινής (Σαν Χουάν)", + "America\/Argentina\/San_Luis": "Ώρα Δυτικής Αργεντινής (Σαν Λούις)", + "America\/Argentina\/Tucuman": "Ώρα Αργεντινής (Τουκουμάν)", + "America\/Argentina\/Ushuaia": "Ώρα Αργεντινής (Ουσουάια)", + "America\/Aruba": "Ώρα Ατλαντικού (Αρούμπα)", + "America\/Asuncion": "Ώρα Παραγουάης (Ασουνσιόν)", + "America\/Bahia": "Ώρα Μπραζίλιας (Μπαΐα)", + "America\/Bahia_Banderas": "Κεντρική ώρα Βόρειας Αμερικής (Μπαΐα ντε Μπαντέρας)", + "America\/Barbados": "Ώρα Ατλαντικού (Μπαρμπέιντος)", + "America\/Belem": "Ώρα Μπραζίλιας (Μπελέμ)", + "America\/Belize": "Κεντρική ώρα Βόρειας Αμερικής (Μπελίζ)", + "America\/Blanc-Sablon": "Ώρα Ατλαντικού (Μπλαν Σαμπλόν)", + "America\/Boa_Vista": "Ώρα Αμαζονίου (Μπόα Βίστα)", + "America\/Bogota": "Ώρα Κολομβίας (Μπογκοτά)", + "America\/Boise": "Ορεινή ώρα Βόρειας Αμερικής (Μπόιζι)", + "America\/Buenos_Aires": "Ώρα Αργεντινής (Μπουένος Άιρες)", + "America\/Cambridge_Bay": "Ορεινή ώρα Βόρειας Αμερικής (Κέμπριτζ Μπέι)", + "America\/Campo_Grande": "Ώρα Αμαζονίου (Κάμπο Γκράντε)", + "America\/Cancun": "Ανατολική ώρα Βόρειας Αμερικής (Κανκούν)", + "America\/Caracas": "Ώρα Βενεζουέλας (Καράκας)", + "America\/Catamarca": "Ώρα Αργεντινής (Καταμάρκα)", + "America\/Cayenne": "Ώρα Γαλλικής Γουιάνας (Καγιέν)", + "America\/Cayman": "Ανατολική ώρα Βόρειας Αμερικής (Κέιμαν)", + "America\/Chicago": "Κεντρική ώρα Βόρειας Αμερικής (Σικάγο)", + "America\/Chihuahua": "Ώρα Ειρηνικού Μεξικού (Τσιουάουα)", + "America\/Coral_Harbour": "Ανατολική ώρα Βόρειας Αμερικής (Ατικόκαν)", + "America\/Cordoba": "Ώρα Αργεντινής (Κόρδοβα)", + "America\/Costa_Rica": "Κεντρική ώρα Βόρειας Αμερικής (Κόστα Ρίκα)", + "America\/Creston": "Ορεινή ώρα Βόρειας Αμερικής (Κρέστον)", + "America\/Cuiaba": "Ώρα Αμαζονίου (Κουιαμπά)", + "America\/Curacao": "Ώρα Ατλαντικού (Κουρασάο)", + "America\/Danmarkshavn": "Μέση ώρα Γκρίνουιτς (Ντανμαρκσάβν)", + "America\/Dawson": "Ώρα Ειρηνικού (Ντόσον)", + "America\/Dawson_Creek": "Ορεινή ώρα Βόρειας Αμερικής (Ντόσον Κρικ)", + "America\/Denver": "Ορεινή ώρα Βόρειας Αμερικής (Ντένβερ)", + "America\/Detroit": "Ανατολική ώρα Βόρειας Αμερικής (Ντιτρόιτ)", + "America\/Dominica": "Ώρα Ατλαντικού (Ντομίνικα)", + "America\/Edmonton": "Ορεινή ώρα Βόρειας Αμερικής (Έντμοντον)", + "America\/El_Salvador": "Κεντρική ώρα Βόρειας Αμερικής (Ελ Σαλβαδόρ)", + "America\/Fort_Nelson": "Ορεινή ώρα Βόρειας Αμερικής (Φορτ Νέλσον)", + "America\/Fortaleza": "Ώρα Μπραζίλιας (Φορταλέζα)", + "America\/Glace_Bay": "Ώρα Ατλαντικού (Γκλέις Μπέι)", + "America\/Godthab": "Ώρα Δυτικής Γροιλανδίας (Νουούκ)", + "America\/Goose_Bay": "Ώρα Ατλαντικού (Γκους Μπέι)", + "America\/Grand_Turk": "Ανατολική ώρα Βόρειας Αμερικής (Γκραντ Τουρκ)", + "America\/Grenada": "Ώρα Ατλαντικού (Γρενάδα)", + "America\/Guadeloupe": "Ώρα Ατλαντικού (Γουαδελούπη)", + "America\/Guatemala": "Κεντρική ώρα Βόρειας Αμερικής (Γουατεμάλα)", + "America\/Guayaquil": "Ώρα Ισημερινού (Γκουαγιακίλ)", + "America\/Guyana": "Ώρα Γουιάνας (Γουιάνα)", + "America\/Halifax": "Ώρα Ατλαντικού (Χάλιφαξ)", + "America\/Havana": "Ώρα Κούβας (Αβάνα)", + "America\/Hermosillo": "Ώρα Ειρηνικού Μεξικού (Ερμοσίγιο)", + "America\/Indiana\/Knox": "Κεντρική ώρα Βόρειας Αμερικής (Νοξ, Ιντιάνα)", + "America\/Indiana\/Marengo": "Ανατολική ώρα Βόρειας Αμερικής (Μαρένγκο, Ιντιάνα)", + "America\/Indiana\/Petersburg": "Ανατολική ώρα Βόρειας Αμερικής (Πίτερσμπεργκ, Ιντιάνα)", + "America\/Indiana\/Tell_City": "Κεντρική ώρα Βόρειας Αμερικής (Τελ Σίτι, Ιντιάνα)", + "America\/Indiana\/Vevay": "Ανατολική ώρα Βόρειας Αμερικής (Βιβέι, Ιντιάνα)", + "America\/Indiana\/Vincennes": "Ανατολική ώρα Βόρειας Αμερικής (Βανσέν, Ιντιάνα)", + "America\/Indiana\/Winamac": "Ανατολική ώρα Βόρειας Αμερικής (Γουίναμακ, Ιντιάνα)", + "America\/Indianapolis": "Ανατολική ώρα Βόρειας Αμερικής (Ιντιανάπολις)", + "America\/Inuvik": "Ορεινή ώρα Βόρειας Αμερικής (Ινούβικ)", + "America\/Iqaluit": "Ανατολική ώρα Βόρειας Αμερικής (Ικαλούιτ)", + "America\/Jamaica": "Ανατολική ώρα Βόρειας Αμερικής (Τζαμάικα)", + "America\/Jujuy": "Ώρα Αργεντινής (Χουχούι)", + "America\/Juneau": "Ώρα Αλάσκας (Τζούνο)", + "America\/Kentucky\/Monticello": "Ανατολική ώρα Βόρειας Αμερικής (Μοντιτσέλο, Κεντάκι)", + "America\/Kralendijk": "Ώρα Ατλαντικού (Κράλεντικ)", + "America\/La_Paz": "Ώρα Βολιβίας (Λα Παζ)", + "America\/Lima": "Ώρα Περού (Λίμα)", + "America\/Los_Angeles": "Ώρα Ειρηνικού (Λος Άντζελες)", + "America\/Louisville": "Ανατολική ώρα Βόρειας Αμερικής (Λούιβιλ)", + "America\/Lower_Princes": "Ώρα Ατλαντικού (Lower Prince’s Quarter)", + "America\/Maceio": "Ώρα Μπραζίλιας (Μασεϊό)", + "America\/Managua": "Κεντρική ώρα Βόρειας Αμερικής (Μανάγκουα)", + "America\/Manaus": "Ώρα Αμαζονίου (Μανάους)", + "America\/Marigot": "Ώρα Ατλαντικού (Μαριγκό)", + "America\/Martinique": "Ώρα Ατλαντικού (Μαρτινίκα)", + "America\/Matamoros": "Κεντρική ώρα Βόρειας Αμερικής (Ματαμόρος)", + "America\/Mazatlan": "Ώρα Ειρηνικού Μεξικού (Μαζατλάν)", + "America\/Mendoza": "Ώρα Αργεντινής (Μεντόζα)", + "America\/Menominee": "Κεντρική ώρα Βόρειας Αμερικής (Μενομίνε)", + "America\/Merida": "Κεντρική ώρα Βόρειας Αμερικής (Μέριδα)", + "America\/Metlakatla": "Ώρα Αλάσκας (Μετλακάτλα)", + "America\/Mexico_City": "Κεντρική ώρα Βόρειας Αμερικής (Πόλη του Μεξικού)", + "America\/Miquelon": "Ώρα Σεν Πιερ και Μικελόν (Μικελόν)", + "America\/Moncton": "Ώρα Ατλαντικού (Μόνκτον)", + "America\/Monterrey": "Κεντρική ώρα Βόρειας Αμερικής (Μοντερέι)", + "America\/Montevideo": "Ώρα Ουρουγουάης (Μοντεβιδέο)", + "America\/Montserrat": "Ώρα Ατλαντικού (Μονσεράτ)", + "America\/Nassau": "Ανατολική ώρα Βόρειας Αμερικής (Νασάου)", + "America\/New_York": "Ανατολική ώρα Βόρειας Αμερικής (Νέα Υόρκη)", + "America\/Nipigon": "Ανατολική ώρα Βόρειας Αμερικής (Νιπιγκόν)", + "America\/Nome": "Ώρα Αλάσκας (Νόμε)", + "America\/Noronha": "Ώρα Φερνάρντο ντε Νορόνια (Νορόνια)", + "America\/North_Dakota\/Beulah": "Κεντρική ώρα Βόρειας Αμερικής (Μπέουλα, Βόρεια Ντακότα)", + "America\/North_Dakota\/Center": "Κεντρική ώρα Βόρειας Αμερικής (Σέντερ, Βόρεια Ντακότα)", + "America\/North_Dakota\/New_Salem": "Κεντρική ώρα Βόρειας Αμερικής (Νιου Σέιλεμ, Βόρεια Ντακότα)", + "America\/Ojinaga": "Ορεινή ώρα Βόρειας Αμερικής (Οχινάγκα)", + "America\/Panama": "Ανατολική ώρα Βόρειας Αμερικής (Παναμάς)", + "America\/Pangnirtung": "Ανατολική ώρα Βόρειας Αμερικής (Πανγκνίρτουνγκ)", + "America\/Paramaribo": "Ώρα Σουρινάμ (Παραμαρίμπο)", + "America\/Phoenix": "Ορεινή ώρα Βόρειας Αμερικής (Φοίνιξ)", + "America\/Port-au-Prince": "Ανατολική ώρα Βόρειας Αμερικής (Πορτ-ο-Πρενς)", + "America\/Port_of_Spain": "Ώρα Ατλαντικού (Πορτ οφ Σπέιν)", + "America\/Porto_Velho": "Ώρα Αμαζονίου (Πόρτο Βέλιο)", + "America\/Puerto_Rico": "Ώρα Ατλαντικού (Πουέρτο Ρίκο)", + "America\/Punta_Arenas": "Ώρα Χιλής (Πούντα Αρένας)", + "America\/Rainy_River": "Κεντρική ώρα Βόρειας Αμερικής (Ρέινι Ρίβερ)", + "America\/Rankin_Inlet": "Κεντρική ώρα Βόρειας Αμερικής (Ράνκιν Ίνλετ)", + "America\/Recife": "Ώρα Μπραζίλιας (Ρεσίφε)", + "America\/Regina": "Κεντρική ώρα Βόρειας Αμερικής (Ρετζίνα)", + "America\/Resolute": "Κεντρική ώρα Βόρειας Αμερικής (Ρέζολουτ)", + "America\/Santa_Isabel": "Ώρα Βορειοδυτικού Μεξικού (Σάντα Ιζαμπέλ)", + "America\/Santarem": "Ώρα Μπραζίλιας (Σανταρέμ)", + "America\/Santiago": "Ώρα Χιλής (Σαντιάγκο)", + "America\/Santo_Domingo": "Ώρα Ατλαντικού (Άγιος Δομίνικος)", + "America\/Sao_Paulo": "Ώρα Μπραζίλιας (Σάο Πάολο)", + "America\/Scoresbysund": "Ώρα Ανατολικής Γροιλανδίας (Σκορεσμπίσουντ)", + "America\/Sitka": "Ώρα Αλάσκας (Σίτκα)", + "America\/St_Barthelemy": "Ώρα Ατλαντικού (Άγιος Βαρθολομαίος)", + "America\/St_Johns": "Ώρα Νέας Γης (Σεν Τζονς)", + "America\/St_Kitts": "Ώρα Ατλαντικού (Σεν Κιτς)", + "America\/St_Lucia": "Ώρα Ατλαντικού (Αγία Λουκία)", + "America\/St_Thomas": "Ώρα Ατλαντικού (Άγιος Θωμάς)", + "America\/St_Vincent": "Ώρα Ατλαντικού (Άγιος Βικέντιος)", + "America\/Swift_Current": "Κεντρική ώρα Βόρειας Αμερικής (Σουίφτ Κάρεντ)", + "America\/Tegucigalpa": "Κεντρική ώρα Βόρειας Αμερικής (Τεγκουσιγκάλπα)", + "America\/Thule": "Ώρα Ατλαντικού (Θούλη)", + "America\/Thunder_Bay": "Ανατολική ώρα Βόρειας Αμερικής (Θάντερ Μπέι)", + "America\/Tijuana": "Ώρα Ειρηνικού (Τιχουάνα)", + "America\/Toronto": "Ανατολική ώρα Βόρειας Αμερικής (Τορόντο)", + "America\/Tortola": "Ώρα Ατλαντικού (Τορτόλα)", + "America\/Vancouver": "Ώρα Ειρηνικού (Βανκούβερ)", + "America\/Whitehorse": "Ώρα Ειρηνικού (Γουάιτχορς)", + "America\/Winnipeg": "Κεντρική ώρα Βόρειας Αμερικής (Γουίνιπεγκ)", + "America\/Yakutat": "Ώρα Αλάσκας (Γιακούτατ)", + "America\/Yellowknife": "Ορεινή ώρα Βόρειας Αμερικής (Γέλοουναϊφ)", + "Antarctica\/Casey": "Ώρα Δυτικής Αυστραλίας (Κάσεϊ)", + "Antarctica\/Davis": "Ώρα Ντέιβις (Ντέιβις)", + "Antarctica\/DumontDUrville": "Ώρα Ντιμόν ντ’ Ουρβίλ (Ντιμόν ντ’ Ουρβίλ)", + "Antarctica\/Macquarie": "Ώρα Νησιού Μακουάρι (Μακουάρι)", + "Antarctica\/Mawson": "Ώρα Μόσον (Μόσον)", + "Antarctica\/McMurdo": "Ώρα Νέας Ζηλανδίας (Μακμέρντο)", + "Antarctica\/Palmer": "Ώρα Χιλής (Πάλμερ)", + "Antarctica\/Rothera": "Ώρα Ρόθερα (Ρόθερα)", + "Antarctica\/Syowa": "Ώρα Σίοβα (Σίοβα)", + "Antarctica\/Troll": "Μέση ώρα Γκρίνουιτς (Τρολ)", + "Antarctica\/Vostok": "Ώρα Βόστοκ (Βόστοκ)", + "Arctic\/Longyearbyen": "Ώρα Κεντρικής Ευρώπης (Λόνγκιεαρμπιεν)", + "Asia\/Aden": "Αραβική ώρα (Άντεν)", + "Asia\/Almaty": "Ώρα Ανατολικού Καζακστάν (Αλμάτι)", + "Asia\/Amman": "Ώρα Ανατολικής Ευρώπης (Αμμάν)", + "Asia\/Anadyr": "Ώρα Αναντίρ (Αναντίρ)", + "Asia\/Aqtau": "Ώρα Δυτικού Καζακστάν (Ακτάου)", + "Asia\/Aqtobe": "Ώρα Δυτικού Καζακστάν (Ακτόμπε)", + "Asia\/Ashgabat": "Ώρα Τουρκμενιστάν (Ασχαμπάτ)", + "Asia\/Atyrau": "Ώρα Δυτικού Καζακστάν (Aτιράου)", + "Asia\/Baghdad": "Αραβική ώρα (Βαγδάτη)", + "Asia\/Bahrain": "Αραβική ώρα (Μπαχρέιν)", + "Asia\/Baku": "Ώρα Αζερμπαϊτζάν (Μπακού)", + "Asia\/Bangkok": "Ώρα Ινδοκίνας (Μπανγκόκ)", + "Asia\/Beirut": "Ώρα Ανατολικής Ευρώπης (Βυρητός)", + "Asia\/Bishkek": "Ώρα Κιργιστάν (Μπισκέκ)", + "Asia\/Brunei": "Ώρα Μπρουνέι Νταρουσαλάμ (Μπρουνέι)", + "Asia\/Calcutta": "Ώρα Ινδίας (Καλκούτα)", + "Asia\/Chita": "Ώρα Γιακούτσκ (Τσιτά)", + "Asia\/Choibalsan": "Ώρα Τσοϊμπαλσάν (Τσοϊμπαλσάν)", + "Asia\/Colombo": "Ώρα Ινδίας (Κολόμπο)", + "Asia\/Damascus": "Ώρα Ανατολικής Ευρώπης (Δαμασκός)", + "Asia\/Dhaka": "Ώρα Μπανγκλαντές (Ντάκα)", + "Asia\/Dili": "Ώρα Ανατολικού Τιμόρ (Ντίλι)", + "Asia\/Dubai": "Ώρα Κόλπου (Ντουμπάι)", + "Asia\/Dushanbe": "Ώρα Τατζικιστάν (Ντουσάνμπε)", + "Asia\/Famagusta": "Ώρα Ανατολικής Ευρώπης (Αμμόχωστος)", + "Asia\/Gaza": "Ώρα Ανατολικής Ευρώπης (Γάζα)", + "Asia\/Hebron": "Ώρα Ανατολικής Ευρώπης (Χεβρώνα)", + "Asia\/Hong_Kong": "Ώρα Χονγκ Κονγκ (Χονγκ Κονγκ)", + "Asia\/Hovd": "Ώρα Χοβντ (Χοβντ)", + "Asia\/Irkutsk": "Ώρα Ιρκούτσκ (Ιρκούτσκ)", + "Asia\/Jakarta": "Ώρα Δυτικής Ινδονησίας (Τζακάρτα)", + "Asia\/Jayapura": "Ώρα Ανατολικής Ινδονησίας (Τζαγιαπούρα)", + "Asia\/Jerusalem": "Ώρα Ισραήλ (Ιερουσαλήμ)", + "Asia\/Kabul": "Ώρα Αφγανιστάν (Καμπούλ)", + "Asia\/Kamchatka": "Ώρα Καμτσάτκα (Καμτσάτκα)", + "Asia\/Karachi": "Ώρα Πακιστάν (Καράτσι)", + "Asia\/Katmandu": "Ώρα Νεπάλ (Κατμαντού)", + "Asia\/Khandyga": "Ώρα Γιακούτσκ (Χαντίγκα)", + "Asia\/Krasnoyarsk": "Ώρα Κρασνογιάρσκ (Κρασνογιάρσκ)", + "Asia\/Kuala_Lumpur": "Ώρα Μαλαισίας (Κουάλα Λουμπούρ)", + "Asia\/Kuching": "Ώρα Μαλαισίας (Κουτσίνγκ)", + "Asia\/Kuwait": "Αραβική ώρα (Κουβέιτ)", + "Asia\/Macau": "Ώρα Κίνας (Μακάο)", + "Asia\/Magadan": "Ώρα Μαγκαντάν (Μαγκαντάν)", + "Asia\/Makassar": "Ώρα Κεντρικής Ινδονησίας (Μακασάρ)", + "Asia\/Manila": "Ώρα Φιλιππινών (Μανίλα)", + "Asia\/Muscat": "Ώρα Κόλπου (Μασκάτ)", + "Asia\/Nicosia": "Ώρα Ανατολικής Ευρώπης (Λευκωσία)", + "Asia\/Novokuznetsk": "Ώρα Κρασνογιάρσκ (Νοβοκουζνέτσκ)", + "Asia\/Novosibirsk": "Ώρα Νοβοσιμπίρσκ (Νοβοσιμπίρσκ)", + "Asia\/Omsk": "Ώρα Ομσκ (Ομσκ)", + "Asia\/Oral": "Ώρα Δυτικού Καζακστάν (Οράλ)", + "Asia\/Phnom_Penh": "Ώρα Ινδοκίνας (Πνομ Πενχ)", + "Asia\/Pontianak": "Ώρα Δυτικής Ινδονησίας (Πόντιανακ)", + "Asia\/Pyongyang": "Ώρα Κορέας (Πιονγκγιάνγκ)", + "Asia\/Qatar": "Αραβική ώρα (Κατάρ)", + "Asia\/Qostanay": "Ώρα Ανατολικού Καζακστάν (Κοστανάι)", + "Asia\/Qyzylorda": "Ώρα Δυτικού Καζακστάν (Κιζιλορντά)", + "Asia\/Rangoon": "Ώρα Μιανμάρ (Ρανγκούν)", + "Asia\/Riyadh": "Αραβική ώρα (Ριάντ)", + "Asia\/Saigon": "Ώρα Ινδοκίνας (Πόλη Χο Τσι Μινχ)", + "Asia\/Sakhalin": "Ώρα Σαχαλίνης (Σαχαλίνη)", + "Asia\/Samarkand": "Ώρα Ουζμπεκιστάν (Σαμαρκάνδη)", + "Asia\/Seoul": "Ώρα Κορέας (Σεούλ)", + "Asia\/Shanghai": "Ώρα Κίνας (Σανγκάη)", + "Asia\/Singapore": "Ώρα Σιγκαπούρης (Σιγκαπούρη)", + "Asia\/Srednekolymsk": "Ώρα Μαγκαντάν (Σρεντνεκολίμσκ)", + "Asia\/Taipei": "Ώρα Ταϊπέι (Ταϊπέι)", + "Asia\/Tashkent": "Ώρα Ουζμπεκιστάν (Τασκένδη)", + "Asia\/Tbilisi": "Ώρα Γεωργίας (Τιφλίδα)", + "Asia\/Tehran": "Ώρα Ιράν (Τεχεράνη)", + "Asia\/Thimphu": "Ώρα Μπουτάν (Θίμφου)", + "Asia\/Tokyo": "Ώρα Ιαπωνίας (Τόκιο)", + "Asia\/Ulaanbaatar": "Ώρα Ουλάν Μπατόρ (Ουλάν Μπατόρ)", + "Asia\/Ust-Nera": "Ώρα Βλαδιβοστόκ (Ουστ-Νερά)", + "Asia\/Vientiane": "Ώρα Ινδοκίνας (Βιεντιάν)", + "Asia\/Vladivostok": "Ώρα Βλαδιβοστόκ (Βλαδιβοστόκ)", + "Asia\/Yakutsk": "Ώρα Γιακούτσκ (Γιακούτσκ)", + "Asia\/Yekaterinburg": "Ώρα Αικατερίνμπουργκ (Αικατερινούπολη)", + "Asia\/Yerevan": "Ώρα Αρμενίας (Ερεβάν)", + "Atlantic\/Azores": "Ώρα Αζορών (Αζόρες)", + "Atlantic\/Bermuda": "Ώρα Ατλαντικού (Βερμούδες)", + "Atlantic\/Canary": "Ώρα Δυτικής Ευρώπης (Κανάρια)", + "Atlantic\/Cape_Verde": "Ώρα Πράσινου Ακρωτηρίου (Πράσινο Ακρωτήριο)", + "Atlantic\/Faeroe": "Ώρα Δυτικής Ευρώπης (Φερόες)", + "Atlantic\/Madeira": "Ώρα Δυτικής Ευρώπης (Μαδέρα)", + "Atlantic\/Reykjavik": "Μέση ώρα Γκρίνουιτς (Ρέυκιαβικ)", + "Atlantic\/South_Georgia": "Ώρα Νότιας Γεωργίας (Νότια Γεωργία)", + "Atlantic\/St_Helena": "Μέση ώρα Γκρίνουιτς (Αγ. Ελένη)", + "Atlantic\/Stanley": "Ώρα Νήσων Φόκλαντ (Στάνλεϊ)", + "Australia\/Adelaide": "Ώρα Κεντρικής Αυστραλίας (Αδελαΐδα)", + "Australia\/Brisbane": "Ώρα Ανατολικής Αυστραλίας (Μπρισμπέιν)", + "Australia\/Broken_Hill": "Ώρα Κεντρικής Αυστραλίας (Μπρόκεν Χιλ)", + "Australia\/Currie": "Ώρα Ανατολικής Αυστραλίας (Κάρι)", + "Australia\/Darwin": "Ώρα Κεντρικής Αυστραλίας (Ντάργουιν)", + "Australia\/Eucla": "Ώρα Κεντροδυτικής Αυστραλίας (Γιούκλα)", + "Australia\/Hobart": "Ώρα Ανατολικής Αυστραλίας (Χόμπαρτ)", + "Australia\/Lindeman": "Ώρα Ανατολικής Αυστραλίας (Λίντεμαν)", + "Australia\/Lord_Howe": "Ώρα Λορντ Χάου (Λορντ Χάου)", + "Australia\/Melbourne": "Ώρα Ανατολικής Αυστραλίας (Μελβούρνη)", + "Australia\/Perth": "Ώρα Δυτικής Αυστραλίας (Περθ)", + "Australia\/Sydney": "Ώρα Ανατολικής Αυστραλίας (Σίδνεϊ)", + "CST6CDT": "Κεντρική ώρα Βόρειας Αμερικής", + "EST5EDT": "Ανατολική ώρα Βόρειας Αμερικής", + "Etc\/GMT": "Μέση ώρα Γκρίνουιτς", + "Etc\/UTC": "Συντονισμένη Παγκόσμια Ώρα", + "Europe\/Amsterdam": "Ώρα Κεντρικής Ευρώπης (Άμστερνταμ)", + "Europe\/Andorra": "Ώρα Κεντρικής Ευρώπης (Ανδόρα)", + "Europe\/Astrakhan": "Ώρα Μόσχας (Αστραχάν)", + "Europe\/Athens": "Ώρα Ανατολικής Ευρώπης (Αθήνα)", + "Europe\/Belgrade": "Ώρα Κεντρικής Ευρώπης (Βελιγράδι)", + "Europe\/Berlin": "Ώρα Κεντρικής Ευρώπης (Βερολίνο)", + "Europe\/Bratislava": "Ώρα Κεντρικής Ευρώπης (Μπρατισλάβα)", + "Europe\/Brussels": "Ώρα Κεντρικής Ευρώπης (Βρυξέλλες)", + "Europe\/Bucharest": "Ώρα Ανατολικής Ευρώπης (Βουκουρέστι)", + "Europe\/Budapest": "Ώρα Κεντρικής Ευρώπης (Βουδαπέστη)", + "Europe\/Busingen": "Ώρα Κεντρικής Ευρώπης (Μπίσινγκεν)", + "Europe\/Chisinau": "Ώρα Ανατολικής Ευρώπης (Κισινάου)", + "Europe\/Copenhagen": "Ώρα Κεντρικής Ευρώπης (Κοπεγχάγη)", + "Europe\/Dublin": "Μέση ώρα Γκρίνουιτς (Δουβλίνο)", + "Europe\/Gibraltar": "Ώρα Κεντρικής Ευρώπης (Γιβραλτάρ)", + "Europe\/Guernsey": "Μέση ώρα Γκρίνουιτς (Γκέρνζι)", + "Europe\/Helsinki": "Ώρα Ανατολικής Ευρώπης (Ελσίνκι)", + "Europe\/Isle_of_Man": "Μέση ώρα Γκρίνουιτς (Νήσος του Μαν)", + "Europe\/Jersey": "Μέση ώρα Γκρίνουιτς (Τζέρσεϊ)", + "Europe\/Kaliningrad": "Ώρα Ανατολικής Ευρώπης (Καλίνινγκραντ)", + "Europe\/Kiev": "Ώρα Ανατολικής Ευρώπης (Κίεβο)", + "Europe\/Lisbon": "Ώρα Δυτικής Ευρώπης (Λισαβόνα)", + "Europe\/Ljubljana": "Ώρα Κεντρικής Ευρώπης (Λιουμπλιάνα)", + "Europe\/London": "Μέση ώρα Γκρίνουιτς (Λονδίνο)", + "Europe\/Luxembourg": "Ώρα Κεντρικής Ευρώπης (Λουξεμβούργο)", + "Europe\/Madrid": "Ώρα Κεντρικής Ευρώπης (Μαδρίτη)", + "Europe\/Malta": "Ώρα Κεντρικής Ευρώπης (Μάλτα)", + "Europe\/Mariehamn": "Ώρα Ανατολικής Ευρώπης (Μάριεχαμν)", + "Europe\/Minsk": "Ώρα Μόσχας (Μινσκ)", + "Europe\/Monaco": "Ώρα Κεντρικής Ευρώπης (Μονακό)", + "Europe\/Moscow": "Ώρα Μόσχας (Μόσχα)", + "Europe\/Oslo": "Ώρα Κεντρικής Ευρώπης (Όσλο)", + "Europe\/Paris": "Ώρα Κεντρικής Ευρώπης (Παρίσι)", + "Europe\/Podgorica": "Ώρα Κεντρικής Ευρώπης (Ποντγκόριτσα)", + "Europe\/Prague": "Ώρα Κεντρικής Ευρώπης (Πράγα)", + "Europe\/Riga": "Ώρα Ανατολικής Ευρώπης (Ρίγα)", + "Europe\/Rome": "Ώρα Κεντρικής Ευρώπης (Ρώμη)", + "Europe\/Samara": "Ώρα Σάμαρας (Σαμάρα)", + "Europe\/San_Marino": "Ώρα Κεντρικής Ευρώπης (Άγιος Μαρίνος)", + "Europe\/Sarajevo": "Ώρα Κεντρικής Ευρώπης (Σαράγεβο)", + "Europe\/Saratov": "Ώρα Μόσχας (Σαράτοφ)", + "Europe\/Simferopol": "Ώρα Μόσχας (Συμφερόπολη)", + "Europe\/Skopje": "Ώρα Κεντρικής Ευρώπης (Σκόπια)", + "Europe\/Sofia": "Ώρα Ανατολικής Ευρώπης (Σόφια)", + "Europe\/Stockholm": "Ώρα Κεντρικής Ευρώπης (Στοκχόλμη)", + "Europe\/Tallinn": "Ώρα Ανατολικής Ευρώπης (Ταλίν)", + "Europe\/Tirane": "Ώρα Κεντρικής Ευρώπης (Τίρανα)", + "Europe\/Ulyanovsk": "Ώρα Μόσχας (Ουλιάνοφσκ)", + "Europe\/Uzhgorod": "Ώρα Ανατολικής Ευρώπης (Ούζχοροντ)", + "Europe\/Vaduz": "Ώρα Κεντρικής Ευρώπης (Βαντούζ)", + "Europe\/Vatican": "Ώρα Κεντρικής Ευρώπης (Βατικανό)", + "Europe\/Vienna": "Ώρα Κεντρικής Ευρώπης (Βιέννη)", + "Europe\/Vilnius": "Ώρα Ανατολικής Ευρώπης (Βίλνιους)", + "Europe\/Volgograd": "Ώρα Βόλγκογκραντ (Βόλγκοκραντ)", + "Europe\/Warsaw": "Ώρα Κεντρικής Ευρώπης (Βαρσοβία)", + "Europe\/Zagreb": "Ώρα Κεντρικής Ευρώπης (Ζάγκρεμπ)", + "Europe\/Zaporozhye": "Ώρα Ανατολικής Ευρώπης (Ζαπορόζιε)", + "Europe\/Zurich": "Ώρα Κεντρικής Ευρώπης (Ζυρίχη)", + "Indian\/Antananarivo": "Ώρα Ανατολικής Αφρικής (Ανταναναρίβο)", + "Indian\/Chagos": "Ώρα Ινδικού Ωκεανού (Τσάγκος)", + "Indian\/Christmas": "Ώρα Νήσου Χριστουγέννων (Νήσος Χριστουγέννων)", + "Indian\/Cocos": "Ώρα Νήσων Κόκος (Κόκος)", + "Indian\/Comoro": "Ώρα Ανατολικής Αφρικής (Κομόρο)", + "Indian\/Kerguelen": "Ώρα Γαλλικού Νότου και Ανταρκτικής (Κεργκελέν)", + "Indian\/Mahe": "Ώρα Σεϋχελλών (Μάχε)", + "Indian\/Maldives": "Ώρα Μαλδίβων (Μαλδίβες)", + "Indian\/Mauritius": "Ώρα Μαυρίκιου (Μαυρίκιος)", + "Indian\/Mayotte": "Ώρα Ανατολικής Αφρικής (Μαγιότ)", + "Indian\/Reunion": "Ώρα Ρεϊνιόν (Ρεϊνιόν)", + "MST7MDT": "Ορεινή ώρα Βόρειας Αμερικής", + "PST8PDT": "Ώρα Ειρηνικού", + "Pacific\/Apia": "Ώρα Απία (Απία)", + "Pacific\/Auckland": "Ώρα Νέας Ζηλανδίας (Όκλαντ)", + "Pacific\/Bougainville": "Ώρα Παπούας Νέας Γουινέας (Μπουγκενβίλ)", + "Pacific\/Chatham": "Ώρα Τσάταμ (Τσάταμ)", + "Pacific\/Easter": "Ώρα Νήσου Πάσχα (Νήσος Πάσχα)", + "Pacific\/Efate": "Ώρα Βανουάτου (Εφάτε)", + "Pacific\/Enderbury": "Ώρα Νήσων Φoίνιξ (Έντερμπερι)", + "Pacific\/Fakaofo": "Ώρα Τοκελάου (Φακαόφο)", + "Pacific\/Fiji": "Ώρα Φίτζι (Φίτζι)", + "Pacific\/Funafuti": "Ώρα Τουβαλού (Φουναφούτι)", + "Pacific\/Galapagos": "Ώρα Γκαλάπαγκος (Γκαλάπαγκος)", + "Pacific\/Gambier": "Ώρα Γκάμπιερ (Γκάμπιερ)", + "Pacific\/Guadalcanal": "Ώρα Νήσων Σολομώντος (Γκουανταλκανάλ)", + "Pacific\/Guam": "Ώρα Τσαμόρο (Γκουάμ)", + "Pacific\/Honolulu": "Ώρα Χαβάης-Αλεούτιων Νήσων (Χονολουλού)", + "Pacific\/Johnston": "Ώρα Χαβάης-Αλεούτιων Νήσων (Τζόνστον)", + "Pacific\/Kiritimati": "Ώρα Νήσων Λάιν (Κιριτιμάτι)", + "Pacific\/Kosrae": "Ώρα Κόσραϊ (Κόσραϊ)", + "Pacific\/Kwajalein": "Ώρα Νήσων Μάρσαλ (Κουατζαλέιν)", + "Pacific\/Majuro": "Ώρα Νήσων Μάρσαλ (Ματζούρο)", + "Pacific\/Marquesas": "Ώρα Μαρκέζας (Μαρκέζας)", + "Pacific\/Midway": "Ώρα Σαμόα (Μίντγουεϊ)", + "Pacific\/Nauru": "Ώρα Ναούρου (Ναούρου)", + "Pacific\/Niue": "Ώρα Νιούε (Νιούε)", + "Pacific\/Norfolk": "Ώρα Νήσου Νόρφολκ (Νόρφολκ)", + "Pacific\/Noumea": "Ώρα Νέας Καληδονίας (Νουμέα)", + "Pacific\/Pago_Pago": "Ώρα Σαμόα (Πάγκο Πάγκο)", + "Pacific\/Palau": "Ώρα Παλάου (Παλάου)", + "Pacific\/Pitcairn": "Ώρα Πίτκερν (Πίτκερν)", + "Pacific\/Ponape": "Ώρα Πονάπε (Πονάπε)", + "Pacific\/Port_Moresby": "Ώρα Παπούας Νέας Γουινέας (Πορτ Μόρεσμπι)", + "Pacific\/Rarotonga": "Ώρα Νήσων Κουκ (Ραροτόνγκα)", + "Pacific\/Saipan": "Ώρα Τσαμόρο (Σαϊπάν)", + "Pacific\/Tahiti": "Ώρα Ταϊτής (Ταϊτή)", + "Pacific\/Tarawa": "Ώρα Νήσων Γκίλμπερτ (Ταράουα)", + "Pacific\/Tongatapu": "Ώρα Τόνγκα (Τονγκατάπου)", + "Pacific\/Truk": "Ώρα Τσουκ (Τσουκ)", + "Pacific\/Wake": "Ώρα Νήσου Γουέικ (Γουέικ)", + "Pacific\/Wallis": "Ώρα Ουάλις και Φουτούνα (Γουάλις)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en.json b/src/Symfony/Component/Intl/Resources/data/timezones/en.json new file mode 100644 index 0000000000000..1400258a41700 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.65", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "East Africa Time (Addis Ababa)", + "Africa\/Algiers": "Central European Time (Algiers)", + "Africa\/Asmera": "East Africa Time (Asmara)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "West Africa Time (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Central Africa Time (Blantyre)", + "Africa\/Brazzaville": "West Africa Time (Brazzaville)", + "Africa\/Bujumbura": "Central Africa Time (Bujumbura)", + "Africa\/Cairo": "Eastern European Time (Cairo)", + "Africa\/Casablanca": "Western European Time (Casablanca)", + "Africa\/Ceuta": "Central European Time (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "East Africa Time (Dar es Salaam)", + "Africa\/Djibouti": "East Africa Time (Djibouti)", + "Africa\/Douala": "West Africa Time (Douala)", + "Africa\/El_Aaiun": "Western European Time (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Central Africa Time (Gaborone)", + "Africa\/Harare": "Central Africa Time (Harare)", + "Africa\/Johannesburg": "South Africa Standard Time (Johannesburg)", + "Africa\/Juba": "East Africa Time (Juba)", + "Africa\/Kampala": "East Africa Time (Kampala)", + "Africa\/Khartoum": "Central Africa Time (Khartoum)", + "Africa\/Kigali": "Central Africa Time (Kigali)", + "Africa\/Kinshasa": "West Africa Time (Kinshasa)", + "Africa\/Lagos": "West Africa Time (Lagos)", + "Africa\/Libreville": "West Africa Time (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lome)", + "Africa\/Luanda": "West Africa Time (Luanda)", + "Africa\/Lubumbashi": "Central Africa Time (Lubumbashi)", + "Africa\/Lusaka": "Central Africa Time (Lusaka)", + "Africa\/Malabo": "West Africa Time (Malabo)", + "Africa\/Maputo": "Central Africa Time (Maputo)", + "Africa\/Maseru": "South Africa Standard Time (Maseru)", + "Africa\/Mbabane": "South Africa Standard Time (Mbabane)", + "Africa\/Mogadishu": "East Africa Time (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "East Africa Time (Nairobi)", + "Africa\/Ndjamena": "West Africa Time (Ndjamena)", + "Africa\/Niamey": "West Africa Time (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "West Africa Time (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (São Tomé)", + "Africa\/Tripoli": "Eastern European Time (Tripoli)", + "Africa\/Tunis": "Central European Time (Tunis)", + "Africa\/Windhoek": "Central Africa Time (Windhoek)", + "America\/Adak": "Hawaii-Aleutian Time (Adak)", + "America\/Anchorage": "Alaska Time (Anchorage)", + "America\/Anguilla": "Atlantic Time (Anguilla)", + "America\/Antigua": "Atlantic Time (Antigua)", + "America\/Araguaina": "Brasilia Time (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentina Time (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentina Time (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentina Time (Salta)", + "America\/Argentina\/San_Juan": "Argentina Time (San Juan)", + "America\/Argentina\/San_Luis": "Western Argentina Time (San Luis)", + "America\/Argentina\/Tucuman": "Argentina Time (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentina Time (Ushuaia)", + "America\/Aruba": "Atlantic Time (Aruba)", + "America\/Asuncion": "Paraguay Time (Asunción)", + "America\/Bahia": "Brasilia Time (Bahia)", + "America\/Bahia_Banderas": "Central Time (Bahia Banderas)", + "America\/Barbados": "Atlantic Time (Barbados)", + "America\/Belem": "Brasilia Time (Belem)", + "America\/Belize": "Central Time (Belize)", + "America\/Blanc-Sablon": "Atlantic Time (Blanc-Sablon)", + "America\/Boa_Vista": "Amazon Time (Boa Vista)", + "America\/Bogota": "Colombia Time (Bogota)", + "America\/Boise": "Mountain Time (Boise)", + "America\/Buenos_Aires": "Argentina Time (Buenos Aires)", + "America\/Cambridge_Bay": "Mountain Time (Cambridge Bay)", + "America\/Campo_Grande": "Amazon Time (Campo Grande)", + "America\/Cancun": "Eastern Time (Cancun)", + "America\/Caracas": "Venezuela Time (Caracas)", + "America\/Catamarca": "Argentina Time (Catamarca)", + "America\/Cayenne": "French Guiana Time (Cayenne)", + "America\/Cayman": "Eastern Time (Cayman)", + "America\/Chicago": "Central Time (Chicago)", + "America\/Chihuahua": "Mexican Pacific Time (Chihuahua)", + "America\/Coral_Harbour": "Eastern Time (Atikokan)", + "America\/Cordoba": "Argentina Time (Cordoba)", + "America\/Costa_Rica": "Central Time (Costa Rica)", + "America\/Creston": "Mountain Time (Creston)", + "America\/Cuiaba": "Amazon Time (Cuiaba)", + "America\/Curacao": "Atlantic Time (Curaçao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Pacific Time (Dawson)", + "America\/Dawson_Creek": "Mountain Time (Dawson Creek)", + "America\/Denver": "Mountain Time (Denver)", + "America\/Detroit": "Eastern Time (Detroit)", + "America\/Dominica": "Atlantic Time (Dominica)", + "America\/Edmonton": "Mountain Time (Edmonton)", + "America\/Eirunepe": "Acre Time (Eirunepe)", + "America\/El_Salvador": "Central Time (El Salvador)", + "America\/Fort_Nelson": "Mountain Time (Fort Nelson)", + "America\/Fortaleza": "Brasilia Time (Fortaleza)", + "America\/Glace_Bay": "Atlantic Time (Glace Bay)", + "America\/Godthab": "West Greenland Time (Nuuk)", + "America\/Goose_Bay": "Atlantic Time (Goose Bay)", + "America\/Grand_Turk": "Eastern Time (Grand Turk)", + "America\/Grenada": "Atlantic Time (Grenada)", + "America\/Guadeloupe": "Atlantic Time (Guadeloupe)", + "America\/Guatemala": "Central Time (Guatemala)", + "America\/Guayaquil": "Ecuador Time (Guayaquil)", + "America\/Guyana": "Guyana Time (Guyana)", + "America\/Halifax": "Atlantic Time (Halifax)", + "America\/Havana": "Cuba Time (Havana)", + "America\/Hermosillo": "Mexican Pacific Time (Hermosillo)", + "America\/Indiana\/Knox": "Central Time (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern Time (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern Time (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Central Time (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern Time (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern Time (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern Time (Winamac, Indiana)", + "America\/Indianapolis": "Eastern Time (Indianapolis)", + "America\/Inuvik": "Mountain Time (Inuvik)", + "America\/Iqaluit": "Eastern Time (Iqaluit)", + "America\/Jamaica": "Eastern Time (Jamaica)", + "America\/Jujuy": "Argentina Time (Jujuy)", + "America\/Juneau": "Alaska Time (Juneau)", + "America\/Kentucky\/Monticello": "Eastern Time (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantic Time (Kralendijk)", + "America\/La_Paz": "Bolivia Time (La Paz)", + "America\/Lima": "Peru Time (Lima)", + "America\/Los_Angeles": "Pacific Time (Los Angeles)", + "America\/Louisville": "Eastern Time (Louisville)", + "America\/Lower_Princes": "Atlantic Time (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilia Time (Maceio)", + "America\/Managua": "Central Time (Managua)", + "America\/Manaus": "Amazon Time (Manaus)", + "America\/Marigot": "Atlantic Time (Marigot)", + "America\/Martinique": "Atlantic Time (Martinique)", + "America\/Matamoros": "Central Time (Matamoros)", + "America\/Mazatlan": "Mexican Pacific Time (Mazatlan)", + "America\/Mendoza": "Argentina Time (Mendoza)", + "America\/Menominee": "Central Time (Menominee)", + "America\/Merida": "Central Time (Merida)", + "America\/Metlakatla": "Alaska Time (Metlakatla)", + "America\/Mexico_City": "Central Time (Mexico City)", + "America\/Miquelon": "St. Pierre & Miquelon Time (Miquelon)", + "America\/Moncton": "Atlantic Time (Moncton)", + "America\/Monterrey": "Central Time (Monterrey)", + "America\/Montevideo": "Uruguay Time (Montevideo)", + "America\/Montserrat": "Atlantic Time (Montserrat)", + "America\/Nassau": "Eastern Time (Nassau)", + "America\/New_York": "Eastern Time (New York)", + "America\/Nipigon": "Eastern Time (Nipigon)", + "America\/Nome": "Alaska Time (Nome)", + "America\/Noronha": "Fernando de Noronha Time (Noronha)", + "America\/North_Dakota\/Beulah": "Central Time (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Central Time (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Central Time (New Salem, North Dakota)", + "America\/Ojinaga": "Mountain Time (Ojinaga)", + "America\/Panama": "Eastern Time (Panama)", + "America\/Pangnirtung": "Eastern Time (Pangnirtung)", + "America\/Paramaribo": "Suriname Time (Paramaribo)", + "America\/Phoenix": "Mountain Time (Phoenix)", + "America\/Port-au-Prince": "Eastern Time (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantic Time (Port of Spain)", + "America\/Porto_Velho": "Amazon Time (Porto Velho)", + "America\/Puerto_Rico": "Atlantic Time (Puerto Rico)", + "America\/Punta_Arenas": "Chile Time (Punta Arenas)", + "America\/Rainy_River": "Central Time (Rainy River)", + "America\/Rankin_Inlet": "Central Time (Rankin Inlet)", + "America\/Recife": "Brasilia Time (Recife)", + "America\/Regina": "Central Time (Regina)", + "America\/Resolute": "Central Time (Resolute)", + "America\/Rio_Branco": "Acre Time (Rio Branco)", + "America\/Santa_Isabel": "Northwest Mexico Time (Santa Isabel)", + "America\/Santarem": "Brasilia Time (Santarem)", + "America\/Santiago": "Chile Time (Santiago)", + "America\/Santo_Domingo": "Atlantic Time (Santo Domingo)", + "America\/Sao_Paulo": "Brasilia Time (Sao Paulo)", + "America\/Scoresbysund": "East Greenland Time (Ittoqqortoormiit)", + "America\/Sitka": "Alaska Time (Sitka)", + "America\/St_Barthelemy": "Atlantic Time (St. Barthélemy)", + "America\/St_Johns": "Newfoundland Time (St. John’s)", + "America\/St_Kitts": "Atlantic Time (St. Kitts)", + "America\/St_Lucia": "Atlantic Time (St. Lucia)", + "America\/St_Thomas": "Atlantic Time (St. Thomas)", + "America\/St_Vincent": "Atlantic Time (St. Vincent)", + "America\/Swift_Current": "Central Time (Swift Current)", + "America\/Tegucigalpa": "Central Time (Tegucigalpa)", + "America\/Thule": "Atlantic Time (Thule)", + "America\/Thunder_Bay": "Eastern Time (Thunder Bay)", + "America\/Tijuana": "Pacific Time (Tijuana)", + "America\/Toronto": "Eastern Time (Toronto)", + "America\/Tortola": "Atlantic Time (Tortola)", + "America\/Vancouver": "Pacific Time (Vancouver)", + "America\/Whitehorse": "Pacific Time (Whitehorse)", + "America\/Winnipeg": "Central Time (Winnipeg)", + "America\/Yakutat": "Alaska Time (Yakutat)", + "America\/Yellowknife": "Mountain Time (Yellowknife)", + "Antarctica\/Casey": "Western Australia Time (Casey)", + "Antarctica\/Davis": "Davis Time (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville Time (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie Island Time (Macquarie)", + "Antarctica\/Mawson": "Mawson Time (Mawson)", + "Antarctica\/McMurdo": "New Zealand Time (McMurdo)", + "Antarctica\/Palmer": "Chile Time (Palmer)", + "Antarctica\/Rothera": "Rothera Time (Rothera)", + "Antarctica\/Syowa": "Syowa Time (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Vostok Time (Vostok)", + "Arctic\/Longyearbyen": "Central European Time (Longyearbyen)", + "Asia\/Aden": "Arabian Time (Aden)", + "Asia\/Almaty": "East Kazakhstan Time (Almaty)", + "Asia\/Amman": "Eastern European Time (Amman)", + "Asia\/Anadyr": "Anadyr Time (Anadyr)", + "Asia\/Aqtau": "West Kazakhstan Time (Aqtau)", + "Asia\/Aqtobe": "West Kazakhstan Time (Aqtobe)", + "Asia\/Ashgabat": "Turkmenistan Time (Ashgabat)", + "Asia\/Atyrau": "West Kazakhstan Time (Atyrau)", + "Asia\/Baghdad": "Arabian Time (Baghdad)", + "Asia\/Bahrain": "Arabian Time (Bahrain)", + "Asia\/Baku": "Azerbaijan Time (Baku)", + "Asia\/Bangkok": "Indochina Time (Bangkok)", + "Asia\/Beirut": "Eastern European Time (Beirut)", + "Asia\/Bishkek": "Kyrgyzstan Time (Bishkek)", + "Asia\/Brunei": "Brunei Darussalam Time (Brunei)", + "Asia\/Calcutta": "India Standard Time (Kolkata)", + "Asia\/Chita": "Yakutsk Time (Chita)", + "Asia\/Choibalsan": "Choibalsan Time (Choibalsan)", + "Asia\/Colombo": "India Standard Time (Colombo)", + "Asia\/Damascus": "Eastern European Time (Damascus)", + "Asia\/Dhaka": "Bangladesh Time (Dhaka)", + "Asia\/Dili": "East Timor Time (Dili)", + "Asia\/Dubai": "Gulf Standard Time (Dubai)", + "Asia\/Dushanbe": "Tajikistan Time (Dushanbe)", + "Asia\/Famagusta": "Eastern European Time (Famagusta)", + "Asia\/Gaza": "Eastern European Time (Gaza)", + "Asia\/Hebron": "Eastern European Time (Hebron)", + "Asia\/Hong_Kong": "Hong Kong Time (Hong Kong)", + "Asia\/Hovd": "Hovd Time (Hovd)", + "Asia\/Irkutsk": "Irkutsk Time (Irkutsk)", + "Asia\/Jakarta": "Western Indonesia Time (Jakarta)", + "Asia\/Jayapura": "Eastern Indonesia Time (Jayapura)", + "Asia\/Jerusalem": "Israel Time (Jerusalem)", + "Asia\/Kabul": "Afghanistan Time (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamchatski Time (Kamchatka)", + "Asia\/Karachi": "Pakistan Time (Karachi)", + "Asia\/Katmandu": "Nepal Time (Kathmandu)", + "Asia\/Khandyga": "Yakutsk Time (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnoyarsk Time (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malaysia Time (Kuala Lumpur)", + "Asia\/Kuching": "Malaysia Time (Kuching)", + "Asia\/Kuwait": "Arabian Time (Kuwait)", + "Asia\/Macau": "China Time (Macao)", + "Asia\/Magadan": "Magadan Time (Magadan)", + "Asia\/Makassar": "Central Indonesia Time (Makassar)", + "Asia\/Manila": "Philippine Time (Manila)", + "Asia\/Muscat": "Gulf Standard Time (Muscat)", + "Asia\/Nicosia": "Eastern European Time (Nicosia)", + "Asia\/Novokuznetsk": "Krasnoyarsk Time (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk Time (Novosibirsk)", + "Asia\/Omsk": "Omsk Time (Omsk)", + "Asia\/Oral": "West Kazakhstan Time (Oral)", + "Asia\/Phnom_Penh": "Indochina Time (Phnom Penh)", + "Asia\/Pontianak": "Western Indonesia Time (Pontianak)", + "Asia\/Pyongyang": "Korean Time (Pyongyang)", + "Asia\/Qatar": "Arabian Time (Qatar)", + "Asia\/Qostanay": "East Kazakhstan Time (Kostanay)", + "Asia\/Qyzylorda": "West Kazakhstan Time (Qyzylorda)", + "Asia\/Rangoon": "Myanmar Time (Yangon)", + "Asia\/Riyadh": "Arabian Time (Riyadh)", + "Asia\/Saigon": "Indochina Time (Ho Chi Minh City)", + "Asia\/Sakhalin": "Sakhalin Time (Sakhalin)", + "Asia\/Samarkand": "Uzbekistan Time (Samarkand)", + "Asia\/Seoul": "Korean Time (Seoul)", + "Asia\/Shanghai": "China Time (Shanghai)", + "Asia\/Singapore": "Singapore Standard Time (Singapore)", + "Asia\/Srednekolymsk": "Magadan Time (Srednekolymsk)", + "Asia\/Taipei": "Taipei Time (Taipei)", + "Asia\/Tashkent": "Uzbekistan Time (Tashkent)", + "Asia\/Tbilisi": "Georgia Time (Tbilisi)", + "Asia\/Tehran": "Iran Time (Tehran)", + "Asia\/Thimphu": "Bhutan Time (Thimphu)", + "Asia\/Tokyo": "Japan Time (Tokyo)", + "Asia\/Ulaanbaatar": "Ulaanbaatar Time (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostok Time (Ust-Nera)", + "Asia\/Vientiane": "Indochina Time (Vientiane)", + "Asia\/Vladivostok": "Vladivostok Time (Vladivostok)", + "Asia\/Yakutsk": "Yakutsk Time (Yakutsk)", + "Asia\/Yekaterinburg": "Yekaterinburg Time (Yekaterinburg)", + "Asia\/Yerevan": "Armenia Time (Yerevan)", + "Atlantic\/Azores": "Azores Time (Azores)", + "Atlantic\/Bermuda": "Atlantic Time (Bermuda)", + "Atlantic\/Canary": "Western European Time (Canary)", + "Atlantic\/Cape_Verde": "Cape Verde Time (Cape Verde)", + "Atlantic\/Faeroe": "Western European Time (Faroe)", + "Atlantic\/Madeira": "Western European Time (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/South_Georgia": "South Georgia Time (South Georgia)", + "Atlantic\/St_Helena": "Greenwich Mean Time (St. Helena)", + "Atlantic\/Stanley": "Falkland Islands Time (Stanley)", + "Australia\/Adelaide": "Central Australia Time (Adelaide)", + "Australia\/Brisbane": "Eastern Australia Time (Brisbane)", + "Australia\/Broken_Hill": "Central Australia Time (Broken Hill)", + "Australia\/Currie": "Eastern Australia Time (Currie)", + "Australia\/Darwin": "Central Australia Time (Darwin)", + "Australia\/Eucla": "Australian Central Western Time (Eucla)", + "Australia\/Hobart": "Eastern Australia Time (Hobart)", + "Australia\/Lindeman": "Eastern Australia Time (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe Time (Lord Howe)", + "Australia\/Melbourne": "Eastern Australia Time (Melbourne)", + "Australia\/Perth": "Western Australia Time (Perth)", + "Australia\/Sydney": "Eastern Australia Time (Sydney)", + "CST6CDT": "Central Time", + "EST5EDT": "Eastern Time", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Coordinated Universal Time", + "Europe\/Amsterdam": "Central European Time (Amsterdam)", + "Europe\/Andorra": "Central European Time (Andorra)", + "Europe\/Astrakhan": "Moscow Time (Astrakhan)", + "Europe\/Athens": "Eastern European Time (Athens)", + "Europe\/Belgrade": "Central European Time (Belgrade)", + "Europe\/Berlin": "Central European Time (Berlin)", + "Europe\/Bratislava": "Central European Time (Bratislava)", + "Europe\/Brussels": "Central European Time (Brussels)", + "Europe\/Bucharest": "Eastern European Time (Bucharest)", + "Europe\/Budapest": "Central European Time (Budapest)", + "Europe\/Busingen": "Central European Time (Busingen)", + "Europe\/Chisinau": "Eastern European Time (Chisinau)", + "Europe\/Copenhagen": "Central European Time (Copenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Central European Time (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Eastern European Time (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Eastern European Time (Kaliningrad)", + "Europe\/Kiev": "Eastern European Time (Kiev)", + "Europe\/Lisbon": "Western European Time (Lisbon)", + "Europe\/Ljubljana": "Central European Time (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (London)", + "Europe\/Luxembourg": "Central European Time (Luxembourg)", + "Europe\/Madrid": "Central European Time (Madrid)", + "Europe\/Malta": "Central European Time (Malta)", + "Europe\/Mariehamn": "Eastern European Time (Mariehamn)", + "Europe\/Minsk": "Moscow Time (Minsk)", + "Europe\/Monaco": "Central European Time (Monaco)", + "Europe\/Moscow": "Moscow Time (Moscow)", + "Europe\/Oslo": "Central European Time (Oslo)", + "Europe\/Paris": "Central European Time (Paris)", + "Europe\/Podgorica": "Central European Time (Podgorica)", + "Europe\/Prague": "Central European Time (Prague)", + "Europe\/Riga": "Eastern European Time (Riga)", + "Europe\/Rome": "Central European Time (Rome)", + "Europe\/Samara": "Samara Time (Samara)", + "Europe\/San_Marino": "Central European Time (San Marino)", + "Europe\/Sarajevo": "Central European Time (Sarajevo)", + "Europe\/Saratov": "Moscow Time (Saratov)", + "Europe\/Simferopol": "Moscow Time (Simferopol)", + "Europe\/Skopje": "Central European Time (Skopje)", + "Europe\/Sofia": "Eastern European Time (Sofia)", + "Europe\/Stockholm": "Central European Time (Stockholm)", + "Europe\/Tallinn": "Eastern European Time (Tallinn)", + "Europe\/Tirane": "Central European Time (Tirane)", + "Europe\/Ulyanovsk": "Moscow Time (Ulyanovsk)", + "Europe\/Uzhgorod": "Eastern European Time (Uzhhorod)", + "Europe\/Vaduz": "Central European Time (Vaduz)", + "Europe\/Vatican": "Central European Time (Vatican)", + "Europe\/Vienna": "Central European Time (Vienna)", + "Europe\/Vilnius": "Eastern European Time (Vilnius)", + "Europe\/Volgograd": "Volgograd Time (Volgograd)", + "Europe\/Warsaw": "Central European Time (Warsaw)", + "Europe\/Zagreb": "Central European Time (Zagreb)", + "Europe\/Zaporozhye": "Eastern European Time (Zaporozhye)", + "Europe\/Zurich": "Central European Time (Zurich)", + "Indian\/Antananarivo": "East Africa Time (Antananarivo)", + "Indian\/Chagos": "Indian Ocean Time (Chagos)", + "Indian\/Christmas": "Christmas Island Time (Christmas)", + "Indian\/Cocos": "Cocos Islands Time (Cocos)", + "Indian\/Comoro": "East Africa Time (Comoro)", + "Indian\/Kerguelen": "French Southern & Antarctic Time (Kerguelen)", + "Indian\/Mahe": "Seychelles Time (Mahe)", + "Indian\/Maldives": "Maldives Time (Maldives)", + "Indian\/Mauritius": "Mauritius Time (Mauritius)", + "Indian\/Mayotte": "East Africa Time (Mayotte)", + "Indian\/Reunion": "Réunion Time (Réunion)", + "MST7MDT": "Mountain Time", + "PST8PDT": "Pacific Time", + "Pacific\/Apia": "Apia Time (Apia)", + "Pacific\/Auckland": "New Zealand Time (Auckland)", + "Pacific\/Bougainville": "Papua New Guinea Time (Bougainville)", + "Pacific\/Chatham": "Chatham Time (Chatham)", + "Pacific\/Easter": "Easter Island Time (Easter)", + "Pacific\/Efate": "Vanuatu Time (Efate)", + "Pacific\/Enderbury": "Phoenix Islands Time (Enderbury)", + "Pacific\/Fakaofo": "Tokelau Time (Fakaofo)", + "Pacific\/Fiji": "Fiji Time (Fiji)", + "Pacific\/Funafuti": "Tuvalu Time (Funafuti)", + "Pacific\/Galapagos": "Galapagos Time (Galapagos)", + "Pacific\/Gambier": "Gambier Time (Gambier)", + "Pacific\/Guadalcanal": "Solomon Islands Time (Guadalcanal)", + "Pacific\/Guam": "Chamorro Standard Time (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleutian Time (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleutian Time (Johnston)", + "Pacific\/Kiritimati": "Line Islands Time (Kiritimati)", + "Pacific\/Kosrae": "Kosrae Time (Kosrae)", + "Pacific\/Kwajalein": "Marshall Islands Time (Kwajalein)", + "Pacific\/Majuro": "Marshall Islands Time (Majuro)", + "Pacific\/Marquesas": "Marquesas Time (Marquesas)", + "Pacific\/Midway": "Samoa Time (Midway)", + "Pacific\/Nauru": "Nauru Time (Nauru)", + "Pacific\/Niue": "Niue Time (Niue)", + "Pacific\/Norfolk": "Norfolk Island Time (Norfolk)", + "Pacific\/Noumea": "New Caledonia Time (Noumea)", + "Pacific\/Pago_Pago": "Samoa Time (Pago Pago)", + "Pacific\/Palau": "Palau Time (Palau)", + "Pacific\/Pitcairn": "Pitcairn Time (Pitcairn)", + "Pacific\/Ponape": "Ponape Time (Pohnpei)", + "Pacific\/Port_Moresby": "Papua New Guinea Time (Port Moresby)", + "Pacific\/Rarotonga": "Cook Islands Time (Rarotonga)", + "Pacific\/Saipan": "Chamorro Standard Time (Saipan)", + "Pacific\/Tahiti": "Tahiti Time (Tahiti)", + "Pacific\/Tarawa": "Gilbert Islands Time (Tarawa)", + "Pacific\/Tongatapu": "Tonga Time (Tongatapu)", + "Pacific\/Truk": "Chuuk Time (Chuuk)", + "Pacific\/Wake": "Wake Island Time (Wake)", + "Pacific\/Wallis": "Wallis & Futuna Time (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_001.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_001.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_001.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_150.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_150.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_150.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_AE.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_AE.json new file mode 100644 index 0000000000000..5bb84099f22c7 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_AE.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.48.67", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_AU.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_AU.json new file mode 100644 index 0000000000000..031cf50752b59 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_AU.json @@ -0,0 +1,77 @@ +{ + "Version": "2.1.48.43", + "Names": { + "Africa\/Addis_Ababa": "Eastern Africa Time (Addis Ababa)", + "Africa\/Asmera": "Eastern Africa Time (Asmara)", + "Africa\/Cairo": "Eastern European Standard Time (Cairo)", + "Africa\/Dar_es_Salaam": "Eastern Africa Time (Dar es Salaam)", + "Africa\/Djibouti": "Eastern Africa Time (Djibouti)", + "Africa\/Juba": "Eastern Africa Time (Juba)", + "Africa\/Kampala": "Eastern Africa Time (Kampala)", + "Africa\/Mogadishu": "Eastern Africa Time (Mogadishu)", + "Africa\/Nairobi": "Eastern Africa Time (Nairobi)", + "Africa\/Tripoli": "Eastern European Standard Time (Tripoli)", + "America\/Boa_Vista": "Amazon Standard Time (Boa Vista)", + "America\/Campo_Grande": "Amazon Standard Time (Campo Grande)", + "America\/Cuiaba": "Amazon Standard Time (Cuiaba)", + "America\/Manaus": "Amazon Standard Time (Manaus)", + "America\/Porto_Velho": "Amazon Standard Time (Porto Velho)", + "Antarctica\/Casey": "Australian Western Time (Casey)", + "Asia\/Aden": "Arabia Time (Aden)", + "Asia\/Amman": "Eastern European Standard Time (Amman)", + "Asia\/Baghdad": "Arabia Time (Baghdad)", + "Asia\/Bahrain": "Arabia Time (Bahrain)", + "Asia\/Beirut": "Eastern European Standard Time (Beirut)", + "Asia\/Damascus": "Eastern European Standard Time (Damascus)", + "Asia\/Famagusta": "Eastern European Standard Time (Famagusta)", + "Asia\/Gaza": "Eastern European Standard Time (Gaza)", + "Asia\/Hebron": "Eastern European Standard Time (Hebron)", + "Asia\/Jerusalem": "Israel Time (Jerusalem)", + "Asia\/Kuwait": "Arabia Time (Kuwait)", + "Asia\/Macau": "China Standard Time (Macao)", + "Asia\/Nicosia": "Eastern European Standard Time (Nicosia)", + "Asia\/Pyongyang": "Korea Time (Pyongyang)", + "Asia\/Qatar": "Arabia Time (Qatar)", + "Asia\/Riyadh": "Arabia Time (Riyadh)", + "Asia\/Seoul": "Korea Time (Seoul)", + "Asia\/Shanghai": "China Standard Time (Shanghai)", + "Asia\/Taipei": "Taipei Time (Taipei)", + "Asia\/Tehran": "Iran Time (Tehran)", + "Asia\/Tokyo": "Japan Time (Tokyo)", + "Australia\/Adelaide": "Australian Central Time (Adelaide)", + "Australia\/Brisbane": "Australian Eastern Time (Brisbane)", + "Australia\/Broken_Hill": "Australian Central Time (Broken Hill)", + "Australia\/Currie": "Australian Eastern Time (Currie)", + "Australia\/Darwin": "Australian Central Time (Darwin)", + "Australia\/Hobart": "Australian Eastern Time (Hobart)", + "Australia\/Lindeman": "Australian Eastern Time (Lindeman)", + "Australia\/Melbourne": "Australian Eastern Time (Melbourne)", + "Australia\/Perth": "Australian Western Time (Perth)", + "Australia\/Sydney": "Australian Eastern Time (Sydney)", + "Europe\/Astrakhan": "Moscow Time (Astrakhan)", + "Europe\/Athens": "Eastern European Standard Time (Athens)", + "Europe\/Bucharest": "Eastern European Standard Time (Bucharest)", + "Europe\/Chisinau": "Eastern European Standard Time (Chisinau)", + "Europe\/Helsinki": "Eastern European Standard Time (Helsinki)", + "Europe\/Kaliningrad": "Eastern European Standard Time (Kaliningrad)", + "Europe\/Kiev": "Eastern European Standard Time (Kiev)", + "Europe\/Mariehamn": "Eastern European Standard Time (Mariehamn)", + "Europe\/Minsk": "Moscow Time (Minsk)", + "Europe\/Moscow": "Moscow Time (Moscow)", + "Europe\/Riga": "Eastern European Standard Time (Riga)", + "Europe\/Saratov": "Moscow Time (Saratov)", + "Europe\/Simferopol": "Moscow Time (Simferopol)", + "Europe\/Sofia": "Eastern European Standard Time (Sofia)", + "Europe\/Tallinn": "Eastern European Standard Time (Tallinn)", + "Europe\/Ulyanovsk": "Moscow Time (Ulyanovsk)", + "Europe\/Uzhgorod": "Eastern European Standard Time (Uzhgorod)", + "Europe\/Vilnius": "Eastern European Standard Time (Vilnius)", + "Europe\/Zaporozhye": "Eastern European Standard Time (Zaporozhye)", + "Indian\/Antananarivo": "Eastern Africa Time (Antananarivo)", + "Indian\/Comoro": "Eastern Africa Time (Comoro)", + "Indian\/Mayotte": "Eastern Africa Time (Mayotte)", + "Pacific\/Midway": "Samoa Time (Midway)", + "Pacific\/Pago_Pago": "Samoa Time (Pago Pago)", + "Pacific\/Rarotonga": "Cook Island Time (Rarotonga)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_BW.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_BW.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_BW.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_CA.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_CA.json new file mode 100644 index 0000000000000..c4e66e1dbf16b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_CA.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.86", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_CM.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_CM.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_CM.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_ER.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_ER.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_ER.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_GB.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_GB.json new file mode 100644 index 0000000000000..d8cd93943f05b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_GB.json @@ -0,0 +1,9 @@ +{ + "Version": "2.1.47.86", + "Names": { + "America\/Miquelon": "St Pierre & Miquelon Time (Miquelon)", + "Australia\/Adelaide": "Central Australia Time (Adelaide)", + "Australia\/Broken_Hill": "Central Australia Time (Broken Hill)", + "Australia\/Darwin": "Central Australia Time (Darwin)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_GH.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_GH.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_GH.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_GM.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_GM.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_GM.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_GU.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_GU.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_GU.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_GY.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_GY.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_GY.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_HK.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_HK.json new file mode 100644 index 0000000000000..c4e66e1dbf16b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_HK.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.86", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_IE.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_IE.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_IE.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_IN.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_IN.json new file mode 100644 index 0000000000000..2bbb2abf12f88 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_IN.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.49.14", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_KE.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_KE.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_KE.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_LR.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_LR.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_LR.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_LS.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_LS.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_LS.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MG.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MG.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MH.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MH.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MH.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MO.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MO.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MO.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MP.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MP.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MP.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MU.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MU.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MU.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MW.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MW.json new file mode 100644 index 0000000000000..3d2a381ae7179 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MW.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.69", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_MY.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_MY.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_MY.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_NA.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_NA.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_NA.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_NG.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_NG.json new file mode 100644 index 0000000000000..13dd4bb13912b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_NG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.48.22", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_NZ.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_NZ.json new file mode 100644 index 0000000000000..c4e66e1dbf16b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_NZ.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.86", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_RH.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_RH.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_RH.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_RW.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_RW.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_RW.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_SD.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_SD.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_SD.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_SG.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_SG.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_SG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_SL.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_SL.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_SL.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_SS.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_SS.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_SS.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_SZ.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_SZ.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_SZ.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_TZ.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_TZ.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_TZ.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_UG.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_UG.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_UG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_ZA.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_ZA.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_ZA.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_ZM.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_ZM.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_ZM.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/en_ZW.json b/src/Symfony/Component/Intl/Resources/data/timezones/en_ZW.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/en_ZW.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es.json b/src/Symfony/Component/Intl/Resources/data/timezones/es.json new file mode 100644 index 0000000000000..19d773e0f0025 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.20", + "Names": { + "Africa\/Abidjan": "hora del meridiano de Greenwich (Abiyán)", + "Africa\/Accra": "hora del meridiano de Greenwich (Acra)", + "Africa\/Addis_Ababa": "hora de África oriental (Addis Abeba)", + "Africa\/Algiers": "hora de Europa central (Argel)", + "Africa\/Asmera": "hora de África oriental (Asmara)", + "Africa\/Bamako": "hora del meridiano de Greenwich (Bamako)", + "Africa\/Bangui": "hora de África occidental (Bangui)", + "Africa\/Banjul": "hora del meridiano de Greenwich (Banjul)", + "Africa\/Bissau": "hora del meridiano de Greenwich (Bisáu)", + "Africa\/Blantyre": "hora de África central (Blantyre)", + "Africa\/Brazzaville": "hora de África occidental (Brazzaville)", + "Africa\/Bujumbura": "hora de África central (Bujumbura)", + "Africa\/Cairo": "hora de Europa oriental (El Cairo)", + "Africa\/Casablanca": "hora de Europa occidental (Casablanca)", + "Africa\/Ceuta": "hora de Europa central (Ceuta)", + "Africa\/Conakry": "hora del meridiano de Greenwich (Conakry)", + "Africa\/Dakar": "hora del meridiano de Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "hora de África oriental (Dar es Salaam)", + "Africa\/Djibouti": "hora de África oriental (Yibuti)", + "Africa\/Douala": "hora de África occidental (Duala)", + "Africa\/El_Aaiun": "hora de Europa occidental (El Aaiún)", + "Africa\/Freetown": "hora del meridiano de Greenwich (Freetown)", + "Africa\/Gaborone": "hora de África central (Gaborone)", + "Africa\/Harare": "hora de África central (Harare)", + "Africa\/Johannesburg": "hora de Sudáfrica (Johannesburgo)", + "Africa\/Juba": "hora de África oriental (Juba)", + "Africa\/Kampala": "hora de África oriental (Kampala)", + "Africa\/Khartoum": "hora de África central (Jartún)", + "Africa\/Kigali": "hora de África central (Kigali)", + "Africa\/Kinshasa": "hora de África occidental (Kinshasa)", + "Africa\/Lagos": "hora de África occidental (Lagos)", + "Africa\/Libreville": "hora de África occidental (Libreville)", + "Africa\/Lome": "hora del meridiano de Greenwich (Lomé)", + "Africa\/Luanda": "hora de África occidental (Luanda)", + "Africa\/Lubumbashi": "hora de África central (Lubumbashi)", + "Africa\/Lusaka": "hora de África central (Lusaka)", + "Africa\/Malabo": "hora de África occidental (Malabo)", + "Africa\/Maputo": "hora de África central (Maputo)", + "Africa\/Maseru": "hora de Sudáfrica (Maseru)", + "Africa\/Mbabane": "hora de Sudáfrica (Mbabane)", + "Africa\/Mogadishu": "hora de África oriental (Mogadiscio)", + "Africa\/Monrovia": "hora del meridiano de Greenwich (Monrovia)", + "Africa\/Nairobi": "hora de África oriental (Nairobi)", + "Africa\/Ndjamena": "hora de África occidental (Yamena)", + "Africa\/Niamey": "hora de África occidental (Niamey)", + "Africa\/Nouakchott": "hora del meridiano de Greenwich (Nuakchot)", + "Africa\/Ouagadougou": "hora del meridiano de Greenwich (Uagadugú)", + "Africa\/Porto-Novo": "hora de África occidental (Portonovo)", + "Africa\/Sao_Tome": "hora del meridiano de Greenwich (Santo Tomé)", + "Africa\/Tripoli": "hora de Europa oriental (Trípoli)", + "Africa\/Tunis": "hora de Europa central (Túnez)", + "Africa\/Windhoek": "hora de África central (Windhoek)", + "America\/Adak": "hora de Hawái-Aleutianas (Adak)", + "America\/Anchorage": "hora de Alaska (Anchorage)", + "America\/Anguilla": "hora del Atlántico (Anguila)", + "America\/Antigua": "hora del Atlántico (Antigua)", + "America\/Araguaina": "hora de Brasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "hora de Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "hora de Argentina (Río Gallegos)", + "America\/Argentina\/Salta": "hora de Argentina (Salta)", + "America\/Argentina\/San_Juan": "hora de Argentina (San Juan)", + "America\/Argentina\/San_Luis": "hora de Argentina occidental (San Luis)", + "America\/Argentina\/Tucuman": "hora de Argentina (Tucumán)", + "America\/Argentina\/Ushuaia": "hora de Argentina (Ushuaia)", + "America\/Aruba": "hora del Atlántico (Aruba)", + "America\/Asuncion": "hora de Paraguay (Asunción)", + "America\/Bahia": "hora de Brasilia (Bahía)", + "America\/Bahia_Banderas": "hora central (Bahía de Banderas)", + "America\/Barbados": "hora del Atlántico (Barbados)", + "America\/Belem": "hora de Brasilia (Belén)", + "America\/Belize": "hora central (Belice)", + "America\/Blanc-Sablon": "hora del Atlántico (Blanc-Sablon)", + "America\/Boa_Vista": "hora del Amazonas (Boa Vista)", + "America\/Bogota": "hora de Colombia (Bogotá)", + "America\/Boise": "hora de las Montañas Rocosas (Boise)", + "America\/Buenos_Aires": "hora de Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "hora de las Montañas Rocosas (Cambridge Bay)", + "America\/Campo_Grande": "hora del Amazonas (Campo Grande)", + "America\/Cancun": "hora oriental (Cancún)", + "America\/Caracas": "hora de Venezuela (Caracas)", + "America\/Catamarca": "hora de Argentina (Catamarca)", + "America\/Cayenne": "hora de la Guayana Francesa (Cayena)", + "America\/Cayman": "hora oriental (Caimán)", + "America\/Chicago": "hora central (Chicago)", + "America\/Chihuahua": "hora del Pacífico de México (Chihuahua)", + "America\/Coral_Harbour": "hora oriental (Atikokan)", + "America\/Cordoba": "hora de Argentina (Córdoba)", + "America\/Costa_Rica": "hora central (Costa Rica)", + "America\/Creston": "hora de las Montañas Rocosas (Creston)", + "America\/Cuiaba": "hora del Amazonas (Cuiabá)", + "America\/Curacao": "hora del Atlántico (Curazao)", + "America\/Danmarkshavn": "hora del meridiano de Greenwich (Danmarkshavn)", + "America\/Dawson": "hora del Pacífico (Dawson)", + "America\/Dawson_Creek": "hora de las Montañas Rocosas (Dawson Creek)", + "America\/Denver": "hora de las Montañas Rocosas (Denver)", + "America\/Detroit": "hora oriental (Detroit)", + "America\/Dominica": "hora del Atlántico (Dominica)", + "America\/Edmonton": "hora de las Montañas Rocosas (Edmonton)", + "America\/Eirunepe": "Hora de Acre (Eirunepé)", + "America\/El_Salvador": "hora central (El Salvador)", + "America\/Fort_Nelson": "hora de las Montañas Rocosas (Fort Nelson)", + "America\/Fortaleza": "hora de Brasilia (Fortaleza)", + "America\/Glace_Bay": "hora del Atlántico (Glace Bay)", + "America\/Godthab": "hora de Groenlandia occidental (Nuuk)", + "America\/Goose_Bay": "hora del Atlántico (Goose Bay)", + "America\/Grand_Turk": "hora oriental (Gran Turca)", + "America\/Grenada": "hora del Atlántico (Granada)", + "America\/Guadeloupe": "hora del Atlántico (Guadalupe)", + "America\/Guatemala": "hora central (Guatemala)", + "America\/Guayaquil": "hora de Ecuador (Guayaquil)", + "America\/Guyana": "hora de Guyana (Guyana)", + "America\/Halifax": "hora del Atlántico (Halifax)", + "America\/Havana": "hora de Cuba (La Habana)", + "America\/Hermosillo": "hora del Pacífico de México (Hermosillo)", + "America\/Indiana\/Knox": "hora central (Knox, Indiana)", + "America\/Indiana\/Marengo": "hora oriental (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "hora oriental (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "hora central (Tell City, Indiana)", + "America\/Indiana\/Vevay": "hora oriental (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "hora oriental (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "hora oriental (Winamac, Indiana)", + "America\/Indianapolis": "hora oriental (Indianápolis)", + "America\/Inuvik": "hora de las Montañas Rocosas (Inuvik)", + "America\/Iqaluit": "hora oriental (Iqaluit)", + "America\/Jamaica": "hora oriental (Jamaica)", + "America\/Jujuy": "hora de Argentina (Jujuy)", + "America\/Juneau": "hora de Alaska (Juneau)", + "America\/Kentucky\/Monticello": "hora oriental (Monticello, Kentucky)", + "America\/Kralendijk": "hora del Atlántico (Kralendijk)", + "America\/La_Paz": "hora de Bolivia (La Paz)", + "America\/Lima": "hora de Perú (Lima)", + "America\/Los_Angeles": "hora del Pacífico (Los Ángeles)", + "America\/Louisville": "hora oriental (Louisville)", + "America\/Lower_Princes": "hora del Atlántico (Lower Prince’s Quarter)", + "America\/Maceio": "hora de Brasilia (Maceió)", + "America\/Managua": "hora central (Managua)", + "America\/Manaus": "hora del Amazonas (Manaos)", + "America\/Marigot": "hora del Atlántico (Marigot)", + "America\/Martinique": "hora del Atlántico (Martinica)", + "America\/Matamoros": "hora central (Matamoros)", + "America\/Mazatlan": "hora del Pacífico de México (Mazatlán)", + "America\/Mendoza": "hora de Argentina (Mendoza)", + "America\/Menominee": "hora central (Menominee)", + "America\/Merida": "hora central (Mérida)", + "America\/Metlakatla": "hora de Alaska (Metlakatla)", + "America\/Mexico_City": "hora central (Ciudad de México)", + "America\/Miquelon": "hora de San Pedro y Miquelón (Miquelón)", + "America\/Moncton": "hora del Atlántico (Moncton)", + "America\/Monterrey": "hora central (Monterrey)", + "America\/Montevideo": "hora de Uruguay (Montevideo)", + "America\/Montserrat": "hora del Atlántico (Montserrat)", + "America\/Nassau": "hora oriental (Nassau)", + "America\/New_York": "hora oriental (Nueva York)", + "America\/Nipigon": "hora oriental (Nipigon)", + "America\/Nome": "hora de Alaska (Nome)", + "America\/Noronha": "hora de Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "hora central (Beulah, Dakota del Norte)", + "America\/North_Dakota\/Center": "hora central (Center, Dakota del Norte)", + "America\/North_Dakota\/New_Salem": "hora central (New Salem, Dakota del Norte)", + "America\/Ojinaga": "hora de las Montañas Rocosas (Ojinaga)", + "America\/Panama": "hora oriental (Panamá)", + "America\/Pangnirtung": "hora oriental (Pangnirtung)", + "America\/Paramaribo": "hora de Surinam (Paramaribo)", + "America\/Phoenix": "hora de las Montañas Rocosas (Phoenix)", + "America\/Port-au-Prince": "hora oriental (Puerto Príncipe)", + "America\/Port_of_Spain": "hora del Atlántico (Puerto España)", + "America\/Porto_Velho": "hora del Amazonas (Porto Velho)", + "America\/Puerto_Rico": "hora del Atlántico (Puerto Rico)", + "America\/Punta_Arenas": "hora de Chile (Punta Arenas)", + "America\/Rainy_River": "hora central (Rainy River)", + "America\/Rankin_Inlet": "hora central (Rankin Inlet)", + "America\/Recife": "hora de Brasilia (Recife)", + "America\/Regina": "hora central (Regina)", + "America\/Resolute": "hora central (Resolute)", + "America\/Rio_Branco": "Hora de Acre (Río Branco)", + "America\/Santa_Isabel": "hora del noroeste de México (Santa Isabel)", + "America\/Santarem": "hora de Brasilia (Santarém)", + "America\/Santiago": "hora de Chile (Santiago de Chile)", + "America\/Santo_Domingo": "hora del Atlántico (Santo Domingo)", + "America\/Sao_Paulo": "hora de Brasilia (São Paulo)", + "America\/Scoresbysund": "hora de Groenlandia oriental (Ittoqqortoormiit)", + "America\/Sitka": "hora de Alaska (Sitka)", + "America\/St_Barthelemy": "hora del Atlántico (San Bartolomé)", + "America\/St_Johns": "hora de Terranova (San Juan de Terranova)", + "America\/St_Kitts": "hora del Atlántico (San Cristóbal)", + "America\/St_Lucia": "hora del Atlántico (Santa Lucía)", + "America\/St_Thomas": "hora del Atlántico (St. Thomas)", + "America\/St_Vincent": "hora del Atlántico (San Vicente)", + "America\/Swift_Current": "hora central (Swift Current)", + "America\/Tegucigalpa": "hora central (Tegucigalpa)", + "America\/Thule": "hora del Atlántico (Thule)", + "America\/Thunder_Bay": "hora oriental (Thunder Bay)", + "America\/Tijuana": "hora del Pacífico (Tijuana)", + "America\/Toronto": "hora oriental (Toronto)", + "America\/Tortola": "hora del Atlántico (Tórtola)", + "America\/Vancouver": "hora del Pacífico (Vancouver)", + "America\/Whitehorse": "hora del Pacífico (Whitehorse)", + "America\/Winnipeg": "hora central (Winnipeg)", + "America\/Yakutat": "hora de Alaska (Yakutat)", + "America\/Yellowknife": "hora de las Montañas Rocosas (Yellowknife)", + "Antarctica\/Casey": "hora de Australia occidental (Casey)", + "Antarctica\/Davis": "hora de Davis (Davis)", + "Antarctica\/DumontDUrville": "hora de Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "hora de la isla Macquarie (Macquarie)", + "Antarctica\/Mawson": "hora de Mawson (Mawson)", + "Antarctica\/McMurdo": "hora de Nueva Zelanda (McMurdo)", + "Antarctica\/Palmer": "hora de Chile (Palmer)", + "Antarctica\/Rothera": "hora de Rothera (Rothera)", + "Antarctica\/Syowa": "hora de Syowa (Syowa)", + "Antarctica\/Troll": "hora del meridiano de Greenwich (Troll)", + "Antarctica\/Vostok": "hora de Vostok (Vostok)", + "Arctic\/Longyearbyen": "hora de Europa central (Longyearbyen)", + "Asia\/Aden": "hora de Arabia (Adén)", + "Asia\/Almaty": "hora de Kazajistán oriental (Almaty)", + "Asia\/Amman": "hora de Europa oriental (Ammán)", + "Asia\/Anadyr": "hora de Anadyr (Anádyr)", + "Asia\/Aqtau": "hora de Kazajistán occidental (Aktau)", + "Asia\/Aqtobe": "hora de Kazajistán occidental (Aktobe)", + "Asia\/Ashgabat": "hora de Turkmenistán (Asjabad)", + "Asia\/Atyrau": "hora de Kazajistán occidental (Atyrau)", + "Asia\/Baghdad": "hora de Arabia (Bagdad)", + "Asia\/Bahrain": "hora de Arabia (Baréin)", + "Asia\/Baku": "hora de Azerbaiyán (Bakú)", + "Asia\/Bangkok": "hora de Indochina (Bangkok)", + "Asia\/Beirut": "hora de Europa oriental (Beirut)", + "Asia\/Bishkek": "hora de Kirguistán (Bishkek)", + "Asia\/Brunei": "hora de Brunéi (Brunéi)", + "Asia\/Calcutta": "hora estándar de la India (Calcuta)", + "Asia\/Chita": "hora de Yakutsk (Chitá)", + "Asia\/Choibalsan": "hora de Choibalsan (Choibalsan)", + "Asia\/Colombo": "hora estándar de la India (Colombo)", + "Asia\/Damascus": "hora de Europa oriental (Damasco)", + "Asia\/Dhaka": "hora de Bangladés (Daca)", + "Asia\/Dili": "hora de Timor Oriental (Dili)", + "Asia\/Dubai": "hora estándar del Golfo (Dubái)", + "Asia\/Dushanbe": "hora de Tayikistán (Dusambé)", + "Asia\/Famagusta": "hora de Europa oriental (Famagusta)", + "Asia\/Gaza": "hora de Europa oriental (Gaza)", + "Asia\/Hebron": "hora de Europa oriental (Hebrón)", + "Asia\/Hong_Kong": "hora de Hong Kong (Hong Kong)", + "Asia\/Hovd": "hora de Hovd (Hovd)", + "Asia\/Irkutsk": "hora de Irkutsk (Irkutsk)", + "Asia\/Jakarta": "hora de Indonesia occidental (Yakarta)", + "Asia\/Jayapura": "hora de Indonesia oriental (Jayapura)", + "Asia\/Jerusalem": "hora de Israel (Jerusalén)", + "Asia\/Kabul": "hora de Afganistán (Kabul)", + "Asia\/Kamchatka": "hora de Kamchatka (Kamchatka)", + "Asia\/Karachi": "hora de Pakistán (Karachi)", + "Asia\/Katmandu": "hora de Nepal (Katmandú)", + "Asia\/Khandyga": "hora de Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "hora de Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "hora de Malasia (Kuala Lumpur)", + "Asia\/Kuching": "hora de Malasia (Kuching)", + "Asia\/Kuwait": "hora de Arabia (Kuwait)", + "Asia\/Macau": "hora de China (Macao)", + "Asia\/Magadan": "hora de Magadán (Magadán)", + "Asia\/Makassar": "hora de Indonesia central (Makasar)", + "Asia\/Manila": "hora de Filipinas (Manila)", + "Asia\/Muscat": "hora estándar del Golfo (Mascate)", + "Asia\/Nicosia": "hora de Europa oriental (Nicosia)", + "Asia\/Novokuznetsk": "hora de Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "hora de Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "hora de Omsk (Omsk)", + "Asia\/Oral": "hora de Kazajistán occidental (Oral)", + "Asia\/Phnom_Penh": "hora de Indochina (Phnom Penh)", + "Asia\/Pontianak": "hora de Indonesia occidental (Pontianak)", + "Asia\/Pyongyang": "hora de Corea (Pyongyang)", + "Asia\/Qatar": "hora de Arabia (Catar)", + "Asia\/Qostanay": "hora de Kazajistán oriental (Kostanái)", + "Asia\/Qyzylorda": "hora de Kazajistán occidental (Kyzylorda)", + "Asia\/Rangoon": "hora de Myanmar (Birmania) (Yangón (Rangún))", + "Asia\/Riyadh": "hora de Arabia (Riad)", + "Asia\/Saigon": "hora de Indochina (Ciudad Ho Chi Minh)", + "Asia\/Sakhalin": "hora de Sajalín (Sajalín)", + "Asia\/Samarkand": "hora de Uzbekistán (Samarcanda)", + "Asia\/Seoul": "hora de Corea (Seúl)", + "Asia\/Shanghai": "hora de China (Shanghái)", + "Asia\/Singapore": "hora de Singapur (Singapur)", + "Asia\/Srednekolymsk": "hora de Magadán (Srednekolimsk)", + "Asia\/Taipei": "hora de Taipéi (Taipéi)", + "Asia\/Tashkent": "hora de Uzbekistán (Taskent)", + "Asia\/Tbilisi": "hora de Georgia (Tiflis)", + "Asia\/Tehran": "hora de Irán (Teherán)", + "Asia\/Thimphu": "hora de Bután (Timbu)", + "Asia\/Tokyo": "hora de Japón (Tokio)", + "Asia\/Ulaanbaatar": "hora de Ulán Bator (Ulán Bator)", + "Asia\/Ust-Nera": "hora de Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "hora de Indochina (Vientián)", + "Asia\/Vladivostok": "hora de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "hora de Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "hora de Ekaterimburgo (Ekaterimburgo)", + "Asia\/Yerevan": "hora de Armenia (Ereván)", + "Atlantic\/Azores": "hora de las Azores (Azores)", + "Atlantic\/Bermuda": "hora del Atlántico (Bermudas)", + "Atlantic\/Canary": "hora de Europa occidental (Islas Canarias)", + "Atlantic\/Cape_Verde": "hora de Cabo Verde (Cabo Verde)", + "Atlantic\/Faeroe": "hora de Europa occidental (Islas Feroe)", + "Atlantic\/Madeira": "hora de Europa occidental (Madeira)", + "Atlantic\/Reykjavik": "hora del meridiano de Greenwich (Reikiavik)", + "Atlantic\/South_Georgia": "hora de Georgia del Sur (Georgia del Sur)", + "Atlantic\/St_Helena": "hora del meridiano de Greenwich (Santa Elena)", + "Atlantic\/Stanley": "hora de las islas Malvinas (Stanley)", + "Australia\/Adelaide": "hora de Australia central (Adelaida)", + "Australia\/Brisbane": "hora de Australia oriental (Brisbane)", + "Australia\/Broken_Hill": "hora de Australia central (Broken Hill)", + "Australia\/Currie": "hora de Australia oriental (Currie)", + "Australia\/Darwin": "hora de Australia central (Darwin)", + "Australia\/Eucla": "hora de Australia centroccidental (Eucla)", + "Australia\/Hobart": "hora de Australia oriental (Hobart)", + "Australia\/Lindeman": "hora de Australia oriental (Lindeman)", + "Australia\/Lord_Howe": "hora de Lord Howe (Lord Howe)", + "Australia\/Melbourne": "hora de Australia oriental (Melbourne)", + "Australia\/Perth": "hora de Australia occidental (Perth)", + "Australia\/Sydney": "hora de Australia oriental (Sídney)", + "CST6CDT": "hora central", + "EST5EDT": "hora oriental", + "Etc\/GMT": "hora del meridiano de Greenwich", + "Etc\/UTC": "tiempo universal coordinado", + "Europe\/Amsterdam": "hora de Europa central (Ámsterdam)", + "Europe\/Andorra": "hora de Europa central (Andorra)", + "Europe\/Astrakhan": "hora de Moscú (Astracán)", + "Europe\/Athens": "hora de Europa oriental (Atenas)", + "Europe\/Belgrade": "hora de Europa central (Belgrado)", + "Europe\/Berlin": "hora de Europa central (Berlín)", + "Europe\/Bratislava": "hora de Europa central (Bratislava)", + "Europe\/Brussels": "hora de Europa central (Bruselas)", + "Europe\/Bucharest": "hora de Europa oriental (Bucarest)", + "Europe\/Budapest": "hora de Europa central (Budapest)", + "Europe\/Busingen": "hora de Europa central (Busingen)", + "Europe\/Chisinau": "hora de Europa oriental (Chisináu)", + "Europe\/Copenhagen": "hora de Europa central (Copenhague)", + "Europe\/Dublin": "hora del meridiano de Greenwich (Dublín)", + "Europe\/Gibraltar": "hora de Europa central (Gibraltar)", + "Europe\/Guernsey": "hora del meridiano de Greenwich (Guernsey)", + "Europe\/Helsinki": "hora de Europa oriental (Helsinki)", + "Europe\/Isle_of_Man": "hora del meridiano de Greenwich (Isla de Man)", + "Europe\/Jersey": "hora del meridiano de Greenwich (Jersey)", + "Europe\/Kaliningrad": "hora de Europa oriental (Kaliningrado)", + "Europe\/Kiev": "hora de Europa oriental (Kiev)", + "Europe\/Lisbon": "hora de Europa occidental (Lisboa)", + "Europe\/Ljubljana": "hora de Europa central (Liubliana)", + "Europe\/London": "hora del meridiano de Greenwich (Londres)", + "Europe\/Luxembourg": "hora de Europa central (Luxemburgo)", + "Europe\/Madrid": "hora de Europa central (Madrid)", + "Europe\/Malta": "hora de Europa central (Malta)", + "Europe\/Mariehamn": "hora de Europa oriental (Mariehamn)", + "Europe\/Minsk": "hora de Moscú (Minsk)", + "Europe\/Monaco": "hora de Europa central (Mónaco)", + "Europe\/Moscow": "hora de Moscú (Moscú)", + "Europe\/Oslo": "hora de Europa central (Oslo)", + "Europe\/Paris": "hora de Europa central (París)", + "Europe\/Podgorica": "hora de Europa central (Podgorica)", + "Europe\/Prague": "hora de Europa central (Praga)", + "Europe\/Riga": "hora de Europa oriental (Riga)", + "Europe\/Rome": "hora de Europa central (Roma)", + "Europe\/Samara": "hora de Samara (Samara)", + "Europe\/San_Marino": "hora de Europa central (San Marino)", + "Europe\/Sarajevo": "hora de Europa central (Sarajevo)", + "Europe\/Saratov": "hora de Moscú (Sarátov)", + "Europe\/Simferopol": "hora de Moscú (Simferópol)", + "Europe\/Skopje": "hora de Europa central (Skopie)", + "Europe\/Sofia": "hora de Europa oriental (Sofía)", + "Europe\/Stockholm": "hora de Europa central (Estocolmo)", + "Europe\/Tallinn": "hora de Europa oriental (Tallin)", + "Europe\/Tirane": "hora de Europa central (Tirana)", + "Europe\/Ulyanovsk": "hora de Moscú (Uliánovsk)", + "Europe\/Uzhgorod": "hora de Europa oriental (Úzhgorod)", + "Europe\/Vaduz": "hora de Europa central (Vaduz)", + "Europe\/Vatican": "hora de Europa central (El Vaticano)", + "Europe\/Vienna": "hora de Europa central (Viena)", + "Europe\/Vilnius": "hora de Europa oriental (Vilna)", + "Europe\/Volgograd": "hora de Volgogrado (Volgogrado)", + "Europe\/Warsaw": "hora de Europa central (Varsovia)", + "Europe\/Zagreb": "hora de Europa central (Zagreb)", + "Europe\/Zaporozhye": "hora de Europa oriental (Zaporiyia)", + "Europe\/Zurich": "hora de Europa central (Zúrich)", + "Indian\/Antananarivo": "hora de África oriental (Antananarivo)", + "Indian\/Chagos": "hora del océano Índico (Chagos)", + "Indian\/Christmas": "hora de la Isla de Navidad (Navidad)", + "Indian\/Cocos": "hora de las Islas Cocos (Cocos)", + "Indian\/Comoro": "hora de África oriental (Comoras)", + "Indian\/Kerguelen": "hora de las Tierras Australes y Antárticas Francesas (Kerguelen)", + "Indian\/Mahe": "hora de Seychelles (Mahé)", + "Indian\/Maldives": "hora de Maldivas (Maldivas)", + "Indian\/Mauritius": "hora de Mauricio (Mauricio)", + "Indian\/Mayotte": "hora de África oriental (Mayotte)", + "Indian\/Reunion": "hora de Reunión (Reunión)", + "MST7MDT": "hora de las Montañas Rocosas", + "PST8PDT": "hora del Pacífico", + "Pacific\/Apia": "hora de Apia (Apia)", + "Pacific\/Auckland": "hora de Nueva Zelanda (Auckland)", + "Pacific\/Bougainville": "hora de Papúa Nueva Guinea (Bougainville)", + "Pacific\/Chatham": "hora de Chatham (Chatham)", + "Pacific\/Easter": "hora de la isla de Pascua (Isla de Pascua)", + "Pacific\/Efate": "hora de Vanuatu (Efate)", + "Pacific\/Enderbury": "hora de las Islas Fénix (Enderbury)", + "Pacific\/Fakaofo": "hora de Tokelau (Fakaofo)", + "Pacific\/Fiji": "hora de Fiyi (Fiyi)", + "Pacific\/Funafuti": "hora de Tuvalu (Funafuti)", + "Pacific\/Galapagos": "hora de Galápagos (Galápagos)", + "Pacific\/Gambier": "hora de Gambier (Gambier)", + "Pacific\/Guadalcanal": "hora de las Islas Salomón (Guadalcanal)", + "Pacific\/Guam": "hora estándar de Chamorro (Guam)", + "Pacific\/Honolulu": "hora de Hawái-Aleutianas (Honolulú)", + "Pacific\/Johnston": "hora de Hawái-Aleutianas (Johnston)", + "Pacific\/Kiritimati": "hora de las Espóradas Ecuatoriales (Kiritimati)", + "Pacific\/Kosrae": "hora de Kosrae (Kosrae)", + "Pacific\/Kwajalein": "hora de las Islas Marshall (Kwajalein)", + "Pacific\/Majuro": "hora de las Islas Marshall (Majuro)", + "Pacific\/Marquesas": "hora de Marquesas (Marquesas)", + "Pacific\/Midway": "hora de Samoa (Midway)", + "Pacific\/Nauru": "hora de Nauru (Nauru)", + "Pacific\/Niue": "hora de Niue (Niue)", + "Pacific\/Norfolk": "hora de la isla Norfolk (Norfolk)", + "Pacific\/Noumea": "hora de Nueva Caledonia (Numea)", + "Pacific\/Pago_Pago": "hora de Samoa (Pago Pago)", + "Pacific\/Palau": "hora de Palaos (Palaos)", + "Pacific\/Pitcairn": "hora de Pitcairn (Pitcairn)", + "Pacific\/Ponape": "hora de Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "hora de Papúa Nueva Guinea (Port Moresby)", + "Pacific\/Rarotonga": "hora de las Islas Cook (Rarotonga)", + "Pacific\/Saipan": "hora estándar de Chamorro (Saipán)", + "Pacific\/Tahiti": "hora de Tahití (Tahití)", + "Pacific\/Tarawa": "hora de las islas Gilbert (Tarawa)", + "Pacific\/Tongatapu": "hora de Tonga (Tongatapu)", + "Pacific\/Truk": "hora de Chuuk (Chuuk)", + "Pacific\/Wake": "hora de la isla Wake (Wake)", + "Pacific\/Wallis": "hora de Wallis y Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_419.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_419.json new file mode 100644 index 0000000000000..24a40d99fa01c --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_419.json @@ -0,0 +1,59 @@ +{ + "Version": "2.1.47.86", + "Names": { + "Africa\/Cairo": "hora de Europa del Este (Cairo)", + "Africa\/Casablanca": "hora de Europa del Oeste (Casablanca)", + "Africa\/El_Aaiun": "hora de Europa del Oeste (El Aaiun)", + "Africa\/Tripoli": "hora de Europa del Este (Tripoli)", + "America\/Boise": "hora de la montaña (Boise)", + "America\/Cambridge_Bay": "hora de la montaña (Cambridge Bay)", + "America\/Creston": "hora de la montaña (Creston)", + "America\/Dawson_Creek": "hora de la montaña (Dawson Creek)", + "America\/Denver": "hora de la montaña (Denver)", + "America\/Edmonton": "hora de la montaña (Edmonton)", + "America\/Fort_Nelson": "hora de la montaña (Fuerte Nelson)", + "America\/Inuvik": "hora de la montaña (Inuvik)", + "America\/Ojinaga": "hora de la montaña (Ojinaga)", + "America\/Phoenix": "hora de la montaña (Phoenix)", + "America\/Yellowknife": "hora de la montaña (Yellowknife)", + "Antarctica\/Macquarie": "hora de la Isla Macquarie (Macquarie)", + "Asia\/Amman": "hora de Europa del Este (Amman)", + "Asia\/Beirut": "hora de Europa del Este (Beirut)", + "Asia\/Calcutta": "hora de India (Kolkata)", + "Asia\/Colombo": "hora de India (Colombo)", + "Asia\/Damascus": "hora de Europa del Este (Damascus)", + "Asia\/Famagusta": "hora de Europa del Este (Famagusta)", + "Asia\/Gaza": "hora de Europa del Este (Gaza)", + "Asia\/Hebron": "hora de Europa del Este (Hebron)", + "Asia\/Nicosia": "hora de Europa del Este (Nicosia)", + "Atlantic\/Canary": "hora de Europa del Oeste (Canary)", + "Atlantic\/Faeroe": "hora de Europa del Oeste (Faroe)", + "Atlantic\/Madeira": "hora de Europa del Oeste (Madeira)", + "Atlantic\/Stanley": "hora de las Islas Malvinas (Stanley)", + "Etc\/UTC": "Hora Universal Coordinada", + "Europe\/Athens": "hora de Europa del Este (Athens)", + "Europe\/Bucharest": "hora de Europa del Este (Bucharest)", + "Europe\/Chisinau": "hora de Europa del Este (Chisinau)", + "Europe\/Helsinki": "hora de Europa del Este (Helsinki)", + "Europe\/Kaliningrad": "hora de Europa del Este (Kaliningrad)", + "Europe\/Kiev": "hora de Europa del Este (Kiev)", + "Europe\/Lisbon": "hora de Europa del Oeste (Lisbon)", + "Europe\/Mariehamn": "hora de Europa del Este (Mariehamn)", + "Europe\/Riga": "hora de Europa del Este (Riga)", + "Europe\/Sofia": "hora de Europa del Este (Sofia)", + "Europe\/Tallinn": "hora de Europa del Este (Tallinn)", + "Europe\/Uzhgorod": "hora de Europa del Este (Uzhgorod)", + "Europe\/Vilnius": "hora de Europa del Este (Vilnius)", + "Europe\/Zaporozhye": "hora de Europa del Este (Zaporozhye)", + "Indian\/Cocos": "hora de Islas Cocos (Cocos)", + "MST7MDT": "hora de la montaña", + "Pacific\/Easter": "hora de la Isla de Pascua (Easter)", + "Pacific\/Guadalcanal": "hora de Islas Salomón (Guadalcanal)", + "Pacific\/Kwajalein": "hora de Islas Marshall (Kwajalein)", + "Pacific\/Majuro": "hora de Islas Marshall (Majuro)", + "Pacific\/Norfolk": "hora de la Isla Norfolk (Norfolk)", + "Pacific\/Rarotonga": "hora de las islas Cook (Rarotonga)", + "Pacific\/Tarawa": "hora de Islas Gilbert (Tarawa)", + "Pacific\/Wake": "hora de Isla Wake (Isla Wake)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_AR.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_AR.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_AR.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_BO.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_BO.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_BO.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_CL.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_CL.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_CL.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_CO.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_CO.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_CO.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_EC.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_EC.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_EC.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_MX.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_MX.json new file mode 100644 index 0000000000000..1d76b246236ed --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_MX.json @@ -0,0 +1,49 @@ +{ + "Version": "2.1.47.96", + "Names": { + "Africa\/Cairo": "hora de Europa oriental (Cairo)", + "Africa\/Casablanca": "hora de Europa occidental (Casablanca)", + "Africa\/El_Aaiun": "hora de Europa occidental (El Aaiun)", + "Africa\/Tripoli": "hora de Europa oriental (Tripoli)", + "America\/Argentina\/San_Luis": "hora de Argentina occidental (San Luis)", + "Antarctica\/Macquarie": "hora de la isla Macquarie (Macquarie)", + "Asia\/Amman": "hora de Europa oriental (Amman)", + "Asia\/Beirut": "hora de Europa oriental (Beirut)", + "Asia\/Damascus": "hora de Europa oriental (Damascus)", + "Asia\/Famagusta": "hora de Europa oriental (Famagusta)", + "Asia\/Gaza": "hora de Europa oriental (Gaza)", + "Asia\/Hebron": "hora de Europa oriental (Hebron)", + "Asia\/Irkutsk": "hora de Irkutsk (Irkutsk)", + "Asia\/Nicosia": "hora de Europa oriental (Nicosia)", + "Atlantic\/Canary": "hora de Europa occidental (Canary)", + "Atlantic\/Faeroe": "hora de Europa occidental (Faroe)", + "Atlantic\/Madeira": "hora de Europa occidental (Madeira)", + "Atlantic\/Stanley": "hora de Islas Malvinas (Stanley)", + "Etc\/UTC": "Tiempo Universal Coordinado", + "Europe\/Athens": "hora de Europa oriental (Athens)", + "Europe\/Bucharest": "hora de Europa oriental (Bucharest)", + "Europe\/Chisinau": "hora de Europa oriental (Chisinau)", + "Europe\/Helsinki": "hora de Europa oriental (Helsinki)", + "Europe\/Kaliningrad": "hora de Europa oriental (Kaliningrad)", + "Europe\/Kiev": "hora de Europa oriental (Kiev)", + "Europe\/Lisbon": "hora de Europa occidental (Lisbon)", + "Europe\/Mariehamn": "hora de Europa oriental (Mariehamn)", + "Europe\/Riga": "hora de Europa oriental (Riga)", + "Europe\/Sofia": "hora de Europa oriental (Sofia)", + "Europe\/Tallinn": "hora de Europa oriental (Tallinn)", + "Europe\/Uzhgorod": "hora de Europa oriental (Uzhgorod)", + "Europe\/Vilnius": "hora de Europa oriental (Vilnius)", + "Europe\/Zaporozhye": "hora de Europa oriental (Zaporozhye)", + "Indian\/Christmas": "hora de la isla de Navidad (Christmas)", + "Indian\/Cocos": "hora de las Islas Cocos (Cocos)", + "Pacific\/Apia": "hora de Apia (Apia)", + "Pacific\/Easter": "hora de Isla de Pascua (Easter)", + "Pacific\/Guadalcanal": "hora de las Islas Salomón (Guadalcanal)", + "Pacific\/Kwajalein": "hora de las Islas Marshall (Kwajalein)", + "Pacific\/Majuro": "hora de las Islas Marshall (Majuro)", + "Pacific\/Norfolk": "hora de la isla Norfolk (Norfolk)", + "Pacific\/Rarotonga": "hora de las Islas Cook (Rarotonga)", + "Pacific\/Tarawa": "hora de las Islas Gilbert (Tarawa)", + "Pacific\/Wake": "hora de la Isla Wake (Wake)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_PE.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_PE.json new file mode 100644 index 0000000000000..212db5e18f200 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_PE.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.83", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_US.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_US.json new file mode 100644 index 0000000000000..65530e3c868f0 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_US.json @@ -0,0 +1,61 @@ +{ + "Version": "2.1.47.86", + "Names": { + "Africa\/Cairo": "hora de Europa oriental (Cairo)", + "Africa\/Casablanca": "hora de Europa occidental (Casablanca)", + "Africa\/El_Aaiun": "hora de Europa occidental (El Aaiun)", + "Africa\/Tripoli": "hora de Europa oriental (Tripoli)", + "America\/Boise": "hora de las Montañas Rocosas (Boise)", + "America\/Cambridge_Bay": "hora de las Montañas Rocosas (Cambridge Bay)", + "America\/Creston": "hora de las Montañas Rocosas (Creston)", + "America\/Dawson_Creek": "hora de las Montañas Rocosas (Dawson Creek)", + "America\/Denver": "hora de las Montañas Rocosas (Denver)", + "America\/Edmonton": "hora de las Montañas Rocosas (Edmonton)", + "America\/Fort_Nelson": "hora de las Montañas Rocosas (Fort Nelson)", + "America\/Inuvik": "hora de las Montañas Rocosas (Inuvik)", + "America\/Ojinaga": "hora de las Montañas Rocosas (Ojinaga)", + "America\/Phoenix": "hora de las Montañas Rocosas (Phoenix)", + "America\/Yellowknife": "hora de las Montañas Rocosas (Yellowknife)", + "Antarctica\/Macquarie": "hora de la isla Macquarie (Macquarie)", + "Asia\/Amman": "hora de Europa oriental (Amman)", + "Asia\/Beirut": "hora de Europa oriental (Beirut)", + "Asia\/Damascus": "hora de Europa oriental (Damascus)", + "Asia\/Famagusta": "hora de Europa oriental (Famagusta)", + "Asia\/Gaza": "hora de Europa oriental (Gaza)", + "Asia\/Hebron": "hora de Europa oriental (Hebron)", + "Asia\/Nicosia": "hora de Europa oriental (Nicosia)", + "Atlantic\/Canary": "hora de Europa occidental (Canary)", + "Atlantic\/Faeroe": "hora de Europa occidental (Faroe)", + "Atlantic\/Madeira": "hora de Europa occidental (Madeira)", + "Atlantic\/Stanley": "hora de las islas Malvinas (Stanley)", + "Etc\/UTC": "hora universal coordinada", + "Europe\/Athens": "hora de Europa oriental (Athens)", + "Europe\/Bucharest": "hora de Europa oriental (Bucharest)", + "Europe\/Chisinau": "hora de Europa oriental (Chisinau)", + "Europe\/Helsinki": "hora de Europa oriental (Helsinki)", + "Europe\/Kaliningrad": "hora de Europa oriental (Kaliningrad)", + "Europe\/Kiev": "hora de Europa oriental (Kiev)", + "Europe\/Lisbon": "hora de Europa occidental (Lisbon)", + "Europe\/Mariehamn": "hora de Europa oriental (Mariehamn)", + "Europe\/Riga": "hora de Europa oriental (Riga)", + "Europe\/Sofia": "hora de Europa oriental (Sofia)", + "Europe\/Tallinn": "hora de Europa oriental (Tallinn)", + "Europe\/Uzhgorod": "hora de Europa oriental (Uzhgorod)", + "Europe\/Vilnius": "hora de Europa oriental (Vilnius)", + "Europe\/Zaporozhye": "hora de Europa oriental (Zaporozhye)", + "Indian\/Chagos": "hora del Océano Índico (Chagos)", + "Indian\/Cocos": "hora de las Islas Cocos (Cocos)", + "MST7MDT": "hora de las Montañas Rocosas", + "Pacific\/Easter": "hora de la isla de Pascua (Easter)", + "Pacific\/Enderbury": "hora de las islas Fénix (Enderbury)", + "Pacific\/Guadalcanal": "hora de las Islas Salomón (Guadalcanal)", + "Pacific\/Guam": "hora de Chamorro (Guam)", + "Pacific\/Kwajalein": "hora de las Islas Marshall (Kwajalein)", + "Pacific\/Majuro": "hora de las Islas Marshall (Majuro)", + "Pacific\/Marquesas": "hora de las islas Marquesas (Marquesas)", + "Pacific\/Norfolk": "hora de la isla Norfolk (Norfolk)", + "Pacific\/Saipan": "hora de Chamorro (Saipan)", + "Pacific\/Tarawa": "hora de las islas Gilbert (Tarawa)", + "Pacific\/Wake": "hora de la isla Wake (Wake)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_UY.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_UY.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_UY.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/es_VE.json b/src/Symfony/Component/Intl/Resources/data/timezones/es_VE.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/es_VE.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/et.json b/src/Symfony/Component/Intl/Resources/data/timezones/et.json new file mode 100644 index 0000000000000..f8517d82e3be3 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/et.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwichi aeg (Abidjan)", + "Africa\/Accra": "Greenwichi aeg (Accra)", + "Africa\/Addis_Ababa": "Ida-Aafrika aeg (Addis Abeba)", + "Africa\/Algiers": "Kesk-Euroopa aeg (Alžiir)", + "Africa\/Asmera": "Ida-Aafrika aeg (Asmara)", + "Africa\/Bamako": "Greenwichi aeg (Bamako)", + "Africa\/Bangui": "Lääne-Aafrika aeg (Bangui)", + "Africa\/Banjul": "Greenwichi aeg (Banjul)", + "Africa\/Bissau": "Greenwichi aeg (Bissau)", + "Africa\/Blantyre": "Kesk-Aafrika aeg (Blantyre)", + "Africa\/Brazzaville": "Lääne-Aafrika aeg (Brazzaville)", + "Africa\/Bujumbura": "Kesk-Aafrika aeg (Bujumbura)", + "Africa\/Cairo": "Ida-Euroopa aeg (Kairo)", + "Africa\/Casablanca": "Lääne-Euroopa aeg (Casablanca)", + "Africa\/Ceuta": "Kesk-Euroopa aeg (Ceuta)", + "Africa\/Conakry": "Greenwichi aeg (Conakry)", + "Africa\/Dakar": "Greenwichi aeg (Dakar)", + "Africa\/Dar_es_Salaam": "Ida-Aafrika aeg (Dar es Salaam)", + "Africa\/Djibouti": "Ida-Aafrika aeg (Djibouti)", + "Africa\/Douala": "Lääne-Aafrika aeg (Douala)", + "Africa\/El_Aaiun": "Lääne-Euroopa aeg (El Aaiun)", + "Africa\/Freetown": "Greenwichi aeg (Freetown)", + "Africa\/Gaborone": "Kesk-Aafrika aeg (Gaborone)", + "Africa\/Harare": "Kesk-Aafrika aeg (Harare)", + "Africa\/Johannesburg": "Lõuna-Aafrika standardaeg (Johannesburg)", + "Africa\/Juba": "Ida-Aafrika aeg (Juba)", + "Africa\/Kampala": "Ida-Aafrika aeg (Kampala)", + "Africa\/Khartoum": "Kesk-Aafrika aeg (Hartum)", + "Africa\/Kigali": "Kesk-Aafrika aeg (Kigali)", + "Africa\/Kinshasa": "Lääne-Aafrika aeg (Kinshasa)", + "Africa\/Lagos": "Lääne-Aafrika aeg (Lagos)", + "Africa\/Libreville": "Lääne-Aafrika aeg (Libreville)", + "Africa\/Lome": "Greenwichi aeg (Lome)", + "Africa\/Luanda": "Lääne-Aafrika aeg (Luanda)", + "Africa\/Lubumbashi": "Kesk-Aafrika aeg (Lubumbashi)", + "Africa\/Lusaka": "Kesk-Aafrika aeg (Lusaka)", + "Africa\/Malabo": "Lääne-Aafrika aeg (Malabo)", + "Africa\/Maputo": "Kesk-Aafrika aeg (Maputo)", + "Africa\/Maseru": "Lõuna-Aafrika standardaeg (Maseru)", + "Africa\/Mbabane": "Lõuna-Aafrika standardaeg (Mbabane)", + "Africa\/Mogadishu": "Ida-Aafrika aeg (Mogadishu)", + "Africa\/Monrovia": "Greenwichi aeg (Monrovia)", + "Africa\/Nairobi": "Ida-Aafrika aeg (Nairobi)", + "Africa\/Ndjamena": "Lääne-Aafrika aeg (N’Djamena)", + "Africa\/Niamey": "Lääne-Aafrika aeg (Niamey)", + "Africa\/Nouakchott": "Greenwichi aeg (Nouakchott)", + "Africa\/Ouagadougou": "Greenwichi aeg (Ouagadougou)", + "Africa\/Porto-Novo": "Lääne-Aafrika aeg (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwichi aeg (São Tomé)", + "Africa\/Tripoli": "Ida-Euroopa aeg (Tripoli)", + "Africa\/Tunis": "Kesk-Euroopa aeg (Tunis)", + "Africa\/Windhoek": "Kesk-Aafrika aeg (Windhoek)", + "America\/Adak": "Hawaii-Aleuudi aeg (Adak)", + "America\/Anchorage": "Alaska aeg (Anchorage)", + "America\/Anguilla": "Atlandi aeg (Anguilla)", + "America\/Antigua": "Atlandi aeg (Antigua)", + "America\/Araguaina": "Brasiilia aeg (Araguaína)", + "America\/Argentina\/La_Rioja": "Argentina aeg (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentina aeg (Río Gallegos)", + "America\/Argentina\/Salta": "Argentina aeg (Salta)", + "America\/Argentina\/San_Juan": "Argentina aeg (San Juan)", + "America\/Argentina\/San_Luis": "Lääne-Argentina aeg (San Luis)", + "America\/Argentina\/Tucuman": "Argentina aeg (Tucumán)", + "America\/Argentina\/Ushuaia": "Argentina aeg (Ushuaia)", + "America\/Aruba": "Atlandi aeg (Aruba)", + "America\/Asuncion": "Paraguay aeg (Asunción)", + "America\/Bahia": "Brasiilia aeg (Bahia)", + "America\/Bahia_Banderas": "Kesk-Ameerika aeg (Bahia Banderas)", + "America\/Barbados": "Atlandi aeg (Barbados)", + "America\/Belem": "Brasiilia aeg (Belém)", + "America\/Belize": "Kesk-Ameerika aeg (Belize)", + "America\/Blanc-Sablon": "Atlandi aeg (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonase aeg (Boa Vista)", + "America\/Bogota": "Colombia aeg (Bogotá)", + "America\/Boise": "Mäestikuvööndi aeg (Boise)", + "America\/Buenos_Aires": "Argentina aeg (Buenos Aires)", + "America\/Cambridge_Bay": "Mäestikuvööndi aeg (Cambridge Bay)", + "America\/Campo_Grande": "Amazonase aeg (Campo Grande)", + "America\/Cancun": "Idaranniku aeg (Cancún)", + "America\/Caracas": "Venezuela aeg (Caracas)", + "America\/Catamarca": "Argentina aeg (Catamarca)", + "America\/Cayenne": "Prantsuse Guajaana aeg (Cayenne)", + "America\/Cayman": "Idaranniku aeg (Cayman)", + "America\/Chicago": "Kesk-Ameerika aeg (Chicago)", + "America\/Chihuahua": "Mehhiko Vaikse ookeani aeg (Chihuahua)", + "America\/Coral_Harbour": "Idaranniku aeg (Atikokan)", + "America\/Cordoba": "Argentina aeg (Córdoba)", + "America\/Costa_Rica": "Kesk-Ameerika aeg (Costa Rica)", + "America\/Creston": "Mäestikuvööndi aeg (Creston)", + "America\/Cuiaba": "Amazonase aeg (Cuiabá)", + "America\/Curacao": "Atlandi aeg (Curaçao)", + "America\/Danmarkshavn": "Greenwichi aeg (Danmarkshavn)", + "America\/Dawson": "Vaikse ookeani aeg (Dawson)", + "America\/Dawson_Creek": "Mäestikuvööndi aeg (Dawson Creek)", + "America\/Denver": "Mäestikuvööndi aeg (Denver)", + "America\/Detroit": "Idaranniku aeg (Detroit)", + "America\/Dominica": "Atlandi aeg (Dominica)", + "America\/Edmonton": "Mäestikuvööndi aeg (Edmonton)", + "America\/Eirunepe": "Acre aeg (Eirunepé)", + "America\/El_Salvador": "Kesk-Ameerika aeg (El Salvador)", + "America\/Fort_Nelson": "Mäestikuvööndi aeg (Fort Nelson)", + "America\/Fortaleza": "Brasiilia aeg (Fortaleza)", + "America\/Glace_Bay": "Atlandi aeg (Glace Bay)", + "America\/Godthab": "Lääne-Gröönimaa aeg (Nuuk)", + "America\/Goose_Bay": "Atlandi aeg (Goose Bay)", + "America\/Grand_Turk": "Idaranniku aeg (Grand Turk)", + "America\/Grenada": "Atlandi aeg (Grenada)", + "America\/Guadeloupe": "Atlandi aeg (Guadeloupe)", + "America\/Guatemala": "Kesk-Ameerika aeg (Guatemala)", + "America\/Guayaquil": "Ecuadori aeg (Guayaquil)", + "America\/Guyana": "Guyana aeg (Guyana)", + "America\/Halifax": "Atlandi aeg (Halifax)", + "America\/Havana": "Kuuba aeg (Havanna)", + "America\/Hermosillo": "Mehhiko Vaikse ookeani aeg (Hermosillo)", + "America\/Indiana\/Knox": "Kesk-Ameerika aeg (Knox, Indiana)", + "America\/Indiana\/Marengo": "Idaranniku aeg (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Idaranniku aeg (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Kesk-Ameerika aeg (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Idaranniku aeg (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Idaranniku aeg (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Idaranniku aeg (Winamac, Indiana)", + "America\/Indianapolis": "Idaranniku aeg (Indianapolis)", + "America\/Inuvik": "Mäestikuvööndi aeg (Inuvik)", + "America\/Iqaluit": "Idaranniku aeg (Iqaluit)", + "America\/Jamaica": "Idaranniku aeg (Jamaica)", + "America\/Jujuy": "Argentina aeg (Jujuy)", + "America\/Juneau": "Alaska aeg (Juneau)", + "America\/Kentucky\/Monticello": "Idaranniku aeg (Monticello, Kentucky)", + "America\/Kralendijk": "Atlandi aeg (Kralendijk)", + "America\/La_Paz": "Boliivia aeg (La Paz)", + "America\/Lima": "Peruu aeg (Lima)", + "America\/Los_Angeles": "Vaikse ookeani aeg (Los Angeles)", + "America\/Louisville": "Idaranniku aeg (Louisville)", + "America\/Lower_Princes": "Atlandi aeg (Lower Prince’s Quarter)", + "America\/Maceio": "Brasiilia aeg (Maceió)", + "America\/Managua": "Kesk-Ameerika aeg (Managua)", + "America\/Manaus": "Amazonase aeg (Manaus)", + "America\/Marigot": "Atlandi aeg (Marigot)", + "America\/Martinique": "Atlandi aeg (Martinique)", + "America\/Matamoros": "Kesk-Ameerika aeg (Matamoros)", + "America\/Mazatlan": "Mehhiko Vaikse ookeani aeg (Mazatlán)", + "America\/Mendoza": "Argentina aeg (Mendoza)", + "America\/Menominee": "Kesk-Ameerika aeg (Menominee)", + "America\/Merida": "Kesk-Ameerika aeg (Mérida)", + "America\/Metlakatla": "Alaska aeg (Metlakatla)", + "America\/Mexico_City": "Kesk-Ameerika aeg (México)", + "America\/Miquelon": "Saint-Pierre’i ja Miqueloni aeg (Miquelon)", + "America\/Moncton": "Atlandi aeg (Moncton)", + "America\/Monterrey": "Kesk-Ameerika aeg (Monterrey)", + "America\/Montevideo": "Uruguay aeg (Montevideo)", + "America\/Montserrat": "Atlandi aeg (Montserrat)", + "America\/Nassau": "Idaranniku aeg (Nassau)", + "America\/New_York": "Idaranniku aeg (New York)", + "America\/Nipigon": "Idaranniku aeg (Nipigon)", + "America\/Nome": "Alaska aeg (Nome)", + "America\/Noronha": "Fernando de Noronha aeg (Noronha)", + "America\/North_Dakota\/Beulah": "Kesk-Ameerika aeg (Beulah, Põhja-Dakota)", + "America\/North_Dakota\/Center": "Kesk-Ameerika aeg (Center, Põhja-Dakota)", + "America\/North_Dakota\/New_Salem": "Kesk-Ameerika aeg (New Salem, Põhja-Dakota)", + "America\/Ojinaga": "Mäestikuvööndi aeg (Ojinaga)", + "America\/Panama": "Idaranniku aeg (Panama)", + "America\/Pangnirtung": "Idaranniku aeg (Pangnirtung)", + "America\/Paramaribo": "Suriname aeg (Paramaribo)", + "America\/Phoenix": "Mäestikuvööndi aeg (Phoenix)", + "America\/Port-au-Prince": "Idaranniku aeg (Port-au-Prince)", + "America\/Port_of_Spain": "Atlandi aeg (Port of Spain)", + "America\/Porto_Velho": "Amazonase aeg (Porto Velho)", + "America\/Puerto_Rico": "Atlandi aeg (Puerto Rico)", + "America\/Punta_Arenas": "Tšiili aeg (Punta Arenas)", + "America\/Rainy_River": "Kesk-Ameerika aeg (Rainy River)", + "America\/Rankin_Inlet": "Kesk-Ameerika aeg (Rankin Inlet)", + "America\/Recife": "Brasiilia aeg (Recife)", + "America\/Regina": "Kesk-Ameerika aeg (Regina)", + "America\/Resolute": "Kesk-Ameerika aeg (Resolute)", + "America\/Rio_Branco": "Acre aeg (Rio Branco)", + "America\/Santa_Isabel": "Loode-Mehhiko aeg (Santa Isabel)", + "America\/Santarem": "Brasiilia aeg (Santarém)", + "America\/Santiago": "Tšiili aeg (Santiago)", + "America\/Santo_Domingo": "Atlandi aeg (Santo Domingo)", + "America\/Sao_Paulo": "Brasiilia aeg (São Paulo)", + "America\/Scoresbysund": "Ida-Gröönimaa aeg (Ittoqqortoormiit)", + "America\/Sitka": "Alaska aeg (Sitka)", + "America\/St_Barthelemy": "Atlandi aeg (Saint-Barthélemy)", + "America\/St_Johns": "Newfoundlandi aeg (Saint John’s)", + "America\/St_Kitts": "Atlandi aeg (Saint Kitts)", + "America\/St_Lucia": "Atlandi aeg (Saint Lucia)", + "America\/St_Thomas": "Atlandi aeg (Saint Thomas)", + "America\/St_Vincent": "Atlandi aeg (Saint Vincent)", + "America\/Swift_Current": "Kesk-Ameerika aeg (Swift Current)", + "America\/Tegucigalpa": "Kesk-Ameerika aeg (Tegucigalpa)", + "America\/Thule": "Atlandi aeg (Thule)", + "America\/Thunder_Bay": "Idaranniku aeg (Thunder Bay)", + "America\/Tijuana": "Vaikse ookeani aeg (Tijuana)", + "America\/Toronto": "Idaranniku aeg (Toronto)", + "America\/Tortola": "Atlandi aeg (Tortola)", + "America\/Vancouver": "Vaikse ookeani aeg (Vancouver)", + "America\/Whitehorse": "Vaikse ookeani aeg (Whitehorse)", + "America\/Winnipeg": "Kesk-Ameerika aeg (Winnipeg)", + "America\/Yakutat": "Alaska aeg (Yakutat)", + "America\/Yellowknife": "Mäestikuvööndi aeg (Yellowknife)", + "Antarctica\/Casey": "Lääne-Austraalia aeg (Casey)", + "Antarctica\/Davis": "Davise aeg (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville’i aeg (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie saare aeg (Macquarie)", + "Antarctica\/Mawson": "Mawsoni aeg (Mawson)", + "Antarctica\/McMurdo": "Uus-Meremaa aeg (McMurdo)", + "Antarctica\/Palmer": "Tšiili aeg (Palmer)", + "Antarctica\/Rothera": "Rothera aeg (Rothera)", + "Antarctica\/Syowa": "Syowa aeg (Syowa)", + "Antarctica\/Troll": "Greenwichi aeg (Troll)", + "Antarctica\/Vostok": "Vostoki aeg (Vostok)", + "Arctic\/Longyearbyen": "Kesk-Euroopa aeg (Longyearbyen)", + "Asia\/Aden": "Araabia aeg (Aden)", + "Asia\/Almaty": "Ida-Kasahstani aeg (Almatõ)", + "Asia\/Amman": "Ida-Euroopa aeg (Amman)", + "Asia\/Anadyr": "Anadõri aeg (Anadõr)", + "Asia\/Aqtau": "Lääne-Kasahstani aeg (Aktau)", + "Asia\/Aqtobe": "Lääne-Kasahstani aeg (Aktöbe)", + "Asia\/Ashgabat": "Türkmenistani aeg (Aşgabat)", + "Asia\/Atyrau": "Lääne-Kasahstani aeg (Atõrau)", + "Asia\/Baghdad": "Araabia aeg (Bagdad)", + "Asia\/Bahrain": "Araabia aeg (Bahrein)", + "Asia\/Baku": "Aserbaidžaani aeg (Bakuu)", + "Asia\/Bangkok": "Indohiina aeg (Bangkok)", + "Asia\/Beirut": "Ida-Euroopa aeg (Beirut)", + "Asia\/Bishkek": "Kõrgõzstani aeg (Biškek)", + "Asia\/Brunei": "Brunei aeg (Brunei)", + "Asia\/Calcutta": "India aeg (Kolkata)", + "Asia\/Chita": "Jakutski aeg (Tšita)", + "Asia\/Choibalsan": "Tšojbalsani aeg (Tšojbalsan)", + "Asia\/Colombo": "India aeg (Colombo)", + "Asia\/Damascus": "Ida-Euroopa aeg (Damaskus)", + "Asia\/Dhaka": "Bangladeshi aeg (Dhaka)", + "Asia\/Dili": "Ida-Timori aeg (Dili)", + "Asia\/Dubai": "Pärsia lahe standardaeg (Dubai)", + "Asia\/Dushanbe": "Tadžikistani aeg (Dušanbe)", + "Asia\/Famagusta": "Ida-Euroopa aeg (Famagusta)", + "Asia\/Gaza": "Ida-Euroopa aeg (Gaza)", + "Asia\/Hebron": "Ida-Euroopa aeg (Hebron)", + "Asia\/Hong_Kong": "Hongkongi aeg (Hongkong)", + "Asia\/Hovd": "Hovdi aeg (Hovd)", + "Asia\/Irkutsk": "Irkutski aeg (Irkutsk)", + "Asia\/Jakarta": "Lääne-Indoneesia aeg (Jakarta)", + "Asia\/Jayapura": "Ida-Indoneesia aeg (Jayapura)", + "Asia\/Jerusalem": "Iisraeli aeg (Jeruusalemm)", + "Asia\/Kabul": "Afganistani aeg (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamtšatski aeg (Kamtšatka)", + "Asia\/Karachi": "Pakistani aeg (Karachi)", + "Asia\/Katmandu": "Nepali aeg (Katmandu)", + "Asia\/Khandyga": "Jakutski aeg (Handõga)", + "Asia\/Krasnoyarsk": "Krasnojarski aeg (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malaisia ​​aeg (Kuala Lumpur)", + "Asia\/Kuching": "Malaisia ​​aeg (Kuching)", + "Asia\/Kuwait": "Araabia aeg (Kuveit)", + "Asia\/Macau": "Hiina aeg (Macau)", + "Asia\/Magadan": "Magadani aeg (Magadan)", + "Asia\/Makassar": "Kesk-Indoneesia aeg (Makassar)", + "Asia\/Manila": "Filipiini aeg (Manila)", + "Asia\/Muscat": "Pärsia lahe standardaeg (Masqaţ)", + "Asia\/Nicosia": "Ida-Euroopa aeg (Nikosia)", + "Asia\/Novokuznetsk": "Krasnojarski aeg (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirski aeg (Novosibirsk)", + "Asia\/Omsk": "Omski aeg (Omsk)", + "Asia\/Oral": "Lääne-Kasahstani aeg (Oral)", + "Asia\/Phnom_Penh": "Indohiina aeg (Phnom Penh)", + "Asia\/Pontianak": "Lääne-Indoneesia aeg (Pontianak)", + "Asia\/Pyongyang": "Korea aeg (Pyongyang)", + "Asia\/Qatar": "Araabia aeg (Katar)", + "Asia\/Qostanay": "Ida-Kasahstani aeg (Kostanaj)", + "Asia\/Qyzylorda": "Lääne-Kasahstani aeg (Kõzõlorda)", + "Asia\/Rangoon": "Birma aeg (Yangon)", + "Asia\/Riyadh": "Araabia aeg (Ar-Riyāḑ)", + "Asia\/Saigon": "Indohiina aeg (Ho Chi Minh)", + "Asia\/Sakhalin": "Sahhalini aeg (Sahhalin)", + "Asia\/Samarkand": "Usbekistani aeg (Samarkand)", + "Asia\/Seoul": "Korea aeg (Soul)", + "Asia\/Shanghai": "Hiina aeg (Shanghai)", + "Asia\/Singapore": "Singapuri standardaeg (Singapur)", + "Asia\/Srednekolymsk": "Magadani aeg (Srednekolõmsk)", + "Asia\/Taipei": "Taipei aeg (Taipei)", + "Asia\/Tashkent": "Usbekistani aeg (Taškent)", + "Asia\/Tbilisi": "Gruusia aeg (Thbilisi)", + "Asia\/Tehran": "Iraani aeg (Teheran)", + "Asia\/Thimphu": "Bhutani aeg (Thimphu)", + "Asia\/Tokyo": "Jaapani aeg (Tōkyō)", + "Asia\/Ulaanbaatar": "Ulaanbaatari aeg (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostoki aeg (Ust-Nera)", + "Asia\/Vientiane": "Indohiina aeg (Vientiane)", + "Asia\/Vladivostok": "Vladivostoki aeg (Vladivostok)", + "Asia\/Yakutsk": "Jakutski aeg (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburgi aeg (Jekaterinburg)", + "Asia\/Yerevan": "Armeenia aeg (Jerevan)", + "Atlantic\/Azores": "Assooride aeg (Assoorid)", + "Atlantic\/Bermuda": "Atlandi aeg (Bermuda)", + "Atlantic\/Canary": "Lääne-Euroopa aeg (Kanaari saared)", + "Atlantic\/Cape_Verde": "Roheneemesaarte aeg (Roheneemesaared)", + "Atlantic\/Faeroe": "Lääne-Euroopa aeg (Fääri saared)", + "Atlantic\/Madeira": "Lääne-Euroopa aeg (Madeira)", + "Atlantic\/Reykjavik": "Greenwichi aeg (Reykjavík)", + "Atlantic\/South_Georgia": "Lõuna-Georgia aeg (Lõuna-Georgia)", + "Atlantic\/St_Helena": "Greenwichi aeg (Saint Helena)", + "Atlantic\/Stanley": "Falklandi saarte aeg (Stanley)", + "Australia\/Adelaide": "Kesk-Austraalia aeg (Adelaide)", + "Australia\/Brisbane": "Ida-Austraalia aeg (Brisbane)", + "Australia\/Broken_Hill": "Kesk-Austraalia aeg (Broken Hill)", + "Australia\/Currie": "Ida-Austraalia aeg (Currie)", + "Australia\/Darwin": "Kesk-Austraalia aeg (Darwin)", + "Australia\/Eucla": "Austraalia Kesk-Lääne aeg (Eucla)", + "Australia\/Hobart": "Ida-Austraalia aeg (Hobart)", + "Australia\/Lindeman": "Ida-Austraalia aeg (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe’i aeg (Lord Howe)", + "Australia\/Melbourne": "Ida-Austraalia aeg (Melbourne)", + "Australia\/Perth": "Lääne-Austraalia aeg (Perth)", + "Australia\/Sydney": "Ida-Austraalia aeg (Sydney)", + "CST6CDT": "Kesk-Ameerika aeg", + "EST5EDT": "Idaranniku aeg", + "Etc\/GMT": "Greenwichi aeg", + "Etc\/UTC": "Koordineeritud maailmaaeg", + "Europe\/Amsterdam": "Kesk-Euroopa aeg (Amsterdam)", + "Europe\/Andorra": "Kesk-Euroopa aeg (Andorra)", + "Europe\/Astrakhan": "Moskva aeg (Astrahan)", + "Europe\/Athens": "Ida-Euroopa aeg (Ateena)", + "Europe\/Belgrade": "Kesk-Euroopa aeg (Belgrad)", + "Europe\/Berlin": "Kesk-Euroopa aeg (Berliin)", + "Europe\/Bratislava": "Kesk-Euroopa aeg (Bratislava)", + "Europe\/Brussels": "Kesk-Euroopa aeg (Brüssel)", + "Europe\/Bucharest": "Ida-Euroopa aeg (Bukarest)", + "Europe\/Budapest": "Kesk-Euroopa aeg (Budapest)", + "Europe\/Busingen": "Kesk-Euroopa aeg (Büsingen)", + "Europe\/Chisinau": "Ida-Euroopa aeg (Chișinău)", + "Europe\/Copenhagen": "Kesk-Euroopa aeg (Kopenhaagen)", + "Europe\/Dublin": "Greenwichi aeg (Dublin)", + "Europe\/Gibraltar": "Kesk-Euroopa aeg (Gibraltar)", + "Europe\/Guernsey": "Greenwichi aeg (Guernsey)", + "Europe\/Helsinki": "Ida-Euroopa aeg (Helsingi)", + "Europe\/Isle_of_Man": "Greenwichi aeg (Mani saar)", + "Europe\/Jersey": "Greenwichi aeg (Jersey)", + "Europe\/Kaliningrad": "Ida-Euroopa aeg (Kaliningrad)", + "Europe\/Kiev": "Ida-Euroopa aeg (Kiiev)", + "Europe\/Lisbon": "Lääne-Euroopa aeg (Lissabon)", + "Europe\/Ljubljana": "Kesk-Euroopa aeg (Ljubljana)", + "Europe\/London": "Greenwichi aeg (London)", + "Europe\/Luxembourg": "Kesk-Euroopa aeg (Luxembourg)", + "Europe\/Madrid": "Kesk-Euroopa aeg (Madrid)", + "Europe\/Malta": "Kesk-Euroopa aeg (Malta)", + "Europe\/Mariehamn": "Ida-Euroopa aeg (Maarianhamina)", + "Europe\/Minsk": "Moskva aeg (Minsk)", + "Europe\/Monaco": "Kesk-Euroopa aeg (Monaco)", + "Europe\/Moscow": "Moskva aeg (Moskva)", + "Europe\/Oslo": "Kesk-Euroopa aeg (Oslo)", + "Europe\/Paris": "Kesk-Euroopa aeg (Pariis)", + "Europe\/Podgorica": "Kesk-Euroopa aeg (Podgorica)", + "Europe\/Prague": "Kesk-Euroopa aeg (Praha)", + "Europe\/Riga": "Ida-Euroopa aeg (Riia)", + "Europe\/Rome": "Kesk-Euroopa aeg (Rooma)", + "Europe\/Samara": "Samara aeg (Samara)", + "Europe\/San_Marino": "Kesk-Euroopa aeg (San Marino)", + "Europe\/Sarajevo": "Kesk-Euroopa aeg (Sarajevo)", + "Europe\/Saratov": "Moskva aeg (Saratov)", + "Europe\/Simferopol": "Moskva aeg (Simferopol)", + "Europe\/Skopje": "Kesk-Euroopa aeg (Skopje)", + "Europe\/Sofia": "Ida-Euroopa aeg (Sofia)", + "Europe\/Stockholm": "Kesk-Euroopa aeg (Stockholm)", + "Europe\/Tallinn": "Ida-Euroopa aeg (Tallinn)", + "Europe\/Tirane": "Kesk-Euroopa aeg (Tirana)", + "Europe\/Ulyanovsk": "Moskva aeg (Uljanovsk)", + "Europe\/Uzhgorod": "Ida-Euroopa aeg (Užgorod)", + "Europe\/Vaduz": "Kesk-Euroopa aeg (Vaduz)", + "Europe\/Vatican": "Kesk-Euroopa aeg (Vatikan)", + "Europe\/Vienna": "Kesk-Euroopa aeg (Viin)", + "Europe\/Vilnius": "Ida-Euroopa aeg (Vilnius)", + "Europe\/Volgograd": "Volgogradi aeg (Volgograd)", + "Europe\/Warsaw": "Kesk-Euroopa aeg (Varssavi)", + "Europe\/Zagreb": "Kesk-Euroopa aeg (Zagreb)", + "Europe\/Zaporozhye": "Ida-Euroopa aeg (Zaporožje)", + "Europe\/Zurich": "Kesk-Euroopa aeg (Zürich)", + "Indian\/Antananarivo": "Ida-Aafrika aeg (Antananarivo)", + "Indian\/Chagos": "India ookeani aeg (Chagos)", + "Indian\/Christmas": "Jõulusaare aeg (Jõulusaar)", + "Indian\/Cocos": "Kookossaarte aeg (Kookossaared)", + "Indian\/Comoro": "Ida-Aafrika aeg (Comoro)", + "Indian\/Kerguelen": "Prantsuse Antarktiliste ja Lõunaalade aeg (Kerguelen)", + "Indian\/Mahe": "Seišelli aeg (Mahe)", + "Indian\/Maldives": "Maldiivi aeg (Maldiivid)", + "Indian\/Mauritius": "Mauritiuse aeg (Mauritius)", + "Indian\/Mayotte": "Ida-Aafrika aeg (Mayotte)", + "Indian\/Reunion": "Réunioni aeg (Réunion)", + "MST7MDT": "Mäestikuvööndi aeg", + "PST8PDT": "Vaikse ookeani aeg", + "Pacific\/Apia": "Apia aeg (Apia)", + "Pacific\/Auckland": "Uus-Meremaa aeg (Auckland)", + "Pacific\/Bougainville": "Paapua Uus-Guinea aeg (Bougainville)", + "Pacific\/Chatham": "Chathami aeg (Chatham)", + "Pacific\/Easter": "Lihavõttesaare aeg (Lihavõttesaar)", + "Pacific\/Efate": "Vanuatu aeg (Efate)", + "Pacific\/Enderbury": "Fööniksisaarte aeg (Enderbury)", + "Pacific\/Fakaofo": "Tokelau aeg (Fakaofo)", + "Pacific\/Fiji": "Fidži aeg (Fidži)", + "Pacific\/Funafuti": "Tuvalu aeg (Funafuti)", + "Pacific\/Galapagos": "Galapagose aeg (Galápagos)", + "Pacific\/Gambier": "Gambier’ aeg (Gambier)", + "Pacific\/Guadalcanal": "Saalomoni Saarte aeg (Guadalcanal)", + "Pacific\/Guam": "Tšamorro standardaeg (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleuudi aeg (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleuudi aeg (Johnston)", + "Pacific\/Kiritimati": "Line’i saarte aeg (Kiritimati)", + "Pacific\/Kosrae": "Kosrae aeg (Kosrae)", + "Pacific\/Kwajalein": "Marshalli Saarte aeg (Kwajalein)", + "Pacific\/Majuro": "Marshalli Saarte aeg (Majuro)", + "Pacific\/Marquesas": "Markiisaarte aeg (Markiisaared)", + "Pacific\/Midway": "Samoa aeg (Midway)", + "Pacific\/Nauru": "Nauru aeg (Nauru)", + "Pacific\/Niue": "Niue aeg (Niue)", + "Pacific\/Norfolk": "Norfolki saarte aeg (Norfolk)", + "Pacific\/Noumea": "Uus-Kaledoonia aeg (Noumea)", + "Pacific\/Pago_Pago": "Samoa aeg (Pago Pago)", + "Pacific\/Palau": "Belau aeg (Belau)", + "Pacific\/Pitcairn": "Pitcairni aeg (Pitcairn)", + "Pacific\/Ponape": "Pohnpei aeg (Pohnpei)", + "Pacific\/Port_Moresby": "Paapua Uus-Guinea aeg (Port Moresby)", + "Pacific\/Rarotonga": "Cooki saarte aeg (Rarotonga)", + "Pacific\/Saipan": "Tšamorro standardaeg (Saipan)", + "Pacific\/Tahiti": "Tahiti aeg (Tahiti)", + "Pacific\/Tarawa": "Gilberti saarte aeg (Tarawa)", + "Pacific\/Tongatapu": "Tonga aeg (Tongatapu)", + "Pacific\/Truk": "Chuuki aeg (Chuuk)", + "Pacific\/Wake": "Wake’i aeg (Wake)", + "Pacific\/Wallis": "Wallise ja Futuna aeg (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/eu.json b/src/Symfony/Component/Intl/Resources/data/timezones/eu.json new file mode 100644 index 0000000000000..436fab031c6b6 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/eu.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Greenwichko meridianoaren ordua (Abidjan)", + "Africa\/Accra": "Greenwichko meridianoaren ordua (Akkra)", + "Africa\/Addis_Ababa": "Afrikako ekialdeko ordua (Addis Abeba)", + "Africa\/Algiers": "Europako erdialdeko ordua (Aljer)", + "Africa\/Asmera": "Afrikako ekialdeko ordua (Asmara)", + "Africa\/Bamako": "Greenwichko meridianoaren ordua (Bamako)", + "Africa\/Bangui": "Afrikako mendebaldeko ordua (Bangi)", + "Africa\/Banjul": "Greenwichko meridianoaren ordua (Banjul)", + "Africa\/Bissau": "Greenwichko meridianoaren ordua (Bissau)", + "Africa\/Blantyre": "Afrikako erdialdeko ordua (Blantyre)", + "Africa\/Brazzaville": "Afrikako mendebaldeko ordua (Brazzaville)", + "Africa\/Bujumbura": "Afrikako erdialdeko ordua (Bujumbura)", + "Africa\/Cairo": "Europako ekialdeko ordua (Kairo)", + "Africa\/Casablanca": "Europako mendebaldeko ordua (Casablanca)", + "Africa\/Ceuta": "Europako erdialdeko ordua (Ceuta)", + "Africa\/Conakry": "Greenwichko meridianoaren ordua (Konakry)", + "Africa\/Dakar": "Greenwichko meridianoaren ordua (Dakar)", + "Africa\/Dar_es_Salaam": "Afrikako ekialdeko ordua (Dar es Salaam)", + "Africa\/Djibouti": "Afrikako ekialdeko ordua (Djibuti)", + "Africa\/Douala": "Afrikako mendebaldeko ordua (Douala)", + "Africa\/El_Aaiun": "Europako mendebaldeko ordua (Aaiun)", + "Africa\/Freetown": "Greenwichko meridianoaren ordua (Freetown)", + "Africa\/Gaborone": "Afrikako erdialdeko ordua (Gaborone)", + "Africa\/Harare": "Afrikako erdialdeko ordua (Harare)", + "Africa\/Johannesburg": "Afrikako hegoaldeko ordua (Johannesburgo)", + "Africa\/Juba": "Afrikako ekialdeko ordua (Juba)", + "Africa\/Kampala": "Afrikako ekialdeko ordua (Kampala)", + "Africa\/Khartoum": "Afrikako erdialdeko ordua (Khartoum)", + "Africa\/Kigali": "Afrikako erdialdeko ordua (Kigali)", + "Africa\/Kinshasa": "Afrikako mendebaldeko ordua (Kinshasa)", + "Africa\/Lagos": "Afrikako mendebaldeko ordua (Lagos)", + "Africa\/Libreville": "Afrikako mendebaldeko ordua (Libreville)", + "Africa\/Lome": "Greenwichko meridianoaren ordua (Lome)", + "Africa\/Luanda": "Afrikako mendebaldeko ordua (Luanda)", + "Africa\/Lubumbashi": "Afrikako erdialdeko ordua (Lubumbashi)", + "Africa\/Lusaka": "Afrikako erdialdeko ordua (Lusaka)", + "Africa\/Malabo": "Afrikako mendebaldeko ordua (Malabo)", + "Africa\/Maputo": "Afrikako erdialdeko ordua (Maputo)", + "Africa\/Maseru": "Afrikako hegoaldeko ordua (Maseru)", + "Africa\/Mbabane": "Afrikako hegoaldeko ordua (Mbabane)", + "Africa\/Mogadishu": "Afrikako ekialdeko ordua (Muqdisho)", + "Africa\/Monrovia": "Greenwichko meridianoaren ordua (Monrovia)", + "Africa\/Nairobi": "Afrikako ekialdeko ordua (Nairobi)", + "Africa\/Ndjamena": "Afrikako mendebaldeko ordua (N’djamena)", + "Africa\/Niamey": "Afrikako mendebaldeko ordua (Niamei)", + "Africa\/Nouakchott": "Greenwichko meridianoaren ordua (Nuakxot)", + "Africa\/Ouagadougou": "Greenwichko meridianoaren ordua (Uagadugu)", + "Africa\/Porto-Novo": "Afrikako mendebaldeko ordua (Porto Novo)", + "Africa\/Sao_Tome": "Greenwichko meridianoaren ordua (Sao Tome)", + "Africa\/Tripoli": "Europako ekialdeko ordua (Tripoli)", + "Africa\/Tunis": "Europako erdialdeko ordua (Tunis)", + "Africa\/Windhoek": "Afrikako erdialdeko ordua (Windhoek)", + "America\/Adak": "Hawaii-Aleutiar uharteetako ordua (Adak)", + "America\/Anchorage": "Alaskako ordua (Anchorage)", + "America\/Anguilla": "Ipar Amerikako Atlantikoko ordua (Aingira)", + "America\/Antigua": "Ipar Amerikako Atlantikoko ordua (Antigua)", + "America\/Araguaina": "Brasiliako ordua (Araguaína)", + "America\/Argentina\/La_Rioja": "Argentinako ordua (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinako ordua (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinako ordua (Salta)", + "America\/Argentina\/San_Juan": "Argentinako ordua (San Juan)", + "America\/Argentina\/San_Luis": "Argentina mendebaldeko ordua (San Luis)", + "America\/Argentina\/Tucuman": "Argentinako ordua (Tucumán)", + "America\/Argentina\/Ushuaia": "Argentinako ordua (Ushuaia)", + "America\/Aruba": "Ipar Amerikako Atlantikoko ordua (Aruba)", + "America\/Asuncion": "Paraguaiko ordua (Asuncion)", + "America\/Bahia": "Brasiliako ordua (Bahia)", + "America\/Bahia_Banderas": "Ipar Amerikako erdialdeko ordua (Bahía de Banderas)", + "America\/Barbados": "Ipar Amerikako Atlantikoko ordua (Barbados)", + "America\/Belem": "Brasiliako ordua (Belem)", + "America\/Belize": "Ipar Amerikako erdialdeko ordua (Belize)", + "America\/Blanc-Sablon": "Ipar Amerikako Atlantikoko ordua (Blanc-Sablon)", + "America\/Boa_Vista": "Amazoniako ordua (Boa Vista)", + "America\/Bogota": "Kolonbiako ordua (Bogota)", + "America\/Boise": "Ipar Amerikako mendialdeko ordua (Boise)", + "America\/Buenos_Aires": "Argentinako ordua (Buenos Aires)", + "America\/Cambridge_Bay": "Ipar Amerikako mendialdeko ordua (Cambridge Bay)", + "America\/Campo_Grande": "Amazoniako ordua (Campo Grande)", + "America\/Cancun": "Ipar Amerikako ekialdeko ordua (Cancún)", + "America\/Caracas": "Venezuelako ordua (Caracas)", + "America\/Catamarca": "Argentinako ordua (Catamarca)", + "America\/Cayenne": "Guyana Frantseseko ordua (Cayenne)", + "America\/Cayman": "Ipar Amerikako ekialdeko ordua (Kaiman)", + "America\/Chicago": "Ipar Amerikako erdialdeko ordua (Chicago)", + "America\/Chihuahua": "Mexikoko Pazifikoko ordua (Chihuahua)", + "America\/Coral_Harbour": "Ipar Amerikako ekialdeko ordua (Atikokan)", + "America\/Cordoba": "Argentinako ordua (Córdoba)", + "America\/Costa_Rica": "Ipar Amerikako erdialdeko ordua (Costa Rica)", + "America\/Creston": "Ipar Amerikako mendialdeko ordua (Creston)", + "America\/Cuiaba": "Amazoniako ordua (Cuiabá)", + "America\/Curacao": "Ipar Amerikako Atlantikoko ordua (Curaçao)", + "America\/Danmarkshavn": "Greenwichko meridianoaren ordua (Danmarkshavn)", + "America\/Dawson": "Ipar Amerikako Pazifikoko ordua (Dawson)", + "America\/Dawson_Creek": "Ipar Amerikako mendialdeko ordua (Dawson Creek)", + "America\/Denver": "Ipar Amerikako mendialdeko ordua (Denver)", + "America\/Detroit": "Ipar Amerikako ekialdeko ordua (Detroit)", + "America\/Dominica": "Ipar Amerikako Atlantikoko ordua (Dominika)", + "America\/Edmonton": "Ipar Amerikako mendialdeko ordua (Edmonton)", + "America\/El_Salvador": "Ipar Amerikako erdialdeko ordua (El Salvador)", + "America\/Fort_Nelson": "Ipar Amerikako mendialdeko ordua (Fort Nelson)", + "America\/Fortaleza": "Brasiliako ordua (Fortaleza)", + "America\/Glace_Bay": "Ipar Amerikako Atlantikoko ordua (Glace Bay)", + "America\/Godthab": "Groenlandiako mendebaldeko ordua (Nuuk)", + "America\/Goose_Bay": "Ipar Amerikako Atlantikoko ordua (Goose Bay)", + "America\/Grand_Turk": "Ipar Amerikako ekialdeko ordua (Grand Turk)", + "America\/Grenada": "Ipar Amerikako Atlantikoko ordua (Grenada)", + "America\/Guadeloupe": "Ipar Amerikako Atlantikoko ordua (Guadalupe)", + "America\/Guatemala": "Ipar Amerikako erdialdeko ordua (Guatemala)", + "America\/Guayaquil": "Ekuadorreko ordua (Guayaquil)", + "America\/Guyana": "Guyanako ordua (Guyana)", + "America\/Halifax": "Ipar Amerikako Atlantikoko ordua (Halifax)", + "America\/Havana": "Kubako ordua (Habana)", + "America\/Hermosillo": "Mexikoko Pazifikoko ordua (Hermosillo)", + "America\/Indiana\/Knox": "Ipar Amerikako erdialdeko ordua (Knox, Indiana)", + "America\/Indiana\/Marengo": "Ipar Amerikako ekialdeko ordua (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Ipar Amerikako ekialdeko ordua (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Ipar Amerikako erdialdeko ordua (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Ipar Amerikako ekialdeko ordua (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Ipar Amerikako ekialdeko ordua (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Ipar Amerikako ekialdeko ordua (Winamac, Indiana)", + "America\/Indianapolis": "Ipar Amerikako ekialdeko ordua (Indianapolis)", + "America\/Inuvik": "Ipar Amerikako mendialdeko ordua (Inuvik)", + "America\/Iqaluit": "Ipar Amerikako ekialdeko ordua (Iqaluit)", + "America\/Jamaica": "Ipar Amerikako ekialdeko ordua (Jamaika)", + "America\/Jujuy": "Argentinako ordua (Jujuy)", + "America\/Juneau": "Alaskako ordua (Juneau)", + "America\/Kentucky\/Monticello": "Ipar Amerikako ekialdeko ordua (Monticello, Kentucky)", + "America\/Kralendijk": "Ipar Amerikako Atlantikoko ordua (Kralendijk)", + "America\/La_Paz": "Boliviako ordua (La Paz)", + "America\/Lima": "Peruko ordua (Lima)", + "America\/Los_Angeles": "Ipar Amerikako Pazifikoko ordua (Los Angeles)", + "America\/Louisville": "Ipar Amerikako ekialdeko ordua (Louisville)", + "America\/Lower_Princes": "Ipar Amerikako Atlantikoko ordua (Lower Prince’s Quarter)", + "America\/Maceio": "Brasiliako ordua (Maceió)", + "America\/Managua": "Ipar Amerikako erdialdeko ordua (Managua)", + "America\/Manaus": "Amazoniako ordua (Manaus)", + "America\/Marigot": "Ipar Amerikako Atlantikoko ordua (Marigot)", + "America\/Martinique": "Ipar Amerikako Atlantikoko ordua (Martinika)", + "America\/Matamoros": "Ipar Amerikako erdialdeko ordua (Matamoros)", + "America\/Mazatlan": "Mexikoko Pazifikoko ordua (Mazatlán)", + "America\/Mendoza": "Argentinako ordua (Mendoza)", + "America\/Menominee": "Ipar Amerikako erdialdeko ordua (Menominee)", + "America\/Merida": "Ipar Amerikako erdialdeko ordua (Mérida)", + "America\/Metlakatla": "Alaskako ordua (Metlakatla)", + "America\/Mexico_City": "Ipar Amerikako erdialdeko ordua (Mexiko Hiria)", + "America\/Miquelon": "Saint-Pierre eta Mikeluneko ordua (Mikelune)", + "America\/Moncton": "Ipar Amerikako Atlantikoko ordua (Moncton)", + "America\/Monterrey": "Ipar Amerikako erdialdeko ordua (Monterrey)", + "America\/Montevideo": "Uruguaiko ordua (Montevideo)", + "America\/Montserrat": "Ipar Amerikako Atlantikoko ordua (Montserrat)", + "America\/Nassau": "Ipar Amerikako ekialdeko ordua (Nassau)", + "America\/New_York": "Ipar Amerikako ekialdeko ordua (New York)", + "America\/Nipigon": "Ipar Amerikako ekialdeko ordua (Nipigon)", + "America\/Nome": "Alaskako ordua (Nome)", + "America\/Noronha": "Fernando de Noronhako ordua (Noronha)", + "America\/North_Dakota\/Beulah": "Ipar Amerikako erdialdeko ordua (Beulah, Ipar Dakota)", + "America\/North_Dakota\/Center": "Ipar Amerikako erdialdeko ordua (Center, Ipar Dakota)", + "America\/North_Dakota\/New_Salem": "Ipar Amerikako erdialdeko ordua (New Salem, Ipar Dakota)", + "America\/Ojinaga": "Ipar Amerikako mendialdeko ordua (Ojinaga)", + "America\/Panama": "Ipar Amerikako ekialdeko ordua (Panama)", + "America\/Pangnirtung": "Ipar Amerikako ekialdeko ordua (Pangnirtung)", + "America\/Paramaribo": "Surinamgo ordua (Paramaribo)", + "America\/Phoenix": "Ipar Amerikako mendialdeko ordua (Phoenix)", + "America\/Port-au-Prince": "Ipar Amerikako ekialdeko ordua (Port-au-Prince)", + "America\/Port_of_Spain": "Ipar Amerikako Atlantikoko ordua (Port-of-Spain)", + "America\/Porto_Velho": "Amazoniako ordua (Porto Velho)", + "America\/Puerto_Rico": "Ipar Amerikako Atlantikoko ordua (Puerto Rico)", + "America\/Punta_Arenas": "Txileko ordua (Punta Arenas)", + "America\/Rainy_River": "Ipar Amerikako erdialdeko ordua (Rainy River)", + "America\/Rankin_Inlet": "Ipar Amerikako erdialdeko ordua (Rankin Inlet)", + "America\/Recife": "Brasiliako ordua (Recife)", + "America\/Regina": "Ipar Amerikako erdialdeko ordua (Regina)", + "America\/Resolute": "Ipar Amerikako erdialdeko ordua (Resolute)", + "America\/Santa_Isabel": "Mexikoko ipar-ekialdeko ordua (Santa Isabel)", + "America\/Santarem": "Brasiliako ordua (Santarém)", + "America\/Santiago": "Txileko ordua (Santiago)", + "America\/Santo_Domingo": "Ipar Amerikako Atlantikoko ordua (Santo Domingo)", + "America\/Sao_Paulo": "Brasiliako ordua (São Paulo)", + "America\/Scoresbysund": "Groenlandiako ekialdeko ordua (Ittoqqortoormiit)", + "America\/Sitka": "Alaskako ordua (Sitka)", + "America\/St_Barthelemy": "Ipar Amerikako Atlantikoko ordua (Saint-Barthélemy)", + "America\/St_Johns": "Ternuako ordua (Saint John’s)", + "America\/St_Kitts": "Ipar Amerikako Atlantikoko ordua (Saint Kitts)", + "America\/St_Lucia": "Ipar Amerikako Atlantikoko ordua (Santa Luzia)", + "America\/St_Thomas": "Ipar Amerikako Atlantikoko ordua (Saint-Thomas)", + "America\/St_Vincent": "Ipar Amerikako Atlantikoko ordua (Saint Vincent)", + "America\/Swift_Current": "Ipar Amerikako erdialdeko ordua (Swift Current)", + "America\/Tegucigalpa": "Ipar Amerikako erdialdeko ordua (Tegucigalpa)", + "America\/Thule": "Ipar Amerikako Atlantikoko ordua (Qaanaac)", + "America\/Thunder_Bay": "Ipar Amerikako ekialdeko ordua (Thunder Bay)", + "America\/Tijuana": "Ipar Amerikako Pazifikoko ordua (Tijuana)", + "America\/Toronto": "Ipar Amerikako ekialdeko ordua (Toronto)", + "America\/Tortola": "Ipar Amerikako Atlantikoko ordua (Tortola)", + "America\/Vancouver": "Ipar Amerikako Pazifikoko ordua (Vancouver)", + "America\/Whitehorse": "Ipar Amerikako Pazifikoko ordua (Whitehorse)", + "America\/Winnipeg": "Ipar Amerikako erdialdeko ordua (Winnipeg)", + "America\/Yakutat": "Alaskako ordua (Yakutat)", + "America\/Yellowknife": "Ipar Amerikako mendialdeko ordua (Yellowknife)", + "Antarctica\/Casey": "Australiako mendebaldeko ordua (Casey)", + "Antarctica\/Davis": "Daviseko ordua (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urvilleko ordua (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie uharteko ordua (Macquarie)", + "Antarctica\/Mawson": "Mawsoneko ordua (Mawson)", + "Antarctica\/McMurdo": "Zeelanda Berriko ordua (McMurdo)", + "Antarctica\/Palmer": "Txileko ordua (Palmer)", + "Antarctica\/Rothera": "Rotherako ordua (Rothera)", + "Antarctica\/Syowa": "Syowako ordua (Syowa)", + "Antarctica\/Troll": "Greenwichko meridianoaren ordua (Troll)", + "Antarctica\/Vostok": "Vostokeko ordua (Vostok)", + "Arctic\/Longyearbyen": "Europako erdialdeko ordua (Longyearbyen)", + "Asia\/Aden": "Arabiako ordua (Aden)", + "Asia\/Almaty": "Kazakhstango ekialdeko ordua (Almaty)", + "Asia\/Amman": "Europako ekialdeko ordua (Amman)", + "Asia\/Anadyr": "Anadyrreko ordua (Anadyr)", + "Asia\/Aqtau": "Kazakhstango mendebaldeko ordua (Aktau)", + "Asia\/Aqtobe": "Kazakhstango mendebaldeko ordua (Aktobe)", + "Asia\/Ashgabat": "Turkmenistango ordua (Asgabat)", + "Asia\/Atyrau": "Kazakhstango mendebaldeko ordua (Atyrau)", + "Asia\/Baghdad": "Arabiako ordua (Bagdad)", + "Asia\/Bahrain": "Arabiako ordua (Bahrain)", + "Asia\/Baku": "Azerbaijango ordua (Baku)", + "Asia\/Bangkok": "Indotxinako ordua (Bangkok)", + "Asia\/Beirut": "Europako ekialdeko ordua (Beirut)", + "Asia\/Bishkek": "Kirgizistango ordua (Bixkek)", + "Asia\/Brunei": "Brunei Darussalamgo ordua (Brunei)", + "Asia\/Calcutta": "Indiako ordua (Kalkuta)", + "Asia\/Chita": "Jakutskeko ordua (Chita)", + "Asia\/Choibalsan": "Txoibalsango ordua (Txoibalsan)", + "Asia\/Colombo": "Indiako ordua (Kolombo)", + "Asia\/Damascus": "Europako ekialdeko ordua (Damasko)", + "Asia\/Dhaka": "Bangladesheko ordua (Dhaka)", + "Asia\/Dili": "Ekialdeko Timorreko ordua (Dili)", + "Asia\/Dubai": "Golkoko ordu estandarra (Dubai)", + "Asia\/Dushanbe": "Tadjikistango ordua (Duxanbe)", + "Asia\/Famagusta": "Europako ekialdeko ordua (Famagusta)", + "Asia\/Gaza": "Europako ekialdeko ordua (Gaza)", + "Asia\/Hebron": "Europako ekialdeko ordua (Hebron)", + "Asia\/Hong_Kong": "Hong Kongo ordua (Hong Kong)", + "Asia\/Hovd": "Khovdeko ordua (Khovd)", + "Asia\/Irkutsk": "Irkutskeko ordua (Irkutsk)", + "Asia\/Jakarta": "Indonesiako mendebaldeko ordua (Jakarta)", + "Asia\/Jayapura": "Indonesiako ekialdeko ordua (Jayapura)", + "Asia\/Jerusalem": "Israelgo ordua (Jerusalem)", + "Asia\/Kabul": "Afganistango ordua (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamchatskiko ordua (Kamtxatka)", + "Asia\/Karachi": "Pakistango ordua (Karatxi)", + "Asia\/Katmandu": "Nepalgo ordua (Katmandu)", + "Asia\/Khandyga": "Jakutskeko ordua (Khandiga)", + "Asia\/Krasnoyarsk": "Krasnoiarskeko ordua (Krasnoiarsk)", + "Asia\/Kuala_Lumpur": "Malaysiako ordua (Kuala Lumpur)", + "Asia\/Kuching": "Malaysiako ordua (Kuching)", + "Asia\/Kuwait": "Arabiako ordua (Kuwait)", + "Asia\/Macau": "Txinako ordua (Macao)", + "Asia\/Magadan": "Magadango ordua (Magadan)", + "Asia\/Makassar": "Indonesiako erdialdeko ordua (Makassar)", + "Asia\/Manila": "Filipinetako ordua (Manila)", + "Asia\/Muscat": "Golkoko ordu estandarra (Maskat)", + "Asia\/Nicosia": "Europako ekialdeko ordua (Nikosia)", + "Asia\/Novokuznetsk": "Krasnoiarskeko ordua (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirskeko ordua (Novosibirsk)", + "Asia\/Omsk": "Omskeko ordua (Omsk)", + "Asia\/Oral": "Kazakhstango mendebaldeko ordua (Oral)", + "Asia\/Phnom_Penh": "Indotxinako ordua (Phnom Penh)", + "Asia\/Pontianak": "Indonesiako mendebaldeko ordua (Pontianak)", + "Asia\/Pyongyang": "Koreako ordua (Piongiang)", + "Asia\/Qatar": "Arabiako ordua (Qatar)", + "Asia\/Qostanay": "Kazakhstango ekialdeko ordua (Qostanay)", + "Asia\/Qyzylorda": "Kazakhstango mendebaldeko ordua (Kyzylorda)", + "Asia\/Rangoon": "Myanmarreko ordua (Yangon)", + "Asia\/Riyadh": "Arabiako ordua (Riad)", + "Asia\/Saigon": "Indotxinako ordua (Ho Chi Minh)", + "Asia\/Sakhalin": "Sakhalingo ordua (Sakhalin)", + "Asia\/Samarkand": "Uzbekistango ordua (Samarkanda)", + "Asia\/Seoul": "Koreako ordua (Seul)", + "Asia\/Shanghai": "Txinako ordua (Shanghai)", + "Asia\/Singapore": "Singapurreko ordu estandarra (Singapur)", + "Asia\/Srednekolymsk": "Magadango ordua (Srednekolimsk)", + "Asia\/Taipei": "Taipeiko ordua (Taipei)", + "Asia\/Tashkent": "Uzbekistango ordua (Taxkent)", + "Asia\/Tbilisi": "Georgiako ordua (Tbilisi)", + "Asia\/Tehran": "Irango ordua (Teheran)", + "Asia\/Thimphu": "Bhutango ordua (Thimphu)", + "Asia\/Tokyo": "Japoniako ordua (Tokio)", + "Asia\/Ulaanbaatar": "Ulan Batorreko ordua (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostokeko ordua (Ust-Nera)", + "Asia\/Vientiane": "Indotxinako ordua (Vientian)", + "Asia\/Vladivostok": "Vladivostokeko ordua (Vladivostok)", + "Asia\/Yakutsk": "Jakutskeko ordua (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburgeko ordua (Jekaterinburg)", + "Asia\/Yerevan": "Armeniako ordua (Erevan)", + "Atlantic\/Azores": "Azoreetako ordua (Azoreak)", + "Atlantic\/Bermuda": "Ipar Amerikako Atlantikoko ordua (Bermuda)", + "Atlantic\/Canary": "Europako mendebaldeko ordua (Kanariak)", + "Atlantic\/Cape_Verde": "Cabo Verdeko ordua (Cabo Verde)", + "Atlantic\/Faeroe": "Europako mendebaldeko ordua (Faroe)", + "Atlantic\/Madeira": "Europako mendebaldeko ordua (Madeira)", + "Atlantic\/Reykjavik": "Greenwichko meridianoaren ordua (Reykjavik)", + "Atlantic\/South_Georgia": "Hegoaldeko Georgietako ordua (South Georgia)", + "Atlantic\/St_Helena": "Greenwichko meridianoaren ordua (Santa Helena)", + "Atlantic\/Stanley": "Falkland uharteetako ordua (Stanley)", + "Australia\/Adelaide": "Australiako erdialdeko ordua (Adelaide)", + "Australia\/Brisbane": "Australiako ekialdeko ordua (Brisbane)", + "Australia\/Broken_Hill": "Australiako erdialdeko ordua (Broken Hill)", + "Australia\/Currie": "Australiako ekialdeko ordua (Currie)", + "Australia\/Darwin": "Australiako erdialdeko ordua (Darwin)", + "Australia\/Eucla": "Australiako erdi-mendebaldeko ordua (Eucla)", + "Australia\/Hobart": "Australiako ekialdeko ordua (Hobart)", + "Australia\/Lindeman": "Australiako ekialdeko ordua (Lindeman)", + "Australia\/Lord_Howe": "Lord Howeko ordua (Lord Howe)", + "Australia\/Melbourne": "Australiako ekialdeko ordua (Melbourne)", + "Australia\/Perth": "Australiako mendebaldeko ordua (Perth)", + "Australia\/Sydney": "Australiako ekialdeko ordua (Sydney)", + "CST6CDT": "Ipar Amerikako erdialdeko ordua", + "EST5EDT": "Ipar Amerikako ekialdeko ordua", + "Etc\/GMT": "Greenwichko meridianoaren ordua", + "Etc\/UTC": "Ordu Unibertsal Koordinatua", + "Europe\/Amsterdam": "Europako erdialdeko ordua (Amsterdam)", + "Europe\/Andorra": "Europako erdialdeko ordua (Andorra)", + "Europe\/Astrakhan": "Moskuko ordua (Astrakhan)", + "Europe\/Athens": "Europako ekialdeko ordua (Atenas)", + "Europe\/Belgrade": "Europako erdialdeko ordua (Belgrad)", + "Europe\/Berlin": "Europako erdialdeko ordua (Berlin)", + "Europe\/Bratislava": "Europako erdialdeko ordua (Bratislava)", + "Europe\/Brussels": "Europako erdialdeko ordua (Brusela)", + "Europe\/Bucharest": "Europako ekialdeko ordua (Bukarest)", + "Europe\/Budapest": "Europako erdialdeko ordua (Budapest)", + "Europe\/Busingen": "Europako erdialdeko ordua (Büsingen)", + "Europe\/Chisinau": "Europako ekialdeko ordua (Chisinau)", + "Europe\/Copenhagen": "Europako erdialdeko ordua (Kopenhage)", + "Europe\/Dublin": "Greenwichko meridianoaren ordua (Dublin)", + "Europe\/Gibraltar": "Europako erdialdeko ordua (Gibraltar)", + "Europe\/Guernsey": "Greenwichko meridianoaren ordua (Guernesey)", + "Europe\/Helsinki": "Europako ekialdeko ordua (Helsinki)", + "Europe\/Isle_of_Man": "Greenwichko meridianoaren ordua (Man uhartea)", + "Europe\/Jersey": "Greenwichko meridianoaren ordua (Jersey)", + "Europe\/Kaliningrad": "Europako ekialdeko ordua (Kaliningrad)", + "Europe\/Kiev": "Europako ekialdeko ordua (Kiev)", + "Europe\/Lisbon": "Europako mendebaldeko ordua (Lisboa)", + "Europe\/Ljubljana": "Europako erdialdeko ordua (Ljubljana)", + "Europe\/London": "Greenwichko meridianoaren ordua (Londres)", + "Europe\/Luxembourg": "Europako erdialdeko ordua (Luxenburgo)", + "Europe\/Madrid": "Europako erdialdeko ordua (Madril)", + "Europe\/Malta": "Europako erdialdeko ordua (Malta)", + "Europe\/Mariehamn": "Europako ekialdeko ordua (Mariehamn)", + "Europe\/Minsk": "Moskuko ordua (Minsk)", + "Europe\/Monaco": "Europako erdialdeko ordua (Monako)", + "Europe\/Moscow": "Moskuko ordua (Mosku)", + "Europe\/Oslo": "Europako erdialdeko ordua (Oslo)", + "Europe\/Paris": "Europako erdialdeko ordua (Paris)", + "Europe\/Podgorica": "Europako erdialdeko ordua (Podgorica)", + "Europe\/Prague": "Europako erdialdeko ordua (Praga)", + "Europe\/Riga": "Europako ekialdeko ordua (Riga)", + "Europe\/Rome": "Europako erdialdeko ordua (Erroma)", + "Europe\/Samara": "Samarako ordua (Samara)", + "Europe\/San_Marino": "Europako erdialdeko ordua (San Marino)", + "Europe\/Sarajevo": "Europako erdialdeko ordua (Sarajevo)", + "Europe\/Saratov": "Moskuko ordua (Saratov)", + "Europe\/Simferopol": "Moskuko ordua (Simferopol)", + "Europe\/Skopje": "Europako erdialdeko ordua (Skopje)", + "Europe\/Sofia": "Europako ekialdeko ordua (Sofia)", + "Europe\/Stockholm": "Europako erdialdeko ordua (Stockholm)", + "Europe\/Tallinn": "Europako ekialdeko ordua (Tallinn)", + "Europe\/Tirane": "Europako erdialdeko ordua (Tirana)", + "Europe\/Ulyanovsk": "Moskuko ordua (Ulianovsk)", + "Europe\/Uzhgorod": "Europako ekialdeko ordua (Uzhhorod)", + "Europe\/Vaduz": "Europako erdialdeko ordua (Vaduz)", + "Europe\/Vatican": "Europako erdialdeko ordua (Vatikano Hiria)", + "Europe\/Vienna": "Europako erdialdeko ordua (Viena)", + "Europe\/Vilnius": "Europako ekialdeko ordua (Vilnius)", + "Europe\/Volgograd": "Volgogradeko ordua (Volgograd)", + "Europe\/Warsaw": "Europako erdialdeko ordua (Varsovia)", + "Europe\/Zagreb": "Europako erdialdeko ordua (Zagreb)", + "Europe\/Zaporozhye": "Europako ekialdeko ordua (Zaporozhye)", + "Europe\/Zurich": "Europako erdialdeko ordua (Zürich)", + "Indian\/Antananarivo": "Afrikako ekialdeko ordua (Antananarivo)", + "Indian\/Chagos": "Indiako Ozeanoko ordua (Chagos)", + "Indian\/Christmas": "Christmas uharteko ordua (Christmas)", + "Indian\/Cocos": "Cocos uharteetako ordua (Cocos)", + "Indian\/Comoro": "Afrikako ekialdeko ordua (Comoro)", + "Indian\/Kerguelen": "Frantziaren lurralde austral eta antartikoetako ordutegia (Kerguelen)", + "Indian\/Mahe": "Seychelle uharteetako ordua (Mahé)", + "Indian\/Maldives": "Maldivetako ordua (Maldivak)", + "Indian\/Mauritius": "Maurizioko ordua (Maurizio)", + "Indian\/Mayotte": "Afrikako ekialdeko ordua (Mayotte)", + "Indian\/Reunion": "Reunioneko ordua (Reunion)", + "MST7MDT": "Ipar Amerikako mendialdeko ordua", + "PST8PDT": "Ipar Amerikako Pazifikoko ordua", + "Pacific\/Apia": "Apiako ordua (Apia)", + "Pacific\/Auckland": "Zeelanda Berriko ordua (Auckland)", + "Pacific\/Bougainville": "Papua Ginea Berriko ordua (Bougainville)", + "Pacific\/Chatham": "Chathamgo ordua (Chatham)", + "Pacific\/Easter": "Pazko uharteko ordua (Pazko uhartea)", + "Pacific\/Efate": "Vanuatuko ordua (Éfaté)", + "Pacific\/Enderbury": "Phoenix uharteetako ordua (Enderbury)", + "Pacific\/Fakaofo": "Tokelauko ordua (Fakaofo)", + "Pacific\/Fiji": "Fijiko ordua (Fiji)", + "Pacific\/Funafuti": "Tuvaluko ordua (Funafuti)", + "Pacific\/Galapagos": "Galapagoetako ordua (Galapagoak)", + "Pacific\/Gambier": "Gambierretako ordua (Gambier)", + "Pacific\/Guadalcanal": "Salomon Uharteetako ordua (Guadalcanal)", + "Pacific\/Guam": "Chamorroko ordu estandarra (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleutiar uharteetako ordua (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleutiar uharteetako ordua (Johnston)", + "Pacific\/Kiritimati": "Line uharteetako ordua (Kiritimati)", + "Pacific\/Kosrae": "Kosraeko ordua (Kosrae)", + "Pacific\/Kwajalein": "Marshall Uharteetako ordua (Kwajalein)", + "Pacific\/Majuro": "Marshall Uharteetako ordua (Majuro)", + "Pacific\/Marquesas": "Markesetako ordua (Markesak)", + "Pacific\/Midway": "Samoako ordua (Midway)", + "Pacific\/Nauru": "Nauruko ordua (Nauru)", + "Pacific\/Niue": "Niueko ordua (Niue)", + "Pacific\/Norfolk": "Norfolk uharteetako ordua (Norfolk)", + "Pacific\/Noumea": "Kaledonia Berriko ordua (Nouméa)", + "Pacific\/Pago_Pago": "Samoako ordua (Pago Pago)", + "Pacific\/Palau": "Palauko ordua (Palau)", + "Pacific\/Pitcairn": "Pitcairneko ordua (Pitcairn)", + "Pacific\/Ponape": "Ponapeko ordua (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Ginea Berriko ordua (Port Moresby)", + "Pacific\/Rarotonga": "Cook uharteetako ordua (Rarotonga)", + "Pacific\/Saipan": "Chamorroko ordu estandarra (Saipan)", + "Pacific\/Tahiti": "Tahitiko ordua (Tahiti)", + "Pacific\/Tarawa": "Gilbert uharteetako ordua (Tarawa)", + "Pacific\/Tongatapu": "Tongako ordua (Tongatapu)", + "Pacific\/Truk": "Chuukeko ordua (Chuuk)", + "Pacific\/Wake": "Wake uharteko ordua (Wake)", + "Pacific\/Wallis": "Wallis eta Futunako ordutegia (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fa.json b/src/Symfony/Component/Intl/Resources/data/timezones/fa.json new file mode 100644 index 0000000000000..5c9f8ca85913b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fa.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "وقت گرینویچ (آبیجان)", + "Africa\/Accra": "وقت گرینویچ (اکرا)", + "Africa\/Addis_Ababa": "وقت شرق افریقا (آدیس آبابا)", + "Africa\/Algiers": "وقت مرکز اروپا (الجزیره)", + "Africa\/Asmera": "وقت شرق افریقا (اسمره)", + "Africa\/Bamako": "وقت گرینویچ (باماکو)", + "Africa\/Bangui": "وقت غرب افریقا (بانگی)", + "Africa\/Banjul": "وقت گرینویچ (بانجول)", + "Africa\/Bissau": "وقت گرینویچ (بیسائو)", + "Africa\/Blantyre": "وقت مرکز افریقا (بلانتیره)", + "Africa\/Brazzaville": "وقت غرب افریقا (برازویل)", + "Africa\/Bujumbura": "وقت مرکز افریقا (بوجومبورا)", + "Africa\/Cairo": "وقت شرق اروپا (قاهره)", + "Africa\/Casablanca": "وقت غرب اروپا (کازابلانکا)", + "Africa\/Ceuta": "وقت مرکز اروپا (سبته)", + "Africa\/Conakry": "وقت گرینویچ (کوناکری)", + "Africa\/Dakar": "وقت گرینویچ (داکار)", + "Africa\/Dar_es_Salaam": "وقت شرق افریقا (دارالسلام)", + "Africa\/Djibouti": "وقت شرق افریقا (جیبوتی)", + "Africa\/Douala": "وقت غرب افریقا (دوآلا)", + "Africa\/El_Aaiun": "وقت غرب اروپا (العیون)", + "Africa\/Freetown": "وقت گرینویچ (فری‌تاون)", + "Africa\/Gaborone": "وقت مرکز افریقا (گابورون)", + "Africa\/Harare": "وقت مرکز افریقا (هراره)", + "Africa\/Johannesburg": "وقت عادی جنوب افریقا (ژوهانسبورگ)", + "Africa\/Juba": "وقت شرق افریقا (جوبا)", + "Africa\/Kampala": "وقت شرق افریقا (کامپالا)", + "Africa\/Khartoum": "وقت مرکز افریقا (خارطوم)", + "Africa\/Kigali": "وقت مرکز افریقا (کیگالی)", + "Africa\/Kinshasa": "وقت غرب افریقا (کینشاسا)", + "Africa\/Lagos": "وقت غرب افریقا (لاگوس)", + "Africa\/Libreville": "وقت غرب افریقا (لیبرویل)", + "Africa\/Lome": "وقت گرینویچ (لومه)", + "Africa\/Luanda": "وقت غرب افریقا (لواندا)", + "Africa\/Lubumbashi": "وقت مرکز افریقا (لوبومباشی)", + "Africa\/Lusaka": "وقت مرکز افریقا (لوزاکا)", + "Africa\/Malabo": "وقت غرب افریقا (مالابو)", + "Africa\/Maputo": "وقت مرکز افریقا (ماپوتو)", + "Africa\/Maseru": "وقت عادی جنوب افریقا (ماسرو)", + "Africa\/Mbabane": "وقت عادی جنوب افریقا (مبابانه)", + "Africa\/Mogadishu": "وقت شرق افریقا (موگادیشو)", + "Africa\/Monrovia": "وقت گرینویچ (مونروویا)", + "Africa\/Nairobi": "وقت شرق افریقا (نایروبی)", + "Africa\/Ndjamena": "وقت غرب افریقا (انجامنا)", + "Africa\/Niamey": "وقت غرب افریقا (نیامی)", + "Africa\/Nouakchott": "وقت گرینویچ (نوآکشوت)", + "Africa\/Ouagadougou": "وقت گرینویچ (اوآگادوگو)", + "Africa\/Porto-Novo": "وقت غرب افریقا (پورتو نووو)", + "Africa\/Sao_Tome": "وقت گرینویچ (سائوتومه)", + "Africa\/Tripoli": "وقت شرق اروپا (طرابلس)", + "Africa\/Tunis": "وقت مرکز اروپا (شهر تونس)", + "Africa\/Windhoek": "وقت مرکز افریقا (ویندهوک)", + "America\/Adak": "وقت هاوایی‐الوشن (ایدک)", + "America\/Anchorage": "وقت آلاسکا (انکوریج)", + "America\/Anguilla": "وقت آتلانتیک (آنگوئیلا)", + "America\/Antigua": "وقت آتلانتیک (آنتیگوا)", + "America\/Araguaina": "وقت برازیلیا (آراگواینا)", + "America\/Argentina\/La_Rioja": "وقت آرژانتین (لاریوخا)", + "America\/Argentina\/Rio_Gallegos": "وقت آرژانتین (ریوگالگوس)", + "America\/Argentina\/Salta": "وقت آرژانتین (سالتا)", + "America\/Argentina\/San_Juan": "وقت آرژانتین (سن‌خوان)", + "America\/Argentina\/San_Luis": "وقت غرب آرژانتین (سن‌لوئیس)", + "America\/Argentina\/Tucuman": "وقت آرژانتین (توکومن)", + "America\/Argentina\/Ushuaia": "وقت آرژانتین (اوشوایا)", + "America\/Aruba": "وقت آتلانتیک (اروبا)", + "America\/Asuncion": "وقت پاراگوئه (آسونسیون)", + "America\/Bahia": "وقت برازیلیا (بایا)", + "America\/Bahia_Banderas": "وقت مرکز امریکا (باهیا باندراس)", + "America\/Barbados": "وقت آتلانتیک (باربادوس)", + "America\/Belem": "وقت برازیلیا (بلم)", + "America\/Belize": "وقت مرکز امریکا (بلیز)", + "America\/Blanc-Sablon": "وقت آتلانتیک (بلان‐سابلون)", + "America\/Boa_Vista": "وقت آمازون (بوئاویستا)", + "America\/Bogota": "وقت کلمبیا (بوگوتا)", + "America\/Boise": "وقت کوهستانی امریکا (بویسی)", + "America\/Buenos_Aires": "وقت آرژانتین (بوئنوس‌آیرس)", + "America\/Cambridge_Bay": "وقت کوهستانی امریکا (کمبریج‌بی)", + "America\/Campo_Grande": "وقت آمازون (کمپو گرانده)", + "America\/Cancun": "وقت شرق امریکا (کانکون)", + "America\/Caracas": "وقت ونزوئلا (کاراکاس)", + "America\/Catamarca": "وقت آرژانتین (کاتامارکا)", + "America\/Cayenne": "وقت گویان فرانسه (کاین)", + "America\/Cayman": "وقت شرق امریکا (کیمن)", + "America\/Chicago": "وقت مرکز امریکا (شیکاگو)", + "America\/Chihuahua": "وقت شرق مکزیک (چیواوا)", + "America\/Coral_Harbour": "وقت شرق امریکا (اتکوکان)", + "America\/Cordoba": "وقت آرژانتین (کوردووا)", + "America\/Costa_Rica": "وقت مرکز امریکا (کاستاریکا)", + "America\/Creston": "وقت کوهستانی امریکا (کرستون)", + "America\/Cuiaba": "وقت آمازون (کویاوا)", + "America\/Curacao": "وقت آتلانتیک (کوراسائو)", + "America\/Danmarkshavn": "وقت گرینویچ (دانمارکس‌هاون)", + "America\/Dawson": "وقت غرب امریکا (داوسن)", + "America\/Dawson_Creek": "وقت کوهستانی امریکا (داوسن کریک)", + "America\/Denver": "وقت کوهستانی امریکا (دنور)", + "America\/Detroit": "وقت شرق امریکا (دیترویت)", + "America\/Dominica": "وقت آتلانتیک (دومینیکا)", + "America\/Edmonton": "وقت کوهستانی امریکا (ادمونتون)", + "America\/El_Salvador": "وقت مرکز امریکا (السالوادور)", + "America\/Fort_Nelson": "وقت کوهستانی امریکا (فورت نلسون)", + "America\/Fortaleza": "وقت برازیلیا (فورتالزا)", + "America\/Glace_Bay": "وقت آتلانتیک (گلیس‌بی)", + "America\/Godthab": "وقت غرب گرینلند (نووک)", + "America\/Goose_Bay": "وقت آتلانتیک (گوس‌بی)", + "America\/Grand_Turk": "وقت شرق امریکا (گراند تورک)", + "America\/Grenada": "وقت آتلانتیک (گرنادا)", + "America\/Guadeloupe": "وقت آتلانتیک (گوادلوپ)", + "America\/Guatemala": "وقت مرکز امریکا (گواتمالا)", + "America\/Guayaquil": "وقت اکوادور (گوایاکیل)", + "America\/Guyana": "وقت گویان (گویان)", + "America\/Halifax": "وقت آتلانتیک (هلیفکس)", + "America\/Havana": "وقت کوبا (هاوانا)", + "America\/Hermosillo": "وقت شرق مکزیک (ارموسیو)", + "America\/Indiana\/Knox": "وقت مرکز امریکا (ناکس، ایندیانا)", + "America\/Indiana\/Marengo": "وقت شرق امریکا (مارنگو، ایندیانا)", + "America\/Indiana\/Petersburg": "وقت شرق امریکا (پیترزبرگ، ایندیانا)", + "America\/Indiana\/Tell_City": "وقت مرکز امریکا (تل‌سیتی، ایندیانا)", + "America\/Indiana\/Vevay": "وقت شرق امریکا (ویوی، ایندیانا)", + "America\/Indiana\/Vincennes": "وقت شرق امریکا (وینسنس، اندیانا)", + "America\/Indiana\/Winamac": "وقت شرق امریکا (ویناماک، ایندیانا)", + "America\/Indianapolis": "وقت شرق امریکا (ایندیاناپولیس)", + "America\/Inuvik": "وقت کوهستانی امریکا (اینوویک)", + "America\/Iqaluit": "وقت شرق امریکا (ایکلوئت)", + "America\/Jamaica": "وقت شرق امریکا (جامائیکا)", + "America\/Jujuy": "وقت آرژانتین (خوخوی)", + "America\/Juneau": "وقت آلاسکا (جونو)", + "America\/Kentucky\/Monticello": "وقت شرق امریکا (مانتیسلو، کنتاکی)", + "America\/Kralendijk": "وقت آتلانتیک (کرالندیک)", + "America\/La_Paz": "وقت بولیوی (لاپاز)", + "America\/Lima": "وقت پرو (لیما)", + "America\/Los_Angeles": "وقت غرب امریکا (لوس‌آنجلس)", + "America\/Louisville": "وقت شرق امریکا (لوئیزویل)", + "America\/Lower_Princes": "وقت آتلانتیک (بخش شاهزاده‌‌نشین پایین)", + "America\/Maceio": "وقت برازیلیا (ماسیو)", + "America\/Managua": "وقت مرکز امریکا (ماناگوا)", + "America\/Manaus": "وقت آمازون (ماناوس)", + "America\/Marigot": "وقت آتلانتیک (ماریگات)", + "America\/Martinique": "وقت آتلانتیک (مارتینیک)", + "America\/Matamoros": "وقت مرکز امریکا (ماتاموروس)", + "America\/Mazatlan": "وقت شرق مکزیک (ماساتلان)", + "America\/Mendoza": "وقت آرژانتین (مندوسا)", + "America\/Menominee": "وقت مرکز امریکا (منامینی)", + "America\/Merida": "وقت مرکز امریکا (مریدا)", + "America\/Metlakatla": "وقت آلاسکا (متالاکاتلا)", + "America\/Mexico_City": "وقت مرکز امریکا (مکزیکوسیتی)", + "America\/Miquelon": "وقت سنت‌پیر و میکلون (میکلون)", + "America\/Moncton": "وقت آتلانتیک (مانکتون)", + "America\/Monterrey": "وقت مرکز امریکا (مونتری)", + "America\/Montevideo": "وقت اروگوئه (مونته‌ویدئو)", + "America\/Montserrat": "وقت آتلانتیک (مونتسرات)", + "America\/Nassau": "وقت شرق امریکا (ناسائو)", + "America\/New_York": "وقت شرق امریکا (نیویورک)", + "America\/Nipigon": "وقت شرق امریکا (نیپیگان)", + "America\/Nome": "وقت آلاسکا (نوم)", + "America\/Noronha": "وقت فرناندو دی نورونیا (نورونیا)", + "America\/North_Dakota\/Beulah": "وقت مرکز امریکا (بیولا، داکوتای شمالی)", + "America\/North_Dakota\/Center": "وقت مرکز امریکا (سنتر، داکوتای شمالی)", + "America\/North_Dakota\/New_Salem": "وقت مرکز امریکا (نیوسالم، داکوتای شمالی)", + "America\/Ojinaga": "وقت کوهستانی امریکا (اخیناگا)", + "America\/Panama": "وقت شرق امریکا (پاناما)", + "America\/Pangnirtung": "وقت شرق امریکا (پانگنیرتونگ)", + "America\/Paramaribo": "وقت سورینام (پاراماریبو)", + "America\/Phoenix": "وقت کوهستانی امریکا (فینکس)", + "America\/Port-au-Prince": "وقت شرق امریکا (پورتوپرنس)", + "America\/Port_of_Spain": "وقت آتلانتیک (پورت‌آواسپین)", + "America\/Porto_Velho": "وقت آمازون (پورتوولیو)", + "America\/Puerto_Rico": "وقت آتلانتیک (پورتوریکو)", + "America\/Punta_Arenas": "وقت شیلی (پونتا آرناس)", + "America\/Rainy_River": "وقت مرکز امریکا (رینی‌ریور)", + "America\/Rankin_Inlet": "وقت مرکز امریکا (خلیجک رنکین)", + "America\/Recife": "وقت برازیلیا (ریسیفی)", + "America\/Regina": "وقت مرکز امریکا (رجاینا)", + "America\/Resolute": "وقت مرکز امریکا (رزولوت)", + "America\/Santa_Isabel": "وقت شمال غرب مکزیک (سانتا ایزابل)", + "America\/Santarem": "وقت برازیلیا (سنتارم)", + "America\/Santiago": "وقت شیلی (سانتیاگو)", + "America\/Santo_Domingo": "وقت آتلانتیک (سانتو دومینگو)", + "America\/Sao_Paulo": "وقت برازیلیا (سائوپائولو)", + "America\/Scoresbysund": "وقت شرق گرینلند (اسکورسبیسوند)", + "America\/Sitka": "وقت آلاسکا (سیتکا)", + "America\/St_Barthelemy": "وقت آتلانتیک (سنت بارتلمی)", + "America\/St_Johns": "وقت نیوفاندلند (سنت جان)", + "America\/St_Kitts": "وقت آتلانتیک (سنت کیتس)", + "America\/St_Lucia": "وقت آتلانتیک (سنت لوسیا)", + "America\/St_Thomas": "وقت آتلانتیک (سنت توماس)", + "America\/St_Vincent": "وقت آتلانتیک (سنت وینسنت)", + "America\/Swift_Current": "وقت مرکز امریکا (سویفت‌کارنت)", + "America\/Tegucigalpa": "وقت مرکز امریکا (تگوسیگالپا)", + "America\/Thule": "وقت آتلانتیک (تول)", + "America\/Thunder_Bay": "وقت شرق امریکا (تاندربی)", + "America\/Tijuana": "وقت غرب امریکا (تیخوانا)", + "America\/Toronto": "وقت شرق امریکا (تورنتو)", + "America\/Tortola": "وقت آتلانتیک (تورتولا)", + "America\/Vancouver": "وقت غرب امریکا (ونکوور)", + "America\/Whitehorse": "وقت غرب امریکا (وایت‌هورس)", + "America\/Winnipeg": "وقت مرکز امریکا (وینیپگ)", + "America\/Yakutat": "وقت آلاسکا (یاکوتات)", + "America\/Yellowknife": "وقت کوهستانی امریکا (یلونایف)", + "Antarctica\/Casey": "وقت غرب استرالیا (کیسی)", + "Antarctica\/Davis": "وقت دیویس (دیویس)", + "Antarctica\/DumontDUrville": "وقت دومون دورویل (دومون دورویل)", + "Antarctica\/Macquarie": "وقت جزیرهٔ مکواری (مکواری)", + "Antarctica\/Mawson": "وقت ماوسون (ماوسون)", + "Antarctica\/McMurdo": "وقت زلاند نو (مک‌موردو)", + "Antarctica\/Palmer": "وقت شیلی (پالمر)", + "Antarctica\/Rothera": "وقت روترا (روترا)", + "Antarctica\/Syowa": "وقت شووا (شووا)", + "Antarctica\/Troll": "وقت گرینویچ (ترول)", + "Antarctica\/Vostok": "وقت وستوک (وستوک)", + "Arctic\/Longyearbyen": "وقت مرکز اروپا (لانگ‌یربین)", + "Asia\/Aden": "وقت عربستان (عدن)", + "Asia\/Almaty": "وقت شرق قزاقستان (آلماتی)", + "Asia\/Amman": "وقت شرق اروپا (عمّان)", + "Asia\/Anadyr": "وقت آنادیر (آنادیر)", + "Asia\/Aqtau": "وقت غرب قزاقستان (آقتاو)", + "Asia\/Aqtobe": "وقت غرب قزاقستان (آقتوبه)", + "Asia\/Ashgabat": "وقت ترکمنستان (عشق‌آباد)", + "Asia\/Atyrau": "وقت غرب قزاقستان (آتیراو)", + "Asia\/Baghdad": "وقت عربستان (بغداد)", + "Asia\/Bahrain": "وقت عربستان (بحرین)", + "Asia\/Baku": "وقت جمهوری آذربایجان (باکو)", + "Asia\/Bangkok": "وقت هندوچین (بانکوک)", + "Asia\/Beirut": "وقت شرق اروپا (بیروت)", + "Asia\/Bishkek": "وقت قرقیزستان (بیشکک)", + "Asia\/Brunei": "وقت برونئی دارالسلام (برونئی)", + "Asia\/Calcutta": "وقت هند (کلکته)", + "Asia\/Chita": "وقت یاکوتسک (چیتا)", + "Asia\/Choibalsan": "وقت چویبالسان (چویبالسان)", + "Asia\/Colombo": "وقت هند (کلمبو)", + "Asia\/Damascus": "وقت شرق اروپا (دمشق)", + "Asia\/Dhaka": "وقت بنگلادش (داکا)", + "Asia\/Dili": "وقت تیمور شرقی (دیلی)", + "Asia\/Dubai": "وقت عادی خلیج فارس (دبی)", + "Asia\/Dushanbe": "وقت تاجیکستان (دوشنبه)", + "Asia\/Famagusta": "وقت شرق اروپا (فاماگوستا)", + "Asia\/Gaza": "وقت شرق اروپا (غزه)", + "Asia\/Hebron": "وقت شرق اروپا (الخلیل)", + "Asia\/Hong_Kong": "وقت هنگ‌کنگ (هنگ‌کنگ)", + "Asia\/Hovd": "وقت خوود (خوود)", + "Asia\/Irkutsk": "وقت ایرکوتسک (ایرکوتسک)", + "Asia\/Jakarta": "وقت غرب اندونزی (جاکارتا)", + "Asia\/Jayapura": "وقت شرق اندونزی (جایاپورا)", + "Asia\/Jerusalem": "وقت اسرائیل (اورشلیم)", + "Asia\/Kabul": "وقت افغانستان (کابل)", + "Asia\/Kamchatka": "وقت پتروپاولوسک‐کامچاتسکی (کامچاتکا)", + "Asia\/Karachi": "وقت پاکستان (کراچی)", + "Asia\/Katmandu": "وقت نپال (کاتماندو)", + "Asia\/Khandyga": "وقت یاکوتسک (خاندیگا)", + "Asia\/Krasnoyarsk": "وقت کراسنویارسک (کراسنویارسک)", + "Asia\/Kuala_Lumpur": "وقت مالزی (کوالالامپور)", + "Asia\/Kuching": "وقت مالزی (کوچینگ)", + "Asia\/Kuwait": "وقت عربستان (کویت)", + "Asia\/Macau": "وقت چین (ماکائو)", + "Asia\/Magadan": "وقت ماگادان (ماگادان)", + "Asia\/Makassar": "وقت مرکز اندونزی (ماکاسار)", + "Asia\/Manila": "وقت فیلیپین (مانیل)", + "Asia\/Muscat": "وقت عادی خلیج فارس (مسقط)", + "Asia\/Nicosia": "وقت شرق اروپا (نیکوزیا)", + "Asia\/Novokuznetsk": "وقت کراسنویارسک (نوووکوزنتسک)", + "Asia\/Novosibirsk": "وقت نووسیبیرسک (نووسیبیریسک)", + "Asia\/Omsk": "وقت اومسک (اومسک)", + "Asia\/Oral": "وقت غرب قزاقستان (اورال)", + "Asia\/Phnom_Penh": "وقت هندوچین (پنوم‌پن)", + "Asia\/Pontianak": "وقت غرب اندونزی (پونتیاناک)", + "Asia\/Pyongyang": "وقت کره (پیونگ‌یانگ)", + "Asia\/Qatar": "وقت عربستان (قطر)", + "Asia\/Qostanay": "وقت شرق قزاقستان (قوستانای)", + "Asia\/Qyzylorda": "وقت غرب قزاقستان (قیزیل‌اوردا)", + "Asia\/Rangoon": "وقت میانمار (یانگون)", + "Asia\/Riyadh": "وقت عربستان (ریاض)", + "Asia\/Saigon": "وقت هندوچین (هوشی‌مین‌سیتی)", + "Asia\/Sakhalin": "وقت ساخالین (ساخالین)", + "Asia\/Samarkand": "وقت ازبکستان (سمرقند)", + "Asia\/Seoul": "وقت کره (سئول)", + "Asia\/Shanghai": "وقت چین (شانگهای)", + "Asia\/Singapore": "وقت سنگاپور (سنگاپور)", + "Asia\/Srednekolymsk": "وقت ماگادان (اسردنکولیمسک)", + "Asia\/Taipei": "وقت تایپه (تایپه)", + "Asia\/Tashkent": "وقت ازبکستان (تاشکند)", + "Asia\/Tbilisi": "وقت گرجستان (تفلیس)", + "Asia\/Tehran": "وقت ایران (تهران)", + "Asia\/Thimphu": "وقت بوتان (تیمفو)", + "Asia\/Tokyo": "وقت ژاپن (توکیو)", + "Asia\/Ulaanbaatar": "وقت اولان‌باتور (اولان‌باتور)", + "Asia\/Ust-Nera": "وقت ولادی‌وستوک (اوست نرا)", + "Asia\/Vientiane": "وقت هندوچین (وینتیان)", + "Asia\/Vladivostok": "وقت ولادی‌وستوک (ولادی‌وستوک)", + "Asia\/Yakutsk": "وقت یاکوتسک (یاکوتسک)", + "Asia\/Yekaterinburg": "وقت یکاترینبورگ (یکاترینبرگ)", + "Asia\/Yerevan": "وقت ارمنستان (ایروان)", + "Atlantic\/Azores": "وقت آزور (آزور)", + "Atlantic\/Bermuda": "وقت آتلانتیک (برمودا)", + "Atlantic\/Canary": "وقت غرب اروپا (قناری)", + "Atlantic\/Cape_Verde": "وقت کیپ‌ورد (کیپ‌ورد)", + "Atlantic\/Faeroe": "وقت غرب اروپا (فارو)", + "Atlantic\/Madeira": "وقت غرب اروپا (مادیرا)", + "Atlantic\/Reykjavik": "وقت گرینویچ (ریکیاویک)", + "Atlantic\/South_Georgia": "وقت جورجیای جنوبی (جورجیای جنوبی)", + "Atlantic\/St_Helena": "وقت گرینویچ (سنت هلنا)", + "Atlantic\/Stanley": "وقت جزایر فالکلند (استانلی)", + "Australia\/Adelaide": "وقت مرکز استرالیا (آدلاید)", + "Australia\/Brisbane": "وقت شرق استرالیا (بریسبین)", + "Australia\/Broken_Hill": "وقت مرکز استرالیا (بروکن‌هیل)", + "Australia\/Currie": "وقت شرق استرالیا (کوری)", + "Australia\/Darwin": "وقت مرکز استرالیا (داروین)", + "Australia\/Eucla": "وقت مرکز-غرب استرالیا (اوکلا)", + "Australia\/Hobart": "وقت شرق استرالیا (هوبارت)", + "Australia\/Lindeman": "وقت شرق استرالیا (لیندمن)", + "Australia\/Lord_Howe": "وقت لردهو (لردهاو)", + "Australia\/Melbourne": "وقت شرق استرالیا (ملبورن)", + "Australia\/Perth": "وقت غرب استرالیا (پرت)", + "Australia\/Sydney": "وقت شرق استرالیا (سیدنی)", + "CST6CDT": "وقت مرکز امریکا", + "EST5EDT": "وقت شرق امریکا", + "Etc\/GMT": "وقت گرینویچ", + "Etc\/UTC": "زمان هماهنگ جهانی", + "Europe\/Amsterdam": "وقت مرکز اروپا (آمستردام)", + "Europe\/Andorra": "وقت مرکز اروپا (آندورا)", + "Europe\/Astrakhan": "وقت مسکو (آستراخان)", + "Europe\/Athens": "وقت شرق اروپا (آتن)", + "Europe\/Belgrade": "وقت مرکز اروپا (بلگراد)", + "Europe\/Berlin": "وقت مرکز اروپا (برلین)", + "Europe\/Bratislava": "وقت مرکز اروپا (براتیسلاوا)", + "Europe\/Brussels": "وقت مرکز اروپا (بروکسل)", + "Europe\/Bucharest": "وقت شرق اروپا (بخارست)", + "Europe\/Budapest": "وقت مرکز اروپا (بوداپست)", + "Europe\/Busingen": "وقت مرکز اروپا (بازنگن)", + "Europe\/Chisinau": "وقت شرق اروپا (کیشیناو)", + "Europe\/Copenhagen": "وقت مرکز اروپا (کپنهاگ)", + "Europe\/Dublin": "وقت گرینویچ (دوبلین)", + "Europe\/Gibraltar": "وقت مرکز اروپا (جبل‌الطارق)", + "Europe\/Guernsey": "وقت گرینویچ (گرنزی)", + "Europe\/Helsinki": "وقت شرق اروپا (هلسینکی)", + "Europe\/Isle_of_Man": "وقت گرینویچ (جزیرهٔ من)", + "Europe\/Jersey": "وقت گرینویچ (جرزی)", + "Europe\/Kaliningrad": "وقت شرق اروپا (کالینینگراد)", + "Europe\/Kiev": "وقت شرق اروپا (کیف)", + "Europe\/Lisbon": "وقت غرب اروپا (لیسبون)", + "Europe\/Ljubljana": "وقت مرکز اروپا (لیوبلیانا)", + "Europe\/London": "وقت گرینویچ (لندن)", + "Europe\/Luxembourg": "وقت مرکز اروپا (لوکزامبورگ)", + "Europe\/Madrid": "وقت مرکز اروپا (مادرید)", + "Europe\/Malta": "وقت مرکز اروپا (مالت)", + "Europe\/Mariehamn": "وقت شرق اروپا (ماریه‌هامن)", + "Europe\/Minsk": "وقت مسکو (مینسک)", + "Europe\/Monaco": "وقت مرکز اروپا (موناکو)", + "Europe\/Moscow": "وقت مسکو (مسکو)", + "Europe\/Oslo": "وقت مرکز اروپا (اسلو)", + "Europe\/Paris": "وقت مرکز اروپا (پاریس)", + "Europe\/Podgorica": "وقت مرکز اروپا (پادگاریتسا)", + "Europe\/Prague": "وقت مرکز اروپا (پراگ)", + "Europe\/Riga": "وقت شرق اروپا (ریگا)", + "Europe\/Rome": "وقت مرکز اروپا (رم)", + "Europe\/Samara": "وقت سامارا (سامارا)", + "Europe\/San_Marino": "وقت مرکز اروپا (سان‌مارینو)", + "Europe\/Sarajevo": "وقت مرکز اروپا (سارایوو)", + "Europe\/Saratov": "وقت مسکو (ساراتوف)", + "Europe\/Simferopol": "وقت مسکو (سیمفروپل)", + "Europe\/Skopje": "وقت مرکز اروپا (اسکوپیه)", + "Europe\/Sofia": "وقت شرق اروپا (صوفیه)", + "Europe\/Stockholm": "وقت مرکز اروپا (استکهلم)", + "Europe\/Tallinn": "وقت شرق اروپا (تالین)", + "Europe\/Tirane": "وقت مرکز اروپا (تیرانا)", + "Europe\/Ulyanovsk": "وقت مسکو (اولیانوفسک)", + "Europe\/Uzhgorod": "وقت شرق اروپا (اوژگورود)", + "Europe\/Vaduz": "وقت مرکز اروپا (فادوتس)", + "Europe\/Vatican": "وقت مرکز اروپا (واتیکان)", + "Europe\/Vienna": "وقت مرکز اروپا (وین)", + "Europe\/Vilnius": "وقت شرق اروپا (ویلنیوس)", + "Europe\/Volgograd": "وقت ولگاگراد (ولگاگراد)", + "Europe\/Warsaw": "وقت مرکز اروپا (ورشو)", + "Europe\/Zagreb": "وقت مرکز اروپا (زاگرب)", + "Europe\/Zaporozhye": "وقت شرق اروپا (زاپوروژیا)", + "Europe\/Zurich": "وقت مرکز اروپا (زوریخ)", + "Indian\/Antananarivo": "وقت شرق افریقا (آنتاناناریوو)", + "Indian\/Chagos": "وقت اقیانوس هند (شاگوس)", + "Indian\/Christmas": "وقت جزیرهٔ کریسمس (کریسمس)", + "Indian\/Cocos": "وقت جزایر کوکوس (کوکوس)", + "Indian\/Comoro": "وقت شرق افریقا (کومورو)", + "Indian\/Kerguelen": "وقت سرزمین‌های جنوبی و جنوبگان فرانسه (کرگولن)", + "Indian\/Mahe": "وقت سیشل (ماهه)", + "Indian\/Maldives": "وقت مالدیو (مالدیو)", + "Indian\/Mauritius": "وقت موریس (موریس)", + "Indian\/Mayotte": "وقت شرق افریقا (مایوت)", + "Indian\/Reunion": "وقت ریونیون (رئونیون)", + "MST7MDT": "وقت کوهستانی امریکا", + "PST8PDT": "وقت غرب امریکا", + "Pacific\/Apia": "وقت آپیا (آپیا)", + "Pacific\/Auckland": "وقت زلاند نو (اوکلند)", + "Pacific\/Bougainville": "وقت پاپوا گینهٔ نو (بوگنویل)", + "Pacific\/Chatham": "وقت چت‌هام (چتم)", + "Pacific\/Easter": "وقت جزیرهٔ ایستر (ایستر)", + "Pacific\/Efate": "وقت واناتو (افاته)", + "Pacific\/Enderbury": "وقت جزایر فونیکس (اندربری)", + "Pacific\/Fakaofo": "وقت توکلائو (فاکائوفو)", + "Pacific\/Fiji": "وقت فیجی (فیجی)", + "Pacific\/Funafuti": "وقت تووالو (فونافوتی)", + "Pacific\/Galapagos": "وقت گالاپاگوس (گالاپاگوس)", + "Pacific\/Gambier": "وقت گامبیه (گامبیر)", + "Pacific\/Guadalcanal": "وقت جزایر سلیمان (گوادال‌کانال)", + "Pacific\/Guam": "وقت عادی چامورو (گوام)", + "Pacific\/Honolulu": "وقت هاوایی‐الوشن (هونولولو)", + "Pacific\/Johnston": "وقت هاوایی‐الوشن (جانستون)", + "Pacific\/Kiritimati": "وقت جزایر لاین (کریتیماتی)", + "Pacific\/Kosrae": "وقت کوسرای (کوسرای)", + "Pacific\/Kwajalein": "وقت جزایر مارشال (کواجیلین)", + "Pacific\/Majuro": "وقت جزایر مارشال (ماجورو)", + "Pacific\/Marquesas": "وقت مارکوئز (مارکوزه)", + "Pacific\/Midway": "وقت ساموا (میدوی)", + "Pacific\/Nauru": "وقت نائورو (نائورو)", + "Pacific\/Niue": "وقت نیوئه (نیوئه)", + "Pacific\/Norfolk": "وقت جزایر نورفولک (نورفولک)", + "Pacific\/Noumea": "وقت کالدونیای جدید (نومئا)", + "Pacific\/Pago_Pago": "وقت ساموا (پاگوپاگو)", + "Pacific\/Palau": "وقت پالائو (پالائو)", + "Pacific\/Pitcairn": "وقت پیتکایرن (پیت‌کرن)", + "Pacific\/Ponape": "وقت پوناپه (پانپی)", + "Pacific\/Port_Moresby": "وقت پاپوا گینهٔ نو (پورت‌مورزبی)", + "Pacific\/Rarotonga": "وقت جزایر کوک (راروتونگا)", + "Pacific\/Saipan": "وقت عادی چامورو (سایپان)", + "Pacific\/Tahiti": "وقت تاهیتی (تاهیتی)", + "Pacific\/Tarawa": "وقت جزایر گیلبرت (تاراوا)", + "Pacific\/Tongatapu": "وقت تونگا (تونگاتاپو)", + "Pacific\/Truk": "وقت چوئوک (چوک)", + "Pacific\/Wake": "وقت جزیرهٔ ویک (ویک)", + "Pacific\/Wallis": "وقت والیس و فوتونا (والیس)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fi.json b/src/Symfony/Component/Intl/Resources/data/timezones/fi.json new file mode 100644 index 0000000000000..09aa0feb7cb97 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fi.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwichin normaaliaika (Abidjan)", + "Africa\/Accra": "Greenwichin normaaliaika (Accra)", + "Africa\/Addis_Ababa": "Itä-Afrikan aika (Addis Abeba)", + "Africa\/Algiers": "Keski-Euroopan aika (Alger)", + "Africa\/Asmera": "Itä-Afrikan aika (Asmara)", + "Africa\/Bamako": "Greenwichin normaaliaika (Bamako)", + "Africa\/Bangui": "Länsi-Afrikan aika (Bangui)", + "Africa\/Banjul": "Greenwichin normaaliaika (Banjul)", + "Africa\/Bissau": "Greenwichin normaaliaika (Bissau)", + "Africa\/Blantyre": "Keski-Afrikan aika (Blantyre)", + "Africa\/Brazzaville": "Länsi-Afrikan aika (Brazzaville)", + "Africa\/Bujumbura": "Keski-Afrikan aika (Bujumbura)", + "Africa\/Cairo": "Itä-Euroopan aika (Kairo)", + "Africa\/Casablanca": "Länsi-Euroopan aika (Casablanca)", + "Africa\/Ceuta": "Keski-Euroopan aika (Ceuta)", + "Africa\/Conakry": "Greenwichin normaaliaika (Conakry)", + "Africa\/Dakar": "Greenwichin normaaliaika (Dakar)", + "Africa\/Dar_es_Salaam": "Itä-Afrikan aika (Dar es Salaam)", + "Africa\/Djibouti": "Itä-Afrikan aika (Djibouti)", + "Africa\/Douala": "Länsi-Afrikan aika (Douala)", + "Africa\/El_Aaiun": "Länsi-Euroopan aika (El Aaiún)", + "Africa\/Freetown": "Greenwichin normaaliaika (Freetown)", + "Africa\/Gaborone": "Keski-Afrikan aika (Gaborone)", + "Africa\/Harare": "Keski-Afrikan aika (Harare)", + "Africa\/Johannesburg": "Etelä-Afrikan aika (Johannesburg)", + "Africa\/Juba": "Itä-Afrikan aika (Juba)", + "Africa\/Kampala": "Itä-Afrikan aika (Kampala)", + "Africa\/Khartoum": "Keski-Afrikan aika (Khartum)", + "Africa\/Kigali": "Keski-Afrikan aika (Kigali)", + "Africa\/Kinshasa": "Länsi-Afrikan aika (Kinshasa)", + "Africa\/Lagos": "Länsi-Afrikan aika (Lagos)", + "Africa\/Libreville": "Länsi-Afrikan aika (Libreville)", + "Africa\/Lome": "Greenwichin normaaliaika (Lomé)", + "Africa\/Luanda": "Länsi-Afrikan aika (Luanda)", + "Africa\/Lubumbashi": "Keski-Afrikan aika (Lubumbashi)", + "Africa\/Lusaka": "Keski-Afrikan aika (Lusaka)", + "Africa\/Malabo": "Länsi-Afrikan aika (Malabo)", + "Africa\/Maputo": "Keski-Afrikan aika (Maputo)", + "Africa\/Maseru": "Etelä-Afrikan aika (Maseru)", + "Africa\/Mbabane": "Etelä-Afrikan aika (Mbabane)", + "Africa\/Mogadishu": "Itä-Afrikan aika (Mogadishu)", + "Africa\/Monrovia": "Greenwichin normaaliaika (Monrovia)", + "Africa\/Nairobi": "Itä-Afrikan aika (Nairobi)", + "Africa\/Ndjamena": "Länsi-Afrikan aika (N’Djamena)", + "Africa\/Niamey": "Länsi-Afrikan aika (Niamey)", + "Africa\/Nouakchott": "Greenwichin normaaliaika (Nouakchott)", + "Africa\/Ouagadougou": "Greenwichin normaaliaika (Ouagadougou)", + "Africa\/Porto-Novo": "Länsi-Afrikan aika (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwichin normaaliaika (São Tomé)", + "Africa\/Tripoli": "Itä-Euroopan aika (Tripoli)", + "Africa\/Tunis": "Keski-Euroopan aika (Tunis)", + "Africa\/Windhoek": "Keski-Afrikan aika (Windhoek)", + "America\/Adak": "Havaijin-Aleuttien aika (Adak)", + "America\/Anchorage": "Alaskan aika (Anchorage)", + "America\/Anguilla": "Kanadan Atlantin aika (Anguilla)", + "America\/Antigua": "Kanadan Atlantin aika (Antigua)", + "America\/Araguaina": "Brasilian aika (Araguaína)", + "America\/Argentina\/La_Rioja": "Argentiinan aika (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentiinan aika (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentiinan aika (Salta)", + "America\/Argentina\/San_Juan": "Argentiinan aika (San Juan)", + "America\/Argentina\/San_Luis": "Länsi-Argentiinan aika (San Luis)", + "America\/Argentina\/Tucuman": "Argentiinan aika (Tucumán)", + "America\/Argentina\/Ushuaia": "Argentiinan aika (Ushuaia)", + "America\/Aruba": "Kanadan Atlantin aika (Aruba)", + "America\/Asuncion": "Paraguayn aika (Asunción)", + "America\/Bahia": "Brasilian aika (Bahia)", + "America\/Bahia_Banderas": "Yhdysvaltain keskinen aika (Bahía de Banderas)", + "America\/Barbados": "Kanadan Atlantin aika (Barbados)", + "America\/Belem": "Brasilian aika (Belem)", + "America\/Belize": "Yhdysvaltain keskinen aika (Belize)", + "America\/Blanc-Sablon": "Kanadan Atlantin aika (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonin aika (Boa Vista)", + "America\/Bogota": "Kolumbian aika (Bogotá)", + "America\/Boise": "Kalliovuorten aika (Boise)", + "America\/Buenos_Aires": "Argentiinan aika (Buenos Aires)", + "America\/Cambridge_Bay": "Kalliovuorten aika (Cambridge Bay)", + "America\/Campo_Grande": "Amazonin aika (Campo Grande)", + "America\/Cancun": "Yhdysvaltain itäinen aika (Cancún)", + "America\/Caracas": "Venezuelan aika (Caracas)", + "America\/Catamarca": "Argentiinan aika (Catamarca)", + "America\/Cayenne": "Ranskan Guayanan aika (Cayenne)", + "America\/Cayman": "Yhdysvaltain itäinen aika (Cayman)", + "America\/Chicago": "Yhdysvaltain keskinen aika (Chicago)", + "America\/Chihuahua": "Meksikon Tyynenmeren aika (Chihuahua)", + "America\/Coral_Harbour": "Yhdysvaltain itäinen aika (Atikokan)", + "America\/Cordoba": "Argentiinan aika (Córdoba)", + "America\/Costa_Rica": "Yhdysvaltain keskinen aika (Costa Rica)", + "America\/Creston": "Kalliovuorten aika (Creston)", + "America\/Cuiaba": "Amazonin aika (Cuiabá)", + "America\/Curacao": "Kanadan Atlantin aika (Curaçao)", + "America\/Danmarkshavn": "Greenwichin normaaliaika (Danmarkshavn)", + "America\/Dawson": "Yhdysvaltain Tyynenmeren aika (Dawson)", + "America\/Dawson_Creek": "Kalliovuorten aika (Dawson Creek)", + "America\/Denver": "Kalliovuorten aika (Denver)", + "America\/Detroit": "Yhdysvaltain itäinen aika (Detroit)", + "America\/Dominica": "Kanadan Atlantin aika (Dominica)", + "America\/Edmonton": "Kalliovuorten aika (Edmonton)", + "America\/Eirunepe": "Acren aika (Eirunepé)", + "America\/El_Salvador": "Yhdysvaltain keskinen aika (El Salvador)", + "America\/Fort_Nelson": "Kalliovuorten aika (Fort Nelson)", + "America\/Fortaleza": "Brasilian aika (Fortaleza)", + "America\/Glace_Bay": "Kanadan Atlantin aika (Glace Bay)", + "America\/Godthab": "Länsi-Grönlannin aika (Nuuk)", + "America\/Goose_Bay": "Kanadan Atlantin aika (Goose Bay)", + "America\/Grand_Turk": "Yhdysvaltain itäinen aika (Grand Turk)", + "America\/Grenada": "Kanadan Atlantin aika (Grenada)", + "America\/Guadeloupe": "Kanadan Atlantin aika (Guadeloupe)", + "America\/Guatemala": "Yhdysvaltain keskinen aika (Guatemala)", + "America\/Guayaquil": "Ecuadorin aika (Guayaquil)", + "America\/Guyana": "Guyanan aika (Guyana)", + "America\/Halifax": "Kanadan Atlantin aika (Halifax)", + "America\/Havana": "Kuuban aika (Havanna)", + "America\/Hermosillo": "Meksikon Tyynenmeren aika (Hermosillo)", + "America\/Indiana\/Knox": "Yhdysvaltain keskinen aika (Knox, Indiana)", + "America\/Indiana\/Marengo": "Yhdysvaltain itäinen aika (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Yhdysvaltain itäinen aika (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Yhdysvaltain keskinen aika (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Yhdysvaltain itäinen aika (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Yhdysvaltain itäinen aika (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Yhdysvaltain itäinen aika (Winamac, Indiana)", + "America\/Indianapolis": "Yhdysvaltain itäinen aika (Indianapolis)", + "America\/Inuvik": "Kalliovuorten aika (Inuvik)", + "America\/Iqaluit": "Yhdysvaltain itäinen aika (Iqaluit)", + "America\/Jamaica": "Yhdysvaltain itäinen aika (Jamaika)", + "America\/Jujuy": "Argentiinan aika (Jujuy)", + "America\/Juneau": "Alaskan aika (Juneau)", + "America\/Kentucky\/Monticello": "Yhdysvaltain itäinen aika (Monticello, Kentucky)", + "America\/Kralendijk": "Kanadan Atlantin aika (Kralendijk)", + "America\/La_Paz": "Bolivian aika (La Paz)", + "America\/Lima": "Perun aika (Lima)", + "America\/Los_Angeles": "Yhdysvaltain Tyynenmeren aika (Los Angeles)", + "America\/Louisville": "Yhdysvaltain itäinen aika (Louisville)", + "America\/Lower_Princes": "Kanadan Atlantin aika (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilian aika (Maceió)", + "America\/Managua": "Yhdysvaltain keskinen aika (Managua)", + "America\/Manaus": "Amazonin aika (Manaus)", + "America\/Marigot": "Kanadan Atlantin aika (Marigot)", + "America\/Martinique": "Kanadan Atlantin aika (Martinique)", + "America\/Matamoros": "Yhdysvaltain keskinen aika (Matamoros)", + "America\/Mazatlan": "Meksikon Tyynenmeren aika (Mazatlán)", + "America\/Mendoza": "Argentiinan aika (Mendoza)", + "America\/Menominee": "Yhdysvaltain keskinen aika (Menominee)", + "America\/Merida": "Yhdysvaltain keskinen aika (Mérida)", + "America\/Metlakatla": "Alaskan aika (Metlakatla)", + "America\/Mexico_City": "Yhdysvaltain keskinen aika (Ciudad de México)", + "America\/Miquelon": "Saint-Pierren ja Miquelonin aika (Miquelon)", + "America\/Moncton": "Kanadan Atlantin aika (Moncton)", + "America\/Monterrey": "Yhdysvaltain keskinen aika (Monterrey)", + "America\/Montevideo": "Uruguayn aika (Montevideo)", + "America\/Montserrat": "Kanadan Atlantin aika (Montserrat)", + "America\/Nassau": "Yhdysvaltain itäinen aika (Nassau)", + "America\/New_York": "Yhdysvaltain itäinen aika (New York)", + "America\/Nipigon": "Yhdysvaltain itäinen aika (Nipigon)", + "America\/Nome": "Alaskan aika (Nome)", + "America\/Noronha": "Fernando de Noronhan aika (Noronha)", + "America\/North_Dakota\/Beulah": "Yhdysvaltain keskinen aika (Beulah, Pohjois-Dakota)", + "America\/North_Dakota\/Center": "Yhdysvaltain keskinen aika (Center, Pohjois-Dakota)", + "America\/North_Dakota\/New_Salem": "Yhdysvaltain keskinen aika (New Salem, Pohjois-Dakota)", + "America\/Ojinaga": "Kalliovuorten aika (Ojinaga)", + "America\/Panama": "Yhdysvaltain itäinen aika (Panama)", + "America\/Pangnirtung": "Yhdysvaltain itäinen aika (Pangnirtung)", + "America\/Paramaribo": "Surinamen aika (Paramaribo)", + "America\/Phoenix": "Kalliovuorten aika (Phoenix)", + "America\/Port-au-Prince": "Yhdysvaltain itäinen aika (Port-au-Prince)", + "America\/Port_of_Spain": "Kanadan Atlantin aika (Port of Spain)", + "America\/Porto_Velho": "Amazonin aika (Porto Velho)", + "America\/Puerto_Rico": "Kanadan Atlantin aika (Puerto Rico)", + "America\/Punta_Arenas": "Chilen aika (Punta Arenas)", + "America\/Rainy_River": "Yhdysvaltain keskinen aika (Rainy River)", + "America\/Rankin_Inlet": "Yhdysvaltain keskinen aika (Rankin Inlet)", + "America\/Recife": "Brasilian aika (Recife)", + "America\/Regina": "Yhdysvaltain keskinen aika (Regina)", + "America\/Resolute": "Yhdysvaltain keskinen aika (Resolute)", + "America\/Rio_Branco": "Acren aika (Rio Branco)", + "America\/Santa_Isabel": "Luoteis-Meksikon aika (Santa Isabel)", + "America\/Santarem": "Brasilian aika (Santarém)", + "America\/Santiago": "Chilen aika (Santiago de Chile)", + "America\/Santo_Domingo": "Kanadan Atlantin aika (Santo Domingo)", + "America\/Sao_Paulo": "Brasilian aika (São Paulo)", + "America\/Scoresbysund": "Itä-Grönlannin aika (Ittoqqortoormiit)", + "America\/Sitka": "Alaskan aika (Sitka)", + "America\/St_Barthelemy": "Kanadan Atlantin aika (Saint-Barthélemy)", + "America\/St_Johns": "Newfoundlandin aika (St. John’s)", + "America\/St_Kitts": "Kanadan Atlantin aika (Saint Kitts)", + "America\/St_Lucia": "Kanadan Atlantin aika (Saint Lucia)", + "America\/St_Thomas": "Kanadan Atlantin aika (Saint Thomas)", + "America\/St_Vincent": "Kanadan Atlantin aika (Saint Vincent)", + "America\/Swift_Current": "Yhdysvaltain keskinen aika (Swift Current)", + "America\/Tegucigalpa": "Yhdysvaltain keskinen aika (Tegucigalpa)", + "America\/Thule": "Kanadan Atlantin aika (Thule)", + "America\/Thunder_Bay": "Yhdysvaltain itäinen aika (Thunder Bay)", + "America\/Tijuana": "Yhdysvaltain Tyynenmeren aika (Tijuana)", + "America\/Toronto": "Yhdysvaltain itäinen aika (Toronto)", + "America\/Tortola": "Kanadan Atlantin aika (Tortola)", + "America\/Vancouver": "Yhdysvaltain Tyynenmeren aika (Vancouver)", + "America\/Whitehorse": "Yhdysvaltain Tyynenmeren aika (Whitehorse)", + "America\/Winnipeg": "Yhdysvaltain keskinen aika (Winnipeg)", + "America\/Yakutat": "Alaskan aika (Yakutat)", + "America\/Yellowknife": "Kalliovuorten aika (Yellowknife)", + "Antarctica\/Casey": "Länsi-Australian aika (Casey)", + "Antarctica\/Davis": "Davisin aika (Davis)", + "Antarctica\/DumontDUrville": "Dumont d’Urvillen aika (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquariensaaren aika (Macquariensaari)", + "Antarctica\/Mawson": "Mawsonin aika (Mawson)", + "Antarctica\/McMurdo": "Uuden-Seelannin aika (McMurdo)", + "Antarctica\/Palmer": "Chilen aika (Palmer)", + "Antarctica\/Rothera": "Rotheran aika (Rothera)", + "Antarctica\/Syowa": "Syowan aika (Syowa)", + "Antarctica\/Troll": "Greenwichin normaaliaika (Troll)", + "Antarctica\/Vostok": "Vostokin aika (Vostok)", + "Arctic\/Longyearbyen": "Keski-Euroopan aika (Longyearbyen)", + "Asia\/Aden": "Saudi-Arabian aika (Aden)", + "Asia\/Almaty": "Itä-Kazakstanin aika (Almaty)", + "Asia\/Amman": "Itä-Euroopan aika (Amman)", + "Asia\/Anadyr": "Anadyrin aika (Anadyr)", + "Asia\/Aqtau": "Länsi-Kazakstanin aika (Aqtaw)", + "Asia\/Aqtobe": "Länsi-Kazakstanin aika (Aqtöbe)", + "Asia\/Ashgabat": "Turkmenistanin aika (Ašgabat)", + "Asia\/Atyrau": "Länsi-Kazakstanin aika (Atıraw)", + "Asia\/Baghdad": "Saudi-Arabian aika (Bagdad)", + "Asia\/Bahrain": "Saudi-Arabian aika (Bahrain)", + "Asia\/Baku": "Azerbaidžanin aika (Baku)", + "Asia\/Bangkok": "Indokiinan aika (Bangkok)", + "Asia\/Beirut": "Itä-Euroopan aika (Beirut)", + "Asia\/Bishkek": "Kirgisian aika (Biškek)", + "Asia\/Brunei": "Brunein aika (Brunei)", + "Asia\/Calcutta": "Intian aika (Kalkutta)", + "Asia\/Chita": "Jakutskin aika (Tšita)", + "Asia\/Choibalsan": "Tšoibalsan aika (Tšoibalsa)", + "Asia\/Colombo": "Intian aika (Colombo)", + "Asia\/Damascus": "Itä-Euroopan aika (Damaskos)", + "Asia\/Dhaka": "Bangladeshin aika (Dhaka)", + "Asia\/Dili": "Itä-Timorin aika (Dili)", + "Asia\/Dubai": "Arabiemiirikuntien normaaliaika (Dubai)", + "Asia\/Dushanbe": "Tadžikistanin aika (Dušanbe)", + "Asia\/Famagusta": "Itä-Euroopan aika (Famagusta)", + "Asia\/Gaza": "Itä-Euroopan aika (Gaza)", + "Asia\/Hebron": "Itä-Euroopan aika (Hebron)", + "Asia\/Hong_Kong": "Hongkongin aika (Hongkong)", + "Asia\/Hovd": "Hovdin aika (Hovd)", + "Asia\/Irkutsk": "Irkutskin aika (Irkutsk)", + "Asia\/Jakarta": "Länsi-Indonesian aika (Jakarta)", + "Asia\/Jayapura": "Itä-Indonesian aika (Jayapura)", + "Asia\/Jerusalem": "Israelin aika (Jerusalem)", + "Asia\/Kabul": "Afganistanin aika (Kabul)", + "Asia\/Kamchatka": "Kamtšatkan aika (Kamtšatka)", + "Asia\/Karachi": "Pakistanin aika (Karachi)", + "Asia\/Katmandu": "Nepalin aika (Kathmandu)", + "Asia\/Khandyga": "Jakutskin aika (Handyga)", + "Asia\/Krasnoyarsk": "Krasnojarskin aika (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malesian aika (Kuala Lumpur)", + "Asia\/Kuching": "Malesian aika (Kuching)", + "Asia\/Kuwait": "Saudi-Arabian aika (Kuwait)", + "Asia\/Macau": "Kiinan aika (Macao)", + "Asia\/Magadan": "Magadanin aika (Magadan)", + "Asia\/Makassar": "Keski-Indonesian aika (Makassar)", + "Asia\/Manila": "Filippiinien aika (Manila)", + "Asia\/Muscat": "Arabiemiirikuntien normaaliaika (Masqat)", + "Asia\/Nicosia": "Itä-Euroopan aika (Nikosia)", + "Asia\/Novokuznetsk": "Krasnojarskin aika (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirskin aika (Novosibirsk)", + "Asia\/Omsk": "Omskin aika (Omsk)", + "Asia\/Oral": "Länsi-Kazakstanin aika (Uralsk)", + "Asia\/Phnom_Penh": "Indokiinan aika (Phnom Penh)", + "Asia\/Pontianak": "Länsi-Indonesian aika (Pontianak)", + "Asia\/Pyongyang": "Korean aika (Pjongjang)", + "Asia\/Qatar": "Saudi-Arabian aika (Qatar)", + "Asia\/Qostanay": "Itä-Kazakstanin aika (Qostanay)", + "Asia\/Qyzylorda": "Länsi-Kazakstanin aika (Qızılorda)", + "Asia\/Rangoon": "Myanmarin aika (Yangon)", + "Asia\/Riyadh": "Saudi-Arabian aika (Riad)", + "Asia\/Saigon": "Indokiinan aika (Hồ Chí Minhin kaupunki)", + "Asia\/Sakhalin": "Sahalinin aika (Sahalin)", + "Asia\/Samarkand": "Uzbekistanin aika (Samarkand)", + "Asia\/Seoul": "Korean aika (Soul)", + "Asia\/Shanghai": "Kiinan aika (Shanghai)", + "Asia\/Singapore": "Singaporen aika (Singapore)", + "Asia\/Srednekolymsk": "Magadanin aika (Srednekolymsk)", + "Asia\/Taipei": "Taipein aika (Taipei)", + "Asia\/Tashkent": "Uzbekistanin aika (Taškent)", + "Asia\/Tbilisi": "Georgian aika (Tbilisi)", + "Asia\/Tehran": "Iranin aika (Teheran)", + "Asia\/Thimphu": "Bhutanin aika (Thimphu)", + "Asia\/Tokyo": "Japanin aika (Tokio)", + "Asia\/Ulaanbaatar": "Ulan Batorin aika (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostokin aika (Ust-Nera)", + "Asia\/Vientiane": "Indokiinan aika (Vientiane)", + "Asia\/Vladivostok": "Vladivostokin aika (Vladivostok)", + "Asia\/Yakutsk": "Jakutskin aika (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburgin aika (Jekaterinburg)", + "Asia\/Yerevan": "Armenian aika (Jerevan)", + "Atlantic\/Azores": "Azorien aika (Azorit)", + "Atlantic\/Bermuda": "Kanadan Atlantin aika (Bermuda)", + "Atlantic\/Canary": "Länsi-Euroopan aika (Kanariansaaret)", + "Atlantic\/Cape_Verde": "Kap Verden aika (Kap Verde)", + "Atlantic\/Faeroe": "Länsi-Euroopan aika (Färsaaret)", + "Atlantic\/Madeira": "Länsi-Euroopan aika (Madeira)", + "Atlantic\/Reykjavik": "Greenwichin normaaliaika (Reykjavík)", + "Atlantic\/South_Georgia": "Etelä-Georgian aika (Etelä-Georgia)", + "Atlantic\/St_Helena": "Greenwichin normaaliaika (Saint Helena)", + "Atlantic\/Stanley": "Falklandinsaarten aika (Stanley)", + "Australia\/Adelaide": "Keski-Australian aika (Adelaide)", + "Australia\/Brisbane": "Itä-Australian aika (Brisbane)", + "Australia\/Broken_Hill": "Keski-Australian aika (Broken Hill)", + "Australia\/Currie": "Itä-Australian aika (Currie)", + "Australia\/Darwin": "Keski-Australian aika (Darwin)", + "Australia\/Eucla": "Läntisen Keski-Australian aika (Eucla)", + "Australia\/Hobart": "Itä-Australian aika (Hobart)", + "Australia\/Lindeman": "Itä-Australian aika (Lindeman)", + "Australia\/Lord_Howe": "Lord Howen aika (Lord Howe)", + "Australia\/Melbourne": "Itä-Australian aika (Melbourne)", + "Australia\/Perth": "Länsi-Australian aika (Perth)", + "Australia\/Sydney": "Itä-Australian aika (Sydney)", + "CST6CDT": "Yhdysvaltain keskinen aika", + "EST5EDT": "Yhdysvaltain itäinen aika", + "Etc\/GMT": "Greenwichin normaaliaika", + "Etc\/UTC": "UTC-yleisaika", + "Europe\/Amsterdam": "Keski-Euroopan aika (Amsterdam)", + "Europe\/Andorra": "Keski-Euroopan aika (Andorra)", + "Europe\/Astrakhan": "Moskovan aika (Astrahan)", + "Europe\/Athens": "Itä-Euroopan aika (Ateena)", + "Europe\/Belgrade": "Keski-Euroopan aika (Belgrad)", + "Europe\/Berlin": "Keski-Euroopan aika (Berliini)", + "Europe\/Bratislava": "Keski-Euroopan aika (Bratislava)", + "Europe\/Brussels": "Keski-Euroopan aika (Bryssel)", + "Europe\/Bucharest": "Itä-Euroopan aika (Bukarest)", + "Europe\/Budapest": "Keski-Euroopan aika (Budapest)", + "Europe\/Busingen": "Keski-Euroopan aika (Büsingen)", + "Europe\/Chisinau": "Itä-Euroopan aika (Chişinău)", + "Europe\/Copenhagen": "Keski-Euroopan aika (Kööpenhamina)", + "Europe\/Dublin": "Greenwichin normaaliaika (Dublin)", + "Europe\/Gibraltar": "Keski-Euroopan aika (Gibraltar)", + "Europe\/Guernsey": "Greenwichin normaaliaika (Guernsey)", + "Europe\/Helsinki": "Itä-Euroopan aika (Helsinki)", + "Europe\/Isle_of_Man": "Greenwichin normaaliaika (Mansaari)", + "Europe\/Jersey": "Greenwichin normaaliaika (Jersey)", + "Europe\/Kaliningrad": "Itä-Euroopan aika (Kaliningrad)", + "Europe\/Kiev": "Itä-Euroopan aika (Kiova)", + "Europe\/Lisbon": "Länsi-Euroopan aika (Lissabon)", + "Europe\/Ljubljana": "Keski-Euroopan aika (Ljubljana)", + "Europe\/London": "Greenwichin normaaliaika (Lontoo)", + "Europe\/Luxembourg": "Keski-Euroopan aika (Luxemburg)", + "Europe\/Madrid": "Keski-Euroopan aika (Madrid)", + "Europe\/Malta": "Keski-Euroopan aika (Malta)", + "Europe\/Mariehamn": "Itä-Euroopan aika (Maarianhamina)", + "Europe\/Minsk": "Moskovan aika (Minsk)", + "Europe\/Monaco": "Keski-Euroopan aika (Monaco)", + "Europe\/Moscow": "Moskovan aika (Moskova)", + "Europe\/Oslo": "Keski-Euroopan aika (Oslo)", + "Europe\/Paris": "Keski-Euroopan aika (Pariisi)", + "Europe\/Podgorica": "Keski-Euroopan aika (Podgorica)", + "Europe\/Prague": "Keski-Euroopan aika (Praha)", + "Europe\/Riga": "Itä-Euroopan aika (Riika)", + "Europe\/Rome": "Keski-Euroopan aika (Rooma)", + "Europe\/Samara": "Samaran aika (Samara)", + "Europe\/San_Marino": "Keski-Euroopan aika (San Marino)", + "Europe\/Sarajevo": "Keski-Euroopan aika (Sarajevo)", + "Europe\/Saratov": "Moskovan aika (Saratov)", + "Europe\/Simferopol": "Moskovan aika (Simferopol)", + "Europe\/Skopje": "Keski-Euroopan aika (Skopje)", + "Europe\/Sofia": "Itä-Euroopan aika (Sofia)", + "Europe\/Stockholm": "Keski-Euroopan aika (Tukholma)", + "Europe\/Tallinn": "Itä-Euroopan aika (Tallinna)", + "Europe\/Tirane": "Keski-Euroopan aika (Tirana)", + "Europe\/Ulyanovsk": "Moskovan aika (Uljanovsk)", + "Europe\/Uzhgorod": "Itä-Euroopan aika (Užgorod)", + "Europe\/Vaduz": "Keski-Euroopan aika (Vaduz)", + "Europe\/Vatican": "Keski-Euroopan aika (Vatikaani)", + "Europe\/Vienna": "Keski-Euroopan aika (Wien)", + "Europe\/Vilnius": "Itä-Euroopan aika (Vilna)", + "Europe\/Volgograd": "Volgogradin aika (Volgograd)", + "Europe\/Warsaw": "Keski-Euroopan aika (Varsova)", + "Europe\/Zagreb": "Keski-Euroopan aika (Zagreb)", + "Europe\/Zaporozhye": "Itä-Euroopan aika (Zaporižžja)", + "Europe\/Zurich": "Keski-Euroopan aika (Zürich)", + "Indian\/Antananarivo": "Itä-Afrikan aika (Antananarivo)", + "Indian\/Chagos": "Intian valtameren aika (Chagos)", + "Indian\/Christmas": "Joulusaaren aika (Joulusaari)", + "Indian\/Cocos": "Kookossaarten aika (Kookossaaret)", + "Indian\/Comoro": "Itä-Afrikan aika (Komorit)", + "Indian\/Kerguelen": "Ranskan eteläisten ja antarktisten alueiden aika (Kerguelensaaret)", + "Indian\/Mahe": "Seychellien aika (Mahé)", + "Indian\/Maldives": "Malediivien aika (Malediivit)", + "Indian\/Mauritius": "Mauritiuksen aika (Mauritius)", + "Indian\/Mayotte": "Itä-Afrikan aika (Mayotte)", + "Indian\/Reunion": "Réunionin aika (Réunion)", + "MST7MDT": "Kalliovuorten aika", + "PST8PDT": "Yhdysvaltain Tyynenmeren aika", + "Pacific\/Apia": "Apian aika (Apia)", + "Pacific\/Auckland": "Uuden-Seelannin aika (Auckland)", + "Pacific\/Bougainville": "Papua-Uuden-Guinean aika (Bougainville)", + "Pacific\/Chatham": "Chathamin aika (Chathamsaaret)", + "Pacific\/Easter": "Pääsiäissaaren aika (Pääsiäissaari)", + "Pacific\/Efate": "Vanuatun aika (Efate)", + "Pacific\/Enderbury": "Phoenixsaarten aika (Enderbury)", + "Pacific\/Fakaofo": "Tokelaun aika (Fakaofo)", + "Pacific\/Fiji": "Fidžin aika (Fidži)", + "Pacific\/Funafuti": "Tuvalun aika (Funafuti)", + "Pacific\/Galapagos": "Galápagossaarten aika (Galapagos)", + "Pacific\/Gambier": "Gambiersaarten aika (Gambiersaaret)", + "Pacific\/Guadalcanal": "Salomonsaarten aika (Guadalcanal)", + "Pacific\/Guam": "Tšamorron aika (Guam)", + "Pacific\/Honolulu": "Havaijin-Aleuttien aika (Honolulu)", + "Pacific\/Johnston": "Havaijin-Aleuttien aika (Johnston)", + "Pacific\/Kiritimati": "Linesaarten aika (Kiritimati)", + "Pacific\/Kosrae": "Kosraen aika (Kosrae)", + "Pacific\/Kwajalein": "Marshallinsaarten aika (Kwajalein)", + "Pacific\/Majuro": "Marshallinsaarten aika (Majuro)", + "Pacific\/Marquesas": "Marquesassaarten aika (Marquesassaaret)", + "Pacific\/Midway": "Samoan aika (Midwaysaaret)", + "Pacific\/Nauru": "Naurun aika (Nauru)", + "Pacific\/Niue": "Niuen aika (Niue)", + "Pacific\/Norfolk": "Norfolkinsaaren aika (Norfolk)", + "Pacific\/Noumea": "Uuden-Kaledonian aika (Nouméa)", + "Pacific\/Pago_Pago": "Samoan aika (Pago Pago)", + "Pacific\/Palau": "Palaun aika (Palau)", + "Pacific\/Pitcairn": "Pitcairnin aika (Pitcairn)", + "Pacific\/Ponape": "Pohnpein aika (Pohnpei)", + "Pacific\/Port_Moresby": "Papua-Uuden-Guinean aika (Port Moresby)", + "Pacific\/Rarotonga": "Cookinsaarten aika (Rarotonga)", + "Pacific\/Saipan": "Tšamorron aika (Saipan)", + "Pacific\/Tahiti": "Tahitin aika (Tahiti)", + "Pacific\/Tarawa": "Gilbertsaarten aika (Tarawa)", + "Pacific\/Tongatapu": "Tongan aika (Tongatapu)", + "Pacific\/Truk": "Chuukin aika (Chuuk)", + "Pacific\/Wake": "Waken aika (Wake)", + "Pacific\/Wallis": "Wallisin ja Futunan aika (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fo.json b/src/Symfony/Component/Intl/Resources/data/timezones/fo.json new file mode 100644 index 0000000000000..07d21efda5035 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fo.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.9", + "Names": { + "Africa\/Abidjan": "Greenwich Mean tíð (Abidjan)", + "Africa\/Accra": "Greenwich Mean tíð (Accra)", + "Africa\/Addis_Ababa": "Eysturafrika tíð (Addis Ababa)", + "Africa\/Algiers": "Miðevropa tíð (Algiers)", + "Africa\/Asmera": "Eysturafrika tíð (Asmara)", + "Africa\/Bamako": "Greenwich Mean tíð (Bamako)", + "Africa\/Bangui": "Vesturafrika tíð (Bangui)", + "Africa\/Banjul": "Greenwich Mean tíð (Banjul)", + "Africa\/Bissau": "Greenwich Mean tíð (Bissau)", + "Africa\/Blantyre": "Miðafrika tíð (Blantyre)", + "Africa\/Brazzaville": "Vesturafrika tíð (Brazzaville)", + "Africa\/Bujumbura": "Miðafrika tíð (Bujumbura)", + "Africa\/Cairo": "Eysturevropa tíð (Cairo)", + "Africa\/Casablanca": "Vesturevropa tíð (Casablanca)", + "Africa\/Ceuta": "Miðevropa tíð (Ceuta)", + "Africa\/Conakry": "Greenwich Mean tíð (Conakry)", + "Africa\/Dakar": "Greenwich Mean tíð (Dakar)", + "Africa\/Dar_es_Salaam": "Eysturafrika tíð (Dar es Salaam)", + "Africa\/Djibouti": "Eysturafrika tíð (Djibuti)", + "Africa\/Douala": "Vesturafrika tíð (Douala)", + "Africa\/El_Aaiun": "Vesturevropa tíð (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean tíð (Freetown)", + "Africa\/Gaborone": "Miðafrika tíð (Gaborone)", + "Africa\/Harare": "Miðafrika tíð (Harare)", + "Africa\/Johannesburg": "Suðurafrika vanlig tíð (Johannesburg)", + "Africa\/Juba": "Eysturafrika tíð (Juba)", + "Africa\/Kampala": "Eysturafrika tíð (Kampala)", + "Africa\/Khartoum": "Miðafrika tíð (Khartoum)", + "Africa\/Kigali": "Miðafrika tíð (Kigali)", + "Africa\/Kinshasa": "Vesturafrika tíð (Kinshasa)", + "Africa\/Lagos": "Vesturafrika tíð (Lagos)", + "Africa\/Libreville": "Vesturafrika tíð (Libreville)", + "Africa\/Lome": "Greenwich Mean tíð (Lome)", + "Africa\/Luanda": "Vesturafrika tíð (Luanda)", + "Africa\/Lubumbashi": "Miðafrika tíð (Lubumbashi)", + "Africa\/Lusaka": "Miðafrika tíð (Lusaka)", + "Africa\/Malabo": "Vesturafrika tíð (Malabo)", + "Africa\/Maputo": "Miðafrika tíð (Maputo)", + "Africa\/Maseru": "Suðurafrika vanlig tíð (Maseru)", + "Africa\/Mbabane": "Suðurafrika vanlig tíð (Mbabane)", + "Africa\/Mogadishu": "Eysturafrika tíð (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean tíð (Monrovia)", + "Africa\/Nairobi": "Eysturafrika tíð (Nairobi)", + "Africa\/Ndjamena": "Vesturafrika tíð (Ndjamena)", + "Africa\/Niamey": "Vesturafrika tíð (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean tíð (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean tíð (Ouagadougou)", + "Africa\/Porto-Novo": "Vesturafrika tíð (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean tíð (São Tomé)", + "Africa\/Tripoli": "Eysturevropa tíð (Tripoli)", + "Africa\/Tunis": "Miðevropa tíð (Tunis)", + "Africa\/Windhoek": "Miðafrika tíð (Windhoek)", + "America\/Adak": "Hawaii-Aleutian tíð (Adak)", + "America\/Anchorage": "Alaska tíð (Anchorage)", + "America\/Anguilla": "Atlantic tíð (Anguilla)", + "America\/Antigua": "Atlantic tíð (Antigua)", + "America\/Araguaina": "Brasilia tíð (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentina tíð (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentina tíð (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentina tíð (Salta)", + "America\/Argentina\/San_Juan": "Argentina tíð (San Juan)", + "America\/Argentina\/San_Luis": "Vestur Argentina tíð (San Luis)", + "America\/Argentina\/Tucuman": "Argentina tíð (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentina tíð (Ushuaia)", + "America\/Aruba": "Atlantic tíð (Aruba)", + "America\/Asuncion": "Paraguai tíð (Asunción)", + "America\/Bahia": "Brasilia tíð (Bahia)", + "America\/Bahia_Banderas": "Central tíð (Bahia Banderas)", + "America\/Barbados": "Atlantic tíð (Barbados)", + "America\/Belem": "Brasilia tíð (Belem)", + "America\/Belize": "Central tíð (Belis)", + "America\/Blanc-Sablon": "Atlantic tíð (Blanc-Sablon)", + "America\/Boa_Vista": "Amasona tíð (Boa Vista)", + "America\/Bogota": "Kolombia tíð (Bogota)", + "America\/Boise": "Mountain tíð (Boise)", + "America\/Buenos_Aires": "Argentina tíð (Buenos Aires)", + "America\/Cambridge_Bay": "Mountain tíð (Cambridge Bay)", + "America\/Campo_Grande": "Amasona tíð (Campo Grande)", + "America\/Cancun": "Eastern tíð (Cancun)", + "America\/Caracas": "Venesuela tíð (Caracas)", + "America\/Catamarca": "Argentina tíð (Catamarca)", + "America\/Cayenne": "Franska Gujana tíð (Cayenne)", + "America\/Cayman": "Eastern tíð (Cayman)", + "America\/Chicago": "Central tíð (Chicago)", + "America\/Chihuahua": "Mexican Pacific tíð (Chihuahua)", + "America\/Coral_Harbour": "Eastern tíð (Atikokan)", + "America\/Cordoba": "Argentina tíð (Cordoba)", + "America\/Costa_Rica": "Central tíð (Kosta Rika)", + "America\/Creston": "Mountain tíð (Creston)", + "America\/Cuiaba": "Amasona tíð (Cuiaba)", + "America\/Curacao": "Atlantic tíð (Curaçao)", + "America\/Danmarkshavn": "Greenwich Mean tíð (Danmarkshavn)", + "America\/Dawson": "Pacific tíð (Dawson)", + "America\/Dawson_Creek": "Mountain tíð (Dawson Creek)", + "America\/Denver": "Mountain tíð (Denver)", + "America\/Detroit": "Eastern tíð (Detroit)", + "America\/Dominica": "Atlantic tíð (Dominica)", + "America\/Edmonton": "Mountain tíð (Edmonton)", + "America\/El_Salvador": "Central tíð (El Salvador)", + "America\/Fort_Nelson": "Mountain tíð (Fort Nelson)", + "America\/Fortaleza": "Brasilia tíð (Fortaleza)", + "America\/Glace_Bay": "Atlantic tíð (Glace Bay)", + "America\/Godthab": "Vestur grønlendsk tíð (Nuuk)", + "America\/Goose_Bay": "Atlantic tíð (Goose Bay)", + "America\/Grand_Turk": "Eastern tíð (Grand Turk)", + "America\/Grenada": "Atlantic tíð (Grenada)", + "America\/Guadeloupe": "Atlantic tíð (Guadeloupe)", + "America\/Guatemala": "Central tíð (Guatemala)", + "America\/Guayaquil": "Ekvador tíð (Guayaquil)", + "America\/Guyana": "Gujana tíð (Guyana)", + "America\/Halifax": "Atlantic tíð (Halifax)", + "America\/Havana": "Cuba tíð (Havana)", + "America\/Hermosillo": "Mexican Pacific tíð (Hermosillo)", + "America\/Indiana\/Knox": "Central tíð (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern tíð (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern tíð (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Central tíð (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern tíð (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern tíð (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern tíð (Winamac, Indiana)", + "America\/Indianapolis": "Eastern tíð (Indianapolis)", + "America\/Inuvik": "Mountain tíð (Inuvik)", + "America\/Iqaluit": "Eastern tíð (Iqaluit)", + "America\/Jamaica": "Eastern tíð (Jamaika)", + "America\/Jujuy": "Argentina tíð (Jujuy)", + "America\/Juneau": "Alaska tíð (Juneau)", + "America\/Kentucky\/Monticello": "Eastern tíð (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantic tíð (Kralendijk)", + "America\/La_Paz": "Bolivia tíð (La Paz)", + "America\/Lima": "Peru tíð (Lima)", + "America\/Los_Angeles": "Pacific tíð (Los Angeles)", + "America\/Louisville": "Eastern tíð (Louisville)", + "America\/Lower_Princes": "Atlantic tíð (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilia tíð (Maceio)", + "America\/Managua": "Central tíð (Managua)", + "America\/Manaus": "Amasona tíð (Manaus)", + "America\/Marigot": "Atlantic tíð (Marigot)", + "America\/Martinique": "Atlantic tíð (Martinique)", + "America\/Matamoros": "Central tíð (Matamoros)", + "America\/Mazatlan": "Mexican Pacific tíð (Mazatlan)", + "America\/Mendoza": "Argentina tíð (Mendoza)", + "America\/Menominee": "Central tíð (Menominee)", + "America\/Merida": "Central tíð (Merida)", + "America\/Metlakatla": "Alaska tíð (Metlakatla)", + "America\/Mexico_City": "Central tíð (Mexico City)", + "America\/Miquelon": "St. Pierre & Miquelon tíð (Miquelon)", + "America\/Moncton": "Atlantic tíð (Moncton)", + "America\/Monterrey": "Central tíð (Monterrey)", + "America\/Montevideo": "Uruguai tíð (Montevideo)", + "America\/Montserrat": "Atlantic tíð (Montserrat)", + "America\/Nassau": "Eastern tíð (Nassau)", + "America\/New_York": "Eastern tíð (New York)", + "America\/Nipigon": "Eastern tíð (Nipigon)", + "America\/Nome": "Alaska tíð (Nome)", + "America\/Noronha": "Fernando de Noronha tíð (Noronha)", + "America\/North_Dakota\/Beulah": "Central tíð (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Central tíð (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Central tíð (New Salem, North Dakota)", + "America\/Ojinaga": "Mountain tíð (Ojinaga)", + "America\/Panama": "Eastern tíð (Panama)", + "America\/Pangnirtung": "Eastern tíð (Pangnirtung)", + "America\/Paramaribo": "Surinam tíð (Paramaribo)", + "America\/Phoenix": "Mountain tíð (Phoenix)", + "America\/Port-au-Prince": "Eastern tíð (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantic tíð (Port of Spain)", + "America\/Porto_Velho": "Amasona tíð (Porto Velho)", + "America\/Puerto_Rico": "Atlantic tíð (Puerto Riko)", + "America\/Punta_Arenas": "Kili tíð (Punta Arenas)", + "America\/Rainy_River": "Central tíð (Rainy River)", + "America\/Rankin_Inlet": "Central tíð (Rankin Inlet)", + "America\/Recife": "Brasilia tíð (Recife)", + "America\/Regina": "Central tíð (Regina)", + "America\/Resolute": "Central tíð (Resolute)", + "America\/Santa_Isabel": "Northwest Mexico tíð (Santa Isabel)", + "America\/Santarem": "Brasilia tíð (Santarem)", + "America\/Santiago": "Kili tíð (Santiago)", + "America\/Santo_Domingo": "Atlantic tíð (Santo Domingo)", + "America\/Sao_Paulo": "Brasilia tíð (Sao Paulo)", + "America\/Scoresbysund": "Eystur grønlendsk tíð (Ittoqqortoormiit)", + "America\/Sitka": "Alaska tíð (Sitka)", + "America\/St_Barthelemy": "Atlantic tíð (St. Barthelemy)", + "America\/St_Johns": "Newfoundland tíð (St. John’s)", + "America\/St_Kitts": "Atlantic tíð (St. Kitts)", + "America\/St_Lucia": "Atlantic tíð (St. Lucia)", + "America\/St_Thomas": "Atlantic tíð (St. Thomas)", + "America\/St_Vincent": "Atlantic tíð (St. Vincent)", + "America\/Swift_Current": "Central tíð (Swift Current)", + "America\/Tegucigalpa": "Central tíð (Tegucigalpa)", + "America\/Thule": "Atlantic tíð (Thule)", + "America\/Thunder_Bay": "Eastern tíð (Thunder Bay)", + "America\/Tijuana": "Pacific tíð (Tijuana)", + "America\/Toronto": "Eastern tíð (Toronto)", + "America\/Tortola": "Atlantic tíð (Tortola)", + "America\/Vancouver": "Pacific tíð (Vancouver)", + "America\/Whitehorse": "Pacific tíð (Whitehorse)", + "America\/Winnipeg": "Central tíð (Winnipeg)", + "America\/Yakutat": "Alaska tíð (Yakutat)", + "America\/Yellowknife": "Mountain tíð (Yellowknife)", + "Antarctica\/Casey": "vestur Avstralia tíð (Casey)", + "Antarctica\/Davis": "Davis tíð (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville tíð (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquariesoyggj tíð (Macquarie)", + "Antarctica\/Mawson": "Mawson tíð (Mawson)", + "Antarctica\/McMurdo": "Nýsæland tíð (McMurdo)", + "Antarctica\/Palmer": "Kili tíð (Palmer)", + "Antarctica\/Rothera": "Rothera tíð (Rothera)", + "Antarctica\/Syowa": "Syowa tíð (Syowa)", + "Antarctica\/Troll": "Greenwich Mean tíð (Troll)", + "Antarctica\/Vostok": "Vostok tíð (Vostok)", + "Arctic\/Longyearbyen": "Miðevropa tíð (Longyearbyen)", + "Asia\/Aden": "Arabisk tíð (Aden)", + "Asia\/Almaty": "Eystur Kasakstan tíð (Almaty)", + "Asia\/Amman": "Eysturevropa tíð (Amman)", + "Asia\/Aqtau": "Vestur Kasakstan tíð (Aqtau)", + "Asia\/Aqtobe": "Vestur Kasakstan tíð (Aqtobe)", + "Asia\/Ashgabat": "Turkmenistan tíð (Ashgabat)", + "Asia\/Atyrau": "Vestur Kasakstan tíð (Atyrau)", + "Asia\/Baghdad": "Arabisk tíð (Baghdad)", + "Asia\/Bahrain": "Arabisk tíð (Barein)", + "Asia\/Baku": "Aserbadjan tíð (Baku)", + "Asia\/Bangkok": "Indokina tíð (Bangkok)", + "Asia\/Beirut": "Eysturevropa tíð (Beirut)", + "Asia\/Bishkek": "Kirgisia tíð (Bishkek)", + "Asia\/Brunei": "Brunei Darussalam tíð (Brunei)", + "Asia\/Calcutta": "India tíð (Kolkata)", + "Asia\/Chita": "Yakutsk tíð (Chita)", + "Asia\/Choibalsan": "Choibalsan tíð (Choibalsan)", + "Asia\/Colombo": "India tíð (Colombo)", + "Asia\/Damascus": "Eysturevropa tíð (Damascus)", + "Asia\/Dhaka": "Bangladesj tíð (Dhaka)", + "Asia\/Dili": "Eysturtimor tíð (Dili)", + "Asia\/Dubai": "Gulf vanlig tíð (Dubai)", + "Asia\/Dushanbe": "Tadsjikistan tíð (Dushanbe)", + "Asia\/Famagusta": "Eysturevropa tíð (Famagusta)", + "Asia\/Gaza": "Eysturevropa tíð (Gasa)", + "Asia\/Hebron": "Eysturevropa tíð (Hebron)", + "Asia\/Hong_Kong": "Hong Kong tíð (Hong Kong)", + "Asia\/Hovd": "Hovd tíð (Hovd)", + "Asia\/Irkutsk": "Irkutsk tíð (Irkutsk)", + "Asia\/Jakarta": "Vestur Indonesia tíð (Jakarta)", + "Asia\/Jayapura": "Eystur Indonesia tíð (Jayapura)", + "Asia\/Jerusalem": "Ísrael tíð (Jerusalem)", + "Asia\/Kabul": "Afganistan tíð (Kabul)", + "Asia\/Karachi": "Pakistan tíð (Karachi)", + "Asia\/Katmandu": "Nepal tíð (Kathmandu)", + "Asia\/Khandyga": "Yakutsk tíð (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnoyarsk tíð (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malaisia tíð (Kuala Lumpur)", + "Asia\/Kuching": "Malaisia tíð (Kuching)", + "Asia\/Kuwait": "Arabisk tíð (Kuvait)", + "Asia\/Macau": "Kina tíð (Makao)", + "Asia\/Magadan": "Magadan tíð (Magadan)", + "Asia\/Makassar": "Mið Indonesia tíð (Makassar)", + "Asia\/Manila": "Filipsoyggjar tíð (Manila)", + "Asia\/Muscat": "Gulf vanlig tíð (Muscat)", + "Asia\/Nicosia": "Eysturevropa tíð (Nicosia)", + "Asia\/Novokuznetsk": "Krasnoyarsk tíð (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk tíð (Novosibirsk)", + "Asia\/Omsk": "Omsk tíð (Omsk)", + "Asia\/Oral": "Vestur Kasakstan tíð (Oral)", + "Asia\/Phnom_Penh": "Indokina tíð (Phnom Penh)", + "Asia\/Pontianak": "Vestur Indonesia tíð (Pontianak)", + "Asia\/Pyongyang": "Korea tíð (Pyongyang)", + "Asia\/Qatar": "Arabisk tíð (Qatar)", + "Asia\/Qostanay": "Eystur Kasakstan tíð (Qostanay)", + "Asia\/Qyzylorda": "Vestur Kasakstan tíð (Qyzylorda)", + "Asia\/Rangoon": "Myanmar (Burma) tíð (Rangoon)", + "Asia\/Riyadh": "Arabisk tíð (Riyadh)", + "Asia\/Saigon": "Indokina tíð (Ho Chi Minh)", + "Asia\/Sakhalin": "Sakhalin tíð (Sakhalin)", + "Asia\/Samarkand": "Usbekistan tíð (Samarkand)", + "Asia\/Seoul": "Korea tíð (Seoul)", + "Asia\/Shanghai": "Kina tíð (Shanghai)", + "Asia\/Singapore": "Singapor tíð (Singapor)", + "Asia\/Srednekolymsk": "Magadan tíð (Srednekolymsk)", + "Asia\/Taipei": "Taipei tíð (Taipei)", + "Asia\/Tashkent": "Usbekistan tíð (Tashkent)", + "Asia\/Tbilisi": "Georgia tíð (Tbilisi)", + "Asia\/Tehran": "Iran tíð (Teheran)", + "Asia\/Thimphu": "Butan tíð (Thimphu)", + "Asia\/Tokyo": "Japan tíð (Tokyo)", + "Asia\/Ulaanbaatar": "Ulan Bator tíð (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostok tíð (Ust-Nera)", + "Asia\/Vientiane": "Indokina tíð (Vientiane)", + "Asia\/Vladivostok": "Vladivostok tíð (Vladivostok)", + "Asia\/Yakutsk": "Yakutsk tíð (Yakutsk)", + "Asia\/Yekaterinburg": "Yekaterinburg tíð (Yekaterinburg)", + "Asia\/Yerevan": "Armenia tíð (Yerevan)", + "Atlantic\/Azores": "Azorurnar tíð (Azorurnar)", + "Atlantic\/Bermuda": "Atlantic tíð (Bermuda)", + "Atlantic\/Canary": "Vesturevropa tíð (Canary)", + "Atlantic\/Cape_Verde": "Grønhøvdaoyggjar tíð (Grønhøvdaoyggjar)", + "Atlantic\/Faeroe": "Vesturevropa tíð (Føroyar)", + "Atlantic\/Madeira": "Vesturevropa tíð (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean tíð (Reykjavík)", + "Atlantic\/South_Georgia": "Suðurgeorgiaoyggjar tíð (Suðurgeorgiaoyggjar)", + "Atlantic\/St_Helena": "Greenwich Mean tíð (St. Helena)", + "Atlantic\/Stanley": "Falklandsoyggjar tíð (Stanley)", + "Australia\/Adelaide": "mið Avstralia tíð (Adelaide)", + "Australia\/Brisbane": "eystur Avstralia tíð (Brisbane)", + "Australia\/Broken_Hill": "mið Avstralia tíð (Broken Hill)", + "Australia\/Currie": "eystur Avstralia tíð (Currie)", + "Australia\/Darwin": "mið Avstralia tíð (Darwin)", + "Australia\/Eucla": "miðvestur Avstralia tíð (Eucla)", + "Australia\/Hobart": "eystur Avstralia tíð (Hobart)", + "Australia\/Lindeman": "eystur Avstralia tíð (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe tíð (Lord Howe)", + "Australia\/Melbourne": "eystur Avstralia tíð (Melbourne)", + "Australia\/Perth": "vestur Avstralia tíð (Perth)", + "Australia\/Sydney": "eystur Avstralia tíð (Sydney)", + "CST6CDT": "Central tíð", + "EST5EDT": "Eastern tíð", + "Etc\/GMT": "Greenwich Mean tíð", + "Etc\/UTC": "Samskipað heimstíð", + "Europe\/Amsterdam": "Miðevropa tíð (Amsterdam)", + "Europe\/Andorra": "Miðevropa tíð (Andorra)", + "Europe\/Astrakhan": "Moskva tíð (Astrakhan)", + "Europe\/Athens": "Eysturevropa tíð (Aten)", + "Europe\/Belgrade": "Miðevropa tíð (Beograd)", + "Europe\/Berlin": "Miðevropa tíð (Berlin)", + "Europe\/Bratislava": "Miðevropa tíð (Bratislava)", + "Europe\/Brussels": "Miðevropa tíð (Bruxelles)", + "Europe\/Bucharest": "Eysturevropa tíð (Bukarest)", + "Europe\/Budapest": "Miðevropa tíð (Budapest)", + "Europe\/Busingen": "Miðevropa tíð (Busingen)", + "Europe\/Chisinau": "Eysturevropa tíð (Chisinau)", + "Europe\/Copenhagen": "Miðevropa tíð (Keypmannahavn)", + "Europe\/Dublin": "Greenwich Mean tíð (Dublin)", + "Europe\/Gibraltar": "Miðevropa tíð (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean tíð (Guernsey)", + "Europe\/Helsinki": "Eysturevropa tíð (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean tíð (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean tíð (Jersey)", + "Europe\/Kaliningrad": "Eysturevropa tíð (Kaliningrad)", + "Europe\/Kiev": "Eysturevropa tíð (Kiev)", + "Europe\/Lisbon": "Vesturevropa tíð (Lissabon)", + "Europe\/Ljubljana": "Miðevropa tíð (Ljubljana)", + "Europe\/London": "Greenwich Mean tíð (London)", + "Europe\/Luxembourg": "Miðevropa tíð (Luksemborg)", + "Europe\/Madrid": "Miðevropa tíð (Madrid)", + "Europe\/Malta": "Miðevropa tíð (Malta)", + "Europe\/Mariehamn": "Eysturevropa tíð (Mariehamn)", + "Europe\/Minsk": "Moskva tíð (Minsk)", + "Europe\/Monaco": "Miðevropa tíð (Monako)", + "Europe\/Moscow": "Moskva tíð (Moskva)", + "Europe\/Oslo": "Miðevropa tíð (Oslo)", + "Europe\/Paris": "Miðevropa tíð (Paris)", + "Europe\/Podgorica": "Miðevropa tíð (Podgorica)", + "Europe\/Prague": "Miðevropa tíð (Prag)", + "Europe\/Riga": "Eysturevropa tíð (Riga)", + "Europe\/Rome": "Miðevropa tíð (Rom)", + "Europe\/San_Marino": "Miðevropa tíð (San Marino)", + "Europe\/Sarajevo": "Miðevropa tíð (Sarajevo)", + "Europe\/Saratov": "Moskva tíð (Saratov)", + "Europe\/Simferopol": "Moskva tíð (Simferopol)", + "Europe\/Skopje": "Miðevropa tíð (Skopje)", + "Europe\/Sofia": "Eysturevropa tíð (Sofia)", + "Europe\/Stockholm": "Miðevropa tíð (Stokkhólm)", + "Europe\/Tallinn": "Eysturevropa tíð (Tallinn)", + "Europe\/Tirane": "Miðevropa tíð (Tirane)", + "Europe\/Ulyanovsk": "Moskva tíð (Ulyanovsk)", + "Europe\/Uzhgorod": "Eysturevropa tíð (Uzhhorod)", + "Europe\/Vaduz": "Miðevropa tíð (Vaduz)", + "Europe\/Vatican": "Miðevropa tíð (Vatikanið)", + "Europe\/Vienna": "Miðevropa tíð (Wien)", + "Europe\/Vilnius": "Eysturevropa tíð (Vilnius)", + "Europe\/Volgograd": "Volgograd tíð (Volgograd)", + "Europe\/Warsaw": "Miðevropa tíð (Varsjava)", + "Europe\/Zagreb": "Miðevropa tíð (Zagreb)", + "Europe\/Zaporozhye": "Eysturevropa tíð (Zaporozhye)", + "Europe\/Zurich": "Miðevropa tíð (Zürich)", + "Indian\/Antananarivo": "Eysturafrika tíð (Antananarivo)", + "Indian\/Chagos": "Indiahav tíð (Chagos)", + "Indian\/Christmas": "Jólaoyggj tíð (Christmas)", + "Indian\/Cocos": "Kokosoyggjar tíð (Cocos)", + "Indian\/Comoro": "Eysturafrika tíð (Comoro)", + "Indian\/Kerguelen": "Fronsku sunnaru landaøki og Antarktis tíð (Kerguelen)", + "Indian\/Mahe": "Seyskelloyggjar tíð (Mahe)", + "Indian\/Maldives": "Maldivoyggjar tíð (Maldivoyggjar)", + "Indian\/Mauritius": "Móritius tíð (Móritius)", + "Indian\/Mayotte": "Eysturafrika tíð (Mayotte)", + "Indian\/Reunion": "Réunion tíð (Réunion)", + "MST7MDT": "Mountain tíð", + "PST8PDT": "Pacific tíð", + "Pacific\/Apia": "Apia tíð (Apia)", + "Pacific\/Auckland": "Nýsæland tíð (Auckland)", + "Pacific\/Bougainville": "Papua Nýguinea tíð (Bougainville)", + "Pacific\/Chatham": "Chatham tíð (Chatham)", + "Pacific\/Easter": "Páskaoyggin tíð (Easter)", + "Pacific\/Efate": "Vanuatu tíð (Efate)", + "Pacific\/Enderbury": "Phoenixoyggjar tíð (Enderbury)", + "Pacific\/Fakaofo": "Tokelau tíð (Fakaofo)", + "Pacific\/Fiji": "Fiji tíð (Fiji)", + "Pacific\/Funafuti": "Tuvalu tíð (Funafuti)", + "Pacific\/Galapagos": "Galapagos tíð (Galapagos)", + "Pacific\/Gambier": "Gambier tíð (Gambier)", + "Pacific\/Guadalcanal": "Salomonoyggjar tíð (Guadalcanal)", + "Pacific\/Guam": "Chamorro vanlig tíð (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleutian tíð (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleutian tíð (Johnston)", + "Pacific\/Kiritimati": "Lineoyggjar tíð (Kiritimati)", + "Pacific\/Kosrae": "Kosrae tíð (Kosrae)", + "Pacific\/Kwajalein": "Marshalloyggjar tíð (Kwajalein)", + "Pacific\/Majuro": "Marshalloyggjar tíð (Majuro)", + "Pacific\/Marquesas": "Marquesas tíð (Marquesas)", + "Pacific\/Midway": "Samoa tíð (Midway)", + "Pacific\/Nauru": "Nauru tíð (Nauru)", + "Pacific\/Niue": "Niue tíð (Niue)", + "Pacific\/Norfolk": "Norfolksoyggj tíð (Norfolk)", + "Pacific\/Noumea": "Nýkaledónia tíð (Noumea)", + "Pacific\/Pago_Pago": "Samoa tíð (Pago Pago)", + "Pacific\/Palau": "Palau tíð (Palau)", + "Pacific\/Pitcairn": "Pitcairnoyggjar tíð (Pitcairn)", + "Pacific\/Ponape": "Ponape tíð (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Nýguinea tíð (Port Moresby)", + "Pacific\/Rarotonga": "Cooksoyggjar tíð (Rarotonga)", + "Pacific\/Saipan": "Chamorro vanlig tíð (Saipan)", + "Pacific\/Tahiti": "Tahiti tíð (Tahiti)", + "Pacific\/Tarawa": "Gilbertoyggjar tíð (Tarawa)", + "Pacific\/Tongatapu": "Tonga tíð (Tongatapu)", + "Pacific\/Truk": "Chuuk tíð (Chuuk)", + "Pacific\/Wake": "Wakeoyggj tíð (Wake)", + "Pacific\/Wallis": "Wallis- og Futunaoyggjar tíð (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fr.json b/src/Symfony/Component/Intl/Resources/data/timezones/fr.json new file mode 100644 index 0000000000000..c666d295cd2e6 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fr.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.43", + "Names": { + "Africa\/Abidjan": "heure moyenne de Greenwich (Abidjan)", + "Africa\/Accra": "heure moyenne de Greenwich (Accra)", + "Africa\/Addis_Ababa": "heure normale d’Afrique de l’Est (Addis-Abeba)", + "Africa\/Algiers": "heure d’Europe centrale (Alger)", + "Africa\/Asmera": "heure normale d’Afrique de l’Est (Asmara)", + "Africa\/Bamako": "heure moyenne de Greenwich (Bamako)", + "Africa\/Bangui": "heure d’Afrique de l’Ouest (Bangui)", + "Africa\/Banjul": "heure moyenne de Greenwich (Banjul)", + "Africa\/Bissau": "heure moyenne de Greenwich (Bissau)", + "Africa\/Blantyre": "heure normale d’Afrique centrale (Blantyre)", + "Africa\/Brazzaville": "heure d’Afrique de l’Ouest (Brazzaville)", + "Africa\/Bujumbura": "heure normale d’Afrique centrale (Bujumbura)", + "Africa\/Cairo": "heure d’Europe de l’Est (Le Caire)", + "Africa\/Casablanca": "heure d’Europe de l’Ouest (Casablanca)", + "Africa\/Ceuta": "heure d’Europe centrale (Ceuta)", + "Africa\/Conakry": "heure moyenne de Greenwich (Conakry)", + "Africa\/Dakar": "heure moyenne de Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "heure normale d’Afrique de l’Est (Dar es Salaam)", + "Africa\/Djibouti": "heure normale d’Afrique de l’Est (Djibouti)", + "Africa\/Douala": "heure d’Afrique de l’Ouest (Douala)", + "Africa\/El_Aaiun": "heure d’Europe de l’Ouest (Laâyoune)", + "Africa\/Freetown": "heure moyenne de Greenwich (Freetown)", + "Africa\/Gaborone": "heure normale d’Afrique centrale (Gaborone)", + "Africa\/Harare": "heure normale d’Afrique centrale (Harare)", + "Africa\/Johannesburg": "heure normale d’Afrique méridionale (Johannesburg)", + "Africa\/Juba": "heure normale d’Afrique de l’Est (Juba)", + "Africa\/Kampala": "heure normale d’Afrique de l’Est (Kampala)", + "Africa\/Khartoum": "heure normale d’Afrique centrale (Khartoum)", + "Africa\/Kigali": "heure normale d’Afrique centrale (Kigali)", + "Africa\/Kinshasa": "heure d’Afrique de l’Ouest (Kinshasa)", + "Africa\/Lagos": "heure d’Afrique de l’Ouest (Lagos)", + "Africa\/Libreville": "heure d’Afrique de l’Ouest (Libreville)", + "Africa\/Lome": "heure moyenne de Greenwich (Lomé)", + "Africa\/Luanda": "heure d’Afrique de l’Ouest (Luanda)", + "Africa\/Lubumbashi": "heure normale d’Afrique centrale (Lubumbashi)", + "Africa\/Lusaka": "heure normale d’Afrique centrale (Lusaka)", + "Africa\/Malabo": "heure d’Afrique de l’Ouest (Malabo)", + "Africa\/Maputo": "heure normale d’Afrique centrale (Maputo)", + "Africa\/Maseru": "heure normale d’Afrique méridionale (Maseru)", + "Africa\/Mbabane": "heure normale d’Afrique méridionale (Mbabane)", + "Africa\/Mogadishu": "heure normale d’Afrique de l’Est (Mogadiscio)", + "Africa\/Monrovia": "heure moyenne de Greenwich (Monrovia)", + "Africa\/Nairobi": "heure normale d’Afrique de l’Est (Nairobi)", + "Africa\/Ndjamena": "heure d’Afrique de l’Ouest (N’Djamena)", + "Africa\/Niamey": "heure d’Afrique de l’Ouest (Niamey)", + "Africa\/Nouakchott": "heure moyenne de Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "heure moyenne de Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "heure d’Afrique de l’Ouest (Porto-Novo)", + "Africa\/Sao_Tome": "heure moyenne de Greenwich (São Tomé)", + "Africa\/Tripoli": "heure d’Europe de l’Est (Tripoli (Libye))", + "Africa\/Tunis": "heure d’Europe centrale (Tunis)", + "Africa\/Windhoek": "heure normale d’Afrique centrale (Windhoek)", + "America\/Adak": "heure d’Hawaii - Aléoutiennes (Adak)", + "America\/Anchorage": "heure de l’Alaska (Anchorage)", + "America\/Anguilla": "heure de l’Atlantique (Anguilla)", + "America\/Antigua": "heure de l’Atlantique (Antigua)", + "America\/Araguaina": "heure de Brasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "heure de l’Argentine (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "heure de l’Argentine (Río Gallegos)", + "America\/Argentina\/Salta": "heure de l’Argentine (Salta)", + "America\/Argentina\/San_Juan": "heure de l’Argentine (San Juan)", + "America\/Argentina\/San_Luis": "heure de l’Ouest argentin (San Luis)", + "America\/Argentina\/Tucuman": "heure de l’Argentine (Tucumán)", + "America\/Argentina\/Ushuaia": "heure de l’Argentine (Ushuaïa)", + "America\/Aruba": "heure de l’Atlantique (Aruba)", + "America\/Asuncion": "heure du Paraguay (Asunción)", + "America\/Bahia": "heure de Brasilia (Bahia)", + "America\/Bahia_Banderas": "heure du centre nord-américain (Bahia de Banderas)", + "America\/Barbados": "heure de l’Atlantique (La Barbade)", + "America\/Belem": "heure de Brasilia (Belém)", + "America\/Belize": "heure du centre nord-américain (Belize)", + "America\/Blanc-Sablon": "heure de l’Atlantique (Blanc-Sablon)", + "America\/Boa_Vista": "heure de l’Amazonie (Boa Vista)", + "America\/Bogota": "heure de Colombie (Bogota)", + "America\/Boise": "heure des Rocheuses (Boise)", + "America\/Buenos_Aires": "heure de l’Argentine (Buenos Aires)", + "America\/Cambridge_Bay": "heure des Rocheuses (Cambridge Bay)", + "America\/Campo_Grande": "heure de l’Amazonie (Campo Grande)", + "America\/Cancun": "heure de l’Est nord-américain (Cancún)", + "America\/Caracas": "heure du Venezuela (Caracas)", + "America\/Catamarca": "heure de l’Argentine (Catamarca)", + "America\/Cayenne": "heure de la Guyane française (Cayenne)", + "America\/Cayman": "heure de l’Est nord-américain (Caïmans)", + "America\/Chicago": "heure du centre nord-américain (Chicago)", + "America\/Chihuahua": "heure du Pacifique mexicain (Chihuahua)", + "America\/Coral_Harbour": "heure de l’Est nord-américain (Atikokan)", + "America\/Cordoba": "heure de l’Argentine (Córdoba)", + "America\/Costa_Rica": "heure du centre nord-américain (Costa Rica)", + "America\/Creston": "heure des Rocheuses (Creston)", + "America\/Cuiaba": "heure de l’Amazonie (Cuiabá)", + "America\/Curacao": "heure de l’Atlantique (Curaçao)", + "America\/Danmarkshavn": "heure moyenne de Greenwich (Danmarkshavn)", + "America\/Dawson": "heure du Pacifique nord-américain (Dawson)", + "America\/Dawson_Creek": "heure des Rocheuses (Dawson Creek)", + "America\/Denver": "heure des Rocheuses (Denver)", + "America\/Detroit": "heure de l’Est nord-américain (Détroit)", + "America\/Dominica": "heure de l’Atlantique (Dominique)", + "America\/Edmonton": "heure des Rocheuses (Edmonton)", + "America\/Eirunepe": "heure de l’Acre (Eirunepé)", + "America\/El_Salvador": "heure du centre nord-américain (El Salvador)", + "America\/Fort_Nelson": "heure des Rocheuses (Fort Nelson)", + "America\/Fortaleza": "heure de Brasilia (Fortaleza)", + "America\/Glace_Bay": "heure de l’Atlantique (Glace Bay)", + "America\/Godthab": "heure de l’Ouest du Groenland (Nuuk)", + "America\/Goose_Bay": "heure de l’Atlantique (Goose Bay)", + "America\/Grand_Turk": "heure de l’Est nord-américain (Grand Turk)", + "America\/Grenada": "heure de l’Atlantique (Grenade)", + "America\/Guadeloupe": "heure de l’Atlantique (Guadeloupe)", + "America\/Guatemala": "heure du centre nord-américain (Guatemala)", + "America\/Guayaquil": "heure de l’Équateur (Guayaquil)", + "America\/Guyana": "heure du Guyana (Guyana)", + "America\/Halifax": "heure de l’Atlantique (Halifax)", + "America\/Havana": "heure de Cuba (La Havane)", + "America\/Hermosillo": "heure du Pacifique mexicain (Hermosillo)", + "America\/Indiana\/Knox": "heure du centre nord-américain (Knox [Indiana])", + "America\/Indiana\/Marengo": "heure de l’Est nord-américain (Marengo [Indiana])", + "America\/Indiana\/Petersburg": "heure de l’Est nord-américain (Petersburg [Indiana])", + "America\/Indiana\/Tell_City": "heure du centre nord-américain (Tell City [Indiana])", + "America\/Indiana\/Vevay": "heure de l’Est nord-américain (Vevay [Indiana])", + "America\/Indiana\/Vincennes": "heure de l’Est nord-américain (Vincennes [Indiana])", + "America\/Indiana\/Winamac": "heure de l’Est nord-américain (Winamac [Indiana])", + "America\/Indianapolis": "heure de l’Est nord-américain (Indianapolis)", + "America\/Inuvik": "heure des Rocheuses (Inuvik)", + "America\/Iqaluit": "heure de l’Est nord-américain (Iqaluit)", + "America\/Jamaica": "heure de l’Est nord-américain (Jamaïque)", + "America\/Jujuy": "heure de l’Argentine (Jujuy)", + "America\/Juneau": "heure de l’Alaska (Juneau)", + "America\/Kentucky\/Monticello": "heure de l’Est nord-américain (Monticello [Kentucky])", + "America\/Kralendijk": "heure de l’Atlantique (Kralendijk)", + "America\/La_Paz": "heure de Bolivie (La Paz)", + "America\/Lima": "heure du Pérou (Lima)", + "America\/Los_Angeles": "heure du Pacifique nord-américain (Los Angeles)", + "America\/Louisville": "heure de l’Est nord-américain (Louisville)", + "America\/Lower_Princes": "heure de l’Atlantique (Lower Prince’s Quarter)", + "America\/Maceio": "heure de Brasilia (Maceió)", + "America\/Managua": "heure du centre nord-américain (Managua)", + "America\/Manaus": "heure de l’Amazonie (Manaos)", + "America\/Marigot": "heure de l’Atlantique (Marigot)", + "America\/Martinique": "heure de l’Atlantique (Martinique)", + "America\/Matamoros": "heure du centre nord-américain (Matamoros)", + "America\/Mazatlan": "heure du Pacifique mexicain (Mazatlán)", + "America\/Mendoza": "heure de l’Argentine (Mendoza)", + "America\/Menominee": "heure du centre nord-américain (Menominee)", + "America\/Merida": "heure du centre nord-américain (Mérida)", + "America\/Metlakatla": "heure de l’Alaska (Metlakatla)", + "America\/Mexico_City": "heure du centre nord-américain (Mexico)", + "America\/Miquelon": "heure de Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "heure de l’Atlantique (Moncton)", + "America\/Monterrey": "heure du centre nord-américain (Monterrey)", + "America\/Montevideo": "heure de l’Uruguay (Montevideo)", + "America\/Montserrat": "heure de l’Atlantique (Montserrat)", + "America\/Nassau": "heure de l’Est nord-américain (Nassau)", + "America\/New_York": "heure de l’Est nord-américain (New York)", + "America\/Nipigon": "heure de l’Est nord-américain (Nipigon)", + "America\/Nome": "heure de l’Alaska (Nome)", + "America\/Noronha": "heure de Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "heure du centre nord-américain (Beulah (Dakota du Nord))", + "America\/North_Dakota\/Center": "heure du centre nord-américain (Center (Dakota du Nord))", + "America\/North_Dakota\/New_Salem": "heure du centre nord-américain (New Salem (Dakota du Nord))", + "America\/Ojinaga": "heure des Rocheuses (Ojinaga)", + "America\/Panama": "heure de l’Est nord-américain (Panama)", + "America\/Pangnirtung": "heure de l’Est nord-américain (Pangnirtung)", + "America\/Paramaribo": "heure du Suriname (Paramaribo)", + "America\/Phoenix": "heure des Rocheuses (Phoenix)", + "America\/Port-au-Prince": "heure de l’Est nord-américain (Port-au-Prince)", + "America\/Port_of_Spain": "heure de l’Atlantique (Port-d’Espagne)", + "America\/Porto_Velho": "heure de l’Amazonie (Porto Velho)", + "America\/Puerto_Rico": "heure de l’Atlantique (Porto Rico)", + "America\/Punta_Arenas": "heure du Chili (Punta Arenas)", + "America\/Rainy_River": "heure du centre nord-américain (Rainy River)", + "America\/Rankin_Inlet": "heure du centre nord-américain (Rankin Inlet)", + "America\/Recife": "heure de Brasilia (Recife)", + "America\/Regina": "heure du centre nord-américain (Regina)", + "America\/Resolute": "heure du centre nord-américain (Resolute)", + "America\/Rio_Branco": "heure de l’Acre (Rio Branco)", + "America\/Santa_Isabel": "heure du Nord-Ouest du Mexique (Santa Isabel)", + "America\/Santarem": "heure de Brasilia (Santarém)", + "America\/Santiago": "heure du Chili (Santiago)", + "America\/Santo_Domingo": "heure de l’Atlantique (Saint-Domingue)", + "America\/Sao_Paulo": "heure de Brasilia (São Paulo)", + "America\/Scoresbysund": "heure de l’Est du Groenland (Ittoqqortoormiit)", + "America\/Sitka": "heure de l’Alaska (Sitka)", + "America\/St_Barthelemy": "heure de l’Atlantique (Saint-Barthélemy)", + "America\/St_Johns": "heure de Terre-Neuve (Saint-Jean de Terre-Neuve)", + "America\/St_Kitts": "heure de l’Atlantique (Saint-Christophe)", + "America\/St_Lucia": "heure de l’Atlantique (Sainte-Lucie)", + "America\/St_Thomas": "heure de l’Atlantique (Saint-Thomas)", + "America\/St_Vincent": "heure de l’Atlantique (Saint-Vincent)", + "America\/Swift_Current": "heure du centre nord-américain (Swift Current)", + "America\/Tegucigalpa": "heure du centre nord-américain (Tégucigalpa)", + "America\/Thule": "heure de l’Atlantique (Thulé)", + "America\/Thunder_Bay": "heure de l’Est nord-américain (Thunder Bay)", + "America\/Tijuana": "heure du Pacifique nord-américain (Tijuana)", + "America\/Toronto": "heure de l’Est nord-américain (Toronto)", + "America\/Tortola": "heure de l’Atlantique (Tortola)", + "America\/Vancouver": "heure du Pacifique nord-américain (Vancouver)", + "America\/Whitehorse": "heure du Pacifique nord-américain (Whitehorse)", + "America\/Winnipeg": "heure du centre nord-américain (Winnipeg)", + "America\/Yakutat": "heure de l’Alaska (Yakutat)", + "America\/Yellowknife": "heure des Rocheuses (Yellowknife)", + "Antarctica\/Casey": "heure de l’Ouest de l’Australie (Casey)", + "Antarctica\/Davis": "heure de Davis (Davis)", + "Antarctica\/DumontDUrville": "heure de Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "heure de l’île Macquarie (Macquarie)", + "Antarctica\/Mawson": "heure de Mawson (Mawson)", + "Antarctica\/McMurdo": "heure de la Nouvelle-Zélande (McMurdo)", + "Antarctica\/Palmer": "heure du Chili (Palmer)", + "Antarctica\/Rothera": "heure de Rothera (Rothera)", + "Antarctica\/Syowa": "heure de Syowa (Showa)", + "Antarctica\/Troll": "heure moyenne de Greenwich (Troll)", + "Antarctica\/Vostok": "heure de Vostok (Vostok)", + "Arctic\/Longyearbyen": "heure d’Europe centrale (Longyearbyen)", + "Asia\/Aden": "heure de l’Arabie (Aden)", + "Asia\/Almaty": "heure de l’Est du Kazakhstan (Alma Ata)", + "Asia\/Amman": "heure d’Europe de l’Est (Amman)", + "Asia\/Anadyr": "heure d’Anadyr (Anadyr)", + "Asia\/Aqtau": "heure de l’Ouest du Kazakhstan (Aktaou)", + "Asia\/Aqtobe": "heure de l’Ouest du Kazakhstan (Aktioubinsk)", + "Asia\/Ashgabat": "heure du Turkménistan (Achgabat)", + "Asia\/Atyrau": "heure de l’Ouest du Kazakhstan (Atyraou)", + "Asia\/Baghdad": "heure de l’Arabie (Bagdad)", + "Asia\/Bahrain": "heure de l’Arabie (Bahreïn)", + "Asia\/Baku": "heure de l’Azerbaïdjan (Bakou)", + "Asia\/Bangkok": "heure d’Indochine (Bangkok)", + "Asia\/Beirut": "heure d’Europe de l’Est (Beyrouth)", + "Asia\/Bishkek": "heure du Kirghizistan (Bichkek)", + "Asia\/Brunei": "heure du Brunéi (Brunei)", + "Asia\/Calcutta": "heure de l’Inde (Calcutta)", + "Asia\/Chita": "heure de Iakoutsk (Tchita)", + "Asia\/Choibalsan": "heure de Choibalsan (Tchoïbalsan)", + "Asia\/Colombo": "heure de l’Inde (Colombo)", + "Asia\/Damascus": "heure d’Europe de l’Est (Damas)", + "Asia\/Dhaka": "heure du Bangladesh (Dhaka)", + "Asia\/Dili": "heure du Timor oriental (Dili)", + "Asia\/Dubai": "heure du Golfe (Dubaï)", + "Asia\/Dushanbe": "heure du Tadjikistan (Douchanbé)", + "Asia\/Famagusta": "heure d’Europe de l’Est (Famagouste)", + "Asia\/Gaza": "heure d’Europe de l’Est (Gaza)", + "Asia\/Hebron": "heure d’Europe de l’Est (Hébron)", + "Asia\/Hong_Kong": "heure de Hong Kong (Hong Kong)", + "Asia\/Hovd": "heure de Hovd (Hovd)", + "Asia\/Irkutsk": "heure d’Irkoutsk (Irkoutsk)", + "Asia\/Jakarta": "heure de l’Ouest indonésien (Jakarta)", + "Asia\/Jayapura": "heure de l’Est indonésien (Jayapura)", + "Asia\/Jerusalem": "heure d’Israël (Jérusalem)", + "Asia\/Kabul": "heure de l’Afghanistan (Kaboul)", + "Asia\/Kamchatka": "heure de Petropavlovsk-Kamchatski (Kamtchatka)", + "Asia\/Karachi": "heure du Pakistan (Karachi)", + "Asia\/Katmandu": "heure du Népal (Katmandou)", + "Asia\/Khandyga": "heure de Iakoutsk (Khandyga)", + "Asia\/Krasnoyarsk": "heure de Krasnoïarsk (Krasnoïarsk)", + "Asia\/Kuala_Lumpur": "heure de la Malaisie (Kuala Lumpur)", + "Asia\/Kuching": "heure de la Malaisie (Kuching)", + "Asia\/Kuwait": "heure de l’Arabie (Koweït)", + "Asia\/Macau": "heure de la Chine (Macao)", + "Asia\/Magadan": "heure de Magadan (Magadan)", + "Asia\/Makassar": "heure du Centre indonésien (Macassar)", + "Asia\/Manila": "heure des Philippines (Manille)", + "Asia\/Muscat": "heure du Golfe (Mascate)", + "Asia\/Nicosia": "heure d’Europe de l’Est (Nicosie)", + "Asia\/Novokuznetsk": "heure de Krasnoïarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "heure de Novossibirsk (Novossibirsk)", + "Asia\/Omsk": "heure de Omsk (Omsk)", + "Asia\/Oral": "heure de l’Ouest du Kazakhstan (Ouralsk)", + "Asia\/Phnom_Penh": "heure d’Indochine (Phnom Penh)", + "Asia\/Pontianak": "heure de l’Ouest indonésien (Pontianak)", + "Asia\/Pyongyang": "heure de la Corée (Pyongyang)", + "Asia\/Qatar": "heure de l’Arabie (Qatar)", + "Asia\/Qostanay": "heure de l’Est du Kazakhstan (Kostanaï)", + "Asia\/Qyzylorda": "heure de l’Ouest du Kazakhstan (Kzyl Orda)", + "Asia\/Rangoon": "heure du Myanmar (Rangoun)", + "Asia\/Riyadh": "heure de l’Arabie (Riyad)", + "Asia\/Saigon": "heure d’Indochine (Hô-Chi-Minh-Ville)", + "Asia\/Sakhalin": "heure de Sakhaline (Sakhaline)", + "Asia\/Samarkand": "heure de l’Ouzbékistan (Samarcande)", + "Asia\/Seoul": "heure de la Corée (Séoul)", + "Asia\/Shanghai": "heure de la Chine (Shanghai)", + "Asia\/Singapore": "heure de Singapour (Singapour)", + "Asia\/Srednekolymsk": "heure de Magadan (Srednekolymsk)", + "Asia\/Taipei": "heure de Taipei (Taipei)", + "Asia\/Tashkent": "heure de l’Ouzbékistan (Tachkent)", + "Asia\/Tbilisi": "heure de la Géorgie (Tbilissi)", + "Asia\/Tehran": "heure de l’Iran (Téhéran)", + "Asia\/Thimphu": "heure du Bhoutan (Thimphu)", + "Asia\/Tokyo": "heure du Japon (Tokyo)", + "Asia\/Ulaanbaatar": "heure d’Oulan-Bator (Oulan-Bator)", + "Asia\/Ust-Nera": "heure de Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "heure d’Indochine (Vientiane)", + "Asia\/Vladivostok": "heure de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "heure de Iakoutsk (Iakoutsk)", + "Asia\/Yekaterinburg": "heure d’Ekaterinbourg (Ekaterinbourg)", + "Asia\/Yerevan": "heure de l’Arménie (Erevan)", + "Atlantic\/Azores": "heure des Açores (Açores)", + "Atlantic\/Bermuda": "heure de l’Atlantique (Bermudes)", + "Atlantic\/Canary": "heure d’Europe de l’Ouest (Îles Canaries)", + "Atlantic\/Cape_Verde": "heure du Cap-Vert (Cap-Vert)", + "Atlantic\/Faeroe": "heure d’Europe de l’Ouest (Féroé)", + "Atlantic\/Madeira": "heure d’Europe de l’Ouest (Madère)", + "Atlantic\/Reykjavik": "heure moyenne de Greenwich (Reykjavik)", + "Atlantic\/South_Georgia": "heure de Géorgie du Sud (Géorgie du Sud)", + "Atlantic\/St_Helena": "heure moyenne de Greenwich (Sainte-Hélène)", + "Atlantic\/Stanley": "heure des îles Malouines (Stanley)", + "Australia\/Adelaide": "heure du centre de l’Australie (Adélaïde)", + "Australia\/Brisbane": "heure de l’Est de l’Australie (Brisbane)", + "Australia\/Broken_Hill": "heure du centre de l’Australie (Broken Hill)", + "Australia\/Currie": "heure de l’Est de l’Australie (Currie)", + "Australia\/Darwin": "heure du centre de l’Australie (Darwin)", + "Australia\/Eucla": "heure du centre-ouest de l’Australie (Eucla)", + "Australia\/Hobart": "heure de l’Est de l’Australie (Hobart)", + "Australia\/Lindeman": "heure de l’Est de l’Australie (Lindeman)", + "Australia\/Lord_Howe": "heure de Lord Howe (Lord Howe)", + "Australia\/Melbourne": "heure de l’Est de l’Australie (Melbourne)", + "Australia\/Perth": "heure de l’Ouest de l’Australie (Perth)", + "Australia\/Sydney": "heure de l’Est de l’Australie (Sydney)", + "CST6CDT": "heure du centre nord-américain", + "EST5EDT": "heure de l’Est nord-américain", + "Etc\/GMT": "heure moyenne de Greenwich", + "Etc\/UTC": "Temps universel coordonné", + "Europe\/Amsterdam": "heure d’Europe centrale (Amsterdam)", + "Europe\/Andorra": "heure d’Europe centrale (Andorre)", + "Europe\/Astrakhan": "heure de Moscou (Astrakhan)", + "Europe\/Athens": "heure d’Europe de l’Est (Athènes)", + "Europe\/Belgrade": "heure d’Europe centrale (Belgrade)", + "Europe\/Berlin": "heure d’Europe centrale (Berlin)", + "Europe\/Bratislava": "heure d’Europe centrale (Bratislava)", + "Europe\/Brussels": "heure d’Europe centrale (Bruxelles)", + "Europe\/Bucharest": "heure d’Europe de l’Est (Bucarest)", + "Europe\/Budapest": "heure d’Europe centrale (Budapest)", + "Europe\/Busingen": "heure d’Europe centrale (Büsingen)", + "Europe\/Chisinau": "heure d’Europe de l’Est (Chisinau)", + "Europe\/Copenhagen": "heure d’Europe centrale (Copenhague)", + "Europe\/Dublin": "heure moyenne de Greenwich (Dublin)", + "Europe\/Gibraltar": "heure d’Europe centrale (Gibraltar)", + "Europe\/Guernsey": "heure moyenne de Greenwich (Guernesey)", + "Europe\/Helsinki": "heure d’Europe de l’Est (Helsinki)", + "Europe\/Isle_of_Man": "heure moyenne de Greenwich (Île de Man)", + "Europe\/Jersey": "heure moyenne de Greenwich (Jersey)", + "Europe\/Kaliningrad": "heure d’Europe de l’Est (Kaliningrad)", + "Europe\/Kiev": "heure d’Europe de l’Est (Kiev)", + "Europe\/Lisbon": "heure d’Europe de l’Ouest (Lisbonne)", + "Europe\/Ljubljana": "heure d’Europe centrale (Ljubljana)", + "Europe\/London": "heure moyenne de Greenwich (Londres)", + "Europe\/Luxembourg": "heure d’Europe centrale (Luxembourg)", + "Europe\/Madrid": "heure d’Europe centrale (Madrid)", + "Europe\/Malta": "heure d’Europe centrale (Malte)", + "Europe\/Mariehamn": "heure d’Europe de l’Est (Mariehamn)", + "Europe\/Minsk": "heure de Moscou (Minsk)", + "Europe\/Monaco": "heure d’Europe centrale (Monaco)", + "Europe\/Moscow": "heure de Moscou (Moscou)", + "Europe\/Oslo": "heure d’Europe centrale (Oslo)", + "Europe\/Paris": "heure d’Europe centrale (Paris)", + "Europe\/Podgorica": "heure d’Europe centrale (Podgorica)", + "Europe\/Prague": "heure d’Europe centrale (Prague)", + "Europe\/Riga": "heure d’Europe de l’Est (Riga)", + "Europe\/Rome": "heure d’Europe centrale (Rome)", + "Europe\/Samara": "heure de Samara (Samara)", + "Europe\/San_Marino": "heure d’Europe centrale (Saint-Marin)", + "Europe\/Sarajevo": "heure d’Europe centrale (Sarajevo)", + "Europe\/Saratov": "heure de Moscou (Saratov)", + "Europe\/Simferopol": "heure de Moscou (Simferopol)", + "Europe\/Skopje": "heure d’Europe centrale (Skopje)", + "Europe\/Sofia": "heure d’Europe de l’Est (Sofia)", + "Europe\/Stockholm": "heure d’Europe centrale (Stockholm)", + "Europe\/Tallinn": "heure d’Europe de l’Est (Tallinn)", + "Europe\/Tirane": "heure d’Europe centrale (Tirana)", + "Europe\/Ulyanovsk": "heure de Moscou (Oulianovsk)", + "Europe\/Uzhgorod": "heure d’Europe de l’Est (Oujgorod)", + "Europe\/Vaduz": "heure d’Europe centrale (Vaduz)", + "Europe\/Vatican": "heure d’Europe centrale (Le Vatican)", + "Europe\/Vienna": "heure d’Europe centrale (Vienne)", + "Europe\/Vilnius": "heure d’Europe de l’Est (Vilnius)", + "Europe\/Volgograd": "heure de Volgograd (Volgograd)", + "Europe\/Warsaw": "heure d’Europe centrale (Varsovie)", + "Europe\/Zagreb": "heure d’Europe centrale (Zagreb)", + "Europe\/Zaporozhye": "heure d’Europe de l’Est (Zaporojie)", + "Europe\/Zurich": "heure d’Europe centrale (Zurich)", + "Indian\/Antananarivo": "heure normale d’Afrique de l’Est (Antananarivo)", + "Indian\/Chagos": "heure de l’Océan Indien (Chagos)", + "Indian\/Christmas": "heure de l’île Christmas (Christmas)", + "Indian\/Cocos": "heure des îles Cocos (Cocos)", + "Indian\/Comoro": "heure normale d’Afrique de l’Est (Comores)", + "Indian\/Kerguelen": "heure des Terres australes et antarctiques françaises (Kerguelen)", + "Indian\/Mahe": "heure des Seychelles (Mahé)", + "Indian\/Maldives": "heure des Maldives (Maldives)", + "Indian\/Mauritius": "heure de Maurice (Maurice)", + "Indian\/Mayotte": "heure normale d’Afrique de l’Est (Mayotte)", + "Indian\/Reunion": "heure de La Réunion (La Réunion)", + "MST7MDT": "heure des Rocheuses", + "PST8PDT": "heure du Pacifique nord-américain", + "Pacific\/Apia": "heure d’Apia (Apia)", + "Pacific\/Auckland": "heure de la Nouvelle-Zélande (Auckland)", + "Pacific\/Bougainville": "heure de la Papouasie-Nouvelle-Guinée (Bougainville)", + "Pacific\/Chatham": "heure des îles Chatham (Chatham)", + "Pacific\/Easter": "heure de l’île de Pâques (Île de Pâques)", + "Pacific\/Efate": "heure du Vanuatu (Éfaté)", + "Pacific\/Enderbury": "heure des îles Phoenix (Enderbury)", + "Pacific\/Fakaofo": "heure de Tokelau (Fakaofo)", + "Pacific\/Fiji": "heure des îles Fidji (Fidji)", + "Pacific\/Funafuti": "heure des Tuvalu (Funafuti)", + "Pacific\/Galapagos": "heure des îles Galápagos (Galápagos)", + "Pacific\/Gambier": "heure des îles Gambier (Gambier)", + "Pacific\/Guadalcanal": "heure des îles Salomon (Guadalcanal)", + "Pacific\/Guam": "heure des Chamorro (Guam)", + "Pacific\/Honolulu": "heure d’Hawaii - Aléoutiennes (Honolulu)", + "Pacific\/Johnston": "heure d’Hawaii - Aléoutiennes (Johnston)", + "Pacific\/Kiritimati": "heure des îles de la Ligne (Kiritimati)", + "Pacific\/Kosrae": "heure de Kosrae (Kosrae)", + "Pacific\/Kwajalein": "heure des îles Marshall (Kwajalein)", + "Pacific\/Majuro": "heure des îles Marshall (Majuro)", + "Pacific\/Marquesas": "heure des îles Marquises (Marquises)", + "Pacific\/Midway": "heure des Samoa (Midway)", + "Pacific\/Nauru": "heure de Nauru (Nauru)", + "Pacific\/Niue": "heure de Nioué (Niue)", + "Pacific\/Norfolk": "heure de l’île Norfolk (Norfolk)", + "Pacific\/Noumea": "heure de la Nouvelle-Calédonie (Nouméa)", + "Pacific\/Pago_Pago": "heure des Samoa (Pago Pago)", + "Pacific\/Palau": "heure des Palaos (Palau)", + "Pacific\/Pitcairn": "heure des îles Pitcairn (Pitcairn)", + "Pacific\/Ponape": "heure de l’île de Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "heure de la Papouasie-Nouvelle-Guinée (Port Moresby)", + "Pacific\/Rarotonga": "heure des îles Cook (Rarotonga)", + "Pacific\/Saipan": "heure des Chamorro (Saipan)", + "Pacific\/Tahiti": "heure de Tahiti (Tahiti)", + "Pacific\/Tarawa": "heure des îles Gilbert (Tarawa)", + "Pacific\/Tongatapu": "heure des Tonga (Tongatapu)", + "Pacific\/Truk": "heure de Chuuk (Chuuk)", + "Pacific\/Wake": "heure de l’île Wake (Wake)", + "Pacific\/Wallis": "heure de Wallis-et-Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fr_CA.json b/src/Symfony/Component/Intl/Resources/data/timezones/fr_CA.json new file mode 100644 index 0000000000000..d4a3c4083925a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fr_CA.json @@ -0,0 +1,334 @@ +{ + "Version": "2.1.47.86", + "Names": { + "Africa\/Addis_Ababa": "heure d’Afrique orientale (Addis Ababa)", + "Africa\/Algiers": "heure d’Europe centrale (Algiers)", + "Africa\/Asmera": "heure d’Afrique orientale (Asmara)", + "Africa\/Bangui": "heure d’Afrique de l’Ouest (Bangui)", + "Africa\/Blantyre": "heure d’Afrique centrale (Blantyre)", + "Africa\/Brazzaville": "heure d’Afrique de l’Ouest (Brazzaville)", + "Africa\/Bujumbura": "heure d’Afrique centrale (Bujumbura)", + "Africa\/Cairo": "heure d’Europe de l’Est (Cairo)", + "Africa\/Casablanca": "heure d’Europe de l’Ouest (Casablanca)", + "Africa\/Ceuta": "heure d’Europe centrale (Ceuta)", + "Africa\/Dar_es_Salaam": "heure d’Afrique orientale (Dar es Salaam)", + "Africa\/Djibouti": "heure d’Afrique orientale (Djibouti)", + "Africa\/Douala": "heure d’Afrique de l’Ouest (Douala)", + "Africa\/El_Aaiun": "heure d’Europe de l’Ouest (El Aaiun)", + "Africa\/Gaborone": "heure d’Afrique centrale (Gaborone)", + "Africa\/Harare": "heure d’Afrique centrale (Harare)", + "Africa\/Johannesburg": "heure normale d’Afrique du Sud (Johannesburg)", + "Africa\/Juba": "heure d’Afrique orientale (Juba)", + "Africa\/Kampala": "heure d’Afrique orientale (Kampala)", + "Africa\/Khartoum": "heure d’Afrique centrale (Khartoum)", + "Africa\/Kigali": "heure d’Afrique centrale (Kigali)", + "Africa\/Kinshasa": "heure d’Afrique de l’Ouest (Kinshasa)", + "Africa\/Lagos": "heure d’Afrique de l’Ouest (Lagos)", + "Africa\/Libreville": "heure d’Afrique de l’Ouest (Libreville)", + "Africa\/Luanda": "heure d’Afrique de l’Ouest (Luanda)", + "Africa\/Lubumbashi": "heure d’Afrique centrale (Lubumbashi)", + "Africa\/Lusaka": "heure d’Afrique centrale (Lusaka)", + "Africa\/Malabo": "heure d’Afrique de l’Ouest (Malabo)", + "Africa\/Maputo": "heure d’Afrique centrale (Maputo)", + "Africa\/Maseru": "heure normale d’Afrique du Sud (Maseru)", + "Africa\/Mbabane": "heure normale d’Afrique du Sud (Mbabane)", + "Africa\/Mogadishu": "heure d’Afrique orientale (Mogadishu)", + "Africa\/Nairobi": "heure d’Afrique orientale (Nairobi)", + "Africa\/Ndjamena": "heure d’Afrique de l’Ouest (Ndjamena)", + "Africa\/Niamey": "heure d’Afrique de l’Ouest (Niamey)", + "Africa\/Porto-Novo": "heure d’Afrique de l’Ouest (Porto-Novo)", + "Africa\/Tripoli": "heure d’Europe de l’Est (Tripoli [Libye])", + "Africa\/Tunis": "heure d’Europe centrale (Tunis)", + "Africa\/Windhoek": "heure d’Afrique centrale (Windhoek)", + "America\/Adak": "heure d’Hawaï-Aléoutiennes (Adak)", + "America\/Anchorage": "heure de l’Alaska (Anchorage)", + "America\/Anguilla": "heure de l’Atlantique (Anguilla)", + "America\/Antigua": "heure de l’Atlantique (Antigua)", + "America\/Araguaina": "heure de Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "heure de l’Argentine (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "heure de l’Argentine (Rio Gallegos)", + "America\/Argentina\/Salta": "heure de l’Argentine (Salta)", + "America\/Argentina\/San_Juan": "heure de l’Argentine (San Juan)", + "America\/Argentina\/San_Luis": "heure de l’Ouest argentin (San Luis)", + "America\/Argentina\/Tucuman": "heure de l’Argentine (Tucuman)", + "America\/Argentina\/Ushuaia": "heure de l’Argentine (Ushuaia)", + "America\/Aruba": "heure de l’Atlantique (Aruba)", + "America\/Asuncion": "heure du Paraguay (Asuncion)", + "America\/Bahia": "heure de Brasilia (Bahia)", + "America\/Bahia_Banderas": "heure du Centre (Bahia Banderas)", + "America\/Barbados": "heure de l’Atlantique (Barbade (La))", + "America\/Belem": "heure de Brasilia (Belem)", + "America\/Belize": "heure du Centre (Belize)", + "America\/Blanc-Sablon": "heure de l’Atlantique (Blanc-Sablon)", + "America\/Boa_Vista": "heure de l’Amazonie (Boa Vista)", + "America\/Bogota": "heure de Colombie (Bogota)", + "America\/Boise": "heure des Rocheuses (Boise)", + "America\/Buenos_Aires": "heure de l’Argentine (Buenos Aires)", + "America\/Cambridge_Bay": "heure des Rocheuses (Cambridge Bay)", + "America\/Campo_Grande": "heure de l’Amazonie (Campo Grande)", + "America\/Cancun": "heure de l’Est (Cancun)", + "America\/Catamarca": "heure de l’Argentine (Catamarca)", + "America\/Cayenne": "heure de Guyane française (Cayenne)", + "America\/Cayman": "heure de l’Est (îles Caïmans)", + "America\/Chicago": "heure du Centre (Chicago)", + "America\/Chihuahua": "heure du Pacifique mexicain (Chihuahua)", + "America\/Coral_Harbour": "heure de l’Est (Atikokan)", + "America\/Cordoba": "heure de l’Argentine (Cordoba)", + "America\/Costa_Rica": "heure du Centre (Costa Rica)", + "America\/Creston": "heure des Rocheuses (Creston)", + "America\/Cuiaba": "heure de l’Amazonie (Cuiaba)", + "America\/Curacao": "heure de l’Atlantique (Curacao)", + "America\/Dawson": "heure du Pacifique (Dawson)", + "America\/Dawson_Creek": "heure des Rocheuses (Dawson Creek)", + "America\/Denver": "heure des Rocheuses (Denver)", + "America\/Detroit": "heure de l’Est (Detroit)", + "America\/Dominica": "heure de l’Atlantique (Dominica)", + "America\/Edmonton": "heure des Rocheuses (Edmonton)", + "America\/Eirunepe": "heure de l’Acre (Eirunepe)", + "America\/El_Salvador": "heure du Centre (El Salvador)", + "America\/Fort_Nelson": "heure des Rocheuses (Fort Nelson)", + "America\/Fortaleza": "heure de Brasilia (Fortaleza)", + "America\/Glace_Bay": "heure de l’Atlantique (Glace Bay)", + "America\/Godthab": "heure de l’Ouest du Groenland (Nuuk)", + "America\/Goose_Bay": "heure de l’Atlantique (Goose Bay)", + "America\/Grand_Turk": "heure de l’Est (Grand Turk)", + "America\/Grenada": "heure de l’Atlantique (Grenada)", + "America\/Guadeloupe": "heure de l’Atlantique (Guadeloupe)", + "America\/Guatemala": "heure du Centre (Guatemala)", + "America\/Halifax": "heure de l’Atlantique (Halifax)", + "America\/Havana": "heure de Cuba (Havana)", + "America\/Hermosillo": "heure du Pacifique mexicain (Hermosillo)", + "America\/Indiana\/Knox": "heure du Centre (Knox, Indiana)", + "America\/Indiana\/Marengo": "heure de l’Est (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "heure de l’Est (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "heure du Centre (Tell City, Indiana)", + "America\/Indiana\/Vevay": "heure de l’Est (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "heure de l’Est (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "heure de l’Est (Winamac, Indiana)", + "America\/Indianapolis": "heure de l’Est (Indianapolis)", + "America\/Inuvik": "heure des Rocheuses (Inuvik)", + "America\/Iqaluit": "heure de l’Est (Iqaluit)", + "America\/Jamaica": "heure de l’Est (Jamaica)", + "America\/Jujuy": "heure de l’Argentine (Jujuy)", + "America\/Juneau": "heure de l’Alaska (Juneau)", + "America\/Kentucky\/Monticello": "heure de l’Est (Monticello, Kentucky)", + "America\/Kralendijk": "heure de l’Atlantique (Kralendijk)", + "America\/Lima": "heure du Pérou (Lima)", + "America\/Los_Angeles": "heure du Pacifique (Los Angeles)", + "America\/Louisville": "heure de l’Est (Louisville)", + "America\/Lower_Princes": "heure de l’Atlantique (Lower Prince’s Quarter)", + "America\/Maceio": "heure de Brasilia (Maceio)", + "America\/Managua": "heure du Centre (Managua)", + "America\/Manaus": "heure de l’Amazonie (Manaus)", + "America\/Marigot": "heure de l’Atlantique (Marigot)", + "America\/Martinique": "heure de l’Atlantique (Martinique)", + "America\/Matamoros": "heure du Centre (Matamoros)", + "America\/Mazatlan": "heure du Pacifique mexicain (Mazatlan)", + "America\/Mendoza": "heure de l’Argentine (Mendoza)", + "America\/Menominee": "heure du Centre (Menominee)", + "America\/Merida": "heure du Centre (Merida)", + "America\/Metlakatla": "heure de l’Alaska (Metlakatla)", + "America\/Mexico_City": "heure du Centre (Mexico City)", + "America\/Miquelon": "heure de Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "heure de l’Atlantique (Moncton)", + "America\/Monterrey": "heure du Centre (Monterrey)", + "America\/Montevideo": "heure de l’Uruguay (Montevideo)", + "America\/Montserrat": "heure de l’Atlantique (Montserrat)", + "America\/Nassau": "heure de l’Est (Nassau)", + "America\/New_York": "heure de l’Est (New York)", + "America\/Nipigon": "heure de l’Est (Nipigon)", + "America\/Nome": "heure de l’Alaska (Nome)", + "America\/Noronha": "heure de Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "heure du Centre (Beulah [Dakota du Nord])", + "America\/North_Dakota\/Center": "heure du Centre (Center [Dakota du Nord])", + "America\/North_Dakota\/New_Salem": "heure du Centre (New Salem, Dakota du Nord)", + "America\/Ojinaga": "heure des Rocheuses (Ojinaga)", + "America\/Panama": "heure de l’Est (Panama)", + "America\/Pangnirtung": "heure de l’Est (Pangnirtung)", + "America\/Phoenix": "heure des Rocheuses (Phoenix)", + "America\/Port-au-Prince": "heure de l’Est (Port-au-Prince)", + "America\/Port_of_Spain": "heure de l’Atlantique (Port of Spain)", + "America\/Porto_Velho": "heure de l’Amazonie (Porto Velho)", + "America\/Puerto_Rico": "heure de l’Atlantique (Puerto Rico)", + "America\/Punta_Arenas": "heure du Chili (Punta Arenas)", + "America\/Rainy_River": "heure du Centre (Rainy River)", + "America\/Rankin_Inlet": "heure du Centre (Rankin Inlet)", + "America\/Recife": "heure de Brasilia (Recife)", + "America\/Regina": "heure du Centre (Regina)", + "America\/Resolute": "heure du Centre (Resolute)", + "America\/Rio_Branco": "heure de l’Acre (Rio Branco)", + "America\/Santa_Isabel": "heure du Nord-Ouest du Mexique (Santa Isabel)", + "America\/Santarem": "heure de Brasilia (Santarem)", + "America\/Santiago": "heure du Chili (Santiago)", + "America\/Santo_Domingo": "heure de l’Atlantique (Santo Domingo)", + "America\/Sao_Paulo": "heure de Brasilia (Sao Paulo)", + "America\/Scoresbysund": "heure de l’Est du Groenland (Ittoqqortoormiit)", + "America\/Sitka": "heure de l’Alaska (Sitka)", + "America\/St_Barthelemy": "heure de l’Atlantique (St. Barthelemy)", + "America\/St_Johns": "heure de Terre-Neuve (St. John’s)", + "America\/St_Kitts": "heure de l’Atlantique (Saint-Christophe-et-Niévès)", + "America\/St_Lucia": "heure de l’Atlantique (St. Lucia)", + "America\/St_Thomas": "heure de l’Atlantique (Saint Thomas)", + "America\/St_Vincent": "heure de l’Atlantique (St. Vincent)", + "America\/Swift_Current": "heure du Centre (Swift Current)", + "America\/Tegucigalpa": "heure du Centre (Tegucigalpa)", + "America\/Thule": "heure de l’Atlantique (Thule)", + "America\/Thunder_Bay": "heure de l’Est (Thunder Bay)", + "America\/Tijuana": "heure du Pacifique (Tijuana)", + "America\/Toronto": "heure de l’Est (Toronto)", + "America\/Tortola": "heure de l’Atlantique (Tortola)", + "America\/Vancouver": "heure du Pacifique (Vancouver)", + "America\/Whitehorse": "heure du Pacifique (Whitehorse)", + "America\/Winnipeg": "heure du Centre (Winnipeg)", + "America\/Yakutat": "heure de l’Alaska (Yakutat)", + "America\/Yellowknife": "heure des Rocheuses (Yellowknife)", + "Antarctica\/Casey": "heure de l’Ouest de l’Australie (Casey)", + "Antarctica\/McMurdo": "heure de la Nouvelle-Zélande (McMurdo)", + "Antarctica\/Palmer": "heure du Chili (Palmer)", + "Arctic\/Longyearbyen": "heure d’Europe centrale (Longyearbyen)", + "Asia\/Aden": "heure de l’Arabie (Aden)", + "Asia\/Amman": "heure d’Europe de l’Est (Amman)", + "Asia\/Anadyr": "heure d’Anadyr (Anadyr)", + "Asia\/Ashgabat": "heure du Turkménistan (Ashgabat)", + "Asia\/Baghdad": "heure de l’Arabie (Baghdad)", + "Asia\/Bahrain": "heure de l’Arabie (Bahrain)", + "Asia\/Baku": "heure de l’Azerbaïdjan (Baku)", + "Asia\/Beirut": "heure d’Europe de l’Est (Beirut)", + "Asia\/Chita": "heure de Iakoutsk (Chita)", + "Asia\/Choibalsan": "heure de Choibalsan (Choibalsan)", + "Asia\/Damascus": "heure d’Europe de l’Est (Damascus)", + "Asia\/Dhaka": "heure du Bangladesh (Dacca)", + "Asia\/Famagusta": "heure d’Europe de l’Est (Famagusta)", + "Asia\/Gaza": "heure d’Europe de l’Est (Gaza)", + "Asia\/Hebron": "heure d’Europe de l’Est (Hebron)", + "Asia\/Hong_Kong": "heure de Hong Kong (Hong Kong)", + "Asia\/Hovd": "heure de Hovd (Hovd)", + "Asia\/Irkutsk": "heure d’Irkoutsk (Irkutsk)", + "Asia\/Jerusalem": "heure d’Israël (Jerusalem)", + "Asia\/Kamchatka": "heure de Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "heure du Pakistan (Karachi)", + "Asia\/Khandyga": "heure de Iakoutsk (Khandyga)", + "Asia\/Krasnoyarsk": "heure de Krasnoïarsk (Krasnoyarsk)", + "Asia\/Kuwait": "heure de l’Arabie (Kuwait)", + "Asia\/Macau": "heure de Chine (Macao)", + "Asia\/Magadan": "heure de Magadan (Magadan)", + "Asia\/Manila": "heure des Philippines (Manila)", + "Asia\/Nicosia": "heure d’Europe de l’Est (Nicosia)", + "Asia\/Novokuznetsk": "heure de Krasnoïarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "heure de Novossibirsk (Novosibirsk)", + "Asia\/Omsk": "heure d’Omsk (Omsk)", + "Asia\/Pyongyang": "heure de la Corée (Pyongyang)", + "Asia\/Qatar": "heure de l’Arabie (Qatar)", + "Asia\/Riyadh": "heure de l’Arabie (Riyadh)", + "Asia\/Sakhalin": "heure de Sakhaline (Sakhalin)", + "Asia\/Samarkand": "heure de l’Ouzbékistan (Samarkand)", + "Asia\/Seoul": "heure de la Corée (Seoul)", + "Asia\/Shanghai": "heure de Chine (Shanghai)", + "Asia\/Srednekolymsk": "heure de Magadan (Srednekolymsk)", + "Asia\/Taipei": "heure de Taipei (Taipei)", + "Asia\/Tashkent": "heure de l’Ouzbékistan (Tashkent)", + "Asia\/Tbilisi": "heure de la Géorgie (Tbilisi)", + "Asia\/Tehran": "heure de l’Iran (Tehran)", + "Asia\/Tokyo": "heure du Japon (Tokyo)", + "Asia\/Ulaanbaatar": "heure d’Oulan-Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "heure de Vladivostok (Ust-Nera)", + "Asia\/Vladivostok": "heure de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "heure de Iakoutsk (Yakutsk)", + "Asia\/Yekaterinburg": "heure d’Ekaterinbourg (Yekaterinburg)", + "Asia\/Yerevan": "heure de l’Arménie (Yerevan)", + "Atlantic\/Azores": "heure des Açores (Azores)", + "Atlantic\/Bermuda": "heure de l’Atlantique (Bermuda)", + "Atlantic\/Canary": "heure d’Europe de l’Ouest (îles Canaries)", + "Atlantic\/Cape_Verde": "heure du Cap-Vert (Cape Verde)", + "Atlantic\/Faeroe": "heure d’Europe de l’Ouest (îles Féroé)", + "Atlantic\/Madeira": "heure d’Europe de l’Ouest (Madeira)", + "Atlantic\/Stanley": "heure des îles Malouines (Stanley)", + "Australia\/Adelaide": "heure du centre de l’Australie (Adelaide)", + "Australia\/Brisbane": "heure de l’Est de l’Australie (Brisbane)", + "Australia\/Broken_Hill": "heure du centre de l’Australie (Broken Hill)", + "Australia\/Currie": "heure de l’Est de l’Australie (Currie)", + "Australia\/Darwin": "heure du centre de l’Australie (Darwin)", + "Australia\/Eucla": "heure du centre-ouest de l’Australie (Eucla)", + "Australia\/Hobart": "heure de l’Est de l’Australie (Hobart)", + "Australia\/Lindeman": "heure de l’Est de l’Australie (Lindeman)", + "Australia\/Lord_Howe": "heure de Lord Howe (Lord Howe)", + "Australia\/Melbourne": "heure de l’Est de l’Australie (Melbourne)", + "Australia\/Perth": "heure de l’Ouest de l’Australie (Perth)", + "Australia\/Sydney": "heure de l’Est de l’Australie (Sydney)", + "CST6CDT": "heure du Centre", + "EST5EDT": "heure de l’Est", + "Etc\/UTC": "temps universel coordonné", + "Europe\/Amsterdam": "heure d’Europe centrale (Amsterdam)", + "Europe\/Andorra": "heure d’Europe centrale (Andorra)", + "Europe\/Astrakhan": "heure de Moscou (Astrakhan)", + "Europe\/Athens": "heure d’Europe de l’Est (Athens)", + "Europe\/Belgrade": "heure d’Europe centrale (Belgrade)", + "Europe\/Berlin": "heure d’Europe centrale (Berlin)", + "Europe\/Bratislava": "heure d’Europe centrale (Bratislava)", + "Europe\/Brussels": "heure d’Europe centrale (Brussels)", + "Europe\/Bucharest": "heure d’Europe de l’Est (Bucharest)", + "Europe\/Budapest": "heure d’Europe centrale (Budapest)", + "Europe\/Busingen": "heure d’Europe centrale (Busingen)", + "Europe\/Chisinau": "heure d’Europe de l’Est (Chisinau)", + "Europe\/Copenhagen": "heure d’Europe centrale (Copenhagen)", + "Europe\/Gibraltar": "heure d’Europe centrale (Gibraltar)", + "Europe\/Helsinki": "heure d’Europe de l’Est (Helsinki)", + "Europe\/Kaliningrad": "heure d’Europe de l’Est (Kaliningrad)", + "Europe\/Kiev": "heure d’Europe de l’Est (Kiev)", + "Europe\/Lisbon": "heure d’Europe de l’Ouest (Lisbon)", + "Europe\/Ljubljana": "heure d’Europe centrale (Ljubljana)", + "Europe\/Luxembourg": "heure d’Europe centrale (Luxembourg)", + "Europe\/Madrid": "heure d’Europe centrale (Madrid)", + "Europe\/Malta": "heure d’Europe centrale (Malta)", + "Europe\/Mariehamn": "heure d’Europe de l’Est (Mariehamn)", + "Europe\/Minsk": "heure de Moscou (Minsk)", + "Europe\/Monaco": "heure d’Europe centrale (Monaco)", + "Europe\/Moscow": "heure de Moscou (Moscow)", + "Europe\/Oslo": "heure d’Europe centrale (Oslo)", + "Europe\/Paris": "heure d’Europe centrale (Paris)", + "Europe\/Podgorica": "heure d’Europe centrale (Podgorica)", + "Europe\/Prague": "heure d’Europe centrale (Prague)", + "Europe\/Riga": "heure d’Europe de l’Est (Riga)", + "Europe\/Rome": "heure d’Europe centrale (Rome)", + "Europe\/San_Marino": "heure d’Europe centrale (San Marino)", + "Europe\/Sarajevo": "heure d’Europe centrale (Sarajevo)", + "Europe\/Saratov": "heure de Moscou (Saratov)", + "Europe\/Simferopol": "heure de Moscou (Simferopol)", + "Europe\/Skopje": "heure d’Europe centrale (Skopje)", + "Europe\/Sofia": "heure d’Europe de l’Est (Sofia)", + "Europe\/Stockholm": "heure d’Europe centrale (Stockholm)", + "Europe\/Tallinn": "heure d’Europe de l’Est (Tallinn)", + "Europe\/Tirane": "heure d’Europe centrale (Tirane)", + "Europe\/Ulyanovsk": "heure de Moscou (Ulyanovsk)", + "Europe\/Uzhgorod": "heure d’Europe de l’Est (Uzhgorod)", + "Europe\/Vaduz": "heure d’Europe centrale (Vaduz)", + "Europe\/Vatican": "heure d’Europe centrale (Vatican)", + "Europe\/Vienna": "heure d’Europe centrale (Vienna)", + "Europe\/Vilnius": "heure d’Europe de l’Est (Vilnius)", + "Europe\/Volgograd": "heure de Volgograd (Volgograd)", + "Europe\/Warsaw": "heure d’Europe centrale (Warsaw)", + "Europe\/Zagreb": "heure d’Europe centrale (Zagreb)", + "Europe\/Zaporozhye": "heure d’Europe de l’Est (Zaporozhye)", + "Europe\/Zurich": "heure d’Europe centrale (Zurich)", + "Indian\/Antananarivo": "heure d’Afrique orientale (Antananarivo)", + "Indian\/Comoro": "heure d’Afrique orientale (Comoro)", + "Indian\/Mauritius": "heure de Maurice (Mauritius)", + "Indian\/Mayotte": "heure d’Afrique orientale (Mayotte)", + "Indian\/Reunion": "heure de la Réunion (Reunion)", + "MST7MDT": "heure des Rocheuses", + "PST8PDT": "heure du Pacifique", + "Pacific\/Apia": "heure d’Apia (Apia)", + "Pacific\/Auckland": "heure de la Nouvelle-Zélande (Auckland)", + "Pacific\/Chatham": "heure des îles Chatham (Chatham)", + "Pacific\/Easter": "heure de l’île de Pâques (île de Pâques)", + "Pacific\/Efate": "heure du Vanuatu (Efate)", + "Pacific\/Fiji": "heure des îles Fidji (Fiji)", + "Pacific\/Honolulu": "heure d’Hawaï-Aléoutiennes (Honolulu)", + "Pacific\/Johnston": "heure d’Hawaï-Aléoutiennes (Johnston)", + "Pacific\/Midway": "heure des Samoa (Midway)", + "Pacific\/Noumea": "heure de la Nouvelle-Calédonie (Noumea)", + "Pacific\/Pago_Pago": "heure des Samoa (Pago Pago)", + "Pacific\/Rarotonga": "heure des îles Cook (Rarotonga)", + "Pacific\/Tongatapu": "heure des Tonga (Tongatapu)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fr_GF.json b/src/Symfony/Component/Intl/Resources/data/timezones/fr_GF.json new file mode 100644 index 0000000000000..99907ebad699e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fr_GF.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.70", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/fy.json b/src/Symfony/Component/Intl/Resources/data/timezones/fy.json new file mode 100644 index 0000000000000..335437f6d0d76 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/fy.json @@ -0,0 +1,427 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "East-Afrikaanske tiid (Addis Abeba)", + "Africa\/Algiers": "Midden-Europeeske tiid (Algiers)", + "Africa\/Asmera": "East-Afrikaanske tiid (Asmara)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "West-Afrikaanske tiid (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Sintraal-Afrikaanske tiid (Blantyre)", + "Africa\/Brazzaville": "West-Afrikaanske tiid (Brazzaville)", + "Africa\/Bujumbura": "Sintraal-Afrikaanske tiid (Bujumbura)", + "Africa\/Cairo": "East-Europeeske tiid (Caïro)", + "Africa\/Casablanca": "West-Europeeske tiid (Casablanca)", + "Africa\/Ceuta": "Midden-Europeeske tiid (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "East-Afrikaanske tiid (Dar es Salaam)", + "Africa\/Djibouti": "East-Afrikaanske tiid (Djibouti)", + "Africa\/Douala": "West-Afrikaanske tiid (Douala)", + "Africa\/El_Aaiun": "West-Europeeske tiid (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Sintraal-Afrikaanske tiid (Gaborone)", + "Africa\/Harare": "Sintraal-Afrikaanske tiid (Harare)", + "Africa\/Johannesburg": "Sûd-Afrikaanske tiid (Johannesburg)", + "Africa\/Juba": "East-Afrikaanske tiid (Juba)", + "Africa\/Kampala": "East-Afrikaanske tiid (Kampala)", + "Africa\/Khartoum": "Sintraal-Afrikaanske tiid (Khartoem)", + "Africa\/Kigali": "Sintraal-Afrikaanske tiid (Kigali)", + "Africa\/Kinshasa": "West-Afrikaanske tiid (Kinshasa)", + "Africa\/Lagos": "West-Afrikaanske tiid (Lagos)", + "Africa\/Libreville": "West-Afrikaanske tiid (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lomé)", + "Africa\/Luanda": "West-Afrikaanske tiid (Luanda)", + "Africa\/Lubumbashi": "Sintraal-Afrikaanske tiid (Lubumbashi)", + "Africa\/Lusaka": "Sintraal-Afrikaanske tiid (Lusaka)", + "Africa\/Malabo": "West-Afrikaanske tiid (Malabo)", + "Africa\/Maputo": "Sintraal-Afrikaanske tiid (Maputo)", + "Africa\/Maseru": "Sûd-Afrikaanske tiid (Maseru)", + "Africa\/Mbabane": "Sûd-Afrikaanske tiid (Mbabane)", + "Africa\/Mogadishu": "East-Afrikaanske tiid (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "East-Afrikaanske tiid (Nairobi)", + "Africa\/Ndjamena": "West-Afrikaanske tiid (Ndjamena)", + "Africa\/Niamey": "West-Afrikaanske tiid (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "West-Afrikaanske tiid (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tomé)", + "Africa\/Tripoli": "East-Europeeske tiid (Tripoli)", + "Africa\/Tunis": "Midden-Europeeske tiid (Tunis)", + "Africa\/Windhoek": "Sintraal-Afrikaanske tiid (Windhoek)", + "America\/Adak": "Hawaii-Aleoetyske tiid (Adak)", + "America\/Anchorage": "Alaska-tiid (Anchorage)", + "America\/Anguilla": "Atlantic-tiid (Anguilla)", + "America\/Antigua": "Atlantic-tiid (Antigua)", + "America\/Araguaina": "Brazyljaanske tiid (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentynske tiid (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentynske tiid (Río Gallegos)", + "America\/Argentina\/Salta": "Argentynske tiid (Salta)", + "America\/Argentina\/San_Juan": "Argentynske tiid (San Juan)", + "America\/Argentina\/San_Luis": "West-Argentynske tiid (San Luis)", + "America\/Argentina\/Tucuman": "Argentynske tiid (Tucumán)", + "America\/Argentina\/Ushuaia": "Argentynske tiid (Ushuaia)", + "America\/Aruba": "Atlantic-tiid (Aruba)", + "America\/Asuncion": "Paraguayaanske tiid (Asunción)", + "America\/Bahia": "Brazyljaanske tiid (Bahia)", + "America\/Bahia_Banderas": "Central-tiid (Bahía de Banderas)", + "America\/Barbados": "Atlantic-tiid (Barbados)", + "America\/Belem": "Brazyljaanske tiid (Belém)", + "America\/Belize": "Central-tiid (Belize)", + "America\/Blanc-Sablon": "Atlantic-tiid (Blanc-Sablon)", + "America\/Boa_Vista": "Amazone-tiid (Boa Vista)", + "America\/Bogota": "Kolombiaanske tiid (Bogotá)", + "America\/Boise": "Mountain-tiid (Boise)", + "America\/Buenos_Aires": "Argentynske tiid (Buenos Aires)", + "America\/Cambridge_Bay": "Mountain-tiid (Cambridge Bay)", + "America\/Campo_Grande": "Amazone-tiid (Campo Grande)", + "America\/Cancun": "Eastern-tiid (Cancun)", + "America\/Caracas": "Fenezolaanske tiid (Caracas)", + "America\/Catamarca": "Argentynske tiid (Catamarca)", + "America\/Cayenne": "Frâns-Guyaanske tiid (Cayenne)", + "America\/Cayman": "Eastern-tiid (Cayman)", + "America\/Chicago": "Central-tiid (Chicago)", + "America\/Coral_Harbour": "Eastern-tiid (Atikokan)", + "America\/Cordoba": "Argentynske tiid (Córdoba)", + "America\/Costa_Rica": "Central-tiid (Costa Rica)", + "America\/Creston": "Mountain-tiid (Creston)", + "America\/Cuiaba": "Amazone-tiid (Cuiabá)", + "America\/Curacao": "Atlantic-tiid (Curaçao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Pasifik-tiid (Dawson)", + "America\/Dawson_Creek": "Mountain-tiid (Dawson Creek)", + "America\/Denver": "Mountain-tiid (Denver)", + "America\/Detroit": "Eastern-tiid (Detroit)", + "America\/Dominica": "Atlantic-tiid (Dominica)", + "America\/Edmonton": "Mountain-tiid (Edmonton)", + "America\/Eirunepe": "Acre-tiid (Eirunepe)", + "America\/El_Salvador": "Central-tiid (Salvador)", + "America\/Fort_Nelson": "Mountain-tiid (Fort Nelson)", + "America\/Fortaleza": "Brazyljaanske tiid (Fortaleza)", + "America\/Glace_Bay": "Atlantic-tiid (Glace Bay)", + "America\/Godthab": "West-Groenlânske tiid (Nuuk)", + "America\/Goose_Bay": "Atlantic-tiid (Goose Bay)", + "America\/Grand_Turk": "Eastern-tiid (Grand Turk)", + "America\/Grenada": "Atlantic-tiid (Grenada)", + "America\/Guadeloupe": "Atlantic-tiid (Guadeloupe)", + "America\/Guatemala": "Central-tiid (Guatemala)", + "America\/Guayaquil": "Ecuadoraanske tiid (Guayaquil)", + "America\/Guyana": "Guyaanske tiid (Guyana)", + "America\/Halifax": "Atlantic-tiid (Halifax)", + "America\/Havana": "Kubaanske tiid (Havana)", + "America\/Indiana\/Knox": "Central-tiid (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern-tiid (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern-tiid (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Central-tiid (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern-tiid (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern-tiid (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern-tiid (Winamac, Indiana)", + "America\/Indianapolis": "Eastern-tiid (Indianapolis)", + "America\/Inuvik": "Mountain-tiid (Inuvik)", + "America\/Iqaluit": "Eastern-tiid (Iqaluit)", + "America\/Jamaica": "Eastern-tiid (Jamaica)", + "America\/Jujuy": "Argentynske tiid (Jujuy)", + "America\/Juneau": "Alaska-tiid (Juneau)", + "America\/Kentucky\/Monticello": "Eastern-tiid (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantic-tiid (Kralendijk)", + "America\/La_Paz": "Boliviaanske tiid (La Paz)", + "America\/Lima": "Peruaanske tiid (Lima)", + "America\/Los_Angeles": "Pasifik-tiid (Los Angeles)", + "America\/Louisville": "Eastern-tiid (Louisville)", + "America\/Lower_Princes": "Atlantic-tiid (Beneden Prinsen Kwartier)", + "America\/Maceio": "Brazyljaanske tiid (Maceió)", + "America\/Managua": "Central-tiid (Managua)", + "America\/Manaus": "Amazone-tiid (Manaus)", + "America\/Marigot": "Atlantic-tiid (Marigot)", + "America\/Martinique": "Atlantic-tiid (Martinique)", + "America\/Matamoros": "Central-tiid (Matamoros)", + "America\/Mendoza": "Argentynske tiid (Mendoza)", + "America\/Menominee": "Central-tiid (Menominee)", + "America\/Merida": "Central-tiid (Mérida)", + "America\/Metlakatla": "Alaska-tiid (Metlakatla)", + "America\/Mexico_City": "Central-tiid (Mexico-stad)", + "America\/Miquelon": "Saint Pierre en Miquelon-tiid (Miquelon)", + "America\/Moncton": "Atlantic-tiid (Moncton)", + "America\/Monterrey": "Central-tiid (Monterrey)", + "America\/Montevideo": "Uruguayaanske tiid (Montevideo)", + "America\/Montserrat": "Atlantic-tiid (Montserrat)", + "America\/Nassau": "Eastern-tiid (Nassau)", + "America\/New_York": "Eastern-tiid (New York)", + "America\/Nipigon": "Eastern-tiid (Nipigon)", + "America\/Nome": "Alaska-tiid (Nome)", + "America\/Noronha": "Fernando de Noronha-tiid (Noronha)", + "America\/North_Dakota\/Beulah": "Central-tiid (Beulah, Noard-Dakota)", + "America\/North_Dakota\/Center": "Central-tiid (Center, Noard-Dakota)", + "America\/North_Dakota\/New_Salem": "Central-tiid (New Salem, Noard-Dakota)", + "America\/Ojinaga": "Mountain-tiid (Ojinaga)", + "America\/Panama": "Eastern-tiid (Panama)", + "America\/Pangnirtung": "Eastern-tiid (Pangnirtung)", + "America\/Paramaribo": "Surinaamske tiid (Paramaribo)", + "America\/Phoenix": "Mountain-tiid (Phoenix)", + "America\/Port-au-Prince": "Eastern-tiid (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantic-tiid (Port of Spain)", + "America\/Porto_Velho": "Amazone-tiid (Pôrto Velho)", + "America\/Puerto_Rico": "Atlantic-tiid (Puerto Rico)", + "America\/Punta_Arenas": "Sileenske tiid (Punta Arenas)", + "America\/Rainy_River": "Central-tiid (Rainy River)", + "America\/Rankin_Inlet": "Central-tiid (Rankin Inlet)", + "America\/Recife": "Brazyljaanske tiid (Recife)", + "America\/Regina": "Central-tiid (Regina)", + "America\/Resolute": "Central-tiid (Resolute)", + "America\/Rio_Branco": "Acre-tiid (Rio Branco)", + "America\/Santarem": "Brazyljaanske tiid (Santarem)", + "America\/Santiago": "Sileenske tiid (Santiago)", + "America\/Santo_Domingo": "Atlantic-tiid (Santo Domingo)", + "America\/Sao_Paulo": "Brazyljaanske tiid (São Paulo)", + "America\/Scoresbysund": "East-Groenlânske tiid (Ittoqqortoormiit)", + "America\/Sitka": "Alaska-tiid (Sitka)", + "America\/St_Barthelemy": "Atlantic-tiid (Saint-Barthélemy)", + "America\/St_Johns": "Newfoundlânske-tiid (St. John’s)", + "America\/St_Kitts": "Atlantic-tiid (St. Kitts)", + "America\/St_Lucia": "Atlantic-tiid (St. Lucia)", + "America\/St_Thomas": "Atlantic-tiid (St. Thomas)", + "America\/St_Vincent": "Atlantic-tiid (St. Vincent)", + "America\/Swift_Current": "Central-tiid (Swift Current)", + "America\/Tegucigalpa": "Central-tiid (Tegucigalpa)", + "America\/Thule": "Atlantic-tiid (Thule)", + "America\/Thunder_Bay": "Eastern-tiid (Thunder Bay)", + "America\/Tijuana": "Pasifik-tiid (Tijuana)", + "America\/Toronto": "Eastern-tiid (Toronto)", + "America\/Tortola": "Atlantic-tiid (Tortola)", + "America\/Vancouver": "Pasifik-tiid (Vancouver)", + "America\/Whitehorse": "Pasifik-tiid (Whitehorse)", + "America\/Winnipeg": "Central-tiid (Winnipeg)", + "America\/Yakutat": "Alaska-tiid (Yakutat)", + "America\/Yellowknife": "Mountain-tiid (Yellowknife)", + "Antarctica\/Casey": "West-Australyske tiid (Casey)", + "Antarctica\/Davis": "Davis tiid (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville tiid (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie-eilânske tiid (Macquarie)", + "Antarctica\/Mawson": "Mawson tiid (Mawson)", + "Antarctica\/McMurdo": "Nij-Seelânske tiid (McMurdo)", + "Antarctica\/Palmer": "Sileenske tiid (Palmer)", + "Antarctica\/Rothera": "Rothera tiid (Rothera)", + "Antarctica\/Syowa": "Syowa tiid (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Vostok tiid (Vostok)", + "Arctic\/Longyearbyen": "Midden-Europeeske tiid (Longyearbyen)", + "Asia\/Aden": "Arabyske tiid (Aden)", + "Asia\/Almaty": "East-Kazachse tiid (Alma-Ata)", + "Asia\/Amman": "East-Europeeske tiid (Amman)", + "Asia\/Anadyr": "Anadyr-tiid (Anadyr)", + "Asia\/Aqtau": "West-Kazachse tiid (Aqtau)", + "Asia\/Aqtobe": "West-Kazachse tiid (Aqtöbe)", + "Asia\/Ashgabat": "Turkmeense tiid (Asjchabad)", + "Asia\/Atyrau": "West-Kazachse tiid (Atyrau)", + "Asia\/Baghdad": "Arabyske tiid (Bagdad)", + "Asia\/Bahrain": "Arabyske tiid (Bahrein)", + "Asia\/Baku": "Azerbeidzjaanske tiid (Bakoe)", + "Asia\/Bangkok": "Yndochinese tiid (Bangkok)", + "Asia\/Beirut": "East-Europeeske tiid (Beiroet)", + "Asia\/Bishkek": "Kirgizyske tiid (Bisjkek)", + "Asia\/Brunei": "Bruneise tiid (Brunei)", + "Asia\/Calcutta": "Yndiaaske tiid (Calcutta)", + "Asia\/Chita": "Jakoetsk-tiid (Chita)", + "Asia\/Choibalsan": "Tsjojbalsan tiid (Choibalsan)", + "Asia\/Colombo": "Yndiaaske tiid (Colombo)", + "Asia\/Damascus": "East-Europeeske tiid (Damascus)", + "Asia\/Dhaka": "Bengalese tiid (Dhaka)", + "Asia\/Dili": "East-Timorese tiid (Dili)", + "Asia\/Dubai": "Golf standerttiid (Dubai)", + "Asia\/Dushanbe": "Tadzjiekse tiid (Dusjanbe)", + "Asia\/Famagusta": "East-Europeeske tiid (Famagusta)", + "Asia\/Gaza": "East-Europeeske tiid (Gaza)", + "Asia\/Hebron": "East-Europeeske tiid (Hebron)", + "Asia\/Hong_Kong": "Hongkongse tiid (Hongkong)", + "Asia\/Hovd": "Hovd tiid (Hovd)", + "Asia\/Irkutsk": "Irkoetsk-tiid (Irkoetsk)", + "Asia\/Jakarta": "West-Yndonezyske tiid (Jakarta)", + "Asia\/Jayapura": "East-Yndonezyske tiid (Jayapura)", + "Asia\/Jerusalem": "Israëlyske tiid (Jeruzalem)", + "Asia\/Kabul": "Afghaanske tiid (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamtsjatski-tiid (Kamtsjatka)", + "Asia\/Karachi": "Pakistaanske tiid (Karachi)", + "Asia\/Katmandu": "Nepalese tiid (Kathmandu)", + "Asia\/Khandyga": "Jakoetsk-tiid (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk-tiid (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Maleisyske tiid (Kuala Lumpur)", + "Asia\/Kuching": "Maleisyske tiid (Kuching)", + "Asia\/Kuwait": "Arabyske tiid (Koeweit)", + "Asia\/Macau": "Sineeske tiid (Macao)", + "Asia\/Magadan": "Magadan-tiid (Magadan)", + "Asia\/Makassar": "Sintraal-Yndonezyske tiid (Makassar)", + "Asia\/Manila": "Filipijnse tiid (Manilla)", + "Asia\/Muscat": "Golf standerttiid (Muscat)", + "Asia\/Nicosia": "East-Europeeske tiid (Nicosia)", + "Asia\/Novokuznetsk": "Krasnojarsk-tiid (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk-tiid (Novosibirsk)", + "Asia\/Omsk": "Omsk-tiid (Omsk)", + "Asia\/Oral": "West-Kazachse tiid (Oral)", + "Asia\/Phnom_Penh": "Yndochinese tiid (Phnom-Penh)", + "Asia\/Pontianak": "West-Yndonezyske tiid (Pontianak)", + "Asia\/Pyongyang": "Koreaanske tiid (Pyongyang)", + "Asia\/Qatar": "Arabyske tiid (Qatar)", + "Asia\/Qostanay": "East-Kazachse tiid (Qostanay)", + "Asia\/Qyzylorda": "West-Kazachse tiid (Qyzylorda)", + "Asia\/Rangoon": "Myanmarese tiid (Yangon)", + "Asia\/Riyadh": "Arabyske tiid (Riyad)", + "Asia\/Saigon": "Yndochinese tiid (Ho Chi Minhstad)", + "Asia\/Sakhalin": "Sachalin-tiid (Sachalin)", + "Asia\/Samarkand": "Oezbeekse tiid (Samarkand)", + "Asia\/Seoul": "Koreaanske tiid (Seoul)", + "Asia\/Shanghai": "Sineeske tiid (Sjanghai)", + "Asia\/Singapore": "Singaporese standerttiid (Singapore)", + "Asia\/Srednekolymsk": "Magadan-tiid (Srednekolymsk)", + "Asia\/Taipei": "Taipei tiid (Taipei)", + "Asia\/Tashkent": "Oezbeekse tiid (Tasjkent)", + "Asia\/Tbilisi": "Georgyske tiid (Tbilisi)", + "Asia\/Tehran": "Iraanske tiid (Teheran)", + "Asia\/Thimphu": "Bhutaanske tiid (Thimphu)", + "Asia\/Tokyo": "Japanske tiid (Tokio)", + "Asia\/Ulaanbaatar": "Ulaanbaatar tiid (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostok-tiid (Ust-Nera)", + "Asia\/Vientiane": "Yndochinese tiid (Vientiane)", + "Asia\/Vladivostok": "Vladivostok-tiid (Vladivostok)", + "Asia\/Yakutsk": "Jakoetsk-tiid (Jakoetsk)", + "Asia\/Yekaterinburg": "Jekaterinenburg-tiid (Jekaterinenburg)", + "Asia\/Yerevan": "Armeense tiid (Jerevan)", + "Atlantic\/Azores": "Azoren-tiid (Azoren)", + "Atlantic\/Bermuda": "Atlantic-tiid (Bermuda)", + "Atlantic\/Canary": "West-Europeeske tiid (Kanaryske Eilannen)", + "Atlantic\/Cape_Verde": "Kaapverdyske tiid (Kaapverdië)", + "Atlantic\/Faeroe": "West-Europeeske tiid (Faeröer)", + "Atlantic\/Madeira": "West-Europeeske tiid (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/South_Georgia": "Sûd-Georgyske tiid (Sûd-Georgia)", + "Atlantic\/St_Helena": "Greenwich Mean Time (Sint-Helena)", + "Atlantic\/Stanley": "Falklâneilânske tiid (Stanley)", + "Australia\/Adelaide": "Midden-Australyske tiid (Adelaide)", + "Australia\/Brisbane": "East-Australyske tiid (Brisbane)", + "Australia\/Broken_Hill": "Midden-Australyske tiid (Broken Hill)", + "Australia\/Currie": "East-Australyske tiid (Currie)", + "Australia\/Darwin": "Midden-Australyske tiid (Darwin)", + "Australia\/Eucla": "Midden-Australyske westelijke tiid (Eucla)", + "Australia\/Hobart": "East-Australyske tiid (Hobart)", + "Australia\/Lindeman": "East-Australyske tiid (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe-eilânske tiid (Lord Howe)", + "Australia\/Melbourne": "East-Australyske tiid (Melbourne)", + "Australia\/Perth": "West-Australyske tiid (Perth)", + "Australia\/Sydney": "East-Australyske tiid (Sydney)", + "CST6CDT": "Central-tiid", + "EST5EDT": "Eastern-tiid", + "Etc\/GMT": "Greenwich Mean Time", + "Europe\/Amsterdam": "Midden-Europeeske tiid (Amsterdam)", + "Europe\/Andorra": "Midden-Europeeske tiid (Andorra)", + "Europe\/Astrakhan": "Moskou-tiid (Astrakhan)", + "Europe\/Athens": "East-Europeeske tiid (Athene)", + "Europe\/Belgrade": "Midden-Europeeske tiid (Belgrado)", + "Europe\/Berlin": "Midden-Europeeske tiid (Berlyn)", + "Europe\/Bratislava": "Midden-Europeeske tiid (Bratislava)", + "Europe\/Brussels": "Midden-Europeeske tiid (Brussel)", + "Europe\/Bucharest": "East-Europeeske tiid (Boekarest)", + "Europe\/Budapest": "Midden-Europeeske tiid (Boedapest)", + "Europe\/Busingen": "Midden-Europeeske tiid (Busingen)", + "Europe\/Chisinau": "East-Europeeske tiid (Chisinau)", + "Europe\/Copenhagen": "Midden-Europeeske tiid (Kopenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Midden-Europeeske tiid (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "East-Europeeske tiid (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "East-Europeeske tiid (Kaliningrad)", + "Europe\/Kiev": "East-Europeeske tiid (Kiev)", + "Europe\/Lisbon": "West-Europeeske tiid (Lissabon)", + "Europe\/Ljubljana": "Midden-Europeeske tiid (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (Londen)", + "Europe\/Luxembourg": "Midden-Europeeske tiid (Luxemburg)", + "Europe\/Madrid": "Midden-Europeeske tiid (Madrid)", + "Europe\/Malta": "Midden-Europeeske tiid (Malta)", + "Europe\/Mariehamn": "East-Europeeske tiid (Mariehamn)", + "Europe\/Minsk": "Moskou-tiid (Minsk)", + "Europe\/Monaco": "Midden-Europeeske tiid (Monaco)", + "Europe\/Moscow": "Moskou-tiid (Moskou)", + "Europe\/Oslo": "Midden-Europeeske tiid (Oslo)", + "Europe\/Paris": "Midden-Europeeske tiid (Parys)", + "Europe\/Podgorica": "Midden-Europeeske tiid (Podgorica)", + "Europe\/Prague": "Midden-Europeeske tiid (Praach)", + "Europe\/Riga": "East-Europeeske tiid (Riga)", + "Europe\/Rome": "Midden-Europeeske tiid (Rome)", + "Europe\/Samara": "Samara-tiid (Samara)", + "Europe\/San_Marino": "Midden-Europeeske tiid (San Marino)", + "Europe\/Sarajevo": "Midden-Europeeske tiid (Sarajevo)", + "Europe\/Saratov": "Moskou-tiid (Saratov)", + "Europe\/Simferopol": "Moskou-tiid (Simferopol)", + "Europe\/Skopje": "Midden-Europeeske tiid (Skopje)", + "Europe\/Sofia": "East-Europeeske tiid (Sofia)", + "Europe\/Stockholm": "Midden-Europeeske tiid (Stockholm)", + "Europe\/Tallinn": "East-Europeeske tiid (Tallinn)", + "Europe\/Tirane": "Midden-Europeeske tiid (Tirana)", + "Europe\/Ulyanovsk": "Moskou-tiid (Ulyanovsk)", + "Europe\/Uzhgorod": "East-Europeeske tiid (Oezjhorod)", + "Europe\/Vaduz": "Midden-Europeeske tiid (Vaduz)", + "Europe\/Vatican": "Midden-Europeeske tiid (Fatikaanstêd)", + "Europe\/Vienna": "Midden-Europeeske tiid (Wenen)", + "Europe\/Vilnius": "East-Europeeske tiid (Vilnius)", + "Europe\/Volgograd": "Wolgograd-tiid (Wolgograd)", + "Europe\/Warsaw": "Midden-Europeeske tiid (Warschau)", + "Europe\/Zagreb": "Midden-Europeeske tiid (Zagreb)", + "Europe\/Zaporozhye": "East-Europeeske tiid (Zaporizja)", + "Europe\/Zurich": "Midden-Europeeske tiid (Zürich)", + "Indian\/Antananarivo": "East-Afrikaanske tiid (Antananarivo)", + "Indian\/Chagos": "Yndyske Oceaan-tiid (Chagosarchipel)", + "Indian\/Christmas": "Krysteilânske tiid (Krysteilân)", + "Indian\/Cocos": "Kokoseilânske tiid (Cocoseilannen)", + "Indian\/Comoro": "East-Afrikaanske tiid (Comoro)", + "Indian\/Kerguelen": "Frânske Súdlike en Antarctyske tiid (Kerguelen)", + "Indian\/Mahe": "Seychelse tiid (Mahé)", + "Indian\/Maldives": "Maldivyske tiid (Maldiven)", + "Indian\/Mauritius": "Mauritiaanske tiid (Mauritius)", + "Indian\/Mayotte": "East-Afrikaanske tiid (Mayotte)", + "Indian\/Reunion": "Réunionse tiid (Réunion)", + "MST7MDT": "Mountain-tiid", + "PST8PDT": "Pasifik-tiid", + "Pacific\/Auckland": "Nij-Seelânske tiid (Auckland)", + "Pacific\/Bougainville": "Papoea-Nij-Guineeske tiid (Bougainville)", + "Pacific\/Chatham": "Chatham tiid (Chatham)", + "Pacific\/Easter": "Peaskeeilânske tiid (Peaskeeilân)", + "Pacific\/Efate": "Vanuatuaanske tiid (Efate)", + "Pacific\/Enderbury": "Phoenixeilânske tiid (Enderbury-eilân)", + "Pacific\/Fakaofo": "Tokelau-eilânske tiid (Fakaofo)", + "Pacific\/Fiji": "Fijyske tiid (Fiji)", + "Pacific\/Funafuti": "Tuvaluaanske tiid (Funafuti)", + "Pacific\/Galapagos": "Galapagoseilânske tiid (Galápagos)", + "Pacific\/Gambier": "Gambiereilânske tiid (Gambiereilannen)", + "Pacific\/Guadalcanal": "Salomonseilânske tiid (Guadalcanal)", + "Pacific\/Guam": "Chamorro-tiid (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleoetyske tiid (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleoetyske tiid (Johnston)", + "Pacific\/Kiritimati": "Line-eilânske tiid (Kiritimati)", + "Pacific\/Kosrae": "Kosraese tiid (Kosrae)", + "Pacific\/Kwajalein": "Marshalleilânske tiid (Kwajalein)", + "Pacific\/Majuro": "Marshalleilânske tiid (Majuro)", + "Pacific\/Marquesas": "Marquesaseilânske tiid (Marquesaseilannen)", + "Pacific\/Midway": "Samoaanske tiid (Midway)", + "Pacific\/Nauru": "Nauruaanske tiid (Nauru)", + "Pacific\/Niue": "Niuese tiid (Niue)", + "Pacific\/Norfolk": "Norfolkeilânske tiid (Norfolk)", + "Pacific\/Noumea": "Nij-Kaledonyske tiid (Nouméa)", + "Pacific\/Pago_Pago": "Samoaanske tiid (Pago Pago)", + "Pacific\/Palau": "Belause tiid (Palau)", + "Pacific\/Pitcairn": "Pitcairneillânske tiid (Pitcairn)", + "Pacific\/Ponape": "Pohnpei tiid (Pohnpei)", + "Pacific\/Port_Moresby": "Papoea-Nij-Guineeske tiid (Port Moresby)", + "Pacific\/Rarotonga": "Cookeilânse tiid (Rarotonga)", + "Pacific\/Saipan": "Chamorro-tiid (Saipan)", + "Pacific\/Tahiti": "Tahitiaanske tiid (Tahiti)", + "Pacific\/Tarawa": "Gilberteilânske tiid (Tarawa)", + "Pacific\/Tongatapu": "Tongaanske tiid (Tongatapu)", + "Pacific\/Truk": "Chuukse tiid (Chuuk)", + "Pacific\/Wake": "Wake-eilânske tiid (Wake)", + "Pacific\/Wallis": "Wallis en Futunase tiid (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ga.json b/src/Symfony/Component/Intl/Resources/data/timezones/ga.json new file mode 100644 index 0000000000000..e1ce36fae7389 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ga.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Meán-Am Greenwich (Abidjan)", + "Africa\/Accra": "Meán-Am Greenwich (Accra)", + "Africa\/Addis_Ababa": "Am Oirthear na hAfraice (Adas Ababa)", + "Africa\/Algiers": "Am Lár na hEorpa (Cathair na hAilgéire)", + "Africa\/Asmera": "Am Oirthear na hAfraice (Asmara)", + "Africa\/Bamako": "Meán-Am Greenwich (Bamako)", + "Africa\/Bangui": "Am Iarthar na hAfraice (Bangui)", + "Africa\/Banjul": "Meán-Am Greenwich (Banjul)", + "Africa\/Bissau": "Meán-Am Greenwich (Bissau)", + "Africa\/Blantyre": "Am Lár na hAfraice (Baile an tSaoir)", + "Africa\/Brazzaville": "Am Iarthar na hAfraice (Brazzaville)", + "Africa\/Bujumbura": "Am Lár na hAfraice (Bujumbura)", + "Africa\/Cairo": "Am Oirthear na hEorpa (Caireo)", + "Africa\/Casablanca": "Am Iarthar na hEorpa (Casablanca)", + "Africa\/Ceuta": "Am Lár na hEorpa (Ceuta)", + "Africa\/Conakry": "Meán-Am Greenwich (Conacraí)", + "Africa\/Dakar": "Meán-Am Greenwich (Dacár)", + "Africa\/Dar_es_Salaam": "Am Oirthear na hAfraice (Dárasalám)", + "Africa\/Djibouti": "Am Oirthear na hAfraice (Djibouti)", + "Africa\/Douala": "Am Iarthar na hAfraice (Douala)", + "Africa\/El_Aaiun": "Am Iarthar na hEorpa (El Aaiun)", + "Africa\/Freetown": "Meán-Am Greenwich (Freetown)", + "Africa\/Gaborone": "Am Lár na hAfraice (Gaborone)", + "Africa\/Harare": "Am Lár na hAfraice (Harare)", + "Africa\/Johannesburg": "Am Caighdeánach na hAfraice Theas (Johannesburg)", + "Africa\/Juba": "Am Oirthear na hAfraice (Juba)", + "Africa\/Kampala": "Am Oirthear na hAfraice (Kampala)", + "Africa\/Khartoum": "Am Lár na hAfraice (Cartúm)", + "Africa\/Kigali": "Am Lár na hAfraice (Kigali)", + "Africa\/Kinshasa": "Am Iarthar na hAfraice (Cinseasa)", + "Africa\/Lagos": "Am Iarthar na hAfraice (Lagos)", + "Africa\/Libreville": "Am Iarthar na hAfraice (Libreville)", + "Africa\/Lome": "Meán-Am Greenwich (Lome)", + "Africa\/Luanda": "Am Iarthar na hAfraice (Luanda)", + "Africa\/Lubumbashi": "Am Lár na hAfraice (Lubumbashi)", + "Africa\/Lusaka": "Am Lár na hAfraice (Lusaka)", + "Africa\/Malabo": "Am Iarthar na hAfraice (Malabo)", + "Africa\/Maputo": "Am Lár na hAfraice (Mapútó)", + "Africa\/Maseru": "Am Caighdeánach na hAfraice Theas (Maseru)", + "Africa\/Mbabane": "Am Caighdeánach na hAfraice Theas (Mbabane)", + "Africa\/Mogadishu": "Am Oirthear na hAfraice (Mogaidisiú)", + "Africa\/Monrovia": "Meán-Am Greenwich (Monrovia)", + "Africa\/Nairobi": "Am Oirthear na hAfraice (Nairobi)", + "Africa\/Ndjamena": "Am Iarthar na hAfraice (Ndjamena)", + "Africa\/Niamey": "Am Iarthar na hAfraice (Niamey)", + "Africa\/Nouakchott": "Meán-Am Greenwich (Nuacsat)", + "Africa\/Ouagadougou": "Meán-Am Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Am Iarthar na hAfraice (Porto-Novo)", + "Africa\/Sao_Tome": "Meán-Am Greenwich (São Tomé)", + "Africa\/Tripoli": "Am Oirthear na hEorpa (Tripilí)", + "Africa\/Tunis": "Am Lár na hEorpa (Túinis)", + "Africa\/Windhoek": "Am Lár na hAfraice (Windhoek)", + "America\/Adak": "Am Haváí-Ailiúit (Adak)", + "America\/Anchorage": "Am Alasca (Anchorage)", + "America\/Anguilla": "Am an Atlantaigh (Angaíle)", + "America\/Antigua": "Am an Atlantaigh (Antigua)", + "America\/Araguaina": "Am Bhrasília (Araguaina)", + "America\/Argentina\/La_Rioja": "Am na hAirgintíne (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Am na hAirgintíne (Rio Gallegos)", + "America\/Argentina\/Salta": "Am na hAirgintíne (Salta)", + "America\/Argentina\/San_Juan": "Am na hAirgintíne (San Juan)", + "America\/Argentina\/San_Luis": "Am Iarthar na hAirgintíne (San Luis)", + "America\/Argentina\/Tucuman": "Am na hAirgintíne (Tucuman)", + "America\/Argentina\/Ushuaia": "Am na hAirgintíne (Ushuaia)", + "America\/Aruba": "Am an Atlantaigh (Arúba)", + "America\/Asuncion": "Am Pharagua (Asúinseon)", + "America\/Bahia": "Am Bhrasília (Bahia)", + "America\/Bahia_Banderas": "Am Lárnach (Bahia Banderas)", + "America\/Barbados": "Am an Atlantaigh (Barbadós)", + "America\/Belem": "Am Bhrasília (Belém)", + "America\/Belize": "Am Lárnach (an Bheilís)", + "America\/Blanc-Sablon": "Am an Atlantaigh (Blanc-Sablon)", + "America\/Boa_Vista": "Am na hAmasóine (Boa Vista)", + "America\/Bogota": "Am na Colóime (Bogatá)", + "America\/Boise": "Am na Sléibhte (Boise)", + "America\/Buenos_Aires": "Am na hAirgintíne (Buenos Aires)", + "America\/Cambridge_Bay": "Am na Sléibhte (Cambridge Bay)", + "America\/Campo_Grande": "Am na hAmasóine (Campo Grande)", + "America\/Cancun": "Am an Oirthir (Cancún)", + "America\/Caracas": "Am Veiniséala (Caracas)", + "America\/Catamarca": "Am na hAirgintíne (Catamarca)", + "America\/Cayenne": "Am Ghuáin na Fraince (Cayenne)", + "America\/Cayman": "Am an Oirthir (Cayman)", + "America\/Chicago": "Am Lárnach (Chicago)", + "America\/Chihuahua": "Am Meicsiceach an Aigéin Chiúin (Chihuahua)", + "America\/Coral_Harbour": "Am an Oirthir (Atikokan)", + "America\/Cordoba": "Am na hAirgintíne (Córdoba)", + "America\/Costa_Rica": "Am Lárnach (Cósta Ríce)", + "America\/Creston": "Am na Sléibhte (Creston)", + "America\/Cuiaba": "Am na hAmasóine (Cuiabá)", + "America\/Curacao": "Am an Atlantaigh (Curaçao)", + "America\/Danmarkshavn": "Meán-Am Greenwich (Danmarkshavn)", + "America\/Dawson": "Am an Aigéin Chiúin (Dawson)", + "America\/Dawson_Creek": "Am na Sléibhte (Dawson Creek)", + "America\/Denver": "Am na Sléibhte (Denver)", + "America\/Detroit": "Am an Oirthir (Detroit)", + "America\/Dominica": "Am an Atlantaigh (Doiminice)", + "America\/Edmonton": "Am na Sléibhte (Edmonton)", + "America\/Eirunepe": "Am Acre (Eirunepé)", + "America\/El_Salvador": "Am Lárnach (an tSalvadóir)", + "America\/Fort_Nelson": "Am na Sléibhte (Fort Nelson)", + "America\/Fortaleza": "Am Bhrasília (Fortaleza)", + "America\/Glace_Bay": "Am an Atlantaigh (Glace Bay)", + "America\/Godthab": "Am Iarthar na Graonlainne (Nuuk)", + "America\/Goose_Bay": "Am an Atlantaigh (Goose Bay)", + "America\/Grand_Turk": "Am an Oirthir (Grand Turk)", + "America\/Grenada": "Am an Atlantaigh (Greanáda)", + "America\/Guadeloupe": "Am an Atlantaigh (Guadalúip)", + "America\/Guatemala": "Am Lárnach (Guatamala)", + "America\/Guayaquil": "Am Eacuadór (Guayaquil)", + "America\/Guyana": "Am na Guáine (an Ghuáin)", + "America\/Halifax": "Am an Atlantaigh (Halifax)", + "America\/Havana": "Am Chúba (Havána)", + "America\/Hermosillo": "Am Meicsiceach an Aigéin Chiúin (Hermosillo)", + "America\/Indiana\/Knox": "Am Lárnach (Knox, Indiana)", + "America\/Indiana\/Marengo": "Am an Oirthir (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Am an Oirthir (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Am Lárnach (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Am an Oirthir (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Am an Oirthir (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Am an Oirthir (Winamac, Indiana)", + "America\/Indianapolis": "Am an Oirthir (Indianapolis)", + "America\/Inuvik": "Am na Sléibhte (Inuvik)", + "America\/Iqaluit": "Am an Oirthir (Iqaluit)", + "America\/Jamaica": "Am an Oirthir (Iamáice)", + "America\/Jujuy": "Am na hAirgintíne (Jujuy)", + "America\/Juneau": "Am Alasca (Juneau)", + "America\/Kentucky\/Monticello": "Am an Oirthir (Monticello, Kentucky)", + "America\/Kralendijk": "Am an Atlantaigh (Kralendijk)", + "America\/La_Paz": "Am na Bolaive (La Paz)", + "America\/Lima": "Am Pheiriú (Líoma)", + "America\/Los_Angeles": "Am an Aigéin Chiúin (Los Angeles)", + "America\/Louisville": "Am an Oirthir (Louisville)", + "America\/Lower_Princes": "Am an Atlantaigh (Lower Prince’s Quarter)", + "America\/Maceio": "Am Bhrasília (Maceió)", + "America\/Managua": "Am Lárnach (Managua)", + "America\/Manaus": "Am na hAmasóine (Manaus)", + "America\/Marigot": "Am an Atlantaigh (Marigot)", + "America\/Martinique": "Am an Atlantaigh (Martinique)", + "America\/Matamoros": "Am Lárnach (Matamoros)", + "America\/Mazatlan": "Am Meicsiceach an Aigéin Chiúin (Mazatlan)", + "America\/Mendoza": "Am na hAirgintíne (Mendoza)", + "America\/Menominee": "Am Lárnach (Menominee)", + "America\/Merida": "Am Lárnach (Merida)", + "America\/Metlakatla": "Am Alasca (Metlakatla)", + "America\/Mexico_City": "Am Lárnach (Cathair Mheicsiceo)", + "America\/Miquelon": "Am Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "Am an Atlantaigh (Moncton)", + "America\/Monterrey": "Am Lárnach (Monterrey)", + "America\/Montevideo": "Am Uragua (Montevideo)", + "America\/Montserrat": "Am an Atlantaigh (Montsarat)", + "America\/Nassau": "Am an Oirthir (Nassau)", + "America\/New_York": "Am an Oirthir (Nua-Eabhrac)", + "America\/Nipigon": "Am an Oirthir (Nipigon)", + "America\/Nome": "Am Alasca (Nome)", + "America\/Noronha": "Am Fhernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Am Lárnach (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Am Lárnach (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Am Lárnach (New Salem, North Dakota)", + "America\/Ojinaga": "Am na Sléibhte (Ojinaga)", + "America\/Panama": "Am an Oirthir (Panama)", + "America\/Pangnirtung": "Am an Oirthir (Pangnirtung)", + "America\/Paramaribo": "Am Shuranam (Paramaribo)", + "America\/Phoenix": "Am na Sléibhte (Phoenix)", + "America\/Port-au-Prince": "Am an Oirthir (Port-au-Prince)", + "America\/Port_of_Spain": "Am an Atlantaigh (Port of Spain)", + "America\/Porto_Velho": "Am na hAmasóine (Porto Velho)", + "America\/Puerto_Rico": "Am an Atlantaigh (Portó Ríce)", + "America\/Punta_Arenas": "Am na Sile (Punta Arenas)", + "America\/Rainy_River": "Am Lárnach (Rainy River)", + "America\/Rankin_Inlet": "Am Lárnach (Rankin Inlet)", + "America\/Recife": "Am Bhrasília (Recife)", + "America\/Regina": "Am Lárnach (Regina)", + "America\/Resolute": "Am Lárnach (Resolute)", + "America\/Rio_Branco": "Am Acre (Rio Branco)", + "America\/Santa_Isabel": "Am Iarthuaisceart Mheicsiceo (Santa Isabel)", + "America\/Santarem": "Am Bhrasília (Santarém)", + "America\/Santiago": "Am na Sile (Saintiagó)", + "America\/Santo_Domingo": "Am an Atlantaigh (Santo Domingo)", + "America\/Sao_Paulo": "Am Bhrasília (São Paulo)", + "America\/Scoresbysund": "Am Oirthear na Graonlainne (Ittoqqortoormiit)", + "America\/Sitka": "Am Alasca (Sitka)", + "America\/St_Barthelemy": "Am an Atlantaigh (Saint Barthélemy)", + "America\/St_Johns": "Am Thalamh an Éisc (St. John’s)", + "America\/St_Kitts": "Am an Atlantaigh (San Críostóir)", + "America\/St_Lucia": "Am an Atlantaigh (St. Lucia)", + "America\/St_Thomas": "Am an Atlantaigh (St. Thomas)", + "America\/St_Vincent": "Am an Atlantaigh (San Uinseann)", + "America\/Swift_Current": "Am Lárnach (Swift Current)", + "America\/Tegucigalpa": "Am Lárnach (Tegucigalpa)", + "America\/Thule": "Am an Atlantaigh (Thule)", + "America\/Thunder_Bay": "Am an Oirthir (Thunder Bay)", + "America\/Tijuana": "Am an Aigéin Chiúin (Tijuana)", + "America\/Toronto": "Am an Oirthir (Toronto)", + "America\/Tortola": "Am an Atlantaigh (Tortola)", + "America\/Vancouver": "Am an Aigéin Chiúin (Vancouver)", + "America\/Whitehorse": "Am an Aigéin Chiúin (Whitehorse)", + "America\/Winnipeg": "Am Lárnach (Winnipeg)", + "America\/Yakutat": "Am Alasca (Yakutat)", + "America\/Yellowknife": "Am na Sléibhte (Yellowknife)", + "Antarctica\/Casey": "Am Iarthar na hAstráile (Casey)", + "Antarctica\/Davis": "Am Stáisiún Davis (Davis)", + "Antarctica\/DumontDUrville": "Am Stáisiún Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Am Oileán Mhic Guaire (Mac Guaire)", + "Antarctica\/Mawson": "Am Stáisiún Mawson (Mawson)", + "Antarctica\/McMurdo": "Am na Nua-Shéalainne (McMurdo)", + "Antarctica\/Palmer": "Am na Sile (Palmer)", + "Antarctica\/Rothera": "Am Stáisiún Rothera (Rothera)", + "Antarctica\/Syowa": "Am Stáisiún Syowa (Syowa)", + "Antarctica\/Troll": "Meán-Am Greenwich (Troll)", + "Antarctica\/Vostok": "Am Stáisiún Vostok (Vostok)", + "Arctic\/Longyearbyen": "Am Lár na hEorpa (Longyearbyen)", + "Asia\/Aden": "Am na hAraibe (Áidin)", + "Asia\/Almaty": "Am Oirthear na Casacstáine (Almaty)", + "Asia\/Amman": "Am Oirthear na hEorpa (Amman)", + "Asia\/Anadyr": "Am Anadyr (Anadyr)", + "Asia\/Aqtau": "Am Iarthar na Casacstáine (Aqtau)", + "Asia\/Aqtobe": "Am Iarthar na Casacstáine (Aqtobe)", + "Asia\/Ashgabat": "Am na Tuircméanastáine (Ashgabat)", + "Asia\/Atyrau": "Am Iarthar na Casacstáine (Atyrau)", + "Asia\/Baghdad": "Am na hAraibe (Bagdad)", + "Asia\/Bahrain": "Am na hAraibe (Bairéin)", + "Asia\/Baku": "Am na hAsarbaiseáine (Baku)", + "Asia\/Bangkok": "Am na hInd-Síne (Bangkok)", + "Asia\/Beirut": "Am Oirthear na hEorpa (Béiriút)", + "Asia\/Bishkek": "Am na Cirgeastáine (Bishkek)", + "Asia\/Brunei": "Am Brúiné Darasalám (Brúiné)", + "Asia\/Calcutta": "Am Caighdeánach na hIndia (Calcúta)", + "Asia\/Chita": "Am Iacútsc (Chita)", + "Asia\/Choibalsan": "Am Choibalsan (Choibalsan)", + "Asia\/Colombo": "Am Caighdeánach na hIndia (Colombo)", + "Asia\/Damascus": "Am Oirthear na hEorpa (an Damaisc)", + "Asia\/Dhaka": "Am na Banglaidéise (Dhaka)", + "Asia\/Dili": "Am Thíomór Thoir (Dili)", + "Asia\/Dubai": "Am Caighdeánach na Murascaille (Dubai)", + "Asia\/Dushanbe": "Am na Táidsíceastáine (Dushanbe)", + "Asia\/Famagusta": "Am Oirthear na hEorpa (Famagusta)", + "Asia\/Gaza": "Am Oirthear na hEorpa (Gaza)", + "Asia\/Hebron": "Am Oirthear na hEorpa (Heabrón)", + "Asia\/Hong_Kong": "Am Hong Cong (Hong Cong)", + "Asia\/Hovd": "Am Hovd (Hovd)", + "Asia\/Irkutsk": "Am Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Am Iarthar na hIndinéise (Iacárta)", + "Asia\/Jayapura": "Am Oirthear na hIndinéise (Jayapura)", + "Asia\/Jerusalem": "Am Iosrael (Iarúsailéim)", + "Asia\/Kabul": "Am na hAfganastáine (Cabúl)", + "Asia\/Kamchatka": "Am Phetropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Am na Pacastáine (Karachi)", + "Asia\/Katmandu": "Am Neipeal (Kathmandu)", + "Asia\/Khandyga": "Am Iacútsc (Khandyga)", + "Asia\/Krasnoyarsk": "Am Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Am na Malaeisia (Kuala Lumpur)", + "Asia\/Kuching": "Am na Malaeisia (Kuching)", + "Asia\/Kuwait": "Am na hAraibe (Cuáit)", + "Asia\/Macau": "Am na Síne (Macao)", + "Asia\/Magadan": "Am Mhagadan (Magadan)", + "Asia\/Makassar": "Am Lár na hIndinéise (Makassar)", + "Asia\/Manila": "Am na nOileán Filipíneach (Mainile)", + "Asia\/Muscat": "Am Caighdeánach na Murascaille (Muscat)", + "Asia\/Nicosia": "Am Oirthear na hEorpa (an Niocóis)", + "Asia\/Novokuznetsk": "Am Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Am Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Am Omsk (Omsk)", + "Asia\/Oral": "Am Iarthar na Casacstáine (Oral)", + "Asia\/Phnom_Penh": "Am na hInd-Síne (Phnom Penh)", + "Asia\/Pontianak": "Am Iarthar na hIndinéise (Pontianak)", + "Asia\/Pyongyang": "Am na Cóiré (Pyongyang)", + "Asia\/Qatar": "Am na hAraibe (Catar)", + "Asia\/Qostanay": "Am Oirthear na Casacstáine (Qostanay)", + "Asia\/Qyzylorda": "Am Iarthar na Casacstáine (Qyzylorda)", + "Asia\/Rangoon": "Am Mhaenmar (Rangún)", + "Asia\/Riyadh": "Am na hAraibe (Riyadh)", + "Asia\/Saigon": "Am na hInd-Síne (Cathair Ho Chi Minh)", + "Asia\/Sakhalin": "Am Shakhalin (Sakhalin)", + "Asia\/Samarkand": "Am na hÚisbéiceastáine (Samarkand)", + "Asia\/Seoul": "Am na Cóiré (Súl)", + "Asia\/Shanghai": "Am na Síne (Shang-hai)", + "Asia\/Singapore": "Am Caighdeánach Shingeapór (Singeapór)", + "Asia\/Srednekolymsk": "Am Mhagadan (Srednekolymsk)", + "Asia\/Taipei": "Am Thaipei (Taipei)", + "Asia\/Tashkent": "Am na hÚisbéiceastáine (Tashkent)", + "Asia\/Tbilisi": "Am na Seoirsia (Tbilisi)", + "Asia\/Tehran": "Am na hIaráine (Tehran)", + "Asia\/Thimphu": "Am na Bútáine (Thimphu)", + "Asia\/Tokyo": "Am na Seapáine (Tóiceo)", + "Asia\/Ulaanbaatar": "Am Ulánbátar (Ulaanbaatar)", + "Asia\/Ust-Nera": "Am Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Am na hInd-Síne (Vientiane)", + "Asia\/Vladivostok": "Am Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Am Iacútsc (Iacútsc)", + "Asia\/Yekaterinburg": "Am Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Am na hAirméine (Eireaván)", + "Atlantic\/Azores": "Am na nAsór (na hAsóir)", + "Atlantic\/Bermuda": "Am an Atlantaigh (Beirmiúda)", + "Atlantic\/Canary": "Am Iarthar na hEorpa (na hOileáin Chanáracha)", + "Atlantic\/Cape_Verde": "Am Rinn Verde (Rinn Verde)", + "Atlantic\/Faeroe": "Am Iarthar na hEorpa (Oileáin Fharó)", + "Atlantic\/Madeira": "Am Iarthar na hEorpa (Maidéara)", + "Atlantic\/Reykjavik": "Meán-Am Greenwich (Réicivíc)", + "Atlantic\/South_Georgia": "Am na Seoirsia Theas (an tSeoirsia Theas)", + "Atlantic\/St_Helena": "Meán-Am Greenwich (San Héilin)", + "Atlantic\/Stanley": "Am Oileáin Fháclainne (Stanley)", + "Australia\/Adelaide": "Am Lár na hAstráile (Adelaide)", + "Australia\/Brisbane": "Am Oirthear na hAstráile (Brisbane)", + "Australia\/Broken_Hill": "Am Lár na hAstráile (Broken Hill)", + "Australia\/Currie": "Am Oirthear na hAstráile (Currie)", + "Australia\/Darwin": "Am Lár na hAstráile (Darwin)", + "Australia\/Eucla": "Am Mheániarthar na hAstráile (Eucla)", + "Australia\/Hobart": "Am Oirthear na hAstráile (Hobart)", + "Australia\/Lindeman": "Am Oirthear na hAstráile (Lindeman)", + "Australia\/Lord_Howe": "Am Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Am Oirthear na hAstráile (Melbourne)", + "Australia\/Perth": "Am Iarthar na hAstráile (Perth)", + "Australia\/Sydney": "Am Oirthear na hAstráile (Sydney)", + "CST6CDT": "Am Lárnach", + "EST5EDT": "Am an Oirthir", + "Etc\/GMT": "Meán-Am Greenwich", + "Etc\/UTC": "Am Uilíoch Lárnach", + "Europe\/Amsterdam": "Am Lár na hEorpa (Amstardam)", + "Europe\/Andorra": "Am Lár na hEorpa (Andóra)", + "Europe\/Astrakhan": "Am Mhoscó (an Astracáin)", + "Europe\/Athens": "Am Oirthear na hEorpa (an Aithin)", + "Europe\/Belgrade": "Am Lár na hEorpa (Béalgrád)", + "Europe\/Berlin": "Am Lár na hEorpa (Beirlín)", + "Europe\/Bratislava": "Am Lár na hEorpa (an Bhratasláiv)", + "Europe\/Brussels": "Am Lár na hEorpa (an Bhruiséil)", + "Europe\/Bucharest": "Am Oirthear na hEorpa (Búcairist)", + "Europe\/Budapest": "Am Lár na hEorpa (Búdaipeist)", + "Europe\/Busingen": "Am Lár na hEorpa (Busingen)", + "Europe\/Chisinau": "Am Oirthear na hEorpa (Císineá)", + "Europe\/Copenhagen": "Am Lár na hEorpa (Cóbanhávan)", + "Europe\/Dublin": "Meán-Am Greenwich (Baile Átha Cliath)", + "Europe\/Gibraltar": "Am Lár na hEorpa (Giobráltar)", + "Europe\/Guernsey": "Meán-Am Greenwich (Geansaí)", + "Europe\/Helsinki": "Am Oirthear na hEorpa (Heilsincí)", + "Europe\/Isle_of_Man": "Meán-Am Greenwich (Oileán Mhanann)", + "Europe\/Jersey": "Meán-Am Greenwich (Geirsí)", + "Europe\/Kaliningrad": "Am Oirthear na hEorpa (Kaliningrad)", + "Europe\/Kiev": "Am Oirthear na hEorpa (Cív)", + "Europe\/Lisbon": "Am Iarthar na hEorpa (Liospóin)", + "Europe\/Ljubljana": "Am Lár na hEorpa (Liúibleána)", + "Europe\/London": "Meán-Am Greenwich (Londain)", + "Europe\/Luxembourg": "Am Lár na hEorpa (Lucsamburg)", + "Europe\/Madrid": "Am Lár na hEorpa (Maidrid)", + "Europe\/Malta": "Am Lár na hEorpa (Málta)", + "Europe\/Mariehamn": "Am Oirthear na hEorpa (Mariehamn)", + "Europe\/Minsk": "Am Mhoscó (Mionsc)", + "Europe\/Monaco": "Am Lár na hEorpa (Monacó)", + "Europe\/Moscow": "Am Mhoscó (Moscó)", + "Europe\/Oslo": "Am Lár na hEorpa (Osló)", + "Europe\/Paris": "Am Lár na hEorpa (Páras)", + "Europe\/Podgorica": "Am Lár na hEorpa (Podgairítse)", + "Europe\/Prague": "Am Lár na hEorpa (Prág)", + "Europe\/Riga": "Am Oirthear na hEorpa (Ríge)", + "Europe\/Rome": "Am Lár na hEorpa (an Róimh)", + "Europe\/Samara": "Am Shamara (Samara)", + "Europe\/San_Marino": "Am Lár na hEorpa (San Mairíne)", + "Europe\/Sarajevo": "Am Lár na hEorpa (Sairéavó)", + "Europe\/Saratov": "Am Mhoscó (Saratov)", + "Europe\/Simferopol": "Am Mhoscó (Simferopol)", + "Europe\/Skopje": "Am Lár na hEorpa (Scóipé)", + "Europe\/Sofia": "Am Oirthear na hEorpa (Sóifia)", + "Europe\/Stockholm": "Am Lár na hEorpa (Stócólm)", + "Europe\/Tallinn": "Am Oirthear na hEorpa (Taillinn)", + "Europe\/Tirane": "Am Lár na hEorpa (Tirane)", + "Europe\/Ulyanovsk": "Am Mhoscó (Ulyanovsk)", + "Europe\/Uzhgorod": "Am Oirthear na hEorpa (Uzhgorod)", + "Europe\/Vaduz": "Am Lár na hEorpa (Vadús)", + "Europe\/Vatican": "Am Lár na hEorpa (Cathair na Vatacáine)", + "Europe\/Vienna": "Am Lár na hEorpa (Vín)", + "Europe\/Vilnius": "Am Oirthear na hEorpa (Vilnias)", + "Europe\/Volgograd": "Am Volgograd (Volgograd)", + "Europe\/Warsaw": "Am Lár na hEorpa (Vársá)", + "Europe\/Zagreb": "Am Lár na hEorpa (Ságrab)", + "Europe\/Zaporozhye": "Am Oirthear na hEorpa (Zaporozhye)", + "Europe\/Zurich": "Am Lár na hEorpa (Zürich)", + "Indian\/Antananarivo": "Am Oirthear na hAfraice (Antananairíveo)", + "Indian\/Chagos": "Am an Aigéin Indiaigh (Chagos)", + "Indian\/Christmas": "Am Oileán na Nollag (Oileán na Nollag)", + "Indian\/Cocos": "Am Oileáin Cocos (Oileán Cocos)", + "Indian\/Comoro": "Am Oirthear na hAfraice (Oileáin Chomóra)", + "Indian\/Kerguelen": "Am Chríocha Francacha Deisceart an Domhain (Kerguelen)", + "Indian\/Mahe": "Am na Séiséal (Mahe)", + "Indian\/Maldives": "Am Oileáin Mhaildíve (Oileáin Mhaildíve)", + "Indian\/Mauritius": "Am Oileán Mhuirís (Oileán Mhuirís)", + "Indian\/Mayotte": "Am Oirthear na hAfraice (Mayotte)", + "Indian\/Reunion": "Am Réunion (La Réunion)", + "MST7MDT": "Am na Sléibhte", + "PST8PDT": "Am an Aigéin Chiúin", + "Pacific\/Apia": "Am Apia (Apia)", + "Pacific\/Auckland": "Am na Nua-Shéalainne (Auckland)", + "Pacific\/Bougainville": "Am Nua-Ghuine Phapua (Bougainville)", + "Pacific\/Chatham": "Am Chatham (Chatham)", + "Pacific\/Easter": "Am Oileán na Cásca (Oileán na Cásca)", + "Pacific\/Efate": "Am Vanuatú (Efate)", + "Pacific\/Enderbury": "Am Oileáin an Fhéinics (Enderbury)", + "Pacific\/Fakaofo": "Am Oileáin Tócalá (Fakaofo)", + "Pacific\/Fiji": "Am Fhidsí (Fidsí)", + "Pacific\/Funafuti": "Am Thuvalu (Funafuti)", + "Pacific\/Galapagos": "Am Oileáin Galápagos (Galápagos)", + "Pacific\/Gambier": "Am Ghambier (Gambier)", + "Pacific\/Guadalcanal": "Am Oileáin Sholomón (Guadalcanal)", + "Pacific\/Guam": "Am Caighdeánach Seamórach (Guam)", + "Pacific\/Honolulu": "Am Haváí-Ailiúit (Honolulu)", + "Pacific\/Johnston": "Am Haváí-Ailiúit (Johnston)", + "Pacific\/Kiritimati": "Am Oileáin na Líne (Kiritimati)", + "Pacific\/Kosrae": "Am Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Am Oileáin Marshall (Kwajalein)", + "Pacific\/Majuro": "Am Oileáin Marshall (Majuro)", + "Pacific\/Marquesas": "Am na nOileán Marcasach (na hOileáin Mharcasacha)", + "Pacific\/Midway": "Am Shamó (Oileáin Midway)", + "Pacific\/Nauru": "Am Nárú (Nárú)", + "Pacific\/Niue": "Am Niue (Niue)", + "Pacific\/Norfolk": "Am Oileán Norfolk (Norfolk)", + "Pacific\/Noumea": "Am na Nua-Chaladóine (Noumea)", + "Pacific\/Pago_Pago": "Am Shamó (Pago Pago)", + "Pacific\/Palau": "Am Oileáin Palau (Palau)", + "Pacific\/Pitcairn": "Am Oileán Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Am Phohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "Am Nua-Ghuine Phapua (Port Moresby)", + "Pacific\/Rarotonga": "Am Oileáin Cook (Rarotonga)", + "Pacific\/Saipan": "Am Caighdeánach Seamórach (Saipan)", + "Pacific\/Tahiti": "Am Thaihítí (Taihítí)", + "Pacific\/Tarawa": "Am Chireabaití (Tarawa)", + "Pacific\/Tongatapu": "Am Thonga (Tongatapu)", + "Pacific\/Truk": "Am Chuuk (Chuuk)", + "Pacific\/Wake": "Am Oileán Wake (Oileán Wake)", + "Pacific\/Wallis": "Am Vailís agus Futúna (Vailís)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/gd.json b/src/Symfony/Component/Intl/Resources/data/timezones/gd.json new file mode 100644 index 0000000000000..22c55a928b2b4 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/gd.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.86", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "Àm Afraga an Ear (Addis Abäba)", + "Africa\/Algiers": "Àm Meadhan na Roinn-Eòrpa (Algiers)", + "Africa\/Asmera": "Àm Afraga an Ear (Asmarà)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "Àm Afraga an Iar (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Àm Meadhan Afraga (Blantyre)", + "Africa\/Brazzaville": "Àm Afraga an Iar (Brazzaville)", + "Africa\/Bujumbura": "Àm Meadhan Afraga (Bujumbura)", + "Africa\/Cairo": "Àm na Roinn-Eòrpa an Ear (Cairo)", + "Africa\/Casablanca": "Àm na Roinn-Eòrpa an Iar (Casablanca)", + "Africa\/Ceuta": "Àm Meadhan na Roinn-Eòrpa (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "Àm Afraga an Ear (Dàr as-Salàm)", + "Africa\/Djibouti": "Àm Afraga an Ear (Diobùtaidh)", + "Africa\/Douala": "Àm Afraga an Iar (Douala)", + "Africa\/El_Aaiun": "Àm na Roinn-Eòrpa an Iar (El Aaiún)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Àm Meadhan Afraga (Gaborone)", + "Africa\/Harare": "Àm Meadhan Afraga (Harare)", + "Africa\/Johannesburg": "Àm Afraga a Deas (Hannsaborgh)", + "Africa\/Juba": "Àm Afraga an Ear (Juba)", + "Africa\/Kampala": "Àm Afraga an Ear (Kampala)", + "Africa\/Khartoum": "Àm Meadhan Afraga (Khartoum)", + "Africa\/Kigali": "Àm Meadhan Afraga (Kigali)", + "Africa\/Kinshasa": "Àm Afraga an Iar (Kinshasa)", + "Africa\/Lagos": "Àm Afraga an Iar (Lagos)", + "Africa\/Libreville": "Àm Afraga an Iar (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lomé)", + "Africa\/Luanda": "Àm Afraga an Iar (Luanda)", + "Africa\/Lubumbashi": "Àm Meadhan Afraga (Lubumbashi)", + "Africa\/Lusaka": "Àm Meadhan Afraga (Lusaka)", + "Africa\/Malabo": "Àm Afraga an Iar (Malabo)", + "Africa\/Maputo": "Àm Meadhan Afraga (Maputo)", + "Africa\/Maseru": "Àm Afraga a Deas (Maseru)", + "Africa\/Mbabane": "Àm Afraga a Deas (Mbabane)", + "Africa\/Mogadishu": "Àm Afraga an Ear (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "Àm Afraga an Ear (Nairobi)", + "Africa\/Ndjamena": "Àm Afraga an Iar (N’Djaména)", + "Africa\/Niamey": "Àm Afraga an Iar (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "Àm Afraga an Iar (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (São Tomé)", + "Africa\/Tripoli": "Àm na Roinn-Eòrpa an Ear (Tripoli)", + "Africa\/Tunis": "Àm Meadhan na Roinn-Eòrpa (Tunis)", + "Africa\/Windhoek": "Àm Meadhan Afraga (Windhoek)", + "America\/Adak": "Àm nan Eileanan Hawai’i ’s Aleutach (Adak)", + "America\/Anchorage": "Àm Alaska (Anchorage)", + "America\/Anguilla": "Àm a’ Chuain Siar (Anguillia)", + "America\/Antigua": "Àm a’ Chuain Siar (Aintìoga)", + "America\/Araguaina": "Àm Bhrasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "Àm na h-Argantaine (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Àm na h-Argantaine (Río Gallegos)", + "America\/Argentina\/Salta": "Àm na h-Argantaine (Salta)", + "America\/Argentina\/San_Juan": "Àm na h-Argantaine (San Juan)", + "America\/Argentina\/San_Luis": "Àm na h-Argantaine Siaraich (San Luis)", + "America\/Argentina\/Tucuman": "Àm na h-Argantaine (Tucumán)", + "America\/Argentina\/Ushuaia": "Àm na h-Argantaine (Ushuaia)", + "America\/Aruba": "Àm a’ Chuain Siar (Arùba)", + "America\/Asuncion": "Àm Paraguaidh (Asunción)", + "America\/Bahia": "Àm Bhrasilia (Bahia)", + "America\/Bahia_Banderas": "Àm Meadhan Aimeireaga a Tuath (Bahía de Banderas)", + "America\/Barbados": "Àm a’ Chuain Siar (Barbados)", + "America\/Belem": "Àm Bhrasilia (Belém)", + "America\/Belize": "Àm Meadhan Aimeireaga a Tuath (A’ Bheilìs)", + "America\/Blanc-Sablon": "Àm a’ Chuain Siar (Blanc-Sablon)", + "America\/Boa_Vista": "Àm Amasoin (Boa Vista)", + "America\/Bogota": "Àm Coloimbia (Bogotá)", + "America\/Boise": "Àm Monadh Aimeireaga a Tuath (Boise)", + "America\/Buenos_Aires": "Àm na h-Argantaine (Buenos Aires)", + "America\/Cambridge_Bay": "Àm Monadh Aimeireaga a Tuath (Cambridge Bay)", + "America\/Campo_Grande": "Àm Amasoin (Campo Grande)", + "America\/Cancun": "Àm Aimeireaga a Tuath an Ear (Cancún)", + "America\/Caracas": "Àm na Bheiniseala (Caracas)", + "America\/Catamarca": "Àm na h-Argantaine (Catamarca)", + "America\/Cayenne": "Àm Guidheàna na Frainge (Cayenne)", + "America\/Cayman": "Àm Aimeireaga a Tuath an Ear (Caimean)", + "America\/Chicago": "Àm Meadhan Aimeireaga a Tuath (Chicago)", + "America\/Chihuahua": "Àm a’ Chuain Sèimh Mheagsago (Chihuahua)", + "America\/Coral_Harbour": "Àm Aimeireaga a Tuath an Ear (Atikokan)", + "America\/Cordoba": "Àm na h-Argantaine (Córdoba)", + "America\/Costa_Rica": "Àm Meadhan Aimeireaga a Tuath (Costa Rìcea)", + "America\/Creston": "Àm Monadh Aimeireaga a Tuath (Creston)", + "America\/Cuiaba": "Àm Amasoin (Cuiabá)", + "America\/Curacao": "Àm a’ Chuain Siar (Curaçao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Àm a’ Chuain Sèimh (Dawson)", + "America\/Dawson_Creek": "Àm Monadh Aimeireaga a Tuath (Dawson Creek)", + "America\/Denver": "Àm Monadh Aimeireaga a Tuath (Denver)", + "America\/Detroit": "Àm Aimeireaga a Tuath an Ear (Detroit)", + "America\/Dominica": "Àm a’ Chuain Siar (Doiminicea)", + "America\/Edmonton": "Àm Monadh Aimeireaga a Tuath (Edmonton)", + "America\/Eirunepe": "Àm Acre (Eirunepé)", + "America\/El_Salvador": "Àm Meadhan Aimeireaga a Tuath (An Salbhador)", + "America\/Fort_Nelson": "Àm Monadh Aimeireaga a Tuath (Fort Nelson)", + "America\/Fortaleza": "Àm Bhrasilia (Fortaleza)", + "America\/Glace_Bay": "Àm a’ Chuain Siar (Glasbaidh)", + "America\/Godthab": "Àm na Graonlainn an Iar (Nuuk)", + "America\/Goose_Bay": "Àm a’ Chuain Siar (Goose Bay)", + "America\/Grand_Turk": "Àm Aimeireaga a Tuath an Ear (An Turc Mhòr)", + "America\/Grenada": "Àm a’ Chuain Siar (Greanàda)", + "America\/Guadeloupe": "Àm a’ Chuain Siar (Guadalup)", + "America\/Guatemala": "Àm Meadhan Aimeireaga a Tuath (Guatamala)", + "America\/Guayaquil": "Àm Eacuadoir (Guayaquil)", + "America\/Guyana": "Àm Guidheàna (Guidheàna)", + "America\/Halifax": "Àm a’ Chuain Siar (Halifax)", + "America\/Havana": "Àm Cùba (Havana)", + "America\/Hermosillo": "Àm a’ Chuain Sèimh Mheagsago (Hermosillo)", + "America\/Indiana\/Knox": "Àm Meadhan Aimeireaga a Tuath (Knox, Indiana)", + "America\/Indiana\/Marengo": "Àm Aimeireaga a Tuath an Ear (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Àm Aimeireaga a Tuath an Ear (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Àm Meadhan Aimeireaga a Tuath (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Àm Aimeireaga a Tuath an Ear (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Àm Aimeireaga a Tuath an Ear (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Àm Aimeireaga a Tuath an Ear (Winamac, Indiana)", + "America\/Indianapolis": "Àm Aimeireaga a Tuath an Ear (Indianapolis)", + "America\/Inuvik": "Àm Monadh Aimeireaga a Tuath (Inuuvik)", + "America\/Iqaluit": "Àm Aimeireaga a Tuath an Ear (Iqaluit)", + "America\/Jamaica": "Àm Aimeireaga a Tuath an Ear (Diameuga)", + "America\/Jujuy": "Àm na h-Argantaine (Jujuy)", + "America\/Juneau": "Àm Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Àm Aimeireaga a Tuath an Ear (Monticello, Kentucky)", + "America\/Kralendijk": "Àm a’ Chuain Siar (Kralendijk)", + "America\/La_Paz": "Àm Boilibhia (La Paz)", + "America\/Lima": "Àm Pearù (Lima)", + "America\/Los_Angeles": "Àm a’ Chuain Sèimh (Los Angeles)", + "America\/Louisville": "Àm Aimeireaga a Tuath an Ear (Louisville)", + "America\/Lower_Princes": "Àm a’ Chuain Siar (Lower Prince’s Quarter)", + "America\/Maceio": "Àm Bhrasilia (Maceió)", + "America\/Managua": "Àm Meadhan Aimeireaga a Tuath (Managua)", + "America\/Manaus": "Àm Amasoin (Manaus)", + "America\/Marigot": "Àm a’ Chuain Siar (Marigot)", + "America\/Martinique": "Àm a’ Chuain Siar (Mairtinic)", + "America\/Matamoros": "Àm Meadhan Aimeireaga a Tuath (Matamoros)", + "America\/Mazatlan": "Àm a’ Chuain Sèimh Mheagsago (Mazatlán)", + "America\/Mendoza": "Àm na h-Argantaine (Mendoza)", + "America\/Menominee": "Àm Meadhan Aimeireaga a Tuath (Menominee)", + "America\/Merida": "Àm Meadhan Aimeireaga a Tuath (Mérida)", + "America\/Metlakatla": "Àm Alaska (Metlakatla)", + "America\/Mexico_City": "Àm Meadhan Aimeireaga a Tuath (Cathair Mheagsago)", + "America\/Miquelon": "Àm Saint Pierre agus Miquelon (Miquelon)", + "America\/Moncton": "Àm a’ Chuain Siar (Moncton)", + "America\/Monterrey": "Àm Meadhan Aimeireaga a Tuath (Monterrey)", + "America\/Montevideo": "Àm Uruguaidh (Montevideo)", + "America\/Montserrat": "Àm a’ Chuain Siar (Montsarat)", + "America\/Nassau": "Àm Aimeireaga a Tuath an Ear (Nassau)", + "America\/New_York": "Àm Aimeireaga a Tuath an Ear (Nuadh Eabhrac)", + "America\/Nipigon": "Àm Aimeireaga a Tuath an Ear (Nipigon)", + "America\/Nome": "Àm Alaska (Nome)", + "America\/Noronha": "Àm Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Àm Meadhan Aimeireaga a Tuath (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Àm Meadhan Aimeireaga a Tuath (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Àm Meadhan Aimeireaga a Tuath (New Salem, North Dakota)", + "America\/Ojinaga": "Àm Monadh Aimeireaga a Tuath (Ojinaga)", + "America\/Panama": "Àm Aimeireaga a Tuath an Ear (Panama)", + "America\/Pangnirtung": "Àm Aimeireaga a Tuath an Ear (Pangniqtuuq)", + "America\/Paramaribo": "Àm Suranaim (Paramaribo)", + "America\/Phoenix": "Àm Monadh Aimeireaga a Tuath (Phoenix)", + "America\/Port-au-Prince": "Àm Aimeireaga a Tuath an Ear (Port-au-Prince)", + "America\/Port_of_Spain": "Àm a’ Chuain Siar (Port na Spàinne)", + "America\/Porto_Velho": "Àm Amasoin (Porto Velho)", + "America\/Puerto_Rico": "Àm a’ Chuain Siar (Porto Rìceo)", + "America\/Punta_Arenas": "Àm na Sile (Punta Arenas)", + "America\/Rainy_River": "Àm Meadhan Aimeireaga a Tuath (Rainy River)", + "America\/Rankin_Inlet": "Àm Meadhan Aimeireaga a Tuath (Kangiqliniq)", + "America\/Recife": "Àm Bhrasilia (Recife)", + "America\/Regina": "Àm Meadhan Aimeireaga a Tuath (Regina)", + "America\/Resolute": "Àm Meadhan Aimeireaga a Tuath (Qausuittuq)", + "America\/Rio_Branco": "Àm Acre (Rio Branco)", + "America\/Santa_Isabel": "Àm Mheagsago an Iar-thuath (Santa Isabel)", + "America\/Santarem": "Àm Bhrasilia (Santarém)", + "America\/Santiago": "Àm na Sile (Santiago)", + "America\/Santo_Domingo": "Àm a’ Chuain Siar (Santo Domingo)", + "America\/Sao_Paulo": "Àm Bhrasilia (São Paulo)", + "America\/Scoresbysund": "Àm na Graonlainn an Ear (Ittoqqortoormiit)", + "America\/Sitka": "Àm Alaska (Sitka)", + "America\/St_Barthelemy": "Àm a’ Chuain Siar (Saint Barthélemy)", + "America\/St_Johns": "Àm Talamh an Èisg (St. John’s)", + "America\/St_Kitts": "Àm a’ Chuain Siar (Naomh Crìstean)", + "America\/St_Lucia": "Àm a’ Chuain Siar (Naomh Lùisea)", + "America\/St_Thomas": "Àm a’ Chuain Siar (St. Thomas)", + "America\/St_Vincent": "Àm a’ Chuain Siar (Naomh Bhionsant)", + "America\/Swift_Current": "Àm Meadhan Aimeireaga a Tuath (Swift Current)", + "America\/Tegucigalpa": "Àm Meadhan Aimeireaga a Tuath (Tegucigalpa)", + "America\/Thule": "Àm a’ Chuain Siar (Qaanaaq)", + "America\/Thunder_Bay": "Àm Aimeireaga a Tuath an Ear (Thunder Bay)", + "America\/Tijuana": "Àm a’ Chuain Sèimh (Tijuana)", + "America\/Toronto": "Àm Aimeireaga a Tuath an Ear (Toronto)", + "America\/Tortola": "Àm a’ Chuain Siar (Tortola)", + "America\/Vancouver": "Àm a’ Chuain Sèimh (Vancouver)", + "America\/Whitehorse": "Àm a’ Chuain Sèimh (Whitehorse)", + "America\/Winnipeg": "Àm Meadhan Aimeireaga a Tuath (Winnipeg)", + "America\/Yakutat": "Àm Alaska (Yakutat)", + "America\/Yellowknife": "Àm Monadh Aimeireaga a Tuath (Yellowknife)", + "Antarctica\/Casey": "Àm Astràilia an Iar (Casey)", + "Antarctica\/Davis": "Àm Dhavis (Davis)", + "Antarctica\/DumontDUrville": "Àm Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Àm Eilein MhicGuaire (Eilean MhicGuaire)", + "Antarctica\/Mawson": "Àm Mhawson (Mawson)", + "Antarctica\/McMurdo": "Àm Shealainn Nuaidh (McMurdo)", + "Antarctica\/Palmer": "Àm na Sile (Palmer)", + "Antarctica\/Rothera": "Àm Rothera (Rothera)", + "Antarctica\/Syowa": "Àm Shyowa (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Àm Vostok (Vostok)", + "Arctic\/Longyearbyen": "Àm Meadhan na Roinn-Eòrpa (Longyearbyen)", + "Asia\/Aden": "Àm Arabach (Aden)", + "Asia\/Almaty": "Àm Casachstàin an Ear (Almaty)", + "Asia\/Amman": "Àm na Roinn-Eòrpa an Ear (Ammān)", + "Asia\/Anadyr": "Àm Anadyr (Anadyr)", + "Asia\/Aqtau": "Àm Casachstàin an Iar (Aqtau)", + "Asia\/Aqtobe": "Àm Casachstàin an Iar (Aqtöbe)", + "Asia\/Ashgabat": "Àm Turcmanastàin (Aşgabat)", + "Asia\/Atyrau": "Àm Casachstàin an Iar (Atyrau)", + "Asia\/Baghdad": "Àm Arabach (Baghdād)", + "Asia\/Bahrain": "Àm Arabach (Bachrain)", + "Asia\/Baku": "Àm Asarbaideàin (Baku)", + "Asia\/Bangkok": "Àm Sìn-Innseanach (Bangkok)", + "Asia\/Beirut": "Àm na Roinn-Eòrpa an Ear (Beirut)", + "Asia\/Bishkek": "Àm Cìorgastain (Bishkek)", + "Asia\/Brunei": "Àm Bhrùnaigh Dàr as-Salàm (Brùnaigh)", + "Asia\/Calcutta": "Àm nan Innseachan (Kolkata)", + "Asia\/Chita": "Àm Yakutsk (Chita)", + "Asia\/Choibalsan": "Àm Choibalsan (Choibalsan)", + "Asia\/Colombo": "Àm nan Innseachan (Colombo)", + "Asia\/Damascus": "Àm na Roinn-Eòrpa an Ear (Damascus)", + "Asia\/Dhaka": "Àm Bangladais (Dhaka)", + "Asia\/Dili": "Àm Thìomor an Ear (Dili)", + "Asia\/Dubai": "Àm a’ Chamais (Dubai)", + "Asia\/Dushanbe": "Àm Taidigeastàin (Dushanbe)", + "Asia\/Famagusta": "Àm na Roinn-Eòrpa an Ear (Famagusta)", + "Asia\/Gaza": "Àm na Roinn-Eòrpa an Ear (Gàsa)", + "Asia\/Hebron": "Àm na Roinn-Eòrpa an Ear (Hebron)", + "Asia\/Hong_Kong": "Àm Hong Kong (Hong Kong)", + "Asia\/Hovd": "Àm Hovd (Khovd)", + "Asia\/Irkutsk": "Àm Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Àm nan Innd-Innse an Iar (Jakarta)", + "Asia\/Jayapura": "Àm nan Innd-Innse an Ear (Jayapura)", + "Asia\/Jerusalem": "Àm Iosrael (Ierusalam)", + "Asia\/Kabul": "Àm Afghanastàin (Kabul)", + "Asia\/Kamchatka": "Àm Petropavlovsk-Kamchatsky (Kamchatka)", + "Asia\/Karachi": "Àm Pagastàin (Karācī)", + "Asia\/Katmandu": "Àm Neapàl (Kathmandu)", + "Asia\/Khandyga": "Àm Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Àm Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Àm Mhalaidhsea (Kuala Lumpur)", + "Asia\/Kuching": "Àm Mhalaidhsea (Kuching)", + "Asia\/Kuwait": "Àm Arabach (Cuibhèit)", + "Asia\/Macau": "Àm na Sìne (Macàthu)", + "Asia\/Magadan": "Àm Magadan (Magadan)", + "Asia\/Makassar": "Àm Meadhan nan Innd-Innse (Makassar)", + "Asia\/Manila": "Àm nan Eilean Filipineach (Manila)", + "Asia\/Muscat": "Àm a’ Chamais (Muscat)", + "Asia\/Nicosia": "Àm na Roinn-Eòrpa an Ear (Nicosia)", + "Asia\/Novokuznetsk": "Àm Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Àm Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Àm Omsk (Omsk)", + "Asia\/Oral": "Àm Casachstàin an Iar (Oral)", + "Asia\/Phnom_Penh": "Àm Sìn-Innseanach (Phnom Penh)", + "Asia\/Pontianak": "Àm nan Innd-Innse an Iar (Pontianak)", + "Asia\/Pyongyang": "Àm Choirèa (Pyeongyang)", + "Asia\/Qatar": "Àm Arabach (Catar)", + "Asia\/Qostanay": "Àm Casachstàin an Ear (Qostanay)", + "Asia\/Qyzylorda": "Àm Casachstàin an Iar (Qızılorda)", + "Asia\/Rangoon": "Àm Miànmar (Rangun)", + "Asia\/Riyadh": "Àm Arabach (Riyadh)", + "Asia\/Saigon": "Àm Sìn-Innseanach (Cathair Ho Chi Minh)", + "Asia\/Sakhalin": "Àm Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Àm Usbagastàn (Samarkand)", + "Asia\/Seoul": "Àm Choirèa (Seoul)", + "Asia\/Shanghai": "Àm na Sìne (Shanghai)", + "Asia\/Singapore": "Àm Singeapòr (Singeapòr)", + "Asia\/Srednekolymsk": "Àm Magadan (Srednekolymsk)", + "Asia\/Taipei": "Àm Taipei (Taipei)", + "Asia\/Tashkent": "Àm Usbagastàn (Tashkent)", + "Asia\/Tbilisi": "Àm na Cairtbheile (Tbilisi)", + "Asia\/Tehran": "Àm Ioràin (Tehrān)", + "Asia\/Thimphu": "Àm Butàin (Thimphu)", + "Asia\/Tokyo": "Àm na Seapaine (Tōkyō)", + "Asia\/Ulaanbaatar": "Àm Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Àm Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Àm Sìn-Innseanach (Viang Chan)", + "Asia\/Vladivostok": "Àm Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Àm Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Àm Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Àm Airmeinia (Yerevan)", + "Atlantic\/Azores": "Àm nan Eileanan Asorach (Ponta Delgada)", + "Atlantic\/Bermuda": "Àm a’ Chuain Siar (Bearmùda)", + "Atlantic\/Canary": "Àm na Roinn-Eòrpa an Iar (Na h-Eileanan Canàrach)", + "Atlantic\/Cape_Verde": "Àm a’ Chip Uaine (An Ceap Uaine)", + "Atlantic\/Faeroe": "Àm na Roinn-Eòrpa an Iar (Fàro)", + "Atlantic\/Madeira": "Àm na Roinn-Eòrpa an Iar (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavík)", + "Atlantic\/South_Georgia": "Àm Seòrsea a Deas (Seòrsea a Deas)", + "Atlantic\/St_Helena": "Greenwich Mean Time (Eilean Naomh Eilidh)", + "Atlantic\/Stanley": "Àm nan Eileanan Fàclannach (Stanley)", + "Australia\/Adelaide": "Àm Meadhan Astràilia (Adelaide)", + "Australia\/Brisbane": "Àm Astràilia an Ear (Brisbane)", + "Australia\/Broken_Hill": "Àm Meadhan Astràilia (Broken Hill)", + "Australia\/Currie": "Àm Astràilia an Ear (Currie)", + "Australia\/Darwin": "Àm Meadhan Astràilia (Darwin)", + "Australia\/Eucla": "Àm Meadhan Astràilia an Iar (Eucla)", + "Australia\/Hobart": "Àm Astràilia an Ear (Hobart)", + "Australia\/Lindeman": "Àm Astràilia an Ear (Lindeman)", + "Australia\/Lord_Howe": "Àm Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Àm Astràilia an Ear (Melbourne)", + "Australia\/Perth": "Àm Astràilia an Iar (Perth)", + "Australia\/Sydney": "Àm Astràilia an Ear (Sidni)", + "CST6CDT": "Àm Meadhan Aimeireaga a Tuath", + "EST5EDT": "Àm Aimeireaga a Tuath an Ear", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Àm Uile-choitcheann Co-òrdanaichte", + "Europe\/Amsterdam": "Àm Meadhan na Roinn-Eòrpa (Amsterdam)", + "Europe\/Andorra": "Àm Meadhan na Roinn-Eòrpa (Andorra)", + "Europe\/Astrakhan": "Àm Mhosgo (Astrakhan)", + "Europe\/Athens": "Àm na Roinn-Eòrpa an Ear (An Àithne)", + "Europe\/Belgrade": "Àm Meadhan na Roinn-Eòrpa (Belgrade)", + "Europe\/Berlin": "Àm Meadhan na Roinn-Eòrpa (Berlin)", + "Europe\/Bratislava": "Àm Meadhan na Roinn-Eòrpa (Bratislava)", + "Europe\/Brussels": "Àm Meadhan na Roinn-Eòrpa (A’ Bhruiseal)", + "Europe\/Bucharest": "Àm na Roinn-Eòrpa an Ear (Bucharest)", + "Europe\/Budapest": "Àm Meadhan na Roinn-Eòrpa (Budapest)", + "Europe\/Busingen": "Àm Meadhan na Roinn-Eòrpa (Busingen)", + "Europe\/Chisinau": "Àm na Roinn-Eòrpa an Ear (Chișinău)", + "Europe\/Copenhagen": "Àm Meadhan na Roinn-Eòrpa (Beirbh)", + "Europe\/Dublin": "Greenwich Mean Time (Baile Àtha Cliath)", + "Europe\/Gibraltar": "Àm Meadhan na Roinn-Eòrpa (Diobraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Geàrnsaidh)", + "Europe\/Helsinki": "Àm na Roinn-Eòrpa an Ear (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Eilean Mhanainn)", + "Europe\/Jersey": "Greenwich Mean Time (Deàrsaidh)", + "Europe\/Kaliningrad": "Àm na Roinn-Eòrpa an Ear (Kaliningrad)", + "Europe\/Kiev": "Àm na Roinn-Eòrpa an Ear (Kiev)", + "Europe\/Lisbon": "Àm na Roinn-Eòrpa an Iar (Lisbon)", + "Europe\/Ljubljana": "Àm Meadhan na Roinn-Eòrpa (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (Dùn Èideann\/Lunnainn)", + "Europe\/Luxembourg": "Àm Meadhan na Roinn-Eòrpa (Lugsamburg)", + "Europe\/Madrid": "Àm Meadhan na Roinn-Eòrpa (Madrid)", + "Europe\/Malta": "Àm Meadhan na Roinn-Eòrpa (Malta)", + "Europe\/Mariehamn": "Àm na Roinn-Eòrpa an Ear (Mariehamn)", + "Europe\/Minsk": "Àm Mhosgo (Minsk)", + "Europe\/Monaco": "Àm Meadhan na Roinn-Eòrpa (Monaco)", + "Europe\/Moscow": "Àm Mhosgo (Mosgo)", + "Europe\/Oslo": "Àm Meadhan na Roinn-Eòrpa (Oslo)", + "Europe\/Paris": "Àm Meadhan na Roinn-Eòrpa (Paras)", + "Europe\/Podgorica": "Àm Meadhan na Roinn-Eòrpa (Podgorica)", + "Europe\/Prague": "Àm Meadhan na Roinn-Eòrpa (Pràg)", + "Europe\/Riga": "Àm na Roinn-Eòrpa an Ear (Rīga)", + "Europe\/Rome": "Àm Meadhan na Roinn-Eòrpa (An Ròimh)", + "Europe\/Samara": "Àm Samara (Samara)", + "Europe\/San_Marino": "Àm Meadhan na Roinn-Eòrpa (San Marino)", + "Europe\/Sarajevo": "Àm Meadhan na Roinn-Eòrpa (Sarajevo)", + "Europe\/Saratov": "Àm Mhosgo (Saratov)", + "Europe\/Simferopol": "Àm Mhosgo (Simferopol)", + "Europe\/Skopje": "Àm Meadhan na Roinn-Eòrpa (Skopje)", + "Europe\/Sofia": "Àm na Roinn-Eòrpa an Ear (Sofiya)", + "Europe\/Stockholm": "Àm Meadhan na Roinn-Eòrpa (Stockholm)", + "Europe\/Tallinn": "Àm na Roinn-Eòrpa an Ear (Tallinn)", + "Europe\/Tirane": "Àm Meadhan na Roinn-Eòrpa (Tiranë)", + "Europe\/Ulyanovsk": "Àm Mhosgo (Ulyanovsk)", + "Europe\/Uzhgorod": "Àm na Roinn-Eòrpa an Ear (Uzhgorod)", + "Europe\/Vaduz": "Àm Meadhan na Roinn-Eòrpa (Vaduz)", + "Europe\/Vatican": "Àm Meadhan na Roinn-Eòrpa (A’ Bhatacan)", + "Europe\/Vienna": "Àm Meadhan na Roinn-Eòrpa (Vienna)", + "Europe\/Vilnius": "Àm na Roinn-Eòrpa an Ear (Vilnius)", + "Europe\/Volgograd": "Àm Volgograd (Volgograd)", + "Europe\/Warsaw": "Àm Meadhan na Roinn-Eòrpa (Warsaw)", + "Europe\/Zagreb": "Àm Meadhan na Roinn-Eòrpa (Zagreb)", + "Europe\/Zaporozhye": "Àm na Roinn-Eòrpa an Ear (Zaporozhye)", + "Europe\/Zurich": "Àm Meadhan na Roinn-Eòrpa (Zürich)", + "Indian\/Antananarivo": "Àm Afraga an Ear (Antananarivo)", + "Indian\/Chagos": "Àm Cuan nan Innseachan (Chagos)", + "Indian\/Christmas": "Àm Eilean na Nollaig (Nollaig)", + "Indian\/Cocos": "Àm Eileanan Chocos (Cocos)", + "Indian\/Comoro": "Àm Afraga an Ear (Comoro)", + "Indian\/Kerguelen": "Àm Deasach agus Antartaigeach na Frainge (Kergelenn)", + "Indian\/Mahe": "Àm nan Eileanan Sheiseall (Mahé)", + "Indian\/Maldives": "Àm nan Eileanan Mhaladaibh (Na h-Eileanan Mhaladaibh)", + "Indian\/Mauritius": "Àm nan Eileanan Mhoiriseas (Na h-Eileanan Mhoiriseas)", + "Indian\/Mayotte": "Àm Afraga an Ear (Mayotte)", + "Indian\/Reunion": "Àm Reunion (Réunion)", + "MST7MDT": "Àm Monadh Aimeireaga a Tuath", + "PST8PDT": "Àm a’ Chuain Sèimh", + "Pacific\/Apia": "Àm Apia (Apia)", + "Pacific\/Auckland": "Àm Shealainn Nuaidh (Auckland)", + "Pacific\/Bougainville": "Àm Gini Nuaidh Paputhaiche (Bougainville)", + "Pacific\/Chatham": "Àm Chatham (Chatham)", + "Pacific\/Easter": "Àm Eilean na Càisge (Rapa Nui)", + "Pacific\/Efate": "Àm Vanuatu (Efate)", + "Pacific\/Enderbury": "Àm Eileanan Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Àm Tokelau (Fakaofo)", + "Pacific\/Fiji": "Àm Fìdi (Fìdi)", + "Pacific\/Funafuti": "Àm Tubhalu (Funafuti)", + "Pacific\/Galapagos": "Àm Ghalapagos (Galápagos)", + "Pacific\/Gambier": "Àm Ghambier (Mangareva)", + "Pacific\/Guadalcanal": "Àm Eileanan Sholaimh (Guadalcanal)", + "Pacific\/Guam": "Àm Chamorro (Guam)", + "Pacific\/Honolulu": "Àm nan Eileanan Hawai’i ’s Aleutach (Honolulu)", + "Pacific\/Johnston": "Àm nan Eileanan Hawai’i ’s Aleutach (Johnston)", + "Pacific\/Kiritimati": "Àm Eileanan Teraina (Kiritimati)", + "Pacific\/Kosrae": "Àm Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Àm Eileanan Mharshall (Kwajalein)", + "Pacific\/Majuro": "Àm Eileanan Mharshall (Majuro)", + "Pacific\/Marquesas": "Àm Eileanan a’ Mharcais (Eileanan a’ Mharcais)", + "Pacific\/Midway": "Àm Samotha (Midway)", + "Pacific\/Nauru": "Àm Nabhru (Nabhru)", + "Pacific\/Niue": "Àm Niue (Niue)", + "Pacific\/Norfolk": "Àm Eilein Norfolk (Norfolk)", + "Pacific\/Noumea": "Àm Chailleann Nuaidh (Noumea)", + "Pacific\/Pago_Pago": "Àm Samotha (Pago Pago)", + "Pacific\/Palau": "Àm Palabh (Palabh)", + "Pacific\/Pitcairn": "Àm Peit a’ Chàirn (Peit a’ Chàirn)", + "Pacific\/Ponape": "Àm Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "Àm Gini Nuaidh Paputhaiche (Port Moresby)", + "Pacific\/Rarotonga": "Àm Eileanan Cook (Rarotonga)", + "Pacific\/Saipan": "Àm Chamorro (Saipan)", + "Pacific\/Tahiti": "Àm Tahiti (Tahiti)", + "Pacific\/Tarawa": "Àm Eileanan Ghileabairt (Tarawa)", + "Pacific\/Tongatapu": "Àm Tonga (Tongatapu)", + "Pacific\/Truk": "Àm Chuuk (Chuuk)", + "Pacific\/Wake": "Àm Eilean Wake (Wake)", + "Pacific\/Wallis": "Àm Uallas agus Futuna (Uallas)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/gl.json b/src/Symfony/Component/Intl/Resources/data/timezones/gl.json new file mode 100644 index 0000000000000..e467c2fdc7e0a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/gl.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Horario do meridiano de Greenwich (Abidjan)", + "Africa\/Accra": "Horario do meridiano de Greenwich (Acra)", + "Africa\/Addis_Ababa": "Horario de África Oriental (Adís Abeba)", + "Africa\/Algiers": "Horario de Europa Central (Alxer)", + "Africa\/Asmera": "Horario de África Oriental (Asmara)", + "Africa\/Bamako": "Horario do meridiano de Greenwich (Bamaco)", + "Africa\/Bangui": "Horario de África Occidental (Bangui)", + "Africa\/Banjul": "Horario do meridiano de Greenwich (Banjul)", + "Africa\/Bissau": "Horario do meridiano de Greenwich (Bissau)", + "Africa\/Blantyre": "Horario de África Central (Blantyre)", + "Africa\/Brazzaville": "Horario de África Occidental (Brazzaville)", + "Africa\/Bujumbura": "Horario de África Central (Bujumbura)", + "Africa\/Cairo": "Horario de Europa Oriental (O Cairo)", + "Africa\/Casablanca": "Horario de Europa Occidental (Casablanca)", + "Africa\/Ceuta": "Horario de Europa Central (Ceuta)", + "Africa\/Conakry": "Horario do meridiano de Greenwich (Conakry)", + "Africa\/Dakar": "Horario do meridiano de Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Horario de África Oriental (Dar es Salaam)", + "Africa\/Djibouti": "Horario de África Oriental (Djibuti)", + "Africa\/Douala": "Horario de África Occidental (Douala)", + "Africa\/El_Aaiun": "Horario de Europa Occidental (O Aiún)", + "Africa\/Freetown": "Horario do meridiano de Greenwich (Freetown)", + "Africa\/Gaborone": "Horario de África Central (Gaborone)", + "Africa\/Harare": "Horario de África Central (Harare)", + "Africa\/Johannesburg": "Horario estándar de África do Sur (Xohanesburgo)", + "Africa\/Juba": "Horario de África Oriental (Juba)", + "Africa\/Kampala": "Horario de África Oriental (Kampala)", + "Africa\/Khartoum": "Horario de África Central (Khartún)", + "Africa\/Kigali": "Horario de África Central (Kigali)", + "Africa\/Kinshasa": "Horario de África Occidental (Kinshasa)", + "Africa\/Lagos": "Horario de África Occidental (Lagos)", + "Africa\/Libreville": "Horario de África Occidental (Libreville)", + "Africa\/Lome": "Horario do meridiano de Greenwich (Lomé)", + "Africa\/Luanda": "Horario de África Occidental (Luanda)", + "Africa\/Lubumbashi": "Horario de África Central (Lubumbashi)", + "Africa\/Lusaka": "Horario de África Central (Lusaca)", + "Africa\/Malabo": "Horario de África Occidental (Malabo)", + "Africa\/Maputo": "Horario de África Central (Maputo)", + "Africa\/Maseru": "Horario estándar de África do Sur (Maseru)", + "Africa\/Mbabane": "Horario estándar de África do Sur (Mbabane)", + "Africa\/Mogadishu": "Horario de África Oriental (Mogadixo)", + "Africa\/Monrovia": "Horario do meridiano de Greenwich (Monrovia)", + "Africa\/Nairobi": "Horario de África Oriental (Nairobi)", + "Africa\/Ndjamena": "Horario de África Occidental (N’Djamena)", + "Africa\/Niamey": "Horario de África Occidental (Niamey)", + "Africa\/Nouakchott": "Horario do meridiano de Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Horario do meridiano de Greenwich (Uagadugu)", + "Africa\/Porto-Novo": "Horario de África Occidental (Porto-Novo)", + "Africa\/Sao_Tome": "Horario do meridiano de Greenwich (San Tomé)", + "Africa\/Tripoli": "Horario de Europa Oriental (Trípoli)", + "Africa\/Tunis": "Horario de Europa Central (Tunes)", + "Africa\/Windhoek": "Horario de África Central (Windhoek)", + "America\/Adak": "Horario de Hawai-Aleutiano (Adak)", + "America\/Anchorage": "Horario de Alasca (Anchorage)", + "America\/Anguilla": "Horario do Atlántico (Anguila)", + "America\/Antigua": "Horario do Atlántico (Antiga)", + "America\/Araguaina": "Horario de Brasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "Horario da Arxentina (A Rioxa)", + "America\/Argentina\/Rio_Gallegos": "Horario da Arxentina (Río Gallegos)", + "America\/Argentina\/Salta": "Horario da Arxentina (Salta)", + "America\/Argentina\/San_Juan": "Horario da Arxentina (San Juan)", + "America\/Argentina\/San_Luis": "Horario da Arxentina Occidental (San Luis)", + "America\/Argentina\/Tucuman": "Horario da Arxentina (Tucumán)", + "America\/Argentina\/Ushuaia": "Horario da Arxentina (Ushuaia)", + "America\/Aruba": "Horario do Atlántico (Aruba)", + "America\/Asuncion": "Horario de Paraguai (Asunción)", + "America\/Bahia": "Horario de Brasilia (Baía)", + "America\/Bahia_Banderas": "Horario central, Norteamérica (Bahía de Banderas)", + "America\/Barbados": "Horario do Atlántico (Barbados)", + "America\/Belem": "Horario de Brasilia (Belém)", + "America\/Belize": "Horario central, Norteamérica (Belize)", + "America\/Blanc-Sablon": "Horario do Atlántico (Blanc-Sablon)", + "America\/Boa_Vista": "Horario do Amazonas (Boa Vista)", + "America\/Bogota": "Horario de Colombia (Bogotá)", + "America\/Boise": "Horario da montaña, Norteamérica (Boise)", + "America\/Buenos_Aires": "Horario da Arxentina (Buenos Aires)", + "America\/Cambridge_Bay": "Horario da montaña, Norteamérica (Cambridge Bay)", + "America\/Campo_Grande": "Horario do Amazonas (Campo Grande)", + "America\/Cancun": "Horario do leste, Norteamérica (Cancún)", + "America\/Caracas": "Horario de Venezuela (Caracas)", + "America\/Catamarca": "Horario da Arxentina (Catamarca)", + "America\/Cayenne": "Horario da Güiana Francesa (Caiena)", + "America\/Cayman": "Horario do leste, Norteamérica (Caimán)", + "America\/Chicago": "Horario central, Norteamérica (Chicago)", + "America\/Chihuahua": "Horario do Pacífico mexicano (Chihuahua)", + "America\/Coral_Harbour": "Horario do leste, Norteamérica (Atikokan)", + "America\/Cordoba": "Horario da Arxentina (Córdoba)", + "America\/Costa_Rica": "Horario central, Norteamérica (Costa Rica)", + "America\/Creston": "Horario da montaña, Norteamérica (Creston)", + "America\/Cuiaba": "Horario do Amazonas (Cuiabá)", + "America\/Curacao": "Horario do Atlántico (Curaçao)", + "America\/Danmarkshavn": "Horario do meridiano de Greenwich (Danmarkshavn)", + "America\/Dawson": "Horario do Pacífico, Norteamérica (Dawson)", + "America\/Dawson_Creek": "Horario da montaña, Norteamérica (Dawson Creek)", + "America\/Denver": "Horario da montaña, Norteamérica (Denver)", + "America\/Detroit": "Horario do leste, Norteamérica (Detroit)", + "America\/Dominica": "Horario do Atlántico (Dominica)", + "America\/Edmonton": "Horario da montaña, Norteamérica (Edmonton)", + "America\/El_Salvador": "Horario central, Norteamérica (O Salvador)", + "America\/Fort_Nelson": "Horario da montaña, Norteamérica (Fort Nelson)", + "America\/Fortaleza": "Horario de Brasilia (Fortaleza)", + "America\/Glace_Bay": "Horario do Atlántico (Glace Bay)", + "America\/Godthab": "Horario de Groenlandia Occidental (Nuuk)", + "America\/Goose_Bay": "Horario do Atlántico (Goose Bay)", + "America\/Grand_Turk": "Horario do leste, Norteamérica (Grand Turk)", + "America\/Grenada": "Horario do Atlántico (Granada)", + "America\/Guadeloupe": "Horario do Atlántico (Guadalupe)", + "America\/Guatemala": "Horario central, Norteamérica (Guatemala)", + "America\/Guayaquil": "Horario de Ecuador (Guayaquil)", + "America\/Guyana": "Horario da Güiana (Güiana)", + "America\/Halifax": "Horario do Atlántico (Halifax)", + "America\/Havana": "Horario de Cuba (A Habana)", + "America\/Hermosillo": "Horario do Pacífico mexicano (Hermosillo)", + "America\/Indiana\/Knox": "Horario central, Norteamérica (Knox, Indiana)", + "America\/Indiana\/Marengo": "Horario do leste, Norteamérica (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Horario do leste, Norteamérica (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Horario central, Norteamérica (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Horario do leste, Norteamérica (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Horario do leste, Norteamérica (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Horario do leste, Norteamérica (Winamac, Indiana)", + "America\/Indianapolis": "Horario do leste, Norteamérica (Indianápolis)", + "America\/Inuvik": "Horario da montaña, Norteamérica (Inuvik)", + "America\/Iqaluit": "Horario do leste, Norteamérica (Iqaluit)", + "America\/Jamaica": "Horario do leste, Norteamérica (Xamaica)", + "America\/Jujuy": "Horario da Arxentina (Jujuy)", + "America\/Juneau": "Horario de Alasca (Juneau)", + "America\/Kentucky\/Monticello": "Horario do leste, Norteamérica (Monticello, Kentucky)", + "America\/Kralendijk": "Horario do Atlántico (Kralendijk)", + "America\/La_Paz": "Horario de Bolivia (A Paz)", + "America\/Lima": "Horario do Perú (Lima)", + "America\/Los_Angeles": "Horario do Pacífico, Norteamérica (Os Ánxeles)", + "America\/Louisville": "Horario do leste, Norteamérica (Louisville)", + "America\/Lower_Princes": "Horario do Atlántico (Lower Prince’s Quarter)", + "America\/Maceio": "Horario de Brasilia (Maceió)", + "America\/Managua": "Horario central, Norteamérica (Managua)", + "America\/Manaus": "Horario do Amazonas (Manaus)", + "America\/Marigot": "Horario do Atlántico (Marigot)", + "America\/Martinique": "Horario do Atlántico (Martinica)", + "America\/Matamoros": "Horario central, Norteamérica (Matamoros)", + "America\/Mazatlan": "Horario do Pacífico mexicano (Mazatlán)", + "America\/Mendoza": "Horario da Arxentina (Mendoza)", + "America\/Menominee": "Horario central, Norteamérica (Menominee)", + "America\/Merida": "Horario central, Norteamérica (Mérida)", + "America\/Metlakatla": "Horario de Alasca (Metlakatla)", + "America\/Mexico_City": "Horario central, Norteamérica (Cidade de México)", + "America\/Miquelon": "Horario de Saint Pierre et Miquelon (Miquelon)", + "America\/Moncton": "Horario do Atlántico (Moncton)", + "America\/Monterrey": "Horario central, Norteamérica (Monterrey)", + "America\/Montevideo": "Horario do Uruguai (Montevideo)", + "America\/Montserrat": "Horario do Atlántico (Montserrat)", + "America\/Nassau": "Horario do leste, Norteamérica (Nassau)", + "America\/New_York": "Horario do leste, Norteamérica (Nova York)", + "America\/Nipigon": "Horario do leste, Norteamérica (Nipigon)", + "America\/Nome": "Horario de Alasca (Nome)", + "America\/Noronha": "Horario de Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Horario central, Norteamérica (Beulah, Dacota do Norte)", + "America\/North_Dakota\/Center": "Horario central, Norteamérica (Center, Dacota do Norte)", + "America\/North_Dakota\/New_Salem": "Horario central, Norteamérica (New Salem, Dacota do Norte)", + "America\/Ojinaga": "Horario da montaña, Norteamérica (Ojinaga)", + "America\/Panama": "Horario do leste, Norteamérica (Panamá)", + "America\/Pangnirtung": "Horario do leste, Norteamérica (Pangnirtung)", + "America\/Paramaribo": "Horario de Suriname (Paramaribo)", + "America\/Phoenix": "Horario da montaña, Norteamérica (Phoenix)", + "America\/Port-au-Prince": "Horario do leste, Norteamérica (Porto Príncipe)", + "America\/Port_of_Spain": "Horario do Atlántico (Porto España)", + "America\/Porto_Velho": "Horario do Amazonas (Porto Velho)", + "America\/Puerto_Rico": "Horario do Atlántico (Porto Rico)", + "America\/Punta_Arenas": "Horario de Chile (Punta Arenas)", + "America\/Rainy_River": "Horario central, Norteamérica (Rainy River)", + "America\/Rankin_Inlet": "Horario central, Norteamérica (Rankin Inlet)", + "America\/Recife": "Horario de Brasilia (Recife)", + "America\/Regina": "Horario central, Norteamérica (Regina)", + "America\/Resolute": "Horario central, Norteamérica (Resolute)", + "America\/Santa_Isabel": "Horario do noroeste de México (Santa Isabel)", + "America\/Santarem": "Horario de Brasilia (Santarém)", + "America\/Santiago": "Horario de Chile (Santiago)", + "America\/Santo_Domingo": "Horario do Atlántico (Santo Domingo)", + "America\/Sao_Paulo": "Horario de Brasilia (São Paulo)", + "America\/Scoresbysund": "Horario de Groenlandia Oriental (Ittoqqortoormiit)", + "America\/Sitka": "Horario de Alasca (Sitka)", + "America\/St_Barthelemy": "Horario do Atlántico (Saint Barthélemy)", + "America\/St_Johns": "Horario de Terranova (Saint John’s)", + "America\/St_Kitts": "Horario do Atlántico (Saint Kitts)", + "America\/St_Lucia": "Horario do Atlántico (Santa Lucía)", + "America\/St_Thomas": "Horario do Atlántico (Saint Thomas)", + "America\/St_Vincent": "Horario do Atlántico (San Vicente)", + "America\/Swift_Current": "Horario central, Norteamérica (Swift Current)", + "America\/Tegucigalpa": "Horario central, Norteamérica (Tegucigalpa)", + "America\/Thule": "Horario do Atlántico (Thule)", + "America\/Thunder_Bay": "Horario do leste, Norteamérica (Thunder Bay)", + "America\/Tijuana": "Horario do Pacífico, Norteamérica (Tijuana)", + "America\/Toronto": "Horario do leste, Norteamérica (Toronto)", + "America\/Tortola": "Horario do Atlántico (Tórtola)", + "America\/Vancouver": "Horario do Pacífico, Norteamérica (Vancouver)", + "America\/Whitehorse": "Horario do Pacífico, Norteamérica (Whitehorse)", + "America\/Winnipeg": "Horario central, Norteamérica (Winnipeg)", + "America\/Yakutat": "Horario de Alasca (Yakutat)", + "America\/Yellowknife": "Horario da montaña, Norteamérica (Yellowknife)", + "Antarctica\/Casey": "Horario de Australia Occidental (Casey)", + "Antarctica\/Davis": "Horario de Davis (Davis)", + "Antarctica\/DumontDUrville": "Horario de Dumont-d’Urville (Dumont-d’Urville)", + "Antarctica\/Macquarie": "Horario da Illa Macquarie (Macquarie)", + "Antarctica\/Mawson": "Horario de Mawson (Mawson)", + "Antarctica\/McMurdo": "Horario de Nova Zelandia (McMurdo)", + "Antarctica\/Palmer": "Horario de Chile (Palmer)", + "Antarctica\/Rothera": "Horario de Rothera (Rothera)", + "Antarctica\/Syowa": "Horario de Syowa (Syowa)", + "Antarctica\/Troll": "Horario do meridiano de Greenwich (Troll)", + "Antarctica\/Vostok": "Horario de Vostok (Vostok)", + "Arctic\/Longyearbyen": "Horario de Europa Central (Longyearbyen)", + "Asia\/Aden": "Horario árabe (Adén)", + "Asia\/Almaty": "Horario de Casaquistán Oriental (Almati)", + "Asia\/Amman": "Horario de Europa Oriental (Amán)", + "Asia\/Anadyr": "Horario de Anadir (Anadyr)", + "Asia\/Aqtau": "Horario de Casaquistán Occidental (Aktau)", + "Asia\/Aqtobe": "Horario de Casaquistán Occidental (Aktobe)", + "Asia\/Ashgabat": "Horario de Turcomenistán (Achkhabad)", + "Asia\/Atyrau": "Horario de Casaquistán Occidental (Atyrau)", + "Asia\/Baghdad": "Horario árabe (Bagdad)", + "Asia\/Bahrain": "Horario árabe (Bahrain)", + "Asia\/Baku": "Horario de Acerbaixán (Bacú)", + "Asia\/Bangkok": "Horario de Indochina (Bangkok)", + "Asia\/Beirut": "Horario de Europa Oriental (Beirut)", + "Asia\/Bishkek": "Horario de Kirguizistán (Bishkek)", + "Asia\/Brunei": "Horario de Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Horario estándar da India (Calcuta)", + "Asia\/Chita": "Horario de Iakutsk (Chitá)", + "Asia\/Choibalsan": "Horario de Choibalsan (Choibalsan)", + "Asia\/Colombo": "Horario estándar da India (Colombo)", + "Asia\/Damascus": "Horario de Europa Oriental (Damasco)", + "Asia\/Dhaka": "Horario de Bangladesh (Dhaka)", + "Asia\/Dili": "Horario de Timor Leste (Dili)", + "Asia\/Dubai": "Horario estándar do Golfo (Dubai)", + "Asia\/Dushanbe": "Horario de Taxiquistán (Dushanbe)", + "Asia\/Famagusta": "Horario de Europa Oriental (Famagusta)", + "Asia\/Gaza": "Horario de Europa Oriental (Gaza)", + "Asia\/Hebron": "Horario de Europa Oriental (Hebrón)", + "Asia\/Hong_Kong": "Horario de Hong Kong (Hong Kong)", + "Asia\/Hovd": "Horario de Hovd (Hovd)", + "Asia\/Irkutsk": "Horario de Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Horario de Indonesia Occidental (Iacarta)", + "Asia\/Jayapura": "Horario de Indonesia Oriental (Jayapura)", + "Asia\/Jerusalem": "Horario de Israel (Xerusalén)", + "Asia\/Kabul": "Horario de Afganistán (Cabul)", + "Asia\/Kamchatka": "Horario de Petropávlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Horario de Paquistán (Karachi)", + "Asia\/Katmandu": "Horario de Nepal (Katmandú)", + "Asia\/Khandyga": "Horario de Iakutsk (Chandyga)", + "Asia\/Krasnoyarsk": "Horario de Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Horario de Malaisia (Kuala Lumpur)", + "Asia\/Kuching": "Horario de Malaisia (Kuching)", + "Asia\/Kuwait": "Horario árabe (Kuwait)", + "Asia\/Macau": "Horario da China (Macau)", + "Asia\/Magadan": "Horario de Magadan (Magadan)", + "Asia\/Makassar": "Horario de Indonesia Central (Makassar)", + "Asia\/Manila": "Horario de Filipinas (Manila)", + "Asia\/Muscat": "Horario estándar do Golfo (Mascate)", + "Asia\/Nicosia": "Horario de Europa Oriental (Nicosia)", + "Asia\/Novokuznetsk": "Horario de Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Horario de Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Horario de Omsk (Omsk)", + "Asia\/Oral": "Horario de Casaquistán Occidental (Oral)", + "Asia\/Phnom_Penh": "Horario de Indochina (Phnom Penh)", + "Asia\/Pontianak": "Horario de Indonesia Occidental (Pontianak)", + "Asia\/Pyongyang": "Horario de Corea (Pyongyang)", + "Asia\/Qatar": "Horario árabe (Qatar)", + "Asia\/Qostanay": "Horario de Casaquistán Oriental (Qostanay)", + "Asia\/Qyzylorda": "Horario de Casaquistán Occidental (Kyzylorda)", + "Asia\/Rangoon": "Horario de Birmania (Yangon)", + "Asia\/Riyadh": "Horario árabe (Riad)", + "Asia\/Saigon": "Horario de Indochina (Ho Chi Minh)", + "Asia\/Sakhalin": "Horario de Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Horario de Uzbequistán (Samarcanda)", + "Asia\/Seoul": "Horario de Corea (Seúl)", + "Asia\/Shanghai": "Horario da China (Shanghai)", + "Asia\/Singapore": "Horario estándar de Singapur (Singapur)", + "Asia\/Srednekolymsk": "Horario de Magadan (Srednekolimsk)", + "Asia\/Taipei": "Horario de Taipei (Taipei)", + "Asia\/Tashkent": "Horario de Uzbequistán (Tashkent)", + "Asia\/Tbilisi": "Horario de Xeorxia (Tbilisi)", + "Asia\/Tehran": "Horario de Irán (Teherán)", + "Asia\/Thimphu": "Horario de Bután (Thimbu)", + "Asia\/Tokyo": "Horario do Xapón (Tokyo)", + "Asia\/Ulaanbaatar": "Horario de Ulaanbaatar (Ulaanbaatar)", + "Asia\/Ust-Nera": "Horario de Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Horario de Indochina (Vientiane)", + "Asia\/Vladivostok": "Horario de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Horario de Iakutsk (Iakutsk)", + "Asia\/Yekaterinburg": "Horario de Ekaterimburgo (Ekaterinburgo)", + "Asia\/Yerevan": "Horario de Armenia (Iereván)", + "Atlantic\/Azores": "Horario das Azores (Azores)", + "Atlantic\/Bermuda": "Horario do Atlántico (Bermudas)", + "Atlantic\/Canary": "Horario de Europa Occidental (Illas Canarias)", + "Atlantic\/Cape_Verde": "Horario de Cabo Verde (Cabo Verde)", + "Atlantic\/Faeroe": "Horario de Europa Occidental (Feroe)", + "Atlantic\/Madeira": "Horario de Europa Occidental (Madeira)", + "Atlantic\/Reykjavik": "Horario do meridiano de Greenwich (Reiquiavik)", + "Atlantic\/South_Georgia": "Horario de Xeorxia do Sur (Xeorxia do Sur)", + "Atlantic\/St_Helena": "Horario do meridiano de Greenwich (Santa Helena)", + "Atlantic\/Stanley": "Horario das Illas Malvinas (Stanley)", + "Australia\/Adelaide": "Horario de Australia Central (Adelaida)", + "Australia\/Brisbane": "Horario de Australia Oriental (Brisbane)", + "Australia\/Broken_Hill": "Horario de Australia Central (Broken Hill)", + "Australia\/Currie": "Horario de Australia Oriental (Currie)", + "Australia\/Darwin": "Horario de Australia Central (Darwin)", + "Australia\/Eucla": "Horario de Australia Occidental Central (Eucla)", + "Australia\/Hobart": "Horario de Australia Oriental (Hobart)", + "Australia\/Lindeman": "Horario de Australia Oriental (Lindeman)", + "Australia\/Lord_Howe": "Horario de Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Horario de Australia Oriental (Melbourne)", + "Australia\/Perth": "Horario de Australia Occidental (Perth)", + "Australia\/Sydney": "Horario de Australia Oriental (Sidney)", + "CST6CDT": "Horario central, Norteamérica", + "EST5EDT": "Horario do leste, Norteamérica", + "Etc\/GMT": "Horario do meridiano de Greenwich", + "Etc\/UTC": "Horario universal coordinado", + "Europe\/Amsterdam": "Horario de Europa Central (Ámsterdan)", + "Europe\/Andorra": "Horario de Europa Central (Andorra)", + "Europe\/Astrakhan": "Horario de Moscova (Astrakán)", + "Europe\/Athens": "Horario de Europa Oriental (Atenas)", + "Europe\/Belgrade": "Horario de Europa Central (Belgrado)", + "Europe\/Berlin": "Horario de Europa Central (Berlín)", + "Europe\/Bratislava": "Horario de Europa Central (Bratislava)", + "Europe\/Brussels": "Horario de Europa Central (Bruxelas)", + "Europe\/Bucharest": "Horario de Europa Oriental (Bucarest)", + "Europe\/Budapest": "Horario de Europa Central (Budapest)", + "Europe\/Busingen": "Horario de Europa Central (Busingen)", + "Europe\/Chisinau": "Horario de Europa Oriental (Chisinau)", + "Europe\/Copenhagen": "Horario de Europa Central (Copenhague)", + "Europe\/Dublin": "Horario do meridiano de Greenwich (Dublín)", + "Europe\/Gibraltar": "Horario de Europa Central (Xibraltar)", + "Europe\/Guernsey": "Horario do meridiano de Greenwich (Guernsey)", + "Europe\/Helsinki": "Horario de Europa Oriental (Helsinqui)", + "Europe\/Isle_of_Man": "Horario do meridiano de Greenwich (Illa de Man)", + "Europe\/Jersey": "Horario do meridiano de Greenwich (Jersey)", + "Europe\/Kaliningrad": "Horario de Europa Oriental (Kaliningrado)", + "Europe\/Kiev": "Horario de Europa Oriental (Kiev)", + "Europe\/Lisbon": "Horario de Europa Occidental (Lisboa)", + "Europe\/Ljubljana": "Horario de Europa Central (Liubliana)", + "Europe\/London": "Horario do meridiano de Greenwich (Londres)", + "Europe\/Luxembourg": "Horario de Europa Central (Luxemburgo)", + "Europe\/Madrid": "Horario de Europa Central (Madrid)", + "Europe\/Malta": "Horario de Europa Central (Malta)", + "Europe\/Mariehamn": "Horario de Europa Oriental (Mariehamn)", + "Europe\/Minsk": "Horario de Moscova (Minsk)", + "Europe\/Monaco": "Horario de Europa Central (Mónaco)", + "Europe\/Moscow": "Horario de Moscova (Moscova)", + "Europe\/Oslo": "Horario de Europa Central (Oslo)", + "Europe\/Paris": "Horario de Europa Central (París)", + "Europe\/Podgorica": "Horario de Europa Central (Podgorica)", + "Europe\/Prague": "Horario de Europa Central (Praga)", + "Europe\/Riga": "Horario de Europa Oriental (Riga)", + "Europe\/Rome": "Horario de Europa Central (Roma)", + "Europe\/Samara": "Horario de Samara (Samara)", + "Europe\/San_Marino": "Horario de Europa Central (San Marino)", + "Europe\/Sarajevo": "Horario de Europa Central (Saraxevo)", + "Europe\/Saratov": "Horario de Moscova (Saratov)", + "Europe\/Simferopol": "Horario de Moscova (Simferópol)", + "Europe\/Skopje": "Horario de Europa Central (Skopje)", + "Europe\/Sofia": "Horario de Europa Oriental (Sofía)", + "Europe\/Stockholm": "Horario de Europa Central (Estocolmo)", + "Europe\/Tallinn": "Horario de Europa Oriental (Tallinn)", + "Europe\/Tirane": "Horario de Europa Central (Tirana)", + "Europe\/Ulyanovsk": "Horario de Moscova (Ulianovsk)", + "Europe\/Uzhgorod": "Horario de Europa Oriental (Úzhgorod)", + "Europe\/Vaduz": "Horario de Europa Central (Vaduz)", + "Europe\/Vatican": "Horario de Europa Central (Vaticano)", + "Europe\/Vienna": "Horario de Europa Central (Viena)", + "Europe\/Vilnius": "Horario de Europa Oriental (Vilnius)", + "Europe\/Volgograd": "Horario de Volgogrado (Volgogrado)", + "Europe\/Warsaw": "Horario de Europa Central (Varsovia)", + "Europe\/Zagreb": "Horario de Europa Central (Zagreb)", + "Europe\/Zaporozhye": "Horario de Europa Oriental (Zaporizhia)", + "Europe\/Zurich": "Horario de Europa Central (Zürich)", + "Indian\/Antananarivo": "Horario de África Oriental (Antananarivo)", + "Indian\/Chagos": "Horario do Océano Índico (Chagos)", + "Indian\/Christmas": "Horario da Illa de Nadal (Illa de Nadal)", + "Indian\/Cocos": "Horario das Illas Cocos (Cocos)", + "Indian\/Comoro": "Horario de África Oriental (Illas Comores)", + "Indian\/Kerguelen": "Horario das Terras Austrais e Antárticas Francesas (Kerguelen)", + "Indian\/Mahe": "Horario das Seychelles (Mahé)", + "Indian\/Maldives": "Horario das Maldivas (Maldivas)", + "Indian\/Mauritius": "Horario de Mauricio (Mauricio)", + "Indian\/Mayotte": "Horario de África Oriental (Mayotte)", + "Indian\/Reunion": "Horario de Reunión (Reunión)", + "MST7MDT": "Horario da montaña, Norteamérica", + "PST8PDT": "Horario do Pacífico, Norteamérica", + "Pacific\/Apia": "Horario de Apia (Apia)", + "Pacific\/Auckland": "Horario de Nova Zelandia (Auckland)", + "Pacific\/Bougainville": "Horario de Papúa-Nova Guinea (Bougainville)", + "Pacific\/Chatham": "Horario de Chatham (Chatham)", + "Pacific\/Easter": "Horario da Illa de Pascua (Illa de Pascua)", + "Pacific\/Efate": "Horario de Vanuatu (Efate)", + "Pacific\/Enderbury": "Horario das Illas Fénix (Enderbury)", + "Pacific\/Fakaofo": "Horario de Tokelau (Fakaofo)", + "Pacific\/Fiji": "Horario de Fidxi (Fidxi)", + "Pacific\/Funafuti": "Horario de Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Horario das Galápagos (Illas Galápagos)", + "Pacific\/Gambier": "Horario de Gambier (Gambier)", + "Pacific\/Guadalcanal": "Horario das Illas Salomón (Guadalcanal)", + "Pacific\/Guam": "Horario estándar chamorro (Guam)", + "Pacific\/Honolulu": "Horario de Hawai-Aleutiano (Honolulú)", + "Pacific\/Johnston": "Horario de Hawai-Aleutiano (Johnston)", + "Pacific\/Kiritimati": "Horario das Illas da Liña (Kiritimati)", + "Pacific\/Kosrae": "Horario de Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Horario das Illas Marshall (Kwajalein)", + "Pacific\/Majuro": "Horario das Illas Marshall (Majuro)", + "Pacific\/Marquesas": "Horario das Marquesas (Marquesas)", + "Pacific\/Midway": "Horario de Samoa (Midway)", + "Pacific\/Nauru": "Horario de Nauru (Nauru)", + "Pacific\/Niue": "Horario de Niue (Niue)", + "Pacific\/Norfolk": "Horario das Illas Norfolk (Norfolk)", + "Pacific\/Noumea": "Horario de Nova Caledonia (Noumea)", + "Pacific\/Pago_Pago": "Horario de Samoa (Pago Pago)", + "Pacific\/Palau": "Horario de Palau (Palau)", + "Pacific\/Pitcairn": "Horario de Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Horario de Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "Horario de Papúa-Nova Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Horario das Illas Cook (Rarotonga)", + "Pacific\/Saipan": "Horario estándar chamorro (Saipan)", + "Pacific\/Tahiti": "Horario de Tahití (Tahití)", + "Pacific\/Tarawa": "Horario das Illas Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Horario de Tonga (Tongatapu)", + "Pacific\/Truk": "Horario de Chuuk (Chuuk)", + "Pacific\/Wake": "Horario da Illa Wake (Wake)", + "Pacific\/Wallis": "Horario de Wallis e Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/gu.json b/src/Symfony/Component/Intl/Resources/data/timezones/gu.json new file mode 100644 index 0000000000000..3d5a62c53da90 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/gu.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "ગ્રીનવિચ મધ્યમ સમય (આબિદ્જાન)", + "Africa\/Accra": "ગ્રીનવિચ મધ્યમ સમય (ઍકરા)", + "Africa\/Addis_Ababa": "પૂર્વ આફ્રિકા સમય (એડિસ અબાબા)", + "Africa\/Algiers": "મધ્ય યુરોપિયન સમય (અલ્જીયર્સ)", + "Africa\/Asmera": "પૂર્વ આફ્રિકા સમય (અસ્મારા)", + "Africa\/Bamako": "ગ્રીનવિચ મધ્યમ સમય (બમેકો)", + "Africa\/Bangui": "પશ્ચિમ આફ્રિકા સમય (બાંગુઈ)", + "Africa\/Banjul": "ગ્રીનવિચ મધ્યમ સમય (બાંજુલ)", + "Africa\/Bissau": "ગ્રીનવિચ મધ્યમ સમય (બિસાઉ)", + "Africa\/Blantyre": "મધ્ય આફ્રિકા સમય (બ્લેંટીર)", + "Africa\/Brazzaville": "પશ્ચિમ આફ્રિકા સમય (બ્રાઝાવિલે)", + "Africa\/Bujumbura": "મધ્ય આફ્રિકા સમય (બુજમ્બુરા)", + "Africa\/Cairo": "પૂર્વી યુરોપિયન સમય (કૈરો)", + "Africa\/Casablanca": "પશ્ચિમી યુરોપિયન સમય (કાસાબ્લાંકા)", + "Africa\/Ceuta": "મધ્ય યુરોપિયન સમય (ક્વેટા)", + "Africa\/Conakry": "ગ્રીનવિચ મધ્યમ સમય (કોનૅક્રી)", + "Africa\/Dakar": "ગ્રીનવિચ મધ્યમ સમય (ડકાર)", + "Africa\/Dar_es_Salaam": "પૂર્વ આફ્રિકા સમય (દાર એસ સલામ)", + "Africa\/Djibouti": "પૂર્વ આફ્રિકા સમય (જીબુટી)", + "Africa\/Douala": "પશ્ચિમ આફ્રિકા સમય (ડૌઆલા)", + "Africa\/El_Aaiun": "પશ્ચિમી યુરોપિયન સમય (એલ ઐઉન)", + "Africa\/Freetown": "ગ્રીનવિચ મધ્યમ સમય (ફ્રીટાઉન)", + "Africa\/Gaborone": "મધ્ય આફ્રિકા સમય (ગૅબોરોન)", + "Africa\/Harare": "મધ્ય આફ્રિકા સમય (હરારે)", + "Africa\/Johannesburg": "દક્ષિણ આફ્રિકા માનક સમય (જોહાન્સબર્ગ)", + "Africa\/Juba": "પૂર્વ આફ્રિકા સમય (જુબા)", + "Africa\/Kampala": "પૂર્વ આફ્રિકા સમય (કમ્પાલા)", + "Africa\/Khartoum": "મધ્ય આફ્રિકા સમય (ખાર્ટૂમ)", + "Africa\/Kigali": "મધ્ય આફ્રિકા સમય (કિગાલી)", + "Africa\/Kinshasa": "પશ્ચિમ આફ્રિકા સમય (કિંશાસા)", + "Africa\/Lagos": "પશ્ચિમ આફ્રિકા સમય (લાગોસ)", + "Africa\/Libreville": "પશ્ચિમ આફ્રિકા સમય (લિબ્રેવિલે)", + "Africa\/Lome": "ગ્રીનવિચ મધ્યમ સમય (લોમ)", + "Africa\/Luanda": "પશ્ચિમ આફ્રિકા સમય (લ્યુએન્ડા)", + "Africa\/Lubumbashi": "મધ્ય આફ્રિકા સમય (લુબુમ્બાશી)", + "Africa\/Lusaka": "મધ્ય આફ્રિકા સમય (લુસાકા)", + "Africa\/Malabo": "પશ્ચિમ આફ્રિકા સમય (મલાબો)", + "Africa\/Maputo": "મધ્ય આફ્રિકા સમય (માપુટો)", + "Africa\/Maseru": "દક્ષિણ આફ્રિકા માનક સમય (મસેરુ)", + "Africa\/Mbabane": "દક્ષિણ આફ્રિકા માનક સમય (અમ્બબાન)", + "Africa\/Mogadishu": "પૂર્વ આફ્રિકા સમય (મોગાડીશુ)", + "Africa\/Monrovia": "ગ્રીનવિચ મધ્યમ સમય (મોંરોવિયા)", + "Africa\/Nairobi": "પૂર્વ આફ્રિકા સમય (નૈરોબી)", + "Africa\/Ndjamena": "પશ્ચિમ આફ્રિકા સમય (અન્જમેન)", + "Africa\/Niamey": "પશ્ચિમ આફ્રિકા સમય (નિયામી)", + "Africa\/Nouakchott": "ગ્રીનવિચ મધ્યમ સમય (નૌકચોટ)", + "Africa\/Ouagadougou": "ગ્રીનવિચ મધ્યમ સમય (ઔઆગાદૌગૌ)", + "Africa\/Porto-Novo": "પશ્ચિમ આફ્રિકા સમય (પોર્ટો-નોવો)", + "Africa\/Sao_Tome": "ગ્રીનવિચ મધ્યમ સમય (સાઓ ટૉમ)", + "Africa\/Tripoli": "પૂર્વી યુરોપિયન સમય (ટ્રીપોલી)", + "Africa\/Tunis": "મધ્ય યુરોપિયન સમય (ટ્યુનિસ)", + "Africa\/Windhoek": "મધ્ય આફ્રિકા સમય (વિંડહૉક)", + "America\/Adak": "હવાઈ-એલ્યુશિઅન સમય (અદક)", + "America\/Anchorage": "અલાસ્કા સમય (એન્કોરેજ)", + "America\/Anguilla": "એટલાન્ટિક સમય (ઍંગ્વિલા)", + "America\/Antigua": "એટલાન્ટિક સમય (ઍન્ટિગુઆ)", + "America\/Araguaina": "બ્રાઝિલિયા સમય (અરાગુઇના)", + "America\/Argentina\/La_Rioja": "આર્જેન્ટીના સમય (લા રિઓહા)", + "America\/Argentina\/Rio_Gallegos": "આર્જેન્ટીના સમય (રિઓ ગેલેગોસ)", + "America\/Argentina\/Salta": "આર્જેન્ટીના સમય (સાલ્ટા)", + "America\/Argentina\/San_Juan": "આર્જેન્ટીના સમય (સેન જુએન)", + "America\/Argentina\/San_Luis": "પશ્ચિમી આર્જેન્ટીના સમય (સેન લુઇસ)", + "America\/Argentina\/Tucuman": "આર્જેન્ટીના સમય (તુકુમાન)", + "America\/Argentina\/Ushuaia": "આર્જેન્ટીના સમય (ઉશાયા)", + "America\/Aruba": "એટલાન્ટિક સમય (અરુબા)", + "America\/Asuncion": "પેરાગ્વે સમય (એસન્શિયન)", + "America\/Bahia": "બ્રાઝિલિયા સમય (બાહિયા)", + "America\/Bahia_Banderas": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (બહિયા બાંદ્રાસ)", + "America\/Barbados": "એટલાન્ટિક સમય (બારબાડોસ)", + "America\/Belem": "બ્રાઝિલિયા સમય (બેલેમ)", + "America\/Belize": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (બેલીઝ)", + "America\/Blanc-Sablon": "એટલાન્ટિક સમય (બ્લાંક-સેબલોન)", + "America\/Boa_Vista": "એમેઝોન સમય (બોઆ વિસ્ટા)", + "America\/Bogota": "કોલંબિયા સમય (બોગોટા)", + "America\/Boise": "ઉત્તર અમેરિકન માઉન્ટન સમય (બોઇઝ)", + "America\/Buenos_Aires": "આર્જેન્ટીના સમય (બ્યુનસ એયર્સ)", + "America\/Cambridge_Bay": "ઉત્તર અમેરિકન માઉન્ટન સમય (કેમ્બ્રિજ બે)", + "America\/Campo_Grande": "એમેઝોન સમય (કામ્પો ગ્રાંડ)", + "America\/Cancun": "ઉત્તર અમેરિકન પૂર્વી સમય (કાન્કુન)", + "America\/Caracas": "વેનેઝુએલા સમય (કૅરાકસ)", + "America\/Catamarca": "આર્જેન્ટીના સમય (કાતામાર્કા)", + "America\/Cayenne": "ફ્રેંચ ગયાના સમય (કાયેને)", + "America\/Cayman": "ઉત્તર અમેરિકન પૂર્વી સમય (કેમેન)", + "America\/Chicago": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (શિકાગો)", + "America\/Chihuahua": "મેક્સિકન પેસિફિક સમય (ચિહુઆહુઆ)", + "America\/Coral_Harbour": "ઉત્તર અમેરિકન પૂર્વી સમય (એટિકોકેન)", + "America\/Cordoba": "આર્જેન્ટીના સમય (કોર્ડોબા)", + "America\/Costa_Rica": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (કોસ્ટા રિકા)", + "America\/Creston": "ઉત્તર અમેરિકન માઉન્ટન સમય (ક્રેસ્ટન)", + "America\/Cuiaba": "એમેઝોન સમય (ક્યુએબા)", + "America\/Curacao": "એટલાન્ટિક સમય (કુરાકાઓ)", + "America\/Danmarkshavn": "ગ્રીનવિચ મધ્યમ સમય (ડેનમાર્કશૉન)", + "America\/Dawson": "ઉત્તર અમેરિકન પેસિફિક સમય (ડૌસન)", + "America\/Dawson_Creek": "ઉત્તર અમેરિકન માઉન્ટન સમય (ડૌસન ક્રિક)", + "America\/Denver": "ઉત્તર અમેરિકન માઉન્ટન સમય (દેન્વર)", + "America\/Detroit": "ઉત્તર અમેરિકન પૂર્વી સમય (ડેટ્રોઇટ)", + "America\/Dominica": "એટલાન્ટિક સમય (ડોમિનિકા)", + "America\/Edmonton": "ઉત્તર અમેરિકન માઉન્ટન સમય (એડમેન્ટન)", + "America\/Eirunepe": "એકર સમય (ઇરુનેપ)", + "America\/El_Salvador": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (એલ સેલ્વાડોર)", + "America\/Fort_Nelson": "ઉત્તર અમેરિકન માઉન્ટન સમય (ફોર્ટ નેલ્સન)", + "America\/Fortaleza": "બ્રાઝિલિયા સમય (ફોર્ટાલેઝા)", + "America\/Glace_Bay": "એટલાન્ટિક સમય (ગ્લેસ બે)", + "America\/Godthab": "પશ્ચિમ ગ્રીનલેન્ડ સમય (નૂક)", + "America\/Goose_Bay": "એટલાન્ટિક સમય (ગૂસ બે)", + "America\/Grand_Turk": "ઉત્તર અમેરિકન પૂર્વી સમય (ગ્રાન્ડ ટર્ક)", + "America\/Grenada": "એટલાન્ટિક સમય (ગ્રેનેડા)", + "America\/Guadeloupe": "એટલાન્ટિક સમય (ગ્વાડેલોપ)", + "America\/Guatemala": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (ગ્વાટેમાલા)", + "America\/Guayaquil": "એક્વાડોર સમય (ગુયાક્વિલ)", + "America\/Guyana": "ગયાના સમય (ગયાના)", + "America\/Halifax": "એટલાન્ટિક સમય (હેલિફેક્સ)", + "America\/Havana": "ક્યુબા સમય (હવાના)", + "America\/Hermosillo": "મેક્સિકન પેસિફિક સમય (એરમોસિયો)", + "America\/Indiana\/Knox": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (નોક્સ, ઇન્ડિયાના)", + "America\/Indiana\/Marengo": "ઉત્તર અમેરિકન પૂર્વી સમય (મેરેંગો, ઇન્ડિયાના)", + "America\/Indiana\/Petersburg": "ઉત્તર અમેરિકન પૂર્વી સમય (પિટર્સબર્ગ, ઇન્ડિયાના)", + "America\/Indiana\/Tell_City": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (ટેલ સિટી, ઇન્ડિયાના)", + "America\/Indiana\/Vevay": "ઉત્તર અમેરિકન પૂર્વી સમય (વેવૈ, ઇન્ડિયાના)", + "America\/Indiana\/Vincennes": "ઉત્તર અમેરિકન પૂર્વી સમય (વિન્સેન્સ, ઇન્ડિયાના)", + "America\/Indiana\/Winamac": "ઉત્તર અમેરિકન પૂર્વી સમય (વિનામેક, ઇન્ડિયાના)", + "America\/Indianapolis": "ઉત્તર અમેરિકન પૂર્વી સમય (ઇન્ડિયાનાપોલિસ)", + "America\/Inuvik": "ઉત્તર અમેરિકન માઉન્ટન સમય (ઇનુવિક)", + "America\/Iqaluit": "ઉત્તર અમેરિકન પૂર્વી સમય (ઇકાલુઇત)", + "America\/Jamaica": "ઉત્તર અમેરિકન પૂર્વી સમય (જમૈકા)", + "America\/Jujuy": "આર્જેન્ટીના સમય (હુહુઇ)", + "America\/Juneau": "અલાસ્કા સમય (જુનેઇ)", + "America\/Kentucky\/Monticello": "ઉત્તર અમેરિકન પૂર્વી સમય (મોન્ટીસેલો, કેન્ટુકી)", + "America\/Kralendijk": "એટલાન્ટિક સમય (ક્રાલેન્ડિક)", + "America\/La_Paz": "બોલિવિયા સમય (લા પેઝ)", + "America\/Lima": "પેરુ સમય (લિમા)", + "America\/Los_Angeles": "ઉત્તર અમેરિકન પેસિફિક સમય (લોસ એંજેલેસ)", + "America\/Louisville": "ઉત્તર અમેરિકન પૂર્વી સમય (લૂઇવિલ)", + "America\/Lower_Princes": "એટલાન્ટિક સમય (લોઅર પ્રિન્સનું ક્વાર્ટર)", + "America\/Maceio": "બ્રાઝિલિયા સમય (મેસિઓ)", + "America\/Managua": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (માનાગુઆ)", + "America\/Manaus": "એમેઝોન સમય (મનૌસ)", + "America\/Marigot": "એટલાન્ટિક સમય (મેરીગોટ)", + "America\/Martinique": "એટલાન્ટિક સમય (માર્ટીનીક)", + "America\/Matamoros": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (માતામોરોસ)", + "America\/Mazatlan": "મેક્સિકન પેસિફિક સમય (મઝત્લાન)", + "America\/Mendoza": "આર્જેન્ટીના સમય (મેન્ડોઝા)", + "America\/Menominee": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (મેનોમિની)", + "America\/Merida": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (મેરિદા)", + "America\/Metlakatla": "અલાસ્કા સમય (મેટ્લાકાટ્લા)", + "America\/Mexico_City": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (મેક્સિકો સિટી)", + "America\/Miquelon": "સેંટ પીએરી અને મિક્યુલોન સમય (મિક્યુલોન)", + "America\/Moncton": "એટલાન્ટિક સમય (મોન્કટન)", + "America\/Monterrey": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (મોન્તોરે)", + "America\/Montevideo": "ઉરુગ્વે સમય (મૉંટેવિડિઓ)", + "America\/Montserrat": "એટલાન્ટિક સમય (મોંટસેરાત)", + "America\/Nassau": "ઉત્તર અમેરિકન પૂર્વી સમય (નાસાઉ)", + "America\/New_York": "ઉત્તર અમેરિકન પૂર્વી સમય (ન્યૂયોર્ક)", + "America\/Nipigon": "ઉત્તર અમેરિકન પૂર્વી સમય (નિપિગોન)", + "America\/Nome": "અલાસ્કા સમય (નોમ)", + "America\/Noronha": "ફર્નાન્ડો ડી નોરોન્હા સમય (નોરોન્હા)", + "America\/North_Dakota\/Beulah": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (બિયુલાહ, ઉત્તર ડેકોટા)", + "America\/North_Dakota\/Center": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (સેન્ટર, ઉત્તર ડેકોટા)", + "America\/North_Dakota\/New_Salem": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (ન્યુ સેલમ, ઉત્તર ડેકોટા)", + "America\/Ojinaga": "ઉત્તર અમેરિકન માઉન્ટન સમય (ઓજિનાગા)", + "America\/Panama": "ઉત્તર અમેરિકન પૂર્વી સમય (પનામા)", + "America\/Pangnirtung": "ઉત્તર અમેરિકન પૂર્વી સમય (પેંગનિરતુંગ)", + "America\/Paramaribo": "સુરીનામ સમય (પેરામેરિબો)", + "America\/Phoenix": "ઉત્તર અમેરિકન માઉન્ટન સમય (ફોનિક્સ)", + "America\/Port-au-Prince": "ઉત્તર અમેરિકન પૂર્વી સમય (પોર્ટ-ઓ-પ્રિન્સ)", + "America\/Port_of_Spain": "એટલાન્ટિક સમય (પોર્ટ ઑફ સ્પેન)", + "America\/Porto_Velho": "એમેઝોન સમય (પોર્ટો વેલ્હો)", + "America\/Puerto_Rico": "એટલાન્ટિક સમય (પ્યુઅર્ટો રિકો)", + "America\/Punta_Arenas": "ચિલી સમય (પુન્ટા એરીનાઝ)", + "America\/Rainy_River": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (રેઇની નદી)", + "America\/Rankin_Inlet": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (રેંકિન ઇન્લેટ)", + "America\/Recife": "બ્રાઝિલિયા સમય (રેસીફ)", + "America\/Regina": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (રેજીના)", + "America\/Resolute": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (રેઝોલૂટ)", + "America\/Rio_Branco": "એકર સમય (રિયો બ્રાંકો)", + "America\/Santa_Isabel": "ઉત્તરપશ્ચિમ મેક્સિકો સમય (સાંતા ઇસાબેલ)", + "America\/Santarem": "બ્રાઝિલિયા સમય (સેન્તારેમ)", + "America\/Santiago": "ચિલી સમય (સાંટિયાગો)", + "America\/Santo_Domingo": "એટલાન્ટિક સમય (સેંટો ડોમિંગો)", + "America\/Sao_Paulo": "બ્રાઝિલિયા સમય (સાઓ પાઉલો)", + "America\/Scoresbysund": "પૂર્વ ગ્રીનલેન્ડ સમય (ઇતોકોર્ટોરોમિટ)", + "America\/Sitka": "અલાસ્કા સમય (સિટ્કા)", + "America\/St_Barthelemy": "એટલાન્ટિક સમય (સેંટ બાર્થેલેમી)", + "America\/St_Johns": "ન્યૂફાઉન્ડલેન્ડ સમય (સેંટ જ્હોન્સ)", + "America\/St_Kitts": "એટલાન્ટિક સમય (સેંટ કીટ્સ)", + "America\/St_Lucia": "એટલાન્ટિક સમય (સેંટ લુસિયા)", + "America\/St_Thomas": "એટલાન્ટિક સમય (સેંટ થોમસ)", + "America\/St_Vincent": "એટલાન્ટિક સમય (સેંટ વિન્સેન્ટ)", + "America\/Swift_Current": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (સ્વિફ્ટ કરંટ)", + "America\/Tegucigalpa": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (તેગુસિગલ્પા)", + "America\/Thule": "એટલાન્ટિક સમય (થુલે)", + "America\/Thunder_Bay": "ઉત્તર અમેરિકન પૂર્વી સમય (થંડર બે)", + "America\/Tijuana": "ઉત્તર અમેરિકન પેસિફિક સમય (તિજુઆના)", + "America\/Toronto": "ઉત્તર અમેરિકન પૂર્વી સમય (ટોરન્ટો)", + "America\/Tortola": "એટલાન્ટિક સમય (ટોર્ટોલા)", + "America\/Vancouver": "ઉત્તર અમેરિકન પેસિફિક સમય (વેન્કુવર)", + "America\/Whitehorse": "ઉત્તર અમેરિકન પેસિફિક સમય (વ્હાઇટહોર્સ)", + "America\/Winnipeg": "ઉત્તર અમેરિકન કેન્દ્રીય સમય (વિન્નિપેગ)", + "America\/Yakutat": "અલાસ્કા સમય (યકુતત)", + "America\/Yellowknife": "ઉત્તર અમેરિકન માઉન્ટન સમય (યેલોનાઇફ)", + "Antarctica\/Casey": "પશ્ચિમી ઓસ્ટ્રેલિયા સમય (કૅસી)", + "Antarctica\/Davis": "ડેવિસ સમય (ડૅવિસ)", + "Antarctica\/DumontDUrville": "ડ્યુમોન્ટ-ડી‘ઉર્વિલ સમય (દુમોન્ત દી‘ઉર્વિલ)", + "Antarctica\/Macquarie": "મેક્વાયર આઇલેન્ડ સમય (મેક્વેરી)", + "Antarctica\/Mawson": "મોસન સમય (મોસન)", + "Antarctica\/McMurdo": "ન્યુઝીલેન્ડ સમય (મૅકમર્ડો)", + "Antarctica\/Palmer": "ચિલી સમય (પાલ્મર)", + "Antarctica\/Rothera": "રોથેરા સમય (રોથેરા)", + "Antarctica\/Syowa": "સ્યોવા સમય (સ્યોવા)", + "Antarctica\/Troll": "ગ્રીનવિચ મધ્યમ સમય (ટ્રોલ)", + "Antarctica\/Vostok": "વોસ્ટોક સમય (વોસ્ટૉક)", + "Arctic\/Longyearbyen": "મધ્ય યુરોપિયન સમય (લોંગઇયરબિયેન)", + "Asia\/Aden": "અરેબિયન સમય (એદેન)", + "Asia\/Almaty": "પૂર્વ કઝાકિસ્તાન સમય (અલ્માટી)", + "Asia\/Amman": "પૂર્વી યુરોપિયન સમય (અમ્માન)", + "Asia\/Anadyr": "અનાદિર સમય (અનદિર)", + "Asia\/Aqtau": "પશ્ચિમ કઝાકિસ્તાન સમય (અકટાઉ)", + "Asia\/Aqtobe": "પશ્ચિમ કઝાકિસ્તાન સમય (ઍક્ટોબ)", + "Asia\/Ashgabat": "તુર્કમેનિસ્તાન સમય (અશગાબટ)", + "Asia\/Atyrau": "પશ્ચિમ કઝાકિસ્તાન સમય (અત્યારુ)", + "Asia\/Baghdad": "અરેબિયન સમય (બગદાદ)", + "Asia\/Bahrain": "અરેબિયન સમય (બેહરીન)", + "Asia\/Baku": "અઝરબૈજાન સમય (બાકુ)", + "Asia\/Bangkok": "ઇન્ડોચાઇના સમય (બેંગકોક)", + "Asia\/Beirut": "પૂર્વી યુરોપિયન સમય (બૈરુત)", + "Asia\/Bishkek": "કિર્ગિઝતાન સમય (બિશકેક)", + "Asia\/Brunei": "બ્રૂનેઈ દારુસલામ સમય (બ્રુનેઇ)", + "Asia\/Calcutta": "ભારતીય માનક સમય (કોલકાતા)", + "Asia\/Chita": "યાકુત્સ્ક સમય (ચિતા)", + "Asia\/Choibalsan": "ચોઇબાલ્સન સમય (ચોઇબાલ્સન)", + "Asia\/Colombo": "ભારતીય માનક સમય (કોલંબો)", + "Asia\/Damascus": "પૂર્વી યુરોપિયન સમય (દમાસ્કસ)", + "Asia\/Dhaka": "બાંગ્લાદેશ સમય (ઢાકા)", + "Asia\/Dili": "પૂર્વ તિમોર સમય (દિલિ)", + "Asia\/Dubai": "ગલ્ફ માનક સમય (દુબઈ)", + "Asia\/Dushanbe": "તાજીકિસ્તાન સમય (દુશામ્બે)", + "Asia\/Famagusta": "પૂર્વી યુરોપિયન સમય (ફામાગુસ્તા)", + "Asia\/Gaza": "પૂર્વી યુરોપિયન સમય (ગાઝા)", + "Asia\/Hebron": "પૂર્વી યુરોપિયન સમય (હેબ્રોન)", + "Asia\/Hong_Kong": "હોંગ કોંગ સમય (હોંગકોંગ)", + "Asia\/Hovd": "હોવ્ડ સમય (હોવ્ડ)", + "Asia\/Irkutsk": "ઇર્કુત્સ્ક સમય (ઇર્કુત્સ્ક)", + "Asia\/Jakarta": "પશ્ચિમી ઇન્ડોનેશિયા સમય (જકાર્તા)", + "Asia\/Jayapura": "પૂર્વીય ઇન્ડોનેશિયા સમય (જયાપુરા)", + "Asia\/Jerusalem": "ઇઝરાઇલ સમય (જેરુસલેમ)", + "Asia\/Kabul": "અફઘાનિસ્તાન સમય (કાબુલ)", + "Asia\/Kamchatka": "પેટ્રોપેવલોવ્સ્ક-કામચતસ્કી સમય (કામચટ્કા)", + "Asia\/Karachi": "પાકિસ્તાન સમય (કરાચી)", + "Asia\/Katmandu": "નેપાળ સમય (કાઠમંડુ)", + "Asia\/Khandyga": "યાકુત્સ્ક સમય (ખંડિગા)", + "Asia\/Krasnoyarsk": "ક્રેસ્નોયાર્સ્ક સમય (ક્રિસ્નોયાર્સ્ક)", + "Asia\/Kuala_Lumpur": "મલેશિયા સમય (કુઆલા લુમ્પુર)", + "Asia\/Kuching": "મલેશિયા સમય (કુચિંગ)", + "Asia\/Kuwait": "અરેબિયન સમય (કુવૈત)", + "Asia\/Macau": "ચીન સમય (મકાઉ)", + "Asia\/Magadan": "મગાડન સમય (મેગાડન)", + "Asia\/Makassar": "મધ્ય ઇન્ડોનેશિયા સમય (માકસ્સર)", + "Asia\/Manila": "ફિલિપાઇન સમય (મનિલા)", + "Asia\/Muscat": "ગલ્ફ માનક સમય (મસ્કત)", + "Asia\/Nicosia": "પૂર્વી યુરોપિયન સમય (નિકોસિયા)", + "Asia\/Novokuznetsk": "ક્રેસ્નોયાર્સ્ક સમય (નોવોકુઝ્નેત્સ્ક)", + "Asia\/Novosibirsk": "નોવસિબિર્સ્ક સમય (નોવોસીર્બિર્સ્ક)", + "Asia\/Omsk": "ઓમ્સ્ક સમય (ઓમ્સ્ક)", + "Asia\/Oral": "પશ્ચિમ કઝાકિસ્તાન સમય (ઓરલ)", + "Asia\/Phnom_Penh": "ઇન્ડોચાઇના સમય (ફ્નોમ પેન્હ)", + "Asia\/Pontianak": "પશ્ચિમી ઇન્ડોનેશિયા સમય (પોન્ટિયનેક)", + "Asia\/Pyongyang": "કોરિયન સમય (પ્યોંગયાંગ)", + "Asia\/Qatar": "અરેબિયન સમય (કતાર)", + "Asia\/Qostanay": "પૂર્વ કઝાકિસ્તાન સમય (કોસ્ટાને)", + "Asia\/Qyzylorda": "પશ્ચિમ કઝાકિસ્તાન સમય (કિઝિલોર્ડા)", + "Asia\/Rangoon": "મ્યાનમાર સમય (રંગૂન)", + "Asia\/Riyadh": "અરેબિયન સમય (રિયાધ)", + "Asia\/Saigon": "ઇન્ડોચાઇના સમય (હો ચી મીન સિટી)", + "Asia\/Sakhalin": "સખાલિન સમય (સખાલિન)", + "Asia\/Samarkand": "ઉઝ્બેકિસ્તાન સમય (સમરકન્ડ)", + "Asia\/Seoul": "કોરિયન સમય (સીઓલ)", + "Asia\/Shanghai": "ચીન સમય (શાંઘાઈ)", + "Asia\/Singapore": "સિંગાપુર માનક સમય (સિંગાપુર)", + "Asia\/Srednekolymsk": "મગાડન સમય (સ્રેડ્નેકોલીમ્સ્ક)", + "Asia\/Taipei": "તાઇપેઇ સમય (તાઇપેઇ)", + "Asia\/Tashkent": "ઉઝ્બેકિસ્તાન સમય (તાશકેન્ટ)", + "Asia\/Tbilisi": "જ્યોર્જિયા સમય (બિલિસિ)", + "Asia\/Tehran": "ઈરાન સમય (તેહરાન)", + "Asia\/Thimphu": "ભૂટાન સમય (થીમ્ફુ)", + "Asia\/Tokyo": "જાપાન સમય (ટોક્યો)", + "Asia\/Ulaanbaatar": "ઉલાન બાટોર સમય (ઉલાંબાતર)", + "Asia\/Ust-Nera": "વ્લાડિવોસ્ટોક સમય (ઉસ્ત-નેરા)", + "Asia\/Vientiane": "ઇન્ડોચાઇના સમય (વિયેનટિયેન)", + "Asia\/Vladivostok": "વ્લાડિવોસ્ટોક સમય (વ્લેડિવોસ્ટોક)", + "Asia\/Yakutsk": "યાકુત્સ્ક સમય (યકુત્સક)", + "Asia\/Yekaterinburg": "યેકાટેરિનબર્ગ સમય (યેકાતેરિનબર્ગ)", + "Asia\/Yerevan": "આર્મેનિયા સમય (યેરેવાન)", + "Atlantic\/Azores": "એઝોર્સ સમય (એઝોરેઝ)", + "Atlantic\/Bermuda": "એટલાન્ટિક સમય (બર્મુડા)", + "Atlantic\/Canary": "પશ્ચિમી યુરોપિયન સમય (કૅનેરી)", + "Atlantic\/Cape_Verde": "કૅપ વર્ડે સમય (કૅપ વર્ડે)", + "Atlantic\/Faeroe": "પશ્ચિમી યુરોપિયન સમય (ફેરો)", + "Atlantic\/Madeira": "પશ્ચિમી યુરોપિયન સમય (મડિરા)", + "Atlantic\/Reykjavik": "ગ્રીનવિચ મધ્યમ સમય (રૅકયાવિક)", + "Atlantic\/South_Georgia": "સાઉથ જ્યોર્જિયા સમય (સાઉથ જ્યોર્જિયા)", + "Atlantic\/St_Helena": "ગ્રીનવિચ મધ્યમ સમય (સેંટ હેલેના)", + "Atlantic\/Stanley": "ફોકલૅંડ આઇલેન્ડ્સ સમય (સ્ટેનલી)", + "Australia\/Adelaide": "કેન્દ્રીય ઓસ્ટ્રેલિયન સમય (એડિલેઇડ)", + "Australia\/Brisbane": "પૂર્વીય ઓસ્ટ્રેલિયા સમય (બ્રિસબેન)", + "Australia\/Broken_Hill": "કેન્દ્રીય ઓસ્ટ્રેલિયન સમય (બ્રોકન હિલ)", + "Australia\/Currie": "પૂર્વીય ઓસ્ટ્રેલિયા સમય (ક્યુરી)", + "Australia\/Darwin": "કેન્દ્રીય ઓસ્ટ્રેલિયન સમય (ડાર્વિન)", + "Australia\/Eucla": "ઓસ્ટ્રેલિયન કેન્દ્રીય પશ્ચિમી સમય (ઉક્લા)", + "Australia\/Hobart": "પૂર્વીય ઓસ્ટ્રેલિયા સમય (હોબાર્ટ)", + "Australia\/Lindeman": "પૂર્વીય ઓસ્ટ્રેલિયા સમય (લિન્ડેમેન)", + "Australia\/Lord_Howe": "લોર્ડ હોવ સમય (લોર્ડ હોવ)", + "Australia\/Melbourne": "પૂર્વીય ઓસ્ટ્રેલિયા સમય (મેલબોર્ન)", + "Australia\/Perth": "પશ્ચિમી ઓસ્ટ્રેલિયા સમય (પર્થ)", + "Australia\/Sydney": "પૂર્વીય ઓસ્ટ્રેલિયા સમય (સિડની)", + "CST6CDT": "ઉત્તર અમેરિકન કેન્દ્રીય સમય", + "EST5EDT": "ઉત્તર અમેરિકન પૂર્વી સમય", + "Etc\/GMT": "ગ્રીનવિચ મધ્યમ સમય", + "Etc\/UTC": "સંકલિત યુનિવર્સલ સમય", + "Europe\/Amsterdam": "મધ્ય યુરોપિયન સમય (ઍમ્સ્ટરડૅમ)", + "Europe\/Andorra": "મધ્ય યુરોપિયન સમય (ઍંડોરા)", + "Europe\/Astrakhan": "મોસ્કો સમય (આસ્ટ્રખન)", + "Europe\/Athens": "પૂર્વી યુરોપિયન સમય (એથેંસ)", + "Europe\/Belgrade": "મધ્ય યુરોપિયન સમય (બેલગ્રેડ)", + "Europe\/Berlin": "મધ્ય યુરોપિયન સમય (બર્લિન)", + "Europe\/Bratislava": "મધ્ય યુરોપિયન સમય (બ્રેટિસલાવા)", + "Europe\/Brussels": "મધ્ય યુરોપિયન સમય (બ્રસેલ્સ)", + "Europe\/Bucharest": "પૂર્વી યુરોપિયન સમય (બુકરેસ્ટ)", + "Europe\/Budapest": "મધ્ય યુરોપિયન સમય (બુડાપેસ્ટ)", + "Europe\/Busingen": "મધ્ય યુરોપિયન સમય (બિઝેન્ગન)", + "Europe\/Chisinau": "પૂર્વી યુરોપિયન સમય (ચિસીનાઉ)", + "Europe\/Copenhagen": "મધ્ય યુરોપિયન સમય (કોપનહેગન)", + "Europe\/Dublin": "ગ્રીનવિચ મધ્યમ સમય (ડબલિન)", + "Europe\/Gibraltar": "મધ્ય યુરોપિયન સમય (જિબ્રાલ્ટર)", + "Europe\/Guernsey": "ગ્રીનવિચ મધ્યમ સમય (ગર્નઝી)", + "Europe\/Helsinki": "પૂર્વી યુરોપિયન સમય (હેલસિંકી)", + "Europe\/Isle_of_Man": "ગ્રીનવિચ મધ્યમ સમય (આઇલ ઑફ મેન)", + "Europe\/Jersey": "ગ્રીનવિચ મધ્યમ સમય (જર્સી)", + "Europe\/Kaliningrad": "પૂર્વી યુરોપિયન સમય (કલિનિન્ગ્રેડ)", + "Europe\/Kiev": "પૂર્વી યુરોપિયન સમય (કૈવ)", + "Europe\/Lisbon": "પશ્ચિમી યુરોપિયન સમય (લિસ્બન)", + "Europe\/Ljubljana": "મધ્ય યુરોપિયન સમય (લુબ્લિયાના)", + "Europe\/London": "ગ્રીનવિચ મધ્યમ સમય (લંડન)", + "Europe\/Luxembourg": "મધ્ય યુરોપિયન સમય (લક્ઝમબર્ગ)", + "Europe\/Madrid": "મધ્ય યુરોપિયન સમય (મેડ્રિડ)", + "Europe\/Malta": "મધ્ય યુરોપિયન સમય (માલ્ટા)", + "Europe\/Mariehamn": "પૂર્વી યુરોપિયન સમય (મેરિહેમ)", + "Europe\/Minsk": "મોસ્કો સમય (મિંસ્ક)", + "Europe\/Monaco": "મધ્ય યુરોપિયન સમય (મોનાકો)", + "Europe\/Moscow": "મોસ્કો સમય (મોસ્કો)", + "Europe\/Oslo": "મધ્ય યુરોપિયન સમય (ઑસ્લો)", + "Europe\/Paris": "મધ્ય યુરોપિયન સમય (પેરિસ)", + "Europe\/Podgorica": "મધ્ય યુરોપિયન સમય (પોડગોરિકા)", + "Europe\/Prague": "મધ્ય યુરોપિયન સમય (પ્રાગ)", + "Europe\/Riga": "પૂર્વી યુરોપિયન સમય (રિગા)", + "Europe\/Rome": "મધ્ય યુરોપિયન સમય (રોમ)", + "Europe\/Samara": "સમારા સમય (સમારા)", + "Europe\/San_Marino": "મધ્ય યુરોપિયન સમય (સૅન મેરિનો)", + "Europe\/Sarajevo": "મધ્ય યુરોપિયન સમય (સારાજેવો)", + "Europe\/Saratov": "મોસ્કો સમય (સારાટોવ)", + "Europe\/Simferopol": "મોસ્કો સમય (સિમ્ફેરોપોલ)", + "Europe\/Skopje": "મધ્ય યુરોપિયન સમય (સ્કોપયે)", + "Europe\/Sofia": "પૂર્વી યુરોપિયન સમય (સોફિયા)", + "Europe\/Stockholm": "મધ્ય યુરોપિયન સમય (સ્ટોકહૉમ)", + "Europe\/Tallinn": "પૂર્વી યુરોપિયન સમય (તલ્લીન)", + "Europe\/Tirane": "મધ્ય યુરોપિયન સમય (તિરાને)", + "Europe\/Ulyanovsk": "મોસ્કો સમય (ઉલેનોવ્સ્ક)", + "Europe\/Uzhgorod": "પૂર્વી યુરોપિયન સમય (ઉઝ્ગોરોદ)", + "Europe\/Vaduz": "મધ્ય યુરોપિયન સમય (વૅદુઝ)", + "Europe\/Vatican": "મધ્ય યુરોપિયન સમય (વેટિકન)", + "Europe\/Vienna": "મધ્ય યુરોપિયન સમય (વિયેના)", + "Europe\/Vilnius": "પૂર્વી યુરોપિયન સમય (વિલ્નિઅસ)", + "Europe\/Volgograd": "વોલ્ગોગ્રેડ સમય (વોલ્ગોગ્રેડ)", + "Europe\/Warsaw": "મધ્ય યુરોપિયન સમય (વોરસૉ)", + "Europe\/Zagreb": "મધ્ય યુરોપિયન સમય (ઝેગરેબ)", + "Europe\/Zaporozhye": "પૂર્વી યુરોપિયન સમય (જેપોરોઝિયે)", + "Europe\/Zurich": "મધ્ય યુરોપિયન સમય (ઝુરીક)", + "Indian\/Antananarivo": "પૂર્વ આફ્રિકા સમય (અંતાનાનારિવો)", + "Indian\/Chagos": "ભારતીય મહાસાગર સમય (ચાગોસ)", + "Indian\/Christmas": "ક્રિસમસ આઇલેન્ડ સમય (ક્રિસમસ)", + "Indian\/Cocos": "કોકોઝ આઇલેન્ડ્સ સમય (કૉકોસ)", + "Indian\/Comoro": "પૂર્વ આફ્રિકા સમય (કોમોરો)", + "Indian\/Kerguelen": "ફ્રેંચ સધર્ન અને એન્ટાર્કટિક સમય (કેરગ્વેલિન)", + "Indian\/Mahe": "સેશલ્સ સમય (માહે)", + "Indian\/Maldives": "માલદીવ સમય (માલદિવ્સ)", + "Indian\/Mauritius": "મોરિશિયસ સમય (મોરિશિયસ)", + "Indian\/Mayotte": "પૂર્વ આફ્રિકા સમય (મેયોટ)", + "Indian\/Reunion": "રીયુનિયન સમય (રિયુનિયન)", + "MST7MDT": "ઉત્તર અમેરિકન માઉન્ટન સમય", + "PST8PDT": "ઉત્તર અમેરિકન પેસિફિક સમય", + "Pacific\/Apia": "એપિયા સમય (એપિયા)", + "Pacific\/Auckland": "ન્યુઝીલેન્ડ સમય (ઑકલેન્ડ)", + "Pacific\/Bougainville": "પાપુઆ ન્યુ ગિની સમય (બૌગેઈનવિલે)", + "Pacific\/Chatham": "ચેતહામ સમય (ચથમ)", + "Pacific\/Easter": "ઇસ્ટર આઇલેન્ડ સમય (ઇસ્ટર)", + "Pacific\/Efate": "વનાતૂ સમય (એફેટ)", + "Pacific\/Enderbury": "ફોનિક્સ આઇલેન્ડ્સ સમય (એંડર્બરી)", + "Pacific\/Fakaofo": "ટોકલાઉ સમય (ફાકાઓફો)", + "Pacific\/Fiji": "ફીજી સમય (ફીજી)", + "Pacific\/Funafuti": "ટવાલૂ સમય (ફુનાફુટી)", + "Pacific\/Galapagos": "ગાલાપાગોસ સમય (ગાલાપેગોસ)", + "Pacific\/Gambier": "ગેમ્બિયર સમય (ગેમ્બિયર)", + "Pacific\/Guadalcanal": "સોલોમન આઇલેન્ડ્સ સમય (ગૌડલકૅનલ)", + "Pacific\/Guam": "કેમોરો માનક સમય (ગ્વામ)", + "Pacific\/Honolulu": "હવાઈ-એલ્યુશિઅન સમય (હોનોલુલુ)", + "Pacific\/Johnston": "હવાઈ-એલ્યુશિઅન સમય (જોહ્નસ્ટોન)", + "Pacific\/Kiritimati": "લાઇન આઇલેન્ડ્સ સમય (કિરિતિમાતી)", + "Pacific\/Kosrae": "કોસરે સમય (કોસરે)", + "Pacific\/Kwajalein": "માર્શલ આઇલેન્ડ્સ સમય (ક્વાજાલીન)", + "Pacific\/Majuro": "માર્શલ આઇલેન્ડ્સ સમય (માજુરો)", + "Pacific\/Marquesas": "માર્ક્યૂસસ સમય (માર્કીસાસ)", + "Pacific\/Midway": "સમોઆ સમય (મીડવે)", + "Pacific\/Nauru": "નૌરુ સમય (નૌરુ)", + "Pacific\/Niue": "નીયુ સમય (નીયુ)", + "Pacific\/Norfolk": "નોરફૉક આઇલેન્ડ સમય (નૉરફૉક)", + "Pacific\/Noumea": "ન્યુ સેલેડોનિયા સમય (નૌમીઆ)", + "Pacific\/Pago_Pago": "સમોઆ સમય (પેગો પેગો)", + "Pacific\/Palau": "પલાઉ સમય (પલાઉ)", + "Pacific\/Pitcairn": "પિટકેયર્ન સમય (પીટકૈર્ન)", + "Pacific\/Ponape": "પોનપે સમય (પોન્પે)", + "Pacific\/Port_Moresby": "પાપુઆ ન્યુ ગિની સમય (પોર્ટ મોર્સ્બી)", + "Pacific\/Rarotonga": "કુક આઇલેન્ડ્સ સમય (રેરોટોંગા)", + "Pacific\/Saipan": "કેમોરો માનક સમય (સાઇપન)", + "Pacific\/Tahiti": "તાહિતી સમય (તાહીતી)", + "Pacific\/Tarawa": "ગિલબર્ટ આઇલેન્ડ્સ સમય (તારાવા)", + "Pacific\/Tongatapu": "ટોંગા સમય (ટૉંગાટાપુ)", + "Pacific\/Truk": "ચુઉક સમય (ચુક)", + "Pacific\/Wake": "વૅક આઇલેન્ડ સમય (વેક)", + "Pacific\/Wallis": "વૉલિસ અને ફ્યુચુના સમય (વાલિસ)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ha.json b/src/Symfony/Component/Intl/Resources/data/timezones/ha.json new file mode 100644 index 0000000000000..a02c6a4867d1b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ha.json @@ -0,0 +1,206 @@ +{ + "Version": "2.1.48.45", + "Names": { + "Africa\/Abidjan": "Lokacin Greenwhich a London (Abidjan)", + "Africa\/Accra": "Lokacin Greenwhich a London (Accra)", + "Africa\/Algiers": "Tsakiyar a lokaci turai (Algiers)", + "Africa\/Bamako": "Lokacin Greenwhich a London (Bamako)", + "Africa\/Banjul": "Lokacin Greenwhich a London (Banjul)", + "Africa\/Bissau": "Lokacin Greenwhich a London (Bissau)", + "Africa\/Cairo": "Lokaci a turai gabas (Cairo)", + "Africa\/Casablanca": "Lokaci ta yammacin turai (Casablanca)", + "Africa\/Ceuta": "Tsakiyar a lokaci turai (Ceuta)", + "Africa\/Conakry": "Lokacin Greenwhich a London (Conakry)", + "Africa\/Dakar": "Lokacin Greenwhich a London (Dakar)", + "Africa\/El_Aaiun": "Lokaci ta yammacin turai (El Aaiun)", + "Africa\/Freetown": "Lokacin Greenwhich a London (Freetown)", + "Africa\/Lome": "Lokacin Greenwhich a London (Lome)", + "Africa\/Monrovia": "Lokacin Greenwhich a London (Monrovia)", + "Africa\/Nouakchott": "Lokacin Greenwhich a London (Nouakchott)", + "Africa\/Ouagadougou": "Lokacin Greenwhich a London (Ouagadougou)", + "Africa\/Sao_Tome": "Lokacin Greenwhich a London (Sao Tome)", + "Africa\/Tripoli": "Lokaci a turai gabas (Tripoli)", + "Africa\/Tunis": "Tsakiyar a lokaci turai (Tunis)", + "America\/Adak": "Lokaci ta Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Lokaci ta Alaska (Anchorage)", + "America\/Anguilla": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Anguilla)", + "America\/Antigua": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Antigua)", + "America\/Aruba": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Aruba)", + "America\/Bahia_Banderas": "Lokaci dake Amurika arewa ta tsakiyar (Bahia Banderas)", + "America\/Barbados": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Barbados)", + "America\/Belize": "Lokaci dake Amurika arewa ta tsakiyar (Belize)", + "America\/Blanc-Sablon": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Blanc-Sablon)", + "America\/Boise": "Lokaci tsauni a arewacin da Amirka (Boise)", + "America\/Cambridge_Bay": "Lokaci tsauni a arewacin da Amirka (Cambridge Bay)", + "America\/Cancun": "Lokaci gabas a arewacin da Amirka (Cancun)", + "America\/Cayman": "Lokaci gabas a arewacin da Amirka (Cayman)", + "America\/Chicago": "Lokaci dake Amurika arewa ta tsakiyar (Chicago)", + "America\/Chihuahua": "Lokaci a lafiya ta Mesiko (Chihuahua)", + "America\/Coral_Harbour": "Lokaci gabas a arewacin da Amirka (Atikokan)", + "America\/Costa_Rica": "Lokaci dake Amurika arewa ta tsakiyar (Costa Rica)", + "America\/Creston": "Lokaci tsauni a arewacin da Amirka (Creston)", + "America\/Curacao": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Curacao)", + "America\/Danmarkshavn": "Lokacin Greenwhich a London (Danmarkshavn)", + "America\/Dawson": "Amurika da arewa a lokaci lafiya (Dawson)", + "America\/Dawson_Creek": "Lokaci tsauni a arewacin da Amirka (Dawson Creek)", + "America\/Denver": "Lokaci tsauni a arewacin da Amirka (Denver)", + "America\/Detroit": "Lokaci gabas a arewacin da Amirka (Detroit)", + "America\/Dominica": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Dominica)", + "America\/Edmonton": "Lokaci tsauni a arewacin da Amirka (Edmonton)", + "America\/El_Salvador": "Lokaci dake Amurika arewa ta tsakiyar (El Salvador)", + "America\/Fort_Nelson": "Lokaci tsauni a arewacin da Amirka (Fort Nelson)", + "America\/Glace_Bay": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Glace Bay)", + "America\/Godthab": "Lokaci a yammacin ta Greeland (Nuuk)", + "America\/Goose_Bay": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Goose Bay)", + "America\/Grand_Turk": "Lokaci gabas a arewacin da Amirka (Grand Turk)", + "America\/Grenada": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Grenada)", + "America\/Guadeloupe": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Guadeloupe)", + "America\/Guatemala": "Lokaci dake Amurika arewa ta tsakiyar (Guatemala)", + "America\/Halifax": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Halifax)", + "America\/Havana": "Lokaci ta Kuba (Havana)", + "America\/Hermosillo": "Lokaci a lafiya ta Mesiko (Hermosillo)", + "America\/Indiana\/Knox": "Lokaci dake Amurika arewa ta tsakiyar (Knox, Indiana)", + "America\/Indiana\/Marengo": "Lokaci gabas a arewacin da Amirka (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Lokaci gabas a arewacin da Amirka (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Lokaci dake Amurika arewa ta tsakiyar (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Lokaci gabas a arewacin da Amirka (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Lokaci gabas a arewacin da Amirka (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Lokaci gabas a arewacin da Amirka (Winamac, Indiana)", + "America\/Indianapolis": "Lokaci gabas a arewacin da Amirka (Indianapolis)", + "America\/Inuvik": "Lokaci tsauni a arewacin da Amirka (Inuvik)", + "America\/Iqaluit": "Lokaci gabas a arewacin da Amirka (Iqaluit)", + "America\/Jamaica": "Lokaci gabas a arewacin da Amirka (Jamaica)", + "America\/Juneau": "Lokaci ta Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Lokaci gabas a arewacin da Amirka (Monticello, Kentucky)", + "America\/Kralendijk": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Kralendijk)", + "America\/Los_Angeles": "Amurika da arewa a lokaci lafiya (Los Angeles)", + "America\/Louisville": "Lokaci gabas a arewacin da Amirka (Louisville)", + "America\/Lower_Princes": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Lower Prince’s Quarter)", + "America\/Managua": "Lokaci dake Amurika arewa ta tsakiyar (Managua)", + "America\/Marigot": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Marigot)", + "America\/Martinique": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Martinique)", + "America\/Matamoros": "Lokaci dake Amurika arewa ta tsakiyar (Matamoros)", + "America\/Mazatlan": "Lokaci a lafiya ta Mesiko (Mazatlan)", + "America\/Menominee": "Lokaci dake Amurika arewa ta tsakiyar (Menominee)", + "America\/Merida": "Lokaci dake Amurika arewa ta tsakiyar (Merida)", + "America\/Metlakatla": "Lokaci ta Alaska (Metlakatla)", + "America\/Mexico_City": "Lokaci dake Amurika arewa ta tsakiyar (Mexico City)", + "America\/Miquelon": "Lokaci ta St. Pierre da Miquelon (Miquelon)", + "America\/Moncton": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Moncton)", + "America\/Monterrey": "Lokaci dake Amurika arewa ta tsakiyar (Monterrey)", + "America\/Montserrat": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Montserrat)", + "America\/Nassau": "Lokaci gabas a arewacin da Amirka (Nassau)", + "America\/New_York": "Lokaci gabas a arewacin da Amirka (New York)", + "America\/Nipigon": "Lokaci gabas a arewacin da Amirka (Nipigon)", + "America\/Nome": "Lokaci ta Alaska (Nome)", + "America\/North_Dakota\/Beulah": "Lokaci dake Amurika arewa ta tsakiyar (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Lokaci dake Amurika arewa ta tsakiyar (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Lokaci dake Amurika arewa ta tsakiyar (New Salem, North Dakota)", + "America\/Ojinaga": "Lokaci tsauni a arewacin da Amirka (Ojinaga)", + "America\/Panama": "Lokaci gabas a arewacin da Amirka (Panama)", + "America\/Pangnirtung": "Lokaci gabas a arewacin da Amirka (Pangnirtung)", + "America\/Phoenix": "Lokaci tsauni a arewacin da Amirka (Phoenix)", + "America\/Port-au-Prince": "Lokaci gabas a arewacin da Amirka (Port-au-Prince)", + "America\/Port_of_Spain": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Port of Spain)", + "America\/Puerto_Rico": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Puerto Rico)", + "America\/Rainy_River": "Lokaci dake Amurika arewa ta tsakiyar (Rainy River)", + "America\/Rankin_Inlet": "Lokaci dake Amurika arewa ta tsakiyar (Rankin Inlet)", + "America\/Regina": "Lokaci dake Amurika arewa ta tsakiyar (Regina)", + "America\/Resolute": "Lokaci dake Amurika arewa ta tsakiyar (Resolute)", + "America\/Santa_Isabel": "Lokaci a arewa da yammacin ta Mesiko (Santa Isabel)", + "America\/Santo_Domingo": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Santo Domingo)", + "America\/Scoresbysund": "Lokaci a gabas ta Greeland (Ittoqqortoormiit)", + "America\/Sitka": "Lokaci ta Alaska (Sitka)", + "America\/St_Barthelemy": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Barthelemy)", + "America\/St_Johns": "Lokaci ta Newfoundland (St. John’s)", + "America\/St_Kitts": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Kitts)", + "America\/St_Lucia": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Lucia)", + "America\/St_Thomas": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Thomas)", + "America\/St_Vincent": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Vincent)", + "America\/Swift_Current": "Lokaci dake Amurika arewa ta tsakiyar (Swift Current)", + "America\/Tegucigalpa": "Lokaci dake Amurika arewa ta tsakiyar (Tegucigalpa)", + "America\/Thule": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Thule)", + "America\/Thunder_Bay": "Lokaci gabas a arewacin da Amirka (Thunder Bay)", + "America\/Tijuana": "Amurika da arewa a lokaci lafiya (Tijuana)", + "America\/Toronto": "Lokaci gabas a arewacin da Amirka (Toronto)", + "America\/Tortola": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Tortola)", + "America\/Vancouver": "Amurika da arewa a lokaci lafiya (Vancouver)", + "America\/Whitehorse": "Amurika da arewa a lokaci lafiya (Whitehorse)", + "America\/Winnipeg": "Lokaci dake Amurika arewa ta tsakiyar (Winnipeg)", + "America\/Yakutat": "Lokaci ta Alaska (Yakutat)", + "America\/Yellowknife": "Lokaci tsauni a arewacin da Amirka (Yellowknife)", + "Antarctica\/Troll": "Lokacin Greenwhich a London (Troll)", + "Arctic\/Longyearbyen": "Tsakiyar a lokaci turai (Longyearbyen)", + "Asia\/Amman": "Lokaci a turai gabas (Amman)", + "Asia\/Beirut": "Lokaci a turai gabas (Beirut)", + "Asia\/Damascus": "Lokaci a turai gabas (Damascus)", + "Asia\/Famagusta": "Lokaci a turai gabas (Famagusta)", + "Asia\/Gaza": "Lokaci a turai gabas (Gaza)", + "Asia\/Hebron": "Lokaci a turai gabas (Hebron)", + "Asia\/Nicosia": "Lokaci a turai gabas (Nicosia)", + "Atlantic\/Bermuda": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Bermuda)", + "Atlantic\/Canary": "Lokaci ta yammacin turai (Canary)", + "Atlantic\/Faeroe": "Lokaci ta yammacin turai (Faroe)", + "Atlantic\/Madeira": "Lokaci ta yammacin turai (Madeira)", + "Atlantic\/Reykjavik": "Lokacin Greenwhich a London (Reykjavik)", + "Atlantic\/St_Helena": "Lokacin Greenwhich a London (St. Helena)", + "CST6CDT": "Lokaci dake Amurika arewa ta tsakiyar", + "EST5EDT": "Lokaci gabas a arewacin da Amirka", + "Etc\/GMT": "Lokacin Greenwhich a London", + "Etc\/UTC": "Hadewa duniya lokaci", + "Europe\/Amsterdam": "Tsakiyar a lokaci turai (Amsterdam)", + "Europe\/Andorra": "Tsakiyar a lokaci turai (Andorra)", + "Europe\/Athens": "Lokaci a turai gabas (Athens)", + "Europe\/Belgrade": "Tsakiyar a lokaci turai (Belgrade)", + "Europe\/Berlin": "Tsakiyar a lokaci turai (Berlin)", + "Europe\/Bratislava": "Tsakiyar a lokaci turai (Bratislava)", + "Europe\/Brussels": "Tsakiyar a lokaci turai (Brussels)", + "Europe\/Bucharest": "Lokaci a turai gabas (Bucharest)", + "Europe\/Budapest": "Tsakiyar a lokaci turai (Budapest)", + "Europe\/Busingen": "Tsakiyar a lokaci turai (Busingen)", + "Europe\/Chisinau": "Lokaci a turai gabas (Chisinau)", + "Europe\/Copenhagen": "Tsakiyar a lokaci turai (Copenhagen)", + "Europe\/Dublin": "Lokacin Greenwhich a London (Dublin)", + "Europe\/Gibraltar": "Tsakiyar a lokaci turai (Gibraltar)", + "Europe\/Guernsey": "Lokacin Greenwhich a London (Guernsey)", + "Europe\/Helsinki": "Lokaci a turai gabas (Helsinki)", + "Europe\/Isle_of_Man": "Lokacin Greenwhich a London (Isle of Man)", + "Europe\/Jersey": "Lokacin Greenwhich a London (Jersey)", + "Europe\/Kaliningrad": "Lokaci a turai gabas (Kaliningrad)", + "Europe\/Kiev": "Lokaci a turai gabas (Kiev)", + "Europe\/Lisbon": "Lokaci ta yammacin turai (Lisbon)", + "Europe\/Ljubljana": "Tsakiyar a lokaci turai (Ljubljana)", + "Europe\/London": "Lokacin Greenwhich a London (London)", + "Europe\/Luxembourg": "Tsakiyar a lokaci turai (Luxembourg)", + "Europe\/Madrid": "Tsakiyar a lokaci turai (Madrid)", + "Europe\/Malta": "Tsakiyar a lokaci turai (Malta)", + "Europe\/Mariehamn": "Lokaci a turai gabas (Mariehamn)", + "Europe\/Monaco": "Tsakiyar a lokaci turai (Monaco)", + "Europe\/Oslo": "Tsakiyar a lokaci turai (Oslo)", + "Europe\/Paris": "Tsakiyar a lokaci turai (Paris)", + "Europe\/Podgorica": "Tsakiyar a lokaci turai (Podgorica)", + "Europe\/Prague": "Tsakiyar a lokaci turai (Prague)", + "Europe\/Riga": "Lokaci a turai gabas (Riga)", + "Europe\/Rome": "Tsakiyar a lokaci turai (Rome)", + "Europe\/San_Marino": "Tsakiyar a lokaci turai (San Marino)", + "Europe\/Sarajevo": "Tsakiyar a lokaci turai (Sarajevo)", + "Europe\/Skopje": "Tsakiyar a lokaci turai (Skopje)", + "Europe\/Sofia": "Lokaci a turai gabas (Sofia)", + "Europe\/Stockholm": "Tsakiyar a lokaci turai (Stockholm)", + "Europe\/Tallinn": "Lokaci a turai gabas (Tallinn)", + "Europe\/Tirane": "Tsakiyar a lokaci turai (Tirane)", + "Europe\/Uzhgorod": "Lokaci a turai gabas (Uzhgorod)", + "Europe\/Vaduz": "Tsakiyar a lokaci turai (Vaduz)", + "Europe\/Vatican": "Tsakiyar a lokaci turai (Vatican)", + "Europe\/Vienna": "Tsakiyar a lokaci turai (Vienna)", + "Europe\/Vilnius": "Lokaci a turai gabas (Vilnius)", + "Europe\/Warsaw": "Tsakiyar a lokaci turai (Warsaw)", + "Europe\/Zagreb": "Tsakiyar a lokaci turai (Zagreb)", + "Europe\/Zaporozhye": "Lokaci a turai gabas (Zaporozhye)", + "Europe\/Zurich": "Tsakiyar a lokaci turai (Zurich)", + "MST7MDT": "Lokaci tsauni a arewacin da Amirka", + "PST8PDT": "Amurika da arewa a lokaci lafiya", + "Pacific\/Honolulu": "Lokaci ta Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Lokaci ta Hawaii-Aleutian (Johnston)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ha_NE.json b/src/Symfony/Component/Intl/Resources/data/timezones/ha_NE.json new file mode 100644 index 0000000000000..71360dbcf4384 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ha_NE.json @@ -0,0 +1,206 @@ +{ + "Version": "2.1.48.77", + "Names": { + "Africa\/Abidjan": "Lokacin Greenwhich a London (Abidjan)", + "Africa\/Accra": "Lokacin Greenwhich a London (Accra)", + "Africa\/Algiers": "Tsakiyar a lokaci turai (Algiers)", + "Africa\/Bamako": "Lokacin Greenwhich a London (Bamako)", + "Africa\/Banjul": "Lokacin Greenwhich a London (Banjul)", + "Africa\/Bissau": "Lokacin Greenwhich a London (Bissau)", + "Africa\/Cairo": "Lokaci a turai gabas (Cairo)", + "Africa\/Casablanca": "Lokaci ta yammacin turai (Casablanca)", + "Africa\/Ceuta": "Tsakiyar a lokaci turai (Ceuta)", + "Africa\/Conakry": "Lokacin Greenwhich a London (Conakry)", + "Africa\/Dakar": "Lokacin Greenwhich a London (Dakar)", + "Africa\/El_Aaiun": "Lokaci ta yammacin turai (El Aaiun)", + "Africa\/Freetown": "Lokacin Greenwhich a London (Freetown)", + "Africa\/Lome": "Lokacin Greenwhich a London (Lome)", + "Africa\/Monrovia": "Lokacin Greenwhich a London (Monrovia)", + "Africa\/Nouakchott": "Lokacin Greenwhich a London (Nouakchott)", + "Africa\/Ouagadougou": "Lokacin Greenwhich a London (Ouagadougou)", + "Africa\/Sao_Tome": "Lokacin Greenwhich a London (Sao Tome)", + "Africa\/Tripoli": "Lokaci a turai gabas (Tripoli)", + "Africa\/Tunis": "Tsakiyar a lokaci turai (Tunis)", + "America\/Adak": "Lokaci ta Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Lokaci ta Alaska (Anchorage)", + "America\/Anguilla": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Anguilla)", + "America\/Antigua": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Antigua)", + "America\/Aruba": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Aruba)", + "America\/Bahia_Banderas": "Lokaci dake Amurika arewa ta tsakiyar (Bahia Banderas)", + "America\/Barbados": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Barbados)", + "America\/Belize": "Lokaci dake Amurika arewa ta tsakiyar (Belize)", + "America\/Blanc-Sablon": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Blanc-Sablon)", + "America\/Boise": "Lokaci tsauni a arewacin da Amirka (Boise)", + "America\/Cambridge_Bay": "Lokaci tsauni a arewacin da Amirka (Cambridge Bay)", + "America\/Cancun": "Lokaci gabas a arewacin da Amirka (Cancun)", + "America\/Cayman": "Lokaci gabas a arewacin da Amirka (Cayman)", + "America\/Chicago": "Lokaci dake Amurika arewa ta tsakiyar (Chicago)", + "America\/Chihuahua": "Lokaci a lafiya ta Mesiko (Chihuahua)", + "America\/Coral_Harbour": "Lokaci gabas a arewacin da Amirka (Atikokan)", + "America\/Costa_Rica": "Lokaci dake Amurika arewa ta tsakiyar (Costa Rica)", + "America\/Creston": "Lokaci tsauni a arewacin da Amirka (Creston)", + "America\/Curacao": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Curacao)", + "America\/Danmarkshavn": "Lokacin Greenwhich a London (Danmarkshavn)", + "America\/Dawson": "Amurika da arewa a lokaci lafiya (Dawson)", + "America\/Dawson_Creek": "Lokaci tsauni a arewacin da Amirka (Dawson Creek)", + "America\/Denver": "Lokaci tsauni a arewacin da Amirka (Denver)", + "America\/Detroit": "Lokaci gabas a arewacin da Amirka (Detroit)", + "America\/Dominica": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Dominica)", + "America\/Edmonton": "Lokaci tsauni a arewacin da Amirka (Edmonton)", + "America\/El_Salvador": "Lokaci dake Amurika arewa ta tsakiyar (El Salvador)", + "America\/Fort_Nelson": "Lokaci tsauni a arewacin da Amirka (Fort Nelson)", + "America\/Glace_Bay": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Glace Bay)", + "America\/Godthab": "Lokaci a yammacin ta Greeland (Nuuk)", + "America\/Goose_Bay": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Goose Bay)", + "America\/Grand_Turk": "Lokaci gabas a arewacin da Amirka (Grand Turk)", + "America\/Grenada": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Grenada)", + "America\/Guadeloupe": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Guadeloupe)", + "America\/Guatemala": "Lokaci dake Amurika arewa ta tsakiyar (Guatemala)", + "America\/Halifax": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Halifax)", + "America\/Havana": "Lokaci ta Kuba (Havana)", + "America\/Hermosillo": "Lokaci a lafiya ta Mesiko (Hermosillo)", + "America\/Indiana\/Knox": "Lokaci dake Amurika arewa ta tsakiyar (Knox, Indiana)", + "America\/Indiana\/Marengo": "Lokaci gabas a arewacin da Amirka (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Lokaci gabas a arewacin da Amirka (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Lokaci dake Amurika arewa ta tsakiyar (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Lokaci gabas a arewacin da Amirka (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Lokaci gabas a arewacin da Amirka (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Lokaci gabas a arewacin da Amirka (Winamac, Indiana)", + "America\/Indianapolis": "Lokaci gabas a arewacin da Amirka (Indianapolis)", + "America\/Inuvik": "Lokaci tsauni a arewacin da Amirka (Inuvik)", + "America\/Iqaluit": "Lokaci gabas a arewacin da Amirka (Iqaluit)", + "America\/Jamaica": "Lokaci gabas a arewacin da Amirka (Jamaica)", + "America\/Juneau": "Lokaci ta Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Lokaci gabas a arewacin da Amirka (Monticello, Kentucky)", + "America\/Kralendijk": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Kralendijk)", + "America\/Los_Angeles": "Amurika da arewa a lokaci lafiya (Los Angeles)", + "America\/Louisville": "Lokaci gabas a arewacin da Amirka (Louisville)", + "America\/Lower_Princes": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Lower Prince’s Quarter)", + "America\/Managua": "Lokaci dake Amurika arewa ta tsakiyar (Managua)", + "America\/Marigot": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Marigot)", + "America\/Martinique": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Martinique)", + "America\/Matamoros": "Lokaci dake Amurika arewa ta tsakiyar (Matamoros)", + "America\/Mazatlan": "Lokaci a lafiya ta Mesiko (Mazatlan)", + "America\/Menominee": "Lokaci dake Amurika arewa ta tsakiyar (Menominee)", + "America\/Merida": "Lokaci dake Amurika arewa ta tsakiyar (Merida)", + "America\/Metlakatla": "Lokaci ta Alaska (Metlakatla)", + "America\/Mexico_City": "Lokaci dake Amurika arewa ta tsakiyar (Mexico City)", + "America\/Miquelon": "Lokaci ta St. Pierre da Miquelon (Miquelon)", + "America\/Moncton": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Moncton)", + "America\/Monterrey": "Lokaci dake Amurika arewa ta tsakiyar (Monterrey)", + "America\/Montserrat": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Montserrat)", + "America\/Nassau": "Lokaci gabas a arewacin da Amirka (Nassau)", + "America\/New_York": "Lokaci gabas a arewacin da Amirka (New York)", + "America\/Nipigon": "Lokaci gabas a arewacin da Amirka (Nipigon)", + "America\/Nome": "Lokaci ta Alaska (Nome)", + "America\/North_Dakota\/Beulah": "Lokaci dake Amurika arewa ta tsakiyar (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Lokaci dake Amurika arewa ta tsakiyar (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Lokaci dake Amurika arewa ta tsakiyar (New Salem, North Dakota)", + "America\/Ojinaga": "Lokaci tsauni a arewacin da Amirka (Ojinaga)", + "America\/Panama": "Lokaci gabas a arewacin da Amirka (Panama)", + "America\/Pangnirtung": "Lokaci gabas a arewacin da Amirka (Pangnirtung)", + "America\/Phoenix": "Lokaci tsauni a arewacin da Amirka (Phoenix)", + "America\/Port-au-Prince": "Lokaci gabas a arewacin da Amirka (Port-au-Prince)", + "America\/Port_of_Spain": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Port of Spain)", + "America\/Puerto_Rico": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Puerto Rico)", + "America\/Rainy_River": "Lokaci dake Amurika arewa ta tsakiyar (Rainy River)", + "America\/Rankin_Inlet": "Lokaci dake Amurika arewa ta tsakiyar (Rankin Inlet)", + "America\/Regina": "Lokaci dake Amurika arewa ta tsakiyar (Regina)", + "America\/Resolute": "Lokaci dake Amurika arewa ta tsakiyar (Resolute)", + "America\/Santa_Isabel": "Lokaci a arewa da yammacin ta Mesiko (Santa Isabel)", + "America\/Santo_Domingo": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Santo Domingo)", + "America\/Scoresbysund": "Lokaci a gabas ta Greeland (Ittoqqortoormiit)", + "America\/Sitka": "Lokaci ta Alaska (Sitka)", + "America\/St_Barthelemy": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Barthelemy)", + "America\/St_Johns": "Lokaci ta Newfoundland (St. John’s)", + "America\/St_Kitts": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Kitts)", + "America\/St_Lucia": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Lucia)", + "America\/St_Thomas": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Thomas)", + "America\/St_Vincent": "Lokaci da Kanada, Puerto Rico da Virgin Islands (St. Vincent)", + "America\/Swift_Current": "Lokaci dake Amurika arewa ta tsakiyar (Swift Current)", + "America\/Tegucigalpa": "Lokaci dake Amurika arewa ta tsakiyar (Tegucigalpa)", + "America\/Thule": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Thule)", + "America\/Thunder_Bay": "Lokaci gabas a arewacin da Amirka (Thunder Bay)", + "America\/Tijuana": "Amurika da arewa a lokaci lafiya (Tijuana)", + "America\/Toronto": "Lokaci gabas a arewacin da Amirka (Toronto)", + "America\/Tortola": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Tortola)", + "America\/Vancouver": "Amurika da arewa a lokaci lafiya (Vancouver)", + "America\/Whitehorse": "Amurika da arewa a lokaci lafiya (Whitehorse)", + "America\/Winnipeg": "Lokaci dake Amurika arewa ta tsakiyar (Winnipeg)", + "America\/Yakutat": "Lokaci ta Alaska (Yakutat)", + "America\/Yellowknife": "Lokaci tsauni a arewacin da Amirka (Yellowknife)", + "Antarctica\/Troll": "Lokacin Greenwhich a London (Troll)", + "Arctic\/Longyearbyen": "Tsakiyar a lokaci turai (Longyearbyen)", + "Asia\/Amman": "Lokaci a turai gabas (Amman)", + "Asia\/Beirut": "Lokaci a turai gabas (Beirut)", + "Asia\/Damascus": "Lokaci a turai gabas (Damascus)", + "Asia\/Famagusta": "Lokaci a turai gabas (Famagusta)", + "Asia\/Gaza": "Lokaci a turai gabas (Gaza)", + "Asia\/Hebron": "Lokaci a turai gabas (Hebron)", + "Asia\/Nicosia": "Lokaci a turai gabas (Nicosia)", + "Atlantic\/Bermuda": "Lokaci da Kanada, Puerto Rico da Virgin Islands (Bermuda)", + "Atlantic\/Canary": "Lokaci ta yammacin turai (Canary)", + "Atlantic\/Faeroe": "Lokaci ta yammacin turai (Faroe)", + "Atlantic\/Madeira": "Lokaci ta yammacin turai (Madeira)", + "Atlantic\/Reykjavik": "Lokacin Greenwhich a London (Reykjavik)", + "Atlantic\/St_Helena": "Lokacin Greenwhich a London (St. Helena)", + "CST6CDT": "Lokaci dake Amurika arewa ta tsakiyar", + "EST5EDT": "Lokaci gabas a arewacin da Amirka", + "Etc\/GMT": "Lokacin Greenwhich a London", + "Etc\/UTC": "Hadewa duniya lokaci", + "Europe\/Amsterdam": "Tsakiyar a lokaci turai (Amsterdam)", + "Europe\/Andorra": "Tsakiyar a lokaci turai (Andorra)", + "Europe\/Athens": "Lokaci a turai gabas (Athens)", + "Europe\/Belgrade": "Tsakiyar a lokaci turai (Belgrade)", + "Europe\/Berlin": "Tsakiyar a lokaci turai (Berlin)", + "Europe\/Bratislava": "Tsakiyar a lokaci turai (Bratislava)", + "Europe\/Brussels": "Tsakiyar a lokaci turai (Brussels)", + "Europe\/Bucharest": "Lokaci a turai gabas (Bucharest)", + "Europe\/Budapest": "Tsakiyar a lokaci turai (Budapest)", + "Europe\/Busingen": "Tsakiyar a lokaci turai (Busingen)", + "Europe\/Chisinau": "Lokaci a turai gabas (Chisinau)", + "Europe\/Copenhagen": "Tsakiyar a lokaci turai (Copenhagen)", + "Europe\/Dublin": "Lokacin Greenwhich a London (Dublin)", + "Europe\/Gibraltar": "Tsakiyar a lokaci turai (Gibraltar)", + "Europe\/Guernsey": "Lokacin Greenwhich a London (Guernsey)", + "Europe\/Helsinki": "Lokaci a turai gabas (Helsinki)", + "Europe\/Isle_of_Man": "Lokacin Greenwhich a London (Isle of Man)", + "Europe\/Jersey": "Lokacin Greenwhich a London (Jersey)", + "Europe\/Kaliningrad": "Lokaci a turai gabas (Kaliningrad)", + "Europe\/Kiev": "Lokaci a turai gabas (Kiev)", + "Europe\/Lisbon": "Lokaci ta yammacin turai (Lisbon)", + "Europe\/Ljubljana": "Tsakiyar a lokaci turai (Ljubljana)", + "Europe\/London": "Lokacin Greenwhich a London (London)", + "Europe\/Luxembourg": "Tsakiyar a lokaci turai (Luxembourg)", + "Europe\/Madrid": "Tsakiyar a lokaci turai (Madrid)", + "Europe\/Malta": "Tsakiyar a lokaci turai (Malta)", + "Europe\/Mariehamn": "Lokaci a turai gabas (Mariehamn)", + "Europe\/Monaco": "Tsakiyar a lokaci turai (Monaco)", + "Europe\/Oslo": "Tsakiyar a lokaci turai (Oslo)", + "Europe\/Paris": "Tsakiyar a lokaci turai (Paris)", + "Europe\/Podgorica": "Tsakiyar a lokaci turai (Podgorica)", + "Europe\/Prague": "Tsakiyar a lokaci turai (Prague)", + "Europe\/Riga": "Lokaci a turai gabas (Riga)", + "Europe\/Rome": "Tsakiyar a lokaci turai (Rome)", + "Europe\/San_Marino": "Tsakiyar a lokaci turai (San Marino)", + "Europe\/Sarajevo": "Tsakiyar a lokaci turai (Sarajevo)", + "Europe\/Skopje": "Tsakiyar a lokaci turai (Skopje)", + "Europe\/Sofia": "Lokaci a turai gabas (Sofia)", + "Europe\/Stockholm": "Tsakiyar a lokaci turai (Stockholm)", + "Europe\/Tallinn": "Lokaci a turai gabas (Tallinn)", + "Europe\/Tirane": "Tsakiyar a lokaci turai (Tirane)", + "Europe\/Uzhgorod": "Lokaci a turai gabas (Uzhgorod)", + "Europe\/Vaduz": "Tsakiyar a lokaci turai (Vaduz)", + "Europe\/Vatican": "Tsakiyar a lokaci turai (Vatican)", + "Europe\/Vienna": "Tsakiyar a lokaci turai (Vienna)", + "Europe\/Vilnius": "Lokaci a turai gabas (Vilnius)", + "Europe\/Warsaw": "Tsakiyar a lokaci turai (Warsaw)", + "Europe\/Zagreb": "Tsakiyar a lokaci turai (Zagreb)", + "Europe\/Zaporozhye": "Lokaci a turai gabas (Zaporozhye)", + "Europe\/Zurich": "Tsakiyar a lokaci turai (Zurich)", + "MST7MDT": "Lokaci tsauni a arewacin da Amirka", + "PST8PDT": "Amurika da arewa a lokaci lafiya", + "Pacific\/Honolulu": "Lokaci ta Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Lokaci ta Hawaii-Aleutian (Johnston)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/he.json b/src/Symfony/Component/Intl/Resources/data/timezones/he.json new file mode 100644 index 0000000000000..14d0630bdef5d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/he.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "שעון גריניץ׳‏ (אביג׳אן)", + "Africa\/Accra": "שעון גריניץ׳‏ (אקרה)", + "Africa\/Addis_Ababa": "שעון מזרח אפריקה (אדיס אבבה)", + "Africa\/Algiers": "שעון מרכז אירופה (אלג׳יר)", + "Africa\/Asmera": "שעון מזרח אפריקה (אסמרה)", + "Africa\/Bamako": "שעון גריניץ׳‏ (במאקו)", + "Africa\/Bangui": "שעון מערב אפריקה (בנגואי)", + "Africa\/Banjul": "שעון גריניץ׳‏ (בנג׳ול)", + "Africa\/Bissau": "שעון גריניץ׳‏ (ביסאו)", + "Africa\/Blantyre": "שעון מרכז אפריקה (בלנטיר)", + "Africa\/Brazzaville": "שעון מערב אפריקה (ברזוויל)", + "Africa\/Bujumbura": "שעון מרכז אפריקה (בוג׳ומבורה)", + "Africa\/Cairo": "שעון מזרח אירופה (קהיר)", + "Africa\/Casablanca": "שעון מערב אירופה (קזבלנקה)", + "Africa\/Ceuta": "שעון מרכז אירופה (סאוטה)", + "Africa\/Conakry": "שעון גריניץ׳‏ (קונאקרי)", + "Africa\/Dakar": "שעון גריניץ׳‏ (דקאר)", + "Africa\/Dar_es_Salaam": "שעון מזרח אפריקה (דאר א-סלאם)", + "Africa\/Djibouti": "שעון מזרח אפריקה (ג׳יבוטי)", + "Africa\/Douala": "שעון מערב אפריקה (דואלה)", + "Africa\/El_Aaiun": "שעון מערב אירופה (אל עיון)", + "Africa\/Freetown": "שעון גריניץ׳‏ (פריטאון)", + "Africa\/Gaborone": "שעון מרכז אפריקה (גבורונה)", + "Africa\/Harare": "שעון מרכז אפריקה (הרארה)", + "Africa\/Johannesburg": "שעון דרום אפריקה (יוהנסבורג)", + "Africa\/Juba": "שעון מזרח אפריקה (ג׳ובה)", + "Africa\/Kampala": "שעון מזרח אפריקה (קמפאלה)", + "Africa\/Khartoum": "שעון מרכז אפריקה (חרטום)", + "Africa\/Kigali": "שעון מרכז אפריקה (קיגלי)", + "Africa\/Kinshasa": "שעון מערב אפריקה (קינשסה)", + "Africa\/Lagos": "שעון מערב אפריקה (לגוס)", + "Africa\/Libreville": "שעון מערב אפריקה (ליברוויל)", + "Africa\/Lome": "שעון גריניץ׳‏ (לומה)", + "Africa\/Luanda": "שעון מערב אפריקה (לואנדה)", + "Africa\/Lubumbashi": "שעון מרכז אפריקה (לובומבאשי)", + "Africa\/Lusaka": "שעון מרכז אפריקה (לוסקה)", + "Africa\/Malabo": "שעון מערב אפריקה (מלבו)", + "Africa\/Maputo": "שעון מרכז אפריקה (מאפוטו)", + "Africa\/Maseru": "שעון דרום אפריקה (מסרו)", + "Africa\/Mbabane": "שעון דרום אפריקה (מבבנה)", + "Africa\/Mogadishu": "שעון מזרח אפריקה (מוגדישו)", + "Africa\/Monrovia": "שעון גריניץ׳‏ (מונרוביה)", + "Africa\/Nairobi": "שעון מזרח אפריקה (ניירובי)", + "Africa\/Ndjamena": "שעון מערב אפריקה (נג׳מנה)", + "Africa\/Niamey": "שעון מערב אפריקה (ניאמיי)", + "Africa\/Nouakchott": "שעון גריניץ׳‏ (נואקצ׳וט)", + "Africa\/Ouagadougou": "שעון גריניץ׳‏ (וואגאדוגו)", + "Africa\/Porto-Novo": "שעון מערב אפריקה (פורטו נובו)", + "Africa\/Sao_Tome": "שעון גריניץ׳‏ (סאו טומה)", + "Africa\/Tripoli": "שעון מזרח אירופה (טריפולי)", + "Africa\/Tunis": "שעון מרכז אירופה (תוניס)", + "Africa\/Windhoek": "שעון מרכז אפריקה (וינדהוק)", + "America\/Adak": "שעון האיים האלאוטיים הוואי (אדאק)", + "America\/Anchorage": "שעון אלסקה (אנקורג׳)", + "America\/Anguilla": "שעון האוקיינוס האטלנטי (אנגווילה)", + "America\/Antigua": "שעון האוקיינוס האטלנטי (אנטיגואה)", + "America\/Araguaina": "שעון ברזיליה (אראגואינה)", + "America\/Argentina\/La_Rioja": "שעון ארגנטינה (לה ריוחה)", + "America\/Argentina\/Rio_Gallegos": "שעון ארגנטינה (ריו גאייגוס)", + "America\/Argentina\/Salta": "שעון ארגנטינה (סלטה)", + "America\/Argentina\/San_Juan": "שעון ארגנטינה (סן חואן)", + "America\/Argentina\/San_Luis": "שעון מערב ארגנטינה (סן לואיס)", + "America\/Argentina\/Tucuman": "שעון ארגנטינה (טוקומן)", + "America\/Argentina\/Ushuaia": "שעון ארגנטינה (אושוואיה)", + "America\/Aruba": "שעון האוקיינוס האטלנטי (ארובה)", + "America\/Asuncion": "שעון פרגוואי (אסונסיון)", + "America\/Bahia": "שעון ברזיליה (באהיה)", + "America\/Bahia_Banderas": "שעון מרכז ארה״ב (באהיה בנדרס)", + "America\/Barbados": "שעון האוקיינוס האטלנטי (ברבדוס)", + "America\/Belem": "שעון ברזיליה (בלם)", + "America\/Belize": "שעון מרכז ארה״ב (בליז)", + "America\/Blanc-Sablon": "שעון האוקיינוס האטלנטי (בלאן-סבלון)", + "America\/Boa_Vista": "שעון אמזונס (בואה ויסטה)", + "America\/Bogota": "שעון קולומביה (בוגוטה)", + "America\/Boise": "שעון אזור ההרים בארה״ב (בויסי)", + "America\/Buenos_Aires": "שעון ארגנטינה (בואנוס איירס)", + "America\/Cambridge_Bay": "שעון אזור ההרים בארה״ב (קיימברידג׳ ביי)", + "America\/Campo_Grande": "שעון אמזונס (קמפו גרנדה)", + "America\/Cancun": "שעון החוף המזרחי (קנקון)", + "America\/Caracas": "שעון ונצואלה (קראקס)", + "America\/Catamarca": "שעון ארגנטינה (קטמרקה)", + "America\/Cayenne": "שעון גיאנה הצרפתית (קאיין)", + "America\/Cayman": "שעון החוף המזרחי (קיימן)", + "America\/Chicago": "שעון מרכז ארה״ב (שיקגו)", + "America\/Chihuahua": "שעון מערב מקסיקו (צ׳יוואווה)", + "America\/Coral_Harbour": "שעון החוף המזרחי (אטיקוקן)", + "America\/Cordoba": "שעון ארגנטינה (קורדובה)", + "America\/Costa_Rica": "שעון מרכז ארה״ב (קוסטה ריקה)", + "America\/Creston": "שעון אזור ההרים בארה״ב (קרסטון)", + "America\/Cuiaba": "שעון אמזונס (קויאבה)", + "America\/Curacao": "שעון האוקיינוס האטלנטי (קוראסאו)", + "America\/Danmarkshavn": "שעון גריניץ׳‏ (דנמרקסהוון)", + "America\/Dawson": "שעון מערב ארה״ב (דוסון)", + "America\/Dawson_Creek": "שעון אזור ההרים בארה״ב (דוסון קריק)", + "America\/Denver": "שעון אזור ההרים בארה״ב (דנוור)", + "America\/Detroit": "שעון החוף המזרחי (דטרויט)", + "America\/Dominica": "שעון האוקיינוס האטלנטי (דומיניקה)", + "America\/Edmonton": "שעון אזור ההרים בארה״ב (אדמונטון)", + "America\/El_Salvador": "שעון מרכז ארה״ב (אל סלבדור)", + "America\/Fort_Nelson": "שעון אזור ההרים בארה״ב (פורט נלסון)", + "America\/Fortaleza": "שעון ברזיליה (פורטאלזה)", + "America\/Glace_Bay": "שעון האוקיינוס האטלנטי (גלייס ביי)", + "America\/Godthab": "שעון מערב גרינלנד (נואוק)", + "America\/Goose_Bay": "שעון האוקיינוס האטלנטי (גוס ביי)", + "America\/Grand_Turk": "שעון החוף המזרחי (גרנד טורק)", + "America\/Grenada": "שעון האוקיינוס האטלנטי (גרנדה)", + "America\/Guadeloupe": "שעון האוקיינוס האטלנטי (גואדלופ)", + "America\/Guatemala": "שעון מרכז ארה״ב (גואטמלה)", + "America\/Guayaquil": "שעון אקוודור (גואיאקיל)", + "America\/Guyana": "שעון גיאנה (גיאנה)", + "America\/Halifax": "שעון האוקיינוס האטלנטי (הליפקס)", + "America\/Havana": "שעון קובה (הוואנה)", + "America\/Hermosillo": "שעון מערב מקסיקו (הרמוסיו)", + "America\/Indiana\/Knox": "שעון מרכז ארה״ב (נוקס, אינדיאנה)", + "America\/Indiana\/Marengo": "שעון החוף המזרחי (מרנגו, אינדיאנה)", + "America\/Indiana\/Petersburg": "שעון החוף המזרחי (פיטרסבורג, אינדיאנה)", + "America\/Indiana\/Tell_City": "שעון מרכז ארה״ב (טל סיטי, אינדיאנה)", + "America\/Indiana\/Vevay": "שעון החוף המזרחי (ויוואיי, אינדיאנה)", + "America\/Indiana\/Vincennes": "שעון החוף המזרחי (וינסנס, אינדיאנה)", + "America\/Indiana\/Winamac": "שעון החוף המזרחי (וינמאק, אינדיאנה)", + "America\/Indianapolis": "שעון החוף המזרחי (אינדיאנפוליס)", + "America\/Inuvik": "שעון אזור ההרים בארה״ב (אינוויק)", + "America\/Iqaluit": "שעון החוף המזרחי (איקלואיט)", + "America\/Jamaica": "שעון החוף המזרחי (ג׳מייקה)", + "America\/Jujuy": "שעון ארגנטינה (חוחוי)", + "America\/Juneau": "שעון אלסקה (ג׳ונו)", + "America\/Kentucky\/Monticello": "שעון החוף המזרחי (מונטיצ׳לו, קנטאקי)", + "America\/Kralendijk": "שעון האוקיינוס האטלנטי (קרלנדייק)", + "America\/La_Paz": "שעון בוליביה (לה פאס)", + "America\/Lima": "שעון פרו (לימה)", + "America\/Los_Angeles": "שעון מערב ארה״ב (לוס אנג׳לס)", + "America\/Louisville": "שעון החוף המזרחי (לואיוויל)", + "America\/Lower_Princes": "שעון האוקיינוס האטלנטי (לואוור פרינסס קוורטר)", + "America\/Maceio": "שעון ברזיליה (מסייאו)", + "America\/Managua": "שעון מרכז ארה״ב (מנגואה)", + "America\/Manaus": "שעון אמזונס (מנאוס)", + "America\/Marigot": "שעון האוקיינוס האטלנטי (מריגו)", + "America\/Martinique": "שעון האוקיינוס האטלנטי (מרטיניק)", + "America\/Matamoros": "שעון מרכז ארה״ב (מטמורוס)", + "America\/Mazatlan": "שעון מערב מקסיקו (מזטלן)", + "America\/Mendoza": "שעון ארגנטינה (מנדוזה)", + "America\/Menominee": "שעון מרכז ארה״ב (מנומיני)", + "America\/Merida": "שעון מרכז ארה״ב (מרידה)", + "America\/Metlakatla": "שעון אלסקה (מטלקטלה)", + "America\/Mexico_City": "שעון מרכז ארה״ב (מקסיקו סיטי)", + "America\/Miquelon": "שעון סנט פייר ומיקלון (מיקלון)", + "America\/Moncton": "שעון האוקיינוס האטלנטי (מונקטון)", + "America\/Monterrey": "שעון מרכז ארה״ב (מונטריי)", + "America\/Montevideo": "שעון אורוגוואי (מונטווידאו)", + "America\/Montserrat": "שעון האוקיינוס האטלנטי (מונסראט)", + "America\/Nassau": "שעון החוף המזרחי (נסאו)", + "America\/New_York": "שעון החוף המזרחי (ניו יורק)", + "America\/Nipigon": "שעון החוף המזרחי (ניפיגון)", + "America\/Nome": "שעון אלסקה (נום)", + "America\/Noronha": "שעון פרננדו די נורוניה (נורוניה)", + "America\/North_Dakota\/Beulah": "שעון מרכז ארה״ב (ביולה, צפון דקוטה)", + "America\/North_Dakota\/Center": "שעון מרכז ארה״ב (סנטר, צפון דקוטה)", + "America\/North_Dakota\/New_Salem": "שעון מרכז ארה״ב (ניו סיילם, צפון דקוטה)", + "America\/Ojinaga": "שעון אזור ההרים בארה״ב (אוג׳ינאגה)", + "America\/Panama": "שעון החוף המזרחי (פנמה)", + "America\/Pangnirtung": "שעון החוף המזרחי (פנגנירטונג)", + "America\/Paramaribo": "שעון סורינאם (פרמריבו)", + "America\/Phoenix": "שעון אזור ההרים בארה״ב (פיניקס)", + "America\/Port-au-Prince": "שעון החוף המזרחי (פורט או פראנס)", + "America\/Port_of_Spain": "שעון האוקיינוס האטלנטי (פורט אוף ספיין)", + "America\/Porto_Velho": "שעון אמזונס (פורטו וליו)", + "America\/Puerto_Rico": "שעון האוקיינוס האטלנטי (פוארטו ריקו)", + "America\/Punta_Arenas": "שעון צ׳ילה (פונטה ארנס)", + "America\/Rainy_River": "שעון מרכז ארה״ב (רייני ריבר)", + "America\/Rankin_Inlet": "שעון מרכז ארה״ב (רנקין אינלט)", + "America\/Recife": "שעון ברזיליה (רסיפה)", + "America\/Regina": "שעון מרכז ארה״ב (רג׳ינה)", + "America\/Resolute": "שעון מרכז ארה״ב (רזולוט)", + "America\/Santa_Isabel": "שעון צפון-מערב מקסיקו (סנטה איזבל)", + "America\/Santarem": "שעון ברזיליה (סנטרם)", + "America\/Santiago": "שעון צ׳ילה (סנטיאגו)", + "America\/Santo_Domingo": "שעון האוקיינוס האטלנטי (סנטו דומינגו)", + "America\/Sao_Paulo": "שעון ברזיליה (סאו פאולו)", + "America\/Scoresbysund": "שעון מזרח גרינלנד (סקורסביסונד)", + "America\/Sitka": "שעון אלסקה (סיטקה)", + "America\/St_Barthelemy": "שעון האוקיינוס האטלנטי (סנט ברתלמי)", + "America\/St_Johns": "שעון ניופאונדלנד (סנט ג׳ונס)", + "America\/St_Kitts": "שעון האוקיינוס האטלנטי (סנט קיטס)", + "America\/St_Lucia": "שעון האוקיינוס האטלנטי (סנט לוסיה)", + "America\/St_Thomas": "שעון האוקיינוס האטלנטי (סנט תומאס)", + "America\/St_Vincent": "שעון האוקיינוס האטלנטי (סנט וינסנט)", + "America\/Swift_Current": "שעון מרכז ארה״ב (סוויפט קרנט)", + "America\/Tegucigalpa": "שעון מרכז ארה״ב (טגוסיגלפה)", + "America\/Thule": "שעון האוקיינוס האטלנטי (תולה)", + "America\/Thunder_Bay": "שעון החוף המזרחי (ת׳אנדר ביי)", + "America\/Tijuana": "שעון מערב ארה״ב (טיחואנה)", + "America\/Toronto": "שעון החוף המזרחי (טורונטו)", + "America\/Tortola": "שעון האוקיינוס האטלנטי (טורטולה)", + "America\/Vancouver": "שעון מערב ארה״ב (ונקובר)", + "America\/Whitehorse": "שעון מערב ארה״ב (ווייטהורס)", + "America\/Winnipeg": "שעון מרכז ארה״ב (וויניפג)", + "America\/Yakutat": "שעון אלסקה (יקוטאט)", + "America\/Yellowknife": "שעון אזור ההרים בארה״ב (ילונייף)", + "Antarctica\/Casey": "שעון מערב אוסטרליה (קאסיי)", + "Antarctica\/Davis": "שעון דיוויס (דיוויס)", + "Antarctica\/DumontDUrville": "שעון דומון ד׳אורוויל (דומון ד׳אורוויל)", + "Antarctica\/Macquarie": "שעון מקווארי (מקרי)", + "Antarctica\/Mawson": "שעון מאוסון (מוסון)", + "Antarctica\/McMurdo": "שעון ניו זילנד (מק-מרדו)", + "Antarctica\/Palmer": "שעון צ׳ילה (פאלמר)", + "Antarctica\/Rothera": "שעון רות׳רה (רות׳רה)", + "Antarctica\/Syowa": "שעון סייווה (סיוואה)", + "Antarctica\/Troll": "שעון גריניץ׳‏ (טרול)", + "Antarctica\/Vostok": "שעון ווסטוק (ווסטוק)", + "Arctic\/Longyearbyen": "שעון מרכז אירופה (לונגיירבין)", + "Asia\/Aden": "שעון חצי האי ערב (עדן)", + "Asia\/Almaty": "שעון מזרח קזחסטן (אלמאטי)", + "Asia\/Amman": "שעון מזרח אירופה (עמאן)", + "Asia\/Anadyr": "שעון אנדיר (אנדיר)", + "Asia\/Aqtau": "שעון מערב קזחסטן (אקטאו)", + "Asia\/Aqtobe": "שעון מערב קזחסטן (אקטובה)", + "Asia\/Ashgabat": "שעון טורקמניסטן (אשגבט)", + "Asia\/Atyrau": "שעון מערב קזחסטן (אטיראו)", + "Asia\/Baghdad": "שעון חצי האי ערב (בגדד)", + "Asia\/Bahrain": "שעון חצי האי ערב (בחריין)", + "Asia\/Baku": "שעון אזרבייג׳אן (באקו)", + "Asia\/Bangkok": "שעון הודו-סין (בנגקוק)", + "Asia\/Beirut": "שעון מזרח אירופה (ביירות)", + "Asia\/Bishkek": "שעון קירגיזסטן (בישקק)", + "Asia\/Brunei": "שעון ברוניי דארוסלאם (ברוניי)", + "Asia\/Calcutta": "שעון הודו (קולקטה)", + "Asia\/Chita": "שעון יקוטסק (צ׳יטה)", + "Asia\/Choibalsan": "שעון צ׳ויבלסן (צ׳ויבלסן)", + "Asia\/Colombo": "שעון הודו (קולומבו)", + "Asia\/Damascus": "שעון מזרח אירופה (דמשק)", + "Asia\/Dhaka": "שעון בנגלדש (דאקה)", + "Asia\/Dili": "שעון מזרח טימור (דילי)", + "Asia\/Dubai": "שעון מדינות המפרץ (דובאי)", + "Asia\/Dushanbe": "שעון טג׳יקיסטן (דושנבה)", + "Asia\/Famagusta": "שעון מזרח אירופה (פמגוסטה)", + "Asia\/Gaza": "שעון מזרח אירופה (עזה)", + "Asia\/Hebron": "שעון מזרח אירופה (חברון)", + "Asia\/Hong_Kong": "שעון הונג קונג (הונג קונג)", + "Asia\/Hovd": "שעון חובד (חובד)", + "Asia\/Irkutsk": "שעון אירקוטסק (אירקוטסק)", + "Asia\/Jakarta": "שעון מערב אינדונזיה (ג׳קרטה)", + "Asia\/Jayapura": "שעון מזרח אינדונזיה (ג׳איאפורה)", + "Asia\/Jerusalem": "שעון ישראל (ירושלים)", + "Asia\/Kabul": "שעון אפגניסטן (קאבול)", + "Asia\/Kamchatka": "שעון פטרופבלובסק-קמצ׳טסקי (קמצ׳טקה)", + "Asia\/Karachi": "שעון פקיסטן (קראצ׳י)", + "Asia\/Katmandu": "שעון נפאל (קטמנדו)", + "Asia\/Khandyga": "שעון יקוטסק (חנדיגה)", + "Asia\/Krasnoyarsk": "שעון קרסנויארסק (קרסנויארסק)", + "Asia\/Kuala_Lumpur": "שעון מלזיה (קואלה לומפור)", + "Asia\/Kuching": "שעון מלזיה (קוצ׳ינג)", + "Asia\/Kuwait": "שעון חצי האי ערב (כווית)", + "Asia\/Macau": "שעון סין (מקאו)", + "Asia\/Magadan": "שעון מגדן (מגדן)", + "Asia\/Makassar": "שעון מרכז אינדונזיה (מאקאסאר)", + "Asia\/Manila": "שעון הפיליפינים (מנילה)", + "Asia\/Muscat": "שעון מדינות המפרץ (מוסקט)", + "Asia\/Nicosia": "שעון מזרח אירופה (ניקוסיה)", + "Asia\/Novokuznetsk": "שעון קרסנויארסק (נובוקוזנטסק)", + "Asia\/Novosibirsk": "שעון נובוסיבירסק (נובוסיבירסק)", + "Asia\/Omsk": "שעון אומסק (אומסק)", + "Asia\/Oral": "שעון מערב קזחסטן (אורל)", + "Asia\/Phnom_Penh": "שעון הודו-סין (פנום פן)", + "Asia\/Pontianak": "שעון מערב אינדונזיה (פונטיאנק)", + "Asia\/Pyongyang": "שעון קוריאה (פיונגיאנג)", + "Asia\/Qatar": "שעון חצי האי ערב (קטאר)", + "Asia\/Qostanay": "שעון מזרח קזחסטן (קוסטנאי)", + "Asia\/Qyzylorda": "שעון מערב קזחסטן (קיזילורדה)", + "Asia\/Rangoon": "שעון מיאנמר (רנגון)", + "Asia\/Riyadh": "שעון חצי האי ערב (ריאד)", + "Asia\/Saigon": "שעון הודו-סין (הו צ׳י מין סיטי)", + "Asia\/Sakhalin": "שעון סחלין (סחלין)", + "Asia\/Samarkand": "שעון אוזבקיסטן (סמרקנד)", + "Asia\/Seoul": "שעון קוריאה (סיאול)", + "Asia\/Shanghai": "שעון סין (שנחאי)", + "Asia\/Singapore": "שעון סינגפור (סינגפור)", + "Asia\/Srednekolymsk": "שעון מגדן (סרדנייקולימסק)", + "Asia\/Taipei": "שעון טאיפיי (טאיפיי)", + "Asia\/Tashkent": "שעון אוזבקיסטן (טשקנט)", + "Asia\/Tbilisi": "שעון גאורגיה (טביליסי)", + "Asia\/Tehran": "שעון איראן (טהרן)", + "Asia\/Thimphu": "שעון בהוטן (טהימפהו)", + "Asia\/Tokyo": "שעון יפן (טוקיו)", + "Asia\/Ulaanbaatar": "שעון אולן בטור (אולאאנבטאר)", + "Asia\/Ust-Nera": "שעון ולדיווסטוק (אוסט-נרה)", + "Asia\/Vientiane": "שעון הודו-סין (האנוי)", + "Asia\/Vladivostok": "שעון ולדיווסטוק (ולדיווסטוק)", + "Asia\/Yakutsk": "שעון יקוטסק (יקוטסק)", + "Asia\/Yekaterinburg": "שעון יקטרינבורג (יקטרינבורג)", + "Asia\/Yerevan": "שעון ארמניה (ירוואן)", + "Atlantic\/Azores": "שעון האיים האזוריים (האיים האזוריים)", + "Atlantic\/Bermuda": "שעון האוקיינוס האטלנטי (ברמודה)", + "Atlantic\/Canary": "שעון מערב אירופה (האיים הקנריים)", + "Atlantic\/Cape_Verde": "שעון כף ורדה (כף ורדה)", + "Atlantic\/Faeroe": "שעון מערב אירופה (פארו)", + "Atlantic\/Madeira": "שעון מערב אירופה (מדיירה)", + "Atlantic\/Reykjavik": "שעון גריניץ׳‏ (רייקיאוויק)", + "Atlantic\/South_Georgia": "שעון דרום ג׳ורג׳יה (דרום ג׳ורג׳יה)", + "Atlantic\/St_Helena": "שעון גריניץ׳‏ (סנט הלנה)", + "Atlantic\/Stanley": "שעון איי פוקלנד (סטנלי)", + "Australia\/Adelaide": "שעון מרכז אוסטרליה (אדלייד)", + "Australia\/Brisbane": "שעון מזרח אוסטרליה (בריסביין)", + "Australia\/Broken_Hill": "שעון מרכז אוסטרליה (ברוקן היל)", + "Australia\/Currie": "שעון מזרח אוסטרליה (קרי)", + "Australia\/Darwin": "שעון מרכז אוסטרליה (דרווין)", + "Australia\/Eucla": "שעון מרכז-מערב אוסטרליה (יוקלה)", + "Australia\/Hobart": "שעון מזרח אוסטרליה (הוברט)", + "Australia\/Lindeman": "שעון מזרח אוסטרליה (לינדמן)", + "Australia\/Lord_Howe": "שעון אי הלורד האו (אי הלורד האו)", + "Australia\/Melbourne": "שעון מזרח אוסטרליה (מלבורן)", + "Australia\/Perth": "שעון מערב אוסטרליה (פרת׳)", + "Australia\/Sydney": "שעון מזרח אוסטרליה (סידני)", + "CST6CDT": "שעון מרכז ארה״ב", + "EST5EDT": "שעון החוף המזרחי", + "Etc\/GMT": "שעון גריניץ׳‏", + "Etc\/UTC": "זמן אוניברסלי מתואם", + "Europe\/Amsterdam": "שעון מרכז אירופה (אמסטרדם)", + "Europe\/Andorra": "שעון מרכז אירופה (אנדורה)", + "Europe\/Astrakhan": "שעון מוסקבה (אסטרחן)", + "Europe\/Athens": "שעון מזרח אירופה (אתונה)", + "Europe\/Belgrade": "שעון מרכז אירופה (בלגרד)", + "Europe\/Berlin": "שעון מרכז אירופה (ברלין)", + "Europe\/Bratislava": "שעון מרכז אירופה (ברטיסלבה)", + "Europe\/Brussels": "שעון מרכז אירופה (בריסל)", + "Europe\/Bucharest": "שעון מזרח אירופה (בוקרשט)", + "Europe\/Budapest": "שעון מרכז אירופה (בודפשט)", + "Europe\/Busingen": "שעון מרכז אירופה (ביזינגן)", + "Europe\/Chisinau": "שעון מזרח אירופה (קישינב)", + "Europe\/Copenhagen": "שעון מרכז אירופה (קופנהגן)", + "Europe\/Dublin": "שעון גריניץ׳‏ (דבלין)", + "Europe\/Gibraltar": "שעון מרכז אירופה (גיברלטר)", + "Europe\/Guernsey": "שעון גריניץ׳‏ (גרנזי)", + "Europe\/Helsinki": "שעון מזרח אירופה (הלסינקי)", + "Europe\/Isle_of_Man": "שעון גריניץ׳‏ (האי מאן)", + "Europe\/Jersey": "שעון גריניץ׳‏ (ג׳רזי)", + "Europe\/Kaliningrad": "שעון מזרח אירופה (קלינינגרד)", + "Europe\/Kiev": "שעון מזרח אירופה (קייב)", + "Europe\/Lisbon": "שעון מערב אירופה (ליסבון)", + "Europe\/Ljubljana": "שעון מרכז אירופה (לובליאנה)", + "Europe\/London": "שעון גריניץ׳‏ (לונדון)", + "Europe\/Luxembourg": "שעון מרכז אירופה (לוקסמבורג)", + "Europe\/Madrid": "שעון מרכז אירופה (מדריד)", + "Europe\/Malta": "שעון מרכז אירופה (מלטה)", + "Europe\/Mariehamn": "שעון מזרח אירופה (מרייהאמן)", + "Europe\/Minsk": "שעון מוסקבה (מינסק)", + "Europe\/Monaco": "שעון מרכז אירופה (מונקו)", + "Europe\/Moscow": "שעון מוסקבה (מוסקבה)", + "Europe\/Oslo": "שעון מרכז אירופה (אוסלו)", + "Europe\/Paris": "שעון מרכז אירופה (פריז)", + "Europe\/Podgorica": "שעון מרכז אירופה (פודגוריצה)", + "Europe\/Prague": "שעון מרכז אירופה (פראג)", + "Europe\/Riga": "שעון מזרח אירופה (ריגה)", + "Europe\/Rome": "שעון מרכז אירופה (רומא)", + "Europe\/Samara": "שעון סמרה (סמרה)", + "Europe\/San_Marino": "שעון מרכז אירופה (סן מרינו)", + "Europe\/Sarajevo": "שעון מרכז אירופה (סרייבו)", + "Europe\/Saratov": "שעון מוסקבה (סראטוב)", + "Europe\/Simferopol": "שעון מוסקבה (סימפרופול)", + "Europe\/Skopje": "שעון מרכז אירופה (סקופיה)", + "Europe\/Sofia": "שעון מזרח אירופה (סופיה)", + "Europe\/Stockholm": "שעון מרכז אירופה (שטוקהולם)", + "Europe\/Tallinn": "שעון מזרח אירופה (טאלין)", + "Europe\/Tirane": "שעון מרכז אירופה (טירנה)", + "Europe\/Ulyanovsk": "שעון מוסקבה (אוליאנובסק)", + "Europe\/Uzhgorod": "שעון מזרח אירופה (אוז׳הורוד)", + "Europe\/Vaduz": "שעון מרכז אירופה (ואדוץ)", + "Europe\/Vatican": "שעון מרכז אירופה (הוותיקן)", + "Europe\/Vienna": "שעון מרכז אירופה (וינה)", + "Europe\/Vilnius": "שעון מזרח אירופה (וילנה)", + "Europe\/Volgograd": "שעון וולגוגרד (וולגוגרד)", + "Europe\/Warsaw": "שעון מרכז אירופה (ורשה)", + "Europe\/Zagreb": "שעון מרכז אירופה (זאגרב)", + "Europe\/Zaporozhye": "שעון מזרח אירופה (זפורוז׳יה)", + "Europe\/Zurich": "שעון מרכז אירופה (ציריך)", + "Indian\/Antananarivo": "שעון מזרח אפריקה (אנטננריבו)", + "Indian\/Chagos": "שעון האוקיינוס ההודי (צ׳אגוס)", + "Indian\/Christmas": "שעון האי כריסטמס (האי כריסטמס)", + "Indian\/Cocos": "שעון איי קוקוס (קוקוס)", + "Indian\/Comoro": "שעון מזרח אפריקה (קומורו)", + "Indian\/Kerguelen": "שעון הארצות הדרומיות והאנטארקטיות של צרפת (קרגוולן)", + "Indian\/Mahe": "שעון איי סיישל (מהא)", + "Indian\/Maldives": "שעון האיים המלדיביים (האיים המלדיביים)", + "Indian\/Mauritius": "שעון מאוריציוס (מאוריציוס)", + "Indian\/Mayotte": "שעון מזרח אפריקה (מאיוט)", + "Indian\/Reunion": "שעון ראוניון (ראוניון)", + "MST7MDT": "שעון אזור ההרים בארה״ב", + "PST8PDT": "שעון מערב ארה״ב", + "Pacific\/Apia": "שעון אפיה (אפיה)", + "Pacific\/Auckland": "שעון ניו זילנד (אוקלנד)", + "Pacific\/Bougainville": "שעון פפואה גיניאה החדשה (בוגנוויל)", + "Pacific\/Chatham": "שעון צ׳טהאם (צ׳אטהאם)", + "Pacific\/Easter": "שעון אי הפסחא (אי הפסחא)", + "Pacific\/Efate": "שעון ונואטו (אפטה)", + "Pacific\/Enderbury": "שעון איי פיניקס (אנדרבורי)", + "Pacific\/Fakaofo": "שעון טוקלאו (פקאופו)", + "Pacific\/Fiji": "שעון פיג׳י (פיג׳י)", + "Pacific\/Funafuti": "שעון טובאלו (פונפוטי)", + "Pacific\/Galapagos": "שעון איי גלאפגוס (גלפאגוס)", + "Pacific\/Gambier": "שעון איי גמבייה (איי גמבייה)", + "Pacific\/Guadalcanal": "שעון איי שלמה (גוודלקנאל)", + "Pacific\/Guam": "שעון צ׳אמורו (גואם)", + "Pacific\/Honolulu": "שעון האיים האלאוטיים הוואי (הונולולו)", + "Pacific\/Johnston": "שעון האיים האלאוטיים הוואי (ג׳ונסטון)", + "Pacific\/Kiritimati": "שעון איי ליין (קיריטימאטי)", + "Pacific\/Kosrae": "שעון קוסראה (קוסרה)", + "Pacific\/Kwajalein": "שעון איי מרשל (קוואג׳ליין)", + "Pacific\/Majuro": "שעון איי מרשל (מאג׳ורו)", + "Pacific\/Marquesas": "שעון איי מרקיז (איי מרקיז)", + "Pacific\/Midway": "שעון סמואה (מידוויי)", + "Pacific\/Nauru": "שעון נאורו (נאורו)", + "Pacific\/Niue": "שעון ניואה (ניואה)", + "Pacific\/Norfolk": "שעון האי נורפוק (נורפוק)", + "Pacific\/Noumea": "שעון קלדוניה החדשה (נומאה)", + "Pacific\/Pago_Pago": "שעון סמואה (פאגו פאגו)", + "Pacific\/Palau": "שעון פלאו (פלאו)", + "Pacific\/Pitcairn": "שעון פיטקרן (פיטקרן)", + "Pacific\/Ponape": "שעון פונאפי (פונפיי)", + "Pacific\/Port_Moresby": "שעון פפואה גיניאה החדשה (פורט מורסבי)", + "Pacific\/Rarotonga": "שעון איי קוק (רארוטונגה)", + "Pacific\/Saipan": "שעון צ׳אמורו (סאיפאן)", + "Pacific\/Tahiti": "שעון טהיטי (טהיטי)", + "Pacific\/Tarawa": "שעון איי גילברט (טאראווה)", + "Pacific\/Tongatapu": "שעון טונגה (טונגטאפו)", + "Pacific\/Truk": "שעון צ׳וק (צ׳וק)", + "Pacific\/Wake": "שעון האי וייק (וייק)", + "Pacific\/Wallis": "שעון וואליס ופוטונה (ווליס)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/hi.json b/src/Symfony/Component/Intl/Resources/data/timezones/hi.json new file mode 100644 index 0000000000000..e2bfbf18aef56 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/hi.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ग्रीनविच मीन टाइम (अबिदजान)", + "Africa\/Accra": "ग्रीनविच मीन टाइम (एक्रा)", + "Africa\/Addis_Ababa": "पूर्वी अफ़्रीका समय (अदीस अबाबा)", + "Africa\/Algiers": "मध्य यूरोपीय समय (अल्जीयर्स)", + "Africa\/Asmera": "पूर्वी अफ़्रीका समय (अस्मारा)", + "Africa\/Bamako": "ग्रीनविच मीन टाइम (बामाको)", + "Africa\/Bangui": "पश्चिम अफ़्रीका समय (बांगुइ)", + "Africa\/Banjul": "ग्रीनविच मीन टाइम (बैंजुल)", + "Africa\/Bissau": "ग्रीनविच मीन टाइम (बिसाऊ)", + "Africa\/Blantyre": "मध्य अफ़्रीका समय (ब्लांटायर)", + "Africa\/Brazzaville": "पश्चिम अफ़्रीका समय (ब्राज़ाविले)", + "Africa\/Bujumbura": "मध्य अफ़्रीका समय (बुजुंबूरा)", + "Africa\/Cairo": "पूर्वी यूरोपीय समय (कायरो)", + "Africa\/Casablanca": "पश्चिमी यूरोपीय समय (कासाब्लांका)", + "Africa\/Ceuta": "मध्य यूरोपीय समय (सेउटा)", + "Africa\/Conakry": "ग्रीनविच मीन टाइम (कोनाक्री)", + "Africa\/Dakar": "ग्रीनविच मीन टाइम (डकार)", + "Africa\/Dar_es_Salaam": "पूर्वी अफ़्रीका समय (दार अस सलाम)", + "Africa\/Djibouti": "पूर्वी अफ़्रीका समय (जिबूती)", + "Africa\/Douala": "पश्चिम अफ़्रीका समय (डूआला)", + "Africa\/El_Aaiun": "पश्चिमी यूरोपीय समय (अल आइयून)", + "Africa\/Freetown": "ग्रीनविच मीन टाइम (फ़्रीटाउन)", + "Africa\/Gaborone": "मध्य अफ़्रीका समय (गाबोरोन)", + "Africa\/Harare": "मध्य अफ़्रीका समय (हरारे)", + "Africa\/Johannesburg": "दक्षिण अफ़्रीका मानक समय (जोहांसबर्ग)", + "Africa\/Juba": "पूर्वी अफ़्रीका समय (जुबा)", + "Africa\/Kampala": "पूर्वी अफ़्रीका समय (कंपाला)", + "Africa\/Khartoum": "मध्य अफ़्रीका समय (खार्तूम)", + "Africa\/Kigali": "मध्य अफ़्रीका समय (किगाली)", + "Africa\/Kinshasa": "पश्चिम अफ़्रीका समय (किंशासा)", + "Africa\/Lagos": "पश्चिम अफ़्रीका समय (लागोस)", + "Africa\/Libreville": "पश्चिम अफ़्रीका समय (लिब्रेविले)", + "Africa\/Lome": "ग्रीनविच मीन टाइम (लोम)", + "Africa\/Luanda": "पश्चिम अफ़्रीका समय (लुआंडा)", + "Africa\/Lubumbashi": "मध्य अफ़्रीका समय (लुबुमबाशी)", + "Africa\/Lusaka": "मध्य अफ़्रीका समय (लुसाका)", + "Africa\/Malabo": "पश्चिम अफ़्रीका समय (मलाबो)", + "Africa\/Maputo": "मध्य अफ़्रीका समय (मापुटो)", + "Africa\/Maseru": "दक्षिण अफ़्रीका मानक समय (मासेरू)", + "Africa\/Mbabane": "दक्षिण अफ़्रीका मानक समय (एमबाबेन)", + "Africa\/Mogadishu": "पूर्वी अफ़्रीका समय (मोगादिशु)", + "Africa\/Monrovia": "ग्रीनविच मीन टाइम (मोनरोविया)", + "Africa\/Nairobi": "पूर्वी अफ़्रीका समय (नैरोबी)", + "Africa\/Ndjamena": "पश्चिम अफ़्रीका समय (नेद्जामीना)", + "Africa\/Niamey": "पश्चिम अफ़्रीका समय (नियामी)", + "Africa\/Nouakchott": "ग्रीनविच मीन टाइम (नौआकशॉट)", + "Africa\/Ouagadougou": "ग्रीनविच मीन टाइम (औगाडोगू)", + "Africa\/Porto-Novo": "पश्चिम अफ़्रीका समय (पोर्टो-नोवो)", + "Africa\/Sao_Tome": "ग्रीनविच मीन टाइम (साओ टोम)", + "Africa\/Tripoli": "पूर्वी यूरोपीय समय (त्रिपोली)", + "Africa\/Tunis": "मध्य यूरोपीय समय (ट्यूनिस)", + "Africa\/Windhoek": "मध्य अफ़्रीका समय (विंडहोक)", + "America\/Adak": "हवाई–आल्यूशन समय (अडक)", + "America\/Anchorage": "अलास्का समय (एंकरेज)", + "America\/Anguilla": "अटलांटिक समय (एंग्विला)", + "America\/Antigua": "अटलांटिक समय (एंटीगुआ)", + "America\/Araguaina": "ब्राज़ीलिया समय (आराग्वेना)", + "America\/Argentina\/La_Rioja": "अर्जेंटीना समय (ला रिओजा)", + "America\/Argentina\/Rio_Gallegos": "अर्जेंटीना समय (रियो गालेगोस)", + "America\/Argentina\/Salta": "अर्जेंटीना समय (साल्टा)", + "America\/Argentina\/San_Juan": "अर्जेंटीना समय (सैन ह्वान)", + "America\/Argentina\/San_Luis": "पश्चिमी अर्जेंटीना समय (सैन लूई)", + "America\/Argentina\/Tucuman": "अर्जेंटीना समय (टोकूमन)", + "America\/Argentina\/Ushuaia": "अर्जेंटीना समय (उशुआइया)", + "America\/Aruba": "अटलांटिक समय (अरूबा)", + "America\/Asuncion": "पैराग्वे समय (एसनशियॉन)", + "America\/Bahia": "ब्राज़ीलिया समय (बहिया)", + "America\/Bahia_Banderas": "उत्तरी अमेरिकी केंद्रीय समय (बेहिया बांडेरास)", + "America\/Barbados": "अटलांटिक समय (बारबाडोस)", + "America\/Belem": "ब्राज़ीलिया समय (बेलेम)", + "America\/Belize": "उत्तरी अमेरिकी केंद्रीय समय (बेलीज़)", + "America\/Blanc-Sablon": "अटलांटिक समय (ब्लांक-सेबलोन)", + "America\/Boa_Vista": "अमेज़न समय (बोआ विस्ता)", + "America\/Bogota": "कोलंबिया समय (बोगोटा)", + "America\/Boise": "उत्तरी अमेरिकी माउंटेन समय (बॉइसी)", + "America\/Buenos_Aires": "अर्जेंटीना समय (ब्यूनस आयरस)", + "America\/Cambridge_Bay": "उत्तरी अमेरिकी माउंटेन समय (कैम्ब्रिज खाड़ी)", + "America\/Campo_Grande": "अमेज़न समय (कैंपो ग्रांडे)", + "America\/Cancun": "उत्तरी अमेरिकी पूर्वी समय (कैनकुन)", + "America\/Caracas": "वेनेज़ुएला समय (काराकस)", + "America\/Catamarca": "अर्जेंटीना समय (काटामार्का)", + "America\/Cayenne": "फ़्रेंच गुयाना समय (कायेन)", + "America\/Cayman": "उत्तरी अमेरिकी पूर्वी समय (कैमेन)", + "America\/Chicago": "उत्तरी अमेरिकी केंद्रीय समय (शिकागो)", + "America\/Chihuahua": "मेक्सिकन प्रशांत समय (चिहुआहुआ)", + "America\/Coral_Harbour": "उत्तरी अमेरिकी पूर्वी समय (अटिकोकान)", + "America\/Cordoba": "अर्जेंटीना समय (कोर्डोबा)", + "America\/Costa_Rica": "उत्तरी अमेरिकी केंद्रीय समय (कोस्टा रिका)", + "America\/Creston": "उत्तरी अमेरिकी माउंटेन समय (क्रेस्टन)", + "America\/Cuiaba": "अमेज़न समय (क्यूआबा)", + "America\/Curacao": "अटलांटिक समय (कुराकाओ)", + "America\/Danmarkshavn": "ग्रीनविच मीन टाइम (डेनमार्कशॉन)", + "America\/Dawson": "उत्तरी अमेरिकी प्रशांत समय (डॉसन)", + "America\/Dawson_Creek": "उत्तरी अमेरिकी माउंटेन समय (डॉसन क्रीक)", + "America\/Denver": "उत्तरी अमेरिकी माउंटेन समय (डेनवर)", + "America\/Detroit": "उत्तरी अमेरिकी पूर्वी समय (डेट्रॉयट)", + "America\/Dominica": "अटलांटिक समय (डोमिनिका)", + "America\/Edmonton": "उत्तरी अमेरिकी माउंटेन समय (एडमंटन)", + "America\/El_Salvador": "उत्तरी अमेरिकी केंद्रीय समय (अल सल्वाडोर)", + "America\/Fort_Nelson": "उत्तरी अमेरिकी माउंटेन समय (फ़ोर्ट नेल्सन)", + "America\/Fortaleza": "ब्राज़ीलिया समय (फ़ोर्टालेज़ा)", + "America\/Glace_Bay": "अटलांटिक समय (ग्लेस खाड़ी)", + "America\/Godthab": "पश्चिमी ग्रीनलैंड समय (नुक)", + "America\/Goose_Bay": "अटलांटिक समय (गूस खाड़ी)", + "America\/Grand_Turk": "उत्तरी अमेरिकी पूर्वी समय (ग्रांड टर्क)", + "America\/Grenada": "अटलांटिक समय (ग्रेनाडा)", + "America\/Guadeloupe": "अटलांटिक समय (ग्वाडेलोप)", + "America\/Guatemala": "उत्तरी अमेरिकी केंद्रीय समय (ग्वाटेमाला)", + "America\/Guayaquil": "इक्वाडोर समय (ग्वायाकील)", + "America\/Guyana": "गुयाना समय (गयाना)", + "America\/Halifax": "अटलांटिक समय (हेलिफ़ैक्स)", + "America\/Havana": "क्यूबा समय (हवाना)", + "America\/Hermosillo": "मेक्सिकन प्रशांत समय (हर्मोसिल्लो)", + "America\/Indiana\/Knox": "उत्तरी अमेरिकी केंद्रीय समय (नौक्स, इंडियाना)", + "America\/Indiana\/Marengo": "उत्तरी अमेरिकी पूर्वी समय (मारेंगो, इंडियाना)", + "America\/Indiana\/Petersburg": "उत्तरी अमेरिकी पूर्वी समय (पीटर्सबर्ग, इंडियाना)", + "America\/Indiana\/Tell_City": "उत्तरी अमेरिकी केंद्रीय समय (टेल सिटी, इंडियाना)", + "America\/Indiana\/Vevay": "उत्तरी अमेरिकी पूर्वी समय (वेवे, इंडियाना)", + "America\/Indiana\/Vincennes": "उत्तरी अमेरिकी पूर्वी समय (विंसेनेस, इंडियाना)", + "America\/Indiana\/Winamac": "उत्तरी अमेरिकी पूर्वी समय (विनामेक, इंडियाना)", + "America\/Indianapolis": "उत्तरी अमेरिकी पूर्वी समय (इंडियानापोलिस)", + "America\/Inuvik": "उत्तरी अमेरिकी माउंटेन समय (इनूविक)", + "America\/Iqaluit": "उत्तरी अमेरिकी पूर्वी समय (इकालुईट)", + "America\/Jamaica": "उत्तरी अमेरिकी पूर्वी समय (जमैका)", + "America\/Jujuy": "अर्जेंटीना समय (जुजोए)", + "America\/Juneau": "अलास्का समय (ज्यूनाउ)", + "America\/Kentucky\/Monticello": "उत्तरी अमेरिकी पूर्वी समय (मोंटीसेलो, केंटकी)", + "America\/Kralendijk": "अटलांटिक समय (क्रालैंडिजिक)", + "America\/La_Paz": "बोलीविया समय (ला पाज़)", + "America\/Lima": "पेरू समय (लीमा)", + "America\/Los_Angeles": "उत्तरी अमेरिकी प्रशांत समय (लॉस एंजिल्स)", + "America\/Louisville": "उत्तरी अमेरिकी पूर्वी समय (लुइसविले)", + "America\/Lower_Princes": "अटलांटिक समय (लोअर प्रिंसेस क्वार्टर)", + "America\/Maceio": "ब्राज़ीलिया समय (मेसीओ)", + "America\/Managua": "उत्तरी अमेरिकी केंद्रीय समय (मानागुआ)", + "America\/Manaus": "अमेज़न समय (मनौस)", + "America\/Marigot": "अटलांटिक समय (मैरीगोट)", + "America\/Martinique": "अटलांटिक समय (मार्टिनिक)", + "America\/Matamoros": "उत्तरी अमेरिकी केंद्रीय समय (माटामोरोस)", + "America\/Mazatlan": "मेक्सिकन प्रशांत समय (माज़ाटलान)", + "America\/Mendoza": "अर्जेंटीना समय (मेंडोज़ा)", + "America\/Menominee": "उत्तरी अमेरिकी केंद्रीय समय (मेनोमिनी)", + "America\/Merida": "उत्तरी अमेरिकी केंद्रीय समय (मेरिडा)", + "America\/Metlakatla": "अलास्का समय (मेट्लेकाट्ला)", + "America\/Mexico_City": "उत्तरी अमेरिकी केंद्रीय समय (मेक्सिको सिटी)", + "America\/Miquelon": "सेंट पिएरे और मिक्वेलान समय (मिकेलॉन)", + "America\/Moncton": "अटलांटिक समय (मोंकटन)", + "America\/Monterrey": "उत्तरी अमेरिकी केंद्रीय समय (मोंटेरेरी)", + "America\/Montevideo": "उरुग्वे समय (मोंटेवीडियो)", + "America\/Montserrat": "अटलांटिक समय (मोंटसेरात)", + "America\/Nassau": "उत्तरी अमेरिकी पूर्वी समय (नासाउ)", + "America\/New_York": "उत्तरी अमेरिकी पूर्वी समय (न्यूयॉर्क)", + "America\/Nipigon": "उत्तरी अमेरिकी पूर्वी समय (निपिगन)", + "America\/Nome": "अलास्का समय (नोम)", + "America\/Noronha": "फ़र्नांर्डो डे नोरोन्हा समय (नोरोन्हा)", + "America\/North_Dakota\/Beulah": "उत्तरी अमेरिकी केंद्रीय समय (ब्यूला, उत्तरी डकोटा)", + "America\/North_Dakota\/Center": "उत्तरी अमेरिकी केंद्रीय समय (मध्य, उत्तरी दाकोता)", + "America\/North_Dakota\/New_Salem": "उत्तरी अमेरिकी केंद्रीय समय (न्यू सालेम, उत्तरी डकोटा)", + "America\/Ojinaga": "उत्तरी अमेरिकी माउंटेन समय (ओखाजीनागा)", + "America\/Panama": "उत्तरी अमेरिकी पूर्वी समय (पनामा)", + "America\/Pangnirtung": "उत्तरी अमेरिकी पूर्वी समय (पांगनिर्टंग)", + "America\/Paramaribo": "सूरीनाम समय (पारामारिबो)", + "America\/Phoenix": "उत्तरी अमेरिकी माउंटेन समय (फ़ीनिक्स)", + "America\/Port-au-Prince": "उत्तरी अमेरिकी पूर्वी समय (पोर्ट-ऑ-प्रिंस)", + "America\/Port_of_Spain": "अटलांटिक समय (पोर्ट ऑफ़ स्पेन)", + "America\/Porto_Velho": "अमेज़न समय (पोर्टो वेल्हो)", + "America\/Puerto_Rico": "अटलांटिक समय (पोर्टो रिको)", + "America\/Punta_Arenas": "चिली समय (पुंटा एरिनास)", + "America\/Rainy_River": "उत्तरी अमेरिकी केंद्रीय समय (रेनी नदी)", + "America\/Rankin_Inlet": "उत्तरी अमेरिकी केंद्रीय समय (रेंकिन इनलेट)", + "America\/Recife": "ब्राज़ीलिया समय (रेसाइफ़)", + "America\/Regina": "उत्तरी अमेरिकी केंद्रीय समय (रेजिना)", + "America\/Resolute": "उत्तरी अमेरिकी केंद्रीय समय (रिसोल्यूट)", + "America\/Santa_Isabel": "उत्तर पश्चिमी मेक्सिको समय (सांता इसाबेल)", + "America\/Santarem": "ब्राज़ीलिया समय (सैंटारेम)", + "America\/Santiago": "चिली समय (सैंटियागो)", + "America\/Santo_Domingo": "अटलांटिक समय (सेंटो डोमिंगो)", + "America\/Sao_Paulo": "ब्राज़ीलिया समय (साओ पाउलो)", + "America\/Scoresbysund": "पूर्वी ग्रीनलैंड समय (इटोकोर्टोरमिट)", + "America\/Sitka": "अलास्का समय (सिट्का)", + "America\/St_Barthelemy": "अटलांटिक समय (सेंट बार्थेलेमी)", + "America\/St_Johns": "न्यूफ़ाउंडलैंड समय (सेंट जोंस)", + "America\/St_Kitts": "अटलांटिक समय (सेंट किट्स)", + "America\/St_Lucia": "अटलांटिक समय (सेंट लूसिया)", + "America\/St_Thomas": "अटलांटिक समय (सेंट थॉमस)", + "America\/St_Vincent": "अटलांटिक समय (सेंट विंसेंट)", + "America\/Swift_Current": "उत्तरी अमेरिकी केंद्रीय समय (स्विफ़्ट करंट)", + "America\/Tegucigalpa": "उत्तरी अमेरिकी केंद्रीय समय (टेगुसिगल्पा)", + "America\/Thule": "अटलांटिक समय (थ्यूले)", + "America\/Thunder_Bay": "उत्तरी अमेरिकी पूर्वी समय (थंडर खाड़ी)", + "America\/Tijuana": "उत्तरी अमेरिकी प्रशांत समय (तिजुआना)", + "America\/Toronto": "उत्तरी अमेरिकी पूर्वी समय (टोरंटो)", + "America\/Tortola": "अटलांटिक समय (टोर्टोला)", + "America\/Vancouver": "उत्तरी अमेरिकी प्रशांत समय (वैंकूवर)", + "America\/Whitehorse": "उत्तरी अमेरिकी प्रशांत समय (व्हाइटहोर्स)", + "America\/Winnipeg": "उत्तरी अमेरिकी केंद्रीय समय (विनीपेग)", + "America\/Yakutat": "अलास्का समय (याकूटाट)", + "America\/Yellowknife": "उत्तरी अमेरिकी माउंटेन समय (येलोनाइफ़)", + "Antarctica\/Casey": "पश्चिमी ऑस्ट्रेलिया समय (केसी)", + "Antarctica\/Davis": "डेविस समय (डेविस)", + "Antarctica\/DumontDUrville": "ड्यूमोंट डी अर्विले समय (ड्यूमोंट डी अर्विले)", + "Antarctica\/Macquarie": "मक्वारी द्वीप समय (मक्वारी)", + "Antarctica\/Mawson": "माव्सन समय (मॉसन)", + "Antarctica\/McMurdo": "न्यूज़ीलैंड समय (मैकमुर्डो)", + "Antarctica\/Palmer": "चिली समय (पॉमर)", + "Antarctica\/Rothera": "रोथेरा समय (रोथेरा)", + "Antarctica\/Syowa": "स्योवा समय (स्योवा)", + "Antarctica\/Troll": "ग्रीनविच मीन टाइम (ट्रोल)", + "Antarctica\/Vostok": "वोस्तोक समय (वोस्तोक)", + "Arctic\/Longyearbyen": "मध्य यूरोपीय समय (लॉन्गईयरबायेन)", + "Asia\/Aden": "अरब समय (आदेन)", + "Asia\/Almaty": "पूर्व कज़ाखस्तान समय (अल्माटी)", + "Asia\/Amman": "पूर्वी यूरोपीय समय (अम्मान)", + "Asia\/Anadyr": "एनाडीयर समय (अनाडिर)", + "Asia\/Aqtau": "पश्चिम कज़ाखस्तान समय (अक्ताउ)", + "Asia\/Aqtobe": "पश्चिम कज़ाखस्तान समय (अक्तोब)", + "Asia\/Ashgabat": "तुर्कमेनिस्तान समय (अश्गाबात)", + "Asia\/Atyrau": "पश्चिम कज़ाखस्तान समय (एतराउ)", + "Asia\/Baghdad": "अरब समय (बगदाद)", + "Asia\/Bahrain": "अरब समय (बहरीन)", + "Asia\/Baku": "अज़रबैजान समय (बाकु)", + "Asia\/Bangkok": "इंडोचाइना समय (बैंकॉक)", + "Asia\/Beirut": "पूर्वी यूरोपीय समय (बेरुत)", + "Asia\/Bishkek": "किर्गिस्‍तान समय (बिश्केक)", + "Asia\/Brunei": "ब्रूनेई दारूस्सलम समय (ब्रूनेई)", + "Asia\/Calcutta": "भारतीय मानक समय (कोलकाता)", + "Asia\/Chita": "याकुत्स्क समय (त्शिता)", + "Asia\/Choibalsan": "कॉइबाल्सन समय (चोइबालसन)", + "Asia\/Colombo": "भारतीय मानक समय (कोलंबो)", + "Asia\/Damascus": "पूर्वी यूरोपीय समय (दमास्कस)", + "Asia\/Dhaka": "बांग्लादेश समय (ढाका)", + "Asia\/Dili": "पूर्वी तिमोर समय (डिलि)", + "Asia\/Dubai": "खाड़ी मानक समय (दुबई)", + "Asia\/Dushanbe": "ताजिकिस्तान समय (दुशांबे)", + "Asia\/Famagusta": "पूर्वी यूरोपीय समय (फ़ामागुस्ता)", + "Asia\/Gaza": "पूर्वी यूरोपीय समय (गाज़ा)", + "Asia\/Hebron": "पूर्वी यूरोपीय समय (हेब्रोन)", + "Asia\/Hong_Kong": "हाँग काँग समय (हाँग काँग)", + "Asia\/Hovd": "होव्ड समय (होव्ड)", + "Asia\/Irkutsk": "इर्कुत्स्क समय (इर्कुत्स्क)", + "Asia\/Jakarta": "पश्चिमी इंडोनेशिया समय (जकार्ता)", + "Asia\/Jayapura": "पूर्वी इंडोनेशिया समय (जयापुरा)", + "Asia\/Jerusalem": "इज़राइल समय (यरूशलम)", + "Asia\/Kabul": "अफ़गानिस्तान समय (काबुल)", + "Asia\/Kamchatka": "पेट्रोपेवलास्क-कैमचात्सकी समय (कमचत्का)", + "Asia\/Karachi": "पाकिस्तान समय (कराची)", + "Asia\/Katmandu": "नेपाल समय (काठमांडू)", + "Asia\/Khandyga": "याकुत्स्क समय (खांडिगा)", + "Asia\/Krasnoyarsk": "क्रास्नोयार्स्क समय (क्रास्नोयार्स्क)", + "Asia\/Kuala_Lumpur": "मलेशिया समय (कुआलालंपुर)", + "Asia\/Kuching": "मलेशिया समय (कूचिंग)", + "Asia\/Kuwait": "अरब समय (कुवैत)", + "Asia\/Macau": "चीन समय (मकाउ)", + "Asia\/Magadan": "मागादान समय (मागादान)", + "Asia\/Makassar": "मध्य इंडोनेशिया समय (मकस्सर)", + "Asia\/Manila": "फ़िलिपीन समय (मनीला)", + "Asia\/Muscat": "खाड़ी मानक समय (मस्कट)", + "Asia\/Nicosia": "पूर्वी यूरोपीय समय (निकोसिया)", + "Asia\/Novokuznetsk": "क्रास्नोयार्स्क समय (नोवोकुज़्नेत्स्क)", + "Asia\/Novosibirsk": "नोवोसिबिर्स्क समय (नोवोसिबिर्स्क)", + "Asia\/Omsk": "ओम्स्क समय (ओम्स्क)", + "Asia\/Oral": "पश्चिम कज़ाखस्तान समय (ओरल)", + "Asia\/Phnom_Penh": "इंडोचाइना समय (नॉम पेन्ह)", + "Asia\/Pontianak": "पश्चिमी इंडोनेशिया समय (पोंटीयांक)", + "Asia\/Pyongyang": "कोरियाई समय (प्योंगयांग)", + "Asia\/Qatar": "अरब समय (कतर)", + "Asia\/Qostanay": "पूर्व कज़ाखस्तान समय (कोस्टाने)", + "Asia\/Qyzylorda": "पश्चिम कज़ाखस्तान समय (केज़ेलोर्डा)", + "Asia\/Rangoon": "म्यांमार समय (रंगून)", + "Asia\/Riyadh": "अरब समय (रियाद)", + "Asia\/Saigon": "इंडोचाइना समय (हो ची मिन्ह सिटी)", + "Asia\/Sakhalin": "सखालिन समय (सखालिन)", + "Asia\/Samarkand": "उज़्बेकिस्तान समय (समरकंद)", + "Asia\/Seoul": "कोरियाई समय (सिओल)", + "Asia\/Shanghai": "चीन समय (शंघाई)", + "Asia\/Singapore": "सिंगापुर समय (सिंगापुर)", + "Asia\/Srednekolymsk": "मागादान समय (स्रेद्निकोलिमस्क)", + "Asia\/Taipei": "ताइपे समय (ताईपेई)", + "Asia\/Tashkent": "उज़्बेकिस्तान समय (ताशकंद)", + "Asia\/Tbilisi": "जॉर्जिया समय (टबिलिसी)", + "Asia\/Tehran": "ईरान समय (तेहरान)", + "Asia\/Thimphu": "भूटान समय (थिंपू)", + "Asia\/Tokyo": "जापान समय (टोक्यो)", + "Asia\/Ulaanbaatar": "उलान बटोर समय (उलानबातर)", + "Asia\/Ust-Nera": "व्लादिवोस्तोक समय (यूस्ट–नेरा)", + "Asia\/Vientiane": "इंडोचाइना समय (विएनतियान)", + "Asia\/Vladivostok": "व्लादिवोस्तोक समय (व्लादिवोस्तोक)", + "Asia\/Yakutsk": "याकुत्स्क समय (याकूत्स्क)", + "Asia\/Yekaterinburg": "येकातेरिनबर्ग समय (येकातेरिनबर्ग)", + "Asia\/Yerevan": "आर्मेनिया समय (येरेवान)", + "Atlantic\/Azores": "अज़ोरेस समय (अज़ोरेस)", + "Atlantic\/Bermuda": "अटलांटिक समय (बरमूडा)", + "Atlantic\/Canary": "पश्चिमी यूरोपीय समय (कैनेरी)", + "Atlantic\/Cape_Verde": "केप वर्ड समय (केप वर्ड)", + "Atlantic\/Faeroe": "पश्चिमी यूरोपीय समय (फ़ैरो)", + "Atlantic\/Madeira": "पश्चिमी यूरोपीय समय (मडेरा)", + "Atlantic\/Reykjavik": "ग्रीनविच मीन टाइम (रेक्याविक)", + "Atlantic\/South_Georgia": "दक्षिणी जॉर्जिया समय (दक्षिण जॉर्जिया)", + "Atlantic\/St_Helena": "ग्रीनविच मीन टाइम (सेंट हेलेना)", + "Atlantic\/Stanley": "फ़ॉकलैंड द्वीपसमूह समय (स्टैनली)", + "Australia\/Adelaide": "मध्य ऑस्ट्रेलियाई समय (एडिलेड)", + "Australia\/Brisbane": "पूर्वी ऑस्ट्रेलिया समय (ब्रिस्बन)", + "Australia\/Broken_Hill": "मध्य ऑस्ट्रेलियाई समय (ब्रोकन हिल)", + "Australia\/Currie": "पूर्वी ऑस्ट्रेलिया समय (क्यूरी)", + "Australia\/Darwin": "मध्य ऑस्ट्रेलियाई समय (डार्विन)", + "Australia\/Eucla": "ऑस्‍ट्रेलियाई केंद्रीय पश्चिमी समय (यूक्ला)", + "Australia\/Hobart": "पूर्वी ऑस्ट्रेलिया समय (होबार्ट)", + "Australia\/Lindeman": "पूर्वी ऑस्ट्रेलिया समय (लिंडेमान)", + "Australia\/Lord_Howe": "लॉर्ड होवे समय (लॉर्ड होवे)", + "Australia\/Melbourne": "पूर्वी ऑस्ट्रेलिया समय (मेलबोर्न)", + "Australia\/Perth": "पश्चिमी ऑस्ट्रेलिया समय (पर्थ)", + "Australia\/Sydney": "पूर्वी ऑस्ट्रेलिया समय (सिडनी)", + "CST6CDT": "उत्तरी अमेरिकी केंद्रीय समय", + "EST5EDT": "उत्तरी अमेरिकी पूर्वी समय", + "Etc\/GMT": "ग्रीनविच मीन टाइम", + "Etc\/UTC": "समन्वित वैश्विक समय", + "Europe\/Amsterdam": "मध्य यूरोपीय समय (एम्स्टर्डम)", + "Europe\/Andorra": "मध्य यूरोपीय समय (अंडोरा)", + "Europe\/Astrakhan": "मॉस्को समय (आस्ट्राखान)", + "Europe\/Athens": "पूर्वी यूरोपीय समय (एथेंस)", + "Europe\/Belgrade": "मध्य यूरोपीय समय (बेलग्रेड)", + "Europe\/Berlin": "मध्य यूरोपीय समय (बर्लिन)", + "Europe\/Bratislava": "मध्य यूरोपीय समय (ब्रातिस्लावा)", + "Europe\/Brussels": "मध्य यूरोपीय समय (ब्रूसेल्स)", + "Europe\/Bucharest": "पूर्वी यूरोपीय समय (बुख़ारेस्ट)", + "Europe\/Budapest": "मध्य यूरोपीय समय (बुडापेस्ट)", + "Europe\/Busingen": "मध्य यूरोपीय समय (ब्यूसिनजेन)", + "Europe\/Chisinau": "पूर्वी यूरोपीय समय (चिसीनाउ)", + "Europe\/Copenhagen": "मध्य यूरोपीय समय (कोपेनहेगन)", + "Europe\/Dublin": "ग्रीनविच मीन टाइम (डबलिन)", + "Europe\/Gibraltar": "मध्य यूरोपीय समय (जिब्राल्टर)", + "Europe\/Guernsey": "ग्रीनविच मीन टाइम (गर्नसी)", + "Europe\/Helsinki": "पूर्वी यूरोपीय समय (हेलसिंकी)", + "Europe\/Isle_of_Man": "ग्रीनविच मीन टाइम (आइल ऑफ़ मैन)", + "Europe\/Jersey": "ग्रीनविच मीन टाइम (जर्सी)", + "Europe\/Kaliningrad": "पूर्वी यूरोपीय समय (कालीनिनग्राड)", + "Europe\/Kiev": "पूर्वी यूरोपीय समय (कीव)", + "Europe\/Lisbon": "पश्चिमी यूरोपीय समय (लिस्बन)", + "Europe\/Ljubljana": "मध्य यूरोपीय समय (ल्यूबेलजाना)", + "Europe\/London": "ग्रीनविच मीन टाइम (लंदन)", + "Europe\/Luxembourg": "मध्य यूरोपीय समय (लक्ज़मबर्ग)", + "Europe\/Madrid": "मध्य यूरोपीय समय (मैड्रिड)", + "Europe\/Malta": "मध्य यूरोपीय समय (माल्टा)", + "Europe\/Mariehamn": "पूर्वी यूरोपीय समय (मारियाहैम)", + "Europe\/Minsk": "मॉस्को समय (मिंस्क)", + "Europe\/Monaco": "मध्य यूरोपीय समय (मोनाको)", + "Europe\/Moscow": "मॉस्को समय (मॉस्को)", + "Europe\/Oslo": "मध्य यूरोपीय समय (ओस्लो)", + "Europe\/Paris": "मध्य यूरोपीय समय (पेरिस)", + "Europe\/Podgorica": "मध्य यूरोपीय समय (पोड्गोरिका)", + "Europe\/Prague": "मध्य यूरोपीय समय (प्राग)", + "Europe\/Riga": "पूर्वी यूरोपीय समय (रीगा)", + "Europe\/Rome": "मध्य यूरोपीय समय (रोम)", + "Europe\/Samara": "समारा समय (समारा)", + "Europe\/San_Marino": "मध्य यूरोपीय समय (सैन मारीनो)", + "Europe\/Sarajevo": "मध्य यूरोपीय समय (साराजेवो)", + "Europe\/Saratov": "मॉस्को समय (सारातोव)", + "Europe\/Simferopol": "मॉस्को समय (सिम्फ़ेरोपोल)", + "Europe\/Skopje": "मध्य यूरोपीय समय (स्कोप्जे)", + "Europe\/Sofia": "पूर्वी यूरोपीय समय (सोफ़िया)", + "Europe\/Stockholm": "मध्य यूरोपीय समय (स्टॉकहोम)", + "Europe\/Tallinn": "पूर्वी यूरोपीय समय (तेलिन)", + "Europe\/Tirane": "मध्य यूरोपीय समय (टाइरेन)", + "Europe\/Ulyanovsk": "मॉस्को समय (उल्यानोव्स्क)", + "Europe\/Uzhgorod": "पूर्वी यूरोपीय समय (अज़्गोरोद)", + "Europe\/Vaduz": "मध्य यूरोपीय समय (वादुज़)", + "Europe\/Vatican": "मध्य यूरोपीय समय (वेटिकन)", + "Europe\/Vienna": "मध्य यूरोपीय समय (विएना)", + "Europe\/Vilnius": "पूर्वी यूरोपीय समय (विल्नियस)", + "Europe\/Volgograd": "वोल्गोग्राड समय (वोल्गोग्राड)", + "Europe\/Warsaw": "मध्य यूरोपीय समय (वॉरसॉ)", + "Europe\/Zagreb": "मध्य यूरोपीय समय (ज़ाग्रेब)", + "Europe\/Zaporozhye": "पूर्वी यूरोपीय समय (ज़ैपोरोज़ाई)", + "Europe\/Zurich": "मध्य यूरोपीय समय (ज़्यूरिख़)", + "Indian\/Antananarivo": "पूर्वी अफ़्रीका समय (एंटानानरीवो)", + "Indian\/Chagos": "हिंद महासागर समय (शागोस)", + "Indian\/Christmas": "क्रिसमस द्वीप समय (क्रिसमस)", + "Indian\/Cocos": "कोकोस द्वीपसमूह समय (कोकोस)", + "Indian\/Comoro": "पूर्वी अफ़्रीका समय (कोमोरो)", + "Indian\/Kerguelen": "दक्षिणी फ़्रांस और अंटार्कटिक समय (करगुलेन)", + "Indian\/Mahe": "सेशेल्स समय (माहे)", + "Indian\/Maldives": "मालदीव समय (मालदीव)", + "Indian\/Mauritius": "मॉरीशस समय (मॉरीशस)", + "Indian\/Mayotte": "पूर्वी अफ़्रीका समय (मायोत्ते)", + "Indian\/Reunion": "रीयूनियन समय (रीयूनियन)", + "MST7MDT": "उत्तरी अमेरिकी माउंटेन समय", + "PST8PDT": "उत्तरी अमेरिकी प्रशांत समय", + "Pacific\/Apia": "एपिआ समय (एपिया)", + "Pacific\/Auckland": "न्यूज़ीलैंड समय (ऑकलैंड)", + "Pacific\/Bougainville": "पापुआ न्यू गिनी समय (बोगनविले)", + "Pacific\/Chatham": "चैथम समय (चैथम)", + "Pacific\/Easter": "ईस्टर द्वीप समय (ईस्टर)", + "Pacific\/Efate": "वनुआतू समय (एफ़ेट)", + "Pacific\/Enderbury": "फ़ीनिक्स द्वीपसमूह समय (एंडरबरी)", + "Pacific\/Fakaofo": "टोकेलाऊ समय (फ़ाकाओफ़ो)", + "Pacific\/Fiji": "फ़िजी समय (फ़िजी)", + "Pacific\/Funafuti": "तुवालू समय (फ़्यूनाफ़ुटी)", + "Pacific\/Galapagos": "गैलापेगोस का समय (गेलापागोस)", + "Pacific\/Gambier": "गैंबियर समय (गैंबियर)", + "Pacific\/Guadalcanal": "सोलोमन द्वीपसमूह समय (ग्वाडलकनाल)", + "Pacific\/Guam": "चामोरो मानक समय (गुआम)", + "Pacific\/Honolulu": "हवाई–आल्यूशन समय (होनोलुलु)", + "Pacific\/Johnston": "हवाई–आल्यूशन समय (जॉनस्टन)", + "Pacific\/Kiritimati": "लाइन द्वीपसमूह समय (किरीतिमाति)", + "Pacific\/Kosrae": "कोसराए समय (कोसराए)", + "Pacific\/Kwajalein": "मार्शल द्वीपसमूह समय (क्वाज़ालीन)", + "Pacific\/Majuro": "मार्शल द्वीपसमूह समय (माजुरो)", + "Pacific\/Marquesas": "मार्केसस समय (मार्केसस)", + "Pacific\/Midway": "समोआ समय (मिडवे)", + "Pacific\/Nauru": "नौरू समय (नौरु)", + "Pacific\/Niue": "नीयू समय (नीयू)", + "Pacific\/Norfolk": "नॉरफ़ॉक द्वीप समय (नॉरफ़ॉक)", + "Pacific\/Noumea": "न्यू कैलेडोनिया समय (नौमिया)", + "Pacific\/Pago_Pago": "समोआ समय (पागो पागो)", + "Pacific\/Palau": "पलाउ समय (पलाऊ)", + "Pacific\/Pitcairn": "पिटकैर्न समय (पिटकैर्न)", + "Pacific\/Ponape": "पोनापे समय (पोनपेई)", + "Pacific\/Port_Moresby": "पापुआ न्यू गिनी समय (पोर्ट मोरेस्बी)", + "Pacific\/Rarotonga": "कुक द्वीपसमूह समय (रारोटोंगा)", + "Pacific\/Saipan": "चामोरो मानक समय (सायपान)", + "Pacific\/Tahiti": "ताहिती समय (ताहिती)", + "Pacific\/Tarawa": "गिल्बर्ट द्वीपसमूह समय (टारावा)", + "Pacific\/Tongatapu": "टोंगा समय (टोंगाटापू)", + "Pacific\/Truk": "चुक समय (चक)", + "Pacific\/Wake": "वेक द्वीप समय (वेक)", + "Pacific\/Wallis": "वालिस और फ़्यूचूना समय (वालिस)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/hr.json b/src/Symfony/Component/Intl/Resources/data/timezones/hr.json new file mode 100644 index 0000000000000..5919906fec4e7 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/hr.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "univerzalno vrijeme (Abidjan)", + "Africa\/Accra": "univerzalno vrijeme (Accra)", + "Africa\/Addis_Ababa": "istočnoafričko vrijeme (Addis Abeba)", + "Africa\/Algiers": "srednjoeuropsko vrijeme (Alžir)", + "Africa\/Asmera": "istočnoafričko vrijeme (Asmara)", + "Africa\/Bamako": "univerzalno vrijeme (Bamako)", + "Africa\/Bangui": "zapadnoafričko vrijeme (Bangui)", + "Africa\/Banjul": "univerzalno vrijeme (Banjul)", + "Africa\/Bissau": "univerzalno vrijeme (Bissau)", + "Africa\/Blantyre": "srednjoafričko vrijeme (Blantyre)", + "Africa\/Brazzaville": "zapadnoafričko vrijeme (Brazzaville)", + "Africa\/Bujumbura": "srednjoafričko vrijeme (Bujumbura)", + "Africa\/Cairo": "istočnoeuropsko vrijeme (Kairo)", + "Africa\/Casablanca": "zapadnoeuropsko vrijeme (Casablanca)", + "Africa\/Ceuta": "srednjoeuropsko vrijeme (Ceuta)", + "Africa\/Conakry": "univerzalno vrijeme (Conakry)", + "Africa\/Dakar": "univerzalno vrijeme (Dakar)", + "Africa\/Dar_es_Salaam": "istočnoafričko vrijeme (Dar es Salaam)", + "Africa\/Djibouti": "istočnoafričko vrijeme (Džibuti)", + "Africa\/Douala": "zapadnoafričko vrijeme (Douala)", + "Africa\/El_Aaiun": "zapadnoeuropsko vrijeme (El Aaiun)", + "Africa\/Freetown": "univerzalno vrijeme (Freetown)", + "Africa\/Gaborone": "srednjoafričko vrijeme (Gaborone)", + "Africa\/Harare": "srednjoafričko vrijeme (Harare)", + "Africa\/Johannesburg": "južnoafričko vrijeme (Johannesburg)", + "Africa\/Juba": "istočnoafričko vrijeme (Juba)", + "Africa\/Kampala": "istočnoafričko vrijeme (Kampala)", + "Africa\/Khartoum": "srednjoafričko vrijeme (Khartoum)", + "Africa\/Kigali": "srednjoafričko vrijeme (Kigali)", + "Africa\/Kinshasa": "zapadnoafričko vrijeme (Kinshasa)", + "Africa\/Lagos": "zapadnoafričko vrijeme (Lagos)", + "Africa\/Libreville": "zapadnoafričko vrijeme (Libreville)", + "Africa\/Lome": "univerzalno vrijeme (Lomé)", + "Africa\/Luanda": "zapadnoafričko vrijeme (Luanda)", + "Africa\/Lubumbashi": "srednjoafričko vrijeme (Lubumbashi)", + "Africa\/Lusaka": "srednjoafričko vrijeme (Lusaka)", + "Africa\/Malabo": "zapadnoafričko vrijeme (Malabo)", + "Africa\/Maputo": "srednjoafričko vrijeme (Maputo)", + "Africa\/Maseru": "južnoafričko vrijeme (Maseru)", + "Africa\/Mbabane": "južnoafričko vrijeme (Mbabane)", + "Africa\/Mogadishu": "istočnoafričko vrijeme (Mogadishu)", + "Africa\/Monrovia": "univerzalno vrijeme (Monrovia)", + "Africa\/Nairobi": "istočnoafričko vrijeme (Nairobi)", + "Africa\/Ndjamena": "zapadnoafričko vrijeme (Ndjamena)", + "Africa\/Niamey": "zapadnoafričko vrijeme (Niamey)", + "Africa\/Nouakchott": "univerzalno vrijeme (Nouakchott)", + "Africa\/Ouagadougou": "univerzalno vrijeme (Ouagadougou)", + "Africa\/Porto-Novo": "zapadnoafričko vrijeme (Porto-Novo)", + "Africa\/Sao_Tome": "univerzalno vrijeme (São Tomé)", + "Africa\/Tripoli": "istočnoeuropsko vrijeme (Tripoli)", + "Africa\/Tunis": "srednjoeuropsko vrijeme (Tunis)", + "Africa\/Windhoek": "srednjoafričko vrijeme (Windhoek)", + "America\/Adak": "havajsko-aleutsko vrijeme (Adak)", + "America\/Anchorage": "aljaško vrijeme (Anchorage)", + "America\/Anguilla": "atlantsko vrijeme (Angvila)", + "America\/Antigua": "atlantsko vrijeme (Antigua)", + "America\/Araguaina": "brazilijsko vrijeme (Araguaina)", + "America\/Argentina\/La_Rioja": "argentinsko vrijeme (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "argentinsko vrijeme (Rio Gallegos)", + "America\/Argentina\/Salta": "argentinsko vrijeme (Salta)", + "America\/Argentina\/San_Juan": "argentinsko vrijeme (San Juan)", + "America\/Argentina\/San_Luis": "zapadnoargentinsko vrijeme (San Luis)", + "America\/Argentina\/Tucuman": "argentinsko vrijeme (Tucuman)", + "America\/Argentina\/Ushuaia": "argentinsko vrijeme (Ushuaia)", + "America\/Aruba": "atlantsko vrijeme (Aruba)", + "America\/Asuncion": "paragvajsko vrijeme (Asunción)", + "America\/Bahia": "brazilijsko vrijeme (Bahia)", + "America\/Bahia_Banderas": "središnje vrijeme (Bahia Banderas)", + "America\/Barbados": "atlantsko vrijeme (Barbados)", + "America\/Belem": "brazilijsko vrijeme (Belem)", + "America\/Belize": "središnje vrijeme (Belize)", + "America\/Blanc-Sablon": "atlantsko vrijeme (Blanc-Sablon)", + "America\/Boa_Vista": "amazonsko vrijeme (Boa Vista)", + "America\/Bogota": "kolumbijsko vrijeme (Bogota)", + "America\/Boise": "planinsko vrijeme (Boise)", + "America\/Buenos_Aires": "argentinsko vrijeme (Buenos Aires)", + "America\/Cambridge_Bay": "planinsko vrijeme (Cambridge Bay)", + "America\/Campo_Grande": "amazonsko vrijeme (Campo Grande)", + "America\/Cancun": "istočno vrijeme (Cancun)", + "America\/Caracas": "venezuelsko vrijeme (Caracas)", + "America\/Catamarca": "argentinsko vrijeme (Catamarca)", + "America\/Cayenne": "vrijeme Francuske Gvajane (Cayenne)", + "America\/Cayman": "istočno vrijeme (Kajman)", + "America\/Chicago": "središnje vrijeme (Chicago)", + "America\/Chihuahua": "meksičko pacifičko vrijeme (Chihuahua)", + "America\/Coral_Harbour": "istočno vrijeme (Atikokan)", + "America\/Cordoba": "argentinsko vrijeme (Cordoba)", + "America\/Costa_Rica": "središnje vrijeme (Kostarika)", + "America\/Creston": "planinsko vrijeme (Creston)", + "America\/Cuiaba": "amazonsko vrijeme (Cuiaba)", + "America\/Curacao": "atlantsko vrijeme (Curaçao)", + "America\/Danmarkshavn": "univerzalno vrijeme (Danmarkshavn)", + "America\/Dawson": "pacifičko vrijeme (Dawson)", + "America\/Dawson_Creek": "planinsko vrijeme (Dawson Creek)", + "America\/Denver": "planinsko vrijeme (Denver)", + "America\/Detroit": "istočno vrijeme (Detroit)", + "America\/Dominica": "atlantsko vrijeme (Dominika)", + "America\/Edmonton": "planinsko vrijeme (Edmonton)", + "America\/Eirunepe": "Acre vrijeme (Eirunepe)", + "America\/El_Salvador": "središnje vrijeme (Salvador)", + "America\/Fort_Nelson": "planinsko vrijeme (Fort Nelson)", + "America\/Fortaleza": "brazilijsko vrijeme (Fortaleza)", + "America\/Glace_Bay": "atlantsko vrijeme (Glace Bay)", + "America\/Godthab": "zapadnogrenlandsko vrijeme (Nuuk)", + "America\/Goose_Bay": "atlantsko vrijeme (Goose Bay)", + "America\/Grand_Turk": "istočno vrijeme (Grand Turk)", + "America\/Grenada": "atlantsko vrijeme (Grenada)", + "America\/Guadeloupe": "atlantsko vrijeme (Guadalupe)", + "America\/Guatemala": "središnje vrijeme (Gvatemala)", + "America\/Guayaquil": "ekvadorsko vrijeme (Guayaquil)", + "America\/Guyana": "gvajansko vrijeme (Gvajana)", + "America\/Halifax": "atlantsko vrijeme (Halifax)", + "America\/Havana": "kubansko vrijeme (Havana)", + "America\/Hermosillo": "meksičko pacifičko vrijeme (Hermosillo)", + "America\/Indiana\/Knox": "središnje vrijeme (Knox, Indiana)", + "America\/Indiana\/Marengo": "istočno vrijeme (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "istočno vrijeme (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "središnje vrijeme (Tell City, Indiana)", + "America\/Indiana\/Vevay": "istočno vrijeme (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "istočno vrijeme (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "istočno vrijeme (Winamac, Indiana)", + "America\/Indianapolis": "istočno vrijeme (Indianapolis)", + "America\/Inuvik": "planinsko vrijeme (Inuvik)", + "America\/Iqaluit": "istočno vrijeme (Iqaluit)", + "America\/Jamaica": "istočno vrijeme (Jamajka)", + "America\/Jujuy": "argentinsko vrijeme (Jujuy)", + "America\/Juneau": "aljaško vrijeme (Juneau)", + "America\/Kentucky\/Monticello": "istočno vrijeme (Monticello, Kentucky)", + "America\/Kralendijk": "atlantsko vrijeme (Kralendijk)", + "America\/La_Paz": "bolivijsko vrijeme (La Paz)", + "America\/Lima": "peruansko vrijeme (Lima)", + "America\/Los_Angeles": "pacifičko vrijeme (Los Angeles)", + "America\/Louisville": "istočno vrijeme (Louisville)", + "America\/Lower_Princes": "atlantsko vrijeme (Lower Prince’s Quarter)", + "America\/Maceio": "brazilijsko vrijeme (Maceio)", + "America\/Managua": "središnje vrijeme (Managua)", + "America\/Manaus": "amazonsko vrijeme (Manaus)", + "America\/Marigot": "atlantsko vrijeme (Marigot)", + "America\/Martinique": "atlantsko vrijeme (Martinique)", + "America\/Matamoros": "središnje vrijeme (Matamoros)", + "America\/Mazatlan": "meksičko pacifičko vrijeme (Mazatlan)", + "America\/Mendoza": "argentinsko vrijeme (Mendoza)", + "America\/Menominee": "središnje vrijeme (Menominee)", + "America\/Merida": "središnje vrijeme (Merida)", + "America\/Metlakatla": "aljaško vrijeme (Metlakatla)", + "America\/Mexico_City": "središnje vrijeme (Ciudad de México)", + "America\/Miquelon": "vrijeme za Sveti Petar i Mikelon (Miquelon)", + "America\/Moncton": "atlantsko vrijeme (Moncton)", + "America\/Monterrey": "središnje vrijeme (Monterrey)", + "America\/Montevideo": "urugvajsko vrijeme (Montevideo)", + "America\/Montserrat": "atlantsko vrijeme (Montserrat)", + "America\/Nassau": "istočno vrijeme (Nassau)", + "America\/New_York": "istočno vrijeme (New York)", + "America\/Nipigon": "istočno vrijeme (Nipigon)", + "America\/Nome": "aljaško vrijeme (Nome)", + "America\/Noronha": "vrijeme grada Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "središnje vrijeme (Beulah, Sjeverna Dakota)", + "America\/North_Dakota\/Center": "središnje vrijeme (Center, Sjeverna Dakota)", + "America\/North_Dakota\/New_Salem": "središnje vrijeme (New Salem, Sjeverna Dakota)", + "America\/Ojinaga": "planinsko vrijeme (Ojinaga)", + "America\/Panama": "istočno vrijeme (Panama)", + "America\/Pangnirtung": "istočno vrijeme (Pangnirtung)", + "America\/Paramaribo": "surinamsko vrijeme (Paramaribo)", + "America\/Phoenix": "planinsko vrijeme (Phoenix)", + "America\/Port-au-Prince": "istočno vrijeme (Port-au-Prince)", + "America\/Port_of_Spain": "atlantsko vrijeme (Port of Spain)", + "America\/Porto_Velho": "amazonsko vrijeme (Porto Velho)", + "America\/Puerto_Rico": "atlantsko vrijeme (Portoriko)", + "America\/Punta_Arenas": "čileansko vrijeme (Punta Arenas)", + "America\/Rainy_River": "središnje vrijeme (Rainy River)", + "America\/Rankin_Inlet": "središnje vrijeme (Rankin Inlet)", + "America\/Recife": "brazilijsko vrijeme (Recife)", + "America\/Regina": "središnje vrijeme (Regina)", + "America\/Resolute": "središnje vrijeme (Resolute)", + "America\/Rio_Branco": "Acre vrijeme (Rio Branco)", + "America\/Santa_Isabel": "sjeverozapadno meksičko vrijeme (Santa Isabel)", + "America\/Santarem": "brazilijsko vrijeme (Santarem)", + "America\/Santiago": "čileansko vrijeme (Santiago)", + "America\/Santo_Domingo": "atlantsko vrijeme (Santo Domingo)", + "America\/Sao_Paulo": "brazilijsko vrijeme (Sao Paulo)", + "America\/Scoresbysund": "istočnogrenlandsko vrijeme (Ittoqqortoormiit)", + "America\/Sitka": "aljaško vrijeme (Sitka)", + "America\/St_Barthelemy": "atlantsko vrijeme (Saint Barthélemy)", + "America\/St_Johns": "newfoundlandsko vrijeme (St. John’s)", + "America\/St_Kitts": "atlantsko vrijeme (St. Kitts)", + "America\/St_Lucia": "atlantsko vrijeme (St. Lucia)", + "America\/St_Thomas": "atlantsko vrijeme (St. Thomas)", + "America\/St_Vincent": "atlantsko vrijeme (St. Vincent)", + "America\/Swift_Current": "središnje vrijeme (Swift Current)", + "America\/Tegucigalpa": "središnje vrijeme (Tegucigalpa)", + "America\/Thule": "atlantsko vrijeme (Thule)", + "America\/Thunder_Bay": "istočno vrijeme (Thunder Bay)", + "America\/Tijuana": "pacifičko vrijeme (Tijuana)", + "America\/Toronto": "istočno vrijeme (Toronto)", + "America\/Tortola": "atlantsko vrijeme (Tortola)", + "America\/Vancouver": "pacifičko vrijeme (Vancouver)", + "America\/Whitehorse": "pacifičko vrijeme (Whitehorse)", + "America\/Winnipeg": "središnje vrijeme (Winnipeg)", + "America\/Yakutat": "aljaško vrijeme (Yakutat)", + "America\/Yellowknife": "planinsko vrijeme (Yellowknife)", + "Antarctica\/Casey": "zapadnoaustralsko vrijeme (Casey)", + "Antarctica\/Davis": "vrijeme Davisa (Davis)", + "Antarctica\/DumontDUrville": "vrijeme Dumont-d’Urvillea (Dumont d’Urville)", + "Antarctica\/Macquarie": "vrijeme otoka Macquarie (Macquarie)", + "Antarctica\/Mawson": "mawsonsko vrijeme (Mawson)", + "Antarctica\/McMurdo": "novozelandsko vrijeme (McMurdo)", + "Antarctica\/Palmer": "čileansko vrijeme (Palmer)", + "Antarctica\/Rothera": "vrijeme Rothere (Rothera)", + "Antarctica\/Syowa": "vrijeme Syowe (Syowa)", + "Antarctica\/Troll": "univerzalno vrijeme (Troll)", + "Antarctica\/Vostok": "vostočko vrijeme (Vostok)", + "Arctic\/Longyearbyen": "srednjoeuropsko vrijeme (Longyearbyen)", + "Asia\/Aden": "arapsko vrijeme (Aden)", + "Asia\/Almaty": "istočnokazahstansko vrijeme (Alma Ata)", + "Asia\/Amman": "istočnoeuropsko vrijeme (Amman)", + "Asia\/Anadyr": "anadirsko vrijeme (Anadir)", + "Asia\/Aqtau": "zapadnokazahstansko vrijeme (Aktau)", + "Asia\/Aqtobe": "zapadnokazahstansko vrijeme (Aktobe)", + "Asia\/Ashgabat": "turkmenistansko vrijeme (Ashgabat)", + "Asia\/Atyrau": "zapadnokazahstansko vrijeme (Atyrau)", + "Asia\/Baghdad": "arapsko vrijeme (Bagdad)", + "Asia\/Bahrain": "arapsko vrijeme (Bahrein)", + "Asia\/Baku": "azerbajdžansko vrijeme (Baku)", + "Asia\/Bangkok": "indokinesko vrijeme (Bangkok)", + "Asia\/Beirut": "istočnoeuropsko vrijeme (Beirut)", + "Asia\/Bishkek": "kirgistansko vrijeme (Biškek)", + "Asia\/Brunei": "vrijeme za Brunej Darussalam (Brunej)", + "Asia\/Calcutta": "indijsko vrijeme (Kolkata)", + "Asia\/Chita": "jakutsko vrijeme (Chita)", + "Asia\/Choibalsan": "choibalsansko vrijeme (Choibalsan)", + "Asia\/Colombo": "indijsko vrijeme (Colombo)", + "Asia\/Damascus": "istočnoeuropsko vrijeme (Damask)", + "Asia\/Dhaka": "bangladeško vrijeme (Dhaka)", + "Asia\/Dili": "istočnotimorsko vrijeme (Dili)", + "Asia\/Dubai": "zaljevsko standardno vrijeme (Dubai)", + "Asia\/Dushanbe": "tadžikistansko vrijeme (Dušanbe)", + "Asia\/Famagusta": "istočnoeuropsko vrijeme (Famagusta)", + "Asia\/Gaza": "istočnoeuropsko vrijeme (Gaza)", + "Asia\/Hebron": "istočnoeuropsko vrijeme (Hebron)", + "Asia\/Hong_Kong": "hongkonško vrijeme (Hong Kong)", + "Asia\/Hovd": "hovdsko vrijeme (Hovd)", + "Asia\/Irkutsk": "irkutsko vrijeme (Irkutsk)", + "Asia\/Jakarta": "zapadnoindonezijsko vrijeme (Džakarta)", + "Asia\/Jayapura": "istočnoindonezijsko vrijeme (Jayapura)", + "Asia\/Jerusalem": "izraelsko vrijeme (Jeruzalem)", + "Asia\/Kabul": "afganistansko vrijeme (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-kamčatsko vrijeme (Kamčatka)", + "Asia\/Karachi": "pakistansko vrijeme (Karachi)", + "Asia\/Katmandu": "nepalsko vrijeme (Kathmandu)", + "Asia\/Khandyga": "jakutsko vrijeme (Handiga)", + "Asia\/Krasnoyarsk": "krasnojarsko vrijeme (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "malezijsko vrijeme (Kuala Lumpur)", + "Asia\/Kuching": "malezijsko vrijeme (Kuching)", + "Asia\/Kuwait": "arapsko vrijeme (Kuvajt)", + "Asia\/Macau": "kinesko vrijeme (Makao)", + "Asia\/Magadan": "magadansko vrijeme (Magadan)", + "Asia\/Makassar": "srednjoindonezijsko vrijeme (Makassar)", + "Asia\/Manila": "filipinsko vrijeme (Manila)", + "Asia\/Muscat": "zaljevsko standardno vrijeme (Muscat)", + "Asia\/Nicosia": "istočnoeuropsko vrijeme (Nikozija)", + "Asia\/Novokuznetsk": "krasnojarsko vrijeme (Novokuznjeck)", + "Asia\/Novosibirsk": "novosibirsko vrijeme (Novosibirsk)", + "Asia\/Omsk": "omsko vrijeme (Omsk)", + "Asia\/Oral": "zapadnokazahstansko vrijeme (Oral)", + "Asia\/Phnom_Penh": "indokinesko vrijeme (Phnom Penh)", + "Asia\/Pontianak": "zapadnoindonezijsko vrijeme (Pontianak)", + "Asia\/Pyongyang": "korejsko vrijeme (Pjongjang)", + "Asia\/Qatar": "arapsko vrijeme (Katar)", + "Asia\/Qostanay": "istočnokazahstansko vrijeme (Kostanay)", + "Asia\/Qyzylorda": "zapadnokazahstansko vrijeme (Kizilorda)", + "Asia\/Rangoon": "mjanmarsko vrijeme (Rangoon)", + "Asia\/Riyadh": "arapsko vrijeme (Rijad)", + "Asia\/Saigon": "indokinesko vrijeme (Ho Ši Min)", + "Asia\/Sakhalin": "sahalinsko vrijeme (Sahalin)", + "Asia\/Samarkand": "uzbekistansko vrijeme (Samarkand)", + "Asia\/Seoul": "korejsko vrijeme (Seoul)", + "Asia\/Shanghai": "kinesko vrijeme (Šangaj)", + "Asia\/Singapore": "singapursko vrijeme (Singapur)", + "Asia\/Srednekolymsk": "magadansko vrijeme (Srednekolimsk)", + "Asia\/Taipei": "tajpeško vrijeme (Taipei)", + "Asia\/Tashkent": "uzbekistansko vrijeme (Taškent)", + "Asia\/Tbilisi": "gruzijsko vrijeme (Tbilisi)", + "Asia\/Tehran": "iransko vrijeme (Teheran)", + "Asia\/Thimphu": "butansko vrijeme (Thimphu)", + "Asia\/Tokyo": "japansko vrijeme (Tokyo)", + "Asia\/Ulaanbaatar": "ulanbatorsko vrijeme (Ulan Bator)", + "Asia\/Ust-Nera": "vladivostočko vrijeme (Ust-Nera)", + "Asia\/Vientiane": "indokinesko vrijeme (Vientiane)", + "Asia\/Vladivostok": "vladivostočko vrijeme (Vladivostok)", + "Asia\/Yakutsk": "jakutsko vrijeme (Jakutsk)", + "Asia\/Yekaterinburg": "ekaterinburško vrijeme (Ekaterinburg)", + "Asia\/Yerevan": "armensko vrijeme (Erevan)", + "Atlantic\/Azores": "azorsko vrijeme (Azorski otoci)", + "Atlantic\/Bermuda": "atlantsko vrijeme (Bermuda)", + "Atlantic\/Canary": "zapadnoeuropsko vrijeme (Kanari)", + "Atlantic\/Cape_Verde": "vrijeme Zelenortskog otočja (Zelenortski Otoci)", + "Atlantic\/Faeroe": "zapadnoeuropsko vrijeme (Ferojski otoci)", + "Atlantic\/Madeira": "zapadnoeuropsko vrijeme (Madeira)", + "Atlantic\/Reykjavik": "univerzalno vrijeme (Reykjavik)", + "Atlantic\/South_Georgia": "vrijeme Južne Georgije (Južna Georgija)", + "Atlantic\/St_Helena": "univerzalno vrijeme (St. Helena)", + "Atlantic\/Stanley": "falklandsko vrijeme (Stanley)", + "Australia\/Adelaide": "srednjoaustralsko vrijeme (Adelaide)", + "Australia\/Brisbane": "istočnoaustralsko vrijeme (Brisbane)", + "Australia\/Broken_Hill": "srednjoaustralsko vrijeme (Broken Hill)", + "Australia\/Currie": "istočnoaustralsko vrijeme (Currie)", + "Australia\/Darwin": "srednjoaustralsko vrijeme (Darwin)", + "Australia\/Eucla": "australsko središnje zapadno vrijeme (Eucla)", + "Australia\/Hobart": "istočnoaustralsko vrijeme (Hobart)", + "Australia\/Lindeman": "istočnoaustralsko vrijeme (Lindeman)", + "Australia\/Lord_Howe": "vrijeme otoka Lord Howe (Lord Howe)", + "Australia\/Melbourne": "istočnoaustralsko vrijeme (Melbourne)", + "Australia\/Perth": "zapadnoaustralsko vrijeme (Perth)", + "Australia\/Sydney": "istočnoaustralsko vrijeme (Sydney)", + "CST6CDT": "središnje vrijeme", + "EST5EDT": "istočno vrijeme", + "Etc\/GMT": "univerzalno vrijeme", + "Etc\/UTC": "koordinirano svjetsko vrijeme", + "Europe\/Amsterdam": "srednjoeuropsko vrijeme (Amsterdam)", + "Europe\/Andorra": "srednjoeuropsko vrijeme (Andora)", + "Europe\/Astrakhan": "moskovsko vrijeme (Astrakhan)", + "Europe\/Athens": "istočnoeuropsko vrijeme (Atena)", + "Europe\/Belgrade": "srednjoeuropsko vrijeme (Beograd)", + "Europe\/Berlin": "srednjoeuropsko vrijeme (Berlin)", + "Europe\/Bratislava": "srednjoeuropsko vrijeme (Bratislava)", + "Europe\/Brussels": "srednjoeuropsko vrijeme (Bruxelles)", + "Europe\/Bucharest": "istočnoeuropsko vrijeme (Bukurešt)", + "Europe\/Budapest": "srednjoeuropsko vrijeme (Budimpešta)", + "Europe\/Busingen": "srednjoeuropsko vrijeme (Busingen)", + "Europe\/Chisinau": "istočnoeuropsko vrijeme (Kišinjev)", + "Europe\/Copenhagen": "srednjoeuropsko vrijeme (Kopenhagen)", + "Europe\/Dublin": "univerzalno vrijeme (Dublin)", + "Europe\/Gibraltar": "srednjoeuropsko vrijeme (Gibraltar)", + "Europe\/Guernsey": "univerzalno vrijeme (Guernsey)", + "Europe\/Helsinki": "istočnoeuropsko vrijeme (Helsinki)", + "Europe\/Isle_of_Man": "univerzalno vrijeme (Otok Man)", + "Europe\/Jersey": "univerzalno vrijeme (Jersey)", + "Europe\/Kaliningrad": "istočnoeuropsko vrijeme (Kalinjingrad)", + "Europe\/Kiev": "istočnoeuropsko vrijeme (Kijev)", + "Europe\/Lisbon": "zapadnoeuropsko vrijeme (Lisabon)", + "Europe\/Ljubljana": "srednjoeuropsko vrijeme (Ljubljana)", + "Europe\/London": "univerzalno vrijeme (London)", + "Europe\/Luxembourg": "srednjoeuropsko vrijeme (Luksemburg)", + "Europe\/Madrid": "srednjoeuropsko vrijeme (Madrid)", + "Europe\/Malta": "srednjoeuropsko vrijeme (Malta)", + "Europe\/Mariehamn": "istočnoeuropsko vrijeme (Mariehamn)", + "Europe\/Minsk": "moskovsko vrijeme (Minsk)", + "Europe\/Monaco": "srednjoeuropsko vrijeme (Monako)", + "Europe\/Moscow": "moskovsko vrijeme (Moskva)", + "Europe\/Oslo": "srednjoeuropsko vrijeme (Oslo)", + "Europe\/Paris": "srednjoeuropsko vrijeme (Pariz)", + "Europe\/Podgorica": "srednjoeuropsko vrijeme (Podgorica)", + "Europe\/Prague": "srednjoeuropsko vrijeme (Prag)", + "Europe\/Riga": "istočnoeuropsko vrijeme (Riga)", + "Europe\/Rome": "srednjoeuropsko vrijeme (Rim)", + "Europe\/Samara": "samarsko vrijeme (Samara)", + "Europe\/San_Marino": "srednjoeuropsko vrijeme (San Marino)", + "Europe\/Sarajevo": "srednjoeuropsko vrijeme (Sarajevo)", + "Europe\/Saratov": "moskovsko vrijeme (Saratov)", + "Europe\/Simferopol": "moskovsko vrijeme (Simferopol)", + "Europe\/Skopje": "srednjoeuropsko vrijeme (Skoplje)", + "Europe\/Sofia": "istočnoeuropsko vrijeme (Sofija)", + "Europe\/Stockholm": "srednjoeuropsko vrijeme (Stockholm)", + "Europe\/Tallinn": "istočnoeuropsko vrijeme (Tallinn)", + "Europe\/Tirane": "srednjoeuropsko vrijeme (Tirana)", + "Europe\/Ulyanovsk": "moskovsko vrijeme (Uljanovsk)", + "Europe\/Uzhgorod": "istočnoeuropsko vrijeme (Užgorod)", + "Europe\/Vaduz": "srednjoeuropsko vrijeme (Vaduz)", + "Europe\/Vatican": "srednjoeuropsko vrijeme (Vatikan)", + "Europe\/Vienna": "srednjoeuropsko vrijeme (Beč)", + "Europe\/Vilnius": "istočnoeuropsko vrijeme (Vilnius)", + "Europe\/Volgograd": "volgogradsko vrijeme (Volgograd)", + "Europe\/Warsaw": "srednjoeuropsko vrijeme (Varšava)", + "Europe\/Zagreb": "srednjoeuropsko vrijeme (Zagreb)", + "Europe\/Zaporozhye": "istočnoeuropsko vrijeme (Zaporožje)", + "Europe\/Zurich": "srednjoeuropsko vrijeme (Zürich)", + "Indian\/Antananarivo": "istočnoafričko vrijeme (Antananarivo)", + "Indian\/Chagos": "vrijeme Indijskog oceana (Chagos)", + "Indian\/Christmas": "vrijeme Božićnog otoka (Božićni otok)", + "Indian\/Cocos": "vrijeme Kokosovih otoka (Kokosovi otoci)", + "Indian\/Comoro": "istočnoafričko vrijeme (Komori)", + "Indian\/Kerguelen": "južnofrancusko i antarktičko vrijeme (Kerguelen)", + "Indian\/Mahe": "sejšelsko vrijeme (Mahe)", + "Indian\/Maldives": "maldivsko vrijeme (Maldivi)", + "Indian\/Mauritius": "vrijeme Mauricijusa (Mauricijus)", + "Indian\/Mayotte": "istočnoafričko vrijeme (Mayotte)", + "Indian\/Reunion": "vrijeme Reuniona (Réunion)", + "MST7MDT": "planinsko vrijeme", + "PST8PDT": "pacifičko vrijeme", + "Pacific\/Apia": "vrijeme Apije (Apia)", + "Pacific\/Auckland": "novozelandsko vrijeme (Auckland)", + "Pacific\/Bougainville": "vrijeme Papue Nove Gvineje (Bougainville)", + "Pacific\/Chatham": "vrijeme Chathama (Chatham)", + "Pacific\/Easter": "vrijeme Uskršnjeg otoka (Uskršnji otok)", + "Pacific\/Efate": "vrijeme Vanuatua (Efate)", + "Pacific\/Enderbury": "vrijeme Otoka Phoenix (Enderbury)", + "Pacific\/Fakaofo": "vrijeme Tokelaua (Fakaofo)", + "Pacific\/Fiji": "vrijeme Fidžija (Fidži)", + "Pacific\/Funafuti": "vrijeme Tuvalua (Funafuti)", + "Pacific\/Galapagos": "vrijeme Galapagosa (Galapagos)", + "Pacific\/Gambier": "vrijeme Gambiera (Gambier)", + "Pacific\/Guadalcanal": "vrijeme Salomonskih Otoka (Guadalcanal)", + "Pacific\/Guam": "standardno vrijeme Chamorra (Guam)", + "Pacific\/Honolulu": "havajsko-aleutsko vrijeme (Honolulu)", + "Pacific\/Johnston": "havajsko-aleutsko vrijeme (Johnston)", + "Pacific\/Kiritimati": "vrijeme Otoka Line (Kiritimati)", + "Pacific\/Kosrae": "vrijeme Kosrae (Kosrae)", + "Pacific\/Kwajalein": "vrijeme Maršalovih Otoka (Kwajalein)", + "Pacific\/Majuro": "vrijeme Maršalovih Otoka (Majuro)", + "Pacific\/Marquesas": "markižansko vrijeme (Markižansko otočje)", + "Pacific\/Midway": "samoansko vrijeme (Midway)", + "Pacific\/Nauru": "vrijeme Naurua (Nauru)", + "Pacific\/Niue": "vrijeme Niuea (Niue)", + "Pacific\/Norfolk": "vrijeme Otoka Norfolk (Norfolk)", + "Pacific\/Noumea": "vrijeme Nove Kaledonije (Noumea)", + "Pacific\/Pago_Pago": "samoansko vrijeme (Pago Pago)", + "Pacific\/Palau": "vrijeme Palaua (Palau)", + "Pacific\/Pitcairn": "vrijeme Pitcairna (Pitcairn)", + "Pacific\/Ponape": "vrijeme Ponapea (Pohnpei)", + "Pacific\/Port_Moresby": "vrijeme Papue Nove Gvineje (Port Moresby)", + "Pacific\/Rarotonga": "vrijeme Cookovih otoka (Rarotonga)", + "Pacific\/Saipan": "standardno vrijeme Chamorra (Saipan)", + "Pacific\/Tahiti": "vrijeme Tahitija (Tahiti)", + "Pacific\/Tarawa": "vrijeme Gilbertovih otoka (Tarawa)", + "Pacific\/Tongatapu": "vrijeme Tonge (Tongatapu)", + "Pacific\/Truk": "vrijeme Chuuka (Chuuk)", + "Pacific\/Wake": "vrijeme Otoka Wake (Wake)", + "Pacific\/Wallis": "vrijeme Otoka Wallis i Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/hu.json b/src/Symfony/Component/Intl/Resources/data/timezones/hu.json new file mode 100644 index 0000000000000..2523c612a78ef --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/hu.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "greenwichi középidő, téli idő (Abidjan)", + "Africa\/Accra": "greenwichi középidő, téli idő (Accra)", + "Africa\/Addis_Ababa": "kelet-afrikai téli idő (Addisz-Abeba)", + "Africa\/Algiers": "közép-európai időzóna (Algír)", + "Africa\/Asmera": "kelet-afrikai téli idő (Asmera)", + "Africa\/Bamako": "greenwichi középidő, téli idő (Bamako)", + "Africa\/Bangui": "nyugat-afrikai időzóna (Bangui)", + "Africa\/Banjul": "greenwichi középidő, téli idő (Banjul)", + "Africa\/Bissau": "greenwichi középidő, téli idő (Bissau)", + "Africa\/Blantyre": "közép-afrikai téli idő (Blantyre)", + "Africa\/Brazzaville": "nyugat-afrikai időzóna (Brazzaville)", + "Africa\/Bujumbura": "közép-afrikai téli idő (Bujumbura)", + "Africa\/Cairo": "kelet-európai időzóna (Kairó)", + "Africa\/Casablanca": "nyugat-európai időzóna (Casablanca)", + "Africa\/Ceuta": "közép-európai időzóna (Ceuta)", + "Africa\/Conakry": "greenwichi középidő, téli idő (Conakry)", + "Africa\/Dakar": "greenwichi középidő, téli idő (Dakar)", + "Africa\/Dar_es_Salaam": "kelet-afrikai téli idő (Dar es-Salaam)", + "Africa\/Djibouti": "kelet-afrikai téli idő (Dzsibuti)", + "Africa\/Douala": "nyugat-afrikai időzóna (Douala)", + "Africa\/El_Aaiun": "nyugat-európai időzóna (El-Ajún)", + "Africa\/Freetown": "greenwichi középidő, téli idő (Freetown)", + "Africa\/Gaborone": "közép-afrikai téli idő (Gaborone)", + "Africa\/Harare": "közép-afrikai téli idő (Harare)", + "Africa\/Johannesburg": "dél-afrikai téli idő (Johannesburg)", + "Africa\/Juba": "kelet-afrikai téli idő (Juba)", + "Africa\/Kampala": "kelet-afrikai téli idő (Kampala)", + "Africa\/Khartoum": "közép-afrikai téli idő (Kartúm)", + "Africa\/Kigali": "közép-afrikai téli idő (Kigali)", + "Africa\/Kinshasa": "nyugat-afrikai időzóna (Kinshasa)", + "Africa\/Lagos": "nyugat-afrikai időzóna (Lagos)", + "Africa\/Libreville": "nyugat-afrikai időzóna (Libreville)", + "Africa\/Lome": "greenwichi középidő, téli idő (Lome)", + "Africa\/Luanda": "nyugat-afrikai időzóna (Luanda)", + "Africa\/Lubumbashi": "közép-afrikai téli idő (Lubumbashi)", + "Africa\/Lusaka": "közép-afrikai téli idő (Lusaka)", + "Africa\/Malabo": "nyugat-afrikai időzóna (Malabó)", + "Africa\/Maputo": "közép-afrikai téli idő (Maputo)", + "Africa\/Maseru": "dél-afrikai téli idő (Maseru)", + "Africa\/Mbabane": "dél-afrikai téli idő (Mbabane)", + "Africa\/Mogadishu": "kelet-afrikai téli idő (Mogadishu)", + "Africa\/Monrovia": "greenwichi középidő, téli idő (Monrovia)", + "Africa\/Nairobi": "kelet-afrikai téli idő (Nairobi)", + "Africa\/Ndjamena": "nyugat-afrikai időzóna (Ndjamena)", + "Africa\/Niamey": "nyugat-afrikai időzóna (Niamey)", + "Africa\/Nouakchott": "greenwichi középidő, téli idő (Nouakchott)", + "Africa\/Ouagadougou": "greenwichi középidő, téli idő (Ouagadougou)", + "Africa\/Porto-Novo": "nyugat-afrikai időzóna (Porto-Novo)", + "Africa\/Sao_Tome": "greenwichi középidő, téli idő (São Tomé)", + "Africa\/Tripoli": "kelet-európai időzóna (Tripoli)", + "Africa\/Tunis": "közép-európai időzóna (Tunisz)", + "Africa\/Windhoek": "közép-afrikai téli idő (Windhoek)", + "America\/Adak": "hawaii-aleuti időzóna (Adak)", + "America\/Anchorage": "alaszkai idő (Anchorage)", + "America\/Anguilla": "atlanti-óceáni idő (Anguilla)", + "America\/Antigua": "atlanti-óceáni idő (Antigua)", + "America\/Araguaina": "brazíliai idő (Araguaína)", + "America\/Argentina\/La_Rioja": "argentínai idő (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "argentínai idő (Río Gallegos)", + "America\/Argentina\/Salta": "argentínai idő (Salta)", + "America\/Argentina\/San_Juan": "argentínai idő (San Juan)", + "America\/Argentina\/San_Luis": "nyugat-argentínai időzóna (San Luis)", + "America\/Argentina\/Tucuman": "argentínai idő (Tucumán)", + "America\/Argentina\/Ushuaia": "argentínai idő (Ushuaia)", + "America\/Aruba": "atlanti-óceáni idő (Aruba)", + "America\/Asuncion": "paraguayi idő (Asunción)", + "America\/Bahia": "brazíliai idő (Bahia)", + "America\/Bahia_Banderas": "középső államokbeli idő (Bahia Banderas)", + "America\/Barbados": "atlanti-óceáni idő (Barbados)", + "America\/Belem": "brazíliai idő (Belém)", + "America\/Belize": "középső államokbeli idő (Belize)", + "America\/Blanc-Sablon": "atlanti-óceáni idő (Blanc-Sablon)", + "America\/Boa_Vista": "amazóniai idő (Boa Vista)", + "America\/Bogota": "kolumbiai idő (Bogotá)", + "America\/Boise": "hegyvidéki idő (Boise)", + "America\/Buenos_Aires": "argentínai idő (Buenos Aires)", + "America\/Cambridge_Bay": "hegyvidéki idő (Cambridge Bay)", + "America\/Campo_Grande": "amazóniai idő (Campo Grande)", + "America\/Cancun": "keleti államokbeli idő (Cancún)", + "America\/Caracas": "venezuelai idő (Caracas)", + "America\/Catamarca": "argentínai idő (Catamarca)", + "America\/Cayenne": "francia-guyanai idő (Cayenne)", + "America\/Cayman": "keleti államokbeli idő (Kajmán-szigetek)", + "America\/Chicago": "középső államokbeli idő (Chicago)", + "America\/Chihuahua": "mexikói csendes-óceáni idő (Chihuahua)", + "America\/Coral_Harbour": "keleti államokbeli idő (Atikokan)", + "America\/Cordoba": "argentínai idő (Córdoba)", + "America\/Costa_Rica": "középső államokbeli idő (Costa Rica)", + "America\/Creston": "hegyvidéki idő (Creston)", + "America\/Cuiaba": "amazóniai idő (Cuiabá)", + "America\/Curacao": "atlanti-óceáni idő (Curaçao)", + "America\/Danmarkshavn": "greenwichi középidő, téli idő (Danmarkshavn)", + "America\/Dawson": "csendes-óceáni idő (Dawson)", + "America\/Dawson_Creek": "hegyvidéki idő (Dawson Creek)", + "America\/Denver": "hegyvidéki idő (Denver)", + "America\/Detroit": "keleti államokbeli idő (Detroit)", + "America\/Dominica": "atlanti-óceáni idő (Dominika)", + "America\/Edmonton": "hegyvidéki idő (Edmonton)", + "America\/Eirunepe": "Acre idő (Eirunepé)", + "America\/El_Salvador": "középső államokbeli idő (Salvador)", + "America\/Fort_Nelson": "hegyvidéki idő (Fort Nelson)", + "America\/Fortaleza": "brazíliai idő (Fortaleza)", + "America\/Glace_Bay": "atlanti-óceáni idő (Glace Bay)", + "America\/Godthab": "nyugat-grönlandi időzóna (Nuuk)", + "America\/Goose_Bay": "atlanti-óceáni idő (Goose Bay)", + "America\/Grand_Turk": "keleti államokbeli idő (Grand Turk)", + "America\/Grenada": "atlanti-óceáni idő (Grenada)", + "America\/Guadeloupe": "atlanti-óceáni idő (Guadeloupe)", + "America\/Guatemala": "középső államokbeli idő (Guatemala)", + "America\/Guayaquil": "ecuadori téli idő (Guayaquil)", + "America\/Guyana": "guyanai téli idő (Guyana)", + "America\/Halifax": "atlanti-óceáni idő (Halifax)", + "America\/Havana": "kubai időzóna (Havanna)", + "America\/Hermosillo": "mexikói csendes-óceáni idő (Hermosillo)", + "America\/Indiana\/Knox": "középső államokbeli idő (Knox, Indiana)", + "America\/Indiana\/Marengo": "keleti államokbeli idő (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "keleti államokbeli idő (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "középső államokbeli idő (Tell City, Indiana)", + "America\/Indiana\/Vevay": "keleti államokbeli idő (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "keleti államokbeli idő (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "keleti államokbeli idő (Winamac, Indiana)", + "America\/Indianapolis": "keleti államokbeli idő (Indianapolis)", + "America\/Inuvik": "hegyvidéki idő (Inuvik)", + "America\/Iqaluit": "keleti államokbeli idő (Iqaluit)", + "America\/Jamaica": "keleti államokbeli idő (Jamaica)", + "America\/Jujuy": "argentínai idő (Jujuy)", + "America\/Juneau": "alaszkai idő (Juneau)", + "America\/Kentucky\/Monticello": "keleti államokbeli idő (Monticello, Kentucky)", + "America\/Kralendijk": "atlanti-óceáni idő (Kralendijk)", + "America\/La_Paz": "bolíviai téli idő (La Paz)", + "America\/Lima": "perui idő (Lima)", + "America\/Los_Angeles": "csendes-óceáni idő (Los Angeles)", + "America\/Louisville": "keleti államokbeli idő (Louisville)", + "America\/Lower_Princes": "atlanti-óceáni idő (Lower Prince’s Quarter)", + "America\/Maceio": "brazíliai idő (Maceió)", + "America\/Managua": "középső államokbeli idő (Managua)", + "America\/Manaus": "amazóniai idő (Manaus)", + "America\/Marigot": "atlanti-óceáni idő (Marigot)", + "America\/Martinique": "atlanti-óceáni idő (Martinique)", + "America\/Matamoros": "középső államokbeli idő (Matamoros)", + "America\/Mazatlan": "mexikói csendes-óceáni idő (Mazatlán)", + "America\/Mendoza": "argentínai idő (Mendoza)", + "America\/Menominee": "középső államokbeli idő (Menominee)", + "America\/Merida": "középső államokbeli idő (Mérida)", + "America\/Metlakatla": "alaszkai idő (Metlakatla)", + "America\/Mexico_City": "középső államokbeli idő (Mexikóváros)", + "America\/Miquelon": "Saint-Pierre és Miquelon-i idő (Miquelon)", + "America\/Moncton": "atlanti-óceáni idő (Moncton)", + "America\/Monterrey": "középső államokbeli idő (Monterrey)", + "America\/Montevideo": "uruguayi idő (Montevideo)", + "America\/Montserrat": "atlanti-óceáni idő (Montserrat)", + "America\/Nassau": "keleti államokbeli idő (Nassau)", + "America\/New_York": "keleti államokbeli idő (New York)", + "America\/Nipigon": "keleti államokbeli idő (Nipigon)", + "America\/Nome": "alaszkai idő (Nome)", + "America\/Noronha": "Fernando de Noronha-i idő (Noronha)", + "America\/North_Dakota\/Beulah": "középső államokbeli idő (Beulah, Észak-Dakota)", + "America\/North_Dakota\/Center": "középső államokbeli idő (Center, Észak-Dakota)", + "America\/North_Dakota\/New_Salem": "középső államokbeli idő (New Salem, Észak-Dakota)", + "America\/Ojinaga": "hegyvidéki idő (Ojinaga)", + "America\/Panama": "keleti államokbeli idő (Panama)", + "America\/Pangnirtung": "keleti államokbeli idő (Pangnirtung)", + "America\/Paramaribo": "szurinámi idő (Paramaribo)", + "America\/Phoenix": "hegyvidéki idő (Phoenix)", + "America\/Port-au-Prince": "keleti államokbeli idő (Port-au-Prince)", + "America\/Port_of_Spain": "atlanti-óceáni idő (Port of Spain)", + "America\/Porto_Velho": "amazóniai idő (Porto Velho)", + "America\/Puerto_Rico": "atlanti-óceáni idő (Puerto Rico)", + "America\/Punta_Arenas": "chilei időzóna (Punta Arenas)", + "America\/Rainy_River": "középső államokbeli idő (Rainy River)", + "America\/Rankin_Inlet": "középső államokbeli idő (Rankin Inlet)", + "America\/Recife": "brazíliai idő (Recife)", + "America\/Regina": "középső államokbeli idő (Regina)", + "America\/Resolute": "középső államokbeli idő (Resolute)", + "America\/Rio_Branco": "Acre idő (Río Branco)", + "America\/Santa_Isabel": "északnyugat-mexikói idő (Santa Isabel)", + "America\/Santarem": "brazíliai idő (Santarem)", + "America\/Santiago": "chilei időzóna (Santiago)", + "America\/Santo_Domingo": "atlanti-óceáni idő (Santo Domingo)", + "America\/Sao_Paulo": "brazíliai idő (São Paulo)", + "America\/Scoresbysund": "kelet-grönlandi időzóna (Ittoqqortoormiit)", + "America\/Sitka": "alaszkai idő (Sitka)", + "America\/St_Barthelemy": "atlanti-óceáni idő (Saint-Barthélemy)", + "America\/St_Johns": "új-fundlandi idő (St. John’s)", + "America\/St_Kitts": "atlanti-óceáni idő (St. Kitts)", + "America\/St_Lucia": "atlanti-óceáni idő (St. Lucia)", + "America\/St_Thomas": "atlanti-óceáni idő (St. Thomas)", + "America\/St_Vincent": "atlanti-óceáni idő (St. Vincent)", + "America\/Swift_Current": "középső államokbeli idő (Swift Current)", + "America\/Tegucigalpa": "középső államokbeli idő (Tegucigalpa)", + "America\/Thule": "atlanti-óceáni idő (Thule)", + "America\/Thunder_Bay": "keleti államokbeli idő (Thunder Bay)", + "America\/Tijuana": "csendes-óceáni idő (Tijuana)", + "America\/Toronto": "keleti államokbeli idő (Toronto)", + "America\/Tortola": "atlanti-óceáni idő (Tortola)", + "America\/Vancouver": "csendes-óceáni idő (Vancouver)", + "America\/Whitehorse": "csendes-óceáni idő (Whitehorse)", + "America\/Winnipeg": "középső államokbeli idő (Winnipeg)", + "America\/Yakutat": "alaszkai idő (Yakutat)", + "America\/Yellowknife": "hegyvidéki idő (Yellowknife)", + "Antarctica\/Casey": "nyugat-ausztráliai idő (Casey)", + "Antarctica\/Davis": "davisi idő (Davis)", + "Antarctica\/DumontDUrville": "dumont-d’Urville-i idő (Dumont d’Urville)", + "Antarctica\/Macquarie": "macquarie-szigeti téli idő (Macquarie)", + "Antarctica\/Mawson": "mawsoni idő (Mawson)", + "Antarctica\/McMurdo": "új-zélandi idő (McMurdo)", + "Antarctica\/Palmer": "chilei időzóna (Palmer)", + "Antarctica\/Rothera": "rotherai idő (Rothera)", + "Antarctica\/Syowa": "syowai idő (Syowa)", + "Antarctica\/Troll": "greenwichi középidő, téli idő (Troll)", + "Antarctica\/Vostok": "vosztoki idő (Vosztok)", + "Arctic\/Longyearbyen": "közép-európai időzóna (Longyearbyen)", + "Asia\/Aden": "arab idő (Áden)", + "Asia\/Almaty": "kelet-kazahsztáni idő (Alma-Ata)", + "Asia\/Amman": "kelet-európai időzóna (Ammán)", + "Asia\/Anadyr": "Anadiri idő (Anadir)", + "Asia\/Aqtau": "nyugat-kazahsztáni idő (Aktau)", + "Asia\/Aqtobe": "nyugat-kazahsztáni idő (Aktöbe)", + "Asia\/Ashgabat": "türkmenisztáni idő (Asgabat)", + "Asia\/Atyrau": "nyugat-kazahsztáni idő (Atyrau)", + "Asia\/Baghdad": "arab idő (Bagdad)", + "Asia\/Bahrain": "arab idő (Bahrein)", + "Asia\/Baku": "azerbajdzsáni idő (Baku)", + "Asia\/Bangkok": "indokínai idő (Bangkok)", + "Asia\/Beirut": "kelet-európai időzóna (Bejrút)", + "Asia\/Bishkek": "kirgizisztáni idő (Biskek)", + "Asia\/Brunei": "Brunei Darussalam-i idő (Brunei)", + "Asia\/Calcutta": "indiai téli idő (Kalkutta)", + "Asia\/Chita": "jakutszki idő (Csita)", + "Asia\/Choibalsan": "csojbalszani idő (Csojbalszan)", + "Asia\/Colombo": "indiai téli idő (Colombo)", + "Asia\/Damascus": "kelet-európai időzóna (Damaszkusz)", + "Asia\/Dhaka": "bangladesi idő (Dakka)", + "Asia\/Dili": "kelet-timori téli idő (Dili)", + "Asia\/Dubai": "öbölbeli téli idő (Dubai)", + "Asia\/Dushanbe": "tádzsikisztáni idő (Dushanbe)", + "Asia\/Famagusta": "kelet-európai időzóna (Famagusta)", + "Asia\/Gaza": "kelet-európai időzóna (Gáza)", + "Asia\/Hebron": "kelet-európai időzóna (Hebron)", + "Asia\/Hong_Kong": "hongkongi időzóna (Hongkong)", + "Asia\/Hovd": "hovdi idő (Hovd)", + "Asia\/Irkutsk": "irkutszki idő (Irkutszk)", + "Asia\/Jakarta": "nyugat-indonéziai téli idő (Jakarta)", + "Asia\/Jayapura": "kelet-indonéziai idő (Jayapura)", + "Asia\/Jerusalem": "izraeli idő (Jeruzsálem)", + "Asia\/Kabul": "afganisztáni idő (Kabul)", + "Asia\/Kamchatka": "Petropavlovszk-kamcsatkai idő (Kamcsatka)", + "Asia\/Karachi": "pakisztáni idő (Karacsi)", + "Asia\/Katmandu": "nepáli idő (Katmandu)", + "Asia\/Khandyga": "jakutszki idő (Handiga)", + "Asia\/Krasnoyarsk": "krasznojarszki idő (Krasznojarszk)", + "Asia\/Kuala_Lumpur": "malajziai idő (Kuala Lumpur)", + "Asia\/Kuching": "malajziai idő (Kucseng)", + "Asia\/Kuwait": "arab idő (Kuvait)", + "Asia\/Macau": "kínai idő (Makaó)", + "Asia\/Magadan": "magadáni idő (Magadán)", + "Asia\/Makassar": "közép-indonéziai idő (Makasar)", + "Asia\/Manila": "fülöp-szigeteki idő (Manila)", + "Asia\/Muscat": "öbölbeli téli idő (Muscat)", + "Asia\/Nicosia": "kelet-európai időzóna (Nicosia)", + "Asia\/Novokuznetsk": "krasznojarszki idő (Novokuznyeck)", + "Asia\/Novosibirsk": "novoszibirszki idő (Novoszibirszk)", + "Asia\/Omsk": "omszki idő (Omszk)", + "Asia\/Oral": "nyugat-kazahsztáni idő (Oral)", + "Asia\/Phnom_Penh": "indokínai idő (Phnom Penh)", + "Asia\/Pontianak": "nyugat-indonéziai téli idő (Pontianak)", + "Asia\/Pyongyang": "koreai idő (Phenjan)", + "Asia\/Qatar": "arab idő (Katar)", + "Asia\/Qostanay": "kelet-kazahsztáni idő (Kosztanaj)", + "Asia\/Qyzylorda": "nyugat-kazahsztáni idő (Kizilorda)", + "Asia\/Rangoon": "mianmari idő (Yangon)", + "Asia\/Riyadh": "arab idő (Rijád)", + "Asia\/Saigon": "indokínai idő (Ho Si Minh-város)", + "Asia\/Sakhalin": "szahalini idő (Szahalin)", + "Asia\/Samarkand": "üzbegisztáni idő (Szamarkand)", + "Asia\/Seoul": "koreai idő (Szöul)", + "Asia\/Shanghai": "kínai idő (Sanghaj)", + "Asia\/Singapore": "szingapúri téli idő (Szingapúr)", + "Asia\/Srednekolymsk": "magadáni idő (Szrednekolimszk)", + "Asia\/Taipei": "taipei idő (Tajpej)", + "Asia\/Tashkent": "üzbegisztáni idő (Taskent)", + "Asia\/Tbilisi": "grúziai idő (Tbiliszi)", + "Asia\/Tehran": "iráni idő (Teherán)", + "Asia\/Thimphu": "butáni idő (Thimphu)", + "Asia\/Tokyo": "japán idő (Tokió)", + "Asia\/Ulaanbaatar": "ulánbátori idő (Ulánbátor)", + "Asia\/Ust-Nera": "vlagyivosztoki idő (Uszty-Nyera)", + "Asia\/Vientiane": "indokínai idő (Vientián)", + "Asia\/Vladivostok": "vlagyivosztoki idő (Vlagyivosztok)", + "Asia\/Yakutsk": "jakutszki idő (Jakutszk)", + "Asia\/Yekaterinburg": "jekatyerinburgi idő (Jekatyerinburg)", + "Asia\/Yerevan": "örményországi idő (Jereván)", + "Atlantic\/Azores": "azori időzóna (Azori-szigetek)", + "Atlantic\/Bermuda": "atlanti-óceáni idő (Bermuda)", + "Atlantic\/Canary": "nyugat-európai időzóna (Kanári-szigetek)", + "Atlantic\/Cape_Verde": "zöld-foki-szigeteki időzóna (Zöld-foki szigetek)", + "Atlantic\/Faeroe": "nyugat-európai időzóna (Feröer)", + "Atlantic\/Madeira": "nyugat-európai időzóna (Madeira)", + "Atlantic\/Reykjavik": "greenwichi középidő, téli idő (Reykjavík)", + "Atlantic\/South_Georgia": "déli-georgiai idő (Déli-Georgia)", + "Atlantic\/St_Helena": "greenwichi középidő, téli idő (Szent Ilona)", + "Atlantic\/Stanley": "falkland-szigeteki idő (Stanley)", + "Australia\/Adelaide": "közép-ausztráliai idő (Adelaide)", + "Australia\/Brisbane": "kelet-ausztráliai idő (Brisbane)", + "Australia\/Broken_Hill": "közép-ausztráliai idő (Broken Hill)", + "Australia\/Currie": "kelet-ausztráliai idő (Currie)", + "Australia\/Darwin": "közép-ausztráliai idő (Darwin)", + "Australia\/Eucla": "közép-nyugat-ausztráliai idő (Eucla)", + "Australia\/Hobart": "kelet-ausztráliai idő (Hobart)", + "Australia\/Lindeman": "kelet-ausztráliai idő (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe-szigeti idő (Lord Howe)", + "Australia\/Melbourne": "kelet-ausztráliai idő (Melbourne)", + "Australia\/Perth": "nyugat-ausztráliai idő (Perth)", + "Australia\/Sydney": "kelet-ausztráliai idő (Sydney)", + "CST6CDT": "középső államokbeli idő", + "EST5EDT": "keleti államokbeli idő", + "Etc\/GMT": "greenwichi középidő, téli idő", + "Etc\/UTC": "egyezményes koordinált világidő", + "Europe\/Amsterdam": "közép-európai időzóna (Amszterdam)", + "Europe\/Andorra": "közép-európai időzóna (Andorra)", + "Europe\/Astrakhan": "moszkvai idő (Asztrahán)", + "Europe\/Athens": "kelet-európai időzóna (Athén)", + "Europe\/Belgrade": "közép-európai időzóna (Belgrád)", + "Europe\/Berlin": "közép-európai időzóna (Berlin)", + "Europe\/Bratislava": "közép-európai időzóna (Pozsony)", + "Europe\/Brussels": "közép-európai időzóna (Brüsszel)", + "Europe\/Bucharest": "kelet-európai időzóna (Bukarest)", + "Europe\/Budapest": "közép-európai időzóna (Budapest)", + "Europe\/Busingen": "közép-európai időzóna (Büsingen)", + "Europe\/Chisinau": "kelet-európai időzóna (Chisinau)", + "Europe\/Copenhagen": "közép-európai időzóna (Koppenhága)", + "Europe\/Dublin": "greenwichi középidő, téli idő (Dublin)", + "Europe\/Gibraltar": "közép-európai időzóna (Gibraltár)", + "Europe\/Guernsey": "greenwichi középidő, téli idő (Guernsey)", + "Europe\/Helsinki": "kelet-európai időzóna (Helsinki)", + "Europe\/Isle_of_Man": "greenwichi középidő, téli idő (Man-sziget)", + "Europe\/Jersey": "greenwichi középidő, téli idő (Jersey)", + "Europe\/Kaliningrad": "kelet-európai időzóna (Kalinyingrád)", + "Europe\/Kiev": "kelet-európai időzóna (Kijev)", + "Europe\/Lisbon": "nyugat-európai időzóna (Lisszabon)", + "Europe\/Ljubljana": "közép-európai időzóna (Ljubljana)", + "Europe\/London": "greenwichi középidő, téli idő (London)", + "Europe\/Luxembourg": "közép-európai időzóna (Luxemburg)", + "Europe\/Madrid": "közép-európai időzóna (Madrid)", + "Europe\/Malta": "közép-európai időzóna (Málta)", + "Europe\/Mariehamn": "kelet-európai időzóna (Mariehamn)", + "Europe\/Minsk": "moszkvai idő (Minszk)", + "Europe\/Monaco": "közép-európai időzóna (Monaco)", + "Europe\/Moscow": "moszkvai idő (Moszkva)", + "Europe\/Oslo": "közép-európai időzóna (Oslo)", + "Europe\/Paris": "közép-európai időzóna (Párizs)", + "Europe\/Podgorica": "közép-európai időzóna (Podgorica)", + "Europe\/Prague": "közép-európai időzóna (Prága)", + "Europe\/Riga": "kelet-európai időzóna (Riga)", + "Europe\/Rome": "közép-európai időzóna (Róma)", + "Europe\/Samara": "Szamarai idő (Szamara)", + "Europe\/San_Marino": "közép-európai időzóna (San Marino)", + "Europe\/Sarajevo": "közép-európai időzóna (Szarajevó)", + "Europe\/Saratov": "moszkvai idő (Szaratov)", + "Europe\/Simferopol": "moszkvai idő (Szimferopol)", + "Europe\/Skopje": "közép-európai időzóna (Skopje)", + "Europe\/Sofia": "kelet-európai időzóna (Szófia)", + "Europe\/Stockholm": "közép-európai időzóna (Stockholm)", + "Europe\/Tallinn": "kelet-európai időzóna (Tallin)", + "Europe\/Tirane": "közép-európai időzóna (Tirana)", + "Europe\/Ulyanovsk": "moszkvai idő (Uljanovszk)", + "Europe\/Uzhgorod": "kelet-európai időzóna (Ungvár)", + "Europe\/Vaduz": "közép-európai időzóna (Vaduz)", + "Europe\/Vatican": "közép-európai időzóna (Vatikán)", + "Europe\/Vienna": "közép-európai időzóna (Bécs)", + "Europe\/Vilnius": "kelet-európai időzóna (Vilnius)", + "Europe\/Volgograd": "volgográdi idő (Volgográd)", + "Europe\/Warsaw": "közép-európai időzóna (Varsó)", + "Europe\/Zagreb": "közép-európai időzóna (Zágráb)", + "Europe\/Zaporozhye": "kelet-európai időzóna (Zaporozsje)", + "Europe\/Zurich": "közép-európai időzóna (Zürich)", + "Indian\/Antananarivo": "kelet-afrikai téli idő (Antananarivo)", + "Indian\/Chagos": "indiai-óceáni idő (Chagos)", + "Indian\/Christmas": "karácsony-szigeti téli idő (Karácsony-sziget)", + "Indian\/Cocos": "kókusz-szigeteki téli idő (Kókusz-sziget)", + "Indian\/Comoro": "kelet-afrikai téli idő (Komoró)", + "Indian\/Kerguelen": "francia déli és antarktiszi idő (Kerguelen)", + "Indian\/Mahe": "seychelle-szigeteki idő (Mahe)", + "Indian\/Maldives": "maldív-szigeteki idő (Maldív-szigetek)", + "Indian\/Mauritius": "mauritiusi időzóna (Mauritius)", + "Indian\/Mayotte": "kelet-afrikai téli idő (Mayotte)", + "Indian\/Reunion": "réunioni idő (Réunion)", + "MST7MDT": "hegyvidéki idő", + "PST8PDT": "csendes-óceáni idő", + "Pacific\/Apia": "apiai idő (Apia)", + "Pacific\/Auckland": "új-zélandi idő (Auckland)", + "Pacific\/Bougainville": "pápua új-guineai idő (Bougainville)", + "Pacific\/Chatham": "chathami idő (Chatham-szigetek)", + "Pacific\/Easter": "húsvét-szigeti időzóna (Húsvét-szigetek)", + "Pacific\/Efate": "vanuatui idő (Efate)", + "Pacific\/Enderbury": "phoenix-szigeteki téli idő (Enderbury)", + "Pacific\/Fakaofo": "tokelaui idő (Fakaofo)", + "Pacific\/Fiji": "fidzsi idő (Fidzsi)", + "Pacific\/Funafuti": "tuvalui idő (Funafuti)", + "Pacific\/Galapagos": "galápagosi téli idő (Galapagos-szigetek)", + "Pacific\/Gambier": "gambieri idő (Gambier-szigetek)", + "Pacific\/Guadalcanal": "salamon-szigeteki idő (Guadalcanal)", + "Pacific\/Guam": "chamorrói téli idő (Guam)", + "Pacific\/Honolulu": "hawaii-aleuti időzóna (Honolulu)", + "Pacific\/Johnston": "hawaii-aleuti időzóna (Johnston)", + "Pacific\/Kiritimati": "sor-szigeteki idő (Kiritimati-sziget)", + "Pacific\/Kosrae": "kosraei idő (Kosrae-szigetek)", + "Pacific\/Kwajalein": "marshall-szigeteki idő (Kwajalein-zátony)", + "Pacific\/Majuro": "marshall-szigeteki idő (Majuro-zátony)", + "Pacific\/Marquesas": "marquises-szigeteki idő (Marquesas-szigetek)", + "Pacific\/Midway": "szamoai idő (Midway-szigetek)", + "Pacific\/Nauru": "naurui idő (Nauru)", + "Pacific\/Niue": "niuei idő (Niue)", + "Pacific\/Norfolk": "norfolk-szigeteki idő (Norfolk)", + "Pacific\/Noumea": "új-kaledóniai idő (Noumea)", + "Pacific\/Pago_Pago": "szamoai idő (Pago Pago)", + "Pacific\/Palau": "palaui idő (Palau)", + "Pacific\/Pitcairn": "pitcairn-szigeteki idő (Pitcairn-szigetek)", + "Pacific\/Ponape": "ponape-szigeti idő (Ponape-szigetek)", + "Pacific\/Port_Moresby": "pápua új-guineai idő (Port Moresby)", + "Pacific\/Rarotonga": "cook-szigeteki idő (Rarotonga)", + "Pacific\/Saipan": "chamorrói téli idő (Saipan)", + "Pacific\/Tahiti": "tahiti idő (Tahiti)", + "Pacific\/Tarawa": "gilbert-szigeteki idő (Tarawa)", + "Pacific\/Tongatapu": "tongai idő (Tongatapu)", + "Pacific\/Truk": "truki idő (Truk)", + "Pacific\/Wake": "wake-szigeti idő (Wake-sziget)", + "Pacific\/Wallis": "Wallis és Futuna-i idő (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/hy.json b/src/Symfony/Component/Intl/Resources/data/timezones/hy.json new file mode 100644 index 0000000000000..d68ff73222efa --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/hy.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Գրինվիչի ժամանակ (Աբիջան)", + "Africa\/Accra": "Գրինվիչի ժամանակ (Աքրա)", + "Africa\/Addis_Ababa": "Արևելյան Աֆրիկայի ժամանակ (Ադիս Աբեբա)", + "Africa\/Algiers": "Կենտրոնական Եվրոպայի ժամանակ (Ալժիր)", + "Africa\/Asmera": "Արևելյան Աֆրիկայի ժամանակ (Ասմերա)", + "Africa\/Bamako": "Գրինվիչի ժամանակ (Բամակո)", + "Africa\/Bangui": "Արևմտյան Աֆրիկայի ժամանակ (Բանգի)", + "Africa\/Banjul": "Գրինվիչի ժամանակ (Բանժուլ)", + "Africa\/Bissau": "Գրինվիչի ժամանակ (Բիսաու)", + "Africa\/Blantyre": "Կենտրոնական Աֆրիկայի ժամանակ (Բլանթայր)", + "Africa\/Brazzaville": "Արևմտյան Աֆրիկայի ժամանակ (Բրազավիլ)", + "Africa\/Bujumbura": "Կենտրոնական Աֆրիկայի ժամանակ (Բուժումբուրա)", + "Africa\/Cairo": "Արևելյան Եվրոպայի ժամանակ (Կահիրե)", + "Africa\/Casablanca": "Արևմտյան Եվրոպայի ժամանակ (Կասաբլանկա)", + "Africa\/Ceuta": "Կենտրոնական Եվրոպայի ժամանակ (Սեուտա)", + "Africa\/Conakry": "Գրինվիչի ժամանակ (Կոնակրի)", + "Africa\/Dakar": "Գրինվիչի ժամանակ (Դաքար)", + "Africa\/Dar_es_Salaam": "Արևելյան Աֆրիկայի ժամանակ (Դար-Էս-Սալամ)", + "Africa\/Djibouti": "Արևելյան Աֆրիկայի ժամանակ (Ջիբութի)", + "Africa\/Douala": "Արևմտյան Աֆրիկայի ժամանակ (Դուալա)", + "Africa\/El_Aaiun": "Արևմտյան Եվրոպայի ժամանակ (Էլ Այուն)", + "Africa\/Freetown": "Գրինվիչի ժամանակ (Ֆրիթաուն)", + "Africa\/Gaborone": "Կենտրոնական Աֆրիկայի ժամանակ (Գաբորոնե)", + "Africa\/Harare": "Կենտրոնական Աֆրիկայի ժամանակ (Հարարե)", + "Africa\/Johannesburg": "Հարավային Աֆրիկայի ժամանակ (Յոհանեսբուրգ)", + "Africa\/Juba": "Արևելյան Աֆրիկայի ժամանակ (Ջուբա)", + "Africa\/Kampala": "Արևելյան Աֆրիկայի ժամանակ (Կամպալա)", + "Africa\/Khartoum": "Կենտրոնական Աֆրիկայի ժամանակ (Խարթում)", + "Africa\/Kigali": "Կենտրոնական Աֆրիկայի ժամանակ (Կիգալի)", + "Africa\/Kinshasa": "Արևմտյան Աֆրիկայի ժամանակ (Կինշասա)", + "Africa\/Lagos": "Արևմտյան Աֆրիկայի ժամանակ (Լագոս)", + "Africa\/Libreville": "Արևմտյան Աֆրիկայի ժամանակ (Լիբրևիլ)", + "Africa\/Lome": "Գրինվիչի ժամանակ (Լոմե)", + "Africa\/Luanda": "Արևմտյան Աֆրիկայի ժամանակ (Լուանդա)", + "Africa\/Lubumbashi": "Կենտրոնական Աֆրիկայի ժամանակ (Լուբումբաշի)", + "Africa\/Lusaka": "Կենտրոնական Աֆրիկայի ժամանակ (Լուսակա)", + "Africa\/Malabo": "Արևմտյան Աֆրիկայի ժամանակ (Մալաբո)", + "Africa\/Maputo": "Կենտրոնական Աֆրիկայի ժամանակ (Մապուտու)", + "Africa\/Maseru": "Հարավային Աֆրիկայի ժամանակ (Մասերու)", + "Africa\/Mbabane": "Հարավային Աֆրիկայի ժամանակ (Մբաբանե)", + "Africa\/Mogadishu": "Արևելյան Աֆրիկայի ժամանակ (Մոգադիշո)", + "Africa\/Monrovia": "Գրինվիչի ժամանակ (Մոնրովիա)", + "Africa\/Nairobi": "Արևելյան Աֆրիկայի ժամանակ (Նայրոբի)", + "Africa\/Ndjamena": "Արևմտյան Աֆրիկայի ժամանակ (Նջամենա)", + "Africa\/Niamey": "Արևմտյան Աֆրիկայի ժամանակ (Նիամեյ)", + "Africa\/Nouakchott": "Գրինվիչի ժամանակ (Նուակշոտ)", + "Africa\/Ouagadougou": "Գրինվիչի ժամանակ (Ուագադուգու)", + "Africa\/Porto-Novo": "Արևմտյան Աֆրիկայի ժամանակ (Պորտո Նովո)", + "Africa\/Sao_Tome": "Գրինվիչի ժամանակ (Սան Տոմե)", + "Africa\/Tripoli": "Արևելյան Եվրոպայի ժամանակ (Տրիպոլի)", + "Africa\/Tunis": "Կենտրոնական Եվրոպայի ժամանակ (Թունիս)", + "Africa\/Windhoek": "Կենտրոնական Աֆրիկայի ժամանակ (Վինդհուկ)", + "America\/Adak": "Հավայան-ալեության ժամանակ (Ադակ կղզի)", + "America\/Anchorage": "Ալյասկայի ժամանակ (Անքորիջ)", + "America\/Anguilla": "Ատլանտյան ժամանակ (Անգուիլա)", + "America\/Antigua": "Ատլանտյան ժամանակ (Անտիգուա)", + "America\/Araguaina": "Բրազիլիայի ժամանակ (Արագուաինա)", + "America\/Argentina\/La_Rioja": "Արգենտինայի ժամանակ (Լա Ռիոխա)", + "America\/Argentina\/Rio_Gallegos": "Արգենտինայի ժամանակ (Ռիո Գալյեգոս)", + "America\/Argentina\/Salta": "Արգենտինայի ժամանակ (Սալտա)", + "America\/Argentina\/San_Juan": "Արգենտինայի ժամանակ (Սան Խուան)", + "America\/Argentina\/San_Luis": "Արևմտյան Արգենտինայի ժամանակ (Սան Լուիս)", + "America\/Argentina\/Tucuman": "Արգենտինայի ժամանակ (Տուկուման)", + "America\/Argentina\/Ushuaia": "Արգենտինայի ժամանակ (Ուշուայա)", + "America\/Aruba": "Ատլանտյան ժամանակ (Արուբա)", + "America\/Asuncion": "Պարագվայի ժամանակ (Ասունսյոն)", + "America\/Bahia": "Բրազիլիայի ժամանակ (Բաիյա)", + "America\/Bahia_Banderas": "Կենտրոնական Ամերիկայի ժամանակ (Բաիյա Բանդերաս)", + "America\/Barbados": "Ատլանտյան ժամանակ (Բարբադոս)", + "America\/Belem": "Բրազիլիայի ժամանակ (Բելեմ)", + "America\/Belize": "Կենտրոնական Ամերիկայի ժամանակ (Բելիզ)", + "America\/Blanc-Sablon": "Ատլանտյան ժամանակ (Բլանկ-Սաբլոն)", + "America\/Boa_Vista": "Ամազոնյան ժամանակ (Բոա Վիստա)", + "America\/Bogota": "Կոլումբիայի ժամանակ (Բոգոտա)", + "America\/Boise": "Լեռնային ժամանակ (ԱՄՆ) (Բոյսե)", + "America\/Buenos_Aires": "Արգենտինայի ժամանակ (Բուենոս Այրես)", + "America\/Cambridge_Bay": "Լեռնային ժամանակ (ԱՄՆ) (Քեմբրիջ Բեյ)", + "America\/Campo_Grande": "Ամազոնյան ժամանակ (Կամպու Գրանդի)", + "America\/Cancun": "Արևելյան Ամերիկայի ժամանակ (Կանկուն)", + "America\/Caracas": "Վենեսուելայի ժամանակ (Կարակաս)", + "America\/Catamarca": "Արգենտինայի ժամանակ (Կատամարկա)", + "America\/Cayenne": "Ֆրանսիական Գվիանայի ժամանակ (Կայեն)", + "America\/Cayman": "Արևելյան Ամերիկայի ժամանակ (Կայման կղզիներ)", + "America\/Chicago": "Կենտրոնական Ամերիկայի ժամանակ (Չիկագո)", + "America\/Chihuahua": "Մեքսիկայի խաղաղօվկիանոսյան ժամանակ (Չիուաուա)", + "America\/Coral_Harbour": "Արևելյան Ամերիկայի ժամանակ (Ատիկոկան)", + "America\/Cordoba": "Արգենտինայի ժամանակ (Կորդովա)", + "America\/Costa_Rica": "Կենտրոնական Ամերիկայի ժամանակ (Կոստա Ռիկա)", + "America\/Creston": "Լեռնային ժամանակ (ԱՄՆ) (Քրեսթոն)", + "America\/Cuiaba": "Ամազոնյան ժամանակ (Կույաբա)", + "America\/Curacao": "Ատլանտյան ժամանակ (Կյուրասաո)", + "America\/Danmarkshavn": "Գրինվիչի ժամանակ (Դենմարքսհավն)", + "America\/Dawson": "Խաղաղօվկիանոսյան ժամանակ (Դոուսոն)", + "America\/Dawson_Creek": "Լեռնային ժամանակ (ԱՄՆ) (Դոուսոն Քրիք)", + "America\/Denver": "Լեռնային ժամանակ (ԱՄՆ) (Դենվեր)", + "America\/Detroit": "Արևելյան Ամերիկայի ժամանակ (Դետրոյթ)", + "America\/Dominica": "Ատլանտյան ժամանակ (Դոմինիկա)", + "America\/Edmonton": "Լեռնային ժամանակ (ԱՄՆ) (Էդմոնտոն)", + "America\/El_Salvador": "Կենտրոնական Ամերիկայի ժամանակ (Սալվադոր)", + "America\/Fort_Nelson": "Լեռնային ժամանակ (ԱՄՆ) (Ֆորտ Նելսոն)", + "America\/Fortaleza": "Բրազիլիայի ժամանակ (Ֆորտալեզա)", + "America\/Glace_Bay": "Ատլանտյան ժամանակ (Գլեյս Բեյ)", + "America\/Godthab": "Արևմտյան Գրենլանդիայի ժամանակ (Նուուկ)", + "America\/Goose_Bay": "Ատլանտյան ժամանակ (Գուս Բեյ)", + "America\/Grand_Turk": "Արևելյան Ամերիկայի ժամանակ (Գրանդ Տյորք)", + "America\/Grenada": "Ատլանտյան ժամանակ (Գրենադա)", + "America\/Guadeloupe": "Ատլանտյան ժամանակ (Գվադելուպա)", + "America\/Guatemala": "Կենտրոնական Ամերիկայի ժամանակ (Գվատեմալա)", + "America\/Guayaquil": "Էկվադորի ժամանակ (Գուայակիլ)", + "America\/Guyana": "Գայանայի ժամանակ (Գայանա)", + "America\/Halifax": "Ատլանտյան ժամանակ (Հալիֆաքս)", + "America\/Havana": "Կուբայի ժամանակ (Հավանա)", + "America\/Hermosillo": "Մեքսիկայի խաղաղօվկիանոսյան ժամանակ (Էրմոսիլյո)", + "America\/Indiana\/Knox": "Կենտրոնական Ամերիկայի ժամանակ (Նոքս, Ինդիանա)", + "America\/Indiana\/Marengo": "Արևելյան Ամերիկայի ժամանակ (Մարենգո, Ինդիանա)", + "America\/Indiana\/Petersburg": "Արևելյան Ամերիկայի ժամանակ (Պետերսբուրգ, Ինդիանա)", + "America\/Indiana\/Tell_City": "Կենտրոնական Ամերիկայի ժամանակ (Թել Սիթի, Ինդիանա)", + "America\/Indiana\/Vevay": "Արևելյան Ամերիկայի ժամանակ (Վիվեյ, Ինդիանա)", + "America\/Indiana\/Vincennes": "Արևելյան Ամերիկայի ժամանակ (Վինսենս, Ինդիանա)", + "America\/Indiana\/Winamac": "Արևելյան Ամերիկայի ժամանակ (Վինամակ, Ինդիանա)", + "America\/Indianapolis": "Արևելյան Ամերիկայի ժամանակ (Ինդիանապոլիս)", + "America\/Inuvik": "Լեռնային ժամանակ (ԱՄՆ) (Ինուվիկ)", + "America\/Iqaluit": "Արևելյան Ամերիկայի ժամանակ (Իկալուիտ)", + "America\/Jamaica": "Արևելյան Ամերիկայի ժամանակ (Ճամայկա)", + "America\/Jujuy": "Արգենտինայի ժամանակ (Ժուժույ)", + "America\/Juneau": "Ալյասկայի ժամանակ (Ջունո)", + "America\/Kentucky\/Monticello": "Արևելյան Ամերիկայի ժամանակ (Մոնտիսելո, Կենտուկի)", + "America\/Kralendijk": "Ատլանտյան ժամանակ (Կրալենդեյկ)", + "America\/La_Paz": "Բոլիվիայի ժամանակ (Լա Պաս)", + "America\/Lima": "Պերուի ժամանակ (Լիմա)", + "America\/Los_Angeles": "Խաղաղօվկիանոսյան ժամանակ (Լոս Անջելես)", + "America\/Louisville": "Արևելյան Ամերիկայի ժամանակ (Լուիսվիլ)", + "America\/Lower_Princes": "Ատլանտյան ժամանակ (Լոուեր Պրինսես Քվորթեր)", + "America\/Maceio": "Բրազիլիայի ժամանակ (Մասեյո)", + "America\/Managua": "Կենտրոնական Ամերիկայի ժամանակ (Մանագուա)", + "America\/Manaus": "Ամազոնյան ժամանակ (Մանաուս)", + "America\/Marigot": "Ատլանտյան ժամանակ (Մարիգո)", + "America\/Martinique": "Ատլանտյան ժամանակ (Մարտինիկա)", + "America\/Matamoros": "Կենտրոնական Ամերիկայի ժամանակ (Մատամորոս)", + "America\/Mazatlan": "Մեքսիկայի խաղաղօվկիանոսյան ժամանակ (Մազաթլան)", + "America\/Mendoza": "Արգենտինայի ժամանակ (Մենդոսա)", + "America\/Menominee": "Կենտրոնական Ամերիկայի ժամանակ (Մենոմինի)", + "America\/Merida": "Կենտրոնական Ամերիկայի ժամանակ (Մերիդա)", + "America\/Metlakatla": "Ալյասկայի ժամանակ (Մետլակատլա)", + "America\/Mexico_City": "Կենտրոնական Ամերիկայի ժամանակ (Մեխիկո)", + "America\/Miquelon": "Սեն Պիեռ և Միքելոնի ժամանակ (Միքելոն)", + "America\/Moncton": "Ատլանտյան ժամանակ (Մոնկտոն)", + "America\/Monterrey": "Կենտրոնական Ամերիկայի ժամանակ (Մոնտեռեյ)", + "America\/Montevideo": "Ուրուգվայի ժամանակ (Մոնտեվիդեո)", + "America\/Montserrat": "Ատլանտյան ժամանակ (Մոնսեռատ)", + "America\/Nassau": "Արևելյան Ամերիկայի ժամանակ (Նասաու)", + "America\/New_York": "Արևելյան Ամերիկայի ժամանակ (Նյու Յորք)", + "America\/Nipigon": "Արևելյան Ամերիկայի ժամանակ (Նիպիգոն)", + "America\/Nome": "Ալյասկայի ժամանակ (Նոմ)", + "America\/Noronha": "Ֆերնանդու դի Նորոնյայի ժամանակ (Նորոնյա)", + "America\/North_Dakota\/Beulah": "Կենտրոնական Ամերիկայի ժամանակ (Բոյլա, Հյուսիսային Դակոտա)", + "America\/North_Dakota\/Center": "Կենտրոնական Ամերիկայի ժամանակ (Հյուսիսային Դակոտա - Կենտրոն)", + "America\/North_Dakota\/New_Salem": "Կենտրոնական Ամերիկայի ժամանակ (Նյու Սալեմ, Հյուսիսային Դակոտա)", + "America\/Ojinaga": "Լեռնային ժամանակ (ԱՄՆ) (Օխինագա)", + "America\/Panama": "Արևելյան Ամերիկայի ժամանակ (Պանամա)", + "America\/Pangnirtung": "Արևելյան Ամերիկայի ժամանակ (Պանգնիրտանգ)", + "America\/Paramaribo": "Սուրինամի ժամանակ (Պարամարիբո)", + "America\/Phoenix": "Լեռնային ժամանակ (ԱՄՆ) (Ֆինիքս)", + "America\/Port-au-Prince": "Արևելյան Ամերիկայի ժամանակ (Պորտ-օ-Պրենս)", + "America\/Port_of_Spain": "Ատլանտյան ժամանակ (Պորտ-օֆ-Սփեյն)", + "America\/Porto_Velho": "Ամազոնյան ժամանակ (Պորտու Վելյու)", + "America\/Puerto_Rico": "Ատլանտյան ժամանակ (Պուերտո Ռիկո)", + "America\/Punta_Arenas": "Չիլիի ժամանակ (Պունտա Արենաս)", + "America\/Rainy_River": "Կենտրոնական Ամերիկայի ժամանակ (Ռեյնի Ռիվեր)", + "America\/Rankin_Inlet": "Կենտրոնական Ամերիկայի ժամանակ (Ռանկին Ինլեթ)", + "America\/Recife": "Բրազիլիայի ժամանակ (Ռեսիֆի)", + "America\/Regina": "Կենտրոնական Ամերիկայի ժամանակ (Ռեջայնա)", + "America\/Resolute": "Կենտրոնական Ամերիկայի ժամանակ (Ռեզոլյուտ)", + "America\/Santa_Isabel": "Հյուսիսարևմտյան Մեքսիկայի ժամանակ (Սանտա Իզաբել)", + "America\/Santarem": "Բրազիլիայի ժամանակ (Սանտարեմ)", + "America\/Santiago": "Չիլիի ժամանակ (Սանտյագո)", + "America\/Santo_Domingo": "Ատլանտյան ժամանակ (Սանտո Դոմինգո)", + "America\/Sao_Paulo": "Բրազիլիայի ժամանակ (Սան Պաուլու)", + "America\/Scoresbysund": "Արևելյան Գրենլանդիայի ժամանակ (Սկորսբիսուն)", + "America\/Sitka": "Ալյասկայի ժամանակ (Սիտկա)", + "America\/St_Barthelemy": "Ատլանտյան ժամանակ (Սեն Բարտելմի)", + "America\/St_Johns": "Նյուֆաունդլենդի ժամանակ (Սենթ Ջոնս)", + "America\/St_Kitts": "Ատլանտյան ժամանակ (Սենթ Քիտս)", + "America\/St_Lucia": "Ատլանտյան ժամանակ (Սենթ Լյուսիա)", + "America\/St_Thomas": "Ատլանտյան ժամանակ (Սենթ Թոմաս)", + "America\/St_Vincent": "Ատլանտյան ժամանակ (Սենթ Վինսենթ)", + "America\/Swift_Current": "Կենտրոնական Ամերիկայի ժամանակ (Սվիֆթ Քարենթ)", + "America\/Tegucigalpa": "Կենտրոնական Ամերիկայի ժամանակ (Տեգուսիգալպա)", + "America\/Thule": "Ատլանտյան ժամանակ (Տուլե)", + "America\/Thunder_Bay": "Արևելյան Ամերիկայի ժամանակ (Թանդեր Բեյ)", + "America\/Tijuana": "Խաղաղօվկիանոսյան ժամանակ (Տիխուանա)", + "America\/Toronto": "Արևելյան Ամերիկայի ժամանակ (Տորոնտո)", + "America\/Tortola": "Ատլանտյան ժամանակ (Թորթոլա)", + "America\/Vancouver": "Խաղաղօվկիանոսյան ժամանակ (Վանկուվեր)", + "America\/Whitehorse": "Խաղաղօվկիանոսյան ժամանակ (Ուայթհորս)", + "America\/Winnipeg": "Կենտրոնական Ամերիկայի ժամանակ (Վինիպեգ)", + "America\/Yakutat": "Ալյասկայի ժամանակ (Յակուտատ)", + "America\/Yellowknife": "Լեռնային ժամանակ (ԱՄՆ) (Յելոունայֆ)", + "Antarctica\/Casey": "Արևմտյան Ավստրալիայի ժամանակ (Քեյսի)", + "Antarctica\/Davis": "Դեյվիսի ժամանակ (Դեյվիս)", + "Antarctica\/DumontDUrville": "Դյումոն դ’Յուրվիլի ժամանակ (Դյումոն դ’Յուրվիլ)", + "Antarctica\/Macquarie": "Մակկուորի կղզու ժամանակ (Մակկուորի կղզի)", + "Antarctica\/Mawson": "Մոուսոնի ժամանակ (Մոուսոն)", + "Antarctica\/McMurdo": "Նոր Զելանդիայի ժամանակ (Մակ-Մերդո)", + "Antarctica\/Palmer": "Չիլիի ժամանակ (Պալմեր)", + "Antarctica\/Rothera": "Ռոտերայի ժամանակ (Ռոտերա)", + "Antarctica\/Syowa": "Սյովայի ժամանակ (Սյովա)", + "Antarctica\/Troll": "Գրինվիչի ժամանակ (Տրոլլ)", + "Antarctica\/Vostok": "Վոստոկի ժամանակ (Վոստոկ)", + "Arctic\/Longyearbyen": "Կենտրոնական Եվրոպայի ժամանակ (Լոնգյիր)", + "Asia\/Aden": "Սաուդյան Արաբիայի ժամանակ (Ադեն)", + "Asia\/Almaty": "Արևելյան Ղազախստանի ժամանակ (Ալմաթի)", + "Asia\/Amman": "Արևելյան Եվրոպայի ժամանակ (Ամման)", + "Asia\/Aqtau": "Արևմտյան Ղազախստանի ժամանակ (Ակտաու)", + "Asia\/Aqtobe": "Արևմտյան Ղազախստանի ժամանակ (Ակտոբե)", + "Asia\/Ashgabat": "Թուրքմենստանի ժամանակ (Աշխաբադ)", + "Asia\/Atyrau": "Արևմտյան Ղազախստանի ժամանակ (Ատիրաու)", + "Asia\/Baghdad": "Սաուդյան Արաբիայի ժամանակ (Բաղդադ)", + "Asia\/Bahrain": "Սաուդյան Արաբիայի ժամանակ (Բահրեյն)", + "Asia\/Baku": "Ադրբեջանի ժամանակ (Բաքու)", + "Asia\/Bangkok": "Հնդկաչինական ժամանակ (Բանգկոկ)", + "Asia\/Beirut": "Արևելյան Եվրոպայի ժամանակ (Բեյրութ)", + "Asia\/Bishkek": "Ղրղզստանի ժամանակ (Բիշքեկ)", + "Asia\/Brunei": "Բրունեյի ժամանակ (Բրունեյ)", + "Asia\/Calcutta": "Հնդկաստանի ստանդարտ ժամանակ (Կալկուտա)", + "Asia\/Chita": "Յակուտսկի ժամանակ (Չիտա)", + "Asia\/Choibalsan": "Չոյբալսանի ժամանակ (Չոյբալսան)", + "Asia\/Colombo": "Հնդկաստանի ստանդարտ ժամանակ (Կոլոմբո)", + "Asia\/Damascus": "Արևելյան Եվրոպայի ժամանակ (Դամասկոս)", + "Asia\/Dhaka": "Բանգլադեշի ժամանակ (Դաքքա)", + "Asia\/Dili": "Արևելյան Թիմորի ժամանակ (Դիլի)", + "Asia\/Dubai": "Պարսից ծոցի ստանդարտ ժամանակ (Դուբայ)", + "Asia\/Dushanbe": "Տաջիկստանի ժամանակ (Դուշանբե)", + "Asia\/Famagusta": "Արևելյան Եվրոպայի ժամանակ (Ֆամագուստա)", + "Asia\/Gaza": "Արևելյան Եվրոպայի ժամանակ (Գազա)", + "Asia\/Hebron": "Արևելյան Եվրոպայի ժամանակ (Հեբրոն)", + "Asia\/Hong_Kong": "Հոնկոնգի ժամանակ (Հոնկոնգ)", + "Asia\/Hovd": "Հովդի ժամանակ (Հովդ)", + "Asia\/Irkutsk": "Իրկուտսկի ժամանակ (Իրկուտսկ)", + "Asia\/Jakarta": "Արևմտյան Ինդոնեզիայի ժամանակ (Ջակարտա)", + "Asia\/Jayapura": "Արևելյան Ինդոնեզիայի ժամանակ (Ջայպուրա)", + "Asia\/Jerusalem": "Իսրայելի ժամանակ (Երուսաղեմ)", + "Asia\/Kabul": "Աֆղանստանի ժամանակ (Քաբուլ)", + "Asia\/Karachi": "Պակիստանի ժամանակ (Կարաչի)", + "Asia\/Katmandu": "Նեպալի ժամանակ (Կատմանդու)", + "Asia\/Khandyga": "Յակուտսկի ժամանակ (Խանդիգա)", + "Asia\/Krasnoyarsk": "Կրասնոյարսկի ժամանակ (Կրասնոյարսկ)", + "Asia\/Kuala_Lumpur": "Մալայզիայի ժամանակ (Կուալա Լումպուր)", + "Asia\/Kuching": "Մալայզիայի ժամանակ (Կուչինգ)", + "Asia\/Kuwait": "Սաուդյան Արաբիայի ժամանակ (Քուվեյթ)", + "Asia\/Macau": "Չինաստանի ժամանակ (Մակաո)", + "Asia\/Magadan": "Մագադանի ժամանակ (Մագադան)", + "Asia\/Makassar": "Կենտրոնական Ինդոնեզիայի ժամանակ (Մակասար)", + "Asia\/Manila": "Ֆիլիպինների ժամանակ (Մանիլա)", + "Asia\/Muscat": "Պարսից ծոցի ստանդարտ ժամանակ (Մասկատ)", + "Asia\/Nicosia": "Արևելյան Եվրոպայի ժամանակ (Նիկոսիա)", + "Asia\/Novokuznetsk": "Կրասնոյարսկի ժամանակ (Նովոկուզնեցկ)", + "Asia\/Novosibirsk": "Նովոսիբիրսկի ժամանակ (Նովոսիբիրսկ)", + "Asia\/Omsk": "Օմսկի ժամանակ (Օմսկ)", + "Asia\/Oral": "Արևմտյան Ղազախստանի ժամանակ (Ուրալսկ)", + "Asia\/Phnom_Penh": "Հնդկաչինական ժամանակ (Պնոմպեն)", + "Asia\/Pontianak": "Արևմտյան Ինդոնեզիայի ժամանակ (Պոնտիանակ)", + "Asia\/Pyongyang": "Կորեայի ժամանակ (Փխենյան)", + "Asia\/Qatar": "Սաուդյան Արաբիայի ժամանակ (Կատար)", + "Asia\/Qostanay": "Արևելյան Ղազախստանի ժամանակ (Qostanay)", + "Asia\/Qyzylorda": "Արևմտյան Ղազախստանի ժամանակ (Կիզիլորդա)", + "Asia\/Rangoon": "Մյանմայի ժամանակ (Ռանգուն)", + "Asia\/Riyadh": "Սաուդյան Արաբիայի ժամանակ (Էր Ռիադ)", + "Asia\/Saigon": "Հնդկաչինական ժամանակ (Հոշիմին)", + "Asia\/Sakhalin": "Սախալինի ժամանակ (Սախալին)", + "Asia\/Samarkand": "Ուզբեկստանի ժամանակ (Սամարղանդ)", + "Asia\/Seoul": "Կորեայի ժամանակ (Սեուլ)", + "Asia\/Shanghai": "Չինաստանի ժամանակ (Շանհայ)", + "Asia\/Singapore": "Սինգապուրի ժամանակ (Սինգապուր)", + "Asia\/Srednekolymsk": "Մագադանի ժամանակ (Սրեդնեկոլիմսկ)", + "Asia\/Taipei": "Թայպեյի ժամանակ (Թայպեյ)", + "Asia\/Tashkent": "Ուզբեկստանի ժամանակ (Տաշքենդ)", + "Asia\/Tbilisi": "Վրաստանի ժամանակ (Թբիլիսի)", + "Asia\/Tehran": "Իրանի ժամանակ (Թեհրան)", + "Asia\/Thimphu": "Բութանի ժամանակ (Տհիմպհու)", + "Asia\/Tokyo": "Ճապոնիայի ժամանակ (Տոկիո)", + "Asia\/Ulaanbaatar": "Ուլան Բատորի ժամանակ (Ուլան Բատոր)", + "Asia\/Ust-Nera": "Վլադիվոստոկի ժամանակ (Ուստ-Ներա)", + "Asia\/Vientiane": "Հնդկաչինական ժամանակ (Վյենտյան)", + "Asia\/Vladivostok": "Վլադիվոստոկի ժամանակ (Վլադիվոստոկ)", + "Asia\/Yakutsk": "Յակուտսկի ժամանակ (Յակուտսկ)", + "Asia\/Yekaterinburg": "Եկատերինբուրգի ժամանակ (Եկատերինբուրգ)", + "Asia\/Yerevan": "Հայաստանի ժամանակ (Երևան)", + "Atlantic\/Azores": "Ազորյան կղզիների ժամանակ (Ազորյան կղզիներ)", + "Atlantic\/Bermuda": "Ատլանտյան ժամանակ (Բերմուդներ)", + "Atlantic\/Canary": "Արևմտյան Եվրոպայի ժամանակ (Կանարյան կղզիներ)", + "Atlantic\/Cape_Verde": "Կաբո Վերդեի ժամանակ (Կաբո Վերդե)", + "Atlantic\/Faeroe": "Արևմտյան Եվրոպայի ժամանակ (Ֆարերյան կղզիներ)", + "Atlantic\/Madeira": "Արևմտյան Եվրոպայի ժամանակ (Մադեյրա)", + "Atlantic\/Reykjavik": "Գրինվիչի ժամանակ (Ռեյկյավիկ)", + "Atlantic\/South_Georgia": "Հարավային Ջորջիայի ժամանակ (Հարավային Ջորջիա)", + "Atlantic\/St_Helena": "Գրինվիչի ժամանակ (Սուրբ Հեղինեի կղզի)", + "Atlantic\/Stanley": "Ֆոլքլենդյան կղզիների ժամանակ (Սթենլի)", + "Australia\/Adelaide": "Կենտրոնական Ավստրալիայի ժամանակ (Ադելաիդա)", + "Australia\/Brisbane": "Արևելյան Ավստրալիայի ժամանակ (Բրիսբեն)", + "Australia\/Broken_Hill": "Կենտրոնական Ավստրալիայի ժամանակ (Բրոքեն Հիլ)", + "Australia\/Currie": "Արևելյան Ավստրալիայի ժամանակ (Քերի)", + "Australia\/Darwin": "Կենտրոնական Ավստրալիայի ժամանակ (Դարվին)", + "Australia\/Eucla": "Կենտրոնական Ավստրալիայի արևմտյան ժամանակ (Յուկլա)", + "Australia\/Hobart": "Արևելյան Ավստրալիայի ժամանակ (Հոբարտ)", + "Australia\/Lindeman": "Արևելյան Ավստրալիայի ժամանակ (Լինդեման)", + "Australia\/Lord_Howe": "Լորդ Հաուի ժամանակ (Լորդ Հաու կղզի)", + "Australia\/Melbourne": "Արևելյան Ավստրալիայի ժամանակ (Մելբուրն)", + "Australia\/Perth": "Արևմտյան Ավստրալիայի ժամանակ (Պերթ)", + "Australia\/Sydney": "Արևելյան Ավստրալիայի ժամանակ (Սիդնեյ)", + "CST6CDT": "Կենտրոնական Ամերիկայի ժամանակ", + "EST5EDT": "Արևելյան Ամերիկայի ժամանակ", + "Etc\/GMT": "Գրինվիչի ժամանակ", + "Etc\/UTC": "Համաշխարհային կոորդինացված ժամանակ", + "Europe\/Amsterdam": "Կենտրոնական Եվրոպայի ժամանակ (Ամստերդամ)", + "Europe\/Andorra": "Կենտրոնական Եվրոպայի ժամանակ (Անդորրա)", + "Europe\/Astrakhan": "Մոսկվայի ժամանակ (Աստրախան)", + "Europe\/Athens": "Արևելյան Եվրոպայի ժամանակ (Աթենք)", + "Europe\/Belgrade": "Կենտրոնական Եվրոպայի ժամանակ (Բելգրադ)", + "Europe\/Berlin": "Կենտրոնական Եվրոպայի ժամանակ (Բեռլին)", + "Europe\/Bratislava": "Կենտրոնական Եվրոպայի ժամանակ (Բրատիսլավա)", + "Europe\/Brussels": "Կենտրոնական Եվրոպայի ժամանակ (Բրյուսել)", + "Europe\/Bucharest": "Արևելյան Եվրոպայի ժամանակ (Բուխարեստ)", + "Europe\/Budapest": "Կենտրոնական Եվրոպայի ժամանակ (Բուդապեշտ)", + "Europe\/Busingen": "Կենտրոնական Եվրոպայի ժամանակ (Բյուզինգեն)", + "Europe\/Chisinau": "Արևելյան Եվրոպայի ժամանակ (Քիշնև)", + "Europe\/Copenhagen": "Կենտրոնական Եվրոպայի ժամանակ (Կոպենհագեն)", + "Europe\/Dublin": "Գրինվիչի ժամանակ (Դուբլին)", + "Europe\/Gibraltar": "Կենտրոնական Եվրոպայի ժամանակ (Ջիբրալթար)", + "Europe\/Guernsey": "Գրինվիչի ժամանակ (Գերնսի)", + "Europe\/Helsinki": "Արևելյան Եվրոպայի ժամանակ (Հելսինկի)", + "Europe\/Isle_of_Man": "Գրինվիչի ժամանակ (Մեն կղզի)", + "Europe\/Jersey": "Գրինվիչի ժամանակ (Ջերսի)", + "Europe\/Kaliningrad": "Արևելյան Եվրոպայի ժամանակ (Կալինինգրադ)", + "Europe\/Kiev": "Արևելյան Եվրոպայի ժամանակ (Կիև)", + "Europe\/Lisbon": "Արևմտյան Եվրոպայի ժամանակ (Լիսաբոն)", + "Europe\/Ljubljana": "Կենտրոնական Եվրոպայի ժամանակ (Լյուբլյանա)", + "Europe\/London": "Գրինվիչի ժամանակ (Լոնդոն)", + "Europe\/Luxembourg": "Կենտրոնական Եվրոպայի ժամանակ (Լյուքսեմբուրգ)", + "Europe\/Madrid": "Կենտրոնական Եվրոպայի ժամանակ (Մադրիդ)", + "Europe\/Malta": "Կենտրոնական Եվրոպայի ժամանակ (Մալթա)", + "Europe\/Mariehamn": "Արևելյան Եվրոպայի ժամանակ (Մարիեհամն)", + "Europe\/Minsk": "Մոսկվայի ժամանակ (Մինսկ)", + "Europe\/Monaco": "Կենտրոնական Եվրոպայի ժամանակ (Մոնակո)", + "Europe\/Moscow": "Մոսկվայի ժամանակ (Մոսկվա)", + "Europe\/Oslo": "Կենտրոնական Եվրոպայի ժամանակ (Օսլո)", + "Europe\/Paris": "Կենտրոնական Եվրոպայի ժամանակ (Փարիզ)", + "Europe\/Podgorica": "Կենտրոնական Եվրոպայի ժամանակ (Պոդգորիցա)", + "Europe\/Prague": "Կենտրոնական Եվրոպայի ժամանակ (Պրահա)", + "Europe\/Riga": "Արևելյան Եվրոպայի ժամանակ (Ռիգա)", + "Europe\/Rome": "Կենտրոնական Եվրոպայի ժամանակ (Հռոմ)", + "Europe\/San_Marino": "Կենտրոնական Եվրոպայի ժամանակ (Սան Մարինո)", + "Europe\/Sarajevo": "Կենտրոնական Եվրոպայի ժամանակ (Սարաևո)", + "Europe\/Saratov": "Մոսկվայի ժամանակ (Սարատով)", + "Europe\/Simferopol": "Մոսկվայի ժամանակ (Սիմֆերոպոլ)", + "Europe\/Skopje": "Կենտրոնական Եվրոպայի ժամանակ (Սկոպյե)", + "Europe\/Sofia": "Արևելյան Եվրոպայի ժամանակ (Սոֆիա)", + "Europe\/Stockholm": "Կենտրոնական Եվրոպայի ժամանակ (Ստոկհոլմ)", + "Europe\/Tallinn": "Արևելյան Եվրոպայի ժամանակ (Տալլին)", + "Europe\/Tirane": "Կենտրոնական Եվրոպայի ժամանակ (Տիրանա)", + "Europe\/Ulyanovsk": "Մոսկվայի ժամանակ (Ուլյանովսկ)", + "Europe\/Uzhgorod": "Արևելյան Եվրոպայի ժամանակ (Ուժգորոդ)", + "Europe\/Vaduz": "Կենտրոնական Եվրոպայի ժամանակ (Վադուց)", + "Europe\/Vatican": "Կենտրոնական Եվրոպայի ժամանակ (Վատիկան)", + "Europe\/Vienna": "Կենտրոնական Եվրոպայի ժամանակ (Վիեննա)", + "Europe\/Vilnius": "Արևելյան Եվրոպայի ժամանակ (Վիլնյուս)", + "Europe\/Volgograd": "Վոլգոգրադի ժամանակ (Վոլգոգրադ)", + "Europe\/Warsaw": "Կենտրոնական Եվրոպայի ժամանակ (Վարշավա)", + "Europe\/Zagreb": "Կենտրոնական Եվրոպայի ժամանակ (Զագրեբ)", + "Europe\/Zaporozhye": "Արևելյան Եվրոպայի ժամանակ (Զապոռոժյե)", + "Europe\/Zurich": "Կենտրոնական Եվրոպայի ժամանակ (Ցյուրիխ)", + "Indian\/Antananarivo": "Արևելյան Աֆրիկայի ժամանակ (Անտանանարիվու)", + "Indian\/Chagos": "Հնդկական օվկիանոսի ժամանակ (Չագոս)", + "Indian\/Christmas": "Սուրբ Ծննդյան կղզու ժամանակ (Սուրբ Ծննդյան կղզի)", + "Indian\/Cocos": "Կոկոսյան կղզիների ժամանակ (Կոկոսյան կղզիներ)", + "Indian\/Comoro": "Արևելյան Աֆրիկայի ժամանակ (Կոմորյան կղզիներ)", + "Indian\/Kerguelen": "Ֆրանսիական հարավային և անտարկտիդյան ժամանակ (Կերգելեն)", + "Indian\/Mahe": "Սեյշելյան կղզիների ժամանակ (Մաէ)", + "Indian\/Maldives": "Մալդիվների ժամանակ (Մալդիվներ)", + "Indian\/Mauritius": "Մավրիկիոսի ժամանակ (Մավրիկիոս)", + "Indian\/Mayotte": "Արևելյան Աֆրիկայի ժամանակ (Մայոթ)", + "Indian\/Reunion": "Ռեյունիոնի ժամանակ (Ռեյունիոն)", + "MST7MDT": "Լեռնային ժամանակ (ԱՄՆ)", + "PST8PDT": "Խաղաղօվկիանոսյան ժամանակ", + "Pacific\/Apia": "Ապիայի ժամանակ (Ապիա)", + "Pacific\/Auckland": "Նոր Զելանդիայի ժամանակ (Օքլենդ)", + "Pacific\/Bougainville": "Պապուա Նոր Գվինեայի ժամանակ (Բուգենվիլ)", + "Pacific\/Chatham": "Չաթեմ կղզու ժամանակ (Չաթեմ կղզի)", + "Pacific\/Easter": "Զատկի կղզու ժամանակ (Զատկի կղզի)", + "Pacific\/Efate": "Վանուատույի ժամանակ (Էֆատե)", + "Pacific\/Enderbury": "Ֆինիքս կղզիների ժամանակ (Էնդերբերի կղզի)", + "Pacific\/Fakaofo": "Տոկելաույի ժամանակ (Ֆակաոֆո)", + "Pacific\/Fiji": "Ֆիջիի ժամանակ (Ֆիջի)", + "Pacific\/Funafuti": "Տուվալույի ժամանակ (Ֆունաֆուտի)", + "Pacific\/Galapagos": "Գալապագոսյան կղզիների ժամանակ (Գալապագոսյան կղզիներ)", + "Pacific\/Gambier": "Գամբյե կղզիների ժամանակ (Գամբյե կղզիներ)", + "Pacific\/Guadalcanal": "Սողոմոնի կղզիների ժամանակ (Գուադալկանալ)", + "Pacific\/Guam": "Չամոռոյի ժամանակ (Գուամ)", + "Pacific\/Honolulu": "Հավայան-ալեության ժամանակ (Հոնոլուլու)", + "Pacific\/Johnston": "Հավայան-ալեության ժամանակ (Ջոնսթոն)", + "Pacific\/Kiritimati": "Լայն կղզիների ժամանակ (Կիրիտիմատի)", + "Pacific\/Kosrae": "Կոսրաեյի ժամանակ (Կոսրաե)", + "Pacific\/Kwajalein": "Մարշալյան կղզիների ժամանակ (Քվաջալեյն)", + "Pacific\/Majuro": "Մարշալյան կղզիների ժամանակ (Մաջուրո)", + "Pacific\/Marquesas": "Մարկիզյան կղզիների ժամանակ (Մարկիզյան կղզիներ)", + "Pacific\/Midway": "Սամոայի ժամանակ (Միդուեյ կղզի)", + "Pacific\/Nauru": "Նաուրուի ժամանակ (Նաուրու)", + "Pacific\/Niue": "Նիուեյի ժամանակ (Նիուե)", + "Pacific\/Norfolk": "Նորֆոլկ կղզու ժամանակ (Նորֆոլկ)", + "Pacific\/Noumea": "Նոր Կալեդոնիայի ժամանակ (Նումեա)", + "Pacific\/Pago_Pago": "Սամոայի ժամանակ (Պագո Պագո)", + "Pacific\/Palau": "Պալաույի ժամանակ (Պալաու)", + "Pacific\/Pitcairn": "Պիտկեռնի ժամանակ (Պիտկեռն)", + "Pacific\/Ponape": "Պոնապե կղզու ժամանակ (Պոնպեի)", + "Pacific\/Port_Moresby": "Պապուա Նոր Գվինեայի ժամանակ (Պորտ Մորսբի)", + "Pacific\/Rarotonga": "Կուկի կղզիների ժամանակ (Ռարոտոնգա)", + "Pacific\/Saipan": "Չամոռոյի ժամանակ (Սայպան)", + "Pacific\/Tahiti": "Թաիթիի ժամանակ (Թաիթի)", + "Pacific\/Tarawa": "Ջիլբերթի կղզիների ժամանակ (Տարավա)", + "Pacific\/Tongatapu": "Տոնգայի ժամանակ (Տոնգատապու)", + "Pacific\/Truk": "Տրուկի ժամանակ (Չուուկ)", + "Pacific\/Wake": "Ուեյք կղզու ժամանակ (Ուեյք կղզի)", + "Pacific\/Wallis": "Ուոլիս և Ֆուտունայի ժամանակ (Ուոլիս)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ia.json b/src/Symfony/Component/Intl/Resources/data/timezones/ia.json new file mode 100644 index 0000000000000..e2da4d87d29f9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ia.json @@ -0,0 +1,228 @@ +{ + "Version": "2.1.48.36", + "Names": { + "Africa\/Abidjan": "hora medie de Greenwich (Abidjan)", + "Africa\/Accra": "hora medie de Greenwich (Accra)", + "Africa\/Algiers": "hora de Europa central (Algiers)", + "Africa\/Bamako": "hora medie de Greenwich (Bamako)", + "Africa\/Banjul": "hora medie de Greenwich (Banjul)", + "Africa\/Bissau": "hora medie de Greenwich (Bissau)", + "Africa\/Cairo": "hora de Europa oriental (Cairo)", + "Africa\/Casablanca": "hora de Europa occidental (Casablanca)", + "Africa\/Ceuta": "hora de Europa central (Ceuta)", + "Africa\/Conakry": "hora medie de Greenwich (Conakry)", + "Africa\/Dakar": "hora medie de Greenwich (Dakar)", + "Africa\/El_Aaiun": "hora de Europa occidental (El Aaiun)", + "Africa\/Freetown": "hora medie de Greenwich (Freetown)", + "Africa\/Lome": "hora medie de Greenwich (Lome)", + "Africa\/Monrovia": "hora medie de Greenwich (Monrovia)", + "Africa\/Nouakchott": "hora medie de Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "hora medie de Greenwich (Ouagadougou)", + "Africa\/Sao_Tome": "hora medie de Greenwich (Sao Tome)", + "Africa\/Tripoli": "hora de Europa oriental (Tripoli)", + "Africa\/Tunis": "hora de Europa central (Tunis)", + "America\/Adak": "hora de Hawaii-Aleutianas (Adak)", + "America\/Anchorage": "hora de Alaska (Anchorage)", + "America\/Anguilla": "hora atlantic (Anguilla)", + "America\/Antigua": "hora atlantic (Antigua)", + "America\/Aruba": "hora atlantic (Aruba)", + "America\/Bahia_Banderas": "hora central (Bahia de Banderas)", + "America\/Barbados": "hora atlantic (Barbados)", + "America\/Belize": "hora central (Belize)", + "America\/Blanc-Sablon": "hora atlantic (Blanc-Sablon)", + "America\/Boise": "hora del montanias (Boise)", + "America\/Cambridge_Bay": "hora del montanias (Cambridge Bay)", + "America\/Cancun": "hora del est (Cancun)", + "America\/Cayman": "hora del est (Caiman)", + "America\/Chicago": "hora central (Chicago)", + "America\/Chihuahua": "hora del Pacifico mexican (Chihuahua)", + "America\/Coral_Harbour": "hora del est (Atikokan)", + "America\/Costa_Rica": "hora central (Costa Rica)", + "America\/Creston": "hora del montanias (Creston)", + "America\/Curacao": "hora atlantic (Curaçao)", + "America\/Danmarkshavn": "hora medie de Greenwich (Danmarkshavn)", + "America\/Dawson": "hora pacific (Dawson)", + "America\/Dawson_Creek": "hora del montanias (Dawson Creek)", + "America\/Denver": "hora del montanias (Denver)", + "America\/Detroit": "hora del est (Detroit)", + "America\/Dominica": "hora atlantic (Dominica)", + "America\/Edmonton": "hora del montanias (Edmonton)", + "America\/El_Salvador": "hora central (El Salvador)", + "America\/Fort_Nelson": "hora del montanias (Fort Nelson)", + "America\/Glace_Bay": "hora atlantic (Glace Bay)", + "America\/Godthab": "hora de Groenlandia occidental (Nuuk)", + "America\/Goose_Bay": "hora atlantic (Goose Bay)", + "America\/Grand_Turk": "hora del est (Grand Turk)", + "America\/Grenada": "hora atlantic (Grenada)", + "America\/Guadeloupe": "hora atlantic (Guadeloupe)", + "America\/Guatemala": "hora central (Guatemala)", + "America\/Halifax": "hora atlantic (Halifax)", + "America\/Havana": "hora de Cuba (Havana)", + "America\/Hermosillo": "hora del Pacifico mexican (Hermosillo)", + "America\/Indiana\/Knox": "hora central (Knox, Indiana)", + "America\/Indiana\/Marengo": "hora del est (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "hora del est (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "hora central (Tell City, Indiana)", + "America\/Indiana\/Vevay": "hora del est (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "hora del est (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "hora del est (Winamac, Indiana)", + "America\/Indianapolis": "hora del est (Indianapolis)", + "America\/Inuvik": "hora del montanias (Inuvik)", + "America\/Iqaluit": "hora del est (Iqaluit)", + "America\/Jamaica": "hora del est (Jamaica)", + "America\/Juneau": "hora de Alaska (Juneau)", + "America\/Kentucky\/Monticello": "hora del est (Monticello, Kentucky)", + "America\/Kralendijk": "hora atlantic (Kralendijk)", + "America\/Los_Angeles": "hora pacific (Los Angeles)", + "America\/Louisville": "hora del est (Louisville)", + "America\/Lower_Princes": "hora atlantic (Lower Prince’s Quarter)", + "America\/Managua": "hora central (Managua)", + "America\/Marigot": "hora atlantic (Marigot)", + "America\/Martinique": "hora atlantic (Martinica)", + "America\/Matamoros": "hora central (Matamoros)", + "America\/Mazatlan": "hora del Pacifico mexican (Mazatlan)", + "America\/Menominee": "hora central (Menominee)", + "America\/Merida": "hora central (Merida)", + "America\/Metlakatla": "hora de Alaska (Metlakatla)", + "America\/Mexico_City": "hora central (Citate de Mexico)", + "America\/Miquelon": "hora de Saint-Pierre e Miquelon (Miquelon)", + "America\/Moncton": "hora atlantic (Moncton)", + "America\/Monterrey": "hora central (Monterrey)", + "America\/Montserrat": "hora atlantic (Montserrat)", + "America\/Nassau": "hora del est (Nassau)", + "America\/New_York": "hora del est (Nove York)", + "America\/Nipigon": "hora del est (Nipigon)", + "America\/Nome": "hora de Alaska (Nome)", + "America\/North_Dakota\/Beulah": "hora central (Beulah, Dakota del Nord)", + "America\/North_Dakota\/Center": "hora central (Center, Dakota del Nord)", + "America\/North_Dakota\/New_Salem": "hora central (New Salem, Dakota del Nord)", + "America\/Ojinaga": "hora del montanias (Ojinaga)", + "America\/Panama": "hora del est (Panama)", + "America\/Pangnirtung": "hora del est (Pangnirtung)", + "America\/Phoenix": "hora del montanias (Phoenix)", + "America\/Port-au-Prince": "hora del est (Port-au-Prince)", + "America\/Port_of_Spain": "hora atlantic (Port of Spain)", + "America\/Puerto_Rico": "hora atlantic (Porto Rico)", + "America\/Rainy_River": "hora central (Rainy River)", + "America\/Rankin_Inlet": "hora central (Rankin Inlet)", + "America\/Regina": "hora central (Regina)", + "America\/Resolute": "hora central (Resolute)", + "America\/Santa_Isabel": "hora del nordwest de Mexico (Santa Isabel)", + "America\/Santo_Domingo": "hora atlantic (Santo Domingo)", + "America\/Scoresbysund": "hora de Groenlandia oriental (Ittoqqortoormiit)", + "America\/Sitka": "hora de Alaska (Sitka)", + "America\/St_Barthelemy": "hora atlantic (Sancte Bartholomeo)", + "America\/St_Johns": "hora de Terranova (Sancte Johannes de Terranova)", + "America\/St_Kitts": "hora atlantic (Sancte Christophoro)", + "America\/St_Lucia": "hora atlantic (Sancte Lucia)", + "America\/St_Thomas": "hora atlantic (Sancte Thomas)", + "America\/St_Vincent": "hora atlantic (Sancte Vincente)", + "America\/Swift_Current": "hora central (Swift Current)", + "America\/Tegucigalpa": "hora central (Tegucigalpa)", + "America\/Thule": "hora atlantic (Thule)", + "America\/Thunder_Bay": "hora del est (Thunder Bay)", + "America\/Tijuana": "hora pacific (Tijuana)", + "America\/Toronto": "hora del est (Toronto)", + "America\/Tortola": "hora atlantic (Tortola)", + "America\/Vancouver": "hora pacific (Vancouver)", + "America\/Whitehorse": "hora pacific (Whitehorse)", + "America\/Winnipeg": "hora central (Winnipeg)", + "America\/Yakutat": "hora de Alaska (Yakutat)", + "America\/Yellowknife": "hora del montanias (Yellowknife)", + "Antarctica\/Troll": "hora medie de Greenwich (Troll)", + "Arctic\/Longyearbyen": "hora de Europa central (Longyearbyen)", + "Asia\/Amman": "hora de Europa oriental (Amman)", + "Asia\/Beirut": "hora de Europa oriental (Beirut)", + "Asia\/Chita": "hora de Yakutsk (Chita)", + "Asia\/Damascus": "hora de Europa oriental (Damascus)", + "Asia\/Famagusta": "hora de Europa oriental (Famagusta)", + "Asia\/Gaza": "hora de Europa oriental (Gaza)", + "Asia\/Hebron": "hora de Europa oriental (Hebron)", + "Asia\/Irkutsk": "hora de Irkutsk (Irkutsk)", + "Asia\/Khandyga": "hora de Yakutsk (Chandyga)", + "Asia\/Krasnoyarsk": "hora de Krasnoyarsk (Krasnoyarsk)", + "Asia\/Magadan": "hora de Magadan (Magadan)", + "Asia\/Nicosia": "hora de Europa oriental (Nicosia)", + "Asia\/Novokuznetsk": "hora de Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "hora de Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "hora de Omsk (Omsk)", + "Asia\/Sakhalin": "hora de Sachalin (Sachalin)", + "Asia\/Srednekolymsk": "hora de Magadan (Srednekolymsk)", + "Asia\/Ust-Nera": "hora de Vladivostok (Ust-Nera)", + "Asia\/Vladivostok": "hora de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "hora de Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "hora de Ekaterinburg (Ekaterinburg)", + "Atlantic\/Azores": "hora del Azores (Azores)", + "Atlantic\/Bermuda": "hora atlantic (Bermuda)", + "Atlantic\/Canary": "hora de Europa occidental (Canarias)", + "Atlantic\/Faeroe": "hora de Europa occidental (Feroe)", + "Atlantic\/Madeira": "hora de Europa occidental (Madeira)", + "Atlantic\/Reykjavik": "hora medie de Greenwich (Reykjavik)", + "Atlantic\/St_Helena": "hora medie de Greenwich (St. Helena)", + "CST6CDT": "hora central", + "EST5EDT": "hora del est", + "Etc\/GMT": "hora medie de Greenwich", + "Etc\/UTC": "Universal Tempore Coordinate", + "Europe\/Amsterdam": "hora de Europa central (Amsterdam)", + "Europe\/Andorra": "hora de Europa central (Andorra)", + "Europe\/Astrakhan": "hora de Moscova (Astrakhan)", + "Europe\/Athens": "hora de Europa oriental (Athenas)", + "Europe\/Belgrade": "hora de Europa central (Belgrado)", + "Europe\/Berlin": "hora de Europa central (Berlin)", + "Europe\/Bratislava": "hora de Europa central (Bratislava)", + "Europe\/Brussels": "hora de Europa central (Bruxelles)", + "Europe\/Bucharest": "hora de Europa oriental (Bucarest)", + "Europe\/Budapest": "hora de Europa central (Budapest)", + "Europe\/Busingen": "hora de Europa central (Büsingen)", + "Europe\/Chisinau": "hora de Europa oriental (Chisinau)", + "Europe\/Copenhagen": "hora de Europa central (Copenhagen)", + "Europe\/Dublin": "hora medie de Greenwich (Dublin)", + "Europe\/Gibraltar": "hora de Europa central (Gibraltar)", + "Europe\/Guernsey": "hora medie de Greenwich (Guernsey)", + "Europe\/Helsinki": "hora de Europa oriental (Helsinki)", + "Europe\/Isle_of_Man": "hora medie de Greenwich (Insula de Man)", + "Europe\/Jersey": "hora medie de Greenwich (Jersey)", + "Europe\/Kaliningrad": "hora de Europa oriental (Kaliningrad)", + "Europe\/Kiev": "hora de Europa oriental (Kiev)", + "Europe\/Lisbon": "hora de Europa occidental (Lisbona)", + "Europe\/Ljubljana": "hora de Europa central (Ljubljana)", + "Europe\/London": "hora medie de Greenwich (London)", + "Europe\/Luxembourg": "hora de Europa central (Luxemburg)", + "Europe\/Madrid": "hora de Europa central (Madrid)", + "Europe\/Malta": "hora de Europa central (Malta)", + "Europe\/Mariehamn": "hora de Europa oriental (Mariehamn)", + "Europe\/Minsk": "hora de Moscova (Minsk)", + "Europe\/Monaco": "hora de Europa central (Monaco)", + "Europe\/Moscow": "hora de Moscova (Moscova)", + "Europe\/Oslo": "hora de Europa central (Oslo)", + "Europe\/Paris": "hora de Europa central (Paris)", + "Europe\/Podgorica": "hora de Europa central (Podgorica)", + "Europe\/Prague": "hora de Europa central (Praga)", + "Europe\/Riga": "hora de Europa oriental (Riga)", + "Europe\/Rome": "hora de Europa central (Roma)", + "Europe\/San_Marino": "hora de Europa central (San Marino)", + "Europe\/Sarajevo": "hora de Europa central (Sarajevo)", + "Europe\/Saratov": "hora de Moscova (Saratov)", + "Europe\/Simferopol": "hora de Moscova (Simferopol)", + "Europe\/Skopje": "hora de Europa central (Skopje)", + "Europe\/Sofia": "hora de Europa oriental (Sofia)", + "Europe\/Stockholm": "hora de Europa central (Stockholm)", + "Europe\/Tallinn": "hora de Europa oriental (Tallinn)", + "Europe\/Tirane": "hora de Europa central (Tirana)", + "Europe\/Ulyanovsk": "hora de Moscova (Ulyanovsk)", + "Europe\/Uzhgorod": "hora de Europa oriental (Uzhgorod)", + "Europe\/Vaduz": "hora de Europa central (Vaduz)", + "Europe\/Vatican": "hora de Europa central (Vaticano)", + "Europe\/Vienna": "hora de Europa central (Vienna)", + "Europe\/Vilnius": "hora de Europa oriental (Vilnius)", + "Europe\/Volgograd": "hora de Volgograd (Volgograd)", + "Europe\/Warsaw": "hora de Europa central (Varsovia)", + "Europe\/Zagreb": "hora de Europa central (Zagreb)", + "Europe\/Zaporozhye": "hora de Europa oriental (Zaporozhye)", + "Europe\/Zurich": "hora de Europa central (Zurich)", + "MST7MDT": "hora del montanias", + "PST8PDT": "hora pacific", + "Pacific\/Honolulu": "hora de Hawaii-Aleutianas (Honolulu)", + "Pacific\/Johnston": "hora de Hawaii-Aleutianas (Johnston)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/id.json b/src/Symfony/Component/Intl/Resources/data/timezones/id.json new file mode 100644 index 0000000000000..348aa804df470 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/id.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "Waktu Afrika Timur (Addis Ababa)", + "Africa\/Algiers": "Waktu Eropa Tengah (Aljir)", + "Africa\/Asmera": "Waktu Afrika Timur (Asmara)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "Waktu Afrika Barat (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Waktu Afrika Tengah (Blantyre)", + "Africa\/Brazzaville": "Waktu Afrika Barat (Brazzaville)", + "Africa\/Bujumbura": "Waktu Afrika Tengah (Bujumbura)", + "Africa\/Cairo": "Waktu Eropa Timur (Kairo)", + "Africa\/Casablanca": "Waktu Eropa Barat (Casablanca)", + "Africa\/Ceuta": "Waktu Eropa Tengah (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "Waktu Afrika Timur (Dar es Salaam)", + "Africa\/Djibouti": "Waktu Afrika Timur (Djibouti)", + "Africa\/Douala": "Waktu Afrika Barat (Douala)", + "Africa\/El_Aaiun": "Waktu Eropa Barat (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Waktu Afrika Tengah (Gaborone)", + "Africa\/Harare": "Waktu Afrika Tengah (Harare)", + "Africa\/Johannesburg": "Waktu Standar Afrika Selatan (Johannesburg)", + "Africa\/Juba": "Waktu Afrika Timur (Juba)", + "Africa\/Kampala": "Waktu Afrika Timur (Kampala)", + "Africa\/Khartoum": "Waktu Afrika Tengah (Khartoum)", + "Africa\/Kigali": "Waktu Afrika Tengah (Kigali)", + "Africa\/Kinshasa": "Waktu Afrika Barat (Kinshasa)", + "Africa\/Lagos": "Waktu Afrika Barat (Lagos)", + "Africa\/Libreville": "Waktu Afrika Barat (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lome)", + "Africa\/Luanda": "Waktu Afrika Barat (Luanda)", + "Africa\/Lubumbashi": "Waktu Afrika Tengah (Lubumbashi)", + "Africa\/Lusaka": "Waktu Afrika Tengah (Lusaka)", + "Africa\/Malabo": "Waktu Afrika Barat (Malabo)", + "Africa\/Maputo": "Waktu Afrika Tengah (Maputo)", + "Africa\/Maseru": "Waktu Standar Afrika Selatan (Maseru)", + "Africa\/Mbabane": "Waktu Standar Afrika Selatan (Mbabane)", + "Africa\/Mogadishu": "Waktu Afrika Timur (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "Waktu Afrika Timur (Nairobi)", + "Africa\/Ndjamena": "Waktu Afrika Barat (Ndjamena)", + "Africa\/Niamey": "Waktu Afrika Barat (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "Waktu Afrika Barat (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tome)", + "Africa\/Tripoli": "Waktu Eropa Timur (Tripoli)", + "Africa\/Tunis": "Waktu Eropa Tengah (Tunis)", + "Africa\/Windhoek": "Waktu Afrika Tengah (Windhoek)", + "America\/Adak": "Waktu Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Waktu Alaska (Anchorage)", + "America\/Anguilla": "Waktu Atlantik (Anguila)", + "America\/Antigua": "Waktu Atlantik (Antigua)", + "America\/Araguaina": "Waktu Brasil (Araguaina)", + "America\/Argentina\/La_Rioja": "Waktu Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Waktu Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Waktu Argentina (Salta)", + "America\/Argentina\/San_Juan": "Waktu Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Waktu Argentina Bagian Barat (San Luis)", + "America\/Argentina\/Tucuman": "Waktu Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Waktu Argentina (Ushuaia)", + "America\/Aruba": "Waktu Atlantik (Aruba)", + "America\/Asuncion": "Waktu Paraguay (Asuncion)", + "America\/Bahia": "Waktu Brasil (Bahia)", + "America\/Bahia_Banderas": "Waktu Tengah (Bahia Banderas)", + "America\/Barbados": "Waktu Atlantik (Barbados)", + "America\/Belem": "Waktu Brasil (Belem)", + "America\/Belize": "Waktu Tengah (Belize)", + "America\/Blanc-Sablon": "Waktu Atlantik (Blanc-Sablon)", + "America\/Boa_Vista": "Waktu Amazon (Boa Vista)", + "America\/Bogota": "Waktu Kolombia (Bogota)", + "America\/Boise": "Waktu Pegunungan (Boise)", + "America\/Buenos_Aires": "Waktu Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Waktu Pegunungan (Cambridge Bay)", + "America\/Campo_Grande": "Waktu Amazon (Campo Grande)", + "America\/Cancun": "Waktu Timur (Cancun)", + "America\/Caracas": "Waktu Venezuela (Caracas)", + "America\/Catamarca": "Waktu Argentina (Catamarca)", + "America\/Cayenne": "Waktu Guyana Prancis (Cayenne)", + "America\/Cayman": "Waktu Timur (Cayman)", + "America\/Chicago": "Waktu Tengah (Chicago)", + "America\/Chihuahua": "Waktu Pasifik Meksiko (Chihuahua)", + "America\/Coral_Harbour": "Waktu Timur (Atikokan)", + "America\/Cordoba": "Waktu Argentina (Cordoba)", + "America\/Costa_Rica": "Waktu Tengah (Kosta Rika)", + "America\/Creston": "Waktu Pegunungan (Creston)", + "America\/Cuiaba": "Waktu Amazon (Cuiaba)", + "America\/Curacao": "Waktu Atlantik (Curacao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Waktu Pasifik (Dawson)", + "America\/Dawson_Creek": "Waktu Pegunungan (Dawson Creek)", + "America\/Denver": "Waktu Pegunungan (Denver)", + "America\/Detroit": "Waktu Timur (Detroit)", + "America\/Dominica": "Waktu Atlantik (Dominika)", + "America\/Edmonton": "Waktu Pegunungan (Edmonton)", + "America\/Eirunepe": "Waktu Acre (Eirunepe)", + "America\/El_Salvador": "Waktu Tengah (El Salvador)", + "America\/Fort_Nelson": "Waktu Pegunungan (Fort Nelson)", + "America\/Fortaleza": "Waktu Brasil (Fortaleza)", + "America\/Glace_Bay": "Waktu Atlantik (Glace Bay)", + "America\/Godthab": "Waktu Greenland Barat (Nuuk)", + "America\/Goose_Bay": "Waktu Atlantik (Goose Bay)", + "America\/Grand_Turk": "Waktu Timur (Grand Turk)", + "America\/Grenada": "Waktu Atlantik (Grenada)", + "America\/Guadeloupe": "Waktu Atlantik (Guadeloupe)", + "America\/Guatemala": "Waktu Tengah (Guatemala)", + "America\/Guayaquil": "Waktu Ekuador (Guayaquil)", + "America\/Guyana": "Waktu Guyana (Guyana)", + "America\/Halifax": "Waktu Atlantik (Halifax)", + "America\/Havana": "Waktu Kuba (Havana)", + "America\/Hermosillo": "Waktu Pasifik Meksiko (Hermosillo)", + "America\/Indiana\/Knox": "Waktu Tengah (Knox, Indiana)", + "America\/Indiana\/Marengo": "Waktu Timur (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Waktu Timur (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Waktu Tengah (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Waktu Timur (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Waktu Timur (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Waktu Timur (Winamac, Indiana)", + "America\/Indianapolis": "Waktu Timur (Indianapolis)", + "America\/Inuvik": "Waktu Pegunungan (Inuvik)", + "America\/Iqaluit": "Waktu Timur (Iqaluit)", + "America\/Jamaica": "Waktu Timur (Jamaica)", + "America\/Jujuy": "Waktu Argentina (Jujuy)", + "America\/Juneau": "Waktu Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Waktu Timur (Monticello, Kentucky)", + "America\/Kralendijk": "Waktu Atlantik (Kralendijk)", + "America\/La_Paz": "Waktu Bolivia (La Paz)", + "America\/Lima": "Waktu Peru (Lima)", + "America\/Los_Angeles": "Waktu Pasifik (Los Angeles)", + "America\/Louisville": "Waktu Timur (Louisville)", + "America\/Lower_Princes": "Waktu Atlantik (Lower Prince’s Quarter)", + "America\/Maceio": "Waktu Brasil (Maceio)", + "America\/Managua": "Waktu Tengah (Managua)", + "America\/Manaus": "Waktu Amazon (Manaus)", + "America\/Marigot": "Waktu Atlantik (Marigot)", + "America\/Martinique": "Waktu Atlantik (Martinik)", + "America\/Matamoros": "Waktu Tengah (Matamoros)", + "America\/Mazatlan": "Waktu Pasifik Meksiko (Mazatlan)", + "America\/Mendoza": "Waktu Argentina (Mendoza)", + "America\/Menominee": "Waktu Tengah (Menominee)", + "America\/Merida": "Waktu Tengah (Merida)", + "America\/Metlakatla": "Waktu Alaska (Metlakatla)", + "America\/Mexico_City": "Waktu Tengah (Mexico City)", + "America\/Miquelon": "Waktu Saint Pierre dan Miquelon (Miquelon)", + "America\/Moncton": "Waktu Atlantik (Moncton)", + "America\/Monterrey": "Waktu Tengah (Monterrey)", + "America\/Montevideo": "Waktu Uruguay (Montevideo)", + "America\/Montserrat": "Waktu Atlantik (Montserrat)", + "America\/Nassau": "Waktu Timur (Nassau)", + "America\/New_York": "Waktu Timur (New York)", + "America\/Nipigon": "Waktu Timur (Nipigon)", + "America\/Nome": "Waktu Alaska (Nome)", + "America\/Noronha": "Waktu Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Waktu Tengah (Beulah, Dakota Utara)", + "America\/North_Dakota\/Center": "Waktu Tengah (Center, Dakota Utara)", + "America\/North_Dakota\/New_Salem": "Waktu Tengah (New Salem, Dakota Utara)", + "America\/Ojinaga": "Waktu Pegunungan (Ojinaga)", + "America\/Panama": "Waktu Timur (Panama)", + "America\/Pangnirtung": "Waktu Timur (Pangnirtung)", + "America\/Paramaribo": "Waktu Suriname (Paramaribo)", + "America\/Phoenix": "Waktu Pegunungan (Phoenix)", + "America\/Port-au-Prince": "Waktu Timur (Port-au-Prince)", + "America\/Port_of_Spain": "Waktu Atlantik (Port of Spain)", + "America\/Porto_Velho": "Waktu Amazon (Porto Velho)", + "America\/Puerto_Rico": "Waktu Atlantik (Puerto Rico)", + "America\/Punta_Arenas": "Waktu Cile (Punta Arenas)", + "America\/Rainy_River": "Waktu Tengah (Rainy River)", + "America\/Rankin_Inlet": "Waktu Tengah (Rankin Inlet)", + "America\/Recife": "Waktu Brasil (Recife)", + "America\/Regina": "Waktu Tengah (Regina)", + "America\/Resolute": "Waktu Tengah (Resolute)", + "America\/Rio_Branco": "Waktu Acre (Rio Branco)", + "America\/Santa_Isabel": "Waktu Meksiko Barat Laut (Santa Isabel)", + "America\/Santarem": "Waktu Brasil (Santarem)", + "America\/Santiago": "Waktu Cile (Santiago)", + "America\/Santo_Domingo": "Waktu Atlantik (Santo Domingo)", + "America\/Sao_Paulo": "Waktu Brasil (Sao Paulo)", + "America\/Scoresbysund": "Waktu Greenland Timur (Ittoqqortoormiit)", + "America\/Sitka": "Waktu Alaska (Sitka)", + "America\/St_Barthelemy": "Waktu Atlantik (St. Barthelemy)", + "America\/St_Johns": "Waktu Newfoundland (St. John’s)", + "America\/St_Kitts": "Waktu Atlantik (St. Kitts)", + "America\/St_Lucia": "Waktu Atlantik (St. Lucia)", + "America\/St_Thomas": "Waktu Atlantik (St. Thomas)", + "America\/St_Vincent": "Waktu Atlantik (St. Vincent)", + "America\/Swift_Current": "Waktu Tengah (Swift Current)", + "America\/Tegucigalpa": "Waktu Tengah (Tegucigalpa)", + "America\/Thule": "Waktu Atlantik (Thule)", + "America\/Thunder_Bay": "Waktu Timur (Thunder Bay)", + "America\/Tijuana": "Waktu Pasifik (Tijuana)", + "America\/Toronto": "Waktu Timur (Toronto)", + "America\/Tortola": "Waktu Atlantik (Tortola)", + "America\/Vancouver": "Waktu Pasifik (Vancouver)", + "America\/Whitehorse": "Waktu Pasifik (Whitehorse)", + "America\/Winnipeg": "Waktu Tengah (Winnipeg)", + "America\/Yakutat": "Waktu Alaska (Yakutat)", + "America\/Yellowknife": "Waktu Pegunungan (Yellowknife)", + "Antarctica\/Casey": "Waktu Barat Australia (Casey)", + "Antarctica\/Davis": "Waktu Davis (Davis)", + "Antarctica\/DumontDUrville": "Waktu Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Waktu Kepulauan Macquarie (Macquarie)", + "Antarctica\/Mawson": "Waktu Mawson (Mawson)", + "Antarctica\/McMurdo": "Waktu Selandia Baru (McMurdo)", + "Antarctica\/Palmer": "Waktu Cile (Palmer)", + "Antarctica\/Rothera": "Waktu Rothera (Rothera)", + "Antarctica\/Syowa": "Waktu Syowa (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Waktu Vostok (Vostok)", + "Arctic\/Longyearbyen": "Waktu Eropa Tengah (Longyearbyen)", + "Asia\/Aden": "Waktu Arab (Aden)", + "Asia\/Almaty": "Waktu Kazakhstan Timur (Almaty)", + "Asia\/Amman": "Waktu Eropa Timur (Amman)", + "Asia\/Anadyr": "Waktu Anadyr (Anadyr)", + "Asia\/Aqtau": "Waktu Kazakhstan Barat (Aktau)", + "Asia\/Aqtobe": "Waktu Kazakhstan Barat (Aktobe)", + "Asia\/Ashgabat": "Waktu Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Waktu Kazakhstan Barat (Atyrau)", + "Asia\/Baghdad": "Waktu Arab (Baghdad)", + "Asia\/Bahrain": "Waktu Arab (Bahrain)", + "Asia\/Baku": "Waktu Azerbaijan (Baku)", + "Asia\/Bangkok": "Waktu Indochina (Bangkok)", + "Asia\/Beirut": "Waktu Eropa Timur (Beirut)", + "Asia\/Bishkek": "Waktu Kirghizia (Bishkek)", + "Asia\/Brunei": "Waktu Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Waktu India (Kolkata)", + "Asia\/Chita": "Waktu Yakutsk (Chita)", + "Asia\/Choibalsan": "Waktu Choibalsan (Choibalsan)", + "Asia\/Colombo": "Waktu India (Kolombo)", + "Asia\/Damascus": "Waktu Eropa Timur (Damaskus)", + "Asia\/Dhaka": "Waktu Bangladesh (Dhaka)", + "Asia\/Dili": "Waktu Timor Leste (Dili)", + "Asia\/Dubai": "Waktu Standar Teluk (Dubai)", + "Asia\/Dushanbe": "Waktu Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Waktu Eropa Timur (Famagusta)", + "Asia\/Gaza": "Waktu Eropa Timur (Gaza)", + "Asia\/Hebron": "Waktu Eropa Timur (Hebron)", + "Asia\/Hong_Kong": "Waktu Hong Kong (Hong Kong)", + "Asia\/Hovd": "Waktu Hovd (Hovd)", + "Asia\/Irkutsk": "Waktu Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Waktu Indonesia Barat (Jakarta)", + "Asia\/Jayapura": "Waktu Indonesia Timur (Jayapura)", + "Asia\/Jerusalem": "Waktu Israel (Yerusalem)", + "Asia\/Kabul": "Waktu Afganistan (Kabul)", + "Asia\/Kamchatka": "Waktu Petropavlovsk-Kamchatsky (Kamchatka)", + "Asia\/Karachi": "Waktu Pakistan (Karachi)", + "Asia\/Katmandu": "Waktu Nepal (Kathmandu)", + "Asia\/Khandyga": "Waktu Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Waktu Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Waktu Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Waktu Malaysia (Kuching)", + "Asia\/Kuwait": "Waktu Arab (Kuwait)", + "Asia\/Macau": "Waktu Tiongkok (Makau)", + "Asia\/Magadan": "Waktu Magadan (Magadan)", + "Asia\/Makassar": "Waktu Indonesia Tengah (Makassar)", + "Asia\/Manila": "Waktu Filipina (Manila)", + "Asia\/Muscat": "Waktu Standar Teluk (Muskat)", + "Asia\/Nicosia": "Waktu Eropa Timur (Nikosia)", + "Asia\/Novokuznetsk": "Waktu Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Waktu Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Waktu Omsk (Omsk)", + "Asia\/Oral": "Waktu Kazakhstan Barat (Oral)", + "Asia\/Phnom_Penh": "Waktu Indochina (Phnom Penh)", + "Asia\/Pontianak": "Waktu Indonesia Barat (Pontianak)", + "Asia\/Pyongyang": "Waktu Korea (Pyongyang)", + "Asia\/Qatar": "Waktu Arab (Qatar)", + "Asia\/Qostanay": "Waktu Kazakhstan Timur (Qostanay)", + "Asia\/Qyzylorda": "Waktu Kazakhstan Barat (Qyzylorda)", + "Asia\/Rangoon": "Waktu Myanmar (Rangoon)", + "Asia\/Riyadh": "Waktu Arab (Riyadh)", + "Asia\/Saigon": "Waktu Indochina (Ho Chi Minh)", + "Asia\/Sakhalin": "Waktu Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Waktu Uzbekistan (Samarkand)", + "Asia\/Seoul": "Waktu Korea (Seoul)", + "Asia\/Shanghai": "Waktu Tiongkok (Shanghai)", + "Asia\/Singapore": "Waktu Standar Singapura (Singapura)", + "Asia\/Srednekolymsk": "Waktu Magadan (Srednekolymsk)", + "Asia\/Taipei": "Waktu Taipei (Taipei)", + "Asia\/Tashkent": "Waktu Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Waktu Georgia (Tbilisi)", + "Asia\/Tehran": "Waktu Iran (Teheran)", + "Asia\/Thimphu": "Waktu Bhutan (Thimphu)", + "Asia\/Tokyo": "Waktu Jepang (Tokyo)", + "Asia\/Ulaanbaatar": "Waktu Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Waktu Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Waktu Indochina (Vientiane)", + "Asia\/Vladivostok": "Waktu Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Waktu Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Waktu Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Waktu Armenia (Yerevan)", + "Atlantic\/Azores": "Waktu Azores (Azores)", + "Atlantic\/Bermuda": "Waktu Atlantik (Bermuda)", + "Atlantic\/Canary": "Waktu Eropa Barat (Canary)", + "Atlantic\/Cape_Verde": "Waktu Tanjung Verde (Tanjung Verde)", + "Atlantic\/Faeroe": "Waktu Eropa Barat (Faroe)", + "Atlantic\/Madeira": "Waktu Eropa Barat (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/South_Georgia": "Waktu Georgia Selatan (Georgia Selatan)", + "Atlantic\/St_Helena": "Greenwich Mean Time (St. Helena)", + "Atlantic\/Stanley": "Waktu Kepulauan Falkland (Stanley)", + "Australia\/Adelaide": "Waktu Tengah Australia (Adelaide)", + "Australia\/Brisbane": "Waktu Timur Australia (Brisbane)", + "Australia\/Broken_Hill": "Waktu Tengah Australia (Broken Hill)", + "Australia\/Currie": "Waktu Timur Australia (Currie)", + "Australia\/Darwin": "Waktu Tengah Australia (Darwin)", + "Australia\/Eucla": "Waktu Barat Tengah Australia (Eucla)", + "Australia\/Hobart": "Waktu Timur Australia (Hobart)", + "Australia\/Lindeman": "Waktu Timur Australia (Lindeman)", + "Australia\/Lord_Howe": "Waktu Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Waktu Timur Australia (Melbourne)", + "Australia\/Perth": "Waktu Barat Australia (Perth)", + "Australia\/Sydney": "Waktu Timur Australia (Sydney)", + "CST6CDT": "Waktu Tengah", + "EST5EDT": "Waktu Timur", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Waktu Universal Terkoordinasi", + "Europe\/Amsterdam": "Waktu Eropa Tengah (Amsterdam)", + "Europe\/Andorra": "Waktu Eropa Tengah (Andorra)", + "Europe\/Astrakhan": "Waktu Moskwa (Astrakhan)", + "Europe\/Athens": "Waktu Eropa Timur (Athena)", + "Europe\/Belgrade": "Waktu Eropa Tengah (Beograd)", + "Europe\/Berlin": "Waktu Eropa Tengah (Berlin)", + "Europe\/Bratislava": "Waktu Eropa Tengah (Bratislava)", + "Europe\/Brussels": "Waktu Eropa Tengah (Brussels)", + "Europe\/Bucharest": "Waktu Eropa Timur (Bucharest)", + "Europe\/Budapest": "Waktu Eropa Tengah (Budapest)", + "Europe\/Busingen": "Waktu Eropa Tengah (Busingen)", + "Europe\/Chisinau": "Waktu Eropa Timur (Kishinev)", + "Europe\/Copenhagen": "Waktu Eropa Tengah (Kopenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Waktu Eropa Tengah (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Waktu Eropa Timur (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Pulau Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Waktu Eropa Timur (Kaliningrad)", + "Europe\/Kiev": "Waktu Eropa Timur (Kiev)", + "Europe\/Lisbon": "Waktu Eropa Barat (Lisbon)", + "Europe\/Ljubljana": "Waktu Eropa Tengah (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (London)", + "Europe\/Luxembourg": "Waktu Eropa Tengah (Luksemburg)", + "Europe\/Madrid": "Waktu Eropa Tengah (Madrid)", + "Europe\/Malta": "Waktu Eropa Tengah (Malta)", + "Europe\/Mariehamn": "Waktu Eropa Timur (Mariehamn)", + "Europe\/Minsk": "Waktu Moskwa (Minsk)", + "Europe\/Monaco": "Waktu Eropa Tengah (Monako)", + "Europe\/Moscow": "Waktu Moskwa (Moskwa)", + "Europe\/Oslo": "Waktu Eropa Tengah (Oslo)", + "Europe\/Paris": "Waktu Eropa Tengah (Paris)", + "Europe\/Podgorica": "Waktu Eropa Tengah (Podgorica)", + "Europe\/Prague": "Waktu Eropa Tengah (Praha)", + "Europe\/Riga": "Waktu Eropa Timur (Riga)", + "Europe\/Rome": "Waktu Eropa Tengah (Roma)", + "Europe\/Samara": "Waktu Samara (Samara)", + "Europe\/San_Marino": "Waktu Eropa Tengah (San Marino)", + "Europe\/Sarajevo": "Waktu Eropa Tengah (Sarajevo)", + "Europe\/Saratov": "Waktu Moskwa (Saratov)", + "Europe\/Simferopol": "Waktu Moskwa (Simferopol)", + "Europe\/Skopje": "Waktu Eropa Tengah (Skopje)", + "Europe\/Sofia": "Waktu Eropa Timur (Sofia)", + "Europe\/Stockholm": "Waktu Eropa Tengah (Stockholm)", + "Europe\/Tallinn": "Waktu Eropa Timur (Tallinn)", + "Europe\/Tirane": "Waktu Eropa Tengah (Tirane)", + "Europe\/Ulyanovsk": "Waktu Moskwa (Ulyanovsk)", + "Europe\/Uzhgorod": "Waktu Eropa Timur (Uzhhorod)", + "Europe\/Vaduz": "Waktu Eropa Tengah (Vaduz)", + "Europe\/Vatican": "Waktu Eropa Tengah (Vatikan)", + "Europe\/Vienna": "Waktu Eropa Tengah (Wina)", + "Europe\/Vilnius": "Waktu Eropa Timur (Vilnius)", + "Europe\/Volgograd": "Waktu Volgograd (Volgograd)", + "Europe\/Warsaw": "Waktu Eropa Tengah (Warsawa)", + "Europe\/Zagreb": "Waktu Eropa Tengah (Zagreb)", + "Europe\/Zaporozhye": "Waktu Eropa Timur (Zaporizhia)", + "Europe\/Zurich": "Waktu Eropa Tengah (Zurich)", + "Indian\/Antananarivo": "Waktu Afrika Timur (Antananarivo)", + "Indian\/Chagos": "Waktu Samudera Hindia (Chagos)", + "Indian\/Christmas": "Waktu Pulau Natal (Christmas)", + "Indian\/Cocos": "Waktu Kepulauan Cocos (Cocos)", + "Indian\/Comoro": "Waktu Afrika Timur (Komoro)", + "Indian\/Kerguelen": "Waktu Wilayah Selatan dan Antarktika Prancis (Kerguelen)", + "Indian\/Mahe": "Waktu Seychelles (Mahe)", + "Indian\/Maldives": "Waktu Maladewa (Maladewa)", + "Indian\/Mauritius": "Waktu Mauritius (Mauritius)", + "Indian\/Mayotte": "Waktu Afrika Timur (Mayotte)", + "Indian\/Reunion": "Waktu Reunion (Reunion)", + "MST7MDT": "Waktu Pegunungan", + "PST8PDT": "Waktu Pasifik", + "Pacific\/Apia": "Waktu Apia (Apia)", + "Pacific\/Auckland": "Waktu Selandia Baru (Auckland)", + "Pacific\/Bougainville": "Waktu Papua Nugini (Bougainville)", + "Pacific\/Chatham": "Waktu Chatham (Chatham)", + "Pacific\/Easter": "Waktu Pulau Paskah (Easter)", + "Pacific\/Efate": "Waktu Vanuatu (Efate)", + "Pacific\/Enderbury": "Waktu Kepulauan Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Waktu Tokelau (Fakaofo)", + "Pacific\/Fiji": "Waktu Fiji (Fiji)", + "Pacific\/Funafuti": "Waktu Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Waktu Galapagos (Galapagos)", + "Pacific\/Gambier": "Waktu Gambier (Gambier)", + "Pacific\/Guadalcanal": "Waktu Kepulauan Solomon (Guadalkanal)", + "Pacific\/Guam": "Waktu Standar Chamorro (Guam)", + "Pacific\/Honolulu": "Waktu Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Waktu Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Waktu Kep. Line (Kiritimati)", + "Pacific\/Kosrae": "Waktu Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Waktu Kep. Marshall (Kwajalein)", + "Pacific\/Majuro": "Waktu Kep. Marshall (Majuro)", + "Pacific\/Marquesas": "Waktu Marquesas (Marquesas)", + "Pacific\/Midway": "Waktu Samoa (Midway)", + "Pacific\/Nauru": "Waktu Nauru (Nauru)", + "Pacific\/Niue": "Waktu Niue (Niue)", + "Pacific\/Norfolk": "Waktu Kepulauan Norfolk (Norfolk)", + "Pacific\/Noumea": "Waktu Kaledonia Baru (Noumea)", + "Pacific\/Pago_Pago": "Waktu Samoa (Pago Pago)", + "Pacific\/Palau": "Waktu Palau (Palau)", + "Pacific\/Pitcairn": "Waktu Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Waktu Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Waktu Papua Nugini (Port Moresby)", + "Pacific\/Rarotonga": "Waktu Kep. Cook (Rarotonga)", + "Pacific\/Saipan": "Waktu Standar Chamorro (Saipan)", + "Pacific\/Tahiti": "Waktu Tahiti (Tahiti)", + "Pacific\/Tarawa": "Waktu Kep. Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Waktu Tonga (Tongatapu)", + "Pacific\/Truk": "Waktu Chuuk (Chuuk)", + "Pacific\/Wake": "Waktu Kepulauan Wake (Wake)", + "Pacific\/Wallis": "Waktu Wallis dan Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ig.json b/src/Symfony/Component/Intl/Resources/data/timezones/ig.json new file mode 100644 index 0000000000000..4f739cc993a13 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ig.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.48.45", + "Names": { + "Africa\/Abidjan": "Oge Mpaghara Greemwich Mean (Abidjan)", + "Africa\/Accra": "Oge Mpaghara Greemwich Mean (Accra)", + "Africa\/Algiers": "Oge Mpaghara Etiti Europe (Algiers)", + "Africa\/Bamako": "Oge Mpaghara Greemwich Mean (Bamako)", + "Africa\/Banjul": "Oge Mpaghara Greemwich Mean (Banjul)", + "Africa\/Bissau": "Oge Mpaghara Greemwich Mean (Bissau)", + "Africa\/Cairo": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Cairo)", + "Africa\/Casablanca": "Oge Mpaghara Ọdịda Anyanwụ Europe (Casablanca)", + "Africa\/Ceuta": "Oge Mpaghara Etiti Europe (Ceuta)", + "Africa\/Conakry": "Oge Mpaghara Greemwich Mean (Conakry)", + "Africa\/Dakar": "Oge Mpaghara Greemwich Mean (Dakar)", + "Africa\/El_Aaiun": "Oge Mpaghara Ọdịda Anyanwụ Europe (El Aaiun)", + "Africa\/Freetown": "Oge Mpaghara Greemwich Mean (Freetown)", + "Africa\/Lome": "Oge Mpaghara Greemwich Mean (Lome)", + "Africa\/Monrovia": "Oge Mpaghara Greemwich Mean (Monrovia)", + "Africa\/Nouakchott": "Oge Mpaghara Greemwich Mean (Nouakchott)", + "Africa\/Ouagadougou": "Oge Mpaghara Greemwich Mean (Ouagadougou)", + "Africa\/Sao_Tome": "Oge Mpaghara Greemwich Mean (Sao Tome)", + "Africa\/Tripoli": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Tripoli)", + "Africa\/Tunis": "Oge Mpaghara Etiti Europe (Tunis)", + "America\/Anguilla": "Oge Mpaghara Atlantic (Anguilla)", + "America\/Antigua": "Oge Mpaghara Atlantic (Antigua)", + "America\/Aruba": "Oge Mpaghara Atlantic (Aruba)", + "America\/Bahia_Banderas": "Oge Mpaghara Etiti (Bahia Banderas)", + "America\/Barbados": "Oge Mpaghara Atlantic (Barbados)", + "America\/Belize": "Oge Mpaghara Etiti (Belize)", + "America\/Blanc-Sablon": "Oge Mpaghara Atlantic (Blanc-Sablon)", + "America\/Boise": "Oge Mpaghara Ugwu (Boise)", + "America\/Cambridge_Bay": "Oge Mpaghara Ugwu (Cambridge Bay)", + "America\/Cancun": "Oge Mpaghara Ọwụwa Anyanwụ (Cancun)", + "America\/Cayman": "Oge Mpaghara Ọwụwa Anyanwụ (Cayman)", + "America\/Chicago": "Oge Mpaghara Etiti (Chicago)", + "America\/Coral_Harbour": "Oge Mpaghara Ọwụwa Anyanwụ (Atikokan)", + "America\/Costa_Rica": "Oge Mpaghara Etiti (Costa Rica)", + "America\/Creston": "Oge Mpaghara Ugwu (Creston)", + "America\/Curacao": "Oge Mpaghara Atlantic (Curacao)", + "America\/Danmarkshavn": "Oge Mpaghara Greemwich Mean (Danmarkshavn)", + "America\/Dawson": "Oge Mpaghara Pacific (Dawson)", + "America\/Dawson_Creek": "Oge Mpaghara Ugwu (Dawson Creek)", + "America\/Denver": "Oge Mpaghara Ugwu (Denver)", + "America\/Detroit": "Oge Mpaghara Ọwụwa Anyanwụ (Detroit)", + "America\/Dominica": "Oge Mpaghara Atlantic (Dominica)", + "America\/Edmonton": "Oge Mpaghara Ugwu (Edmonton)", + "America\/El_Salvador": "Oge Mpaghara Etiti (El Salvador)", + "America\/Fort_Nelson": "Oge Mpaghara Ugwu (Fort Nelson)", + "America\/Glace_Bay": "Oge Mpaghara Atlantic (Glace Bay)", + "America\/Goose_Bay": "Oge Mpaghara Atlantic (Goose Bay)", + "America\/Grand_Turk": "Oge Mpaghara Ọwụwa Anyanwụ (Grand Turk)", + "America\/Grenada": "Oge Mpaghara Atlantic (Grenada)", + "America\/Guadeloupe": "Oge Mpaghara Atlantic (Guadeloupe)", + "America\/Guatemala": "Oge Mpaghara Etiti (Guatemala)", + "America\/Halifax": "Oge Mpaghara Atlantic (Halifax)", + "America\/Indiana\/Knox": "Oge Mpaghara Etiti (Knox, Indiana)", + "America\/Indiana\/Marengo": "Oge Mpaghara Ọwụwa Anyanwụ (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Oge Mpaghara Ọwụwa Anyanwụ (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Oge Mpaghara Etiti (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Oge Mpaghara Ọwụwa Anyanwụ (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Oge Mpaghara Ọwụwa Anyanwụ (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Oge Mpaghara Ọwụwa Anyanwụ (Winamac, Indiana)", + "America\/Indianapolis": "Oge Mpaghara Ọwụwa Anyanwụ (Indianapolis)", + "America\/Inuvik": "Oge Mpaghara Ugwu (Inuvik)", + "America\/Iqaluit": "Oge Mpaghara Ọwụwa Anyanwụ (Iqaluit)", + "America\/Jamaica": "Oge Mpaghara Ọwụwa Anyanwụ (Jamaica)", + "America\/Kentucky\/Monticello": "Oge Mpaghara Ọwụwa Anyanwụ (Monticello, Kentucky)", + "America\/Kralendijk": "Oge Mpaghara Atlantic (Kralendijk)", + "America\/Los_Angeles": "Oge Mpaghara Pacific (Los Angeles)", + "America\/Louisville": "Oge Mpaghara Ọwụwa Anyanwụ (Louisville)", + "America\/Lower_Princes": "Oge Mpaghara Atlantic (Lower Prince’s Quarter)", + "America\/Managua": "Oge Mpaghara Etiti (Managua)", + "America\/Marigot": "Oge Mpaghara Atlantic (Marigot)", + "America\/Martinique": "Oge Mpaghara Atlantic (Martinique)", + "America\/Matamoros": "Oge Mpaghara Etiti (Matamoros)", + "America\/Menominee": "Oge Mpaghara Etiti (Menominee)", + "America\/Merida": "Oge Mpaghara Etiti (Merida)", + "America\/Mexico_City": "Oge Mpaghara Etiti (Mexico City)", + "America\/Moncton": "Oge Mpaghara Atlantic (Moncton)", + "America\/Monterrey": "Oge Mpaghara Etiti (Monterrey)", + "America\/Montserrat": "Oge Mpaghara Atlantic (Montserrat)", + "America\/Nassau": "Oge Mpaghara Ọwụwa Anyanwụ (Nassau)", + "America\/New_York": "Oge Mpaghara Ọwụwa Anyanwụ (New York)", + "America\/Nipigon": "Oge Mpaghara Ọwụwa Anyanwụ (Nipigon)", + "America\/North_Dakota\/Beulah": "Oge Mpaghara Etiti (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Oge Mpaghara Etiti (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Oge Mpaghara Etiti (New Salem, North Dakota)", + "America\/Ojinaga": "Oge Mpaghara Ugwu (Ojinaga)", + "America\/Panama": "Oge Mpaghara Ọwụwa Anyanwụ (Panama)", + "America\/Pangnirtung": "Oge Mpaghara Ọwụwa Anyanwụ (Pangnirtung)", + "America\/Phoenix": "Oge Mpaghara Ugwu (Phoenix)", + "America\/Port-au-Prince": "Oge Mpaghara Ọwụwa Anyanwụ (Port-au-Prince)", + "America\/Port_of_Spain": "Oge Mpaghara Atlantic (Port of Spain)", + "America\/Puerto_Rico": "Oge Mpaghara Atlantic (Puerto Rico)", + "America\/Rainy_River": "Oge Mpaghara Etiti (Rainy River)", + "America\/Rankin_Inlet": "Oge Mpaghara Etiti (Rankin Inlet)", + "America\/Regina": "Oge Mpaghara Etiti (Regina)", + "America\/Resolute": "Oge Mpaghara Etiti (Resolute)", + "America\/Santo_Domingo": "Oge Mpaghara Atlantic (Santo Domingo)", + "America\/St_Barthelemy": "Oge Mpaghara Atlantic (St. Barthelemy)", + "America\/St_Kitts": "Oge Mpaghara Atlantic (St. Kitts)", + "America\/St_Lucia": "Oge Mpaghara Atlantic (St. Lucia)", + "America\/St_Thomas": "Oge Mpaghara Atlantic (St. Thomas)", + "America\/St_Vincent": "Oge Mpaghara Atlantic (St. Vincent)", + "America\/Swift_Current": "Oge Mpaghara Etiti (Swift Current)", + "America\/Tegucigalpa": "Oge Mpaghara Etiti (Tegucigalpa)", + "America\/Thule": "Oge Mpaghara Atlantic (Thule)", + "America\/Thunder_Bay": "Oge Mpaghara Ọwụwa Anyanwụ (Thunder Bay)", + "America\/Tijuana": "Oge Mpaghara Pacific (Tijuana)", + "America\/Toronto": "Oge Mpaghara Ọwụwa Anyanwụ (Toronto)", + "America\/Tortola": "Oge Mpaghara Atlantic (Tortola)", + "America\/Vancouver": "Oge Mpaghara Pacific (Vancouver)", + "America\/Whitehorse": "Oge Mpaghara Pacific (Whitehorse)", + "America\/Winnipeg": "Oge Mpaghara Etiti (Winnipeg)", + "America\/Yellowknife": "Oge Mpaghara Ugwu (Yellowknife)", + "Antarctica\/Troll": "Oge Mpaghara Greemwich Mean (Troll)", + "Arctic\/Longyearbyen": "Oge Mpaghara Etiti Europe (Longyearbyen)", + "Asia\/Amman": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Amman)", + "Asia\/Beirut": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Beirut)", + "Asia\/Damascus": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Damascus)", + "Asia\/Famagusta": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Famagusta)", + "Asia\/Gaza": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Gaza)", + "Asia\/Hebron": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Hebron)", + "Asia\/Nicosia": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Nicosia)", + "Atlantic\/Bermuda": "Oge Mpaghara Atlantic (Bermuda)", + "Atlantic\/Canary": "Oge Mpaghara Ọdịda Anyanwụ Europe (Canary)", + "Atlantic\/Faeroe": "Oge Mpaghara Ọdịda Anyanwụ Europe (Faroe)", + "Atlantic\/Madeira": "Oge Mpaghara Ọdịda Anyanwụ Europe (Madeira)", + "Atlantic\/Reykjavik": "Oge Mpaghara Greemwich Mean (Reykjavik)", + "Atlantic\/St_Helena": "Oge Mpaghara Greemwich Mean (St. Helena)", + "CST6CDT": "Oge Mpaghara Etiti", + "EST5EDT": "Oge Mpaghara Ọwụwa Anyanwụ", + "Etc\/GMT": "Oge Mpaghara Greemwich Mean", + "Etc\/UTC": "Nhazi Oge Ụwa Niile", + "Europe\/Amsterdam": "Oge Mpaghara Etiti Europe (Amsterdam)", + "Europe\/Andorra": "Oge Mpaghara Etiti Europe (Andorra)", + "Europe\/Athens": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Athens)", + "Europe\/Belgrade": "Oge Mpaghara Etiti Europe (Belgrade)", + "Europe\/Berlin": "Oge Mpaghara Etiti Europe (Berlin)", + "Europe\/Bratislava": "Oge Mpaghara Etiti Europe (Bratislava)", + "Europe\/Brussels": "Oge Mpaghara Etiti Europe (Brussels)", + "Europe\/Bucharest": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Bucharest)", + "Europe\/Budapest": "Oge Mpaghara Etiti Europe (Budapest)", + "Europe\/Busingen": "Oge Mpaghara Etiti Europe (Busingen)", + "Europe\/Chisinau": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Chisinau)", + "Europe\/Copenhagen": "Oge Mpaghara Etiti Europe (Copenhagen)", + "Europe\/Dublin": "Oge Mpaghara Greemwich Mean (Dublin)", + "Europe\/Gibraltar": "Oge Mpaghara Etiti Europe (Gibraltar)", + "Europe\/Guernsey": "Oge Mpaghara Greemwich Mean (Guernsey)", + "Europe\/Helsinki": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Helsinki)", + "Europe\/Isle_of_Man": "Oge Mpaghara Greemwich Mean (Isle of Man)", + "Europe\/Jersey": "Oge Mpaghara Greemwich Mean (Jersey)", + "Europe\/Kaliningrad": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Kaliningrad)", + "Europe\/Kiev": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Kiev)", + "Europe\/Lisbon": "Oge Mpaghara Ọdịda Anyanwụ Europe (Lisbon)", + "Europe\/Ljubljana": "Oge Mpaghara Etiti Europe (Ljubljana)", + "Europe\/London": "Oge Mpaghara Greemwich Mean (London)", + "Europe\/Luxembourg": "Oge Mpaghara Etiti Europe (Luxembourg)", + "Europe\/Madrid": "Oge Mpaghara Etiti Europe (Madrid)", + "Europe\/Malta": "Oge Mpaghara Etiti Europe (Malta)", + "Europe\/Mariehamn": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Mariehamn)", + "Europe\/Monaco": "Oge Mpaghara Etiti Europe (Monaco)", + "Europe\/Oslo": "Oge Mpaghara Etiti Europe (Oslo)", + "Europe\/Paris": "Oge Mpaghara Etiti Europe (Paris)", + "Europe\/Podgorica": "Oge Mpaghara Etiti Europe (Podgorica)", + "Europe\/Prague": "Oge Mpaghara Etiti Europe (Prague)", + "Europe\/Riga": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Riga)", + "Europe\/Rome": "Oge Mpaghara Etiti Europe (Rome)", + "Europe\/San_Marino": "Oge Mpaghara Etiti Europe (San Marino)", + "Europe\/Sarajevo": "Oge Mpaghara Etiti Europe (Sarajevo)", + "Europe\/Skopje": "Oge Mpaghara Etiti Europe (Skopje)", + "Europe\/Sofia": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Sofia)", + "Europe\/Stockholm": "Oge Mpaghara Etiti Europe (Stockholm)", + "Europe\/Tallinn": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Tallinn)", + "Europe\/Tirane": "Oge Mpaghara Etiti Europe (Tirane)", + "Europe\/Uzhgorod": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Uzhgorod)", + "Europe\/Vaduz": "Oge Mpaghara Etiti Europe (Vaduz)", + "Europe\/Vatican": "Oge Mpaghara Etiti Europe (Vatican)", + "Europe\/Vienna": "Oge Mpaghara Etiti Europe (Vienna)", + "Europe\/Vilnius": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Vilnius)", + "Europe\/Warsaw": "Oge Mpaghara Etiti Europe (Warsaw)", + "Europe\/Zagreb": "Oge Mpaghara Etiti Europe (Zagreb)", + "Europe\/Zaporozhye": "Oge Mpaghara Ọwụwa Anyanwụ Europe (Zaporozhye)", + "Europe\/Zurich": "Oge Mpaghara Etiti Europe (Zurich)", + "MST7MDT": "Oge Mpaghara Ugwu", + "PST8PDT": "Oge Mpaghara Pacific" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ii.json b/src/Symfony/Component/Intl/Resources/data/timezones/ii.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ii.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/in.json b/src/Symfony/Component/Intl/Resources/data/timezones/in.json new file mode 100644 index 0000000000000..348aa804df470 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/in.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "Waktu Afrika Timur (Addis Ababa)", + "Africa\/Algiers": "Waktu Eropa Tengah (Aljir)", + "Africa\/Asmera": "Waktu Afrika Timur (Asmara)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "Waktu Afrika Barat (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Waktu Afrika Tengah (Blantyre)", + "Africa\/Brazzaville": "Waktu Afrika Barat (Brazzaville)", + "Africa\/Bujumbura": "Waktu Afrika Tengah (Bujumbura)", + "Africa\/Cairo": "Waktu Eropa Timur (Kairo)", + "Africa\/Casablanca": "Waktu Eropa Barat (Casablanca)", + "Africa\/Ceuta": "Waktu Eropa Tengah (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "Waktu Afrika Timur (Dar es Salaam)", + "Africa\/Djibouti": "Waktu Afrika Timur (Djibouti)", + "Africa\/Douala": "Waktu Afrika Barat (Douala)", + "Africa\/El_Aaiun": "Waktu Eropa Barat (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Waktu Afrika Tengah (Gaborone)", + "Africa\/Harare": "Waktu Afrika Tengah (Harare)", + "Africa\/Johannesburg": "Waktu Standar Afrika Selatan (Johannesburg)", + "Africa\/Juba": "Waktu Afrika Timur (Juba)", + "Africa\/Kampala": "Waktu Afrika Timur (Kampala)", + "Africa\/Khartoum": "Waktu Afrika Tengah (Khartoum)", + "Africa\/Kigali": "Waktu Afrika Tengah (Kigali)", + "Africa\/Kinshasa": "Waktu Afrika Barat (Kinshasa)", + "Africa\/Lagos": "Waktu Afrika Barat (Lagos)", + "Africa\/Libreville": "Waktu Afrika Barat (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lome)", + "Africa\/Luanda": "Waktu Afrika Barat (Luanda)", + "Africa\/Lubumbashi": "Waktu Afrika Tengah (Lubumbashi)", + "Africa\/Lusaka": "Waktu Afrika Tengah (Lusaka)", + "Africa\/Malabo": "Waktu Afrika Barat (Malabo)", + "Africa\/Maputo": "Waktu Afrika Tengah (Maputo)", + "Africa\/Maseru": "Waktu Standar Afrika Selatan (Maseru)", + "Africa\/Mbabane": "Waktu Standar Afrika Selatan (Mbabane)", + "Africa\/Mogadishu": "Waktu Afrika Timur (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "Waktu Afrika Timur (Nairobi)", + "Africa\/Ndjamena": "Waktu Afrika Barat (Ndjamena)", + "Africa\/Niamey": "Waktu Afrika Barat (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "Waktu Afrika Barat (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tome)", + "Africa\/Tripoli": "Waktu Eropa Timur (Tripoli)", + "Africa\/Tunis": "Waktu Eropa Tengah (Tunis)", + "Africa\/Windhoek": "Waktu Afrika Tengah (Windhoek)", + "America\/Adak": "Waktu Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Waktu Alaska (Anchorage)", + "America\/Anguilla": "Waktu Atlantik (Anguila)", + "America\/Antigua": "Waktu Atlantik (Antigua)", + "America\/Araguaina": "Waktu Brasil (Araguaina)", + "America\/Argentina\/La_Rioja": "Waktu Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Waktu Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Waktu Argentina (Salta)", + "America\/Argentina\/San_Juan": "Waktu Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Waktu Argentina Bagian Barat (San Luis)", + "America\/Argentina\/Tucuman": "Waktu Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Waktu Argentina (Ushuaia)", + "America\/Aruba": "Waktu Atlantik (Aruba)", + "America\/Asuncion": "Waktu Paraguay (Asuncion)", + "America\/Bahia": "Waktu Brasil (Bahia)", + "America\/Bahia_Banderas": "Waktu Tengah (Bahia Banderas)", + "America\/Barbados": "Waktu Atlantik (Barbados)", + "America\/Belem": "Waktu Brasil (Belem)", + "America\/Belize": "Waktu Tengah (Belize)", + "America\/Blanc-Sablon": "Waktu Atlantik (Blanc-Sablon)", + "America\/Boa_Vista": "Waktu Amazon (Boa Vista)", + "America\/Bogota": "Waktu Kolombia (Bogota)", + "America\/Boise": "Waktu Pegunungan (Boise)", + "America\/Buenos_Aires": "Waktu Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Waktu Pegunungan (Cambridge Bay)", + "America\/Campo_Grande": "Waktu Amazon (Campo Grande)", + "America\/Cancun": "Waktu Timur (Cancun)", + "America\/Caracas": "Waktu Venezuela (Caracas)", + "America\/Catamarca": "Waktu Argentina (Catamarca)", + "America\/Cayenne": "Waktu Guyana Prancis (Cayenne)", + "America\/Cayman": "Waktu Timur (Cayman)", + "America\/Chicago": "Waktu Tengah (Chicago)", + "America\/Chihuahua": "Waktu Pasifik Meksiko (Chihuahua)", + "America\/Coral_Harbour": "Waktu Timur (Atikokan)", + "America\/Cordoba": "Waktu Argentina (Cordoba)", + "America\/Costa_Rica": "Waktu Tengah (Kosta Rika)", + "America\/Creston": "Waktu Pegunungan (Creston)", + "America\/Cuiaba": "Waktu Amazon (Cuiaba)", + "America\/Curacao": "Waktu Atlantik (Curacao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Waktu Pasifik (Dawson)", + "America\/Dawson_Creek": "Waktu Pegunungan (Dawson Creek)", + "America\/Denver": "Waktu Pegunungan (Denver)", + "America\/Detroit": "Waktu Timur (Detroit)", + "America\/Dominica": "Waktu Atlantik (Dominika)", + "America\/Edmonton": "Waktu Pegunungan (Edmonton)", + "America\/Eirunepe": "Waktu Acre (Eirunepe)", + "America\/El_Salvador": "Waktu Tengah (El Salvador)", + "America\/Fort_Nelson": "Waktu Pegunungan (Fort Nelson)", + "America\/Fortaleza": "Waktu Brasil (Fortaleza)", + "America\/Glace_Bay": "Waktu Atlantik (Glace Bay)", + "America\/Godthab": "Waktu Greenland Barat (Nuuk)", + "America\/Goose_Bay": "Waktu Atlantik (Goose Bay)", + "America\/Grand_Turk": "Waktu Timur (Grand Turk)", + "America\/Grenada": "Waktu Atlantik (Grenada)", + "America\/Guadeloupe": "Waktu Atlantik (Guadeloupe)", + "America\/Guatemala": "Waktu Tengah (Guatemala)", + "America\/Guayaquil": "Waktu Ekuador (Guayaquil)", + "America\/Guyana": "Waktu Guyana (Guyana)", + "America\/Halifax": "Waktu Atlantik (Halifax)", + "America\/Havana": "Waktu Kuba (Havana)", + "America\/Hermosillo": "Waktu Pasifik Meksiko (Hermosillo)", + "America\/Indiana\/Knox": "Waktu Tengah (Knox, Indiana)", + "America\/Indiana\/Marengo": "Waktu Timur (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Waktu Timur (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Waktu Tengah (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Waktu Timur (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Waktu Timur (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Waktu Timur (Winamac, Indiana)", + "America\/Indianapolis": "Waktu Timur (Indianapolis)", + "America\/Inuvik": "Waktu Pegunungan (Inuvik)", + "America\/Iqaluit": "Waktu Timur (Iqaluit)", + "America\/Jamaica": "Waktu Timur (Jamaica)", + "America\/Jujuy": "Waktu Argentina (Jujuy)", + "America\/Juneau": "Waktu Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Waktu Timur (Monticello, Kentucky)", + "America\/Kralendijk": "Waktu Atlantik (Kralendijk)", + "America\/La_Paz": "Waktu Bolivia (La Paz)", + "America\/Lima": "Waktu Peru (Lima)", + "America\/Los_Angeles": "Waktu Pasifik (Los Angeles)", + "America\/Louisville": "Waktu Timur (Louisville)", + "America\/Lower_Princes": "Waktu Atlantik (Lower Prince’s Quarter)", + "America\/Maceio": "Waktu Brasil (Maceio)", + "America\/Managua": "Waktu Tengah (Managua)", + "America\/Manaus": "Waktu Amazon (Manaus)", + "America\/Marigot": "Waktu Atlantik (Marigot)", + "America\/Martinique": "Waktu Atlantik (Martinik)", + "America\/Matamoros": "Waktu Tengah (Matamoros)", + "America\/Mazatlan": "Waktu Pasifik Meksiko (Mazatlan)", + "America\/Mendoza": "Waktu Argentina (Mendoza)", + "America\/Menominee": "Waktu Tengah (Menominee)", + "America\/Merida": "Waktu Tengah (Merida)", + "America\/Metlakatla": "Waktu Alaska (Metlakatla)", + "America\/Mexico_City": "Waktu Tengah (Mexico City)", + "America\/Miquelon": "Waktu Saint Pierre dan Miquelon (Miquelon)", + "America\/Moncton": "Waktu Atlantik (Moncton)", + "America\/Monterrey": "Waktu Tengah (Monterrey)", + "America\/Montevideo": "Waktu Uruguay (Montevideo)", + "America\/Montserrat": "Waktu Atlantik (Montserrat)", + "America\/Nassau": "Waktu Timur (Nassau)", + "America\/New_York": "Waktu Timur (New York)", + "America\/Nipigon": "Waktu Timur (Nipigon)", + "America\/Nome": "Waktu Alaska (Nome)", + "America\/Noronha": "Waktu Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Waktu Tengah (Beulah, Dakota Utara)", + "America\/North_Dakota\/Center": "Waktu Tengah (Center, Dakota Utara)", + "America\/North_Dakota\/New_Salem": "Waktu Tengah (New Salem, Dakota Utara)", + "America\/Ojinaga": "Waktu Pegunungan (Ojinaga)", + "America\/Panama": "Waktu Timur (Panama)", + "America\/Pangnirtung": "Waktu Timur (Pangnirtung)", + "America\/Paramaribo": "Waktu Suriname (Paramaribo)", + "America\/Phoenix": "Waktu Pegunungan (Phoenix)", + "America\/Port-au-Prince": "Waktu Timur (Port-au-Prince)", + "America\/Port_of_Spain": "Waktu Atlantik (Port of Spain)", + "America\/Porto_Velho": "Waktu Amazon (Porto Velho)", + "America\/Puerto_Rico": "Waktu Atlantik (Puerto Rico)", + "America\/Punta_Arenas": "Waktu Cile (Punta Arenas)", + "America\/Rainy_River": "Waktu Tengah (Rainy River)", + "America\/Rankin_Inlet": "Waktu Tengah (Rankin Inlet)", + "America\/Recife": "Waktu Brasil (Recife)", + "America\/Regina": "Waktu Tengah (Regina)", + "America\/Resolute": "Waktu Tengah (Resolute)", + "America\/Rio_Branco": "Waktu Acre (Rio Branco)", + "America\/Santa_Isabel": "Waktu Meksiko Barat Laut (Santa Isabel)", + "America\/Santarem": "Waktu Brasil (Santarem)", + "America\/Santiago": "Waktu Cile (Santiago)", + "America\/Santo_Domingo": "Waktu Atlantik (Santo Domingo)", + "America\/Sao_Paulo": "Waktu Brasil (Sao Paulo)", + "America\/Scoresbysund": "Waktu Greenland Timur (Ittoqqortoormiit)", + "America\/Sitka": "Waktu Alaska (Sitka)", + "America\/St_Barthelemy": "Waktu Atlantik (St. Barthelemy)", + "America\/St_Johns": "Waktu Newfoundland (St. John’s)", + "America\/St_Kitts": "Waktu Atlantik (St. Kitts)", + "America\/St_Lucia": "Waktu Atlantik (St. Lucia)", + "America\/St_Thomas": "Waktu Atlantik (St. Thomas)", + "America\/St_Vincent": "Waktu Atlantik (St. Vincent)", + "America\/Swift_Current": "Waktu Tengah (Swift Current)", + "America\/Tegucigalpa": "Waktu Tengah (Tegucigalpa)", + "America\/Thule": "Waktu Atlantik (Thule)", + "America\/Thunder_Bay": "Waktu Timur (Thunder Bay)", + "America\/Tijuana": "Waktu Pasifik (Tijuana)", + "America\/Toronto": "Waktu Timur (Toronto)", + "America\/Tortola": "Waktu Atlantik (Tortola)", + "America\/Vancouver": "Waktu Pasifik (Vancouver)", + "America\/Whitehorse": "Waktu Pasifik (Whitehorse)", + "America\/Winnipeg": "Waktu Tengah (Winnipeg)", + "America\/Yakutat": "Waktu Alaska (Yakutat)", + "America\/Yellowknife": "Waktu Pegunungan (Yellowknife)", + "Antarctica\/Casey": "Waktu Barat Australia (Casey)", + "Antarctica\/Davis": "Waktu Davis (Davis)", + "Antarctica\/DumontDUrville": "Waktu Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Waktu Kepulauan Macquarie (Macquarie)", + "Antarctica\/Mawson": "Waktu Mawson (Mawson)", + "Antarctica\/McMurdo": "Waktu Selandia Baru (McMurdo)", + "Antarctica\/Palmer": "Waktu Cile (Palmer)", + "Antarctica\/Rothera": "Waktu Rothera (Rothera)", + "Antarctica\/Syowa": "Waktu Syowa (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Waktu Vostok (Vostok)", + "Arctic\/Longyearbyen": "Waktu Eropa Tengah (Longyearbyen)", + "Asia\/Aden": "Waktu Arab (Aden)", + "Asia\/Almaty": "Waktu Kazakhstan Timur (Almaty)", + "Asia\/Amman": "Waktu Eropa Timur (Amman)", + "Asia\/Anadyr": "Waktu Anadyr (Anadyr)", + "Asia\/Aqtau": "Waktu Kazakhstan Barat (Aktau)", + "Asia\/Aqtobe": "Waktu Kazakhstan Barat (Aktobe)", + "Asia\/Ashgabat": "Waktu Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Waktu Kazakhstan Barat (Atyrau)", + "Asia\/Baghdad": "Waktu Arab (Baghdad)", + "Asia\/Bahrain": "Waktu Arab (Bahrain)", + "Asia\/Baku": "Waktu Azerbaijan (Baku)", + "Asia\/Bangkok": "Waktu Indochina (Bangkok)", + "Asia\/Beirut": "Waktu Eropa Timur (Beirut)", + "Asia\/Bishkek": "Waktu Kirghizia (Bishkek)", + "Asia\/Brunei": "Waktu Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Waktu India (Kolkata)", + "Asia\/Chita": "Waktu Yakutsk (Chita)", + "Asia\/Choibalsan": "Waktu Choibalsan (Choibalsan)", + "Asia\/Colombo": "Waktu India (Kolombo)", + "Asia\/Damascus": "Waktu Eropa Timur (Damaskus)", + "Asia\/Dhaka": "Waktu Bangladesh (Dhaka)", + "Asia\/Dili": "Waktu Timor Leste (Dili)", + "Asia\/Dubai": "Waktu Standar Teluk (Dubai)", + "Asia\/Dushanbe": "Waktu Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Waktu Eropa Timur (Famagusta)", + "Asia\/Gaza": "Waktu Eropa Timur (Gaza)", + "Asia\/Hebron": "Waktu Eropa Timur (Hebron)", + "Asia\/Hong_Kong": "Waktu Hong Kong (Hong Kong)", + "Asia\/Hovd": "Waktu Hovd (Hovd)", + "Asia\/Irkutsk": "Waktu Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Waktu Indonesia Barat (Jakarta)", + "Asia\/Jayapura": "Waktu Indonesia Timur (Jayapura)", + "Asia\/Jerusalem": "Waktu Israel (Yerusalem)", + "Asia\/Kabul": "Waktu Afganistan (Kabul)", + "Asia\/Kamchatka": "Waktu Petropavlovsk-Kamchatsky (Kamchatka)", + "Asia\/Karachi": "Waktu Pakistan (Karachi)", + "Asia\/Katmandu": "Waktu Nepal (Kathmandu)", + "Asia\/Khandyga": "Waktu Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Waktu Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Waktu Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Waktu Malaysia (Kuching)", + "Asia\/Kuwait": "Waktu Arab (Kuwait)", + "Asia\/Macau": "Waktu Tiongkok (Makau)", + "Asia\/Magadan": "Waktu Magadan (Magadan)", + "Asia\/Makassar": "Waktu Indonesia Tengah (Makassar)", + "Asia\/Manila": "Waktu Filipina (Manila)", + "Asia\/Muscat": "Waktu Standar Teluk (Muskat)", + "Asia\/Nicosia": "Waktu Eropa Timur (Nikosia)", + "Asia\/Novokuznetsk": "Waktu Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Waktu Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Waktu Omsk (Omsk)", + "Asia\/Oral": "Waktu Kazakhstan Barat (Oral)", + "Asia\/Phnom_Penh": "Waktu Indochina (Phnom Penh)", + "Asia\/Pontianak": "Waktu Indonesia Barat (Pontianak)", + "Asia\/Pyongyang": "Waktu Korea (Pyongyang)", + "Asia\/Qatar": "Waktu Arab (Qatar)", + "Asia\/Qostanay": "Waktu Kazakhstan Timur (Qostanay)", + "Asia\/Qyzylorda": "Waktu Kazakhstan Barat (Qyzylorda)", + "Asia\/Rangoon": "Waktu Myanmar (Rangoon)", + "Asia\/Riyadh": "Waktu Arab (Riyadh)", + "Asia\/Saigon": "Waktu Indochina (Ho Chi Minh)", + "Asia\/Sakhalin": "Waktu Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Waktu Uzbekistan (Samarkand)", + "Asia\/Seoul": "Waktu Korea (Seoul)", + "Asia\/Shanghai": "Waktu Tiongkok (Shanghai)", + "Asia\/Singapore": "Waktu Standar Singapura (Singapura)", + "Asia\/Srednekolymsk": "Waktu Magadan (Srednekolymsk)", + "Asia\/Taipei": "Waktu Taipei (Taipei)", + "Asia\/Tashkent": "Waktu Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Waktu Georgia (Tbilisi)", + "Asia\/Tehran": "Waktu Iran (Teheran)", + "Asia\/Thimphu": "Waktu Bhutan (Thimphu)", + "Asia\/Tokyo": "Waktu Jepang (Tokyo)", + "Asia\/Ulaanbaatar": "Waktu Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Waktu Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Waktu Indochina (Vientiane)", + "Asia\/Vladivostok": "Waktu Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Waktu Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Waktu Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Waktu Armenia (Yerevan)", + "Atlantic\/Azores": "Waktu Azores (Azores)", + "Atlantic\/Bermuda": "Waktu Atlantik (Bermuda)", + "Atlantic\/Canary": "Waktu Eropa Barat (Canary)", + "Atlantic\/Cape_Verde": "Waktu Tanjung Verde (Tanjung Verde)", + "Atlantic\/Faeroe": "Waktu Eropa Barat (Faroe)", + "Atlantic\/Madeira": "Waktu Eropa Barat (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/South_Georgia": "Waktu Georgia Selatan (Georgia Selatan)", + "Atlantic\/St_Helena": "Greenwich Mean Time (St. Helena)", + "Atlantic\/Stanley": "Waktu Kepulauan Falkland (Stanley)", + "Australia\/Adelaide": "Waktu Tengah Australia (Adelaide)", + "Australia\/Brisbane": "Waktu Timur Australia (Brisbane)", + "Australia\/Broken_Hill": "Waktu Tengah Australia (Broken Hill)", + "Australia\/Currie": "Waktu Timur Australia (Currie)", + "Australia\/Darwin": "Waktu Tengah Australia (Darwin)", + "Australia\/Eucla": "Waktu Barat Tengah Australia (Eucla)", + "Australia\/Hobart": "Waktu Timur Australia (Hobart)", + "Australia\/Lindeman": "Waktu Timur Australia (Lindeman)", + "Australia\/Lord_Howe": "Waktu Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Waktu Timur Australia (Melbourne)", + "Australia\/Perth": "Waktu Barat Australia (Perth)", + "Australia\/Sydney": "Waktu Timur Australia (Sydney)", + "CST6CDT": "Waktu Tengah", + "EST5EDT": "Waktu Timur", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Waktu Universal Terkoordinasi", + "Europe\/Amsterdam": "Waktu Eropa Tengah (Amsterdam)", + "Europe\/Andorra": "Waktu Eropa Tengah (Andorra)", + "Europe\/Astrakhan": "Waktu Moskwa (Astrakhan)", + "Europe\/Athens": "Waktu Eropa Timur (Athena)", + "Europe\/Belgrade": "Waktu Eropa Tengah (Beograd)", + "Europe\/Berlin": "Waktu Eropa Tengah (Berlin)", + "Europe\/Bratislava": "Waktu Eropa Tengah (Bratislava)", + "Europe\/Brussels": "Waktu Eropa Tengah (Brussels)", + "Europe\/Bucharest": "Waktu Eropa Timur (Bucharest)", + "Europe\/Budapest": "Waktu Eropa Tengah (Budapest)", + "Europe\/Busingen": "Waktu Eropa Tengah (Busingen)", + "Europe\/Chisinau": "Waktu Eropa Timur (Kishinev)", + "Europe\/Copenhagen": "Waktu Eropa Tengah (Kopenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Waktu Eropa Tengah (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Waktu Eropa Timur (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Pulau Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Waktu Eropa Timur (Kaliningrad)", + "Europe\/Kiev": "Waktu Eropa Timur (Kiev)", + "Europe\/Lisbon": "Waktu Eropa Barat (Lisbon)", + "Europe\/Ljubljana": "Waktu Eropa Tengah (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (London)", + "Europe\/Luxembourg": "Waktu Eropa Tengah (Luksemburg)", + "Europe\/Madrid": "Waktu Eropa Tengah (Madrid)", + "Europe\/Malta": "Waktu Eropa Tengah (Malta)", + "Europe\/Mariehamn": "Waktu Eropa Timur (Mariehamn)", + "Europe\/Minsk": "Waktu Moskwa (Minsk)", + "Europe\/Monaco": "Waktu Eropa Tengah (Monako)", + "Europe\/Moscow": "Waktu Moskwa (Moskwa)", + "Europe\/Oslo": "Waktu Eropa Tengah (Oslo)", + "Europe\/Paris": "Waktu Eropa Tengah (Paris)", + "Europe\/Podgorica": "Waktu Eropa Tengah (Podgorica)", + "Europe\/Prague": "Waktu Eropa Tengah (Praha)", + "Europe\/Riga": "Waktu Eropa Timur (Riga)", + "Europe\/Rome": "Waktu Eropa Tengah (Roma)", + "Europe\/Samara": "Waktu Samara (Samara)", + "Europe\/San_Marino": "Waktu Eropa Tengah (San Marino)", + "Europe\/Sarajevo": "Waktu Eropa Tengah (Sarajevo)", + "Europe\/Saratov": "Waktu Moskwa (Saratov)", + "Europe\/Simferopol": "Waktu Moskwa (Simferopol)", + "Europe\/Skopje": "Waktu Eropa Tengah (Skopje)", + "Europe\/Sofia": "Waktu Eropa Timur (Sofia)", + "Europe\/Stockholm": "Waktu Eropa Tengah (Stockholm)", + "Europe\/Tallinn": "Waktu Eropa Timur (Tallinn)", + "Europe\/Tirane": "Waktu Eropa Tengah (Tirane)", + "Europe\/Ulyanovsk": "Waktu Moskwa (Ulyanovsk)", + "Europe\/Uzhgorod": "Waktu Eropa Timur (Uzhhorod)", + "Europe\/Vaduz": "Waktu Eropa Tengah (Vaduz)", + "Europe\/Vatican": "Waktu Eropa Tengah (Vatikan)", + "Europe\/Vienna": "Waktu Eropa Tengah (Wina)", + "Europe\/Vilnius": "Waktu Eropa Timur (Vilnius)", + "Europe\/Volgograd": "Waktu Volgograd (Volgograd)", + "Europe\/Warsaw": "Waktu Eropa Tengah (Warsawa)", + "Europe\/Zagreb": "Waktu Eropa Tengah (Zagreb)", + "Europe\/Zaporozhye": "Waktu Eropa Timur (Zaporizhia)", + "Europe\/Zurich": "Waktu Eropa Tengah (Zurich)", + "Indian\/Antananarivo": "Waktu Afrika Timur (Antananarivo)", + "Indian\/Chagos": "Waktu Samudera Hindia (Chagos)", + "Indian\/Christmas": "Waktu Pulau Natal (Christmas)", + "Indian\/Cocos": "Waktu Kepulauan Cocos (Cocos)", + "Indian\/Comoro": "Waktu Afrika Timur (Komoro)", + "Indian\/Kerguelen": "Waktu Wilayah Selatan dan Antarktika Prancis (Kerguelen)", + "Indian\/Mahe": "Waktu Seychelles (Mahe)", + "Indian\/Maldives": "Waktu Maladewa (Maladewa)", + "Indian\/Mauritius": "Waktu Mauritius (Mauritius)", + "Indian\/Mayotte": "Waktu Afrika Timur (Mayotte)", + "Indian\/Reunion": "Waktu Reunion (Reunion)", + "MST7MDT": "Waktu Pegunungan", + "PST8PDT": "Waktu Pasifik", + "Pacific\/Apia": "Waktu Apia (Apia)", + "Pacific\/Auckland": "Waktu Selandia Baru (Auckland)", + "Pacific\/Bougainville": "Waktu Papua Nugini (Bougainville)", + "Pacific\/Chatham": "Waktu Chatham (Chatham)", + "Pacific\/Easter": "Waktu Pulau Paskah (Easter)", + "Pacific\/Efate": "Waktu Vanuatu (Efate)", + "Pacific\/Enderbury": "Waktu Kepulauan Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Waktu Tokelau (Fakaofo)", + "Pacific\/Fiji": "Waktu Fiji (Fiji)", + "Pacific\/Funafuti": "Waktu Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Waktu Galapagos (Galapagos)", + "Pacific\/Gambier": "Waktu Gambier (Gambier)", + "Pacific\/Guadalcanal": "Waktu Kepulauan Solomon (Guadalkanal)", + "Pacific\/Guam": "Waktu Standar Chamorro (Guam)", + "Pacific\/Honolulu": "Waktu Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Waktu Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Waktu Kep. Line (Kiritimati)", + "Pacific\/Kosrae": "Waktu Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Waktu Kep. Marshall (Kwajalein)", + "Pacific\/Majuro": "Waktu Kep. Marshall (Majuro)", + "Pacific\/Marquesas": "Waktu Marquesas (Marquesas)", + "Pacific\/Midway": "Waktu Samoa (Midway)", + "Pacific\/Nauru": "Waktu Nauru (Nauru)", + "Pacific\/Niue": "Waktu Niue (Niue)", + "Pacific\/Norfolk": "Waktu Kepulauan Norfolk (Norfolk)", + "Pacific\/Noumea": "Waktu Kaledonia Baru (Noumea)", + "Pacific\/Pago_Pago": "Waktu Samoa (Pago Pago)", + "Pacific\/Palau": "Waktu Palau (Palau)", + "Pacific\/Pitcairn": "Waktu Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Waktu Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Waktu Papua Nugini (Port Moresby)", + "Pacific\/Rarotonga": "Waktu Kep. Cook (Rarotonga)", + "Pacific\/Saipan": "Waktu Standar Chamorro (Saipan)", + "Pacific\/Tahiti": "Waktu Tahiti (Tahiti)", + "Pacific\/Tarawa": "Waktu Kep. Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Waktu Tonga (Tongatapu)", + "Pacific\/Truk": "Waktu Chuuk (Chuuk)", + "Pacific\/Wake": "Waktu Kepulauan Wake (Wake)", + "Pacific\/Wallis": "Waktu Wallis dan Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/is.json b/src/Symfony/Component/Intl/Resources/data/timezones/is.json new file mode 100644 index 0000000000000..435666f6433ce --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/is.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Greenwich-staðaltími (Abidjan)", + "Africa\/Accra": "Greenwich-staðaltími (Accra)", + "Africa\/Addis_Ababa": "Austur-Afríkutími (Addis Ababa)", + "Africa\/Algiers": "Mið-Evróputími (Algeirsborg)", + "Africa\/Asmera": "Austur-Afríkutími (Asmara)", + "Africa\/Bamako": "Greenwich-staðaltími (Bamako)", + "Africa\/Bangui": "Vestur-Afríkutími (Bangui)", + "Africa\/Banjul": "Greenwich-staðaltími (Banjul)", + "Africa\/Bissau": "Greenwich-staðaltími (Bissá)", + "Africa\/Blantyre": "Mið-Afríkutími (Blantyre)", + "Africa\/Brazzaville": "Vestur-Afríkutími (Brazzaville)", + "Africa\/Bujumbura": "Mið-Afríkutími (Bujumbura)", + "Africa\/Cairo": "Austur-Evróputími (Kaíró)", + "Africa\/Casablanca": "Vestur-Evróputími (Casablanca)", + "Africa\/Ceuta": "Mið-Evróputími (Ceuta)", + "Africa\/Conakry": "Greenwich-staðaltími (Conakry)", + "Africa\/Dakar": "Greenwich-staðaltími (Dakar)", + "Africa\/Dar_es_Salaam": "Austur-Afríkutími (Dar es Salaam)", + "Africa\/Djibouti": "Austur-Afríkutími (Djibútí)", + "Africa\/Douala": "Vestur-Afríkutími (Douala)", + "Africa\/El_Aaiun": "Vestur-Evróputími (El Aaiun)", + "Africa\/Freetown": "Greenwich-staðaltími (Freetown)", + "Africa\/Gaborone": "Mið-Afríkutími (Gaborone)", + "Africa\/Harare": "Mið-Afríkutími (Harare)", + "Africa\/Johannesburg": "Suður-Afríkutími (Jóhannesarborg)", + "Africa\/Juba": "Austur-Afríkutími (Juba)", + "Africa\/Kampala": "Austur-Afríkutími (Kampala)", + "Africa\/Khartoum": "Mið-Afríkutími (Khartoum)", + "Africa\/Kigali": "Mið-Afríkutími (Kigali)", + "Africa\/Kinshasa": "Vestur-Afríkutími (Kinshasa)", + "Africa\/Lagos": "Vestur-Afríkutími (Lagos)", + "Africa\/Libreville": "Vestur-Afríkutími (Libreville)", + "Africa\/Lome": "Greenwich-staðaltími (Lome)", + "Africa\/Luanda": "Vestur-Afríkutími (Luanda)", + "Africa\/Lubumbashi": "Mið-Afríkutími (Lubumbashi)", + "Africa\/Lusaka": "Mið-Afríkutími (Lusaka)", + "Africa\/Malabo": "Vestur-Afríkutími (Malabo)", + "Africa\/Maputo": "Mið-Afríkutími (Maputo)", + "Africa\/Maseru": "Suður-Afríkutími (Maseru)", + "Africa\/Mbabane": "Suður-Afríkutími (Mbabane)", + "Africa\/Mogadishu": "Austur-Afríkutími (Mogadishu)", + "Africa\/Monrovia": "Greenwich-staðaltími (Monrovia)", + "Africa\/Nairobi": "Austur-Afríkutími (Nairobi)", + "Africa\/Ndjamena": "Vestur-Afríkutími (Ndjamena)", + "Africa\/Niamey": "Vestur-Afríkutími (Niamey)", + "Africa\/Nouakchott": "Greenwich-staðaltími (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich-staðaltími (Ouagadougou)", + "Africa\/Porto-Novo": "Vestur-Afríkutími (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich-staðaltími (Saó Tóme)", + "Africa\/Tripoli": "Austur-Evróputími (Trípólí)", + "Africa\/Tunis": "Mið-Evróputími (Túnisborg)", + "Africa\/Windhoek": "Mið-Afríkutími (Windhoek)", + "America\/Adak": "Tími á Havaí og Aleúta (Adak)", + "America\/Anchorage": "Tími í Alaska (Anchorage)", + "America\/Anguilla": "Tími á Atlantshafssvæðinu (Angvilla)", + "America\/Antigua": "Tími á Atlantshafssvæðinu (Antígva)", + "America\/Araguaina": "Brasilíutími (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentínutími (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentínutími (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentínutími (Salta)", + "America\/Argentina\/San_Juan": "Argentínutími (San Juan)", + "America\/Argentina\/San_Luis": "Vestur-Argentínutími (San Luis)", + "America\/Argentina\/Tucuman": "Argentínutími (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentínutími (Ushuaia)", + "America\/Aruba": "Tími á Atlantshafssvæðinu (Arúba)", + "America\/Asuncion": "Paragvætími (Asunción)", + "America\/Bahia": "Brasilíutími (Bahia)", + "America\/Bahia_Banderas": "Tími í miðhluta Bandaríkjanna og Kanada (Bahia Banderas)", + "America\/Barbados": "Tími á Atlantshafssvæðinu (Barbados)", + "America\/Belem": "Brasilíutími (Belem)", + "America\/Belize": "Tími í miðhluta Bandaríkjanna og Kanada (Belís)", + "America\/Blanc-Sablon": "Tími á Atlantshafssvæðinu (Blanc-Sablon)", + "America\/Boa_Vista": "Amasóntími (Boa Vista)", + "America\/Bogota": "Kólumbíutími (Bogota)", + "America\/Boise": "Tími í Klettafjöllum (Boise)", + "America\/Buenos_Aires": "Argentínutími (Buenos Aires)", + "America\/Cambridge_Bay": "Tími í Klettafjöllum (Cambridge Bay)", + "America\/Campo_Grande": "Amasóntími (Campo Grande)", + "America\/Cancun": "Tími í austurhluta Bandaríkjanna og Kanada (Kankún)", + "America\/Caracas": "Venesúelatími (Caracas)", + "America\/Catamarca": "Argentínutími (Catamarca)", + "America\/Cayenne": "Tími í Frönsku Gvæjana (Cayenne)", + "America\/Cayman": "Tími í austurhluta Bandaríkjanna og Kanada (Cayman-eyjar)", + "America\/Chicago": "Tími í miðhluta Bandaríkjanna og Kanada (Chicago)", + "America\/Chihuahua": "Kyrrahafstími í Mexíkó (Chihuahua)", + "America\/Coral_Harbour": "Tími í austurhluta Bandaríkjanna og Kanada (Atikokan)", + "America\/Cordoba": "Argentínutími (Cordoba)", + "America\/Costa_Rica": "Tími í miðhluta Bandaríkjanna og Kanada (Kostaríka)", + "America\/Creston": "Tími í Klettafjöllum (Creston)", + "America\/Cuiaba": "Amasóntími (Cuiaba)", + "America\/Curacao": "Tími á Atlantshafssvæðinu (Curacao)", + "America\/Danmarkshavn": "Greenwich-staðaltími (Danmarkshavn)", + "America\/Dawson": "Tími á Kyrrahafssvæðinu (Dawson)", + "America\/Dawson_Creek": "Tími í Klettafjöllum (Dawson Creek)", + "America\/Denver": "Tími í Klettafjöllum (Denver)", + "America\/Detroit": "Tími í austurhluta Bandaríkjanna og Kanada (Detroit)", + "America\/Dominica": "Tími á Atlantshafssvæðinu (Dóminíka)", + "America\/Edmonton": "Tími í Klettafjöllum (Edmonton)", + "America\/El_Salvador": "Tími í miðhluta Bandaríkjanna og Kanada (El Salvador)", + "America\/Fort_Nelson": "Tími í Klettafjöllum (Fort Nelson)", + "America\/Fortaleza": "Brasilíutími (Fortaleza)", + "America\/Glace_Bay": "Tími á Atlantshafssvæðinu (Glace Bay)", + "America\/Godthab": "Vestur-Grænlandstími (Nuuk)", + "America\/Goose_Bay": "Tími á Atlantshafssvæðinu (Goose Bay)", + "America\/Grand_Turk": "Tími í austurhluta Bandaríkjanna og Kanada (Grand Turk)", + "America\/Grenada": "Tími á Atlantshafssvæðinu (Grenada)", + "America\/Guadeloupe": "Tími á Atlantshafssvæðinu (Gvadelúp)", + "America\/Guatemala": "Tími í miðhluta Bandaríkjanna og Kanada (Gvatemala)", + "America\/Guayaquil": "Ekvadortími (Guayaquil)", + "America\/Guyana": "Gvæjanatími (Gvæjana)", + "America\/Halifax": "Tími á Atlantshafssvæðinu (Halifax)", + "America\/Havana": "Kúbutími (Havana)", + "America\/Hermosillo": "Kyrrahafstími í Mexíkó (Hermosillo)", + "America\/Indiana\/Knox": "Tími í miðhluta Bandaríkjanna og Kanada (Knox, Indiana)", + "America\/Indiana\/Marengo": "Tími í austurhluta Bandaríkjanna og Kanada (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Tími í austurhluta Bandaríkjanna og Kanada (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Tími í miðhluta Bandaríkjanna og Kanada (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Tími í austurhluta Bandaríkjanna og Kanada (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Tími í austurhluta Bandaríkjanna og Kanada (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Tími í austurhluta Bandaríkjanna og Kanada (Winamac, Indiana)", + "America\/Indianapolis": "Tími í austurhluta Bandaríkjanna og Kanada (Indianapolis)", + "America\/Inuvik": "Tími í Klettafjöllum (Inuvik)", + "America\/Iqaluit": "Tími í austurhluta Bandaríkjanna og Kanada (Iqaluit)", + "America\/Jamaica": "Tími í austurhluta Bandaríkjanna og Kanada (Jamaíka)", + "America\/Jujuy": "Argentínutími (Jujuy)", + "America\/Juneau": "Tími í Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Tími í austurhluta Bandaríkjanna og Kanada (Monticello, Kentucky)", + "America\/Kralendijk": "Tími á Atlantshafssvæðinu (Kralendijk)", + "America\/La_Paz": "Bólivíutími (La Paz)", + "America\/Lima": "Perútími (Lima)", + "America\/Los_Angeles": "Tími á Kyrrahafssvæðinu (Los Angeles)", + "America\/Louisville": "Tími í austurhluta Bandaríkjanna og Kanada (Louisville)", + "America\/Lower_Princes": "Tími á Atlantshafssvæðinu (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilíutími (Maceio)", + "America\/Managua": "Tími í miðhluta Bandaríkjanna og Kanada (Managua)", + "America\/Manaus": "Amasóntími (Manaus)", + "America\/Marigot": "Tími á Atlantshafssvæðinu (Marigot)", + "America\/Martinique": "Tími á Atlantshafssvæðinu (Martiník)", + "America\/Matamoros": "Tími í miðhluta Bandaríkjanna og Kanada (Matamoros)", + "America\/Mazatlan": "Kyrrahafstími í Mexíkó (Mazatlan)", + "America\/Mendoza": "Argentínutími (Mendoza)", + "America\/Menominee": "Tími í miðhluta Bandaríkjanna og Kanada (Menominee)", + "America\/Merida": "Tími í miðhluta Bandaríkjanna og Kanada (Merida)", + "America\/Metlakatla": "Tími í Alaska (Metlakatla)", + "America\/Mexico_City": "Tími í miðhluta Bandaríkjanna og Kanada (Mexíkóborg)", + "America\/Miquelon": "Tími á Sankti Pierre og Miquelon (Miquelon)", + "America\/Moncton": "Tími á Atlantshafssvæðinu (Moncton)", + "America\/Monterrey": "Tími í miðhluta Bandaríkjanna og Kanada (Monterrey)", + "America\/Montevideo": "Úrúgvætími (Montevideo)", + "America\/Montserrat": "Tími á Atlantshafssvæðinu (Montserrat)", + "America\/Nassau": "Tími í austurhluta Bandaríkjanna og Kanada (Nassau)", + "America\/New_York": "Tími í austurhluta Bandaríkjanna og Kanada (New York)", + "America\/Nipigon": "Tími í austurhluta Bandaríkjanna og Kanada (Nipigon)", + "America\/Nome": "Tími í Alaska (Nome)", + "America\/Noronha": "Tími í Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Tími í miðhluta Bandaríkjanna og Kanada (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Tími í miðhluta Bandaríkjanna og Kanada (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Tími í miðhluta Bandaríkjanna og Kanada (New Salem, North Dakota)", + "America\/Ojinaga": "Tími í Klettafjöllum (Ojinaga)", + "America\/Panama": "Tími í austurhluta Bandaríkjanna og Kanada (Panama)", + "America\/Pangnirtung": "Tími í austurhluta Bandaríkjanna og Kanada (Pangnirtung)", + "America\/Paramaribo": "Súrinamtími (Paramaribo)", + "America\/Phoenix": "Tími í Klettafjöllum (Phoenix)", + "America\/Port-au-Prince": "Tími í austurhluta Bandaríkjanna og Kanada (Port-au-Prince)", + "America\/Port_of_Spain": "Tími á Atlantshafssvæðinu (Port of Spain)", + "America\/Porto_Velho": "Amasóntími (Porto Velho)", + "America\/Puerto_Rico": "Tími á Atlantshafssvæðinu (Púertó Ríkó)", + "America\/Punta_Arenas": "Síletími (Punta Arenas)", + "America\/Rainy_River": "Tími í miðhluta Bandaríkjanna og Kanada (Rainy River)", + "America\/Rankin_Inlet": "Tími í miðhluta Bandaríkjanna og Kanada (Rankin Inlet)", + "America\/Recife": "Brasilíutími (Recife)", + "America\/Regina": "Tími í miðhluta Bandaríkjanna og Kanada (Regina)", + "America\/Resolute": "Tími í miðhluta Bandaríkjanna og Kanada (Resolute)", + "America\/Santa_Isabel": "Tími í Norðvestur-Mexíkó (Santa Isabel)", + "America\/Santarem": "Brasilíutími (Santarem)", + "America\/Santiago": "Síletími (Santiago)", + "America\/Santo_Domingo": "Tími á Atlantshafssvæðinu (Santo Domingo)", + "America\/Sao_Paulo": "Brasilíutími (Sao Paulo)", + "America\/Scoresbysund": "Austur-Grænlandstími (Ittoqqortoormiit)", + "America\/Sitka": "Tími í Alaska (Sitka)", + "America\/St_Barthelemy": "Tími á Atlantshafssvæðinu (Sankti Bartólómeusareyjar)", + "America\/St_Johns": "Tími á Nýfundnalandi (St. John’s)", + "America\/St_Kitts": "Tími á Atlantshafssvæðinu (Sankti Kitts)", + "America\/St_Lucia": "Tími á Atlantshafssvæðinu (Sankti Lúsía)", + "America\/St_Thomas": "Tími á Atlantshafssvæðinu (Sankti Thomas)", + "America\/St_Vincent": "Tími á Atlantshafssvæðinu (Sankti Vinsent)", + "America\/Swift_Current": "Tími í miðhluta Bandaríkjanna og Kanada (Swift Current)", + "America\/Tegucigalpa": "Tími í miðhluta Bandaríkjanna og Kanada (Tegucigalpa)", + "America\/Thule": "Tími á Atlantshafssvæðinu (Thule)", + "America\/Thunder_Bay": "Tími í austurhluta Bandaríkjanna og Kanada (Thunder Bay)", + "America\/Tijuana": "Tími á Kyrrahafssvæðinu (Tijuana)", + "America\/Toronto": "Tími í austurhluta Bandaríkjanna og Kanada (Toronto)", + "America\/Tortola": "Tími á Atlantshafssvæðinu (Tortóla)", + "America\/Vancouver": "Tími á Kyrrahafssvæðinu (Vancouver)", + "America\/Whitehorse": "Tími á Kyrrahafssvæðinu (Whitehorse)", + "America\/Winnipeg": "Tími í miðhluta Bandaríkjanna og Kanada (Winnipeg)", + "America\/Yakutat": "Tími í Alaska (Yakutat)", + "America\/Yellowknife": "Tími í Klettafjöllum (Yellowknife)", + "Antarctica\/Casey": "Tími í Vestur-Ástralíu (Casey)", + "Antarctica\/Davis": "Davis-tími (Davis)", + "Antarctica\/DumontDUrville": "Tími á Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie-eyjartími (Macquarie)", + "Antarctica\/Mawson": "Mawson-tími (Mawson)", + "Antarctica\/McMurdo": "Tími á Nýja-Sjálandi (McMurdo)", + "Antarctica\/Palmer": "Síletími (Palmer)", + "Antarctica\/Rothera": "Rothera-tími (Rothera)", + "Antarctica\/Syowa": "Syowa-tími (Syowa)", + "Antarctica\/Troll": "Greenwich-staðaltími (Troll)", + "Antarctica\/Vostok": "Vostok-tími (Vostok)", + "Arctic\/Longyearbyen": "Mið-Evróputími (Longyearbyen)", + "Asia\/Aden": "Arabíutími (Aden)", + "Asia\/Almaty": "Tími í Austur-Kasakstan (Almaty)", + "Asia\/Amman": "Austur-Evróputími (Amman)", + "Asia\/Anadyr": "Tími í Anadyr (Anadyr)", + "Asia\/Aqtau": "Tími í Vestur-Kasakstan (Aqtau)", + "Asia\/Aqtobe": "Tími í Vestur-Kasakstan (Aqtobe)", + "Asia\/Ashgabat": "Túrkmenistan-tími (Ashgabat)", + "Asia\/Atyrau": "Tími í Vestur-Kasakstan (Atyrau)", + "Asia\/Baghdad": "Arabíutími (Bagdad)", + "Asia\/Bahrain": "Arabíutími (Barein)", + "Asia\/Baku": "Aserbaídsjantími (Bakú)", + "Asia\/Bangkok": "Indókínatími (Bangkok)", + "Asia\/Beirut": "Austur-Evróputími (Beirút)", + "Asia\/Bishkek": "Kirgistan-tími (Bishkek)", + "Asia\/Brunei": "Brúneitími (Brúnei)", + "Asia\/Calcutta": "Indlandstími (Kalkútta)", + "Asia\/Chita": "Tíminn í Yakutsk (Chita)", + "Asia\/Choibalsan": "Tími í Choibalsan (Choibalsan)", + "Asia\/Colombo": "Indlandstími (Kólombó)", + "Asia\/Damascus": "Austur-Evróputími (Damaskus)", + "Asia\/Dhaka": "Bangladess-tími (Dakka)", + "Asia\/Dili": "Tíminn á Tímor-Leste (Dili)", + "Asia\/Dubai": "Staðaltími við Persaflóa (Dubai)", + "Asia\/Dushanbe": "Tadsjíkistan-tími (Dushanbe)", + "Asia\/Famagusta": "Austur-Evróputími (Famagusta)", + "Asia\/Gaza": "Austur-Evróputími (Gaza)", + "Asia\/Hebron": "Austur-Evróputími (Hebron)", + "Asia\/Hong_Kong": "Hong Kong-tími (Hong Kong)", + "Asia\/Hovd": "Hovd-tími (Hovd)", + "Asia\/Irkutsk": "Tími í Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Vestur-Indónesíutími (Djakarta)", + "Asia\/Jayapura": "Austur-Indónesíutími (Jayapura)", + "Asia\/Jerusalem": "Ísraelstími (Jerúsalem)", + "Asia\/Kabul": "Afganistantími (Kabúl)", + "Asia\/Kamchatka": "Tími í Petropavlovsk-Kamchatski (Kamtsjatka)", + "Asia\/Karachi": "Pakistantími (Karachi)", + "Asia\/Katmandu": "Nepaltími (Katmandú)", + "Asia\/Khandyga": "Tíminn í Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Tími í Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malasíutími (Kúala Lúmpúr)", + "Asia\/Kuching": "Malasíutími (Kuching)", + "Asia\/Kuwait": "Arabíutími (Kúveit)", + "Asia\/Macau": "Kínatími (Makaó)", + "Asia\/Magadan": "Tími í Magadan (Magadan)", + "Asia\/Makassar": "Mið-Indónesíutími (Makassar)", + "Asia\/Manila": "Filippseyjatími (Manila)", + "Asia\/Muscat": "Staðaltími við Persaflóa (Muscat)", + "Asia\/Nicosia": "Austur-Evróputími (Níkósía)", + "Asia\/Novokuznetsk": "Tími í Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Tími í Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Tíminn í Omsk (Omsk)", + "Asia\/Oral": "Tími í Vestur-Kasakstan (Oral)", + "Asia\/Phnom_Penh": "Indókínatími (Phnom Penh)", + "Asia\/Pontianak": "Vestur-Indónesíutími (Pontianak)", + "Asia\/Pyongyang": "Kóreutími (Pjongjang)", + "Asia\/Qatar": "Arabíutími (Katar)", + "Asia\/Qostanay": "Tími í Austur-Kasakstan (Kostanay)", + "Asia\/Qyzylorda": "Tími í Vestur-Kasakstan (Qyzylorda)", + "Asia\/Rangoon": "Mjanmar-tími (Rangún)", + "Asia\/Riyadh": "Arabíutími (Ríjad)", + "Asia\/Saigon": "Indókínatími (Ho Chi Minh-borg)", + "Asia\/Sakhalin": "Tími í Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Úsbekistan-tími (Samarkand)", + "Asia\/Seoul": "Kóreutími (Seúl)", + "Asia\/Shanghai": "Kínatími (Sjanghæ)", + "Asia\/Singapore": "Singapúrtími (Singapúr)", + "Asia\/Srednekolymsk": "Tími í Magadan (Srednekolymsk)", + "Asia\/Taipei": "Taipei-tími (Taipei)", + "Asia\/Tashkent": "Úsbekistan-tími (Tashkent)", + "Asia\/Tbilisi": "Georgíutími (Tbilisi)", + "Asia\/Tehran": "Íranstími (Teheran)", + "Asia\/Thimphu": "Bútantími (Thimphu)", + "Asia\/Tokyo": "Japanstími (Tókýó)", + "Asia\/Ulaanbaatar": "Tími í Úlan Bator (Úlan Bator)", + "Asia\/Ust-Nera": "Tími í Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Indókínatími (Vientiane)", + "Asia\/Vladivostok": "Tími í Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Tíminn í Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Tími í Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Armeníutími (Yerevan)", + "Atlantic\/Azores": "Asóreyjatími (Azoreyjar)", + "Atlantic\/Bermuda": "Tími á Atlantshafssvæðinu (Bermúda)", + "Atlantic\/Canary": "Vestur-Evróputími (Kanaríeyjar)", + "Atlantic\/Cape_Verde": "Grænhöfðaeyjatími (Grænhöfðaeyjar)", + "Atlantic\/Faeroe": "Vestur-Evróputími (Færeyjar)", + "Atlantic\/Madeira": "Vestur-Evróputími (Madeira)", + "Atlantic\/Reykjavik": "Greenwich-staðaltími (Reykjavík)", + "Atlantic\/South_Georgia": "Suður-Georgíutími (Suður-Georgía)", + "Atlantic\/St_Helena": "Greenwich-staðaltími (Sankti Helena)", + "Atlantic\/Stanley": "Falklandseyjatími (Stanley)", + "Australia\/Adelaide": "Tími í Mið-Ástralíu (Adelaide)", + "Australia\/Brisbane": "Tími í Austur-Ástralíu (Brisbane)", + "Australia\/Broken_Hill": "Tími í Mið-Ástralíu (Broken Hill)", + "Australia\/Currie": "Tími í Austur-Ástralíu (Currie)", + "Australia\/Darwin": "Tími í Mið-Ástralíu (Darwin)", + "Australia\/Eucla": "Tími í miðvesturhluta Ástralíu (Eucla)", + "Australia\/Hobart": "Tími í Austur-Ástralíu (Hobart)", + "Australia\/Lindeman": "Tími í Austur-Ástralíu (Lindeman)", + "Australia\/Lord_Howe": "Tími á Lord Howe-eyju (Lord Howe)", + "Australia\/Melbourne": "Tími í Austur-Ástralíu (Melbourne)", + "Australia\/Perth": "Tími í Vestur-Ástralíu (Perth)", + "Australia\/Sydney": "Tími í Austur-Ástralíu (Sydney)", + "CST6CDT": "Tími í miðhluta Bandaríkjanna og Kanada", + "EST5EDT": "Tími í austurhluta Bandaríkjanna og Kanada", + "Etc\/GMT": "Greenwich-staðaltími", + "Etc\/UTC": "Samræmdur alþjóðlegur tími", + "Europe\/Amsterdam": "Mið-Evróputími (Amsterdam)", + "Europe\/Andorra": "Mið-Evróputími (Andorra)", + "Europe\/Astrakhan": "Moskvutími (Astrakhan)", + "Europe\/Athens": "Austur-Evróputími (Aþena)", + "Europe\/Belgrade": "Mið-Evróputími (Belgrad)", + "Europe\/Berlin": "Mið-Evróputími (Berlín)", + "Europe\/Bratislava": "Mið-Evróputími (Bratislava)", + "Europe\/Brussels": "Mið-Evróputími (Brussel)", + "Europe\/Bucharest": "Austur-Evróputími (Búkarest)", + "Europe\/Budapest": "Mið-Evróputími (Búdapest)", + "Europe\/Busingen": "Mið-Evróputími (Busingen)", + "Europe\/Chisinau": "Austur-Evróputími (Chisinau)", + "Europe\/Copenhagen": "Mið-Evróputími (Kaupmannahöfn)", + "Europe\/Dublin": "Greenwich-staðaltími (Dublin)", + "Europe\/Gibraltar": "Mið-Evróputími (Gíbraltar)", + "Europe\/Guernsey": "Greenwich-staðaltími (Guernsey)", + "Europe\/Helsinki": "Austur-Evróputími (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich-staðaltími (Mön)", + "Europe\/Jersey": "Greenwich-staðaltími (Jersey)", + "Europe\/Kaliningrad": "Austur-Evróputími (Kaliningrad)", + "Europe\/Kiev": "Austur-Evróputími (Kænugarður)", + "Europe\/Lisbon": "Vestur-Evróputími (Lissabon)", + "Europe\/Ljubljana": "Mið-Evróputími (Ljubljana)", + "Europe\/London": "Greenwich-staðaltími (Lundúnir)", + "Europe\/Luxembourg": "Mið-Evróputími (Lúxemborg)", + "Europe\/Madrid": "Mið-Evróputími (Madríd)", + "Europe\/Malta": "Mið-Evróputími (Malta)", + "Europe\/Mariehamn": "Austur-Evróputími (Maríuhöfn)", + "Europe\/Minsk": "Moskvutími (Minsk)", + "Europe\/Monaco": "Mið-Evróputími (Mónakó)", + "Europe\/Moscow": "Moskvutími (Moskva)", + "Europe\/Oslo": "Mið-Evróputími (Osló)", + "Europe\/Paris": "Mið-Evróputími (París)", + "Europe\/Podgorica": "Mið-Evróputími (Podgorica)", + "Europe\/Prague": "Mið-Evróputími (Prag)", + "Europe\/Riga": "Austur-Evróputími (Riga)", + "Europe\/Rome": "Mið-Evróputími (Róm)", + "Europe\/Samara": "Tími í Samara (Samara)", + "Europe\/San_Marino": "Mið-Evróputími (San Marínó)", + "Europe\/Sarajevo": "Mið-Evróputími (Sarajevó)", + "Europe\/Saratov": "Moskvutími (Saratov)", + "Europe\/Simferopol": "Moskvutími (Simferopol)", + "Europe\/Skopje": "Mið-Evróputími (Skopje)", + "Europe\/Sofia": "Austur-Evróputími (Sófía)", + "Europe\/Stockholm": "Mið-Evróputími (Stokkhólmur)", + "Europe\/Tallinn": "Austur-Evróputími (Tallinn)", + "Europe\/Tirane": "Mið-Evróputími (Tirane)", + "Europe\/Ulyanovsk": "Moskvutími (Ulyanovsk)", + "Europe\/Uzhgorod": "Austur-Evróputími (Uzhgorod)", + "Europe\/Vaduz": "Mið-Evróputími (Vaduz)", + "Europe\/Vatican": "Mið-Evróputími (Vatíkanið)", + "Europe\/Vienna": "Mið-Evróputími (Vín)", + "Europe\/Vilnius": "Austur-Evróputími (Vilníus)", + "Europe\/Volgograd": "Tími í Volgograd (Volgograd)", + "Europe\/Warsaw": "Mið-Evróputími (Varsjá)", + "Europe\/Zagreb": "Mið-Evróputími (Zagreb)", + "Europe\/Zaporozhye": "Austur-Evróputími (Zaporozhye)", + "Europe\/Zurich": "Mið-Evróputími (Zurich)", + "Indian\/Antananarivo": "Austur-Afríkutími (Antananarivo)", + "Indian\/Chagos": "Indlandshafstími (Chagos)", + "Indian\/Christmas": "Jólaeyjartími (Jólaey)", + "Indian\/Cocos": "Kókoseyjatími (Kókoseyjar)", + "Indian\/Comoro": "Austur-Afríkutími (Comoro)", + "Indian\/Kerguelen": "Tími á frönsku suðurhafssvæðum og Suðurskautslandssvæði (Kerguelen)", + "Indian\/Mahe": "Seychelles-eyjatími (Mahe)", + "Indian\/Maldives": "Maldíveyja-tími (Maldíveyjar)", + "Indian\/Mauritius": "Máritíustími (Máritíus)", + "Indian\/Mayotte": "Austur-Afríkutími (Mayotte)", + "Indian\/Reunion": "Réunion-tími (Réunion)", + "MST7MDT": "Tími í Klettafjöllum", + "PST8PDT": "Tími á Kyrrahafssvæðinu", + "Pacific\/Apia": "Tími í Apía (Apia)", + "Pacific\/Auckland": "Tími á Nýja-Sjálandi (Auckland)", + "Pacific\/Bougainville": "Tími á Papúa Nýju-Gíneu (Bougainville)", + "Pacific\/Chatham": "Chatham-tími (Chatham)", + "Pacific\/Easter": "Páskaeyjutími (Páskaeyja)", + "Pacific\/Efate": "Vanúatú-tími (Efate)", + "Pacific\/Enderbury": "Fönixeyjatími (Enderbury)", + "Pacific\/Fakaofo": "Tókelá-tími (Fakaofo)", + "Pacific\/Fiji": "Fídjíeyjatími (Fidjí)", + "Pacific\/Funafuti": "Túvalútími (Funafuti)", + "Pacific\/Galapagos": "Galapagos-tími (Galapagos)", + "Pacific\/Gambier": "Gambier-tími (Gambier)", + "Pacific\/Guadalcanal": "Salómonseyjatími (Guadalcanal)", + "Pacific\/Guam": "Chamorro-staðaltími (Gvam)", + "Pacific\/Honolulu": "Tími á Havaí og Aleúta (Honolulu)", + "Pacific\/Johnston": "Tími á Havaí og Aleúta (Johnston)", + "Pacific\/Kiritimati": "Línueyja-tími (Kiritimati)", + "Pacific\/Kosrae": "Kosrae-tími (Kosrae)", + "Pacific\/Kwajalein": "Tími á Marshall-eyjum (Kwajalein)", + "Pacific\/Majuro": "Tími á Marshall-eyjum (Majuro)", + "Pacific\/Marquesas": "Tími á Markgreifafrúreyjum (Marquesas-eyjar)", + "Pacific\/Midway": "Samóa-tími (Midway)", + "Pacific\/Nauru": "Nárú-tími (Nárú)", + "Pacific\/Niue": "Niue-tími (Niue)", + "Pacific\/Norfolk": "Tími á Norfolk-eyju (Norfolk)", + "Pacific\/Noumea": "Tími í Nýju-Kaledóníu (Noumea)", + "Pacific\/Pago_Pago": "Samóa-tími (Pago Pago)", + "Pacific\/Palau": "Palátími (Palá)", + "Pacific\/Pitcairn": "Pitcairn-tími (Pitcairn)", + "Pacific\/Ponape": "Ponape-tími (Pohnpei)", + "Pacific\/Port_Moresby": "Tími á Papúa Nýju-Gíneu (Port Moresby)", + "Pacific\/Rarotonga": "Cooks-eyjatími (Rarotonga)", + "Pacific\/Saipan": "Chamorro-staðaltími (Saipan)", + "Pacific\/Tahiti": "Tahítí-tími (Tahítí)", + "Pacific\/Tarawa": "Tími á Gilbert-eyjum (Tarawa)", + "Pacific\/Tongatapu": "Tongatími (Tongatapu)", + "Pacific\/Truk": "Chuuk-tími (Chuuk)", + "Pacific\/Wake": "Tími á Wake-eyju (Wake)", + "Pacific\/Wallis": "Tími á Wallis- og Fútúnaeyjum (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/it.json b/src/Symfony/Component/Intl/Resources/data/timezones/it.json new file mode 100644 index 0000000000000..10557b89c0034 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/it.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Ora del meridiano di Greenwich (Abidjan)", + "Africa\/Accra": "Ora del meridiano di Greenwich (Accra)", + "Africa\/Addis_Ababa": "Ora dell’Africa orientale (Addis Abeba)", + "Africa\/Algiers": "Ora dell’Europa centrale (Algeri)", + "Africa\/Asmera": "Ora dell’Africa orientale (Asmara)", + "Africa\/Bamako": "Ora del meridiano di Greenwich (Bamako)", + "Africa\/Bangui": "Ora dell’Africa occidentale (Bangui)", + "Africa\/Banjul": "Ora del meridiano di Greenwich (Banjul)", + "Africa\/Bissau": "Ora del meridiano di Greenwich (Bissau)", + "Africa\/Blantyre": "Ora dell’Africa centrale (Blantyre)", + "Africa\/Brazzaville": "Ora dell’Africa occidentale (Brazzaville)", + "Africa\/Bujumbura": "Ora dell’Africa centrale (Bujumbura)", + "Africa\/Cairo": "Ora dell’Europa orientale (Il Cairo)", + "Africa\/Casablanca": "Ora dell’Europa occidentale (Casablanca)", + "Africa\/Ceuta": "Ora dell’Europa centrale (Ceuta)", + "Africa\/Conakry": "Ora del meridiano di Greenwich (Conakry)", + "Africa\/Dakar": "Ora del meridiano di Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Ora dell’Africa orientale (Dar es Salaam)", + "Africa\/Djibouti": "Ora dell’Africa orientale (Gibuti)", + "Africa\/Douala": "Ora dell’Africa occidentale (Douala)", + "Africa\/El_Aaiun": "Ora dell’Europa occidentale (El Ayun)", + "Africa\/Freetown": "Ora del meridiano di Greenwich (Freetown)", + "Africa\/Gaborone": "Ora dell’Africa centrale (Gaborone)", + "Africa\/Harare": "Ora dell’Africa centrale (Harare)", + "Africa\/Johannesburg": "Ora dell’Africa meridionale (Johannesburg)", + "Africa\/Juba": "Ora dell’Africa orientale (Giuba)", + "Africa\/Kampala": "Ora dell’Africa orientale (Kampala)", + "Africa\/Khartoum": "Ora dell’Africa centrale (Khartum)", + "Africa\/Kigali": "Ora dell’Africa centrale (Kigali)", + "Africa\/Kinshasa": "Ora dell’Africa occidentale (Kinshasa)", + "Africa\/Lagos": "Ora dell’Africa occidentale (Lagos)", + "Africa\/Libreville": "Ora dell’Africa occidentale (Libreville)", + "Africa\/Lome": "Ora del meridiano di Greenwich (Lomé)", + "Africa\/Luanda": "Ora dell’Africa occidentale (Luanda)", + "Africa\/Lubumbashi": "Ora dell’Africa centrale (Lubumbashi)", + "Africa\/Lusaka": "Ora dell’Africa centrale (Lusaka)", + "Africa\/Malabo": "Ora dell’Africa occidentale (Malabo)", + "Africa\/Maputo": "Ora dell’Africa centrale (Maputo)", + "Africa\/Maseru": "Ora dell’Africa meridionale (Maseru)", + "Africa\/Mbabane": "Ora dell’Africa meridionale (Mbabane)", + "Africa\/Mogadishu": "Ora dell’Africa orientale (Mogadiscio)", + "Africa\/Monrovia": "Ora del meridiano di Greenwich (Monrovia)", + "Africa\/Nairobi": "Ora dell’Africa orientale (Nairobi)", + "Africa\/Ndjamena": "Ora dell’Africa occidentale (N’Djamena)", + "Africa\/Niamey": "Ora dell’Africa occidentale (Niamey)", + "Africa\/Nouakchott": "Ora del meridiano di Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Ora del meridiano di Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Ora dell’Africa occidentale (Porto-Novo)", + "Africa\/Sao_Tome": "Ora del meridiano di Greenwich (São Tomé)", + "Africa\/Tripoli": "Ora dell’Europa orientale (Tripoli)", + "Africa\/Tunis": "Ora dell’Europa centrale (Tunisi)", + "Africa\/Windhoek": "Ora dell’Africa centrale (Windhoek)", + "America\/Adak": "Ora delle isole Hawaii-Aleutine (Adak)", + "America\/Anchorage": "Ora dell’Alaska (Anchorage)", + "America\/Anguilla": "Ora dell’Atlantico (Anguilla)", + "America\/Antigua": "Ora dell’Atlantico (Antigua)", + "America\/Araguaina": "Ora di Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "Ora dell’Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Ora dell’Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Ora dell’Argentina (Salta)", + "America\/Argentina\/San_Juan": "Ora dell’Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Ora dell’Argentina occidentale (San Luis)", + "America\/Argentina\/Tucuman": "Ora dell’Argentina (Tucumán)", + "America\/Argentina\/Ushuaia": "Ora dell’Argentina (Ushuaia)", + "America\/Aruba": "Ora dell’Atlantico (Aruba)", + "America\/Asuncion": "Ora del Paraguay (Asunción)", + "America\/Bahia": "Ora di Brasilia (Bahia)", + "America\/Bahia_Banderas": "Ora centrale USA (Bahía de Banderas)", + "America\/Barbados": "Ora dell’Atlantico (Barbados)", + "America\/Belem": "Ora di Brasilia (Belem)", + "America\/Belize": "Ora centrale USA (Belize)", + "America\/Blanc-Sablon": "Ora dell’Atlantico (Blanc-Sablon)", + "America\/Boa_Vista": "Ora dell’Amazzonia (Boa Vista)", + "America\/Bogota": "Ora della Colombia (Bogotá)", + "America\/Boise": "Ora Montagne Rocciose USA (Boise)", + "America\/Buenos_Aires": "Ora dell’Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Ora Montagne Rocciose USA (Cambridge Bay)", + "America\/Campo_Grande": "Ora dell’Amazzonia (Campo Grande)", + "America\/Cancun": "Ora orientale USA (Cancún)", + "America\/Caracas": "Ora del Venezuela (Caracas)", + "America\/Catamarca": "Ora dell’Argentina (Catamarca)", + "America\/Cayenne": "Ora della Guiana francese (Caienna)", + "America\/Cayman": "Ora orientale USA (Cayman)", + "America\/Chicago": "Ora centrale USA (Chicago)", + "America\/Chihuahua": "Ora del Pacifico (Messico) (Chihuahua)", + "America\/Coral_Harbour": "Ora orientale USA (Atikokan)", + "America\/Cordoba": "Ora dell’Argentina (Cordoba)", + "America\/Costa_Rica": "Ora centrale USA (Costa Rica)", + "America\/Creston": "Ora Montagne Rocciose USA (Creston)", + "America\/Cuiaba": "Ora dell’Amazzonia (Cuiaba)", + "America\/Curacao": "Ora dell’Atlantico (Curaçao)", + "America\/Danmarkshavn": "Ora del meridiano di Greenwich (Danmarkshavn)", + "America\/Dawson": "Ora del Pacifico USA (Dawson)", + "America\/Dawson_Creek": "Ora Montagne Rocciose USA (Dawson Creek)", + "America\/Denver": "Ora Montagne Rocciose USA (Denver)", + "America\/Detroit": "Ora orientale USA (Detroit)", + "America\/Dominica": "Ora dell’Atlantico (Dominica)", + "America\/Edmonton": "Ora Montagne Rocciose USA (Edmonton)", + "America\/El_Salvador": "Ora centrale USA (El Salvador)", + "America\/Fort_Nelson": "Ora Montagne Rocciose USA (Fort Nelson)", + "America\/Fortaleza": "Ora di Brasilia (Fortaleza)", + "America\/Glace_Bay": "Ora dell’Atlantico (Glace Bay)", + "America\/Godthab": "Ora della Groenlandia occidentale (Nuuk)", + "America\/Goose_Bay": "Ora dell’Atlantico (Goose Bay)", + "America\/Grand_Turk": "Ora orientale USA (Grand Turk)", + "America\/Grenada": "Ora dell’Atlantico (Grenada)", + "America\/Guadeloupe": "Ora dell’Atlantico (Guadalupa)", + "America\/Guatemala": "Ora centrale USA (Guatemala)", + "America\/Guayaquil": "Ora dell’Ecuador (Guayaquil)", + "America\/Guyana": "Ora della Guyana (Guyana)", + "America\/Halifax": "Ora dell’Atlantico (Halifax)", + "America\/Havana": "Ora di Cuba (L’Avana)", + "America\/Hermosillo": "Ora del Pacifico (Messico) (Hermosillo)", + "America\/Indiana\/Knox": "Ora centrale USA (Knox, Indiana)", + "America\/Indiana\/Marengo": "Ora orientale USA (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Ora orientale USA (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Ora centrale USA (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Ora orientale USA (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Ora orientale USA (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Ora orientale USA (Winamac, Indiana)", + "America\/Indianapolis": "Ora orientale USA (Indianapolis)", + "America\/Inuvik": "Ora Montagne Rocciose USA (Inuvik)", + "America\/Iqaluit": "Ora orientale USA (Iqaluit)", + "America\/Jamaica": "Ora orientale USA (Giamaica)", + "America\/Jujuy": "Ora dell’Argentina (Jujuy)", + "America\/Juneau": "Ora dell’Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Ora orientale USA (Monticello, Kentucky)", + "America\/Kralendijk": "Ora dell’Atlantico (Kralendijk)", + "America\/La_Paz": "Ora della Bolivia (La Paz)", + "America\/Lima": "Ora del Perù (Lima)", + "America\/Los_Angeles": "Ora del Pacifico USA (Los Angeles)", + "America\/Louisville": "Ora orientale USA (Louisville)", + "America\/Lower_Princes": "Ora dell’Atlantico (Lower Prince’s Quarter)", + "America\/Maceio": "Ora di Brasilia (Maceio)", + "America\/Managua": "Ora centrale USA (Managua)", + "America\/Manaus": "Ora dell’Amazzonia (Manaus)", + "America\/Marigot": "Ora dell’Atlantico (Marigot)", + "America\/Martinique": "Ora dell’Atlantico (Martinica)", + "America\/Matamoros": "Ora centrale USA (Matamoros)", + "America\/Mazatlan": "Ora del Pacifico (Messico) (Mazatlan)", + "America\/Mendoza": "Ora dell’Argentina (Mendoza)", + "America\/Menominee": "Ora centrale USA (Menominee)", + "America\/Merida": "Ora centrale USA (Mérida)", + "America\/Metlakatla": "Ora dell’Alaska (Metlakatla)", + "America\/Mexico_City": "Ora centrale USA (Città del Messico)", + "America\/Miquelon": "Ora di Saint-Pierre e Miquelon (Miquelon)", + "America\/Moncton": "Ora dell’Atlantico (Moncton)", + "America\/Monterrey": "Ora centrale USA (Monterrey)", + "America\/Montevideo": "Ora dell’Uruguay (Montevideo)", + "America\/Montserrat": "Ora dell’Atlantico (Montserrat)", + "America\/Nassau": "Ora orientale USA (Nassau)", + "America\/New_York": "Ora orientale USA (New York)", + "America\/Nipigon": "Ora orientale USA (Nipigon)", + "America\/Nome": "Ora dell’Alaska (Nome)", + "America\/Noronha": "Ora di Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Ora centrale USA (Beulah, Dakota del nord)", + "America\/North_Dakota\/Center": "Ora centrale USA (Center, Dakota del nord)", + "America\/North_Dakota\/New_Salem": "Ora centrale USA (New Salem, Dakota del nord)", + "America\/Ojinaga": "Ora Montagne Rocciose USA (Ojinaga)", + "America\/Panama": "Ora orientale USA (Panamá)", + "America\/Pangnirtung": "Ora orientale USA (Pangnirtung)", + "America\/Paramaribo": "Ora del Suriname (Paramaribo)", + "America\/Phoenix": "Ora Montagne Rocciose USA (Phoenix)", + "America\/Port-au-Prince": "Ora orientale USA (Port-au-Prince)", + "America\/Port_of_Spain": "Ora dell’Atlantico (Port of Spain)", + "America\/Porto_Velho": "Ora dell’Amazzonia (Porto Velho)", + "America\/Puerto_Rico": "Ora dell’Atlantico (Portorico)", + "America\/Punta_Arenas": "Ora del Cile (Punta Arenas)", + "America\/Rainy_River": "Ora centrale USA (Rainy River)", + "America\/Rankin_Inlet": "Ora centrale USA (Rankin Inlet)", + "America\/Recife": "Ora di Brasilia (Recife)", + "America\/Regina": "Ora centrale USA (Regina)", + "America\/Resolute": "Ora centrale USA (Resolute)", + "America\/Santa_Isabel": "Ora del Messico nord-occidentale (Santa Isabel)", + "America\/Santarem": "Ora di Brasilia (Santarém)", + "America\/Santiago": "Ora del Cile (Santiago)", + "America\/Santo_Domingo": "Ora dell’Atlantico (Santo Domingo)", + "America\/Sao_Paulo": "Ora di Brasilia (San Paolo)", + "America\/Scoresbysund": "Ora della Groenlandia orientale (Ittoqqortoormiit)", + "America\/Sitka": "Ora dell’Alaska (Sitka)", + "America\/St_Barthelemy": "Ora dell’Atlantico (Saint-Barthélemy)", + "America\/St_Johns": "Ora di Terranova (St. John’s)", + "America\/St_Kitts": "Ora dell’Atlantico (St. Kitts)", + "America\/St_Lucia": "Ora dell’Atlantico (Santa Lucia)", + "America\/St_Thomas": "Ora dell’Atlantico (Saint Thomas)", + "America\/St_Vincent": "Ora dell’Atlantico (Saint Vincent)", + "America\/Swift_Current": "Ora centrale USA (Swift Current)", + "America\/Tegucigalpa": "Ora centrale USA (Tegucigalpa)", + "America\/Thule": "Ora dell’Atlantico (Thule)", + "America\/Thunder_Bay": "Ora orientale USA (Thunder Bay)", + "America\/Tijuana": "Ora del Pacifico USA (Tijuana)", + "America\/Toronto": "Ora orientale USA (Toronto)", + "America\/Tortola": "Ora dell’Atlantico (Tortola)", + "America\/Vancouver": "Ora del Pacifico USA (Vancouver)", + "America\/Whitehorse": "Ora del Pacifico USA (Whitehorse)", + "America\/Winnipeg": "Ora centrale USA (Winnipeg)", + "America\/Yakutat": "Ora dell’Alaska (Yakutat)", + "America\/Yellowknife": "Ora Montagne Rocciose USA (Yellowknife)", + "Antarctica\/Casey": "Ora dell’Australia occidentale (Casey)", + "Antarctica\/Davis": "Ora di Davis (Davis)", + "Antarctica\/DumontDUrville": "Ora di Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Ora dell’Isola Macquarie (Macquarie)", + "Antarctica\/Mawson": "Ora di Mawson (Mawson)", + "Antarctica\/McMurdo": "Ora della Nuova Zelanda (McMurdo)", + "Antarctica\/Palmer": "Ora del Cile (Palmer)", + "Antarctica\/Rothera": "Ora di Rothera (Rothera)", + "Antarctica\/Syowa": "Ora di Syowa (Syowa)", + "Antarctica\/Troll": "Ora del meridiano di Greenwich (Troll)", + "Antarctica\/Vostok": "Ora di Vostok (Vostok)", + "Arctic\/Longyearbyen": "Ora dell’Europa centrale (Longyearbyen)", + "Asia\/Aden": "Ora araba (Aden)", + "Asia\/Almaty": "Ora del Kazakistan orientale (Almaty)", + "Asia\/Amman": "Ora dell’Europa orientale (Amman)", + "Asia\/Anadyr": "Ora di Anadyr (Anadyr’)", + "Asia\/Aqtau": "Ora del Kazakistan occidentale (Aqtau)", + "Asia\/Aqtobe": "Ora del Kazakistan occidentale (Aqtöbe)", + "Asia\/Ashgabat": "Ora del Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Ora del Kazakistan occidentale (Atyrau)", + "Asia\/Baghdad": "Ora araba (Baghdad)", + "Asia\/Bahrain": "Ora araba (Bahrein)", + "Asia\/Baku": "Ora dell’Azerbaigian (Baku)", + "Asia\/Bangkok": "Ora dell’Indocina (Bangkok)", + "Asia\/Beirut": "Ora dell’Europa orientale (Beirut)", + "Asia\/Bishkek": "Ora del Kirghizistan (Bishkek)", + "Asia\/Brunei": "Ora del Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Ora standard dell’India (Calcutta)", + "Asia\/Chita": "Ora di Yakutsk (Čita)", + "Asia\/Choibalsan": "Ora di Choibalsan (Choibalsan)", + "Asia\/Colombo": "Ora standard dell’India (Colombo)", + "Asia\/Damascus": "Ora dell’Europa orientale (Damasco)", + "Asia\/Dhaka": "Ora del Bangladesh (Dacca)", + "Asia\/Dili": "Ora di Timor Est (Dili)", + "Asia\/Dubai": "Ora del Golfo (Dubai)", + "Asia\/Dushanbe": "Ora del Tagikistan (Dushanbe)", + "Asia\/Famagusta": "Ora dell’Europa orientale (Famagosta)", + "Asia\/Gaza": "Ora dell’Europa orientale (Gaza)", + "Asia\/Hebron": "Ora dell’Europa orientale (Hebron)", + "Asia\/Hong_Kong": "Ora di Hong Kong (Hong Kong)", + "Asia\/Hovd": "Ora di Hovd (Hovd)", + "Asia\/Irkutsk": "Ora di Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Ora dell’Indonesia occidentale (Giacarta)", + "Asia\/Jayapura": "Ora dell’Indonesia orientale (Jayapura)", + "Asia\/Jerusalem": "Ora di Israele (Gerusalemme)", + "Asia\/Kabul": "Ora dell’Afghanistan (Kabul)", + "Asia\/Kamchatka": "Ora di Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Ora del Pakistan (Karachi)", + "Asia\/Katmandu": "Ora del Nepal (Kathmandu)", + "Asia\/Khandyga": "Ora di Yakutsk (Chandyga)", + "Asia\/Krasnoyarsk": "Ora di Krasnoyarsk (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Ora della Malesia (Kuala Lumpur)", + "Asia\/Kuching": "Ora della Malesia (Kuching)", + "Asia\/Kuwait": "Ora araba (Kuwait)", + "Asia\/Macau": "Ora della Cina (Macao)", + "Asia\/Magadan": "Ora di Magadan (Magadan)", + "Asia\/Makassar": "Ora dell’Indonesia centrale (Makassar)", + "Asia\/Manila": "Ora delle Filippine (Manila)", + "Asia\/Muscat": "Ora del Golfo (Mascate)", + "Asia\/Nicosia": "Ora dell’Europa orientale (Nicosia)", + "Asia\/Novokuznetsk": "Ora di Krasnoyarsk (Novokuzneck)", + "Asia\/Novosibirsk": "Ora di Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Ora di Omsk (Omsk)", + "Asia\/Oral": "Ora del Kazakistan occidentale (Oral)", + "Asia\/Phnom_Penh": "Ora dell’Indocina (Phnom Penh)", + "Asia\/Pontianak": "Ora dell’Indonesia occidentale (Pontianak)", + "Asia\/Pyongyang": "Ora coreana (Pyongyang)", + "Asia\/Qatar": "Ora araba (Qatar)", + "Asia\/Qostanay": "Ora del Kazakistan orientale (Qostanay)", + "Asia\/Qyzylorda": "Ora del Kazakistan occidentale (Qyzylorda)", + "Asia\/Rangoon": "Ora della Birmania (Rangoon)", + "Asia\/Riyadh": "Ora araba (Riyad)", + "Asia\/Saigon": "Ora dell’Indocina (Ho Chi Minh)", + "Asia\/Sakhalin": "Ora di Sakhalin (Sachalin)", + "Asia\/Samarkand": "Ora dell’Uzbekistan (Samarcanda)", + "Asia\/Seoul": "Ora coreana (Seul)", + "Asia\/Shanghai": "Ora della Cina (Shanghai)", + "Asia\/Singapore": "Ora di Singapore (Singapore)", + "Asia\/Srednekolymsk": "Ora di Magadan (Srednekolymsk)", + "Asia\/Taipei": "Ora di Taipei (Taipei)", + "Asia\/Tashkent": "Ora dell’Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Ora della Georgia (Tbilisi)", + "Asia\/Tehran": "Ora dell’Iran (Teheran)", + "Asia\/Thimphu": "Ora del Bhutan (Thimphu)", + "Asia\/Tokyo": "Ora del Giappone (Tokyo)", + "Asia\/Ulaanbaatar": "Ora di Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Ora di Vladivostok (Ust’-Nera)", + "Asia\/Vientiane": "Ora dell’Indocina (Vientiane)", + "Asia\/Vladivostok": "Ora di Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Ora di Yakutsk (Jakutsk)", + "Asia\/Yekaterinburg": "Ora di Ekaterinburg (Ekaterinburg)", + "Asia\/Yerevan": "Ora dell’Armenia (Yerevan)", + "Atlantic\/Azores": "Ora delle Azzorre (Azzorre)", + "Atlantic\/Bermuda": "Ora dell’Atlantico (Bermuda)", + "Atlantic\/Canary": "Ora dell’Europa occidentale (Canarie)", + "Atlantic\/Cape_Verde": "Ora di Capo Verde (Capo Verde)", + "Atlantic\/Faeroe": "Ora dell’Europa occidentale (Isole Fær Øer)", + "Atlantic\/Madeira": "Ora dell’Europa occidentale (Madeira)", + "Atlantic\/Reykjavik": "Ora del meridiano di Greenwich (Reykjavík)", + "Atlantic\/South_Georgia": "Ora della Georgia del Sud (Georgia del Sud)", + "Atlantic\/St_Helena": "Ora del meridiano di Greenwich (Sant’Elena)", + "Atlantic\/Stanley": "Ora delle Isole Falkland (Stanley)", + "Australia\/Adelaide": "Ora dell’Australia centrale (Adelaide)", + "Australia\/Brisbane": "Ora dell’Australia orientale (Brisbane)", + "Australia\/Broken_Hill": "Ora dell’Australia centrale (Broken Hill)", + "Australia\/Currie": "Ora dell’Australia orientale (Currie)", + "Australia\/Darwin": "Ora dell’Australia centrale (Darwin)", + "Australia\/Eucla": "Ora dell’Australia centroccidentale (Eucla)", + "Australia\/Hobart": "Ora dell’Australia orientale (Hobart)", + "Australia\/Lindeman": "Ora dell’Australia orientale (Lindeman)", + "Australia\/Lord_Howe": "Ora di Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Ora dell’Australia orientale (Melbourne)", + "Australia\/Perth": "Ora dell’Australia occidentale (Perth)", + "Australia\/Sydney": "Ora dell’Australia orientale (Sydney)", + "CST6CDT": "Ora centrale USA", + "EST5EDT": "Ora orientale USA", + "Etc\/GMT": "Ora del meridiano di Greenwich", + "Etc\/UTC": "Tempo coordinato universale", + "Europe\/Amsterdam": "Ora dell’Europa centrale (Amsterdam)", + "Europe\/Andorra": "Ora dell’Europa centrale (Andorra)", + "Europe\/Astrakhan": "Ora di Mosca (Astrakhan)", + "Europe\/Athens": "Ora dell’Europa orientale (Atene)", + "Europe\/Belgrade": "Ora dell’Europa centrale (Belgrado)", + "Europe\/Berlin": "Ora dell’Europa centrale (Berlino)", + "Europe\/Bratislava": "Ora dell’Europa centrale (Bratislava)", + "Europe\/Brussels": "Ora dell’Europa centrale (Bruxelles)", + "Europe\/Bucharest": "Ora dell’Europa orientale (Bucarest)", + "Europe\/Budapest": "Ora dell’Europa centrale (Budapest)", + "Europe\/Busingen": "Ora dell’Europa centrale (Büsingen)", + "Europe\/Chisinau": "Ora dell’Europa orientale (Chisinau)", + "Europe\/Copenhagen": "Ora dell’Europa centrale (Copenaghen)", + "Europe\/Dublin": "Ora del meridiano di Greenwich (Dublino)", + "Europe\/Gibraltar": "Ora dell’Europa centrale (Gibilterra)", + "Europe\/Guernsey": "Ora del meridiano di Greenwich (Guernsey)", + "Europe\/Helsinki": "Ora dell’Europa orientale (Helsinki)", + "Europe\/Isle_of_Man": "Ora del meridiano di Greenwich (Isola di Man)", + "Europe\/Jersey": "Ora del meridiano di Greenwich (Jersey)", + "Europe\/Kaliningrad": "Ora dell’Europa orientale (Kaliningrad)", + "Europe\/Kiev": "Ora dell’Europa orientale (Kiev)", + "Europe\/Lisbon": "Ora dell’Europa occidentale (Lisbona)", + "Europe\/Ljubljana": "Ora dell’Europa centrale (Lubiana)", + "Europe\/London": "Ora del meridiano di Greenwich (Londra)", + "Europe\/Luxembourg": "Ora dell’Europa centrale (Lussemburgo)", + "Europe\/Madrid": "Ora dell’Europa centrale (Madrid)", + "Europe\/Malta": "Ora dell’Europa centrale (Malta)", + "Europe\/Mariehamn": "Ora dell’Europa orientale (Mariehamn)", + "Europe\/Minsk": "Ora di Mosca (Minsk)", + "Europe\/Monaco": "Ora dell’Europa centrale (Monaco)", + "Europe\/Moscow": "Ora di Mosca (Mosca)", + "Europe\/Oslo": "Ora dell’Europa centrale (Oslo)", + "Europe\/Paris": "Ora dell’Europa centrale (Parigi)", + "Europe\/Podgorica": "Ora dell’Europa centrale (Podgorica)", + "Europe\/Prague": "Ora dell’Europa centrale (Praga)", + "Europe\/Riga": "Ora dell’Europa orientale (Riga)", + "Europe\/Rome": "Ora dell’Europa centrale (Roma)", + "Europe\/Samara": "Ora di Samara (Samara)", + "Europe\/San_Marino": "Ora dell’Europa centrale (San Marino)", + "Europe\/Sarajevo": "Ora dell’Europa centrale (Sarajevo)", + "Europe\/Saratov": "Ora di Mosca (Saratov)", + "Europe\/Simferopol": "Ora di Mosca (Sinferopoli)", + "Europe\/Skopje": "Ora dell’Europa centrale (Skopje)", + "Europe\/Sofia": "Ora dell’Europa orientale (Sofia)", + "Europe\/Stockholm": "Ora dell’Europa centrale (Stoccolma)", + "Europe\/Tallinn": "Ora dell’Europa orientale (Tallinn)", + "Europe\/Tirane": "Ora dell’Europa centrale (Tirana)", + "Europe\/Ulyanovsk": "Ora di Mosca (Ulyanovsk)", + "Europe\/Uzhgorod": "Ora dell’Europa orientale (Užhorod)", + "Europe\/Vaduz": "Ora dell’Europa centrale (Vaduz)", + "Europe\/Vatican": "Ora dell’Europa centrale (Città del Vaticano)", + "Europe\/Vienna": "Ora dell’Europa centrale (Vienna)", + "Europe\/Vilnius": "Ora dell’Europa orientale (Vilnius)", + "Europe\/Volgograd": "Ora di Volgograd (Volgograd)", + "Europe\/Warsaw": "Ora dell’Europa centrale (Varsavia)", + "Europe\/Zagreb": "Ora dell’Europa centrale (Zagabria)", + "Europe\/Zaporozhye": "Ora dell’Europa orientale (Zaporozhye)", + "Europe\/Zurich": "Ora dell’Europa centrale (Zurigo)", + "Indian\/Antananarivo": "Ora dell’Africa orientale (Antananarivo)", + "Indian\/Chagos": "Ora dell’Oceano Indiano (Chagos)", + "Indian\/Christmas": "Ora dell’Isola Christmas (Natale)", + "Indian\/Cocos": "Ora delle Isole Cocos (Cocos)", + "Indian\/Comoro": "Ora dell’Africa orientale (Comore)", + "Indian\/Kerguelen": "Ora delle Terre australi e antartiche francesi (Kerguelen)", + "Indian\/Mahe": "Ora delle Seychelles (Mahe)", + "Indian\/Maldives": "Ora delle Maldive (Maldive)", + "Indian\/Mauritius": "Ora delle Mauritius (Mauritius)", + "Indian\/Mayotte": "Ora dell’Africa orientale (Mayotte)", + "Indian\/Reunion": "Ora di Riunione (La Riunione)", + "MST7MDT": "Ora Montagne Rocciose USA", + "PST8PDT": "Ora del Pacifico USA", + "Pacific\/Apia": "Ora di Apia (Apia)", + "Pacific\/Auckland": "Ora della Nuova Zelanda (Auckland)", + "Pacific\/Bougainville": "Ora della Papua Nuova Guinea (Bougainville)", + "Pacific\/Chatham": "Ora delle Chatham (Chatham)", + "Pacific\/Easter": "Ora dell’Isola di Pasqua (Pasqua)", + "Pacific\/Efate": "Ora del Vanuatu (Efate)", + "Pacific\/Enderbury": "Ora delle Isole della Fenice (Enderbury)", + "Pacific\/Fakaofo": "Ora di Tokelau (Fakaofo)", + "Pacific\/Fiji": "Ora delle Figi (Figi)", + "Pacific\/Funafuti": "Ora di Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Ora delle Galapagos (Galapagos)", + "Pacific\/Gambier": "Ora di Gambier (Gambier)", + "Pacific\/Guadalcanal": "Ora delle Isole Salomone (Guadalcanal)", + "Pacific\/Guam": "Ora di Chamorro (Guam)", + "Pacific\/Honolulu": "Ora delle isole Hawaii-Aleutine (Honolulu)", + "Pacific\/Johnston": "Ora delle isole Hawaii-Aleutine (Johnston)", + "Pacific\/Kiritimati": "Ora delle Sporadi equatoriali (Kiritimati)", + "Pacific\/Kosrae": "Ora del Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Ora delle Isole Marshall (Kwajalein)", + "Pacific\/Majuro": "Ora delle Isole Marshall (Majuro)", + "Pacific\/Marquesas": "Ora delle Marchesi (Marchesi)", + "Pacific\/Midway": "Ora di Samoa (Midway)", + "Pacific\/Nauru": "Ora di Nauru (Nauru)", + "Pacific\/Niue": "Ora di Niue (Niue)", + "Pacific\/Norfolk": "Ora delle Isole Norfolk (Norfolk)", + "Pacific\/Noumea": "Ora della Nuova Caledonia (Noumea)", + "Pacific\/Pago_Pago": "Ora di Samoa (Pago Pago)", + "Pacific\/Palau": "Ora di Palau (Palau)", + "Pacific\/Pitcairn": "Ora delle Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Ora di Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "Ora della Papua Nuova Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Ora delle isole Cook (Rarotonga)", + "Pacific\/Saipan": "Ora di Chamorro (Saipan)", + "Pacific\/Tahiti": "Ora di Tahiti (Tahiti)", + "Pacific\/Tarawa": "Ora delle isole Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Ora di Tonga (Tongatapu)", + "Pacific\/Truk": "Ora del Chuuk (Chuuk)", + "Pacific\/Wake": "Ora dell’Isola di Wake (Wake)", + "Pacific\/Wallis": "Ora di Wallis e Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/iw.json b/src/Symfony/Component/Intl/Resources/data/timezones/iw.json new file mode 100644 index 0000000000000..14d0630bdef5d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/iw.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "שעון גריניץ׳‏ (אביג׳אן)", + "Africa\/Accra": "שעון גריניץ׳‏ (אקרה)", + "Africa\/Addis_Ababa": "שעון מזרח אפריקה (אדיס אבבה)", + "Africa\/Algiers": "שעון מרכז אירופה (אלג׳יר)", + "Africa\/Asmera": "שעון מזרח אפריקה (אסמרה)", + "Africa\/Bamako": "שעון גריניץ׳‏ (במאקו)", + "Africa\/Bangui": "שעון מערב אפריקה (בנגואי)", + "Africa\/Banjul": "שעון גריניץ׳‏ (בנג׳ול)", + "Africa\/Bissau": "שעון גריניץ׳‏ (ביסאו)", + "Africa\/Blantyre": "שעון מרכז אפריקה (בלנטיר)", + "Africa\/Brazzaville": "שעון מערב אפריקה (ברזוויל)", + "Africa\/Bujumbura": "שעון מרכז אפריקה (בוג׳ומבורה)", + "Africa\/Cairo": "שעון מזרח אירופה (קהיר)", + "Africa\/Casablanca": "שעון מערב אירופה (קזבלנקה)", + "Africa\/Ceuta": "שעון מרכז אירופה (סאוטה)", + "Africa\/Conakry": "שעון גריניץ׳‏ (קונאקרי)", + "Africa\/Dakar": "שעון גריניץ׳‏ (דקאר)", + "Africa\/Dar_es_Salaam": "שעון מזרח אפריקה (דאר א-סלאם)", + "Africa\/Djibouti": "שעון מזרח אפריקה (ג׳יבוטי)", + "Africa\/Douala": "שעון מערב אפריקה (דואלה)", + "Africa\/El_Aaiun": "שעון מערב אירופה (אל עיון)", + "Africa\/Freetown": "שעון גריניץ׳‏ (פריטאון)", + "Africa\/Gaborone": "שעון מרכז אפריקה (גבורונה)", + "Africa\/Harare": "שעון מרכז אפריקה (הרארה)", + "Africa\/Johannesburg": "שעון דרום אפריקה (יוהנסבורג)", + "Africa\/Juba": "שעון מזרח אפריקה (ג׳ובה)", + "Africa\/Kampala": "שעון מזרח אפריקה (קמפאלה)", + "Africa\/Khartoum": "שעון מרכז אפריקה (חרטום)", + "Africa\/Kigali": "שעון מרכז אפריקה (קיגלי)", + "Africa\/Kinshasa": "שעון מערב אפריקה (קינשסה)", + "Africa\/Lagos": "שעון מערב אפריקה (לגוס)", + "Africa\/Libreville": "שעון מערב אפריקה (ליברוויל)", + "Africa\/Lome": "שעון גריניץ׳‏ (לומה)", + "Africa\/Luanda": "שעון מערב אפריקה (לואנדה)", + "Africa\/Lubumbashi": "שעון מרכז אפריקה (לובומבאשי)", + "Africa\/Lusaka": "שעון מרכז אפריקה (לוסקה)", + "Africa\/Malabo": "שעון מערב אפריקה (מלבו)", + "Africa\/Maputo": "שעון מרכז אפריקה (מאפוטו)", + "Africa\/Maseru": "שעון דרום אפריקה (מסרו)", + "Africa\/Mbabane": "שעון דרום אפריקה (מבבנה)", + "Africa\/Mogadishu": "שעון מזרח אפריקה (מוגדישו)", + "Africa\/Monrovia": "שעון גריניץ׳‏ (מונרוביה)", + "Africa\/Nairobi": "שעון מזרח אפריקה (ניירובי)", + "Africa\/Ndjamena": "שעון מערב אפריקה (נג׳מנה)", + "Africa\/Niamey": "שעון מערב אפריקה (ניאמיי)", + "Africa\/Nouakchott": "שעון גריניץ׳‏ (נואקצ׳וט)", + "Africa\/Ouagadougou": "שעון גריניץ׳‏ (וואגאדוגו)", + "Africa\/Porto-Novo": "שעון מערב אפריקה (פורטו נובו)", + "Africa\/Sao_Tome": "שעון גריניץ׳‏ (סאו טומה)", + "Africa\/Tripoli": "שעון מזרח אירופה (טריפולי)", + "Africa\/Tunis": "שעון מרכז אירופה (תוניס)", + "Africa\/Windhoek": "שעון מרכז אפריקה (וינדהוק)", + "America\/Adak": "שעון האיים האלאוטיים הוואי (אדאק)", + "America\/Anchorage": "שעון אלסקה (אנקורג׳)", + "America\/Anguilla": "שעון האוקיינוס האטלנטי (אנגווילה)", + "America\/Antigua": "שעון האוקיינוס האטלנטי (אנטיגואה)", + "America\/Araguaina": "שעון ברזיליה (אראגואינה)", + "America\/Argentina\/La_Rioja": "שעון ארגנטינה (לה ריוחה)", + "America\/Argentina\/Rio_Gallegos": "שעון ארגנטינה (ריו גאייגוס)", + "America\/Argentina\/Salta": "שעון ארגנטינה (סלטה)", + "America\/Argentina\/San_Juan": "שעון ארגנטינה (סן חואן)", + "America\/Argentina\/San_Luis": "שעון מערב ארגנטינה (סן לואיס)", + "America\/Argentina\/Tucuman": "שעון ארגנטינה (טוקומן)", + "America\/Argentina\/Ushuaia": "שעון ארגנטינה (אושוואיה)", + "America\/Aruba": "שעון האוקיינוס האטלנטי (ארובה)", + "America\/Asuncion": "שעון פרגוואי (אסונסיון)", + "America\/Bahia": "שעון ברזיליה (באהיה)", + "America\/Bahia_Banderas": "שעון מרכז ארה״ב (באהיה בנדרס)", + "America\/Barbados": "שעון האוקיינוס האטלנטי (ברבדוס)", + "America\/Belem": "שעון ברזיליה (בלם)", + "America\/Belize": "שעון מרכז ארה״ב (בליז)", + "America\/Blanc-Sablon": "שעון האוקיינוס האטלנטי (בלאן-סבלון)", + "America\/Boa_Vista": "שעון אמזונס (בואה ויסטה)", + "America\/Bogota": "שעון קולומביה (בוגוטה)", + "America\/Boise": "שעון אזור ההרים בארה״ב (בויסי)", + "America\/Buenos_Aires": "שעון ארגנטינה (בואנוס איירס)", + "America\/Cambridge_Bay": "שעון אזור ההרים בארה״ב (קיימברידג׳ ביי)", + "America\/Campo_Grande": "שעון אמזונס (קמפו גרנדה)", + "America\/Cancun": "שעון החוף המזרחי (קנקון)", + "America\/Caracas": "שעון ונצואלה (קראקס)", + "America\/Catamarca": "שעון ארגנטינה (קטמרקה)", + "America\/Cayenne": "שעון גיאנה הצרפתית (קאיין)", + "America\/Cayman": "שעון החוף המזרחי (קיימן)", + "America\/Chicago": "שעון מרכז ארה״ב (שיקגו)", + "America\/Chihuahua": "שעון מערב מקסיקו (צ׳יוואווה)", + "America\/Coral_Harbour": "שעון החוף המזרחי (אטיקוקן)", + "America\/Cordoba": "שעון ארגנטינה (קורדובה)", + "America\/Costa_Rica": "שעון מרכז ארה״ב (קוסטה ריקה)", + "America\/Creston": "שעון אזור ההרים בארה״ב (קרסטון)", + "America\/Cuiaba": "שעון אמזונס (קויאבה)", + "America\/Curacao": "שעון האוקיינוס האטלנטי (קוראסאו)", + "America\/Danmarkshavn": "שעון גריניץ׳‏ (דנמרקסהוון)", + "America\/Dawson": "שעון מערב ארה״ב (דוסון)", + "America\/Dawson_Creek": "שעון אזור ההרים בארה״ב (דוסון קריק)", + "America\/Denver": "שעון אזור ההרים בארה״ב (דנוור)", + "America\/Detroit": "שעון החוף המזרחי (דטרויט)", + "America\/Dominica": "שעון האוקיינוס האטלנטי (דומיניקה)", + "America\/Edmonton": "שעון אזור ההרים בארה״ב (אדמונטון)", + "America\/El_Salvador": "שעון מרכז ארה״ב (אל סלבדור)", + "America\/Fort_Nelson": "שעון אזור ההרים בארה״ב (פורט נלסון)", + "America\/Fortaleza": "שעון ברזיליה (פורטאלזה)", + "America\/Glace_Bay": "שעון האוקיינוס האטלנטי (גלייס ביי)", + "America\/Godthab": "שעון מערב גרינלנד (נואוק)", + "America\/Goose_Bay": "שעון האוקיינוס האטלנטי (גוס ביי)", + "America\/Grand_Turk": "שעון החוף המזרחי (גרנד טורק)", + "America\/Grenada": "שעון האוקיינוס האטלנטי (גרנדה)", + "America\/Guadeloupe": "שעון האוקיינוס האטלנטי (גואדלופ)", + "America\/Guatemala": "שעון מרכז ארה״ב (גואטמלה)", + "America\/Guayaquil": "שעון אקוודור (גואיאקיל)", + "America\/Guyana": "שעון גיאנה (גיאנה)", + "America\/Halifax": "שעון האוקיינוס האטלנטי (הליפקס)", + "America\/Havana": "שעון קובה (הוואנה)", + "America\/Hermosillo": "שעון מערב מקסיקו (הרמוסיו)", + "America\/Indiana\/Knox": "שעון מרכז ארה״ב (נוקס, אינדיאנה)", + "America\/Indiana\/Marengo": "שעון החוף המזרחי (מרנגו, אינדיאנה)", + "America\/Indiana\/Petersburg": "שעון החוף המזרחי (פיטרסבורג, אינדיאנה)", + "America\/Indiana\/Tell_City": "שעון מרכז ארה״ב (טל סיטי, אינדיאנה)", + "America\/Indiana\/Vevay": "שעון החוף המזרחי (ויוואיי, אינדיאנה)", + "America\/Indiana\/Vincennes": "שעון החוף המזרחי (וינסנס, אינדיאנה)", + "America\/Indiana\/Winamac": "שעון החוף המזרחי (וינמאק, אינדיאנה)", + "America\/Indianapolis": "שעון החוף המזרחי (אינדיאנפוליס)", + "America\/Inuvik": "שעון אזור ההרים בארה״ב (אינוויק)", + "America\/Iqaluit": "שעון החוף המזרחי (איקלואיט)", + "America\/Jamaica": "שעון החוף המזרחי (ג׳מייקה)", + "America\/Jujuy": "שעון ארגנטינה (חוחוי)", + "America\/Juneau": "שעון אלסקה (ג׳ונו)", + "America\/Kentucky\/Monticello": "שעון החוף המזרחי (מונטיצ׳לו, קנטאקי)", + "America\/Kralendijk": "שעון האוקיינוס האטלנטי (קרלנדייק)", + "America\/La_Paz": "שעון בוליביה (לה פאס)", + "America\/Lima": "שעון פרו (לימה)", + "America\/Los_Angeles": "שעון מערב ארה״ב (לוס אנג׳לס)", + "America\/Louisville": "שעון החוף המזרחי (לואיוויל)", + "America\/Lower_Princes": "שעון האוקיינוס האטלנטי (לואוור פרינסס קוורטר)", + "America\/Maceio": "שעון ברזיליה (מסייאו)", + "America\/Managua": "שעון מרכז ארה״ב (מנגואה)", + "America\/Manaus": "שעון אמזונס (מנאוס)", + "America\/Marigot": "שעון האוקיינוס האטלנטי (מריגו)", + "America\/Martinique": "שעון האוקיינוס האטלנטי (מרטיניק)", + "America\/Matamoros": "שעון מרכז ארה״ב (מטמורוס)", + "America\/Mazatlan": "שעון מערב מקסיקו (מזטלן)", + "America\/Mendoza": "שעון ארגנטינה (מנדוזה)", + "America\/Menominee": "שעון מרכז ארה״ב (מנומיני)", + "America\/Merida": "שעון מרכז ארה״ב (מרידה)", + "America\/Metlakatla": "שעון אלסקה (מטלקטלה)", + "America\/Mexico_City": "שעון מרכז ארה״ב (מקסיקו סיטי)", + "America\/Miquelon": "שעון סנט פייר ומיקלון (מיקלון)", + "America\/Moncton": "שעון האוקיינוס האטלנטי (מונקטון)", + "America\/Monterrey": "שעון מרכז ארה״ב (מונטריי)", + "America\/Montevideo": "שעון אורוגוואי (מונטווידאו)", + "America\/Montserrat": "שעון האוקיינוס האטלנטי (מונסראט)", + "America\/Nassau": "שעון החוף המזרחי (נסאו)", + "America\/New_York": "שעון החוף המזרחי (ניו יורק)", + "America\/Nipigon": "שעון החוף המזרחי (ניפיגון)", + "America\/Nome": "שעון אלסקה (נום)", + "America\/Noronha": "שעון פרננדו די נורוניה (נורוניה)", + "America\/North_Dakota\/Beulah": "שעון מרכז ארה״ב (ביולה, צפון דקוטה)", + "America\/North_Dakota\/Center": "שעון מרכז ארה״ב (סנטר, צפון דקוטה)", + "America\/North_Dakota\/New_Salem": "שעון מרכז ארה״ב (ניו סיילם, צפון דקוטה)", + "America\/Ojinaga": "שעון אזור ההרים בארה״ב (אוג׳ינאגה)", + "America\/Panama": "שעון החוף המזרחי (פנמה)", + "America\/Pangnirtung": "שעון החוף המזרחי (פנגנירטונג)", + "America\/Paramaribo": "שעון סורינאם (פרמריבו)", + "America\/Phoenix": "שעון אזור ההרים בארה״ב (פיניקס)", + "America\/Port-au-Prince": "שעון החוף המזרחי (פורט או פראנס)", + "America\/Port_of_Spain": "שעון האוקיינוס האטלנטי (פורט אוף ספיין)", + "America\/Porto_Velho": "שעון אמזונס (פורטו וליו)", + "America\/Puerto_Rico": "שעון האוקיינוס האטלנטי (פוארטו ריקו)", + "America\/Punta_Arenas": "שעון צ׳ילה (פונטה ארנס)", + "America\/Rainy_River": "שעון מרכז ארה״ב (רייני ריבר)", + "America\/Rankin_Inlet": "שעון מרכז ארה״ב (רנקין אינלט)", + "America\/Recife": "שעון ברזיליה (רסיפה)", + "America\/Regina": "שעון מרכז ארה״ב (רג׳ינה)", + "America\/Resolute": "שעון מרכז ארה״ב (רזולוט)", + "America\/Santa_Isabel": "שעון צפון-מערב מקסיקו (סנטה איזבל)", + "America\/Santarem": "שעון ברזיליה (סנטרם)", + "America\/Santiago": "שעון צ׳ילה (סנטיאגו)", + "America\/Santo_Domingo": "שעון האוקיינוס האטלנטי (סנטו דומינגו)", + "America\/Sao_Paulo": "שעון ברזיליה (סאו פאולו)", + "America\/Scoresbysund": "שעון מזרח גרינלנד (סקורסביסונד)", + "America\/Sitka": "שעון אלסקה (סיטקה)", + "America\/St_Barthelemy": "שעון האוקיינוס האטלנטי (סנט ברתלמי)", + "America\/St_Johns": "שעון ניופאונדלנד (סנט ג׳ונס)", + "America\/St_Kitts": "שעון האוקיינוס האטלנטי (סנט קיטס)", + "America\/St_Lucia": "שעון האוקיינוס האטלנטי (סנט לוסיה)", + "America\/St_Thomas": "שעון האוקיינוס האטלנטי (סנט תומאס)", + "America\/St_Vincent": "שעון האוקיינוס האטלנטי (סנט וינסנט)", + "America\/Swift_Current": "שעון מרכז ארה״ב (סוויפט קרנט)", + "America\/Tegucigalpa": "שעון מרכז ארה״ב (טגוסיגלפה)", + "America\/Thule": "שעון האוקיינוס האטלנטי (תולה)", + "America\/Thunder_Bay": "שעון החוף המזרחי (ת׳אנדר ביי)", + "America\/Tijuana": "שעון מערב ארה״ב (טיחואנה)", + "America\/Toronto": "שעון החוף המזרחי (טורונטו)", + "America\/Tortola": "שעון האוקיינוס האטלנטי (טורטולה)", + "America\/Vancouver": "שעון מערב ארה״ב (ונקובר)", + "America\/Whitehorse": "שעון מערב ארה״ב (ווייטהורס)", + "America\/Winnipeg": "שעון מרכז ארה״ב (וויניפג)", + "America\/Yakutat": "שעון אלסקה (יקוטאט)", + "America\/Yellowknife": "שעון אזור ההרים בארה״ב (ילונייף)", + "Antarctica\/Casey": "שעון מערב אוסטרליה (קאסיי)", + "Antarctica\/Davis": "שעון דיוויס (דיוויס)", + "Antarctica\/DumontDUrville": "שעון דומון ד׳אורוויל (דומון ד׳אורוויל)", + "Antarctica\/Macquarie": "שעון מקווארי (מקרי)", + "Antarctica\/Mawson": "שעון מאוסון (מוסון)", + "Antarctica\/McMurdo": "שעון ניו זילנד (מק-מרדו)", + "Antarctica\/Palmer": "שעון צ׳ילה (פאלמר)", + "Antarctica\/Rothera": "שעון רות׳רה (רות׳רה)", + "Antarctica\/Syowa": "שעון סייווה (סיוואה)", + "Antarctica\/Troll": "שעון גריניץ׳‏ (טרול)", + "Antarctica\/Vostok": "שעון ווסטוק (ווסטוק)", + "Arctic\/Longyearbyen": "שעון מרכז אירופה (לונגיירבין)", + "Asia\/Aden": "שעון חצי האי ערב (עדן)", + "Asia\/Almaty": "שעון מזרח קזחסטן (אלמאטי)", + "Asia\/Amman": "שעון מזרח אירופה (עמאן)", + "Asia\/Anadyr": "שעון אנדיר (אנדיר)", + "Asia\/Aqtau": "שעון מערב קזחסטן (אקטאו)", + "Asia\/Aqtobe": "שעון מערב קזחסטן (אקטובה)", + "Asia\/Ashgabat": "שעון טורקמניסטן (אשגבט)", + "Asia\/Atyrau": "שעון מערב קזחסטן (אטיראו)", + "Asia\/Baghdad": "שעון חצי האי ערב (בגדד)", + "Asia\/Bahrain": "שעון חצי האי ערב (בחריין)", + "Asia\/Baku": "שעון אזרבייג׳אן (באקו)", + "Asia\/Bangkok": "שעון הודו-סין (בנגקוק)", + "Asia\/Beirut": "שעון מזרח אירופה (ביירות)", + "Asia\/Bishkek": "שעון קירגיזסטן (בישקק)", + "Asia\/Brunei": "שעון ברוניי דארוסלאם (ברוניי)", + "Asia\/Calcutta": "שעון הודו (קולקטה)", + "Asia\/Chita": "שעון יקוטסק (צ׳יטה)", + "Asia\/Choibalsan": "שעון צ׳ויבלסן (צ׳ויבלסן)", + "Asia\/Colombo": "שעון הודו (קולומבו)", + "Asia\/Damascus": "שעון מזרח אירופה (דמשק)", + "Asia\/Dhaka": "שעון בנגלדש (דאקה)", + "Asia\/Dili": "שעון מזרח טימור (דילי)", + "Asia\/Dubai": "שעון מדינות המפרץ (דובאי)", + "Asia\/Dushanbe": "שעון טג׳יקיסטן (דושנבה)", + "Asia\/Famagusta": "שעון מזרח אירופה (פמגוסטה)", + "Asia\/Gaza": "שעון מזרח אירופה (עזה)", + "Asia\/Hebron": "שעון מזרח אירופה (חברון)", + "Asia\/Hong_Kong": "שעון הונג קונג (הונג קונג)", + "Asia\/Hovd": "שעון חובד (חובד)", + "Asia\/Irkutsk": "שעון אירקוטסק (אירקוטסק)", + "Asia\/Jakarta": "שעון מערב אינדונזיה (ג׳קרטה)", + "Asia\/Jayapura": "שעון מזרח אינדונזיה (ג׳איאפורה)", + "Asia\/Jerusalem": "שעון ישראל (ירושלים)", + "Asia\/Kabul": "שעון אפגניסטן (קאבול)", + "Asia\/Kamchatka": "שעון פטרופבלובסק-קמצ׳טסקי (קמצ׳טקה)", + "Asia\/Karachi": "שעון פקיסטן (קראצ׳י)", + "Asia\/Katmandu": "שעון נפאל (קטמנדו)", + "Asia\/Khandyga": "שעון יקוטסק (חנדיגה)", + "Asia\/Krasnoyarsk": "שעון קרסנויארסק (קרסנויארסק)", + "Asia\/Kuala_Lumpur": "שעון מלזיה (קואלה לומפור)", + "Asia\/Kuching": "שעון מלזיה (קוצ׳ינג)", + "Asia\/Kuwait": "שעון חצי האי ערב (כווית)", + "Asia\/Macau": "שעון סין (מקאו)", + "Asia\/Magadan": "שעון מגדן (מגדן)", + "Asia\/Makassar": "שעון מרכז אינדונזיה (מאקאסאר)", + "Asia\/Manila": "שעון הפיליפינים (מנילה)", + "Asia\/Muscat": "שעון מדינות המפרץ (מוסקט)", + "Asia\/Nicosia": "שעון מזרח אירופה (ניקוסיה)", + "Asia\/Novokuznetsk": "שעון קרסנויארסק (נובוקוזנטסק)", + "Asia\/Novosibirsk": "שעון נובוסיבירסק (נובוסיבירסק)", + "Asia\/Omsk": "שעון אומסק (אומסק)", + "Asia\/Oral": "שעון מערב קזחסטן (אורל)", + "Asia\/Phnom_Penh": "שעון הודו-סין (פנום פן)", + "Asia\/Pontianak": "שעון מערב אינדונזיה (פונטיאנק)", + "Asia\/Pyongyang": "שעון קוריאה (פיונגיאנג)", + "Asia\/Qatar": "שעון חצי האי ערב (קטאר)", + "Asia\/Qostanay": "שעון מזרח קזחסטן (קוסטנאי)", + "Asia\/Qyzylorda": "שעון מערב קזחסטן (קיזילורדה)", + "Asia\/Rangoon": "שעון מיאנמר (רנגון)", + "Asia\/Riyadh": "שעון חצי האי ערב (ריאד)", + "Asia\/Saigon": "שעון הודו-סין (הו צ׳י מין סיטי)", + "Asia\/Sakhalin": "שעון סחלין (סחלין)", + "Asia\/Samarkand": "שעון אוזבקיסטן (סמרקנד)", + "Asia\/Seoul": "שעון קוריאה (סיאול)", + "Asia\/Shanghai": "שעון סין (שנחאי)", + "Asia\/Singapore": "שעון סינגפור (סינגפור)", + "Asia\/Srednekolymsk": "שעון מגדן (סרדנייקולימסק)", + "Asia\/Taipei": "שעון טאיפיי (טאיפיי)", + "Asia\/Tashkent": "שעון אוזבקיסטן (טשקנט)", + "Asia\/Tbilisi": "שעון גאורגיה (טביליסי)", + "Asia\/Tehran": "שעון איראן (טהרן)", + "Asia\/Thimphu": "שעון בהוטן (טהימפהו)", + "Asia\/Tokyo": "שעון יפן (טוקיו)", + "Asia\/Ulaanbaatar": "שעון אולן בטור (אולאאנבטאר)", + "Asia\/Ust-Nera": "שעון ולדיווסטוק (אוסט-נרה)", + "Asia\/Vientiane": "שעון הודו-סין (האנוי)", + "Asia\/Vladivostok": "שעון ולדיווסטוק (ולדיווסטוק)", + "Asia\/Yakutsk": "שעון יקוטסק (יקוטסק)", + "Asia\/Yekaterinburg": "שעון יקטרינבורג (יקטרינבורג)", + "Asia\/Yerevan": "שעון ארמניה (ירוואן)", + "Atlantic\/Azores": "שעון האיים האזוריים (האיים האזוריים)", + "Atlantic\/Bermuda": "שעון האוקיינוס האטלנטי (ברמודה)", + "Atlantic\/Canary": "שעון מערב אירופה (האיים הקנריים)", + "Atlantic\/Cape_Verde": "שעון כף ורדה (כף ורדה)", + "Atlantic\/Faeroe": "שעון מערב אירופה (פארו)", + "Atlantic\/Madeira": "שעון מערב אירופה (מדיירה)", + "Atlantic\/Reykjavik": "שעון גריניץ׳‏ (רייקיאוויק)", + "Atlantic\/South_Georgia": "שעון דרום ג׳ורג׳יה (דרום ג׳ורג׳יה)", + "Atlantic\/St_Helena": "שעון גריניץ׳‏ (סנט הלנה)", + "Atlantic\/Stanley": "שעון איי פוקלנד (סטנלי)", + "Australia\/Adelaide": "שעון מרכז אוסטרליה (אדלייד)", + "Australia\/Brisbane": "שעון מזרח אוסטרליה (בריסביין)", + "Australia\/Broken_Hill": "שעון מרכז אוסטרליה (ברוקן היל)", + "Australia\/Currie": "שעון מזרח אוסטרליה (קרי)", + "Australia\/Darwin": "שעון מרכז אוסטרליה (דרווין)", + "Australia\/Eucla": "שעון מרכז-מערב אוסטרליה (יוקלה)", + "Australia\/Hobart": "שעון מזרח אוסטרליה (הוברט)", + "Australia\/Lindeman": "שעון מזרח אוסטרליה (לינדמן)", + "Australia\/Lord_Howe": "שעון אי הלורד האו (אי הלורד האו)", + "Australia\/Melbourne": "שעון מזרח אוסטרליה (מלבורן)", + "Australia\/Perth": "שעון מערב אוסטרליה (פרת׳)", + "Australia\/Sydney": "שעון מזרח אוסטרליה (סידני)", + "CST6CDT": "שעון מרכז ארה״ב", + "EST5EDT": "שעון החוף המזרחי", + "Etc\/GMT": "שעון גריניץ׳‏", + "Etc\/UTC": "זמן אוניברסלי מתואם", + "Europe\/Amsterdam": "שעון מרכז אירופה (אמסטרדם)", + "Europe\/Andorra": "שעון מרכז אירופה (אנדורה)", + "Europe\/Astrakhan": "שעון מוסקבה (אסטרחן)", + "Europe\/Athens": "שעון מזרח אירופה (אתונה)", + "Europe\/Belgrade": "שעון מרכז אירופה (בלגרד)", + "Europe\/Berlin": "שעון מרכז אירופה (ברלין)", + "Europe\/Bratislava": "שעון מרכז אירופה (ברטיסלבה)", + "Europe\/Brussels": "שעון מרכז אירופה (בריסל)", + "Europe\/Bucharest": "שעון מזרח אירופה (בוקרשט)", + "Europe\/Budapest": "שעון מרכז אירופה (בודפשט)", + "Europe\/Busingen": "שעון מרכז אירופה (ביזינגן)", + "Europe\/Chisinau": "שעון מזרח אירופה (קישינב)", + "Europe\/Copenhagen": "שעון מרכז אירופה (קופנהגן)", + "Europe\/Dublin": "שעון גריניץ׳‏ (דבלין)", + "Europe\/Gibraltar": "שעון מרכז אירופה (גיברלטר)", + "Europe\/Guernsey": "שעון גריניץ׳‏ (גרנזי)", + "Europe\/Helsinki": "שעון מזרח אירופה (הלסינקי)", + "Europe\/Isle_of_Man": "שעון גריניץ׳‏ (האי מאן)", + "Europe\/Jersey": "שעון גריניץ׳‏ (ג׳רזי)", + "Europe\/Kaliningrad": "שעון מזרח אירופה (קלינינגרד)", + "Europe\/Kiev": "שעון מזרח אירופה (קייב)", + "Europe\/Lisbon": "שעון מערב אירופה (ליסבון)", + "Europe\/Ljubljana": "שעון מרכז אירופה (לובליאנה)", + "Europe\/London": "שעון גריניץ׳‏ (לונדון)", + "Europe\/Luxembourg": "שעון מרכז אירופה (לוקסמבורג)", + "Europe\/Madrid": "שעון מרכז אירופה (מדריד)", + "Europe\/Malta": "שעון מרכז אירופה (מלטה)", + "Europe\/Mariehamn": "שעון מזרח אירופה (מרייהאמן)", + "Europe\/Minsk": "שעון מוסקבה (מינסק)", + "Europe\/Monaco": "שעון מרכז אירופה (מונקו)", + "Europe\/Moscow": "שעון מוסקבה (מוסקבה)", + "Europe\/Oslo": "שעון מרכז אירופה (אוסלו)", + "Europe\/Paris": "שעון מרכז אירופה (פריז)", + "Europe\/Podgorica": "שעון מרכז אירופה (פודגוריצה)", + "Europe\/Prague": "שעון מרכז אירופה (פראג)", + "Europe\/Riga": "שעון מזרח אירופה (ריגה)", + "Europe\/Rome": "שעון מרכז אירופה (רומא)", + "Europe\/Samara": "שעון סמרה (סמרה)", + "Europe\/San_Marino": "שעון מרכז אירופה (סן מרינו)", + "Europe\/Sarajevo": "שעון מרכז אירופה (סרייבו)", + "Europe\/Saratov": "שעון מוסקבה (סראטוב)", + "Europe\/Simferopol": "שעון מוסקבה (סימפרופול)", + "Europe\/Skopje": "שעון מרכז אירופה (סקופיה)", + "Europe\/Sofia": "שעון מזרח אירופה (סופיה)", + "Europe\/Stockholm": "שעון מרכז אירופה (שטוקהולם)", + "Europe\/Tallinn": "שעון מזרח אירופה (טאלין)", + "Europe\/Tirane": "שעון מרכז אירופה (טירנה)", + "Europe\/Ulyanovsk": "שעון מוסקבה (אוליאנובסק)", + "Europe\/Uzhgorod": "שעון מזרח אירופה (אוז׳הורוד)", + "Europe\/Vaduz": "שעון מרכז אירופה (ואדוץ)", + "Europe\/Vatican": "שעון מרכז אירופה (הוותיקן)", + "Europe\/Vienna": "שעון מרכז אירופה (וינה)", + "Europe\/Vilnius": "שעון מזרח אירופה (וילנה)", + "Europe\/Volgograd": "שעון וולגוגרד (וולגוגרד)", + "Europe\/Warsaw": "שעון מרכז אירופה (ורשה)", + "Europe\/Zagreb": "שעון מרכז אירופה (זאגרב)", + "Europe\/Zaporozhye": "שעון מזרח אירופה (זפורוז׳יה)", + "Europe\/Zurich": "שעון מרכז אירופה (ציריך)", + "Indian\/Antananarivo": "שעון מזרח אפריקה (אנטננריבו)", + "Indian\/Chagos": "שעון האוקיינוס ההודי (צ׳אגוס)", + "Indian\/Christmas": "שעון האי כריסטמס (האי כריסטמס)", + "Indian\/Cocos": "שעון איי קוקוס (קוקוס)", + "Indian\/Comoro": "שעון מזרח אפריקה (קומורו)", + "Indian\/Kerguelen": "שעון הארצות הדרומיות והאנטארקטיות של צרפת (קרגוולן)", + "Indian\/Mahe": "שעון איי סיישל (מהא)", + "Indian\/Maldives": "שעון האיים המלדיביים (האיים המלדיביים)", + "Indian\/Mauritius": "שעון מאוריציוס (מאוריציוס)", + "Indian\/Mayotte": "שעון מזרח אפריקה (מאיוט)", + "Indian\/Reunion": "שעון ראוניון (ראוניון)", + "MST7MDT": "שעון אזור ההרים בארה״ב", + "PST8PDT": "שעון מערב ארה״ב", + "Pacific\/Apia": "שעון אפיה (אפיה)", + "Pacific\/Auckland": "שעון ניו זילנד (אוקלנד)", + "Pacific\/Bougainville": "שעון פפואה גיניאה החדשה (בוגנוויל)", + "Pacific\/Chatham": "שעון צ׳טהאם (צ׳אטהאם)", + "Pacific\/Easter": "שעון אי הפסחא (אי הפסחא)", + "Pacific\/Efate": "שעון ונואטו (אפטה)", + "Pacific\/Enderbury": "שעון איי פיניקס (אנדרבורי)", + "Pacific\/Fakaofo": "שעון טוקלאו (פקאופו)", + "Pacific\/Fiji": "שעון פיג׳י (פיג׳י)", + "Pacific\/Funafuti": "שעון טובאלו (פונפוטי)", + "Pacific\/Galapagos": "שעון איי גלאפגוס (גלפאגוס)", + "Pacific\/Gambier": "שעון איי גמבייה (איי גמבייה)", + "Pacific\/Guadalcanal": "שעון איי שלמה (גוודלקנאל)", + "Pacific\/Guam": "שעון צ׳אמורו (גואם)", + "Pacific\/Honolulu": "שעון האיים האלאוטיים הוואי (הונולולו)", + "Pacific\/Johnston": "שעון האיים האלאוטיים הוואי (ג׳ונסטון)", + "Pacific\/Kiritimati": "שעון איי ליין (קיריטימאטי)", + "Pacific\/Kosrae": "שעון קוסראה (קוסרה)", + "Pacific\/Kwajalein": "שעון איי מרשל (קוואג׳ליין)", + "Pacific\/Majuro": "שעון איי מרשל (מאג׳ורו)", + "Pacific\/Marquesas": "שעון איי מרקיז (איי מרקיז)", + "Pacific\/Midway": "שעון סמואה (מידוויי)", + "Pacific\/Nauru": "שעון נאורו (נאורו)", + "Pacific\/Niue": "שעון ניואה (ניואה)", + "Pacific\/Norfolk": "שעון האי נורפוק (נורפוק)", + "Pacific\/Noumea": "שעון קלדוניה החדשה (נומאה)", + "Pacific\/Pago_Pago": "שעון סמואה (פאגו פאגו)", + "Pacific\/Palau": "שעון פלאו (פלאו)", + "Pacific\/Pitcairn": "שעון פיטקרן (פיטקרן)", + "Pacific\/Ponape": "שעון פונאפי (פונפיי)", + "Pacific\/Port_Moresby": "שעון פפואה גיניאה החדשה (פורט מורסבי)", + "Pacific\/Rarotonga": "שעון איי קוק (רארוטונגה)", + "Pacific\/Saipan": "שעון צ׳אמורו (סאיפאן)", + "Pacific\/Tahiti": "שעון טהיטי (טהיטי)", + "Pacific\/Tarawa": "שעון איי גילברט (טאראווה)", + "Pacific\/Tongatapu": "שעון טונגה (טונגטאפו)", + "Pacific\/Truk": "שעון צ׳וק (צ׳וק)", + "Pacific\/Wake": "שעון האי וייק (וייק)", + "Pacific\/Wallis": "שעון וואליס ופוטונה (ווליס)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ja.json b/src/Symfony/Component/Intl/Resources/data/timezones/ja.json new file mode 100644 index 0000000000000..2a750865dbe3f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ja.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "グリニッジ標準時 (アビジャン)", + "Africa\/Accra": "グリニッジ標準時 (アクラ)", + "Africa\/Addis_Ababa": "東アフリカ時間 (アジスアベバ)", + "Africa\/Algiers": "中央ヨーロッパ時間 (アルジェ)", + "Africa\/Asmera": "東アフリカ時間 (アスマラ)", + "Africa\/Bamako": "グリニッジ標準時 (バマコ)", + "Africa\/Bangui": "西アフリカ時間 (バンギ)", + "Africa\/Banjul": "グリニッジ標準時 (バンジュール)", + "Africa\/Bissau": "グリニッジ標準時 (ビサウ)", + "Africa\/Blantyre": "中央アフリカ時間 (ブランタイヤ)", + "Africa\/Brazzaville": "西アフリカ時間 (ブラザビル)", + "Africa\/Bujumbura": "中央アフリカ時間 (ブジュンブラ)", + "Africa\/Cairo": "東ヨーロッパ時間 (カイロ)", + "Africa\/Casablanca": "西ヨーロッパ時間 (カサブランカ)", + "Africa\/Ceuta": "中央ヨーロッパ時間 (セウタ)", + "Africa\/Conakry": "グリニッジ標準時 (コナクリ)", + "Africa\/Dakar": "グリニッジ標準時 (ダカール)", + "Africa\/Dar_es_Salaam": "東アフリカ時間 (ダルエスサラーム)", + "Africa\/Djibouti": "東アフリカ時間 (ジブチ)", + "Africa\/Douala": "西アフリカ時間 (ドゥアラ)", + "Africa\/El_Aaiun": "西ヨーロッパ時間 (アイウン)", + "Africa\/Freetown": "グリニッジ標準時 (フリータウン)", + "Africa\/Gaborone": "中央アフリカ時間 (ハボローネ)", + "Africa\/Harare": "中央アフリカ時間 (ハラレ)", + "Africa\/Johannesburg": "南アフリカ標準時 (ヨハネスブルグ)", + "Africa\/Juba": "東アフリカ時間 (ジュバ)", + "Africa\/Kampala": "東アフリカ時間 (カンパラ)", + "Africa\/Khartoum": "中央アフリカ時間 (ハルツーム)", + "Africa\/Kigali": "中央アフリカ時間 (キガリ)", + "Africa\/Kinshasa": "西アフリカ時間 (キンシャサ)", + "Africa\/Lagos": "西アフリカ時間 (ラゴス)", + "Africa\/Libreville": "西アフリカ時間 (リーブルヴィル)", + "Africa\/Lome": "グリニッジ標準時 (ロメ)", + "Africa\/Luanda": "西アフリカ時間 (ルアンダ)", + "Africa\/Lubumbashi": "中央アフリカ時間 (ルブンバシ)", + "Africa\/Lusaka": "中央アフリカ時間 (ルサカ)", + "Africa\/Malabo": "西アフリカ時間 (マラボ)", + "Africa\/Maputo": "中央アフリカ時間 (マプト)", + "Africa\/Maseru": "南アフリカ標準時 (マセル)", + "Africa\/Mbabane": "南アフリカ標準時 (ムババーネ)", + "Africa\/Mogadishu": "東アフリカ時間 (モガディシオ)", + "Africa\/Monrovia": "グリニッジ標準時 (モンロビア)", + "Africa\/Nairobi": "東アフリカ時間 (ナイロビ)", + "Africa\/Ndjamena": "西アフリカ時間 (ンジャメナ)", + "Africa\/Niamey": "西アフリカ時間 (ニアメ)", + "Africa\/Nouakchott": "グリニッジ標準時 (ヌアクショット)", + "Africa\/Ouagadougou": "グリニッジ標準時 (ワガドゥグー)", + "Africa\/Porto-Novo": "西アフリカ時間 (ポルトノボ)", + "Africa\/Sao_Tome": "グリニッジ標準時 (サントメ)", + "Africa\/Tripoli": "東ヨーロッパ時間 (トリポリ)", + "Africa\/Tunis": "中央ヨーロッパ時間 (チュニス)", + "Africa\/Windhoek": "中央アフリカ時間 (ウィントフック)", + "America\/Adak": "ハワイ・アリューシャン時間 (アダック)", + "America\/Anchorage": "アラスカ時間 (アンカレッジ)", + "America\/Anguilla": "大西洋時間 (アンギラ)", + "America\/Antigua": "大西洋時間 (アンティグア)", + "America\/Araguaina": "ブラジリア時間 (アラグァイナ)", + "America\/Argentina\/La_Rioja": "アルゼンチン時間 (ラリオハ)", + "America\/Argentina\/Rio_Gallegos": "アルゼンチン時間 (リオガジェゴス)", + "America\/Argentina\/Salta": "アルゼンチン時間 (サルタ)", + "America\/Argentina\/San_Juan": "アルゼンチン時間 (サンファン)", + "America\/Argentina\/San_Luis": "西部アルゼンチン時間 (サンルイス)", + "America\/Argentina\/Tucuman": "アルゼンチン時間 (トゥクマン)", + "America\/Argentina\/Ushuaia": "アルゼンチン時間 (ウシュアイア)", + "America\/Aruba": "大西洋時間 (アルバ)", + "America\/Asuncion": "パラグアイ時間 (アスンシオン)", + "America\/Bahia": "ブラジリア時間 (バイーア)", + "America\/Bahia_Banderas": "アメリカ中部時間 (バイアバンデラ)", + "America\/Barbados": "大西洋時間 (バルバドス)", + "America\/Belem": "ブラジリア時間 (ベレン)", + "America\/Belize": "アメリカ中部時間 (ベリーズ)", + "America\/Blanc-Sablon": "大西洋時間 (ブラン・サブロン)", + "America\/Boa_Vista": "アマゾン時間 (ボアビスタ)", + "America\/Bogota": "コロンビア時間 (ボゴタ)", + "America\/Boise": "アメリカ山地時間 (ボイシ)", + "America\/Buenos_Aires": "アルゼンチン時間 (ブエノスアイレス)", + "America\/Cambridge_Bay": "アメリカ山地時間 (ケンブリッジベイ)", + "America\/Campo_Grande": "アマゾン時間 (カンポグランデ)", + "America\/Cancun": "アメリカ東部時間 (カンクン)", + "America\/Caracas": "ベネズエラ時間 (カラカス)", + "America\/Catamarca": "アルゼンチン時間 (カタマルカ)", + "America\/Cayenne": "仏領ギアナ時間 (カイエンヌ)", + "America\/Cayman": "アメリカ東部時間 (ケイマン)", + "America\/Chicago": "アメリカ中部時間 (シカゴ)", + "America\/Chihuahua": "メキシコ太平洋時間 (チワワ)", + "America\/Coral_Harbour": "アメリカ東部時間 (アティコカン)", + "America\/Cordoba": "アルゼンチン時間 (コルドバ)", + "America\/Costa_Rica": "アメリカ中部時間 (コスタリカ)", + "America\/Creston": "アメリカ山地時間 (クレストン)", + "America\/Cuiaba": "アマゾン時間 (クイアバ)", + "America\/Curacao": "大西洋時間 (キュラソー)", + "America\/Danmarkshavn": "グリニッジ標準時 (デンマークシャウン)", + "America\/Dawson": "アメリカ太平洋時間 (ドーソン)", + "America\/Dawson_Creek": "アメリカ山地時間 (ドーソンクリーク)", + "America\/Denver": "アメリカ山地時間 (デンバー)", + "America\/Detroit": "アメリカ東部時間 (デトロイト)", + "America\/Dominica": "大西洋時間 (ドミニカ)", + "America\/Edmonton": "アメリカ山地時間 (エドモントン)", + "America\/Eirunepe": "アクレ時間 (エイルネペ)", + "America\/El_Salvador": "アメリカ中部時間 (エルサルバドル)", + "America\/Fort_Nelson": "アメリカ山地時間 (フォートネルソン)", + "America\/Fortaleza": "ブラジリア時間 (フォルタレザ)", + "America\/Glace_Bay": "大西洋時間 (グレースベイ)", + "America\/Godthab": "グリーンランド西部時間 (ヌーク)", + "America\/Goose_Bay": "大西洋時間 (グースベイ)", + "America\/Grand_Turk": "アメリカ東部時間 (グランドターク)", + "America\/Grenada": "大西洋時間 (グレナダ)", + "America\/Guadeloupe": "大西洋時間 (グアドループ)", + "America\/Guatemala": "アメリカ中部時間 (グアテマラ)", + "America\/Guayaquil": "エクアドル時間 (グアヤキル)", + "America\/Guyana": "ガイアナ時間 (ガイアナ)", + "America\/Halifax": "大西洋時間 (ハリファクス)", + "America\/Havana": "キューバ時間 (ハバナ)", + "America\/Hermosillo": "メキシコ太平洋時間 (エルモシヨ)", + "America\/Indiana\/Knox": "アメリカ中部時間 (インディアナ州ノックス)", + "America\/Indiana\/Marengo": "アメリカ東部時間 (インディアナ州マレンゴ)", + "America\/Indiana\/Petersburg": "アメリカ東部時間 (インディアナ州ピーターズバーグ)", + "America\/Indiana\/Tell_City": "アメリカ中部時間 (インディアナ州テルシティ)", + "America\/Indiana\/Vevay": "アメリカ東部時間 (インディアナ州ビベー)", + "America\/Indiana\/Vincennes": "アメリカ東部時間 (インディアナ州ビンセンス)", + "America\/Indiana\/Winamac": "アメリカ東部時間 (インディアナ州ウィナマック)", + "America\/Indianapolis": "アメリカ東部時間 (インディアナポリス)", + "America\/Inuvik": "アメリカ山地時間 (イヌヴィク)", + "America\/Iqaluit": "アメリカ東部時間 (イカルイット)", + "America\/Jamaica": "アメリカ東部時間 (ジャマイカ)", + "America\/Jujuy": "アルゼンチン時間 (フフイ)", + "America\/Juneau": "アラスカ時間 (ジュノー)", + "America\/Kentucky\/Monticello": "アメリカ東部時間 (ケンタッキー州モンティチェロ)", + "America\/Kralendijk": "大西洋時間 (クラレンダイク)", + "America\/La_Paz": "ボリビア時間 (ラパス)", + "America\/Lima": "ペルー時間 (リマ)", + "America\/Los_Angeles": "アメリカ太平洋時間 (ロサンゼルス)", + "America\/Louisville": "アメリカ東部時間 (ルイビル)", + "America\/Lower_Princes": "大西洋時間 (ローワー・プリンセズ・クウォーター)", + "America\/Maceio": "ブラジリア時間 (マセイオ)", + "America\/Managua": "アメリカ中部時間 (マナグア)", + "America\/Manaus": "アマゾン時間 (マナウス)", + "America\/Marigot": "大西洋時間 (マリゴ)", + "America\/Martinique": "大西洋時間 (マルティニーク)", + "America\/Matamoros": "アメリカ中部時間 (マタモロス)", + "America\/Mazatlan": "メキシコ太平洋時間 (マサトラン)", + "America\/Mendoza": "アルゼンチン時間 (メンドーサ)", + "America\/Menominee": "アメリカ中部時間 (メノミニー)", + "America\/Merida": "アメリカ中部時間 (メリダ)", + "America\/Metlakatla": "アラスカ時間 (メトラカトラ)", + "America\/Mexico_City": "アメリカ中部時間 (メキシコシティー)", + "America\/Miquelon": "サンピエール島・ミクロン島時間 (ミクロン島)", + "America\/Moncton": "大西洋時間 (モンクトン)", + "America\/Monterrey": "アメリカ中部時間 (モンテレイ)", + "America\/Montevideo": "ウルグアイ時間 (モンテビデオ)", + "America\/Montserrat": "大西洋時間 (モントセラト)", + "America\/Nassau": "アメリカ東部時間 (ナッソー)", + "America\/New_York": "アメリカ東部時間 (ニューヨーク)", + "America\/Nipigon": "アメリカ東部時間 (ニピゴン)", + "America\/Nome": "アラスカ時間 (ノーム)", + "America\/Noronha": "フェルナンド・デ・ノローニャ時間 (ノローニャ)", + "America\/North_Dakota\/Beulah": "アメリカ中部時間 (ノースダコタ州ビューラー)", + "America\/North_Dakota\/Center": "アメリカ中部時間 (ノースダコタ州センター)", + "America\/North_Dakota\/New_Salem": "アメリカ中部時間 (ノースダコタ州ニューセーラム)", + "America\/Ojinaga": "アメリカ山地時間 (オヒナガ)", + "America\/Panama": "アメリカ東部時間 (パナマ)", + "America\/Pangnirtung": "アメリカ東部時間 (パンナータング)", + "America\/Paramaribo": "スリナム時間 (パラマリボ)", + "America\/Phoenix": "アメリカ山地時間 (フェニックス)", + "America\/Port-au-Prince": "アメリカ東部時間 (ポルトープランス)", + "America\/Port_of_Spain": "大西洋時間 (ポートオブスペイン)", + "America\/Porto_Velho": "アマゾン時間 (ポルトベーリョ)", + "America\/Puerto_Rico": "大西洋時間 (プエルトリコ)", + "America\/Punta_Arenas": "チリ時間 (プンタアレナス)", + "America\/Rainy_River": "アメリカ中部時間 (レイニーリバー)", + "America\/Rankin_Inlet": "アメリカ中部時間 (ランキンインレット)", + "America\/Recife": "ブラジリア時間 (レシフェ)", + "America\/Regina": "アメリカ中部時間 (レジャイナ)", + "America\/Resolute": "アメリカ中部時間 (レゾリュート)", + "America\/Rio_Branco": "アクレ時間 (リオブランコ)", + "America\/Santa_Isabel": "メキシコ北西部時間 (サンタイサベル)", + "America\/Santarem": "ブラジリア時間 (サンタレム)", + "America\/Santiago": "チリ時間 (サンチアゴ)", + "America\/Santo_Domingo": "大西洋時間 (サントドミンゴ)", + "America\/Sao_Paulo": "ブラジリア時間 (サンパウロ)", + "America\/Scoresbysund": "グリーンランド東部時間 (イトコルトルミット)", + "America\/Sitka": "アラスカ時間 (シトカ)", + "America\/St_Barthelemy": "大西洋時間 (サン・バルテルミー)", + "America\/St_Johns": "ニューファンドランド時間 (セントジョンズ)", + "America\/St_Kitts": "大西洋時間 (セントクリストファー)", + "America\/St_Lucia": "大西洋時間 (セントルシア)", + "America\/St_Thomas": "大西洋時間 (セントトーマス)", + "America\/St_Vincent": "大西洋時間 (セントビンセント)", + "America\/Swift_Current": "アメリカ中部時間 (スウィフトカレント)", + "America\/Tegucigalpa": "アメリカ中部時間 (テグシガルパ)", + "America\/Thule": "大西洋時間 (チューレ)", + "America\/Thunder_Bay": "アメリカ東部時間 (サンダーベイ)", + "America\/Tijuana": "アメリカ太平洋時間 (ティフアナ)", + "America\/Toronto": "アメリカ東部時間 (トロント)", + "America\/Tortola": "大西洋時間 (トルトーラ)", + "America\/Vancouver": "アメリカ太平洋時間 (バンクーバー)", + "America\/Whitehorse": "アメリカ太平洋時間 (ホワイトホース)", + "America\/Winnipeg": "アメリカ中部時間 (ウィニペグ)", + "America\/Yakutat": "アラスカ時間 (ヤクタット)", + "America\/Yellowknife": "アメリカ山地時間 (イエローナイフ)", + "Antarctica\/Casey": "オーストラリア西部時間 (ケーシー基地)", + "Antarctica\/Davis": "デービス基地時間 (デービス基地)", + "Antarctica\/DumontDUrville": "デュモン・デュルヴィル基地時間 (デュモン・デュルヴィル基地)", + "Antarctica\/Macquarie": "マッコーリー島時間 (マッコリー)", + "Antarctica\/Mawson": "モーソン基地時間 (モーソン基地)", + "Antarctica\/McMurdo": "ニュージーランド時間 (マクマード基地)", + "Antarctica\/Palmer": "チリ時間 (パーマー基地)", + "Antarctica\/Rothera": "ロゼラ基地時間 (ロゼラ基地)", + "Antarctica\/Syowa": "昭和基地時間 (昭和基地)", + "Antarctica\/Troll": "グリニッジ標準時 (トロル基地)", + "Antarctica\/Vostok": "ボストーク基地時間 (ボストーク基地)", + "Arctic\/Longyearbyen": "中央ヨーロッパ時間 (ロングイェールビーン)", + "Asia\/Aden": "アラビア時間 (アデン)", + "Asia\/Almaty": "東カザフスタン時間 (アルマトイ)", + "Asia\/Amman": "東ヨーロッパ時間 (アンマン)", + "Asia\/Anadyr": "アナディリ時間 (アナディリ)", + "Asia\/Aqtau": "西カザフスタン時間 (アクタウ)", + "Asia\/Aqtobe": "西カザフスタン時間 (アクトベ)", + "Asia\/Ashgabat": "トルクメニスタン時間 (アシガバード)", + "Asia\/Atyrau": "西カザフスタン時間 (アティラウ)", + "Asia\/Baghdad": "アラビア時間 (バグダッド)", + "Asia\/Bahrain": "アラビア時間 (バーレーン)", + "Asia\/Baku": "アゼルバイジャン時間 (バクー)", + "Asia\/Bangkok": "インドシナ時間 (バンコク)", + "Asia\/Beirut": "東ヨーロッパ時間 (ベイルート)", + "Asia\/Bishkek": "キルギス時間 (ビシュケク)", + "Asia\/Brunei": "ブルネイ・ダルサラーム時間 (ブルネイ)", + "Asia\/Calcutta": "インド標準時 (コルカタ)", + "Asia\/Chita": "ヤクーツク時間 (チタ)", + "Asia\/Choibalsan": "チョイバルサン時間 (チョイバルサン)", + "Asia\/Colombo": "インド標準時 (コロンボ)", + "Asia\/Damascus": "東ヨーロッパ時間 (ダマスカス)", + "Asia\/Dhaka": "バングラデシュ時間 (ダッカ)", + "Asia\/Dili": "東ティモール時間 (ディリ)", + "Asia\/Dubai": "湾岸標準時 (ドバイ)", + "Asia\/Dushanbe": "タジキスタン時間 (ドゥシャンベ)", + "Asia\/Famagusta": "東ヨーロッパ時間 (ファマグスタ)", + "Asia\/Gaza": "東ヨーロッパ時間 (ガザ)", + "Asia\/Hebron": "東ヨーロッパ時間 (ヘブロン)", + "Asia\/Hong_Kong": "香港時間 (香港)", + "Asia\/Hovd": "ホブド時間 (ホブド)", + "Asia\/Irkutsk": "イルクーツク時間 (イルクーツク)", + "Asia\/Jakarta": "インドネシア西部時間 (ジャカルタ)", + "Asia\/Jayapura": "インドネシア東部時間 (ジャヤプラ)", + "Asia\/Jerusalem": "イスラエル時間 (エルサレム)", + "Asia\/Kabul": "アフガニスタン時間 (カブール)", + "Asia\/Kamchatka": "ペトロパブロフスク・カムチャツキー時間 (カムチャッカ)", + "Asia\/Karachi": "パキスタン時間 (カラチ)", + "Asia\/Katmandu": "ネパール時間 (カトマンズ)", + "Asia\/Khandyga": "ヤクーツク時間 (ハンドゥイガ)", + "Asia\/Krasnoyarsk": "クラスノヤルスク時間 (クラスノヤルスク)", + "Asia\/Kuala_Lumpur": "マレーシア時間 (クアラルンプール)", + "Asia\/Kuching": "マレーシア時間 (クチン)", + "Asia\/Kuwait": "アラビア時間 (クウェート)", + "Asia\/Macau": "中国時間 (マカオ)", + "Asia\/Magadan": "マガダン時間 (マガダン)", + "Asia\/Makassar": "インドネシア中部時間 (マカッサル)", + "Asia\/Manila": "フィリピン時間 (マニラ)", + "Asia\/Muscat": "湾岸標準時 (マスカット)", + "Asia\/Nicosia": "東ヨーロッパ時間 (ニコシア)", + "Asia\/Novokuznetsk": "クラスノヤルスク時間 (ノヴォクズネツク)", + "Asia\/Novosibirsk": "ノヴォシビルスク時間 (ノヴォシビルスク)", + "Asia\/Omsk": "オムスク時間 (オムスク)", + "Asia\/Oral": "西カザフスタン時間 (オラル)", + "Asia\/Phnom_Penh": "インドシナ時間 (プノンペン)", + "Asia\/Pontianak": "インドネシア西部時間 (ポンティアナック)", + "Asia\/Pyongyang": "韓国時間 (平壌)", + "Asia\/Qatar": "アラビア時間 (カタール)", + "Asia\/Qostanay": "東カザフスタン時間 (Qostanay)", + "Asia\/Qyzylorda": "西カザフスタン時間 (クズロルダ)", + "Asia\/Rangoon": "ミャンマー時間 (ヤンゴン)", + "Asia\/Riyadh": "アラビア時間 (リヤド)", + "Asia\/Saigon": "インドシナ時間 (ホーチミン)", + "Asia\/Sakhalin": "サハリン時間 (サハリン)", + "Asia\/Samarkand": "ウズベキスタン時間 (サマルカンド)", + "Asia\/Seoul": "韓国時間 (ソウル)", + "Asia\/Shanghai": "中国時間 (上海)", + "Asia\/Singapore": "シンガポール標準時 (シンガポール)", + "Asia\/Srednekolymsk": "マガダン時間 (スレドネコリムスク)", + "Asia\/Taipei": "台北時間 (台北)", + "Asia\/Tashkent": "ウズベキスタン時間 (タシケント)", + "Asia\/Tbilisi": "ジョージア時間 (トビリシ)", + "Asia\/Tehran": "イラン時間 (テヘラン)", + "Asia\/Thimphu": "ブータン時間 (ティンプー)", + "Asia\/Tokyo": "日本時間 (東京)", + "Asia\/Ulaanbaatar": "ウランバートル時間 (ウランバートル)", + "Asia\/Ust-Nera": "ウラジオストク時間 (ウスチネラ)", + "Asia\/Vientiane": "インドシナ時間 (ビエンチャン)", + "Asia\/Vladivostok": "ウラジオストク時間 (ウラジオストク)", + "Asia\/Yakutsk": "ヤクーツク時間 (ヤクーツク)", + "Asia\/Yekaterinburg": "エカテリンブルグ時間 (エカテリンブルグ)", + "Asia\/Yerevan": "アルメニア時間 (エレバン)", + "Atlantic\/Azores": "アゾレス時間 (アゾレス)", + "Atlantic\/Bermuda": "大西洋時間 (バミューダ)", + "Atlantic\/Canary": "西ヨーロッパ時間 (カナリア)", + "Atlantic\/Cape_Verde": "カーボベルデ時間 (カーボベルデ)", + "Atlantic\/Faeroe": "西ヨーロッパ時間 (フェロー)", + "Atlantic\/Madeira": "西ヨーロッパ時間 (マデイラ)", + "Atlantic\/Reykjavik": "グリニッジ標準時 (レイキャビク)", + "Atlantic\/South_Georgia": "サウスジョージア時間 (サウスジョージア)", + "Atlantic\/St_Helena": "グリニッジ標準時 (セントヘレナ)", + "Atlantic\/Stanley": "フォークランド諸島時間 (スタンレー)", + "Australia\/Adelaide": "オーストラリア中部時間 (アデレード)", + "Australia\/Brisbane": "オーストラリア東部時間 (ブリスベン)", + "Australia\/Broken_Hill": "オーストラリア中部時間 (ブロークンヒル)", + "Australia\/Currie": "オーストラリア東部時間 (カリー)", + "Australia\/Darwin": "オーストラリア中部時間 (ダーウィン)", + "Australia\/Eucla": "オーストラリア中西部時間 (ユークラ)", + "Australia\/Hobart": "オーストラリア東部時間 (ホバート)", + "Australia\/Lindeman": "オーストラリア東部時間 (リンデマン)", + "Australia\/Lord_Howe": "ロードハウ時間 (ロードハウ)", + "Australia\/Melbourne": "オーストラリア東部時間 (メルボルン)", + "Australia\/Perth": "オーストラリア西部時間 (パース)", + "Australia\/Sydney": "オーストラリア東部時間 (シドニー)", + "CST6CDT": "アメリカ中部時間", + "EST5EDT": "アメリカ東部時間", + "Etc\/GMT": "グリニッジ標準時", + "Etc\/UTC": "協定世界時", + "Europe\/Amsterdam": "中央ヨーロッパ時間 (アムステルダム)", + "Europe\/Andorra": "中央ヨーロッパ時間 (アンドラ)", + "Europe\/Astrakhan": "モスクワ時間 (アストラハン)", + "Europe\/Athens": "東ヨーロッパ時間 (アテネ)", + "Europe\/Belgrade": "中央ヨーロッパ時間 (ベオグラード)", + "Europe\/Berlin": "中央ヨーロッパ時間 (ベルリン)", + "Europe\/Bratislava": "中央ヨーロッパ時間 (ブラチスラバ)", + "Europe\/Brussels": "中央ヨーロッパ時間 (ブリュッセル)", + "Europe\/Bucharest": "東ヨーロッパ時間 (ブカレスト)", + "Europe\/Budapest": "中央ヨーロッパ時間 (ブダペスト)", + "Europe\/Busingen": "中央ヨーロッパ時間 (ビュージンゲン)", + "Europe\/Chisinau": "東ヨーロッパ時間 (キシナウ)", + "Europe\/Copenhagen": "中央ヨーロッパ時間 (コペンハーゲン)", + "Europe\/Dublin": "グリニッジ標準時 (ダブリン)", + "Europe\/Gibraltar": "中央ヨーロッパ時間 (ジブラルタル)", + "Europe\/Guernsey": "グリニッジ標準時 (ガーンジー)", + "Europe\/Helsinki": "東ヨーロッパ時間 (ヘルシンキ)", + "Europe\/Isle_of_Man": "グリニッジ標準時 (マン島)", + "Europe\/Jersey": "グリニッジ標準時 (ジャージー)", + "Europe\/Kaliningrad": "東ヨーロッパ時間 (カリーニングラード)", + "Europe\/Kiev": "東ヨーロッパ時間 (キエフ)", + "Europe\/Lisbon": "西ヨーロッパ時間 (リスボン)", + "Europe\/Ljubljana": "中央ヨーロッパ時間 (リュブリャナ)", + "Europe\/London": "グリニッジ標準時 (ロンドン)", + "Europe\/Luxembourg": "中央ヨーロッパ時間 (ルクセンブルク)", + "Europe\/Madrid": "中央ヨーロッパ時間 (マドリード)", + "Europe\/Malta": "中央ヨーロッパ時間 (マルタ)", + "Europe\/Mariehamn": "東ヨーロッパ時間 (マリエハムン)", + "Europe\/Minsk": "モスクワ時間 (ミンスク)", + "Europe\/Monaco": "中央ヨーロッパ時間 (モナコ)", + "Europe\/Moscow": "モスクワ時間 (モスクワ)", + "Europe\/Oslo": "中央ヨーロッパ時間 (オスロ)", + "Europe\/Paris": "中央ヨーロッパ時間 (パリ)", + "Europe\/Podgorica": "中央ヨーロッパ時間 (ポドゴリツァ)", + "Europe\/Prague": "中央ヨーロッパ時間 (プラハ)", + "Europe\/Riga": "東ヨーロッパ時間 (リガ)", + "Europe\/Rome": "中央ヨーロッパ時間 (ローマ)", + "Europe\/Samara": "サマラ時間 (サマラ)", + "Europe\/San_Marino": "中央ヨーロッパ時間 (サンマリノ)", + "Europe\/Sarajevo": "中央ヨーロッパ時間 (サラエボ)", + "Europe\/Saratov": "モスクワ時間 (サラトフ)", + "Europe\/Simferopol": "モスクワ時間 (シンフェロポリ)", + "Europe\/Skopje": "中央ヨーロッパ時間 (スコピエ)", + "Europe\/Sofia": "東ヨーロッパ時間 (ソフィア)", + "Europe\/Stockholm": "中央ヨーロッパ時間 (ストックホルム)", + "Europe\/Tallinn": "東ヨーロッパ時間 (タリン)", + "Europe\/Tirane": "中央ヨーロッパ時間 (ティラナ)", + "Europe\/Ulyanovsk": "モスクワ時間 (ウリヤノフスク)", + "Europe\/Uzhgorod": "東ヨーロッパ時間 (ウージュホロド)", + "Europe\/Vaduz": "中央ヨーロッパ時間 (ファドゥーツ)", + "Europe\/Vatican": "中央ヨーロッパ時間 (バチカン)", + "Europe\/Vienna": "中央ヨーロッパ時間 (ウィーン)", + "Europe\/Vilnius": "東ヨーロッパ時間 (ヴィリニュス)", + "Europe\/Volgograd": "ボルゴグラード時間 (ボルゴグラード)", + "Europe\/Warsaw": "中央ヨーロッパ時間 (ワルシャワ)", + "Europe\/Zagreb": "中央ヨーロッパ時間 (ザグレブ)", + "Europe\/Zaporozhye": "東ヨーロッパ時間 (ザポリージャ)", + "Europe\/Zurich": "中央ヨーロッパ時間 (チューリッヒ)", + "Indian\/Antananarivo": "東アフリカ時間 (アンタナナリボ)", + "Indian\/Chagos": "インド洋時間 (チャゴス)", + "Indian\/Christmas": "クリスマス島時間 (クリスマス島)", + "Indian\/Cocos": "ココス諸島時間 (ココス諸島)", + "Indian\/Comoro": "東アフリカ時間 (コモロ)", + "Indian\/Kerguelen": "仏領南方南極時間 (ケルゲレン諸島)", + "Indian\/Mahe": "セーシェル時間 (マヘ)", + "Indian\/Maldives": "モルディブ時間 (モルディブ)", + "Indian\/Mauritius": "モーリシャス時間 (モーリシャス)", + "Indian\/Mayotte": "東アフリカ時間 (マヨット)", + "Indian\/Reunion": "レユニオン時間 (レユニオン)", + "MST7MDT": "アメリカ山地時間", + "PST8PDT": "アメリカ太平洋時間", + "Pacific\/Apia": "アピア時間 (アピア)", + "Pacific\/Auckland": "ニュージーランド時間 (オークランド)", + "Pacific\/Bougainville": "パプアニューギニア時間 (ブーゲンビル)", + "Pacific\/Chatham": "チャタム時間 (チャタム)", + "Pacific\/Easter": "イースター島時間 (イースター島)", + "Pacific\/Efate": "バヌアツ時間 (エフェテ島)", + "Pacific\/Enderbury": "フェニックス諸島時間 (エンダーベリー島)", + "Pacific\/Fakaofo": "トケラウ時間 (ファカオフォ)", + "Pacific\/Fiji": "フィジー時間 (フィジー)", + "Pacific\/Funafuti": "ツバル時間 (フナフティ)", + "Pacific\/Galapagos": "ガラパゴス時間 (ガラパゴス)", + "Pacific\/Gambier": "ガンビエ諸島時間 (ガンビエ諸島)", + "Pacific\/Guadalcanal": "ソロモン諸島時間 (ガダルカナル)", + "Pacific\/Guam": "チャモロ時間 (グアム)", + "Pacific\/Honolulu": "ハワイ・アリューシャン時間 (ホノルル)", + "Pacific\/Johnston": "ハワイ・アリューシャン時間 (ジョンストン島)", + "Pacific\/Kiritimati": "ライン諸島時間 (キリスィマスィ島)", + "Pacific\/Kosrae": "コスラエ時間 (コスラエ)", + "Pacific\/Kwajalein": "マーシャル諸島時間 (クェゼリン)", + "Pacific\/Majuro": "マーシャル諸島時間 (マジュロ)", + "Pacific\/Marquesas": "マルキーズ時間 (マルキーズ)", + "Pacific\/Midway": "サモア時間 (ミッドウェー島)", + "Pacific\/Nauru": "ナウル時間 (ナウル)", + "Pacific\/Niue": "ニウエ時間 (ニウエ)", + "Pacific\/Norfolk": "ノーフォーク島時間 (ノーフォーク島)", + "Pacific\/Noumea": "ニューカレドニア時間 (ヌメア)", + "Pacific\/Pago_Pago": "サモア時間 (パゴパゴ)", + "Pacific\/Palau": "パラオ時間 (パラオ)", + "Pacific\/Pitcairn": "ピトケアン時間 (ピトケアン諸島)", + "Pacific\/Ponape": "ポナペ時間 (ポンペイ島)", + "Pacific\/Port_Moresby": "パプアニューギニア時間 (ポートモレスビー)", + "Pacific\/Rarotonga": "クック諸島時間 (ラロトンガ)", + "Pacific\/Saipan": "チャモロ時間 (サイパン)", + "Pacific\/Tahiti": "タヒチ時間 (タヒチ)", + "Pacific\/Tarawa": "ギルバート諸島時間 (タラワ)", + "Pacific\/Tongatapu": "トンガ時間 (トンガタプ)", + "Pacific\/Truk": "チューク時間 (チューク)", + "Pacific\/Wake": "ウェーク島時間 (ウェーク島)", + "Pacific\/Wallis": "ウォリス・フツナ時間 (ウォリス諸島)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/jv.json b/src/Symfony/Component/Intl/Resources/data/timezones/jv.json new file mode 100644 index 0000000000000..4ae3582aca1be --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/jv.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.44", + "Names": { + "Africa\/Abidjan": "Wektu Rerata Greenwich (Abidjan)", + "Africa\/Accra": "Wektu Rerata Greenwich (Accra)", + "Africa\/Addis_Ababa": "Wektu Afrika Wetan (Addis Ababa)", + "Africa\/Algiers": "Wektu Eropa Tengah (Algiers)", + "Africa\/Asmera": "Wektu Afrika Wetan (Asmara)", + "Africa\/Bamako": "Wektu Rerata Greenwich (Bamako)", + "Africa\/Bangui": "Wektu Afrika Kulon (Bangui)", + "Africa\/Banjul": "Wektu Rerata Greenwich (Banjul)", + "Africa\/Bissau": "Wektu Rerata Greenwich (Bissau)", + "Africa\/Blantyre": "Wektu Afrika Tengah (Blantyre)", + "Africa\/Brazzaville": "Wektu Afrika Kulon (Brazzaville)", + "Africa\/Bujumbura": "Wektu Afrika Tengah (Bujumbura)", + "Africa\/Cairo": "Wektu Eropa sisih Wetan (Kairo)", + "Africa\/Casablanca": "Wektu Eropa sisih Kulon (Kasablanka)", + "Africa\/Ceuta": "Wektu Eropa Tengah (Ceuta)", + "Africa\/Conakry": "Wektu Rerata Greenwich (Konakri)", + "Africa\/Dakar": "Wektu Rerata Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Wektu Afrika Wetan (Dar es Salaam)", + "Africa\/Djibouti": "Wektu Afrika Wetan (Djibouti)", + "Africa\/Douala": "Wektu Afrika Kulon (Douala)", + "Africa\/El_Aaiun": "Wektu Eropa sisih Kulon (El Aaiun)", + "Africa\/Freetown": "Wektu Rerata Greenwich (Freetown)", + "Africa\/Gaborone": "Wektu Afrika Tengah (Gaborone)", + "Africa\/Harare": "Wektu Afrika Tengah (Harare)", + "Africa\/Johannesburg": "Wektu Standar Afrika Kidul (Johannesburg)", + "Africa\/Juba": "Wektu Afrika Wetan (Juba)", + "Africa\/Kampala": "Wektu Afrika Wetan (Kampala)", + "Africa\/Khartoum": "Wektu Afrika Tengah (Khartoum)", + "Africa\/Kigali": "Wektu Afrika Tengah (Kigali)", + "Africa\/Kinshasa": "Wektu Afrika Kulon (Kinshasa)", + "Africa\/Lagos": "Wektu Afrika Kulon (Lagos)", + "Africa\/Libreville": "Wektu Afrika Kulon (Libreville)", + "Africa\/Lome": "Wektu Rerata Greenwich (Lome)", + "Africa\/Luanda": "Wektu Afrika Kulon (Luanda)", + "Africa\/Lubumbashi": "Wektu Afrika Tengah (Lubumbashi)", + "Africa\/Lusaka": "Wektu Afrika Tengah (Lusaka)", + "Africa\/Malabo": "Wektu Afrika Kulon (Malabo)", + "Africa\/Maputo": "Wektu Afrika Tengah (Maputo)", + "Africa\/Maseru": "Wektu Standar Afrika Kidul (Maseru)", + "Africa\/Mbabane": "Wektu Standar Afrika Kidul (Mbabane)", + "Africa\/Mogadishu": "Wektu Afrika Wetan (Mogadishu)", + "Africa\/Monrovia": "Wektu Rerata Greenwich (Monrovia)", + "Africa\/Nairobi": "Wektu Afrika Wetan (Nairobi)", + "Africa\/Ndjamena": "Wektu Afrika Kulon (Ndjamena)", + "Africa\/Niamey": "Wektu Afrika Kulon (Niamey)", + "Africa\/Nouakchott": "Wektu Rerata Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Wektu Rerata Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Wektu Afrika Kulon (Porto-Novo)", + "Africa\/Sao_Tome": "Wektu Rerata Greenwich (Sao Tome)", + "Africa\/Tripoli": "Wektu Eropa sisih Wetan (Tripoli)", + "Africa\/Tunis": "Wektu Eropa Tengah (Tunis)", + "Africa\/Windhoek": "Wektu Afrika Tengah (Windhoek)", + "America\/Adak": "Wektu Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Wektu Alaska (Anchorage)", + "America\/Anguilla": "Wektu Atlantik (Anguilla)", + "America\/Antigua": "Wektu Atlantik (Antigua)", + "America\/Araguaina": "Wektu Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "Wektu Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Wektu Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Wektu Argentina (Salta)", + "America\/Argentina\/San_Juan": "Wektu Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Wektu Argentina sisih Kulon (San Luis)", + "America\/Argentina\/Tucuman": "Wektu Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Wektu Argentina (Ushuaia)", + "America\/Aruba": "Wektu Atlantik (Aruba)", + "America\/Asuncion": "Wektu Paraguay (Asuncion)", + "America\/Bahia": "Wektu Brasilia (Bahia)", + "America\/Bahia_Banderas": "Wektu Tengah (Bahia Banderas)", + "America\/Barbados": "Wektu Atlantik (Barbados)", + "America\/Belem": "Wektu Brasilia (Belem)", + "America\/Belize": "Wektu Tengah (Belise)", + "America\/Blanc-Sablon": "Wektu Atlantik (Blanc-Sablon)", + "America\/Boa_Vista": "Wektu Amazon (Boa Vista)", + "America\/Bogota": "Wektu Kolombia (Bogota)", + "America\/Boise": "Wektu Giri (Boise)", + "America\/Buenos_Aires": "Wektu Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Wektu Giri (Teluk Cambridge)", + "America\/Campo_Grande": "Wektu Amazon (Kampo Grande)", + "America\/Cancun": "Wektu sisih Wetan (Cancun)", + "America\/Caracas": "Wektu Venezuela (Karakas)", + "America\/Catamarca": "Wektu Argentina (Katamarka)", + "America\/Cayenne": "Wektu Guiana Prancis (Kayenne)", + "America\/Cayman": "Wektu sisih Wetan (Caiman)", + "America\/Chicago": "Wektu Tengah (Chicago)", + "America\/Chihuahua": "Wektu Pasifik Meksiko (Chihuahua)", + "America\/Coral_Harbour": "Wektu sisih Wetan (Atikokan)", + "America\/Cordoba": "Wektu Argentina (Kordoba)", + "America\/Costa_Rica": "Wektu Tengah (Kosta Rika)", + "America\/Creston": "Wektu Giri (Creston)", + "America\/Cuiaba": "Wektu Amazon (Kuiaba)", + "America\/Curacao": "Wektu Atlantik (Curacao)", + "America\/Danmarkshavn": "Wektu Rerata Greenwich (Danmarkshavn)", + "America\/Dawson": "Wektu Pasifik (Dawson)", + "America\/Dawson_Creek": "Wektu Giri (Dawson Creek)", + "America\/Denver": "Wektu Giri (Denver)", + "America\/Detroit": "Wektu sisih Wetan (Detroit)", + "America\/Dominica": "Wektu Atlantik (Dominika)", + "America\/Edmonton": "Wektu Giri (Edmonton)", + "America\/El_Salvador": "Wektu Tengah (El Salvador)", + "America\/Fort_Nelson": "Wektu Giri (Benteng Nelson)", + "America\/Fortaleza": "Wektu Brasilia (Fortaleza)", + "America\/Glace_Bay": "Wektu Atlantik (Teluk Glace)", + "America\/Godthab": "Wektu Grinland Kulon (Nuuk)", + "America\/Goose_Bay": "Wektu Atlantik (Teluk Goose)", + "America\/Grand_Turk": "Wektu sisih Wetan (Grand Turk)", + "America\/Grenada": "Wektu Atlantik (Grenada)", + "America\/Guadeloupe": "Wektu Atlantik (Guadeloupe)", + "America\/Guatemala": "Wektu Tengah (Guatemala)", + "America\/Guayaquil": "Wektu Ekuador (Guayaquil)", + "America\/Guyana": "Wektu Guyana (Guyana)", + "America\/Halifax": "Wektu Atlantik (Halifak)", + "America\/Havana": "Wektu Kuba (Havana)", + "America\/Hermosillo": "Wektu Pasifik Meksiko (Hermosillo)", + "America\/Indiana\/Knox": "Wektu Tengah (Knox [Indiana])", + "America\/Indiana\/Marengo": "Wektu sisih Wetan (Marengo [Indiana])", + "America\/Indiana\/Petersburg": "Wektu sisih Wetan (Petersburg [Indiana])", + "America\/Indiana\/Tell_City": "Wektu Tengah (Tell City [Indiana])", + "America\/Indiana\/Vevay": "Wektu sisih Wetan (Vevay [Indiana])", + "America\/Indiana\/Vincennes": "Wektu sisih Wetan (Vincennes [Indiana])", + "America\/Indiana\/Winamac": "Wektu sisih Wetan (Winamac [Indiana])", + "America\/Indianapolis": "Wektu sisih Wetan (Indianapolis)", + "America\/Inuvik": "Wektu Giri (Inuvik)", + "America\/Iqaluit": "Wektu sisih Wetan (Iqaluit)", + "America\/Jamaica": "Wektu sisih Wetan (Jamaica)", + "America\/Jujuy": "Wektu Argentina (Jujuy)", + "America\/Juneau": "Wektu Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Wektu sisih Wetan (Monticello [Kentucky])", + "America\/Kralendijk": "Wektu Atlantik (Kralendijk)", + "America\/La_Paz": "Wektu Bolivia (La Paz)", + "America\/Lima": "Wektu Peru (Lima)", + "America\/Los_Angeles": "Wektu Pasifik (Los Angeles)", + "America\/Louisville": "Wektu sisih Wetan (Louisville)", + "America\/Lower_Princes": "Wektu Atlantik (Lower Prince’s Quarter)", + "America\/Maceio": "Wektu Brasilia (Maceio)", + "America\/Managua": "Wektu Tengah (Managua)", + "America\/Manaus": "Wektu Amazon (Manaus)", + "America\/Marigot": "Wektu Atlantik (Marigot)", + "America\/Martinique": "Wektu Atlantik (Martinik)", + "America\/Matamoros": "Wektu Tengah (Matamoros)", + "America\/Mazatlan": "Wektu Pasifik Meksiko (Mazatlan)", + "America\/Mendoza": "Wektu Argentina (Mendosa)", + "America\/Menominee": "Wektu Tengah (Menominee)", + "America\/Merida": "Wektu Tengah (Merida)", + "America\/Metlakatla": "Wektu Alaska (Metlakatla)", + "America\/Mexico_City": "Wektu Tengah (Kutho Meksiko)", + "America\/Miquelon": "Wektu Santa Pierre lan Miquelon (Miquelon)", + "America\/Moncton": "Wektu Atlantik (Moncton)", + "America\/Monterrey": "Wektu Tengah (Monterrey)", + "America\/Montevideo": "Wektu Uruguay (Montevideo)", + "America\/Montserrat": "Wektu Atlantik (Montserrat)", + "America\/Nassau": "Wektu sisih Wetan (Nassau)", + "America\/New_York": "Wektu sisih Wetan (New York)", + "America\/Nipigon": "Wektu sisih Wetan (Nipigon)", + "America\/Nome": "Wektu Alaska (Nome)", + "America\/Noronha": "Wektu Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Wektu Tengah (Beulah [Dakota Lor])", + "America\/North_Dakota\/Center": "Wektu Tengah (Tengah [Dakota Lor])", + "America\/North_Dakota\/New_Salem": "Wektu Tengah (Salem Anyar [Dakota Lor])", + "America\/Ojinaga": "Wektu Giri (Ojinaga)", + "America\/Panama": "Wektu sisih Wetan (Panama)", + "America\/Pangnirtung": "Wektu sisih Wetan (Pangnirtung)", + "America\/Paramaribo": "Wektu Suriname (Paramaribo)", + "America\/Phoenix": "Wektu Giri (Phoenix)", + "America\/Port-au-Prince": "Wektu sisih Wetan (Port-au-Prince)", + "America\/Port_of_Spain": "Wektu Atlantik (Palabuhan Spanyol)", + "America\/Porto_Velho": "Wektu Amazon (Porto Velho)", + "America\/Puerto_Rico": "Wektu Atlantik (Puerto Riko)", + "America\/Punta_Arenas": "Wektu Chili (Punta Arenas)", + "America\/Rainy_River": "Wektu Tengah (Kali Rainy)", + "America\/Rankin_Inlet": "Wektu Tengah (Rankin Inlet)", + "America\/Recife": "Wektu Brasilia (Recife)", + "America\/Regina": "Wektu Tengah (Regina)", + "America\/Resolute": "Wektu Tengah (Resolute)", + "America\/Santa_Isabel": "Wektu Meksiko Lor-Kulon (Santa Isabel)", + "America\/Santarem": "Wektu Brasilia (Santarem)", + "America\/Santiago": "Wektu Chili (Santiago)", + "America\/Santo_Domingo": "Wektu Atlantik (Santo Domingo)", + "America\/Sao_Paulo": "Wektu Brasilia (Sao Paulo)", + "America\/Scoresbysund": "Wektu Grinland Wetan (Ittoqqortoormiit)", + "America\/Sitka": "Wektu Alaska (Sitka)", + "America\/St_Barthelemy": "Wektu Atlantik (Santa Barthelemy)", + "America\/St_Johns": "Wektu Newfoundland (Santa John)", + "America\/St_Kitts": "Wektu Atlantik (Santa Kitts)", + "America\/St_Lucia": "Wektu Atlantik (Santa Lucia)", + "America\/St_Thomas": "Wektu Atlantik (Santa Thomas)", + "America\/St_Vincent": "Wektu Atlantik (Santa Vincent)", + "America\/Swift_Current": "Wektu Tengah (Arus Banter)", + "America\/Tegucigalpa": "Wektu Tengah (Tegucigalpa)", + "America\/Thule": "Wektu Atlantik (Thule)", + "America\/Thunder_Bay": "Wektu sisih Wetan (Teluk Gludhug)", + "America\/Tijuana": "Wektu Pasifik (Tijuana)", + "America\/Toronto": "Wektu sisih Wetan (Toronto)", + "America\/Tortola": "Wektu Atlantik (Tortola)", + "America\/Vancouver": "Wektu Pasifik (Vancouver)", + "America\/Whitehorse": "Wektu Pasifik (Whitehorse)", + "America\/Winnipeg": "Wektu Tengah (Winnipeg)", + "America\/Yakutat": "Wektu Alaska (Yakutat)", + "America\/Yellowknife": "Wektu Giri (Yellowknife)", + "Antarctica\/Casey": "Wektu Australia sisih Kulon (Casey)", + "Antarctica\/Davis": "Wektu Davis (Davis)", + "Antarctica\/DumontDUrville": "Wektu Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Wektu Pulo Macquarie (Macquarie)", + "Antarctica\/Mawson": "Wektu Mawson (Mawson)", + "Antarctica\/McMurdo": "Wektu Selandia Anyar (McMurdo)", + "Antarctica\/Palmer": "Wektu Chili (Palmer)", + "Antarctica\/Rothera": "Wektu Rothera (Rothera)", + "Antarctica\/Syowa": "Wektu Syowa (Syowa)", + "Antarctica\/Troll": "Wektu Rerata Greenwich (Troll)", + "Antarctica\/Vostok": "Wektu Vostok (Vostok)", + "Arctic\/Longyearbyen": "Wektu Eropa Tengah (Longyearbyen)", + "Asia\/Aden": "Wektu Arab (Aden)", + "Asia\/Almaty": "Wektu Kazakhstan Wetan (Almaty)", + "Asia\/Amman": "Wektu Eropa sisih Wetan (Amman)", + "Asia\/Aqtau": "Wektu Kazakhstan Kulon (Aqtau)", + "Asia\/Aqtobe": "Wektu Kazakhstan Kulon (Aqtobe)", + "Asia\/Ashgabat": "Wektu Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Wektu Kazakhstan Kulon (Atyrau)", + "Asia\/Baghdad": "Wektu Arab (Baghdad)", + "Asia\/Bahrain": "Wektu Arab (Bahrain)", + "Asia\/Baku": "Wektu Azerbaijan (Baku)", + "Asia\/Bangkok": "Wektu Indocina (Bangkok)", + "Asia\/Beirut": "Wektu Eropa sisih Wetan (Beirut)", + "Asia\/Bishkek": "Wektu Kirgizstan (Bishkek)", + "Asia\/Brunei": "Wektu Brunai Darussalam (Brunei)", + "Asia\/Calcutta": "Wektu Standar India (Kalkuta)", + "Asia\/Chita": "Wektu Yakutsk (Chita)", + "Asia\/Choibalsan": "Wektu Choibalsan (Choibalsan)", + "Asia\/Colombo": "Wektu Standar India (Kolombo)", + "Asia\/Damascus": "Wektu Eropa sisih Wetan (Damaskus)", + "Asia\/Dhaka": "Wektu Bangladesh (Dhaka)", + "Asia\/Dili": "Wektu Timor Leste (Dili)", + "Asia\/Dubai": "Wektu Standar Teluk (Dubai)", + "Asia\/Dushanbe": "Wektu Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Wektu Eropa sisih Wetan (Famagusta)", + "Asia\/Gaza": "Wektu Eropa sisih Wetan (Gaza)", + "Asia\/Hebron": "Wektu Eropa sisih Wetan (Hebron)", + "Asia\/Hong_Kong": "Wektu Hong Kong (Hong Kong)", + "Asia\/Hovd": "Wektu Hovd (Hovd)", + "Asia\/Irkutsk": "Wektu Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Wektu Indonesia sisih Kulon (Jakarta)", + "Asia\/Jayapura": "Wektu Indonesia sisih Wetan (Jayapura)", + "Asia\/Jerusalem": "Wektu Israel (Yerusalem)", + "Asia\/Kabul": "Wektu Afghanistan (Kabul)", + "Asia\/Karachi": "Wektu Pakistan (Karachi)", + "Asia\/Katmandu": "Wektu Nepal (Kathmandu)", + "Asia\/Khandyga": "Wektu Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Wektu Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Wektu Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Wektu Malaysia (Kuching)", + "Asia\/Kuwait": "Wektu Arab (Kuwait)", + "Asia\/Macau": "Wektu Cina (Macau)", + "Asia\/Magadan": "Wektu Magadan (Magadan)", + "Asia\/Makassar": "Wektu Indonesia Tengah (Makasar)", + "Asia\/Manila": "Wektu Filipina (Manila)", + "Asia\/Muscat": "Wektu Standar Teluk (Muscat)", + "Asia\/Nicosia": "Wektu Eropa sisih Wetan (Nicosia)", + "Asia\/Novokuznetsk": "Wektu Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Wektu Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Wektu Omsk (Omsk)", + "Asia\/Oral": "Wektu Kazakhstan Kulon (Oral)", + "Asia\/Phnom_Penh": "Wektu Indocina (Phnom Penh)", + "Asia\/Pontianak": "Wektu Indonesia sisih Kulon (Pontianak)", + "Asia\/Pyongyang": "Wektu Korea (Pyongyang)", + "Asia\/Qatar": "Wektu Arab (Qatar)", + "Asia\/Qostanay": "Wektu Kazakhstan Wetan (Qostanay)", + "Asia\/Qyzylorda": "Wektu Kazakhstan Kulon (Qyzylorda)", + "Asia\/Rangoon": "Wektu Myanmar (Yangon)", + "Asia\/Riyadh": "Wektu Arab (Riyadh)", + "Asia\/Saigon": "Wektu Indocina (Ho Chi Minh)", + "Asia\/Sakhalin": "Wektu Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Wektu Usbekistan (Samarkand)", + "Asia\/Seoul": "Wektu Korea (Seoul)", + "Asia\/Shanghai": "Wektu Cina (Shanghai)", + "Asia\/Singapore": "Wektu Standar Singapura (Singapura)", + "Asia\/Srednekolymsk": "Wektu Magadan (Srednekolymsk)", + "Asia\/Taipei": "Wektu Taipei (Taipei)", + "Asia\/Tashkent": "Wektu Usbekistan (Tashkent)", + "Asia\/Tbilisi": "Wektu Georgia (Tbilisi)", + "Asia\/Tehran": "Wektu Iran (Teheran)", + "Asia\/Thimphu": "Wektu Bhutan (Thimphu)", + "Asia\/Tokyo": "Wektu Jepang (Tokyo)", + "Asia\/Ulaanbaatar": "Wektu Ulaanbaatar (Ulaanbaatar)", + "Asia\/Ust-Nera": "Wektu Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Wektu Indocina (Vientiane)", + "Asia\/Vladivostok": "Wektu Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Wektu Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Wektu Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Wektu Armenia (Yerevan)", + "Atlantic\/Azores": "Wektu Azores (Azores)", + "Atlantic\/Bermuda": "Wektu Atlantik (Bermuda)", + "Atlantic\/Canary": "Wektu Eropa sisih Kulon (Kanari)", + "Atlantic\/Cape_Verde": "Wektu Tanjung Verde (Kape Verde)", + "Atlantic\/Faeroe": "Wektu Eropa sisih Kulon (Faroe)", + "Atlantic\/Madeira": "Wektu Eropa sisih Kulon (Madeira)", + "Atlantic\/Reykjavik": "Wektu Rerata Greenwich (Reykjavik)", + "Atlantic\/South_Georgia": "Wektu Georgia Kidul (Georgia Kidul)", + "Atlantic\/St_Helena": "Wektu Rerata Greenwich (Saint Helena)", + "Atlantic\/Stanley": "Wektu Kepuloan Falkland (Stanley)", + "Australia\/Adelaide": "Wektu Australia Tengah (Adelaide)", + "Australia\/Brisbane": "Wektu Australia sisih Wetan (Brisbane)", + "Australia\/Broken_Hill": "Wektu Australia Tengah (Broken Hill)", + "Australia\/Currie": "Wektu Australia sisih Wetan (Currie)", + "Australia\/Darwin": "Wektu Australia Tengah (Darwin)", + "Australia\/Eucla": "Wektu Australia Tengah sisih Kulon (Eucla)", + "Australia\/Hobart": "Wektu Australia sisih Wetan (Hobart)", + "Australia\/Lindeman": "Wektu Australia sisih Wetan (Lindeman)", + "Australia\/Lord_Howe": "Wektu Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Wektu Australia sisih Wetan (Melbourne)", + "Australia\/Perth": "Wektu Australia sisih Kulon (Perth)", + "Australia\/Sydney": "Wektu Australia sisih Wetan (Sydney)", + "CST6CDT": "Wektu Tengah", + "EST5EDT": "Wektu sisih Wetan", + "Etc\/GMT": "Wektu Rerata Greenwich", + "Etc\/UTC": "Wektu Kordinat Universal", + "Europe\/Amsterdam": "Wektu Eropa Tengah (Amsterdam)", + "Europe\/Andorra": "Wektu Eropa Tengah (Andorra)", + "Europe\/Astrakhan": "Wektu Moscow (Astrakhan)", + "Europe\/Athens": "Wektu Eropa sisih Wetan (Athena)", + "Europe\/Belgrade": "Wektu Eropa Tengah (Belgrade)", + "Europe\/Berlin": "Wektu Eropa Tengah (Berlin)", + "Europe\/Bratislava": "Wektu Eropa Tengah (Bratislava)", + "Europe\/Brussels": "Wektu Eropa Tengah (Brussels)", + "Europe\/Bucharest": "Wektu Eropa sisih Wetan (Bucharest)", + "Europe\/Budapest": "Wektu Eropa Tengah (Budapest)", + "Europe\/Busingen": "Wektu Eropa Tengah (Busingen)", + "Europe\/Chisinau": "Wektu Eropa sisih Wetan (Chisinau)", + "Europe\/Copenhagen": "Wektu Eropa Tengah (Kopenhagen)", + "Europe\/Dublin": "Wektu Rerata Greenwich (Dublin)", + "Europe\/Gibraltar": "Wektu Eropa Tengah (Gibraltar)", + "Europe\/Guernsey": "Wektu Rerata Greenwich (Guernsey)", + "Europe\/Helsinki": "Wektu Eropa sisih Wetan (Helsinki)", + "Europe\/Isle_of_Man": "Wektu Rerata Greenwich (Pulo Man)", + "Europe\/Jersey": "Wektu Rerata Greenwich (Jersey)", + "Europe\/Kaliningrad": "Wektu Eropa sisih Wetan (Kaliningrad)", + "Europe\/Kiev": "Wektu Eropa sisih Wetan (Kiev)", + "Europe\/Lisbon": "Wektu Eropa sisih Kulon (Lisbon)", + "Europe\/Ljubljana": "Wektu Eropa Tengah (Ljubljana)", + "Europe\/London": "Wektu Rerata Greenwich (London)", + "Europe\/Luxembourg": "Wektu Eropa Tengah (Luksemburk)", + "Europe\/Madrid": "Wektu Eropa Tengah (Madrid)", + "Europe\/Malta": "Wektu Eropa Tengah (Malta)", + "Europe\/Mariehamn": "Wektu Eropa sisih Wetan (Mariehamn)", + "Europe\/Minsk": "Wektu Moscow (Minsk)", + "Europe\/Monaco": "Wektu Eropa Tengah (Monako)", + "Europe\/Moscow": "Wektu Moscow (Moscow)", + "Europe\/Oslo": "Wektu Eropa Tengah (Oslo)", + "Europe\/Paris": "Wektu Eropa Tengah (Paris)", + "Europe\/Podgorica": "Wektu Eropa Tengah (Podgorica)", + "Europe\/Prague": "Wektu Eropa Tengah (Prague)", + "Europe\/Riga": "Wektu Eropa sisih Wetan (Riga)", + "Europe\/Rome": "Wektu Eropa Tengah (Roma)", + "Europe\/San_Marino": "Wektu Eropa Tengah (San Marino)", + "Europe\/Sarajevo": "Wektu Eropa Tengah (Sarajevo)", + "Europe\/Saratov": "Wektu Moscow (Saratov)", + "Europe\/Simferopol": "Wektu Moscow (Simferopol)", + "Europe\/Skopje": "Wektu Eropa Tengah (Skopje)", + "Europe\/Sofia": "Wektu Eropa sisih Wetan (Sofia)", + "Europe\/Stockholm": "Wektu Eropa Tengah (Stockholm)", + "Europe\/Tallinn": "Wektu Eropa sisih Wetan (Tallinn)", + "Europe\/Tirane": "Wektu Eropa Tengah (Tirane)", + "Europe\/Ulyanovsk": "Wektu Moscow (Ulyanovsk)", + "Europe\/Uzhgorod": "Wektu Eropa sisih Wetan (Uzhgorod)", + "Europe\/Vaduz": "Wektu Eropa Tengah (Vaduz)", + "Europe\/Vatican": "Wektu Eropa Tengah (Vatikan)", + "Europe\/Vienna": "Wektu Eropa Tengah (Vienna)", + "Europe\/Vilnius": "Wektu Eropa sisih Wetan (Vilnius)", + "Europe\/Volgograd": "Wektu Volgograd (Volgograd)", + "Europe\/Warsaw": "Wektu Eropa Tengah (Warsaw)", + "Europe\/Zagreb": "Wektu Eropa Tengah (Zagreb)", + "Europe\/Zaporozhye": "Wektu Eropa sisih Wetan (Zaporozhye)", + "Europe\/Zurich": "Wektu Eropa Tengah (Zurich)", + "Indian\/Antananarivo": "Wektu Afrika Wetan (Antananarivo)", + "Indian\/Chagos": "Wektu Segoro Hindia (Khagos)", + "Indian\/Christmas": "Wektu Pulo Natal (Natal)", + "Indian\/Cocos": "Wektu Kepuloan Cocos (Cocos)", + "Indian\/Comoro": "Wektu Afrika Wetan (Komoro)", + "Indian\/Kerguelen": "Wektu Antartika lan Prancis sisih Kidul (Kerguelen)", + "Indian\/Mahe": "Wektu Seichelles (Mahe)", + "Indian\/Maldives": "Wektu Maladewa (Maladewa)", + "Indian\/Mauritius": "Wektu Mauritius (Mauritius)", + "Indian\/Mayotte": "Wektu Afrika Wetan (Mayotte)", + "Indian\/Reunion": "Wektu Reunion (Reunion)", + "MST7MDT": "Wektu Giri", + "PST8PDT": "Wektu Pasifik", + "Pacific\/Apia": "Wektu Apia (Apia)", + "Pacific\/Auckland": "Wektu Selandia Anyar (Auckland)", + "Pacific\/Bougainville": "Wektu Papua Nugini (Bougainville)", + "Pacific\/Chatham": "Wektu Chatham (Chatham)", + "Pacific\/Easter": "Wektu Pulo Paskah (Paskah)", + "Pacific\/Efate": "Wektu Vanuatu (Efate)", + "Pacific\/Enderbury": "Wektu Kepuloan Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Wektu Tokelau (Fakaofo)", + "Pacific\/Fiji": "Wektu Fiji (Fiji)", + "Pacific\/Funafuti": "Wektu Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Wektu Galapagos (Galapagos)", + "Pacific\/Gambier": "Wektu Gambier (Gambier)", + "Pacific\/Guadalcanal": "Wektu Kepuloan Solomon (Guadalcanal)", + "Pacific\/Guam": "Wektu Standar Chamorro (Guam)", + "Pacific\/Honolulu": "Wektu Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Wektu Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Wektu Kepuloan Line (Kiritimati)", + "Pacific\/Kosrae": "Wektu Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Wektu Kepuloan Marshall (Kwajalein)", + "Pacific\/Majuro": "Wektu Kepuloan Marshall (Majuro)", + "Pacific\/Marquesas": "Wektu Marquesas (Marquesas)", + "Pacific\/Midway": "Wektu Samoa (Midway)", + "Pacific\/Nauru": "Wektu Nauru (Nauru)", + "Pacific\/Niue": "Wektu Niue (Niue)", + "Pacific\/Norfolk": "Wektu Pulo Norfolk (Norfolk)", + "Pacific\/Noumea": "Wektu Kaledonia Anyar (Noumea)", + "Pacific\/Pago_Pago": "Wektu Samoa (Pago Pago)", + "Pacific\/Palau": "Wektu Palau (Palau)", + "Pacific\/Pitcairn": "Wektu Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Wektu Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Wektu Papua Nugini (Pelabuhan Moresby)", + "Pacific\/Rarotonga": "Wektu Kepuloan Cook (Rarotonga)", + "Pacific\/Saipan": "Wektu Standar Chamorro (Saipan)", + "Pacific\/Tahiti": "Wektu Tahiti (Tahiti)", + "Pacific\/Tarawa": "Wektu Kepuloan Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Wektu Tonga (Tongatapu)", + "Pacific\/Truk": "Wektu Chuuk (Chuuk)", + "Pacific\/Wake": "Wektu Pulo Wake (Wake)", + "Pacific\/Wallis": "Wektu Wallis lan Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ka.json b/src/Symfony/Component/Intl/Resources/data/timezones/ka.json new file mode 100644 index 0000000000000..2eaaa42acdd8f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ka.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "გრინვიჩის საშუალო დრო (აბიჯანი)", + "Africa\/Accra": "გრინვიჩის საშუალო დრო (აკრა)", + "Africa\/Addis_Ababa": "აღმოსავლეთ აფრიკის დრო (ადის-აბება)", + "Africa\/Algiers": "ცენტრალური ევროპის დრო (ალჟირი)", + "Africa\/Asmera": "აღმოსავლეთ აფრიკის დრო (ასმარა)", + "Africa\/Bamako": "გრინვიჩის საშუალო დრო (ბამაკო)", + "Africa\/Bangui": "დასავლეთ აფრიკის დრო (ბანგი)", + "Africa\/Banjul": "გრინვიჩის საშუალო დრო (ბანჯული)", + "Africa\/Bissau": "გრინვიჩის საშუალო დრო (ბისაუ)", + "Africa\/Blantyre": "ცენტრალური აფრიკის დრო (ბლანტირი)", + "Africa\/Brazzaville": "დასავლეთ აფრიკის დრო (ბრაზავილი)", + "Africa\/Bujumbura": "ცენტრალური აფრიკის დრო (ბუჯუმბურა)", + "Africa\/Cairo": "აღმოსავლეთ ევროპის დრო (კაირო)", + "Africa\/Casablanca": "დასავლეთ ევროპის დრო (კასაბლანკა)", + "Africa\/Ceuta": "ცენტრალური ევროპის დრო (სეუტა)", + "Africa\/Conakry": "გრინვიჩის საშუალო დრო (კონაკრი)", + "Africa\/Dakar": "გრინვიჩის საშუალო დრო (დაკარი)", + "Africa\/Dar_es_Salaam": "აღმოსავლეთ აფრიკის დრო (დარ-ეს-სალამი)", + "Africa\/Djibouti": "აღმოსავლეთ აფრიკის დრო (ჯიბუტი)", + "Africa\/Douala": "დასავლეთ აფრიკის დრო (დუალა)", + "Africa\/El_Aaiun": "დასავლეთ ევროპის დრო (ელ-ააიუნი)", + "Africa\/Freetown": "გრინვიჩის საშუალო დრო (ფრიტაუნი)", + "Africa\/Gaborone": "ცენტრალური აფრიკის დრო (გაბორონე)", + "Africa\/Harare": "ცენტრალური აფრიკის დრო (ჰარარე)", + "Africa\/Johannesburg": "სამხრეთ აფრიკის დრო (იოჰანესბურგი)", + "Africa\/Juba": "აღმოსავლეთ აფრიკის დრო (ჯუბა)", + "Africa\/Kampala": "აღმოსავლეთ აფრიკის დრო (კამპალა)", + "Africa\/Khartoum": "ცენტრალური აფრიკის დრო (ხარტუმი)", + "Africa\/Kigali": "ცენტრალური აფრიკის დრო (კიგალი)", + "Africa\/Kinshasa": "დასავლეთ აფრიკის დრო (კინშასა)", + "Africa\/Lagos": "დასავლეთ აფრიკის დრო (ლაგოსი)", + "Africa\/Libreville": "დასავლეთ აფრიკის დრო (ლიბრევილი)", + "Africa\/Lome": "გრინვიჩის საშუალო დრო (ლომე)", + "Africa\/Luanda": "დასავლეთ აფრიკის დრო (ლუანდა)", + "Africa\/Lubumbashi": "ცენტრალური აფრიკის დრო (ლუბუმბაში)", + "Africa\/Lusaka": "ცენტრალური აფრიკის დრო (ლუსაკა)", + "Africa\/Malabo": "დასავლეთ აფრიკის დრო (მალაბო)", + "Africa\/Maputo": "ცენტრალური აფრიკის დრო (მაპუტო)", + "Africa\/Maseru": "სამხრეთ აფრიკის დრო (მასერუ)", + "Africa\/Mbabane": "სამხრეთ აფრიკის დრო (მბაბანე)", + "Africa\/Mogadishu": "აღმოსავლეთ აფრიკის დრო (მოგადიშუ)", + "Africa\/Monrovia": "გრინვიჩის საშუალო დრო (მონროვია)", + "Africa\/Nairobi": "აღმოსავლეთ აფრიკის დრო (ნაირობი)", + "Africa\/Ndjamena": "დასავლეთ აფრიკის დრო (ნჯამენა)", + "Africa\/Niamey": "დასავლეთ აფრიკის დრო (ნიამეი)", + "Africa\/Nouakchott": "გრინვიჩის საშუალო დრო (ნუაკშოტი)", + "Africa\/Ouagadougou": "გრინვიჩის საშუალო დრო (უაგადუგუ)", + "Africa\/Porto-Novo": "დასავლეთ აფრიკის დრო (პორტო-ნოვო)", + "Africa\/Sao_Tome": "გრინვიჩის საშუალო დრო (სენ-ტომე)", + "Africa\/Tripoli": "აღმოსავლეთ ევროპის დრო (ტრიპოლი)", + "Africa\/Tunis": "ცენტრალური ევროპის დრო (ტუნისი)", + "Africa\/Windhoek": "ცენტრალური აფრიკის დრო (ვინდხუკი)", + "America\/Adak": "ჰავაისა და ალეუტის დრო (ადაკი)", + "America\/Anchorage": "ალასკის დრო (ენქორაჯი)", + "America\/Anguilla": "ატლანტიკის ოკეანის დრო (ანგილა)", + "America\/Antigua": "ატლანტიკის ოკეანის დრო (ანტიგუა)", + "America\/Araguaina": "ბრაზილიის დრო (არაგუაინა)", + "America\/Argentina\/La_Rioja": "არგენტინის დრო (ლა რიოხა)", + "America\/Argentina\/Rio_Gallegos": "არგენტინის დრო (რიო გალეგოსი)", + "America\/Argentina\/Salta": "არგენტინის დრო (სალტა)", + "America\/Argentina\/San_Juan": "არგენტინის დრო (სან ხუანი)", + "America\/Argentina\/San_Luis": "დასავლეთ არგენტინის დრო (სან-ლუისი)", + "America\/Argentina\/Tucuman": "არგენტინის დრო (ტუკუმანი)", + "America\/Argentina\/Ushuaia": "არგენტინის დრო (უშუაია)", + "America\/Aruba": "ატლანტიკის ოკეანის დრო (არუბა)", + "America\/Asuncion": "პარაგვაის დრო (ასუნსიონი)", + "America\/Bahia": "ბრაზილიის დრო (ბაია)", + "America\/Bahia_Banderas": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ბაჰია ბანდერასი)", + "America\/Barbados": "ატლანტიკის ოკეანის დრო (ბარბადოსი)", + "America\/Belem": "ბრაზილიის დრო (ბელემი)", + "America\/Belize": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ბელიზი)", + "America\/Blanc-Sablon": "ატლანტიკის ოკეანის დრო (ბლან-საბლონი)", + "America\/Boa_Vista": "ამაზონიის დრო (ბოა ვისტა)", + "America\/Bogota": "კოლუმბიის დრო (ბოგოტა)", + "America\/Boise": "ჩრდილოეთ ამერიკის მაუნთინის დრო (ბუასი)", + "America\/Buenos_Aires": "არგენტინის დრო (ბუენოს-აირესი)", + "America\/Cambridge_Bay": "ჩრდილოეთ ამერიკის მაუნთინის დრო (კემბრიჯ ბეი)", + "America\/Campo_Grande": "ამაზონიის დრო (კამპო გრანდე)", + "America\/Cancun": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (კანკუნი)", + "America\/Caracas": "ვენესუელის დრო (კარაკასი)", + "America\/Catamarca": "არგენტინის დრო (კატამარკა)", + "America\/Cayenne": "საფრანგეთის გვიანის დრო (კაიენა)", + "America\/Cayman": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (კაიმანი)", + "America\/Chicago": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ჩიკაგო)", + "America\/Chihuahua": "მექსიკის წყნარი ოკეანის დრო (ჩიჰუაჰუა)", + "America\/Coral_Harbour": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ატიკოკანი)", + "America\/Cordoba": "არგენტინის დრო (კორდობა)", + "America\/Costa_Rica": "ჩრდილოეთ ამერიკის ცენტრალური დრო (კოსტა-რიკა)", + "America\/Creston": "ჩრდილოეთ ამერიკის მაუნთინის დრო (კრესტონი)", + "America\/Cuiaba": "ამაზონიის დრო (კუიაბა)", + "America\/Curacao": "ატლანტიკის ოკეანის დრო (კიურასაო)", + "America\/Danmarkshavn": "გრინვიჩის საშუალო დრო (დენმარკშავნი)", + "America\/Dawson": "ჩრდილოეთ ამერიკის წყნარი ოკეანის დრო (დოუსონი)", + "America\/Dawson_Creek": "ჩრდილოეთ ამერიკის მაუნთინის დრო (დოუსონ ქრიკი)", + "America\/Denver": "ჩრდილოეთ ამერიკის მაუნთინის დრო (დენვერი)", + "America\/Detroit": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (დეტროიტი)", + "America\/Dominica": "ატლანტიკის ოკეანის დრო (დომინიკა)", + "America\/Edmonton": "ჩრდილოეთ ამერიკის მაუნთინის დრო (ედმონტონი)", + "America\/El_Salvador": "ჩრდილოეთ ამერიკის ცენტრალური დრო (სალვადორი)", + "America\/Fort_Nelson": "ჩრდილოეთ ამერიკის მაუნთინის დრო (ფორტ-ნელსონი)", + "America\/Fortaleza": "ბრაზილიის დრო (ფორტალეზა)", + "America\/Glace_Bay": "ატლანტიკის ოკეანის დრო (გლეის ბეი)", + "America\/Godthab": "დასავლეთ გრენლანდიის დრო (გოდთები)", + "America\/Goose_Bay": "ატლანტიკის ოკეანის დრო (გუზ ბეი)", + "America\/Grand_Turk": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (გრანდ-ტურკი)", + "America\/Grenada": "ატლანტიკის ოკეანის დრო (გრენადა)", + "America\/Guadeloupe": "ატლანტიკის ოკეანის დრო (გვადელუპა)", + "America\/Guatemala": "ჩრდილოეთ ამერიკის ცენტრალური დრო (გვატემალა)", + "America\/Guayaquil": "ეკვადორის დრო (გუაიაკილი)", + "America\/Guyana": "გაიანის დრო (გაიანა)", + "America\/Halifax": "ატლანტიკის ოკეანის დრო (ჰალიფაქსი)", + "America\/Havana": "კუბის დრო (ჰავანა)", + "America\/Hermosillo": "მექსიკის წყნარი ოკეანის დრო (ჰერმოსილო)", + "America\/Indiana\/Knox": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ნოქსი, ინდიანა)", + "America\/Indiana\/Marengo": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (მარენგო, ინდიანა)", + "America\/Indiana\/Petersburg": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (პიტერსბურგი, ინდიანა)", + "America\/Indiana\/Tell_City": "ჩრდილოეთ ამერიკის ცენტრალური დრო (თელ სითი, ინდიანა)", + "America\/Indiana\/Vevay": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ვივეი, ინდიანა)", + "America\/Indiana\/Vincennes": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ვინსენი, ინდიანა)", + "America\/Indiana\/Winamac": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (უინემაკი, ინდიანა)", + "America\/Indianapolis": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ინდიანაპოლისი)", + "America\/Inuvik": "ჩრდილოეთ ამერიკის მაუნთინის დრო (ინუვიკი)", + "America\/Iqaluit": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (იქალუიტი)", + "America\/Jamaica": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (იამაიკა)", + "America\/Jujuy": "არგენტინის დრო (ჯუჯუი)", + "America\/Juneau": "ალასკის დრო (ჯუნო)", + "America\/Kentucky\/Monticello": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (მონტიჩელო, კენტუკი)", + "America\/Kralendijk": "ატლანტიკის ოკეანის დრო (კრალენდიიკი)", + "America\/La_Paz": "ბოლივიის დრო (ლა-პაზი)", + "America\/Lima": "პერუს დრო (ლიმა)", + "America\/Los_Angeles": "ჩრდილოეთ ამერიკის წყნარი ოკეანის დრო (ლოს-ანჯელესი)", + "America\/Louisville": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ლუისვილი)", + "America\/Lower_Princes": "ატლანტიკის ოკეანის დრო (ლოერ პრინც კვორტერი)", + "America\/Maceio": "ბრაზილიის დრო (მასეიო)", + "America\/Managua": "ჩრდილოეთ ამერიკის ცენტრალური დრო (მანაგუა)", + "America\/Manaus": "ამაზონიის დრო (მანაუსი)", + "America\/Marigot": "ატლანტიკის ოკეანის დრო (მარიგო)", + "America\/Martinique": "ატლანტიკის ოკეანის დრო (მარტინიკი)", + "America\/Matamoros": "ჩრდილოეთ ამერიკის ცენტრალური დრო (მატამოროსი)", + "America\/Mazatlan": "მექსიკის წყნარი ოკეანის დრო (მაზატლანი)", + "America\/Mendoza": "არგენტინის დრო (მენდოზა)", + "America\/Menominee": "ჩრდილოეთ ამერიკის ცენტრალური დრო (მენომინი)", + "America\/Merida": "ჩრდილოეთ ამერიკის ცენტრალური დრო (მერიდა)", + "America\/Metlakatla": "ალასკის დრო (მეტლაკატლა)", + "America\/Mexico_City": "ჩრდილოეთ ამერიკის ცენტრალური დრო (მეხიკო)", + "America\/Miquelon": "სენ-პიერის და მიკელონის დრო (მიკელონი)", + "America\/Moncton": "ატლანტიკის ოკეანის დრო (მონქტონი)", + "America\/Monterrey": "ჩრდილოეთ ამერიკის ცენტრალური დრო (მონტერეი)", + "America\/Montevideo": "ურუგვაის დრო (მონტევიდეო)", + "America\/Montserrat": "ატლანტიკის ოკეანის დრო (მონსერატი)", + "America\/Nassau": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ნასაუ)", + "America\/New_York": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ნიუ-იორკი)", + "America\/Nipigon": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ნიპიგონი)", + "America\/Nome": "ალასკის დრო (ნომი)", + "America\/Noronha": "ფერნანდო-დე-ნორონიას დრო (ნორონია)", + "America\/North_Dakota\/Beulah": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ბიულა, ჩრდილოეთი დაკოტა)", + "America\/North_Dakota\/Center": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ცენტრი, ჩრდილოეთი დაკოტა)", + "America\/North_Dakota\/New_Salem": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ნიუ-სალემი, ჩრდილოეთი დაკოტა)", + "America\/Ojinaga": "ჩრდილოეთ ამერიკის მაუნთინის დრო (ოხინაგა)", + "America\/Panama": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (პანამა)", + "America\/Pangnirtung": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (პანგნირტუნგი)", + "America\/Paramaribo": "სურინამის დრო (პარამარიბო)", + "America\/Phoenix": "ჩრდილოეთ ამერიკის მაუნთინის დრო (ფენიქსი)", + "America\/Port-au-Prince": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (პორტ-ა-პრინსი)", + "America\/Port_of_Spain": "ატლანტიკის ოკეანის დრო (პორტ-ოვ-სპეინი)", + "America\/Porto_Velho": "ამაზონიის დრო (პორტუ-ველიო)", + "America\/Puerto_Rico": "ატლანტიკის ოკეანის დრო (პუერტო-რიკო)", + "America\/Punta_Arenas": "ჩილეს დრო (პუნტა-არენასი)", + "America\/Rainy_River": "ჩრდილოეთ ამერიკის ცენტრალური დრო (რეინი რივერი)", + "America\/Rankin_Inlet": "ჩრდილოეთ ამერიკის ცენტრალური დრო (რენკინ ინლეტი)", + "America\/Recife": "ბრაზილიის დრო (რეციფე)", + "America\/Regina": "ჩრდილოეთ ამერიკის ცენტრალური დრო (რეჯინა)", + "America\/Resolute": "ჩრდილოეთ ამერიკის ცენტრალური დრო (რეზოლუტე)", + "America\/Santa_Isabel": "ჩრდილო-აღმოსავლეთ მექსიკის დრო (სანტა ისაბელი)", + "America\/Santarem": "ბრაზილიის დრო (სანტარემი)", + "America\/Santiago": "ჩილეს დრო (სანტიაგო)", + "America\/Santo_Domingo": "ატლანტიკის ოკეანის დრო (სანტო-დომინგო)", + "America\/Sao_Paulo": "ბრაზილიის დრო (სან-პაულუ)", + "America\/Scoresbysund": "აღმოსავლეთ გრენლანდიის დრო (სკორსბისუნდი)", + "America\/Sitka": "ალასკის დრო (სიტკა)", + "America\/St_Barthelemy": "ატლანტიკის ოკეანის დრო (სენ-ბართელემი)", + "America\/St_Johns": "ნიუფაუნდლენდის დრო (სენტ-ჯონსი)", + "America\/St_Kitts": "ატლანტიკის ოკეანის დრო (სენტ-კიტსი)", + "America\/St_Lucia": "ატლანტიკის ოკეანის დრო (სენტ-ლუსია)", + "America\/St_Thomas": "ატლანტიკის ოკეანის დრო (სენ-ტომასი)", + "America\/St_Vincent": "ატლანტიკის ოკეანის დრო (სენ-ვინსენტი)", + "America\/Swift_Current": "ჩრდილოეთ ამერიკის ცენტრალური დრო (სვიფტ კარენტი)", + "America\/Tegucigalpa": "ჩრდილოეთ ამერიკის ცენტრალური დრო (ტეგუჩიგალპა)", + "America\/Thule": "ატლანტიკის ოკეანის დრო (თულე)", + "America\/Thunder_Bay": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (თანდერ ბეი)", + "America\/Tijuana": "ჩრდილოეთ ამერიკის წყნარი ოკეანის დრო (ტიხუანა)", + "America\/Toronto": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო (ტორონტო)", + "America\/Tortola": "ატლანტიკის ოკეანის დრო (ტორტოლა)", + "America\/Vancouver": "ჩრდილოეთ ამერიკის წყნარი ოკეანის დრო (ვანკუვერი)", + "America\/Whitehorse": "ჩრდილოეთ ამერიკის წყნარი ოკეანის დრო (უაითჰორსი)", + "America\/Winnipeg": "ჩრდილოეთ ამერიკის ცენტრალური დრო (უინიპეგი)", + "America\/Yakutat": "ალასკის დრო (იაკუტატი)", + "America\/Yellowknife": "ჩრდილოეთ ამერიკის მაუნთინის დრო (იელოუნაიფი)", + "Antarctica\/Casey": "დასავლეთ ავსტრალიის დრო (კეისი)", + "Antarctica\/Davis": "დევისის დრო (დევისი)", + "Antarctica\/DumontDUrville": "დუმონ-დურვილის დრო (დიუმონ დ’ურვილი)", + "Antarctica\/Macquarie": "მაქკუორის კუნძულის დრო (მექვორი)", + "Antarctica\/Mawson": "მოუსონის დრო (მოუსონი)", + "Antarctica\/McMurdo": "ახალი ზელანდიის დრო (მაკმურდო)", + "Antarctica\/Palmer": "ჩილეს დრო (პალმერი)", + "Antarctica\/Rothera": "როთერის დრო (როთერა)", + "Antarctica\/Syowa": "სიოვას დრო (სიოუა)", + "Antarctica\/Troll": "გრინვიჩის საშუალო დრო (ტროლი)", + "Antarctica\/Vostok": "ვოსტოკის დრო (ვოსტოკი)", + "Arctic\/Longyearbyen": "ცენტრალური ევროპის დრო (ლონგირბიენი)", + "Asia\/Aden": "არაბეთის დრო (ადენი)", + "Asia\/Almaty": "აღმოსავლეთ ყაზახეთის დრო (ალმატი)", + "Asia\/Amman": "აღმოსავლეთ ევროპის დრო (ამანი)", + "Asia\/Aqtau": "დასავლეთ ყაზახეთის დრო (აქტაუ)", + "Asia\/Aqtobe": "დასავლეთ ყაზახეთის დრო (აქტობე)", + "Asia\/Ashgabat": "თურქმენეთის დრო (აშხაბადი)", + "Asia\/Atyrau": "დასავლეთ ყაზახეთის დრო (ატირაუ)", + "Asia\/Baghdad": "არაბეთის დრო (ბაღდადი)", + "Asia\/Bahrain": "არაბეთის დრო (ბაჰრეინი)", + "Asia\/Baku": "აზერბაიჯანის დრო (ბაქო)", + "Asia\/Bangkok": "ინდოჩინეთის დრო (ბანგკოკი)", + "Asia\/Beirut": "აღმოსავლეთ ევროპის დრო (ბეირუთი)", + "Asia\/Bishkek": "ყირგიზეთის დრო (ბიშკეკი)", + "Asia\/Brunei": "ბრუნეი-დარუსალამის დრო (ბრუნეი)", + "Asia\/Calcutta": "ინდოეთის დრო (კალკუტა)", + "Asia\/Chita": "იაკუტსკის დრო (ჩიტა)", + "Asia\/Choibalsan": "ჩოიბალსანის დრო (ჩოიბალსანი)", + "Asia\/Colombo": "ინდოეთის დრო (კოლომბო)", + "Asia\/Damascus": "აღმოსავლეთ ევროპის დრო (დამასკი)", + "Asia\/Dhaka": "ბანგლადეშის დრო (დაკა)", + "Asia\/Dili": "აღმოსავლეთ ტიმორის დრო (დილი)", + "Asia\/Dubai": "სპარსეთის ყურის სტანდარტული დრო (დუბაი)", + "Asia\/Dushanbe": "ტაჯიკეთის დრო (დუშანბე)", + "Asia\/Famagusta": "აღმოსავლეთ ევროპის დრო (ფამაგუსტა)", + "Asia\/Gaza": "აღმოსავლეთ ევროპის დრო (გაზა)", + "Asia\/Hebron": "აღმოსავლეთ ევროპის დრო (ჰებრონი)", + "Asia\/Hong_Kong": "ჰონკონგის დრო (ჰონკონგი)", + "Asia\/Hovd": "ჰოვდის დრო (ჰოვდი)", + "Asia\/Irkutsk": "ირკუტსკის დრო (ირკუტსკი)", + "Asia\/Jakarta": "დასავლეთ ინდონეზიის დრო (ჯაკარტა)", + "Asia\/Jayapura": "აღმოსავლეთ ინდონეზიის დრო (ჯაიაპურა)", + "Asia\/Jerusalem": "ისრაელის დრო (იერუსალიმი)", + "Asia\/Kabul": "ავღანეთის დრო (ქაბული)", + "Asia\/Karachi": "პაკისტანის დრო (კარაჩი)", + "Asia\/Katmandu": "ნეპალის დრო (კატმანდუ)", + "Asia\/Khandyga": "იაკუტსკის დრო (ხანდიგა)", + "Asia\/Krasnoyarsk": "კრასნოიარსკის დრო (კრასნოიარსკი)", + "Asia\/Kuala_Lumpur": "მალაიზიის დრო (კუალა-ლუმპური)", + "Asia\/Kuching": "მალაიზიის დრო (კუჩინგი)", + "Asia\/Kuwait": "არაბეთის დრო (ქუვეითი)", + "Asia\/Macau": "ჩინეთის დრო (მაკაო)", + "Asia\/Magadan": "მაგადანის დრო (მაგადანი)", + "Asia\/Makassar": "ცენტრალური ინდონეზიის დრო (მაკასარი)", + "Asia\/Manila": "ფილიპინების დრო (მანილა)", + "Asia\/Muscat": "სპარსეთის ყურის სტანდარტული დრო (მუსკატი)", + "Asia\/Nicosia": "აღმოსავლეთ ევროპის დრო (ნიკოსია)", + "Asia\/Novokuznetsk": "კრასნოიარსკის დრო (ნოვოკუზნეცკი)", + "Asia\/Novosibirsk": "ნოვოსიბირსკის დრო (ნოვოსიბირსკი)", + "Asia\/Omsk": "ომსკის დრო (ომსკი)", + "Asia\/Oral": "დასავლეთ ყაზახეთის დრო (ორალი)", + "Asia\/Phnom_Penh": "ინდოჩინეთის დრო (პნომპენი)", + "Asia\/Pontianak": "დასავლეთ ინდონეზიის დრო (პონტიანაკი)", + "Asia\/Pyongyang": "კორეის დრო (ფხენიანი)", + "Asia\/Qatar": "არაბეთის დრო (კატარი)", + "Asia\/Qostanay": "აღმოსავლეთ ყაზახეთის დრო (კოსტანაი)", + "Asia\/Qyzylorda": "დასავლეთ ყაზახეთის დრო (ყიზილორდა)", + "Asia\/Rangoon": "მიანმარის დრო (რანგუნი)", + "Asia\/Riyadh": "არაბეთის დრო (ერ-რიადი)", + "Asia\/Saigon": "ინდოჩინეთის დრო (ჰოჩიმინი)", + "Asia\/Sakhalin": "სახალინის დრო (სახალინი)", + "Asia\/Samarkand": "უზბეკეთის დრო (სამარყანდი)", + "Asia\/Seoul": "კორეის დრო (სეული)", + "Asia\/Shanghai": "ჩინეთის დრო (შანხაი)", + "Asia\/Singapore": "სინგაპურის დრო (სინგაპური)", + "Asia\/Srednekolymsk": "მაგადანის დრო (სრედნეკოლიმსკი)", + "Asia\/Taipei": "ტაიბეის დრო (ტაიპეი)", + "Asia\/Tashkent": "უზბეკეთის დრო (ტაშკენტი)", + "Asia\/Tbilisi": "საქართველოს დრო (თბილისი)", + "Asia\/Tehran": "ირანის დრო (თეირანი)", + "Asia\/Thimphu": "ბუტანის დრო (თხიმფხუ)", + "Asia\/Tokyo": "იაპონიის დრო (ტოკიო)", + "Asia\/Ulaanbaatar": "ულან-ბატორის დრო (ულანბატარი)", + "Asia\/Ust-Nera": "ვლადივოსტოკის დრო (უსტ-ნერა)", + "Asia\/Vientiane": "ინდოჩინეთის დრო (ვიენტიანი)", + "Asia\/Vladivostok": "ვლადივოსტოკის დრო (ვლადივოსტოკი)", + "Asia\/Yakutsk": "იაკუტსკის დრო (იაკუტსკი)", + "Asia\/Yekaterinburg": "ეკატერინბურგის დრო (ეკატერინბურგი)", + "Asia\/Yerevan": "სომხეთის დრო (ერევანი)", + "Atlantic\/Azores": "აზორის კუნძულების დრო (აზორის კუნძულები)", + "Atlantic\/Bermuda": "ატლანტიკის ოკეანის დრო (ბერმუდა)", + "Atlantic\/Canary": "დასავლეთ ევროპის დრო (კანარი)", + "Atlantic\/Cape_Verde": "კაბო-ვერდეს დრო (კაბო-ვერდე)", + "Atlantic\/Faeroe": "დასავლეთ ევროპის დრო (ფარერის კუნძულები)", + "Atlantic\/Madeira": "დასავლეთ ევროპის დრო (მადეირა)", + "Atlantic\/Reykjavik": "გრინვიჩის საშუალო დრო (რეიკიავიკი)", + "Atlantic\/South_Georgia": "სამხრეთ გეორგიის დრო (სამხრეთ ჯორჯია)", + "Atlantic\/St_Helena": "გრინვიჩის საშუალო დრო (წმ. ელენეს კუნძული)", + "Atlantic\/Stanley": "ფოლკლენდის კუნძულების დრო (სტენლი)", + "Australia\/Adelaide": "ცენტრალური ავსტრალიის დრო (ადელაიდა)", + "Australia\/Brisbane": "აღმოსავლეთ ავსტრალიის დრო (ბრისბეინი)", + "Australia\/Broken_Hill": "ცენტრალური ავსტრალიის დრო (ბროუკენ ჰილი)", + "Australia\/Currie": "აღმოსავლეთ ავსტრალიის დრო (ქური)", + "Australia\/Darwin": "ცენტრალური ავსტრალიის დრო (დარვინი)", + "Australia\/Eucla": "ცენტრალური და დასავლეთ ავსტრალიის დრო (ეუკლა)", + "Australia\/Hobart": "აღმოსავლეთ ავსტრალიის დრო (ჰობარტი)", + "Australia\/Lindeman": "აღმოსავლეთ ავსტრალიის დრო (ლინდმანი)", + "Australia\/Lord_Howe": "ლორდ-ჰაუს დრო (ლორდ ჰოუი)", + "Australia\/Melbourne": "აღმოსავლეთ ავსტრალიის დრო (მელბურნი)", + "Australia\/Perth": "დასავლეთ ავსტრალიის დრო (პერთი)", + "Australia\/Sydney": "აღმოსავლეთ ავსტრალიის დრო (სიდნეი)", + "CST6CDT": "ჩრდილოეთ ამერიკის ცენტრალური დრო", + "EST5EDT": "ჩრდილოეთ ამერიკის აღმოსავლეთის დრო", + "Etc\/GMT": "გრინვიჩის საშუალო დრო", + "Etc\/UTC": "მსოფლიო კოორდინირებული დრო", + "Europe\/Amsterdam": "ცენტრალური ევროპის დრო (ამსტერდამი)", + "Europe\/Andorra": "ცენტრალური ევროპის დრო (ანდორა)", + "Europe\/Astrakhan": "მოსკოვის დრო (ასტრახანი)", + "Europe\/Athens": "აღმოსავლეთ ევროპის დრო (ათენი)", + "Europe\/Belgrade": "ცენტრალური ევროპის დრო (ბელგრადი)", + "Europe\/Berlin": "ცენტრალური ევროპის დრო (ბერლინი)", + "Europe\/Bratislava": "ცენტრალური ევროპის დრო (ბრატისლავა)", + "Europe\/Brussels": "ცენტრალური ევროპის დრო (ბრიუსელი)", + "Europe\/Bucharest": "აღმოსავლეთ ევროპის დრო (ბუხარესტი)", + "Europe\/Budapest": "ცენტრალური ევროპის დრო (ბუდაპეშტი)", + "Europe\/Busingen": "ცენტრალური ევროპის დრო (ბუსინგენი)", + "Europe\/Chisinau": "აღმოსავლეთ ევროპის დრო (კიშინიოვი)", + "Europe\/Copenhagen": "ცენტრალური ევროპის დრო (კოპენჰაგენი)", + "Europe\/Dublin": "გრინვიჩის საშუალო დრო (დუბლინი)", + "Europe\/Gibraltar": "ცენტრალური ევროპის დრო (გიბრალტარი)", + "Europe\/Guernsey": "გრინვიჩის საშუალო დრო (გერნსი)", + "Europe\/Helsinki": "აღმოსავლეთ ევროპის დრო (ჰელსინკი)", + "Europe\/Isle_of_Man": "გრინვიჩის საშუალო დრო (მენის კუნძული)", + "Europe\/Jersey": "გრინვიჩის საშუალო დრო (ჯერსი)", + "Europe\/Kaliningrad": "აღმოსავლეთ ევროპის დრო (კალინინგრადი)", + "Europe\/Kiev": "აღმოსავლეთ ევროპის დრო (კიევი)", + "Europe\/Lisbon": "დასავლეთ ევროპის დრო (ლისაბონი)", + "Europe\/Ljubljana": "ცენტრალური ევროპის დრო (ლიუბლიანა)", + "Europe\/London": "გრინვიჩის საშუალო დრო (ლონდონი)", + "Europe\/Luxembourg": "ცენტრალური ევროპის დრო (ლუქსემბურგი)", + "Europe\/Madrid": "ცენტრალური ევროპის დრო (მადრიდი)", + "Europe\/Malta": "ცენტრალური ევროპის დრო (მალტა)", + "Europe\/Mariehamn": "აღმოსავლეთ ევროპის დრო (მარიჰამნი)", + "Europe\/Minsk": "მოსკოვის დრო (მინსკი)", + "Europe\/Monaco": "ცენტრალური ევროპის დრო (მონაკო)", + "Europe\/Moscow": "მოსკოვის დრო (მოსკოვი)", + "Europe\/Oslo": "ცენტრალური ევროპის დრო (ოსლო)", + "Europe\/Paris": "ცენტრალური ევროპის დრო (პარიზი)", + "Europe\/Podgorica": "ცენტრალური ევროპის დრო (პოდგორიცა)", + "Europe\/Prague": "ცენტრალური ევროპის დრო (პრაღა)", + "Europe\/Riga": "აღმოსავლეთ ევროპის დრო (რიგა)", + "Europe\/Rome": "ცენტრალური ევროპის დრო (რომი)", + "Europe\/San_Marino": "ცენტრალური ევროპის დრო (სან-მარინო)", + "Europe\/Sarajevo": "ცენტრალური ევროპის დრო (სარაევო)", + "Europe\/Saratov": "მოსკოვის დრო (სარატოვი)", + "Europe\/Simferopol": "მოსკოვის დრო (სიმფეროპოლი)", + "Europe\/Skopje": "ცენტრალური ევროპის დრო (სკოპიე)", + "Europe\/Sofia": "აღმოსავლეთ ევროპის დრო (სოფია)", + "Europe\/Stockholm": "ცენტრალური ევროპის დრო (სტოკჰოლმი)", + "Europe\/Tallinn": "აღმოსავლეთ ევროპის დრო (ტალინი)", + "Europe\/Tirane": "ცენტრალური ევროპის დრო (ტირანა)", + "Europe\/Ulyanovsk": "მოსკოვის დრო (ულიანოვსკი)", + "Europe\/Uzhgorod": "აღმოსავლეთ ევროპის დრო (უჟგოროდი)", + "Europe\/Vaduz": "ცენტრალური ევროპის დრო (ვადუზი)", + "Europe\/Vatican": "ცენტრალური ევროპის დრო (ვატიკანი)", + "Europe\/Vienna": "ცენტრალური ევროპის დრო (ვენა)", + "Europe\/Vilnius": "აღმოსავლეთ ევროპის დრო (ვილნიუსი)", + "Europe\/Volgograd": "ვოლგოგრადის დრო (ვოლგოგრადი)", + "Europe\/Warsaw": "ცენტრალური ევროპის დრო (ვარშავა)", + "Europe\/Zagreb": "ცენტრალური ევროპის დრო (ზაგრები)", + "Europe\/Zaporozhye": "აღმოსავლეთ ევროპის დრო (ზაპოროჟიე)", + "Europe\/Zurich": "ცენტრალური ევროპის დრო (ციურიხი)", + "Indian\/Antananarivo": "აღმოსავლეთ აფრიკის დრო (ანტანანარივუ)", + "Indian\/Chagos": "ინდოეთის ოკეანის კუნძულების დრო (ჩაგოსი)", + "Indian\/Christmas": "შობის კუნძულის დრო (შობის კუნძული)", + "Indian\/Cocos": "ქოქოსის კუნძულების დრო (ქოქოსი)", + "Indian\/Comoro": "აღმოსავლეთ აფრიკის დრო (კომორო)", + "Indian\/Kerguelen": "ფრანგული სამხრეთის და ანტარქტიკის დრო (კერგელენი)", + "Indian\/Mahe": "სეიშელის კუნძულების დრო (მაჰე)", + "Indian\/Maldives": "მალდივების დრო (მალდივები)", + "Indian\/Mauritius": "მავრიკის დრო (მავრიკი)", + "Indian\/Mayotte": "აღმოსავლეთ აფრიკის დრო (მაიოტი)", + "Indian\/Reunion": "რეიუნიონის დრო (რეიუნიონი)", + "MST7MDT": "ჩრდილოეთ ამერიკის მაუნთინის დრო", + "PST8PDT": "ჩრდილოეთ ამერიკის წყნარი ოკეანის დრო", + "Pacific\/Apia": "აპიას დრო (აპია)", + "Pacific\/Auckland": "ახალი ზელანდიის დრო (ოკლენდი)", + "Pacific\/Bougainville": "პაპუა-ახალი გვინეის დრო (ბუგენვილი)", + "Pacific\/Chatham": "ჩატემის დრო (ჩათამი)", + "Pacific\/Easter": "აღდგომის კუნძულის დრო (ისთერი)", + "Pacific\/Efate": "ვანუატუს დრო (ეფატე)", + "Pacific\/Enderbury": "ფენიქსის კუნძულების დრო (ენდერბური)", + "Pacific\/Fakaofo": "ტოკელაუს დრო (ფაკაოფო)", + "Pacific\/Fiji": "ფიჯის დრო (ფიჯი)", + "Pacific\/Funafuti": "ტუვალუს დრო (ფუნაფუტი)", + "Pacific\/Galapagos": "გალაპაგოსის დრო (გალაპაგოსი)", + "Pacific\/Gambier": "გამბიერის დრო (გამბიერი)", + "Pacific\/Guadalcanal": "სოლომონის კუნძულების დრო (გვადალკანალი)", + "Pacific\/Guam": "ჩამოროს დრო (გუამი)", + "Pacific\/Honolulu": "ჰავაისა და ალეუტის დრო (ჰონოლულუ)", + "Pacific\/Johnston": "ჰავაისა და ალეუტის დრო (ჯონსტონი)", + "Pacific\/Kiritimati": "ლაინის კუნძულების დრო (კირიტიმატი)", + "Pacific\/Kosrae": "კოსრეს დრო (კოსრაე)", + "Pacific\/Kwajalein": "მარშალის კუნძულების დრო (კვაჯალეინი)", + "Pacific\/Majuro": "მარშალის კუნძულების დრო (მახურო)", + "Pacific\/Marquesas": "მარკიზის კუნძულების დრო (მარკეზასი)", + "Pacific\/Midway": "სამოას დრო (მიდუეი)", + "Pacific\/Nauru": "ნაურუს დრო (ნაურუ)", + "Pacific\/Niue": "ნიუეს დრო (ნიუე)", + "Pacific\/Norfolk": "ნორფოლკის კუნძულის დრო (ნორფოლკი)", + "Pacific\/Noumea": "ახალი კალედონიის დრო (ნუმეა)", + "Pacific\/Pago_Pago": "სამოას დრო (პაგო-პაგო)", + "Pacific\/Palau": "პალაუს დრო (პალაუ)", + "Pacific\/Pitcairn": "პიტკერნის დრო (პიტკერნი)", + "Pacific\/Ponape": "პონაპეს დრო (პონპეი)", + "Pacific\/Port_Moresby": "პაპუა-ახალი გვინეის დრო (პორტ მორსბი)", + "Pacific\/Rarotonga": "კუკის კუნძულების დრო (რაროტონგა)", + "Pacific\/Saipan": "ჩამოროს დრო (საიპანი)", + "Pacific\/Tahiti": "ტაიტის დრო (ტაიტი)", + "Pacific\/Tarawa": "გილბერტის კუნძულების დრო (ტარაუა)", + "Pacific\/Tongatapu": "ტონგის დრო (ტონგატაპუ)", + "Pacific\/Truk": "ჩუუკის დრო (ჩუუკი)", + "Pacific\/Wake": "ვეიკის კუნძულის დრო (უეიკი)", + "Pacific\/Wallis": "ვოლისი და ფუტუნას დრო (ვალისი)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/kk.json b/src/Symfony/Component/Intl/Resources/data/timezones/kk.json new file mode 100644 index 0000000000000..708aa84345871 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/kk.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Гринвич уақыты (Абиджан)", + "Africa\/Accra": "Гринвич уақыты (Аккра)", + "Africa\/Addis_Ababa": "Шығыс Африка уақыты (Аддис-Абеба)", + "Africa\/Algiers": "Орталық Еуропа уақыты (Алжир)", + "Africa\/Asmera": "Шығыс Африка уақыты (Асмара)", + "Africa\/Bamako": "Гринвич уақыты (Бамако)", + "Africa\/Bangui": "Батыс Африка уақыты (Банги)", + "Africa\/Banjul": "Гринвич уақыты (Банжул)", + "Africa\/Bissau": "Гринвич уақыты (Бисау)", + "Africa\/Blantyre": "Орталық Африка уақыты (Блантайр)", + "Africa\/Brazzaville": "Батыс Африка уақыты (Браззавиль)", + "Africa\/Bujumbura": "Орталық Африка уақыты (Бужумбура)", + "Africa\/Cairo": "Шығыс Еуропа уақыты (Каир)", + "Africa\/Casablanca": "Батыс Еуропа уақыты (Касабланка)", + "Africa\/Ceuta": "Орталық Еуропа уақыты (Сеута)", + "Africa\/Conakry": "Гринвич уақыты (Конакри)", + "Africa\/Dakar": "Гринвич уақыты (Дакар)", + "Africa\/Dar_es_Salaam": "Шығыс Африка уақыты (Дар-эс-Салам)", + "Africa\/Djibouti": "Шығыс Африка уақыты (Джибути)", + "Africa\/Douala": "Батыс Африка уақыты (Дуала)", + "Africa\/El_Aaiun": "Батыс Еуропа уақыты (Эль-Аюн)", + "Africa\/Freetown": "Гринвич уақыты (Фритаун)", + "Africa\/Gaborone": "Орталық Африка уақыты (Габороне)", + "Africa\/Harare": "Орталық Африка уақыты (Хараре)", + "Africa\/Johannesburg": "Оңтүстік Африка уақыты (Йоханнесбург)", + "Africa\/Juba": "Шығыс Африка уақыты (Джуба)", + "Africa\/Kampala": "Шығыс Африка уақыты (Кампала)", + "Africa\/Khartoum": "Орталық Африка уақыты (Хартум)", + "Africa\/Kigali": "Орталық Африка уақыты (Кигали)", + "Africa\/Kinshasa": "Батыс Африка уақыты (Киншаса)", + "Africa\/Lagos": "Батыс Африка уақыты (Лагос)", + "Africa\/Libreville": "Батыс Африка уақыты (Либревиль)", + "Africa\/Lome": "Гринвич уақыты (Ломе)", + "Africa\/Luanda": "Батыс Африка уақыты (Луанда)", + "Africa\/Lubumbashi": "Орталық Африка уақыты (Лубумбаши)", + "Africa\/Lusaka": "Орталық Африка уақыты (Лусака)", + "Africa\/Malabo": "Батыс Африка уақыты (Малабо)", + "Africa\/Maputo": "Орталық Африка уақыты (Мапуту)", + "Africa\/Maseru": "Оңтүстік Африка уақыты (Масеру)", + "Africa\/Mbabane": "Оңтүстік Африка уақыты (Мбабане)", + "Africa\/Mogadishu": "Шығыс Африка уақыты (Могадишо)", + "Africa\/Monrovia": "Гринвич уақыты (Монровия)", + "Africa\/Nairobi": "Шығыс Африка уақыты (Найроби)", + "Africa\/Ndjamena": "Батыс Африка уақыты (Нджамена)", + "Africa\/Niamey": "Батыс Африка уақыты (Ниамей)", + "Africa\/Nouakchott": "Гринвич уақыты (Нуакшот)", + "Africa\/Ouagadougou": "Гринвич уақыты (Уагадугу)", + "Africa\/Porto-Novo": "Батыс Африка уақыты (Порто-Ново)", + "Africa\/Sao_Tome": "Гринвич уақыты (Сан-Томе)", + "Africa\/Tripoli": "Шығыс Еуропа уақыты (Триполи)", + "Africa\/Tunis": "Орталық Еуропа уақыты (Тунис)", + "Africa\/Windhoek": "Орталық Африка уақыты (Виндхук)", + "America\/Adak": "Гавай және Алеут аралдары уақыты (Адак)", + "America\/Anchorage": "Аляска уақыты (Анкоридж)", + "America\/Anguilla": "Атлантика уақыты (Ангилья)", + "America\/Antigua": "Атлантика уақыты (Антигуа)", + "America\/Araguaina": "Бразилия уақыты (Арагуаина)", + "America\/Argentina\/La_Rioja": "Аргентина уақыты (Ла-Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аргентина уақыты (Рио-Гальегос)", + "America\/Argentina\/Salta": "Аргентина уақыты (Сальта)", + "America\/Argentina\/San_Juan": "Аргентина уақыты (Сан-Хуан)", + "America\/Argentina\/San_Luis": "Батыс Аргентина уақыты (Сан-Луис)", + "America\/Argentina\/Tucuman": "Аргентина уақыты (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентина уақыты (Ушуайя)", + "America\/Aruba": "Атлантика уақыты (Аруба)", + "America\/Asuncion": "Парагвай уақыты (Асунсьон)", + "America\/Bahia": "Бразилия уақыты (Баия)", + "America\/Bahia_Banderas": "Солтүстік Америка орталық уақыты (Баия-де-Бандерас)", + "America\/Barbados": "Атлантика уақыты (Барбадос)", + "America\/Belem": "Бразилия уақыты (Белен)", + "America\/Belize": "Солтүстік Америка орталық уақыты (Белиз)", + "America\/Blanc-Sablon": "Атлантика уақыты (Бланк-Саблон)", + "America\/Boa_Vista": "Амазонка уақыты (Боа-Вишта)", + "America\/Bogota": "Колумбия уақыты (Богота)", + "America\/Boise": "Солтүстік Америка тау уақыты (Бойсе)", + "America\/Buenos_Aires": "Аргентина уақыты (Буэнос-Айрес)", + "America\/Cambridge_Bay": "Солтүстік Америка тау уақыты (Кембридж-Бей)", + "America\/Campo_Grande": "Амазонка уақыты (Кампу-Гранди)", + "America\/Cancun": "Солтүстік Америка шығыс уақыты (Канкун)", + "America\/Caracas": "Венесуэла уақыты (Каракас)", + "America\/Catamarca": "Аргентина уақыты (Катамарка)", + "America\/Cayenne": "Француз Гвианасы уақыты (Кайенна)", + "America\/Cayman": "Солтүстік Америка шығыс уақыты (Кайман аралдары)", + "America\/Chicago": "Солтүстік Америка орталық уақыты (Чикаго)", + "America\/Chihuahua": "Мексика Тынық мұхит уақыты (Чиуауа)", + "America\/Coral_Harbour": "Солтүстік Америка шығыс уақыты (Корал-Харбор)", + "America\/Cordoba": "Аргентина уақыты (Кордова)", + "America\/Costa_Rica": "Солтүстік Америка орталық уақыты (Коста-Рика)", + "America\/Creston": "Солтүстік Америка тау уақыты (Крестон)", + "America\/Cuiaba": "Амазонка уақыты (Куяба)", + "America\/Curacao": "Атлантика уақыты (Кюрасао)", + "America\/Danmarkshavn": "Гринвич уақыты (Денмарксхавн)", + "America\/Dawson": "Солтүстік Америка Тынық мұхиты уақыты (Доусон)", + "America\/Dawson_Creek": "Солтүстік Америка тау уақыты (Досон-Крик)", + "America\/Denver": "Солтүстік Америка тау уақыты (Денвер)", + "America\/Detroit": "Солтүстік Америка шығыс уақыты (Детройт)", + "America\/Dominica": "Атлантика уақыты (Доминика)", + "America\/Edmonton": "Солтүстік Америка тау уақыты (Эдмонтон)", + "America\/El_Salvador": "Солтүстік Америка орталық уақыты (Сальвадор)", + "America\/Fort_Nelson": "Солтүстік Америка тау уақыты (Форт-Нельсон)", + "America\/Fortaleza": "Бразилия уақыты (Форталеза)", + "America\/Glace_Bay": "Атлантика уақыты (Глейс-Бей)", + "America\/Godthab": "Батыс Гренландия уақыты (Нуук)", + "America\/Goose_Bay": "Атлантика уақыты (Гус-Бей)", + "America\/Grand_Turk": "Солтүстік Америка шығыс уақыты (Гранд-Терк)", + "America\/Grenada": "Атлантика уақыты (Гренада)", + "America\/Guadeloupe": "Атлантика уақыты (Гваделупа)", + "America\/Guatemala": "Солтүстік Америка орталық уақыты (Гватемала)", + "America\/Guayaquil": "Эквадор уақыты (Гуаякиль)", + "America\/Guyana": "Гайана уақыты (Гайана)", + "America\/Halifax": "Атлантика уақыты (Галифакс)", + "America\/Havana": "Куба уақыты (Гавана)", + "America\/Hermosillo": "Мексика Тынық мұхит уақыты (Эрмосильо)", + "America\/Indiana\/Knox": "Солтүстік Америка орталық уақыты (Нокс, Индиана)", + "America\/Indiana\/Marengo": "Солтүстік Америка шығыс уақыты (Маренго, Индиана)", + "America\/Indiana\/Petersburg": "Солтүстік Америка шығыс уақыты (Питерсберг, Индиана)", + "America\/Indiana\/Tell_City": "Солтүстік Америка орталық уақыты (Телл-Сити, Индиана)", + "America\/Indiana\/Vevay": "Солтүстік Америка шығыс уақыты (Вивей, Индиана)", + "America\/Indiana\/Vincennes": "Солтүстік Америка шығыс уақыты (Винсеннес, Индиана)", + "America\/Indiana\/Winamac": "Солтүстік Америка шығыс уақыты (Уинамак, Индиана)", + "America\/Indianapolis": "Солтүстік Америка шығыс уақыты (Индианаполис)", + "America\/Inuvik": "Солтүстік Америка тау уақыты (Инувик)", + "America\/Iqaluit": "Солтүстік Америка шығыс уақыты (Икалуит)", + "America\/Jamaica": "Солтүстік Америка шығыс уақыты (Ямайка)", + "America\/Jujuy": "Аргентина уақыты (Жужуй)", + "America\/Juneau": "Аляска уақыты (Джуно)", + "America\/Kentucky\/Monticello": "Солтүстік Америка шығыс уақыты (Монтиселло, Кентукки)", + "America\/Kralendijk": "Атлантика уақыты (Кралендейк)", + "America\/La_Paz": "Боливия уақыты (Ла-Пас)", + "America\/Lima": "Перу уақыты (Лима)", + "America\/Los_Angeles": "Солтүстік Америка Тынық мұхиты уақыты (Лос-Анжелес)", + "America\/Louisville": "Солтүстік Америка шығыс уақыты (Луисвилл)", + "America\/Lower_Princes": "Атлантика уақыты (Лоуэр-Принсес-Куортер)", + "America\/Maceio": "Бразилия уақыты (Масейо)", + "America\/Managua": "Солтүстік Америка орталық уақыты (Манагуа)", + "America\/Manaus": "Амазонка уақыты (Манаус)", + "America\/Marigot": "Атлантика уақыты (Мариго)", + "America\/Martinique": "Атлантика уақыты (Мартиника)", + "America\/Matamoros": "Солтүстік Америка орталық уақыты (Матаморос)", + "America\/Mazatlan": "Мексика Тынық мұхит уақыты (Масатлан)", + "America\/Mendoza": "Аргентина уақыты (Мендоса)", + "America\/Menominee": "Солтүстік Америка орталық уақыты (Меномини)", + "America\/Merida": "Солтүстік Америка орталық уақыты (Мерида)", + "America\/Metlakatla": "Аляска уақыты (Метлакатла)", + "America\/Mexico_City": "Солтүстік Америка орталық уақыты (Мехико)", + "America\/Miquelon": "Сен-Пьер және Микелон уақыты (Микелон)", + "America\/Moncton": "Атлантика уақыты (Монктон)", + "America\/Monterrey": "Солтүстік Америка орталық уақыты (Монтеррей)", + "America\/Montevideo": "Уругвай уақыты (Монтевидео)", + "America\/Montserrat": "Атлантика уақыты (Монтсеррат)", + "America\/Nassau": "Солтүстік Америка шығыс уақыты (Нассау)", + "America\/New_York": "Солтүстік Америка шығыс уақыты (Нью-Йорк)", + "America\/Nipigon": "Солтүстік Америка шығыс уақыты (Нипигон)", + "America\/Nome": "Аляска уақыты (Ном)", + "America\/Noronha": "Фернанду-ди-Норонья уақыты (Норонья)", + "America\/North_Dakota\/Beulah": "Солтүстік Америка орталық уақыты (Бойла, Солтүстік Дакота)", + "America\/North_Dakota\/Center": "Солтүстік Америка орталық уақыты (Сентер, Солтүстік Дакота)", + "America\/North_Dakota\/New_Salem": "Солтүстік Америка орталық уақыты (Нью Сейлем, Солтүстік Дакота)", + "America\/Ojinaga": "Солтүстік Америка тау уақыты (Охинага)", + "America\/Panama": "Солтүстік Америка шығыс уақыты (Панама)", + "America\/Pangnirtung": "Солтүстік Америка шығыс уақыты (Пангниртанг)", + "America\/Paramaribo": "Суринам уақыты (Парамарибо)", + "America\/Phoenix": "Солтүстік Америка тау уақыты (Финикс)", + "America\/Port-au-Prince": "Солтүстік Америка шығыс уақыты (Порт-о-Пренс)", + "America\/Port_of_Spain": "Атлантика уақыты (Порт-оф-Спейн)", + "America\/Porto_Velho": "Амазонка уақыты (Порту-Велью)", + "America\/Puerto_Rico": "Атлантика уақыты (Пуэрто-Рико)", + "America\/Punta_Arenas": "Чили уақыты (Пунта-Аренас)", + "America\/Rainy_River": "Солтүстік Америка орталық уақыты (Рейни-Ривер)", + "America\/Rankin_Inlet": "Солтүстік Америка орталық уақыты (Ранкин-Инлет)", + "America\/Recife": "Бразилия уақыты (Ресифи)", + "America\/Regina": "Солтүстік Америка орталық уақыты (Реджайна)", + "America\/Resolute": "Солтүстік Америка орталық уақыты (Резольют)", + "America\/Santa_Isabel": "Солтүстік-батыс Мексика уақыты (Санта-Изабел)", + "America\/Santarem": "Бразилия уақыты (Сантарен)", + "America\/Santiago": "Чили уақыты (Сантьяго)", + "America\/Santo_Domingo": "Атлантика уақыты (Санто-Доминго)", + "America\/Sao_Paulo": "Бразилия уақыты (Сан-Паулу)", + "America\/Scoresbysund": "Шығыс Гренландия уақыты (Скорсбиссун)", + "America\/Sitka": "Аляска уақыты (Ситка)", + "America\/St_Barthelemy": "Атлантика уақыты (Сен-Бартелеми)", + "America\/St_Johns": "Ньюфаундленд уақыты (Сент-Джонс)", + "America\/St_Kitts": "Атлантика уақыты (Сент-Китс)", + "America\/St_Lucia": "Атлантика уақыты (Сент-Люсия)", + "America\/St_Thomas": "Атлантика уақыты (Сент-Томас)", + "America\/St_Vincent": "Атлантика уақыты (Сент-Винсент)", + "America\/Swift_Current": "Солтүстік Америка орталық уақыты (Свифт-Керрент)", + "America\/Tegucigalpa": "Солтүстік Америка орталық уақыты (Тегусигальпа)", + "America\/Thule": "Атлантика уақыты (Туле)", + "America\/Thunder_Bay": "Солтүстік Америка шығыс уақыты (Тандер-Бей)", + "America\/Tijuana": "Солтүстік Америка Тынық мұхиты уақыты (Тихуана)", + "America\/Toronto": "Солтүстік Америка шығыс уақыты (Торонто)", + "America\/Tortola": "Атлантика уақыты (Тортола)", + "America\/Vancouver": "Солтүстік Америка Тынық мұхиты уақыты (Ванкувер)", + "America\/Whitehorse": "Солтүстік Америка Тынық мұхиты уақыты (Уайтхорс)", + "America\/Winnipeg": "Солтүстік Америка орталық уақыты (Виннипег)", + "America\/Yakutat": "Аляска уақыты (Якутат)", + "America\/Yellowknife": "Солтүстік Америка тау уақыты (Йеллоунайф)", + "Antarctica\/Casey": "Австралия батыс уақыты (Кейси)", + "Antarctica\/Davis": "Дейвис уақыты (Дэйвис)", + "Antarctica\/DumontDUrville": "Дюмон-д’Юрвиль уақыты (Дюмон-д’Юрвиль)", + "Antarctica\/Macquarie": "Маккуори аралы уақыты (Маккуори)", + "Antarctica\/Mawson": "Моусон уақыты (Моусон)", + "Antarctica\/McMurdo": "Жаңа Зеландия уақыты (Мак-Мердо)", + "Antarctica\/Palmer": "Чили уақыты (Палмер)", + "Antarctica\/Rothera": "Ротера уақыты (Ротера)", + "Antarctica\/Syowa": "Сёва уақыты (Сёва)", + "Antarctica\/Troll": "Гринвич уақыты (Тролль)", + "Antarctica\/Vostok": "Восток уақыты (Восток)", + "Arctic\/Longyearbyen": "Орталық Еуропа уақыты (Лонгйир)", + "Asia\/Aden": "Сауд Арабиясы уақыты (Аден)", + "Asia\/Almaty": "Шығыс Қазақстан уақыты (Алматы)", + "Asia\/Amman": "Шығыс Еуропа уақыты (Амман)", + "Asia\/Aqtau": "Батыс Қазақстан уақыты (Ақтау)", + "Asia\/Aqtobe": "Батыс Қазақстан уақыты (Ақтөбе)", + "Asia\/Ashgabat": "Түрікменстан уақыты (Ашхабад)", + "Asia\/Atyrau": "Батыс Қазақстан уақыты (Атырау)", + "Asia\/Baghdad": "Сауд Арабиясы уақыты (Бағдат)", + "Asia\/Bahrain": "Сауд Арабиясы уақыты (Бахрейн)", + "Asia\/Baku": "Әзірбайжан уақыты (Баку)", + "Asia\/Bangkok": "Үндіқытай уақыты (Бангкок)", + "Asia\/Beirut": "Шығыс Еуропа уақыты (Бейрут)", + "Asia\/Bishkek": "Қырғызстан уақыты (Бішкек)", + "Asia\/Brunei": "Бруней-Даруссалам уақыты (Бруней)", + "Asia\/Calcutta": "Үндістан стандартты уақыты (Калькутта)", + "Asia\/Chita": "Якутск уақыты (Чита)", + "Asia\/Choibalsan": "Чойбалсан уақыты (Чойбалсан)", + "Asia\/Colombo": "Үндістан стандартты уақыты (Коломбо)", + "Asia\/Damascus": "Шығыс Еуропа уақыты (Дамаск)", + "Asia\/Dhaka": "Бангладеш уақыты (Дакка)", + "Asia\/Dili": "Шығыс Тимор уақыты (Дили)", + "Asia\/Dubai": "Парсы шығанағы уақыты (Дубай)", + "Asia\/Dushanbe": "Тәжікстан уақыты (Душанбе)", + "Asia\/Famagusta": "Шығыс Еуропа уақыты (Фамагуста)", + "Asia\/Gaza": "Шығыс Еуропа уақыты (Газа)", + "Asia\/Hebron": "Шығыс Еуропа уақыты (Хеврон)", + "Asia\/Hong_Kong": "Гонконг уақыты (Гонконг)", + "Asia\/Hovd": "Ховд уақыты (Ховд)", + "Asia\/Irkutsk": "Иркутск уақыты (Иркутск)", + "Asia\/Jakarta": "Батыс Индонезия уақыты (Джакарта)", + "Asia\/Jayapura": "Шығыс Индонезия уақыты (Джаяпура)", + "Asia\/Jerusalem": "Израиль уақыты (Иерусалим)", + "Asia\/Kabul": "Ауғанстан уақыты (Кабул)", + "Asia\/Karachi": "Пәкістан уақыты (Карачи)", + "Asia\/Katmandu": "Непал уақыты (Катманду)", + "Asia\/Khandyga": "Якутск уақыты (Хандыга)", + "Asia\/Krasnoyarsk": "Красноярск уақыты (Красноярск)", + "Asia\/Kuala_Lumpur": "Малайзия уақыты (Куала-Лумпур)", + "Asia\/Kuching": "Малайзия уақыты (Кучинг)", + "Asia\/Kuwait": "Сауд Арабиясы уақыты (Кувейт)", + "Asia\/Macau": "Қытай уақыты (Макао)", + "Asia\/Magadan": "Магадан уақыты (Магадан)", + "Asia\/Makassar": "Орталық Индонезия уақыты (Макасар)", + "Asia\/Manila": "Филиппин аралдары уақыты (Манила)", + "Asia\/Muscat": "Парсы шығанағы уақыты (Маскат)", + "Asia\/Nicosia": "Шығыс Еуропа уақыты (Никосия)", + "Asia\/Novokuznetsk": "Красноярск уақыты (Новокузнецк)", + "Asia\/Novosibirsk": "Новосібір уақыты (Новосібір)", + "Asia\/Omsk": "Омбы уақыты (Омбы)", + "Asia\/Oral": "Батыс Қазақстан уақыты (Орал)", + "Asia\/Phnom_Penh": "Үндіқытай уақыты (Пномпень)", + "Asia\/Pontianak": "Батыс Индонезия уақыты (Понтианак)", + "Asia\/Pyongyang": "Корея уақыты (Пхеньян)", + "Asia\/Qatar": "Сауд Арабиясы уақыты (Катар)", + "Asia\/Qostanay": "Шығыс Қазақстан уақыты (Qostanay)", + "Asia\/Qyzylorda": "Батыс Қазақстан уақыты (Қызылорда)", + "Asia\/Rangoon": "Мьянма уақыты (Янгон)", + "Asia\/Riyadh": "Сауд Арабиясы уақыты (Эр-Рияд)", + "Asia\/Saigon": "Үндіқытай уақыты (Хошимин)", + "Asia\/Sakhalin": "Сахалин уақыты (Сахалин)", + "Asia\/Samarkand": "Өзбекстан уақыты (Самарқанд)", + "Asia\/Seoul": "Корея уақыты (Сеул)", + "Asia\/Shanghai": "Қытай уақыты (Шанхай)", + "Asia\/Singapore": "Сингапур стандартты уақыты (Сингапур)", + "Asia\/Srednekolymsk": "Магадан уақыты (Среднеколымск)", + "Asia\/Taipei": "Тайбэй уақыты (Тайбэй)", + "Asia\/Tashkent": "Өзбекстан уақыты (Ташкент)", + "Asia\/Tbilisi": "Грузия уақыты (Тбилиси)", + "Asia\/Tehran": "Иран уақыты (Тегеран)", + "Asia\/Thimphu": "Бутан уақыты (Тхимпху)", + "Asia\/Tokyo": "Жапония уақыты (Токио)", + "Asia\/Ulaanbaatar": "Ұланбатыр уақыты (Улан-Батор)", + "Asia\/Ust-Nera": "Владивосток уақыты (Усть-Нера)", + "Asia\/Vientiane": "Үндіқытай уақыты (Вьентьян)", + "Asia\/Vladivostok": "Владивосток уақыты (Владивосток)", + "Asia\/Yakutsk": "Якутск уақыты (Якутск)", + "Asia\/Yekaterinburg": "Екатеринбург уақыты (Екатеринбург)", + "Asia\/Yerevan": "Армения уақыты (Ереван)", + "Atlantic\/Azores": "Азор аралдары уақыты (Азор аралдары)", + "Atlantic\/Bermuda": "Атлантика уақыты (Бермуд аралдары)", + "Atlantic\/Canary": "Батыс Еуропа уақыты (Канар аралдары)", + "Atlantic\/Cape_Verde": "Кабо-Верде уақыты (Кабо-Верде)", + "Atlantic\/Faeroe": "Батыс Еуропа уақыты (Фарер аралдары)", + "Atlantic\/Madeira": "Батыс Еуропа уақыты (Мадейра)", + "Atlantic\/Reykjavik": "Гринвич уақыты (Рейкьявик)", + "Atlantic\/South_Georgia": "Оңтүстік Георгия уақыты (Оңтүстік Георгия)", + "Atlantic\/St_Helena": "Гринвич уақыты (Әулие Елена аралы)", + "Atlantic\/Stanley": "Фолкленд аралдары уақыты (Стэнли)", + "Australia\/Adelaide": "Австралия орталық уақыты (Аделаида)", + "Australia\/Brisbane": "Австралия шығыс уақыты (Брисбен)", + "Australia\/Broken_Hill": "Австралия орталық уақыты (Брокен-Хилл)", + "Australia\/Currie": "Австралия шығыс уақыты (Керри)", + "Australia\/Darwin": "Австралия орталық уақыты (Дарвин)", + "Australia\/Eucla": "Австралия орталық-батыс уақыты (Юкла)", + "Australia\/Hobart": "Австралия шығыс уақыты (Хобарт)", + "Australia\/Lindeman": "Австралия шығыс уақыты (Линдеман)", + "Australia\/Lord_Howe": "Лорд-Хау уақыты (Лорд-Хау аралы)", + "Australia\/Melbourne": "Австралия шығыс уақыты (Мельбурн)", + "Australia\/Perth": "Австралия батыс уақыты (Перт)", + "Australia\/Sydney": "Австралия шығыс уақыты (Сидней)", + "CST6CDT": "Солтүстік Америка орталық уақыты", + "EST5EDT": "Солтүстік Америка шығыс уақыты", + "Etc\/GMT": "Гринвич уақыты", + "Etc\/UTC": "Дүниежүзілік үйлестірілген уақыт", + "Europe\/Amsterdam": "Орталық Еуропа уақыты (Амстердам)", + "Europe\/Andorra": "Орталық Еуропа уақыты (Андорра)", + "Europe\/Astrakhan": "Мәскеу уақыты (Астрахан)", + "Europe\/Athens": "Шығыс Еуропа уақыты (Афина)", + "Europe\/Belgrade": "Орталық Еуропа уақыты (Белград)", + "Europe\/Berlin": "Орталық Еуропа уақыты (Берлин)", + "Europe\/Bratislava": "Орталық Еуропа уақыты (Братислава)", + "Europe\/Brussels": "Орталық Еуропа уақыты (Брюссель)", + "Europe\/Bucharest": "Шығыс Еуропа уақыты (Бухарест)", + "Europe\/Budapest": "Орталық Еуропа уақыты (Будапешт)", + "Europe\/Busingen": "Орталық Еуропа уақыты (Бюзинген-ам-Хохрайн)", + "Europe\/Chisinau": "Шығыс Еуропа уақыты (Кишинев)", + "Europe\/Copenhagen": "Орталық Еуропа уақыты (Копенгаген)", + "Europe\/Dublin": "Гринвич уақыты (Дублин)", + "Europe\/Gibraltar": "Орталық Еуропа уақыты (Гибралтар)", + "Europe\/Guernsey": "Гринвич уақыты (Гернси)", + "Europe\/Helsinki": "Шығыс Еуропа уақыты (Хелсинки)", + "Europe\/Isle_of_Man": "Гринвич уақыты (Мэн аралы)", + "Europe\/Jersey": "Гринвич уақыты (Джерси)", + "Europe\/Kaliningrad": "Шығыс Еуропа уақыты (Калининград)", + "Europe\/Kiev": "Шығыс Еуропа уақыты (Киев)", + "Europe\/Lisbon": "Батыс Еуропа уақыты (Лиссабон)", + "Europe\/Ljubljana": "Орталық Еуропа уақыты (Любляна)", + "Europe\/London": "Гринвич уақыты (Лондон)", + "Europe\/Luxembourg": "Орталық Еуропа уақыты (Люксембург)", + "Europe\/Madrid": "Орталық Еуропа уақыты (Мадрид)", + "Europe\/Malta": "Орталық Еуропа уақыты (Мальта)", + "Europe\/Mariehamn": "Шығыс Еуропа уақыты (Мариехамн)", + "Europe\/Minsk": "Мәскеу уақыты (Минск)", + "Europe\/Monaco": "Орталық Еуропа уақыты (Монако)", + "Europe\/Moscow": "Мәскеу уақыты (Мәскеу)", + "Europe\/Oslo": "Орталық Еуропа уақыты (Осло)", + "Europe\/Paris": "Орталық Еуропа уақыты (Париж)", + "Europe\/Podgorica": "Орталық Еуропа уақыты (Подгорица)", + "Europe\/Prague": "Орталық Еуропа уақыты (Прага)", + "Europe\/Riga": "Шығыс Еуропа уақыты (Рига)", + "Europe\/Rome": "Орталық Еуропа уақыты (Рим)", + "Europe\/San_Marino": "Орталық Еуропа уақыты (Сан-Марино)", + "Europe\/Sarajevo": "Орталық Еуропа уақыты (Сараево)", + "Europe\/Saratov": "Мәскеу уақыты (Саратов)", + "Europe\/Simferopol": "Мәскеу уақыты (Симферополь)", + "Europe\/Skopje": "Орталық Еуропа уақыты (Скопье)", + "Europe\/Sofia": "Шығыс Еуропа уақыты (София)", + "Europe\/Stockholm": "Орталық Еуропа уақыты (Стокгольм)", + "Europe\/Tallinn": "Шығыс Еуропа уақыты (Таллин)", + "Europe\/Tirane": "Орталық Еуропа уақыты (Тирана)", + "Europe\/Ulyanovsk": "Мәскеу уақыты (Ульяновск)", + "Europe\/Uzhgorod": "Шығыс Еуропа уақыты (Ужгород)", + "Europe\/Vaduz": "Орталық Еуропа уақыты (Вадуц)", + "Europe\/Vatican": "Орталық Еуропа уақыты (Ватикан)", + "Europe\/Vienna": "Орталық Еуропа уақыты (Вена)", + "Europe\/Vilnius": "Шығыс Еуропа уақыты (Вильнюс)", + "Europe\/Volgograd": "Волгоград уақыты (Волгоград)", + "Europe\/Warsaw": "Орталық Еуропа уақыты (Варшава)", + "Europe\/Zagreb": "Орталық Еуропа уақыты (Загреб)", + "Europe\/Zaporozhye": "Шығыс Еуропа уақыты (Запорожье)", + "Europe\/Zurich": "Орталық Еуропа уақыты (Цюрих)", + "Indian\/Antananarivo": "Шығыс Африка уақыты (Антананариву)", + "Indian\/Chagos": "Үнді мұхиты уақыты (Чагос)", + "Indian\/Christmas": "Рождество аралының уақыты (Рождество аралы)", + "Indian\/Cocos": "Кокос аралдарының уақыты (Кокос аралдары)", + "Indian\/Comoro": "Шығыс Африка уақыты (Комор аралдары)", + "Indian\/Kerguelen": "Францияның оңтүстік аймағы және Антарктика уақыты (Кергелен)", + "Indian\/Mahe": "Сейшель аралдары уақыты (Маэ)", + "Indian\/Maldives": "Мальдив аралдары уақыты (Мальдив аралдары)", + "Indian\/Mauritius": "Маврикий уақыты (Маврикий)", + "Indian\/Mayotte": "Шығыс Африка уақыты (Майотта)", + "Indian\/Reunion": "Реюньон уақыты (Реюньон)", + "MST7MDT": "Солтүстік Америка тау уақыты", + "PST8PDT": "Солтүстік Америка Тынық мұхиты уақыты", + "Pacific\/Apia": "Апиа уақыты (Апиа)", + "Pacific\/Auckland": "Жаңа Зеландия уақыты (Окленд)", + "Pacific\/Bougainville": "Папуа – Жаңа Гвинея уақыты (Бугенвиль)", + "Pacific\/Chatham": "Чатем уақыты (Чатем)", + "Pacific\/Easter": "Пасха аралы уақыты (Пасха аралы)", + "Pacific\/Efate": "Вануату уақыты (Эфате)", + "Pacific\/Enderbury": "Феникс аралдары уақыты (Эндербери)", + "Pacific\/Fakaofo": "Токелау уақыты (Факаофо)", + "Pacific\/Fiji": "Фиджи уақыты (Фиджи)", + "Pacific\/Funafuti": "Тувалу уақыты (Фунафути)", + "Pacific\/Galapagos": "Галапагос уақыты (Галапагос)", + "Pacific\/Gambier": "Гамбье уақыты (Гамбье)", + "Pacific\/Guadalcanal": "Соломон аралдары уақыты (Гуадалканал)", + "Pacific\/Guam": "Чаморро стандартты уақыты (Гуам)", + "Pacific\/Honolulu": "Гавай және Алеут аралдары уақыты (Гонолулу)", + "Pacific\/Johnston": "Гавай және Алеут аралдары уақыты (Джонстон)", + "Pacific\/Kiritimati": "Лайн аралдары уақыты (Киритимати)", + "Pacific\/Kosrae": "Кусаие уақыты (Кусаие)", + "Pacific\/Kwajalein": "Маршалл аралдары уақыты (Кваджалейн)", + "Pacific\/Majuro": "Маршалл аралдары уақыты (Маджуро)", + "Pacific\/Marquesas": "Маркиз аралдары уақыты (Маркиз аралдары)", + "Pacific\/Midway": "Самоа уақыты (Мидуэй)", + "Pacific\/Nauru": "Науру уақыты (Науру)", + "Pacific\/Niue": "Ниуэ уақыты (Ниуэ)", + "Pacific\/Norfolk": "Норфолк аралы уақыты (Норфолк)", + "Pacific\/Noumea": "Жаңа Каледония уақыты (Нумеа)", + "Pacific\/Pago_Pago": "Самоа уақыты (Паго-Паго)", + "Pacific\/Palau": "Палау уақыты (Палау)", + "Pacific\/Pitcairn": "Питкэрн уақыты (Питкэрн)", + "Pacific\/Ponape": "Понпеи уақыты (Понапе)", + "Pacific\/Port_Moresby": "Папуа – Жаңа Гвинея уақыты (Порт-Морсби)", + "Pacific\/Rarotonga": "Кук аралдарының уақыты (Раротонга)", + "Pacific\/Saipan": "Чаморро стандартты уақыты (Сайпан)", + "Pacific\/Tahiti": "Таити уақыты (Таити)", + "Pacific\/Tarawa": "Гилберт аралдарының уақыты (Тарава)", + "Pacific\/Tongatapu": "Тонга уақыты (Тонгатапу)", + "Pacific\/Truk": "Трук уақыты (Трук)", + "Pacific\/Wake": "Уэйк аралы уақыты (Уэйк)", + "Pacific\/Wallis": "Уоллис және Футуна уақыты (Уоллис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/km.json b/src/Symfony/Component/Intl/Resources/data/timezones/km.json new file mode 100644 index 0000000000000..e88f66700e116 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/km.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ម៉ោងនៅគ្រីនវិច (អាប៊ីដ្យាន)", + "Africa\/Accra": "ម៉ោងនៅគ្រីនវិច (អាក្រា)", + "Africa\/Addis_Ababa": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (អាឌីសអាបេបា)", + "Africa\/Algiers": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (អាល់ហ្សេ)", + "Africa\/Asmera": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (អាស្មារ៉ា)", + "Africa\/Bamako": "ម៉ោងនៅគ្រីនវិច (បាម៉ាកូ)", + "Africa\/Bangui": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (បង់ហ្គី)", + "Africa\/Banjul": "ម៉ោងនៅគ្រីនវិច (បង់ហ្ស៊ុល)", + "Africa\/Bissau": "ម៉ោងនៅគ្រីនវិច (ប៊ីស្សូ)", + "Africa\/Blantyre": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (ប្លាំងទីរ៉េ)", + "Africa\/Brazzaville": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (ប្រាស្ហាវីល)", + "Africa\/Bujumbura": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (ប៊ូយ៉ាំប៊ូរ៉ា)", + "Africa\/Cairo": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (គែរ)", + "Africa\/Casablanca": "ម៉ោង​នៅ​អឺរ៉ុប​ខាង​លិច (កាសាប្លាំងកា)", + "Africa\/Ceuta": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ឈៀតា)", + "Africa\/Conakry": "ម៉ោងនៅគ្រីនវិច (កូណាគ្រី)", + "Africa\/Dakar": "ម៉ោងនៅគ្រីនវិច (ដាកា)", + "Africa\/Dar_es_Salaam": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (ដាអ៊ីសាឡាំ)", + "Africa\/Djibouti": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (ជីប៊ូទី)", + "Africa\/Douala": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (ឌូអ៊ូឡា)", + "Africa\/El_Aaiun": "ម៉ោង​នៅ​អឺរ៉ុប​ខាង​លិច (អែល​អ៊ុយញៀន)", + "Africa\/Freetown": "ម៉ោងនៅគ្រីនវិច (ហ្វ្រីថោន)", + "Africa\/Gaborone": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (ហ្គាបូរ៉ូន)", + "Africa\/Harare": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (ហារ៉ារ៉េ)", + "Africa\/Johannesburg": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​ត្បូង (ជូហានណេប៊ឺហ្គ)", + "Africa\/Juba": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (ជូបា)", + "Africa\/Kampala": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (កំប៉ាឡា)", + "Africa\/Khartoum": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (ខាទុំ)", + "Africa\/Kigali": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (គីហ្គាលី)", + "Africa\/Kinshasa": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (គីនស្ហាសា)", + "Africa\/Lagos": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (ឡាហ្គូស)", + "Africa\/Libreville": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (លីប្រីវីល)", + "Africa\/Lome": "ម៉ោងនៅគ្រីនវិច (ឡូម៉េ)", + "Africa\/Luanda": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (លូអង់ដា)", + "Africa\/Lubumbashi": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (លូប៊ុមបាស៊ី)", + "Africa\/Lusaka": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (លូសាកា)", + "Africa\/Malabo": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (ម៉ាឡាបូ)", + "Africa\/Maputo": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (ម៉ាពុយតូ)", + "Africa\/Maseru": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​ត្បូង (ម៉ាសេរុយ)", + "Africa\/Mbabane": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​ត្បូង (បាបាន)", + "Africa\/Mogadishu": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (ម៉ូហ្គាឌីស្យូ)", + "Africa\/Monrovia": "ម៉ោងនៅគ្រីនវិច (ម៉ុងរ៉ូវីយ៉ា)", + "Africa\/Nairobi": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (ណៃរ៉ូប៊ី)", + "Africa\/Ndjamena": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (ដ្យាមេណា)", + "Africa\/Niamey": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (នីញ៉ាម៉េ)", + "Africa\/Nouakchott": "ម៉ោងនៅគ្រីនវិច (ណួកសុត)", + "Africa\/Ouagadougou": "ម៉ោងនៅគ្រីនវិច (អៅហ្គាឌូហ្គូ)", + "Africa\/Porto-Novo": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​លិច (ព័រតូណូវ៉ូ)", + "Africa\/Sao_Tome": "ម៉ោងនៅគ្រីនវិច (សៅតូម៉េ)", + "Africa\/Tripoli": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ទ្រីប៉ូលី)", + "Africa\/Tunis": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ទុយនីស)", + "Africa\/Windhoek": "ម៉ោង​នៅ​អាហ្វ្រិក​កណ្ដាល (វីនដុក)", + "America\/Adak": "ម៉ោង​​នៅ​ហាវៃ-អាល់ដ្យូសិន (អាដាក)", + "America\/Anchorage": "ម៉ោង​នៅ​អាឡាស្កា (អង់ចូរ៉ាក)", + "America\/Anguilla": "ម៉ោង​នៅ​អាត្លង់ទិក (អង់ហ្គីឡា)", + "America\/Antigua": "ម៉ោង​នៅ​អាត្លង់ទិក (អង់ទីហ្គា)", + "America\/Araguaina": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (អារ៉ាហ្គុយណា)", + "America\/Argentina\/La_Rioja": "ម៉ោង​នៅ​អាហ្សង់ទីន (ឡារីយ៉ូហា)", + "America\/Argentina\/Rio_Gallegos": "ម៉ោង​នៅ​អាហ្សង់ទីន (រីយ៉ូហ្គាឡេហ្គូស)", + "America\/Argentina\/Salta": "ម៉ោង​នៅ​អាហ្សង់ទីន (សាល់តា)", + "America\/Argentina\/San_Juan": "ម៉ោង​នៅ​អាហ្សង់ទីន (សាំងហ្សង់)", + "America\/Argentina\/San_Luis": "ម៉ោង​នៅ​អាហ្សង់ទីនភាគខាងលិច (សាន់លូអ៊ីស)", + "America\/Argentina\/Tucuman": "ម៉ោង​នៅ​អាហ្សង់ទីន (ទូគូម៉ង់)", + "America\/Argentina\/Ushuaia": "ម៉ោង​នៅ​អាហ្សង់ទីន (អ៊ុយសូអៃ)", + "America\/Aruba": "ម៉ោង​នៅ​អាត្លង់ទិក (អារ៉ូបា)", + "America\/Asuncion": "ម៉ោង​នៅ​ប៉ារ៉ាហ្គាយ (អាសង់ស្យុង)", + "America\/Bahia": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (បាហៀ)", + "America\/Bahia_Banderas": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (បាហៀបង់ដេរ៉ាស)", + "America\/Barbados": "ម៉ោង​នៅ​អាត្លង់ទិក (បាបាដុស)", + "America\/Belem": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (បេឡឹម)", + "America\/Belize": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (បេលី)", + "America\/Blanc-Sablon": "ម៉ោង​នៅ​អាត្លង់ទិក (ប្លង់​សាប់ឡុង)", + "America\/Boa_Vista": "ម៉ោង​នៅ​អាម៉ាហ្សូន (បៅ​វីស្តា)", + "America\/Bogota": "ម៉ោង​នៅ​កូឡុំប៊ី (បូហ្គោតា)", + "America\/Boise": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ប៊ូស៊ី)", + "America\/Buenos_Aires": "ម៉ោង​នៅ​អាហ្សង់ទីន (ប៊ុយណូស៊ែ)", + "America\/Cambridge_Bay": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ខេមប្រីដបេ)", + "America\/Campo_Grande": "ម៉ោង​នៅ​អាម៉ាហ្សូន (ខេមប៉ូហ្គ្រង់​)", + "America\/Cancun": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ខានខុន)", + "America\/Caracas": "ម៉ោង​នៅ​វ៉េណេស៊ុយអេឡា (ការ៉ាកាស)", + "America\/Catamarca": "ម៉ោង​នៅ​អាហ្សង់ទីន (កាតាម៉ាកា)", + "America\/Cayenne": "ម៉ោង​នៅ​ហ្គីយ៉ាន​បារាំង (កាយ៉េន)", + "America\/Cayman": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (កៃមែន)", + "America\/Chicago": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ស៊ីកាហ្គោ)", + "America\/Chihuahua": "ម៉ោង​នៅ​ប៉ាស៊ីហ្វិក​ម៉ិកស៊ិក (ជីហួហួ)", + "America\/Coral_Harbour": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (អាទីកូកាន)", + "America\/Cordoba": "ម៉ោង​នៅ​អាហ្សង់ទីន (កូដូបា)", + "America\/Costa_Rica": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (កូស្តារីកា)", + "America\/Creston": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ក្រេស្តុន)", + "America\/Cuiaba": "ម៉ោង​នៅ​អាម៉ាហ្សូន (គុយអាបា)", + "America\/Curacao": "ម៉ោង​នៅ​អាត្លង់ទិក (កូរ៉ាកៅ)", + "America\/Danmarkshavn": "ម៉ោងនៅគ្រីនវិច (ដានម៉ាកស្ហាវិន)", + "America\/Dawson": "ម៉ោង​​នៅទ្វីប​អាមរិក​ខាង​ជើងភាគខាងលិច (ដាវសុន)", + "America\/Dawson_Creek": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ដាវសុន​ក្រិក)", + "America\/Denver": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ដែនវើ)", + "America\/Detroit": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ដេត្រូអ៊ីត)", + "America\/Dominica": "ម៉ោង​នៅ​អាត្លង់ទិក (ដូមីនីក)", + "America\/Edmonton": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (អែតម៉ុងតុង)", + "America\/El_Salvador": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (អែលសាល់វ៉ាឌ័រ)", + "America\/Fort_Nelson": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ហ្វតណេលសាន់)", + "America\/Fortaleza": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (ហ្វ័រតាឡេហ្សារ)", + "America\/Glace_Bay": "ម៉ោង​នៅ​អាត្លង់ទិក (ក្លាស​បេ)", + "America\/Godthab": "ម៉ោងនៅហ្គ្រីនលែនខាងលិច (នូក)", + "America\/Goose_Bay": "ម៉ោង​នៅ​អាត្លង់ទិក (កូសេបេ)", + "America\/Grand_Turk": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ហ្គ្រេន​ទូក)", + "America\/Grenada": "ម៉ោង​នៅ​អាត្លង់ទិក (ហ្គ្រើណាដ)", + "America\/Guadeloupe": "ម៉ោង​នៅ​អាត្លង់ទិក (ហ្គោដេលូប៉េ)", + "America\/Guatemala": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ក្វាតេម៉ាឡា)", + "America\/Guayaquil": "ម៉ោង​នៅ​អេក្វាទ័រ (ហ្គុយ៉ាគីល)", + "America\/Guyana": "ម៉ោង​នៅ​ហ្គីយ៉ាន (ហ្គីយ៉ាន)", + "America\/Halifax": "ម៉ោង​នៅ​អាត្លង់ទិក (ហាលីហ្វាក)", + "America\/Havana": "ម៉ោង​នៅ​គុយបា (ឡាហាវ៉ាន)", + "America\/Hermosillo": "ម៉ោង​នៅ​ប៉ាស៊ីហ្វិក​ម៉ិកស៊ិក (ហ៊ែម៉ូស៊ីឡូ)", + "America\/Indiana\/Knox": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ណុក ឥណ្ឌាណា)", + "America\/Indiana\/Marengo": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ម៉ារេនកូ ឥណ្ឌាណា)", + "America\/Indiana\/Petersburg": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ភីធើ​ប៊ឹក ឥណ្ឌាណា)", + "America\/Indiana\/Tell_City": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ទីក្រុងថែល ឥណ្ឌាណា)", + "America\/Indiana\/Vevay": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (វេវ៉ៃ ឥណ្ឌាយ៉ាណា)", + "America\/Indiana\/Vincennes": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (វិនសេណេស ឥណ្ឌាណា)", + "America\/Indiana\/Winamac": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (វីណាម៉ាក់ ឥណ្ឌាណា)", + "America\/Indianapolis": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ឥណ្ឌាណាប៉ូលីស)", + "America\/Inuvik": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (អ៊ីនូវីក)", + "America\/Iqaluit": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (អ៊ីកាឡូអ៊ីត)", + "America\/Jamaica": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ហ្សាម៉ាអ៊ីក)", + "America\/Jujuy": "ម៉ោង​នៅ​អាហ្សង់ទីន (សូសុយ)", + "America\/Juneau": "ម៉ោង​នៅ​អាឡាស្កា (ហ្យូនៀ)", + "America\/Kentucky\/Monticello": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ម៉ងទីសេឡូ កេនទូគី)", + "America\/Kralendijk": "ម៉ោង​នៅ​អាត្លង់ទិក (ក្រាលែនឌីក)", + "America\/La_Paz": "ម៉ោង​នៅ​បូលីវី (ឡាប៉ាស)", + "America\/Lima": "ម៉ោង​នៅ​ប៉េរូ (លីម៉ា)", + "America\/Los_Angeles": "ម៉ោង​​នៅទ្វីប​អាមរិក​ខាង​ជើងភាគខាងលិច (ឡូអង់ហ្គិឡេស)", + "America\/Louisville": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (លូអ៊ីវីល)", + "America\/Lower_Princes": "ម៉ោង​នៅ​អាត្លង់ទិក (ឡូវើ​ព្រីន​ហ្គ័រទ័រ)", + "America\/Maceio": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (ម៉ាកសេអូ)", + "America\/Managua": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ម៉ាណាហ្គា)", + "America\/Manaus": "ម៉ោង​នៅ​អាម៉ាហ្សូន (ម៉ាណាអ៊ូស)", + "America\/Marigot": "ម៉ោង​នៅ​អាត្លង់ទិក (ម៉ារីហ្គុត)", + "America\/Martinique": "ម៉ោង​នៅ​អាត្លង់ទិក (ម៉ាទីនីក)", + "America\/Matamoros": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ម៉ាតាម៉ូរ៉ូស)", + "America\/Mazatlan": "ម៉ោង​នៅ​ប៉ាស៊ីហ្វិក​ម៉ិកស៊ិក (ម៉ាហ្សាតឡង់)", + "America\/Mendoza": "ម៉ោង​នៅ​អាហ្សង់ទីន (ម៉ែនឌូហ្សា)", + "America\/Menominee": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ម៉េណូមីនី)", + "America\/Merida": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ម៉េរីដា)", + "America\/Metlakatla": "ម៉ោង​នៅ​អាឡាស្កា (មេត្លា កាត្លា)", + "America\/Mexico_City": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ទីក្រុងម៉ិចស៊ីកូ)", + "America\/Miquelon": "ម៉ោង​​​នៅសង់​ព្យែរ និង​មីគុយឡុង (មីហ្គីឡុង)", + "America\/Moncton": "ម៉ោង​នៅ​អាត្លង់ទិក (ម៉ុងតុន)", + "America\/Monterrey": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ម៉ុនតេរ៉េ)", + "America\/Montevideo": "ម៉ោង​នៅ​អ៊ុយរូហ្គាយ (ម៉ុងតេវីដេអូ)", + "America\/Montserrat": "ម៉ោង​នៅ​អាត្លង់ទិក (ម៉ុងស៊ែរ៉ាត​)", + "America\/Nassau": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ណាស្សូ)", + "America\/New_York": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ញូវយ៉ក)", + "America\/Nipigon": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (នីពីកុន)", + "America\/Nome": "ម៉ោង​នៅ​អាឡាស្កា (ណូម)", + "America\/Noronha": "ម៉ោង​នៅហ្វ៊ែណាន់ដូ​ដឺណូរ៉ូញ៉ា (ណូរ៉ុនញ៉ា)", + "America\/North_Dakota\/Beulah": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ប៊ឺឡា ដាកូតា​ខាងជើង)", + "America\/North_Dakota\/Center": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (សិនធឺ ដាកូតា​ខាង​ជើង)", + "America\/North_Dakota\/New_Salem": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ញូវ​សាឡឹម ដាកូតា​ខាង​ជើង)", + "America\/Ojinaga": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (អូជីណាហ្កា)", + "America\/Panama": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ប៉ាណាម៉ា)", + "America\/Pangnirtung": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ប៉ាងនីទុង)", + "America\/Paramaribo": "ម៉ោង​នៅ​សូរីណាម (ប៉ារ៉ាម៉ារីបូ)", + "America\/Phoenix": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (ផូនីក)", + "America\/Port-au-Prince": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (ព័រអូប្រ៉ាំង)", + "America\/Port_of_Spain": "ម៉ោង​នៅ​អាត្លង់ទិក (ព័រអេស្ប៉ាញ)", + "America\/Porto_Velho": "ម៉ោង​នៅ​អាម៉ាហ្សូន (ព័រតូ​វិលហូ)", + "America\/Puerto_Rico": "ម៉ោង​នៅ​អាត្លង់ទិក (ព័រតូរីកូ)", + "America\/Punta_Arenas": "ម៉ោងនៅស៊ីលី (ពុនតា អារ៉េណា)", + "America\/Rainy_River": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (រ៉េនីរីវើ)", + "America\/Rankin_Inlet": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (រ៉ាន់ឃីន​អ៊ីនឡិត)", + "America\/Recife": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (រ៉េស៊ីហ្វី)", + "America\/Regina": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (រ៉េហ្គីណា)", + "America\/Resolute": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (រ៉េ​ស៊ូឡូត)", + "America\/Santa_Isabel": "ម៉ោង​នៅ​ម៉ិកស៊ិកភាគពាយព្យ (សាន់តាអ៊ីសាប៊ែល)", + "America\/Santarem": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (សាន់តារឹម)", + "America\/Santiago": "ម៉ោងនៅស៊ីលី (សាន់ទីអេហ្គោ)", + "America\/Santo_Domingo": "ម៉ោង​នៅ​អាត្លង់ទិក (សាន់ដូម៉ាំង)", + "America\/Sao_Paulo": "ម៉ោង​នៅ​ប្រាស៊ីលីយ៉ា (សៅ​ប៉ូឡូ)", + "America\/Scoresbysund": "ម៉ោង​​នៅ​ហ្គ្រីនលែន​ខាង​កើត (អ៊ីតូគ័រតូមីត)", + "America\/Sitka": "ម៉ោង​នៅ​អាឡាស្កា (ស៊ីតកា)", + "America\/St_Barthelemy": "ម៉ោង​នៅ​អាត្លង់ទិក (សាំង​បាធីលីម៉ី)", + "America\/St_Johns": "ម៉ោង​​នៅញូវហ្វោនឡែន (សាំង​ចន)", + "America\/St_Kitts": "ម៉ោង​នៅ​អាត្លង់ទិក (សាំង​ឃីត)", + "America\/St_Lucia": "ម៉ោង​នៅ​អាត្លង់ទិក (សាំង​លូសៀ)", + "America\/St_Thomas": "ម៉ោង​នៅ​អាត្លង់ទិក (សាំង​តូម៉ាស់)", + "America\/St_Vincent": "ម៉ោង​នៅ​អាត្លង់ទិក (សាំង​វីនសេន)", + "America\/Swift_Current": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (ស្វីត​ខឺរិន)", + "America\/Tegucigalpa": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (តេហ្គូស៊ីហ្គាល់ប៉ា)", + "America\/Thule": "ម៉ោង​នៅ​អាត្លង់ទិក (ធុឡេ)", + "America\/Thunder_Bay": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (សាន់ដឺ​បេ)", + "America\/Tijuana": "ម៉ោង​​នៅទ្វីប​អាមរិក​ខាង​ជើងភាគខាងលិច (ទីយ្យូអាណា)", + "America\/Toronto": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត (តូរ៉ុនតូ)", + "America\/Tortola": "ម៉ោង​នៅ​អាត្លង់ទិក (តូតូឡា)", + "America\/Vancouver": "ម៉ោង​​នៅទ្វីប​អាមរិក​ខាង​ជើងភាគខាងលិច (វ៉ាន់កូវើ)", + "America\/Whitehorse": "ម៉ោង​​នៅទ្វីប​អាមរិក​ខាង​ជើងភាគខាងលិច (វ៉ាយហស)", + "America\/Winnipeg": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល (វីនីភិក)", + "America\/Yakutat": "ម៉ោង​នៅ​អាឡាស្កា (យ៉ាគូតាត)", + "America\/Yellowknife": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង (យេឡូណៃ)", + "Antarctica\/Casey": "ម៉ោង​​​នៅ​អូស្ត្រាលី​ខាង​លិច (កាសី)", + "Antarctica\/Davis": "ម៉ោង​នៅ​ដាវីស (ដាវីស)", + "Antarctica\/DumontDUrville": "ម៉ោង​នៅ​ឌុយម៉ុងដឺអ៊ុយវីល (ឌុយម៉ុងដឺអ៊ុយវីល)", + "Antarctica\/Macquarie": "ម៉ោង​នៅ​កោះ​ម៉ាកគែរី (ម៉ាកខ្វារី)", + "Antarctica\/Mawson": "ម៉ោង​នៅ​ម៉ៅ​សាន់ (ម៉ៅសាន់)", + "Antarctica\/McMurdo": "ម៉ោង​នៅ​នូវែលសេឡង់ (ម៉ាក់មុយដូ)", + "Antarctica\/Palmer": "ម៉ោងនៅស៊ីលី (ផាល់ម័រ)", + "Antarctica\/Rothera": "ម៉ោង​នៅ​រ៉ូធឺរ៉ា (រ៉ូធីរ៉ា)", + "Antarctica\/Syowa": "ម៉ោង​នៅ​ស៊ីអូវ៉ា (ស៊ីយ៉ូវ៉ា)", + "Antarctica\/Troll": "ម៉ោងនៅគ្រីនវិច (ត្រូល)", + "Antarctica\/Vostok": "ម៉ោង​នៅ​វ័រស្តុក (វ៉ូស្តុក)", + "Arctic\/Longyearbyen": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ឡុង​យ៉ា​ប៊ីយេន)", + "Asia\/Aden": "ម៉ោង​នៅ​អារ៉ាប់ (អាដែន)", + "Asia\/Almaty": "ម៉ោង​កាហ្សាក់ស្ថាន​​ខាង​កើត (អាល់ម៉ាទី)", + "Asia\/Amman": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (អាម៉ាន់)", + "Asia\/Aqtau": "ម៉ោង​នៅ​កាហ្សាក់ស្ថាន​ខាង​​​លិច (អាកទូ)", + "Asia\/Aqtobe": "ម៉ោង​នៅ​កាហ្សាក់ស្ថាន​ខាង​​​លិច (អាកទូប៊ី)", + "Asia\/Ashgabat": "ម៉ោង​នៅ​តួកម៉េនីស្ថាន (អាសហ្គាបាត)", + "Asia\/Atyrau": "ម៉ោង​នៅ​កាហ្សាក់ស្ថាន​ខាង​​​លិច (អាទីរ៉ូ)", + "Asia\/Baghdad": "ម៉ោង​នៅ​អារ៉ាប់ (បាកដាដ)", + "Asia\/Bahrain": "ម៉ោង​នៅ​អារ៉ាប់ (បារ៉ែន)", + "Asia\/Baku": "ម៉ោង​នៅ​អាស៊ែបៃហ្សង់ (បាគូ)", + "Asia\/Bangkok": "ម៉ោង​នៅ​ឥណ្ឌូចិន (បាងកក)", + "Asia\/Beirut": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (បេរូត)", + "Asia\/Bishkek": "ម៉ោងនៅកៀហ្ស៊ីស៊ីស្ថាន (ប៊ីស្កេក)", + "Asia\/Brunei": "ម៉ោងនៅព្រុយណេដារូសាឡឹម (ព្រុយណេ)", + "Asia\/Calcutta": "ម៉ោង​ស្តង់ដារនៅ​ឥណ្ឌា (កុលកាតា)", + "Asia\/Chita": "ម៉ោង​នៅ​យ៉ាគុតស្កិ៍ (ឈីតា)", + "Asia\/Choibalsan": "ម៉ោង​នៅ​ឆូបាល់សាន (ឈូបាល់សាន)", + "Asia\/Colombo": "ម៉ោង​ស្តង់ដារនៅ​ឥណ្ឌា (កូឡុំបូ)", + "Asia\/Damascus": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ដាម៉ាស)", + "Asia\/Dhaka": "ម៉ោង​នៅ​បង់ក្លាដែស (ដាក្កា)", + "Asia\/Dili": "ម៉ោង​នៅ​​ទីម័រ​ខាង​កើត (ដេលី)", + "Asia\/Dubai": "ម៉ោង​ស្តង់ដា​នៅ​កាល់ (ឌុយបៃ)", + "Asia\/Dushanbe": "ម៉ោងនៅតាជីគីស្ថាន (ឌូស្ហាន់បេ)", + "Asia\/Famagusta": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ហ្វ៉ាម៉ាហ្គុស្តា)", + "Asia\/Gaza": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (កាសា)", + "Asia\/Hebron": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ហេបរុន)", + "Asia\/Hong_Kong": "ម៉ោង​នៅ​ហុងកុង (ហុងកុង)", + "Asia\/Hovd": "ម៉ោង​នៅ​ហូវ (ហូវ)", + "Asia\/Irkutsk": "ម៉ោងនៅអៀរគុតស្កិ៍ (អៀរគុតស្កិ៍)", + "Asia\/Jakarta": "ម៉ោង​នៅ​ឥណ្ឌូណេស៊ី​​ខាង​លិច (ហ្សាការតា)", + "Asia\/Jayapura": "ម៉ោង​នៅ​ឥណ្ឌូណេស៊ី​​ខាង​កើត (ចាយ៉ាភូរ៉ា)", + "Asia\/Jerusalem": "ម៉ោង​នៅ​អ៊ីស្រាអែល (ហ្ស៊េរុយសាឡិម)", + "Asia\/Kabul": "ម៉ោង​នៅ​អាហ្វហ្គានីស្ថាន (កាប៊ុល)", + "Asia\/Karachi": "ម៉ោង​នៅ​ប៉ាគីស្ថាន (ការ៉ាជី)", + "Asia\/Katmandu": "ម៉ោងនៅនេប៉ាល់ (កាត់ម៉ាន់ឌូ)", + "Asia\/Khandyga": "ម៉ោង​នៅ​យ៉ាគុតស្កិ៍ (ខាន់ឌីហ្គា)", + "Asia\/Krasnoyarsk": "ម៉ោង​នៅ​ក្រាណូយ៉ាស (ក្រាសនុយ៉ាក)", + "Asia\/Kuala_Lumpur": "ម៉ោង​នៅ​ម៉ាឡេស៊ី (កូឡាឡាំពួរ)", + "Asia\/Kuching": "ម៉ោង​នៅ​ម៉ាឡេស៊ី (ឃឺតចីង)", + "Asia\/Kuwait": "ម៉ោង​នៅ​អារ៉ាប់ (កូវ៉ែត)", + "Asia\/Macau": "ម៉ោង​នៅ​ចិន (ម៉ាកាវ)", + "Asia\/Magadan": "ម៉ោង​នៅ​ម៉ាហ្កាដាន (ម៉ាហ្គាដាន)", + "Asia\/Makassar": "ម៉ោង​នៅ​ឥណ្ឌូណេស៊ី​​​កណ្ដាល (ម៉ាកាសសារ)", + "Asia\/Manila": "ម៉ោង​នៅ​ហ្វីលីពីន (ម៉ានីល)", + "Asia\/Muscat": "ម៉ោង​ស្តង់ដា​នៅ​កាល់ (ម៉ាស្កាត)", + "Asia\/Nicosia": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (នីកូស៊ី)", + "Asia\/Novokuznetsk": "ម៉ោង​នៅ​ក្រាណូយ៉ាស (ណូវ៉ូឃូសណេតស្កិ៍)", + "Asia\/Novosibirsk": "ម៉ោង​នៅ​ណូវ៉ូស៊ីប៊ីក (ណូវ៉ូស៊ីប៊ឺក)", + "Asia\/Omsk": "ម៉ោង​នៅ​អូម (អូមស្កិ៍)", + "Asia\/Oral": "ម៉ោង​នៅ​កាហ្សាក់ស្ថាន​ខាង​​​លិច (អូរ៉ាល់)", + "Asia\/Phnom_Penh": "ម៉ោង​នៅ​ឥណ្ឌូចិន (ភ្នំពេញ)", + "Asia\/Pontianak": "ម៉ោង​នៅ​ឥណ្ឌូណេស៊ី​​ខាង​លិច (ប៉ុនទីអាណាក់)", + "Asia\/Pyongyang": "ម៉ោង​នៅ​កូរ៉េ (ព្យុងយ៉ាង)", + "Asia\/Qatar": "ម៉ោង​នៅ​អារ៉ាប់ (កាតា)", + "Asia\/Qostanay": "ម៉ោង​កាហ្សាក់ស្ថាន​​ខាង​កើត (Qostanay)", + "Asia\/Qyzylorda": "ម៉ោង​នៅ​កាហ្សាក់ស្ថាន​ខាង​​​លិច (គីហ្ស៊ីឡូដា)", + "Asia\/Rangoon": "ម៉ោង​នៅ​មីយ៉ាន់ម៉ា (រ៉ង់ហ្គូន)", + "Asia\/Riyadh": "ម៉ោង​នៅ​អារ៉ាប់ (រីយ៉ាដ)", + "Asia\/Saigon": "ម៉ោង​នៅ​ឥណ្ឌូចិន (ហូជីមីញ)", + "Asia\/Sakhalin": "ម៉ោង​នៅ​សាក់ខាលីន (សាខាលីន)", + "Asia\/Samarkand": "ម៉ោង​នៅ​អ៊ូសបេគីស្ថាន (សាម៉ាកាន់)", + "Asia\/Seoul": "ម៉ោង​នៅ​កូរ៉េ (សេអ៊ូល)", + "Asia\/Shanghai": "ម៉ោង​នៅ​ចិន (សៀងហៃ)", + "Asia\/Singapore": "ម៉ោង​នៅ​សិង្ហបូរី (សិង្ហបូរី)", + "Asia\/Srednekolymsk": "ម៉ោង​នៅ​ម៉ាហ្កាដាន (ស្រីតនីកូលីម)", + "Asia\/Taipei": "ម៉ោង​នៅ​តៃប៉ិ (តៃប៉ិ)", + "Asia\/Tashkent": "ម៉ោង​នៅ​អ៊ូសបេគីស្ថាន (តាស្កិន)", + "Asia\/Tbilisi": "ម៉ោង​នៅ​ហ្សកហ្ស៊ី (ប៊ីលីស៊ី)", + "Asia\/Tehran": "ម៉ោង​នៅ​អ៊ីរ៉ង់ (តេហេរ៉ង់)", + "Asia\/Thimphu": "ម៉ោងនៅប៊ូតង់ (ធីមភូ)", + "Asia\/Tokyo": "ម៉ោង​នៅ​ជប៉ុន (តូក្យូ)", + "Asia\/Ulaanbaatar": "ម៉ោង​នៅ​អ៊ូឡាន​បាទូ (អ៊ូឡង់បាទ័រ)", + "Asia\/Ust-Nera": "ម៉ោង​នៅ​វ៉្លាឌីវ៉ូស្តុក (អូស្តណេរ៉ា)", + "Asia\/Vientiane": "ម៉ោង​នៅ​ឥណ្ឌូចិន (វៀងចន្ទន៍)", + "Asia\/Vladivostok": "ម៉ោង​នៅ​វ៉្លាឌីវ៉ូស្តុក (វ៉្លាដីវ៉ូស្តុក)", + "Asia\/Yakutsk": "ម៉ោង​នៅ​យ៉ាគុតស្កិ៍ (យ៉ាគុតស្កិ៍)", + "Asia\/Yekaterinburg": "ម៉ោង​នៅ​អ៊ិខាធឺរីនប៊័ក (យ៉េកាធឺរិនប៊ើក)", + "Asia\/Yerevan": "ម៉ោង​នៅ​អាមេនី (យ៉េរ៉េវ៉ាន់)", + "Atlantic\/Azores": "ម៉ោង​នៅ​អេហ្សស (អាសូរ៉េស)", + "Atlantic\/Bermuda": "ម៉ោង​នៅ​អាត្លង់ទិក (ប៉ឺមុយដា)", + "Atlantic\/Canary": "ម៉ោង​នៅ​អឺរ៉ុប​ខាង​លិច (កាណារី)", + "Atlantic\/Cape_Verde": "ម៉ោង​នៅ​កាប់វែរ (កាប់វែរ)", + "Atlantic\/Faeroe": "ម៉ោង​នៅ​អឺរ៉ុប​ខាង​លិច (ហ្វារ៉ូ)", + "Atlantic\/Madeira": "ម៉ោង​នៅ​អឺរ៉ុប​ខាង​លិច (ម៉ាដៀរ៉ា)", + "Atlantic\/Reykjavik": "ម៉ោងនៅគ្រីនវិច (រ៉ៃក្យាវិក)", + "Atlantic\/South_Georgia": "ម៉ោង​នៅ​កោះ​ហ្សកហ្ស៊ី (ហ្សកហ្ស៊ី​ខាង​ត្បូង)", + "Atlantic\/St_Helena": "ម៉ោងនៅគ្រីនវិច (សាំងហេឡេណា)", + "Atlantic\/Stanley": "ម៉ោង​នៅ​ប្រជុំកោះ​ហ្វក់ឡែន (ស្តង់លី)", + "Australia\/Adelaide": "ម៉ោង​នៅអូស្ត្រាលី​កណ្ដាល (អាដេឡែត)", + "Australia\/Brisbane": "ម៉ោង​នៅ​អូស្ត្រាលី​ខាង​កើត (ប្រីសប៊ែន)", + "Australia\/Broken_Hill": "ម៉ោង​នៅអូស្ត្រាលី​កណ្ដាល (ប្រូកខិនហីល)", + "Australia\/Currie": "ម៉ោង​នៅ​អូស្ត្រាលី​ខាង​កើត (ខូរៀ)", + "Australia\/Darwin": "ម៉ោង​នៅអូស្ត្រាលី​កណ្ដាល (ដាវីន)", + "Australia\/Eucla": "ម៉ោង​នៅ​​​ភាគ​ខាង​លិច​នៅ​អូស្ត្រាលី​កណ្ដាល (អ៊ុយក្លា)", + "Australia\/Hobart": "ម៉ោង​នៅ​អូស្ត្រាលី​ខាង​កើត (ហូបាត)", + "Australia\/Lindeman": "ម៉ោង​នៅ​អូស្ត្រាលី​ខាង​កើត (លីនឌីម៉ែន)", + "Australia\/Lord_Howe": "ម៉ោង​នៅ​ឡតហៅ (ឡតហូវ៉េ)", + "Australia\/Melbourne": "ម៉ោង​នៅ​អូស្ត្រាលី​ខាង​កើត (ម៉េលប៊ន)", + "Australia\/Perth": "ម៉ោង​​​នៅ​អូស្ត្រាលី​ខាង​លិច (ភឺធ)", + "Australia\/Sydney": "ម៉ោង​នៅ​អូស្ត្រាលី​ខាង​កើត (ស៊ីដនី)", + "CST6CDT": "ម៉ោង​​នៅ​ទ្វីបអាមេរិក​ខាង​ជើងភាគកណ្តាល", + "EST5EDT": "ម៉ោងនៅទ្វីបអាមរិកខាងជើងភាគខាងកើត", + "Etc\/GMT": "ម៉ោងនៅគ្រីនវិច", + "Etc\/UTC": "ម៉ោងសកលដែលមានការសម្រួល", + "Europe\/Amsterdam": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (អាំស្ទែដាំ)", + "Europe\/Andorra": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (អង់ដូរ៉ា)", + "Europe\/Astrakhan": "ម៉ោង​នៅ​មូស្គូ (អាស្ត្រាខាន់)", + "Europe\/Athens": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (អាថែន)", + "Europe\/Belgrade": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (បែលក្រាដ)", + "Europe\/Berlin": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (បែរឡាំង)", + "Europe\/Bratislava": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ប្រាទីស្លាវ៉ា)", + "Europe\/Brussels": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ព្រុចសែល)", + "Europe\/Bucharest": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ប៊ុយការ៉េស)", + "Europe\/Budapest": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ប៊ុយដាប៉ែស)", + "Europe\/Busingen": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ប៊ូស៊ីងហ្គែន)", + "Europe\/Chisinau": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ជីស៊ីណូ)", + "Europe\/Copenhagen": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (កូប៉ិនហាក)", + "Europe\/Dublin": "ម៉ោងនៅគ្រីនវិច (ឌុយប្លាំង)", + "Europe\/Gibraltar": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ហ្ស៊ីប្រាល់តា)", + "Europe\/Guernsey": "ម៉ោងនៅគ្រីនវិច (ហ្គេនស៊ី)", + "Europe\/Helsinki": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ហែលស៊ិងគី)", + "Europe\/Isle_of_Man": "ម៉ោងនៅគ្រីនវិច (អែលអុហ្វម៉ែន)", + "Europe\/Jersey": "ម៉ោងនៅគ្រីនវិច (ជេស៊ី)", + "Europe\/Kaliningrad": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (កាលីនីងហ្រ្គាដ)", + "Europe\/Kiev": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (កៀវ)", + "Europe\/Lisbon": "ម៉ោង​នៅ​អឺរ៉ុប​ខាង​លិច (លីសបោន)", + "Europe\/Ljubljana": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ជូបហ្សាណា)", + "Europe\/London": "ម៉ោងនៅគ្រីនវិច (ឡុងដ៍)", + "Europe\/Luxembourg": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (លុចសំបួ)", + "Europe\/Madrid": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ម៉ាឌ្រីដ)", + "Europe\/Malta": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ម៉ាល់ត៍)", + "Europe\/Mariehamn": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ម៉ារៀហាំ)", + "Europe\/Minsk": "ម៉ោង​នៅ​មូស្គូ (មីនស្កិ៍)", + "Europe\/Monaco": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ម៉ូណាកូ)", + "Europe\/Moscow": "ម៉ោង​នៅ​មូស្គូ (មូស្គូ)", + "Europe\/Oslo": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (អូស្លូ)", + "Europe\/Paris": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ប៉ារីស)", + "Europe\/Podgorica": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ប៉ូដហ្គោរីកា)", + "Europe\/Prague": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ប្រាក)", + "Europe\/Riga": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (រីហ្គា)", + "Europe\/Rome": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (រ៉ូម)", + "Europe\/San_Marino": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (សាំងម៉ារ៉ាំង)", + "Europe\/Sarajevo": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (សារ៉ាយ៉េវ៉ូ)", + "Europe\/Saratov": "ម៉ោង​នៅ​មូស្គូ (សារ៉ាតាវ)", + "Europe\/Simferopol": "ម៉ោង​នៅ​មូស្គូ (ស៊ីមហ្វើរ៉ុប៉ូល)", + "Europe\/Skopje": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ស្កុបជេ)", + "Europe\/Sofia": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (សូហ៊្វីយ៉ា)", + "Europe\/Stockholm": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ស្តុកខុល)", + "Europe\/Tallinn": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (តាលិន)", + "Europe\/Tirane": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ទីរ៉ាណេ)", + "Europe\/Ulyanovsk": "ម៉ោង​នៅ​មូស្គូ (អុលយ៉ាណូវស្កិ៍)", + "Europe\/Uzhgorod": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (អ៊ុយហ្គោរ៉ូដ)", + "Europe\/Vaduz": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (វ៉ាឌូស)", + "Europe\/Vatican": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (វ៉ាទីកង់)", + "Europe\/Vienna": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (វីយែន)", + "Europe\/Vilnius": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (វីលនីញូស)", + "Europe\/Volgograd": "ម៉ោង​នៅ​វ៉ូហ្កោក្រាដ (វ៉ុលហ្គោហ្គ្រាដ)", + "Europe\/Warsaw": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (វ៉ាសូវី)", + "Europe\/Zagreb": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (សាគ្រែប)", + "Europe\/Zaporozhye": "ម៉ោង​នៅ​អឺរ៉ុប​​ខាង​កើត​ (ហ្សាប៉ូរ៉ូហ្ស៊ីយ៉េ)", + "Europe\/Zurich": "ម៉ោង​នៅ​អឺរ៉ុប​កណ្ដាល (ហ៊្សូរីច)", + "Indian\/Antananarivo": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (អង់តាណាណារីវ)", + "Indian\/Chagos": "ម៉ោង​នៅ​មហាសមុទ្រ​ឥណ្ឌា (កាហ្គោ)", + "Indian\/Christmas": "ម៉ោង​នៅ​កោះ​គ្រីស្មាស (គ្រីស្មាស)", + "Indian\/Cocos": "ម៉ោង​នៅ​ប្រជុំកោះ​កូកូស (កូកូស)", + "Indian\/Comoro": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (កូម័រ)", + "Indian\/Kerguelen": "ម៉ោងនៅបារាំងខាងត្បូង និងនៅអង់តាំងទិក (ឃឺហ្គុយឡែន)", + "Indian\/Mahe": "ម៉ោង​នៅ​សីស្ហែល (ម៉ាហេ)", + "Indian\/Maldives": "ម៉ោង​នៅ​ម៉ាល់ឌីវ (ម៉ាល់ឌីវ)", + "Indian\/Mauritius": "ម៉ោង​នៅ​ម៉ូរីស (ម៉ូរីស)", + "Indian\/Mayotte": "ម៉ោង​នៅ​អាហ្វ្រិក​ខាង​កើត (ម៉ាយុត)", + "Indian\/Reunion": "ម៉ោងនៅរេអ៊ុយ៉ុង (រេអ៊ុយ៉ុង)", + "MST7MDT": "ម៉ោង​នៅតំបន់ភ្នំនៃទ្វីប​អាមេរិក​​​ខាង​ជើង", + "PST8PDT": "ម៉ោង​​នៅទ្វីប​អាមរិក​ខាង​ជើងភាគខាងលិច", + "Pacific\/Apia": "ម៉ោង​នៅ​អាប្យា (អាពី)", + "Pacific\/Auckland": "ម៉ោង​នៅ​នូវែលសេឡង់ (អកឡែន)", + "Pacific\/Bougainville": "ម៉ោង​នៅប៉ាពូអាស៊ី នូវែលហ្គីណេ (បូហ្គែនវីល)", + "Pacific\/Chatham": "ម៉ោង​នៅ​ចាថាំ (ចាថាំ)", + "Pacific\/Easter": "ម៉ោងនៅកោះអ៊ីស្ទ័រ (អ៊ីស្ទ័រ)", + "Pacific\/Efate": "ម៉ោង​នៅ​វ៉ានូទូ (អ៊ីហ្វាតេ)", + "Pacific\/Enderbury": "ម៉ោង​នៅ​កោះ​ផូនីក (អ៊ីនដឺប៊ូរី)", + "Pacific\/Fakaofo": "ម៉ោង​នៅ​តូខេឡៅ (ហ្វាកៅហ្វូ)", + "Pacific\/Fiji": "ម៉ោង​នៅ​ហ្វីជី (ហ្វីជី)", + "Pacific\/Funafuti": "ម៉ោង​នៅ​ទុយវ៉ាលូ (ហ៊្វូណាហ៊្វូទី)", + "Pacific\/Galapagos": "ម៉ោង​នៅ​កាឡាប៉ាកូស (ហ្គាឡាប៉ាហ្គោស)", + "Pacific\/Gambier": "ម៉ោង​នៅ​កាំបៀ (ហ្គាំបៀ)", + "Pacific\/Guadalcanal": "ម៉ោង​នៅ​កោះ​សូឡូម៉ុន (ហ្គាដាល់ខាណាល់)", + "Pacific\/Guam": "ម៉ោង​ស្តង់ដារនៅ​ចាំម៉ូរ៉ូ (ហ្គាំ)", + "Pacific\/Honolulu": "ម៉ោង​​នៅ​ហាវៃ-អាល់ដ្យូសិន (ហូណូលូលូ)", + "Pacific\/Johnston": "ម៉ោង​​នៅ​ហាវៃ-អាល់ដ្យូសិន (ចនស្តុន)", + "Pacific\/Kiritimati": "ម៉ោង​នៅ​កោះ​ឡាញ (គិរីទីម៉ាទិ)", + "Pacific\/Kosrae": "ម៉ោង​នៅ​កូស្រៃ (កូស្រែ)", + "Pacific\/Kwajalein": "ម៉ោង​នៅ​ម៉ាសាល (ក្វាហ្សាលៀន)", + "Pacific\/Majuro": "ម៉ោង​នៅ​ម៉ាសាល (ម៉ាហ្សូរ៉ូ)", + "Pacific\/Marquesas": "ម៉ោង​នៅ​កោះ​ម៉ាគឺសាស់ (ម៉ាហ្គីសាស)", + "Pacific\/Midway": "ម៉ោង​នៅ​សាម័រ (មីតវ៉េ)", + "Pacific\/Nauru": "ម៉ោង​នៅ​ណូរូ (ណូរូ)", + "Pacific\/Niue": "ម៉ោងនៅ​នីវ៉េ (នីវ៉េ)", + "Pacific\/Norfolk": "ម៉ោង​នៅ​កោះ​ន័រហ្វក់ (ណ័រហ្វុក)", + "Pacific\/Noumea": "ម៉ោង​នៅណូវ៉ែលកាឡេដូនៀ (ណូមៀ)", + "Pacific\/Pago_Pago": "ម៉ោង​នៅ​សាម័រ (ប៉ាហ្គោ ប៉ាហ្គោ)", + "Pacific\/Palau": "ម៉ោង​នៅ​ផាឡៅ (ប៉ាឡៅ)", + "Pacific\/Pitcairn": "ម៉ោង​នៅ​ភីឃឺន (ភីតខៃរ៉ិន)", + "Pacific\/Ponape": "ម៉ោង​នៅ​ប៉ូណាប់ (ផុនប៉ី)", + "Pacific\/Port_Moresby": "ម៉ោង​នៅប៉ាពូអាស៊ី នូវែលហ្គីណេ (ព័រម៉ូរេសប៊ី)", + "Pacific\/Rarotonga": "ម៉ោង​នៅប្រជុំ​កោះ​ខូក (រ៉ារ៉ូតុងហ្គា)", + "Pacific\/Saipan": "ម៉ោង​ស្តង់ដារនៅ​ចាំម៉ូរ៉ូ (សៃប៉ាន)", + "Pacific\/Tahiti": "ម៉ោង​នៅ​តាហិទី (តាហីទី)", + "Pacific\/Tarawa": "ម៉ោង​នៅ​កោះ​កីប៊ឺត (តារ៉ាវ៉ា)", + "Pacific\/Tongatapu": "ម៉ោង​នៅ​តុងហ្គា (តុងហ្គាតាពូ)", + "Pacific\/Truk": "ម៉ោង​នៅ​ចូអុក (ឈូអុក)", + "Pacific\/Wake": "ម៉ោង​នៅ​កោះវេក (វ៉ាគី)", + "Pacific\/Wallis": "ម៉ោង​នៅ​វ៉ាលីស និងហ្វ៊ុទូណា (វ៉ាលីស)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/kn.json b/src/Symfony/Component/Intl/Resources/data/timezones/kn.json new file mode 100644 index 0000000000000..c1a3944baf3e1 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/kn.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಅಬಿದ್‌ಜನ್)", + "Africa\/Accra": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಅಕ್ರಾ)", + "Africa\/Addis_Ababa": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಆಡಿಸ್ ಅಬಾಬಾ)", + "Africa\/Algiers": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಅಲ್ಜೀರ್ಸ್)", + "Africa\/Asmera": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಅಸ್ಮಾರಾ)", + "Africa\/Bamako": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಬಮಾಕೊ)", + "Africa\/Bangui": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಬಾಂಗಿ)", + "Africa\/Banjul": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಬಂಜುಲ್)", + "Africa\/Bissau": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಬಿಸ್ಸಾವ್)", + "Africa\/Blantyre": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಬ್ಲ್ಯಾಂಟೈರ್)", + "Africa\/Brazzaville": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಬ್ರೆಜಾವೀಲ್)", + "Africa\/Bujumbura": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಬುಜುಂಬುರಾ)", + "Africa\/Cairo": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಕೈರೋ)", + "Africa\/Casablanca": "ಪಶ್ಚಿಮ ಯುರೋಪಿಯನ್ ಸಮಯ (ಕ್ಯಾಸಾಬ್ಲಾಂಕಾ)", + "Africa\/Ceuta": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಸೆಯುಟಾ)", + "Africa\/Conakry": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಕೊನಾಕ್ರಿ)", + "Africa\/Dakar": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಡಾಕರ್)", + "Africa\/Dar_es_Salaam": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಡಾರ್ ಎಸ್ ಸಲಾಮ್)", + "Africa\/Djibouti": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಜಿಬೂಟಿ)", + "Africa\/Douala": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ದೌಲಾ)", + "Africa\/El_Aaiun": "ಪಶ್ಚಿಮ ಯುರೋಪಿಯನ್ ಸಮಯ (ಎಲ್ ಔನ್)", + "Africa\/Freetown": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಫ್ರೀಟೌನ್)", + "Africa\/Gaborone": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಗ್ಯಾಬರೋನೆ)", + "Africa\/Harare": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಹರಾರೆ)", + "Africa\/Johannesburg": "ದಕ್ಷಿಣ ಆಫ್ರಿಕಾ ಪ್ರಮಾಣಿತ ಸಮಯ (ಜೋಹಾನ್ಸ್‌ಬರ್ಗ್)", + "Africa\/Juba": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಜುಬಾ)", + "Africa\/Kampala": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಕಂಪಾಲಾ)", + "Africa\/Khartoum": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಖರ್ಟೋಮ್)", + "Africa\/Kigali": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಕಿಗಾಲಿ)", + "Africa\/Kinshasa": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಕಿನ್ಷಾಸಾ)", + "Africa\/Lagos": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಲಾಗೋಸ್)", + "Africa\/Libreville": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಲಿಬ್ರೆವೀಲ್)", + "Africa\/Lome": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಲೋಮ್)", + "Africa\/Luanda": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಲುವಾಂಡಾ)", + "Africa\/Lubumbashi": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಲುಬುಂಬಾಶಿ)", + "Africa\/Lusaka": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಲುಸಾಕಾ)", + "Africa\/Malabo": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಮಲಾಬೋ)", + "Africa\/Maputo": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ಮ್ಯಾಪುಟೊ)", + "Africa\/Maseru": "ದಕ್ಷಿಣ ಆಫ್ರಿಕಾ ಪ್ರಮಾಣಿತ ಸಮಯ (ಮಸೇರು)", + "Africa\/Mbabane": "ದಕ್ಷಿಣ ಆಫ್ರಿಕಾ ಪ್ರಮಾಣಿತ ಸಮಯ (ಅಂಬಬಾನೆ)", + "Africa\/Mogadishu": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಮೊಗಾದಿಶು)", + "Africa\/Monrovia": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಮೊನ್ರೋವಿಯಾ)", + "Africa\/Nairobi": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ನೈರೋಬಿ)", + "Africa\/Ndjamena": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಡ್ಜಮೇನಾ)", + "Africa\/Niamey": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ನಿಯಾಮೆ)", + "Africa\/Nouakchott": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ನೌಕ್‌ಚೋಟ್ಟ್)", + "Africa\/Ouagadougou": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಔಗಾಡೋಗು)", + "Africa\/Porto-Novo": "ಪಶ್ಚಿಮ ಆಫ್ರಿಕಾ ಸಮಯ (ಪೋರ್ಟೋ-ನೋವೋ)", + "Africa\/Sao_Tome": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಸಾವ್ ಟೊಮಿ)", + "Africa\/Tripoli": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಟ್ರೈಪೋಲಿ)", + "Africa\/Tunis": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಟುನೀಸ್)", + "Africa\/Windhoek": "ಮಧ್ಯ ಆಫ್ರಿಕಾ ಸಮಯ (ವಿಂಡ್ಹೋಕ್)", + "America\/Adak": "ಹವಾಯಿ-ಅಲ್ಯುಟಿಯನ್ ಸಮಯ (ಅಡಕ್‌‌)", + "America\/Anchorage": "ಅಲಾಸ್ಕಾ ಸಮಯ (ಆಂಕರೋಜ್)", + "America\/Anguilla": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಆಂಗ್ವಿಲ್ಲಾ)", + "America\/Antigua": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಆಂಟಿಗುವಾ)", + "America\/Araguaina": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಅರಾಗುಯಾನಾ)", + "America\/Argentina\/La_Rioja": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಲಾ ರಿಯೋಜಾ)", + "America\/Argentina\/Rio_Gallegos": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ರಿಯೋ ಗಲ್ಲೆಗೊಸ್)", + "America\/Argentina\/Salta": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಸಾಲ್ಟಾ)", + "America\/Argentina\/San_Juan": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಸ್ಯಾನ್ ಜುವಾನ್)", + "America\/Argentina\/San_Luis": "ಪಶ್ಚಿಮ ಅರ್ಜೆಂಟೀನಾ ಸಮಯ (ಸ್ಯಾನ್ ಲೂಯೀಸ್)", + "America\/Argentina\/Tucuman": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಟುಕುಮಾನ್)", + "America\/Argentina\/Ushuaia": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಉಶ್ವಾಯ)", + "America\/Aruba": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಅರುಬಾ)", + "America\/Asuncion": "ಪರಾಗ್ವೇ ಸಮಯ (ಅಸುನ್ಸಿಯಾನ್)", + "America\/Bahia": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಬಹೀಯಾ)", + "America\/Bahia_Banderas": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಬಾಹಿಯಾ ಬಂಡೇರಾಸ್)", + "America\/Barbados": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಬಾರ್ಬಡೋಸ್)", + "America\/Belem": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಬೇಲೆಂ)", + "America\/Belize": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಬೆಲೀಜ್)", + "America\/Blanc-Sablon": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಬ್ಲಾಂಕ್-ಸಾಬ್ಲನ್)", + "America\/Boa_Vista": "ಅಮೆಜಾನ್ ಸಮಯ (ಬೋವಾ ವಿಸ್ಟ)", + "America\/Bogota": "ಕೊಲಂಬಿಯಾ ಸಮಯ (ಬೊಗೋಟ)", + "America\/Boise": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಬ್ವಾಸಿ)", + "America\/Buenos_Aires": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಬ್ಯೂನಸ್ ಐರಿಸ್)", + "America\/Cambridge_Bay": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಕೇಮ್‌ಬ್ರಿಡ್ಜ್ ಬೇ)", + "America\/Campo_Grande": "ಅಮೆಜಾನ್ ಸಮಯ (ಕಾಂಪೊ ಗ್ರಾಂಡೆ)", + "America\/Cancun": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಕ್ಯಾಂಕನ್)", + "America\/Caracas": "ವೆನಿಜುವೆಲಾ ಸಮಯ (ಕ್ಯಾರಕಾಸ್)", + "America\/Catamarca": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಕಟಮಾರ್ಕ)", + "America\/Cayenne": "ಫ್ರೆಂಚ್ ಗಯಾನಾ ಸಮಯ (ಕೆಯೆನಿ)", + "America\/Cayman": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಕೇಮನ್)", + "America\/Chicago": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಚಿಕಾಗೋ)", + "America\/Chihuahua": "ಮೆಕ್ಸಿಕನ್ ಪೆಸಿಫಿಕ್ ಸಮಯ (ಚಿವಾವ)", + "America\/Coral_Harbour": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಅಟಿಕೊಕಾನ್)", + "America\/Cordoba": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಕೊರ್ಡೊಬಾ)", + "America\/Costa_Rica": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಕೋಸ್ಟಾ ರಿಕಾ)", + "America\/Creston": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಕ್ರೆಸ್ಟನ್)", + "America\/Cuiaba": "ಅಮೆಜಾನ್ ಸಮಯ (ಕ್ಯೂಇಬಾ)", + "America\/Curacao": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಕುರಾಕಾವ್)", + "America\/Danmarkshavn": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಡನ್‌ಮಾರ್ಕ್‌ಶ್ವಾನ್)", + "America\/Dawson": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೆಸಿಫಿಕ್ ಸಮಯ (ಡಾಸನ್)", + "America\/Dawson_Creek": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಡಾಸನ್ ಕ್ರೀಕ್)", + "America\/Denver": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಡೆನ್ವರ್)", + "America\/Detroit": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಡೆಟ್ರಾಯ್ಟ್)", + "America\/Dominica": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಡೊಮಿನಿಕಾ)", + "America\/Edmonton": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಎಡ್ಮಂಟನ್‌)", + "America\/El_Salvador": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಎಲ್ ಸಾಲ್ವಡೋರ್)", + "America\/Fort_Nelson": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಫೋರ್ಟ್ ನೆಲ್ಸನ್)", + "America\/Fortaleza": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಫೊರ್ಟಲೆಜಾ)", + "America\/Glace_Bay": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಗ್ಲೇಸ್ ಬೇ)", + "America\/Godthab": "ಪಶ್ಚಿಮ ಗ್ರೀನ್‌ಲ್ಯಾಂಡ್ ಸಮಯ (ನೂಕ್)", + "America\/Goose_Bay": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಗೂಸ್ ಬೇ)", + "America\/Grand_Turk": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಗ್ರ್ಯಾಂಡ್ ಟರ್ಕ್)", + "America\/Grenada": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಗ್ರೆನಾಡ)", + "America\/Guadeloupe": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಗ್ವಾಡೆಲೋಪ್)", + "America\/Guatemala": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಗ್ವಾಟೆಮಾಲಾ)", + "America\/Guayaquil": "ಈಕ್ವೆಡಾರ್ ಸಮಯ (ಗುಯಾಕ್ವಿಲ್)", + "America\/Guyana": "ಗಯಾನಾ ಸಮಯ (ಗಯಾನಾ)", + "America\/Halifax": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಹ್ಯಾಲಿಫೆಕ್ಸ್)", + "America\/Havana": "ಕ್ಯೂಬಾ ಸಮಯ (ಹವಾನಾ)", + "America\/Hermosillo": "ಮೆಕ್ಸಿಕನ್ ಪೆಸಿಫಿಕ್ ಸಮಯ (ಹರ್ಮೊಸಿಲ್ಲೋ)", + "America\/Indiana\/Knox": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ನಾಕ್ಸ್, ಇಂಡಿಯಾನಾ)", + "America\/Indiana\/Marengo": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಮರೆಂಗೊ, ಇಂಡಿಯಾನಾ)", + "America\/Indiana\/Petersburg": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಪೀಟರ್ಸ್‌ಬರ್ಗ್, ಇಂಡಿಯಾನಾ)", + "America\/Indiana\/Tell_City": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಟೆಲ್ ಸಿಟಿ, ಇಂಡಿಯಾನಾ)", + "America\/Indiana\/Vevay": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ವೇವಾಯ್, ಇಂಡಿಯಾನಾ)", + "America\/Indiana\/Vincennes": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ವಿನ್‌ಸೆನ್ನೀಸ್, ಇಂಡಿಯಾನಾ)", + "America\/Indiana\/Winamac": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ವಿನಾಮ್ಯಾಕ್, ಇಂಡಿಯಾನಾ)", + "America\/Indianapolis": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಇಂಡಿಯಾನಾಪೊಲಿಸ್)", + "America\/Inuvik": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಇನುವಿಕ್)", + "America\/Iqaluit": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಈಕ್ವಾಲಿಟ್)", + "America\/Jamaica": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಜಮೈಕಾ)", + "America\/Jujuy": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಜುಜೈ)", + "America\/Juneau": "ಅಲಾಸ್ಕಾ ಸಮಯ (ಜುನೇವ್)", + "America\/Kentucky\/Monticello": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಮೊಂಟಿಸೆಲ್ಲೋ, ಕೆಂಟುಕಿ)", + "America\/Kralendijk": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಕ್ರೆಲೆಂಡಿಜ್ಕ್)", + "America\/La_Paz": "ಬೊಲಿವಿಯಾ ಸಮಯ (ಲಾ ಪೆಜ್)", + "America\/Lima": "ಪೆರು ಸಮಯ (ಲಿಮಾ)", + "America\/Los_Angeles": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೆಸಿಫಿಕ್ ಸಮಯ (ಲಾಸ್ ಏಂಜಲೀಸ್)", + "America\/Louisville": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಲೂಯೀಸ್‌ವಿಲ್ಲೆ)", + "America\/Lower_Princes": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಲೋವರ್ ಪ್ರಿನ್ಸಸ್ ಕ್ವಾರ್ಟರ್)", + "America\/Maceio": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಮೆಸೀಯೊ)", + "America\/Managua": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಮನಾಗುವಾ)", + "America\/Manaus": "ಅಮೆಜಾನ್ ಸಮಯ (ಮನಾವ್ಸ್)", + "America\/Marigot": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಮರಿಗೊ)", + "America\/Martinique": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಮಾರ್ಟಿನಿಕ್)", + "America\/Matamoros": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಮಟಾಮೋರಸ್)", + "America\/Mazatlan": "ಮೆಕ್ಸಿಕನ್ ಪೆಸಿಫಿಕ್ ಸಮಯ (ಮಜಟ್ಲಾನ್)", + "America\/Mendoza": "ಅರ್ಜೆಂಟಿನಾ ಸಮಯ (ಮೆಂಡೊಜಾ)", + "America\/Menominee": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಮೆನೊಮಿನೀ)", + "America\/Merida": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಮೆರಿದಾ)", + "America\/Metlakatla": "ಅಲಾಸ್ಕಾ ಸಮಯ (ಮೆಟ್ಲಾಕಾಟ್ಲಾ)", + "America\/Mexico_City": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಮೆಕ್ಸಿಕೋ ನಗರ)", + "America\/Miquelon": "ಸೇಂಟ್ ಪಿಯರ್ ಮತ್ತು ಮಿಕ್ವೆಲನ್ ಸಮಯ (ಮಿಕೆಲಾನ್)", + "America\/Moncton": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಮಾಂಕ್ಟನ್)", + "America\/Monterrey": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಮಾಂಟೆರ್ರಿ)", + "America\/Montevideo": "ಉರುಗ್ವೇ ಸಮಯ (ಮಾಂಟಿವೀಡಿಯೊ)", + "America\/Montserrat": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಮಾಂಟ್‌ಸೆರೇಟ್)", + "America\/Nassau": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ನಸ್ಸೌವ್)", + "America\/New_York": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ನ್ಯೂಯಾರ್ಕ್)", + "America\/Nipigon": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ನಿಪಿಗನ್)", + "America\/Nome": "ಅಲಾಸ್ಕಾ ಸಮಯ (ನೋಮ್)", + "America\/Noronha": "ಫೆರ್ನಾಂಡೋ ಡೆ ನೊರೊನ್ಹಾ ಸಮಯ (ನೊರೊನ್ಹಾ)", + "America\/North_Dakota\/Beulah": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಬ್ಯೂಲಾ, ಉತ್ತರ ಡಕೊಟ)", + "America\/North_Dakota\/Center": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಸೆಂಟರ್, ಉತ್ತರ ಡಕೊಟ)", + "America\/North_Dakota\/New_Salem": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ನ್ಯೂ ಸಲೇಂ, ಉತ್ತರ ಡಕೊಟ)", + "America\/Ojinaga": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಓಜಿನಾಗಾ)", + "America\/Panama": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಪನಾಮಾ)", + "America\/Pangnirtung": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಪಂಗ್ನೀರ್‌ಟಂಗ್)", + "America\/Paramaribo": "ಸುರಿನೇಮ್ ಸಮಯ (ಪರಮಾರಿಬೋ)", + "America\/Phoenix": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಫಿನಿಕ್ಸ್)", + "America\/Port-au-Prince": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಪೋರ್ಟ್-ಒ-ಪ್ರಿನ್ಸ್)", + "America\/Port_of_Spain": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಪೋರ್ಟ್ ಆಫ್ ಸ್ಪೇನ್)", + "America\/Porto_Velho": "ಅಮೆಜಾನ್ ಸಮಯ (ಪೋರ್ಟೊ ವೆಲ್ಹೋ)", + "America\/Puerto_Rico": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಪ್ಯುರ್ಟೋ ರಿಕೊ)", + "America\/Punta_Arenas": "ಚಿಲಿ ಸಮಯ (ಪುಂತಾ ಅರೇನಾಸ್)", + "America\/Rainy_River": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ರೈನಿ ರಿವರ್)", + "America\/Rankin_Inlet": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ರಾಂಕಿನ್ ಇನ್‌ಲೆಟ್)", + "America\/Recife": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ರೆಸಿಫಿ)", + "America\/Regina": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ರೆಜಿನಾ)", + "America\/Resolute": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ರೆಸೊಲ್ಯೂಟ್)", + "America\/Santa_Isabel": "ವಾಯವ್ಯ ಮೆಕ್ಸಿಕೊ ಸಮಯ (ಸಾಂತಾ ಇಸಾಬೆಲ್)", + "America\/Santarem": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಸಾಂಟರೆಮ್)", + "America\/Santiago": "ಚಿಲಿ ಸಮಯ (ಸ್ಯಾಂಟಿಯಾಗೊ)", + "America\/Santo_Domingo": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಸ್ಯಾಂಟೋ ಡೊಮಿಂಗೊ)", + "America\/Sao_Paulo": "ಬ್ರೆಸಿಲಿಯಾದ ಸಮಯ (ಸಾವ್ ಪಾಲೊ)", + "America\/Scoresbysund": "ಪೂರ್ವ ಗ್ರೀನ್‌ಲ್ಯಾಂಡ್ ಸಮಯ (ಇಟ್ಟೊಕ್ಕೊರ್ಟೂಮಿಯೈಟ್)", + "America\/Sitka": "ಅಲಾಸ್ಕಾ ಸಮಯ (ಸಿತ್ಕಾ)", + "America\/St_Barthelemy": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಸೇಂಟ್ ಬಾರ್ತೆಲೆಮಿ)", + "America\/St_Johns": "ನ್ಯೂಫೌಂಡ್‌ಲ್ಯಾಂಡ್ ಸಮಯ (ಸೇಂಟ್ ಜಾನ್ಸ್)", + "America\/St_Kitts": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಸೇಂಟ್ ಕಿಟ್ಸ್)", + "America\/St_Lucia": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಸೇಂಟ್ ಲೂಸಿಯಾ)", + "America\/St_Thomas": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಸೆಂಟ್ ಥಾಮಸ್)", + "America\/St_Vincent": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಸೇಂಟ್ ವಿನ್ಸೆಂಟ್)", + "America\/Swift_Current": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ಸ್ವಿಫ್ಟ್ ಕರೆಂಟ್)", + "America\/Tegucigalpa": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ತೆಗುಸಿಗಲ್ಪಾ)", + "America\/Thule": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಥೂಲೆ)", + "America\/Thunder_Bay": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಥಂಡರ್ ಬೇ)", + "America\/Tijuana": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೆಸಿಫಿಕ್ ಸಮಯ (ತಿಜ್ವಾನಾ)", + "America\/Toronto": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ (ಟೊರೊಂಟೋ)", + "America\/Tortola": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಟಾರ್ಟೊಲಾ)", + "America\/Vancouver": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೆಸಿಫಿಕ್ ಸಮಯ (ವ್ಯಾಂಕೊವರ್‌)", + "America\/Whitehorse": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೆಸಿಫಿಕ್ ಸಮಯ (ವೈಟ್‌ಹಾರ್ಸ್)", + "America\/Winnipeg": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ (ವಿನ್ನಿಪೆಗ್)", + "America\/Yakutat": "ಅಲಾಸ್ಕಾ ಸಮಯ (ಯಾಕುಟಾಟ್)", + "America\/Yellowknife": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ (ಯೆಲ್ಲೋ‌ನೈಫ್)", + "Antarctica\/Casey": "ಪಶ್ಚಿಮ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಕೇಸಿ)", + "Antarctica\/Davis": "ಡೇವಿಸ್ ಸಮಯ (ಡೇವೀಸ್)", + "Antarctica\/DumontDUrville": "ಡುಮಂಟ್-ಡಿ ಉರ್ವಿಲೆ ಸಮಯ (ಡುಮಂಟ್ ಡಿ ಉರ್ವಿಲೆ)", + "Antarctica\/Macquarie": "ಮ್ಯಾಕ್‌ಕ್ಯುರೈ ದ್ವೀಪ ಸಮಯ (ಮ್ಯಾಕ್ವೆರಿ)", + "Antarctica\/Mawson": "ಮಾವ್‌ಸನ್ ಸಮಯ (ಮಾವ್ಸನ್)", + "Antarctica\/McMurdo": "ನ್ಯೂಜಿಲ್ಯಾಂಡ್ ಸಮಯ (ಮ್ಯಾಕ್‍ಮುರ್ಡೊ)", + "Antarctica\/Palmer": "ಚಿಲಿ ಸಮಯ (ಪಾಲ್ಮರ್)", + "Antarctica\/Rothera": "ರೊತೇರಾ ಸಮಯ (ರೊಥೇರಾ)", + "Antarctica\/Syowa": "ಸ್ಯೊವಾ ಸಮಯ (ಸ್ಯೋವಾ)", + "Antarctica\/Troll": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಟ್ರಾಲ್)", + "Antarctica\/Vostok": "ವೋಸ್ಟೊಕ್ ಸಮಯ (ವೋಸ್ಟೋಕ್)", + "Arctic\/Longyearbyen": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಲಾಂಗ್ಯೀರ್ಬೆನ್)", + "Asia\/Aden": "ಅರೇಬಿಯನ್ ಸಮಯ (ಏಡನ್)", + "Asia\/Almaty": "ಪೂರ್ವ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಅಲ್ಮಾಟಿ)", + "Asia\/Amman": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಅಮ್ಮಾನ್)", + "Asia\/Anadyr": "ಅನಡೀರ್‌ ಸಮಯ (ಅನದ್ಯರ್)", + "Asia\/Aqtau": "ಪಶ್ಚಿಮ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಅಕ್ತಾವ್)", + "Asia\/Aqtobe": "ಪಶ್ಚಿಮ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಅಕ್ಟೋಬೆ)", + "Asia\/Ashgabat": "ತುರ್ಕ್‌ಮೇನಿಸ್ತಾನ್ ಸಮಯ (ಅಶ್ಗಬಾತ್)", + "Asia\/Atyrau": "ಪಶ್ಚಿಮ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಅಟ್ರಾವ್)", + "Asia\/Baghdad": "ಅರೇಬಿಯನ್ ಸಮಯ (ಬಾಗ್ದಾದ್)", + "Asia\/Bahrain": "ಅರೇಬಿಯನ್ ಸಮಯ (ಬಹ್ರೇನ್)", + "Asia\/Baku": "ಅಜರ್ಬೈಜಾನ್ ಸಮಯ (ಬಕು)", + "Asia\/Bangkok": "ಇಂಡೊಚೈನಾ ಸಮಯ (ಬ್ಯಾಂಕಾಕ್)", + "Asia\/Beirut": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬೀರಟ್)", + "Asia\/Bishkek": "ಕಿರ್ಗಿಸ್ತಾನ್ ಸಮಯ (ಬಿಶ್ಕೆಕ್)", + "Asia\/Brunei": "ಬ್ರೂನಿ ದಾರುಸಲೆಮ್ ಸಮಯ (ಬ್ರೂನಿ)", + "Asia\/Calcutta": "ಭಾರತೀಯ ಪ್ರಮಾಣಿತ ಸಮಯ (ಕೊಲ್ಕತ್ತಾ)", + "Asia\/Chita": "ಯಾಕುಟ್ಸಕ್ ಸಮಯ (ಚಿಟ)", + "Asia\/Choibalsan": "ಚೊಯ್‌ಬಲ್ಸಾನ್ ಸಮಯ (ಚೊಯ್‍ಬಾಲ್ಸನ್)", + "Asia\/Colombo": "ಭಾರತೀಯ ಪ್ರಮಾಣಿತ ಸಮಯ (ಕೊಲಂಬೊ)", + "Asia\/Damascus": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಡಮಾಸ್ಕಸ್)", + "Asia\/Dhaka": "ಬಾಂಗ್ಲಾದೇಶ ಸಮಯ (ಢಾಕಾ)", + "Asia\/Dili": "ಪೂರ್ವ ಟಿಮೋರ್ ಸಮಯ (ದಿಲಿ)", + "Asia\/Dubai": "ಗಲ್ಫ್ ಪ್ರಮಾಣಿತ ಸಮಯ (ದುಬೈ)", + "Asia\/Dushanbe": "ತಝಕಿಸ್ತಾನ್ ಸಮಯ (ದುಶಾಂಬೆ)", + "Asia\/Famagusta": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಫಮಾಗುಸ್ತಾ)", + "Asia\/Gaza": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಗಾಜಾ)", + "Asia\/Hebron": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಹೆಬ್ರಾನ್)", + "Asia\/Hong_Kong": "ಹಾಂಗ್ ಕಾಂಗ್ ಸಮಯ (ಹಾಂಗ್ ಕಾಂಗ್)", + "Asia\/Hovd": "ಹವ್ಡ್ ಸಮಯ (ಹೋವ್ಡ್)", + "Asia\/Irkutsk": "ಇರ್‌ಕುಟಸ್ಕ್ ಸಮಯ (ಇರಕುಟ್ಸ್ಕ್)", + "Asia\/Jakarta": "ಪಶ್ಚಿಮ ಇಂಡೋನೇಷಿಯ ಸಮಯ (ಜಕಾರ್ತಾ)", + "Asia\/Jayapura": "ಪೂರ್ವ ಇಂಡೋನೇಷಿಯಾ ಸಮಯ (ಜಯಪುರ)", + "Asia\/Jerusalem": "ಇಸ್ರೇಲ್ ಸಮಯ (ಜೆರುಸಲೆಮ್)", + "Asia\/Kabul": "ಅಫಘಾನಿಸ್ತಾನ ಸಮಯ (ಕಾಬೂಲ್)", + "Asia\/Kamchatka": "ಪೆತ್ರೋಪಾವ್ಲೋಸ್ಕ್‌‌-ಕಮ್ಚತ್ಸ್‌ಕೀ ಸಮಯ (ಕಂಚಟ್ಕ್)", + "Asia\/Karachi": "ಪಾಕಿಸ್ತಾನ ಸಮಯ (ಕರಾಚಿ)", + "Asia\/Katmandu": "ನೇಪಾಳ ಸಮಯ (ಕಠ್ಮಂಡು)", + "Asia\/Khandyga": "ಯಾಕುಟ್ಸಕ್ ಸಮಯ (ಖಂಡ್ಯಾಗಾ)", + "Asia\/Krasnoyarsk": "ಕ್ರಾಸ್‌ನೊಯಾರ್ಸ್ಕ್ ಸಮಯ (ಕ್ರಾಸ್ನೊಯಾರ್ಸ್ಕ್)", + "Asia\/Kuala_Lumpur": "ಮಲೇಷಿಯಾ ಸಮಯ (ಕೌಲಾ ಲಂಪುರ)", + "Asia\/Kuching": "ಮಲೇಷಿಯಾ ಸಮಯ (ಕುಚಿಂಗ್)", + "Asia\/Kuwait": "ಅರೇಬಿಯನ್ ಸಮಯ (ಕುವೈತ್)", + "Asia\/Macau": "ಚೀನಾ ಸಮಯ (ಮಕಾವು)", + "Asia\/Magadan": "ಮಗಡಾನ್ ಸಮಯ (ಮಗದನ್‌)", + "Asia\/Makassar": "ಮಧ್ಯ ಇಂಡೋನೇಷಿಯಾ ಸಮಯ (ಮೆಕಾಸ್ಸರ್)", + "Asia\/Manila": "ಫಿಲಿಫೈನ್ ಸಮಯ (ಮನಿಲಾ)", + "Asia\/Muscat": "ಗಲ್ಫ್ ಪ್ರಮಾಣಿತ ಸಮಯ (ಮಸ್ಕಟ್)", + "Asia\/Nicosia": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ನಿಕೋಸಿಯಾ)", + "Asia\/Novokuznetsk": "ಕ್ರಾಸ್‌ನೊಯಾರ್ಸ್ಕ್ ಸಮಯ (ನೋವೋಕುಜೆ)", + "Asia\/Novosibirsk": "ನೊವೊಸಿಬಿರ್‌ಸ್ಕ್ ಸಮಯ (ನೊವೋಸಿಬಿಸ್ಕ್)", + "Asia\/Omsk": "ಒಮಾಸ್ಕ್ ಸಮಯ (ಒಮ್ಸ್ಕ್)", + "Asia\/Oral": "ಪಶ್ಚಿಮ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಒರಲ್)", + "Asia\/Phnom_Penh": "ಇಂಡೊಚೈನಾ ಸಮಯ (ನೋಮ್ ಪೆನ್)", + "Asia\/Pontianak": "ಪಶ್ಚಿಮ ಇಂಡೋನೇಷಿಯ ಸಮಯ (ಪೊಂಟಿಯಾನಕ್)", + "Asia\/Pyongyang": "ಕೊರಿಯನ್ ಸಮಯ (ಪ್ಯೊಂಗ್‍ಯಾಂಗ್)", + "Asia\/Qatar": "ಅರೇಬಿಯನ್ ಸಮಯ (ಖತಾರ್)", + "Asia\/Qostanay": "ಪೂರ್ವ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಕೊಸ್ಟನಯ್)", + "Asia\/Qyzylorda": "ಪಶ್ಚಿಮ ಕಜಕಿಸ್ತಾನ್ ಸಮಯ (ಕಿಜೈಲೋರ್ದ)", + "Asia\/Rangoon": "ಮ್ಯಾನ್ಮಾರ್ ಸಮಯ (ಯಾಂಗೊನ್)", + "Asia\/Riyadh": "ಅರೇಬಿಯನ್ ಸಮಯ (ರಿಯಾದ್)", + "Asia\/Saigon": "ಇಂಡೊಚೈನಾ ಸಮಯ (ಹೊ ಚಿ ಮಿನ್ ಸಿಟಿ)", + "Asia\/Sakhalin": "ಸ್ಯಾಕ್‌ಹಲಿನ್ ಸಮಯ (ಸಖಾಲಿನ್)", + "Asia\/Samarkand": "ಉಜ್ಬೇಕಿಸ್ತಾನ್ ಸಮಯ (ಸಮರಖಂಡ)", + "Asia\/Seoul": "ಕೊರಿಯನ್ ಸಮಯ (ಸಿಯೋಲ್)", + "Asia\/Shanghai": "ಚೀನಾ ಸಮಯ (ಶಾಂಘೈ)", + "Asia\/Singapore": "ಸಿಂಗಾಪುರ್ ಪ್ರಮಾಣಿತ ಸಮಯ (ಸಿಂಗಾಪೂರ್)", + "Asia\/Srednekolymsk": "ಮಗಡಾನ್ ಸಮಯ (ಸ್ರೇದ್ನೇಕೋಲೀಮಸ್ಕ)", + "Asia\/Taipei": "ತೈಪೆ ಸಮಯ (ತೈಪೆ)", + "Asia\/Tashkent": "ಉಜ್ಬೇಕಿಸ್ತಾನ್ ಸಮಯ (ತಾಶ್ಕೆಂಟ್)", + "Asia\/Tbilisi": "ಜಾರ್ಜಿಯಾ ಸಮಯ (ತಿಬಿಲಿಸಿ)", + "Asia\/Tehran": "ಇರಾನ್ ಸಮಯ (ತೆಹ್ರಾನ್)", + "Asia\/Thimphu": "ಭೂತಾನ್ ಸಮಯ (ಥಿಂಪು)", + "Asia\/Tokyo": "ಜಪಾನ್ ಸಮಯ (ಟೋಕಿಯೊ)", + "Asia\/Ulaanbaatar": "ಉಲನ್ ಬ್ಯಾಟರ್ ಸಮಯ (ಉಲಾನ್‍ಬಾತರ್)", + "Asia\/Ust-Nera": "ವ್ಲಾಡಿವೋಸ್ಟೋಕ್ ಸಮಯ (ಉಸ್ತ್-ನೆರಾ)", + "Asia\/Vientiane": "ಇಂಡೊಚೈನಾ ಸಮಯ (ವಿಯೆಂಟಿಯಾನ್)", + "Asia\/Vladivostok": "ವ್ಲಾಡಿವೋಸ್ಟೋಕ್ ಸಮಯ (ವ್ಲಾದಿವೊಸ್ಟಾಕ್‌)", + "Asia\/Yakutsk": "ಯಾಕುಟ್ಸಕ್ ಸಮಯ (ಯಕುಟ್ಸ್ಕ್)", + "Asia\/Yekaterinburg": "ಯೇಕಟರಿನ್‌ಬರ್ಗ್ ಸಮಯ (ಎಕ್ಯಾಟೆರಿನ್ಬರ್ಗ್)", + "Asia\/Yerevan": "ಅರ್ಮೇನಿಯ ಸಮಯ (ಯೆರಿವಾನ್)", + "Atlantic\/Azores": "ಅಜೋರಸ್ ಸಮಯ (ಅಝೋರಿಸ್)", + "Atlantic\/Bermuda": "ಅಟ್ಲಾಂಟಿಕ್ ಸಮಯ (ಬರ್ಮುಡಾ)", + "Atlantic\/Canary": "ಪಶ್ಚಿಮ ಯುರೋಪಿಯನ್ ಸಮಯ (ಕ್ಯಾನರಿ)", + "Atlantic\/Cape_Verde": "ಕೇಪ್ ವರ್ಡ್ ಸಮಯ (ಕೇಪ್ ವೆರ್ಡ್)", + "Atlantic\/Faeroe": "ಪಶ್ಚಿಮ ಯುರೋಪಿಯನ್ ಸಮಯ (ಫ್ಯಾರೊ)", + "Atlantic\/Madeira": "ಪಶ್ಚಿಮ ಯುರೋಪಿಯನ್ ಸಮಯ (ಮೆಡಿರಾ)", + "Atlantic\/Reykjavik": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ರೈಕ್ಜಾವಿಕ್)", + "Atlantic\/South_Georgia": "ದಕ್ಷಿಣ ಜಾರ್ಜಿಯಾ ಸಮಯ (ದಕ್ಷಿಣ ಜಾರ್ಜಿಯಾ)", + "Atlantic\/St_Helena": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಸೇಂಟ್ ಹೆಲೆನಾ)", + "Atlantic\/Stanley": "ಫಾಲ್ಕ್‌ಲ್ಯಾಂಡ್ ದ್ವೀಪಗಳ ಸಮಯ (ಸ್ಟ್ಯಾನ್ಲಿ)", + "Australia\/Adelaide": "ಕೇಂದ್ರ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಅಡಿಲೇಡ್)", + "Australia\/Brisbane": "ಪೂರ್ವ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಬ್ರಿಸ್ಬೇನ್‌)", + "Australia\/Broken_Hill": "ಕೇಂದ್ರ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಬ್ರೊಕನ್ ಹಿಲ್)", + "Australia\/Currie": "ಪೂರ್ವ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಕರೀ)", + "Australia\/Darwin": "ಕೇಂದ್ರ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಡಾರ್ವಿನ್)", + "Australia\/Eucla": "ಆಸ್ಟ್ರೇಲಿಯಾದ ಕೇಂದ್ರ ಪಶ್ಚಿಮ ಸಮಯ (ಯುಕ್ಲಾ)", + "Australia\/Hobart": "ಪೂರ್ವ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಹೋಬಾರ್ಟ್‌)", + "Australia\/Lindeman": "ಪೂರ್ವ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಲಿಂಡಿಮಾನ್)", + "Australia\/Lord_Howe": "ಲಾರ್ಡ್ ಹೋವ್ ಸಮಯ (ಲಾರ್ಡ್ ಹೋವ್)", + "Australia\/Melbourne": "ಪೂರ್ವ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಮೆಲ್ಬರ್ನ್)", + "Australia\/Perth": "ಪಶ್ಚಿಮ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಪರ್ಥ್)", + "Australia\/Sydney": "ಪೂರ್ವ ಆಸ್ಟ್ರೇಲಿಯಾ ಸಮಯ (ಸಿಡ್ನಿ)", + "CST6CDT": "ಉತ್ತರ ಅಮೆರಿಕದ ಕೇಂದ್ರ ಸಮಯ", + "EST5EDT": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೂರ್ವದ ಸಮಯ", + "Etc\/GMT": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ", + "Etc\/UTC": "ಸಂಘಟಿತ ಸಾರ್ವತ್ರಿಕ ಸಮಯ", + "Europe\/Amsterdam": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಆಮ್‌ಸ್ಟೆರ್‌ಡ್ಯಾಂ)", + "Europe\/Andorra": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಅಂಡೋರಾ)", + "Europe\/Astrakhan": "ಮಾಸ್ಕೋ ಸಮಯ (ಆಸ್ಟ್ರಾಖಾನ್)", + "Europe\/Athens": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಅಥೆನ್ಸ್)", + "Europe\/Belgrade": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬೆಲ್‌ಗ್ರೇಡ್)", + "Europe\/Berlin": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬರ್ಲಿನ್)", + "Europe\/Bratislava": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬ್ರಾಟಿಸ್ಲಾವ)", + "Europe\/Brussels": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬ್ರಸ್ಸೆಲ್ಸ್)", + "Europe\/Bucharest": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬುಕಾರೆಸ್ಟ್)", + "Europe\/Budapest": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬುಡಾಪೆಸ್ಟ್)", + "Europe\/Busingen": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಬುಸಿಂಜೆನ್)", + "Europe\/Chisinau": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಚಿಸಿನಾವ್)", + "Europe\/Copenhagen": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಕೋಪೆನ್‌ಹೇಗನ್)", + "Europe\/Dublin": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಡುಬ್ಲಿನ್)", + "Europe\/Gibraltar": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಜಿಬ್ರಾಲ್ಟರ್)", + "Europe\/Guernsey": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಗ್ಯುರ್ನ್‍ಸೆ)", + "Europe\/Helsinki": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಹೆಲ್ಸಿಂಕಿ)", + "Europe\/Isle_of_Man": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಐಲ್ ಆಫ್ ಮ್ಯಾನ್)", + "Europe\/Jersey": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಜೆರ್ಸಿ)", + "Europe\/Kaliningrad": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಕಲಿನಿನ್‌ಗ್ರಾಡ್)", + "Europe\/Kiev": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಕಿವ್)", + "Europe\/Lisbon": "ಪಶ್ಚಿಮ ಯುರೋಪಿಯನ್ ಸಮಯ (ಲಿಸ್ಬನ್)", + "Europe\/Ljubljana": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಲ್ಯೂಬ್ಲ್ಯಾನಾ)", + "Europe\/London": "ಗ್ರೀನ್‌ವಿಚ್ ಸರಾಸರಿ ಕಾಲಮಾನ (ಲಂಡನ್)", + "Europe\/Luxembourg": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಲಕ್ಸೆಂಬರ್ಗ್)", + "Europe\/Madrid": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಮ್ಯಾಡ್ರಿಡ್)", + "Europe\/Malta": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಮಾಲ್ಟಾ)", + "Europe\/Mariehamn": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಮರಿಹಮ್ನ್)", + "Europe\/Minsk": "ಮಾಸ್ಕೋ ಸಮಯ (ಮಿನ್‌ಸ್ಕ್)", + "Europe\/Monaco": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಮೊನಾಕೊ)", + "Europe\/Moscow": "ಮಾಸ್ಕೋ ಸಮಯ (ಮಾಸ್ಕೋ)", + "Europe\/Oslo": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಓಸ್ಲೋ)", + "Europe\/Paris": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಪ್ಯಾರಿಸ್)", + "Europe\/Podgorica": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಪೊಡ್ಗೊರಿಕ)", + "Europe\/Prague": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಪ್ರಾಗ್ವೆ)", + "Europe\/Riga": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ರಿಗಾ)", + "Europe\/Rome": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ರೋಮ್)", + "Europe\/Samara": "ಸಮರ ಸಮಯ (ಸಮರ)", + "Europe\/San_Marino": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಸ್ಯಾನ್ ಮರೀನೊ)", + "Europe\/Sarajevo": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಸರಜೆವೊ)", + "Europe\/Saratov": "ಮಾಸ್ಕೋ ಸಮಯ (ಸರಾಟೋವ್)", + "Europe\/Simferopol": "ಮಾಸ್ಕೋ ಸಮಯ (ಸಿಮ್ಫೆರೋಪೋಲ್)", + "Europe\/Skopje": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಸ್ಕಾಪಿಯಾ)", + "Europe\/Sofia": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಸೋಫಿಯಾ)", + "Europe\/Stockholm": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಸ್ಟಾಕ್‍ಹೋಮ್)", + "Europe\/Tallinn": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಟ್ಯಾಲಿನ್)", + "Europe\/Tirane": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಟಿರಾನೆ)", + "Europe\/Ulyanovsk": "ಮಾಸ್ಕೋ ಸಮಯ (ಉಲ್ಯಾನೊವಸ್ಕ್)", + "Europe\/Uzhgorod": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಉಜ್‌ಗೊರೊದ್)", + "Europe\/Vaduz": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ವಡೂಜ್)", + "Europe\/Vatican": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ವ್ಯಾಟಿಕನ್)", + "Europe\/Vienna": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ವಿಯೆನ್ನಾ)", + "Europe\/Vilnius": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ವಿಲ್ನಿಯಸ್)", + "Europe\/Volgograd": "ವೋಲ್ಗೋಗಾರ್ಡ್ ಸಮಯ (ವೊಲ್ಗೊಗ್ರಾಡ್)", + "Europe\/Warsaw": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ವಾರ್ಸಾ)", + "Europe\/Zagreb": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಜಾಗ್ರೆಬ್‌)", + "Europe\/Zaporozhye": "ಪೂರ್ವ ಯುರೋಪಿಯನ್ ಸಮಯ (ಜಾಪರೀಝಿಯಾ)", + "Europe\/Zurich": "ಮಧ್ಯ ಯುರೋಪಿಯನ್ ಸಮಯ (ಜ್ಯೂರಿಕ್)", + "Indian\/Antananarivo": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಅಂಟಾನನಾರಿವೊ)", + "Indian\/Chagos": "ಹಿಂದೂ ಮಹಾಸಾಗರ ಸಮಯ (ಚಾಗೊಸ್)", + "Indian\/Christmas": "ಕ್ರಿಸ್ಮಸ್ ದ್ವೀಪ ಸಮಯ (ಕ್ರಿಸ್ಮಸ್)", + "Indian\/Cocos": "ಕೋಕೋಸ್ ದ್ವೀಪಗಳ ಸಮಯ (ಕೊಕೋಸ್)", + "Indian\/Comoro": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಕೊಮೋರೊ)", + "Indian\/Kerguelen": "ದಕ್ಷಿಣ ಫ್ರೆಂಚ್ ಮತ್ತು ಅಂಟಾರ್ಟಿಕಾ ಸಮಯ (ಕೆರ್ಗ್ಯುಲೆನ್)", + "Indian\/Mahe": "ಸೀಷೆಲ್ಸ್ ಸಮಯ (ಮಾಹೆ)", + "Indian\/Maldives": "ಮಾಲ್ಡೀವ್ಸ್ ಸಮಯ (ಮಾಲ್ಡೀವ್ಸ್)", + "Indian\/Mauritius": "ಮಾರಿಷಸ್ ಸಮಯ (ಮಾರಿಷಸ್)", + "Indian\/Mayotte": "ಪೂರ್ವ ಆಫ್ರಿಕಾ ಸಮಯ (ಮಯೊಟ್ಟೆ)", + "Indian\/Reunion": "ರಿಯೂನಿಯನ್ ಸಮಯ (ರೀಯೂನಿಯನ್)", + "MST7MDT": "ಉತ್ತರ ಅಮೆರಿಕದ ಪರ್ವತ ಸಮಯ", + "PST8PDT": "ಉತ್ತರ ಅಮೆರಿಕದ ಪೆಸಿಫಿಕ್ ಸಮಯ", + "Pacific\/Apia": "ಅಪಿಯಾ ಸಮಯ (ಅಪಿಯಾ)", + "Pacific\/Auckland": "ನ್ಯೂಜಿಲ್ಯಾಂಡ್ ಸಮಯ (ಆಕ್ ಲ್ಯಾಂಡ್)", + "Pacific\/Bougainville": "ಪಪುವಾ ನ್ಯೂ ಗಿನಿಯಾ ಸಮಯ (ಬೌಗೆನ್‍ವಿಲ್ಲೆ)", + "Pacific\/Chatham": "ಚಥಾಮ್ ಸಮಯ (ಚಥಾಮ್)", + "Pacific\/Easter": "ಈಸ್ಟರ್ ದ್ವೀಪ ಸಮಯ (ಈಸ್ಟರ್)", + "Pacific\/Efate": "ವನೌತು ಸಮಯ (ಇಫೇಟ್)", + "Pacific\/Enderbury": "ಫಿನಿಕ್ಸ್ ದ್ವೀಪಗಳ ಸಮಯ (ಎಂಡರ್ಬರಿ)", + "Pacific\/Fakaofo": "ಟೊಕೆಲಾವ್ ಸಮಯ (ಫಕೋಫೋ)", + "Pacific\/Fiji": "ಫಿಜಿ ಸಮಯ (ಫಿಜಿ)", + "Pacific\/Funafuti": "ತುವಾಲು ಸಮಯ (ಫುನಾಫುಟಿ)", + "Pacific\/Galapagos": "ಗಾಲಾಪಾಗೋಸ್ ಸಮಯ (ಗಲಾಪಗೋಸ್)", + "Pacific\/Gambier": "ಗ್ಯಾಂಬಿಯರ್ ಸಮಯ (ಗ್ಯಾಂಬಿಯರ್)", + "Pacific\/Guadalcanal": "ಸಾಲಮನ್ ದ್ವೀಪಗಳ ಸಮಯ (ಗ್ವಾಡಲ್ಕೆನಾಲ್)", + "Pacific\/Guam": "ಚಮೋರೋ ಪ್ರಮಾಣಿತ ಸಮಯ (ಗ್ವಾಮ್)", + "Pacific\/Honolulu": "ಹವಾಯಿ-ಅಲ್ಯುಟಿಯನ್ ಸಮಯ (ಹೊನಲುಲು)", + "Pacific\/Johnston": "ಹವಾಯಿ-ಅಲ್ಯುಟಿಯನ್ ಸಮಯ (ಜಾನ್‌ಸ್ಟನ್)", + "Pacific\/Kiritimati": "ಲೈನ್ ದ್ವೀಪಗಳ ಸಮಯ (ಕಿರಿತಿಮತಿ)", + "Pacific\/Kosrae": "ಕೊಸರೆ ಸಮಯ (ಕೋಸ್ರೆ)", + "Pacific\/Kwajalein": "ಮಾರ್ಷಲ್ ದ್ವೀಪಗಳ ಸಮಯ (ಕ್ವಾಜಲೇನ್)", + "Pacific\/Majuro": "ಮಾರ್ಷಲ್ ದ್ವೀಪಗಳ ಸಮಯ (ಮಜುರೊ)", + "Pacific\/Marquesas": "ಮಾರ್ಕ್ಯುಸಸ್ ಸಮಯ (ಮಾರ್ಕ್ಯೂಸಸ್)", + "Pacific\/Midway": "ಸಮೋವಾ ಸಮಯ (ಮಿಡ್‌ವೇ)", + "Pacific\/Nauru": "ನೌರು ಸಮಯ (ನೌರು)", + "Pacific\/Niue": "ನಿಯು ಸಮಯ (ನಿಯು)", + "Pacific\/Norfolk": "ನಾರ್ಫೋಕ್ ದ್ವೀಪ ಸಮಯ (ನಾರ್ಫೋಕ್)", + "Pacific\/Noumea": "ಹೊಸ ಕ್ಯಾಲೆಡೋನಿಯಾ ಸಮಯ (ನ್ಯೂಮಿಯಾ)", + "Pacific\/Pago_Pago": "ಸಮೋವಾ ಸಮಯ (ಪಾಗೊ ಪಾಗೊ)", + "Pacific\/Palau": "ಪಾಲಾವ್ ಸಮಯ (ಪಾಲಾವ್)", + "Pacific\/Pitcairn": "ಪಿಟ್‌ಕೈರ್ನ್ ಸಮಯ (ಪಿಟ್‌ಕೈರ್ನ್)", + "Pacific\/Ponape": "ಪೊನಾಪೆ ಸಮಯ (ಪೋನ್‌ಪೆ)", + "Pacific\/Port_Moresby": "ಪಪುವಾ ನ್ಯೂ ಗಿನಿಯಾ ಸಮಯ (ಪೋರ್ಟ್ ಮೋರಿಸ್‌ಬೈ)", + "Pacific\/Rarotonga": "ಕುಕ್ ದ್ವೀಪಗಳ ಸಮಯ (ರರೋಟೋಂಗಾ)", + "Pacific\/Saipan": "ಚಮೋರೋ ಪ್ರಮಾಣಿತ ಸಮಯ (ಸೈಪನ್)", + "Pacific\/Tahiti": "ತಾಹಿತಿ ಸಮಯ (ತಹಿತಿ)", + "Pacific\/Tarawa": "ಗಿಲ್ಬರ್ಟ್ ದ್ವೀಪಗಳ ಸಮಯ (ತರಾವಾ)", + "Pacific\/Tongatapu": "ಟೊಂಗಾ ಸಮಯ (ಟೊಂಗಾಟಾಪು)", + "Pacific\/Truk": "ಚುಕ್ ಸಮಯ (ಚುಕ್)", + "Pacific\/Wake": "ವೇಕ್ ದ್ವೀಪ ಸಮಯ (ವೇಕ್)", + "Pacific\/Wallis": "ವ್ಯಾಲೀಸ್ ಮತ್ತು ಫ್ಯುಟುನಾ ಸಮಯ (ವ್ಯಾಲಿಸ್)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ko.json b/src/Symfony/Component/Intl/Resources/data/timezones/ko.json new file mode 100644 index 0000000000000..347191f40b1e8 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ko.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "그리니치 표준시 (아비장)", + "Africa\/Accra": "그리니치 표준시 (아크라)", + "Africa\/Addis_Ababa": "동아프리카 시간 (아디스아바바)", + "Africa\/Algiers": "중부 유럽 시간 (알제)", + "Africa\/Asmera": "동아프리카 시간 (아스메라)", + "Africa\/Bamako": "그리니치 표준시 (바마코)", + "Africa\/Bangui": "서아프리카 시간 (방기)", + "Africa\/Banjul": "그리니치 표준시 (반줄)", + "Africa\/Bissau": "그리니치 표준시 (비사우)", + "Africa\/Blantyre": "중앙아프리카 시간 (블랜타이어)", + "Africa\/Brazzaville": "서아프리카 시간 (브라자빌)", + "Africa\/Bujumbura": "중앙아프리카 시간 (부줌부라)", + "Africa\/Cairo": "동유럽 시간 (카이로)", + "Africa\/Casablanca": "서유럽 시간 (카사블랑카)", + "Africa\/Ceuta": "중부 유럽 시간 (세우타)", + "Africa\/Conakry": "그리니치 표준시 (코나크리)", + "Africa\/Dakar": "그리니치 표준시 (다카르)", + "Africa\/Dar_es_Salaam": "동아프리카 시간 (다르에스살람)", + "Africa\/Djibouti": "동아프리카 시간 (지부티)", + "Africa\/Douala": "서아프리카 시간 (두알라)", + "Africa\/El_Aaiun": "서유럽 시간 (엘아이운)", + "Africa\/Freetown": "그리니치 표준시 (프리타운)", + "Africa\/Gaborone": "중앙아프리카 시간 (가보로네)", + "Africa\/Harare": "중앙아프리카 시간 (하라레)", + "Africa\/Johannesburg": "남아프리카 시간 (요하네스버그)", + "Africa\/Juba": "동아프리카 시간 (주바)", + "Africa\/Kampala": "동아프리카 시간 (캄팔라)", + "Africa\/Khartoum": "중앙아프리카 시간 (카르툼)", + "Africa\/Kigali": "중앙아프리카 시간 (키갈리)", + "Africa\/Kinshasa": "서아프리카 시간 (킨샤사)", + "Africa\/Lagos": "서아프리카 시간 (라고스)", + "Africa\/Libreville": "서아프리카 시간 (리브르빌)", + "Africa\/Lome": "그리니치 표준시 (로메)", + "Africa\/Luanda": "서아프리카 시간 (루안다)", + "Africa\/Lubumbashi": "중앙아프리카 시간 (루붐바시)", + "Africa\/Lusaka": "중앙아프리카 시간 (루사카)", + "Africa\/Malabo": "서아프리카 시간 (말라보)", + "Africa\/Maputo": "중앙아프리카 시간 (마푸토)", + "Africa\/Maseru": "남아프리카 시간 (마세루)", + "Africa\/Mbabane": "남아프리카 시간 (음바바네)", + "Africa\/Mogadishu": "동아프리카 시간 (모가디슈)", + "Africa\/Monrovia": "그리니치 표준시 (몬로비아)", + "Africa\/Nairobi": "동아프리카 시간 (나이로비)", + "Africa\/Ndjamena": "서아프리카 시간 (엔자메나)", + "Africa\/Niamey": "서아프리카 시간 (니아메)", + "Africa\/Nouakchott": "그리니치 표준시 (누악쇼트)", + "Africa\/Ouagadougou": "그리니치 표준시 (와가두구)", + "Africa\/Porto-Novo": "서아프리카 시간 (포르토노보)", + "Africa\/Sao_Tome": "그리니치 표준시 (상투메)", + "Africa\/Tripoli": "동유럽 시간 (트리폴리)", + "Africa\/Tunis": "중부 유럽 시간 (튀니스)", + "Africa\/Windhoek": "중앙아프리카 시간 (빈트후크)", + "America\/Adak": "하와이 알류샨 시간 (에이닥)", + "America\/Anchorage": "알래스카 시간 (앵커리지)", + "America\/Anguilla": "대서양 시간 (앙귈라)", + "America\/Antigua": "대서양 시간 (안티과)", + "America\/Araguaina": "브라질리아 시간 (아라과이나)", + "America\/Argentina\/La_Rioja": "아르헨티나 시간 (라 리오하)", + "America\/Argentina\/Rio_Gallegos": "아르헨티나 시간 (리오 가예고스)", + "America\/Argentina\/Salta": "아르헨티나 시간 (살타)", + "America\/Argentina\/San_Juan": "아르헨티나 시간 (산후안)", + "America\/Argentina\/San_Luis": "아르헨티나 서부 시간 (산루이스)", + "America\/Argentina\/Tucuman": "아르헨티나 시간 (투쿠만)", + "America\/Argentina\/Ushuaia": "아르헨티나 시간 (우수아이아)", + "America\/Aruba": "대서양 시간 (아루바)", + "America\/Asuncion": "파라과이 시간 (아순시온)", + "America\/Bahia": "브라질리아 시간 (바히아)", + "America\/Bahia_Banderas": "미 중부 시간 (바이아 반데라스)", + "America\/Barbados": "대서양 시간 (바베이도스)", + "America\/Belem": "브라질리아 시간 (벨렘)", + "America\/Belize": "미 중부 시간 (벨리즈)", + "America\/Blanc-Sablon": "대서양 시간 (블랑 사블롱)", + "America\/Boa_Vista": "아마존 시간 (보아 비스타)", + "America\/Bogota": "콜롬비아 시간 (보고타)", + "America\/Boise": "미 산지 시간 (보이시)", + "America\/Buenos_Aires": "아르헨티나 시간 (부에노스 아이레스)", + "America\/Cambridge_Bay": "미 산지 시간 (케임브리지 베이)", + "America\/Campo_Grande": "아마존 시간 (캄포 그란데)", + "America\/Cancun": "미 동부 시간 (칸쿤)", + "America\/Caracas": "베네수엘라 시간 (카라카스)", + "America\/Catamarca": "아르헨티나 시간 (카타마르카)", + "America\/Cayenne": "프랑스령 가이아나 시간 (카옌)", + "America\/Cayman": "미 동부 시간 (케이맨)", + "America\/Chicago": "미 중부 시간 (시카고)", + "America\/Chihuahua": "멕시코 태평양 시간 (치와와)", + "America\/Coral_Harbour": "미 동부 시간 (코랄하버)", + "America\/Cordoba": "아르헨티나 시간 (코르도바)", + "America\/Costa_Rica": "미 중부 시간 (코스타리카)", + "America\/Creston": "미 산지 시간 (크레스톤)", + "America\/Cuiaba": "아마존 시간 (쿠이아바)", + "America\/Curacao": "대서양 시간 (퀴라소)", + "America\/Danmarkshavn": "그리니치 표준시 (덴마크샤븐)", + "America\/Dawson": "미 태평양 시간 (도슨)", + "America\/Dawson_Creek": "미 산지 시간 (도슨크릭)", + "America\/Denver": "미 산지 시간 (덴버)", + "America\/Detroit": "미 동부 시간 (디트로이트)", + "America\/Dominica": "대서양 시간 (도미니카)", + "America\/Edmonton": "미 산지 시간 (에드먼턴)", + "America\/Eirunepe": "아크레 시간 (아이루네페)", + "America\/El_Salvador": "미 중부 시간 (엘살바도르)", + "America\/Fort_Nelson": "미 산지 시간 (포트 넬슨)", + "America\/Fortaleza": "브라질리아 시간 (포르탈레자)", + "America\/Glace_Bay": "대서양 시간 (글라스베이)", + "America\/Godthab": "그린란드 서부 시간 (고드호프)", + "America\/Goose_Bay": "대서양 시간 (구즈베이)", + "America\/Grand_Turk": "미 동부 시간 (그랜드 터크)", + "America\/Grenada": "대서양 시간 (그레나다)", + "America\/Guadeloupe": "대서양 시간 (과들루프)", + "America\/Guatemala": "미 중부 시간 (과테말라)", + "America\/Guayaquil": "에콰도르 시간 (과야킬)", + "America\/Guyana": "가이아나 시간 (가이아나)", + "America\/Halifax": "대서양 시간 (핼리팩스)", + "America\/Havana": "쿠바 시간 (하바나)", + "America\/Hermosillo": "멕시코 태평양 시간 (에르모시요)", + "America\/Indiana\/Knox": "미 중부 시간 (인디애나주 녹스)", + "America\/Indiana\/Marengo": "미 동부 시간 (인디애나주, 마렝고)", + "America\/Indiana\/Petersburg": "미 동부 시간 (인디애나주, 피츠버그)", + "America\/Indiana\/Tell_City": "미 중부 시간 (인디아나주, 텔시티)", + "America\/Indiana\/Vevay": "미 동부 시간 (비비)", + "America\/Indiana\/Vincennes": "미 동부 시간 (인디아나주, 뱅센)", + "America\/Indiana\/Winamac": "미 동부 시간 (인디아나주, 워너맥)", + "America\/Indianapolis": "미 동부 시간 (인디애나폴리스)", + "America\/Inuvik": "미 산지 시간 (이누빅)", + "America\/Iqaluit": "미 동부 시간 (이칼루이트)", + "America\/Jamaica": "미 동부 시간 (자메이카)", + "America\/Jujuy": "아르헨티나 시간 (후후이)", + "America\/Juneau": "알래스카 시간 (주노)", + "America\/Kentucky\/Monticello": "미 동부 시간 (켄터키주, 몬티첼로)", + "America\/Kralendijk": "대서양 시간 (크라렌디즈크)", + "America\/La_Paz": "볼리비아 시간 (라파스)", + "America\/Lima": "페루 시간 (리마)", + "America\/Los_Angeles": "미 태평양 시간 (로스앤젤레스)", + "America\/Louisville": "미 동부 시간 (루이빌)", + "America\/Lower_Princes": "대서양 시간 (로워 프린스 쿼터)", + "America\/Maceio": "브라질리아 시간 (마세이오)", + "America\/Managua": "미 중부 시간 (마나과)", + "America\/Manaus": "아마존 시간 (마나우스)", + "America\/Marigot": "대서양 시간 (마리곳)", + "America\/Martinique": "대서양 시간 (마티니크)", + "America\/Matamoros": "미 중부 시간 (마타모로스)", + "America\/Mazatlan": "멕시코 태평양 시간 (마사틀란)", + "America\/Mendoza": "아르헨티나 시간 (멘도사)", + "America\/Menominee": "미 중부 시간 (메노미니)", + "America\/Merida": "미 중부 시간 (메리다)", + "America\/Metlakatla": "알래스카 시간 (메틀라카틀라)", + "America\/Mexico_City": "미 중부 시간 (멕시코 시티)", + "America\/Miquelon": "세인트피에르 미클롱 시간 (미클롱)", + "America\/Moncton": "대서양 시간 (몽턴)", + "America\/Monterrey": "미 중부 시간 (몬테레이)", + "America\/Montevideo": "우루과이 시간 (몬테비데오)", + "America\/Montserrat": "대서양 시간 (몬세라트)", + "America\/Nassau": "미 동부 시간 (나소)", + "America\/New_York": "미 동부 시간 (뉴욕)", + "America\/Nipigon": "미 동부 시간 (니피곤)", + "America\/Nome": "알래스카 시간 (놈)", + "America\/Noronha": "페르난도 데 노로냐 시간 (노롱야)", + "America\/North_Dakota\/Beulah": "미 중부 시간 (노스다코타주, 베라)", + "America\/North_Dakota\/Center": "미 중부 시간 (중부, 노스다코타)", + "America\/North_Dakota\/New_Salem": "미 중부 시간 (노스 다코타주, 뉴살렘)", + "America\/Ojinaga": "미 산지 시간 (오히나가)", + "America\/Panama": "미 동부 시간 (파나마)", + "America\/Pangnirtung": "미 동부 시간 (팡니르퉁)", + "America\/Paramaribo": "수리남 시간 (파라마리보)", + "America\/Phoenix": "미 산지 시간 (피닉스)", + "America\/Port-au-Prince": "미 동부 시간 (포르토프랭스)", + "America\/Port_of_Spain": "대서양 시간 (포트오브스페인)", + "America\/Porto_Velho": "아마존 시간 (포르토벨료)", + "America\/Puerto_Rico": "대서양 시간 (푸에르토리코)", + "America\/Punta_Arenas": "칠레 시간 (푼타아레나스)", + "America\/Rainy_River": "미 중부 시간 (레이니강)", + "America\/Rankin_Inlet": "미 중부 시간 (랭킹 인렛)", + "America\/Recife": "브라질리아 시간 (레시페)", + "America\/Regina": "미 중부 시간 (리자이나)", + "America\/Resolute": "미 중부 시간 (리졸루트)", + "America\/Rio_Branco": "아크레 시간 (히우 브랑쿠)", + "America\/Santa_Isabel": "멕시코 북서부 시간 (산타 이사벨)", + "America\/Santarem": "브라질리아 시간 (산타렘)", + "America\/Santiago": "칠레 시간 (산티아고)", + "America\/Santo_Domingo": "대서양 시간 (산토도밍고)", + "America\/Sao_Paulo": "브라질리아 시간 (상파울루)", + "America\/Scoresbysund": "그린란드 동부 시간 (스코레스바이선드)", + "America\/Sitka": "알래스카 시간 (싯카)", + "America\/St_Barthelemy": "대서양 시간 (생바르텔레미)", + "America\/St_Johns": "뉴펀들랜드 시간 (세인트존스)", + "America\/St_Kitts": "대서양 시간 (세인트 키츠)", + "America\/St_Lucia": "대서양 시간 (세인트 루시아)", + "America\/St_Thomas": "대서양 시간 (세인트 토마스)", + "America\/St_Vincent": "대서양 시간 (세인트 빈센트)", + "America\/Swift_Current": "미 중부 시간 (스위프트커런트)", + "America\/Tegucigalpa": "미 중부 시간 (테구시갈파)", + "America\/Thule": "대서양 시간 (툴레)", + "America\/Thunder_Bay": "미 동부 시간 (선더베이)", + "America\/Tijuana": "미 태평양 시간 (티후아나)", + "America\/Toronto": "미 동부 시간 (토론토)", + "America\/Tortola": "대서양 시간 (토르톨라)", + "America\/Vancouver": "미 태평양 시간 (벤쿠버)", + "America\/Whitehorse": "미 태평양 시간 (화이트호스)", + "America\/Winnipeg": "미 중부 시간 (위니펙)", + "America\/Yakutat": "알래스카 시간 (야쿠타트)", + "America\/Yellowknife": "미 산지 시간 (옐로나이프)", + "Antarctica\/Casey": "오스트레일리아 서부 시간 (케이시)", + "Antarctica\/Davis": "데이비스 시간 (데이비스)", + "Antarctica\/DumontDUrville": "뒤몽뒤르빌 시간 (뒤몽 뒤르빌)", + "Antarctica\/Macquarie": "매쿼리섬 시간 (맥쿼리)", + "Antarctica\/Mawson": "모슨 시간 (모슨)", + "Antarctica\/McMurdo": "뉴질랜드 시간 (맥머도)", + "Antarctica\/Palmer": "칠레 시간 (파머)", + "Antarctica\/Rothera": "로데라 시간 (로데라)", + "Antarctica\/Syowa": "쇼와 시간 (쇼와)", + "Antarctica\/Troll": "그리니치 표준시 (트롤)", + "Antarctica\/Vostok": "보스톡 시간 (보스토크)", + "Arctic\/Longyearbyen": "중부 유럽 시간 (롱이어비엔)", + "Asia\/Aden": "아라비아 시간 (아덴)", + "Asia\/Almaty": "동부 카자흐스탄 시간 (알마티)", + "Asia\/Amman": "동유럽 시간 (암만)", + "Asia\/Anadyr": "아나디리 시간 (아나디리)", + "Asia\/Aqtau": "서부 카자흐스탄 시간 (아크타우)", + "Asia\/Aqtobe": "서부 카자흐스탄 시간 (악토브)", + "Asia\/Ashgabat": "투르크메니스탄 시간 (아슈하바트)", + "Asia\/Atyrau": "서부 카자흐스탄 시간 (아티라우)", + "Asia\/Baghdad": "아라비아 시간 (바그다드)", + "Asia\/Bahrain": "아라비아 시간 (바레인)", + "Asia\/Baku": "아제르바이잔 시간 (바쿠)", + "Asia\/Bangkok": "인도차이나 시간 (방콕)", + "Asia\/Beirut": "동유럽 시간 (베이루트)", + "Asia\/Bishkek": "키르기스스탄 시간 (비슈케크)", + "Asia\/Brunei": "브루나이 시간 (브루나이)", + "Asia\/Calcutta": "인도 표준시 (콜카타)", + "Asia\/Chita": "야쿠츠크 시간 (치타)", + "Asia\/Choibalsan": "초이발산 시간 (초이발산)", + "Asia\/Colombo": "인도 표준시 (콜롬보)", + "Asia\/Damascus": "동유럽 시간 (다마스쿠스)", + "Asia\/Dhaka": "방글라데시 시간 (다카)", + "Asia\/Dili": "동티모르 시간 (딜리)", + "Asia\/Dubai": "걸프만 표준시 (두바이)", + "Asia\/Dushanbe": "타지키스탄 시간 (두샨베)", + "Asia\/Famagusta": "동유럽 시간 (파마구스타)", + "Asia\/Gaza": "동유럽 시간 (가자)", + "Asia\/Hebron": "동유럽 시간 (헤브론)", + "Asia\/Hong_Kong": "홍콩 시간 (홍콩)", + "Asia\/Hovd": "호브드 시간 (호브드)", + "Asia\/Irkutsk": "이르쿠츠크 시간 (이르쿠츠크)", + "Asia\/Jakarta": "서부 인도네시아 시간 (자카르타)", + "Asia\/Jayapura": "동부 인도네시아 시간 (자야푸라)", + "Asia\/Jerusalem": "이스라엘 시간 (예루살렘)", + "Asia\/Kabul": "아프가니스탄 시간 (카불)", + "Asia\/Kamchatka": "페트로파블롭스크-캄차츠키 시간 (캄차카)", + "Asia\/Karachi": "파키스탄 시간 (카라치)", + "Asia\/Katmandu": "네팔 시간 (카트만두)", + "Asia\/Khandyga": "야쿠츠크 시간 (한디가)", + "Asia\/Krasnoyarsk": "크라스노야르스크 시간 (크라스노야르스크)", + "Asia\/Kuala_Lumpur": "말레이시아 시간 (쿠알라룸푸르)", + "Asia\/Kuching": "말레이시아 시간 (쿠칭)", + "Asia\/Kuwait": "아라비아 시간 (쿠웨이트)", + "Asia\/Macau": "중국 시간 (마카오)", + "Asia\/Magadan": "마가단 시간 (마가단)", + "Asia\/Makassar": "중부 인도네시아 시간 (마카사르)", + "Asia\/Manila": "필리핀 시간 (마닐라)", + "Asia\/Muscat": "걸프만 표준시 (무스카트)", + "Asia\/Nicosia": "동유럽 시간 (니코시아)", + "Asia\/Novokuznetsk": "크라스노야르스크 시간 (노보쿠즈네츠크)", + "Asia\/Novosibirsk": "노보시비르스크 시간 (노보시비르스크)", + "Asia\/Omsk": "옴스크 시간 (옴스크)", + "Asia\/Oral": "서부 카자흐스탄 시간 (오랄)", + "Asia\/Phnom_Penh": "인도차이나 시간 (프놈펜)", + "Asia\/Pontianak": "서부 인도네시아 시간 (폰티아나크)", + "Asia\/Pyongyang": "대한민국 시간 (평양)", + "Asia\/Qatar": "아라비아 시간 (카타르)", + "Asia\/Qostanay": "동부 카자흐스탄 시간 (코스타나이)", + "Asia\/Qyzylorda": "서부 카자흐스탄 시간 (키질로르다)", + "Asia\/Rangoon": "미얀마 시간 (랑군)", + "Asia\/Riyadh": "아라비아 시간 (리야드)", + "Asia\/Saigon": "인도차이나 시간 (사이공)", + "Asia\/Sakhalin": "사할린 시간 (사할린)", + "Asia\/Samarkand": "우즈베키스탄 시간 (사마르칸트)", + "Asia\/Seoul": "대한민국 시간 (서울)", + "Asia\/Shanghai": "중국 시간 (상하이)", + "Asia\/Singapore": "싱가포르 표준시 (싱가포르)", + "Asia\/Srednekolymsk": "마가단 시간 (스레드네콜림스크)", + "Asia\/Taipei": "대만 시간 (타이베이)", + "Asia\/Tashkent": "우즈베키스탄 시간 (타슈켄트)", + "Asia\/Tbilisi": "조지아 시간 (트빌리시)", + "Asia\/Tehran": "이란 시간 (테헤란)", + "Asia\/Thimphu": "부탄 시간 (팀부)", + "Asia\/Tokyo": "일본 시간 (도쿄)", + "Asia\/Ulaanbaatar": "울란바토르 시간 (울란바토르)", + "Asia\/Ust-Nera": "블라디보스토크 시간 (우스티네라)", + "Asia\/Vientiane": "인도차이나 시간 (비엔티안)", + "Asia\/Vladivostok": "블라디보스토크 시간 (블라디보스토크)", + "Asia\/Yakutsk": "야쿠츠크 시간 (야쿠츠크)", + "Asia\/Yekaterinburg": "예카테린부르크 시간 (예카테린부르크)", + "Asia\/Yerevan": "아르메니아 시간 (예레반)", + "Atlantic\/Azores": "아조레스 시간 (아조레스)", + "Atlantic\/Bermuda": "대서양 시간 (버뮤다)", + "Atlantic\/Canary": "서유럽 시간 (카나리아 제도)", + "Atlantic\/Cape_Verde": "카보 베르데 시간 (카보 베르데)", + "Atlantic\/Faeroe": "서유럽 시간 (페로 제도)", + "Atlantic\/Madeira": "서유럽 시간 (마데이라)", + "Atlantic\/Reykjavik": "그리니치 표준시 (레이캬비크)", + "Atlantic\/South_Georgia": "사우스 조지아 시간 (사우스조지아)", + "Atlantic\/St_Helena": "그리니치 표준시 (세인트 헬레나)", + "Atlantic\/Stanley": "포클랜드 제도 시간 (스탠리)", + "Australia\/Adelaide": "오스트레일리아 중부 시간 (애들레이드)", + "Australia\/Brisbane": "오스트레일리아 동부 시간 (브리스베인)", + "Australia\/Broken_Hill": "오스트레일리아 중부 시간 (브로컨힐)", + "Australia\/Currie": "오스트레일리아 동부 시간 (퀴리)", + "Australia\/Darwin": "오스트레일리아 중부 시간 (다윈)", + "Australia\/Eucla": "오스트레일리아 중서부 시간 (유클라)", + "Australia\/Hobart": "오스트레일리아 동부 시간 (호바트)", + "Australia\/Lindeman": "오스트레일리아 동부 시간 (린데만)", + "Australia\/Lord_Howe": "로드 하우 시간 (로드 하우)", + "Australia\/Melbourne": "오스트레일리아 동부 시간 (멜버른)", + "Australia\/Perth": "오스트레일리아 서부 시간 (퍼스)", + "Australia\/Sydney": "오스트레일리아 동부 시간 (시드니)", + "CST6CDT": "미 중부 시간", + "EST5EDT": "미 동부 시간", + "Etc\/GMT": "그리니치 표준시", + "Etc\/UTC": "협정 세계시", + "Europe\/Amsterdam": "중부 유럽 시간 (암스테르담)", + "Europe\/Andorra": "중부 유럽 시간 (안도라)", + "Europe\/Astrakhan": "모스크바 시간 (아스트라한)", + "Europe\/Athens": "동유럽 시간 (아테네)", + "Europe\/Belgrade": "중부 유럽 시간 (베오그라드)", + "Europe\/Berlin": "중부 유럽 시간 (베를린)", + "Europe\/Bratislava": "중부 유럽 시간 (브라티슬라바)", + "Europe\/Brussels": "중부 유럽 시간 (브뤼셀)", + "Europe\/Bucharest": "동유럽 시간 (부쿠레슈티)", + "Europe\/Budapest": "중부 유럽 시간 (부다페스트)", + "Europe\/Busingen": "중부 유럽 시간 (뷔지겐)", + "Europe\/Chisinau": "동유럽 시간 (키시나우)", + "Europe\/Copenhagen": "중부 유럽 시간 (코펜하겐)", + "Europe\/Dublin": "그리니치 표준시 (더블린)", + "Europe\/Gibraltar": "중부 유럽 시간 (지브롤터)", + "Europe\/Guernsey": "그리니치 표준시 (건지)", + "Europe\/Helsinki": "동유럽 시간 (헬싱키)", + "Europe\/Isle_of_Man": "그리니치 표준시 (맨섬)", + "Europe\/Jersey": "그리니치 표준시 (저지)", + "Europe\/Kaliningrad": "동유럽 시간 (칼리닌그라드)", + "Europe\/Kiev": "동유럽 시간 (키예프)", + "Europe\/Lisbon": "서유럽 시간 (리스본)", + "Europe\/Ljubljana": "중부 유럽 시간 (류블랴나)", + "Europe\/London": "그리니치 표준시 (런던)", + "Europe\/Luxembourg": "중부 유럽 시간 (룩셈부르크)", + "Europe\/Madrid": "중부 유럽 시간 (마드리드)", + "Europe\/Malta": "중부 유럽 시간 (몰타)", + "Europe\/Mariehamn": "동유럽 시간 (마리에함)", + "Europe\/Minsk": "모스크바 시간 (민스크)", + "Europe\/Monaco": "중부 유럽 시간 (모나코)", + "Europe\/Moscow": "모스크바 시간 (모스크바)", + "Europe\/Oslo": "중부 유럽 시간 (오슬로)", + "Europe\/Paris": "중부 유럽 시간 (파리)", + "Europe\/Podgorica": "중부 유럽 시간 (포드고리차)", + "Europe\/Prague": "중부 유럽 시간 (프라하)", + "Europe\/Riga": "동유럽 시간 (리가)", + "Europe\/Rome": "중부 유럽 시간 (로마)", + "Europe\/Samara": "사마라 시간 (사마라)", + "Europe\/San_Marino": "중부 유럽 시간 (산마리노)", + "Europe\/Sarajevo": "중부 유럽 시간 (사라예보)", + "Europe\/Saratov": "모스크바 시간 (사라토프)", + "Europe\/Simferopol": "모스크바 시간 (심페로폴)", + "Europe\/Skopje": "중부 유럽 시간 (스코페)", + "Europe\/Sofia": "동유럽 시간 (소피아)", + "Europe\/Stockholm": "중부 유럽 시간 (스톡홀름)", + "Europe\/Tallinn": "동유럽 시간 (탈린)", + "Europe\/Tirane": "중부 유럽 시간 (티라나)", + "Europe\/Ulyanovsk": "모스크바 시간 (울리야노프스크)", + "Europe\/Uzhgorod": "동유럽 시간 (우주고로트)", + "Europe\/Vaduz": "중부 유럽 시간 (파두츠)", + "Europe\/Vatican": "중부 유럽 시간 (바티칸)", + "Europe\/Vienna": "중부 유럽 시간 (비엔나)", + "Europe\/Vilnius": "동유럽 시간 (빌니우스)", + "Europe\/Volgograd": "볼고그라드 시간 (볼고그라트)", + "Europe\/Warsaw": "중부 유럽 시간 (바르샤바)", + "Europe\/Zagreb": "중부 유럽 시간 (자그레브)", + "Europe\/Zaporozhye": "동유럽 시간 (자포로지예)", + "Europe\/Zurich": "중부 유럽 시간 (취리히)", + "Indian\/Antananarivo": "동아프리카 시간 (안타나나리보)", + "Indian\/Chagos": "인도양 시간 (차고스)", + "Indian\/Christmas": "크리스마스섬 시간 (크리스마스)", + "Indian\/Cocos": "코코스 제도 시간 (코코스)", + "Indian\/Comoro": "동아프리카 시간 (코모로)", + "Indian\/Kerguelen": "프랑스령 남부 식민지 및 남극 시간 (케르켈렌)", + "Indian\/Mahe": "세이셸 시간 (마헤)", + "Indian\/Maldives": "몰디브 시간 (몰디브)", + "Indian\/Mauritius": "모리셔스 시간 (모리셔스)", + "Indian\/Mayotte": "동아프리카 시간 (메요트)", + "Indian\/Reunion": "레위니옹 시간 (레위니옹)", + "MST7MDT": "미 산지 시간", + "PST8PDT": "미 태평양 시간", + "Pacific\/Apia": "아피아 시간 (아피아)", + "Pacific\/Auckland": "뉴질랜드 시간 (오클랜드)", + "Pacific\/Bougainville": "파푸아뉴기니 시간 (부갱빌)", + "Pacific\/Chatham": "채텀 시간 (채텀)", + "Pacific\/Easter": "이스터섬 시간 (이스터 섬)", + "Pacific\/Efate": "바누아투 시간 (에파테)", + "Pacific\/Enderbury": "피닉스 제도 시간 (엔더베리)", + "Pacific\/Fakaofo": "토켈라우 시간 (파카오푸)", + "Pacific\/Fiji": "피지 시간 (피지)", + "Pacific\/Funafuti": "투발루 시간 (푸나푸티)", + "Pacific\/Galapagos": "갈라파고스 시간 (갈라파고스)", + "Pacific\/Gambier": "감비에 시간 (감비어)", + "Pacific\/Guadalcanal": "솔로몬 제도 시간 (과달카날)", + "Pacific\/Guam": "차모로 시간 (괌)", + "Pacific\/Honolulu": "하와이 알류샨 시간 (호놀룰루)", + "Pacific\/Johnston": "하와이 알류샨 시간 (존스톤)", + "Pacific\/Kiritimati": "라인 제도 시간 (키리티마티)", + "Pacific\/Kosrae": "코스라에섬 시간 (코스레)", + "Pacific\/Kwajalein": "마셜 제도 시간 (콰잘렌)", + "Pacific\/Majuro": "마셜 제도 시간 (마주로)", + "Pacific\/Marquesas": "마르키즈 제도 시간 (마퀘사스)", + "Pacific\/Midway": "사모아 시간 (미드웨이)", + "Pacific\/Nauru": "나우루 시간 (나우루)", + "Pacific\/Niue": "니우에 시간 (니우에)", + "Pacific\/Norfolk": "노퍽섬 시간 (노퍽)", + "Pacific\/Noumea": "뉴칼레도니아 시간 (누메아)", + "Pacific\/Pago_Pago": "사모아 시간 (파고파고)", + "Pacific\/Palau": "팔라우 시간 (팔라우)", + "Pacific\/Pitcairn": "핏케언 시간 (핏케언)", + "Pacific\/Ponape": "포나페 시간 (포나페)", + "Pacific\/Port_Moresby": "파푸아뉴기니 시간 (포트모르즈비)", + "Pacific\/Rarotonga": "쿡 제도 시간 (라로통가)", + "Pacific\/Saipan": "차모로 시간 (사이판)", + "Pacific\/Tahiti": "타히티 시간 (타히티)", + "Pacific\/Tarawa": "길버트 제도 시간 (타라와)", + "Pacific\/Tongatapu": "통가 시간 (통가타푸)", + "Pacific\/Truk": "추크 시간 (트루크)", + "Pacific\/Wake": "웨이크섬 시간 (웨이크)", + "Pacific\/Wallis": "월리스푸투나 제도 시간 (월리스)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ko_KP.json b/src/Symfony/Component/Intl/Resources/data/timezones/ko_KP.json new file mode 100644 index 0000000000000..4fbc6afe043e3 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ko_KP.json @@ -0,0 +1,7 @@ +{ + "Version": "2.1.47.71", + "Names": { + "Asia\/Pyongyang": "조선 시간 (Pyongyang)", + "Asia\/Seoul": "조선 시간 (Seoul)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ks.json b/src/Symfony/Component/Intl/Resources/data/timezones/ks.json new file mode 100644 index 0000000000000..8d8d48ac031a7 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ks.json @@ -0,0 +1,425 @@ +{ + "Version": "2.1.47.83", + "Names": { + "Africa\/Abidjan": "گریٖن وِچ میٖن ٹایِم (عابِدجان)", + "Africa\/Accra": "گریٖن وِچ میٖن ٹایِم (اؠکرا)", + "Africa\/Addis_Ababa": "مشرقی افریٖقا ٹایِم (Addis Ababa)", + "Africa\/Algiers": "مرکزی یوٗرپی ٹایِم (اَلجیٖرِیا)", + "Africa\/Asmera": "مشرقی افریٖقا ٹایِم (اَسمیرا)", + "Africa\/Bamako": "گریٖن وِچ میٖن ٹایِم (بماکو)", + "Africa\/Bangui": "مغربی افریٖقا ٹایِم (بؠنگوٗیی)", + "Africa\/Banjul": "گریٖن وِچ میٖن ٹایِم (بَنجوٗل)", + "Africa\/Bissau": "گریٖن وِچ میٖن ٹایِم (بِساؤں)", + "Africa\/Blantyre": "مرکزی افریٖقا ٹایِم (بلانتَیر)", + "Africa\/Brazzaville": "مغربی افریٖقا ٹایِم (برازاوِل)", + "Africa\/Bujumbura": "مرکزی افریٖقا ٹایِم (بُجُمبُرا)", + "Africa\/Cairo": "مشرقی یوٗرپی ٹایِم (کَیرو)", + "Africa\/Casablanca": "مغرِبی یوٗرپی ٹایِم (کؠسابلؠنکا)", + "Africa\/Ceuta": "مرکزی یوٗرپی ٹایِم (کیوٗٹا)", + "Africa\/Conakry": "گریٖن وِچ میٖن ٹایِم (کوناکری)", + "Africa\/Dakar": "گریٖن وِچ میٖن ٹایِم (دَکار)", + "Africa\/Dar_es_Salaam": "مشرقی افریٖقا ٹایِم (دارُالسلام)", + "Africa\/Djibouti": "مشرقی افریٖقا ٹایِم (ڑِزِبوٹی)", + "Africa\/Douala": "مغربی افریٖقا ٹایِم (دوعالا)", + "Africa\/El_Aaiun": "مغرِبی یوٗرپی ٹایِم (El Aaiun)", + "Africa\/Freetown": "گریٖن وِچ میٖن ٹایِم (فری ٹاوُن)", + "Africa\/Gaborone": "مرکزی افریٖقا ٹایِم (گؠبورون)", + "Africa\/Harare": "مرکزی افریٖقا ٹایِم (ہَراریے)", + "Africa\/Johannesburg": "جنوٗبی افریقا ٹایِم (جانسبٔرگ)", + "Africa\/Juba": "مشرقی افریٖقا ٹایِم (Juba)", + "Africa\/Kampala": "مشرقی افریٖقا ٹایِم (کَمپالا)", + "Africa\/Khartoum": "مرکزی افریٖقا ٹایِم (کھارتوم)", + "Africa\/Kigali": "مرکزی افریٖقا ٹایِم (کِگالی)", + "Africa\/Kinshasa": "مغربی افریٖقا ٹایِم (کِنشاسا)", + "Africa\/Lagos": "مغربی افریٖقا ٹایِم (لیگوس)", + "Africa\/Libreville": "مغربی افریٖقا ٹایِم (لِبَروِل)", + "Africa\/Lome": "گریٖن وِچ میٖن ٹایِم (لوم)", + "Africa\/Luanda": "مغربی افریٖقا ٹایِم (لُعؠنڑا)", + "Africa\/Lubumbashi": "مرکزی افریٖقا ٹایِم (لُبُمباشی)", + "Africa\/Lusaka": "مرکزی افریٖقا ٹایِم (لُساکا)", + "Africa\/Malabo": "مغربی افریٖقا ٹایِم (مالابو)", + "Africa\/Maputo": "مرکزی افریٖقا ٹایِم (مَپوٗٹو)", + "Africa\/Maseru": "جنوٗبی افریقا ٹایِم (مَسیروٗ)", + "Africa\/Mbabane": "جنوٗبی افریقا ٹایِم (مابین)", + "Africa\/Mogadishu": "مشرقی افریٖقا ٹایِم (موگادِشوٗ)", + "Africa\/Monrovia": "گریٖن وِچ میٖن ٹایِم (مونرووِیا)", + "Africa\/Nairobi": "مشرقی افریٖقا ٹایِم (نیروبی)", + "Africa\/Ndjamena": "مغربی افریٖقا ٹایِم (جَمیٖنا)", + "Africa\/Niamey": "مغربی افریٖقا ٹایِم (نَیمیے)", + "Africa\/Nouakchott": "گریٖن وِچ میٖن ٹایِم (نوواکچھوت)", + "Africa\/Ouagadougou": "گریٖن وِچ میٖن ٹایِم (اوآگدوگو)", + "Africa\/Porto-Novo": "مغربی افریٖقا ٹایِم (پوٹو نووو)", + "Africa\/Sao_Tome": "گریٖن وِچ میٖن ٹایِم (ساو ٹوم)", + "Africa\/Tripoli": "مشرقی یوٗرپی ٹایِم (ترپولی)", + "Africa\/Tunis": "مرکزی یوٗرپی ٹایِم (ٹوٗنِس)", + "Africa\/Windhoek": "مرکزی افریٖقا ٹایِم (وِنڈہوک)", + "America\/Adak": "حَواے اؠلیوٗٹِیَن ٹایِم (اِدَک)", + "America\/Anchorage": "اؠلاسکا ٹایِم (اَنکوراج)", + "America\/Anguilla": "اؠٹلانٹِک ٹایِم (اؠنگِولا)", + "America\/Antigua": "اؠٹلانٹِک ٹایِم (اؠنٹِگُوا)", + "America\/Araguaina": "برؠسِلِیا ٹایِم (اؠریگُوینا)", + "America\/Argentina\/La_Rioja": "ارجؠنٹیٖنا ٹایِم (لا رِیوجا)", + "America\/Argentina\/Rio_Gallegos": "ارجؠنٹیٖنا ٹایِم (رِیو گالیگوس)", + "America\/Argentina\/Salta": "ارجؠنٹیٖنا ٹایِم (Salta)", + "America\/Argentina\/San_Juan": "ارجؠنٹیٖنا ٹایِم (سین جُواں)", + "America\/Argentina\/San_Luis": "مغربی ارجؠنٹیٖنا ٹایِم (سین لوٗیِس)", + "America\/Argentina\/Tucuman": "ارجؠنٹیٖنا ٹایِم (ٹوکوٗمَن)", + "America\/Argentina\/Ushuaia": "ارجؠنٹیٖنا ٹایِم (اُشُوٗاییا)", + "America\/Aruba": "اؠٹلانٹِک ٹایِم (اَروٗبا)", + "America\/Asuncion": "پیرؠگوے ٹایِم (اَسُنچِیَن)", + "America\/Bahia": "برؠسِلِیا ٹایِم (بَہِیا)", + "America\/Bahia_Banderas": "مرکزی ٹایِم (Bahia Banderas)", + "America\/Barbados": "اؠٹلانٹِک ٹایِم (بَرباڑوس)", + "America\/Belem": "برؠسِلِیا ٹایِم (بؠلؠم)", + "America\/Belize": "مرکزی ٹایِم (بؠلیٖز)", + "America\/Blanc-Sablon": "اؠٹلانٹِک ٹایِم (بلانک سؠبلَن)", + "America\/Boa_Vista": "اؠمَزَن ٹایِم (بوآ وِسٹا)", + "America\/Bogota": "کولومبِیا ٹایِم (بوگوٹا)", + "America\/Boise": "ماونٹین ٹایِم (بویِس)", + "America\/Buenos_Aires": "ارجؠنٹیٖنا ٹایِم (بیوٗنَس آیرَس)", + "America\/Cambridge_Bay": "ماونٹین ٹایِم (کیمبرِج خلیٖج)", + "America\/Campo_Grande": "اؠمَزَن ٹایِم (کؠمپو گرینڑ)", + "America\/Cancun": "مشرقی ٹایِم (کینکَن)", + "America\/Caracas": "وؠنؠزیوٗلا ٹایِم (کیرَکَس)", + "America\/Catamarca": "ارجؠنٹیٖنا ٹایِم (کیٹامارکا)", + "America\/Cayenne": "فرؠنچ گیوٗؠنا ٹایِم (کَیین)", + "America\/Cayman": "مشرقی ٹایِم (کیمَن)", + "America\/Chicago": "مرکزی ٹایِم (شِکاگو)", + "America\/Coral_Harbour": "مشرقی ٹایِم (کورَل بٔندٕرگاہ)", + "America\/Cordoba": "ارجؠنٹیٖنا ٹایِم (کورڑوبا)", + "America\/Costa_Rica": "مرکزی ٹایِم (کوسٹا ریٖکا)", + "America\/Creston": "ماونٹین ٹایِم (Creston)", + "America\/Cuiaba": "اؠمَزَن ٹایِم (کوٗیابا)", + "America\/Curacao": "اؠٹلانٹِک ٹایِم (کیوٗراکااو)", + "America\/Danmarkshavn": "گریٖن وِچ میٖن ٹایِم (ڑؠنمارکشَون)", + "America\/Dawson": "پیسِفِک ٹایِم (ڑاسَن)", + "America\/Dawson_Creek": "ماونٹین ٹایِم (ڑاسَن کریٖک)", + "America\/Denver": "ماونٹین ٹایِم (ڈینوَر)", + "America\/Detroit": "مشرقی ٹایِم (ڈیٹرایِٹ)", + "America\/Dominica": "اؠٹلانٹِک ٹایِم (ڈومِنِکا)", + "America\/Edmonton": "ماونٹین ٹایِم (اؠڑمَنٹَن)", + "America\/Eirunepe": "اؠکرے ٹایِم (ایٖروٗنیپ)", + "America\/El_Salvador": "مرکزی ٹایِم (ایل سَلویدَر)", + "America\/Fort_Nelson": "ماونٹین ٹایِم (Fort Nelson)", + "America\/Fortaleza": "برؠسِلِیا ٹایِم (فورٹیلیزا)", + "America\/Glace_Bay": "اؠٹلانٹِک ٹایِم (گلیس خلیٖج)", + "America\/Godthab": "مغرِبی گریٖن لینڑُک ٹایِم (گعاڑتھیب)", + "America\/Goose_Bay": "اؠٹلانٹِک ٹایِم (گوٗس خلیٖج)", + "America\/Grand_Turk": "مشرقی ٹایِم (گرینڈ تٔرک)", + "America\/Grenada": "اؠٹلانٹِک ٹایِم (گریناڑا)", + "America\/Guadeloupe": "اؠٹلانٹِک ٹایِم (گوڑلوپ)", + "America\/Guatemala": "مرکزی ٹایِم (گواٹیمالا)", + "America\/Guayaquil": "اِکویڑَر ٹایِم (گوایاکِوَل)", + "America\/Guyana": "گُیَنا ٹایِم (گُیانا)", + "America\/Halifax": "اؠٹلانٹِک ٹایِم (حیلِفؠکس)", + "America\/Havana": "کیوٗبا ٹایِم (حوانا)", + "America\/Indiana\/Knox": "مرکزی ٹایِم (نوکس)", + "America\/Indiana\/Marengo": "مشرقی ٹایِم (میرینگو)", + "America\/Indiana\/Petersburg": "مشرقی ٹایِم (پِٹس بٔرگ)", + "America\/Indiana\/Tell_City": "مرکزی ٹایِم (ٹیل سِٹی)", + "America\/Indiana\/Vevay": "مشرقی ٹایِم (ویویے)", + "America\/Indiana\/Vincennes": "مشرقی ٹایِم (وِنسینیس)", + "America\/Indiana\/Winamac": "مشرقی ٹایِم (وِنیمیک)", + "America\/Indianapolis": "مشرقی ٹایِم (اِنڈیَن پولِس)", + "America\/Inuvik": "ماونٹین ٹایِم (اِنوٗوِک)", + "America\/Iqaluit": "مشرقی ٹایِم (اِقالیوٗیِت)", + "America\/Jamaica": "مشرقی ٹایِم (جَمَیکا)", + "America\/Jujuy": "ارجؠنٹیٖنا ٹایِم (جُجویے)", + "America\/Juneau": "اؠلاسکا ٹایِم (جوٗنی)", + "America\/Kentucky\/Monticello": "مشرقی ٹایِم (مونٹِسیلو)", + "America\/Kralendijk": "اؠٹلانٹِک ٹایِم (Kralendijk)", + "America\/La_Paz": "بولِوِیا ٹایِم (لا پاز)", + "America\/Lima": "پٔروٗ ٹایِم (لِما)", + "America\/Los_Angeles": "پیسِفِک ٹایِم (لاس اینجٕلز)", + "America\/Louisville": "مشرقی ٹایِم (لوٗیِس وِل)", + "America\/Lower_Princes": "اؠٹلانٹِک ٹایِم (Lower Prince’s Quarter)", + "America\/Maceio": "برؠسِلِیا ٹایِم (میسِیوو)", + "America\/Managua": "مرکزی ٹایِم (مَناگوا)", + "America\/Manaus": "اؠمَزَن ٹایِم (مَنوس)", + "America\/Marigot": "اؠٹلانٹِک ٹایِم (Marigot)", + "America\/Martinique": "اؠٹلانٹِک ٹایِم (مارٹِنِک)", + "America\/Matamoros": "مرکزی ٹایِم (Matamoros)", + "America\/Mendoza": "ارجؠنٹیٖنا ٹایِم (مؠنڑوزا)", + "America\/Menominee": "مرکزی ٹایِم (مینومِنی)", + "America\/Merida": "مرکزی ٹایِم (میرِڈا)", + "America\/Metlakatla": "اؠلاسکا ٹایِم (Metlakatla)", + "America\/Mexico_City": "مرکزی ٹایِم (میکسِکو سِٹی)", + "America\/Miquelon": "سینٹ پَیری مِقیوٗلَن ٹایِم (مِکیٖلَن)", + "America\/Moncton": "اؠٹلانٹِک ٹایِم (مونکٹٕن)", + "America\/Monterrey": "مرکزی ٹایِم (موٹیری)", + "America\/Montevideo": "یوٗرؠگوَے ٹایِم (مونٹیوِڈیو)", + "America\/Montserrat": "اؠٹلانٹِک ٹایِم (مونژیرات)", + "America\/Nassau": "مشرقی ٹایِم (نساؤں)", + "America\/New_York": "مشرقی ٹایِم (نِو یارک)", + "America\/Nipigon": "مشرقی ٹایِم (نِپِگَن)", + "America\/Nome": "اؠلاسکا ٹایِم (نوم)", + "America\/Noronha": "نورونہا ٹایِم (نورونہا)", + "America\/North_Dakota\/Beulah": "مرکزی ٹایِم (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "مرکزی ٹایِم (مَرکزی جنوٗبی ڈکوٹا)", + "America\/North_Dakota\/New_Salem": "مرکزی ٹایِم (نوو سیلٕم)", + "America\/Ojinaga": "ماونٹین ٹایِم (Ojinaga)", + "America\/Panama": "مشرقی ٹایِم (پَناما)", + "America\/Pangnirtung": "مشرقی ٹایِم (پَنگنِرٹَنگ)", + "America\/Paramaribo": "سُرِنام ٹایِم (پَرامارِبو)", + "America\/Phoenix": "ماونٹین ٹایِم (پھِنِکس)", + "America\/Port-au-Prince": "مشرقی ٹایِم (پوٹ آؤں پرِنس)", + "America\/Port_of_Spain": "اؠٹلانٹِک ٹایِم (پوٹ آف سپین)", + "America\/Porto_Velho": "اؠمَزَن ٹایِم (پوٹو وؠلہو)", + "America\/Puerto_Rico": "اؠٹلانٹِک ٹایِم (پیٖٹو رِکو)", + "America\/Punta_Arenas": "چِلی ٹایِم (Punta Arenas)", + "America\/Rainy_River": "مرکزی ٹایِم (رینی رِوَر)", + "America\/Rankin_Inlet": "مرکزی ٹایِم (رینکِن اِنلؠٹ)", + "America\/Recife": "برؠسِلِیا ٹایِم (رؠچیٖف)", + "America\/Regina": "مرکزی ٹایِم (رؠجیٖنا)", + "America\/Resolute": "مرکزی ٹایِم (رِسولیوٗٹ)", + "America\/Rio_Branco": "اؠکرے ٹایِم (رِیو برانکو)", + "America\/Santarem": "برؠسِلِیا ٹایِم (Santarem)", + "America\/Santiago": "چِلی ٹایِم (سینٹِعؠگو)", + "America\/Santo_Domingo": "اؠٹلانٹِک ٹایِم (سؠنٹو ڑومِنگو)", + "America\/Sao_Paulo": "برؠسِلِیا ٹایِم (ساو پعالو)", + "America\/Scoresbysund": "مشرِقی گریٖن لینڑُک ٹایِم (سکورٕسباےسَنڑ)", + "America\/Sitka": "اؠلاسکا ٹایِم (Sitka)", + "America\/St_Barthelemy": "اؠٹلانٹِک ٹایِم (St. Barthelemy)", + "America\/St_Johns": "نیوٗ فاونڑلینڑ ٹایِم (سؠنٹ جونس)", + "America\/St_Kitts": "اؠٹلانٹِک ٹایِم (سینٹ کِٹس)", + "America\/St_Lucia": "اؠٹلانٹِک ٹایِم (سؠنٹ لوٗسِیا)", + "America\/St_Thomas": "اؠٹلانٹِک ٹایِم (سینٹ تھامَس)", + "America\/St_Vincent": "اؠٹلانٹِک ٹایِم (وِنسینٹ)", + "America\/Swift_Current": "مرکزی ٹایِم (سٕوِفٹ کَرَنٹ)", + "America\/Tegucigalpa": "مرکزی ٹایِم (Tegucigalpa)", + "America\/Thule": "اؠٹلانٹِک ٹایِم (تھیوٗلے)", + "America\/Thunder_Bay": "مشرقی ٹایِم (تھَنڑَر خلیٖج)", + "America\/Tijuana": "پیسِفِک ٹایِم (تِجُوانا)", + "America\/Toronto": "مشرقی ٹایِم (ٹورونٹو)", + "America\/Tortola": "اؠٹلانٹِک ٹایِم (ٹارٹولا)", + "America\/Vancouver": "پیسِفِک ٹایِم (وؠنکووَر)", + "America\/Whitehorse": "پیسِفِک ٹایِم (وایِٹ ہارٕس)", + "America\/Winnipeg": "مرکزی ٹایِم (وِنِپؠگ)", + "America\/Yakutat": "اؠلاسکا ٹایِم (یکوٗتات)", + "America\/Yellowknife": "ماونٹین ٹایِم (یؠلو نایِف)", + "Antarctica\/Casey": "مغرِبی آسٹریلِیا ٹایِم (کیسی)", + "Antarctica\/Davis": "ڑیوِس ٹایِم (ڈیوِس)", + "Antarctica\/DumontDUrville": "ڑمانٹ ڈی اُرویٖل ٹایِم (ڈُمونٹ ڈ اَروِل)", + "Antarctica\/Mawson": "ماسَن ٹایِم (ماسَن)", + "Antarctica\/McMurdo": "نِوزِلینڑ ٹایِم (مؠک مٲڑو)", + "Antarctica\/Palmer": "چِلی ٹایِم (پامَر)", + "Antarctica\/Rothera": "روتھؠرا ٹایِم (روتھیرا)", + "Antarctica\/Syowa": "سیووا ٹایِم (سیووا)", + "Antarctica\/Troll": "گریٖن وِچ میٖن ٹایِم (Troll)", + "Antarctica\/Vostok": "ووسٹوک ٹایِم (ووستوک)", + "Arctic\/Longyearbyen": "مرکزی یوٗرپی ٹایِم (Longyearbyen)", + "Asia\/Aden": "ارؠبِیَن ٹایِم (ایڈٕن)", + "Asia\/Almaty": "مشرِقی کَزاکھِستان ٹایِم (اَلماٹی)", + "Asia\/Amman": "مشرقی یوٗرپی ٹایِم (اَمان)", + "Asia\/Anadyr": "اؠنَڑیٖر ٹایِم (اَنَدیر)", + "Asia\/Aqtau": "مغرِبی کَزاکھِستان ٹایِم (اَکتاؤں)", + "Asia\/Aqtobe": "مغرِبی کَزاکھِستان ٹایِم (اَقٹوب)", + "Asia\/Ashgabat": "تُرکمؠنِستان ٹایِم (اَشگَبَت)", + "Asia\/Atyrau": "مغرِبی کَزاکھِستان ٹایِم (Atyrau)", + "Asia\/Baghdad": "ارؠبِیَن ٹایِم (بغداد)", + "Asia\/Bahrain": "ارؠبِیَن ٹایِم (بؠہریٖن)", + "Asia\/Baku": "اَزَربیجان ٹایِم (باقوٗ)", + "Asia\/Bangkok": "اِنڑوچَینا ٹایِم (بینگ کاک)", + "Asia\/Beirut": "مشرقی یوٗرپی ٹایِم (بیرُت)", + "Asia\/Bishkek": "کِرگِستان ٹایِم (بِشکیک)", + "Asia\/Brunei": "بروٗنَے دَروٗسَلَم ٹایِم (بروٗنَے)", + "Asia\/Calcutta": "ہِندوستان (Kolkata)", + "Asia\/Chita": "یَکُٹسک ٹایِم (Chita)", + "Asia\/Choibalsan": "کوےبؠلسَن ٹایِم (چویبالسَن)", + "Asia\/Colombo": "ہِندوستان (کولَمبو)", + "Asia\/Damascus": "مشرقی یوٗرپی ٹایِم (دَمَسکَس)", + "Asia\/Dhaka": "بَنگلادیش ٹایِم (ڈھاکا)", + "Asia\/Dili": "ایٖسٹ ٹیٖمَر ٹایِم (دِلی)", + "Asia\/Dubai": "گَلف سٹینڑاڑ ٹایِم (دُبَے)", + "Asia\/Dushanbe": "تازِکِستان ٹایِم (دُشانبیے)", + "Asia\/Famagusta": "مشرقی یوٗرپی ٹایِم (Famagusta)", + "Asia\/Gaza": "مشرقی یوٗرپی ٹایِم (غازا)", + "Asia\/Hebron": "مشرقی یوٗرپی ٹایِم (Hebron)", + "Asia\/Hong_Kong": "حانگ کانگ ٹایِم (حانگ کانگ)", + "Asia\/Hovd": "حووڑ ٹایِم (حووڑ)", + "Asia\/Irkutsk": "اِرکُٹسک ٹایِم (اِرکُسک)", + "Asia\/Jakarta": "مغرِبی اِنڑونیشِیا ٹایِم (جکارتا)", + "Asia\/Jayapura": "مشرِقی اِنڑونیشِیا ٹایِم (جَیاپوٗرا)", + "Asia\/Jerusalem": "اِسرٲیِلی ٹایِم (یؠروٗسَلَم)", + "Asia\/Kabul": "افغانِستان ٹایِم (قابُل)", + "Asia\/Kamchatka": "کَمچَٹکا ٹایِم (کَمچھٹکا)", + "Asia\/Karachi": "پاکِستان ٹایِم (کَراچی)", + "Asia\/Katmandu": "نؠپٲلۍ ٹایِم (کاٹھمَنڈوٗ)", + "Asia\/Khandyga": "یَکُٹسک ٹایِم (Khandyga)", + "Asia\/Krasnoyarsk": "کرؠسنوےیارسک ٹایِم (کرنسنویارسک)", + "Asia\/Kuala_Lumpur": "مَلیشِیا ٹایِم (کولالَمپوٗر)", + "Asia\/Kuching": "مَلیشِیا ٹایِم (کُچِنگ)", + "Asia\/Kuwait": "ارؠبِیَن ٹایِم (کُویت)", + "Asia\/Macau": "چَینا ٹایِم (مقاؤں)", + "Asia\/Magadan": "مَگَدَن ٹایِم (مَگادَن)", + "Asia\/Makassar": "مرکزی اِنڑونیشِیا ٹایِم (مَکَسَر)", + "Asia\/Manila": "پھِلِپایِن ٹایِم (مَنیٖلا)", + "Asia\/Muscat": "گَلف سٹینڑاڑ ٹایِم (مَسکَت)", + "Asia\/Nicosia": "مشرقی یوٗرپی ٹایِم (نِکوسِیا)", + "Asia\/Novokuznetsk": "کرؠسنوےیارسک ٹایِم (Novokuznetsk)", + "Asia\/Novosibirsk": "نۄوۄسِبٔرسک ٹایِم (نوووسِبِرسک)", + "Asia\/Omsk": "اۄمسک ٹایِم (اومسک)", + "Asia\/Oral": "مغرِبی کَزاکھِستان ٹایِم (اورَل)", + "Asia\/Phnom_Penh": "اِنڑوچَینا ٹایِم (نوم پؠنہہ)", + "Asia\/Pontianak": "مغرِبی اِنڑونیشِیا ٹایِم (پونتِعانک)", + "Asia\/Pyongyang": "کورِیا ٹایِم (پیونگیانگ)", + "Asia\/Qatar": "ارؠبِیَن ٹایِم (قَتَر)", + "Asia\/Qostanay": "مشرِقی کَزاکھِستان ٹایِم (Qostanay)", + "Asia\/Qyzylorda": "مغرِبی کَزاکھِستان ٹایِم (قؠزؠلوڑا)", + "Asia\/Rangoon": "مِیانمَر ٹایِم (رنگوٗن)", + "Asia\/Riyadh": "ارؠبِیَن ٹایِم (رِیاد)", + "Asia\/Saigon": "اِنڑوچَینا ٹایِم (سیگَن)", + "Asia\/Sakhalin": "سَکھؠلِن ٹایِم (سَکھالِن)", + "Asia\/Samarkand": "اُزبیکِستان ٹایِم (سَمَرکَند)", + "Asia\/Seoul": "کورِیا ٹایِم (سول)", + "Asia\/Shanghai": "چَینا ٹایِم (Shanghai)", + "Asia\/Singapore": "سِنگاپوٗر ٹایِم (سِنگاپور)", + "Asia\/Srednekolymsk": "مَگَدَن ٹایِم (Srednekolymsk)", + "Asia\/Tashkent": "اُزبیکِستان ٹایِم (تاشکینٹ)", + "Asia\/Tbilisi": "جورجِیاہُک ٹایِم (بِلِسی)", + "Asia\/Tehran": "اِیٖرٲنۍ ٹایِم (تؠہران)", + "Asia\/Thimphu": "بوٗٹان ٹایِم (تھِمپوٗ)", + "Asia\/Tokyo": "جاپٲنۍ ٹایِم (ٹوکیو)", + "Asia\/Ulaanbaatar": "مونگولِیا ٹایِم (اُلانباٹَر)", + "Asia\/Ust-Nera": "ولاڑِووسٹوک ٹایِم (Ust-Nera)", + "Asia\/Vientiane": "اِنڑوچَینا ٹایِم (وِیَنتِیین)", + "Asia\/Vladivostok": "ولاڑِووسٹوک ٹایِم (لادِووستوک)", + "Asia\/Yakutsk": "یَکُٹسک ٹایِم (یکوسک)", + "Asia\/Yekaterinburg": "یؠکَٹٔرِنبٔرگ ٹایِم (یَکاتِرِنبٔرگ)", + "Asia\/Yerevan": "ارمیٖنِیا ٹایِم (یےریوَن)", + "Atlantic\/Azores": "اؠزورٕس ٹایِم (اَزورَس)", + "Atlantic\/Bermuda": "اؠٹلانٹِک ٹایِم (برموٗڑا)", + "Atlantic\/Canary": "مغرِبی یوٗرپی ٹایِم (کؠنَری)", + "Atlantic\/Cape_Verde": "کیپ ؤرڑو ٹایِم (کیپ ؤرڑے)", + "Atlantic\/Faeroe": "مغرِبی یوٗرپی ٹایِم (فؠرو)", + "Atlantic\/Madeira": "مغرِبی یوٗرپی ٹایِم (مَڈیٖرا)", + "Atlantic\/Reykjavik": "گریٖن وِچ میٖن ٹایِم (رؠکیاوِک)", + "Atlantic\/South_Georgia": "شُمٲلی جورجِیا ٹایِم (ساوتھ جورجِیا)", + "Atlantic\/St_Helena": "گریٖن وِچ میٖن ٹایِم (سینٹ ہیلِنا)", + "Atlantic\/Stanley": "فاکلینڑ ٹایِم (سٹینلی)", + "Australia\/Adelaide": "مرکزی آسٹریلِیَن ٹایِم (اؠڑِلیڑ)", + "Australia\/Brisbane": "مشرِقی آسٹریلِیا ٹایِم (برسبین)", + "Australia\/Broken_Hill": "مرکزی آسٹریلِیَن ٹایِم (بروکٕن ہِل)", + "Australia\/Currie": "مشرِقی آسٹریلِیا ٹایِم (کیوٗری)", + "Australia\/Darwin": "مرکزی آسٹریلِیَن ٹایِم (ڈاروِن)", + "Australia\/Eucla": "آسٹریلِیَن مرکزی مغربی ٹایِم (یوٗکلا)", + "Australia\/Hobart": "مشرِقی آسٹریلِیا ٹایِم (حۄبٲٹ)", + "Australia\/Lindeman": "مشرِقی آسٹریلِیا ٹایِم (لِنڑیمان)", + "Australia\/Lord_Howe": "لعاڑ حووے ٹایِم (لعاڑ ہووے)", + "Australia\/Melbourne": "مشرِقی آسٹریلِیا ٹایِم (مؠلبعارن)", + "Australia\/Perth": "مغرِبی آسٹریلِیا ٹایِم (پٔرتھ)", + "Australia\/Sydney": "مشرِقی آسٹریلِیا ٹایِم (سِڑنی)", + "CST6CDT": "مرکزی ٹایِم", + "EST5EDT": "مشرقی ٹایِم", + "Etc\/GMT": "گریٖن وِچ میٖن ٹایِم", + "Europe\/Amsterdam": "مرکزی یوٗرپی ٹایِم (ایمسٹَرڈیم)", + "Europe\/Andorra": "مرکزی یوٗرپی ٹایِم (اَنڑورا)", + "Europe\/Astrakhan": "ماسکَو ٹایِم (Astrakhan)", + "Europe\/Athens": "مشرقی یوٗرپی ٹایِم (اؠتھٕنس)", + "Europe\/Belgrade": "مرکزی یوٗرپی ٹایِم (Belgrade)", + "Europe\/Berlin": "مرکزی یوٗرپی ٹایِم (بٔرلِن)", + "Europe\/Bratislava": "مرکزی یوٗرپی ٹایِم (Bratislava)", + "Europe\/Brussels": "مرکزی یوٗرپی ٹایِم (برسٕلس)", + "Europe\/Bucharest": "مشرقی یوٗرپی ٹایِم (بَچاریسٹ)", + "Europe\/Budapest": "مرکزی یوٗرپی ٹایِم (بُڑاپیسٹ)", + "Europe\/Busingen": "مرکزی یوٗرپی ٹایِم (Busingen)", + "Europe\/Chisinau": "مشرقی یوٗرپی ٹایِم (چِسیٖنو)", + "Europe\/Copenhagen": "مرکزی یوٗرپی ٹایِم (کوپَنہیگَن)", + "Europe\/Dublin": "گریٖن وِچ میٖن ٹایِم (ڈَبلِن)", + "Europe\/Gibraltar": "مرکزی یوٗرپی ٹایِم (گِبرالٹَر)", + "Europe\/Guernsey": "گریٖن وِچ میٖن ٹایِم (Guernsey)", + "Europe\/Helsinki": "مشرقی یوٗرپی ٹایِم (حؠلسِنکی)", + "Europe\/Isle_of_Man": "گریٖن وِچ میٖن ٹایِم (Isle of Man)", + "Europe\/Jersey": "گریٖن وِچ میٖن ٹایِم (Jersey)", + "Europe\/Kaliningrad": "مشرقی یوٗرپی ٹایِم (کَلِناِنگرَد)", + "Europe\/Kiev": "مشرقی یوٗرپی ٹایِم (کیٖو)", + "Europe\/Lisbon": "مغرِبی یوٗرپی ٹایِم (لِسبَن)", + "Europe\/Ljubljana": "مرکزی یوٗرپی ٹایِم (Ljubljana)", + "Europe\/London": "گریٖن وِچ میٖن ٹایِم (لَندَن)", + "Europe\/Luxembourg": "مرکزی یوٗرپی ٹایِم (لَکزٕمبٔرگ)", + "Europe\/Madrid": "مرکزی یوٗرپی ٹایِم (میڑرِڑ)", + "Europe\/Malta": "مرکزی یوٗرپی ٹایِم (مالٹا)", + "Europe\/Mariehamn": "مشرقی یوٗرپی ٹایِم (Mariehamn)", + "Europe\/Minsk": "ماسکَو ٹایِم (مِنسک)", + "Europe\/Monaco": "مرکزی یوٗرپی ٹایِم (موناکو)", + "Europe\/Moscow": "ماسکَو ٹایِم (ماسکو)", + "Europe\/Oslo": "مرکزی یوٗرپی ٹایِم (اوسلو)", + "Europe\/Paris": "مرکزی یوٗرپی ٹایِم (پیرِس)", + "Europe\/Podgorica": "مرکزی یوٗرپی ٹایِم (Podgorica)", + "Europe\/Prague": "مرکزی یوٗرپی ٹایِم (Prague)", + "Europe\/Riga": "مشرقی یوٗرپی ٹایِم (رِگا)", + "Europe\/Rome": "مرکزی یوٗرپی ٹایِم (روم)", + "Europe\/Samara": "سمؠرا ٹایِم (سَمارا)", + "Europe\/San_Marino": "مرکزی یوٗرپی ٹایِم (San Marino)", + "Europe\/Sarajevo": "مرکزی یوٗرپی ٹایِم (Sarajevo)", + "Europe\/Saratov": "ماسکَو ٹایِم (Saratov)", + "Europe\/Simferopol": "ماسکَو ٹایِم (سِمفیروپول)", + "Europe\/Skopje": "مرکزی یوٗرپی ٹایِم (Skopje)", + "Europe\/Sofia": "مشرقی یوٗرپی ٹایِم (سوفِیا)", + "Europe\/Stockholm": "مرکزی یوٗرپی ٹایِم (سٹاک ہولم)", + "Europe\/Tallinn": "مشرقی یوٗرپی ٹایِم (ٹؠلِن)", + "Europe\/Tirane": "مرکزی یوٗرپی ٹایِم (ٹِرین)", + "Europe\/Ulyanovsk": "ماسکَو ٹایِم (Ulyanovsk)", + "Europe\/Uzhgorod": "مشرقی یوٗرپی ٹایِم (اُزگورود)", + "Europe\/Vaduz": "مرکزی یوٗرپی ٹایِم (وادُز)", + "Europe\/Vatican": "مرکزی یوٗرپی ٹایِم (Vatican)", + "Europe\/Vienna": "مرکزی یوٗرپی ٹایِم (وِیَننا)", + "Europe\/Vilnius": "مشرقی یوٗرپی ٹایِم (وِلِنِیَس)", + "Europe\/Volgograd": "وولگوگریڑ ٹایِم (وولگوگرَد)", + "Europe\/Warsaw": "مرکزی یوٗرپی ٹایِم (وارسا)", + "Europe\/Zagreb": "مرکزی یوٗرپی ٹایِم (Zagreb)", + "Europe\/Zaporozhye": "مشرقی یوٗرپی ٹایِم (زَپوروزَے)", + "Europe\/Zurich": "مرکزی یوٗرپی ٹایِم (زیوٗرِک)", + "Indian\/Antananarivo": "مشرقی افریٖقا ٹایِم (اؠنٹنانرِوو)", + "Indian\/Chagos": "ہِندوستٲنۍ اوشَن ٹایِن (چاگوس)", + "Indian\/Christmas": "کرسمَس ٹایِم (کرِسمَس)", + "Indian\/Cocos": "کوکوز اَیلینڑز ٹایِم (کوکوس)", + "Indian\/Comoro": "مشرقی افریٖقا ٹایِم (کومورو)", + "Indian\/Kerguelen": "جنوٗبی فرؠنچ ٹایِم (کیرگولِن)", + "Indian\/Mahe": "سیشؠلٕز ٹایِم (ماہیے)", + "Indian\/Maldives": "مالدیٖوٕز ٹایِم (مالدیٖوز)", + "Indian\/Mauritius": "مورِشَس ٹایِم (مورِشیس)", + "Indian\/Mayotte": "مشرقی افریٖقا ٹایِم (میوٹ)", + "Indian\/Reunion": "رِیوٗنِیَن ٹایِم (رِیوٗنیَن)", + "MST7MDT": "ماونٹین ٹایِم", + "PST8PDT": "پیسِفِک ٹایِم", + "Pacific\/Auckland": "نِوزِلینڑ ٹایِم (آکلینڈ)", + "Pacific\/Bougainville": "پاپُعا نیوٗ گؠنی ٹایِم (Bougainville)", + "Pacific\/Chatham": "کؠتھَم ٹایِم (چَتھَم)", + "Pacific\/Easter": "ایٖسٹَر ٹایِم (ایٖسٹَر)", + "Pacific\/Efate": "وَنوٗاَٹوٗ ٹایِم (ایفاتیے)", + "Pacific\/Enderbury": "پھونِکس ججیٖرُک ٹایِم (اؠنڑربیری)", + "Pacific\/Fakaofo": "ٹوکؠلو ٹایِم (فَکَوفو)", + "Pacific\/Fiji": "فیٖجی ٹایِم (فِجی)", + "Pacific\/Funafuti": "ٹوٗوَلوٗ ٹایِم (فُنافوٗتی)", + "Pacific\/Galapagos": "گؠلؠپیگوز ٹایِم (گؠلَپگوس)", + "Pacific\/Gambier": "گؠمبِیَر ٹایِم (گیمبِیَر)", + "Pacific\/Guadalcanal": "سولومَن ججیٖرَن ہُند ٹایِم (گُوادَلچَنَل)", + "Pacific\/Guam": "کؠمورو سٹینڑاڑ ٹایِم (گوام)", + "Pacific\/Honolulu": "حَواے اؠلیوٗٹِیَن ٹایِم (ہونولو لو)", + "Pacific\/Johnston": "حَواے اؠلیوٗٹِیَن ٹایِم (جانسٹَن)", + "Pacific\/Kiritimati": "لایِٔن ججیٖرُک ٹایِم (کِرِتِماتی)", + "Pacific\/Kosrae": "کورسَے ٹایِم (کوسراے)", + "Pacific\/Kwajalein": "مارشَل ججیٖرُک ٹایِم (کُوجلین)", + "Pacific\/Majuro": "مارشَل ججیٖرُک ٹایِم (مَجوٗرو)", + "Pacific\/Marquesas": "مارقیوٗسَس ٹایِم (مارکیسَس)", + "Pacific\/Midway": "سؠموآ ٹایِم (مِڈویے)", + "Pacific\/Nauru": "نَعوٗروٗ ٹایِم (ناوروٗ)", + "Pacific\/Niue": "نِیوٗ ٹایِم (نِو)", + "Pacific\/Norfolk": "نورفعاک ٹایِم (نورفوک)", + "Pacific\/Noumea": "نِو کیلؠڑونِیا ٹایِم (نومیی)", + "Pacific\/Pago_Pago": "سؠموآ ٹایِم (پیگو پیگو)", + "Pacific\/Palau": "پَلاو ٹایِم (پَلاو)", + "Pacific\/Pitcairn": "پِٹکیرٕن ٹایِم (پِٹکیرَن)", + "Pacific\/Ponape": "پونیپ ٹایِم (پوناپے)", + "Pacific\/Port_Moresby": "پاپُعا نیوٗ گؠنی ٹایِم (پوٹ مورسبی)", + "Pacific\/Rarotonga": "کُک اَیلینڑز ٹایِم (راروٹونگا)", + "Pacific\/Saipan": "کؠمورو سٹینڑاڑ ٹایِم (سَیپان)", + "Pacific\/Tahiti": "ٹاہِٹی ٹایِم (تَہِتی)", + "Pacific\/Tarawa": "گِلبٲٹ ججیٖرُک ٹایِم (ٹَراوا)", + "Pacific\/Tongatapu": "ٹعانگا ٹایِم (تونگاتَپوٗ)", + "Pacific\/Truk": "ٹٔرک ٹایِم (ٹرک)", + "Pacific\/Wake": "ویک ججیٖرُک ٹایِم (ویک)", + "Pacific\/Wallis": "والِس تہٕ فیوٗٹیوٗنا ٹایِم (ویلِس)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ky.json b/src/Symfony/Component/Intl/Resources/data/timezones/ky.json new file mode 100644 index 0000000000000..e9ae9a1b95d6c --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ky.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Гринвич боюнча орточо убакыт (Абиджан)", + "Africa\/Accra": "Гринвич боюнча орточо убакыт (Аккра)", + "Africa\/Addis_Ababa": "Чыгыш Африка убактысы (Аддис-Абеба)", + "Africa\/Algiers": "Борбордук Европа убактысы (Алжир)", + "Africa\/Asmera": "Чыгыш Африка убактысы (Асмара)", + "Africa\/Bamako": "Гринвич боюнча орточо убакыт (Бамако)", + "Africa\/Bangui": "Батыш Африка убактысы (Баги)", + "Africa\/Banjul": "Гринвич боюнча орточо убакыт (Банжул)", + "Africa\/Bissau": "Гринвич боюнча орточо убакыт (Бисау)", + "Africa\/Blantyre": "Борбордук Африка убактысы (Блантайр)", + "Africa\/Brazzaville": "Батыш Африка убактысы (Браззавилл)", + "Africa\/Bujumbura": "Борбордук Африка убактысы (Бужумбура)", + "Africa\/Cairo": "Чыгыш Европа убактысы (Каир)", + "Africa\/Casablanca": "Батыш Европа убактысы (Касабланка)", + "Africa\/Ceuta": "Борбордук Европа убактысы (Сеута)", + "Africa\/Conakry": "Гринвич боюнча орточо убакыт (Конакри)", + "Africa\/Dakar": "Гринвич боюнча орточо убакыт (Дакар)", + "Africa\/Dar_es_Salaam": "Чыгыш Африка убактысы (Дар эс Салаам)", + "Africa\/Djibouti": "Чыгыш Африка убактысы (Жибути)", + "Africa\/Douala": "Батыш Африка убактысы (Дуала)", + "Africa\/El_Aaiun": "Батыш Европа убактысы (Эл Айун)", + "Africa\/Freetown": "Гринвич боюнча орточо убакыт (Фритаун)", + "Africa\/Gaborone": "Борбордук Африка убактысы (Габороне)", + "Africa\/Harare": "Борбордук Африка убактысы (Хараре)", + "Africa\/Johannesburg": "Түштүк Африка убактысы (Йоханнесбург)", + "Africa\/Juba": "Чыгыш Африка убактысы (Жуба)", + "Africa\/Kampala": "Чыгыш Африка убактысы (Кампала)", + "Africa\/Khartoum": "Борбордук Африка убактысы (Картум)", + "Africa\/Kigali": "Борбордук Африка убактысы (Кигали)", + "Africa\/Kinshasa": "Батыш Африка убактысы (Киншаса)", + "Africa\/Lagos": "Батыш Африка убактысы (Лагос)", + "Africa\/Libreville": "Батыш Африка убактысы (Либревилл)", + "Africa\/Lome": "Гринвич боюнча орточо убакыт (Ломе)", + "Africa\/Luanda": "Батыш Африка убактысы (Луанда)", + "Africa\/Lubumbashi": "Борбордук Африка убактысы (Лубумбаши)", + "Africa\/Lusaka": "Борбордук Африка убактысы (Лусака)", + "Africa\/Malabo": "Батыш Африка убактысы (Малабо)", + "Africa\/Maputo": "Борбордук Африка убактысы (Мапуто)", + "Africa\/Maseru": "Түштүк Африка убактысы (Масеру)", + "Africa\/Mbabane": "Түштүк Африка убактысы (Мбабане)", + "Africa\/Mogadishu": "Чыгыш Африка убактысы (Могадишу)", + "Africa\/Monrovia": "Гринвич боюнча орточо убакыт (Монровиа)", + "Africa\/Nairobi": "Чыгыш Африка убактысы (Найроби)", + "Africa\/Ndjamena": "Батыш Африка убактысы (Нжамена)", + "Africa\/Niamey": "Батыш Африка убактысы (Нйаме)", + "Africa\/Nouakchott": "Гринвич боюнча орточо убакыт (Нуакшот)", + "Africa\/Ouagadougou": "Гринвич боюнча орточо убакыт (Уагадугу)", + "Africa\/Porto-Novo": "Батыш Африка убактысы (Порто-Ново)", + "Africa\/Sao_Tome": "Гринвич боюнча орточо убакыт (Сао Томе)", + "Africa\/Tripoli": "Чыгыш Европа убактысы (Триполи)", + "Africa\/Tunis": "Борбордук Европа убактысы (Тунис)", + "Africa\/Windhoek": "Борбордук Африка убактысы (Уиндхук)", + "America\/Adak": "Гавайи-Алеут убактысы (Адак)", + "America\/Anchorage": "Аляска убактысы (Анкориж)", + "America\/Anguilla": "Атлантика убактысы (Ангуила)", + "America\/Antigua": "Атлантика убактысы (Антигуа)", + "America\/Araguaina": "Бразилия убактысы (Арагуаина)", + "America\/Argentina\/La_Rioja": "Аргентина убактысы (Ла-Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аргентина убактысы (Рио Галлегос)", + "America\/Argentina\/Salta": "Аргентина убактысы (Салта)", + "America\/Argentina\/San_Juan": "Аргентина убактысы (Сан Хуан)", + "America\/Argentina\/San_Luis": "Батыш Аргентина убактысы (Сан Луи)", + "America\/Argentina\/Tucuman": "Аргентина убактысы (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентина убактысы (Ушуайа)", + "America\/Aruba": "Атлантика убактысы (Аруба)", + "America\/Asuncion": "Парагвай убактысы (Асунсион)", + "America\/Bahia": "Бразилия убактысы (Байиа)", + "America\/Bahia_Banderas": "Түндүк Америка, борбордук убакыт (Баийа Бандерас)", + "America\/Barbados": "Атлантика убактысы (Барбадос)", + "America\/Belem": "Бразилия убактысы (Белем)", + "America\/Belize": "Түндүк Америка, борбордук убакыт (Белиз)", + "America\/Blanc-Sablon": "Атлантика убактысы (Бланк-Саблон)", + "America\/Boa_Vista": "Амазон убактысы (Боа Виста)", + "America\/Bogota": "Колумбия убактысы (Богота)", + "America\/Boise": "Түндүк Америка, тоо убактысы (Бойсе)", + "America\/Buenos_Aires": "Аргентина убактысы (Буэнос-Айрес)", + "America\/Cambridge_Bay": "Түндүк Америка, тоо убактысы (Кэмбриж Бей)", + "America\/Campo_Grande": "Амазон убактысы (Кампо Гранде)", + "America\/Cancun": "Түндүк Америка, чыгыш убактысы (Канкун)", + "America\/Caracas": "Венесуэла убактысы (Каракас)", + "America\/Catamarca": "Аргентина убактысы (Катамарка)", + "America\/Cayenne": "Француз Гвиана убактысы (Кайен)", + "America\/Cayman": "Түндүк Америка, чыгыш убактысы (Кайман)", + "America\/Chicago": "Түндүк Америка, борбордук убакыт (Чикаго)", + "America\/Chihuahua": "Мексика, Тынч океан убактысы (Чихуахуа)", + "America\/Coral_Harbour": "Түндүк Америка, чыгыш убактысы (Атикокан)", + "America\/Cordoba": "Аргентина убактысы (Кордова)", + "America\/Costa_Rica": "Түндүк Америка, борбордук убакыт (Коста-Рика)", + "America\/Creston": "Түндүк Америка, тоо убактысы (Крестон)", + "America\/Cuiaba": "Амазон убактысы (Куйаба)", + "America\/Curacao": "Атлантика убактысы (Кюрасао)", + "America\/Danmarkshavn": "Гринвич боюнча орточо убакыт (Данмарксхавн)", + "America\/Dawson": "Түндүк Америка, Тынч океан убактысы (Доусон)", + "America\/Dawson_Creek": "Түндүк Америка, тоо убактысы (Доусон Грек)", + "America\/Denver": "Түндүк Америка, тоо убактысы (Денвер)", + "America\/Detroit": "Түндүк Америка, чыгыш убактысы (Детройт)", + "America\/Dominica": "Атлантика убактысы (Доминика)", + "America\/Edmonton": "Түндүк Америка, тоо убактысы (Эдмонтон)", + "America\/El_Salvador": "Түндүк Америка, борбордук убакыт (Эл Салвадор)", + "America\/Fort_Nelson": "Түндүк Америка, тоо убактысы (Форт Нельсон)", + "America\/Fortaleza": "Бразилия убактысы (Форталеза)", + "America\/Glace_Bay": "Атлантика убактысы (Глейс Бей)", + "America\/Godthab": "Батыш Гренландия убактысы (Нуук)", + "America\/Goose_Bay": "Атлантика убактысы (Гус Бей)", + "America\/Grand_Turk": "Түндүк Америка, чыгыш убактысы (Гранд Түрк)", + "America\/Grenada": "Атлантика убактысы (Гренада)", + "America\/Guadeloupe": "Атлантика убактысы (Гваделупе)", + "America\/Guatemala": "Түндүк Америка, борбордук убакыт (Гватемала)", + "America\/Guayaquil": "Экуадор убактысы (Гуайакил)", + "America\/Guyana": "Гвиана убактысы (Гуйана)", + "America\/Halifax": "Атлантика убактысы (Галифакс)", + "America\/Havana": "Куба убактысы (Гавана)", + "America\/Hermosillo": "Мексика, Тынч океан убактысы (Эрмосилло)", + "America\/Indiana\/Knox": "Түндүк Америка, борбордук убакыт (Нокс, Индиана)", + "America\/Indiana\/Marengo": "Түндүк Америка, чыгыш убактысы (Маренго, Индиана)", + "America\/Indiana\/Petersburg": "Түндүк Америка, чыгыш убактысы (Питерсбург, Индиана)", + "America\/Indiana\/Tell_City": "Түндүк Америка, борбордук убакыт (Телл Сити, Индиана)", + "America\/Indiana\/Vevay": "Түндүк Америка, чыгыш убактысы (Вивей, Индиана)", + "America\/Indiana\/Vincennes": "Түндүк Америка, чыгыш убактысы (Винсен, Индиана)", + "America\/Indiana\/Winamac": "Түндүк Америка, чыгыш убактысы (Уинамак, Индиана)", + "America\/Indianapolis": "Түндүк Америка, чыгыш убактысы (Индианаполис)", + "America\/Inuvik": "Түндүк Америка, тоо убактысы (Инувик)", + "America\/Iqaluit": "Түндүк Америка, чыгыш убактысы (Икалуит)", + "America\/Jamaica": "Түндүк Америка, чыгыш убактысы (Ямайка)", + "America\/Jujuy": "Аргентина убактысы (Жужуй)", + "America\/Juneau": "Аляска убактысы (Жуно)", + "America\/Kentucky\/Monticello": "Түндүк Америка, чыгыш убактысы (Монтичелло, Кентукки)", + "America\/Kralendijk": "Атлантика убактысы (Кралендейк)", + "America\/La_Paz": "Боливия убактысы (Ла Пас)", + "America\/Lima": "Перу убактысы (Лима)", + "America\/Los_Angeles": "Түндүк Америка, Тынч океан убактысы (Лос-Анжелес)", + "America\/Louisville": "Түндүк Америка, чыгыш убактысы (Луизвилл)", + "America\/Lower_Princes": "Атлантика убактысы (Лоуэр Принсес Куате)", + "America\/Maceio": "Бразилия убактысы (Масейо)", + "America\/Managua": "Түндүк Америка, борбордук убакыт (Манагуа)", + "America\/Manaus": "Амазон убактысы (Манаус)", + "America\/Marigot": "Атлантика убактысы (Мариго)", + "America\/Martinique": "Атлантика убактысы (Мартиник)", + "America\/Matamoros": "Түндүк Америка, борбордук убакыт (Матаморос)", + "America\/Mazatlan": "Мексика, Тынч океан убактысы (Мазатлан)", + "America\/Mendoza": "Аргентина убактысы (Мендоза)", + "America\/Menominee": "Түндүк Америка, борбордук убакыт (Меномини)", + "America\/Merida": "Түндүк Америка, борбордук убакыт (Мерида)", + "America\/Metlakatla": "Аляска убактысы (Метлакатла)", + "America\/Mexico_City": "Түндүк Америка, борбордук убакыт (Мехико шаары)", + "America\/Miquelon": "Сен Пьер жана Микелон убактысы (Микелон)", + "America\/Moncton": "Атлантика убактысы (Монктон)", + "America\/Monterrey": "Түндүк Америка, борбордук убакыт (Монтерей)", + "America\/Montevideo": "Уругвай убактысы (Монтевидео)", + "America\/Montserrat": "Атлантика убактысы (Монсерат)", + "America\/Nassau": "Түндүк Америка, чыгыш убактысы (Нассау)", + "America\/New_York": "Түндүк Америка, чыгыш убактысы (Нью-Йорк)", + "America\/Nipigon": "Түндүк Америка, чыгыш убактысы (Нипигон)", + "America\/Nome": "Аляска убактысы (Ном)", + "America\/Noronha": "Фернандо де Норонья убактысы (Норониа)", + "America\/North_Dakota\/Beulah": "Түндүк Америка, борбордук убакыт (Беула, Түндүк Дакота)", + "America\/North_Dakota\/Center": "Түндүк Америка, борбордук убакыт (Түндүк Дакотанын борбору)", + "America\/North_Dakota\/New_Salem": "Түндүк Америка, борбордук убакыт (Нью-Салем, Түндүк Дакота)", + "America\/Ojinaga": "Түндүк Америка, тоо убактысы (Охинага)", + "America\/Panama": "Түндүк Америка, чыгыш убактысы (Панама)", + "America\/Pangnirtung": "Түндүк Америка, чыгыш убактысы (Пангиртуң)", + "America\/Paramaribo": "Суринаме убактысы (Парамарибо)", + "America\/Phoenix": "Түндүк Америка, тоо убактысы (Феникс)", + "America\/Port-au-Prince": "Түндүк Америка, чыгыш убактысы (Порт-о-Пренс)", + "America\/Port_of_Spain": "Атлантика убактысы (Порт оф Спейн)", + "America\/Porto_Velho": "Амазон убактысы (Порто Велио)", + "America\/Puerto_Rico": "Атлантика убактысы (Пуэрто-Рико)", + "America\/Punta_Arenas": "Чили убактысы (Пунта-Аренас)", + "America\/Rainy_River": "Түндүк Америка, борбордук убакыт (Рейни Ривер)", + "America\/Rankin_Inlet": "Түндүк Америка, борбордук убакыт (Рэнкин Инлет)", + "America\/Recife": "Бразилия убактысы (Ресифи)", + "America\/Regina": "Түндүк Америка, борбордук убакыт (Регина)", + "America\/Resolute": "Түндүк Америка, борбордук убакыт (Резолут)", + "America\/Santa_Isabel": "Түндүк-чыгыш Мексика убактысы (Санта Изабел)", + "America\/Santarem": "Бразилия убактысы (Сантарем)", + "America\/Santiago": "Чили убактысы (Сантиаго)", + "America\/Santo_Domingo": "Атлантика убактысы (Санто Доминго)", + "America\/Sao_Paulo": "Бразилия убактысы (Сао Пауло)", + "America\/Scoresbysund": "Чыгыш Гренландия убактысы (Иттоккортоормиит)", + "America\/Sitka": "Аляска убактысы (Ситка)", + "America\/St_Barthelemy": "Атлантика убактысы (Сент-Бартелеми)", + "America\/St_Johns": "Нюфаундлэнд убактысы (Сент Жонс)", + "America\/St_Kitts": "Атлантика убактысы (Сент-Китс)", + "America\/St_Lucia": "Атлантика убактысы (Санта Лючия)", + "America\/St_Thomas": "Атлантика убактысы (Сент-Томас)", + "America\/St_Vincent": "Атлантика убактысы (Сент-Винсент)", + "America\/Swift_Current": "Түндүк Америка, борбордук убакыт (Свифт Каррент)", + "America\/Tegucigalpa": "Түндүк Америка, борбордук убакыт (Тегусигальпа)", + "America\/Thule": "Атлантика убактысы (Туле)", + "America\/Thunder_Bay": "Түндүк Америка, чыгыш убактысы (Сандер Бей)", + "America\/Tijuana": "Түндүк Америка, Тынч океан убактысы (Тихуана)", + "America\/Toronto": "Түндүк Америка, чыгыш убактысы (Торонто)", + "America\/Tortola": "Атлантика убактысы (Тортола)", + "America\/Vancouver": "Түндүк Америка, Тынч океан убактысы (Ванкувер)", + "America\/Whitehorse": "Түндүк Америка, Тынч океан убактысы (Уайтхорс)", + "America\/Winnipeg": "Түндүк Америка, борбордук убакыт (Уиннипег)", + "America\/Yakutat": "Аляска убактысы (Якутат)", + "America\/Yellowknife": "Түндүк Америка, тоо убактысы (Йеллоунайф)", + "Antarctica\/Casey": "Австралия батыш убактысы (Кейси)", + "Antarctica\/Davis": "Дэвис убактысы (Дэвис)", + "Antarctica\/DumontDUrville": "Дюмон-д-Урвил убактысы (Дюмон д-Урвил)", + "Antarctica\/Macquarie": "Макуари убактысы (Маккуори)", + "Antarctica\/Mawson": "Моусон убактысы (Моусон)", + "Antarctica\/McMurdo": "Жаңы Зеландия убактысы (МакМёрдо)", + "Antarctica\/Palmer": "Чили убактысы (Палмер)", + "Antarctica\/Rothera": "Ротера убактысы (Ротера)", + "Antarctica\/Syowa": "Саоа убактысы (Саоа)", + "Antarctica\/Troll": "Гринвич боюнча орточо убакыт (Тролл)", + "Antarctica\/Vostok": "Восток убактысы (Восток)", + "Arctic\/Longyearbyen": "Борбордук Европа убактысы (Лонгйербиен)", + "Asia\/Aden": "Арабия убактысы (Аден)", + "Asia\/Almaty": "Чыгыш Казакстан убактысы (Алматы)", + "Asia\/Amman": "Чыгыш Европа убактысы (Амман)", + "Asia\/Aqtau": "Батыш Казакстан убактысы (Актау)", + "Asia\/Aqtobe": "Батыш Казакстан убактысы (Актобе)", + "Asia\/Ashgabat": "Түркмөнстан убактысы (Ашхабад)", + "Asia\/Atyrau": "Батыш Казакстан убактысы (Атырау)", + "Asia\/Baghdad": "Арабия убактысы (Багдад)", + "Asia\/Bahrain": "Арабия убактысы (Бахрейн)", + "Asia\/Baku": "Азербайжан убактысы (Баку)", + "Asia\/Bangkok": "Индокытай убактысы (Бангкок)", + "Asia\/Beirut": "Чыгыш Европа убактысы (Бейрут)", + "Asia\/Bishkek": "Кыргызстан убактысы (Бишкек)", + "Asia\/Brunei": "Бруней Даруссалам убактысы (Бруней)", + "Asia\/Calcutta": "Индия убактысы (Калькутта)", + "Asia\/Chita": "Якутск убактысы (Чита)", + "Asia\/Choibalsan": "Чойбалсан убактысы (Чойбалсан)", + "Asia\/Colombo": "Индия убактысы (Коломбо)", + "Asia\/Damascus": "Чыгыш Европа убактысы (Дамаск)", + "Asia\/Dhaka": "Бангладеш убактысы (Дакка)", + "Asia\/Dili": "Чыгыш Тимор убактысы (Дили)", + "Asia\/Dubai": "Булуңдун стандарттык убакыты (Дубай)", + "Asia\/Dushanbe": "Тажикстан убактысы (Душанбе)", + "Asia\/Famagusta": "Чыгыш Европа убактысы (Фамагуста)", + "Asia\/Gaza": "Чыгыш Европа убактысы (Газа)", + "Asia\/Hebron": "Чыгыш Европа убактысы (Хеброн)", + "Asia\/Hong_Kong": "Гонконг убактысы (Гонконг)", + "Asia\/Hovd": "Ховд убактысы (Ховд)", + "Asia\/Irkutsk": "Иркутск убактысы (Иркутск)", + "Asia\/Jakarta": "Батыш Индонезия убактысы (Жакарта)", + "Asia\/Jayapura": "Чыгыш Индонезия убактысы (Жайапура)", + "Asia\/Jerusalem": "Израиль убакыты (Иерусалим)", + "Asia\/Kabul": "Афганистан убактысы (Кабул)", + "Asia\/Karachi": "Пакистан убактысы (Карачи)", + "Asia\/Katmandu": "Непал убактысы (Катманду)", + "Asia\/Khandyga": "Якутск убактысы (Кандыга)", + "Asia\/Krasnoyarsk": "Красноярск убактысы (Красноярск)", + "Asia\/Kuala_Lumpur": "Малайзия убактысы (Куала Лумпур)", + "Asia\/Kuching": "Малайзия убактысы (Кучиң)", + "Asia\/Kuwait": "Арабия убактысы (Кувейт)", + "Asia\/Macau": "Кытай убактысы (Макау)", + "Asia\/Magadan": "Магадан убактысы (Магадан)", + "Asia\/Makassar": "Борбордук Индонезия убактысы (Макассар)", + "Asia\/Manila": "Филиппин аралдарынын убактысы (Манила)", + "Asia\/Muscat": "Булуңдун стандарттык убакыты (Мускат)", + "Asia\/Nicosia": "Чыгыш Европа убактысы (Никосия)", + "Asia\/Novokuznetsk": "Красноярск убактысы (Новокузнецк)", + "Asia\/Novosibirsk": "Новосибирск убактысы (Новосибирск)", + "Asia\/Omsk": "Омск убактысы (Омск)", + "Asia\/Oral": "Батыш Казакстан убактысы (Орал)", + "Asia\/Phnom_Penh": "Индокытай убактысы (Пномпень)", + "Asia\/Pontianak": "Батыш Индонезия убактысы (Понтианак)", + "Asia\/Pyongyang": "Корея убактысы (Пхеньян)", + "Asia\/Qatar": "Арабия убактысы (Катар)", + "Asia\/Qostanay": "Чыгыш Казакстан убактысы (Qostanay)", + "Asia\/Qyzylorda": "Батыш Казакстан убактысы (Кызылорда)", + "Asia\/Rangoon": "Мйанмар убактысы (Рангун)", + "Asia\/Riyadh": "Арабия убактысы (Рийад)", + "Asia\/Saigon": "Индокытай убактысы (Хо Ши Мин)", + "Asia\/Sakhalin": "Сахалин убактысы (Сахалин)", + "Asia\/Samarkand": "Өзбекстан убактысы (Самарканд)", + "Asia\/Seoul": "Корея убактысы (Сеул)", + "Asia\/Shanghai": "Кытай убактысы (Шанхай)", + "Asia\/Singapore": "Сингапур убактысы (Сингапур)", + "Asia\/Srednekolymsk": "Магадан убактысы (Среднеколымск)", + "Asia\/Taipei": "Тайпей убактысы (Тайпей)", + "Asia\/Tashkent": "Өзбекстан убактысы (Ташкент)", + "Asia\/Tbilisi": "Грузия убактысы (Тбилиси)", + "Asia\/Tehran": "Иран убактысы (Тегеран)", + "Asia\/Thimphu": "Бутан убактысы (Тимпу)", + "Asia\/Tokyo": "Жапон убактысы (Токио)", + "Asia\/Ulaanbaatar": "Улан Батор убактысы (Улан-Батор)", + "Asia\/Ust-Nera": "Владивосток убактысы (Усть-Нера)", + "Asia\/Vientiane": "Индокытай убактысы (Виентиан)", + "Asia\/Vladivostok": "Владивосток убактысы (Владивосток)", + "Asia\/Yakutsk": "Якутск убактысы (Якутск)", + "Asia\/Yekaterinburg": "Екатеринбург убактысы (Екатеринбург)", + "Asia\/Yerevan": "Армения убактысы (Ереван)", + "Atlantic\/Azores": "Азор убактысы (Азор)", + "Atlantic\/Bermuda": "Атлантика убактысы (Бермуда)", + "Atlantic\/Canary": "Батыш Европа убактысы (Канари)", + "Atlantic\/Cape_Verde": "Капе Верде убактысы (Капе Верде)", + "Atlantic\/Faeroe": "Батыш Европа убактысы (Фарер)", + "Atlantic\/Madeira": "Батыш Европа убактысы (Мадейра)", + "Atlantic\/Reykjavik": "Гринвич боюнча орточо убакыт (Рейкьявик)", + "Atlantic\/South_Georgia": "Түштүк Жоржия убактысы (Түштүк Жоржия)", + "Atlantic\/St_Helena": "Гринвич боюнча орточо убакыт (Сент Елена)", + "Atlantic\/Stanley": "Фолкленд аралдарынын убактысы (Стэнли)", + "Australia\/Adelaide": "Австралия борбордук убактысы (Аделаида)", + "Australia\/Brisbane": "Австралия чыгыш убактысы (Брисбен)", + "Australia\/Broken_Hill": "Австралия борбордук убактысы (Броукен Хил)", + "Australia\/Currie": "Австралия чыгыш убактысы (Керри)", + "Australia\/Darwin": "Австралия борбордук убактысы (Дарвин)", + "Australia\/Eucla": "Австралия борбордук батыш убактысы (Юкла)", + "Australia\/Hobart": "Австралия чыгыш убактысы (Хобарт)", + "Australia\/Lindeman": "Австралия чыгыш убактысы (Линдеман)", + "Australia\/Lord_Howe": "Лорд Хау убактысы (Лорд Хау)", + "Australia\/Melbourne": "Австралия чыгыш убактысы (Мельбурн)", + "Australia\/Perth": "Австралия батыш убактысы (Перт)", + "Australia\/Sydney": "Австралия чыгыш убактысы (Сидней)", + "CST6CDT": "Түндүк Америка, борбордук убакыт", + "EST5EDT": "Түндүк Америка, чыгыш убактысы", + "Etc\/GMT": "Гринвич боюнча орточо убакыт", + "Etc\/UTC": "Бирдиктүү дүйнөлүк убакыт", + "Europe\/Amsterdam": "Борбордук Европа убактысы (Амстердам)", + "Europe\/Andorra": "Борбордук Европа убактысы (Андорра)", + "Europe\/Astrakhan": "Москва убактысы (Астрахань)", + "Europe\/Athens": "Чыгыш Европа убактысы (Афины)", + "Europe\/Belgrade": "Борбордук Европа убактысы (Белград)", + "Europe\/Berlin": "Борбордук Европа убактысы (Берлин)", + "Europe\/Bratislava": "Борбордук Европа убактысы (Братислава)", + "Europe\/Brussels": "Борбордук Европа убактысы (Брюссель)", + "Europe\/Bucharest": "Чыгыш Европа убактысы (Бухарест)", + "Europe\/Budapest": "Борбордук Европа убактысы (Будапешт)", + "Europe\/Busingen": "Борбордук Европа убактысы (Бузинген)", + "Europe\/Chisinau": "Чыгыш Европа убактысы (Кишинев)", + "Europe\/Copenhagen": "Борбордук Европа убактысы (Копенгаген)", + "Europe\/Dublin": "Гринвич боюнча орточо убакыт (Дублин)", + "Europe\/Gibraltar": "Борбордук Европа убактысы (Гибралтар)", + "Europe\/Guernsey": "Гринвич боюнча орточо убакыт (Гернси)", + "Europe\/Helsinki": "Чыгыш Европа убактысы (Хельсинки)", + "Europe\/Isle_of_Man": "Гринвич боюнча орточо убакыт (Мэн аралы)", + "Europe\/Jersey": "Гринвич боюнча орточо убакыт (Жерси)", + "Europe\/Kaliningrad": "Чыгыш Европа убактысы (Калининград)", + "Europe\/Kiev": "Чыгыш Европа убактысы (Киев)", + "Europe\/Lisbon": "Батыш Европа убактысы (Лиссабон)", + "Europe\/Ljubljana": "Борбордук Европа убактысы (Любляна)", + "Europe\/London": "Гринвич боюнча орточо убакыт (Лондон)", + "Europe\/Luxembourg": "Борбордук Европа убактысы (Люксембург)", + "Europe\/Madrid": "Борбордук Европа убактысы (Мадрид)", + "Europe\/Malta": "Борбордук Европа убактысы (Мальта)", + "Europe\/Mariehamn": "Чыгыш Европа убактысы (Мариехамн)", + "Europe\/Minsk": "Москва убактысы (Минск)", + "Europe\/Monaco": "Борбордук Европа убактысы (Монако)", + "Europe\/Moscow": "Москва убактысы (Москва)", + "Europe\/Oslo": "Борбордук Европа убактысы (Осло)", + "Europe\/Paris": "Борбордук Европа убактысы (Париж)", + "Europe\/Podgorica": "Борбордук Европа убактысы (Подгорица)", + "Europe\/Prague": "Борбордук Европа убактысы (Прага)", + "Europe\/Riga": "Чыгыш Европа убактысы (Рига)", + "Europe\/Rome": "Борбордук Европа убактысы (Рим)", + "Europe\/San_Marino": "Борбордук Европа убактысы (Сан Марино)", + "Europe\/Sarajevo": "Борбордук Европа убактысы (Сараево)", + "Europe\/Saratov": "Москва убактысы (Саратов)", + "Europe\/Simferopol": "Москва убактысы (Симферополь)", + "Europe\/Skopje": "Борбордук Европа убактысы (Скопйе)", + "Europe\/Sofia": "Чыгыш Европа убактысы (София)", + "Europe\/Stockholm": "Борбордук Европа убактысы (Стокгольм)", + "Europe\/Tallinn": "Чыгыш Европа убактысы (Таллин)", + "Europe\/Tirane": "Борбордук Европа убактысы (Тирана)", + "Europe\/Ulyanovsk": "Москва убактысы (Ульяновск)", + "Europe\/Uzhgorod": "Чыгыш Европа убактысы (Ужгород)", + "Europe\/Vaduz": "Борбордук Европа убактысы (Фадуц)", + "Europe\/Vatican": "Борбордук Европа убактысы (Ватикан)", + "Europe\/Vienna": "Борбордук Европа убактысы (Вена)", + "Europe\/Vilnius": "Чыгыш Европа убактысы (Вильнюс)", + "Europe\/Volgograd": "Волгоград убактысы (Волгоград)", + "Europe\/Warsaw": "Борбордук Европа убактысы (Варшава)", + "Europe\/Zagreb": "Борбордук Европа убактысы (Загреб)", + "Europe\/Zaporozhye": "Чыгыш Европа убактысы (Запорожье)", + "Europe\/Zurich": "Борбордук Европа убактысы (Цюрих)", + "Indian\/Antananarivo": "Чыгыш Африка убактысы (Антананариво)", + "Indian\/Chagos": "Инди океан убактысы (Чагос)", + "Indian\/Christmas": "Крисмас аралынын убактысы (Крисмас)", + "Indian\/Cocos": "Кокос аралдарынын убактысы (Кокос)", + "Indian\/Comoro": "Чыгыш Африка убактысы (Коморо)", + "Indian\/Kerguelen": "Француз Түштүгү жана Антарктика убактысы (Кергелен)", + "Indian\/Mahe": "Сейшел убактысы (Маэ)", + "Indian\/Maldives": "Мальдив убактысы (Мальдив аралдары)", + "Indian\/Mauritius": "Маврикий убактысы (Маврикий)", + "Indian\/Mayotte": "Чыгыш Африка убактысы (Майотт)", + "Indian\/Reunion": "Реюнион убактысы (Реюнион)", + "MST7MDT": "Түндүк Америка, тоо убактысы", + "PST8PDT": "Түндүк Америка, Тынч океан убактысы", + "Pacific\/Apia": "Апиа убактысы (Апиа)", + "Pacific\/Auckland": "Жаңы Зеландия убактысы (Оклэнд)", + "Pacific\/Bougainville": "Папуа-Жаңы Гвинея убакыты (Бугенвиль)", + "Pacific\/Chatham": "Чатам убактысы (Чатем)", + "Pacific\/Easter": "Истер аралынын убактысы (Истер)", + "Pacific\/Efate": "Вануату убактысы (Эфат)", + "Pacific\/Enderbury": "Феникс аралдарынын убактысы (Эндербери)", + "Pacific\/Fakaofo": "Токелау убактысы (Факаофо)", + "Pacific\/Fiji": "Фижи убактысы (Фижи)", + "Pacific\/Funafuti": "Тувалу убактысы (Фунафути)", + "Pacific\/Galapagos": "Галапагос убактысы (Галапагос)", + "Pacific\/Gambier": "Гамбие убактысы (Гамбие)", + "Pacific\/Guadalcanal": "Соломон аралдарынын убактысы (Гуадалканал)", + "Pacific\/Guam": "Чаморро убактысы (Гуам)", + "Pacific\/Honolulu": "Гавайи-Алеут убактысы (Гонолулу)", + "Pacific\/Johnston": "Гавайи-Алеут убактысы (Жонстон)", + "Pacific\/Kiritimati": "Лайн аралдарынын убактысы (Киритимати)", + "Pacific\/Kosrae": "Косрае убактысы (Козрае)", + "Pacific\/Kwajalein": "Маршалл аралдарынын убактысы (Куажалейн)", + "Pacific\/Majuro": "Маршалл аралдарынын убактысы (Мажуро)", + "Pacific\/Marquesas": "Маркезас убактысы (Маркезас)", + "Pacific\/Midway": "Самоа убактысы (Мидуэй)", + "Pacific\/Nauru": "Науру убактысы (Науру)", + "Pacific\/Niue": "Ниуэ убактысы (Ниуэ)", + "Pacific\/Norfolk": "Норфолк убактысы (Норфолк)", + "Pacific\/Noumea": "Жаңы Каледония убактысы (Нумеа)", + "Pacific\/Pago_Pago": "Самоа убактысы (Паго Паго)", + "Pacific\/Palau": "Палау убактысы (Палау)", + "Pacific\/Pitcairn": "Питкэрнг убактысы (Питкэрн)", + "Pacific\/Ponape": "Понапе убактысы (Понпей)", + "Pacific\/Port_Moresby": "Папуа-Жаңы Гвинея убакыты (Порт Моэрсби)", + "Pacific\/Rarotonga": "Кук аралдарынын убактысы (Раготонга)", + "Pacific\/Saipan": "Чаморро убактысы (Сайпан)", + "Pacific\/Tahiti": "Таити убактысы (Таити)", + "Pacific\/Tarawa": "Гилберт убактысы (Тарава)", + "Pacific\/Tongatapu": "Тонга убактысы (Тонгатапу)", + "Pacific\/Truk": "Чуук убактысы (Чуук)", + "Pacific\/Wake": "Уейк аралдарынын убактысы (Уейк)", + "Pacific\/Wallis": "Уолис жана Футуна убактысы (Уолис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/lb.json b/src/Symfony/Component/Intl/Resources/data/timezones/lb.json new file mode 100644 index 0000000000000..a351fec053c83 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/lb.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "Mëttler Greenwich-Zäit (Abidjan)", + "Africa\/Accra": "Mëttler Greenwich-Zäit (Accra)", + "Africa\/Addis_Ababa": "Ostafrikanesch Zäit (Addis Abeba)", + "Africa\/Algiers": "Mëtteleuropäesch Zäit (Alger)", + "Africa\/Asmera": "Ostafrikanesch Zäit (Asmara)", + "Africa\/Bamako": "Mëttler Greenwich-Zäit (Bamako)", + "Africa\/Bangui": "Westafrikanesch Zäit (Bangui)", + "Africa\/Banjul": "Mëttler Greenwich-Zäit (Banjul)", + "Africa\/Bissau": "Mëttler Greenwich-Zäit (Bissau)", + "Africa\/Blantyre": "Zentralafrikanesch Zäit (Blantyre)", + "Africa\/Brazzaville": "Westafrikanesch Zäit (Brazzaville)", + "Africa\/Bujumbura": "Zentralafrikanesch Zäit (Bujumbura)", + "Africa\/Cairo": "Osteuropäesch Zäit (Kairo)", + "Africa\/Casablanca": "Westeuropäesch Zäit (Casablanca)", + "Africa\/Ceuta": "Mëtteleuropäesch Zäit (Ceuta)", + "Africa\/Conakry": "Mëttler Greenwich-Zäit (Conakry)", + "Africa\/Dakar": "Mëttler Greenwich-Zäit (Dakar)", + "Africa\/Dar_es_Salaam": "Ostafrikanesch Zäit (Dar es Salaam)", + "Africa\/Djibouti": "Ostafrikanesch Zäit (Dschibuti)", + "Africa\/Douala": "Westafrikanesch Zäit (Douala)", + "Africa\/El_Aaiun": "Westeuropäesch Zäit (El Aaiún)", + "Africa\/Freetown": "Mëttler Greenwich-Zäit (Freetown)", + "Africa\/Gaborone": "Zentralafrikanesch Zäit (Gaborone)", + "Africa\/Harare": "Zentralafrikanesch Zäit (Harare)", + "Africa\/Johannesburg": "Südafrikanesch Zäit (Johannesburg)", + "Africa\/Juba": "Ostafrikanesch Zäit (Juba)", + "Africa\/Kampala": "Ostafrikanesch Zäit (Kampala)", + "Africa\/Khartoum": "Zentralafrikanesch Zäit (Khartum)", + "Africa\/Kigali": "Zentralafrikanesch Zäit (Kigali)", + "Africa\/Kinshasa": "Westafrikanesch Zäit (Kinshasa)", + "Africa\/Lagos": "Westafrikanesch Zäit (Lagos)", + "Africa\/Libreville": "Westafrikanesch Zäit (Libreville)", + "Africa\/Lome": "Mëttler Greenwich-Zäit (Lome)", + "Africa\/Luanda": "Westafrikanesch Zäit (Luanda)", + "Africa\/Lubumbashi": "Zentralafrikanesch Zäit (Lubumbashi)", + "Africa\/Lusaka": "Zentralafrikanesch Zäit (Lusaka)", + "Africa\/Malabo": "Westafrikanesch Zäit (Malabo)", + "Africa\/Maputo": "Zentralafrikanesch Zäit (Maputo)", + "Africa\/Maseru": "Südafrikanesch Zäit (Maseru)", + "Africa\/Mbabane": "Südafrikanesch Zäit (Mbabane)", + "Africa\/Mogadishu": "Ostafrikanesch Zäit (Mogadischu)", + "Africa\/Monrovia": "Mëttler Greenwich-Zäit (Monrovia)", + "Africa\/Nairobi": "Ostafrikanesch Zäit (Nairobi)", + "Africa\/Ndjamena": "Westafrikanesch Zäit (Ndjamena)", + "Africa\/Niamey": "Westafrikanesch Zäit (Niamey)", + "Africa\/Nouakchott": "Mëttler Greenwich-Zäit (Nouakchott)", + "Africa\/Ouagadougou": "Mëttler Greenwich-Zäit (Wagadugu)", + "Africa\/Porto-Novo": "Westafrikanesch Zäit (Porto-Novo)", + "Africa\/Sao_Tome": "Mëttler Greenwich-Zäit (São Tomé)", + "Africa\/Tripoli": "Osteuropäesch Zäit (Tripoli)", + "Africa\/Tunis": "Mëtteleuropäesch Zäit (Tunis)", + "Africa\/Windhoek": "Zentralafrikanesch Zäit (Windhoek)", + "America\/Adak": "Hawaii-Aleuten-Zäit (Adak)", + "America\/Anchorage": "Alaska-Zäit (Anchorage)", + "America\/Anguilla": "Atlantik-Zäit (Anguilla)", + "America\/Antigua": "Atlantik-Zäit (Antigua)", + "America\/Araguaina": "Brasília-Zäit (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentinesch Zäit (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinesch Zäit (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinesch Zäit (Salta)", + "America\/Argentina\/San_Juan": "Argentinesch Zäit (San Juan)", + "America\/Argentina\/San_Luis": "Westargentinesch Zäit (San Luis)", + "America\/Argentina\/Tucuman": "Argentinesch Zäit (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentinesch Zäit (Ushuaia)", + "America\/Aruba": "Atlantik-Zäit (Aruba)", + "America\/Asuncion": "Paraguayanesch Zäit (Asunción)", + "America\/Bahia": "Brasília-Zäit (Bahia)", + "America\/Bahia_Banderas": "Nordamerikanesch Inlandzäit (Bahia Banderas)", + "America\/Barbados": "Atlantik-Zäit (Barbados)", + "America\/Belem": "Brasília-Zäit (Belem)", + "America\/Belize": "Nordamerikanesch Inlandzäit (Belize)", + "America\/Blanc-Sablon": "Atlantik-Zäit (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonas-Zäit (Boa Vista)", + "America\/Bogota": "Kolumbianesch Zäit (Bogota)", + "America\/Boise": "Rocky-Mountain-Zäit (Boise)", + "America\/Buenos_Aires": "Argentinesch Zäit (Buenos Aires)", + "America\/Cambridge_Bay": "Rocky-Mountain-Zäit (Cambridge Bay)", + "America\/Campo_Grande": "Amazonas-Zäit (Campo Grande)", + "America\/Cancun": "Nordamerikanesch Ostküstenzäit (Cancun)", + "America\/Caracas": "Venezuela-Zäit (Caracas)", + "America\/Catamarca": "Argentinesch Zäit (Catamarca)", + "America\/Cayenne": "Franséisch-Guayane-Zäit (Cayenne)", + "America\/Cayman": "Nordamerikanesch Ostküstenzäit (Kaimaninselen)", + "America\/Chicago": "Nordamerikanesch Inlandzäit (Chicago)", + "America\/Chihuahua": "Mexikanesch Pazifikzäit (Chihuahua)", + "America\/Coral_Harbour": "Nordamerikanesch Ostküstenzäit (Atikokan)", + "America\/Cordoba": "Argentinesch Zäit (Cordoba)", + "America\/Costa_Rica": "Nordamerikanesch Inlandzäit (Costa Rica)", + "America\/Creston": "Rocky-Mountain-Zäit (Creston)", + "America\/Cuiaba": "Amazonas-Zäit (Cuiaba)", + "America\/Curacao": "Atlantik-Zäit (Curaçao)", + "America\/Danmarkshavn": "Mëttler Greenwich-Zäit (Danmarkshavn)", + "America\/Dawson": "Nordamerikanesch Westküstenzäit (Dawson)", + "America\/Dawson_Creek": "Rocky-Mountain-Zäit (Dawson Creek)", + "America\/Denver": "Rocky-Mountain-Zäit (Denver)", + "America\/Detroit": "Nordamerikanesch Ostküstenzäit (Detroit)", + "America\/Dominica": "Atlantik-Zäit (Dominica)", + "America\/Edmonton": "Rocky-Mountain-Zäit (Edmonton)", + "America\/Eirunepe": "Acre-Zäit (Eirunepe)", + "America\/El_Salvador": "Nordamerikanesch Inlandzäit (Salvador)", + "America\/Fort_Nelson": "Rocky-Mountain-Zäit (Fort Nelson)", + "America\/Fortaleza": "Brasília-Zäit (Fortaleza)", + "America\/Glace_Bay": "Atlantik-Zäit (Glace Bay)", + "America\/Godthab": "Westgrönland-Zäit (Nuuk)", + "America\/Goose_Bay": "Atlantik-Zäit (Goose Bay)", + "America\/Grand_Turk": "Nordamerikanesch Ostküstenzäit (Grand Turk)", + "America\/Grenada": "Atlantik-Zäit (Grenada)", + "America\/Guadeloupe": "Atlantik-Zäit (Guadeloupe)", + "America\/Guatemala": "Nordamerikanesch Inlandzäit (Guatemala)", + "America\/Guayaquil": "Ecuadorianesch Zäit (Guayaquil)", + "America\/Guyana": "Guyana-Zäit (Guyana)", + "America\/Halifax": "Atlantik-Zäit (Halifax)", + "America\/Havana": "Kubanesch Zäit (Havanna)", + "America\/Hermosillo": "Mexikanesch Pazifikzäit (Hermosillo)", + "America\/Indiana\/Knox": "Nordamerikanesch Inlandzäit (Knox, Indiana)", + "America\/Indiana\/Marengo": "Nordamerikanesch Ostküstenzäit (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Nordamerikanesch Ostküstenzäit (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Nordamerikanesch Inlandzäit (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Nordamerikanesch Ostküstenzäit (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Nordamerikanesch Ostküstenzäit (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Nordamerikanesch Ostküstenzäit (Winamac, Indiana)", + "America\/Indianapolis": "Nordamerikanesch Ostküstenzäit (Indianapolis)", + "America\/Inuvik": "Rocky-Mountain-Zäit (Inuvik)", + "America\/Iqaluit": "Nordamerikanesch Ostküstenzäit (Iqaluit)", + "America\/Jamaica": "Nordamerikanesch Ostküstenzäit (Jamaika)", + "America\/Jujuy": "Argentinesch Zäit (Jujuy)", + "America\/Juneau": "Alaska-Zäit (Juneau)", + "America\/Kentucky\/Monticello": "Nordamerikanesch Ostküstenzäit (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantik-Zäit (Kralendijk)", + "America\/La_Paz": "Bolivianesch Zäit (La Paz)", + "America\/Lima": "Peruanesch Zäit (Lima)", + "America\/Los_Angeles": "Nordamerikanesch Westküstenzäit (Los Angeles)", + "America\/Louisville": "Nordamerikanesch Ostküstenzäit (Louisville)", + "America\/Lower_Princes": "Atlantik-Zäit (Lower Prince’s Quarter)", + "America\/Maceio": "Brasília-Zäit (Maceio)", + "America\/Managua": "Nordamerikanesch Inlandzäit (Managua)", + "America\/Manaus": "Amazonas-Zäit (Manaus)", + "America\/Marigot": "Atlantik-Zäit (Marigot)", + "America\/Martinique": "Atlantik-Zäit (Martinique)", + "America\/Matamoros": "Nordamerikanesch Inlandzäit (Matamoros)", + "America\/Mazatlan": "Mexikanesch Pazifikzäit (Mazatlan)", + "America\/Mendoza": "Argentinesch Zäit (Mendoza)", + "America\/Menominee": "Nordamerikanesch Inlandzäit (Menominee)", + "America\/Merida": "Nordamerikanesch Inlandzäit (Merida)", + "America\/Metlakatla": "Alaska-Zäit (Metlakatla)", + "America\/Mexico_City": "Nordamerikanesch Inlandzäit (Mexiko-Stad)", + "America\/Miquelon": "Saint-Pierre-a-Miquelon-Zäit (Miquelon)", + "America\/Moncton": "Atlantik-Zäit (Moncton)", + "America\/Monterrey": "Nordamerikanesch Inlandzäit (Monterrey)", + "America\/Montevideo": "Uruguayanesch Zäit (Montevideo)", + "America\/Montserrat": "Atlantik-Zäit (Montserrat)", + "America\/Nassau": "Nordamerikanesch Ostküstenzäit (Nassau)", + "America\/New_York": "Nordamerikanesch Ostküstenzäit (New York)", + "America\/Nipigon": "Nordamerikanesch Ostküstenzäit (Nipigon)", + "America\/Nome": "Alaska-Zäit (Nome)", + "America\/Noronha": "Fernando-de-Noronha-Zäit (Noronha)", + "America\/North_Dakota\/Beulah": "Nordamerikanesch Inlandzäit (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Nordamerikanesch Inlandzäit (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Nordamerikanesch Inlandzäit (New Salem, North Dakota)", + "America\/Ojinaga": "Rocky-Mountain-Zäit (Ojinaga)", + "America\/Panama": "Nordamerikanesch Ostküstenzäit (Panama)", + "America\/Pangnirtung": "Nordamerikanesch Ostküstenzäit (Pangnirtung)", + "America\/Paramaribo": "Suriname-Zäit (Paramaribo)", + "America\/Phoenix": "Rocky-Mountain-Zäit (Phoenix)", + "America\/Port-au-Prince": "Nordamerikanesch Ostküstenzäit (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantik-Zäit (Port-of-Spain)", + "America\/Porto_Velho": "Amazonas-Zäit (Porto Velho)", + "America\/Puerto_Rico": "Atlantik-Zäit (Puerto Rico)", + "America\/Punta_Arenas": "Chilenesch Zäit (Punta Arenas)", + "America\/Rainy_River": "Nordamerikanesch Inlandzäit (Rainy River)", + "America\/Rankin_Inlet": "Nordamerikanesch Inlandzäit (Rankin Inlet)", + "America\/Recife": "Brasília-Zäit (Recife)", + "America\/Regina": "Nordamerikanesch Inlandzäit (Regina)", + "America\/Resolute": "Nordamerikanesch Inlandzäit (Resolute)", + "America\/Rio_Branco": "Acre-Zäit (Rio Branco)", + "America\/Santa_Isabel": "Nordwest-Mexiko-Zäit (Santa Isabel)", + "America\/Santarem": "Brasília-Zäit (Santarem)", + "America\/Santiago": "Chilenesch Zäit (Santiago)", + "America\/Santo_Domingo": "Atlantik-Zäit (Santo Domingo)", + "America\/Sao_Paulo": "Brasília-Zäit (Sao Paulo)", + "America\/Scoresbysund": "Ostgrönland-Zäit (Ittoqqortoormiit)", + "America\/Sitka": "Alaska-Zäit (Sitka)", + "America\/St_Barthelemy": "Atlantik-Zäit (Saint-Barthélemy)", + "America\/St_Johns": "Neifundland-Zäit (St. John’s)", + "America\/St_Kitts": "Atlantik-Zäit (St. Kitts)", + "America\/St_Lucia": "Atlantik-Zäit (St. Lucia)", + "America\/St_Thomas": "Atlantik-Zäit (St. Thomas)", + "America\/St_Vincent": "Atlantik-Zäit (St. Vincent)", + "America\/Swift_Current": "Nordamerikanesch Inlandzäit (Swift Current)", + "America\/Tegucigalpa": "Nordamerikanesch Inlandzäit (Tegucigalpa)", + "America\/Thule": "Atlantik-Zäit (Thule)", + "America\/Thunder_Bay": "Nordamerikanesch Ostküstenzäit (Thunder Bay)", + "America\/Tijuana": "Nordamerikanesch Westküstenzäit (Tijuana)", + "America\/Toronto": "Nordamerikanesch Ostküstenzäit (Toronto)", + "America\/Tortola": "Atlantik-Zäit (Tortola)", + "America\/Vancouver": "Nordamerikanesch Westküstenzäit (Vancouver)", + "America\/Whitehorse": "Nordamerikanesch Westküstenzäit (Whitehorse)", + "America\/Winnipeg": "Nordamerikanesch Inlandzäit (Winnipeg)", + "America\/Yakutat": "Alaska-Zäit (Yakutat)", + "America\/Yellowknife": "Rocky-Mountain-Zäit (Yellowknife)", + "Antarctica\/Casey": "Westaustralesch Zäit (Casey)", + "Antarctica\/Davis": "Davis-Zäit (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville-Zäit (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarieinsel-Zäit (Macquarie)", + "Antarctica\/Mawson": "Mawson-Zäit (Mawson)", + "Antarctica\/McMurdo": "Neiséiland-Zäit (McMurdo)", + "Antarctica\/Palmer": "Chilenesch Zäit (Palmer)", + "Antarctica\/Rothera": "Rothera-Zäit (Rothera)", + "Antarctica\/Syowa": "Syowa-Zäit (Syowa)", + "Antarctica\/Troll": "Mëttler Greenwich-Zäit (Troll)", + "Antarctica\/Vostok": "Wostok-Zäit (Wostok)", + "Arctic\/Longyearbyen": "Mëtteleuropäesch Zäit (Longyearbyen)", + "Asia\/Aden": "Arabesch Zäit (Aden)", + "Asia\/Almaty": "Ostkasachesch Zäit (Almaty)", + "Asia\/Amman": "Osteuropäesch Zäit (Amman)", + "Asia\/Anadyr": "Anadyr-Zäit (Anadyr)", + "Asia\/Aqtau": "Westkasachesch Zäit (Aqtau)", + "Asia\/Aqtobe": "Westkasachesch Zäit (Aqtöbe)", + "Asia\/Ashgabat": "Turkmenistan-Zäit (Ashgabat)", + "Asia\/Atyrau": "Westkasachesch Zäit (Atyrau)", + "Asia\/Baghdad": "Arabesch Zäit (Bagdad)", + "Asia\/Bahrain": "Arabesch Zäit (Bahrain)", + "Asia\/Baku": "Aserbaidschanesch Zäit (Baku)", + "Asia\/Bangkok": "Indochina-Zäit (Bangkok)", + "Asia\/Beirut": "Osteuropäesch Zäit (Beirut)", + "Asia\/Bishkek": "Kirgisistan-Zäit (Bischkek)", + "Asia\/Brunei": "Brunei-Zäit (Brunei)", + "Asia\/Calcutta": "Indesch Zäit (Kalkutta)", + "Asia\/Chita": "Jakutsk-Zäit (Chita)", + "Asia\/Choibalsan": "Choibalsan-Zäit (Choibalsan)", + "Asia\/Colombo": "Indesch Zäit (Colombo)", + "Asia\/Damascus": "Osteuropäesch Zäit (Damaskus)", + "Asia\/Dhaka": "Bangladesch-Zäit (Dhaka)", + "Asia\/Dili": "Osttimor-Zäit (Dili)", + "Asia\/Dubai": "Golf-Zäit (Dubai)", + "Asia\/Dushanbe": "Tadschikistan-Zäit (Duschanbe)", + "Asia\/Famagusta": "Osteuropäesch Zäit (Famagusta)", + "Asia\/Gaza": "Osteuropäesch Zäit (Gaza)", + "Asia\/Hebron": "Osteuropäesch Zäit (Hebron)", + "Asia\/Hong_Kong": "Hong-Kong-Zäit (Hong Kong)", + "Asia\/Hovd": "Hovd-Zäit (Hovd)", + "Asia\/Irkutsk": "Irkutsk-Zäit (Irkutsk)", + "Asia\/Jakarta": "Westindonesesch Zäit (Jakarta)", + "Asia\/Jayapura": "Ostindonesesch Zäit (Port Numbay)", + "Asia\/Jerusalem": "Israelesch Zäit (Jerusalem)", + "Asia\/Kabul": "Afghanistan-Zäit (Kabul)", + "Asia\/Kamchatka": "Kamtschatka-Zäit (Kamtschatka)", + "Asia\/Karachi": "Pakistanesch Zäit (Karachi)", + "Asia\/Katmandu": "Nepalesesch Zäit (Kathmandu)", + "Asia\/Khandyga": "Jakutsk-Zäit (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk-Zäit (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malaysesch Zäit (Kuala Lumpur)", + "Asia\/Kuching": "Malaysesch Zäit (Kuching)", + "Asia\/Kuwait": "Arabesch Zäit (Kuwait)", + "Asia\/Macau": "Chinesesch Zäit (Macau)", + "Asia\/Magadan": "Magadan-Zäit (Magadan)", + "Asia\/Makassar": "Zentralindonesesch Zäit (Makassar)", + "Asia\/Manila": "Philippinnesch Zäit (Manila)", + "Asia\/Muscat": "Golf-Zäit (Muskat)", + "Asia\/Nicosia": "Osteuropäesch Zäit (Nikosia)", + "Asia\/Novokuznetsk": "Krasnojarsk-Zäit (Novokuznetsk)", + "Asia\/Novosibirsk": "Nowosibirsk-Zäit (Nowosibirsk)", + "Asia\/Omsk": "Omsk-Zäit (Omsk)", + "Asia\/Oral": "Westkasachesch Zäit (Oral)", + "Asia\/Phnom_Penh": "Indochina-Zäit (Phnom Penh)", + "Asia\/Pontianak": "Westindonesesch Zäit (Pontianak)", + "Asia\/Pyongyang": "Koreanesch Zäit (Pjöngjang)", + "Asia\/Qatar": "Arabesch Zäit (Katar)", + "Asia\/Qostanay": "Ostkasachesch Zäit (Qostanay)", + "Asia\/Qyzylorda": "Westkasachesch Zäit (Qyzylorda)", + "Asia\/Rangoon": "Myanmar-Zäit (Yangon)", + "Asia\/Riyadh": "Arabesch Zäit (Riad)", + "Asia\/Saigon": "Indochina-Zäit (Ho-Chi-Minh-Stad)", + "Asia\/Sakhalin": "Sakhalin-Zäit (Sachalin)", + "Asia\/Samarkand": "Usbekistan-Zäit (Samarkand)", + "Asia\/Seoul": "Koreanesch Zäit (Seoul)", + "Asia\/Shanghai": "Chinesesch Zäit (Shanghai)", + "Asia\/Singapore": "Singapur-Standardzäit (Singapur)", + "Asia\/Srednekolymsk": "Magadan-Zäit (Srednekolymsk)", + "Asia\/Taipei": "Taipei-Zäit (Taipeh)", + "Asia\/Tashkent": "Usbekistan-Zäit (Taschkent)", + "Asia\/Tbilisi": "Georgesch Zäit (Tiflis)", + "Asia\/Tehran": "Iranesch Zäit (Teheran)", + "Asia\/Thimphu": "Bhutan-Zäit (Thimphu)", + "Asia\/Tokyo": "Japanesch Zäit (Tokio)", + "Asia\/Ulaanbaatar": "Ulaanbaatar-Zäit (Ulaanbaatar)", + "Asia\/Ust-Nera": "Wladiwostok-Zäit (Ust-Nera)", + "Asia\/Vientiane": "Indochina-Zäit (Vientiane)", + "Asia\/Vladivostok": "Wladiwostok-Zäit (Wladiwostok)", + "Asia\/Yakutsk": "Jakutsk-Zäit (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinbuerg-Zäit (Jekaterinbuerg)", + "Asia\/Yerevan": "Armenesch Zäit (Erivan)", + "Atlantic\/Azores": "Azoren-Zäit (Azoren)", + "Atlantic\/Bermuda": "Atlantik-Zäit (Bermudas)", + "Atlantic\/Canary": "Westeuropäesch Zäit (Kanaresch Inselen)", + "Atlantic\/Cape_Verde": "Kap-Verde-Zäit (Kap Verde)", + "Atlantic\/Faeroe": "Westeuropäesch Zäit (Färöer)", + "Atlantic\/Madeira": "Westeuropäesch Zäit (Madeira)", + "Atlantic\/Reykjavik": "Mëttler Greenwich-Zäit (Reykjavik)", + "Atlantic\/South_Georgia": "Südgeorgesch Zäit (Südgeorgien)", + "Atlantic\/St_Helena": "Mëttler Greenwich-Zäit (St. Helena)", + "Atlantic\/Stanley": "Falklandinselen-Zäit (Stanley)", + "Australia\/Adelaide": "Zentralaustralesch Zäit (Adelaide)", + "Australia\/Brisbane": "Ostaustralesch Zäit (Brisbane)", + "Australia\/Broken_Hill": "Zentralaustralesch Zäit (Broken Hill)", + "Australia\/Currie": "Ostaustralesch Zäit (Currie)", + "Australia\/Darwin": "Zentralaustralesch Zäit (Darwin)", + "Australia\/Eucla": "Zentral-\/Westaustralesch Zäit (Eucla)", + "Australia\/Hobart": "Ostaustralesch Zäit (Hobart)", + "Australia\/Lindeman": "Ostaustralesch Zäit (Lindeman)", + "Australia\/Lord_Howe": "Lord-Howe-Zäit (Lord Howe)", + "Australia\/Melbourne": "Ostaustralesch Zäit (Melbourne)", + "Australia\/Perth": "Westaustralesch Zäit (Perth)", + "Australia\/Sydney": "Ostaustralesch Zäit (Sydney)", + "CST6CDT": "Nordamerikanesch Inlandzäit", + "EST5EDT": "Nordamerikanesch Ostküstenzäit", + "Etc\/GMT": "Mëttler Greenwich-Zäit", + "Europe\/Amsterdam": "Mëtteleuropäesch Zäit (Amsterdam)", + "Europe\/Andorra": "Mëtteleuropäesch Zäit (Andorra)", + "Europe\/Astrakhan": "Moskauer Zäit (Astrakhan)", + "Europe\/Athens": "Osteuropäesch Zäit (Athen)", + "Europe\/Belgrade": "Mëtteleuropäesch Zäit (Belgrad)", + "Europe\/Berlin": "Mëtteleuropäesch Zäit (Berlin)", + "Europe\/Bratislava": "Mëtteleuropäesch Zäit (Bratislava)", + "Europe\/Brussels": "Mëtteleuropäesch Zäit (Bréissel)", + "Europe\/Bucharest": "Osteuropäesch Zäit (Bukarest)", + "Europe\/Budapest": "Mëtteleuropäesch Zäit (Budapest)", + "Europe\/Busingen": "Mëtteleuropäesch Zäit (Busingen)", + "Europe\/Chisinau": "Osteuropäesch Zäit (Kischinau)", + "Europe\/Copenhagen": "Mëtteleuropäesch Zäit (Kopenhagen)", + "Europe\/Dublin": "Mëttler Greenwich-Zäit (Dublin)", + "Europe\/Gibraltar": "Mëtteleuropäesch Zäit (Gibraltar)", + "Europe\/Guernsey": "Mëttler Greenwich-Zäit (Guernsey)", + "Europe\/Helsinki": "Osteuropäesch Zäit (Helsinki)", + "Europe\/Isle_of_Man": "Mëttler Greenwich-Zäit (Isle of Man)", + "Europe\/Jersey": "Mëttler Greenwich-Zäit (Jersey)", + "Europe\/Kaliningrad": "Osteuropäesch Zäit (Kaliningrad)", + "Europe\/Kiev": "Osteuropäesch Zäit (Kiew)", + "Europe\/Lisbon": "Westeuropäesch Zäit (Lissabon)", + "Europe\/Ljubljana": "Mëtteleuropäesch Zäit (Ljubljana)", + "Europe\/London": "Mëttler Greenwich-Zäit (London)", + "Europe\/Luxembourg": "Mëtteleuropäesch Zäit (Lëtzebuerg)", + "Europe\/Madrid": "Mëtteleuropäesch Zäit (Madrid)", + "Europe\/Malta": "Mëtteleuropäesch Zäit (Malta)", + "Europe\/Mariehamn": "Osteuropäesch Zäit (Mariehamn)", + "Europe\/Minsk": "Moskauer Zäit (Minsk)", + "Europe\/Monaco": "Mëtteleuropäesch Zäit (Monaco)", + "Europe\/Moscow": "Moskauer Zäit (Moskau)", + "Europe\/Oslo": "Mëtteleuropäesch Zäit (Oslo)", + "Europe\/Paris": "Mëtteleuropäesch Zäit (Paris)", + "Europe\/Podgorica": "Mëtteleuropäesch Zäit (Podgorica)", + "Europe\/Prague": "Mëtteleuropäesch Zäit (Prag)", + "Europe\/Riga": "Osteuropäesch Zäit (Riga)", + "Europe\/Rome": "Mëtteleuropäesch Zäit (Roum)", + "Europe\/Samara": "Samara-Zäit (Samara)", + "Europe\/San_Marino": "Mëtteleuropäesch Zäit (San Marino)", + "Europe\/Sarajevo": "Mëtteleuropäesch Zäit (Sarajevo)", + "Europe\/Saratov": "Moskauer Zäit (Saratov)", + "Europe\/Simferopol": "Moskauer Zäit (Simferopol)", + "Europe\/Skopje": "Mëtteleuropäesch Zäit (Skopje)", + "Europe\/Sofia": "Osteuropäesch Zäit (Sofia)", + "Europe\/Stockholm": "Mëtteleuropäesch Zäit (Stockholm)", + "Europe\/Tallinn": "Osteuropäesch Zäit (Tallinn)", + "Europe\/Tirane": "Mëtteleuropäesch Zäit (Tirana)", + "Europe\/Ulyanovsk": "Moskauer Zäit (Ulyanovsk)", + "Europe\/Uzhgorod": "Osteuropäesch Zäit (Uschgorod)", + "Europe\/Vaduz": "Mëtteleuropäesch Zäit (Vaduz)", + "Europe\/Vatican": "Mëtteleuropäesch Zäit (Vatikan)", + "Europe\/Vienna": "Mëtteleuropäesch Zäit (Wien)", + "Europe\/Vilnius": "Osteuropäesch Zäit (Wilna)", + "Europe\/Volgograd": "Wolgograd-Zäit (Wolgograd)", + "Europe\/Warsaw": "Mëtteleuropäesch Zäit (Warschau)", + "Europe\/Zagreb": "Mëtteleuropäesch Zäit (Zagreb)", + "Europe\/Zaporozhye": "Osteuropäesch Zäit (Saporischschja)", + "Europe\/Zurich": "Mëtteleuropäesch Zäit (Zürech)", + "Indian\/Antananarivo": "Ostafrikanesch Zäit (Antananarivo)", + "Indian\/Chagos": "Indeschen Ozean-Zäit (Chagos)", + "Indian\/Christmas": "Chrëschtdagsinsel-Zäit (Chrëschtdagsinsel)", + "Indian\/Cocos": "Kokosinselen-Zäit (Cocos)", + "Indian\/Comoro": "Ostafrikanesch Zäit (Komoren)", + "Indian\/Kerguelen": "Franséisch Süd- an Antarktisgebidder-Zäit (Kerguelen)", + "Indian\/Mahe": "Seychellen-Zäit (Mahe)", + "Indian\/Maldives": "Maldiven-Zäit (Maldiven)", + "Indian\/Mauritius": "Mauritius-Zäit (Mauritius)", + "Indian\/Mayotte": "Ostafrikanesch Zäit (Mayotte)", + "Indian\/Reunion": "Réunion-Zäit (Réunion)", + "MST7MDT": "Rocky-Mountain-Zäit", + "PST8PDT": "Nordamerikanesch Westküstenzäit", + "Pacific\/Auckland": "Neiséiland-Zäit (Auckland)", + "Pacific\/Bougainville": "Papua-Neiguinea-Zäit (Bougainville)", + "Pacific\/Chatham": "Chatham-Zäit (Chatham)", + "Pacific\/Easter": "Ouschterinsel-Zäit (Ouschterinsel)", + "Pacific\/Efate": "Vanuatu-Zäit (Efate)", + "Pacific\/Enderbury": "Phoenixinselen-Zäit (Enderbury)", + "Pacific\/Fakaofo": "Tokelau-Zäit (Fakaofo)", + "Pacific\/Fiji": "Fidschi-Zäit (Fidschi)", + "Pacific\/Funafuti": "Tuvalu-Zäit (Funafuti)", + "Pacific\/Galapagos": "Galapagos-Zäit (Galapagos)", + "Pacific\/Gambier": "Gambier-Zäit (Gambier)", + "Pacific\/Guadalcanal": "Salomoninselen-Zäit (Guadalcanal)", + "Pacific\/Guam": "Chamorro-Zäit (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleuten-Zäit (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleuten-Zäit (Johnston)", + "Pacific\/Kiritimati": "Linneninselen-Zäit (Kiritimati)", + "Pacific\/Kosrae": "Kosrae-Zäit (Kosrae)", + "Pacific\/Kwajalein": "Marshallinselen-Zäit (Kwajalein)", + "Pacific\/Majuro": "Marshallinselen-Zäit (Majuro)", + "Pacific\/Marquesas": "Marquesas-Zäit (Marquesas)", + "Pacific\/Midway": "Samoa-Zäit (Midway)", + "Pacific\/Nauru": "Nauru-Zäit (Nauru)", + "Pacific\/Niue": "Niue-Zäit (Niue)", + "Pacific\/Norfolk": "Norfolkinselen-Zäit (Norfolk)", + "Pacific\/Noumea": "Neikaledonesch Zäit (Noumea)", + "Pacific\/Pago_Pago": "Samoa-Zäit (Pago Pago)", + "Pacific\/Palau": "Palau-Zäit (Palau)", + "Pacific\/Pitcairn": "Pitcairninselen-Zäit (Pitcairn)", + "Pacific\/Ponape": "Ponape-Zäit (Pohnpei)", + "Pacific\/Port_Moresby": "Papua-Neiguinea-Zäit (Port Moresby)", + "Pacific\/Rarotonga": "Cookinselen-Zäit (Rarotonga)", + "Pacific\/Saipan": "Chamorro-Zäit (Saipan)", + "Pacific\/Tahiti": "Tahiti-Zäit (Tahiti)", + "Pacific\/Tarawa": "Gilbert-Inselen-Zäit (Tarawa)", + "Pacific\/Tongatapu": "Tonganesch Zäit (Tongatapu)", + "Pacific\/Truk": "Chuuk-Zäit (Chuuk)", + "Pacific\/Wake": "Wake-Insel-Zäit (Wake)", + "Pacific\/Wallis": "Wallis-a-Futuna-Zäit (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ln.json b/src/Symfony/Component/Intl/Resources/data/timezones/ln.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ln.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/lo.json b/src/Symfony/Component/Intl/Resources/data/timezones/lo.json new file mode 100644 index 0000000000000..af59bf41a1620 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/lo.json @@ -0,0 +1,430 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ເວ​ລາກຣີນ​ວິ​ຊ (ອາບິດແຈນ)", + "Africa\/Accra": "ເວ​ລາກຣີນ​ວິ​ຊ (ອັກຄຣາ)", + "Africa\/Addis_Ababa": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ແອດດິສ ອະບາບາ)", + "Africa\/Algiers": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ແອວເຈຍ)", + "Africa\/Asmera": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ອັສມາຣາ)", + "Africa\/Bamako": "ເວ​ລາກຣີນ​ວິ​ຊ (ບາມາໂກ)", + "Africa\/Bangui": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ບັງກຸຍ)", + "Africa\/Banjul": "ເວ​ລາກຣີນ​ວິ​ຊ (ບານຈູ)", + "Africa\/Bissau": "ເວ​ລາກຣີນ​ວິ​ຊ (ບິສເຊົາ)", + "Africa\/Blantyre": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ແບລນໄທຣ໌)", + "Africa\/Brazzaville": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ບຣາຊາວິວ)", + "Africa\/Bujumbura": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ບູຈູມບູຣາ)", + "Africa\/Cairo": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ໄຄໂຣ)", + "Africa\/Casablanca": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ຕົກ (ຄາຊາບລັງກາ)", + "Africa\/Ceuta": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ຊີວຕາ)", + "Africa\/Conakry": "ເວ​ລາກຣີນ​ວິ​ຊ (ໂຄນາຄຣີ)", + "Africa\/Dakar": "ເວ​ລາກຣີນ​ວິ​ຊ (ດາກາ)", + "Africa\/Dar_es_Salaam": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ດາເອສສະລາມ)", + "Africa\/Djibouti": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ຈີບູຕິ)", + "Africa\/Douala": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ດູອາລາ)", + "Africa\/El_Aaiun": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ຕົກ (ເອວ ອາຢູນ)", + "Africa\/Freetown": "ເວ​ລາກຣີນ​ວິ​ຊ (ຟຣີທາວ)", + "Africa\/Gaborone": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ກາບໍໂຣນ)", + "Africa\/Harare": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ຮາຣາເຣ)", + "Africa\/Johannesburg": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ໃຕ້ (ໂຈຮັນເນດສເບີກ)", + "Africa\/Juba": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ຈູບາ)", + "Africa\/Kampala": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ຄຳປາລາ)", + "Africa\/Khartoum": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ຄາທູມ)", + "Africa\/Kigali": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ຄີກາລີ)", + "Africa\/Kinshasa": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ກິນຊາຊາ)", + "Africa\/Lagos": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ລາໂກສ)", + "Africa\/Libreville": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ລິເບຼີວິວ)", + "Africa\/Lome": "ເວ​ລາກຣີນ​ວິ​ຊ (ໂລເມ)", + "Africa\/Luanda": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ລວນດາ)", + "Africa\/Lubumbashi": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ລູບຳບາຊິ)", + "Africa\/Lusaka": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ລູຊາກາ)", + "Africa\/Malabo": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ມາລາໂບ)", + "Africa\/Maputo": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ມາປູໂຕ)", + "Africa\/Maseru": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ໃຕ້ (ມາເຊຣູ)", + "Africa\/Mbabane": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ໃຕ້ (ອຳບາບາເນ)", + "Africa\/Mogadishu": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ໂມກາດີຊູ)", + "Africa\/Monrovia": "ເວ​ລາກຣີນ​ວິ​ຊ (ມອນໂຣເວຍ)", + "Africa\/Nairobi": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ໄນໂຣບີ)", + "Africa\/Ndjamena": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ເອນຈາເມນ່າ)", + "Africa\/Niamey": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ນີອາເມ)", + "Africa\/Nouakchott": "ເວ​ລາກຣີນ​ວິ​ຊ (ນູແອກຊອດ)", + "Africa\/Ouagadougou": "ເວ​ລາກຣີນ​ວິ​ຊ (ອູກາດູກູ)", + "Africa\/Porto-Novo": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ຕົກ (ປໍໂຕ-ໂນໂວ)", + "Africa\/Sao_Tome": "ເວ​ລາກຣີນ​ວິ​ຊ (ຊາວໂຕເມ)", + "Africa\/Tripoli": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ທຣິໂພລິ)", + "Africa\/Tunis": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ຕູນິສ)", + "Africa\/Windhoek": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ກາງ (ວີນຮູດ)", + "America\/Adak": "ເວລາຮາວາຍ-ເອລູທຽນ (ອາແດກ)", + "America\/Anchorage": "ເວລາອະແລສກາ (ແອນເຄີເຣກ)", + "America\/Anguilla": "ເວລາຂອງອາແລນຕິກ (ແອນກິນລາ)", + "America\/Antigua": "ເວລາຂອງອາແລນຕິກ (ແອນທິກົວ)", + "America\/Araguaina": "ເວລາຕາມເຂດບຣາຊິເລຍ (ອາຣາກົວນາ)", + "America\/Argentina\/La_Rioja": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ລາ ຣິໂອຈາ)", + "America\/Argentina\/Rio_Gallegos": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ຣິໂກ ແກວເລກອສ)", + "America\/Argentina\/Salta": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ຊານຕາ)", + "America\/Argentina\/San_Juan": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ແຊນຮວນ)", + "America\/Argentina\/San_Luis": "ເວ​ລາ​ເວ​ສ​ເທິນອາ​ເຈນ​ທິ​ນາ (ແຊນລຸຍສ໌)", + "America\/Argentina\/Tucuman": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ຕູຄູແມນ)", + "America\/Argentina\/Ushuaia": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ອູຊູເອຍ)", + "America\/Aruba": "ເວລາຂອງອາແລນຕິກ (ອາຣູບາ)", + "America\/Asuncion": "ເວ​ລາ​ປາ​ຣາ​ກວຍ (ອະຊຸນຊິອອງ)", + "America\/Bahia": "ເວລາຕາມເຂດບຣາຊິເລຍ (ບາເຢຍ)", + "America\/Bahia_Banderas": "ເວລາກາງ (ບາເຮຍ ແບນເດີຣາສ)", + "America\/Barbados": "ເວລາຂອງອາແລນຕິກ (ບາເບດອສ)", + "America\/Belem": "ເວລາຕາມເຂດບຣາຊິເລຍ (ບີເລມ)", + "America\/Belize": "ເວລາກາງ (ເບລີຊ)", + "America\/Blanc-Sablon": "ເວລາຂອງອາແລນຕິກ (ບລານ-ຊາບລອນ)", + "America\/Boa_Vista": "ເວລາຕາມເຂດອາເມຊອນ (ບົວ ວິສຕາ)", + "America\/Bogota": "ເວລາໂຄລໍາເບຍ (ໂບໂກຕາ)", + "America\/Boise": "ເວລາແຖບພູເຂົາ (ບອຍຊ໌)", + "America\/Buenos_Aires": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ບົວໂນສ ໄອເຣສ)", + "America\/Cambridge_Bay": "ເວລາແຖບພູເຂົາ (ແຄມບຣິດ ເບ)", + "America\/Campo_Grande": "ເວລາຕາມເຂດອາເມຊອນ (ກັງປູຣັງຈີ)", + "America\/Cancun": "ເວລາຕາເວັນອອກ (ແຄນກຸນ)", + "America\/Caracas": "ເວ​ລາ​ເວ​ເນ​ຊູ​ເອ​ລາ (ຄາຣາກັສ)", + "America\/Catamarca": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ຄາຕາມາກາ)", + "America\/Cayenne": "ເວ​ລາ​ເຟ​ຣນ​ຊ໌​ເກຍ​ນາ (ຄາເຢນ)", + "America\/Cayman": "ເວລາຕາເວັນອອກ (ເຄແມນ)", + "America\/Chicago": "ເວລາກາງ (ຊິຄາໂກ)", + "America\/Chihuahua": "ເວລາແປຊິຟິກເມັກຊິກັນ (ຊິວາວາ)", + "America\/Coral_Harbour": "ເວລາຕາເວັນອອກ (ອາທິໂຄຄານ)", + "America\/Cordoba": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ຄໍໂດບາ)", + "America\/Costa_Rica": "ເວລາກາງ (ຄອສຕາຣິກາ)", + "America\/Creston": "ເວລາແຖບພູເຂົາ (ເຄຣສຕັນ)", + "America\/Cuiaba": "ເວລາຕາມເຂດອາເມຊອນ (ກຸຢາບາ)", + "America\/Curacao": "ເວລາຂອງອາແລນຕິກ (ກືຣາເຊົາ)", + "America\/Danmarkshavn": "ເວ​ລາກຣີນ​ວິ​ຊ (ເດນມາກແຊນ)", + "America\/Dawson": "ເວລາແປຊິຟິກ (ດໍສັນ)", + "America\/Dawson_Creek": "ເວລາແຖບພູເຂົາ (ດໍສັນ ຄຣີກ)", + "America\/Denver": "ເວລາແຖບພູເຂົາ (ເດັນເວີ)", + "America\/Detroit": "ເວລາຕາເວັນອອກ (ດີທຣອຍ)", + "America\/Dominica": "ເວລາຂອງອາແລນຕິກ (ໂດມິນິກາ)", + "America\/Edmonton": "ເວລາແຖບພູເຂົາ (ເອດມອນຕອນ)", + "America\/Eirunepe": "ເວລາຂອງອາເກຣ (ເອຣຸເນປີ)", + "America\/El_Salvador": "ເວລາກາງ (ເອວ ຊາວາດໍ)", + "America\/Fort_Nelson": "ເວລາແຖບພູເຂົາ (ຟອດ ເນວສັນ)", + "America\/Fortaleza": "ເວລາຕາມເຂດບຣາຊິເລຍ (ຟໍຕາເລຊາ)", + "America\/Glace_Bay": "ເວລາຂອງອາແລນຕິກ (ເກລດເບ)", + "America\/Godthab": "ເວລາກຣີນແລນຕາເວັນຕົກ (ນູກ)", + "America\/Goose_Bay": "ເວລາຂອງອາແລນຕິກ (ກູສເບ)", + "America\/Grand_Turk": "ເວລາຕາເວັນອອກ (ແກຣນ ເທີກ)", + "America\/Grenada": "ເວລາຂອງອາແລນຕິກ (ເກຣນາດາ)", + "America\/Guadeloupe": "ເວລາຂອງອາແລນຕິກ (ກາວເດລູບ)", + "America\/Guatemala": "ເວລາກາງ (ກົວເຕມາລາ)", + "America\/Guayaquil": "ເວ​ລາ​ເອ​ກົວ​ດໍ (ກົວຢາກິລ)", + "America\/Guyana": "ເວລາກາຍອານາ (ກູຢານາ)", + "America\/Halifax": "ເວລາຂອງອາແລນຕິກ (ຮາລິແຟັກ)", + "America\/Havana": "ເວລາຄິວບາ (ຮາວານາ)", + "America\/Hermosillo": "ເວລາແປຊິຟິກເມັກຊິກັນ (ເອໂມຊິໂຢ)", + "America\/Indiana\/Knox": "ເວລາກາງ (ນ໋ອກ, ອິນເດຍນາ)", + "America\/Indiana\/Marengo": "ເວລາຕາເວັນອອກ (ມາເຣນໂກ, ອິນເດຍນາ)", + "America\/Indiana\/Petersburg": "ເວລາຕາເວັນອອກ (ປີເຕີສເປີກ, ອິນເດຍນາ)", + "America\/Indiana\/Tell_City": "ເວລາກາງ (ເທວ ຊິຕີ, ອິນເດຍນາ)", + "America\/Indiana\/Vevay": "ເວລາຕາເວັນອອກ (ວີເວ, ອິນເດຍນາ)", + "America\/Indiana\/Vincennes": "ເວລາຕາເວັນອອກ (ວິນເຊນເນສ, ອິນເດຍນາ)", + "America\/Indiana\/Winamac": "ເວລາຕາເວັນອອກ (ວິນາແມັກ, ອິນເດຍນາ)", + "America\/Indianapolis": "ເວລາຕາເວັນອອກ (ອິນດີເອນາໂພລິສ)", + "America\/Inuvik": "ເວລາແຖບພູເຂົາ (ອີນູວິກ)", + "America\/Iqaluit": "ເວລາຕາເວັນອອກ (ອີກົວລິດ)", + "America\/Jamaica": "ເວລາຕາເວັນອອກ (ຈາໄມກາ)", + "America\/Jujuy": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ຈູຈຸຍ)", + "America\/Juneau": "ເວລາອະແລສກາ (ຈູໂນ)", + "America\/Kentucky\/Monticello": "ເວລາຕາເວັນອອກ (ມອນຕີເຊວໂລ, ເຄນທັກກີ)", + "America\/Kralendijk": "ເວລາຂອງອາແລນຕິກ (ຄຣາເລນດິກ)", + "America\/La_Paz": "ເວ​ລາ​ໂບ​ລິ​ເວຍ (ລາປາສ)", + "America\/Lima": "ເວ​ລາ​ເປ​ຣູ (ລີມາ)", + "America\/Los_Angeles": "ເວລາແປຊິຟິກ (ລອສ ແອນເຈລີສ)", + "America\/Louisville": "ເວລາຕາເວັນອອກ (ຫລຸຍວິວ)", + "America\/Lower_Princes": "ເວລາຂອງອາແລນຕິກ (ໂລເວີ ພຣິນຊ໌ ຄວດເຕີ)", + "America\/Maceio": "ເວລາຕາມເຂດບຣາຊິເລຍ (ມາເຊໂອ)", + "America\/Managua": "ເວລາກາງ (ມານາກົວ)", + "America\/Manaus": "ເວລາຕາມເຂດອາເມຊອນ (ມາເນົາສ໌)", + "America\/Marigot": "ເວລາຂອງອາແລນຕິກ (ມາຣີໂກດ)", + "America\/Martinique": "ເວລາຂອງອາແລນຕິກ (ມາທີນິກ)", + "America\/Matamoros": "ເວລາກາງ (ມາຕາໂມຣອສ)", + "America\/Mazatlan": "ເວລາແປຊິຟິກເມັກຊິກັນ (ມາຊາດລານ)", + "America\/Mendoza": "ເວ​ລາ​ອາ​ເຈ​ທິ​ນາ (ເມັນໂດຊ່າ)", + "America\/Menominee": "ເວລາກາງ (ເມໂນມິນີ)", + "America\/Merida": "ເວລາກາງ (ເມີຣິດາ)", + "America\/Metlakatla": "ເວລາອະແລສກາ (ເມັດລາກັດລາ)", + "America\/Mexico_City": "ເວລາກາງ (ເມັກຊິໂກ ຊິຕີ)", + "America\/Miquelon": "​ເວ​ລາເຊນ​ປີ​ແອ ແລະ​ມິ​ກົວ​ລອນ (ມິກົວລອນ)", + "America\/Moncton": "ເວລາຂອງອາແລນຕິກ (ມອນຕັນ)", + "America\/Monterrey": "ເວລາກາງ (ມອນເຕີເຣຍ)", + "America\/Montevideo": "​ເວ​ລາ​ອູ​ຣູ​ກວຍ (ມອນເຕວິເດໂອ)", + "America\/Montserrat": "ເວລາຂອງອາແລນຕິກ (ມອນເຊີຣັດ)", + "America\/Nassau": "ເວລາຕາເວັນອອກ (ແນສຊໍ)", + "America\/New_York": "ເວລາຕາເວັນອອກ (ນິວຢອກ)", + "America\/Nipigon": "ເວລາຕາເວັນອອກ (ນີປີກອນ)", + "America\/Nome": "ເວລາອະແລສກາ (ນອມ)", + "America\/Noronha": "ເວລາເຟນັນໂດເດໂນຮອນຮາ (ນໍຣອນຮາ)", + "America\/North_Dakota\/Beulah": "ເວລາກາງ (ເບີລາ, ນອດ ດາໂກຕາ)", + "America\/North_Dakota\/Center": "ເວລາກາງ (ເຊັນເຈີ, ນອດ ດາໂກຕາ)", + "America\/North_Dakota\/New_Salem": "ເວລາກາງ (ນິວ ຊາເລມ, ນອດ ດາໂກຕາ)", + "America\/Ojinaga": "ເວລາແຖບພູເຂົາ (ໂອຈິນາກາ)", + "America\/Panama": "ເວລາຕາເວັນອອກ (ພານາມາ)", + "America\/Pangnirtung": "ເວລາຕາເວັນອອກ (ແພງເນີດທັງ)", + "America\/Paramaribo": "ເວ​ລາ​ຊຸ​ຣິ​ນາມ (ພາຣາມາຣິໂບ)", + "America\/Phoenix": "ເວລາແຖບພູເຂົາ (ຟິນິກ)", + "America\/Port-au-Prince": "ເວລາຕາເວັນອອກ (ປໍໂຕແປຣງ)", + "America\/Port_of_Spain": "ເວລາຂອງອາແລນຕິກ (ພອດອອບສະເປນ)", + "America\/Porto_Velho": "ເວລາຕາມເຂດອາເມຊອນ (ປໍຕູ ເວວຢູ)", + "America\/Puerto_Rico": "ເວລາຂອງອາແລນຕິກ (ເປີໂທຣິໂກ)", + "America\/Punta_Arenas": "ເວ​ລາ​ຊິ​ລີ (ພຸນທາ ອະຣີນາສ໌)", + "America\/Rainy_River": "ເວລາກາງ (ເຣນນີ ຣິເວີ)", + "America\/Rankin_Inlet": "ເວລາກາງ (ແຣນກິນ ອິນເລັດ)", + "America\/Recife": "ເວລາຕາມເຂດບຣາຊິເລຍ (ເຣຊິເຟ)", + "America\/Regina": "ເວລາກາງ (ເຣຈິນາ)", + "America\/Resolute": "ເວລາກາງ (ເຣໂຊລຸດ)", + "America\/Rio_Branco": "ເວລາຂອງອາເກຣ (ຣິໂອ ບຣັນໂກ)", + "America\/Santa_Isabel": "​ເວ​ລາ​ນອດ​ເວ​ສ​ເມັກ​ຊິ​ໂກ (ຊານຕາ ອິດຊາເບວ)", + "America\/Santarem": "ເວລາຕາມເຂດບຣາຊິເລຍ (ຊັນຕາເຣມ)", + "America\/Santiago": "ເວ​ລາ​ຊິ​ລີ (ຊັນຕີອາໂກ)", + "America\/Santo_Domingo": "ເວລາຂອງອາແລນຕິກ (ຊານໂຕໂດມິນໂກ)", + "America\/Sao_Paulo": "ເວລາຕາມເຂດບຣາຊິເລຍ (ເຊົາ ເປົາໂລ)", + "America\/Scoresbysund": "ເວລາຕາເວັນອອກຂອງກຣີນແລນ (ອິໂຕຄໍທົວມິດ)", + "America\/Sitka": "ເວລາອະແລສກາ (ຊິດກາ)", + "America\/St_Barthelemy": "ເວລາຂອງອາແລນຕິກ (ເຊນບາເທເລມີ)", + "America\/St_Johns": "ເວ​ລາ​ນິວ​ຟາວ​ແລນ (ເຊນ ຈອນ)", + "America\/St_Kitts": "ເວລາຂອງອາແລນຕິກ (ເຊນ ຄິດສ໌)", + "America\/St_Lucia": "ເວລາຂອງອາແລນຕິກ (ເຊນ ລູເຊຍ)", + "America\/St_Thomas": "ເວລາຂອງອາແລນຕິກ (ເຊນ ໂທມັສ)", + "America\/St_Vincent": "ເວລາຂອງອາແລນຕິກ (ເຊນ ວິນເຊນ)", + "America\/Swift_Current": "ເວລາກາງ (ສະວິວ ເຄີເຣນ)", + "America\/Tegucigalpa": "ເວລາກາງ (ເຕກູຊີການປາ)", + "America\/Thule": "ເວລາຂອງອາແລນຕິກ (ທູເລ)", + "America\/Thunder_Bay": "ເວລາຕາເວັນອອກ (ທັນເດີເບ)", + "America\/Tijuana": "ເວລາແປຊິຟິກ (ທີຈົວນາ)", + "America\/Toronto": "ເວລາຕາເວັນອອກ (ໂທຣອນໂຕ)", + "America\/Tortola": "ເວລາຂອງອາແລນຕິກ (ທໍໂຕລາ)", + "America\/Vancouver": "ເວລາແປຊິຟິກ (ແວນຄູເວີ)", + "America\/Whitehorse": "ເວລາແປຊິຟິກ (ໄວທ໌ຮອສ)", + "America\/Winnipeg": "ເວລາກາງ (ວິນນີເພກ)", + "America\/Yakutat": "ເວລາອະແລສກາ (ຢາຄູຕັດ)", + "America\/Yellowknife": "ເວລາແຖບພູເຂົາ (ເຢໂລໄນຟ໌)", + "Antarctica\/Casey": "ເວ​ລາ​ອອສ​ເຕຣ​ເລຍ​ຕາ​ເວັນ​ຕົກ (ເຄຊີ)", + "Antarctica\/Davis": "ເວລາເດວິດ (ດາວີສ)", + "Antarctica\/DumontDUrville": "ເວລາດູມອງດູວິລ (ດູມອນດີຍູວີວສ໌)", + "Antarctica\/Macquarie": "ເວ​ລາ​ເກາະ​ແມັກ​ຄົວ​ຣີ (ແມັກຄົວຣີ)", + "Antarctica\/Mawson": "ເວລາມໍສັນ (ເມົາຊັນ)", + "Antarctica\/McMurdo": "ເວ​ລາ​ນິວ​ຊີ​ແລນ (ແມັກມົວໂດ)", + "Antarctica\/Palmer": "ເວ​ລາ​ຊິ​ລີ (ພາມເມີ)", + "Antarctica\/Rothera": "ເວລາ ໂຣທີຕາ (ໂຣເທຣາ)", + "Antarctica\/Syowa": "ເວລາ ໂຊວາ (ເຊຍວາ)", + "Antarctica\/Troll": "ເວ​ລາກຣີນ​ວິ​ຊ (ໂທຣລ໌)", + "Antarctica\/Vostok": "ເວລາ ວອສໂຕກ (ວໍສະຕອກ)", + "Arctic\/Longyearbyen": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ລອງເຢຍບຽນ)", + "Asia\/Aden": "ເວ​ລາ​ອາ​ຣາ​ບຽນ (ເອເດັນ)", + "Asia\/Almaty": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ອອກ (ອໍມາຕີ)", + "Asia\/Amman": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ອຳມານ)", + "Asia\/Aqtau": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ຕົກ (ອັດຕາອູ)", + "Asia\/Aqtobe": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ຕົກ (ອັດໂທບີ)", + "Asia\/Ashgabat": "ເວລາຕວກເມນິສຖານ (ອາດຊ໌ກາບັດ)", + "Asia\/Atyrau": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ຕົກ (ອັດທີເຣົາ)", + "Asia\/Baghdad": "ເວ​ລາ​ອາ​ຣາ​ບຽນ (ແບກແດດ)", + "Asia\/Bahrain": "ເວ​ລາ​ອາ​ຣາ​ບຽນ (ບາເຣນ)", + "Asia\/Baku": "ເວລາອັສເຊີໄບຈັນ (ບາກູ)", + "Asia\/Bangkok": "ເວລາອິນດູຈີນ (ບາງກອກ)", + "Asia\/Beirut": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ເບຣຸດ)", + "Asia\/Bishkek": "ເວລາເຄຍກິສຖານ (ບິດຊ໌ເຄກ)", + "Asia\/Brunei": "​ເວ​ລາບຣູ​ໄນດາ​ຣຸສ​ຊາ​ລາມ (ບຣູໄນ)", + "Asia\/Calcutta": "ເວລາ ອິນເດຍ (ໂຄກາຕາ)", + "Asia\/Chita": "ເວລາຢາກູດສ (ຊີຕ່າ)", + "Asia\/Choibalsan": "ເວ​ລາ​ໂຊຍ​ບາ​ຊັນ (ຊອຍບອລຊານ)", + "Asia\/Colombo": "ເວລາ ອິນເດຍ (ໂຄລຳໂບ)", + "Asia\/Damascus": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ດາມາສຄັສ)", + "Asia\/Dhaka": "ເວລາ ບັງກະລາເທດ (ດາຫ໌ກາ)", + "Asia\/Dili": "ເວລາຕີມໍຕາເວັນອອກ (ດີລີ)", + "Asia\/Dubai": "ເວ​ລາ​ກູ​ລ​໌ຟ (ດູໄບ)", + "Asia\/Dushanbe": "ເວລາທາຈິກິສຖານ (ດູຊານເບ)", + "Asia\/Famagusta": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ຟາມາກັສທາ)", + "Asia\/Gaza": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ກາຊາ)", + "Asia\/Hebron": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ເຮບຣອນ)", + "Asia\/Hong_Kong": "ເວ​ລາ​ຮອງ​ກົງ (ຮ່ອງກົງ)", + "Asia\/Hovd": "ເວ​ລາ​ຮອບ​ດ໌ (ຮອບ)", + "Asia\/Irkutsk": "ເວ​ລ​າອີ​ຄຸດ​ສ​ຄ໌ (ອີຄຸສຄ໌)", + "Asia\/Jakarta": "ເວ​ລາ​ອິນ​ໂດ​ເນ​ເຊຍ​ຕາ​ເວັນ​ຕົກ (ຈາກາຕາ)", + "Asia\/Jayapura": "ເວ​ລາ​ອິນ​ໂດ​ເນ​ເຊຍ​ຕາ​ເວັນ​ອອກ (ຈາຢາປູຣະ)", + "Asia\/Jerusalem": "ເວ​ລາ​ອິ​ສ​ຣາ​ເອວ (ເຢຣູຊາເລມ)", + "Asia\/Kabul": "ເວລາ ອັຟການິສຖານ (ຄາບູ)", + "Asia\/Karachi": "ເວ​ລາ​ປາ​ກີສຖານ (ກາຣາຈີ)", + "Asia\/Katmandu": "​ເວ​ລາ​ເນ​ປານ (ຄັດມັນດູ)", + "Asia\/Khandyga": "ເວລາຢາກູດສ (ແຄນດີກາ)", + "Asia\/Krasnoyarsk": "ເວ​ລາ​ຄຣັສ​ໂນ​ຢາ​ສ​ຄ໌ (ຄຣັສໂນຢາສຄ໌)", + "Asia\/Kuala_Lumpur": "ເວ​ລາ​ມາ​ເລ​ເຊຍ (ກົວລາລຳເປີ)", + "Asia\/Kuching": "ເວ​ລາ​ມາ​ເລ​ເຊຍ (ກູຊີງ)", + "Asia\/Kuwait": "ເວ​ລາ​ອາ​ຣາ​ບຽນ (ຄູເວດ)", + "Asia\/Macau": "ເວ​ລາ​ຈີນ (ມາເກົາ)", + "Asia\/Magadan": "ເວລາເມັກກາເດນ (ມາກາແດນ)", + "Asia\/Makassar": "ເວ​ລາ​ອິນ​ໂດ​ເນ​ເຊຍ​ກາງ (ມາກາສຊາ)", + "Asia\/Manila": "​ເວ​ລາ​ຟິ​ລິບ​ປິນ (ມານີລາ)", + "Asia\/Muscat": "ເວ​ລາ​ກູ​ລ​໌ຟ (ມາສຄັດ)", + "Asia\/Nicosia": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ນິໂຄເຊຍ)", + "Asia\/Novokuznetsk": "ເວ​ລາ​ຄຣັສ​ໂນ​ຢາ​ສ​ຄ໌ (ໂນໂວຄຸສເນັດ)", + "Asia\/Novosibirsk": "ເວ​ລາ​ໂນ​ໂບ​ຊິ​ບິ​ສ​ຄ໌ (ໂນໂວຊີບີສຄ໌)", + "Asia\/Omsk": "​ເວ​ລາອອມ​ສ​ຄ໌ (ອອມສຄ໌)", + "Asia\/Oral": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ຕົກ (ອໍຣໍ)", + "Asia\/Phnom_Penh": "ເວລາອິນດູຈີນ (ພະນົມເປັນ)", + "Asia\/Pontianak": "ເວ​ລາ​ອິນ​ໂດ​ເນ​ເຊຍ​ຕາ​ເວັນ​ຕົກ (ພອນເທຍນັກ)", + "Asia\/Pyongyang": "ເວລາເກົາຫຼີ (ປຽງຢາງ)", + "Asia\/Qatar": "ເວ​ລາ​ອາ​ຣາ​ບຽນ (ກາຕາຣ໌)", + "Asia\/Qostanay": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ອອກ (Qostanay)", + "Asia\/Qyzylorda": "ເວ​ລາ​ຄາ​ຊັກ​ສ​ຖານ​ຕາ​ເວັນ​ຕົກ (ໄຄຊີລໍດາ)", + "Asia\/Rangoon": "ເວລາມຽນມາ (ຢາງກອນ)", + "Asia\/Riyadh": "ເວ​ລາ​ອາ​ຣາ​ບຽນ (ຣີຢາດ)", + "Asia\/Saigon": "ເວລາອິນດູຈີນ (ໂຮຈິມິນ)", + "Asia\/Sakhalin": "ເວ​ລາ​ຊາ​ຮາ​ລິນ (ຊາຄາລິນ)", + "Asia\/Samarkand": "ເວລາອຸສເບກິດສະຖານ (ຊາມາແຄນ)", + "Asia\/Seoul": "ເວລາເກົາຫຼີ (ໂຊລ໌)", + "Asia\/Shanghai": "ເວ​ລາ​ຈີນ (ຊ່ຽງໄຮ້)", + "Asia\/Singapore": "ເວ​ລາ​ສິງ​ກະ​ໂປ (ສິງກະໂປ)", + "Asia\/Srednekolymsk": "ເວລາເມັກກາເດນ (ສຣິລເນັກໂກລີດ)", + "Asia\/Taipei": "ເວ​ລາ​ໄທ​ເປ (ໄທເປ)", + "Asia\/Tashkent": "ເວລາອຸສເບກິດສະຖານ (ທາດສ໌ເຄນ)", + "Asia\/Tbilisi": "ເວລາຈໍເຈຍ (ທິບີລີຊີ)", + "Asia\/Tehran": "ເວ​ລາ​ອີ​ຣານ (ເຕຣານ)", + "Asia\/Thimphu": "ເວ​ລາ​ພູ​ຖານ (ທິມພູ)", + "Asia\/Tokyo": "ເວ​ລາ​ຍີ່​ປຸ່ນ (ໂຕກຽວ)", + "Asia\/Ulaanbaatar": "ເວລາ ອູລານບາເຕີ (ອູລານບາຕາຣ໌)", + "Asia\/Ust-Nera": "ເວລາລາດີໂວສຕົກ (ອຸສ ເນຣາ)", + "Asia\/Vientiane": "ເວລາອິນດູຈີນ (ວຽງຈັນ)", + "Asia\/Vladivostok": "ເວລາລາດີໂວສຕົກ (ວີລາດິໂວສຕອກ)", + "Asia\/Yakutsk": "ເວລາຢາກູດສ (ຢາຄຸທຊ໌)", + "Asia\/Yekaterinburg": "ເວລາເຢກາເຕລິນເບີກ (ເຢຄາເຕີຣິນເບີກ)", + "Asia\/Yerevan": "ເວລາອາເມເນຍ (ເຍເຣວານ)", + "Atlantic\/Azores": "ເວ​ລາ​ອາ​ໂຊ​ເຣ​ສ (ອາຊໍເຣສ)", + "Atlantic\/Bermuda": "ເວລາຂອງອາແລນຕິກ (ເບີມິວດາ)", + "Atlantic\/Canary": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ຕົກ (ຄານາຣີ)", + "Atlantic\/Cape_Verde": "ເວ​ລາ​ເຄບ​ເວີດ (ເຄບເວີດ)", + "Atlantic\/Faeroe": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ຕົກ (ແຟໂຣ)", + "Atlantic\/Madeira": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ຕົກ (ມາເດຣາ)", + "Atlantic\/Reykjavik": "ເວ​ລາກຣີນ​ວິ​ຊ (ເຣກຢາວິກ)", + "Atlantic\/South_Georgia": "ເວລາຈໍເຈຍໃຕ້ (ເຊົາຈໍເຈຍ)", + "Atlantic\/St_Helena": "ເວ​ລາກຣີນ​ວິ​ຊ (ເຊນ ເຮເລນາ)", + "Atlantic\/Stanley": "​ເວ​ລາ​ໝູ່​ເກາະ​ຟອ​ລ໌ກ​ແລນ (ສະແຕນເລ)", + "Australia\/Adelaide": "ເວ​ລາອອ​ສ​ເຕຣ​ເລຍ​ກາງ (ເອດີແລດ)", + "Australia\/Brisbane": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ຕາ​ເວັນ​ອອກ (ບຣິສເບນ)", + "Australia\/Broken_Hill": "ເວ​ລາອອ​ສ​ເຕຣ​ເລຍ​ກາງ (ໂບຣກເຄນ ຮິວ)", + "Australia\/Currie": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ຕາ​ເວັນ​ອອກ (ກູຣີ)", + "Australia\/Darwin": "ເວ​ລາອອ​ສ​ເຕຣ​ເລຍ​ກາງ (ດາວິນ)", + "Australia\/Eucla": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ກາງ​ຕາ​ເວັນ​ຕົກ (ຢູຄລາ)", + "Australia\/Hobart": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ຕາ​ເວັນ​ອອກ (ໂຮບາດ)", + "Australia\/Lindeman": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ຕາ​ເວັນ​ອອກ (ລິນດີແມນ)", + "Australia\/Lord_Howe": "ເວ​ລາ​ລອດ​ເຮົາ (ໂລດໂຮວີ)", + "Australia\/Melbourne": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ຕາ​ເວັນ​ອອກ (ເມວເບິນ)", + "Australia\/Perth": "ເວ​ລາ​ອອສ​ເຕຣ​ເລຍ​ຕາ​ເວັນ​ຕົກ (ເພີດ)", + "Australia\/Sydney": "ເວ​ລາອອສ​ເຕຣ​ລຽນ​ຕາ​ເວັນ​ອອກ (ຊິດນີ)", + "CST6CDT": "ເວລາກາງ", + "EST5EDT": "ເວລາຕາເວັນອອກ", + "Etc\/GMT": "ເວ​ລາກຣີນ​ວິ​ຊ", + "Etc\/UTC": "ເວລາສາກົນເຊີງພິກັດ", + "Europe\/Amsterdam": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ອາມສເຕີດຳ)", + "Europe\/Andorra": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ອິນດໍຣາ)", + "Europe\/Astrakhan": "ເວ​ລາ​ມອ​ສ​ໂຄ (ອາສຕຣາຄານ)", + "Europe\/Athens": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ເອເທນສ໌)", + "Europe\/Belgrade": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ເບວເກຣດ)", + "Europe\/Berlin": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ເບີລິນ)", + "Europe\/Bratislava": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ບຣາທິສລາວາ)", + "Europe\/Brussels": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ບຣັສເຊວ)", + "Europe\/Bucharest": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ບູຄາເຣສຕ໌)", + "Europe\/Budapest": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ບູດາເປສຕ໌)", + "Europe\/Busingen": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ບັດຊິນເກນ)", + "Europe\/Chisinau": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ຄີຊີເນົາ)", + "Europe\/Copenhagen": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ໂຄເປນເຮເກນ)", + "Europe\/Dublin": "ເວ​ລາກຣີນ​ວິ​ຊ (ດັບບລິນ)", + "Europe\/Gibraltar": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ກິບຣອລທາ)", + "Europe\/Guernsey": "ເວ​ລາກຣີນ​ວິ​ຊ (ເກີນຊີ)", + "Europe\/Helsinki": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ເຮວຊິນກິ)", + "Europe\/Isle_of_Man": "ເວ​ລາກຣີນ​ວິ​ຊ (ເກາະແມນ)", + "Europe\/Jersey": "ເວ​ລາກຣີນ​ວິ​ຊ (ເຈີຊີ)", + "Europe\/Kaliningrad": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ຄາລິນິນກຣາດ)", + "Europe\/Kiev": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ຂຽບ)", + "Europe\/Lisbon": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ຕົກ (ລິສບອນ)", + "Europe\/Ljubljana": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ລູບລີຍານາ)", + "Europe\/London": "ເວ​ລາກຣີນ​ວິ​ຊ (ລອນດອນ)", + "Europe\/Luxembourg": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ລັກເຊັມເບີກ)", + "Europe\/Madrid": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ມາດຣິດ)", + "Europe\/Malta": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ມອລຕາ)", + "Europe\/Mariehamn": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ມາຣີແຮມນ໌)", + "Europe\/Minsk": "ເວ​ລາ​ມອ​ສ​ໂຄ (ມິນສກ໌)", + "Europe\/Monaco": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ໂມນາໂຄ)", + "Europe\/Moscow": "ເວ​ລາ​ມອ​ສ​ໂຄ (ມອສໂຄ)", + "Europe\/Oslo": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ອອສໂລ)", + "Europe\/Paris": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ປາຣີສ)", + "Europe\/Podgorica": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ພອດກໍຣີກາ)", + "Europe\/Prague": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ປຣາກ)", + "Europe\/Riga": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ຣິກາ)", + "Europe\/Rome": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ໂຣມ)", + "Europe\/San_Marino": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ຊານມາຣີໂນ)", + "Europe\/Sarajevo": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ຊາຣາເຢໂວ)", + "Europe\/Saratov": "ເວ​ລາ​ມອ​ສ​ໂຄ (ຊາຣາທອບ)", + "Europe\/Simferopol": "ເວ​ລາ​ມອ​ສ​ໂຄ (ຊີມເຟໂລໂປ)", + "Europe\/Skopje": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ສະໂກເປຍ)", + "Europe\/Sofia": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ໂຊເຟຍ)", + "Europe\/Stockholm": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ສະຕອກໂຮມ)", + "Europe\/Tallinn": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ທາລລິນນ໌)", + "Europe\/Tirane": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ທິຣານ)", + "Europe\/Ulyanovsk": "ເວ​ລາ​ມອ​ສ​ໂຄ (ອູລີອານອບສຄ໌)", + "Europe\/Uzhgorod": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ອັສຊ໌ກໍໂຣດ)", + "Europe\/Vaduz": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ວາດາຊ)", + "Europe\/Vatican": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ວາຕິກັນ)", + "Europe\/Vienna": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ວຽນນາ)", + "Europe\/Vilnius": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ວິລນິອຸສ)", + "Europe\/Volgograd": "ເວລາໂວໂກກຣາດ (ວອລໂກກຣາດ)", + "Europe\/Warsaw": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ວໍຊໍ)", + "Europe\/Zagreb": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ຊາເກຣບ)", + "Europe\/Zaporozhye": "ເວ​ລາ​ຢູ​ໂຣບ​ຕາ​ເວັນ​ອອກ (ຊາໂປໂຣຊີ)", + "Europe\/Zurich": "ເວ​ລາ​ຢູ​ໂຣບ​ກາງ (ຊູຣິກ)", + "Indian\/Antananarivo": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ອັນຕານານາຣິໂວ)", + "Indian\/Chagos": "ເວລາຫມະຫາສະຫມຸດອິນເດຍ (ຊາໂກສ)", + "Indian\/Christmas": "ເວ​ລາ​ເກາະ​ຄ​ຣິສ​ມາສ (ຄຣິດສະມາດ)", + "Indian\/Cocos": "ເວລາຫມູ່ເກາະໂກໂກສ (ໂຄໂຄສ)", + "Indian\/Comoro": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ໂຄໂມໂຣ)", + "Indian\/Kerguelen": "ເວລາຝຣັ່ງຕອນໃຕ້ ແລະ ແອນຕາກຕິກ (ແກເກີເລນ)", + "Indian\/Mahe": "ເວ​ລາ​ເຊ​ເຊ​ລ​ສ໌ (ມາເຮ)", + "Indian\/Maldives": "ເວລາມັນດີຟ (ມັລດີບ)", + "Indian\/Mauritius": "ເວ​ລາ​ເມົາ​ຣິ​ທຽ​ສ (ເມົາຣິທຽສ)", + "Indian\/Mayotte": "ເວ​ລາ​ອາ​ຟຣິ​ກາ​ຕາ​ເວັນ​ອອກ (ມາຢັອດເຕ)", + "Indian\/Reunion": "ເວ​ລາ​ເຣ​ອູ​ນິ​ຢົງ (ເຣອູນິຢົງ)", + "MST7MDT": "ເວລາແຖບພູເຂົາ", + "PST8PDT": "ເວລາແປຊິຟິກ", + "Pacific\/Apia": "ເວລາເອເພຍ (ເອປີອາ)", + "Pacific\/Auckland": "ເວ​ລາ​ນິວ​ຊີ​ແລນ (ອັກແລນ)", + "Pacific\/Bougainville": "ເວລາປາປົວກິນີ (ເວລາຕາມເຂດບູນກຽນວິວ)", + "Pacific\/Chatham": "ເວ​ລາ​ຊາ​ທາມ (ແຊແທມ)", + "Pacific\/Easter": "ເວ​ລາ​ເກາະ​ອີ​ສ​ເຕີ (ເອສເຕີ)", + "Pacific\/Efate": "ເວລາວານູອາຕູ (ເອຟາເຕ)", + "Pacific\/Enderbury": "ເວລາຫມູ່ເກາະຟີນິກ (ເອັນເດີເບີລີ)", + "Pacific\/Fakaofo": "ເວລາໂຕເກເລົາ (ຟາກາວໂຟ)", + "Pacific\/Fiji": "ເວລາຟິຈິ (ຟູຈິ)", + "Pacific\/Funafuti": "ເວລາຕູວາລູ (ຟູນະຟູຕິ)", + "Pacific\/Galapagos": "ເວ​ລາ​ກາ​ລາ​ປາ​ກອ​ສ (ກາລາປາກອສ)", + "Pacific\/Gambier": "ເວລາແກມເບຍ (ແກມເບຍ)", + "Pacific\/Guadalcanal": "ເວລາຫມູ່ເກາະໂຊໂລມອນ (ກົວດັລຄະແນລ)", + "Pacific\/Guam": "ເວ​ລາ​ຈາ​ໂມ​ໂຣ (ກວມ)", + "Pacific\/Honolulu": "ເວລາຮາວາຍ-ເອລູທຽນ (ໂຮໂນລູລູ)", + "Pacific\/Johnston": "ເວລາຮາວາຍ-ເອລູທຽນ (ຈອນສະໂຕນ)", + "Pacific\/Kiritimati": "ເວ​ລາ​ໝູ່​ເກາະ​ລາຍ (ຄີຣິທີມາຕີ)", + "Pacific\/Kosrae": "ເວລາຄອສແຣ (ຄໍສແຣ)", + "Pacific\/Kwajalein": "ເວ​ລາ​ໝູ່​ເກາະ​ມາ​ແຊວ (ຄວາຈາເລນ)", + "Pacific\/Majuro": "ເວ​ລາ​ໝູ່​ເກາະ​ມາ​ແຊວ (ມາຈູໂຣ)", + "Pacific\/Marquesas": "ເວລາມາເຄີຊັສ (ມາຄິວຊາສ)", + "Pacific\/Midway": "ເວລາຊາມົວ (ມິດເວ)", + "Pacific\/Nauru": "ເວ​ລາ​ນາ​ອູ​ຣຸ (ນາອູຣູ)", + "Pacific\/Niue": "ເວລານິອູເອ (ນີອູເອ)", + "Pacific\/Norfolk": "ເວ​ລາ​ເກາະ​ນໍ​ຟອ​ລ໌ກ (ນໍຟອລ໌ກ)", + "Pacific\/Noumea": "ເວລານິວແຄລິໂດເນຍ (ນູເມອາ)", + "Pacific\/Pago_Pago": "ເວລາຊາມົວ (ປາໂກປາໂກ)", + "Pacific\/Palau": "ເວລາປາເລົາ (ປາເລົາ)", + "Pacific\/Pitcairn": "ເວລາພິດແຄຣ໌ນ (ພິດແຄນ)", + "Pacific\/Ponape": "ເວລາໂປເນບ (ປົນເປີຍ)", + "Pacific\/Port_Moresby": "ເວລາປາປົວກິນີ (ພອດ ມໍເຣສບີ)", + "Pacific\/Rarotonga": "ເວລາຫມູ່ເກາະຄຸກ (ຣາໂຣຕອງກາ)", + "Pacific\/Saipan": "ເວ​ລາ​ຈາ​ໂມ​ໂຣ (ໄຊປານ)", + "Pacific\/Tahiti": "ເວລາທາຮິຕິ (ທາຮີຕິ)", + "Pacific\/Tarawa": "ເວລາຫມູ່ເກາະກິລເບີດ (ຕາຣາວາ)", + "Pacific\/Tongatapu": "ເວລາຕອງກາ (ຕອງກາຕາປູ)", + "Pacific\/Truk": "ເວລາຊຸກ (ຈັກ)", + "Pacific\/Wake": "ເວລາເກາະເວກ (ເວກ)", + "Pacific\/Wallis": "ເວລາວາລລິສ ແລະ ຟູຕູນາ (ວາລິດ)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/lt.json b/src/Symfony/Component/Intl/Resources/data/timezones/lt.json new file mode 100644 index 0000000000000..45a337709fa17 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/lt.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Grinvičo laikas (Abidžanas)", + "Africa\/Accra": "Grinvičo laikas (Akra)", + "Africa\/Addis_Ababa": "Rytų Afrikos laikas (Adis Abeba)", + "Africa\/Algiers": "Vidurio Europos laikas (Alžyras)", + "Africa\/Asmera": "Rytų Afrikos laikas (Asmara)", + "Africa\/Bamako": "Grinvičo laikas (Bamakas)", + "Africa\/Bangui": "Vakarų Afrikos laikas (Bangis)", + "Africa\/Banjul": "Grinvičo laikas (Bandžulis)", + "Africa\/Bissau": "Grinvičo laikas (Bisau)", + "Africa\/Blantyre": "Centrinės Afrikos laikas (Blantairas)", + "Africa\/Brazzaville": "Vakarų Afrikos laikas (Brazavilis)", + "Africa\/Bujumbura": "Centrinės Afrikos laikas (Bužumbūra)", + "Africa\/Cairo": "Rytų Europos laikas (Kairas)", + "Africa\/Casablanca": "Vakarų Europos laikas (Kasablanka)", + "Africa\/Ceuta": "Vidurio Europos laikas (Seuta)", + "Africa\/Conakry": "Grinvičo laikas (Konakris)", + "Africa\/Dakar": "Grinvičo laikas (Dakaras)", + "Africa\/Dar_es_Salaam": "Rytų Afrikos laikas (Dar es Salamas)", + "Africa\/Djibouti": "Rytų Afrikos laikas (Džibutis)", + "Africa\/Douala": "Vakarų Afrikos laikas (Duala)", + "Africa\/El_Aaiun": "Vakarų Europos laikas (al Ajūnas)", + "Africa\/Freetown": "Grinvičo laikas (Fritaunas)", + "Africa\/Gaborone": "Centrinės Afrikos laikas (Gaboronas)", + "Africa\/Harare": "Centrinės Afrikos laikas (Hararė)", + "Africa\/Johannesburg": "Pietų Afrikos laikas (Johanesburgas)", + "Africa\/Juba": "Rytų Afrikos laikas (Džuba)", + "Africa\/Kampala": "Rytų Afrikos laikas (Kampala)", + "Africa\/Khartoum": "Centrinės Afrikos laikas (Chartumas)", + "Africa\/Kigali": "Centrinės Afrikos laikas (Kigalis)", + "Africa\/Kinshasa": "Vakarų Afrikos laikas (Kinšasa)", + "Africa\/Lagos": "Vakarų Afrikos laikas (Lagosas)", + "Africa\/Libreville": "Vakarų Afrikos laikas (Librevilis)", + "Africa\/Lome": "Grinvičo laikas (Lomė)", + "Africa\/Luanda": "Vakarų Afrikos laikas (Luanda)", + "Africa\/Lubumbashi": "Centrinės Afrikos laikas (Lubumbašis)", + "Africa\/Lusaka": "Centrinės Afrikos laikas (Lusaka)", + "Africa\/Malabo": "Vakarų Afrikos laikas (Malabas)", + "Africa\/Maputo": "Centrinės Afrikos laikas (Maputas)", + "Africa\/Maseru": "Pietų Afrikos laikas (Maseru)", + "Africa\/Mbabane": "Pietų Afrikos laikas (Mbabanė)", + "Africa\/Mogadishu": "Rytų Afrikos laikas (Mogadišas)", + "Africa\/Monrovia": "Grinvičo laikas (Monrovija)", + "Africa\/Nairobi": "Rytų Afrikos laikas (Nairobis)", + "Africa\/Ndjamena": "Vakarų Afrikos laikas (Ndžamena)", + "Africa\/Niamey": "Vakarų Afrikos laikas (Niamėjus)", + "Africa\/Nouakchott": "Grinvičo laikas (Nuakšotas)", + "Africa\/Ouagadougou": "Grinvičo laikas (Vagadugu)", + "Africa\/Porto-Novo": "Vakarų Afrikos laikas (Porto Novas)", + "Africa\/Sao_Tome": "Grinvičo laikas (San Tomė)", + "Africa\/Tripoli": "Rytų Europos laikas (Tripolis)", + "Africa\/Tunis": "Vidurio Europos laikas (Tunisas)", + "Africa\/Windhoek": "Centrinės Afrikos laikas (Vindhukas)", + "America\/Adak": "Havajų-Aleutų laikas (Eidakas)", + "America\/Anchorage": "Aliaskos laikas (Ankoridžas)", + "America\/Anguilla": "Atlanto laikas (Angilija)", + "America\/Antigua": "Atlanto laikas (Antigva)", + "America\/Araguaina": "Brazilijos laikas (Aragvajana)", + "America\/Argentina\/La_Rioja": "Argentinos laikas (La Riocha)", + "America\/Argentina\/Rio_Gallegos": "Argentinos laikas (Rio Galjegosas)", + "America\/Argentina\/Salta": "Argentinos laikas (Saltas)", + "America\/Argentina\/San_Juan": "Argentinos laikas (San Chuanas)", + "America\/Argentina\/San_Luis": "Vakarų Argentinos laikas (Sent Luisas)", + "America\/Argentina\/Tucuman": "Argentinos laikas (Tukumanas)", + "America\/Argentina\/Ushuaia": "Argentinos laikas (Ušuaja)", + "America\/Aruba": "Atlanto laikas (Aruba)", + "America\/Asuncion": "Paragvajaus laikas (Asunsjonas)", + "America\/Bahia": "Brazilijos laikas (Baija)", + "America\/Bahia_Banderas": "Šiaurės Amerikos centro laikas (Bahia Banderasas)", + "America\/Barbados": "Atlanto laikas (Barbadosas)", + "America\/Belem": "Brazilijos laikas (Belenas)", + "America\/Belize": "Šiaurės Amerikos centro laikas (Belizas)", + "America\/Blanc-Sablon": "Atlanto laikas (Blanč Sablonas)", + "America\/Boa_Vista": "Amazonės laikas (Bua Vista)", + "America\/Bogota": "Kolumbijos laikas (Bogota)", + "America\/Boise": "Šiaurės Amerikos kalnų laikas (Boisis)", + "America\/Buenos_Aires": "Argentinos laikas (Buenos Airės)", + "America\/Cambridge_Bay": "Šiaurės Amerikos kalnų laikas (Keimbridž Bėjus)", + "America\/Campo_Grande": "Amazonės laikas (Kampo Grandė)", + "America\/Cancun": "Šiaurės Amerikos rytų laikas (Kankūnas)", + "America\/Caracas": "Venesuelos laikas (Karakasas)", + "America\/Catamarca": "Argentinos laikas (Katamarka)", + "America\/Cayenne": "Prancūzijos Gvianos laikas (Kajenas)", + "America\/Cayman": "Šiaurės Amerikos rytų laikas (Kaimanas)", + "America\/Chicago": "Šiaurės Amerikos centro laikas (Čikaga)", + "America\/Chihuahua": "Meksikos Ramiojo vandenyno laikas (Čihuahua)", + "America\/Coral_Harbour": "Šiaurės Amerikos rytų laikas (Atikokanas)", + "America\/Cordoba": "Argentinos laikas (Kordoba)", + "America\/Costa_Rica": "Šiaurės Amerikos centro laikas (Kosta Rika)", + "America\/Creston": "Šiaurės Amerikos kalnų laikas (Krestonas)", + "America\/Cuiaba": "Amazonės laikas (Kujaba)", + "America\/Curacao": "Atlanto laikas (Kiurasao)", + "America\/Danmarkshavn": "Grinvičo laikas (Danmarkshaunas)", + "America\/Dawson": "Šiaurės Amerikos Ramiojo vandenyno laikas (Dosonas)", + "America\/Dawson_Creek": "Šiaurės Amerikos kalnų laikas (Doson Krikas)", + "America\/Denver": "Šiaurės Amerikos kalnų laikas (Denveris)", + "America\/Detroit": "Šiaurės Amerikos rytų laikas (Detroitas)", + "America\/Dominica": "Atlanto laikas (Dominika)", + "America\/Edmonton": "Šiaurės Amerikos kalnų laikas (Edmontonas)", + "America\/Eirunepe": "Ako laikas (Eirunepė)", + "America\/El_Salvador": "Šiaurės Amerikos centro laikas (Salvadoras)", + "America\/Fort_Nelson": "Šiaurės Amerikos kalnų laikas (Fort Nelsonas)", + "America\/Fortaleza": "Brazilijos laikas (Fortaleza)", + "America\/Glace_Bay": "Atlanto laikas (Gleis Bėjus)", + "America\/Godthab": "Grenlandijos vakarų laikas (Nūkas)", + "America\/Goose_Bay": "Atlanto laikas (Gus Bėjus)", + "America\/Grand_Turk": "Šiaurės Amerikos rytų laikas (Grand Terkas)", + "America\/Grenada": "Atlanto laikas (Grenada)", + "America\/Guadeloupe": "Atlanto laikas (Gvadalupė)", + "America\/Guatemala": "Šiaurės Amerikos centro laikas (Gvatemala)", + "America\/Guayaquil": "Ekvadoro laikas (Gvajakilis)", + "America\/Guyana": "Gajanos laikas (Gvajana)", + "America\/Halifax": "Atlanto laikas (Halifaksas)", + "America\/Havana": "Kubos laikas (Havana)", + "America\/Hermosillo": "Meksikos Ramiojo vandenyno laikas (Hermosiljas)", + "America\/Indiana\/Knox": "Šiaurės Amerikos centro laikas (Noksas, Indiana)", + "America\/Indiana\/Marengo": "Šiaurės Amerikos rytų laikas (Marengas, Indiana)", + "America\/Indiana\/Petersburg": "Šiaurės Amerikos rytų laikas (Pitersbergas, Indiana)", + "America\/Indiana\/Tell_City": "Šiaurės Amerikos centro laikas (Tel Sitis, Indiana)", + "America\/Indiana\/Vevay": "Šiaurės Amerikos rytų laikas (Vivis, Indiana)", + "America\/Indiana\/Vincennes": "Šiaurės Amerikos rytų laikas (Vinsenas, Indiana)", + "America\/Indiana\/Winamac": "Šiaurės Amerikos rytų laikas (Vinamakas, Indiana)", + "America\/Indianapolis": "Šiaurės Amerikos rytų laikas (Indianapolis)", + "America\/Inuvik": "Šiaurės Amerikos kalnų laikas (Inuvikas)", + "America\/Iqaluit": "Šiaurės Amerikos rytų laikas (Ikaluitas)", + "America\/Jamaica": "Šiaurės Amerikos rytų laikas (Jamaika)", + "America\/Jujuy": "Argentinos laikas (Chuchujus)", + "America\/Juneau": "Aliaskos laikas (Džunas)", + "America\/Kentucky\/Monticello": "Šiaurės Amerikos rytų laikas (Montiselas, Kentukis)", + "America\/Kralendijk": "Atlanto laikas (Kralendeikas)", + "America\/La_Paz": "Bolivijos laikas (La Pasas)", + "America\/Lima": "Peru laikas (Lima)", + "America\/Los_Angeles": "Šiaurės Amerikos Ramiojo vandenyno laikas (Los Andželas)", + "America\/Louisville": "Šiaurės Amerikos rytų laikas (Luisvilis)", + "America\/Lower_Princes": "Atlanto laikas (Žemutinis Prinses Kvorteris)", + "America\/Maceio": "Brazilijos laikas (Masejo)", + "America\/Managua": "Šiaurės Amerikos centro laikas (Managva)", + "America\/Manaus": "Amazonės laikas (Manausas)", + "America\/Marigot": "Atlanto laikas (Marigo)", + "America\/Martinique": "Atlanto laikas (Martinika)", + "America\/Matamoros": "Šiaurės Amerikos centro laikas (Matamorosas)", + "America\/Mazatlan": "Meksikos Ramiojo vandenyno laikas (Masatlanas)", + "America\/Mendoza": "Argentinos laikas (Mendosa)", + "America\/Menominee": "Šiaurės Amerikos centro laikas (Menominis)", + "America\/Merida": "Šiaurės Amerikos centro laikas (Merida)", + "America\/Metlakatla": "Aliaskos laikas (Metlakatla)", + "America\/Mexico_City": "Šiaurės Amerikos centro laikas (Meksikas)", + "America\/Miquelon": "Sen Pjero ir Mikelono laikas (Mikelonas)", + "America\/Moncton": "Atlanto laikas (Monktonas)", + "America\/Monterrey": "Šiaurės Amerikos centro laikas (Monterėjus)", + "America\/Montevideo": "Urugvajaus laikas (Montevidėjas)", + "America\/Montserrat": "Atlanto laikas (Montseratas)", + "America\/Nassau": "Šiaurės Amerikos rytų laikas (Nasau)", + "America\/New_York": "Šiaurės Amerikos rytų laikas (Niujorkas)", + "America\/Nipigon": "Šiaurės Amerikos rytų laikas (Nipigonas)", + "America\/Nome": "Aliaskos laikas (Nomas)", + "America\/Noronha": "Fernando de Noronjos laikas (Noronja)", + "America\/North_Dakota\/Beulah": "Šiaurės Amerikos centro laikas (Bjula, Šiaurės Dakota)", + "America\/North_Dakota\/Center": "Šiaurės Amerikos centro laikas (Senteris, Šiaurės Dakota)", + "America\/North_Dakota\/New_Salem": "Šiaurės Amerikos centro laikas (Niu Seilemas, Šiaurės Dakota)", + "America\/Ojinaga": "Šiaurės Amerikos kalnų laikas (Ochinaga)", + "America\/Panama": "Šiaurės Amerikos rytų laikas (Panama)", + "America\/Pangnirtung": "Šiaurės Amerikos rytų laikas (Pangnirtungas)", + "America\/Paramaribo": "Surinamo laikas (Paramaribas)", + "America\/Phoenix": "Šiaurės Amerikos kalnų laikas (Finiksas)", + "America\/Port-au-Prince": "Šiaurės Amerikos rytų laikas (Port o Prensas)", + "America\/Port_of_Spain": "Atlanto laikas (Port of Speinas)", + "America\/Porto_Velho": "Amazonės laikas (Porto Veljas)", + "America\/Puerto_Rico": "Atlanto laikas (Puerto Rikas)", + "America\/Punta_Arenas": "Čilės laikas (Punta Arenasas)", + "America\/Rainy_River": "Šiaurės Amerikos centro laikas (Reini Riveris)", + "America\/Rankin_Inlet": "Šiaurės Amerikos centro laikas (Rankin Inletas)", + "America\/Recife": "Brazilijos laikas (Resifė)", + "America\/Regina": "Šiaurės Amerikos centro laikas (Redžina)", + "America\/Resolute": "Šiaurės Amerikos centro laikas (Resolutas)", + "America\/Rio_Branco": "Ako laikas (Rio Brankas)", + "America\/Santa_Isabel": "Šiaurės Vakarų Meksikos laikas (Santa Izabelė)", + "America\/Santarem": "Brazilijos laikas (Santarenas)", + "America\/Santiago": "Čilės laikas (Santjagas)", + "America\/Santo_Domingo": "Atlanto laikas (Santo Domingas)", + "America\/Sao_Paulo": "Brazilijos laikas (San Paulas)", + "America\/Scoresbysund": "Grenlandijos rytų laikas (Itokortormitas)", + "America\/Sitka": "Aliaskos laikas (Sitka)", + "America\/St_Barthelemy": "Atlanto laikas (Sen Bartelemi)", + "America\/St_Johns": "Niufaundlendo laikas (Sent Džonsas)", + "America\/St_Kitts": "Atlanto laikas (Sent Kitsas)", + "America\/St_Lucia": "Atlanto laikas (Sent Lusija)", + "America\/St_Thomas": "Atlanto laikas (Sent Tomasas)", + "America\/St_Vincent": "Atlanto laikas (Sent Vincentas)", + "America\/Swift_Current": "Šiaurės Amerikos centro laikas (Svift Karentas)", + "America\/Tegucigalpa": "Šiaurės Amerikos centro laikas (Tegusigalpa)", + "America\/Thule": "Atlanto laikas (Kanakas)", + "America\/Thunder_Bay": "Šiaurės Amerikos rytų laikas (Tander Bėjus)", + "America\/Tijuana": "Šiaurės Amerikos Ramiojo vandenyno laikas (Tichuana)", + "America\/Toronto": "Šiaurės Amerikos rytų laikas (Torontas)", + "America\/Tortola": "Atlanto laikas (Tortola)", + "America\/Vancouver": "Šiaurės Amerikos Ramiojo vandenyno laikas (Vankuveris)", + "America\/Whitehorse": "Šiaurės Amerikos Ramiojo vandenyno laikas (Vaithorsas)", + "America\/Winnipeg": "Šiaurės Amerikos centro laikas (Vinipegas)", + "America\/Yakutat": "Aliaskos laikas (Jakutatas)", + "America\/Yellowknife": "Šiaurės Amerikos kalnų laikas (Jelounaifas)", + "Antarctica\/Casey": "Vakarų Australijos laikas (Keisis)", + "Antarctica\/Davis": "Deiviso laikas (Deivisas)", + "Antarctica\/DumontDUrville": "Diumono d’Urvilio laikas (Diumonas d’Urvilis)", + "Antarctica\/Macquarie": "Makvorio Salos laikas (Makvoris)", + "Antarctica\/Mawson": "Mosono laikas (Mosonas)", + "Antarctica\/McMurdo": "Naujosios Zelandijos laikas (Makmerdas)", + "Antarctica\/Palmer": "Čilės laikas (Palmeris)", + "Antarctica\/Rothera": "Roteros laikas (Rotera)", + "Antarctica\/Syowa": "Siovos laikas (Siova)", + "Antarctica\/Troll": "Grinvičo laikas (Trolis)", + "Antarctica\/Vostok": "Vostoko laikas (Vostokas)", + "Arctic\/Longyearbyen": "Vidurio Europos laikas (Longjyrbienas)", + "Asia\/Aden": "Arabijos laikas (Adenas)", + "Asia\/Almaty": "Rytų Kazachstano laikas (Alma Ata)", + "Asia\/Amman": "Rytų Europos laikas (Amanas)", + "Asia\/Anadyr": "Anadyrės laikas (Anadyris)", + "Asia\/Aqtau": "Vakarų Kazachstano laikas (Aktau)", + "Asia\/Aqtobe": "Vakarų Kazachstano laikas (Aktiubinskas)", + "Asia\/Ashgabat": "Turkmėnistano laikas (Ašchabadas)", + "Asia\/Atyrau": "Vakarų Kazachstano laikas (Atyrau)", + "Asia\/Baghdad": "Arabijos laikas (Bagdadas)", + "Asia\/Bahrain": "Arabijos laikas (Bahreinas)", + "Asia\/Baku": "Azerbaidžano laikas (Baku)", + "Asia\/Bangkok": "Indokinijos laikas (Bankokas)", + "Asia\/Beirut": "Rytų Europos laikas (Beirutas)", + "Asia\/Bishkek": "Kirgistano laikas (Biškekas)", + "Asia\/Brunei": "Brunėjaus Darusalamo laikas (Brunėjus)", + "Asia\/Calcutta": "Indijos laikas (Kolkata)", + "Asia\/Chita": "Jakutsko laikas (Čita)", + "Asia\/Choibalsan": "Čoibalsano laikas (Čoibalsanas)", + "Asia\/Colombo": "Indijos laikas (Kolombas)", + "Asia\/Damascus": "Rytų Europos laikas (Damaskas)", + "Asia\/Dhaka": "Bangladešo laikas (Daka)", + "Asia\/Dili": "Rytų Timoro laikas (Dilis)", + "Asia\/Dubai": "Persijos įlankos laikas (Dubajus)", + "Asia\/Dushanbe": "Tadžikistano laikas (Dušanbė)", + "Asia\/Famagusta": "Rytų Europos laikas (Famagusta)", + "Asia\/Gaza": "Rytų Europos laikas (Gazos ruožas)", + "Asia\/Hebron": "Rytų Europos laikas (Hebronas)", + "Asia\/Hong_Kong": "Honkongo laikas (Honkongas)", + "Asia\/Hovd": "Hovdo laikas (Hovdas)", + "Asia\/Irkutsk": "Irkutsko laikas (Irkutskas)", + "Asia\/Jakarta": "Vakarų Indonezijos laikas (Džakarta)", + "Asia\/Jayapura": "Rytų Indonezijos laikas (Džajapura)", + "Asia\/Jerusalem": "Izraelio laikas (Jeruzalė)", + "Asia\/Kabul": "Afganistano laikas (Kabulas)", + "Asia\/Kamchatka": "Kamčiatkos Petropavlovsko laikas (Kamčiatka)", + "Asia\/Karachi": "Pakistano laikas (Karačis)", + "Asia\/Katmandu": "Nepalo laikas (Katmandu)", + "Asia\/Khandyga": "Jakutsko laikas (Chandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsko laikas (Krasnojarskas)", + "Asia\/Kuala_Lumpur": "Malaizijos laikas (Kvala Lumpūras)", + "Asia\/Kuching": "Malaizijos laikas (Kučingas)", + "Asia\/Kuwait": "Arabijos laikas (Kuveitas)", + "Asia\/Macau": "Kinijos laikas (Makao)", + "Asia\/Magadan": "Magadano laikas (Magadanas)", + "Asia\/Makassar": "Centrinės Indonezijos laikas (Makasaras)", + "Asia\/Manila": "Filipinų laikas (Manila)", + "Asia\/Muscat": "Persijos įlankos laikas (Maskatas)", + "Asia\/Nicosia": "Rytų Europos laikas (Nikosija)", + "Asia\/Novokuznetsk": "Krasnojarsko laikas (Novokuzneckas)", + "Asia\/Novosibirsk": "Novosibirsko laikas (Novosibirskas)", + "Asia\/Omsk": "Omsko laikas (Omskas)", + "Asia\/Oral": "Vakarų Kazachstano laikas (Uralskas)", + "Asia\/Phnom_Penh": "Indokinijos laikas (Pnompenis)", + "Asia\/Pontianak": "Vakarų Indonezijos laikas (Pontianakas)", + "Asia\/Pyongyang": "Korėjos laikas (Pchenjanas)", + "Asia\/Qatar": "Arabijos laikas (Kataras)", + "Asia\/Qostanay": "Rytų Kazachstano laikas (Kostanajus)", + "Asia\/Qyzylorda": "Vakarų Kazachstano laikas (Kzyl-Orda)", + "Asia\/Rangoon": "Mianmaro laikas (Rangūnas)", + "Asia\/Riyadh": "Arabijos laikas (Rijadas)", + "Asia\/Saigon": "Indokinijos laikas (Hošiminas)", + "Asia\/Sakhalin": "Sachalino laikas (Sachalinas)", + "Asia\/Samarkand": "Uzbekistano laikas (Samarkandas)", + "Asia\/Seoul": "Korėjos laikas (Seulas)", + "Asia\/Shanghai": "Kinijos laikas (Šanchajus)", + "Asia\/Singapore": "Singapūro laikas (Singapūras)", + "Asia\/Srednekolymsk": "Magadano laikas (Srednekolymskas)", + "Asia\/Taipei": "Taipėjaus laikas (Taipėjus)", + "Asia\/Tashkent": "Uzbekistano laikas (Taškentas)", + "Asia\/Tbilisi": "Gruzijos laikas (Tbilisis)", + "Asia\/Tehran": "Irano laikas (Teheranas)", + "Asia\/Thimphu": "Butano laikas (Timpu)", + "Asia\/Tokyo": "Japonijos laikas (Tokijas)", + "Asia\/Ulaanbaatar": "Ulan Batoro laikas (Ulan Batoras)", + "Asia\/Ust-Nera": "Vladivostoko laikas (Ust Nera)", + "Asia\/Vientiane": "Indokinijos laikas (Vientianas)", + "Asia\/Vladivostok": "Vladivostoko laikas (Vladivostokas)", + "Asia\/Yakutsk": "Jakutsko laikas (Jakutskas)", + "Asia\/Yekaterinburg": "Jekaterinburgo laikas (Jekaterinburgas)", + "Asia\/Yerevan": "Armėnijos laikas (Jerevanas)", + "Atlantic\/Azores": "Azorų Salų laikas (Azorai)", + "Atlantic\/Bermuda": "Atlanto laikas (Bermuda)", + "Atlantic\/Canary": "Vakarų Europos laikas (Kanarų salos)", + "Atlantic\/Cape_Verde": "Žaliojo Kyšulio laikas (Žaliasis Kyšulys)", + "Atlantic\/Faeroe": "Vakarų Europos laikas (Farerai)", + "Atlantic\/Madeira": "Vakarų Europos laikas (Madeira)", + "Atlantic\/Reykjavik": "Grinvičo laikas (Reikjavikas)", + "Atlantic\/South_Georgia": "Pietų Džordžijos laikas (Pietų Džordžija)", + "Atlantic\/St_Helena": "Grinvičo laikas (Sent Helena)", + "Atlantic\/Stanley": "Folklando Salų laikas (Stenlis)", + "Australia\/Adelaide": "Centrinės Australijos laikas (Adelaidė)", + "Australia\/Brisbane": "Rytų Australijos laikas (Brisbanas)", + "Australia\/Broken_Hill": "Centrinės Australijos laikas (Broken Hilis)", + "Australia\/Currie": "Rytų Australijos laikas (Karis)", + "Australia\/Darwin": "Centrinės Australijos laikas (Darvinas)", + "Australia\/Eucla": "Centrinės vakarų Australijos laikas (Jukla)", + "Australia\/Hobart": "Rytų Australijos laikas (Hobartas)", + "Australia\/Lindeman": "Rytų Australijos laikas (Lindemanas)", + "Australia\/Lord_Howe": "Lordo Hau laikas (Lordo Hau sala)", + "Australia\/Melbourne": "Rytų Australijos laikas (Melburnas)", + "Australia\/Perth": "Vakarų Australijos laikas (Pertas)", + "Australia\/Sydney": "Rytų Australijos laikas (Sidnėjus)", + "CST6CDT": "Šiaurės Amerikos centro laikas", + "EST5EDT": "Šiaurės Amerikos rytų laikas", + "Etc\/GMT": "Grinvičo laikas", + "Etc\/UTC": "pasaulio suderintasis laikas", + "Europe\/Amsterdam": "Vidurio Europos laikas (Amsterdamas)", + "Europe\/Andorra": "Vidurio Europos laikas (Andora)", + "Europe\/Astrakhan": "Maskvos laikas (Astrachanė)", + "Europe\/Athens": "Rytų Europos laikas (Atėnai)", + "Europe\/Belgrade": "Vidurio Europos laikas (Belgradas)", + "Europe\/Berlin": "Vidurio Europos laikas (Berlynas)", + "Europe\/Bratislava": "Vidurio Europos laikas (Bratislava)", + "Europe\/Brussels": "Vidurio Europos laikas (Briuselis)", + "Europe\/Bucharest": "Rytų Europos laikas (Bukareštas)", + "Europe\/Budapest": "Vidurio Europos laikas (Budapeštas)", + "Europe\/Busingen": "Vidurio Europos laikas (Biusingenas)", + "Europe\/Chisinau": "Rytų Europos laikas (Kišiniovas)", + "Europe\/Copenhagen": "Vidurio Europos laikas (Kopenhaga)", + "Europe\/Dublin": "Grinvičo laikas (Dublinas)", + "Europe\/Gibraltar": "Vidurio Europos laikas (Gibraltaras)", + "Europe\/Guernsey": "Grinvičo laikas (Gernsis)", + "Europe\/Helsinki": "Rytų Europos laikas (Helsinkis)", + "Europe\/Isle_of_Man": "Grinvičo laikas (Meno sala)", + "Europe\/Jersey": "Grinvičo laikas (Džersis)", + "Europe\/Kaliningrad": "Rytų Europos laikas (Kaliningradas)", + "Europe\/Kiev": "Rytų Europos laikas (Kijevas)", + "Europe\/Lisbon": "Vakarų Europos laikas (Lisabona)", + "Europe\/Ljubljana": "Vidurio Europos laikas (Liubliana)", + "Europe\/London": "Grinvičo laikas (Londonas)", + "Europe\/Luxembourg": "Vidurio Europos laikas (Liuksemburgas)", + "Europe\/Madrid": "Vidurio Europos laikas (Madridas)", + "Europe\/Malta": "Vidurio Europos laikas (Malta)", + "Europe\/Mariehamn": "Rytų Europos laikas (Marianhamina)", + "Europe\/Minsk": "Maskvos laikas (Minskas)", + "Europe\/Monaco": "Vidurio Europos laikas (Monakas)", + "Europe\/Moscow": "Maskvos laikas (Maskva)", + "Europe\/Oslo": "Vidurio Europos laikas (Oslas)", + "Europe\/Paris": "Vidurio Europos laikas (Paryžius)", + "Europe\/Podgorica": "Vidurio Europos laikas (Podgorica)", + "Europe\/Prague": "Vidurio Europos laikas (Praha)", + "Europe\/Riga": "Rytų Europos laikas (Ryga)", + "Europe\/Rome": "Vidurio Europos laikas (Roma)", + "Europe\/Samara": "Samaros laikas (Samara)", + "Europe\/San_Marino": "Vidurio Europos laikas (San Marinas)", + "Europe\/Sarajevo": "Vidurio Europos laikas (Sarajevas)", + "Europe\/Saratov": "Maskvos laikas (Saratovas)", + "Europe\/Simferopol": "Maskvos laikas (Simferopolis)", + "Europe\/Skopje": "Vidurio Europos laikas (Skopjė)", + "Europe\/Sofia": "Rytų Europos laikas (Sofija)", + "Europe\/Stockholm": "Vidurio Europos laikas (Stokholmas)", + "Europe\/Tallinn": "Rytų Europos laikas (Talinas)", + "Europe\/Tirane": "Vidurio Europos laikas (Tirana)", + "Europe\/Ulyanovsk": "Maskvos laikas (Uljanovskas)", + "Europe\/Uzhgorod": "Rytų Europos laikas (Užhorodas)", + "Europe\/Vaduz": "Vidurio Europos laikas (Vaducas)", + "Europe\/Vatican": "Vidurio Europos laikas (Vatikanas)", + "Europe\/Vienna": "Vidurio Europos laikas (Viena)", + "Europe\/Vilnius": "Rytų Europos laikas (Vilnius)", + "Europe\/Volgograd": "Volgogrado laikas (Volgogradas)", + "Europe\/Warsaw": "Vidurio Europos laikas (Varšuva)", + "Europe\/Zagreb": "Vidurio Europos laikas (Zagrebas)", + "Europe\/Zaporozhye": "Rytų Europos laikas (Zaporožė)", + "Europe\/Zurich": "Vidurio Europos laikas (Ciurichas)", + "Indian\/Antananarivo": "Rytų Afrikos laikas (Antananaryvas)", + "Indian\/Chagos": "Indijos vandenyno laikas (Čagosas)", + "Indian\/Christmas": "Kalėdų Salos laikas (Kalėdų Sala)", + "Indian\/Cocos": "Kokosų Salų laikas (Kokosų sala)", + "Indian\/Comoro": "Rytų Afrikos laikas (Komoras)", + "Indian\/Kerguelen": "Pietų Prancūzijos ir antarktinis laikas (Kergelenas)", + "Indian\/Mahe": "Seišelių laikas (Mahė)", + "Indian\/Maldives": "Maldyvų laikas (Maldyvai)", + "Indian\/Mauritius": "Mauricijaus laikas (Mauricijus)", + "Indian\/Mayotte": "Rytų Afrikos laikas (Majotas)", + "Indian\/Reunion": "Reunjono laikas (Reunjonas)", + "MST7MDT": "Šiaurės Amerikos kalnų laikas", + "PST8PDT": "Šiaurės Amerikos Ramiojo vandenyno laikas", + "Pacific\/Apia": "Apijos laikas (Apija)", + "Pacific\/Auckland": "Naujosios Zelandijos laikas (Oklandas)", + "Pacific\/Bougainville": "Papua Naujosios Gvinėjos laikas (Bugenvilis)", + "Pacific\/Chatham": "Čatamo laikas (Čatamas)", + "Pacific\/Easter": "Velykų Salos laikas (Velykų sala)", + "Pacific\/Efate": "Vanuatu laikas (Efatė)", + "Pacific\/Enderbury": "Fenikso Salų laikas (Enderburis)", + "Pacific\/Fakaofo": "Tokelau laikas (Fakaofas)", + "Pacific\/Fiji": "Fidžio laikas (Fidžis)", + "Pacific\/Funafuti": "Tuvalu laikas (Funafutis)", + "Pacific\/Galapagos": "Galapagų laikas (Galapagai)", + "Pacific\/Gambier": "Gambyro laikas (Gambyras)", + "Pacific\/Guadalcanal": "Saliamono Salų laikas (Gvadalkanalis)", + "Pacific\/Guam": "Čamoro laikas (Guamas)", + "Pacific\/Honolulu": "Havajų-Aleutų laikas (Honolulu)", + "Pacific\/Johnston": "Havajų-Aleutų laikas (Džonstonas)", + "Pacific\/Kiritimati": "Laino Salų laikas (Kiritimatis)", + "Pacific\/Kosrae": "Kosrajė laikas (Kosrajė)", + "Pacific\/Kwajalein": "Maršalo Salų laikas (Kvadžaleinas)", + "Pacific\/Majuro": "Maršalo Salų laikas (Madžūras)", + "Pacific\/Marquesas": "Markizo Salų laikas (Markizo salos)", + "Pacific\/Midway": "Samoa laikas (Midvėjus)", + "Pacific\/Nauru": "Nauru laikas (Nauru)", + "Pacific\/Niue": "Niujė laikas (Niujė)", + "Pacific\/Norfolk": "Norfolko Salų laikas (Norfolkas)", + "Pacific\/Noumea": "Naujosios Kaledonijos laikas (Numėja)", + "Pacific\/Pago_Pago": "Samoa laikas (Pago Pagas)", + "Pacific\/Palau": "Palau laikas (Palau)", + "Pacific\/Pitcairn": "Pitkerno laikas (Pitkerno sala)", + "Pacific\/Ponape": "Ponapės laikas (Ponapė)", + "Pacific\/Port_Moresby": "Papua Naujosios Gvinėjos laikas (Port Morsbis)", + "Pacific\/Rarotonga": "Kuko Salų laikas (Rarotonga)", + "Pacific\/Saipan": "Čamoro laikas (Saipanas)", + "Pacific\/Tahiti": "Tahičio laikas (Taitis)", + "Pacific\/Tarawa": "Gilberto Salų laikas (Tarava)", + "Pacific\/Tongatapu": "Tongos laikas (Tongatapu)", + "Pacific\/Truk": "Čuko laikas (Čukas)", + "Pacific\/Wake": "Veiko Salos laikas (Veiko sala)", + "Pacific\/Wallis": "Voliso ir Futūnos laikas (Volisas)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/lv.json b/src/Symfony/Component/Intl/Resources/data/timezones/lv.json new file mode 100644 index 0000000000000..d7b894ee01622 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/lv.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.43", + "Names": { + "Africa\/Abidjan": "Griničas laiks (Abidžana)", + "Africa\/Accra": "Griničas laiks (Akra)", + "Africa\/Addis_Ababa": "Austrumāfrikas laiks (Adisabeba)", + "Africa\/Algiers": "Centrāleiropas laiks (Alžīra)", + "Africa\/Asmera": "Austrumāfrikas laiks (Asmara)", + "Africa\/Bamako": "Griničas laiks (Bamako)", + "Africa\/Bangui": "Rietumāfrikas laiks (Bangi)", + "Africa\/Banjul": "Griničas laiks (Bandžula)", + "Africa\/Bissau": "Griničas laiks (Bisava)", + "Africa\/Blantyre": "Centrālāfrikas laiks (Blantaira)", + "Africa\/Brazzaville": "Rietumāfrikas laiks (Brazavila)", + "Africa\/Bujumbura": "Centrālāfrikas laiks (Bužumbura)", + "Africa\/Cairo": "Austrumeiropas laiks (Kaira)", + "Africa\/Casablanca": "Rietumeiropas laiks (Kasablanka)", + "Africa\/Ceuta": "Centrāleiropas laiks (Seuta)", + "Africa\/Conakry": "Griničas laiks (Konakri)", + "Africa\/Dakar": "Griničas laiks (Dakara)", + "Africa\/Dar_es_Salaam": "Austrumāfrikas laiks (Dāresalāma)", + "Africa\/Djibouti": "Austrumāfrikas laiks (Džibutija)", + "Africa\/Douala": "Rietumāfrikas laiks (Duala)", + "Africa\/El_Aaiun": "Rietumeiropas laiks (Ajūna)", + "Africa\/Freetown": "Griničas laiks (Frītauna)", + "Africa\/Gaborone": "Centrālāfrikas laiks (Gaborone)", + "Africa\/Harare": "Centrālāfrikas laiks (Harare)", + "Africa\/Johannesburg": "Dienvidāfrikas ziemas laiks (Johannesburga)", + "Africa\/Juba": "Austrumāfrikas laiks (Džūba)", + "Africa\/Kampala": "Austrumāfrikas laiks (Kampala)", + "Africa\/Khartoum": "Centrālāfrikas laiks (Hartūma)", + "Africa\/Kigali": "Centrālāfrikas laiks (Kigali)", + "Africa\/Kinshasa": "Rietumāfrikas laiks (Kinšasa)", + "Africa\/Lagos": "Rietumāfrikas laiks (Lagosa)", + "Africa\/Libreville": "Rietumāfrikas laiks (Librevila)", + "Africa\/Lome": "Griničas laiks (Lome)", + "Africa\/Luanda": "Rietumāfrikas laiks (Luanda)", + "Africa\/Lubumbashi": "Centrālāfrikas laiks (Lubumbaši)", + "Africa\/Lusaka": "Centrālāfrikas laiks (Lusaka)", + "Africa\/Malabo": "Rietumāfrikas laiks (Malabo)", + "Africa\/Maputo": "Centrālāfrikas laiks (Maputu)", + "Africa\/Maseru": "Dienvidāfrikas ziemas laiks (Maseru)", + "Africa\/Mbabane": "Dienvidāfrikas ziemas laiks (Mbabane)", + "Africa\/Mogadishu": "Austrumāfrikas laiks (Mogadīšo)", + "Africa\/Monrovia": "Griničas laiks (Monrovija)", + "Africa\/Nairobi": "Austrumāfrikas laiks (Nairobi)", + "Africa\/Ndjamena": "Rietumāfrikas laiks (Ndžamena)", + "Africa\/Niamey": "Rietumāfrikas laiks (Niameja)", + "Africa\/Nouakchott": "Griničas laiks (Nuakšota)", + "Africa\/Ouagadougou": "Griničas laiks (Vagadugu)", + "Africa\/Porto-Novo": "Rietumāfrikas laiks (Portonovo)", + "Africa\/Sao_Tome": "Griničas laiks (Santome)", + "Africa\/Tripoli": "Austrumeiropas laiks (Tripole)", + "Africa\/Tunis": "Centrāleiropas laiks (Tunisa)", + "Africa\/Windhoek": "Centrālāfrikas laiks (Vindhuka)", + "America\/Adak": "Havaju–Aleutu laiks (Adaka)", + "America\/Anchorage": "Aļaskas laiks (Ankurāža)", + "America\/Anguilla": "Atlantijas laiks (Angilja)", + "America\/Antigua": "Atlantijas laiks (Antigva)", + "America\/Araguaina": "Brazīlijas laiks (Aragvaina)", + "America\/Argentina\/La_Rioja": "Argentīnas laiks (Larjoha)", + "America\/Argentina\/Rio_Gallegos": "Argentīnas laiks (Riogaljegosa)", + "America\/Argentina\/Salta": "Argentīnas laiks (Salta)", + "America\/Argentina\/San_Juan": "Argentīnas laiks (Sanhuana)", + "America\/Argentina\/San_Luis": "Rietumargentīnas laiks (Sanluisa)", + "America\/Argentina\/Tucuman": "Argentīnas laiks (Tukumana)", + "America\/Argentina\/Ushuaia": "Argentīnas laiks (Ušuaja)", + "America\/Aruba": "Atlantijas laiks (Aruba)", + "America\/Asuncion": "Paragvajas laiks (Asunsjona)", + "America\/Bahia": "Brazīlijas laiks (Baija)", + "America\/Bahia_Banderas": "Centrālais laiks (Bajabanderasa)", + "America\/Barbados": "Atlantijas laiks (Barbadosa)", + "America\/Belem": "Brazīlijas laiks (Belena)", + "America\/Belize": "Centrālais laiks (Beliza)", + "America\/Blanc-Sablon": "Atlantijas laiks (Blansablona)", + "America\/Boa_Vista": "Amazones laiks (Boavista)", + "America\/Bogota": "Kolumbijas laiks (Bogota)", + "America\/Boise": "Kalnu laiks (Boisisitija)", + "America\/Buenos_Aires": "Argentīnas laiks (Buenosairesa)", + "America\/Cambridge_Bay": "Kalnu laiks (Kembridžbeja)", + "America\/Campo_Grande": "Amazones laiks (Kampugrandi)", + "America\/Cancun": "Austrumu laiks (Kankuna)", + "America\/Caracas": "Venecuēlas laiks (Karakasa)", + "America\/Catamarca": "Argentīnas laiks (Katamarka)", + "America\/Cayenne": "Francijas Gviānas laiks (Kajenna)", + "America\/Cayman": "Austrumu laiks (Kaimanu salas)", + "America\/Chicago": "Centrālais laiks (Čikāga)", + "America\/Chihuahua": "Meksikas Klusā okeāna piekrastes laiks (Čivava)", + "America\/Coral_Harbour": "Austrumu laiks (Atikokana)", + "America\/Cordoba": "Argentīnas laiks (Kordova)", + "America\/Costa_Rica": "Centrālais laiks (Kostarika)", + "America\/Creston": "Kalnu laiks (Krestona)", + "America\/Cuiaba": "Amazones laiks (Kujaba)", + "America\/Curacao": "Atlantijas laiks (Kirasao)", + "America\/Danmarkshavn": "Griničas laiks (Denmārkšavna)", + "America\/Dawson": "Klusā okeāna laiks (Dousona)", + "America\/Dawson_Creek": "Kalnu laiks (Dousonkrīka)", + "America\/Denver": "Kalnu laiks (Denvera)", + "America\/Detroit": "Austrumu laiks (Detroita)", + "America\/Dominica": "Atlantijas laiks (Dominika)", + "America\/Edmonton": "Kalnu laiks (Edmontona)", + "America\/El_Salvador": "Centrālais laiks (Salvadora)", + "America\/Fort_Nelson": "Kalnu laiks (Fortnelsona)", + "America\/Fortaleza": "Brazīlijas laiks (Fortaleza)", + "America\/Glace_Bay": "Atlantijas laiks (Gleisbeja)", + "America\/Godthab": "Rietumgrenlandes laiks (Nūka)", + "America\/Goose_Bay": "Atlantijas laiks (Gūsbeja)", + "America\/Grand_Turk": "Austrumu laiks (Grandtkērka)", + "America\/Grenada": "Atlantijas laiks (Grenāda)", + "America\/Guadeloupe": "Atlantijas laiks (Gvadelupa)", + "America\/Guatemala": "Centrālais laiks (Gvatemala)", + "America\/Guayaquil": "Ekvadoras laiks (Gvajakila)", + "America\/Guyana": "Gajānas laiks (Gajāna)", + "America\/Halifax": "Atlantijas laiks (Helifeksa)", + "America\/Havana": "Kubas laiks (Havana)", + "America\/Hermosillo": "Meksikas Klusā okeāna piekrastes laiks (Ermosiljo)", + "America\/Indiana\/Knox": "Centrālais laiks (Noksa, Indiāna)", + "America\/Indiana\/Marengo": "Austrumu laiks (Marengo, Indiāna)", + "America\/Indiana\/Petersburg": "Austrumu laiks (Pītersbērga, Indiāna)", + "America\/Indiana\/Tell_City": "Centrālais laiks (Telsitija, Indiāna)", + "America\/Indiana\/Vevay": "Austrumu laiks (Vīveja, Indiāna)", + "America\/Indiana\/Vincennes": "Austrumu laiks (Vinsensa, Indiāna)", + "America\/Indiana\/Winamac": "Austrumu laiks (Vinamaka, Indiāna)", + "America\/Indianapolis": "Austrumu laiks (Indianapolisa)", + "America\/Inuvik": "Kalnu laiks (Inuvika)", + "America\/Iqaluit": "Austrumu laiks (Ikaluita)", + "America\/Jamaica": "Austrumu laiks (Jamaika)", + "America\/Jujuy": "Argentīnas laiks (Huhuja)", + "America\/Juneau": "Aļaskas laiks (Džuno)", + "America\/Kentucky\/Monticello": "Austrumu laiks (Montičelo, Kentuki)", + "America\/Kralendijk": "Atlantijas laiks (Krālendeika)", + "America\/La_Paz": "Bolīvijas laiks (Lapasa)", + "America\/Lima": "Peru laiks (Lima)", + "America\/Los_Angeles": "Klusā okeāna laiks (Losandželosa)", + "America\/Louisville": "Austrumu laiks (Lūivila)", + "America\/Lower_Princes": "Atlantijas laiks (Louerprinseskvotera)", + "America\/Maceio": "Brazīlijas laiks (Masejo)", + "America\/Managua": "Centrālais laiks (Managva)", + "America\/Manaus": "Amazones laiks (Manausa)", + "America\/Marigot": "Atlantijas laiks (Merigota)", + "America\/Martinique": "Atlantijas laiks (Martinika)", + "America\/Matamoros": "Centrālais laiks (Matamorosa)", + "America\/Mazatlan": "Meksikas Klusā okeāna piekrastes laiks (Masatlana)", + "America\/Mendoza": "Argentīnas laiks (Mendosa)", + "America\/Menominee": "Centrālais laiks (Menominī)", + "America\/Merida": "Centrālais laiks (Merida)", + "America\/Metlakatla": "Aļaskas laiks (Metlakatla)", + "America\/Mexico_City": "Centrālais laiks (Mehiko)", + "America\/Miquelon": "Senpjēras un Mikelonas laiks (Mikelona)", + "America\/Moncton": "Atlantijas laiks (Monktona)", + "America\/Monterrey": "Centrālais laiks (Monterreja)", + "America\/Montevideo": "Urugvajas laiks (Montevideo)", + "America\/Montserrat": "Atlantijas laiks (Montserrata)", + "America\/Nassau": "Austrumu laiks (Naso)", + "America\/New_York": "Austrumu laiks (Ņujorka)", + "America\/Nipigon": "Austrumu laiks (Nipigona)", + "America\/Nome": "Aļaskas laiks (Noma)", + "America\/Noronha": "Fernandu di Noroņas laiks (Noroņa)", + "America\/North_Dakota\/Beulah": "Centrālais laiks (Bjula, Ziemeļdakota)", + "America\/North_Dakota\/Center": "Centrālais laiks (Sentera, Ziemeļdakota)", + "America\/North_Dakota\/New_Salem": "Centrālais laiks (Ņūseilema, Ziemeļdakota)", + "America\/Ojinaga": "Kalnu laiks (Ohinaga)", + "America\/Panama": "Austrumu laiks (Panama)", + "America\/Pangnirtung": "Austrumu laiks (Pannirtuna)", + "America\/Paramaribo": "Surinamas laiks (Paramaribo)", + "America\/Phoenix": "Kalnu laiks (Fīniksa)", + "America\/Port-au-Prince": "Austrumu laiks (Portoprensa)", + "America\/Port_of_Spain": "Atlantijas laiks (Portofspeina)", + "America\/Porto_Velho": "Amazones laiks (Portuveļu)", + "America\/Puerto_Rico": "Atlantijas laiks (Puertoriko)", + "America\/Punta_Arenas": "Čīles laiks (Puntaarenasa)", + "America\/Rainy_River": "Centrālais laiks (Reinirivera)", + "America\/Rankin_Inlet": "Centrālais laiks (Rankininleta)", + "America\/Recife": "Brazīlijas laiks (Resifi)", + "America\/Regina": "Centrālais laiks (Ridžaina)", + "America\/Resolute": "Centrālais laiks (Rezolūta)", + "America\/Santa_Isabel": "Ziemeļrietumu Meksikas laiks (Santaisabela)", + "America\/Santarem": "Brazīlijas laiks (Santarena)", + "America\/Santiago": "Čīles laiks (Santjago)", + "America\/Santo_Domingo": "Atlantijas laiks (Santodomingo)", + "America\/Sao_Paulo": "Brazīlijas laiks (Sanpaulu)", + "America\/Scoresbysund": "Austrumgrenlandes laiks (Itokortormita)", + "America\/Sitka": "Aļaskas laiks (Sitka)", + "America\/St_Barthelemy": "Atlantijas laiks (Senbartelmī)", + "America\/St_Johns": "Ņūfaundlendas laiks (Sentdžonsa)", + "America\/St_Kitts": "Atlantijas laiks (Sentkitsa)", + "America\/St_Lucia": "Atlantijas laiks (Sentlūsija)", + "America\/St_Thomas": "Atlantijas laiks (Sentomasa)", + "America\/St_Vincent": "Atlantijas laiks (Sentvinsenta)", + "America\/Swift_Current": "Centrālais laiks (Sviftkarenta)", + "America\/Tegucigalpa": "Centrālais laiks (Tegusigalpa)", + "America\/Thule": "Atlantijas laiks (Tule)", + "America\/Thunder_Bay": "Austrumu laiks (Tanderbeja)", + "America\/Tijuana": "Klusā okeāna laiks (Tihuana)", + "America\/Toronto": "Austrumu laiks (Toronto)", + "America\/Tortola": "Atlantijas laiks (Tortola)", + "America\/Vancouver": "Klusā okeāna laiks (Vankūvera)", + "America\/Whitehorse": "Klusā okeāna laiks (Vaithorsa)", + "America\/Winnipeg": "Centrālais laiks (Vinipega)", + "America\/Yakutat": "Aļaskas laiks (Jakutata)", + "America\/Yellowknife": "Kalnu laiks (Jelounaifa)", + "Antarctica\/Casey": "Austrālijas rietumu laiks (Keisi)", + "Antarctica\/Davis": "Deivisas laiks (Deivisa)", + "Antarctica\/DumontDUrville": "Dimondirvilas laiks (Dimondirvila)", + "Antarctica\/Macquarie": "Makvorija salas laiks (Makvori)", + "Antarctica\/Mawson": "Mosonas laiks (Mosona)", + "Antarctica\/McMurdo": "Jaunzēlandes laiks (Makmerdo)", + "Antarctica\/Palmer": "Čīles laiks (Pālmera)", + "Antarctica\/Rothera": "Roteras laiks (Rotera)", + "Antarctica\/Syowa": "Šovas laiks (Šova)", + "Antarctica\/Troll": "Griničas laiks (Trolla)", + "Antarctica\/Vostok": "Vostokas laiks (Vostoka)", + "Arctic\/Longyearbyen": "Centrāleiropas laiks (Longjērbīene)", + "Asia\/Aden": "Arābijas pussalas laiks (Adena)", + "Asia\/Almaty": "Austrumkazahstānas laiks (Almati)", + "Asia\/Amman": "Austrumeiropas laiks (Ammāna)", + "Asia\/Anadyr": "Anadiras laiks (Anadira)", + "Asia\/Aqtau": "Rietumkazahstānas laiks (Aktau)", + "Asia\/Aqtobe": "Rietumkazahstānas laiks (Aktebe)", + "Asia\/Ashgabat": "Turkmenistānas laiks (Ašgabata)", + "Asia\/Atyrau": "Rietumkazahstānas laiks (Atirau)", + "Asia\/Baghdad": "Arābijas pussalas laiks (Bagdāde)", + "Asia\/Bahrain": "Arābijas pussalas laiks (Bahreina)", + "Asia\/Baku": "Azerbaidžānas laiks (Baku)", + "Asia\/Bangkok": "Indoķīnas laiks (Bangkoka)", + "Asia\/Beirut": "Austrumeiropas laiks (Beirūta)", + "Asia\/Bishkek": "Kirgizstānas laiks (Biškeka)", + "Asia\/Brunei": "Brunejas Darusalamas laiks (Bruneja)", + "Asia\/Calcutta": "Indijas ziemas laiks (Kalkāta)", + "Asia\/Chita": "Jakutskas laiks (Čita)", + "Asia\/Choibalsan": "Čoibalsanas laiks (Čoibalsana)", + "Asia\/Colombo": "Indijas ziemas laiks (Kolombo)", + "Asia\/Damascus": "Austrumeiropas laiks (Damaska)", + "Asia\/Dhaka": "Bangladešas laiks (Daka)", + "Asia\/Dili": "Austrumtimoras laiks (Dili)", + "Asia\/Dubai": "Persijas līča laiks (Dubaija)", + "Asia\/Dushanbe": "Tadžikistānas laiks (Dušanbe)", + "Asia\/Famagusta": "Austrumeiropas laiks (Famagusta)", + "Asia\/Gaza": "Austrumeiropas laiks (Gaza)", + "Asia\/Hebron": "Austrumeiropas laiks (Hebrona)", + "Asia\/Hong_Kong": "Honkongas laiks (Honkonga)", + "Asia\/Hovd": "Hovdas laiks (Hovda)", + "Asia\/Irkutsk": "Irkutskas laiks (Irkutska)", + "Asia\/Jakarta": "Rietumindonēzijas laiks (Džakarta)", + "Asia\/Jayapura": "Austrumindonēzijas laiks (Džajapura)", + "Asia\/Jerusalem": "Izraēlas laiks (Jeruzaleme)", + "Asia\/Kabul": "Afganistānas laiks (Kabula)", + "Asia\/Kamchatka": "Petropavlovskas-Kamčatskas laiks (Kamčatka)", + "Asia\/Karachi": "Pakistānas laiks (Karāči)", + "Asia\/Katmandu": "Nepālas laiks (Katmandu)", + "Asia\/Khandyga": "Jakutskas laiks (Handiga)", + "Asia\/Krasnoyarsk": "Krasnojarskas laiks (Krasnojarska)", + "Asia\/Kuala_Lumpur": "Malaizijas laiks (Kualalumpura)", + "Asia\/Kuching": "Malaizijas laiks (Kučina)", + "Asia\/Kuwait": "Arābijas pussalas laiks (Kuveita)", + "Asia\/Macau": "Ķīnas laiks (Makao)", + "Asia\/Magadan": "Magadanas laiks (Magadana)", + "Asia\/Makassar": "Centrālindonēzijas laiks (Makasara)", + "Asia\/Manila": "Filipīnu laiks (Manila)", + "Asia\/Muscat": "Persijas līča laiks (Maskata)", + "Asia\/Nicosia": "Austrumeiropas laiks (Nikosija)", + "Asia\/Novokuznetsk": "Krasnojarskas laiks (Novokuzņecka)", + "Asia\/Novosibirsk": "Novosibirskas laiks (Novosibirska)", + "Asia\/Omsk": "Omskas laiks (Omska)", + "Asia\/Oral": "Rietumkazahstānas laiks (Orala)", + "Asia\/Phnom_Penh": "Indoķīnas laiks (Pnompeņa)", + "Asia\/Pontianak": "Rietumindonēzijas laiks (Pontianaka)", + "Asia\/Pyongyang": "Korejas laiks (Phenjana)", + "Asia\/Qatar": "Arābijas pussalas laiks (Katara)", + "Asia\/Qostanay": "Austrumkazahstānas laiks (Qostanay)", + "Asia\/Qyzylorda": "Rietumkazahstānas laiks (Kizilorda)", + "Asia\/Rangoon": "Mjanmas laiks (Ranguna)", + "Asia\/Riyadh": "Arābijas pussalas laiks (Rijāda)", + "Asia\/Saigon": "Indoķīnas laiks (Hošimina)", + "Asia\/Sakhalin": "Sahalīnas laiks (Sahalīna)", + "Asia\/Samarkand": "Uzbekistānas laiks (Samarkanda)", + "Asia\/Seoul": "Korejas laiks (Seula)", + "Asia\/Shanghai": "Ķīnas laiks (Šanhaja)", + "Asia\/Singapore": "Singapūras laiks (Singapūra)", + "Asia\/Srednekolymsk": "Magadanas laiks (Sredņekolimska)", + "Asia\/Taipei": "Taibei laiks (Taibei)", + "Asia\/Tashkent": "Uzbekistānas laiks (Taškenta)", + "Asia\/Tbilisi": "Gruzijas laiks (Tbilisi)", + "Asia\/Tehran": "Irānas laiks (Teherāna)", + "Asia\/Thimphu": "Butānas laiks (Thimphu)", + "Asia\/Tokyo": "Japānas laiks (Tokija)", + "Asia\/Ulaanbaatar": "Ulanbatoras laiks (Ulanbatora)", + "Asia\/Ust-Nera": "Vladivostokas laiks (Ustjņera)", + "Asia\/Vientiane": "Indoķīnas laiks (Vjenčana)", + "Asia\/Vladivostok": "Vladivostokas laiks (Vladivostoka)", + "Asia\/Yakutsk": "Jakutskas laiks (Jakutska)", + "Asia\/Yekaterinburg": "Jekaterinburgas laiks (Jekaterinburga)", + "Asia\/Yerevan": "Armēnijas laiks (Erevāna)", + "Atlantic\/Azores": "Azoru salu laiks (Azoru salas)", + "Atlantic\/Bermuda": "Atlantijas laiks (Bermuda)", + "Atlantic\/Canary": "Rietumeiropas laiks (Kanāriju salas)", + "Atlantic\/Cape_Verde": "Kaboverdes laiks (Kaboverde)", + "Atlantic\/Faeroe": "Rietumeiropas laiks (Fēru salas)", + "Atlantic\/Madeira": "Rietumeiropas laiks (Madeira)", + "Atlantic\/Reykjavik": "Griničas laiks (Reikjavika)", + "Atlantic\/South_Georgia": "Dienviddžordžijas laiks (Dienviddžordžija)", + "Atlantic\/St_Helena": "Griničas laiks (Sv.Helēnas sala)", + "Atlantic\/Stanley": "Folklenda (Malvinu) salu laiks (Stenli)", + "Australia\/Adelaide": "Austrālijas centrālais laiks (Adelaida)", + "Australia\/Brisbane": "Austrālijas austrumu laiks (Brisbena)", + "Australia\/Broken_Hill": "Austrālijas centrālais laiks (Brokenhila)", + "Australia\/Currie": "Austrālijas austrumu laiks (Kari)", + "Australia\/Darwin": "Austrālijas centrālais laiks (Dārvina)", + "Australia\/Eucla": "Austrālijas centrālais rietumu laiks (Jukla)", + "Australia\/Hobart": "Austrālijas austrumu laiks (Hobārta)", + "Australia\/Lindeman": "Austrālijas austrumu laiks (Lindemana)", + "Australia\/Lord_Howe": "Lorda Hava salas laiks (Lordhava)", + "Australia\/Melbourne": "Austrālijas austrumu laiks (Melburna)", + "Australia\/Perth": "Austrālijas rietumu laiks (Pērta)", + "Australia\/Sydney": "Austrālijas austrumu laiks (Sidneja)", + "CST6CDT": "Centrālais laiks", + "EST5EDT": "Austrumu laiks", + "Etc\/GMT": "Griničas laiks", + "Etc\/UTC": "Universālais koordinētais laiks", + "Europe\/Amsterdam": "Centrāleiropas laiks (Amsterdama)", + "Europe\/Andorra": "Centrāleiropas laiks (Andora)", + "Europe\/Astrakhan": "Maskavas laiks (Astrahaņa)", + "Europe\/Athens": "Austrumeiropas laiks (Atēnas)", + "Europe\/Belgrade": "Centrāleiropas laiks (Belgrada)", + "Europe\/Berlin": "Centrāleiropas laiks (Berlīne)", + "Europe\/Bratislava": "Centrāleiropas laiks (Bratislava)", + "Europe\/Brussels": "Centrāleiropas laiks (Brisele)", + "Europe\/Bucharest": "Austrumeiropas laiks (Bukareste)", + "Europe\/Budapest": "Centrāleiropas laiks (Budapešta)", + "Europe\/Busingen": "Centrāleiropas laiks (Bīzingene)", + "Europe\/Chisinau": "Austrumeiropas laiks (Kišiņeva)", + "Europe\/Copenhagen": "Centrāleiropas laiks (Kopenhāgena)", + "Europe\/Dublin": "Griničas laiks (Dublina)", + "Europe\/Gibraltar": "Centrāleiropas laiks (Gibraltārs)", + "Europe\/Guernsey": "Griničas laiks (Gērnsija)", + "Europe\/Helsinki": "Austrumeiropas laiks (Helsinki)", + "Europe\/Isle_of_Man": "Griničas laiks (Menas sala)", + "Europe\/Jersey": "Griničas laiks (Džērsija)", + "Europe\/Kaliningrad": "Austrumeiropas laiks (Kaļiņingrada)", + "Europe\/Kiev": "Austrumeiropas laiks (Kijeva)", + "Europe\/Lisbon": "Rietumeiropas laiks (Lisabona)", + "Europe\/Ljubljana": "Centrāleiropas laiks (Ļubļana)", + "Europe\/London": "Griničas laiks (Londona)", + "Europe\/Luxembourg": "Centrāleiropas laiks (Luksemburga)", + "Europe\/Madrid": "Centrāleiropas laiks (Madride)", + "Europe\/Malta": "Centrāleiropas laiks (Malta)", + "Europe\/Mariehamn": "Austrumeiropas laiks (Mariehamna)", + "Europe\/Minsk": "Maskavas laiks (Minska)", + "Europe\/Monaco": "Centrāleiropas laiks (Monako)", + "Europe\/Moscow": "Maskavas laiks (Maskava)", + "Europe\/Oslo": "Centrāleiropas laiks (Oslo)", + "Europe\/Paris": "Centrāleiropas laiks (Parīze)", + "Europe\/Podgorica": "Centrāleiropas laiks (Podgorica)", + "Europe\/Prague": "Centrāleiropas laiks (Prāga)", + "Europe\/Riga": "Austrumeiropas laiks (Rīga)", + "Europe\/Rome": "Centrāleiropas laiks (Roma)", + "Europe\/Samara": "Samaras laiks (Samara)", + "Europe\/San_Marino": "Centrāleiropas laiks (Sanmarīno)", + "Europe\/Sarajevo": "Centrāleiropas laiks (Sarajeva)", + "Europe\/Saratov": "Maskavas laiks (Saratova)", + "Europe\/Simferopol": "Maskavas laiks (Simferopole)", + "Europe\/Skopje": "Centrāleiropas laiks (Skopje)", + "Europe\/Sofia": "Austrumeiropas laiks (Sofija)", + "Europe\/Stockholm": "Centrāleiropas laiks (Stokholma)", + "Europe\/Tallinn": "Austrumeiropas laiks (Tallina)", + "Europe\/Tirane": "Centrāleiropas laiks (Tirāna)", + "Europe\/Ulyanovsk": "Maskavas laiks (Uļjanovska)", + "Europe\/Uzhgorod": "Austrumeiropas laiks (Užhoroda)", + "Europe\/Vaduz": "Centrāleiropas laiks (Vaduca)", + "Europe\/Vatican": "Centrāleiropas laiks (Vatikāns)", + "Europe\/Vienna": "Centrāleiropas laiks (Vīne)", + "Europe\/Vilnius": "Austrumeiropas laiks (Viļņa)", + "Europe\/Volgograd": "Volgogradas laiks (Volgograda)", + "Europe\/Warsaw": "Centrāleiropas laiks (Varšava)", + "Europe\/Zagreb": "Centrāleiropas laiks (Zagreba)", + "Europe\/Zaporozhye": "Austrumeiropas laiks (Zaporožje)", + "Europe\/Zurich": "Centrāleiropas laiks (Cīrihe)", + "Indian\/Antananarivo": "Austrumāfrikas laiks (Antananarivu)", + "Indian\/Chagos": "Indijas okeāna laiks (Čagosu arhipelāgs)", + "Indian\/Christmas": "Ziemsvētku salas laiks (Ziemsvētku sala)", + "Indian\/Cocos": "Kokosu (Kīlinga) salu laiks (Kokosu (Kīlinga) sala)", + "Indian\/Comoro": "Austrumāfrikas laiks (Komoras)", + "Indian\/Kerguelen": "Francijas Dienvidjūru un Antarktikas teritorijas laiks (Kergelēna sala)", + "Indian\/Mahe": "Seišeļu salu laiks (Mae)", + "Indian\/Maldives": "Maldīvijas laiks (Maldīvija)", + "Indian\/Mauritius": "Maurīcijas laiks (Maurīcija)", + "Indian\/Mayotte": "Austrumāfrikas laiks (Majota)", + "Indian\/Reunion": "Reinjonas laiks (Reinjona)", + "MST7MDT": "Kalnu laiks", + "PST8PDT": "Klusā okeāna laiks", + "Pacific\/Apia": "Apijas laiks (Apija)", + "Pacific\/Auckland": "Jaunzēlandes laiks (Oklenda)", + "Pacific\/Bougainville": "Papua-Jaungvinejas laiks (Bugenvila sala)", + "Pacific\/Chatham": "Četemas laiks (Četema)", + "Pacific\/Easter": "Lieldienu salas laiks (Lieldienu sala)", + "Pacific\/Efate": "Vanuatu laiks (Efate)", + "Pacific\/Enderbury": "Fēniksa salu laiks (Enderberija)", + "Pacific\/Fakaofo": "Tokelau laiks (Fakaofo)", + "Pacific\/Fiji": "Fidži laiks (Fidži)", + "Pacific\/Funafuti": "Tuvalu laiks (Funafuti)", + "Pacific\/Galapagos": "Galapagu laiks (Galapagu salas)", + "Pacific\/Gambier": "Gambjē salu laiks (Gambjē salas)", + "Pacific\/Guadalcanal": "Zālamana salu laiks (Gvadalkanala)", + "Pacific\/Guam": "Čamorra ziemas laiks (Guama)", + "Pacific\/Honolulu": "Havaju–Aleutu laiks (Honolulu)", + "Pacific\/Johnston": "Havaju–Aleutu laiks (Džonstona atols)", + "Pacific\/Kiritimati": "Lainas salu laiks (Kirisimasi)", + "Pacific\/Kosrae": "Kosrae laiks (Kosraja)", + "Pacific\/Kwajalein": "Māršala salu laiks (Kvadžaleina)", + "Pacific\/Majuro": "Māršala salu laiks (Madžuro)", + "Pacific\/Marquesas": "Marķīza salu laiks (Marķīza salas)", + "Pacific\/Midway": "Samoa laiks (Midvejs)", + "Pacific\/Nauru": "Nauru laiks (Nauru)", + "Pacific\/Niue": "Niues laiks (Niue)", + "Pacific\/Norfolk": "Norfolkas salas laiks (Norfolka)", + "Pacific\/Noumea": "Jaunkaledonijas laiks (Numea)", + "Pacific\/Pago_Pago": "Samoa laiks (Pagopago)", + "Pacific\/Palau": "Palau laiks (Palau)", + "Pacific\/Pitcairn": "Pitkērnas laiks (Pitkērna)", + "Pacific\/Ponape": "Ponapē laiks (Ponpeja)", + "Pacific\/Port_Moresby": "Papua-Jaungvinejas laiks (Portmorsbi)", + "Pacific\/Rarotonga": "Kuka salu laiks (Rarotonga)", + "Pacific\/Saipan": "Čamorra ziemas laiks (Saipana)", + "Pacific\/Tahiti": "Taiti laiks (Taiti)", + "Pacific\/Tarawa": "Gilberta salu laiks (Tarava)", + "Pacific\/Tongatapu": "Tongas laiks (Tongatapu)", + "Pacific\/Truk": "Čūkas laiks (Čūka)", + "Pacific\/Wake": "Veika salas laiks (Veika sala)", + "Pacific\/Wallis": "Volisas un Futunas laiks (Volisa)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/meta.json b/src/Symfony/Component/Intl/Resources/data/timezones/meta.json new file mode 100644 index 0000000000000..bcf8a6a395321 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/meta.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.47.82", + "Zones": [ + "Africa\/Abidjan", + "Africa\/Accra", + "Africa\/Addis_Ababa", + "Africa\/Algiers", + "Africa\/Asmera", + "Africa\/Bamako", + "Africa\/Bangui", + "Africa\/Banjul", + "Africa\/Bissau", + "Africa\/Blantyre", + "Africa\/Brazzaville", + "Africa\/Bujumbura", + "Africa\/Cairo", + "Africa\/Casablanca", + "Africa\/Ceuta", + "Africa\/Conakry", + "Africa\/Dakar", + "Africa\/Dar_es_Salaam", + "Africa\/Djibouti", + "Africa\/Douala", + "Africa\/El_Aaiun", + "Africa\/Freetown", + "Africa\/Gaborone", + "Africa\/Harare", + "Africa\/Johannesburg", + "Africa\/Juba", + "Africa\/Kampala", + "Africa\/Khartoum", + "Africa\/Kigali", + "Africa\/Kinshasa", + "Africa\/Lagos", + "Africa\/Libreville", + "Africa\/Lome", + "Africa\/Luanda", + "Africa\/Lubumbashi", + "Africa\/Lusaka", + "Africa\/Malabo", + "Africa\/Maputo", + "Africa\/Maseru", + "Africa\/Mbabane", + "Africa\/Mogadishu", + "Africa\/Monrovia", + "Africa\/Nairobi", + "Africa\/Ndjamena", + "Africa\/Niamey", + "Africa\/Nouakchott", + "Africa\/Ouagadougou", + "Africa\/Porto-Novo", + "Africa\/Sao_Tome", + "Africa\/Tripoli", + "Africa\/Tunis", + "Africa\/Windhoek", + "America\/Adak", + "America\/Anchorage", + "America\/Anguilla", + "America\/Antigua", + "America\/Araguaina", + "America\/Argentina\/La_Rioja", + "America\/Argentina\/Rio_Gallegos", + "America\/Argentina\/Salta", + "America\/Argentina\/San_Juan", + "America\/Argentina\/San_Luis", + "America\/Argentina\/Tucuman", + "America\/Argentina\/Ushuaia", + "America\/Aruba", + "America\/Asuncion", + "America\/Bahia", + "America\/Bahia_Banderas", + "America\/Barbados", + "America\/Belem", + "America\/Belize", + "America\/Blanc-Sablon", + "America\/Boa_Vista", + "America\/Bogota", + "America\/Boise", + "America\/Buenos_Aires", + "America\/Cambridge_Bay", + "America\/Campo_Grande", + "America\/Cancun", + "America\/Caracas", + "America\/Catamarca", + "America\/Cayenne", + "America\/Cayman", + "America\/Chicago", + "America\/Chihuahua", + "America\/Coral_Harbour", + "America\/Cordoba", + "America\/Costa_Rica", + "America\/Creston", + "America\/Cuiaba", + "America\/Curacao", + "America\/Danmarkshavn", + "America\/Dawson", + "America\/Dawson_Creek", + "America\/Denver", + "America\/Detroit", + "America\/Dominica", + "America\/Edmonton", + "America\/Eirunepe", + "America\/El_Salvador", + "America\/Fort_Nelson", + "America\/Fortaleza", + "America\/Glace_Bay", + "America\/Godthab", + "America\/Goose_Bay", + "America\/Grand_Turk", + "America\/Grenada", + "America\/Guadeloupe", + "America\/Guatemala", + "America\/Guayaquil", + "America\/Guyana", + "America\/Halifax", + "America\/Havana", + "America\/Hermosillo", + "America\/Indiana\/Knox", + "America\/Indiana\/Marengo", + "America\/Indiana\/Petersburg", + "America\/Indiana\/Tell_City", + "America\/Indiana\/Vevay", + "America\/Indiana\/Vincennes", + "America\/Indiana\/Winamac", + "America\/Indianapolis", + "America\/Inuvik", + "America\/Iqaluit", + "America\/Jamaica", + "America\/Jujuy", + "America\/Juneau", + "America\/Kentucky\/Monticello", + "America\/Kralendijk", + "America\/La_Paz", + "America\/Lima", + "America\/Los_Angeles", + "America\/Louisville", + "America\/Lower_Princes", + "America\/Maceio", + "America\/Managua", + "America\/Manaus", + "America\/Marigot", + "America\/Martinique", + "America\/Matamoros", + "America\/Mazatlan", + "America\/Mendoza", + "America\/Menominee", + "America\/Merida", + "America\/Metlakatla", + "America\/Mexico_City", + "America\/Miquelon", + "America\/Moncton", + "America\/Monterrey", + "America\/Montevideo", + "America\/Montserrat", + "America\/Nassau", + "America\/New_York", + "America\/Nipigon", + "America\/Nome", + "America\/Noronha", + "America\/North_Dakota\/Beulah", + "America\/North_Dakota\/Center", + "America\/North_Dakota\/New_Salem", + "America\/Ojinaga", + "America\/Panama", + "America\/Pangnirtung", + "America\/Paramaribo", + "America\/Phoenix", + "America\/Port-au-Prince", + "America\/Port_of_Spain", + "America\/Porto_Velho", + "America\/Puerto_Rico", + "America\/Punta_Arenas", + "America\/Rainy_River", + "America\/Rankin_Inlet", + "America\/Recife", + "America\/Regina", + "America\/Resolute", + "America\/Rio_Branco", + "America\/Santa_Isabel", + "America\/Santarem", + "America\/Santiago", + "America\/Santo_Domingo", + "America\/Sao_Paulo", + "America\/Scoresbysund", + "America\/Sitka", + "America\/St_Barthelemy", + "America\/St_Johns", + "America\/St_Kitts", + "America\/St_Lucia", + "America\/St_Thomas", + "America\/St_Vincent", + "America\/Swift_Current", + "America\/Tegucigalpa", + "America\/Thule", + "America\/Thunder_Bay", + "America\/Tijuana", + "America\/Toronto", + "America\/Tortola", + "America\/Vancouver", + "America\/Whitehorse", + "America\/Winnipeg", + "America\/Yakutat", + "America\/Yellowknife", + "Antarctica\/Casey", + "Antarctica\/Davis", + "Antarctica\/DumontDUrville", + "Antarctica\/Macquarie", + "Antarctica\/Mawson", + "Antarctica\/McMurdo", + "Antarctica\/Palmer", + "Antarctica\/Rothera", + "Antarctica\/Syowa", + "Antarctica\/Troll", + "Antarctica\/Vostok", + "Arctic\/Longyearbyen", + "Asia\/Aden", + "Asia\/Almaty", + "Asia\/Amman", + "Asia\/Anadyr", + "Asia\/Aqtau", + "Asia\/Aqtobe", + "Asia\/Ashgabat", + "Asia\/Atyrau", + "Asia\/Baghdad", + "Asia\/Bahrain", + "Asia\/Baku", + "Asia\/Bangkok", + "Asia\/Beirut", + "Asia\/Bishkek", + "Asia\/Brunei", + "Asia\/Calcutta", + "Asia\/Chita", + "Asia\/Choibalsan", + "Asia\/Colombo", + "Asia\/Damascus", + "Asia\/Dhaka", + "Asia\/Dili", + "Asia\/Dubai", + "Asia\/Dushanbe", + "Asia\/Famagusta", + "Asia\/Gaza", + "Asia\/Hebron", + "Asia\/Hong_Kong", + "Asia\/Hovd", + "Asia\/Irkutsk", + "Asia\/Jakarta", + "Asia\/Jayapura", + "Asia\/Jerusalem", + "Asia\/Kabul", + "Asia\/Kamchatka", + "Asia\/Karachi", + "Asia\/Katmandu", + "Asia\/Khandyga", + "Asia\/Krasnoyarsk", + "Asia\/Kuala_Lumpur", + "Asia\/Kuching", + "Asia\/Kuwait", + "Asia\/Macau", + "Asia\/Magadan", + "Asia\/Makassar", + "Asia\/Manila", + "Asia\/Muscat", + "Asia\/Nicosia", + "Asia\/Novokuznetsk", + "Asia\/Novosibirsk", + "Asia\/Omsk", + "Asia\/Oral", + "Asia\/Phnom_Penh", + "Asia\/Pontianak", + "Asia\/Pyongyang", + "Asia\/Qatar", + "Asia\/Qostanay", + "Asia\/Qyzylorda", + "Asia\/Rangoon", + "Asia\/Riyadh", + "Asia\/Saigon", + "Asia\/Sakhalin", + "Asia\/Samarkand", + "Asia\/Seoul", + "Asia\/Shanghai", + "Asia\/Singapore", + "Asia\/Srednekolymsk", + "Asia\/Taipei", + "Asia\/Tashkent", + "Asia\/Tbilisi", + "Asia\/Tehran", + "Asia\/Thimphu", + "Asia\/Tokyo", + "Asia\/Ulaanbaatar", + "Asia\/Ust-Nera", + "Asia\/Vientiane", + "Asia\/Vladivostok", + "Asia\/Yakutsk", + "Asia\/Yekaterinburg", + "Asia\/Yerevan", + "Atlantic\/Azores", + "Atlantic\/Bermuda", + "Atlantic\/Canary", + "Atlantic\/Cape_Verde", + "Atlantic\/Faeroe", + "Atlantic\/Madeira", + "Atlantic\/Reykjavik", + "Atlantic\/South_Georgia", + "Atlantic\/St_Helena", + "Atlantic\/Stanley", + "Australia\/Adelaide", + "Australia\/Brisbane", + "Australia\/Broken_Hill", + "Australia\/Currie", + "Australia\/Darwin", + "Australia\/Eucla", + "Australia\/Hobart", + "Australia\/Lindeman", + "Australia\/Lord_Howe", + "Australia\/Melbourne", + "Australia\/Perth", + "Australia\/Sydney", + "CST6CDT", + "EST5EDT", + "Etc\/GMT", + "Etc\/UTC", + "Europe\/Amsterdam", + "Europe\/Andorra", + "Europe\/Astrakhan", + "Europe\/Athens", + "Europe\/Belgrade", + "Europe\/Berlin", + "Europe\/Bratislava", + "Europe\/Brussels", + "Europe\/Bucharest", + "Europe\/Budapest", + "Europe\/Busingen", + "Europe\/Chisinau", + "Europe\/Copenhagen", + "Europe\/Dublin", + "Europe\/Gibraltar", + "Europe\/Guernsey", + "Europe\/Helsinki", + "Europe\/Isle_of_Man", + "Europe\/Jersey", + "Europe\/Kaliningrad", + "Europe\/Kiev", + "Europe\/Lisbon", + "Europe\/Ljubljana", + "Europe\/London", + "Europe\/Luxembourg", + "Europe\/Madrid", + "Europe\/Malta", + "Europe\/Mariehamn", + "Europe\/Minsk", + "Europe\/Monaco", + "Europe\/Moscow", + "Europe\/Oslo", + "Europe\/Paris", + "Europe\/Podgorica", + "Europe\/Prague", + "Europe\/Riga", + "Europe\/Rome", + "Europe\/Samara", + "Europe\/San_Marino", + "Europe\/Sarajevo", + "Europe\/Saratov", + "Europe\/Simferopol", + "Europe\/Skopje", + "Europe\/Sofia", + "Europe\/Stockholm", + "Europe\/Tallinn", + "Europe\/Tirane", + "Europe\/Ulyanovsk", + "Europe\/Uzhgorod", + "Europe\/Vaduz", + "Europe\/Vatican", + "Europe\/Vienna", + "Europe\/Vilnius", + "Europe\/Volgograd", + "Europe\/Warsaw", + "Europe\/Zagreb", + "Europe\/Zaporozhye", + "Europe\/Zurich", + "Indian\/Antananarivo", + "Indian\/Chagos", + "Indian\/Christmas", + "Indian\/Cocos", + "Indian\/Comoro", + "Indian\/Kerguelen", + "Indian\/Mahe", + "Indian\/Maldives", + "Indian\/Mauritius", + "Indian\/Mayotte", + "Indian\/Reunion", + "MST7MDT", + "PST8PDT", + "Pacific\/Apia", + "Pacific\/Auckland", + "Pacific\/Bougainville", + "Pacific\/Chatham", + "Pacific\/Easter", + "Pacific\/Efate", + "Pacific\/Enderbury", + "Pacific\/Fakaofo", + "Pacific\/Fiji", + "Pacific\/Funafuti", + "Pacific\/Galapagos", + "Pacific\/Gambier", + "Pacific\/Guadalcanal", + "Pacific\/Guam", + "Pacific\/Honolulu", + "Pacific\/Johnston", + "Pacific\/Kiritimati", + "Pacific\/Kosrae", + "Pacific\/Kwajalein", + "Pacific\/Majuro", + "Pacific\/Marquesas", + "Pacific\/Midway", + "Pacific\/Nauru", + "Pacific\/Niue", + "Pacific\/Norfolk", + "Pacific\/Noumea", + "Pacific\/Pago_Pago", + "Pacific\/Palau", + "Pacific\/Pitcairn", + "Pacific\/Ponape", + "Pacific\/Port_Moresby", + "Pacific\/Rarotonga", + "Pacific\/Saipan", + "Pacific\/Tahiti", + "Pacific\/Tarawa", + "Pacific\/Tongatapu", + "Pacific\/Truk", + "Pacific\/Wake", + "Pacific\/Wallis" + ] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/mi.json b/src/Symfony/Component/Intl/Resources/data/timezones/mi.json new file mode 100644 index 0000000000000..bb330ccd49978 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/mi.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.47.85", + "Names": { + "Africa\/Abidjan": "Wā Toharite Greenwich (Abidjan)", + "Africa\/Accra": "Wā Toharite Greenwich (Accra)", + "Africa\/Algiers": "Wā Uropi Waenga (Algiers)", + "Africa\/Bamako": "Wā Toharite Greenwich (Bamako)", + "Africa\/Banjul": "Wā Toharite Greenwich (Banjul)", + "Africa\/Bissau": "Wā Toharite Greenwich (Bissau)", + "Africa\/Cairo": "Wā Uropi Rāwhiti (Cairo)", + "Africa\/Casablanca": "Wā Uropi Uru (Casablanca)", + "Africa\/Ceuta": "Wā Uropi Waenga (Ceuta)", + "Africa\/Conakry": "Wā Toharite Greenwich (Conakry)", + "Africa\/Dakar": "Wā Toharite Greenwich (Dakar)", + "Africa\/El_Aaiun": "Wā Uropi Uru (El Aaiun)", + "Africa\/Freetown": "Wā Toharite Greenwich (Freetown)", + "Africa\/Lome": "Wā Toharite Greenwich (Lome)", + "Africa\/Monrovia": "Wā Toharite Greenwich (Monrovia)", + "Africa\/Nouakchott": "Wā Toharite Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Wā Toharite Greenwich (Ouagadougou)", + "Africa\/Sao_Tome": "Wā Toharite Greenwich (Sao Tome)", + "Africa\/Tripoli": "Wā Uropi Rāwhiti (Tripoli)", + "Africa\/Tunis": "Wā Uropi Waenga (Tunis)", + "America\/Anguilla": "Wā Ranatiki (Anguilla)", + "America\/Antigua": "Wā Ranatiki (Antigua)", + "America\/Aruba": "Wā Ranatiki (Aruba)", + "America\/Bahia_Banderas": "Wā Waenga (Bahia Banderas)", + "America\/Barbados": "Wā Ranatiki (Barbados)", + "America\/Belize": "Wā Waenga (Belize)", + "America\/Blanc-Sablon": "Wā Ranatiki (Blanc-Sablon)", + "America\/Boise": "Wā Maunga (Boise)", + "America\/Cambridge_Bay": "Wā Maunga (Cambridge Bay)", + "America\/Cancun": "Wā Rāwhiti (Cancun)", + "America\/Cayman": "Wā Rāwhiti (Cayman)", + "America\/Chicago": "Wā Waenga (Chicago)", + "America\/Coral_Harbour": "Wā Rāwhiti (Atikokan)", + "America\/Costa_Rica": "Wā Waenga (Costa Rica)", + "America\/Creston": "Wā Maunga (Creston)", + "America\/Curacao": "Wā Ranatiki (Curacao)", + "America\/Danmarkshavn": "Wā Toharite Greenwich (Danmarkshavn)", + "America\/Dawson": "Wā Kiwa (Dawson)", + "America\/Dawson_Creek": "Wā Maunga (Dawson Creek)", + "America\/Denver": "Wā Maunga (Denver)", + "America\/Detroit": "Wā Rāwhiti (Detroit)", + "America\/Dominica": "Wā Ranatiki (Dominica)", + "America\/Edmonton": "Wā Maunga (Edmonton)", + "America\/El_Salvador": "Wā Waenga (El Salvador)", + "America\/Fort_Nelson": "Wā Maunga (Fort Nelson)", + "America\/Glace_Bay": "Wā Ranatiki (Glace Bay)", + "America\/Goose_Bay": "Wā Ranatiki (Goose Bay)", + "America\/Grand_Turk": "Wā Rāwhiti (Grand Turk)", + "America\/Grenada": "Wā Ranatiki (Grenada)", + "America\/Guadeloupe": "Wā Ranatiki (Guadeloupe)", + "America\/Guatemala": "Wā Waenga (Guatemala)", + "America\/Halifax": "Wā Ranatiki (Halifax)", + "America\/Indiana\/Knox": "Wā Waenga (Knox, Indiana)", + "America\/Indiana\/Marengo": "Wā Rāwhiti (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Wā Rāwhiti (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Wā Waenga (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Wā Rāwhiti (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Wā Rāwhiti (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Wā Rāwhiti (Winamac, Indiana)", + "America\/Indianapolis": "Wā Rāwhiti (Indianapolis)", + "America\/Inuvik": "Wā Maunga (Inuvik)", + "America\/Iqaluit": "Wā Rāwhiti (Iqaluit)", + "America\/Jamaica": "Wā Rāwhiti (Jamaica)", + "America\/Kentucky\/Monticello": "Wā Rāwhiti (Monticello, Kentucky)", + "America\/Kralendijk": "Wā Ranatiki (Kralendijk)", + "America\/Los_Angeles": "Wā Kiwa (Los Angeles)", + "America\/Louisville": "Wā Rāwhiti (Louisville)", + "America\/Lower_Princes": "Wā Ranatiki (Lower Prince’s Quarter)", + "America\/Managua": "Wā Waenga (Managua)", + "America\/Marigot": "Wā Ranatiki (Marigot)", + "America\/Martinique": "Wā Ranatiki (Martinique)", + "America\/Matamoros": "Wā Waenga (Matamoros)", + "America\/Menominee": "Wā Waenga (Menominee)", + "America\/Merida": "Wā Waenga (Merida)", + "America\/Mexico_City": "Wā Waenga (Mexico City)", + "America\/Moncton": "Wā Ranatiki (Moncton)", + "America\/Monterrey": "Wā Waenga (Monterrey)", + "America\/Montserrat": "Wā Ranatiki (Montserrat)", + "America\/Nassau": "Wā Rāwhiti (Nassau)", + "America\/New_York": "Wā Rāwhiti (New York)", + "America\/Nipigon": "Wā Rāwhiti (Nipigon)", + "America\/North_Dakota\/Beulah": "Wā Waenga (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Wā Waenga (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Wā Waenga (New Salem, North Dakota)", + "America\/Ojinaga": "Wā Maunga (Ojinaga)", + "America\/Panama": "Wā Rāwhiti (Panama)", + "America\/Pangnirtung": "Wā Rāwhiti (Pangnirtung)", + "America\/Phoenix": "Wā Maunga (Phoenix)", + "America\/Port-au-Prince": "Wā Rāwhiti (Port-au-Prince)", + "America\/Port_of_Spain": "Wā Ranatiki (Port of Spain)", + "America\/Puerto_Rico": "Wā Ranatiki (Puerto Rico)", + "America\/Rainy_River": "Wā Waenga (Rainy River)", + "America\/Rankin_Inlet": "Wā Waenga (Rankin Inlet)", + "America\/Regina": "Wā Waenga (Regina)", + "America\/Resolute": "Wā Waenga (Resolute)", + "America\/Santo_Domingo": "Wā Ranatiki (Santo Domingo)", + "America\/St_Barthelemy": "Wā Ranatiki (St. Barthelemy)", + "America\/St_Kitts": "Wā Ranatiki (St. Kitts)", + "America\/St_Lucia": "Wā Ranatiki (St. Lucia)", + "America\/St_Thomas": "Wā Ranatiki (St. Thomas)", + "America\/St_Vincent": "Wā Ranatiki (St. Vincent)", + "America\/Swift_Current": "Wā Waenga (Swift Current)", + "America\/Tegucigalpa": "Wā Waenga (Tegucigalpa)", + "America\/Thule": "Wā Ranatiki (Thule)", + "America\/Thunder_Bay": "Wā Rāwhiti (Thunder Bay)", + "America\/Tijuana": "Wā Kiwa (Tijuana)", + "America\/Toronto": "Wā Rāwhiti (Toronto)", + "America\/Tortola": "Wā Ranatiki (Tortola)", + "America\/Vancouver": "Wā Kiwa (Vancouver)", + "America\/Whitehorse": "Wā Kiwa (Whitehorse)", + "America\/Winnipeg": "Wā Waenga (Winnipeg)", + "America\/Yellowknife": "Wā Maunga (Yellowknife)", + "Antarctica\/Troll": "Wā Toharite Greenwich (Troll)", + "Arctic\/Longyearbyen": "Wā Uropi Waenga (Longyearbyen)", + "Asia\/Amman": "Wā Uropi Rāwhiti (Amman)", + "Asia\/Beirut": "Wā Uropi Rāwhiti (Beirut)", + "Asia\/Damascus": "Wā Uropi Rāwhiti (Damascus)", + "Asia\/Famagusta": "Wā Uropi Rāwhiti (Famagusta)", + "Asia\/Gaza": "Wā Uropi Rāwhiti (Gaza)", + "Asia\/Hebron": "Wā Uropi Rāwhiti (Hebron)", + "Asia\/Nicosia": "Wā Uropi Rāwhiti (Nicosia)", + "Atlantic\/Bermuda": "Wā Ranatiki (Bermuda)", + "Atlantic\/Canary": "Wā Uropi Uru (Canary)", + "Atlantic\/Faeroe": "Wā Uropi Uru (Faroe)", + "Atlantic\/Madeira": "Wā Uropi Uru (Madeira)", + "Atlantic\/Reykjavik": "Wā Toharite Greenwich (Reykjavik)", + "Atlantic\/St_Helena": "Wā Toharite Greenwich (St. Helena)", + "CST6CDT": "Wā Waenga", + "EST5EDT": "Wā Rāwhiti", + "Etc\/GMT": "Wā Toharite Greenwich", + "Etc\/UTC": "Wā Aonui Kōtuitui", + "Europe\/Amsterdam": "Wā Uropi Waenga (Amsterdam)", + "Europe\/Andorra": "Wā Uropi Waenga (Andorra)", + "Europe\/Athens": "Wā Uropi Rāwhiti (Athens)", + "Europe\/Belgrade": "Wā Uropi Waenga (Belgrade)", + "Europe\/Berlin": "Wā Uropi Waenga (Berlin)", + "Europe\/Bratislava": "Wā Uropi Waenga (Bratislava)", + "Europe\/Brussels": "Wā Uropi Waenga (Brussels)", + "Europe\/Bucharest": "Wā Uropi Rāwhiti (Bucharest)", + "Europe\/Budapest": "Wā Uropi Waenga (Budapest)", + "Europe\/Busingen": "Wā Uropi Waenga (Busingen)", + "Europe\/Chisinau": "Wā Uropi Rāwhiti (Chisinau)", + "Europe\/Copenhagen": "Wā Uropi Waenga (Copenhagen)", + "Europe\/Dublin": "Wā Toharite Greenwich (Dublin)", + "Europe\/Gibraltar": "Wā Uropi Waenga (Gibraltar)", + "Europe\/Guernsey": "Wā Toharite Greenwich (Guernsey)", + "Europe\/Helsinki": "Wā Uropi Rāwhiti (Helsinki)", + "Europe\/Isle_of_Man": "Wā Toharite Greenwich (Isle of Man)", + "Europe\/Jersey": "Wā Toharite Greenwich (Jersey)", + "Europe\/Kaliningrad": "Wā Uropi Rāwhiti (Kaliningrad)", + "Europe\/Kiev": "Wā Uropi Rāwhiti (Kiev)", + "Europe\/Lisbon": "Wā Uropi Uru (Lisbon)", + "Europe\/Ljubljana": "Wā Uropi Waenga (Ljubljana)", + "Europe\/London": "Wā Toharite Greenwich (London)", + "Europe\/Luxembourg": "Wā Uropi Waenga (Luxembourg)", + "Europe\/Madrid": "Wā Uropi Waenga (Madrid)", + "Europe\/Malta": "Wā Uropi Waenga (Malta)", + "Europe\/Mariehamn": "Wā Uropi Rāwhiti (Mariehamn)", + "Europe\/Monaco": "Wā Uropi Waenga (Monaco)", + "Europe\/Oslo": "Wā Uropi Waenga (Oslo)", + "Europe\/Paris": "Wā Uropi Waenga (Paris)", + "Europe\/Podgorica": "Wā Uropi Waenga (Podgorica)", + "Europe\/Prague": "Wā Uropi Waenga (Prague)", + "Europe\/Riga": "Wā Uropi Rāwhiti (Riga)", + "Europe\/Rome": "Wā Uropi Waenga (Rome)", + "Europe\/San_Marino": "Wā Uropi Waenga (San Marino)", + "Europe\/Sarajevo": "Wā Uropi Waenga (Sarajevo)", + "Europe\/Skopje": "Wā Uropi Waenga (Skopje)", + "Europe\/Sofia": "Wā Uropi Rāwhiti (Sofia)", + "Europe\/Stockholm": "Wā Uropi Waenga (Stockholm)", + "Europe\/Tallinn": "Wā Uropi Rāwhiti (Tallinn)", + "Europe\/Tirane": "Wā Uropi Waenga (Tirane)", + "Europe\/Uzhgorod": "Wā Uropi Rāwhiti (Uzhgorod)", + "Europe\/Vaduz": "Wā Uropi Waenga (Vaduz)", + "Europe\/Vatican": "Wā Uropi Waenga (Vatican)", + "Europe\/Vienna": "Wā Uropi Waenga (Vienna)", + "Europe\/Vilnius": "Wā Uropi Rāwhiti (Vilnius)", + "Europe\/Warsaw": "Wā Uropi Waenga (Warsaw)", + "Europe\/Zagreb": "Wā Uropi Waenga (Zagreb)", + "Europe\/Zaporozhye": "Wā Uropi Rāwhiti (Zaporozhye)", + "Europe\/Zurich": "Wā Uropi Waenga (Zurich)", + "MST7MDT": "Wā Maunga", + "PST8PDT": "Wā Kiwa" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/mk.json b/src/Symfony/Component/Intl/Resources/data/timezones/mk.json new file mode 100644 index 0000000000000..d14409e03c4ed --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/mk.json @@ -0,0 +1,432 @@ +{ + "Version": "2.1.48.27", + "Names": { + "Africa\/Abidjan": "Средно време по Гринич (Абиџан)", + "Africa\/Accra": "Средно време по Гринич (Акра)", + "Africa\/Addis_Ababa": "Источноафриканско време (Адис Абеба)", + "Africa\/Algiers": "Средноевропско време (Алжир)", + "Africa\/Asmera": "Источноафриканско време (Асмара)", + "Africa\/Bamako": "Средно време по Гринич (Бамако)", + "Africa\/Bangui": "Западноафриканско време (Банги)", + "Africa\/Banjul": "Средно време по Гринич (Банџул)", + "Africa\/Bissau": "Средно време по Гринич (Бисау)", + "Africa\/Blantyre": "Средноафриканско време (Блантајр)", + "Africa\/Brazzaville": "Западноафриканско време (Бразавил)", + "Africa\/Bujumbura": "Средноафриканско време (Буџумбура)", + "Africa\/Cairo": "Источноевропско време (Каиро)", + "Africa\/Casablanca": "Западноевропско време (Казабланка)", + "Africa\/Ceuta": "Средноевропско време (Сеута)", + "Africa\/Conakry": "Средно време по Гринич (Конакри)", + "Africa\/Dakar": "Средно време по Гринич (Дакар)", + "Africa\/Dar_es_Salaam": "Источноафриканско време (Дар ес Салам)", + "Africa\/Djibouti": "Источноафриканско време (Џибути)", + "Africa\/Douala": "Западноафриканско време (Дуала)", + "Africa\/El_Aaiun": "Западноевропско време (Ел Ајун)", + "Africa\/Freetown": "Средно време по Гринич (Фритаун)", + "Africa\/Gaborone": "Средноафриканско време (Габороне)", + "Africa\/Harare": "Средноафриканско време (Хараре)", + "Africa\/Johannesburg": "Време во Јужноафриканска Република (Јоханесбург)", + "Africa\/Juba": "Источноафриканско време (Џуба)", + "Africa\/Kampala": "Источноафриканско време (Кампала)", + "Africa\/Khartoum": "Средноафриканско време (Картум)", + "Africa\/Kigali": "Средноафриканско време (Кигали)", + "Africa\/Kinshasa": "Западноафриканско време (Киншаса)", + "Africa\/Lagos": "Западноафриканско време (Лагос)", + "Africa\/Libreville": "Западноафриканско време (Либрвил)", + "Africa\/Lome": "Средно време по Гринич (Ломе)", + "Africa\/Luanda": "Западноафриканско време (Луанда)", + "Africa\/Lubumbashi": "Средноафриканско време (Лубумбаши)", + "Africa\/Lusaka": "Средноафриканско време (Лусака)", + "Africa\/Malabo": "Западноафриканско време (Малабо)", + "Africa\/Maputo": "Средноафриканско време (Мапуто)", + "Africa\/Maseru": "Време во Јужноафриканска Република (Масеру)", + "Africa\/Mbabane": "Време во Јужноафриканска Република (Мбабане)", + "Africa\/Mogadishu": "Источноафриканско време (Могадишу)", + "Africa\/Monrovia": "Средно време по Гринич (Монровија)", + "Africa\/Nairobi": "Источноафриканско време (Најроби)", + "Africa\/Ndjamena": "Западноафриканско време (Нџамена)", + "Africa\/Niamey": "Западноафриканско време (Нијамеј)", + "Africa\/Nouakchott": "Средно време по Гринич (Нуакшот)", + "Africa\/Ouagadougou": "Средно време по Гринич (Уагадугу)", + "Africa\/Porto-Novo": "Западноафриканско време (Порто Ново)", + "Africa\/Sao_Tome": "Средно време по Гринич (Саун Томе)", + "Africa\/Tripoli": "Источноевропско време (Триполи)", + "Africa\/Tunis": "Средноевропско време (Тунис)", + "Africa\/Windhoek": "Средноафриканско време (Виндхук)", + "America\/Adak": "Време во Хаваи - Алеутски острови (Адак)", + "America\/Anchorage": "Време во Алјаска (Енкориџ)", + "America\/Anguilla": "Атлантско време (Ангвила)", + "America\/Antigua": "Атлантско време (Антига)", + "America\/Araguaina": "Време во Бразилија (Арагвајана)", + "America\/Argentina\/La_Rioja": "Време во Аргентина (Ла Риоха)", + "America\/Argentina\/Rio_Gallegos": "Време во Аргентина (Рио Галегос)", + "America\/Argentina\/Salta": "Време во Аргентина (Салта)", + "America\/Argentina\/San_Juan": "Време во Аргентина (Сан Хуан)", + "America\/Argentina\/San_Luis": "Време во западна Аргентина (Сан Луис)", + "America\/Argentina\/Tucuman": "Време во Аргентина (Тукуман)", + "America\/Argentina\/Ushuaia": "Време во Аргентина (Ушуаја)", + "America\/Aruba": "Атлантско време (Аруба)", + "America\/Asuncion": "Време во Парагвај (Асунсион)", + "America\/Bahia": "Време во Бразилија (Бахиа)", + "America\/Bahia_Banderas": "Централно време во Северна Америка (Бахија де Бандерас)", + "America\/Barbados": "Атлантско време (Барбадос)", + "America\/Belem": "Време во Бразилија (Белем)", + "America\/Belize": "Централно време во Северна Америка (Белизе)", + "America\/Blanc-Sablon": "Атлантско време (Бланк-Сејблон)", + "America\/Boa_Vista": "Време во Амазон (Боа Виста)", + "America\/Bogota": "Време во Колумбија (Богота)", + "America\/Boise": "Планинско време (Бојзи)", + "America\/Buenos_Aires": "Време во Аргентина (Буенос Аирес)", + "America\/Cambridge_Bay": "Планинско време (Кембриџ Беј)", + "America\/Campo_Grande": "Време во Амазон (Кампо Гранде)", + "America\/Cancun": "Источно време (Канкун)", + "America\/Caracas": "Време во Венецуела (Каракас)", + "America\/Catamarca": "Време во Аргентина (Катамарка)", + "America\/Cayenne": "Време во Француска Гвајана (Кајена)", + "America\/Cayman": "Источно време (Кајмански Острови)", + "America\/Chicago": "Централно време во Северна Америка (Чикаго)", + "America\/Chihuahua": "Пацифичко време во Мексико (Чивава)", + "America\/Coral_Harbour": "Источно време (Корал Харбор)", + "America\/Cordoba": "Време во Аргентина (Кордоба)", + "America\/Costa_Rica": "Централно време во Северна Америка (Костарика)", + "America\/Creston": "Планинско време (Крестон)", + "America\/Cuiaba": "Време во Амазон (Кујаба)", + "America\/Curacao": "Атлантско време (Курасао)", + "America\/Danmarkshavn": "Средно време по Гринич (Данмаркшан)", + "America\/Dawson": "Пацифичко време (Досон)", + "America\/Dawson_Creek": "Планинско време (Досон Крик)", + "America\/Denver": "Планинско време (Денвер)", + "America\/Detroit": "Источно време (Детроит)", + "America\/Dominica": "Атлантско време (Доминика)", + "America\/Edmonton": "Планинско време (Едмонтон)", + "America\/Eirunepe": "Акре време (Еирунепе)", + "America\/El_Salvador": "Централно време во Северна Америка (Ел Салвадор)", + "America\/Fort_Nelson": "Планинско време (Форт Нелсон)", + "America\/Fortaleza": "Време во Бразилија (Форталеза)", + "America\/Glace_Bay": "Атлантско време (Глејс Беј)", + "America\/Godthab": "Време во Западен Гренланд (Нук)", + "America\/Goose_Bay": "Атлантско време (Гус Беј)", + "America\/Grand_Turk": "Источно време (Гранд Турк)", + "America\/Grenada": "Атлантско време (Гренада)", + "America\/Guadeloupe": "Атлантско време (Гвадалупе)", + "America\/Guatemala": "Централно време во Северна Америка (Гватемала)", + "America\/Guayaquil": "Време во Еквадор (Гвајакил)", + "America\/Guyana": "Време во Гвајана (Гвајана)", + "America\/Halifax": "Атлантско време (Халифакс)", + "America\/Havana": "Време во Куба (Хавана)", + "America\/Hermosillo": "Пацифичко време во Мексико (Ермосиљо)", + "America\/Indiana\/Knox": "Централно време во Северна Америка (Нокс, Индијана)", + "America\/Indiana\/Marengo": "Источно време (Маренго, Индијана)", + "America\/Indiana\/Petersburg": "Источно време (Питерсбург, Индијана)", + "America\/Indiana\/Tell_City": "Централно време во Северна Америка (Тел Сити, Индијана)", + "America\/Indiana\/Vevay": "Источно време (Вивеј, Индијана)", + "America\/Indiana\/Vincennes": "Источно време (Венсен, Индијана)", + "America\/Indiana\/Winamac": "Источно време (Винамак, Индијана)", + "America\/Indianapolis": "Источно време (Индијанаполис)", + "America\/Inuvik": "Планинско време (Инувик)", + "America\/Iqaluit": "Источно време (Икалуит)", + "America\/Jamaica": "Источно време (Јамајка)", + "America\/Jujuy": "Време во Аргентина (Хухуј)", + "America\/Juneau": "Време во Алјаска (Џуно)", + "America\/Kentucky\/Monticello": "Источно време (Монтичело, Кентаки)", + "America\/Kralendijk": "Атлантско време (Кралендајк)", + "America\/La_Paz": "Време во Боливија (Ла Паз)", + "America\/Lima": "Време во Перу (Лима)", + "America\/Los_Angeles": "Пацифичко време (Лос Анџелес)", + "America\/Louisville": "Источно време (Луизвил)", + "America\/Lower_Princes": "Атлантско време (Долен Принс квортр)", + "America\/Maceio": "Време во Бразилија (Масејо)", + "America\/Managua": "Централно време во Северна Америка (Манагва)", + "America\/Manaus": "Време во Амазон (Манаус)", + "America\/Marigot": "Атлантско време (Мариго)", + "America\/Martinique": "Атлантско време (Мартиник)", + "America\/Matamoros": "Централно време во Северна Америка (Матаморос)", + "America\/Mazatlan": "Пацифичко време во Мексико (Мазатлан)", + "America\/Mendoza": "Време во Аргентина (Мендоза)", + "America\/Menominee": "Централно време во Северна Америка (Меномини)", + "America\/Merida": "Централно време во Северна Америка (Мерида)", + "America\/Metlakatla": "Време во Алјаска (Метлакатла)", + "America\/Mexico_City": "Централно време во Северна Америка (Мексико Сити)", + "America\/Miquelon": "Време на на Сент Пјер и Микелан (Микелан)", + "America\/Moncton": "Атлантско време (Монктон)", + "America\/Monterrey": "Централно време во Северна Америка (Монтереј)", + "America\/Montevideo": "Време во Уругвај (Монтевидео)", + "America\/Montserrat": "Атлантско време (Монтсерат)", + "America\/Nassau": "Источно време (Насау)", + "America\/New_York": "Источно време (Њујорк)", + "America\/Nipigon": "Источно време (Нипигон)", + "America\/Nome": "Време во Алјаска (Ном)", + "America\/Noronha": "Време на Фернандо де Нороња (Нороња)", + "America\/North_Dakota\/Beulah": "Централно време во Северна Америка (Бјула, Северна Дакота)", + "America\/North_Dakota\/Center": "Централно време во Северна Америка (Центар, Северна Дакота)", + "America\/North_Dakota\/New_Salem": "Централно време во Северна Америка (Њу Салем, Северна Дакота)", + "America\/Ojinaga": "Планинско време (Охинага)", + "America\/Panama": "Источно време (Панама)", + "America\/Pangnirtung": "Источно време (Пангниртунг)", + "America\/Paramaribo": "Време во Суринам (Парамарибо)", + "America\/Phoenix": "Планинско време (Феникс)", + "America\/Port-au-Prince": "Источно време (Порт о Пренс)", + "America\/Port_of_Spain": "Атлантско време (Порт ов Спејн)", + "America\/Porto_Velho": "Време во Амазон (Порто Вељо)", + "America\/Puerto_Rico": "Атлантско време (Порторико)", + "America\/Punta_Arenas": "Време во Чиле (Пунта Аренас)", + "America\/Rainy_River": "Централно време во Северна Америка (Рејни Ривер)", + "America\/Rankin_Inlet": "Централно време во Северна Америка (Ренкин Инлет)", + "America\/Recife": "Време во Бразилија (Ресифи)", + "America\/Regina": "Централно време во Северна Америка (Реџајна)", + "America\/Resolute": "Централно време во Северна Америка (Резолут)", + "America\/Rio_Branco": "Акре време (Рио Бранко)", + "America\/Santa_Isabel": "Време во северозападно Мексико (Света Изабела)", + "America\/Santarem": "Време во Бразилија (Сантарем)", + "America\/Santiago": "Време во Чиле (Сантијаго)", + "America\/Santo_Domingo": "Атлантско време (Санто Доминго)", + "America\/Sao_Paulo": "Време во Бразилија (Сао Паоло)", + "America\/Scoresbysund": "Време во Источен Гренланд (Итокортормит)", + "America\/Sitka": "Време во Алјаска (Ситка)", + "America\/St_Barthelemy": "Атлантско време (Сент Бартоломеј)", + "America\/St_Johns": "Време на Њуфаундленд (Сент Џонс)", + "America\/St_Kitts": "Атлантско време (Свети Китс)", + "America\/St_Lucia": "Атлантско време (Сент Лусија)", + "America\/St_Thomas": "Атлантско време (Сент Томас)", + "America\/St_Vincent": "Атлантско време (Сент Винсент)", + "America\/Swift_Current": "Централно време во Северна Америка (Свифт Курент)", + "America\/Tegucigalpa": "Централно време во Северна Америка (Тегусигалпа)", + "America\/Thule": "Атлантско време (Туле)", + "America\/Thunder_Bay": "Источно време (Тандр Беј)", + "America\/Tijuana": "Пацифичко време (Тихуана)", + "America\/Toronto": "Источно време (Торонто)", + "America\/Tortola": "Атлантско време (Тортола)", + "America\/Vancouver": "Пацифичко време (Ванкувер)", + "America\/Whitehorse": "Пацифичко време (Вајтхорс)", + "America\/Winnipeg": "Централно време во Северна Америка (Винипег)", + "America\/Yakutat": "Време во Алјаска (Јакутат)", + "America\/Yellowknife": "Планинско време (Јелоунајф)", + "Antarctica\/Casey": "Време во Западна Австралија (Кејси)", + "Antarctica\/Davis": "Време во Дејвис (Дејвис)", + "Antarctica\/DumontDUrville": "Време во Димон Дирвил (Димон Дирвил)", + "Antarctica\/Macquarie": "Време на Островот Макуари (Маквори)", + "Antarctica\/Mawson": "Време во Мосон (Мосон)", + "Antarctica\/McMurdo": "Време во Нов Зеланд (Макмурдо)", + "Antarctica\/Palmer": "Време во Чиле (Палмер)", + "Antarctica\/Rothera": "Време во Ротера (Ротера)", + "Antarctica\/Syowa": "Време во Сајова (Сајова)", + "Antarctica\/Troll": "Средно време по Гринич (Трол)", + "Antarctica\/Vostok": "Време во Восток (Восток)", + "Arctic\/Longyearbyen": "Средноевропско време (Лонгјирбјен)", + "Asia\/Aden": "Арапско време (Аден)", + "Asia\/Almaty": "Време во Источен Казахстан (Алмати)", + "Asia\/Amman": "Источноевропско време (Аман)", + "Asia\/Anadyr": "Анадирско време (Анадир)", + "Asia\/Aqtau": "Време во Западен Казахстан (Актау)", + "Asia\/Aqtobe": "Време во Западен Казахстан (Актобе)", + "Asia\/Ashgabat": "Време во Туркменистан (Ашкабад)", + "Asia\/Atyrau": "Време во Западен Казахстан (Атирау)", + "Asia\/Baghdad": "Арапско време (Багдад)", + "Asia\/Bahrain": "Арапско време (Бахреин)", + "Asia\/Baku": "Време во Азербејџан (Баку)", + "Asia\/Bangkok": "Време во Индокина (Бангкок)", + "Asia\/Beirut": "Источноевропско време (Бејрут)", + "Asia\/Bishkek": "Време во Киргистан (Бишкек)", + "Asia\/Brunei": "Време во Брунеј Дарусалам (Брунеј)", + "Asia\/Calcutta": "Време во Индија (Калкута)", + "Asia\/Chita": "Време во Јакутск (Чита)", + "Asia\/Choibalsan": "Време во Чојбалсан (Чојбалсан)", + "Asia\/Colombo": "Време во Индија (Коломбо)", + "Asia\/Damascus": "Источноевропско време (Дамаск)", + "Asia\/Dhaka": "Време во Бангладеш (Дака)", + "Asia\/Dili": "Време во Источен Тимор (Дили)", + "Asia\/Dubai": "Време на Мексиканскиот Залив (Дубаи)", + "Asia\/Dushanbe": "Време во Таџикистан (Душанбе)", + "Asia\/Famagusta": "Источноевропско време (Фамагуста)", + "Asia\/Gaza": "Источноевропско време (Газа)", + "Asia\/Hebron": "Источноевропско време (Хеброн)", + "Asia\/Hong_Kong": "Време во Хонг Конг (Хонг Конг)", + "Asia\/Hovd": "Време во Ховд (Ховд)", + "Asia\/Irkutsk": "Време во Иркутск (Иркутск)", + "Asia\/Jakarta": "Време во Западна Индонезија (Џакарта)", + "Asia\/Jayapura": "Време во Источна Индонезија (Џајапура)", + "Asia\/Jerusalem": "Време во Израел (Ерусалим)", + "Asia\/Kabul": "Време во Авганистан (Кабул)", + "Asia\/Karachi": "Време во Пакистан (Карачи)", + "Asia\/Katmandu": "Време во Непал (Катманду)", + "Asia\/Khandyga": "Време во Јакутск (Хандига)", + "Asia\/Krasnoyarsk": "Време во Краснојарск (Краснојарск)", + "Asia\/Kuala_Lumpur": "Време во Малезија (Куала Лумпур)", + "Asia\/Kuching": "Време во Малезија (Кучинг)", + "Asia\/Kuwait": "Арапско време (Кувајт)", + "Asia\/Macau": "Време во Кина (Макао)", + "Asia\/Magadan": "Време во Магадан (Магадан)", + "Asia\/Makassar": "Време во Централна Индонезија (Макасар)", + "Asia\/Manila": "Време во Филипини (Манила)", + "Asia\/Muscat": "Време на Мексиканскиот Залив (Мускат)", + "Asia\/Nicosia": "Источноевропско време (Никозија)", + "Asia\/Novokuznetsk": "Време во Краснојарск (Новокузњецк)", + "Asia\/Novosibirsk": "Време во Новосибирск (Новосибирск)", + "Asia\/Omsk": "Време во Омск (Омск)", + "Asia\/Oral": "Време во Западен Казахстан (Орал)", + "Asia\/Phnom_Penh": "Време во Индокина (Пном Пен)", + "Asia\/Pontianak": "Време во Западна Индонезија (Понтијанак)", + "Asia\/Pyongyang": "Време во Кореја (Пјонгјанг)", + "Asia\/Qatar": "Арапско време (Катар)", + "Asia\/Qostanay": "Време во Источен Казахстан (Костанај)", + "Asia\/Qyzylorda": "Време во Западен Казахстан (Кизилорда)", + "Asia\/Rangoon": "Време во Мјанмар (Рангун)", + "Asia\/Riyadh": "Арапско време (Ријад)", + "Asia\/Saigon": "Време во Индокина (Хо Ши Мин)", + "Asia\/Sakhalin": "Време во Сакалин (Сакалин)", + "Asia\/Samarkand": "Време во Узбекистан (Самарканд)", + "Asia\/Seoul": "Време во Кореја (Сеул)", + "Asia\/Shanghai": "Време во Кина (Шангај)", + "Asia\/Singapore": "Време во Сингапур (Сингапур)", + "Asia\/Srednekolymsk": "Време во Магадан (Среднеколимск)", + "Asia\/Taipei": "Време во Тајпеј (Тајпеј)", + "Asia\/Tashkent": "Време во Узбекистан (Ташкент)", + "Asia\/Tbilisi": "Време во Грузија (Тбилиси)", + "Asia\/Tehran": "Време во Иран (Техеран)", + "Asia\/Thimphu": "Време во Бутан (Тимпу)", + "Asia\/Tokyo": "Време во Јапонија (Токио)", + "Asia\/Ulaanbaatar": "Време во Улан Батор (Улан Батор)", + "Asia\/Ust-Nera": "Време во Владивосток (Уст-Нера)", + "Asia\/Vientiane": "Време во Индокина (Виентијан)", + "Asia\/Vladivostok": "Време во Владивосток (Владивосток)", + "Asia\/Yakutsk": "Време во Јакутск (Јакутск)", + "Asia\/Yekaterinburg": "Време во Екатеринбург (Екатеринбург)", + "Asia\/Yerevan": "Време во Ерменија (Ереван)", + "Atlantic\/Azores": "Време на Азорските Острови (Азорски Острови)", + "Atlantic\/Bermuda": "Атлантско време (Бермуди)", + "Atlantic\/Canary": "Западноевропско време (Канарски Острови)", + "Atlantic\/Cape_Verde": "Време на Кабо Верде (Кабо Верде)", + "Atlantic\/Faeroe": "Западноевропско време (Фарски Острови)", + "Atlantic\/Madeira": "Западноевропско време (Мадеира)", + "Atlantic\/Reykjavik": "Средно време по Гринич (Рејкјавик)", + "Atlantic\/South_Georgia": "Време во Јужна Грузија (Јужна Џорџија)", + "Atlantic\/St_Helena": "Средно време по Гринич (Света Елена)", + "Atlantic\/Stanley": "Време на Фолкландските Острови (Стенли)", + "Australia\/Adelaide": "Време во Централна Австралија (Аделаида)", + "Australia\/Brisbane": "Време во Источна Австралија (Бризбејн)", + "Australia\/Broken_Hill": "Време во Централна Австралија (Брокен Хил)", + "Australia\/Currie": "Време во Источна Австралија (Курие)", + "Australia\/Darwin": "Време во Централна Австралија (Дарвин)", + "Australia\/Eucla": "Време во Централна и Западна Австралија (Јукла)", + "Australia\/Hobart": "Време во Источна Австралија (Хобарт)", + "Australia\/Lindeman": "Време во Источна Австралија (Линдеман)", + "Australia\/Lord_Howe": "Време во Лорд Хау (Лорд Хау)", + "Australia\/Melbourne": "Време во Источна Австралија (Мелбурн)", + "Australia\/Perth": "Време во Западна Австралија (Перт)", + "Australia\/Sydney": "Време во Источна Австралија (Сиднеј)", + "CST6CDT": "Централно време во Северна Америка", + "EST5EDT": "Источно време", + "Etc\/GMT": "Средно време по Гринич", + "Etc\/UTC": "Координирано универзално време", + "Europe\/Amsterdam": "Средноевропско време (Амстердам)", + "Europe\/Andorra": "Средноевропско време (Андора)", + "Europe\/Astrakhan": "Време во Москва (Астрахан)", + "Europe\/Athens": "Источноевропско време (Атина)", + "Europe\/Belgrade": "Средноевропско време (Белград)", + "Europe\/Berlin": "Средноевропско време (Берлин)", + "Europe\/Bratislava": "Средноевропско време (Братислава)", + "Europe\/Brussels": "Средноевропско време (Брисел)", + "Europe\/Bucharest": "Источноевропско време (Букурешт)", + "Europe\/Budapest": "Средноевропско време (Будимпешта)", + "Europe\/Busingen": "Средноевропско време (Бисинген)", + "Europe\/Chisinau": "Источноевропско време (Кишинау)", + "Europe\/Copenhagen": "Средноевропско време (Копенхаген)", + "Europe\/Dublin": "Средно време по Гринич (Даблин)", + "Europe\/Gibraltar": "Средноевропско време (Гибралтар)", + "Europe\/Guernsey": "Средно време по Гринич (Гернзи)", + "Europe\/Helsinki": "Источноевропско време (Хелсинки)", + "Europe\/Isle_of_Man": "Средно време по Гринич (Остров Ман)", + "Europe\/Jersey": "Средно време по Гринич (Џерзи)", + "Europe\/Kaliningrad": "Источноевропско време (Калининград)", + "Europe\/Kiev": "Источноевропско време (Киев)", + "Europe\/Lisbon": "Западноевропско време (Лисабон)", + "Europe\/Ljubljana": "Средноевропско време (Љубљана)", + "Europe\/London": "Средно време по Гринич (Лондон)", + "Europe\/Luxembourg": "Средноевропско време (Луксембург)", + "Europe\/Madrid": "Средноевропско време (Мадрид)", + "Europe\/Malta": "Средноевропско време (Малта)", + "Europe\/Mariehamn": "Источноевропско време (Маријехамен)", + "Europe\/Minsk": "Време во Москва (Минск)", + "Europe\/Monaco": "Средноевропско време (Монако)", + "Europe\/Moscow": "Време во Москва (Москва)", + "Europe\/Oslo": "Средноевропско време (Осло)", + "Europe\/Paris": "Средноевропско време (Париз)", + "Europe\/Podgorica": "Средноевропско време (Подгорица)", + "Europe\/Prague": "Средноевропско време (Прага)", + "Europe\/Riga": "Источноевропско време (Рига)", + "Europe\/Rome": "Средноевропско време (Рим)", + "Europe\/Samara": "Самара време (Самара)", + "Europe\/San_Marino": "Средноевропско време (Сан Марино)", + "Europe\/Sarajevo": "Средноевропско време (Сараево)", + "Europe\/Saratov": "Време во Москва (Саратов)", + "Europe\/Simferopol": "Време во Москва (Симферопол)", + "Europe\/Skopje": "Средноевропско време (Скопје)", + "Europe\/Sofia": "Источноевропско време (Софија)", + "Europe\/Stockholm": "Средноевропско време (Стокхолм)", + "Europe\/Tallinn": "Источноевропско време (Талин)", + "Europe\/Tirane": "Средноевропско време (Тирана)", + "Europe\/Ulyanovsk": "Време во Москва (Улјановск)", + "Europe\/Uzhgorod": "Источноевропско време (Ужхород)", + "Europe\/Vaduz": "Средноевропско време (Вадуц)", + "Europe\/Vatican": "Средноевропско време (Ватикан)", + "Europe\/Vienna": "Средноевропско време (Виена)", + "Europe\/Vilnius": "Источноевропско време (Вилнус)", + "Europe\/Volgograd": "Време во Волгоград (Волгоград)", + "Europe\/Warsaw": "Средноевропско време (Варшава)", + "Europe\/Zagreb": "Средноевропско време (Загреб)", + "Europe\/Zaporozhye": "Источноевропско време (Запорожје)", + "Europe\/Zurich": "Средноевропско време (Цирих)", + "Indian\/Antananarivo": "Источноафриканско време (Антананариво)", + "Indian\/Chagos": "Време на Индиски океан (Чагос)", + "Indian\/Christmas": "Време на Божиќниот Остров (Божиќен Остров)", + "Indian\/Cocos": "Време на Кокосовите Острови (Кокосови Острови)", + "Indian\/Comoro": "Источноафриканско време (Комори)", + "Indian\/Kerguelen": "Француско јужно и антарктичко време (Кергелен)", + "Indian\/Mahe": "Време на Сејшели (Махе)", + "Indian\/Maldives": "Време на Малдиви (Малдиви)", + "Indian\/Mauritius": "Време на Маврициус (Маврициус)", + "Indian\/Mayotte": "Источноафриканско време (Мајот)", + "Indian\/Reunion": "Време на Ријунион (Ријунион)", + "MST7MDT": "Планинско време", + "PST8PDT": "Пацифичко време", + "Pacific\/Apia": "Време во Апија (Апија)", + "Pacific\/Auckland": "Време во Нов Зеланд (Окленд)", + "Pacific\/Bougainville": "Време во Папуа Нова Гвинеја (Буганвил)", + "Pacific\/Chatham": "Време во Чатам (Чатам)", + "Pacific\/Easter": "Време на Велигденскиот Остров (Велигденски Остров)", + "Pacific\/Efate": "Време во Вануату (Ефате)", + "Pacific\/Enderbury": "Време на Островите Феникс (Ендербери)", + "Pacific\/Fakaofo": "Време во Токелау (Факаофо)", + "Pacific\/Fiji": "Време во Фиџи (Фиџи)", + "Pacific\/Funafuti": "Време во Тувалу (Фунафути)", + "Pacific\/Galapagos": "Време во Галапагос (Галапагос)", + "Pacific\/Gambier": "Време во Гамбе (Гамбије)", + "Pacific\/Guadalcanal": "Време на Соломонските острови (Гвадалканал)", + "Pacific\/Guam": "Време во Чаморо (Гвам)", + "Pacific\/Honolulu": "Време во Хаваи - Алеутски острови (Хонолулу)", + "Pacific\/Johnston": "Време во Хаваи - Алеутски острови (Џонстон)", + "Pacific\/Kiritimati": "Време во Линиски Острови (Киритимати)", + "Pacific\/Kosrae": "Време во Косра (Косрае)", + "Pacific\/Kwajalein": "Време на Маршалски Острови (Кваџалејн)", + "Pacific\/Majuro": "Време на Маршалски Острови (Маџуро)", + "Pacific\/Marquesas": "Време во Маркесас (Маркески Острови)", + "Pacific\/Midway": "Време во Самоа (Мидвеј)", + "Pacific\/Nauru": "Време во Науру (Науру)", + "Pacific\/Niue": "Време во Ниуе (Ниуе)", + "Pacific\/Norfolk": "Време на Островите Норфолк (Норфолк)", + "Pacific\/Noumea": "Време во Нова Каледонија (Нумеа)", + "Pacific\/Pago_Pago": "Време во Самоа (Паго Паго)", + "Pacific\/Palau": "Време во Палау (Палау)", + "Pacific\/Pitcairn": "Време во Питкерн (Питкернски Острови)", + "Pacific\/Ponape": "Време во Понапе (Понпеј)", + "Pacific\/Port_Moresby": "Време во Папуа Нова Гвинеја (Порт Морсби)", + "Pacific\/Rarotonga": "Време на Островите Кук (Раротонга)", + "Pacific\/Saipan": "Време во Чаморо (Сајпан)", + "Pacific\/Tahiti": "Време во Тахити (Тахити)", + "Pacific\/Tarawa": "Време на Островите Гилберт (Тарава)", + "Pacific\/Tongatapu": "Време во Тонга (Тонгатапу)", + "Pacific\/Truk": "Време во Чуук (Чук)", + "Pacific\/Wake": "Време на островот Вејк (Вејк)", + "Pacific\/Wallis": "Време во Валис и Футуна (Валис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ml.json b/src/Symfony/Component/Intl/Resources/data/timezones/ml.json new file mode 100644 index 0000000000000..b5095a41c9ac9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ml.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "ഗ്രീൻവിച്ച് മീൻ സമയം (അബിദ്‌ജാൻ‌)", + "Africa\/Accra": "ഗ്രീൻവിച്ച് മീൻ സമയം (ആക്ര)", + "Africa\/Addis_Ababa": "കിഴക്കൻ ആഫ്രിക്ക സമയം (അഡിസ് അബാബ)", + "Africa\/Algiers": "സെൻട്രൽ യൂറോപ്യൻ സമയം (അൾജിയേഴ്‌സ്)", + "Africa\/Asmera": "കിഴക്കൻ ആഫ്രിക്ക സമയം (അസ്‍മാര)", + "Africa\/Bamako": "ഗ്രീൻവിച്ച് മീൻ സമയം (ബമാകോ)", + "Africa\/Bangui": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ബംഗുയി)", + "Africa\/Banjul": "ഗ്രീൻവിച്ച് മീൻ സമയം (ബഞ്ചുൽ)", + "Africa\/Bissau": "ഗ്രീൻവിച്ച് മീൻ സമയം (ബിസ്സാവു)", + "Africa\/Blantyre": "മധ്യ ആഫ്രിക്ക സമയം (ബ്ലാണ്ടെയർ‌)", + "Africa\/Brazzaville": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ബ്രാസവിൽ)", + "Africa\/Bujumbura": "മധ്യ ആഫ്രിക്ക സമയം (ബുജും‌ബുര)", + "Africa\/Cairo": "കിഴക്കൻ യൂറോപ്യൻ സമയം (കെയ്‌റോ)", + "Africa\/Casablanca": "പടിഞ്ഞാറൻ യൂറോപ്യൻ സമയം (കാസബ്ലാങ്ക)", + "Africa\/Ceuta": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ക്യൂട്ട)", + "Africa\/Conakry": "ഗ്രീൻവിച്ച് മീൻ സമയം (കൊണാക്രി)", + "Africa\/Dakar": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഡാക്കർ‌)", + "Africa\/Dar_es_Salaam": "കിഴക്കൻ ആഫ്രിക്ക സമയം (ദാർ എസ് സലാം)", + "Africa\/Djibouti": "കിഴക്കൻ ആഫ്രിക്ക സമയം (ദിജിബൗട്ടി)", + "Africa\/Douala": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ഡൗല)", + "Africa\/El_Aaiun": "പടിഞ്ഞാറൻ യൂറോപ്യൻ സമയം (എൽ‌ ഐയുൻ‌)", + "Africa\/Freetown": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഫ്രീടൗൺ)", + "Africa\/Gaborone": "മധ്യ ആഫ്രിക്ക സമയം (ഗാബറോൺ)", + "Africa\/Harare": "മധ്യ ആഫ്രിക്ക സമയം (ഹരാരെ)", + "Africa\/Johannesburg": "ദക്ഷിണാഫ്രിക്ക സ്റ്റാൻഡേർഡ് സമയം (ജോഹന്നാസ്ബർ‌ഗ്)", + "Africa\/Juba": "കിഴക്കൻ ആഫ്രിക്ക സമയം (ജുബ)", + "Africa\/Kampala": "കിഴക്കൻ ആഫ്രിക്ക സമയം (കമ്പാല)", + "Africa\/Khartoum": "മധ്യ ആഫ്രിക്ക സമയം (ഖാർ‌തൌം)", + "Africa\/Kigali": "മധ്യ ആഫ്രിക്ക സമയം (കിഗാലി)", + "Africa\/Kinshasa": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (കിൻഷാസ)", + "Africa\/Lagos": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ലാഗോസ്)", + "Africa\/Libreville": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ലിബ്രെവില്ല)", + "Africa\/Lome": "ഗ്രീൻവിച്ച് മീൻ സമയം (ലോം)", + "Africa\/Luanda": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ലുവാൻഡ)", + "Africa\/Lubumbashi": "മധ്യ ആഫ്രിക്ക സമയം (ലൂബുംബാഷി)", + "Africa\/Lusaka": "മധ്യ ആഫ്രിക്ക സമയം (ലുസാക)", + "Africa\/Malabo": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (മലാബോ)", + "Africa\/Maputo": "മധ്യ ആഫ്രിക്ക സമയം (മാപ്യുട്ടോ)", + "Africa\/Maseru": "ദക്ഷിണാഫ്രിക്ക സ്റ്റാൻഡേർഡ് സമയം (മസേറു)", + "Africa\/Mbabane": "ദക്ഷിണാഫ്രിക്ക സ്റ്റാൻഡേർഡ് സമയം (മബാബെയ്‌ൻ‌)", + "Africa\/Mogadishu": "കിഴക്കൻ ആഫ്രിക്ക സമയം (മൊഗാദിഷു)", + "Africa\/Monrovia": "ഗ്രീൻവിച്ച് മീൻ സമയം (മൺ‌റോവിയ)", + "Africa\/Nairobi": "കിഴക്കൻ ആഫ്രിക്ക സമയം (നയ്‌റോബി)", + "Africa\/Ndjamena": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (ജമെന)", + "Africa\/Niamey": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (നിയാമി)", + "Africa\/Nouakchott": "ഗ്രീൻവിച്ച് മീൻ സമയം (നൗവാക്‌ഷോട്ട്)", + "Africa\/Ouagadougou": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഔഗാദൗഗൗ)", + "Africa\/Porto-Novo": "പടിഞ്ഞാറൻ ആഫ്രിക്ക സമയം (പോർ‌ട്ടോ-നോവോ)", + "Africa\/Sao_Tome": "ഗ്രീൻവിച്ച് മീൻ സമയം (സാവോ ടോം‌)", + "Africa\/Tripoli": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ട്രിപൊളി)", + "Africa\/Tunis": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ട്യൂണിസ്)", + "Africa\/Windhoek": "മധ്യ ആഫ്രിക്ക സമയം (വിൻഡ്‌ഹോക്)", + "America\/Adak": "ഹവായ്-അലൂഷ്യൻ സമയം (അഡാക്)", + "America\/Anchorage": "അലാസ്‌ക സമയം (ആങ്കറേജ്)", + "America\/Anguilla": "അറ്റ്‌ലാന്റിക് സമയം (ആൻഗ്വില്ല)", + "America\/Antigua": "അറ്റ്‌ലാന്റിക് സമയം (ആൻറിഗ്വ)", + "America\/Araguaina": "ബ്രസീലിയ സമയം (അറഗ്വൈന)", + "America\/Argentina\/La_Rioja": "അർജന്റീന സമയം (ലാ റിയോജ)", + "America\/Argentina\/Rio_Gallegos": "അർജന്റീന സമയം (റിയോ ഗ്യാലഗോസ്)", + "America\/Argentina\/Salta": "അർജന്റീന സമയം (സാൽട്ട)", + "America\/Argentina\/San_Juan": "അർജന്റീന സമയം (സാൻ ജുവാൻ)", + "America\/Argentina\/San_Luis": "പടിഞ്ഞാറൻ അർജന്റീന സമയം (സാൻ ലൂയിസ്)", + "America\/Argentina\/Tucuman": "അർജന്റീന സമയം (റ്റുകുമാൻ)", + "America\/Argentina\/Ushuaia": "അർജന്റീന സമയം (ഉഷിയ)", + "America\/Aruba": "അറ്റ്‌ലാന്റിക് സമയം (അറൂബ)", + "America\/Asuncion": "പരാഗ്വേ സമയം (അസൻ‌ഷ്യൻ‌)", + "America\/Bahia": "ബ്രസീലിയ സമയം (ബഹിയ)", + "America\/Bahia_Banderas": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ബഹിയ ബൻഡാരസ്)", + "America\/Barbados": "അറ്റ്‌ലാന്റിക് സമയം (ബാർബഡോസ്)", + "America\/Belem": "ബ്രസീലിയ സമയം (ബെലം)", + "America\/Belize": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ബെലീസ്)", + "America\/Blanc-Sablon": "അറ്റ്‌ലാന്റിക് സമയം (ബ്ലാങ്ക് സാബ്ലോൺ)", + "America\/Boa_Vista": "ആമസോൺ സമയം (ബോവ വിസ്റ്റ)", + "America\/Bogota": "കൊളംബിയ സമയം (ബൊഗോട്ട)", + "America\/Boise": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ബൊയ്സി)", + "America\/Buenos_Aires": "അർജന്റീന സമയം (ബ്യൂണസ് ഐറിസ്)", + "America\/Cambridge_Bay": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (കേംബ്രിഡ്‌ജ് ബേ)", + "America\/Campo_Grande": "ആമസോൺ സമയം (ക്യാമ്പോ ഗ്രാൻഡെ)", + "America\/Cancun": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (കാൻകൂൺ)", + "America\/Caracas": "വെനിസ്വേല സമയം (കരാക്കസ്)", + "America\/Catamarca": "അർജന്റീന സമയം (‍ക്യാറ്റമാർക്ക)", + "America\/Cayenne": "ഫ്രഞ്ച് ഗയാന സമയം (കയീൻ‌)", + "America\/Cayman": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (കേമാൻ)", + "America\/Chicago": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ചിക്കാഗോ)", + "America\/Chihuahua": "മെക്സിക്കൻ പസഫിക് സമയം (ചിഹ്വാഹ)", + "America\/Coral_Harbour": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ഏറ്റികോക്കൺ)", + "America\/Cordoba": "അർജന്റീന സമയം (കോർഡോബ)", + "America\/Costa_Rica": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (കോസ്റ്റ റിക്ക)", + "America\/Creston": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ക്രെസ്റ്റൺ)", + "America\/Cuiaba": "ആമസോൺ സമയം (കുയ്‌ബ)", + "America\/Curacao": "അറ്റ്‌ലാന്റിക് സമയം (കുറാക്കാവോ)", + "America\/Danmarkshavn": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഡാൻമാർക്ക്ഷാവ്ൻ)", + "America\/Dawson": "വടക്കെ അമേരിക്കൻ പസഫിക് സമയം (ഡോവ്സൺ)", + "America\/Dawson_Creek": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ഡോവ്സൺ ക്രീക്ക്)", + "America\/Denver": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ഡെൻ‌വർ)", + "America\/Detroit": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ഡെട്രോയിറ്റ്)", + "America\/Dominica": "അറ്റ്‌ലാന്റിക് സമയം (ഡൊമിനിക്ക)", + "America\/Edmonton": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (എഡ്മോൺടൺ)", + "America\/Eirunepe": "എയ്ക്കർ സമയം (യെറുനീപ്പെ)", + "America\/El_Salvador": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (എൽ സാൽ‌വദോർ)", + "America\/Fort_Nelson": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ഫോർട്ട് നെൽസൺ)", + "America\/Fortaleza": "ബ്രസീലിയ സമയം (ഫോർട്ടലീസ)", + "America\/Glace_Bay": "അറ്റ്‌ലാന്റിക് സമയം (ഗ്ലെയ്സ് ബേ)", + "America\/Godthab": "പടിഞ്ഞാറൻ ഗ്രീൻലാൻഡ് സമയം (നൂക്ക്)", + "America\/Goose_Bay": "അറ്റ്‌ലാന്റിക് സമയം (ഗൂസ് ബേ)", + "America\/Grand_Turk": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ഗ്രാൻഡ് ടർക്ക്)", + "America\/Grenada": "അറ്റ്‌ലാന്റിക് സമയം (ഗ്രനേഡ)", + "America\/Guadeloupe": "അറ്റ്‌ലാന്റിക് സമയം (ഗ്വാഡലൂപ്പ്)", + "America\/Guatemala": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ഗ്വാട്ടിമാല)", + "America\/Guayaquil": "ഇക്വഡോർ സമയം (ഗുവായക്വിൽ)", + "America\/Guyana": "ഗയാന സമയം (ഗയാന)", + "America\/Halifax": "അറ്റ്‌ലാന്റിക് സമയം (ഹാലിഫാക്സ്)", + "America\/Havana": "ക്യൂബ സമയം (ഹവാന)", + "America\/Hermosillo": "മെക്സിക്കൻ പസഫിക് സമയം (ഹെർമോസില്ലോ)", + "America\/Indiana\/Knox": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (നോക്സ്, ഇൻഡ്യാന)", + "America\/Indiana\/Marengo": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (മരെങ്കോ, ഇൻഡ്യാന)", + "America\/Indiana\/Petersburg": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (പീറ്റേഴ്സ്ബർഗ്, ഇൻഡ്യാന)", + "America\/Indiana\/Tell_City": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (റ്റെൽ സിറ്റി, ഇൻഡ്യാന)", + "America\/Indiana\/Vevay": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (വിവെയ്, ഇൻഡ്യാന)", + "America\/Indiana\/Vincennes": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (വിൻസെൻസ്, ഇൻഡ്യാന)", + "America\/Indiana\/Winamac": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (വിനാമാക്, ഇൻഡ്യാന)", + "America\/Indianapolis": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ഇൻഡ്യാനാപോലീസ്)", + "America\/Inuvik": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ഇനുവിക്)", + "America\/Iqaluit": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ഇഖാലിത്)", + "America\/Jamaica": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ജമൈക്ക)", + "America\/Jujuy": "അർജന്റീന സമയം (ജുജുയ്)", + "America\/Juneau": "അലാസ്‌ക സമയം (ജൂനോ)", + "America\/Kentucky\/Monticello": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (മോണ്ടിസെല്ലോ, കെന്റക്കി)", + "America\/Kralendijk": "അറ്റ്‌ലാന്റിക് സമയം (കാർലൻഡിജെക്ക്)", + "America\/La_Paz": "ബൊളീവിയ സമയം (ലാ പാസ്)", + "America\/Lima": "പെറു സമയം (ലിമ)", + "America\/Los_Angeles": "വടക്കെ അമേരിക്കൻ പസഫിക് സമയം (ലോസ് എയ്ഞ്ചലസ്)", + "America\/Louisville": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ലൂയിസ്‌വില്ലെ)", + "America\/Lower_Princes": "അറ്റ്‌ലാന്റിക് സമയം (ലോവർ പ്രിൻസസ് ക്വാർട്ടർ)", + "America\/Maceio": "ബ്രസീലിയ സമയം (മാസിയോ)", + "America\/Managua": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (മനാഗ്വ)", + "America\/Manaus": "ആമസോൺ സമയം (മനൗസ്)", + "America\/Marigot": "അറ്റ്‌ലാന്റിക് സമയം (മാരിഗോ)", + "America\/Martinique": "അറ്റ്‌ലാന്റിക് സമയം (മാർട്ടിനിക്)", + "America\/Matamoros": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (മറ്റാമൊറോസ്)", + "America\/Mazatlan": "മെക്സിക്കൻ പസഫിക് സമയം (മസറ്റ്‌ലാൻ)", + "America\/Mendoza": "അർജന്റീന സമയം (മെൻഡോസ)", + "America\/Menominee": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (മെനോമിനീ)", + "America\/Merida": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (മെരിഡ)", + "America\/Metlakatla": "അലാസ്‌ക സമയം (മെഡ്‌ലകട്‌ലെ)", + "America\/Mexico_City": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (മെക്സിക്കോ സിറ്റി)", + "America\/Miquelon": "സെന്റ് പിയറി ആൻഡ് മിക്വലൻ സമയം (മിക്വലൻ)", + "America\/Moncton": "അറ്റ്‌ലാന്റിക് സമയം (മോംഗ്‌ടൻ)", + "America\/Monterrey": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (മോണ്ടെറി)", + "America\/Montevideo": "ഉറുഗ്വേ സമയം (മൊണ്ടെ‌വീഡിയോ)", + "America\/Montserrat": "അറ്റ്‌ലാന്റിക് സമയം (മൊണ്ടെസരത്ത്)", + "America\/Nassau": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (നാസൗ)", + "America\/New_York": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ന്യൂയോർക്ക്)", + "America\/Nipigon": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (നിപ്പിഗോൺ)", + "America\/Nome": "അലാസ്‌ക സമയം (നോം)", + "America\/Noronha": "ഫെർണാഡോ ഡി നൊറോൻഹ സമയം (നൊറോന)", + "America\/North_Dakota\/Beulah": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ബ്യൂല, വടക്കൻ ഡെക്കോട്ട)", + "America\/North_Dakota\/Center": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (സെന്റർ, വടക്കൻ ഡെക്കോട്ട)", + "America\/North_Dakota\/New_Salem": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ന്യൂ സെയ്‌ലം, വടക്കൻ ഡെക്കോട്ട)", + "America\/Ojinaga": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ഒജിൻഗ)", + "America\/Panama": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (പനാമ)", + "America\/Pangnirtung": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (പാൻഗ്‌നിറ്റംഗ്)", + "America\/Paramaribo": "സുരിനെയിം സമയം (പരാമാരിബോ)", + "America\/Phoenix": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (ഫീനിക്സ്)", + "America\/Port-au-Prince": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (പോർട്ടോപ്രിൻസ്)", + "America\/Port_of_Spain": "അറ്റ്‌ലാന്റിക് സമയം (പോർ‌ട്ട് ഓഫ് സ്‌പെയിൻ‌)", + "America\/Porto_Velho": "ആമസോൺ സമയം (പോർട്ടോ വെല്ലോ)", + "America\/Puerto_Rico": "അറ്റ്‌ലാന്റിക് സമയം (പ്യൂർട്ടോ റിക്കോ)", + "America\/Punta_Arenas": "ചിലി സമയം (പുന്റ അരീനസ്)", + "America\/Rainy_River": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (റെയ്നി റിവർ)", + "America\/Rankin_Inlet": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (റാങ്കിൻ ഇൻലെറ്റ്)", + "America\/Recife": "ബ്രസീലിയ സമയം (റെസീഫെ)", + "America\/Regina": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (റിജീന)", + "America\/Resolute": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (റെസല്യൂട്ട്)", + "America\/Rio_Branco": "എയ്ക്കർ സമയം (റിയോ ബ്രാങ്കോ)", + "America\/Santa_Isabel": "വടക്കുപടിഞ്ഞാറൻ മെക്സിക്കൻ സമയം (സാന്ത ഇസബേൽ)", + "America\/Santarem": "ബ്രസീലിയ സമയം (സാന്ററെം)", + "America\/Santiago": "ചിലി സമയം (സാന്റിയാഗോ)", + "America\/Santo_Domingo": "അറ്റ്‌ലാന്റിക് സമയം (സാന്തോ ഡോമിംഗോ)", + "America\/Sao_Paulo": "ബ്രസീലിയ സമയം (സാവോപോളോ)", + "America\/Scoresbysund": "കിഴക്കൻ ഗ്രീൻലാൻഡ് സമയം (ഇറ്റ്വാഖ്വാർടൂർമിറ്റ്)", + "America\/Sitka": "അലാസ്‌ക സമയം (സിറ്റ്‌കാ)", + "America\/St_Barthelemy": "അറ്റ്‌ലാന്റിക് സമയം (സെൻറ് ബർത്തലെമി)", + "America\/St_Johns": "ന്യൂഫൗണ്ട്‌ലാന്റ് സമയം (സെന്റ് ജോൺസ്)", + "America\/St_Kitts": "അറ്റ്‌ലാന്റിക് സമയം (സെന്റ് കിറ്റ്സ്)", + "America\/St_Lucia": "അറ്റ്‌ലാന്റിക് സമയം (സെൻറ് ലൂസിയ)", + "America\/St_Thomas": "അറ്റ്‌ലാന്റിക് സമയം (സെന്റ് തോമസ്)", + "America\/St_Vincent": "അറ്റ്‌ലാന്റിക് സമയം (സെന്റ് വിൻസെന്റ്)", + "America\/Swift_Current": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (സ്വിഫ്‌റ്റ് കറന്റ്)", + "America\/Tegucigalpa": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (ടെഗൂസിഗാൽപ)", + "America\/Thule": "അറ്റ്‌ലാന്റിക് സമയം (തൂളി)", + "America\/Thunder_Bay": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (തണ്ടർ ബേ)", + "America\/Tijuana": "വടക്കെ അമേരിക്കൻ പസഫിക് സമയം (തിയുവാന)", + "America\/Toronto": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം (ടൊറണ്ടോ)", + "America\/Tortola": "അറ്റ്‌ലാന്റിക് സമയം (ടോർ‌ട്ടോള)", + "America\/Vancouver": "വടക്കെ അമേരിക്കൻ പസഫിക് സമയം (വാൻ‌കൂവർ)", + "America\/Whitehorse": "വടക്കെ അമേരിക്കൻ പസഫിക് സമയം (വൈറ്റ്ഹോഴ്സ്)", + "America\/Winnipeg": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം (വിന്നിപെഗ്)", + "America\/Yakutat": "അലാസ്‌ക സമയം (യാകുറ്റാറ്റ്)", + "America\/Yellowknife": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം (യെല്ലോനൈഫ്)", + "Antarctica\/Casey": "പടിഞ്ഞാറൻ ഓസ്‌ട്രേലിയ സമയം (കാസെ)", + "Antarctica\/Davis": "ഡേവിസ് സമയം (ഡെയ്‌വിസ്)", + "Antarctica\/DumontDUrville": "ഡുമോണ്ട് ഡി ഉർവില്ലെ സമയം (ഡ്യൂമണ്ട് ഡി യുർവിൽ)", + "Antarctica\/Macquarie": "മക്വാറി ദ്വീപ് സമയം (മക്വയറി)", + "Antarctica\/Mawson": "മാസൺ സമയം (മാവ്സൺ)", + "Antarctica\/McMurdo": "ന്യൂസിലാൻഡ് സമയം (മാക്മർഡോ)", + "Antarctica\/Palmer": "ചിലി സമയം (പാമർ)", + "Antarctica\/Rothera": "റോഥെറ സമയം (റൊതീറ)", + "Antarctica\/Syowa": "സയോവ സമയം (സ്യോവ)", + "Antarctica\/Troll": "ഗ്രീൻവിച്ച് മീൻ സമയം (ട്രോൾ)", + "Antarctica\/Vostok": "വോസ്റ്റോക് സമയം (വോസ്റ്റോക്)", + "Arctic\/Longyearbyen": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ലംഗ്‍യെർബിൻ)", + "Asia\/Aden": "അറേബ്യൻ സമയം (ഏദെൻ)", + "Asia\/Almaty": "കിഴക്കൻ കസാഖിസ്ഥാൻ സമയം (അൽമാട്ടി)", + "Asia\/Amman": "കിഴക്കൻ യൂറോപ്യൻ സമയം (അമ്മാൻ‌)", + "Asia\/Anadyr": "അനാഡിർ സമയം (അനാഡിർ)", + "Asia\/Aqtau": "പടിഞ്ഞാറൻ കസാഖിസ്ഥാൻ സമയം (അക്തൗ)", + "Asia\/Aqtobe": "പടിഞ്ഞാറൻ കസാഖിസ്ഥാൻ സമയം (അഖ്‌തോബ്)", + "Asia\/Ashgabat": "തുർക്ക്‌മെനിസ്ഥാൻ സമയം (ആഷ്‌ഗാബട്ട്)", + "Asia\/Atyrau": "പടിഞ്ഞാറൻ കസാഖിസ്ഥാൻ സമയം (അറ്റിറോ)", + "Asia\/Baghdad": "അറേബ്യൻ സമയം (ബാഗ്‌ദാദ്)", + "Asia\/Bahrain": "അറേബ്യൻ സമയം (ബഹ്റിൻ)", + "Asia\/Baku": "അസർബൈജാൻ സമയം (ബാക്കു)", + "Asia\/Bangkok": "ഇൻഡോചൈന സമയം (ബാങ്കോക്ക്)", + "Asia\/Beirut": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ബെയ്‌റൂട്ട്)", + "Asia\/Bishkek": "കിർഗിസ്ഥാൻ സമയം (ബിഷ്‌കേക്)", + "Asia\/Brunei": "ബ്രൂണൈ ദാറുസ്സലാം സമയം (ബ്രൂണൈ)", + "Asia\/Calcutta": "ഇന്ത്യൻ സ്റ്റാൻഡേർഡ് സമയം (കൊൽ‌ക്കത്ത)", + "Asia\/Chita": "യാകസ്‌ക്ക് സമയം (ചീറ്റ)", + "Asia\/Choibalsan": "ചോയി‍ബൽസാൻ സമയം (ചൊയ്ബൽസൻ)", + "Asia\/Colombo": "ഇന്ത്യൻ സ്റ്റാൻഡേർഡ് സമയം (കൊളം‌ബോ)", + "Asia\/Damascus": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ദമാസ്കസ്)", + "Asia\/Dhaka": "ബംഗ്ലാദേശ് സമയം (ധാക്ക)", + "Asia\/Dili": "കിഴക്കൻ തിമോർ സമയം (ദിലി)", + "Asia\/Dubai": "ഗൾഫ് സ്റ്റാൻഡേർഡ് സമയം (ദുബായ്)", + "Asia\/Dushanbe": "താജിക്കിസ്ഥാൻ സമയം (ദുഷൻ‌ബെ)", + "Asia\/Famagusta": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ഫാമഗുസ്‌റ്റ)", + "Asia\/Gaza": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ഗാസ)", + "Asia\/Hebron": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ഹെബ്‌റോൺ)", + "Asia\/Hong_Kong": "ഹോങ്കോങ്ങ് സമയം (ഹോങ്കോംഗ്)", + "Asia\/Hovd": "ഹോഡ് സമയം (ഹോഡ്)", + "Asia\/Irkutsk": "ഇർകസ്ക് സമയം (ഇർകസ്ക്)", + "Asia\/Jakarta": "പടിഞ്ഞാറൻ ഇന്തോനേഷ്യ സമയം (ജക്കാർത്ത)", + "Asia\/Jayapura": "കിഴക്കൻ ഇന്തോനേഷ്യ സമയം (ജയപുര)", + "Asia\/Jerusalem": "ഇസ്രായേൽ സമയം (ജെറുസലേം)", + "Asia\/Kabul": "അഫ്‌ഗാനിസ്ഥാൻ സമയം (കാബൂൾ)", + "Asia\/Kamchatka": "പെട്രോപാവ്‌ലോസ്ക് കംചാസ്കി സമയം (കാംചട്ക)", + "Asia\/Karachi": "പാക്കിസ്ഥാൻ സമയം (കറാച്ചി)", + "Asia\/Katmandu": "നേപ്പാൾ സമയം (കാഠ്‌മണ്ഡു)", + "Asia\/Khandyga": "യാകസ്‌ക്ക് സമയം (കച്ചൻഗ)", + "Asia\/Krasnoyarsk": "ക്രാസ്‌നോയാർസ്‌ക് സമയം (ക്രാസ്നോയാസ്ക്)", + "Asia\/Kuala_Lumpur": "മലേഷ്യ സമയം (ക്വാലലം‌പൂർ‌‌)", + "Asia\/Kuching": "മലേഷ്യ സമയം (കുചിങ്)", + "Asia\/Kuwait": "അറേബ്യൻ സമയം (കുവൈത്ത്)", + "Asia\/Macau": "ചൈന സമയം (മക്കാവു)", + "Asia\/Magadan": "മഗാദൻ സമയം (മഗഡാൻ)", + "Asia\/Makassar": "മധ്യ ഇന്തോനേഷ്യ സമയം (മകസ്സർ)", + "Asia\/Manila": "ഫിലിപ്പൈൻ സമയം (മനില)", + "Asia\/Muscat": "ഗൾഫ് സ്റ്റാൻഡേർഡ് സമയം (മസ്കറ്റ്)", + "Asia\/Nicosia": "കിഴക്കൻ യൂറോപ്യൻ സമയം (നിക്കോഷ്യ)", + "Asia\/Novokuznetsk": "ക്രാസ്‌നോയാർസ്‌ക് സമയം (നോവോകുസെൻസ്‌ക്)", + "Asia\/Novosibirsk": "നോവോസിബിർസ്‌ക് സമയം (നൊവോസിബിർസ്ക്)", + "Asia\/Omsk": "ഓംസ്‌ക്ക് സമയം (ഒംസ്ക്)", + "Asia\/Oral": "പടിഞ്ഞാറൻ കസാഖിസ്ഥാൻ സമയം (ഓറൽ)", + "Asia\/Phnom_Penh": "ഇൻഡോചൈന സമയം (ഫെനോം പെൻ)", + "Asia\/Pontianak": "പടിഞ്ഞാറൻ ഇന്തോനേഷ്യ സമയം (പൊന്റിയാനക്)", + "Asia\/Pyongyang": "കൊറിയൻ സമയം (പ്യോംഗ്‌യാംഗ്)", + "Asia\/Qatar": "അറേബ്യൻ സമയം (ഖത്തർ)", + "Asia\/Qostanay": "കിഴക്കൻ കസാഖിസ്ഥാൻ സമയം (കോസ്റ്റനേ)", + "Asia\/Qyzylorda": "പടിഞ്ഞാറൻ കസാഖിസ്ഥാൻ സമയം (ഖിസിലോർഡ)", + "Asia\/Rangoon": "മ്യാൻമാർ സമയം (റങ്കൂൺ‌)", + "Asia\/Riyadh": "അറേബ്യൻ സമയം (റിയാദ്)", + "Asia\/Saigon": "ഇൻഡോചൈന സമയം (ഹോ ചി മിൻ സിറ്റി)", + "Asia\/Sakhalin": "സഖാലിൻ സമയം (സഖാലിൻ)", + "Asia\/Samarkand": "ഉസ്‌ബെക്കിസ്ഥാൻ സമയം (സമർക്കന്ദ്)", + "Asia\/Seoul": "കൊറിയൻ സമയം (സോൾ)", + "Asia\/Shanghai": "ചൈന സമയം (ഷാങ്‌ഹായി)", + "Asia\/Singapore": "സിംഗപ്പൂർ സ്റ്റാൻഡേർഡ് സമയം (സിംഗപ്പൂർ)", + "Asia\/Srednekolymsk": "മഗാദൻ സമയം (സ്രിഡ്‌നികോളിംസ്ക്)", + "Asia\/Taipei": "തായ്‌പെയ് സമയം (തായ്‌പെയ്)", + "Asia\/Tashkent": "ഉസ്‌ബെക്കിസ്ഥാൻ സമയം (താഷ്‌ക്കന്റ്)", + "Asia\/Tbilisi": "ജോർജ്ജിയ സമയം (തിബിലിസി)", + "Asia\/Tehran": "ഇറാൻ സമയം (ടെഹ്‌റാൻ‌)", + "Asia\/Thimphu": "ഭൂട്ടാൻ സമയം (തിംഫു)", + "Asia\/Tokyo": "ജപ്പാൻ സമയം (ടോക്കിയോ)", + "Asia\/Ulaanbaatar": "ഉലൻ ബറ്റർ സമയം (ഉലാൻബാത്തർ)", + "Asia\/Ust-Nera": "വ്ലാഡിവോസ്റ്റോക് സമയം (യുസ്-നേര)", + "Asia\/Vientiane": "ഇൻഡോചൈന സമയം (വെന്റിയാൻ)", + "Asia\/Vladivostok": "വ്ലാഡിവോസ്റ്റോക് സമയം (വ്ളാഡിവോസ്റ്റോക്)", + "Asia\/Yakutsk": "യാകസ്‌ക്ക് സമയം (യാക്കറ്റ്സ്‌ക്)", + "Asia\/Yekaterinburg": "യെക്കാറ്റരിൻബർഗ് സമയം (യാകാറ്റെറിൻബർഗ്)", + "Asia\/Yerevan": "അർമേനിയ സമയം (യേരവൻ‌)", + "Atlantic\/Azores": "അസോർസ് സമയം (അസോറസ്)", + "Atlantic\/Bermuda": "അറ്റ്‌ലാന്റിക് സമയം (ബർമുഡ)", + "Atlantic\/Canary": "പടിഞ്ഞാറൻ യൂറോപ്യൻ സമയം (ക്യാനറി)", + "Atlantic\/Cape_Verde": "കേപ് വെർദെ സമയം (കേപ് വെർദെ)", + "Atlantic\/Faeroe": "പടിഞ്ഞാറൻ യൂറോപ്യൻ സമയം (ഫെറോ)", + "Atlantic\/Madeira": "പടിഞ്ഞാറൻ യൂറോപ്യൻ സമയം (മഡെയ്റ)", + "Atlantic\/Reykjavik": "ഗ്രീൻവിച്ച് മീൻ സമയം (റേയ്‌ജാവിക്)", + "Atlantic\/South_Georgia": "ദക്ഷിണ ജോർജ്ജിയൻ സമയം (ദക്ഷിണ ജോർജിയ)", + "Atlantic\/St_Helena": "ഗ്രീൻവിച്ച് മീൻ സമയം (സെൻറ് ഹെലെന)", + "Atlantic\/Stanley": "ഫാക്ക്‌ലാൻഡ് ദ്വീപുകൾ സമയം (സ്റ്റാൻ‌ലി)", + "Australia\/Adelaide": "സെൻട്രൽ ഓസ്ട്രേലിയ സമയം (അഡിലെയ്‌ഡ്)", + "Australia\/Brisbane": "കിഴക്കൻ ഓസ്‌ട്രേലിയ സമയം (ബ്രിസ്‌ബെയിൻ)", + "Australia\/Broken_Hill": "സെൻട്രൽ ഓസ്ട്രേലിയ സമയം (ബ്രോക്കൺ ഹിൽ)", + "Australia\/Currie": "കിഴക്കൻ ഓസ്‌ട്രേലിയ സമയം (ക്യൂറി)", + "Australia\/Darwin": "സെൻട്രൽ ഓസ്ട്രേലിയ സമയം (ഡാർവിൻ)", + "Australia\/Eucla": "ഓസ്ട്രേലിയൻ സെൻട്രൽ പടിഞ്ഞാറൻ സമയം (യൂക്ല)", + "Australia\/Hobart": "കിഴക്കൻ ഓസ്‌ട്രേലിയ സമയം (ഹൊബാർട്ട്)", + "Australia\/Lindeman": "കിഴക്കൻ ഓസ്‌ട്രേലിയ സമയം (ലിൻഡെമാൻ)", + "Australia\/Lord_Howe": "ലോർഡ് ഹോവ് സമയം (ലോഡ് ഹോവ്)", + "Australia\/Melbourne": "കിഴക്കൻ ഓസ്‌ട്രേലിയ സമയം (മെൽബൺ)", + "Australia\/Perth": "പടിഞ്ഞാറൻ ഓസ്‌ട്രേലിയ സമയം (പെർത്ത്)", + "Australia\/Sydney": "കിഴക്കൻ ഓസ്‌ട്രേലിയ സമയം (സിഡ്നി)", + "CST6CDT": "വടക്കെ അമേരിക്കൻ സെൻട്രൽ സമയം", + "EST5EDT": "വടക്കെ അമേരിക്കൻ കിഴക്കൻ സമയം", + "Etc\/GMT": "ഗ്രീൻവിച്ച് മീൻ സമയം", + "Etc\/UTC": "കോർഡിനേറ്റഡ് യൂണിവേഴ്‌സൽ ടൈം", + "Europe\/Amsterdam": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ആം‌സ്റ്റർ‌ഡാം)", + "Europe\/Andorra": "സെൻട്രൽ യൂറോപ്യൻ സമയം (അണ്ടോറ)", + "Europe\/Astrakhan": "മോസ്കോ സമയം (അസ്‌ട്രഖാൻ)", + "Europe\/Athens": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ഏതൻ‌സ്)", + "Europe\/Belgrade": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ബെൽഗ്രേഡ്)", + "Europe\/Berlin": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ബെർ‌ലിൻ‌)", + "Europe\/Bratislava": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ബ്രാട്ടിസ്‍ലാവ)", + "Europe\/Brussels": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ബ്രസ്സൽ‌സ്)", + "Europe\/Bucharest": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ബുച്ചാറെസ്റ്റ്)", + "Europe\/Budapest": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ബുഡാപെസ്റ്റ്)", + "Europe\/Busingen": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ബുസിൻജൻ)", + "Europe\/Chisinau": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ചിസിനാവു)", + "Europe\/Copenhagen": "സെൻട്രൽ യൂറോപ്യൻ സമയം (കോപ്പൻ‌ഹേഗൻ‌)", + "Europe\/Dublin": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഡബ്ലിൻ)", + "Europe\/Gibraltar": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ജിബ്രാൾട്ടർ)", + "Europe\/Guernsey": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഗേൺസേ)", + "Europe\/Helsinki": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ഹെൽ‌സിങ്കി)", + "Europe\/Isle_of_Man": "ഗ്രീൻവിച്ച് മീൻ സമയം (ഐൽ‌ ഓഫ് മാൻ‌)", + "Europe\/Jersey": "ഗ്രീൻവിച്ച് മീൻ സമയം (ജേഴ്‌സി)", + "Europe\/Kaliningrad": "കിഴക്കൻ യൂറോപ്യൻ സമയം (കലിനിൻഗ്രാഡ്)", + "Europe\/Kiev": "കിഴക്കൻ യൂറോപ്യൻ സമയം (കീവ്)", + "Europe\/Lisbon": "പടിഞ്ഞാറൻ യൂറോപ്യൻ സമയം (ലിസ്‌ബൺ‌)", + "Europe\/Ljubljana": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ലുബ്‍ലിയാന)", + "Europe\/London": "ഗ്രീൻവിച്ച് മീൻ സമയം (ലണ്ടൻ‌)", + "Europe\/Luxembourg": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ലക്‌സംബർഗ്)", + "Europe\/Madrid": "സെൻട്രൽ യൂറോപ്യൻ സമയം (മാഡ്രിഡ്)", + "Europe\/Malta": "സെൻട്രൽ യൂറോപ്യൻ സമയം (മാൾട്ട)", + "Europe\/Mariehamn": "കിഴക്കൻ യൂറോപ്യൻ സമയം (മരിയാഹാമൻ)", + "Europe\/Minsk": "മോസ്കോ സമയം (മിൻ‌സ്ക്)", + "Europe\/Monaco": "സെൻട്രൽ യൂറോപ്യൻ സമയം (മൊണാക്കോ)", + "Europe\/Moscow": "മോസ്കോ സമയം (മോസ്കോ)", + "Europe\/Oslo": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ഓസ്ലോ)", + "Europe\/Paris": "സെൻട്രൽ യൂറോപ്യൻ സമയം (പാരീസ്)", + "Europe\/Podgorica": "സെൻട്രൽ യൂറോപ്യൻ സമയം (പൊഡ്‍ഗൊറിസ)", + "Europe\/Prague": "സെൻട്രൽ യൂറോപ്യൻ സമയം (പ്രാഗ്)", + "Europe\/Riga": "കിഴക്കൻ യൂറോപ്യൻ സമയം (റിഗ)", + "Europe\/Rome": "സെൻട്രൽ യൂറോപ്യൻ സമയം (റോം)", + "Europe\/Samara": "സമാര സമയം (സമാറ)", + "Europe\/San_Marino": "സെൻട്രൽ യൂറോപ്യൻ സമയം (സാൻ മാരിനോ)", + "Europe\/Sarajevo": "സെൻട്രൽ യൂറോപ്യൻ സമയം (സരയേവോ)", + "Europe\/Saratov": "മോസ്കോ സമയം (സരാറ്റോവ്)", + "Europe\/Simferopol": "മോസ്കോ സമയം (സിംഫെറോപോൾ)", + "Europe\/Skopje": "സെൻട്രൽ യൂറോപ്യൻ സമയം (സ്കോപ്പിയെ)", + "Europe\/Sofia": "കിഴക്കൻ യൂറോപ്യൻ സമയം (സോഫിയ)", + "Europe\/Stockholm": "സെൻട്രൽ യൂറോപ്യൻ സമയം (സ്റ്റോക്ക്ഹോം)", + "Europe\/Tallinn": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ടാലിൻ‌)", + "Europe\/Tirane": "സെൻട്രൽ യൂറോപ്യൻ സമയം (ടിരാനെ)", + "Europe\/Ulyanovsk": "മോസ്കോ സമയം (ഉല്ല്യാനോവ്‌സ്‌ക്)", + "Europe\/Uzhgorod": "കിഴക്കൻ യൂറോപ്യൻ സമയം (ഉസ്ഗൊറോഡ്)", + "Europe\/Vaduz": "സെൻട്രൽ യൂറോപ്യൻ സമയം (വാദുസ്)", + "Europe\/Vatican": "സെൻട്രൽ യൂറോപ്യൻ സമയം (വത്തിക്കാൻ)", + "Europe\/Vienna": "സെൻട്രൽ യൂറോപ്യൻ സമയം (വിയന്ന)", + "Europe\/Vilnius": "കിഴക്കൻ യൂറോപ്യൻ സമയം (വിൽ‌നിയസ്)", + "Europe\/Volgograd": "വോൾഗോഗ്രാഡ് സമയം (വോൾഗോഗ്രാഡ്)", + "Europe\/Warsaw": "സെൻട്രൽ യൂറോപ്യൻ സമയം (വാർസോ)", + "Europe\/Zagreb": "സെൻട്രൽ യൂറോപ്യൻ സമയം (സാക്രെബ്)", + "Europe\/Zaporozhye": "കിഴക്കൻ യൂറോപ്യൻ സമയം (സാപ്പറോസൈ)", + "Europe\/Zurich": "സെൻട്രൽ യൂറോപ്യൻ സമയം (സൂറിച്ച്)", + "Indian\/Antananarivo": "കിഴക്കൻ ആഫ്രിക്ക സമയം (അൻറാനനറിവോ)", + "Indian\/Chagos": "ഇന്ത്യൻ മഹാസമുദ്ര സമയം (ചാഗോസ്)", + "Indian\/Christmas": "ക്രിസ്‌മസ് ദ്വീപ് സമയം (ക്രിസ്തുമസ്)", + "Indian\/Cocos": "കൊക്കോസ് ദ്വീപുകൾ സമയം (കോക്കോസ്)", + "Indian\/Comoro": "കിഴക്കൻ ആഫ്രിക്ക സമയം (കൊമോറോ)", + "Indian\/Kerguelen": "ഫ്രഞ്ച് സതേൺ, അന്റാർട്ടിക് സമയം (കെർഗുലെൻ)", + "Indian\/Mahe": "സീഷെൽസ് സമയം (മാഹി)", + "Indian\/Maldives": "മാലിദ്വീപുകൾ സമയം (മാലിദ്വീപുകൾ)", + "Indian\/Mauritius": "മൗറീഷ്യസ് സമയം (മൌറീഷ്യസ്)", + "Indian\/Mayotte": "കിഴക്കൻ ആഫ്രിക്ക സമയം (മയോട്ടി)", + "Indian\/Reunion": "റീയൂണിയൻ സമയം (റീയൂണിയൻ)", + "MST7MDT": "വടക്കെ അമേരിക്കൻ മൌണ്ടൻ സമയം", + "PST8PDT": "വടക്കെ അമേരിക്കൻ പസഫിക് സമയം", + "Pacific\/Apia": "അപിയ സമയം (ആപിയ)", + "Pacific\/Auckland": "ന്യൂസിലാൻഡ് സമയം (ഓക്ക്‌ലാന്റ്)", + "Pacific\/Bougainville": "പാപ്പുവ ന്യൂ ഗിനിയ സമയം (ബോഗൺവില്ലെ)", + "Pacific\/Chatham": "ചാത്തം സമയം (ചാത്തം)", + "Pacific\/Easter": "ഈസ്റ്റർ ദ്വീപ് സമയം (ഈസ്റ്റർ)", + "Pacific\/Efate": "വന്വാതു സമയം (ഇഫാതെ)", + "Pacific\/Enderbury": "ഫിനിക്‌സ് ദ്വീപുകൾ സമയം (എൻഡബറി)", + "Pacific\/Fakaofo": "ടോക്കെലൂ സമയം (ഫക്കാവോഫോ)", + "Pacific\/Fiji": "ഫിജി സമയം (ഫിജി)", + "Pacific\/Funafuti": "ടുവാലു സമയം (ഫുണാഫുട്ടി)", + "Pacific\/Galapagos": "ഗാലപ്പഗോസ് സമയം (ഗാലപ്പാഗോസ്)", + "Pacific\/Gambier": "ഗാമ്പിയർ സമയം (ഗാമ്പിയർ)", + "Pacific\/Guadalcanal": "സോളമൻ ദ്വീപുകൾ സമയം (ഗ്വാഡൽകനാൽ)", + "Pacific\/Guam": "ചമോറോ സ്റ്റാൻഡേർഡ് സമയം (ഗ്വാം)", + "Pacific\/Honolulu": "ഹവായ്-അലൂഷ്യൻ സമയം (ഹോണലൂലു)", + "Pacific\/Johnston": "ഹവായ്-അലൂഷ്യൻ സമയം (ജോൺസ്റ്റൺ)", + "Pacific\/Kiritimati": "ലൈൻ ദ്വീപുകൾ സമയം (കിരിറ്റിമാറ്റി)", + "Pacific\/Kosrae": "കൊസ്ര സമയം (കൊസ്രേ)", + "Pacific\/Kwajalein": "മാർഷൽ ദ്വീപുകൾ സമയം (ക്വാജലെയ്ൻ)", + "Pacific\/Majuro": "മാർഷൽ ദ്വീപുകൾ സമയം (മജൂറോ)", + "Pacific\/Marquesas": "മർക്കസസ് സമയം (മാർക്യുസാസ്)", + "Pacific\/Midway": "സമോവ സമയം (മിഡ്‌വേ)", + "Pacific\/Nauru": "നൗറു സമയം (നൗറു)", + "Pacific\/Niue": "ന്യൂയി സമയം (നിയു)", + "Pacific\/Norfolk": "നോർഫാക്ക് ദ്വീപുകൾ സമയം (നോർ‌ഫോക്ക്)", + "Pacific\/Noumea": "ന്യൂ കാലിഡോണിയ സമയം (നോമിയ)", + "Pacific\/Pago_Pago": "സമോവ സമയം (പാഗോ പാഗോ)", + "Pacific\/Palau": "പലാവു സമയം (പലാവു)", + "Pacific\/Pitcairn": "പിറ്റ്കേൻ സമയം (പിറ്റ്കയിൻ‌)", + "Pacific\/Ponape": "പൊനാപ്പ് സമയം (പോൺപെ)", + "Pacific\/Port_Moresby": "പാപ്പുവ ന്യൂ ഗിനിയ സമയം (പോർട്ട് മോഴ്‌സ്ബൈ)", + "Pacific\/Rarotonga": "കുക്ക് ദ്വീപുകൾ സമയം (റാരോടോംഗ)", + "Pacific\/Saipan": "ചമോറോ സ്റ്റാൻഡേർഡ് സമയം (സെയ്‌പ്പാൻ‌)", + "Pacific\/Tahiti": "താഹിതി സമയം (താഹിതി)", + "Pacific\/Tarawa": "ഗിൽബേർട്ട് ദ്വീപുകൾ സമയം (തരാവ)", + "Pacific\/Tongatapu": "ടോംഗ സമയം (ടോംഗാടാപു)", + "Pacific\/Truk": "ചൂക്ക് സമയം (ട്രക്)", + "Pacific\/Wake": "വേക്ക് ദ്വീപ് സമയം (വെയ്ക്)", + "Pacific\/Wallis": "വാലിസ് ആന്റ് ഫ്യൂച്യുന സമയം (വാല്ലിസ്)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/mn.json b/src/Symfony/Component/Intl/Resources/data/timezones/mn.json new file mode 100644 index 0000000000000..fe24e172a220f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/mn.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Гринвичийн цаг (Абижан)", + "Africa\/Accra": "Гринвичийн цаг (Аккра)", + "Africa\/Addis_Ababa": "Зүүн Африкийн цаг (Аддис-абеба)", + "Africa\/Algiers": "Төв Европын цаг (Алжир)", + "Africa\/Asmera": "Зүүн Африкийн цаг (Асмара)", + "Africa\/Bamako": "Гринвичийн цаг (Бамако)", + "Africa\/Bangui": "Баруун Африкийн цаг (Бангуй)", + "Africa\/Banjul": "Гринвичийн цаг (Банжул)", + "Africa\/Bissau": "Гринвичийн цаг (Биссау)", + "Africa\/Blantyre": "Төв Африкийн цаг (Блантайр)", + "Africa\/Brazzaville": "Баруун Африкийн цаг (Браззавиль)", + "Africa\/Bujumbura": "Төв Африкийн цаг (Бужумбура)", + "Africa\/Cairo": "Зүүн Европын цаг (Каир)", + "Africa\/Casablanca": "Баруун Европын цаг (Касабланка)", + "Africa\/Ceuta": "Төв Европын цаг (Сеута)", + "Africa\/Conakry": "Гринвичийн цаг (Конакри)", + "Africa\/Dakar": "Гринвичийн цаг (Дакар)", + "Africa\/Dar_es_Salaam": "Зүүн Африкийн цаг (Дар-эс-Салам)", + "Africa\/Djibouti": "Зүүн Африкийн цаг (Жибути)", + "Africa\/Douala": "Баруун Африкийн цаг (Дуала)", + "Africa\/El_Aaiun": "Баруун Европын цаг (Эль-Аюн)", + "Africa\/Freetown": "Гринвичийн цаг (Фритаун)", + "Africa\/Gaborone": "Төв Африкийн цаг (Габороне)", + "Africa\/Harare": "Төв Африкийн цаг (Хараре)", + "Africa\/Johannesburg": "Өмнөд Африкийн стандарт цаг (Йоханнесбург)", + "Africa\/Juba": "Зүүн Африкийн цаг (Жуба)", + "Africa\/Kampala": "Зүүн Африкийн цаг (Кампала)", + "Africa\/Khartoum": "Төв Африкийн цаг (Хартум)", + "Africa\/Kigali": "Төв Африкийн цаг (Кигали)", + "Africa\/Kinshasa": "Баруун Африкийн цаг (Киншаса)", + "Africa\/Lagos": "Баруун Африкийн цаг (Лагос)", + "Africa\/Libreville": "Баруун Африкийн цаг (Либревиль)", + "Africa\/Lome": "Гринвичийн цаг (Ломе)", + "Africa\/Luanda": "Баруун Африкийн цаг (Луанда)", + "Africa\/Lubumbashi": "Төв Африкийн цаг (Лубумбаши)", + "Africa\/Lusaka": "Төв Африкийн цаг (Лусака)", + "Africa\/Malabo": "Баруун Африкийн цаг (Малабо)", + "Africa\/Maputo": "Төв Африкийн цаг (Мапуто)", + "Africa\/Maseru": "Өмнөд Африкийн стандарт цаг (Масеру)", + "Africa\/Mbabane": "Өмнөд Африкийн стандарт цаг (Мбабане)", + "Africa\/Mogadishu": "Зүүн Африкийн цаг (Могадишу)", + "Africa\/Monrovia": "Гринвичийн цаг (Монровиа)", + "Africa\/Nairobi": "Зүүн Африкийн цаг (Найроби)", + "Africa\/Ndjamena": "Баруун Африкийн цаг (Нжамена)", + "Africa\/Niamey": "Баруун Африкийн цаг (Ниамей)", + "Africa\/Nouakchott": "Гринвичийн цаг (Нуакшот)", + "Africa\/Ouagadougou": "Гринвичийн цаг (Уагадугу)", + "Africa\/Porto-Novo": "Баруун Африкийн цаг (Порто-Ново)", + "Africa\/Sao_Tome": "Гринвичийн цаг (Сан-Томе)", + "Africa\/Tripoli": "Зүүн Европын цаг (Триполи)", + "Africa\/Tunis": "Төв Европын цаг (Тунис)", + "Africa\/Windhoek": "Төв Африкийн цаг (Виндхук)", + "America\/Adak": "Хавай-Алеутын цаг (Адак)", + "America\/Anchorage": "Аляскийн цаг (Анкораж)", + "America\/Anguilla": "Атлантын цаг (Ангилья)", + "America\/Antigua": "Атлантын цаг (Антигуа)", + "America\/Araguaina": "Бразилийн цаг (Арагуаяна)", + "America\/Argentina\/La_Rioja": "Аргентины цаг (Ла-Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аргентины цаг (Рио-Гальегос)", + "America\/Argentina\/Salta": "Аргентины цаг (Салта)", + "America\/Argentina\/San_Juan": "Аргентины цаг (Сан-Хуан)", + "America\/Argentina\/San_Luis": "Баруун Аргентины цаг (Сан Луи)", + "America\/Argentina\/Tucuman": "Аргентины цаг (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентины цаг (Ушуайя)", + "America\/Aruba": "Атлантын цаг (Аруба)", + "America\/Asuncion": "Парагвайн цаг (Асунсьон)", + "America\/Bahia": "Бразилийн цаг (Байя)", + "America\/Bahia_Banderas": "Төв цаг (Бахья Бандерас)", + "America\/Barbados": "Атлантын цаг (Барбадос)", + "America\/Belem": "Бразилийн цаг (Белем)", + "America\/Belize": "Төв цаг (Белизе)", + "America\/Blanc-Sablon": "Атлантын цаг (Бланк-Саблон)", + "America\/Boa_Vista": "Амазоны цаг (Боа-Виста)", + "America\/Bogota": "Колумбын цаг (Богота)", + "America\/Boise": "Уулын цаг (Боисе)", + "America\/Buenos_Aires": "Аргентины цаг (Буэнос Айрес)", + "America\/Cambridge_Bay": "Уулын цаг (Кэмбрижийн булан)", + "America\/Campo_Grande": "Амазоны цаг (Кампо-Гранде)", + "America\/Cancun": "Зүүн эргийн цаг (Канкун)", + "America\/Caracas": "Венесуэлийн цаг (Каракас)", + "America\/Catamarca": "Аргентины цаг (Катамарка)", + "America\/Cayenne": "Францын Гвианагийн цаг (Кайенна)", + "America\/Cayman": "Зүүн эргийн цаг (Кайман)", + "America\/Chicago": "Төв цаг (Чикаго)", + "America\/Chihuahua": "Мексик-Номхон далайн цаг (Чихуахуа)", + "America\/Coral_Harbour": "Зүүн эргийн цаг (Атикокан)", + "America\/Cordoba": "Аргентины цаг (Кордова)", + "America\/Costa_Rica": "Төв цаг (Коста-Рика)", + "America\/Creston": "Уулын цаг (Крестон)", + "America\/Cuiaba": "Амазоны цаг (Куяба)", + "America\/Curacao": "Атлантын цаг (Кюрасао)", + "America\/Danmarkshavn": "Гринвичийн цаг (Данмаркшавн)", + "America\/Dawson": "Номхон далайн цаг (Доусон)", + "America\/Dawson_Creek": "Уулын цаг (Доусон Крик)", + "America\/Denver": "Уулын цаг (Денвер)", + "America\/Detroit": "Зүүн эргийн цаг (Детройт)", + "America\/Dominica": "Атлантын цаг (Доминика)", + "America\/Edmonton": "Уулын цаг (Эдмонтон)", + "America\/El_Salvador": "Төв цаг (Эль Сальвадор)", + "America\/Fort_Nelson": "Уулын цаг (Форт Нэльсон)", + "America\/Fortaleza": "Бразилийн цаг (Форталеза)", + "America\/Glace_Bay": "Атлантын цаг (Глейс булан)", + "America\/Godthab": "Баруун Гринландын цаг (Нүүк)", + "America\/Goose_Bay": "Атлантын цаг (Гуус булан)", + "America\/Grand_Turk": "Зүүн эргийн цаг (Гранд Турк)", + "America\/Grenada": "Атлантын цаг (Гренада)", + "America\/Guadeloupe": "Атлантын цаг (Гваделуп)", + "America\/Guatemala": "Төв цаг (Гватемал)", + "America\/Guayaquil": "Эквадорын цаг (Гуаякиль)", + "America\/Guyana": "Гайанагийн цаг (Гайана)", + "America\/Halifax": "Атлантын цаг (Халифакс)", + "America\/Havana": "Кубын цаг (Хавана)", + "America\/Hermosillo": "Мексик-Номхон далайн цаг (Хермосилло)", + "America\/Indiana\/Knox": "Төв цаг (Нокс, Индиана)", + "America\/Indiana\/Marengo": "Зүүн эргийн цаг (Маренго, Индиана)", + "America\/Indiana\/Petersburg": "Зүүн эргийн цаг (Питерсбург, Индиана)", + "America\/Indiana\/Tell_City": "Төв цаг (Тел Сити, Индиана)", + "America\/Indiana\/Vevay": "Зүүн эргийн цаг (Вивей, Индиана)", + "America\/Indiana\/Vincennes": "Зүүн эргийн цаг (Винсенес, Индиана)", + "America\/Indiana\/Winamac": "Зүүн эргийн цаг (Винамак, Индиана)", + "America\/Indianapolis": "Зүүн эргийн цаг (Индианаполис)", + "America\/Inuvik": "Уулын цаг (Инувик)", + "America\/Iqaluit": "Зүүн эргийн цаг (Икалуит)", + "America\/Jamaica": "Зүүн эргийн цаг (Ямайка)", + "America\/Jujuy": "Аргентины цаг (Жужуй)", + "America\/Juneau": "Аляскийн цаг (Жуно)", + "America\/Kentucky\/Monticello": "Зүүн эргийн цаг (Монтичелло, Кентаки)", + "America\/Kralendijk": "Атлантын цаг (Кралендик)", + "America\/La_Paz": "Боливийн цаг (Ла Паз)", + "America\/Lima": "Перугийн цаг (Лима)", + "America\/Los_Angeles": "Номхон далайн цаг (Лос-Анжелес)", + "America\/Louisville": "Зүүн эргийн цаг (Луисвилл)", + "America\/Lower_Princes": "Атлантын цаг (Ловер Принсес Квартер)", + "America\/Maceio": "Бразилийн цаг (Масейо)", + "America\/Managua": "Төв цаг (Манагуа)", + "America\/Manaus": "Амазоны цаг (Манаус)", + "America\/Marigot": "Атлантын цаг (Маригот)", + "America\/Martinique": "Атлантын цаг (Мартиник)", + "America\/Matamoros": "Төв цаг (Матаморос)", + "America\/Mazatlan": "Мексик-Номхон далайн цаг (Мазатлан)", + "America\/Mendoza": "Аргентины цаг (Мендоза)", + "America\/Menominee": "Төв цаг (Меномини)", + "America\/Merida": "Төв цаг (Мерида)", + "America\/Metlakatla": "Аляскийн цаг (Метлакатла)", + "America\/Mexico_City": "Төв цаг (Мехико)", + "America\/Miquelon": "Сен-Пьер ба Микелоны цаг (Микелон)", + "America\/Moncton": "Атлантын цаг (Монктон)", + "America\/Monterrey": "Төв цаг (Монтерей)", + "America\/Montevideo": "Уругвайн цаг (Монтевидео)", + "America\/Montserrat": "Атлантын цаг (Монтсеррат)", + "America\/Nassau": "Зүүн эргийн цаг (Нассау)", + "America\/New_York": "Зүүн эргийн цаг (Нью-Йорк)", + "America\/Nipigon": "Зүүн эргийн цаг (Нипигон)", + "America\/Nome": "Аляскийн цаг (Ном)", + "America\/Noronha": "Фернандо де Норонагийн цаг (Норона)", + "America\/North_Dakota\/Beulah": "Төв цаг (Била, Хойд Дакота)", + "America\/North_Dakota\/Center": "Төв цаг (Төв, Хойд Дакота)", + "America\/North_Dakota\/New_Salem": "Төв цаг (Нью-Салем, Хойд Дакота)", + "America\/Ojinaga": "Уулын цаг (Ожинага)", + "America\/Panama": "Зүүн эргийн цаг (Панама)", + "America\/Pangnirtung": "Зүүн эргийн цаг (Пангниртунг)", + "America\/Paramaribo": "Суринамын цаг (Парамарибо)", + "America\/Phoenix": "Уулын цаг (Феникс)", + "America\/Port-au-Prince": "Зүүн эргийн цаг (Порт-о-Принс)", + "America\/Port_of_Spain": "Атлантын цаг (Испаний боомт)", + "America\/Porto_Velho": "Амазоны цаг (Порто-Велью)", + "America\/Puerto_Rico": "Атлантын цаг (Пуэрто-Рико)", + "America\/Punta_Arenas": "Чилийн цаг (Пунта Арена)", + "America\/Rainy_River": "Төв цаг (Рейни Ривер)", + "America\/Rankin_Inlet": "Төв цаг (Рэнкин Инлет)", + "America\/Recife": "Бразилийн цаг (Ресифи)", + "America\/Regina": "Төв цаг (Регина)", + "America\/Resolute": "Төв цаг (Резолют)", + "America\/Santa_Isabel": "Баруун хойд Мексикийн цаг (Санта Изабель)", + "America\/Santarem": "Бразилийн цаг (Сантарем)", + "America\/Santiago": "Чилийн цаг (Сантьяго)", + "America\/Santo_Domingo": "Атлантын цаг (Санто Доминго)", + "America\/Sao_Paulo": "Бразилийн цаг (Сан-Паулу)", + "America\/Scoresbysund": "Зүүн Гринландын цаг (Скорсбисунн)", + "America\/Sitka": "Аляскийн цаг (Ситка)", + "America\/St_Barthelemy": "Атлантын цаг (Сент-Бартельми)", + "America\/St_Johns": "Нью-Фаундлендын цаг (Сент-Жонс)", + "America\/St_Kitts": "Атлантын цаг (Сент-Киттс)", + "America\/St_Lucia": "Атлантын цаг (Сент Люсиа)", + "America\/St_Thomas": "Атлантын цаг (Сент Томас)", + "America\/St_Vincent": "Атлантын цаг (Сент Винсент)", + "America\/Swift_Current": "Төв цаг (Свифт Каррент)", + "America\/Tegucigalpa": "Төв цаг (Тегусигальпа)", + "America\/Thule": "Атлантын цаг (Туле)", + "America\/Thunder_Bay": "Зүүн эргийн цаг (Сандер Бэй)", + "America\/Tijuana": "Номхон далайн цаг (Тихуана)", + "America\/Toronto": "Зүүн эргийн цаг (Торонто)", + "America\/Tortola": "Атлантын цаг (Тортола)", + "America\/Vancouver": "Номхон далайн цаг (Ванкувер)", + "America\/Whitehorse": "Номхон далайн цаг (Уайтхорз)", + "America\/Winnipeg": "Төв цаг (Виннипег)", + "America\/Yakutat": "Аляскийн цаг (Якутат)", + "America\/Yellowknife": "Уулын цаг (Йелоунайф)", + "Antarctica\/Casey": "Баруун Австралийн цаг (Кэсей)", + "Antarctica\/Davis": "Дэвисийн цаг (Дэвис)", + "Antarctica\/DumontDUrville": "Дюмон д’Юрвилийн цаг (Дюмон д’Юрвиль)", + "Antarctica\/Macquarie": "Маккуори Арлын цаг (Маккуори)", + "Antarctica\/Mawson": "Моусоны цаг (Моусон)", + "Antarctica\/McMurdo": "Шинэ Зеландын цаг (Мак-Мөрдо)", + "Antarctica\/Palmer": "Чилийн цаг (Палмер)", + "Antarctica\/Rothera": "Ротерагийн цаг (Ротера)", + "Antarctica\/Syowa": "Сёвагийн цаг (Сёва)", + "Antarctica\/Troll": "Гринвичийн цаг (Тролл)", + "Antarctica\/Vostok": "Востокийн цаг (Восток)", + "Arctic\/Longyearbyen": "Төв Европын цаг (Лонгирбайен)", + "Asia\/Aden": "Арабын цаг (Аден)", + "Asia\/Almaty": "Зүүн Казахстаны цаг (Алматы)", + "Asia\/Amman": "Зүүн Европын цаг (Амман)", + "Asia\/Aqtau": "Баруун Казахстаны цаг (Актау)", + "Asia\/Aqtobe": "Баруун Казахстаны цаг (Актөбе)", + "Asia\/Ashgabat": "Туркменистаны цаг (Ашхабад)", + "Asia\/Atyrau": "Баруун Казахстаны цаг (Атырау)", + "Asia\/Baghdad": "Арабын цаг (Багдад)", + "Asia\/Bahrain": "Арабын цаг (Бахрейн)", + "Asia\/Baku": "Азербайжаны цаг (Баку)", + "Asia\/Bangkok": "Энэтхэг-Хятадын хойгийн цаг (Бангкок)", + "Asia\/Beirut": "Зүүн Европын цаг (Бейрут)", + "Asia\/Bishkek": "Киргизийн цаг (Бишкек)", + "Asia\/Brunei": "Бруней Даруссаламын цаг (Бруней)", + "Asia\/Calcutta": "Энэтхэгийн цаг (Калькутта)", + "Asia\/Chita": "Якутын цаг (Чита)", + "Asia\/Choibalsan": "Чойбалсангийн цаг (Чойбалсан)", + "Asia\/Colombo": "Энэтхэгийн цаг (Коломбо)", + "Asia\/Damascus": "Зүүн Европын цаг (Дамаск)", + "Asia\/Dhaka": "Бангладешийн цаг (Дака)", + "Asia\/Dili": "Зүүн Тиморын цаг (Дили)", + "Asia\/Dubai": "Галфийн стандарт цаг (Дубай)", + "Asia\/Dushanbe": "Тажикистаны цаг (Душанбе)", + "Asia\/Famagusta": "Зүүн Европын цаг (Фамагуста)", + "Asia\/Gaza": "Зүүн Европын цаг (Газа)", + "Asia\/Hebron": "Зүүн Европын цаг (Хеброн)", + "Asia\/Hong_Kong": "Хонг Конгийн цаг (Хонг Конг)", + "Asia\/Hovd": "Ховдын цаг (Ховд)", + "Asia\/Irkutsk": "Эрхүүгийн цаг (Эрхүү)", + "Asia\/Jakarta": "Баруун Индонезийн цаг (Жакарта)", + "Asia\/Jayapura": "Зүүн Индонезийн цаг (Жайпур)", + "Asia\/Jerusalem": "Израилийн цаг (Ерусалем)", + "Asia\/Kabul": "Афганистаны цаг (Кабул)", + "Asia\/Karachi": "Пакистаны цаг (Карачи)", + "Asia\/Katmandu": "Балбын цаг (Катманду)", + "Asia\/Khandyga": "Якутын цаг (Кандыга)", + "Asia\/Krasnoyarsk": "Красноярскийн цаг (Красноярск)", + "Asia\/Kuala_Lumpur": "Малайзын цаг (Куала Лумпур)", + "Asia\/Kuching": "Малайзын цаг (Кучин)", + "Asia\/Kuwait": "Арабын цаг (Кувейт)", + "Asia\/Macau": "Хятадын цаг (Макао)", + "Asia\/Magadan": "Магаданы цаг (Магадан)", + "Asia\/Makassar": "Төв Индонезийн цаг (Макассар)", + "Asia\/Manila": "Филиппиний цаг (Манила)", + "Asia\/Muscat": "Галфийн стандарт цаг (Мускат)", + "Asia\/Nicosia": "Зүүн Европын цаг (Никосия)", + "Asia\/Novokuznetsk": "Красноярскийн цаг (Новокузнецк)", + "Asia\/Novosibirsk": "Новосибирскийн цаг (Новосибирск)", + "Asia\/Omsk": "Омскийн цаг (Омск)", + "Asia\/Oral": "Баруун Казахстаны цаг (Орал)", + "Asia\/Phnom_Penh": "Энэтхэг-Хятадын хойгийн цаг (Пномпень)", + "Asia\/Pontianak": "Баруун Индонезийн цаг (Понтианак)", + "Asia\/Pyongyang": "Солонгосын цаг (Пёньян)", + "Asia\/Qatar": "Арабын цаг (Катар)", + "Asia\/Qostanay": "Зүүн Казахстаны цаг (Qostanay)", + "Asia\/Qyzylorda": "Баруун Казахстаны цаг (Кызылорд)", + "Asia\/Rangoon": "Мьянмарын цаг (Рангун)", + "Asia\/Riyadh": "Арабын цаг (Рияд)", + "Asia\/Saigon": "Энэтхэг-Хятадын хойгийн цаг (Хо Ши Мин хот)", + "Asia\/Sakhalin": "Сахалины цаг (Сахалин)", + "Asia\/Samarkand": "Узбекистаны цаг (Самарканд)", + "Asia\/Seoul": "Солонгосын цаг (Сөүл)", + "Asia\/Shanghai": "Хятадын цаг (Шанхай)", + "Asia\/Singapore": "Сингапурын цаг (Сингапур)", + "Asia\/Srednekolymsk": "Магаданы цаг (Среднеколымск)", + "Asia\/Taipei": "Тайпейн цаг (Тайпей)", + "Asia\/Tashkent": "Узбекистаны цаг (Ташкент)", + "Asia\/Tbilisi": "Гүржийн цаг (Тбилиси)", + "Asia\/Tehran": "Ираны цаг (Тегеран)", + "Asia\/Thimphu": "Бутаны цаг (Тхимпху)", + "Asia\/Tokyo": "Японы цаг (Токио)", + "Asia\/Ulaanbaatar": "Улаанбаатарын цаг (Улаанбаатар)", + "Asia\/Ust-Nera": "Владивостокийн цаг (Уст-Нера)", + "Asia\/Vientiane": "Энэтхэг-Хятадын хойгийн цаг (Вьентьян)", + "Asia\/Vladivostok": "Владивостокийн цаг (Владивосток)", + "Asia\/Yakutsk": "Якутын цаг (Якутск)", + "Asia\/Yekaterinburg": "Екатеринбургийн цаг (Екатеринбург)", + "Asia\/Yerevan": "Арменийн цаг (Ереван)", + "Atlantic\/Azores": "Азорын цаг (Азор)", + "Atlantic\/Bermuda": "Атлантын цаг (Бермуда)", + "Atlantic\/Canary": "Баруун Европын цаг (Канари)", + "Atlantic\/Cape_Verde": "Кабо Вердийн цаг (Кабо Верде)", + "Atlantic\/Faeroe": "Баруун Европын цаг (Фароэ)", + "Atlantic\/Madeira": "Баруун Европын цаг (Мадейра)", + "Atlantic\/Reykjavik": "Гринвичийн цаг (Рейкьявик)", + "Atlantic\/South_Georgia": "Өмнөд Жоржийн цаг (Өмнөд Жоржиа)", + "Atlantic\/St_Helena": "Гринвичийн цаг (Сент Хелена)", + "Atlantic\/Stanley": "Фолклендийн арлуудын цаг (Стэнли)", + "Australia\/Adelaide": "Төв Австралийн цаг (Аделаида)", + "Australia\/Brisbane": "Зүүн Австралийн цаг (Брисбен)", + "Australia\/Broken_Hill": "Төв Австралийн цаг (Брокен Хилл)", + "Australia\/Currie": "Зүүн Австралийн цаг (Кюрри)", + "Australia\/Darwin": "Төв Австралийн цаг (Дарвин)", + "Australia\/Eucla": "Австралийн төв баруун эргийн цаг (Еукла)", + "Australia\/Hobart": "Зүүн Австралийн цаг (Хобарт)", + "Australia\/Lindeman": "Зүүн Австралийн цаг (Линдемэн)", + "Australia\/Lord_Howe": "Лорд Хоугийн цаг (Лорд Хоу)", + "Australia\/Melbourne": "Зүүн Австралийн цаг (Мельбурн)", + "Australia\/Perth": "Баруун Австралийн цаг (Перс)", + "Australia\/Sydney": "Зүүн Австралийн цаг (Сидней)", + "CST6CDT": "Төв цаг", + "EST5EDT": "Зүүн эргийн цаг", + "Etc\/GMT": "Гринвичийн цаг", + "Etc\/UTC": "Олон улсын зохицуулалттай цаг", + "Europe\/Amsterdam": "Төв Европын цаг (Амстердам)", + "Europe\/Andorra": "Төв Европын цаг (Андорра)", + "Europe\/Astrakhan": "Москвагийн цаг (Астрахань)", + "Europe\/Athens": "Зүүн Европын цаг (Афин)", + "Europe\/Belgrade": "Төв Европын цаг (Белград)", + "Europe\/Berlin": "Төв Европын цаг (Берлин)", + "Europe\/Bratislava": "Төв Европын цаг (Братислав)", + "Europe\/Brussels": "Төв Европын цаг (Брюссель)", + "Europe\/Bucharest": "Зүүн Европын цаг (Бухарест)", + "Europe\/Budapest": "Төв Европын цаг (Будапешт)", + "Europe\/Busingen": "Төв Европын цаг (Бусинген)", + "Europe\/Chisinau": "Зүүн Европын цаг (Кишинёв)", + "Europe\/Copenhagen": "Төв Европын цаг (Копенгаген)", + "Europe\/Dublin": "Гринвичийн цаг (Дублин)", + "Europe\/Gibraltar": "Төв Европын цаг (Гибралтар)", + "Europe\/Guernsey": "Гринвичийн цаг (Гернси)", + "Europe\/Helsinki": "Зүүн Европын цаг (Хельсинк)", + "Europe\/Isle_of_Man": "Гринвичийн цаг (Мэн Арал)", + "Europe\/Jersey": "Гринвичийн цаг (Жерси)", + "Europe\/Kaliningrad": "Зүүн Европын цаг (Калининград)", + "Europe\/Kiev": "Зүүн Европын цаг (Киев)", + "Europe\/Lisbon": "Баруун Европын цаг (Лисбон)", + "Europe\/Ljubljana": "Төв Европын цаг (Любляна)", + "Europe\/London": "Гринвичийн цаг (Лондон)", + "Europe\/Luxembourg": "Төв Европын цаг (Люксембург)", + "Europe\/Madrid": "Төв Европын цаг (Мадрид)", + "Europe\/Malta": "Төв Европын цаг (Мальта)", + "Europe\/Mariehamn": "Зүүн Европын цаг (Марихамн)", + "Europe\/Minsk": "Москвагийн цаг (Минск)", + "Europe\/Monaco": "Төв Европын цаг (Монако)", + "Europe\/Moscow": "Москвагийн цаг (Москва)", + "Europe\/Oslo": "Төв Европын цаг (Осло)", + "Europe\/Paris": "Төв Европын цаг (Парис)", + "Europe\/Podgorica": "Төв Европын цаг (Подгорица)", + "Europe\/Prague": "Төв Европын цаг (Прага)", + "Europe\/Riga": "Зүүн Европын цаг (Рига)", + "Europe\/Rome": "Төв Европын цаг (Ром)", + "Europe\/San_Marino": "Төв Европын цаг (Сан Марино)", + "Europe\/Sarajevo": "Төв Европын цаг (Сараево)", + "Europe\/Saratov": "Москвагийн цаг (Саратов)", + "Europe\/Simferopol": "Москвагийн цаг (Симферополь)", + "Europe\/Skopje": "Төв Европын цаг (Скопье)", + "Europe\/Sofia": "Зүүн Европын цаг (София)", + "Europe\/Stockholm": "Төв Европын цаг (Стокольм)", + "Europe\/Tallinn": "Зүүн Европын цаг (Таллин)", + "Europe\/Tirane": "Төв Европын цаг (Тирана)", + "Europe\/Ulyanovsk": "Москвагийн цаг (Ульяновск)", + "Europe\/Uzhgorod": "Зүүн Европын цаг (Ужгород)", + "Europe\/Vaduz": "Төв Европын цаг (Вадуз)", + "Europe\/Vatican": "Төв Европын цаг (Ватикан)", + "Europe\/Vienna": "Төв Европын цаг (Вена)", + "Europe\/Vilnius": "Зүүн Европын цаг (Вильнюс)", + "Europe\/Volgograd": "Волгоградын цаг (Волгоград)", + "Europe\/Warsaw": "Төв Европын цаг (Варшав)", + "Europe\/Zagreb": "Төв Европын цаг (Загреб)", + "Europe\/Zaporozhye": "Зүүн Европын цаг (Запорожье)", + "Europe\/Zurich": "Төв Европын цаг (Цюрих)", + "Indian\/Antananarivo": "Зүүн Африкийн цаг (Антананариво)", + "Indian\/Chagos": "Энэтхэгийн далайн цаг (Чагос)", + "Indian\/Christmas": "Крисмас арлын цаг (Крисмас)", + "Indian\/Cocos": "Кокос арлын цаг (Кокос)", + "Indian\/Comoro": "Зүүн Африкийн цаг (Коморо)", + "Indian\/Kerguelen": "Францын Өмнөд ба Антарктидийн цаг (Кергелен)", + "Indian\/Mahe": "Сейшелийн арлуудын цаг (Махе)", + "Indian\/Maldives": "Мальдивийн цаг (Мальдив)", + "Indian\/Mauritius": "Маврикийн цаг (Маврикий)", + "Indian\/Mayotte": "Зүүн Африкийн цаг (Майотта)", + "Indian\/Reunion": "Реюнионы цаг (Реюнион)", + "MST7MDT": "Уулын цаг", + "PST8PDT": "Номхон далайн цаг", + "Pacific\/Apia": "Апиагийн цаг (Апиа)", + "Pacific\/Auckland": "Шинэ Зеландын цаг (Оукленд)", + "Pacific\/Bougainville": "Папуа Шинэ Гвинейн цаг (Бугенвиль)", + "Pacific\/Chatham": "Чатемын цаг (Чатем)", + "Pacific\/Easter": "Зүүн Исландын цаг (Истер)", + "Pacific\/Efate": "Вануатугийн цаг (Эфате)", + "Pacific\/Enderbury": "Феникс арлын цаг (Эндербери)", + "Pacific\/Fakaofo": "Токелаугийн цаг (Факаофо)", + "Pacific\/Fiji": "Фижигийн цаг (Фижи)", + "Pacific\/Funafuti": "Тувалугийн цаг (Фунафути)", + "Pacific\/Galapagos": "Галапагосын цаг (Галапагос)", + "Pacific\/Gambier": "Гамбьегийн цаг (Гамбьер)", + "Pacific\/Guadalcanal": "Соломоны арлуудын цаг (Гуадалканал)", + "Pacific\/Guam": "Чаморрогийн цаг (Гуам)", + "Pacific\/Honolulu": "Хавай-Алеутын цаг (Хонолулу)", + "Pacific\/Johnston": "Хавай-Алеутын цаг (Жонстон)", + "Pacific\/Kiritimati": "Лайн арлын цаг (Киритимати)", + "Pacific\/Kosrae": "Косрэгийн цаг (Косрэ)", + "Pacific\/Kwajalein": "Маршаллын арлын цаг (Кважалейн)", + "Pacific\/Majuro": "Маршаллын арлын цаг (Мажуро)", + "Pacific\/Marquesas": "Маркесасын цаг (Маркизас)", + "Pacific\/Midway": "Самоагийн цаг (Мидвей)", + "Pacific\/Nauru": "Науругийн цаг (Науру)", + "Pacific\/Niue": "Ниуэгийн цаг (Ниуэ)", + "Pacific\/Norfolk": "Норфолк арлын цаг (Норфолк)", + "Pacific\/Noumea": "Шинэ Каледонийн цаг (Нумеа)", + "Pacific\/Pago_Pago": "Самоагийн цаг (Паго Паго)", + "Pacific\/Palau": "Палаугийн цаг (Палау)", + "Pacific\/Pitcairn": "Питкернийн цаг (Питкэрн)", + "Pacific\/Ponape": "Понапегийн цаг (Понпей)", + "Pacific\/Port_Moresby": "Папуа Шинэ Гвинейн цаг (Порт-Морсби)", + "Pacific\/Rarotonga": "Күүк арлын цаг (Раротонга)", + "Pacific\/Saipan": "Чаморрогийн цаг (Сайпан)", + "Pacific\/Tahiti": "Таитигийн цаг (Таити)", + "Pacific\/Tarawa": "Жильбер арлын цаг (Тарава)", + "Pacific\/Tongatapu": "Тонгагийн цаг (Тонгатапу)", + "Pacific\/Truk": "Чүүкийн цаг (Чүүк)", + "Pacific\/Wake": "Вейк арлын цаг (Уэйк)", + "Pacific\/Wallis": "Уоллис ба Футунагийн цаг (Уоллис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/mo.json b/src/Symfony/Component/Intl/Resources/data/timezones/mo.json new file mode 100644 index 0000000000000..be228ce8d967d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/mo.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.20", + "Names": { + "Africa\/Abidjan": "Ora de Greenwhich (Abidjan)", + "Africa\/Accra": "Ora de Greenwhich (Accra)", + "Africa\/Addis_Ababa": "Ora Africii Orientale (Addis Abeba)", + "Africa\/Algiers": "Ora Europei Centrale (Alger)", + "Africa\/Asmera": "Ora Africii Orientale (Asmara)", + "Africa\/Bamako": "Ora de Greenwhich (Bamako)", + "Africa\/Bangui": "Ora Africii Occidentale (Bangui)", + "Africa\/Banjul": "Ora de Greenwhich (Banjul)", + "Africa\/Bissau": "Ora de Greenwhich (Bissau)", + "Africa\/Blantyre": "Ora Africii Centrale (Blantyre)", + "Africa\/Brazzaville": "Ora Africii Occidentale (Brazzaville)", + "Africa\/Bujumbura": "Ora Africii Centrale (Bujumbura)", + "Africa\/Cairo": "Ora Europei de Est (Cairo)", + "Africa\/Casablanca": "Ora Europei de Vest (Casablanca)", + "Africa\/Ceuta": "Ora Europei Centrale (Ceuta)", + "Africa\/Conakry": "Ora de Greenwhich (Conakry)", + "Africa\/Dakar": "Ora de Greenwhich (Dakar)", + "Africa\/Dar_es_Salaam": "Ora Africii Orientale (Dar es Salaam)", + "Africa\/Djibouti": "Ora Africii Orientale (Djibouti)", + "Africa\/Douala": "Ora Africii Occidentale (Douala)", + "Africa\/El_Aaiun": "Ora Europei de Vest (El Aaiun)", + "Africa\/Freetown": "Ora de Greenwhich (Freetown)", + "Africa\/Gaborone": "Ora Africii Centrale (Gaborone)", + "Africa\/Harare": "Ora Africii Centrale (Harare)", + "Africa\/Johannesburg": "Ora Africii Meridionale (Johannesburg)", + "Africa\/Juba": "Ora Africii Orientale (Juba)", + "Africa\/Kampala": "Ora Africii Orientale (Kampala)", + "Africa\/Khartoum": "Ora Africii Centrale (Khartoum)", + "Africa\/Kigali": "Ora Africii Centrale (Kigali)", + "Africa\/Kinshasa": "Ora Africii Occidentale (Kinshasa)", + "Africa\/Lagos": "Ora Africii Occidentale (Lagos)", + "Africa\/Libreville": "Ora Africii Occidentale (Libreville)", + "Africa\/Lome": "Ora de Greenwhich (Lome)", + "Africa\/Luanda": "Ora Africii Occidentale (Luanda)", + "Africa\/Lubumbashi": "Ora Africii Centrale (Lubumbashi)", + "Africa\/Lusaka": "Ora Africii Centrale (Lusaka)", + "Africa\/Malabo": "Ora Africii Occidentale (Malabo)", + "Africa\/Maputo": "Ora Africii Centrale (Maputo)", + "Africa\/Maseru": "Ora Africii Meridionale (Maseru)", + "Africa\/Mbabane": "Ora Africii Meridionale (Mbabane)", + "Africa\/Mogadishu": "Ora Africii Orientale (Mogadiscio)", + "Africa\/Monrovia": "Ora de Greenwhich (Monrovia)", + "Africa\/Nairobi": "Ora Africii Orientale (Nairobi)", + "Africa\/Ndjamena": "Ora Africii Occidentale (N’Djamena)", + "Africa\/Niamey": "Ora Africii Occidentale (Niamey)", + "Africa\/Nouakchott": "Ora de Greenwhich (Nouakchott)", + "Africa\/Ouagadougou": "Ora de Greenwhich (Ouagadougou)", + "Africa\/Porto-Novo": "Ora Africii Occidentale (Porto-Novo)", + "Africa\/Sao_Tome": "Ora de Greenwhich (Sao Tomé)", + "Africa\/Tripoli": "Ora Europei de Est (Tripoli)", + "Africa\/Tunis": "Ora Europei Centrale (Tunis)", + "Africa\/Windhoek": "Ora Africii Centrale (Windhoek)", + "America\/Adak": "Ora din Hawaii-Aleutine (Adak)", + "America\/Anchorage": "Ora din Alaska (Anchorage)", + "America\/Anguilla": "Ora zonei Atlantic nord-americane (Anguilla)", + "America\/Antigua": "Ora zonei Atlantic nord-americane (Antigua)", + "America\/Araguaina": "Ora Brasiliei (Araguaina)", + "America\/Argentina\/La_Rioja": "Ora Argentinei (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Ora Argentinei (Rio Gallegos)", + "America\/Argentina\/Salta": "Ora Argentinei (Salta)", + "America\/Argentina\/San_Juan": "Ora Argentinei (San Juan)", + "America\/Argentina\/San_Luis": "Ora Argentinei Occidentale (San Luis)", + "America\/Argentina\/Tucuman": "Ora Argentinei (Tucuman)", + "America\/Argentina\/Ushuaia": "Ora Argentinei (Ushuaia)", + "America\/Aruba": "Ora zonei Atlantic nord-americane (Aruba)", + "America\/Asuncion": "Ora din Paraguay (Asunción)", + "America\/Bahia": "Ora Brasiliei (Bahia)", + "America\/Bahia_Banderas": "Ora centrală nord-americană (Bahia Banderas)", + "America\/Barbados": "Ora zonei Atlantic nord-americane (Barbados)", + "America\/Belem": "Ora Brasiliei (Belem)", + "America\/Belize": "Ora centrală nord-americană (Belize)", + "America\/Blanc-Sablon": "Ora zonei Atlantic nord-americane (Blanc-Sablon)", + "America\/Boa_Vista": "Ora Amazonului (Boa Vista)", + "America\/Bogota": "Ora Columbiei (Bogota)", + "America\/Boise": "Ora zonei montane nord-americane (Boise)", + "America\/Buenos_Aires": "Ora Argentinei (Buenos Aires)", + "America\/Cambridge_Bay": "Ora zonei montane nord-americane (Cambridge Bay)", + "America\/Campo_Grande": "Ora Amazonului (Campo Grande)", + "America\/Cancun": "Ora orientală nord-americană (Cancun)", + "America\/Caracas": "Ora Venezuelei (Caracas)", + "America\/Catamarca": "Ora Argentinei (Catamarca)", + "America\/Cayenne": "Ora din Guyana Franceză (Cayenne)", + "America\/Cayman": "Ora orientală nord-americană (Cayman)", + "America\/Chicago": "Ora centrală nord-americană (Chicago)", + "America\/Chihuahua": "Ora zonei Pacific mexicane (Chihuahua)", + "America\/Coral_Harbour": "Ora orientală nord-americană (Atikokan)", + "America\/Cordoba": "Ora Argentinei (Cordoba)", + "America\/Costa_Rica": "Ora centrală nord-americană (Costa Rica)", + "America\/Creston": "Ora zonei montane nord-americane (Creston)", + "America\/Cuiaba": "Ora Amazonului (Cuiaba)", + "America\/Curacao": "Ora zonei Atlantic nord-americane (Curaçao)", + "America\/Danmarkshavn": "Ora de Greenwhich (Danmarkshavn)", + "America\/Dawson": "Ora zonei Pacific nord-americane (Dawson)", + "America\/Dawson_Creek": "Ora zonei montane nord-americane (Dawson Creek)", + "America\/Denver": "Ora zonei montane nord-americane (Denver)", + "America\/Detroit": "Ora orientală nord-americană (Detroit)", + "America\/Dominica": "Ora zonei Atlantic nord-americane (Dominica)", + "America\/Edmonton": "Ora zonei montane nord-americane (Edmonton)", + "America\/Eirunepe": "Ora Acre (Eirunepe)", + "America\/El_Salvador": "Ora centrală nord-americană (El Salvador)", + "America\/Fort_Nelson": "Ora zonei montane nord-americane (Fort Nelson)", + "America\/Fortaleza": "Ora Brasiliei (Fortaleza)", + "America\/Glace_Bay": "Ora zonei Atlantic nord-americane (Glace Bay)", + "America\/Godthab": "Ora Groenlandei occidentale (Nuuk)", + "America\/Goose_Bay": "Ora zonei Atlantic nord-americane (Goose Bay)", + "America\/Grand_Turk": "Ora orientală nord-americană (Grand Turk)", + "America\/Grenada": "Ora zonei Atlantic nord-americane (Grenada)", + "America\/Guadeloupe": "Ora zonei Atlantic nord-americane (Guadelupa)", + "America\/Guatemala": "Ora centrală nord-americană (Guatemala)", + "America\/Guayaquil": "Ora Ecuadorului (Guayaquil)", + "America\/Guyana": "Ora din Guyana (Guyana)", + "America\/Halifax": "Ora zonei Atlantic nord-americane (Halifax)", + "America\/Havana": "Ora Cubei (Havana)", + "America\/Hermosillo": "Ora zonei Pacific mexicane (Hermosillo)", + "America\/Indiana\/Knox": "Ora centrală nord-americană (Knox, Indiana)", + "America\/Indiana\/Marengo": "Ora orientală nord-americană (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Ora orientală nord-americană (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Ora centrală nord-americană (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Ora orientală nord-americană (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Ora orientală nord-americană (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Ora orientală nord-americană (Winamac, Indiana)", + "America\/Indianapolis": "Ora orientală nord-americană (Indianapolis)", + "America\/Inuvik": "Ora zonei montane nord-americane (Inuvik)", + "America\/Iqaluit": "Ora orientală nord-americană (Iqaluit)", + "America\/Jamaica": "Ora orientală nord-americană (Jamaica)", + "America\/Jujuy": "Ora Argentinei (Jujuy)", + "America\/Juneau": "Ora din Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Ora orientală nord-americană (Monticello, Kentucky)", + "America\/Kralendijk": "Ora zonei Atlantic nord-americane (Kralendijk)", + "America\/La_Paz": "Ora Boliviei (La Paz)", + "America\/Lima": "Ora din Peru (Lima)", + "America\/Los_Angeles": "Ora zonei Pacific nord-americane (Los Angeles)", + "America\/Louisville": "Ora orientală nord-americană (Louisville)", + "America\/Lower_Princes": "Ora zonei Atlantic nord-americane (Lower Prince’s Quarter)", + "America\/Maceio": "Ora Brasiliei (Maceio)", + "America\/Managua": "Ora centrală nord-americană (Managua)", + "America\/Manaus": "Ora Amazonului (Manaus)", + "America\/Marigot": "Ora zonei Atlantic nord-americane (Marigot)", + "America\/Martinique": "Ora zonei Atlantic nord-americane (Martinica)", + "America\/Matamoros": "Ora centrală nord-americană (Matamoros)", + "America\/Mazatlan": "Ora zonei Pacific mexicane (Mazatlan)", + "America\/Mendoza": "Ora Argentinei (Mendoza)", + "America\/Menominee": "Ora centrală nord-americană (Menominee)", + "America\/Merida": "Ora centrală nord-americană (Merida)", + "America\/Metlakatla": "Ora din Alaska (Metlakatla)", + "America\/Mexico_City": "Ora centrală nord-americană (Ciudad de Mexico)", + "America\/Miquelon": "Ora din Saint-Pierre și Miquelon (Miquelon)", + "America\/Moncton": "Ora zonei Atlantic nord-americane (Moncton)", + "America\/Monterrey": "Ora centrală nord-americană (Monterrey)", + "America\/Montevideo": "Ora Uruguayului (Montevideo)", + "America\/Montserrat": "Ora zonei Atlantic nord-americane (Montserrat)", + "America\/Nassau": "Ora orientală nord-americană (Nassau)", + "America\/New_York": "Ora orientală nord-americană (New York)", + "America\/Nipigon": "Ora orientală nord-americană (Nipigon)", + "America\/Nome": "Ora din Alaska (Nome)", + "America\/Noronha": "Ora din Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Ora centrală nord-americană (Beulah, Dakota de Nord)", + "America\/North_Dakota\/Center": "Ora centrală nord-americană (Center, Dakota de Nord)", + "America\/North_Dakota\/New_Salem": "Ora centrală nord-americană (New Salem, Dakota de Nord)", + "America\/Ojinaga": "Ora zonei montane nord-americane (Ojinaga)", + "America\/Panama": "Ora orientală nord-americană (Panama)", + "America\/Pangnirtung": "Ora orientală nord-americană (Pangnirtung)", + "America\/Paramaribo": "Ora Surinamului (Paramaribo)", + "America\/Phoenix": "Ora zonei montane nord-americane (Phoenix)", + "America\/Port-au-Prince": "Ora orientală nord-americană (Port-au-Prince)", + "America\/Port_of_Spain": "Ora zonei Atlantic nord-americane (Port of Spain)", + "America\/Porto_Velho": "Ora Amazonului (Porto Velho)", + "America\/Puerto_Rico": "Ora zonei Atlantic nord-americane (Puerto Rico)", + "America\/Punta_Arenas": "Ora din Chile (Punta Arenas)", + "America\/Rainy_River": "Ora centrală nord-americană (Rainy River)", + "America\/Rankin_Inlet": "Ora centrală nord-americană (Rankin Inlet)", + "America\/Recife": "Ora Brasiliei (Recife)", + "America\/Regina": "Ora centrală nord-americană (Regina)", + "America\/Resolute": "Ora centrală nord-americană (Resolute)", + "America\/Rio_Branco": "Ora Acre (Rio Branco)", + "America\/Santa_Isabel": "Ora Mexicului de nord-vest (Santa Isabel)", + "America\/Santarem": "Ora Brasiliei (Santarem)", + "America\/Santiago": "Ora din Chile (Santiago)", + "America\/Santo_Domingo": "Ora zonei Atlantic nord-americane (Santo Domingo)", + "America\/Sao_Paulo": "Ora Brasiliei (Sao Paulo)", + "America\/Scoresbysund": "Ora Groenlandei orientale (Ittoqqortoormiit)", + "America\/Sitka": "Ora din Alaska (Sitka)", + "America\/St_Barthelemy": "Ora zonei Atlantic nord-americane (Saint Barthélemy)", + "America\/St_Johns": "Ora din Newfoundland (St. John’s)", + "America\/St_Kitts": "Ora zonei Atlantic nord-americane (St. Kitts)", + "America\/St_Lucia": "Ora zonei Atlantic nord-americane (St. Lucia)", + "America\/St_Thomas": "Ora zonei Atlantic nord-americane (St. Thomas)", + "America\/St_Vincent": "Ora zonei Atlantic nord-americane (St. Vincent)", + "America\/Swift_Current": "Ora centrală nord-americană (Swift Current)", + "America\/Tegucigalpa": "Ora centrală nord-americană (Tegucigalpa)", + "America\/Thule": "Ora zonei Atlantic nord-americane (Thule)", + "America\/Thunder_Bay": "Ora orientală nord-americană (Thunder Bay)", + "America\/Tijuana": "Ora zonei Pacific nord-americane (Tijuana)", + "America\/Toronto": "Ora orientală nord-americană (Toronto)", + "America\/Tortola": "Ora zonei Atlantic nord-americane (Tortola)", + "America\/Vancouver": "Ora zonei Pacific nord-americane (Vancouver)", + "America\/Whitehorse": "Ora zonei Pacific nord-americane (Whitehorse)", + "America\/Winnipeg": "Ora centrală nord-americană (Winnipeg)", + "America\/Yakutat": "Ora din Alaska (Yakutat)", + "America\/Yellowknife": "Ora zonei montane nord-americane (Yellowknife)", + "Antarctica\/Casey": "Ora Australiei Occidentale (Casey)", + "Antarctica\/Davis": "Ora din Davis (Davis)", + "Antarctica\/DumontDUrville": "Ora din Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Ora din Macquarie (Macquarie)", + "Antarctica\/Mawson": "Ora din Mawson (Mawson)", + "Antarctica\/McMurdo": "Ora Noii Zeelande (McMurdo)", + "Antarctica\/Palmer": "Ora din Chile (Palmer)", + "Antarctica\/Rothera": "Ora din Rothera (Rothera)", + "Antarctica\/Syowa": "Ora din Syowa (Showa)", + "Antarctica\/Troll": "Ora de Greenwhich (Troll)", + "Antarctica\/Vostok": "Ora din Vostok (Vostok)", + "Arctic\/Longyearbyen": "Ora Europei Centrale (Longyearbyen)", + "Asia\/Aden": "Ora arabă (Aden)", + "Asia\/Almaty": "Ora din Kazahstanul de Est (Almatî)", + "Asia\/Amman": "Ora Europei de Est (Amman)", + "Asia\/Anadyr": "Ora din Anadyr (Anadir)", + "Asia\/Aqtau": "Ora din Kazahstanul de Vest (Aktau)", + "Asia\/Aqtobe": "Ora din Kazahstanul de Vest (Aktobe)", + "Asia\/Ashgabat": "Ora din Turkmenistan (Așgabat)", + "Asia\/Atyrau": "Ora din Kazahstanul de Vest (Atîrau)", + "Asia\/Baghdad": "Ora arabă (Bagdad)", + "Asia\/Bahrain": "Ora arabă (Bahrain)", + "Asia\/Baku": "Ora Azerbaidjanului (Baku)", + "Asia\/Bangkok": "Ora Indochinei (Bangkok)", + "Asia\/Beirut": "Ora Europei de Est (Beirut)", + "Asia\/Bishkek": "Ora din Kârgâzstan (Bișkek)", + "Asia\/Brunei": "Ora din Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Ora Indiei (Calcutta)", + "Asia\/Chita": "Ora din Iakuțk (Cita)", + "Asia\/Choibalsan": "Ora din Choibalsan (Choibalsan)", + "Asia\/Colombo": "Ora Indiei (Colombo)", + "Asia\/Damascus": "Ora Europei de Est (Damasc)", + "Asia\/Dhaka": "Ora din Bangladesh (Dacca)", + "Asia\/Dili": "Ora Timorului de Est (Dili)", + "Asia\/Dubai": "Ora standard a Golfului (Dubai)", + "Asia\/Dushanbe": "Ora din Tadjikistan (Dușanbe)", + "Asia\/Famagusta": "Ora Europei de Est (Famagusta)", + "Asia\/Gaza": "Ora Europei de Est (Gaza)", + "Asia\/Hebron": "Ora Europei de Est (Hebron)", + "Asia\/Hong_Kong": "Ora din Hong Kong (Hong Kong)", + "Asia\/Hovd": "Ora din Hovd (Hovd)", + "Asia\/Irkutsk": "Ora din Irkuțk (Irkuțk)", + "Asia\/Jakarta": "Ora Indoneziei de Vest (Jakarta)", + "Asia\/Jayapura": "Ora Indoneziei de Est (Jayapura)", + "Asia\/Jerusalem": "Ora Israelului (Ierusalim)", + "Asia\/Kabul": "Ora Afganistanului (Kabul)", + "Asia\/Kamchatka": "Ora din Petropavlovsk-Kamciațki (Kamciatka)", + "Asia\/Karachi": "Ora Pakistanului (Karachi)", + "Asia\/Katmandu": "Ora Nepalului (Kathmandu)", + "Asia\/Khandyga": "Ora din Iakuțk (Khandyga)", + "Asia\/Krasnoyarsk": "Ora din Krasnoiarsk (Krasnoiarsk)", + "Asia\/Kuala_Lumpur": "Ora din Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Ora din Malaysia (Kuching)", + "Asia\/Kuwait": "Ora arabă (Kuweit)", + "Asia\/Macau": "Ora Chinei (Macao)", + "Asia\/Magadan": "Ora din Magadan (Magadan)", + "Asia\/Makassar": "Ora Indoneziei Centrale (Makassar)", + "Asia\/Manila": "Ora din Filipine (Manila)", + "Asia\/Muscat": "Ora standard a Golfului (Muscat)", + "Asia\/Nicosia": "Ora Europei de Est (Nicosia)", + "Asia\/Novokuznetsk": "Ora din Krasnoiarsk (Novokuznețk)", + "Asia\/Novosibirsk": "Ora din Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Ora din Omsk (Omsk)", + "Asia\/Oral": "Ora din Kazahstanul de Vest (Uralsk)", + "Asia\/Phnom_Penh": "Ora Indochinei (Phnom Penh)", + "Asia\/Pontianak": "Ora Indoneziei de Vest (Pontianak)", + "Asia\/Pyongyang": "Ora Coreei (Phenian)", + "Asia\/Qatar": "Ora arabă (Qatar)", + "Asia\/Qostanay": "Ora din Kazahstanul de Est (Kostanay)", + "Asia\/Qyzylorda": "Ora din Kazahstanul de Vest (Kyzylorda)", + "Asia\/Rangoon": "Ora Myanmarului (Yangon)", + "Asia\/Riyadh": "Ora arabă (Riad)", + "Asia\/Saigon": "Ora Indochinei (Ho Și Min)", + "Asia\/Sakhalin": "Ora din Sahalin (Sahalin)", + "Asia\/Samarkand": "Ora din Uzbekistan (Samarkand)", + "Asia\/Seoul": "Ora Coreei (Seoul)", + "Asia\/Shanghai": "Ora Chinei (Shanghai)", + "Asia\/Singapore": "Ora din Singapore (Singapore)", + "Asia\/Srednekolymsk": "Ora din Magadan (Srednekolimsk)", + "Asia\/Taipei": "Ora din Taipei (Taipei)", + "Asia\/Tashkent": "Ora din Uzbekistan (Tașkent)", + "Asia\/Tbilisi": "Ora Georgiei (Tbilisi)", + "Asia\/Tehran": "Ora Iranului (Teheran)", + "Asia\/Thimphu": "Ora Bhutanului (Thimphu)", + "Asia\/Tokyo": "Ora Japoniei (Tokyo)", + "Asia\/Ulaanbaatar": "Ora din Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "Ora din Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Ora Indochinei (Vientiane)", + "Asia\/Vladivostok": "Ora din Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Ora din Iakuțk (Iakuțk)", + "Asia\/Yekaterinburg": "Ora din Ekaterinburg (Ekaterinburg)", + "Asia\/Yerevan": "Ora Armeniei (Erevan)", + "Atlantic\/Azores": "Ora din Azore (Azore)", + "Atlantic\/Bermuda": "Ora zonei Atlantic nord-americane (Bermuda)", + "Atlantic\/Canary": "Ora Europei de Vest (Canare)", + "Atlantic\/Cape_Verde": "Ora din Capul Verde (Capul Verde)", + "Atlantic\/Faeroe": "Ora Europei de Vest (Faroe)", + "Atlantic\/Madeira": "Ora Europei de Vest (Madeira)", + "Atlantic\/Reykjavik": "Ora de Greenwhich (Reykjavik)", + "Atlantic\/South_Georgia": "Ora Georgiei de Sud (Georgia de Sud)", + "Atlantic\/St_Helena": "Ora de Greenwhich (Sf. Elena)", + "Atlantic\/Stanley": "Ora din Insulele Falkland (Stanley)", + "Australia\/Adelaide": "Ora Australiei Centrale (Adelaide)", + "Australia\/Brisbane": "Ora Australiei Orientale (Brisbane)", + "Australia\/Broken_Hill": "Ora Australiei Centrale (Broken Hill)", + "Australia\/Currie": "Ora Australiei Orientale (Currie)", + "Australia\/Darwin": "Ora Australiei Centrale (Darwin)", + "Australia\/Eucla": "Ora Australiei Central Occidentale (Eucla)", + "Australia\/Hobart": "Ora Australiei Orientale (Hobart)", + "Australia\/Lindeman": "Ora Australiei Orientale (Lindeman)", + "Australia\/Lord_Howe": "Ora din Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Ora Australiei Orientale (Melbourne)", + "Australia\/Perth": "Ora Australiei Occidentale (Perth)", + "Australia\/Sydney": "Ora Australiei Orientale (Sydney)", + "CST6CDT": "Ora centrală nord-americană", + "EST5EDT": "Ora orientală nord-americană", + "Etc\/GMT": "Ora de Greenwhich", + "Etc\/UTC": "Timpul universal coordonat", + "Europe\/Amsterdam": "Ora Europei Centrale (Amsterdam)", + "Europe\/Andorra": "Ora Europei Centrale (Andorra)", + "Europe\/Astrakhan": "Ora Moscovei (Astrahan)", + "Europe\/Athens": "Ora Europei de Est (Atena)", + "Europe\/Belgrade": "Ora Europei Centrale (Belgrad)", + "Europe\/Berlin": "Ora Europei Centrale (Berlin)", + "Europe\/Bratislava": "Ora Europei Centrale (Bratislava)", + "Europe\/Brussels": "Ora Europei Centrale (Bruxelles)", + "Europe\/Bucharest": "Ora Europei de Est (București)", + "Europe\/Budapest": "Ora Europei Centrale (Budapesta)", + "Europe\/Busingen": "Ora Europei Centrale (Busingen)", + "Europe\/Chisinau": "Ora Europei de Est (Chișinău)", + "Europe\/Copenhagen": "Ora Europei Centrale (Copenhaga)", + "Europe\/Dublin": "Ora de Greenwhich (Dublin)", + "Europe\/Gibraltar": "Ora Europei Centrale (Gibraltar)", + "Europe\/Guernsey": "Ora de Greenwhich (Guernsey)", + "Europe\/Helsinki": "Ora Europei de Est (Helsinki)", + "Europe\/Isle_of_Man": "Ora de Greenwhich (Insula Man)", + "Europe\/Jersey": "Ora de Greenwhich (Jersey)", + "Europe\/Kaliningrad": "Ora Europei de Est (Kaliningrad)", + "Europe\/Kiev": "Ora Europei de Est (Kiev)", + "Europe\/Lisbon": "Ora Europei de Vest (Lisabona)", + "Europe\/Ljubljana": "Ora Europei Centrale (Ljubljana)", + "Europe\/London": "Ora de Greenwhich (Londra)", + "Europe\/Luxembourg": "Ora Europei Centrale (Luxemburg)", + "Europe\/Madrid": "Ora Europei Centrale (Madrid)", + "Europe\/Malta": "Ora Europei Centrale (Malta)", + "Europe\/Mariehamn": "Ora Europei de Est (Mariehamn)", + "Europe\/Minsk": "Ora Moscovei (Minsk)", + "Europe\/Monaco": "Ora Europei Centrale (Monaco)", + "Europe\/Moscow": "Ora Moscovei (Moscova)", + "Europe\/Oslo": "Ora Europei Centrale (Oslo)", + "Europe\/Paris": "Ora Europei Centrale (Paris)", + "Europe\/Podgorica": "Ora Europei Centrale (Podgorica)", + "Europe\/Prague": "Ora Europei Centrale (Praga)", + "Europe\/Riga": "Ora Europei de Est (Riga)", + "Europe\/Rome": "Ora Europei Centrale (Roma)", + "Europe\/Samara": "Ora din Samara (Samara)", + "Europe\/San_Marino": "Ora Europei Centrale (San Marino)", + "Europe\/Sarajevo": "Ora Europei Centrale (Sarajevo)", + "Europe\/Saratov": "Ora Moscovei (Saratov)", + "Europe\/Simferopol": "Ora Moscovei (Simferopol)", + "Europe\/Skopje": "Ora Europei Centrale (Skopje)", + "Europe\/Sofia": "Ora Europei de Est (Sofia)", + "Europe\/Stockholm": "Ora Europei Centrale (Stockholm)", + "Europe\/Tallinn": "Ora Europei de Est (Tallinn)", + "Europe\/Tirane": "Ora Europei Centrale (Tirana)", + "Europe\/Ulyanovsk": "Ora Moscovei (Ulianovsk)", + "Europe\/Uzhgorod": "Ora Europei de Est (Ujhorod)", + "Europe\/Vaduz": "Ora Europei Centrale (Vaduz)", + "Europe\/Vatican": "Ora Europei Centrale (Vatican)", + "Europe\/Vienna": "Ora Europei Centrale (Viena)", + "Europe\/Vilnius": "Ora Europei de Est (Vilnius)", + "Europe\/Volgograd": "Ora din Volgograd (Volgograd)", + "Europe\/Warsaw": "Ora Europei Centrale (Varșovia)", + "Europe\/Zagreb": "Ora Europei Centrale (Zagreb)", + "Europe\/Zaporozhye": "Ora Europei de Est (Zaporoje)", + "Europe\/Zurich": "Ora Europei Centrale (Zürich)", + "Indian\/Antananarivo": "Ora Africii Orientale (Antananarivo)", + "Indian\/Chagos": "Ora Oceanului Indian (Chagos)", + "Indian\/Christmas": "Ora din Insula Christmas (Christmas)", + "Indian\/Cocos": "Ora Insulelor Cocos (Cocos)", + "Indian\/Comoro": "Ora Africii Orientale (Comore)", + "Indian\/Kerguelen": "Ora din Teritoriile Australe și Antarctice Franceze (Kerguelen)", + "Indian\/Mahe": "Ora din Seychelles (Mahe)", + "Indian\/Maldives": "Ora din Maldive (Maldive)", + "Indian\/Mauritius": "Ora din Mauritius (Mauritius)", + "Indian\/Mayotte": "Ora Africii Orientale (Mayotte)", + "Indian\/Reunion": "Ora din Reunion (Réunion)", + "MST7MDT": "Ora zonei montane nord-americane", + "PST8PDT": "Ora zonei Pacific nord-americane", + "Pacific\/Apia": "Ora din Apia (Apia)", + "Pacific\/Auckland": "Ora Noii Zeelande (Auckland)", + "Pacific\/Bougainville": "Ora din Papua Noua Guinee (Bougainville)", + "Pacific\/Chatham": "Ora din Chatham (Chatham)", + "Pacific\/Easter": "Ora din Insula Paștelui (Insula Paștelui)", + "Pacific\/Efate": "Ora din Vanuatu (Efate)", + "Pacific\/Enderbury": "Ora Insulelor Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Ora din Tokelau (Fakaofo)", + "Pacific\/Fiji": "Ora din Fiji (Fiji)", + "Pacific\/Funafuti": "Ora din Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Ora din Galapagos (Galapagos)", + "Pacific\/Gambier": "Ora din Gambier (Gambier)", + "Pacific\/Guadalcanal": "Ora Insulelor Solomon (Guadalcanal)", + "Pacific\/Guam": "Ora din Chamorro (Guam)", + "Pacific\/Honolulu": "Ora din Hawaii-Aleutine (Honolulu)", + "Pacific\/Johnston": "Ora din Hawaii-Aleutine (Johnston)", + "Pacific\/Kiritimati": "Ora din Insulele Line (Kiritimati)", + "Pacific\/Kosrae": "Ora din Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Ora Insulelor Marshall (Kwajalein)", + "Pacific\/Majuro": "Ora Insulelor Marshall (Majuro)", + "Pacific\/Marquesas": "Ora Insulelor Marchize (Marchize)", + "Pacific\/Midway": "Ora din Samoa (Midway)", + "Pacific\/Nauru": "Ora din Nauru (Nauru)", + "Pacific\/Niue": "Ora din Niue (Niue)", + "Pacific\/Norfolk": "Ora Insulelor Norfolk (Norfolk)", + "Pacific\/Noumea": "Ora Noii Caledonii (Noumea)", + "Pacific\/Pago_Pago": "Ora din Samoa (Pago Pago)", + "Pacific\/Palau": "Ora din Palau (Palau)", + "Pacific\/Pitcairn": "Ora din Pitcairn (Insula Pitcairn)", + "Pacific\/Ponape": "Ora din Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Ora din Papua Noua Guinee (Port Moresby)", + "Pacific\/Rarotonga": "Ora Insulelor Cook (Rarotonga)", + "Pacific\/Saipan": "Ora din Chamorro (Saipan)", + "Pacific\/Tahiti": "Ora din Tahiti (Tahiti)", + "Pacific\/Tarawa": "Ora Insulelor Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Ora din Tonga (Tongatapu)", + "Pacific\/Truk": "Ora din Chuuk (Chuuk)", + "Pacific\/Wake": "Ora Insulei Wake (Wake)", + "Pacific\/Wallis": "Ora din Wallis și Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/mr.json b/src/Symfony/Component/Intl/Resources/data/timezones/mr.json new file mode 100644 index 0000000000000..1ad68d258da50 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/mr.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "ग्रीनिच प्रमाण वेळ (अबिद्जान)", + "Africa\/Accra": "ग्रीनिच प्रमाण वेळ (अ‍ॅक्रा)", + "Africa\/Addis_Ababa": "पूर्व आफ्रिका वेळ (आदिस अबाबा)", + "Africa\/Algiers": "मध्‍य युरोपियन वेळ (अल्जिअर्स)", + "Africa\/Asmera": "पूर्व आफ्रिका वेळ (एस्मारा)", + "Africa\/Bamako": "ग्रीनिच प्रमाण वेळ (बामको)", + "Africa\/Bangui": "पश्चिम आफ्रिका वेळ (बांगुई)", + "Africa\/Banjul": "ग्रीनिच प्रमाण वेळ (बंजुल)", + "Africa\/Bissau": "ग्रीनिच प्रमाण वेळ (बिसाउ)", + "Africa\/Blantyre": "मध्‍य आफ्रिका वेळ (ब्लँटायर)", + "Africa\/Brazzaville": "पश्चिम आफ्रिका वेळ (ब्राझाव्हिले)", + "Africa\/Bujumbura": "मध्‍य आफ्रिका वेळ (बुजुंबुरा)", + "Africa\/Cairo": "पूर्व युरोपियन वेळ (कैरो)", + "Africa\/Casablanca": "पश्चिम युरोपियन वेळ (कॅसाब्लान्का)", + "Africa\/Ceuta": "मध्‍य युरोपियन वेळ (सेउटा)", + "Africa\/Conakry": "ग्रीनिच प्रमाण वेळ (कोनाक्रि)", + "Africa\/Dakar": "ग्रीनिच प्रमाण वेळ (डकर)", + "Africa\/Dar_es_Salaam": "पूर्व आफ्रिका वेळ (दार ए सलाम)", + "Africa\/Djibouti": "पूर्व आफ्रिका वेळ (जिबौटी)", + "Africa\/Douala": "पश्चिम आफ्रिका वेळ (दोउआला)", + "Africa\/El_Aaiun": "पश्चिम युरोपियन वेळ (एल ऐउन)", + "Africa\/Freetown": "ग्रीनिच प्रमाण वेळ (फ्रीटाउन)", + "Africa\/Gaborone": "मध्‍य आफ्रिका वेळ (गाबोरोन)", + "Africa\/Harare": "मध्‍य आफ्रिका वेळ (हरारे)", + "Africa\/Johannesburg": "दक्षिण आफ्रिका प्रमाण वेळ (जोहान्सबर्ग)", + "Africa\/Juba": "पूर्व आफ्रिका वेळ (जुबा)", + "Africa\/Kampala": "पूर्व आफ्रिका वेळ (कंपाला)", + "Africa\/Khartoum": "मध्‍य आफ्रिका वेळ (खार्टुम)", + "Africa\/Kigali": "मध्‍य आफ्रिका वेळ (कीगाली)", + "Africa\/Kinshasa": "पश्चिम आफ्रिका वेळ (किन्शासा)", + "Africa\/Lagos": "पश्चिम आफ्रिका वेळ (लागोस)", + "Africa\/Libreville": "पश्चिम आफ्रिका वेळ (लिबरव्हिल)", + "Africa\/Lome": "ग्रीनिच प्रमाण वेळ (लोम)", + "Africa\/Luanda": "पश्चिम आफ्रिका वेळ (लुआंडा)", + "Africa\/Lubumbashi": "मध्‍य आफ्रिका वेळ (लुबंबाशी)", + "Africa\/Lusaka": "मध्‍य आफ्रिका वेळ (लुसाका)", + "Africa\/Malabo": "पश्चिम आफ्रिका वेळ (मलाबो)", + "Africa\/Maputo": "मध्‍य आफ्रिका वेळ (मापुटो)", + "Africa\/Maseru": "दक्षिण आफ्रिका प्रमाण वेळ (मसेरु)", + "Africa\/Mbabane": "दक्षिण आफ्रिका प्रमाण वेळ (अंबाबाने)", + "Africa\/Mogadishu": "पूर्व आफ्रिका वेळ (मोगादिशु)", + "Africa\/Monrovia": "ग्रीनिच प्रमाण वेळ (मोनरोव्हिया)", + "Africa\/Nairobi": "पूर्व आफ्रिका वेळ (नैरोबी)", + "Africa\/Ndjamena": "पश्चिम आफ्रिका वेळ (इंजामेना)", + "Africa\/Niamey": "पश्चिम आफ्रिका वेळ (नियामे)", + "Africa\/Nouakchott": "ग्रीनिच प्रमाण वेळ (नुवाकसुत)", + "Africa\/Ouagadougou": "ग्रीनिच प्रमाण वेळ (वागडूगू)", + "Africa\/Porto-Novo": "पश्चिम आफ्रिका वेळ (पोर्टो-नोव्हो)", + "Africa\/Sao_Tome": "ग्रीनिच प्रमाण वेळ (साओ तोमे)", + "Africa\/Tripoli": "पूर्व युरोपियन वेळ (त्रिपोली)", + "Africa\/Tunis": "मध्‍य युरोपियन वेळ (टयूनिस)", + "Africa\/Windhoek": "मध्‍य आफ्रिका वेळ (विंडहोएक)", + "America\/Adak": "हवाई-अलूशन वेळ (अडॅक)", + "America\/Anchorage": "अलास्का वेळ (अँकरेज)", + "America\/Anguilla": "अटलांटिक वेळ (अँग्विला)", + "America\/Antigua": "अटलांटिक वेळ (अँटिग्वा)", + "America\/Araguaina": "ब्राझिलिया वेळ (अरागायना)", + "America\/Argentina\/La_Rioja": "अर्जेंटिना वेळ (ला रियोजा)", + "America\/Argentina\/Rio_Gallegos": "अर्जेंटिना वेळ (रियो गॅलेगॉस)", + "America\/Argentina\/Salta": "अर्जेंटिना वेळ (सॉल्ता)", + "America\/Argentina\/San_Juan": "अर्जेंटिना वेळ (सान जुआन)", + "America\/Argentina\/San_Luis": "पश्चिमी अर्जेंटिना वेळ (सान ल्युइस)", + "America\/Argentina\/Tucuman": "अर्जेंटिना वेळ (टुकुमान)", + "America\/Argentina\/Ushuaia": "अर्जेंटिना वेळ (उस्वाइया)", + "America\/Aruba": "अटलांटिक वेळ (अरुबा)", + "America\/Asuncion": "पॅराग्वे वेळ (आसुन्सियोन)", + "America\/Bahia": "ब्राझिलिया वेळ (बहिया)", + "America\/Bahia_Banderas": "केंद्रीय वेळ (बाहिया बांदेरास)", + "America\/Barbados": "अटलांटिक वेळ (बार्बाडोस)", + "America\/Belem": "ब्राझिलिया वेळ (बेलेम)", + "America\/Belize": "केंद्रीय वेळ (बेलिझे)", + "America\/Blanc-Sablon": "अटलांटिक वेळ (ब्लांक सॅबलोन)", + "America\/Boa_Vista": "अॅमेझॉन वेळ (बोआ व्हिस्टा)", + "America\/Bogota": "कोलंबिया वेळ (बोगोटा)", + "America\/Boise": "पर्वतीय वेळ (बोइसी)", + "America\/Buenos_Aires": "अर्जेंटिना वेळ (ब्युनोस आयर्स)", + "America\/Cambridge_Bay": "पर्वतीय वेळ (केंब्रिज उपसागर)", + "America\/Campo_Grande": "अॅमेझॉन वेळ (कॅम्पो ग्रँडे)", + "America\/Cancun": "पौर्वात्य वेळ (कानकुन)", + "America\/Caracas": "व्हेनेझुएला वेळ (कराकास)", + "America\/Catamarca": "अर्जेंटिना वेळ (कॅटामार्का)", + "America\/Cayenne": "फ्रेंच गयाना वेळ (कायेने)", + "America\/Cayman": "पौर्वात्य वेळ (केमन)", + "America\/Chicago": "केंद्रीय वेळ (शिकागो)", + "America\/Chihuahua": "मेक्सिको पॅसिफिक वेळ (चिहुआहुआ)", + "America\/Coral_Harbour": "पौर्वात्य वेळ (अॅटिकोकन)", + "America\/Cordoba": "अर्जेंटिना वेळ (कॉर्डोबा)", + "America\/Costa_Rica": "केंद्रीय वेळ (कोस्टा रिका)", + "America\/Creston": "पर्वतीय वेळ (क्रेस्टन)", + "America\/Cuiaba": "अॅमेझॉन वेळ (कुयाबा)", + "America\/Curacao": "अटलांटिक वेळ (क्युरासाओ)", + "America\/Danmarkshavn": "ग्रीनिच प्रमाण वेळ (डेन्मार्कशॉन)", + "America\/Dawson": "पॅसिफिक वेळ (डॉसन)", + "America\/Dawson_Creek": "पर्वतीय वेळ (डॉसन क्रीक)", + "America\/Denver": "पर्वतीय वेळ (डेन्व्हर)", + "America\/Detroit": "पौर्वात्य वेळ (डेट्रॉइट)", + "America\/Dominica": "अटलांटिक वेळ (डोमिनिका)", + "America\/Edmonton": "पर्वतीय वेळ (एडमाँटन)", + "America\/Eirunepe": "एकर वेळ (यूरुनीपे)", + "America\/El_Salvador": "केंद्रीय वेळ (एल साल्वाडोर)", + "America\/Fort_Nelson": "पर्वतीय वेळ (फोर्ट नेल्सन)", + "America\/Fortaleza": "ब्राझिलिया वेळ (फोर्टालेझा)", + "America\/Glace_Bay": "अटलांटिक वेळ (ग्लेस उपसागर)", + "America\/Godthab": "पश्चिम ग्रीनलँड वेळ (नूक)", + "America\/Goose_Bay": "अटलांटिक वेळ (गूस उपसागर)", + "America\/Grand_Turk": "पौर्वात्य वेळ (ग्रँड टर्क)", + "America\/Grenada": "अटलांटिक वेळ (ग्रेनेडा)", + "America\/Guadeloupe": "अटलांटिक वेळ (ग्वाडेलोउपे)", + "America\/Guatemala": "केंद्रीय वेळ (ग्वाटेमाला)", + "America\/Guayaquil": "इक्वेडोर वेळ (गयाक्विल)", + "America\/Guyana": "गयाना वेळ (गयाना)", + "America\/Halifax": "अटलांटिक वेळ (हॅलिफॅक्स)", + "America\/Havana": "क्यूबा वेळ (हवाना)", + "America\/Hermosillo": "मेक्सिको पॅसिफिक वेळ (हर्मोसिलो)", + "America\/Indiana\/Knox": "केंद्रीय वेळ (नॉक्स, इंडियाना)", + "America\/Indiana\/Marengo": "पौर्वात्य वेळ (मारेंगो, इंडियाना)", + "America\/Indiana\/Petersburg": "पौर्वात्य वेळ (पीटर्सबर्ग, इंडियाना)", + "America\/Indiana\/Tell_City": "केंद्रीय वेळ (टेल सिटी, इंडियाना)", + "America\/Indiana\/Vevay": "पौर्वात्य वेळ (वेवाय-इंडियाना)", + "America\/Indiana\/Vincennes": "पौर्वात्य वेळ (विंसेनस, इंडियाना)", + "America\/Indiana\/Winamac": "पौर्वात्य वेळ (विनमॅक, इंडियाना)", + "America\/Indianapolis": "पौर्वात्य वेळ (इंडियानापोलिस)", + "America\/Inuvik": "पर्वतीय वेळ (इनुविक)", + "America\/Iqaluit": "पौर्वात्य वेळ (इकालुइत)", + "America\/Jamaica": "पौर्वात्य वेळ (जमैका)", + "America\/Jujuy": "अर्जेंटिना वेळ (जुजुय)", + "America\/Juneau": "अलास्का वेळ (ज्यूनौ)", + "America\/Kentucky\/Monticello": "पौर्वात्य वेळ (माँटिसेलो, केंटुकी)", + "America\/Kralendijk": "अटलांटिक वेळ (क्रालेंदिजिक)", + "America\/La_Paz": "बोलिव्हिया वेळ (ला पाझ)", + "America\/Lima": "पेरु वेळ (लीमा)", + "America\/Los_Angeles": "पॅसिफिक वेळ (लॉस एंजेलिस)", + "America\/Louisville": "पौर्वात्य वेळ (ल्युइसव्हिल)", + "America\/Lower_Princes": "अटलांटिक वेळ (लोअर प्रिन्सस क्वार्टर)", + "America\/Maceio": "ब्राझिलिया वेळ (मेसेइओ)", + "America\/Managua": "केंद्रीय वेळ (मानागुआ)", + "America\/Manaus": "अॅमेझॉन वेळ (मनौस)", + "America\/Marigot": "अटलांटिक वेळ (मेरीगोट)", + "America\/Martinique": "अटलांटिक वेळ (मार्टिनिक)", + "America\/Matamoros": "केंद्रीय वेळ (माटामोरोस)", + "America\/Mazatlan": "मेक्सिको पॅसिफिक वेळ (माझातलान)", + "America\/Mendoza": "अर्जेंटिना वेळ (मेंदोझा)", + "America\/Menominee": "केंद्रीय वेळ (मेनोमिनी)", + "America\/Merida": "केंद्रीय वेळ (मेरिडा)", + "America\/Metlakatla": "अलास्का वेळ (मेतलाकतला)", + "America\/Mexico_City": "केंद्रीय वेळ (मेक्सिको सिटी)", + "America\/Miquelon": "सेंट पियर आणि मिक्वेलोन वेळ (मिक्वेलोन)", + "America\/Moncton": "अटलांटिक वेळ (माँकटन)", + "America\/Monterrey": "केंद्रीय वेळ (मॉन्टेरे)", + "America\/Montevideo": "उरुग्वे वेळ (मोन्टेव्हिडियो)", + "America\/Montserrat": "अटलांटिक वेळ (माँन्टसेरात)", + "America\/Nassau": "पौर्वात्य वेळ (नसाऊ)", + "America\/New_York": "पौर्वात्य वेळ (न्यूयॉर्क)", + "America\/Nipigon": "पौर्वात्य वेळ (निपिगोन)", + "America\/Nome": "अलास्का वेळ (नोम)", + "America\/Noronha": "फर्नांडो दी नोरोन्हा वेळ (नोरोन्हा)", + "America\/North_Dakota\/Beulah": "केंद्रीय वेळ (ब्युलाह, उत्तर डकोटा)", + "America\/North_Dakota\/Center": "केंद्रीय वेळ (मध्य, उत्तर डकोटा)", + "America\/North_Dakota\/New_Salem": "केंद्रीय वेळ (न्यू सालेम, उत्तर डकोटा)", + "America\/Ojinaga": "पर्वतीय वेळ (ओजिनागा)", + "America\/Panama": "पौर्वात्य वेळ (पनामा)", + "America\/Pangnirtung": "पौर्वात्य वेळ (पँगनिरतुंग)", + "America\/Paramaribo": "सुरिनाम वेळ (पारमरीबो)", + "America\/Phoenix": "पर्वतीय वेळ (फॉनिक्स)", + "America\/Port-au-Prince": "पौर्वात्य वेळ (पोर्ट-औ-प्रिंस)", + "America\/Port_of_Spain": "अटलांटिक वेळ (पोर्ट ऑफ स्पेन)", + "America\/Porto_Velho": "अॅमेझॉन वेळ (पोर्टो वेल्हो)", + "America\/Puerto_Rico": "अटलांटिक वेळ (प्युएर्तो रिको)", + "America\/Punta_Arenas": "चिली वेळ (पुंता अरीनास)", + "America\/Rainy_River": "केंद्रीय वेळ (रेनी नदी)", + "America\/Rankin_Inlet": "केंद्रीय वेळ (रॅनकिन इनलेट)", + "America\/Recife": "ब्राझिलिया वेळ (रेसिफे)", + "America\/Regina": "केंद्रीय वेळ (रेजिना)", + "America\/Resolute": "केंद्रीय वेळ (रेजोल्यूट)", + "America\/Rio_Branco": "एकर वेळ (रियो ब्रांको)", + "America\/Santa_Isabel": "वायव्य मेक्सिको वेळ (सांता इसाबेल)", + "America\/Santarem": "ब्राझिलिया वेळ (सँटारेम)", + "America\/Santiago": "चिली वेळ (सॅन्टिएगो)", + "America\/Santo_Domingo": "अटलांटिक वेळ (सॅन्टो डोमिंगो)", + "America\/Sao_Paulo": "ब्राझिलिया वेळ (साओ पावलो)", + "America\/Scoresbysund": "पूर्व ग्रीनलँड वेळ (इटोकॉरटॉर्मीट)", + "America\/Sitka": "अलास्का वेळ (सिटका)", + "America\/St_Barthelemy": "अटलांटिक वेळ (सेंट बार्थेलेमी)", + "America\/St_Johns": "न्यू फाउंडलंड वेळ (सेंट जॉन्स)", + "America\/St_Kitts": "अटलांटिक वेळ (सेंट किट्स)", + "America\/St_Lucia": "अटलांटिक वेळ (सेंट लुसिया)", + "America\/St_Thomas": "अटलांटिक वेळ (सेंट थॉमस)", + "America\/St_Vincent": "अटलांटिक वेळ (सेंट विन्सेंट)", + "America\/Swift_Current": "केंद्रीय वेळ (स्विफ्ट करंट)", + "America\/Tegucigalpa": "केंद्रीय वेळ (टेगुसिगाल्पा)", + "America\/Thule": "अटलांटिक वेळ (थुले)", + "America\/Thunder_Bay": "पौर्वात्य वेळ (थंडर उपसागर)", + "America\/Tijuana": "पॅसिफिक वेळ (तिजुआना)", + "America\/Toronto": "पौर्वात्य वेळ (टोरोंटो)", + "America\/Tortola": "अटलांटिक वेळ (टोर्टोला)", + "America\/Vancouver": "पॅसिफिक वेळ (व्हॅनकुव्हर)", + "America\/Whitehorse": "पॅसिफिक वेळ (व्हाइटहॉर्स)", + "America\/Winnipeg": "केंद्रीय वेळ (विनीपेग)", + "America\/Yakutat": "अलास्का वेळ (यकुतात)", + "America\/Yellowknife": "पर्वतीय वेळ (यलोनाइफ)", + "Antarctica\/Casey": "पश्चिम ऑस्ट्रेलिया वेळ (कॅसे)", + "Antarctica\/Davis": "डेव्हिस वेळ (डेव्हिस)", + "Antarctica\/DumontDUrville": "ड्युमॉन्ट-ड्युर्विल वेळ (ड्युमॉन्ट ड्युर्विल)", + "Antarctica\/Macquarie": "मॅक्वेरी बेट वेळ (मॅक्वायर)", + "Antarctica\/Mawson": "मॉसन वेळ (मॉसन)", + "Antarctica\/McMurdo": "न्यूझीलंड वेळ (मॅक्मुरडो)", + "Antarctica\/Palmer": "चिली वेळ (पामेर)", + "Antarctica\/Rothera": "रोथेरा वेळ (रोथेरा)", + "Antarctica\/Syowa": "स्योवा वेळ (स्योवा)", + "Antarctica\/Troll": "ग्रीनिच प्रमाण वेळ (ट्रोल)", + "Antarctica\/Vostok": "व्होस्टॉक वेळ (वोस्टोक)", + "Arctic\/Longyearbyen": "मध्‍य युरोपियन वेळ (लाँगइयरबीयेन)", + "Asia\/Aden": "अरेबियन वेळ (एडेन)", + "Asia\/Almaty": "पूर्व कझाकस्तान वेळ (अल्माटी)", + "Asia\/Amman": "पूर्व युरोपियन वेळ (अम्मान)", + "Asia\/Anadyr": "एनाडीयर वेळ (एनाडीयर)", + "Asia\/Aqtau": "पश्चिम कझाकस्तान वेळ (अ‍ॅक्टौ)", + "Asia\/Aqtobe": "पश्चिम कझाकस्तान वेळ (अ‍ॅक्टोबे)", + "Asia\/Ashgabat": "तुर्कमेनिस्तान वेळ (अश्गाबात)", + "Asia\/Atyrau": "पश्चिम कझाकस्तान वेळ (अतिरॉ)", + "Asia\/Baghdad": "अरेबियन वेळ (बगदाद)", + "Asia\/Bahrain": "अरेबियन वेळ (बेहरीन)", + "Asia\/Baku": "अझरबैजान वेळ (बाकु)", + "Asia\/Bangkok": "इंडोचायना वेळ (बँकॉक)", + "Asia\/Beirut": "पूर्व युरोपियन वेळ (बैरुत)", + "Asia\/Bishkek": "किरगिस्तान वेळ (बिश्केक)", + "Asia\/Brunei": "ब्रुनेई दारूसलाम वेळ (ब्रुनेई)", + "Asia\/Calcutta": "भारतीय प्रमाण वेळ (कोलकाता)", + "Asia\/Chita": "याकुत्सक वेळ (चिता)", + "Asia\/Choibalsan": "चोईबाल्सन वेळ (चोईबाल्सन)", + "Asia\/Colombo": "भारतीय प्रमाण वेळ (कोलंबो)", + "Asia\/Damascus": "पूर्व युरोपियन वेळ (दमास्कस)", + "Asia\/Dhaka": "बांगलादेश वेळ (ढाका)", + "Asia\/Dili": "पूर्व तिमोर वेळ (डिलि)", + "Asia\/Dubai": "खाडी प्रमाण वेळ (दुबई)", + "Asia\/Dushanbe": "ताजिकिस्तान वेळ (दुशान्बे)", + "Asia\/Famagusta": "पूर्व युरोपियन वेळ (फॅमगुस्ता)", + "Asia\/Gaza": "पूर्व युरोपियन वेळ (गाझा)", + "Asia\/Hebron": "पूर्व युरोपियन वेळ (हेब्रॉन)", + "Asia\/Hong_Kong": "हाँग काँग वेळ (हाँगकाँग)", + "Asia\/Hovd": "होव्ह्ड वेळ (होव्ड)", + "Asia\/Irkutsk": "इर्कुत्सक वेळ (ईर्कुत्स्क)", + "Asia\/Jakarta": "पश्चिमी इंडोनेशिया वेळ (जकार्ता)", + "Asia\/Jayapura": "पौर्वात्य इंडोनेशिया वेळ (जयापुरा)", + "Asia\/Jerusalem": "इस्रायल (जेरुसलेम)", + "Asia\/Kabul": "अफगाणिस्तान वेळ (काबूल)", + "Asia\/Kamchatka": "पेट्रोपाव्हलोस्क- कामचाट्स्की वेळ (कॅमचाटका)", + "Asia\/Karachi": "पाकिस्तान वेळ (कराची)", + "Asia\/Katmandu": "नेपाळ वेळ (काठमांडू)", + "Asia\/Khandyga": "याकुत्सक वेळ (खंदिगा)", + "Asia\/Krasnoyarsk": "क्रास्नोयार्स्क वेळ (क्रास्नोयार्स्क)", + "Asia\/Kuala_Lumpur": "मलेशिया वेळ (क्वालालंपूर)", + "Asia\/Kuching": "मलेशिया वेळ (कुचिंग)", + "Asia\/Kuwait": "अरेबियन वेळ (कुवेत)", + "Asia\/Macau": "चीनी वेळ (मकाऊ)", + "Asia\/Magadan": "मॅगाडन वेळ (मेगाडन)", + "Asia\/Makassar": "मध्‍य इंडोनेशिया वेळ (मकस्सार)", + "Asia\/Manila": "फिलिपाइन वेळ (मनिला)", + "Asia\/Muscat": "खाडी प्रमाण वेळ (मस्कत)", + "Asia\/Nicosia": "पूर्व युरोपियन वेळ (निकोसिया)", + "Asia\/Novokuznetsk": "क्रास्नोयार्स्क वेळ (नोवोकुझ्नेत्स्क)", + "Asia\/Novosibirsk": "नोवोसिबिर्स्क वेळ (नोवोसिबिर्स्क)", + "Asia\/Omsk": "ओम्स्क वेळ (ओम्स्क)", + "Asia\/Oral": "पश्चिम कझाकस्तान वेळ (ओरल)", + "Asia\/Phnom_Penh": "इंडोचायना वेळ (प्नोम पेन्ह)", + "Asia\/Pontianak": "पश्चिमी इंडोनेशिया वेळ (पाँटियानाक)", + "Asia\/Pyongyang": "कोरियन वेळ (प्योंगयांग)", + "Asia\/Qatar": "अरेबियन वेळ (कतार)", + "Asia\/Qostanay": "पूर्व कझाकस्तान वेळ (कोस्टाने)", + "Asia\/Qyzylorda": "पश्चिम कझाकस्तान वेळ (किझीलोर्डा)", + "Asia\/Rangoon": "म्यानमार वेळ (रंगून)", + "Asia\/Riyadh": "अरेबियन वेळ (रियाध)", + "Asia\/Saigon": "इंडोचायना वेळ (हो चि मिन्ह शहर)", + "Asia\/Sakhalin": "सखलिन वेळ (साखालिन)", + "Asia\/Samarkand": "उझबेकिस्तान वेळ (समरकंद)", + "Asia\/Seoul": "कोरियन वेळ (सेउल)", + "Asia\/Shanghai": "चीनी वेळ (शांघाय)", + "Asia\/Singapore": "सिंगापूर प्रमाण वेळ (सिंगापूर)", + "Asia\/Srednekolymsk": "मॅगाडन वेळ (स्रेदनेकोलीम्स्क)", + "Asia\/Taipei": "तैपेई वेळ (तैपेई)", + "Asia\/Tashkent": "उझबेकिस्तान वेळ (ताश्कंद)", + "Asia\/Tbilisi": "जॉर्जिया वेळ (बिलिसी)", + "Asia\/Tehran": "इराण वेळ (तेहरान)", + "Asia\/Thimphu": "भूतान वेळ (थिंफू)", + "Asia\/Tokyo": "जपान वेळ (टोकियो)", + "Asia\/Ulaanbaatar": "उलान बाटोर वेळ (उलानबातर)", + "Asia\/Ust-Nera": "व्लादिवोस्तोक वेळ (उस्त-नेरा)", + "Asia\/Vientiane": "इंडोचायना वेळ (व्हिएन्टाइन)", + "Asia\/Vladivostok": "व्लादिवोस्तोक वेळ (व्लादिवोस्टोक)", + "Asia\/Yakutsk": "याकुत्सक वेळ (यकुत्स्क)", + "Asia\/Yekaterinburg": "येकतरिनबर्ग वेळ (येक्तेरिनबर्ग)", + "Asia\/Yerevan": "आर्मेनिया वेळ (येरेवन)", + "Atlantic\/Azores": "अ‍ॅझोरेस वेळ (अझोरेस)", + "Atlantic\/Bermuda": "अटलांटिक वेळ (बर्मुडा)", + "Atlantic\/Canary": "पश्चिम युरोपियन वेळ (कॅनरी)", + "Atlantic\/Cape_Verde": "केप व्हर्डे वेळ (केप व्हर्डे)", + "Atlantic\/Faeroe": "पश्चिम युरोपियन वेळ (फॅरो)", + "Atlantic\/Madeira": "पश्चिम युरोपियन वेळ (मडीयरा)", + "Atlantic\/Reykjavik": "ग्रीनिच प्रमाण वेळ (रेयक्जाविक)", + "Atlantic\/South_Georgia": "दक्षिण जॉर्जिया वेळ (दक्षिण जॉर्जिया)", + "Atlantic\/St_Helena": "ग्रीनिच प्रमाण वेळ (सेंट. हेलेना)", + "Atlantic\/Stanley": "फॉकलंड बेटे वेळ (स्टॅनले)", + "Australia\/Adelaide": "मध्य ऑस्ट्रेलिया वेळ (एडलेड)", + "Australia\/Brisbane": "पूर्व ऑस्ट्रेलिया वेळ (ब्रिस्बेन)", + "Australia\/Broken_Hill": "मध्य ऑस्ट्रेलिया वेळ (ब्रोकन हिल)", + "Australia\/Currie": "पूर्व ऑस्ट्रेलिया वेळ (कुह्री)", + "Australia\/Darwin": "मध्य ऑस्ट्रेलिया वेळ (डार्विन)", + "Australia\/Eucla": "ऑस्ट्रेलियन मध्य-पश्चिम वेळ (उक्ला)", + "Australia\/Hobart": "पूर्व ऑस्ट्रेलिया वेळ (होबार्ट)", + "Australia\/Lindeman": "पूर्व ऑस्ट्रेलिया वेळ (लिंडेमन)", + "Australia\/Lord_Howe": "लॉर्ड होवे वेळ (लॉर्ड होवे)", + "Australia\/Melbourne": "पूर्व ऑस्ट्रेलिया वेळ (मेलबोर्न)", + "Australia\/Perth": "पश्चिम ऑस्ट्रेलिया वेळ (पर्थ)", + "Australia\/Sydney": "पूर्व ऑस्ट्रेलिया वेळ (सिडनी)", + "CST6CDT": "केंद्रीय वेळ", + "EST5EDT": "पौर्वात्य वेळ", + "Etc\/GMT": "ग्रीनिच प्रमाण वेळ", + "Etc\/UTC": "समन्वित वैश्विक वेळ", + "Europe\/Amsterdam": "मध्‍य युरोपियन वेळ (अ‍ॅमस्टरडॅम)", + "Europe\/Andorra": "मध्‍य युरोपियन वेळ (अँडोरा)", + "Europe\/Astrakhan": "मॉस्को वेळ (आस्त्राखान)", + "Europe\/Athens": "पूर्व युरोपियन वेळ (अथेन्स)", + "Europe\/Belgrade": "मध्‍य युरोपियन वेळ (बेलग्रेड)", + "Europe\/Berlin": "मध्‍य युरोपियन वेळ (बर्लिन)", + "Europe\/Bratislava": "मध्‍य युरोपियन वेळ (ब्रातिस्लाव्हा)", + "Europe\/Brussels": "मध्‍य युरोपियन वेळ (ब्रुसेल्स)", + "Europe\/Bucharest": "पूर्व युरोपियन वेळ (बुखारेस्ट)", + "Europe\/Budapest": "मध्‍य युरोपियन वेळ (बुडापेस्ट)", + "Europe\/Busingen": "मध्‍य युरोपियन वेळ (बुसिंजेन)", + "Europe\/Chisinau": "पूर्व युरोपियन वेळ (चिसिनौ)", + "Europe\/Copenhagen": "मध्‍य युरोपियन वेळ (कोपेनहेगन)", + "Europe\/Dublin": "ग्रीनिच प्रमाण वेळ (डब्लिन)", + "Europe\/Gibraltar": "मध्‍य युरोपियन वेळ (जिब्राल्टर)", + "Europe\/Guernsey": "ग्रीनिच प्रमाण वेळ (ग्वेर्नसे)", + "Europe\/Helsinki": "पूर्व युरोपियन वेळ (हेलसिंकी)", + "Europe\/Isle_of_Man": "ग्रीनिच प्रमाण वेळ (आइल ऑफ मॅन)", + "Europe\/Jersey": "ग्रीनिच प्रमाण वेळ (जर्सी)", + "Europe\/Kaliningrad": "पूर्व युरोपियन वेळ (कलिनिनग्राड)", + "Europe\/Kiev": "पूर्व युरोपियन वेळ (कीव)", + "Europe\/Lisbon": "पश्चिम युरोपियन वेळ (लिस्बन)", + "Europe\/Ljubljana": "मध्‍य युरोपियन वेळ (लुब्लियाना)", + "Europe\/London": "ग्रीनिच प्रमाण वेळ (लंडन)", + "Europe\/Luxembourg": "मध्‍य युरोपियन वेळ (लक्झेंबर्ग)", + "Europe\/Madrid": "मध्‍य युरोपियन वेळ (माद्रिद)", + "Europe\/Malta": "मध्‍य युरोपियन वेळ (माल्टा)", + "Europe\/Mariehamn": "पूर्व युरोपियन वेळ (मरियेहामेन)", + "Europe\/Minsk": "मॉस्को वेळ (मिन्स्क)", + "Europe\/Monaco": "मध्‍य युरोपियन वेळ (मोनॅको)", + "Europe\/Moscow": "मॉस्को वेळ (मॉस्को)", + "Europe\/Oslo": "मध्‍य युरोपियन वेळ (ऑस्लो)", + "Europe\/Paris": "मध्‍य युरोपियन वेळ (पॅरिस)", + "Europe\/Podgorica": "मध्‍य युरोपियन वेळ (पॉडगोरिका)", + "Europe\/Prague": "मध्‍य युरोपियन वेळ (प्राग)", + "Europe\/Riga": "पूर्व युरोपियन वेळ (रिगा)", + "Europe\/Rome": "मध्‍य युरोपियन वेळ (रोम)", + "Europe\/Samara": "समारा वेळ (समारा)", + "Europe\/San_Marino": "मध्‍य युरोपियन वेळ (सॅन मरिनो)", + "Europe\/Sarajevo": "मध्‍य युरोपियन वेळ (साराजेव्हो)", + "Europe\/Saratov": "मॉस्को वेळ (सारातोव)", + "Europe\/Simferopol": "मॉस्को वेळ (सिम्फरोपोल)", + "Europe\/Skopje": "मध्‍य युरोपियन वेळ (स्कॉप्जे)", + "Europe\/Sofia": "पूर्व युरोपियन वेळ (सोफिया)", + "Europe\/Stockholm": "मध्‍य युरोपियन वेळ (स्टॉकहोम)", + "Europe\/Tallinn": "पूर्व युरोपियन वेळ (तालिन)", + "Europe\/Tirane": "मध्‍य युरोपियन वेळ (टिराने)", + "Europe\/Ulyanovsk": "मॉस्को वेळ (उल्यानोव्स्क)", + "Europe\/Uzhgorod": "पूर्व युरोपियन वेळ (उझहोरोड)", + "Europe\/Vaduz": "मध्‍य युरोपियन वेळ (वडूझ)", + "Europe\/Vatican": "मध्‍य युरोपियन वेळ (व्हॅटिकन)", + "Europe\/Vienna": "मध्‍य युरोपियन वेळ (व्हिएन्ना)", + "Europe\/Vilnius": "पूर्व युरोपियन वेळ (विलनियस)", + "Europe\/Volgograd": "व्होल्गोग्राड वेळ (व्होल्गोग्राड)", + "Europe\/Warsaw": "मध्‍य युरोपियन वेळ (वॉर्सा)", + "Europe\/Zagreb": "मध्‍य युरोपियन वेळ (झॅग्रेब)", + "Europe\/Zaporozhye": "पूर्व युरोपियन वेळ (झापोरोझे)", + "Europe\/Zurich": "मध्‍य युरोपियन वेळ (झुरिच)", + "Indian\/Antananarivo": "पूर्व आफ्रिका वेळ (अंटानानारिवो)", + "Indian\/Chagos": "हिंदमहासागर वेळ (चागोस)", + "Indian\/Christmas": "ख्रिसमस बेट वेळ (ख्रिसमस)", + "Indian\/Cocos": "कॉकोस बेटे वेळ (कोकोस)", + "Indian\/Comoro": "पूर्व आफ्रिका वेळ (कोमोरो)", + "Indian\/Kerguelen": "फ्रेंच दक्षिण आणि अंटार्क्टिक वेळ (करग्यूलेन)", + "Indian\/Mahe": "सेशेल्स वेळ (माहे)", + "Indian\/Maldives": "मालदिव वेळ (मालदीव)", + "Indian\/Mauritius": "मॉरीशस वेळ (मॉरिशस)", + "Indian\/Mayotte": "पूर्व आफ्रिका वेळ (मायोट्टे)", + "Indian\/Reunion": "रियुनियन वेळ (रियुनियन)", + "MST7MDT": "पर्वतीय वेळ", + "PST8PDT": "पॅसिफिक वेळ", + "Pacific\/Apia": "एपिया वेळ (अपिया)", + "Pacific\/Auckland": "न्यूझीलंड वेळ (ऑकलंड)", + "Pacific\/Bougainville": "पापुआ न्यू गिनी वेळ (बॉगॅनव्हिल)", + "Pacific\/Chatham": "चॅथम वेळ (चॅटहॅम)", + "Pacific\/Easter": "इस्टर बेट वेळ (ईस्टर)", + "Pacific\/Efate": "वानुआतु वेळ (इफेट)", + "Pacific\/Enderbury": "‍फोनिक्स बेटे वेळ (एंडरबरी)", + "Pacific\/Fakaofo": "टोकेलाऊ वेळ (फाकाओफो)", + "Pacific\/Fiji": "फिजी वेळ (फिजी)", + "Pacific\/Funafuti": "तुवालू वेळ (फुनाफुती)", + "Pacific\/Galapagos": "गॅलापागोस वेळ (गॅलापागोस)", + "Pacific\/Gambier": "गॅम्बियर वेळ (गॅम्बियर)", + "Pacific\/Guadalcanal": "सोलोमॉन बेटे वेळ (ग्वाडलकनाल)", + "Pacific\/Guam": "चामोरो प्रमाण वेळ (गुआम)", + "Pacific\/Honolulu": "हवाई-अलूशन वेळ (होनोलुलू)", + "Pacific\/Johnston": "हवाई-अलूशन वेळ (जोहान्स्टन)", + "Pacific\/Kiritimati": "लाइन बेटे वेळ (किरितिमाती)", + "Pacific\/Kosrae": "कोस्राई वेळ (कोशाय)", + "Pacific\/Kwajalein": "मार्शल बेटे वेळ (क्वाजालेईन)", + "Pacific\/Majuro": "मार्शल बेटे वेळ (मजुरो)", + "Pacific\/Marquesas": "मार्क्वेसास वेळ (मारक्विसास)", + "Pacific\/Midway": "सामोआ वेळ (मिडवे)", + "Pacific\/Nauru": "नउरु वेळ (नउरु)", + "Pacific\/Niue": "न्युए वेळ (न्युए)", + "Pacific\/Norfolk": "नॉरफोक बेट वेळ (नॉरफोक)", + "Pacific\/Noumea": "न्यू कॅलेडोनिया वेळ (नौमिआ)", + "Pacific\/Pago_Pago": "सामोआ वेळ (पॅगो पॅगो)", + "Pacific\/Palau": "पलाऊ वेळ (पलाऊ)", + "Pacific\/Pitcairn": "पिटकैर्न वेळ (पिटकेर्न)", + "Pacific\/Ponape": "पोनॅपे वेळ (पोनपेई)", + "Pacific\/Port_Moresby": "पापुआ न्यू गिनी वेळ (पोर्ट मोरेस्बे)", + "Pacific\/Rarotonga": "कुक बेटे वेळ (रारोटोंगा)", + "Pacific\/Saipan": "चामोरो प्रमाण वेळ (सैपान)", + "Pacific\/Tahiti": "ताहिती वेळ (ताहिती)", + "Pacific\/Tarawa": "गिल्बर्ट बेटे वेळ (तारावा)", + "Pacific\/Tongatapu": "टोंगा वेळ (टोंगाटापू)", + "Pacific\/Truk": "चूक वेळ (चूक)", + "Pacific\/Wake": "वेक बेट वेळ (वेक)", + "Pacific\/Wallis": "वॉलिस आणि फुटुना वेळ (वालिस)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ms.json b/src/Symfony/Component/Intl/Resources/data/timezones/ms.json new file mode 100644 index 0000000000000..80297e3a04548 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ms.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.49.2", + "Names": { + "Africa\/Abidjan": "Waktu Min Greenwich (Abidjan)", + "Africa\/Accra": "Waktu Min Greenwich (Accra)", + "Africa\/Addis_Ababa": "Waktu Afrika Timur (Addis Ababa)", + "Africa\/Algiers": "Waktu Eropah Tengah (Algiers)", + "Africa\/Asmera": "Waktu Afrika Timur (Asmara)", + "Africa\/Bamako": "Waktu Min Greenwich (Bamako)", + "Africa\/Bangui": "Waktu Afrika Barat (Bangui)", + "Africa\/Banjul": "Waktu Min Greenwich (Banjul)", + "Africa\/Bissau": "Waktu Min Greenwich (Bissau)", + "Africa\/Blantyre": "Waktu Afrika Tengah (Blantyre)", + "Africa\/Brazzaville": "Waktu Afrika Barat (Brazzaville)", + "Africa\/Bujumbura": "Waktu Afrika Tengah (Bujumbura)", + "Africa\/Cairo": "Waktu Eropah Timur (Kaherah)", + "Africa\/Casablanca": "Waktu Eropah Barat (Casablanca)", + "Africa\/Ceuta": "Waktu Eropah Tengah (Ceuta)", + "Africa\/Conakry": "Waktu Min Greenwich (Conakry)", + "Africa\/Dakar": "Waktu Min Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Waktu Afrika Timur (Dar es Salaam)", + "Africa\/Djibouti": "Waktu Afrika Timur (Djibouti)", + "Africa\/Douala": "Waktu Afrika Barat (Douala)", + "Africa\/El_Aaiun": "Waktu Eropah Barat (El Aaiun)", + "Africa\/Freetown": "Waktu Min Greenwich (Freetown)", + "Africa\/Gaborone": "Waktu Afrika Tengah (Gaborone)", + "Africa\/Harare": "Waktu Afrika Tengah (Harare)", + "Africa\/Johannesburg": "Waktu Piawai Afrika Selatan (Johannesburg)", + "Africa\/Juba": "Waktu Afrika Timur (Juba)", + "Africa\/Kampala": "Waktu Afrika Timur (Kampala)", + "Africa\/Khartoum": "Waktu Afrika Tengah (Khartoum)", + "Africa\/Kigali": "Waktu Afrika Tengah (Kigali)", + "Africa\/Kinshasa": "Waktu Afrika Barat (Kinshasa)", + "Africa\/Lagos": "Waktu Afrika Barat (Lagos)", + "Africa\/Libreville": "Waktu Afrika Barat (Libreville)", + "Africa\/Lome": "Waktu Min Greenwich (Lome)", + "Africa\/Luanda": "Waktu Afrika Barat (Luanda)", + "Africa\/Lubumbashi": "Waktu Afrika Tengah (Lubumbashi)", + "Africa\/Lusaka": "Waktu Afrika Tengah (Lusaka)", + "Africa\/Malabo": "Waktu Afrika Barat (Malabo)", + "Africa\/Maputo": "Waktu Afrika Tengah (Maputo)", + "Africa\/Maseru": "Waktu Piawai Afrika Selatan (Maseru)", + "Africa\/Mbabane": "Waktu Piawai Afrika Selatan (Mbabane)", + "Africa\/Mogadishu": "Waktu Afrika Timur (Mogadishu)", + "Africa\/Monrovia": "Waktu Min Greenwich (Monrovia)", + "Africa\/Nairobi": "Waktu Afrika Timur (Nairobi)", + "Africa\/Ndjamena": "Waktu Afrika Barat (Ndjamena)", + "Africa\/Niamey": "Waktu Afrika Barat (Niamey)", + "Africa\/Nouakchott": "Waktu Min Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Waktu Min Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Waktu Afrika Barat (Porto-Novo)", + "Africa\/Sao_Tome": "Waktu Min Greenwich (Sao Tome)", + "Africa\/Tripoli": "Waktu Eropah Timur (Tripoli)", + "Africa\/Tunis": "Waktu Eropah Tengah (Tunis)", + "Africa\/Windhoek": "Waktu Afrika Tengah (Windhoek)", + "America\/Adak": "Waktu Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Waktu Alaska (Anchorage)", + "America\/Anguilla": "Waktu Atlantik (Anguilla)", + "America\/Antigua": "Waktu Atlantik (Antigua)", + "America\/Araguaina": "Waktu Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "Waktu Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Waktu Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Waktu Argentina (Salta)", + "America\/Argentina\/San_Juan": "Waktu Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Waktu Argentina Barat (San Luis)", + "America\/Argentina\/Tucuman": "Waktu Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Waktu Argentina (Ushuaia)", + "America\/Aruba": "Waktu Atlantik (Aruba)", + "America\/Asuncion": "Waktu Paraguay (Asuncion)", + "America\/Bahia": "Waktu Brasilia (Bahia)", + "America\/Bahia_Banderas": "Waktu Pusat (Bahia Banderas)", + "America\/Barbados": "Waktu Atlantik (Barbados)", + "America\/Belem": "Waktu Brasilia (Belem)", + "America\/Belize": "Waktu Pusat (Belize)", + "America\/Blanc-Sablon": "Waktu Atlantik (Blanc-Sablon)", + "America\/Boa_Vista": "Waktu Amazon (Boa Vista)", + "America\/Bogota": "Waktu Colombia (Bogota)", + "America\/Boise": "Waktu Pergunungan (Boise)", + "America\/Buenos_Aires": "Waktu Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Waktu Pergunungan (Teluk Cambridge)", + "America\/Campo_Grande": "Waktu Amazon (Campo Grande)", + "America\/Cancun": "Waktu Timur (Cancun)", + "America\/Caracas": "Waktu Venezuela (Caracas)", + "America\/Catamarca": "Waktu Argentina (Catamarca)", + "America\/Cayenne": "Waktu Guyana Perancis (Cayenne)", + "America\/Cayman": "Waktu Timur (Cayman)", + "America\/Chicago": "Waktu Pusat (Chicago)", + "America\/Chihuahua": "Waktu Pasifik Mexico (Chihuahua)", + "America\/Coral_Harbour": "Waktu Timur (Atikokan)", + "America\/Cordoba": "Waktu Argentina (Cordoba)", + "America\/Costa_Rica": "Waktu Pusat (Costa Rica)", + "America\/Creston": "Waktu Pergunungan (Creston)", + "America\/Cuiaba": "Waktu Amazon (Cuiaba)", + "America\/Curacao": "Waktu Atlantik (Curacao)", + "America\/Danmarkshavn": "Waktu Min Greenwich (Danmarkshavn)", + "America\/Dawson": "Waktu Pasifik (Dawson)", + "America\/Dawson_Creek": "Waktu Pergunungan (Dawson Creek)", + "America\/Denver": "Waktu Pergunungan (Denver)", + "America\/Detroit": "Waktu Timur (Detroit)", + "America\/Dominica": "Waktu Atlantik (Dominica)", + "America\/Edmonton": "Waktu Pergunungan (Edmonton)", + "America\/El_Salvador": "Waktu Pusat (El Salvador)", + "America\/Fort_Nelson": "Waktu Pergunungan (Fort Nelson)", + "America\/Fortaleza": "Waktu Brasilia (Fortaleza)", + "America\/Glace_Bay": "Waktu Atlantik (Teluk Glace)", + "America\/Godthab": "Waktu Greenland Barat (Nuuk)", + "America\/Goose_Bay": "Waktu Atlantik (Teluk Goose)", + "America\/Grand_Turk": "Waktu Timur (Grand Turk)", + "America\/Grenada": "Waktu Atlantik (Grenada)", + "America\/Guadeloupe": "Waktu Atlantik (Guadeloupe)", + "America\/Guatemala": "Waktu Pusat (Guatemala)", + "America\/Guayaquil": "Waktu Ecuador (Guayaquil)", + "America\/Guyana": "Waktu Guyana (Guyana)", + "America\/Halifax": "Waktu Atlantik (Halifax)", + "America\/Havana": "Waktu Cuba (Havana)", + "America\/Hermosillo": "Waktu Pasifik Mexico (Hermosillo)", + "America\/Indiana\/Knox": "Waktu Pusat (Knox, Indiana)", + "America\/Indiana\/Marengo": "Waktu Timur (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Waktu Timur (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Waktu Pusat (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Waktu Timur (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Waktu Timur (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Waktu Timur (Winamac, Indiana)", + "America\/Indianapolis": "Waktu Timur (Indianapolis)", + "America\/Inuvik": "Waktu Pergunungan (Inuvik)", + "America\/Iqaluit": "Waktu Timur (Iqaluit)", + "America\/Jamaica": "Waktu Timur (Jamaica)", + "America\/Jujuy": "Waktu Argentina (Jujuy)", + "America\/Juneau": "Waktu Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Waktu Timur (Monticello, Kentucky)", + "America\/Kralendijk": "Waktu Atlantik (Kralendijk)", + "America\/La_Paz": "Waktu Bolivia (La Paz)", + "America\/Lima": "Waktu Peru (Lima)", + "America\/Los_Angeles": "Waktu Pasifik (Los Angeles)", + "America\/Louisville": "Waktu Timur (Louisville)", + "America\/Lower_Princes": "Waktu Atlantik (Lower Prince’s Quarter)", + "America\/Maceio": "Waktu Brasilia (Maceio)", + "America\/Managua": "Waktu Pusat (Managua)", + "America\/Manaus": "Waktu Amazon (Manaus)", + "America\/Marigot": "Waktu Atlantik (Marigot)", + "America\/Martinique": "Waktu Atlantik (Martinique)", + "America\/Matamoros": "Waktu Pusat (Matamoros)", + "America\/Mazatlan": "Waktu Pasifik Mexico (Mazatlan)", + "America\/Mendoza": "Waktu Argentina (Mendoza)", + "America\/Menominee": "Waktu Pusat (Menominee)", + "America\/Merida": "Waktu Pusat (Merida)", + "America\/Metlakatla": "Waktu Alaska (Metlakatla)", + "America\/Mexico_City": "Waktu Pusat (Mexico City)", + "America\/Miquelon": "Waktu Saint Pierre dan Miquelon (Miquelon)", + "America\/Moncton": "Waktu Atlantik (Moncton)", + "America\/Monterrey": "Waktu Pusat (Monterrey)", + "America\/Montevideo": "Waktu Uruguay (Montevideo)", + "America\/Montserrat": "Waktu Atlantik (Montserrat)", + "America\/Nassau": "Waktu Timur (Nassau)", + "America\/New_York": "Waktu Timur (New York)", + "America\/Nipigon": "Waktu Timur (Nipigon)", + "America\/Nome": "Waktu Alaska (Nome)", + "America\/Noronha": "Waktu Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Waktu Pusat (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Waktu Pusat (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Waktu Pusat (New Salem, North Dakota)", + "America\/Ojinaga": "Waktu Pergunungan (Ojinaga)", + "America\/Panama": "Waktu Timur (Panama)", + "America\/Pangnirtung": "Waktu Timur (Pangnirtung)", + "America\/Paramaribo": "Waktu Suriname (Paramaribo)", + "America\/Phoenix": "Waktu Pergunungan (Phoenix)", + "America\/Port-au-Prince": "Waktu Timur (Port-au-Prince)", + "America\/Port_of_Spain": "Waktu Atlantik (Port of Spain)", + "America\/Porto_Velho": "Waktu Amazon (Porto Velho)", + "America\/Puerto_Rico": "Waktu Atlantik (Puerto Rico)", + "America\/Punta_Arenas": "Waktu Chile (Punta Arenas)", + "America\/Rainy_River": "Waktu Pusat (Sungai Rainy)", + "America\/Rankin_Inlet": "Waktu Pusat (Rankin Inlet)", + "America\/Recife": "Waktu Brasilia (Recife)", + "America\/Regina": "Waktu Pusat (Regina)", + "America\/Resolute": "Waktu Pusat (Resolute)", + "America\/Santa_Isabel": "Waktu Barat Laut Mexico (Santa Isabel)", + "America\/Santarem": "Waktu Brasilia (Santarem)", + "America\/Santiago": "Waktu Chile (Santiago)", + "America\/Santo_Domingo": "Waktu Atlantik (Santo Domingo)", + "America\/Sao_Paulo": "Waktu Brasilia (Sao Paulo)", + "America\/Scoresbysund": "Waktu Greenland Timur (Ittoqqortoormiit)", + "America\/Sitka": "Waktu Alaska (Sitka)", + "America\/St_Barthelemy": "Waktu Atlantik (Saint Barthelemy)", + "America\/St_Johns": "Waktu Newfoundland (St. John’s)", + "America\/St_Kitts": "Waktu Atlantik (St. Kitts)", + "America\/St_Lucia": "Waktu Atlantik (St. Lucia)", + "America\/St_Thomas": "Waktu Atlantik (St. Thomas)", + "America\/St_Vincent": "Waktu Atlantik (St. Vincent)", + "America\/Swift_Current": "Waktu Pusat (Swift Current)", + "America\/Tegucigalpa": "Waktu Pusat (Tegucigalpa)", + "America\/Thule": "Waktu Atlantik (Thule)", + "America\/Thunder_Bay": "Waktu Timur (Thunder Bay)", + "America\/Tijuana": "Waktu Pasifik (Tijuana)", + "America\/Toronto": "Waktu Timur (Toronto)", + "America\/Tortola": "Waktu Atlantik (Tortola)", + "America\/Vancouver": "Waktu Pasifik (Vancouver)", + "America\/Whitehorse": "Waktu Pasifik (Whitehorse)", + "America\/Winnipeg": "Waktu Pusat (Winnipeg)", + "America\/Yakutat": "Waktu Alaska (Yakutat)", + "America\/Yellowknife": "Waktu Pergunungan (Yellowknife)", + "Antarctica\/Casey": "Waktu Australia Barat (Casey)", + "Antarctica\/Davis": "Waktu Davis (Davis)", + "Antarctica\/DumontDUrville": "Waktu Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Waktu Pulau Macquarie (Macquarie)", + "Antarctica\/Mawson": "Waktu Mawson (Mawson)", + "Antarctica\/McMurdo": "Waktu New Zealand (McMurdo)", + "Antarctica\/Palmer": "Waktu Chile (Palmer)", + "Antarctica\/Rothera": "Waktu Rothera (Rothera)", + "Antarctica\/Syowa": "Waktu Syowa (Syowa)", + "Antarctica\/Troll": "Waktu Min Greenwich (Troll)", + "Antarctica\/Vostok": "Waktu Vostok (Vostok)", + "Arctic\/Longyearbyen": "Waktu Eropah Tengah (Longyearbyen)", + "Asia\/Aden": "Waktu Arab (Aden)", + "Asia\/Almaty": "Waktu Kazakhstan Timur (Almaty)", + "Asia\/Amman": "Waktu Eropah Timur (Amman)", + "Asia\/Anadyr": "Waktu Anadyr (Anadyr)", + "Asia\/Aqtau": "Waktu Kazakhstan Barat (Aqtau)", + "Asia\/Aqtobe": "Waktu Kazakhstan Barat (Aqtobe)", + "Asia\/Ashgabat": "Waktu Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Waktu Kazakhstan Barat (Atyrau)", + "Asia\/Baghdad": "Waktu Arab (Baghdad)", + "Asia\/Bahrain": "Waktu Arab (Bahrain)", + "Asia\/Baku": "Waktu Azerbaijan (Baku)", + "Asia\/Bangkok": "Waktu Indochina (Bangkok)", + "Asia\/Beirut": "Waktu Eropah Timur (Beirut)", + "Asia\/Bishkek": "Waktu Kyrgystan (Bishkek)", + "Asia\/Brunei": "Waktu Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Waktu Piawai India (Kolkata)", + "Asia\/Chita": "Waktu Yakutsk (Chita)", + "Asia\/Choibalsan": "Waktu Choibalsan (Choibalsan)", + "Asia\/Colombo": "Waktu Piawai India (Colombo)", + "Asia\/Damascus": "Waktu Eropah Timur (Damsyik)", + "Asia\/Dhaka": "Waktu Bangladesh (Dhaka)", + "Asia\/Dili": "Waktu Timor Timur (Dili)", + "Asia\/Dubai": "Waktu Piawai Teluk (Dubai)", + "Asia\/Dushanbe": "Waktu Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Waktu Eropah Timur (Famagusta)", + "Asia\/Gaza": "Waktu Eropah Timur (Gaza)", + "Asia\/Hebron": "Waktu Eropah Timur (Hebron)", + "Asia\/Hong_Kong": "Waktu Hong Kong (Hong Kong)", + "Asia\/Hovd": "Waktu Hovd (Hovd)", + "Asia\/Irkutsk": "Waktu Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Waktu Indonesia Barat (Jakarta)", + "Asia\/Jayapura": "Waktu Indonesia Timur (Jayapura)", + "Asia\/Jerusalem": "Waktu Israel (Baitulmuqaddis)", + "Asia\/Kabul": "Waktu Afghanistan (Kabul)", + "Asia\/Kamchatka": "Waktu Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Waktu Pakistan (Karachi)", + "Asia\/Katmandu": "Waktu Nepal (Kathmandu)", + "Asia\/Khandyga": "Waktu Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Waktu Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Waktu Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Waktu Malaysia (Kuching)", + "Asia\/Kuwait": "Waktu Arab (Kuwait)", + "Asia\/Macau": "Waktu China (Macau)", + "Asia\/Magadan": "Waktu Magadan (Magadan)", + "Asia\/Makassar": "Waktu Indonesia Tengah (Makassar)", + "Asia\/Manila": "Waktu Filipina (Manila)", + "Asia\/Muscat": "Waktu Piawai Teluk (Muscat)", + "Asia\/Nicosia": "Waktu Eropah Timur (Nicosia)", + "Asia\/Novokuznetsk": "Waktu Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Waktu Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Waktu Omsk (Omsk)", + "Asia\/Oral": "Waktu Kazakhstan Barat (Oral)", + "Asia\/Phnom_Penh": "Waktu Indochina (Phnom Penh)", + "Asia\/Pontianak": "Waktu Indonesia Barat (Pontianak)", + "Asia\/Pyongyang": "Waktu Korea (Pyongyang)", + "Asia\/Qatar": "Waktu Arab (Qatar)", + "Asia\/Qostanay": "Waktu Kazakhstan Timur (Qostanay)", + "Asia\/Qyzylorda": "Waktu Kazakhstan Barat (Qyzylorda)", + "Asia\/Rangoon": "Waktu Myanmar (Yangon)", + "Asia\/Riyadh": "Waktu Arab (Riyadh)", + "Asia\/Saigon": "Waktu Indochina (Ho Chi Minh)", + "Asia\/Sakhalin": "Waktu Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Waktu Uzbekistan (Samarkand)", + "Asia\/Seoul": "Waktu Korea (Seoul)", + "Asia\/Shanghai": "Waktu China (Shanghai)", + "Asia\/Singapore": "Waktu Piawai Singapura (Singapura)", + "Asia\/Srednekolymsk": "Waktu Magadan (Srednekolymsk)", + "Asia\/Taipei": "Waktu Taipei (Taipei)", + "Asia\/Tashkent": "Waktu Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Waktu Georgia (Tbilisi)", + "Asia\/Tehran": "Waktu Iran (Tehran)", + "Asia\/Thimphu": "Waktu Bhutan (Thimphu)", + "Asia\/Tokyo": "Waktu Jepun (Tokyo)", + "Asia\/Ulaanbaatar": "Waktu Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Waktu Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Waktu Indochina (Vientiane)", + "Asia\/Vladivostok": "Waktu Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Waktu Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Waktu Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Waktu Armenia (Yerevan)", + "Atlantic\/Azores": "Waktu Azores (Azores)", + "Atlantic\/Bermuda": "Waktu Atlantik (Bermuda)", + "Atlantic\/Canary": "Waktu Eropah Barat (Canary)", + "Atlantic\/Cape_Verde": "Waktu Tanjung Verde (Cape Verde)", + "Atlantic\/Faeroe": "Waktu Eropah Barat (Faroe)", + "Atlantic\/Madeira": "Waktu Eropah Barat (Madeira)", + "Atlantic\/Reykjavik": "Waktu Min Greenwich (Reykjavik)", + "Atlantic\/South_Georgia": "Waktu Georgia Selatan (South Georgia)", + "Atlantic\/St_Helena": "Waktu Min Greenwich (St. Helena)", + "Atlantic\/Stanley": "Waktu Kepulauan Falkland (Stanley)", + "Australia\/Adelaide": "Waktu Australia Tengah (Adelaide)", + "Australia\/Brisbane": "Waktu Australia Timur (Brisbane)", + "Australia\/Broken_Hill": "Waktu Australia Tengah (Broken Hill)", + "Australia\/Currie": "Waktu Australia Timur (Currie)", + "Australia\/Darwin": "Waktu Australia Tengah (Darwin)", + "Australia\/Eucla": "Waktu Barat Tengah Australia (Eucla)", + "Australia\/Hobart": "Waktu Australia Timur (Hobart)", + "Australia\/Lindeman": "Waktu Australia Timur (Lindeman)", + "Australia\/Lord_Howe": "Waktu Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Waktu Australia Timur (Melbourne)", + "Australia\/Perth": "Waktu Australia Barat (Perth)", + "Australia\/Sydney": "Waktu Australia Timur (Sydney)", + "CST6CDT": "Waktu Pusat", + "EST5EDT": "Waktu Timur", + "Etc\/GMT": "Waktu Min Greenwich", + "Etc\/UTC": "Waktu Universal Selaras", + "Europe\/Amsterdam": "Waktu Eropah Tengah (Amsterdam)", + "Europe\/Andorra": "Waktu Eropah Tengah (Andorra)", + "Europe\/Astrakhan": "Waktu Moscow (Astrakhan)", + "Europe\/Athens": "Waktu Eropah Timur (Athens)", + "Europe\/Belgrade": "Waktu Eropah Tengah (Belgrade)", + "Europe\/Berlin": "Waktu Eropah Tengah (Berlin)", + "Europe\/Bratislava": "Waktu Eropah Tengah (Bratislava)", + "Europe\/Brussels": "Waktu Eropah Tengah (Brussels)", + "Europe\/Bucharest": "Waktu Eropah Timur (Bucharest)", + "Europe\/Budapest": "Waktu Eropah Tengah (Budapest)", + "Europe\/Busingen": "Waktu Eropah Tengah (Busingen)", + "Europe\/Chisinau": "Waktu Eropah Timur (Chisinau)", + "Europe\/Copenhagen": "Waktu Eropah Tengah (Copenhagen)", + "Europe\/Dublin": "Waktu Min Greenwich (Dublin)", + "Europe\/Gibraltar": "Waktu Eropah Tengah (Gibraltar)", + "Europe\/Guernsey": "Waktu Min Greenwich (Guernsey)", + "Europe\/Helsinki": "Waktu Eropah Timur (Helsinki)", + "Europe\/Isle_of_Man": "Waktu Min Greenwich (Isle of Man)", + "Europe\/Jersey": "Waktu Min Greenwich (Jersey)", + "Europe\/Kaliningrad": "Waktu Eropah Timur (Kaliningrad)", + "Europe\/Kiev": "Waktu Eropah Timur (Kiev)", + "Europe\/Lisbon": "Waktu Eropah Barat (Lisbon)", + "Europe\/Ljubljana": "Waktu Eropah Tengah (Ljubljana)", + "Europe\/London": "Waktu Min Greenwich (London)", + "Europe\/Luxembourg": "Waktu Eropah Tengah (Luxembourg)", + "Europe\/Madrid": "Waktu Eropah Tengah (Madrid)", + "Europe\/Malta": "Waktu Eropah Tengah (Malta)", + "Europe\/Mariehamn": "Waktu Eropah Timur (Mariehamn)", + "Europe\/Minsk": "Waktu Moscow (Minsk)", + "Europe\/Monaco": "Waktu Eropah Tengah (Monaco)", + "Europe\/Moscow": "Waktu Moscow (Moscow)", + "Europe\/Oslo": "Waktu Eropah Tengah (Oslo)", + "Europe\/Paris": "Waktu Eropah Tengah (Paris)", + "Europe\/Podgorica": "Waktu Eropah Tengah (Podgorica)", + "Europe\/Prague": "Waktu Eropah Tengah (Prague)", + "Europe\/Riga": "Waktu Eropah Timur (Riga)", + "Europe\/Rome": "Waktu Eropah Tengah (Rome)", + "Europe\/Samara": "Waktu Samara (Samara)", + "Europe\/San_Marino": "Waktu Eropah Tengah (San Marino)", + "Europe\/Sarajevo": "Waktu Eropah Tengah (Sarajevo)", + "Europe\/Saratov": "Waktu Moscow (Saratov)", + "Europe\/Simferopol": "Waktu Moscow (Simferopol)", + "Europe\/Skopje": "Waktu Eropah Tengah (Skopje)", + "Europe\/Sofia": "Waktu Eropah Timur (Sofia)", + "Europe\/Stockholm": "Waktu Eropah Tengah (Stockholm)", + "Europe\/Tallinn": "Waktu Eropah Timur (Tallinn)", + "Europe\/Tirane": "Waktu Eropah Tengah (Tirane)", + "Europe\/Ulyanovsk": "Waktu Moscow (Ulyanovsk)", + "Europe\/Uzhgorod": "Waktu Eropah Timur (Uzhgorod)", + "Europe\/Vaduz": "Waktu Eropah Tengah (Vaduz)", + "Europe\/Vatican": "Waktu Eropah Tengah (Vatican)", + "Europe\/Vienna": "Waktu Eropah Tengah (Vienna)", + "Europe\/Vilnius": "Waktu Eropah Timur (Vilnius)", + "Europe\/Volgograd": "Waktu Volgograd (Volgograd)", + "Europe\/Warsaw": "Waktu Eropah Tengah (Warsaw)", + "Europe\/Zagreb": "Waktu Eropah Tengah (Zagreb)", + "Europe\/Zaporozhye": "Waktu Eropah Timur (Zaporozhye)", + "Europe\/Zurich": "Waktu Eropah Tengah (Zurich)", + "Indian\/Antananarivo": "Waktu Afrika Timur (Antananarivo)", + "Indian\/Chagos": "Waktu Lautan Hindi (Chagos)", + "Indian\/Christmas": "Waktu Pulau Christmas (Christmas)", + "Indian\/Cocos": "Waktu Kepulauan Cocos (Cocos)", + "Indian\/Comoro": "Waktu Afrika Timur (Comoro)", + "Indian\/Kerguelen": "Waktu Perancis Selatan dan Antartika (Kerguelen)", + "Indian\/Mahe": "Waktu Seychelles (Mahe)", + "Indian\/Maldives": "Waktu Maldives (Maldives)", + "Indian\/Mauritius": "Waktu Mauritius (Mauritius)", + "Indian\/Mayotte": "Waktu Afrika Timur (Mayotte)", + "Indian\/Reunion": "Waktu Reunion (Reunion)", + "MST7MDT": "Waktu Pergunungan", + "PST8PDT": "Waktu Pasifik", + "Pacific\/Apia": "Waktu Apia (Apia)", + "Pacific\/Auckland": "Waktu New Zealand (Auckland)", + "Pacific\/Bougainville": "Waktu Papua New Guinea (Bougainville)", + "Pacific\/Chatham": "Waktu Chatham (Chatham)", + "Pacific\/Easter": "Waktu Pulau Easter (Easter)", + "Pacific\/Efate": "Waktu Vanuatu (Efate)", + "Pacific\/Enderbury": "Waktu Kepulauan Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Waktu Tokelau (Fakaofo)", + "Pacific\/Fiji": "Waktu Fiji (Fiji)", + "Pacific\/Funafuti": "Waktu Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Waktu Galapagos (Galapagos)", + "Pacific\/Gambier": "Waktu Gambier (Gambier)", + "Pacific\/Guadalcanal": "Waktu Kepulauan Solomon (Guadalcanal)", + "Pacific\/Guam": "Waktu Piawai Chamorro (Guam)", + "Pacific\/Honolulu": "Waktu Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Waktu Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Waktu Kepulauan Line (Kiritimati)", + "Pacific\/Kosrae": "Waktu Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Waktu Kepulauan Marshall (Kwajalein)", + "Pacific\/Majuro": "Waktu Kepulauan Marshall (Majuro)", + "Pacific\/Marquesas": "Waktu Marquesas (Marquesas)", + "Pacific\/Midway": "Waktu Samoa (Midway)", + "Pacific\/Nauru": "Waktu Nauru (Nauru)", + "Pacific\/Niue": "Waktu Niue (Niue)", + "Pacific\/Norfolk": "Waktu Kepulauan Norfolk (Norfolk)", + "Pacific\/Noumea": "Waktu New Caledonia (Noumea)", + "Pacific\/Pago_Pago": "Waktu Samoa (Pago Pago)", + "Pacific\/Palau": "Waktu Palau (Palau)", + "Pacific\/Pitcairn": "Waktu Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Waktu Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Waktu Papua New Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Waktu Kepulauan Cook (Rarotonga)", + "Pacific\/Saipan": "Waktu Piawai Chamorro (Saipan)", + "Pacific\/Tahiti": "Waktu Tahiti (Tahiti)", + "Pacific\/Tarawa": "Waktu Kepulauan Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Waktu Tonga (Tongatapu)", + "Pacific\/Truk": "Waktu Chuuk (Chuuk)", + "Pacific\/Wake": "Waktu Pulau Wake (Wake)", + "Pacific\/Wallis": "Waktu Wallis dan Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/mt.json b/src/Symfony/Component/Intl/Resources/data/timezones/mt.json new file mode 100644 index 0000000000000..147baf07f8213 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/mt.json @@ -0,0 +1,40 @@ +{ + "Version": "2.1.47.72", + "Names": { + "Africa\/Algiers": "Ħin Ċentrali Ewropew (l-Alġier)", + "Africa\/Ceuta": "Ħin Ċentrali Ewropew (Ceuta)", + "Africa\/Tunis": "Ħin Ċentrali Ewropew (Tunis)", + "Arctic\/Longyearbyen": "Ħin Ċentrali Ewropew (Longyearbyen)", + "Europe\/Amsterdam": "Ħin Ċentrali Ewropew (Amsterdam)", + "Europe\/Andorra": "Ħin Ċentrali Ewropew (Andorra)", + "Europe\/Belgrade": "Ħin Ċentrali Ewropew (Belgrad)", + "Europe\/Berlin": "Ħin Ċentrali Ewropew (Berlin)", + "Europe\/Bratislava": "Ħin Ċentrali Ewropew (Bratislava)", + "Europe\/Brussels": "Ħin Ċentrali Ewropew (Brussell)", + "Europe\/Budapest": "Ħin Ċentrali Ewropew (Budapest)", + "Europe\/Busingen": "Ħin Ċentrali Ewropew (Busingen)", + "Europe\/Copenhagen": "Ħin Ċentrali Ewropew (Copenhagen)", + "Europe\/Gibraltar": "Ħin Ċentrali Ewropew (Ġibiltà)", + "Europe\/Ljubljana": "Ħin Ċentrali Ewropew (Ljubljana)", + "Europe\/Luxembourg": "Ħin Ċentrali Ewropew (il-Lussemburgu)", + "Europe\/Madrid": "Ħin Ċentrali Ewropew (Madrid)", + "Europe\/Malta": "Ħin Ċentrali Ewropew (Valletta)", + "Europe\/Monaco": "Ħin Ċentrali Ewropew (Monaco)", + "Europe\/Oslo": "Ħin Ċentrali Ewropew (Oslo)", + "Europe\/Paris": "Ħin Ċentrali Ewropew (Pariġi)", + "Europe\/Podgorica": "Ħin Ċentrali Ewropew (Podgorica)", + "Europe\/Prague": "Ħin Ċentrali Ewropew (Praga)", + "Europe\/Rome": "Ħin Ċentrali Ewropew (Ruma)", + "Europe\/San_Marino": "Ħin Ċentrali Ewropew (San Marino)", + "Europe\/Sarajevo": "Ħin Ċentrali Ewropew (Sarajevo)", + "Europe\/Skopje": "Ħin Ċentrali Ewropew (Skopje)", + "Europe\/Stockholm": "Ħin Ċentrali Ewropew (Stokkolma)", + "Europe\/Tirane": "Ħin Ċentrali Ewropew (Tirana)", + "Europe\/Vaduz": "Ħin Ċentrali Ewropew (Vaduz)", + "Europe\/Vatican": "Ħin Ċentrali Ewropew (il-belt tal-Vatikan)", + "Europe\/Vienna": "Ħin Ċentrali Ewropew (Vjenna)", + "Europe\/Warsaw": "Ħin Ċentrali Ewropew (Varsavja)", + "Europe\/Zagreb": "Ħin Ċentrali Ewropew (Zagreb)", + "Europe\/Zurich": "Ħin Ċentrali Ewropew (Zurich)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/my.json b/src/Symfony/Component/Intl/Resources/data/timezones/my.json new file mode 100644 index 0000000000000..cf22a7e52fc84 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/my.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.36", + "Names": { + "Africa\/Abidjan": "ဂရင်းနစ် စံတော်ချိန် (အာဘီဂျန်)", + "Africa\/Accra": "ဂရင်းနစ် စံတော်ချိန် (အက်ကရာ)", + "Africa\/Addis_Ababa": "အရှေ့အာဖရိက အချိန် (အားဒစ် အဘာဘာ)", + "Africa\/Algiers": "ဥရောပအလယ်ပိုင်း အချိန် (အယ်လ်ဂျီးရီးယား)", + "Africa\/Asmera": "အရှေ့အာဖရိက အချိန် (အားစ်မားရာ)", + "Africa\/Bamako": "ဂရင်းနစ် စံတော်ချိန် (ဘာမာကို)", + "Africa\/Bangui": "အနောက်အာဖရိက အချိန် (ဘာန်ဂီး)", + "Africa\/Banjul": "ဂရင်းနစ် စံတော်ချိန် (ဘန်ဂျုးလ်)", + "Africa\/Bissau": "ဂရင်းနစ် စံတော်ချိန် (ဘီစာအို)", + "Africa\/Blantyre": "အလယ်အာဖရိက အချိန် (ဘလန်တိုင်းရဲလ်)", + "Africa\/Brazzaville": "အနောက်အာဖရိက အချိန် (ဘရားဇာဗီးလ်)", + "Africa\/Bujumbura": "အလယ်အာဖရိက အချိန် (ဘူဂျွန်ဘူးရာ)", + "Africa\/Cairo": "အရှေ့ဥရောပ အချိန် (ကိုင်ရို)", + "Africa\/Casablanca": "အနောက်ဥရောပ အချိန် (ကာဆာဘလန်ကာ)", + "Africa\/Ceuta": "ဥရောပအလယ်ပိုင်း အချိန် (ဆီရူးတာ)", + "Africa\/Conakry": "ဂရင်းနစ် စံတော်ချိန် (ကိုနာကရီး)", + "Africa\/Dakar": "ဂရင်းနစ် စံတော်ချိန် (ဒကျကား)", + "Africa\/Dar_es_Salaam": "အရှေ့အာဖရိက အချိန် (ဒါရက်စ်ဆာလမ်)", + "Africa\/Djibouti": "အရှေ့အာဖရိက အချိန် (ဂျီဘူတီ)", + "Africa\/Douala": "အနောက်အာဖရိက အချိန် (ဒိုအူအာလာ)", + "Africa\/El_Aaiun": "အနောက်ဥရောပ အချိန် (အယ်လ်အာယွန်း)", + "Africa\/Freetown": "ဂရင်းနစ် စံတော်ချိန် (ဖရီးတောင်းန်)", + "Africa\/Gaborone": "အလယ်အာဖရိက အချိန် (ဂါဘာရွန်းနီ)", + "Africa\/Harare": "အလယ်အာဖရိက အချိန် (ဟာရားရဲယ်)", + "Africa\/Johannesburg": "တောင်အာဖရိက အချိန် (ဂျိုဟန်းနက်စဘတ်)", + "Africa\/Juba": "အရှေ့အာဖရိက အချိန် (ဂျုဘာ)", + "Africa\/Kampala": "အရှေ့အာဖရိက အချိန် (ကမ်ပါလာ)", + "Africa\/Khartoum": "အလယ်အာဖရိက အချိန် (ခါတိုအန်)", + "Africa\/Kigali": "အလယ်အာဖရိက အချိန် (ကီဂါးလီ)", + "Africa\/Kinshasa": "အနောက်အာဖရိက အချိန် (ကင်ရှာစာ)", + "Africa\/Lagos": "အနောက်အာဖရိက အချိန် (လာဂိုစ်)", + "Africa\/Libreville": "အနောက်အာဖရိက အချိန် (လီဗရာဗီးလ်)", + "Africa\/Lome": "ဂရင်းနစ် စံတော်ချိန် (လိုမီ)", + "Africa\/Luanda": "အနောက်အာဖရိက အချိန် (လူဝမ်ဒါ)", + "Africa\/Lubumbashi": "အလယ်အာဖရိက အချိန် (လူဘွန်းဘာရှီ)", + "Africa\/Lusaka": "အလယ်အာဖရိက အချိန် (လူစာကာ)", + "Africa\/Malabo": "အနောက်အာဖရိက အချိန် (မာလာဘို)", + "Africa\/Maputo": "အလယ်အာဖရိက အချိန် (မာပူးတို)", + "Africa\/Maseru": "တောင်အာဖရိက အချိန် (မာဆူရူး)", + "Africa\/Mbabane": "တောင်အာဖရိက အချိန် (ဘားဘာန်း)", + "Africa\/Mogadishu": "အရှေ့အာဖရိက အချိန် (မော်ဂါဒီးသျုး)", + "Africa\/Monrovia": "ဂရင်းနစ် စံတော်ချိန် (မွန်ရိုးဗီးယား)", + "Africa\/Nairobi": "အရှေ့အာဖရိက အချိန် (နိုင်ရိုဘီ)", + "Africa\/Ndjamena": "အနောက်အာဖရိက အချိန် (အင်ဂျာမီနာ)", + "Africa\/Niamey": "အနောက်အာဖရိက အချိန် (ညာမဲယ်)", + "Africa\/Nouakchott": "ဂရင်းနစ် စံတော်ချိန် (နိုအာ့ခ်ရှော့တ်)", + "Africa\/Ouagadougou": "ဂရင်းနစ် စံတော်ချိန် (ဝါဂါဒူးဂူ)", + "Africa\/Porto-Novo": "အနောက်အာဖရိက အချိန် (ပိုတို-နိုဗို)", + "Africa\/Sao_Tome": "ဂရင်းနစ် စံတော်ချိန် (ဆောင်တူမေး)", + "Africa\/Tripoli": "အရှေ့ဥရောပ အချိန် (ထရီပိုလီ)", + "Africa\/Tunis": "ဥရောပအလယ်ပိုင်း အချိန် (တူနီစ်)", + "Africa\/Windhoek": "အလယ်အာဖရိက အချိန် (ဗင်းဟူးခ်)", + "America\/Adak": "ဟာဝိုင်ယီ အယ်လူးရှန်း အချိန် (အာဒချ)", + "America\/Anchorage": "အလာစကာ အချိန် (အန်ကာရေ့ဂျ်)", + "America\/Anguilla": "အတ္တလန်တစ် အချိန် (အန်ဂီလာ)", + "America\/Antigua": "အတ္တလန်တစ် အချိန် (အန်တီဂွါ)", + "America\/Araguaina": "ဘရာဇီး အချိန် (အာရာဂွါအီနာ)", + "America\/Argentina\/La_Rioja": "အာဂျင်တီးနား အချိန် (လာ ရီယိုဟာ)", + "America\/Argentina\/Rio_Gallegos": "အာဂျင်တီးနား အချိန် (ရီယို ဂါလီဂိုစ်)", + "America\/Argentina\/Salta": "အာဂျင်တီးနား အချိန် (ဆာလ်တာ)", + "America\/Argentina\/San_Juan": "အာဂျင်တီးနား အချိန် (ဆန် ဂွမ်)", + "America\/Argentina\/San_Luis": "အနောက် အာဂျင်တီးနား အချိန် (ဆန် လူဝီစ်)", + "America\/Argentina\/Tucuman": "အာဂျင်တီးနား အချိန် (တူကူမန်)", + "America\/Argentina\/Ushuaia": "အာဂျင်တီးနား အချိန် (ဥဆွာအီအာ)", + "America\/Aruba": "အတ္တလန်တစ် အချိန် (အာရူးဗာ)", + "America\/Asuncion": "ပါရာဂွေး အချိန် (အာဆူစီအွန်း)", + "America\/Bahia": "ဘရာဇီး အချိန် (ဘာဟီအာ)", + "America\/Bahia_Banderas": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ဘာဟီအာ ဘန်ဒရက်စ်)", + "America\/Barbados": "အတ္တလန်တစ် အချိန် (ဘာဘေးဒိုးစ်)", + "America\/Belem": "ဘရာဇီး အချိန် (ဘီလင်မ်)", + "America\/Belize": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ဘလိဇ်)", + "America\/Blanc-Sablon": "အတ္တလန်တစ် အချိန် (ဘလွန်ခ်-စာဘလွန်)", + "America\/Boa_Vista": "အမေဇုံ အချိန် (ဘိုအာဗီစ်တာ)", + "America\/Bogota": "ကိုလံဘီယာ အချိန် (ဘိုဂိုတာ)", + "America\/Boise": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ဗွိုက်စီ)", + "America\/Buenos_Aires": "အာဂျင်တီးနား အချိန် (ဗျူနိုအေးရိစ်)", + "America\/Cambridge_Bay": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ကိန်းဘရစ်ချ် ဘေး)", + "America\/Campo_Grande": "အမေဇုံ အချိန် (ကိမ်ပို ဂရန်ဒီ)", + "America\/Cancun": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ကန်ခန်)", + "America\/Caracas": "ဗင်နီဇွဲလား အချိန် (ကာရာကာစ်)", + "America\/Catamarca": "အာဂျင်တီးနား အချိန် (ကာတာမာရကွာ)", + "America\/Cayenne": "ပြင်သစ် ဂီအားနား အချိန် (ကေညင်န်)", + "America\/Cayman": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ကေမန်)", + "America\/Chicago": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ချီကာကို)", + "America\/Chihuahua": "မက္ကဆီကန် ပစိဖိတ် အချိန် (ချီဟူအာဟူအာ)", + "America\/Coral_Harbour": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (အာတီကိုကန်)", + "America\/Cordoba": "အာဂျင်တီးနား အချိန် (ကိုဒိုဘာ)", + "America\/Costa_Rica": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ကို့စတာရီကာ)", + "America\/Creston": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ကရစ်စတွန်)", + "America\/Cuiaba": "အမေဇုံ အချိန် (ကွီရာဘာ)", + "America\/Curacao": "အတ္တလန်တစ် အချိန် (ကျူရေးကိုး)", + "America\/Danmarkshavn": "ဂရင်းနစ် စံတော်ချိန် (ဒန်မတ်ရှ်ဗာန်)", + "America\/Dawson": "မြောက်အမေရိက ပစိဖိတ်အချိန် (ဒေါ်ဆန်)", + "America\/Dawson_Creek": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ဒေါ်ဆန် ခရိခ်)", + "America\/Denver": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ဒင်န်ဗာ)", + "America\/Detroit": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဒက်ထရွိုက်)", + "America\/Dominica": "အတ္တလန်တစ် အချိန် (ဒိုမီနီကာ)", + "America\/Edmonton": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (အက်ဒ်မွန်တန်)", + "America\/El_Salvador": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (အယ်လ်ဆာဗေဒို)", + "America\/Fort_Nelson": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ဖို့တ် နယ်လ်ဆင်)", + "America\/Fortaleza": "ဘရာဇီး အချိန် (ဖို့တ်တာလီဇာ)", + "America\/Glace_Bay": "အတ္တလန်တစ် အချိန် (ဂလဲစ်ဘေး)", + "America\/Godthab": "အနောက် ဂရင်းလန်း အချိန် (နုခ်)", + "America\/Goose_Bay": "အတ္တလန်တစ် အချိန် (ဂူးစ်ဘေး)", + "America\/Grand_Turk": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဂရန်ဒ် တခ်)", + "America\/Grenada": "အတ္တလန်တစ် အချိန် (ဂရီနေဒါ)", + "America\/Guadeloupe": "အတ္တလန်တစ် အချိန် (ဂွါဒီလုပ်)", + "America\/Guatemala": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ဂွါတီမာလာ)", + "America\/Guayaquil": "အီကွေဒေါ အချိန် (ဂွါရာကွီးလ်)", + "America\/Guyana": "ဂိုင်ယာနာ အချိန် (ဂိုင်ယာနာ)", + "America\/Halifax": "အတ္တလန်တစ် အချိန် (ဟလီဖက်စ်)", + "America\/Havana": "ကျူးဘား အချိန် (ဟာဗာနာ)", + "America\/Hermosillo": "မက္ကဆီကန် ပစိဖိတ် အချိန် (ဟာမိုစ်စီလို)", + "America\/Indiana\/Knox": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (နောက်ခ်စ် အင်ဒီယားနား)", + "America\/Indiana\/Marengo": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (မာရန်ဂို အင်ဒီယားနား)", + "America\/Indiana\/Petersburg": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ပီတာစ်ဘတ်ခ် အင်ဒီယားနား)", + "America\/Indiana\/Tell_City": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (တဲလ်စီးတီး အင်ဒီယားနား)", + "America\/Indiana\/Vevay": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဗီဗဲ အင်ဒီယားနား)", + "America\/Indiana\/Vincennes": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဗင်ဆင့်စ် အင်ဒီယားနား)", + "America\/Indiana\/Winamac": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဝီနာမက်ခ် အင်ဒီယားနား)", + "America\/Indianapolis": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (အင်ဒီယားနား ပိုလိစ်)", + "America\/Inuvik": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (အီနုဗီခ်)", + "America\/Iqaluit": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (အီကာလူအီတ်)", + "America\/Jamaica": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဂျမေကာ)", + "America\/Jujuy": "အာဂျင်တီးနား အချိန် (ဂျုဂျေ)", + "America\/Juneau": "အလာစကာ အချိန် (ဂျုနိုအော)", + "America\/Kentucky\/Monticello": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (မွန်တီချယ်လို ကင်တပ်ကီ)", + "America\/Kralendijk": "အတ္တလန်တစ် အချိန် (ခရာလဲန်းဒစ်ချ်)", + "America\/La_Paz": "ဘိုလီးဘီးယား အချိန် (လာပါဇ်)", + "America\/Lima": "ပီရူး အချိန် (လီမာ)", + "America\/Los_Angeles": "မြောက်အမေရိက ပစိဖိတ်အချိန် (လော့စ်အိန်ဂျယ်လိစ်)", + "America\/Louisville": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (လူဝီဗီးလ်)", + "America\/Lower_Princes": "အတ္တလန်တစ် အချိန် (လိုအာပရင့်စ် ကွာတာ)", + "America\/Maceio": "ဘရာဇီး အချိန် (မာဆဲသွာ)", + "America\/Managua": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (မာနာဂွါ)", + "America\/Manaus": "အမေဇုံ အချိန် (မာနောက်စ်)", + "America\/Marigot": "အတ္တလန်တစ် အချိန် (မာရီဂေါ့)", + "America\/Martinique": "အတ္တလန်တစ် အချိန် (မာတီနီဂ်)", + "America\/Matamoros": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (မာတာမိုရိုစ်)", + "America\/Mazatlan": "မက္ကဆီကန် ပစိဖိတ် အချိန် (မာဇတ်လန်)", + "America\/Mendoza": "အာဂျင်တီးနား အချိန် (မန်ဒိုဇာ)", + "America\/Menominee": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (မီနိုမီနီး)", + "America\/Merida": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (မီရီဒါ)", + "America\/Metlakatla": "အလာစကာ အချိန် (မက်တ်လာကက်လာ)", + "America\/Mexico_City": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (မက်ကဆီကို စီးတီး)", + "America\/Miquelon": "စိန့်ပီအဲနှင့်မီခွီလွန်အချိန် (မီကွီလွန်)", + "America\/Moncton": "အတ္တလန်တစ် အချိန် (မွန်ခ်တွန်)", + "America\/Monterrey": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (မွန်တဲရေး)", + "America\/Montevideo": "ဥရုဂွေး အချိန် (မွန်တီဗီဒီအို)", + "America\/Montserrat": "အတ္တလန်တစ် အချိန် (မွန့်(တ်)ဆေးရတ်)", + "America\/Nassau": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (နာ့ဆော်)", + "America\/New_York": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (နယူးယောက်)", + "America\/Nipigon": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (နီပီဂွန်)", + "America\/Nome": "အလာစကာ အချိန် (နိုမီ)", + "America\/Noronha": "ဖာနန်ဒိုးဒီနိုးရိုးညာ အချိန် (နိုရိုညာ)", + "America\/North_Dakota\/Beulah": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ဗြူလာ၊ မြောက်ဒါကိုတာ)", + "America\/North_Dakota\/Center": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (စင်တာ၊ မြောက်ဒါကိုတာ)", + "America\/North_Dakota\/New_Salem": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (နယူးဆေးလမ်၊ မြောက်ဒါကိုတာ)", + "America\/Ojinaga": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (အိုခီနဂါ)", + "America\/Panama": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ပနားမား)", + "America\/Pangnirtung": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ဖန်ဂ်နသ်တံ)", + "America\/Paramaribo": "စူးရီနာမ်အချိန် (ပါရာမာရီဘို)", + "America\/Phoenix": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ဖီးနစ်)", + "America\/Port-au-Prince": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (ပို့တ်-အို-ပရင့်စ်)", + "America\/Port_of_Spain": "အတ္တလန်တစ် အချိန် (ပို့တ် အော့ဖ် စပိန်)", + "America\/Porto_Velho": "အမေဇုံ အချိန် (ပို့တ်တို ဗဲလီယို)", + "America\/Puerto_Rico": "အတ္တလန်တစ် အချိန် (ပေါ်တိုရီကို)", + "America\/Punta_Arenas": "ချီလီ အချိန် (ပွန်တာ အရီနာစ်)", + "America\/Rainy_River": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ရိမ်းနီး ရီဗာ)", + "America\/Rankin_Inlet": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ရန်ကင် အင်းလက်)", + "America\/Recife": "ဘရာဇီး အချိန် (ဟေစီဖီလ်)", + "America\/Regina": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ရယ်ဂျီနာ)", + "America\/Resolute": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ရီဆိုလုပ်(တ်))", + "America\/Santa_Isabel": "အနောက်တောင် မက္ကဆီကို အချိန် (ဆန်တာ အစ္ဇဘဲလ်)", + "America\/Santarem": "ဘရာဇီး အချိန် (ဆန်တာရမ်)", + "America\/Santiago": "ချီလီ အချိန် (ဆန်တီအာဂို)", + "America\/Santo_Domingo": "အတ္တလန်တစ် အချိန် (ဆန်တို ဒိုမင်းဂို)", + "America\/Sao_Paulo": "ဘရာဇီး အချိန် (ဆော်ပိုလို)", + "America\/Scoresbysund": "အရှေ့ဂရင်းလန်း အချိန် (အစ်တာကာ တိုးမိရက်တ်)", + "America\/Sitka": "အလာစကာ အချိန် (စစ်ကာ)", + "America\/St_Barthelemy": "အတ္တလန်တစ် အချိန် (စိန့်ဘာသယ်လမီ)", + "America\/St_Johns": "နယူးဖောင်လန် အချိန် (စိန့်ဂျွန်း)", + "America\/St_Kitts": "အတ္တလန်တစ် အချိန် (စိန့်ကိစ်)", + "America\/St_Lucia": "အတ္တလန်တစ် အချိန် (စိန့်လူစီယာ)", + "America\/St_Thomas": "အတ္တလန်တစ် အချိန် (စိန့်သောမတ်စ်)", + "America\/St_Vincent": "အတ္တလန်တစ် အချိန် (စိန့်ဗင်းဆင့်)", + "America\/Swift_Current": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (စွတ်ဖ်တ် ကားရင့်)", + "America\/Tegucigalpa": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (တီဂူစီဂလ်ပါ)", + "America\/Thule": "အတ္တလန်တစ် အချိန် (သုလီ)", + "America\/Thunder_Bay": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (သန်းန်ဒါး ဘေး)", + "America\/Tijuana": "မြောက်အမေရိက ပစိဖိတ်အချိန် (တီဂွါနာ)", + "America\/Toronto": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန် (တိုရန်တို)", + "America\/Tortola": "အတ္တလန်တစ် အချိန် (တောတိုလာ)", + "America\/Vancouver": "မြောက်အမေရိက ပစိဖိတ်အချိန် (ဗန်ကူးဗား)", + "America\/Whitehorse": "မြောက်အမေရိက ပစိဖိတ်အချိန် (ဝိုက်(တ်)ဟိုစ်)", + "America\/Winnipeg": "မြောက်အမေရိက အလယ်ပိုင်းအချိန် (ဝီနီဗက်ဂ်)", + "America\/Yakutat": "အလာစကာ အချိန် (ရာကုတတ်)", + "America\/Yellowknife": "မြောက်အမေရိက တောင်တန်းဒေသအချိန် (ရဲလိုနိုက်ဖ်)", + "Antarctica\/Casey": "အနောက်ဩစတြေးလျ အချိန် (ကေစီ)", + "Antarctica\/Davis": "ဒေးဗစ် အချိန် (ဒေးဗစ်)", + "Antarctica\/DumontDUrville": "ဒူးမော့တ် ဒါရ်ဗီးလ် အချိန် (ဒူးမော့တ် ဒါရ်ဗီးလ်)", + "Antarctica\/Macquarie": "မက်ကွယ်ရီကျွန်း အချိန် (မက်ကွယ်ရီ)", + "Antarctica\/Mawson": "မော်စွန် အချိန် (မော်စွန်)", + "Antarctica\/McMurdo": "နယူးဇီလန် အချိန် (မက်မူဒိုး)", + "Antarctica\/Palmer": "ချီလီ အချိန် (ပါလ်မာ)", + "Antarctica\/Rothera": "ရိုသီရာ အချိန် (ရိုသီရာ)", + "Antarctica\/Syowa": "ရှိုဝါ အချိန် (ရှိုးဝါ)", + "Antarctica\/Troll": "ဂရင်းနစ် စံတော်ချိန် (ထရိုလ်)", + "Antarctica\/Vostok": "ဗိုစ်တိုခ် အချိန် (ဗိုစ်တိုခ်)", + "Arctic\/Longyearbyen": "ဥရောပအလယ်ပိုင်း အချိန် (လောင်ရီယားဘရံ)", + "Asia\/Aden": "အာရေဗျ အချိန် (အာဒင်)", + "Asia\/Almaty": "အရှေ့ကာဇက်စတန် အချိန် (အော်မာတီ)", + "Asia\/Amman": "အရှေ့ဥရောပ အချိန် (အာမာန်း)", + "Asia\/Aqtau": "အနောက်ကာဇက်စတန် အချိန် (အက်တာဥု)", + "Asia\/Aqtobe": "အနောက်ကာဇက်စတန် အချိန် (အာချတူးဘီ)", + "Asia\/Ashgabat": "တာ့ခ်မင်နစ္စတန် အချိန် (အာရှ်ဂါဘာဒ်)", + "Asia\/Atyrau": "အနောက်ကာဇက်စတန် အချိန် (အာတီရအူ)", + "Asia\/Baghdad": "အာရေဗျ အချိန် (ဘဂ္ဂဒက်)", + "Asia\/Bahrain": "အာရေဗျ အချိန် (ဘာရိန်း)", + "Asia\/Baku": "အဇာဘိုင်ဂျန် အချိန် (ဘာကူ)", + "Asia\/Bangkok": "အင်ဒိုချိုင်းနား အချိန် (ဘန်ကောက်)", + "Asia\/Beirut": "အရှေ့ဥရောပ အချိန် (ဘေရွတ်)", + "Asia\/Bishkek": "ကာဂျစ္စတန် အချိန် (ဘီရှ်ခက်)", + "Asia\/Brunei": "ဘရူနိုင်း စံတော်ချိန် (ဘရူနိုင်း)", + "Asia\/Calcutta": "အိန္ဒိယ စံတော်ချိန် (ကိုလျကတ်တား)", + "Asia\/Chita": "ယူခူးတ်စ် အချိန် (ချီတာ)", + "Asia\/Choibalsan": "ချွဲဘော်ဆန်း အချိန် (ချွဲဘောဆန်)", + "Asia\/Colombo": "အိန္ဒိယ စံတော်ချိန် (ကိုလံဘို)", + "Asia\/Damascus": "အရှေ့ဥရောပ အချိန် (ဒမားစကပ်)", + "Asia\/Dhaka": "ဘင်္ဂလားဒေ့ရှ် အချိန် (ဒက်ကာ)", + "Asia\/Dili": "အရှေ့တီမော အချိန် (ဒစ်လီ)", + "Asia\/Dubai": "ပင်လယ်ကွေ့ အချိန် (ဒူဘိုင်း)", + "Asia\/Dushanbe": "တာဂျစ်ကစ္စတန် အချိန် (ဒူရှန်းဘဲ)", + "Asia\/Famagusta": "အရှေ့ဥရောပ အချိန် (ဖာမာဂူစတာ)", + "Asia\/Gaza": "အရှေ့ဥရောပ အချိန် (ဂါဇာ)", + "Asia\/Hebron": "အရှေ့ဥရောပ အချိန် (ဟီဘရွန်)", + "Asia\/Hong_Kong": "ဟောင်ကောင် အချိန် (ဟောင်ကောင်)", + "Asia\/Hovd": "ဟိုးဗ် အချိန် (ဟိုးဗျ)", + "Asia\/Irkutsk": "အီရူခူတ် အချိန် (အီရူခူတ်)", + "Asia\/Jakarta": "အနောက်ပိုင်း အင်ဒိုနီးရှား အချိန် (ဂျကာတာ)", + "Asia\/Jayapura": "အရှေ့ပိုင်း အင်ဒိုနီးရှား အချိန် (ဂျာရာပူရာ)", + "Asia\/Jerusalem": "အစ္စရေး အချိန် (ဂျေရုဆလင်)", + "Asia\/Kabul": "အာဖဂန်နစ္စတန် အချိန် (ကဘူးလျ)", + "Asia\/Karachi": "ပါကစ္စတန် အချိန် (ကရာချိ)", + "Asia\/Katmandu": "နီပေါ အချိန် (ခတ်တမန်ဒူ)", + "Asia\/Khandyga": "ယူခူးတ်စ် အချိန် (ခန်ဒိုင်ဂါ)", + "Asia\/Krasnoyarsk": "ခရာ့စ်နိုရာစ် အချိန် (ခရာ့စ်နိုရာစ်)", + "Asia\/Kuala_Lumpur": "မလေးရှား အချိန် (ကွာလာလမ်ပူ)", + "Asia\/Kuching": "မလေးရှား အချိန် (ကူချင်)", + "Asia\/Kuwait": "အာရေဗျ အချိန် (ကူဝိတ်)", + "Asia\/Macau": "တရုတ် အချိန် (မကာအို)", + "Asia\/Magadan": "မာဂါဒန်း အချိန် (မာဂါဒန်း)", + "Asia\/Makassar": "အလယ်ပိုင်း အင်ဒိုနီးရှား အချိန် (မခက်စ်ဆာ)", + "Asia\/Manila": "ဖိလစ်ပိုင် အချိန် (မနီလာ)", + "Asia\/Muscat": "ပင်လယ်ကွေ့ အချိန် (မတ်စ်ကက်တ်)", + "Asia\/Nicosia": "အရှေ့ဥရောပ အချိန် (နီကိုရှား)", + "Asia\/Novokuznetsk": "ခရာ့စ်နိုရာစ် အချိန် (နိုဗိုခူဇ်နက်စ်)", + "Asia\/Novosibirsk": "နိုဗိုစဲဘီအဲယ်စ် အချိန် (နိုဗိုစဲဘီအဲယ်စ်)", + "Asia\/Omsk": "အွမ်းစ်ခ် အချိန် (အွမ်းစ်ခ်)", + "Asia\/Oral": "အနောက်ကာဇက်စတန် အချိန် (အော်ရဲလ်)", + "Asia\/Phnom_Penh": "အင်ဒိုချိုင်းနား အချိန် (ဖနွမ်ပင်)", + "Asia\/Pontianak": "အနောက်ပိုင်း အင်ဒိုနီးရှား အချိန် (ပွန်တီအားနာ့ခ်)", + "Asia\/Pyongyang": "ကိုရီးယား အချိန် (ပြုံယန်း)", + "Asia\/Qatar": "အာရေဗျ အချိန် (ကာတာ)", + "Asia\/Qostanay": "အရှေ့ကာဇက်စတန် အချိန် (Qostanay)", + "Asia\/Qyzylorda": "အနောက်ကာဇက်စတန် အချိန် (ကီဇလော်ဒါ)", + "Asia\/Rangoon": "မြန်မာ အချိန် (ရန်ကုန်)", + "Asia\/Riyadh": "အာရေဗျ အချိန် (ရီယားဒ်)", + "Asia\/Saigon": "အင်ဒိုချိုင်းနား အချိန် (ဟိုချီမင်းစီးတီး)", + "Asia\/Sakhalin": "ဆာခါလင် အချိန် (ဆာခါလင်)", + "Asia\/Samarkand": "ဥဇဘက်ကစ္စတန် အချိန် (ဆမ်းမာခန်းဒ်)", + "Asia\/Seoul": "ကိုရီးယား အချိန် (ဆိုးလ်)", + "Asia\/Shanghai": "တရုတ် အချိန် (ရှန်ဟိုင်း)", + "Asia\/Singapore": "စင်္ကာပူ အချိန် (စင်္ကာပူ)", + "Asia\/Srednekolymsk": "မာဂါဒန်း အချိန် (ဆရစ်နစ်ကာလင်မ်စ်)", + "Asia\/Taipei": "ထိုင်ပေ အချိန် (တိုင်ပေ)", + "Asia\/Tashkent": "ဥဇဘက်ကစ္စတန် အချိန် (တာရှ်ကဲန့်)", + "Asia\/Tbilisi": "ဂျော်ဂျီယာ အချိန် (တဘီးလီစီ)", + "Asia\/Tehran": "အီရန် အချိန် (တီဟီရန်)", + "Asia\/Thimphu": "ဘူတန် အချိန် (တင်ဖူး)", + "Asia\/Tokyo": "ဂျပန် အချိန် (တိုကျို)", + "Asia\/Ulaanbaatar": "ဥလန်ဘာတော အချိန် (ဥလန်ဘာတော)", + "Asia\/Ust-Nera": "ဗလာဒီဗော့စတော့ခ် အချိန် (အူးစ် နီရား)", + "Asia\/Vientiane": "အင်ဒိုချိုင်းနား အချိန် (ဗီယင်ကျန်း)", + "Asia\/Vladivostok": "ဗလာဒီဗော့စတော့ခ် အချိန် (ဗလာဒီဗော့စတော့ခ်)", + "Asia\/Yakutsk": "ယူခူးတ်စ် အချိန် (ယူခူးတ်စ်)", + "Asia\/Yekaterinburg": "ရယ်ခါးတီရင်ဘားခ် အချိန် (ရယ်ခါးတီရင်ဘားခ်)", + "Asia\/Yerevan": "အာမေးနီးယား အချိန် (ရဲယ်ရေဗန်း)", + "Atlantic\/Azores": "အေဇိုးရီးစ် အချိန် (အေဇိုးရီးစ်)", + "Atlantic\/Bermuda": "အတ္တလန်တစ် အချိန် (ဘာမြူဒါ)", + "Atlantic\/Canary": "အနောက်ဥရောပ အချိန် (ကနေရီ)", + "Atlantic\/Cape_Verde": "ကိတ်ပ် ဗာဒီ အချိန် (ကိတ်ပ် ဗာဒီ)", + "Atlantic\/Faeroe": "အနောက်ဥရောပ အချိန် (ဖါရို)", + "Atlantic\/Madeira": "အနောက်ဥရောပ အချိန် (မဒီးရာ)", + "Atlantic\/Reykjavik": "ဂရင်းနစ် စံတော်ချိန် (ရေးကီဗစ်ခ်)", + "Atlantic\/South_Georgia": "တောင်ဂျော်ဂျီယာ အချိန် (တောင်ဂျော်ဂျီယာ)", + "Atlantic\/St_Helena": "ဂရင်းနစ် စံတော်ချိန် (စိန့်ဟယ်လယ်နာ)", + "Atlantic\/Stanley": "ဖော့ကလန်ကျွန်းစု အချိန် (စတန်လေ)", + "Australia\/Adelaide": "ဩစတြေးလျ အလယ်ပိုင်း အချိန် (အန္ဒီလိတ်ဒ်)", + "Australia\/Brisbane": "အရှေ့ဩစတြေးလျ အချိန် (ဘရစ္စဘိန်း)", + "Australia\/Broken_Hill": "ဩစတြေးလျ အလယ်ပိုင်း အချိန် (ဘရိုကင်ဟီးလ်)", + "Australia\/Currie": "အရှေ့ဩစတြေးလျ အချိန် (ကာရီ)", + "Australia\/Darwin": "ဩစတြေးလျ အလယ်ပိုင်း အချိန် (ဒါဝင်)", + "Australia\/Eucla": "သြစတြေးလျား အနောက်အလယ်ပိုင်း အချိန် (ယူးခလာ)", + "Australia\/Hobart": "အရှေ့ဩစတြေးလျ အချိန် (ဟိုးဘားတ်)", + "Australia\/Lindeman": "အရှေ့ဩစတြေးလျ အချိန် (လင်းဒီမန်း)", + "Australia\/Lord_Howe": "လော့ဒ်ဟောင် အချိန် (လော့ဒ် ဟောင်)", + "Australia\/Melbourne": "အရှေ့ဩစတြေးလျ အချိန် (မဲလ်ဘုန်း)", + "Australia\/Perth": "အနောက်ဩစတြေးလျ အချိန် (ပါးသ်)", + "Australia\/Sydney": "အရှေ့ဩစတြေးလျ အချိန် (ဆစ်ဒနီ)", + "CST6CDT": "မြောက်အမေရိက အလယ်ပိုင်းအချိန်", + "EST5EDT": "မြောက်အမေရိက အရှေ့ပိုင်းအချိန်", + "Etc\/GMT": "ဂရင်းနစ် စံတော်ချိန်", + "Etc\/UTC": "ညှိထားသည့် ကမ္ဘာ့ စံတော်ချိန်", + "Europe\/Amsterdam": "ဥရောပအလယ်ပိုင်း အချိန် (အမ်စတာဒမ်)", + "Europe\/Andorra": "ဥရောပအလယ်ပိုင်း အချိန် (အန်ဒိုရာ)", + "Europe\/Astrakhan": "မော်စကို အချိန် (အားစ်တရခန်း)", + "Europe\/Athens": "အရှေ့ဥရောပ အချိန် (အေသင်)", + "Europe\/Belgrade": "ဥရောပအလယ်ပိုင်း အချိန် (ဘဲလ်ဂရိတ်)", + "Europe\/Berlin": "ဥရောပအလယ်ပိုင်း အချိန် (ဘာလင်)", + "Europe\/Bratislava": "ဥရောပအလယ်ပိုင်း အချိန် (ဘရာတီးစ်လားဗာ)", + "Europe\/Brussels": "ဥရောပအလယ်ပိုင်း အချိန် (ဘရပ်ဆဲလ်)", + "Europe\/Bucharest": "အရှေ့ဥရောပ အချိန် (ဘူခါရက်စ်)", + "Europe\/Budapest": "ဥရောပအလယ်ပိုင်း အချိန် (ဘူဒါပက်စ်)", + "Europe\/Busingen": "ဥရောပအလယ်ပိုင်း အချိန် (ဘူရှင်ဂျင်)", + "Europe\/Chisinau": "အရှေ့ဥရောပ အချိန် (ချီရှီနားအူ)", + "Europe\/Copenhagen": "ဥရောပအလယ်ပိုင်း အချိန် (ကိုပင်ဟေဂင်)", + "Europe\/Dublin": "ဂရင်းနစ် စံတော်ချိန် (ဒတ်ဘလင်)", + "Europe\/Gibraltar": "ဥရောပအလယ်ပိုင်း အချိန် (ဂျီဘရော်လ်တာ)", + "Europe\/Guernsey": "ဂရင်းနစ် စံတော်ချိန် (ဂွန်းဇီ)", + "Europe\/Helsinki": "အရှေ့ဥရောပ အချိန် (ဟဲလ်စင်ကီ)", + "Europe\/Isle_of_Man": "ဂရင်းနစ် စံတော်ချိန် (မန်းကျွန်း)", + "Europe\/Jersey": "ဂရင်းနစ် စံတော်ချိန် (ဂျာစီ)", + "Europe\/Kaliningrad": "အရှေ့ဥရောပ အချိန် (ခါလီနင်ဂရက်)", + "Europe\/Kiev": "အရှေ့ဥရောပ အချိန် (ခီးအက်ဖ်)", + "Europe\/Lisbon": "အနောက်ဥရောပ အချိန် (လစ္စဘွန်း)", + "Europe\/Ljubljana": "ဥရောပအလယ်ပိုင်း အချိန် (လူဘလီအားနား)", + "Europe\/London": "ဂရင်းနစ် စံတော်ချိန် (လန်ဒန်)", + "Europe\/Luxembourg": "ဥရောပအလယ်ပိုင်း အချိန် (လူဇင်ဘတ်)", + "Europe\/Madrid": "ဥရောပအလယ်ပိုင်း အချိန် (မဒရစ်)", + "Europe\/Malta": "ဥရောပအလယ်ပိုင်း အချိန် (မော်လ်တာ)", + "Europe\/Mariehamn": "အရှေ့ဥရောပ အချိန် (မရီအာ ဟားမန်)", + "Europe\/Minsk": "မော်စကို အချိန် (မင်းစခ်)", + "Europe\/Monaco": "ဥရောပအလယ်ပိုင်း အချိန် (မိုနာကို)", + "Europe\/Moscow": "မော်စကို အချိန် (မော်စကို)", + "Europe\/Oslo": "ဥရောပအလယ်ပိုင်း အချိန် (အော်စလို)", + "Europe\/Paris": "ဥရောပအလယ်ပိုင်း အချိန် (ပဲရစ်)", + "Europe\/Podgorica": "ဥရောပအလယ်ပိုင်း အချိန် (ပေါ့ဂိုရီကာ)", + "Europe\/Prague": "ဥရောပအလယ်ပိုင်း အချိန် (ပရက်ဂ်)", + "Europe\/Riga": "အရှေ့ဥရောပ အချိန် (ရီဂါ)", + "Europe\/Rome": "ဥရောပအလယ်ပိုင်း အချိန် (ရောမ)", + "Europe\/San_Marino": "ဥရောပအလယ်ပိုင်း အချိန် (ဆန်မရီးနို)", + "Europe\/Sarajevo": "ဥရောပအလယ်ပိုင်း အချိန် (ဆာရာယေဗို)", + "Europe\/Saratov": "မော်စကို အချိန် (ဆာရာတို့ဖ်)", + "Europe\/Simferopol": "မော်စကို အချိန် (စင်ဖာရိုးဖို)", + "Europe\/Skopje": "ဥရောပအလယ်ပိုင်း အချိန် (စကော့ပ်ရာ)", + "Europe\/Sofia": "အရှေ့ဥရောပ အချိန် (ဆိုဖီအာ)", + "Europe\/Stockholm": "ဥရောပအလယ်ပိုင်း အချိန် (စတော့ဟုမ်း)", + "Europe\/Tallinn": "အရှေ့ဥရောပ အချိန် (ထားလင်)", + "Europe\/Tirane": "ဥရောပအလယ်ပိုင်း အချိန် (တီရာနီ)", + "Europe\/Ulyanovsk": "မော်စကို အချိန် (အူလီယာနိုစကစ်ဖ်)", + "Europe\/Uzhgorod": "အရှေ့ဥရောပ အချိန် (ဥဇ်ဂိုရို့တ်)", + "Europe\/Vaduz": "ဥရောပအလယ်ပိုင်း အချိန် (ဗာဒူးစ်)", + "Europe\/Vatican": "ဥရောပအလယ်ပိုင်း အချိန် (ဗာတီကန်)", + "Europe\/Vienna": "ဥရောပအလယ်ပိုင်း အချိန် (ဗီယင်နာ)", + "Europe\/Vilnius": "အရှေ့ဥရောပ အချိန် (ဗီးလ်နီအိုးစ်)", + "Europe\/Volgograd": "ဗိုလ်ဂိုဂရက် အချိန် (ဗိုလ်ဂိုဂရက်)", + "Europe\/Warsaw": "ဥရောပအလယ်ပိုင်း အချိန် (ဝါဆော)", + "Europe\/Zagreb": "ဥရောပအလယ်ပိုင်း အချိန် (ဇာဂ်ဂရက်ဘ်)", + "Europe\/Zaporozhye": "အရှေ့ဥရောပ အချိန် (ဇာဖိုရိုးစ်ဂျာ)", + "Europe\/Zurich": "ဥရောပအလယ်ပိုင်း အချိန် (ဇူးရစ်ချ်)", + "Indian\/Antananarivo": "အရှေ့အာဖရိက အချိန် (အန်တာနာနာရီးဘို)", + "Indian\/Chagos": "အိန္ဒိယသမုဒ္ဒရာ အချိန် (ချာဂိုစ်)", + "Indian\/Christmas": "ခရစ်စမတ်ကျွန်း အချိန် (ခရစ်စမတ်)", + "Indian\/Cocos": "ကိုကိုးကျွန်း အချိန် (ကိုကိုးစ်)", + "Indian\/Comoro": "အရှေ့အာဖရိက အချိန် (ကိုမိုရို)", + "Indian\/Kerguelen": "ပြင်သစ်တောင်ပိုင်းနှင့် အန္တာတိတ် အချိန် (ခါဂါလန်)", + "Indian\/Mahe": "ဆေးရှဲ အချိန် (မာဟီ)", + "Indian\/Maldives": "မော်လဒိုက် အချိန် (မော်လဒိုက်)", + "Indian\/Mauritius": "မောရစ်ရှ် အချိန် (မောရစ်ရှ)", + "Indian\/Mayotte": "အရှေ့အာဖရိက အချိန် (မာယိုတဲ)", + "Indian\/Reunion": "ရီယူနီယံ အချိန် (ရီယူနီယန်)", + "MST7MDT": "မြောက်အမေရိက တောင်တန်းဒေသအချိန်", + "PST8PDT": "မြောက်အမေရိက ပစိဖိတ်အချိန်", + "Pacific\/Apia": "အပီယာ အချိန် (အားပီအား)", + "Pacific\/Auckland": "နယူးဇီလန် အချိန် (အော့ကလန်)", + "Pacific\/Bougainville": "ပါပူအာနယူးဂီနီ အချိန် (ဘူဂန်ဗီးလီးယား)", + "Pacific\/Chatham": "ချားသမ်အချိန် (ချားသမ်)", + "Pacific\/Easter": "အီစတာကျွန်းအချိန် (အီစတာ)", + "Pacific\/Efate": "ဗနွားတူ အချိန် (အီဖာတီ)", + "Pacific\/Enderbury": "ဖီးနစ်ကျွန်းစု အချိန် (အန်ဒါဘူရီ)", + "Pacific\/Fakaofo": "တိုကီလာဥ အချိန် (ဖာခါအိုဖို)", + "Pacific\/Fiji": "ဖီဂျီ အချိန် (ဖီဂျီ)", + "Pacific\/Funafuti": "တူဗားလူ အချိန် (ဖူနာဖူတီ)", + "Pacific\/Galapagos": "ဂါလားပါဂိုးစ်အချိန် (ဂါလာပါကပ်စ်)", + "Pacific\/Gambier": "ဂမ်ဘီယာ အချိန် (ဂမ်ဘီယာ)", + "Pacific\/Guadalcanal": "ဆော်လမွန်ကျွန်းစု အချိန် (ဂွါဒါကနဲလ်)", + "Pacific\/Guam": "ချာမိုရို အချိန် (ဂူအမ်)", + "Pacific\/Honolulu": "ဟာဝိုင်ယီ အယ်လူးရှန်း အချိန် (ဟိုနိုလူလူ)", + "Pacific\/Johnston": "ဟာဝိုင်ယီ အယ်လူးရှန်း အချိန် (ဂျွန်စတန်)", + "Pacific\/Kiritimati": "လိုင်းကျွန်းစု အချိန် (ခရိဒီမတီ)", + "Pacific\/Kosrae": "ခိုစ်ရိုင် အချိန် (ခိုစ်ရိုင်)", + "Pacific\/Kwajalein": "မာရှယ်ကျွန်းစု အချိန် (ခွာဂျာလိန်)", + "Pacific\/Majuro": "မာရှယ်ကျွန်းစု အချိန် (မာဂျူးရို)", + "Pacific\/Marquesas": "မာခေးအပ်စ် အချိန် (မာခေးအပ်စ်)", + "Pacific\/Midway": "ဆမိုအာ အချိန် (မစ်ဒ်ဝေး)", + "Pacific\/Nauru": "နာဥူရူ အချိန် (နာဥူရူ)", + "Pacific\/Niue": "နီဦးအေ အချိန် (နီဦးအေ)", + "Pacific\/Norfolk": "နောဖော့ခ်ကျွန်းအချိန် (နော်ဖော့ခ်)", + "Pacific\/Noumea": "နယူးကယ်လီဒိုးနီးယား အချိန် (နူမယ်အာ)", + "Pacific\/Pago_Pago": "ဆမိုအာ အချိန် (ပါဂိုပါဂို)", + "Pacific\/Palau": "ပလာအို အချိန် (ပလာအို)", + "Pacific\/Pitcairn": "ပါတ်ကယ်ရင် အချိန် (ပါတ်ကယ်ရင်)", + "Pacific\/Ponape": "ဖိုနာဖဲအ် အချိန် (ဖိုနာဖဲအ်)", + "Pacific\/Port_Moresby": "ပါပူအာနယူးဂီနီ အချိန် (ဖို့တ် မိုရက်စ်ဘီ)", + "Pacific\/Rarotonga": "ကွတ်ခ်ကျွန်းစု အချိန် (ရာရိုတွန်းဂါ)", + "Pacific\/Saipan": "ချာမိုရို အချိန် (ဆိုင်ပန်)", + "Pacific\/Tahiti": "တဟီတီ အချိန် (တဟီတီ)", + "Pacific\/Tarawa": "ဂီလ်ဘတ်ကျွန်းစု အချိန် (တာရာဝါ)", + "Pacific\/Tongatapu": "တွန်ဂါ အချိန် (တွန်ဂါတာပု)", + "Pacific\/Truk": "ချုခ် အချိန် (ချုခ်)", + "Pacific\/Wake": "ဝိတ်ခ်ကျွန်း အချိန် (ဝိက်ခ်)", + "Pacific\/Wallis": "ဝေါလီစ်နှင့် ဖူကျူနာ အချိန် (ဝေါလီစ်)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/nb.json b/src/Symfony/Component/Intl/Resources/data/timezones/nb.json new file mode 100644 index 0000000000000..ef2dd45464cf5 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/nb.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwich middeltid (Abidjan)", + "Africa\/Accra": "Greenwich middeltid (Accra)", + "Africa\/Addis_Ababa": "østafrikansk tid (Addis Abeba)", + "Africa\/Algiers": "sentraleuropeisk tid (Alger)", + "Africa\/Asmera": "østafrikansk tid (Asmara)", + "Africa\/Bamako": "Greenwich middeltid (Bamako)", + "Africa\/Bangui": "vestafrikansk tid (Bangui)", + "Africa\/Banjul": "Greenwich middeltid (Banjul)", + "Africa\/Bissau": "Greenwich middeltid (Bissau)", + "Africa\/Blantyre": "sentralafrikansk tid (Blantyre)", + "Africa\/Brazzaville": "vestafrikansk tid (Brazzaville)", + "Africa\/Bujumbura": "sentralafrikansk tid (Bujumbura)", + "Africa\/Cairo": "østeuropeisk tid (Kairo)", + "Africa\/Casablanca": "vesteuropeisk tid (Casablanca)", + "Africa\/Ceuta": "sentraleuropeisk tid (Ceuta)", + "Africa\/Conakry": "Greenwich middeltid (Conakry)", + "Africa\/Dakar": "Greenwich middeltid (Dakar)", + "Africa\/Dar_es_Salaam": "østafrikansk tid (Dar-es-Salaam)", + "Africa\/Djibouti": "østafrikansk tid (Djibouti)", + "Africa\/Douala": "vestafrikansk tid (Douala)", + "Africa\/El_Aaiun": "vesteuropeisk tid (El Aaiún)", + "Africa\/Freetown": "Greenwich middeltid (Freetown)", + "Africa\/Gaborone": "sentralafrikansk tid (Gaborone)", + "Africa\/Harare": "sentralafrikansk tid (Harare)", + "Africa\/Johannesburg": "sørafrikansk tid (Johannesburg)", + "Africa\/Juba": "østafrikansk tid (Juba)", + "Africa\/Kampala": "østafrikansk tid (Kampala)", + "Africa\/Khartoum": "sentralafrikansk tid (Khartoum)", + "Africa\/Kigali": "sentralafrikansk tid (Kigali)", + "Africa\/Kinshasa": "vestafrikansk tid (Kinshasa)", + "Africa\/Lagos": "vestafrikansk tid (Lagos)", + "Africa\/Libreville": "vestafrikansk tid (Libreville)", + "Africa\/Lome": "Greenwich middeltid (Lomé)", + "Africa\/Luanda": "vestafrikansk tid (Luanda)", + "Africa\/Lubumbashi": "sentralafrikansk tid (Lubumbashi)", + "Africa\/Lusaka": "sentralafrikansk tid (Lusaka)", + "Africa\/Malabo": "vestafrikansk tid (Malabo)", + "Africa\/Maputo": "sentralafrikansk tid (Maputo)", + "Africa\/Maseru": "sørafrikansk tid (Maseru)", + "Africa\/Mbabane": "sørafrikansk tid (Mbabane)", + "Africa\/Mogadishu": "østafrikansk tid (Mogadishu)", + "Africa\/Monrovia": "Greenwich middeltid (Monrovia)", + "Africa\/Nairobi": "østafrikansk tid (Nairobi)", + "Africa\/Ndjamena": "vestafrikansk tid (Ndjamena)", + "Africa\/Niamey": "vestafrikansk tid (Niamey)", + "Africa\/Nouakchott": "Greenwich middeltid (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich middeltid (Ouagadougou)", + "Africa\/Porto-Novo": "vestafrikansk tid (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich middeltid (São Tomé)", + "Africa\/Tripoli": "østeuropeisk tid (Tripoli)", + "Africa\/Tunis": "sentraleuropeisk tid (Tunis)", + "Africa\/Windhoek": "sentralafrikansk tid (Windhoek)", + "America\/Adak": "tidssone for Hawaii og Aleutene (Adak)", + "America\/Anchorage": "alaskisk tid (Anchorage)", + "America\/Anguilla": "tidssone for den nordamerikanske atlanterhavskysten (Anguilla)", + "America\/Antigua": "tidssone for den nordamerikanske atlanterhavskysten (Antigua)", + "America\/Araguaina": "tidssone for Brasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "argentinsk tid (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "argentinsk tid (Rio Gallegos)", + "America\/Argentina\/Salta": "argentinsk tid (Salta)", + "America\/Argentina\/San_Juan": "argentinsk tid (San Juan)", + "America\/Argentina\/San_Luis": "vestargentinsk tid (San Luis)", + "America\/Argentina\/Tucuman": "argentinsk tid (Tucumán)", + "America\/Argentina\/Ushuaia": "argentinsk tid (Ushuaia)", + "America\/Aruba": "tidssone for den nordamerikanske atlanterhavskysten (Aruba)", + "America\/Asuncion": "paraguayansk tid (Asunción)", + "America\/Bahia": "tidssone for Brasilia (Bahia)", + "America\/Bahia_Banderas": "tidssone for det sentrale Nord-Amerika (Bahía Banderas)", + "America\/Barbados": "tidssone for den nordamerikanske atlanterhavskysten (Barbados)", + "America\/Belem": "tidssone for Brasilia (Belém)", + "America\/Belize": "tidssone for det sentrale Nord-Amerika (Belize)", + "America\/Blanc-Sablon": "tidssone for den nordamerikanske atlanterhavskysten (Blanc-Sablon)", + "America\/Boa_Vista": "tidssone for Amazonas (Boa Vista)", + "America\/Bogota": "colombiansk tid (Bogotá)", + "America\/Boise": "tidssone for Rocky Mountains (USA) (Boise)", + "America\/Buenos_Aires": "argentinsk tid (Buenos Aires)", + "America\/Cambridge_Bay": "tidssone for Rocky Mountains (USA) (Cambridge Bay)", + "America\/Campo_Grande": "tidssone for Amazonas (Campo Grande)", + "America\/Cancun": "tidssone for den nordamerikanske østkysten (Cancún)", + "America\/Caracas": "venezuelansk tid (Caracas)", + "America\/Catamarca": "argentinsk tid (Catamarca)", + "America\/Cayenne": "tidssone for Fransk Guyana (Cayenne)", + "America\/Cayman": "tidssone for den nordamerikanske østkysten (Caymanøyene)", + "America\/Chicago": "tidssone for det sentrale Nord-Amerika (Chicago)", + "America\/Chihuahua": "tidssone for den meksikanske Stillehavskysten (Chihuahua)", + "America\/Coral_Harbour": "tidssone for den nordamerikanske østkysten (Atikokan)", + "America\/Cordoba": "argentinsk tid (Córdoba)", + "America\/Costa_Rica": "tidssone for det sentrale Nord-Amerika (Costa Rica)", + "America\/Creston": "tidssone for Rocky Mountains (USA) (Creston)", + "America\/Cuiaba": "tidssone for Amazonas (Cuiabá)", + "America\/Curacao": "tidssone for den nordamerikanske atlanterhavskysten (Curaçao)", + "America\/Danmarkshavn": "Greenwich middeltid (Danmarkshavn)", + "America\/Dawson": "tidssone for den nordamerikanske Stillehavskysten (Dawson)", + "America\/Dawson_Creek": "tidssone for Rocky Mountains (USA) (Dawson Creek)", + "America\/Denver": "tidssone for Rocky Mountains (USA) (Denver)", + "America\/Detroit": "tidssone for den nordamerikanske østkysten (Detroit)", + "America\/Dominica": "tidssone for den nordamerikanske atlanterhavskysten (Dominica)", + "America\/Edmonton": "tidssone for Rocky Mountains (USA) (Edmonton)", + "America\/Eirunepe": "Acre-tid (Eirunepe)", + "America\/El_Salvador": "tidssone for det sentrale Nord-Amerika (El Salvador)", + "America\/Fort_Nelson": "tidssone for Rocky Mountains (USA) (Fort Nelson)", + "America\/Fortaleza": "tidssone for Brasilia (Fortaleza)", + "America\/Glace_Bay": "tidssone for den nordamerikanske atlanterhavskysten (Glace Bay)", + "America\/Godthab": "vestgrønlandsk tid (Nuuk)", + "America\/Goose_Bay": "tidssone for den nordamerikanske atlanterhavskysten (Goose Bay)", + "America\/Grand_Turk": "tidssone for den nordamerikanske østkysten (Grand Turk)", + "America\/Grenada": "tidssone for den nordamerikanske atlanterhavskysten (Grenada)", + "America\/Guadeloupe": "tidssone for den nordamerikanske atlanterhavskysten (Guadeloupe)", + "America\/Guatemala": "tidssone for det sentrale Nord-Amerika (Guatemala)", + "America\/Guayaquil": "ecuadoriansk tid (Guayaquil)", + "America\/Guyana": "guyansk tid (Guyana)", + "America\/Halifax": "tidssone for den nordamerikanske atlanterhavskysten (Halifax)", + "America\/Havana": "cubansk tid (Havana)", + "America\/Hermosillo": "tidssone for den meksikanske Stillehavskysten (Hermosillo)", + "America\/Indiana\/Knox": "tidssone for det sentrale Nord-Amerika (Knox, Indiana)", + "America\/Indiana\/Marengo": "tidssone for den nordamerikanske østkysten (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "tidssone for den nordamerikanske østkysten (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "tidssone for det sentrale Nord-Amerika (Tell City, Indiana)", + "America\/Indiana\/Vevay": "tidssone for den nordamerikanske østkysten (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "tidssone for den nordamerikanske østkysten (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "tidssone for den nordamerikanske østkysten (Winamac, Indiana)", + "America\/Indianapolis": "tidssone for den nordamerikanske østkysten (Indianapolis)", + "America\/Inuvik": "tidssone for Rocky Mountains (USA) (Inuvik)", + "America\/Iqaluit": "tidssone for den nordamerikanske østkysten (Iqaluit)", + "America\/Jamaica": "tidssone for den nordamerikanske østkysten (Jamaica)", + "America\/Jujuy": "argentinsk tid (Jujuy)", + "America\/Juneau": "alaskisk tid (Juneau)", + "America\/Kentucky\/Monticello": "tidssone for den nordamerikanske østkysten (Monticello, Kentucky)", + "America\/Kralendijk": "tidssone for den nordamerikanske atlanterhavskysten (Kralendijk)", + "America\/La_Paz": "boliviansk tid (La Paz)", + "America\/Lima": "peruansk tid (Lima)", + "America\/Los_Angeles": "tidssone for den nordamerikanske Stillehavskysten (Los Angeles)", + "America\/Louisville": "tidssone for den nordamerikanske østkysten (Louisville)", + "America\/Lower_Princes": "tidssone for den nordamerikanske atlanterhavskysten (Lower Prince’s Quarter)", + "America\/Maceio": "tidssone for Brasilia (Maceió)", + "America\/Managua": "tidssone for det sentrale Nord-Amerika (Managua)", + "America\/Manaus": "tidssone for Amazonas (Manaus)", + "America\/Marigot": "tidssone for den nordamerikanske atlanterhavskysten (Marigot)", + "America\/Martinique": "tidssone for den nordamerikanske atlanterhavskysten (Martinique)", + "America\/Matamoros": "tidssone for det sentrale Nord-Amerika (Matamoros)", + "America\/Mazatlan": "tidssone for den meksikanske Stillehavskysten (Mazatlan)", + "America\/Mendoza": "argentinsk tid (Mendoza)", + "America\/Menominee": "tidssone for det sentrale Nord-Amerika (Menominee)", + "America\/Merida": "tidssone for det sentrale Nord-Amerika (Mérida)", + "America\/Metlakatla": "alaskisk tid (Metlakatla)", + "America\/Mexico_City": "tidssone for det sentrale Nord-Amerika (Mexico by)", + "America\/Miquelon": "tidssone for Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "tidssone for den nordamerikanske atlanterhavskysten (Moncton)", + "America\/Monterrey": "tidssone for det sentrale Nord-Amerika (Monterrey)", + "America\/Montevideo": "uruguayansk tid (Montevideo)", + "America\/Montserrat": "tidssone for den nordamerikanske atlanterhavskysten (Montserrat)", + "America\/Nassau": "tidssone for den nordamerikanske østkysten (Nassau)", + "America\/New_York": "tidssone for den nordamerikanske østkysten (New York)", + "America\/Nipigon": "tidssone for den nordamerikanske østkysten (Nipigon)", + "America\/Nome": "alaskisk tid (Nome)", + "America\/Noronha": "tidssone for Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "tidssone for det sentrale Nord-Amerika (Beulah, Nord-Dakota)", + "America\/North_Dakota\/Center": "tidssone for det sentrale Nord-Amerika (Center, Nord-Dakota)", + "America\/North_Dakota\/New_Salem": "tidssone for det sentrale Nord-Amerika (New Salem, Nord-Dakota)", + "America\/Ojinaga": "tidssone for Rocky Mountains (USA) (Ojinaga)", + "America\/Panama": "tidssone for den nordamerikanske østkysten (Panama)", + "America\/Pangnirtung": "tidssone for den nordamerikanske østkysten (Pangnirtung)", + "America\/Paramaribo": "surinamsk tid (Paramaribo)", + "America\/Phoenix": "tidssone for Rocky Mountains (USA) (Phoenix)", + "America\/Port-au-Prince": "tidssone for den nordamerikanske østkysten (Port-au-Prince)", + "America\/Port_of_Spain": "tidssone for den nordamerikanske atlanterhavskysten (Port of Spain)", + "America\/Porto_Velho": "tidssone for Amazonas (Porto Velho)", + "America\/Puerto_Rico": "tidssone for den nordamerikanske atlanterhavskysten (Puerto Rico)", + "America\/Punta_Arenas": "chilensk tid (Punta Arenas)", + "America\/Rainy_River": "tidssone for det sentrale Nord-Amerika (Rainy River)", + "America\/Rankin_Inlet": "tidssone for det sentrale Nord-Amerika (Rankin Inlet)", + "America\/Recife": "tidssone for Brasilia (Recife)", + "America\/Regina": "tidssone for det sentrale Nord-Amerika (Regina)", + "America\/Resolute": "tidssone for det sentrale Nord-Amerika (Resolute)", + "America\/Rio_Branco": "Acre-tid (Rio Branco)", + "America\/Santa_Isabel": "tidssone for nordvestlige Mexico (Santa Isabel)", + "America\/Santarem": "tidssone for Brasilia (Santarém)", + "America\/Santiago": "chilensk tid (Santiago)", + "America\/Santo_Domingo": "tidssone for den nordamerikanske atlanterhavskysten (Santo Domingo)", + "America\/Sao_Paulo": "tidssone for Brasilia (São Paulo)", + "America\/Scoresbysund": "østgrønlandsk tid (Ittoqqortoormiit)", + "America\/Sitka": "alaskisk tid (Sitka)", + "America\/St_Barthelemy": "tidssone for den nordamerikanske atlanterhavskysten (Saint-Barthélemy)", + "America\/St_Johns": "tidssone for Newfoundland (St. John’s)", + "America\/St_Kitts": "tidssone for den nordamerikanske atlanterhavskysten (St. Kitts)", + "America\/St_Lucia": "tidssone for den nordamerikanske atlanterhavskysten (St. Lucia)", + "America\/St_Thomas": "tidssone for den nordamerikanske atlanterhavskysten (St. Thomas)", + "America\/St_Vincent": "tidssone for den nordamerikanske atlanterhavskysten (St. Vincent)", + "America\/Swift_Current": "tidssone for det sentrale Nord-Amerika (Swift Current)", + "America\/Tegucigalpa": "tidssone for det sentrale Nord-Amerika (Tegucigalpa)", + "America\/Thule": "tidssone for den nordamerikanske atlanterhavskysten (Thule)", + "America\/Thunder_Bay": "tidssone for den nordamerikanske østkysten (Thunder Bay)", + "America\/Tijuana": "tidssone for den nordamerikanske Stillehavskysten (Tijuana)", + "America\/Toronto": "tidssone for den nordamerikanske østkysten (Toronto)", + "America\/Tortola": "tidssone for den nordamerikanske atlanterhavskysten (Tortola)", + "America\/Vancouver": "tidssone for den nordamerikanske Stillehavskysten (Vancouver)", + "America\/Whitehorse": "tidssone for den nordamerikanske Stillehavskysten (Whitehorse)", + "America\/Winnipeg": "tidssone for det sentrale Nord-Amerika (Winnipeg)", + "America\/Yakutat": "alaskisk tid (Yakutat)", + "America\/Yellowknife": "tidssone for Rocky Mountains (USA) (Yellowknife)", + "Antarctica\/Casey": "vestaustralsk tid (Casey)", + "Antarctica\/Davis": "tidssone for Davis (Davis)", + "Antarctica\/DumontDUrville": "tidssone for Dumont d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "tidssone for Macquarieøya (Macquarie)", + "Antarctica\/Mawson": "tidssone for Mawson (Mawson)", + "Antarctica\/McMurdo": "newzealandsk tid (McMurdo)", + "Antarctica\/Palmer": "chilensk tid (Palmer)", + "Antarctica\/Rothera": "tidssone for Rothera (Rothera)", + "Antarctica\/Syowa": "tidssone for Syowa (Syowa)", + "Antarctica\/Troll": "Greenwich middeltid (Troll)", + "Antarctica\/Vostok": "tidssone for Vostok (Vostok)", + "Arctic\/Longyearbyen": "sentraleuropeisk tid (Longyearbyen)", + "Asia\/Aden": "arabisk tid (Aden)", + "Asia\/Almaty": "østkasakhstansk tid (Almaty)", + "Asia\/Amman": "østeuropeisk tid (Amman)", + "Asia\/Anadyr": "Russisk (Anadyr) tid (Anadyr)", + "Asia\/Aqtau": "vestkasakhstansk tid (Aktau)", + "Asia\/Aqtobe": "vestkasakhstansk tid (Aqtöbe)", + "Asia\/Ashgabat": "turkmensk tid (Asjkhabad)", + "Asia\/Atyrau": "vestkasakhstansk tid (Atyrau)", + "Asia\/Baghdad": "arabisk tid (Bagdad)", + "Asia\/Bahrain": "arabisk tid (Bahrain)", + "Asia\/Baku": "aserbajdsjansk tid (Baku)", + "Asia\/Bangkok": "indokinesisk tid (Bangkok)", + "Asia\/Beirut": "østeuropeisk tid (Beirut)", + "Asia\/Bishkek": "kirgisisk tid (Bisjkek)", + "Asia\/Brunei": "tidssone for Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "indisk tid (Kolkata)", + "Asia\/Chita": "tidssone for Jakutsk (Tsjita)", + "Asia\/Choibalsan": "tidssone for Tsjojbalsan (Choybalsan)", + "Asia\/Colombo": "indisk tid (Colombo)", + "Asia\/Damascus": "østeuropeisk tid (Damaskus)", + "Asia\/Dhaka": "bangladeshisk tid (Dhaka)", + "Asia\/Dili": "østtimoresisk tid (Dili)", + "Asia\/Dubai": "tidssone for Persiabukta (Dubai)", + "Asia\/Dushanbe": "tadsjikisk tid (Dusjanbe)", + "Asia\/Famagusta": "østeuropeisk tid (Famagusta)", + "Asia\/Gaza": "østeuropeisk tid (Gaza)", + "Asia\/Hebron": "østeuropeisk tid (Hebron)", + "Asia\/Hong_Kong": "tidssone for Hongkong (Hongkong)", + "Asia\/Hovd": "tidssone for Khovd (Hovd)", + "Asia\/Irkutsk": "tidssone for Irkutsk (Irkutsk)", + "Asia\/Jakarta": "vestindonesisk tid (Jakarta)", + "Asia\/Jayapura": "østindonesisk tid (Jajapura)", + "Asia\/Jerusalem": "israelsk tid (Jerusalem)", + "Asia\/Kabul": "afghansk tid (Kabul)", + "Asia\/Kamchatka": "Russisk (Petropavlovsk-Kamtsjatskij) tid (Kamtsjatka)", + "Asia\/Karachi": "pakistansk tid (Karachi)", + "Asia\/Katmandu": "nepalsk tid (Katmandu)", + "Asia\/Khandyga": "tidssone for Jakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "tidssone for Krasnojarsk (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "malaysisk tid (Kuala Lumpur)", + "Asia\/Kuching": "malaysisk tid (Kuching)", + "Asia\/Kuwait": "arabisk tid (Kuwait)", + "Asia\/Macau": "kinesisk tid (Macao)", + "Asia\/Magadan": "tidssone for Magadan (Magadan)", + "Asia\/Makassar": "sentralindonesisk tid (Makassar)", + "Asia\/Manila": "filippinsk tid (Manila)", + "Asia\/Muscat": "tidssone for Persiabukta (Muskat)", + "Asia\/Nicosia": "østeuropeisk tid (Nikosia)", + "Asia\/Novokuznetsk": "tidssone for Krasnojarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "tidssone for Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "tidssone for Omsk (Omsk)", + "Asia\/Oral": "vestkasakhstansk tid (Oral)", + "Asia\/Phnom_Penh": "indokinesisk tid (Phnom Penh)", + "Asia\/Pontianak": "vestindonesisk tid (Pontianak)", + "Asia\/Pyongyang": "koreansk tid (Pyongyang)", + "Asia\/Qatar": "arabisk tid (Qatar)", + "Asia\/Qostanay": "østkasakhstansk tid (Kostanay)", + "Asia\/Qyzylorda": "vestkasakhstansk tid (Kyzylorda)", + "Asia\/Rangoon": "myanmarsk tid (Yangon)", + "Asia\/Riyadh": "arabisk tid (Riyadh)", + "Asia\/Saigon": "indokinesisk tid (Ho Chi Minh-byen)", + "Asia\/Sakhalin": "tidssone for Sakhalin (Sakhalin)", + "Asia\/Samarkand": "usbekisk tid (Samarkand)", + "Asia\/Seoul": "koreansk tid (Seoul)", + "Asia\/Shanghai": "kinesisk tid (Shanghai)", + "Asia\/Singapore": "singaporsk tid (Singapore)", + "Asia\/Srednekolymsk": "tidssone for Magadan (Srednekolymsk)", + "Asia\/Taipei": "tidssone for Taipei (Taipei)", + "Asia\/Tashkent": "usbekisk tid (Tasjkent)", + "Asia\/Tbilisi": "georgisk tid (Tbilisi)", + "Asia\/Tehran": "iransk tid (Teheran)", + "Asia\/Thimphu": "bhutansk tid (Thimpu)", + "Asia\/Tokyo": "japansk tid (Tokyo)", + "Asia\/Ulaanbaatar": "tidssone for Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "tidssone for Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "indokinesisk tid (Vientiane)", + "Asia\/Vladivostok": "tidssone for Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "tidssone for Jakutsk (Jakutsk)", + "Asia\/Yekaterinburg": "tidssone for Jekaterinburg (Jekaterinburg)", + "Asia\/Yerevan": "armensk tid (Jerevan)", + "Atlantic\/Azores": "asorisk tid (Asorene)", + "Atlantic\/Bermuda": "tidssone for den nordamerikanske atlanterhavskysten (Bermuda)", + "Atlantic\/Canary": "vesteuropeisk tid (Kanariøyene)", + "Atlantic\/Cape_Verde": "kappverdisk tid (Kapp Verde)", + "Atlantic\/Faeroe": "vesteuropeisk tid (Færøyene)", + "Atlantic\/Madeira": "vesteuropeisk tid (Madeira)", + "Atlantic\/Reykjavik": "Greenwich middeltid (Reykjavík)", + "Atlantic\/South_Georgia": "tidssone for Sør-Georgia (Sør-Georgia)", + "Atlantic\/St_Helena": "Greenwich middeltid (St. Helena)", + "Atlantic\/Stanley": "tidssone for Falklandsøyene (Stanley)", + "Australia\/Adelaide": "sentralaustralsk tid (Adelaide)", + "Australia\/Brisbane": "østaustralsk tid (Brisbane)", + "Australia\/Broken_Hill": "sentralaustralsk tid (Broken Hill)", + "Australia\/Currie": "østaustralsk tid (Currie)", + "Australia\/Darwin": "sentralaustralsk tid (Darwin)", + "Australia\/Eucla": "vest-sentralaustralsk tid (Eucla)", + "Australia\/Hobart": "østaustralsk tid (Hobart)", + "Australia\/Lindeman": "østaustralsk tid (Lindeman)", + "Australia\/Lord_Howe": "tidssone for Lord Howe-øya (Lord Howe)", + "Australia\/Melbourne": "østaustralsk tid (Melbourne)", + "Australia\/Perth": "vestaustralsk tid (Perth)", + "Australia\/Sydney": "østaustralsk tid (Sydney)", + "CST6CDT": "tidssone for det sentrale Nord-Amerika", + "EST5EDT": "tidssone for den nordamerikanske østkysten", + "Etc\/GMT": "Greenwich middeltid", + "Etc\/UTC": "koordinert universaltid", + "Europe\/Amsterdam": "sentraleuropeisk tid (Amsterdam)", + "Europe\/Andorra": "sentraleuropeisk tid (Andorra)", + "Europe\/Astrakhan": "tidssone for Moskva (Astrakhan)", + "Europe\/Athens": "østeuropeisk tid (Athen)", + "Europe\/Belgrade": "sentraleuropeisk tid (Beograd)", + "Europe\/Berlin": "sentraleuropeisk tid (Berlin)", + "Europe\/Bratislava": "sentraleuropeisk tid (Bratislava)", + "Europe\/Brussels": "sentraleuropeisk tid (Brussel)", + "Europe\/Bucharest": "østeuropeisk tid (București)", + "Europe\/Budapest": "sentraleuropeisk tid (Budapest)", + "Europe\/Busingen": "sentraleuropeisk tid (Büsingen)", + "Europe\/Chisinau": "østeuropeisk tid (Chișinău)", + "Europe\/Copenhagen": "sentraleuropeisk tid (København)", + "Europe\/Dublin": "Greenwich middeltid (Dublin)", + "Europe\/Gibraltar": "sentraleuropeisk tid (Gibraltar)", + "Europe\/Guernsey": "Greenwich middeltid (Guernsey)", + "Europe\/Helsinki": "østeuropeisk tid (Helsingfors)", + "Europe\/Isle_of_Man": "Greenwich middeltid (Man)", + "Europe\/Jersey": "Greenwich middeltid (Jersey)", + "Europe\/Kaliningrad": "østeuropeisk tid (Kaliningrad)", + "Europe\/Kiev": "østeuropeisk tid (Kiev)", + "Europe\/Lisbon": "vesteuropeisk tid (Lisboa)", + "Europe\/Ljubljana": "sentraleuropeisk tid (Ljubljana)", + "Europe\/London": "Greenwich middeltid (London)", + "Europe\/Luxembourg": "sentraleuropeisk tid (Luxemburg)", + "Europe\/Madrid": "sentraleuropeisk tid (Madrid)", + "Europe\/Malta": "sentraleuropeisk tid (Malta)", + "Europe\/Mariehamn": "østeuropeisk tid (Mariehamn)", + "Europe\/Minsk": "tidssone for Moskva (Minsk)", + "Europe\/Monaco": "sentraleuropeisk tid (Monaco)", + "Europe\/Moscow": "tidssone for Moskva (Moskva)", + "Europe\/Oslo": "sentraleuropeisk tid (Oslo)", + "Europe\/Paris": "sentraleuropeisk tid (Paris)", + "Europe\/Podgorica": "sentraleuropeisk tid (Podgorica)", + "Europe\/Prague": "sentraleuropeisk tid (Praha)", + "Europe\/Riga": "østeuropeisk tid (Riga)", + "Europe\/Rome": "sentraleuropeisk tid (Roma)", + "Europe\/Samara": "Russisk (Samara) tid (Samara)", + "Europe\/San_Marino": "sentraleuropeisk tid (San Marino)", + "Europe\/Sarajevo": "sentraleuropeisk tid (Sarajevo)", + "Europe\/Saratov": "tidssone for Moskva (Saratov)", + "Europe\/Simferopol": "tidssone for Moskva (Simferopol)", + "Europe\/Skopje": "sentraleuropeisk tid (Skopje)", + "Europe\/Sofia": "østeuropeisk tid (Sofia)", + "Europe\/Stockholm": "sentraleuropeisk tid (Stockholm)", + "Europe\/Tallinn": "østeuropeisk tid (Tallinn)", + "Europe\/Tirane": "sentraleuropeisk tid (Tirana)", + "Europe\/Ulyanovsk": "tidssone for Moskva (Uljanovsk)", + "Europe\/Uzhgorod": "østeuropeisk tid (Uzjhorod)", + "Europe\/Vaduz": "sentraleuropeisk tid (Vaduz)", + "Europe\/Vatican": "sentraleuropeisk tid (Vatikanstaten)", + "Europe\/Vienna": "sentraleuropeisk tid (Wien)", + "Europe\/Vilnius": "østeuropeisk tid (Vilnius)", + "Europe\/Volgograd": "tidssone for Volgograd (Volgograd)", + "Europe\/Warsaw": "sentraleuropeisk tid (Warszawa)", + "Europe\/Zagreb": "sentraleuropeisk tid (Zagreb)", + "Europe\/Zaporozhye": "østeuropeisk tid (Zaporizjzja)", + "Europe\/Zurich": "sentraleuropeisk tid (Zürich)", + "Indian\/Antananarivo": "østafrikansk tid (Antananarivo)", + "Indian\/Chagos": "tidssone for Indiahavet (Chagos)", + "Indian\/Christmas": "tidssone for Christmasøya (Christmasøya)", + "Indian\/Cocos": "tidssone for Kokosøyene (Kokosøyene)", + "Indian\/Comoro": "østafrikansk tid (Komorene)", + "Indian\/Kerguelen": "tidssone for De franske sørterritorier (Kerguelen)", + "Indian\/Mahe": "seychellisk tid (Mahé)", + "Indian\/Maldives": "maldivisk tid (Maldivene)", + "Indian\/Mauritius": "mauritisk tid (Mauritius)", + "Indian\/Mayotte": "østafrikansk tid (Mayotte)", + "Indian\/Reunion": "tidssone for Réunion (Réunion)", + "MST7MDT": "tidssone for Rocky Mountains (USA)", + "PST8PDT": "tidssone for den nordamerikanske Stillehavskysten", + "Pacific\/Apia": "tidssone for Apia (Apia)", + "Pacific\/Auckland": "newzealandsk tid (Auckland)", + "Pacific\/Bougainville": "papuansk tid (Bougainville)", + "Pacific\/Chatham": "tidssone for Chatham (Chatham)", + "Pacific\/Easter": "tidssone for Påskeøya (Påskeøya)", + "Pacific\/Efate": "vanuatisk tid (Efate)", + "Pacific\/Enderbury": "tidssone for Phoenixøyene (Enderbury)", + "Pacific\/Fakaofo": "tidssone for Tokelau (Fakaofo)", + "Pacific\/Fiji": "fijiansk tid (Fiji)", + "Pacific\/Funafuti": "tuvalsk tid (Funafuti)", + "Pacific\/Galapagos": "tidssone for Galápagosøyene (Galápagosøyene)", + "Pacific\/Gambier": "tidssone for Gambier (Gambier)", + "Pacific\/Guadalcanal": "salomonsk tid (Guadalcanal)", + "Pacific\/Guam": "tidssone for Chamorro (Guam)", + "Pacific\/Honolulu": "tidssone for Hawaii og Aleutene (Honolulu)", + "Pacific\/Johnston": "tidssone for Hawaii og Aleutene (Johnston)", + "Pacific\/Kiritimati": "tidssone for Linjeøyene (Kiritimati)", + "Pacific\/Kosrae": "tidssone for Kosrae (Kosrae)", + "Pacific\/Kwajalein": "marshallesisk tid (Kwajalein)", + "Pacific\/Majuro": "marshallesisk tid (Majuro)", + "Pacific\/Marquesas": "tidssone for Marquesasøyene (Marquesas)", + "Pacific\/Midway": "samoansk tid (Midway)", + "Pacific\/Nauru": "naurisk tid (Nauru)", + "Pacific\/Niue": "tidssone for Niue (Niue)", + "Pacific\/Norfolk": "tidssone for Norfolkøya (Norfolkøya)", + "Pacific\/Noumea": "kaledonsk tid (Nouméa)", + "Pacific\/Pago_Pago": "samoansk tid (Pago Pago)", + "Pacific\/Palau": "palauisk tid (Palau)", + "Pacific\/Pitcairn": "tidssone for Pitcairn (Pitcairn)", + "Pacific\/Ponape": "tidssone for Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "papuansk tid (Port Moresby)", + "Pacific\/Rarotonga": "tidssone for Cookøyene (Rarotonga)", + "Pacific\/Saipan": "tidssone for Chamorro (Saipan)", + "Pacific\/Tahiti": "tahitisk tid (Tahiti)", + "Pacific\/Tarawa": "tidssone for Gilbertøyene (Tarawa)", + "Pacific\/Tongatapu": "tongansk tid (Tongatapu)", + "Pacific\/Truk": "tidssone for Chuukøyene (Chuuk)", + "Pacific\/Wake": "tidssone for Wake Island (Wake)", + "Pacific\/Wallis": "tidssone for Wallis- og Futunaøyene (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ne.json b/src/Symfony/Component/Intl/Resources/data/timezones/ne.json new file mode 100644 index 0000000000000..0460101e02c5f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ne.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ग्रीनविच मिन समय (अविड्जान)", + "Africa\/Accra": "ग्रीनविच मिन समय (अक्रा)", + "Africa\/Addis_Ababa": "पूर्वी अफ्रिकी समय (एड्डिस आबाबा)", + "Africa\/Algiers": "केन्द्रीय युरोपेली समय (अल्जियर्स)", + "Africa\/Asmera": "पूर्वी अफ्रिकी समय (आस्मारा)", + "Africa\/Bamako": "ग्रीनविच मिन समय (बोमाको)", + "Africa\/Bangui": "पश्चिम अफ्रिकी समय (बाङ्गुवी)", + "Africa\/Banjul": "ग्रीनविच मिन समय (बन्जुल)", + "Africa\/Bissau": "ग्रीनविच मिन समय (बिसाउ)", + "Africa\/Blantyre": "केन्द्रीय अफ्रिकी समय (ब्लान्टायर)", + "Africa\/Brazzaville": "पश्चिम अफ्रिकी समय (ब्राजाभिल्ले)", + "Africa\/Bujumbura": "केन्द्रीय अफ्रिकी समय (बुजुम्बुरा)", + "Africa\/Cairo": "पूर्वी युरोपेली समय (काइरो)", + "Africa\/Casablanca": "पश्चिमी युरोपेली समय (कासाब्लान्का)", + "Africa\/Ceuta": "केन्द्रीय युरोपेली समय (सेउटा)", + "Africa\/Conakry": "ग्रीनविच मिन समय (कोनाक्री)", + "Africa\/Dakar": "ग्रीनविच मिन समय (डाकार)", + "Africa\/Dar_es_Salaam": "पूर्वी अफ्रिकी समय (डार एस् सलाम)", + "Africa\/Djibouti": "पूर्वी अफ्रिकी समय (जिबौंटी)", + "Africa\/Douala": "पश्चिम अफ्रिकी समय (डोउआला)", + "Africa\/El_Aaiun": "पश्चिमी युरोपेली समय (एल् आइयुन)", + "Africa\/Freetown": "ग्रीनविच मिन समय (फ्रिटाउन)", + "Africa\/Gaborone": "केन्द्रीय अफ्रिकी समय (गावोरोन)", + "Africa\/Harare": "केन्द्रीय अफ्रिकी समय (हरारे)", + "Africa\/Johannesburg": "दक्षिण अफ्रिकी समय (जोहानेसवर्ग)", + "Africa\/Juba": "पूर्वी अफ्रिकी समय (जुबा)", + "Africa\/Kampala": "पूर्वी अफ्रिकी समय (काम्पाला)", + "Africa\/Khartoum": "केन्द्रीय अफ्रिकी समय (खार्टउम)", + "Africa\/Kigali": "केन्द्रीय अफ्रिकी समय (किगाली)", + "Africa\/Kinshasa": "पश्चिम अफ्रिकी समय (किन्शासा)", + "Africa\/Lagos": "पश्चिम अफ्रिकी समय (लागोस)", + "Africa\/Libreville": "पश्चिम अफ्रिकी समय (लिब्रेभिल्ले)", + "Africa\/Lome": "ग्रीनविच मिन समय (लोम)", + "Africa\/Luanda": "पश्चिम अफ्रिकी समय (लुवान्डा)", + "Africa\/Lubumbashi": "केन्द्रीय अफ्रिकी समय (लुबुम्बासी)", + "Africa\/Lusaka": "केन्द्रीय अफ्रिकी समय (लुसाका)", + "Africa\/Malabo": "पश्चिम अफ्रिकी समय (मालाबो)", + "Africa\/Maputo": "केन्द्रीय अफ्रिकी समय (मापुतो)", + "Africa\/Maseru": "दक्षिण अफ्रिकी समय (मासेरू)", + "Africa\/Mbabane": "दक्षिण अफ्रिकी समय (एमबाबेन)", + "Africa\/Mogadishu": "पूर्वी अफ्रिकी समय (मोगाडिशु)", + "Africa\/Monrovia": "ग्रीनविच मिन समय (मोन्रोभिया)", + "Africa\/Nairobi": "पूर्वी अफ्रिकी समय (नाइरोबी)", + "Africa\/Ndjamena": "पश्चिम अफ्रिकी समय (एन्‌जामेना)", + "Africa\/Niamey": "पश्चिम अफ्रिकी समय (नायमे)", + "Africa\/Nouakchott": "ग्रीनविच मिन समय (नोउआकचोट)", + "Africa\/Ouagadougou": "ग्रीनविच मिन समय (औआगाडौगौ)", + "Africa\/Porto-Novo": "पश्चिम अफ्रिकी समय (पोर्टो-नोभो)", + "Africa\/Sao_Tome": "ग्रीनविच मिन समय (साओ टोमे)", + "Africa\/Tripoli": "पूर्वी युरोपेली समय (त्रिपोली)", + "Africa\/Tunis": "केन्द्रीय युरोपेली समय (टुनिस)", + "Africa\/Windhoek": "केन्द्रीय अफ्रिकी समय (विन्डहोएक)", + "America\/Adak": "हवाई-एलुटियन समय (आडाक)", + "America\/Anchorage": "अलस्काको समय (एङ्कोरेज)", + "America\/Anguilla": "एट्लान्टिक समय (एङ्ग्विल्ला)", + "America\/Antigua": "एट्लान्टिक समय (एन्टिगुवा)", + "America\/Araguaina": "ब्राजिलीया समय (आरागुवाना)", + "America\/Argentina\/La_Rioja": "अर्जेनटिनी समय (ला रियोजा)", + "America\/Argentina\/Rio_Gallegos": "अर्जेनटिनी समय (रियो ग्यालेगोस)", + "America\/Argentina\/Salta": "अर्जेनटिनी समय (साल्टा)", + "America\/Argentina\/San_Juan": "अर्जेनटिनी समय (सान जुवान)", + "America\/Argentina\/San_Luis": "पश्चिमी अर्जेनटिनी समय (सान लुइस)", + "America\/Argentina\/Tucuman": "अर्जेनटिनी समय (टुकुमान)", + "America\/Argentina\/Ushuaia": "अर्जेनटिनी समय (उशुआइआ)", + "America\/Aruba": "एट्लान्टिक समय (अरुबा)", + "America\/Asuncion": "पाराग्वे समय (असन्सियन)", + "America\/Bahia": "ब्राजिलीया समय (बाहिया)", + "America\/Bahia_Banderas": "केन्द्रीय समय (बाहिया बान्डेराश)", + "America\/Barbados": "एट्लान्टिक समय (बार्बाडोस)", + "America\/Belem": "ब्राजिलीया समय (बेलेम)", + "America\/Belize": "केन्द्रीय समय (बेलिज)", + "America\/Blanc-Sablon": "एट्लान्टिक समय (ब्लान्क-साब्लोन)", + "America\/Boa_Vista": "एमाजोन समय (बोआ भिष्टा)", + "America\/Bogota": "कोलम्बियाली समय (बोगोटा)", + "America\/Boise": "हिमाली समय (बोइज)", + "America\/Buenos_Aires": "अर्जेनटिनी समय (ब्यनेश आयर्स)", + "America\/Cambridge_Bay": "हिमाली समय (क्याम्ब्रिज बे)", + "America\/Campo_Grande": "एमाजोन समय (क्याम्पो ग्रान्डे)", + "America\/Cancun": "पूर्वी समय (कानकुन)", + "America\/Caracas": "भेनेज्युएला समय (काराकास)", + "America\/Catamarca": "अर्जेनटिनी समय (कातामार्का)", + "America\/Cayenne": "फ्रेन्च ग्वाना समय (कायेन्ने)", + "America\/Cayman": "पूर्वी समय (केम्यान)", + "America\/Chicago": "केन्द्रीय समय (शिकागो)", + "America\/Chihuahua": "मेक्सिकन प्यासिफिक समय (चिहुवाहुवा)", + "America\/Coral_Harbour": "पूर्वी समय (एटिकोकान)", + "America\/Cordoba": "अर्जेनटिनी समय (कोरडोवा)", + "America\/Costa_Rica": "केन्द्रीय समय (कोष्टा रिका)", + "America\/Creston": "हिमाली समय (क्रेस्टन)", + "America\/Cuiaba": "एमाजोन समय (क्युइआबा)", + "America\/Curacao": "एट्लान्टिक समय (कुराकाओ)", + "America\/Danmarkshavn": "ग्रीनविच मिन समय (डान्मार्कशाभन)", + "America\/Dawson": "प्यासिफिक समय (डसन)", + "America\/Dawson_Creek": "हिमाली समय (डसन क्रिक)", + "America\/Denver": "हिमाली समय (डेन्भर)", + "America\/Detroit": "पूर्वी समय (डिट्रोइट)", + "America\/Dominica": "एट्लान्टिक समय (डोमिनिका)", + "America\/Edmonton": "हिमाली समय (एड्मोन्टन)", + "America\/El_Salvador": "केन्द्रीय समय (एल् साल्भाडोर)", + "America\/Fort_Nelson": "हिमाली समय (फोर्ट नेल्सन)", + "America\/Fortaleza": "ब्राजिलीया समय (फोर्टालेजा)", + "America\/Glace_Bay": "एट्लान्टिक समय (ग्लेस बे)", + "America\/Godthab": "पश्चिमी ग्रीनल्यान्डको समय (नूक)", + "America\/Goose_Bay": "एट्लान्टिक समय (गुज बे)", + "America\/Grand_Turk": "पूर्वी समय (ग्रान्ड टर्क)", + "America\/Grenada": "एट्लान्टिक समय (ग्रेनाडा)", + "America\/Guadeloupe": "एट्लान्टिक समय (ग्वाडेलुप)", + "America\/Guatemala": "केन्द्रीय समय (ग्वाटेमाला)", + "America\/Guayaquil": "ईक्वोडोर समय (गुयाक्विल)", + "America\/Guyana": "गुयाना समय (गुयाना)", + "America\/Halifax": "एट्लान्टिक समय (ह्यालिफ्याक्स)", + "America\/Havana": "क्यूबाको समय (हभाना)", + "America\/Hermosillo": "मेक्सिकन प्यासिफिक समय (हेर्मोसिल्लो)", + "America\/Indiana\/Knox": "केन्द्रीय समय (नोक्स इन्डियाना)", + "America\/Indiana\/Marengo": "पूर्वी समय (मारेन्गो, इन्डियाना)", + "America\/Indiana\/Petersburg": "पूर्वी समय (पिटर्सबर्ग, इन्डियाना)", + "America\/Indiana\/Tell_City": "केन्द्रीय समय (टेल सिटी, इन्डियाना)", + "America\/Indiana\/Vevay": "पूर्वी समय (भेभे, इन्डियाना)", + "America\/Indiana\/Vincennes": "पूर्वी समय (भिन्सेन्स)", + "America\/Indiana\/Winamac": "पूर्वी समय (विनामाक, इन्डियाना)", + "America\/Indianapolis": "पूर्वी समय (इन्डियानापोलिस)", + "America\/Inuvik": "हिमाली समय (इनुभिक)", + "America\/Iqaluit": "पूर्वी समय (इक्वालुइट)", + "America\/Jamaica": "पूर्वी समय (जमाइका)", + "America\/Jujuy": "अर्जेनटिनी समय (जुजुई)", + "America\/Juneau": "अलस्काको समय (जुनिउ)", + "America\/Kentucky\/Monticello": "पूर्वी समय (मोन्टिसेल्लो,केन्टकी)", + "America\/Kralendijk": "एट्लान्टिक समय (कालेन्देजिक)", + "America\/La_Paz": "बोलिभिया समय (ला पाज)", + "America\/Lima": "पेरु समय (लिमा)", + "America\/Los_Angeles": "प्यासिफिक समय (लस् एन्जेलस)", + "America\/Louisville": "पूर्वी समय (लुइसभिल्ले)", + "America\/Lower_Princes": "एट्लान्टिक समय (लोअर प्रिन्स्स क्वार्टर)", + "America\/Maceio": "ब्राजिलीया समय (मासेइओ)", + "America\/Managua": "केन्द्रीय समय (मानागुवा)", + "America\/Manaus": "एमाजोन समय (मानाउस)", + "America\/Marigot": "एट्लान्टिक समय (म्यारिगट)", + "America\/Martinique": "एट्लान्टिक समय (मार्टिनिक)", + "America\/Matamoros": "केन्द्रीय समय (माट्तामोरोस्)", + "America\/Mazatlan": "मेक्सिकन प्यासिफिक समय (माजाट्लान)", + "America\/Mendoza": "अर्जेनटिनी समय (मेन्डोजा)", + "America\/Menominee": "केन्द्रीय समय (मेनोमिनी)", + "America\/Merida": "केन्द्रीय समय (मेरिडा)", + "America\/Metlakatla": "अलस्काको समय (मेट्लाक्टला)", + "America\/Mexico_City": "केन्द्रीय समय (मेक्सिको सिटी)", + "America\/Miquelon": "सेन्ट पियर्रे र मिक्युलोनको समय (मिक्विलन)", + "America\/Moncton": "एट्लान्टिक समय (मोन्कटन)", + "America\/Monterrey": "केन्द्रीय समय (मोन्टेर्रे)", + "America\/Montevideo": "उरुग्वे समय (मोन्टेभिडियो)", + "America\/Montserrat": "एट्लान्टिक समय (मन्टसेर्राट)", + "America\/Nassau": "पूर्वी समय (नास्साउ)", + "America\/New_York": "पूर्वी समय (न्युयोर्क)", + "America\/Nipigon": "पूर्वी समय (निपिगन)", + "America\/Nome": "अलस्काको समय (नोम)", + "America\/Noronha": "फर्नान्डो डे नोरोन्हा समय (नोरोन्हा)", + "America\/North_Dakota\/Beulah": "केन्द्रीय समय (बेउला, उत्तर डाकोटा)", + "America\/North_Dakota\/Center": "केन्द्रीय समय (उत्तर डाकोटा, केन्द्र)", + "America\/North_Dakota\/New_Salem": "केन्द्रीय समय (नयाँ सालेम, उत्तर डाकोटा)", + "America\/Ojinaga": "हिमाली समय (ओजिनागा)", + "America\/Panama": "पूर्वी समय (पानामा)", + "America\/Pangnirtung": "पूर्वी समय (पाङ्निरतुङ)", + "America\/Paramaribo": "सुरिनामा समय (पारामारिवो)", + "America\/Phoenix": "हिमाली समय (फिनिक्स)", + "America\/Port-au-Prince": "पूर्वी समय (पोर्ट-अउ-प्रिन्स)", + "America\/Port_of_Spain": "एट्लान्टिक समय (पोर्ट अफ् स्पेन)", + "America\/Porto_Velho": "एमाजोन समय (पोर्टो भेल्हो)", + "America\/Puerto_Rico": "एट्लान्टिक समय (प्युर्टो रिको)", + "America\/Punta_Arenas": "चिली समय (पुन्टा अरिनाज)", + "America\/Rainy_River": "केन्द्रीय समय (रेनिरिभर)", + "America\/Rankin_Inlet": "केन्द्रीय समय (रान्किन इन्लेट)", + "America\/Recife": "ब्राजिलीया समय (रिसाइफ)", + "America\/Regina": "केन्द्रीय समय (रेजिना)", + "America\/Resolute": "केन्द्रीय समय (रिजोलुट)", + "America\/Santa_Isabel": "उत्तर पश्चिम मेक्सिको समय (सान्टा ईसाबेल)", + "America\/Santarem": "ब्राजिलीया समय (सान्टारेम)", + "America\/Santiago": "चिली समय (सान्टिआगो)", + "America\/Santo_Domingo": "एट्लान्टिक समय (सान्टो डोमिङ्गो)", + "America\/Sao_Paulo": "ब्राजिलीया समय (साओ पाउलो)", + "America\/Scoresbysund": "पूर्वी ग्रीनल्यान्डको समय (ईट्टोक्कोरटूर्मिट)", + "America\/Sitka": "अलस्काको समय (सिट्का)", + "America\/St_Barthelemy": "एट्लान्टिक समय (सेन्ट बार्थेलेमी)", + "America\/St_Johns": "न्यूफाउन्डल्यान्डको समय (सेन्ट जोन्स)", + "America\/St_Kitts": "एट्लान्टिक समय (सेन्ट् किट्स)", + "America\/St_Lucia": "एट्लान्टिक समय (सेन्ट लुसिया)", + "America\/St_Thomas": "एट्लान्टिक समय (सेन्ट थोमस)", + "America\/St_Vincent": "एट्लान्टिक समय (सेन्ट भिन्सेन्ट)", + "America\/Swift_Current": "केन्द्रीय समय (स्विफ्ट करेन्ट)", + "America\/Tegucigalpa": "केन्द्रीय समय (टेगुसिगाल्पा)", + "America\/Thule": "एट्लान्टिक समय (थुले)", + "America\/Thunder_Bay": "पूर्वी समय (थण्डर बे)", + "America\/Tijuana": "प्यासिफिक समय (तिजुआना)", + "America\/Toronto": "पूर्वी समय (टोरोण्टो)", + "America\/Tortola": "एट्लान्टिक समय (टार्टोला)", + "America\/Vancouver": "प्यासिफिक समय (भ्यानकोभर)", + "America\/Whitehorse": "प्यासिफिक समय (ह्वाइटहर्स)", + "America\/Winnipeg": "केन्द्रीय समय (विन्निपेग)", + "America\/Yakutat": "अलस्काको समय (याकुटाट)", + "America\/Yellowknife": "हिमाली समय (येल्लोनाइफ)", + "Antarctica\/Casey": "पश्चिमी अस्ट्रेलिया समय (केजे)", + "Antarctica\/Davis": "डेभिस समय (डेभिस)", + "Antarctica\/DumontDUrville": "डुमोन्ट-डी‘ उर्भिले समय (दुमोन्ट डि उर्भेल्ले)", + "Antarctica\/Macquarie": "माक्वेरी टापु समय (मक्वारिई)", + "Antarctica\/Mawson": "म्वसन समय (माउसन)", + "Antarctica\/McMurdo": "न्यूजिल्यान्ड समय (माकमुर्डो)", + "Antarctica\/Palmer": "चिली समय (पाल्मेर)", + "Antarctica\/Rothera": "रोथेरा समय (रोथेरा)", + "Antarctica\/Syowa": "स्योवा समय (सिओआ)", + "Antarctica\/Troll": "ग्रीनविच मिन समय (ट्रोल)", + "Antarctica\/Vostok": "भास्टोक समय (भास्टोक)", + "Arctic\/Longyearbyen": "केन्द्रीय युरोपेली समय (लङयिअरबाइएन)", + "Asia\/Aden": "अरबी समय (एडेन)", + "Asia\/Almaty": "पूर्वी काजकस्तान समय (आल्माटी)", + "Asia\/Amman": "पूर्वी युरोपेली समय (आम्मान)", + "Asia\/Aqtau": "पश्चिम काजकस्तान समय (आक्टाउ)", + "Asia\/Aqtobe": "पश्चिम काजकस्तान समय (आक्टोब)", + "Asia\/Ashgabat": "तुर्कमेनिस्तान समय (अस्काबाट)", + "Asia\/Atyrau": "पश्चिम काजकस्तान समय (अटिराउ)", + "Asia\/Baghdad": "अरबी समय (बगदाद)", + "Asia\/Bahrain": "अरबी समय (बहराईन)", + "Asia\/Baku": "अजरबैजान समय (बाकु)", + "Asia\/Bangkok": "इन्डोचाइना समय (बैंकक)", + "Asia\/Beirut": "पूर्वी युरोपेली समय (बेईरुट)", + "Asia\/Bishkek": "किर्गिस्तान समय (बिसकेक्)", + "Asia\/Brunei": "ब्रुनाइ दारूस्सलम समय (ब्रुनाइ)", + "Asia\/Calcutta": "भारतीय मानक समय (कोलकाता)", + "Asia\/Chita": "याकुस्ट समय (चिता)", + "Asia\/Choibalsan": "चोइबाल्सन समय (चोइबाल्सान)", + "Asia\/Colombo": "भारतीय मानक समय (कोलम्बो)", + "Asia\/Damascus": "पूर्वी युरोपेली समय (दामास्कस्)", + "Asia\/Dhaka": "बंगलादेशी समय (ढाका)", + "Asia\/Dili": "पूर्वी टिमोर समय (दिल्ली)", + "Asia\/Dubai": "खाडी मानक समय (दुबही)", + "Asia\/Dushanbe": "ताजिकस्तान समय (दस्सान्बे)", + "Asia\/Famagusta": "पूर्वी युरोपेली समय (फामागुस्ता)", + "Asia\/Gaza": "पूर्वी युरोपेली समय (गाजा)", + "Asia\/Hebron": "पूर्वी युरोपेली समय (हिब्रोन)", + "Asia\/Hong_Kong": "हङकङ समय (हङकङ)", + "Asia\/Hovd": "होब्ड समय (होभ्ड)", + "Asia\/Irkutsk": "ईर्कुट्स्क समय (इर्कुत्स्क)", + "Asia\/Jakarta": "पश्चिमी इन्डोनेशिया समय (जाकार्ता)", + "Asia\/Jayapura": "पूर्वी इन्डोनेशिया समय (जयापुरा)", + "Asia\/Jerusalem": "इजरायल समय (जेरुसलेम)", + "Asia\/Kabul": "अफगानिस्तान समय (काबुल)", + "Asia\/Karachi": "पाकिस्तानी समय (कराची)", + "Asia\/Katmandu": "नेपाली समय (काठमाण्डौं)", + "Asia\/Khandyga": "याकुस्ट समय (खान्दिगा)", + "Asia\/Krasnoyarsk": "क्रासनोयार्क समय (क्रास्नोयार्स्क)", + "Asia\/Kuala_Lumpur": "मलेसिया समय (कुआ लाम्पुर)", + "Asia\/Kuching": "मलेसिया समय (कुचिङ)", + "Asia\/Kuwait": "अरबी समय (कुवेत)", + "Asia\/Macau": "चीन समय (मकाउ)", + "Asia\/Magadan": "मागादान समय (मागाडान)", + "Asia\/Makassar": "केन्द्रीय इन्डोनेशिया समय (माकास्सार)", + "Asia\/Manila": "फिलिपिनी समय (मनिला)", + "Asia\/Muscat": "खाडी मानक समय (मस्क्याट)", + "Asia\/Nicosia": "पूर्वी युरोपेली समय (निकोसिया)", + "Asia\/Novokuznetsk": "क्रासनोयार्क समय (नेभोकुजनेस्क)", + "Asia\/Novosibirsk": "नोभोसिविर्स्क समय (नोबोसिबिर्स्क)", + "Asia\/Omsk": "ओम्स्क समय (ओम्स्क)", + "Asia\/Oral": "पश्चिम काजकस्तान समय (ओरल)", + "Asia\/Phnom_Penh": "इन्डोचाइना समय (फेनोम फेन)", + "Asia\/Pontianak": "पश्चिमी इन्डोनेशिया समय (पोन्टिआनाक)", + "Asia\/Pyongyang": "कोरियाली समय (प्योङयाङ)", + "Asia\/Qatar": "अरबी समय (कतार)", + "Asia\/Qostanay": "पूर्वी काजकस्तान समय (Qostanay)", + "Asia\/Qyzylorda": "पश्चिम काजकस्तान समय (किजिलोर्डा)", + "Asia\/Rangoon": "म्यानमार समय (रान्गुन)", + "Asia\/Riyadh": "अरबी समय (रियाद)", + "Asia\/Saigon": "इन्डोचाइना समय (हो ची मिन्ह शहर)", + "Asia\/Sakhalin": "साखालिन समय (साखालिन)", + "Asia\/Samarkand": "उज्बेकिस्तान समय (समारकण्ड)", + "Asia\/Seoul": "कोरियाली समय (सिओल)", + "Asia\/Shanghai": "चीन समय (सान्घाई)", + "Asia\/Singapore": "सिंगापुर मानक समय (सिंगापुर)", + "Asia\/Srednekolymsk": "मागादान समय (स्रेद्निकोलिम्स्क)", + "Asia\/Taipei": "ताइपेइ समय (ताईपे)", + "Asia\/Tashkent": "उज्बेकिस्तान समय (तास्केन्ट)", + "Asia\/Tbilisi": "जर्जिया समय (तिबिलिसी)", + "Asia\/Tehran": "इरानी समय (तेहेरान)", + "Asia\/Thimphu": "भुटानी समय (थिम्पु)", + "Asia\/Tokyo": "जापान समय (टोकियो)", + "Asia\/Ulaanbaatar": "उलान बाटोर समय (उलानबटार)", + "Asia\/Ust-Nera": "भ्लादिभास्टोक समय (उस्ट-नेरा)", + "Asia\/Vientiane": "इन्डोचाइना समय (भियन्तिन)", + "Asia\/Vladivostok": "भ्लादिभास्टोक समय (भ्लाडिभास्टोक)", + "Asia\/Yakutsk": "याकुस्ट समय (याकुत्स्क)", + "Asia\/Yekaterinburg": "येकाटेरिनबर्ग समय (एकटरिनबुर्ग)", + "Asia\/Yerevan": "अर्मेनिया समय (येरेभान)", + "Atlantic\/Azores": "एजोरेस् समय (आजोर्स)", + "Atlantic\/Bermuda": "एट्लान्टिक समय (बर्मुडा)", + "Atlantic\/Canary": "पश्चिमी युरोपेली समय (क्यानारी)", + "Atlantic\/Cape_Verde": "केप भर्दे समय (केप भर्डे)", + "Atlantic\/Faeroe": "पश्चिमी युरोपेली समय (फारोइ)", + "Atlantic\/Madeira": "पश्चिमी युरोपेली समय (माडेइरा)", + "Atlantic\/Reykjavik": "ग्रीनविच मिन समय (रेक्जाभिक)", + "Atlantic\/South_Georgia": "दक्षिण जर्जिया समय (दक्षिण जर्जिया)", + "Atlantic\/St_Helena": "ग्रीनविच मिन समय (सेन्ट हेलेना)", + "Atlantic\/Stanley": "फल्कल्यान्ड टापू समय (स्ट्यान्ली)", + "Australia\/Adelaide": "केन्द्रीय अस्ट्रेलिया समय (एडेलेड)", + "Australia\/Brisbane": "पूर्वी अस्ट्रेलिया समय (ब्रिस्बेन)", + "Australia\/Broken_Hill": "केन्द्रीय अस्ट्रेलिया समय (ब्रोकन हिल)", + "Australia\/Currie": "पूर्वी अस्ट्रेलिया समय (क्युरी)", + "Australia\/Darwin": "केन्द्रीय अस्ट्रेलिया समय (डार्विन)", + "Australia\/Eucla": "केन्द्रीय पश्चिमी अस्ट्रेलिया समय (इयुक्ला)", + "Australia\/Hobart": "पूर्वी अस्ट्रेलिया समय (होभार्ट)", + "Australia\/Lindeman": "पूर्वी अस्ट्रेलिया समय (लिन्डेम्यान)", + "Australia\/Lord_Howe": "लर्ड हावे समय (लर्ड होवे)", + "Australia\/Melbourne": "पूर्वी अस्ट्रेलिया समय (मेल्बर्न)", + "Australia\/Perth": "पश्चिमी अस्ट्रेलिया समय (पर्थ)", + "Australia\/Sydney": "पूर्वी अस्ट्रेलिया समय (सिड्नी)", + "CST6CDT": "केन्द्रीय समय", + "EST5EDT": "पूर्वी समय", + "Etc\/GMT": "ग्रीनविच मिन समय", + "Etc\/UTC": "समन्वित विश्व समय", + "Europe\/Amsterdam": "केन्द्रीय युरोपेली समय (एम्स्ट्र्डम)", + "Europe\/Andorra": "केन्द्रीय युरोपेली समय (आन्डोर्रा)", + "Europe\/Astrakhan": "मस्को समय (अस्त्रखान)", + "Europe\/Athens": "पूर्वी युरोपेली समय (एथेन्स)", + "Europe\/Belgrade": "केन्द्रीय युरोपेली समय (बेलग्रेड)", + "Europe\/Berlin": "केन्द्रीय युरोपेली समय (बर्लिन)", + "Europe\/Bratislava": "केन्द्रीय युरोपेली समय (ब्राटिस्लाभा)", + "Europe\/Brussels": "केन्द्रीय युरोपेली समय (ब्रसेल्स)", + "Europe\/Bucharest": "पूर्वी युरोपेली समय (वुचारेस्ट)", + "Europe\/Budapest": "केन्द्रीय युरोपेली समय (बुडापेस्ट)", + "Europe\/Busingen": "केन्द्रीय युरोपेली समय (बुसिन्नगन)", + "Europe\/Chisinau": "पूर्वी युरोपेली समय (चिसिनाउ)", + "Europe\/Copenhagen": "केन्द्रीय युरोपेली समय (कोपेनह्यागन)", + "Europe\/Dublin": "ग्रीनविच मिन समय (डब्लिन)", + "Europe\/Gibraltar": "केन्द्रीय युरोपेली समय (जिब्राल्टार)", + "Europe\/Guernsey": "ग्रीनविच मिन समय (गुएर्नसे)", + "Europe\/Helsinki": "पूर्वी युरोपेली समय (हेल्सिन्की)", + "Europe\/Isle_of_Man": "ग्रीनविच मिन समय (इजल अफ् म्यान)", + "Europe\/Jersey": "ग्रीनविच मिन समय (जर्सी)", + "Europe\/Kaliningrad": "पूर्वी युरोपेली समय (कालिनिनग्राद)", + "Europe\/Kiev": "पूर्वी युरोपेली समय (किभ)", + "Europe\/Lisbon": "पश्चिमी युरोपेली समय (लिस्बोन)", + "Europe\/Ljubljana": "केन्द्रीय युरोपेली समय (लजुबिजाना)", + "Europe\/London": "ग्रीनविच मिन समय (लण्डन)", + "Europe\/Luxembourg": "केन्द्रीय युरोपेली समय (लक्जेम्वर्ग)", + "Europe\/Madrid": "केन्द्रीय युरोपेली समय (म्याड्रिड)", + "Europe\/Malta": "केन्द्रीय युरोपेली समय (माल्टा)", + "Europe\/Mariehamn": "पूर्वी युरोपेली समय (म्यारिह्याम्न)", + "Europe\/Minsk": "मस्को समय (मिन्स्क)", + "Europe\/Monaco": "केन्द्रीय युरोपेली समय (मोनाको)", + "Europe\/Moscow": "मस्को समय (मस्को)", + "Europe\/Oslo": "केन्द्रीय युरोपेली समय (ओस्लो)", + "Europe\/Paris": "केन्द्रीय युरोपेली समय (पेरिस)", + "Europe\/Podgorica": "केन्द्रीय युरोपेली समय (पड्गोरिका)", + "Europe\/Prague": "केन्द्रीय युरोपेली समय (प्राग)", + "Europe\/Riga": "पूर्वी युरोपेली समय (रिगा)", + "Europe\/Rome": "केन्द्रीय युरोपेली समय (रोम)", + "Europe\/San_Marino": "केन्द्रीय युरोपेली समय (सान मारिनो)", + "Europe\/Sarajevo": "केन्द्रीय युरोपेली समय (साराजेभो)", + "Europe\/Saratov": "मस्को समय (साराटोभ)", + "Europe\/Simferopol": "मस्को समय (सिम्फेरोपोल)", + "Europe\/Skopje": "केन्द्रीय युरोपेली समय (स्कोपजे)", + "Europe\/Sofia": "पूर्वी युरोपेली समय (सोफिया)", + "Europe\/Stockholm": "केन्द्रीय युरोपेली समय (स्टकहोल्म)", + "Europe\/Tallinn": "पूर्वी युरोपेली समय (ताल्लिन)", + "Europe\/Tirane": "केन्द्रीय युरोपेली समय (टिराने)", + "Europe\/Ulyanovsk": "मस्को समय (उल्यानोभ्स्क)", + "Europe\/Uzhgorod": "पूर्वी युरोपेली समय (उझगोरद)", + "Europe\/Vaduz": "केन्द्रीय युरोपेली समय (भाडुज)", + "Europe\/Vatican": "केन्द्रीय युरोपेली समय (भ्याटिकन)", + "Europe\/Vienna": "केन्द्रीय युरोपेली समय (भियना)", + "Europe\/Vilnius": "पूर्वी युरोपेली समय (भिल्निअस)", + "Europe\/Volgograd": "भोल्गाग्राड समय (भोल्गोग्राद)", + "Europe\/Warsaw": "केन्द्रीय युरोपेली समय (वारसअ)", + "Europe\/Zagreb": "केन्द्रीय युरोपेली समय (जाग्रेब)", + "Europe\/Zaporozhye": "पूर्वी युरोपेली समय (जापोरोझ्ये)", + "Europe\/Zurich": "केन्द्रीय युरोपेली समय (जुरिक)", + "Indian\/Antananarivo": "पूर्वी अफ्रिकी समय (अन्टानारिभो)", + "Indian\/Chagos": "हिन्द महासागर समय (चागोस)", + "Indian\/Christmas": "क्रिस्मस टापु समय (ख्रिस्टमस)", + "Indian\/Cocos": "कोकोस टापु समय (कोकोस)", + "Indian\/Comoro": "पूर्वी अफ्रिकी समय (कोमोरो)", + "Indian\/Kerguelen": "फ्रेन्च दक्षिणी र अन्टार्टिक समय (केर्गुएलेन)", + "Indian\/Mahe": "सेयेचेलास् समय (माहे)", + "Indian\/Maldives": "माल्दिभ्स समय (माल्दिभ्स)", + "Indian\/Mauritius": "मउरिटस समय (मउरिटिअस)", + "Indian\/Mayotte": "पूर्वी अफ्रिकी समय (मायोट्टे)", + "Indian\/Reunion": "रियुनियन समय (रियुनियन)", + "MST7MDT": "हिमाली समय", + "PST8PDT": "प्यासिफिक समय", + "Pacific\/Apia": "आपिया समय (अपिया)", + "Pacific\/Auckland": "न्यूजिल्यान्ड समय (अकल्यान्ड)", + "Pacific\/Bougainville": "पपूवा न्यू गिनी समय (बुगेनभिल्ले)", + "Pacific\/Chatham": "चाथाम समय (चाथाम)", + "Pacific\/Easter": "इस्टर टापू समय (इस्टर)", + "Pacific\/Efate": "भानुआतु समय (ईफाते)", + "Pacific\/Enderbury": "फिनिक्स टापु समय (एन्डरबरी)", + "Pacific\/Fakaofo": "तोकेलाउ समय (फाकाओफो)", + "Pacific\/Fiji": "फिजी समय (फिजी)", + "Pacific\/Funafuti": "टुभालु समय (फुनाफुति)", + "Pacific\/Galapagos": "गालापागोस् समय (गलापागोस)", + "Pacific\/Gambier": "ग्याम्बियर समय (ग्याम्बियर)", + "Pacific\/Guadalcanal": "सोलोमोन टापु समय (गुअडालकनाल)", + "Pacific\/Guam": "चामोर्रो मानक समय (गुवाम)", + "Pacific\/Honolulu": "हवाई-एलुटियन समय (होनोलुलु)", + "Pacific\/Johnston": "हवाई-एलुटियन समय (जोन्सटन)", + "Pacific\/Kiritimati": "लाइन टापु समय (किरितिमाटी)", + "Pacific\/Kosrae": "कोसराए समय (कोस्राए)", + "Pacific\/Kwajalein": "मार्शल टापु समय (क्वाजालेइन)", + "Pacific\/Majuro": "मार्शल टापु समय (माजुरो)", + "Pacific\/Marquesas": "मार्किसस समय (मार्केसास)", + "Pacific\/Midway": "सामोअ समय (मिडवे)", + "Pacific\/Nauru": "नाउरु समय (नाउरु)", + "Pacific\/Niue": "निउए समय (निउई)", + "Pacific\/Norfolk": "नोर्फल्क टापू समय (नरफोल्क)", + "Pacific\/Noumea": "नयाँ कालेदोनिया समय (नोउमेअ)", + "Pacific\/Pago_Pago": "सामोअ समय (पागो पागो)", + "Pacific\/Palau": "पालाउ समय (पलाउ)", + "Pacific\/Pitcairn": "पिटकैरण समय (पितकाईरन)", + "Pacific\/Ponape": "पोनापे समय (पोनापे)", + "Pacific\/Port_Moresby": "पपूवा न्यू गिनी समय (पोर्ट मोरेस्बी)", + "Pacific\/Rarotonga": "कुक टापु समय (राओतोंगा)", + "Pacific\/Saipan": "चामोर्रो मानक समय (साईपन)", + "Pacific\/Tahiti": "ताहिती समय (ताहिती)", + "Pacific\/Tarawa": "गिल्बर्ट टापु समय (तरवा)", + "Pacific\/Tongatapu": "टोंगा समय (टंगातपु)", + "Pacific\/Truk": "चुउक समय (चूक)", + "Pacific\/Wake": "वेक टापु समय (वेक)", + "Pacific\/Wallis": "वालिस् र फुटुना समय (वालिस)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ne_IN.json b/src/Symfony/Component/Intl/Resources/data/timezones/ne_IN.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ne_IN.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/nl.json b/src/Symfony/Component/Intl/Resources/data/timezones/nl.json new file mode 100644 index 0000000000000..64f3fa482c17a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/nl.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.86", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "Oost-Afrikaanse tijd (Addis Abeba)", + "Africa\/Algiers": "Midden-Europese tijd (Algiers)", + "Africa\/Asmera": "Oost-Afrikaanse tijd (Asmara)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "West-Afrikaanse tijd (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Centraal-Afrikaanse tijd (Blantyre)", + "Africa\/Brazzaville": "West-Afrikaanse tijd (Brazzaville)", + "Africa\/Bujumbura": "Centraal-Afrikaanse tijd (Bujumbura)", + "Africa\/Cairo": "Oost-Europese tijd (Caïro)", + "Africa\/Casablanca": "West-Europese tijd (Casablanca)", + "Africa\/Ceuta": "Midden-Europese tijd (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "Oost-Afrikaanse tijd (Dar es Salaam)", + "Africa\/Djibouti": "Oost-Afrikaanse tijd (Djibouti)", + "Africa\/Douala": "West-Afrikaanse tijd (Douala)", + "Africa\/El_Aaiun": "West-Europese tijd (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Centraal-Afrikaanse tijd (Gaborone)", + "Africa\/Harare": "Centraal-Afrikaanse tijd (Harare)", + "Africa\/Johannesburg": "Zuid-Afrikaanse tijd (Johannesburg)", + "Africa\/Juba": "Oost-Afrikaanse tijd (Juba)", + "Africa\/Kampala": "Oost-Afrikaanse tijd (Kampala)", + "Africa\/Khartoum": "Centraal-Afrikaanse tijd (Khartoem)", + "Africa\/Kigali": "Centraal-Afrikaanse tijd (Kigali)", + "Africa\/Kinshasa": "West-Afrikaanse tijd (Kinshasa)", + "Africa\/Lagos": "West-Afrikaanse tijd (Lagos)", + "Africa\/Libreville": "West-Afrikaanse tijd (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lomé)", + "Africa\/Luanda": "West-Afrikaanse tijd (Luanda)", + "Africa\/Lubumbashi": "Centraal-Afrikaanse tijd (Lubumbashi)", + "Africa\/Lusaka": "Centraal-Afrikaanse tijd (Lusaka)", + "Africa\/Malabo": "West-Afrikaanse tijd (Malabo)", + "Africa\/Maputo": "Centraal-Afrikaanse tijd (Maputo)", + "Africa\/Maseru": "Zuid-Afrikaanse tijd (Maseru)", + "Africa\/Mbabane": "Zuid-Afrikaanse tijd (Mbabane)", + "Africa\/Mogadishu": "Oost-Afrikaanse tijd (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "Oost-Afrikaanse tijd (Nairobi)", + "Africa\/Ndjamena": "West-Afrikaanse tijd (Ndjamena)", + "Africa\/Niamey": "West-Afrikaanse tijd (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "West-Afrikaanse tijd (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tomé)", + "Africa\/Tripoli": "Oost-Europese tijd (Tripoli)", + "Africa\/Tunis": "Midden-Europese tijd (Tunis)", + "Africa\/Windhoek": "Centraal-Afrikaanse tijd (Windhoek)", + "America\/Adak": "Hawaii-Aleoetische tijd (Adak)", + "America\/Anchorage": "Alaska-tijd (Anchorage)", + "America\/Anguilla": "Atlantic-tijd (Anguilla)", + "America\/Antigua": "Atlantic-tijd (Antigua)", + "America\/Araguaina": "Braziliaanse tijd (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentijnse tijd (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentijnse tijd (Río Gallegos)", + "America\/Argentina\/Salta": "Argentijnse tijd (Salta)", + "America\/Argentina\/San_Juan": "Argentijnse tijd (San Juan)", + "America\/Argentina\/San_Luis": "West-Argentijnse tijd (San Luis)", + "America\/Argentina\/Tucuman": "Argentijnse tijd (Tucumán)", + "America\/Argentina\/Ushuaia": "Argentijnse tijd (Ushuaia)", + "America\/Aruba": "Atlantic-tijd (Aruba)", + "America\/Asuncion": "Paraguayaanse tijd (Asunción)", + "America\/Bahia": "Braziliaanse tijd (Bahia)", + "America\/Bahia_Banderas": "Central-tijd (Bahía de Banderas)", + "America\/Barbados": "Atlantic-tijd (Barbados)", + "America\/Belem": "Braziliaanse tijd (Belém)", + "America\/Belize": "Central-tijd (Belize)", + "America\/Blanc-Sablon": "Atlantic-tijd (Blanc-Sablon)", + "America\/Boa_Vista": "Amazone-tijd (Boa Vista)", + "America\/Bogota": "Colombiaanse tijd (Bogota)", + "America\/Boise": "Mountain-tijd (Boise)", + "America\/Buenos_Aires": "Argentijnse tijd (Buenos Aires)", + "America\/Cambridge_Bay": "Mountain-tijd (Cambridge Bay)", + "America\/Campo_Grande": "Amazone-tijd (Campo Grande)", + "America\/Cancun": "Eastern-tijd (Cancun)", + "America\/Caracas": "Venezolaanse tijd (Caracas)", + "America\/Catamarca": "Argentijnse tijd (Catamarca)", + "America\/Cayenne": "Frans-Guyaanse tijd (Cayenne)", + "America\/Cayman": "Eastern-tijd (Cayman)", + "America\/Chicago": "Central-tijd (Chicago)", + "America\/Chihuahua": "Mexicaanse Pacific-tijd (Chihuahua)", + "America\/Coral_Harbour": "Eastern-tijd (Atikokan)", + "America\/Cordoba": "Argentijnse tijd (Córdoba)", + "America\/Costa_Rica": "Central-tijd (Costa Rica)", + "America\/Creston": "Mountain-tijd (Creston)", + "America\/Cuiaba": "Amazone-tijd (Cuiabá)", + "America\/Curacao": "Atlantic-tijd (Curaçao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Pacific-tijd (Dawson)", + "America\/Dawson_Creek": "Mountain-tijd (Dawson Creek)", + "America\/Denver": "Mountain-tijd (Denver)", + "America\/Detroit": "Eastern-tijd (Detroit)", + "America\/Dominica": "Atlantic-tijd (Dominica)", + "America\/Edmonton": "Mountain-tijd (Edmonton)", + "America\/Eirunepe": "Acre-tijd (Eirunepe)", + "America\/El_Salvador": "Central-tijd (El Salvador)", + "America\/Fort_Nelson": "Mountain-tijd (Fort Nelson)", + "America\/Fortaleza": "Braziliaanse tijd (Fortaleza)", + "America\/Glace_Bay": "Atlantic-tijd (Glace Bay)", + "America\/Godthab": "West-Groenlandse tijd (Nuuk)", + "America\/Goose_Bay": "Atlantic-tijd (Goose Bay)", + "America\/Grand_Turk": "Eastern-tijd (Grand Turk)", + "America\/Grenada": "Atlantic-tijd (Grenada)", + "America\/Guadeloupe": "Atlantic-tijd (Guadeloupe)", + "America\/Guatemala": "Central-tijd (Guatemala)", + "America\/Guayaquil": "Ecuadoraanse tijd (Guayaquil)", + "America\/Guyana": "Guyaanse tijd (Guyana)", + "America\/Halifax": "Atlantic-tijd (Halifax)", + "America\/Havana": "Cubaanse tijd (Havana)", + "America\/Hermosillo": "Mexicaanse Pacific-tijd (Hermosillo)", + "America\/Indiana\/Knox": "Central-tijd (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern-tijd (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern-tijd (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Central-tijd (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern-tijd (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern-tijd (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern-tijd (Winamac, Indiana)", + "America\/Indianapolis": "Eastern-tijd (Indianapolis)", + "America\/Inuvik": "Mountain-tijd (Inuvik)", + "America\/Iqaluit": "Eastern-tijd (Iqaluit)", + "America\/Jamaica": "Eastern-tijd (Jamaica)", + "America\/Jujuy": "Argentijnse tijd (Jujuy)", + "America\/Juneau": "Alaska-tijd (Juneau)", + "America\/Kentucky\/Monticello": "Eastern-tijd (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantic-tijd (Kralendijk)", + "America\/La_Paz": "Boliviaanse tijd (La Paz)", + "America\/Lima": "Peruaanse tijd (Lima)", + "America\/Los_Angeles": "Pacific-tijd (Los Angeles)", + "America\/Louisville": "Eastern-tijd (Louisville)", + "America\/Lower_Princes": "Atlantic-tijd (Beneden Prinsen Kwartier)", + "America\/Maceio": "Braziliaanse tijd (Maceió)", + "America\/Managua": "Central-tijd (Managua)", + "America\/Manaus": "Amazone-tijd (Manaus)", + "America\/Marigot": "Atlantic-tijd (Marigot)", + "America\/Martinique": "Atlantic-tijd (Martinique)", + "America\/Matamoros": "Central-tijd (Matamoros)", + "America\/Mazatlan": "Mexicaanse Pacific-tijd (Mazatlán)", + "America\/Mendoza": "Argentijnse tijd (Mendoza)", + "America\/Menominee": "Central-tijd (Menominee)", + "America\/Merida": "Central-tijd (Mérida)", + "America\/Metlakatla": "Alaska-tijd (Metlakatla)", + "America\/Mexico_City": "Central-tijd (Mexico-Stad)", + "America\/Miquelon": "Saint Pierre en Miquelon-tijd (Miquelon)", + "America\/Moncton": "Atlantic-tijd (Moncton)", + "America\/Monterrey": "Central-tijd (Monterrey)", + "America\/Montevideo": "Uruguayaanse tijd (Montevideo)", + "America\/Montserrat": "Atlantic-tijd (Montserrat)", + "America\/Nassau": "Eastern-tijd (Nassau)", + "America\/New_York": "Eastern-tijd (New York)", + "America\/Nipigon": "Eastern-tijd (Nipigon)", + "America\/Nome": "Alaska-tijd (Nome)", + "America\/Noronha": "Fernando de Noronha-tijd (Noronha)", + "America\/North_Dakota\/Beulah": "Central-tijd (Beulah, Noord-Dakota)", + "America\/North_Dakota\/Center": "Central-tijd (Center, Noord-Dakota)", + "America\/North_Dakota\/New_Salem": "Central-tijd (New Salem, Noord-Dakota)", + "America\/Ojinaga": "Mountain-tijd (Ojinaga)", + "America\/Panama": "Eastern-tijd (Panama)", + "America\/Pangnirtung": "Eastern-tijd (Pangnirtung)", + "America\/Paramaribo": "Surinaamse tijd (Paramaribo)", + "America\/Phoenix": "Mountain-tijd (Phoenix)", + "America\/Port-au-Prince": "Eastern-tijd (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantic-tijd (Port of Spain)", + "America\/Porto_Velho": "Amazone-tijd (Porto Velho)", + "America\/Puerto_Rico": "Atlantic-tijd (Puerto Rico)", + "America\/Punta_Arenas": "Chileense tijd (Punta Arenas)", + "America\/Rainy_River": "Central-tijd (Rainy River)", + "America\/Rankin_Inlet": "Central-tijd (Rankin Inlet)", + "America\/Recife": "Braziliaanse tijd (Recife)", + "America\/Regina": "Central-tijd (Regina)", + "America\/Resolute": "Central-tijd (Resolute)", + "America\/Rio_Branco": "Acre-tijd (Rio Branco)", + "America\/Santa_Isabel": "Noordwest-Mexicaanse tijd (Santa Isabel)", + "America\/Santarem": "Braziliaanse tijd (Santarem)", + "America\/Santiago": "Chileense tijd (Santiago)", + "America\/Santo_Domingo": "Atlantic-tijd (Santo Domingo)", + "America\/Sao_Paulo": "Braziliaanse tijd (São Paulo)", + "America\/Scoresbysund": "Oost-Groenlandse tijd (Ittoqqortoormiit)", + "America\/Sitka": "Alaska-tijd (Sitka)", + "America\/St_Barthelemy": "Atlantic-tijd (Saint-Barthélemy)", + "America\/St_Johns": "Newfoundland-tijd (St. John’s)", + "America\/St_Kitts": "Atlantic-tijd (St. Kitts)", + "America\/St_Lucia": "Atlantic-tijd (St. Lucia)", + "America\/St_Thomas": "Atlantic-tijd (St. Thomas)", + "America\/St_Vincent": "Atlantic-tijd (St. Vincent)", + "America\/Swift_Current": "Central-tijd (Swift Current)", + "America\/Tegucigalpa": "Central-tijd (Tegucigalpa)", + "America\/Thule": "Atlantic-tijd (Thule)", + "America\/Thunder_Bay": "Eastern-tijd (Thunder Bay)", + "America\/Tijuana": "Pacific-tijd (Tijuana)", + "America\/Toronto": "Eastern-tijd (Toronto)", + "America\/Tortola": "Atlantic-tijd (Tortola)", + "America\/Vancouver": "Pacific-tijd (Vancouver)", + "America\/Whitehorse": "Pacific-tijd (Whitehorse)", + "America\/Winnipeg": "Central-tijd (Winnipeg)", + "America\/Yakutat": "Alaska-tijd (Yakutat)", + "America\/Yellowknife": "Mountain-tijd (Yellowknife)", + "Antarctica\/Casey": "West-Australische tijd (Casey)", + "Antarctica\/Davis": "Davis-tijd (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville-tijd (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie-eilandse tijd (Macquarie)", + "Antarctica\/Mawson": "Mawson-tijd (Mawson)", + "Antarctica\/McMurdo": "Nieuw-Zeelandse tijd (McMurdo)", + "Antarctica\/Palmer": "Chileense tijd (Palmer)", + "Antarctica\/Rothera": "Rothera-tijd (Rothera)", + "Antarctica\/Syowa": "Syowa-tijd (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Vostok-tijd (Vostok)", + "Arctic\/Longyearbyen": "Midden-Europese tijd (Longyearbyen)", + "Asia\/Aden": "Arabische tijd (Aden)", + "Asia\/Almaty": "Oost-Kazachse tijd (Alma-Ata)", + "Asia\/Amman": "Oost-Europese tijd (Amman)", + "Asia\/Anadyr": "Anadyr-tijd (Anadyr)", + "Asia\/Aqtau": "West-Kazachse tijd (Aqtau)", + "Asia\/Aqtobe": "West-Kazachse tijd (Aqtöbe)", + "Asia\/Ashgabat": "Turkmeense tijd (Asjchabad)", + "Asia\/Atyrau": "West-Kazachse tijd (Atıraw)", + "Asia\/Baghdad": "Arabische tijd (Bagdad)", + "Asia\/Bahrain": "Arabische tijd (Bahrein)", + "Asia\/Baku": "Azerbeidzjaanse tijd (Bakoe)", + "Asia\/Bangkok": "Indochinese tijd (Bangkok)", + "Asia\/Beirut": "Oost-Europese tijd (Beiroet)", + "Asia\/Bishkek": "Kirgizische tijd (Bisjkek)", + "Asia\/Brunei": "Bruneise tijd (Brunei)", + "Asia\/Calcutta": "Indiase tijd (Calcutta)", + "Asia\/Chita": "Jakoetsk-tijd (Chita)", + "Asia\/Choibalsan": "Tsjojbalsan-tijd (Tsjojbalsan)", + "Asia\/Colombo": "Indiase tijd (Colombo)", + "Asia\/Damascus": "Oost-Europese tijd (Damascus)", + "Asia\/Dhaka": "Bengalese tijd (Dhaka)", + "Asia\/Dili": "Oost-Timorese tijd (Dili)", + "Asia\/Dubai": "Golf-standaardtijd (Dubai)", + "Asia\/Dushanbe": "Tadzjiekse tijd (Doesjanbe)", + "Asia\/Famagusta": "Oost-Europese tijd (Famagusta)", + "Asia\/Gaza": "Oost-Europese tijd (Gaza)", + "Asia\/Hebron": "Oost-Europese tijd (Hebron)", + "Asia\/Hong_Kong": "Hongkongse tijd (Hongkong)", + "Asia\/Hovd": "Hovd-tijd (Hovd)", + "Asia\/Irkutsk": "Irkoetsk-tijd (Irkoetsk)", + "Asia\/Jakarta": "West-Indonesische tijd (Jakarta)", + "Asia\/Jayapura": "Oost-Indonesische tijd (Jayapura)", + "Asia\/Jerusalem": "Israëlische tijd (Jeruzalem)", + "Asia\/Kabul": "Afghaanse tijd (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamtsjatski-tijd (Kamtsjatka)", + "Asia\/Karachi": "Pakistaanse tijd (Karachi)", + "Asia\/Katmandu": "Nepalese tijd (Kathmandu)", + "Asia\/Khandyga": "Jakoetsk-tijd (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk-tijd (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Maleisische tijd (Kuala Lumpur)", + "Asia\/Kuching": "Maleisische tijd (Kuching)", + "Asia\/Kuwait": "Arabische tijd (Koeweit)", + "Asia\/Macau": "Chinese tijd (Macau)", + "Asia\/Magadan": "Magadan-tijd (Magadan)", + "Asia\/Makassar": "Centraal-Indonesische tijd (Makassar)", + "Asia\/Manila": "Filipijnse tijd (Manilla)", + "Asia\/Muscat": "Golf-standaardtijd (Muscat)", + "Asia\/Nicosia": "Oost-Europese tijd (Nicosia)", + "Asia\/Novokuznetsk": "Krasnojarsk-tijd (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk-tijd (Novosibirsk)", + "Asia\/Omsk": "Omsk-tijd (Omsk)", + "Asia\/Oral": "West-Kazachse tijd (Oral)", + "Asia\/Phnom_Penh": "Indochinese tijd (Phnom-Penh)", + "Asia\/Pontianak": "West-Indonesische tijd (Pontianak)", + "Asia\/Pyongyang": "Koreaanse tijd (Pyongyang)", + "Asia\/Qatar": "Arabische tijd (Qatar)", + "Asia\/Qostanay": "Oost-Kazachse tijd (Qostanay)", + "Asia\/Qyzylorda": "West-Kazachse tijd (Qyzylorda)", + "Asia\/Rangoon": "Myanmarese tijd (Rangoon)", + "Asia\/Riyadh": "Arabische tijd (Riyad)", + "Asia\/Saigon": "Indochinese tijd (Ho Chi Minhstad)", + "Asia\/Sakhalin": "Sachalin-tijd (Sachalin)", + "Asia\/Samarkand": "Oezbeekse tijd (Samarkand)", + "Asia\/Seoul": "Koreaanse tijd (Seoul)", + "Asia\/Shanghai": "Chinese tijd (Sjanghai)", + "Asia\/Singapore": "Singaporese standaardtijd (Singapore)", + "Asia\/Srednekolymsk": "Magadan-tijd (Srednekolymsk)", + "Asia\/Taipei": "Taipei-tijd (Taipei)", + "Asia\/Tashkent": "Oezbeekse tijd (Tasjkent)", + "Asia\/Tbilisi": "Georgische tijd (Tbilisi)", + "Asia\/Tehran": "Iraanse tijd (Teheran)", + "Asia\/Thimphu": "Bhutaanse tijd (Thimphu)", + "Asia\/Tokyo": "Japanse tijd (Tokio)", + "Asia\/Ulaanbaatar": "Ulaanbaatar-tijd (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostok-tijd (Ust-Nera)", + "Asia\/Vientiane": "Indochinese tijd (Vientiane)", + "Asia\/Vladivostok": "Vladivostok-tijd (Vladivostok)", + "Asia\/Yakutsk": "Jakoetsk-tijd (Jakoetsk)", + "Asia\/Yekaterinburg": "Jekaterinenburg-tijd (Jekaterinenburg)", + "Asia\/Yerevan": "Armeense tijd (Jerevan)", + "Atlantic\/Azores": "Azoren-tijd (Azoren)", + "Atlantic\/Bermuda": "Atlantic-tijd (Bermuda)", + "Atlantic\/Canary": "West-Europese tijd (Canarische Eilanden)", + "Atlantic\/Cape_Verde": "Kaapverdische tijd (Kaapverdië)", + "Atlantic\/Faeroe": "West-Europese tijd (Faeröer)", + "Atlantic\/Madeira": "West-Europese tijd (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/South_Georgia": "Zuid-Georgische tijd (Zuid-Georgia)", + "Atlantic\/St_Helena": "Greenwich Mean Time (Sint-Helena)", + "Atlantic\/Stanley": "Falklandeilandse tijd (Stanley)", + "Australia\/Adelaide": "Midden-Australische tijd (Adelaide)", + "Australia\/Brisbane": "Oost-Australische tijd (Brisbane)", + "Australia\/Broken_Hill": "Midden-Australische tijd (Broken Hill)", + "Australia\/Currie": "Oost-Australische tijd (Currie)", + "Australia\/Darwin": "Midden-Australische tijd (Darwin)", + "Australia\/Eucla": "Midden-Australische westelijke tijd (Eucla)", + "Australia\/Hobart": "Oost-Australische tijd (Hobart)", + "Australia\/Lindeman": "Oost-Australische tijd (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe-eilandse tijd (Lord Howe)", + "Australia\/Melbourne": "Oost-Australische tijd (Melbourne)", + "Australia\/Perth": "West-Australische tijd (Perth)", + "Australia\/Sydney": "Oost-Australische tijd (Sydney)", + "CST6CDT": "Central-tijd", + "EST5EDT": "Eastern-tijd", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Gecoördineerde wereldtijd", + "Europe\/Amsterdam": "Midden-Europese tijd (Amsterdam)", + "Europe\/Andorra": "Midden-Europese tijd (Andorra)", + "Europe\/Astrakhan": "Moskou-tijd (Astrakhan)", + "Europe\/Athens": "Oost-Europese tijd (Athene)", + "Europe\/Belgrade": "Midden-Europese tijd (Belgrado)", + "Europe\/Berlin": "Midden-Europese tijd (Berlijn)", + "Europe\/Bratislava": "Midden-Europese tijd (Bratislava)", + "Europe\/Brussels": "Midden-Europese tijd (Brussel)", + "Europe\/Bucharest": "Oost-Europese tijd (Boekarest)", + "Europe\/Budapest": "Midden-Europese tijd (Boedapest)", + "Europe\/Busingen": "Midden-Europese tijd (Busingen)", + "Europe\/Chisinau": "Oost-Europese tijd (Chisinau)", + "Europe\/Copenhagen": "Midden-Europese tijd (Kopenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Midden-Europese tijd (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Oost-Europese tijd (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Oost-Europese tijd (Kaliningrad)", + "Europe\/Kiev": "Oost-Europese tijd (Kiev)", + "Europe\/Lisbon": "West-Europese tijd (Lissabon)", + "Europe\/Ljubljana": "Midden-Europese tijd (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (Londen)", + "Europe\/Luxembourg": "Midden-Europese tijd (Luxemburg)", + "Europe\/Madrid": "Midden-Europese tijd (Madrid)", + "Europe\/Malta": "Midden-Europese tijd (Malta)", + "Europe\/Mariehamn": "Oost-Europese tijd (Mariehamn)", + "Europe\/Minsk": "Moskou-tijd (Minsk)", + "Europe\/Monaco": "Midden-Europese tijd (Monaco)", + "Europe\/Moscow": "Moskou-tijd (Moskou)", + "Europe\/Oslo": "Midden-Europese tijd (Oslo)", + "Europe\/Paris": "Midden-Europese tijd (Parijs)", + "Europe\/Podgorica": "Midden-Europese tijd (Podgorica)", + "Europe\/Prague": "Midden-Europese tijd (Praag)", + "Europe\/Riga": "Oost-Europese tijd (Riga)", + "Europe\/Rome": "Midden-Europese tijd (Rome)", + "Europe\/Samara": "Samara-tijd (Samara)", + "Europe\/San_Marino": "Midden-Europese tijd (San Marino)", + "Europe\/Sarajevo": "Midden-Europese tijd (Sarajevo)", + "Europe\/Saratov": "Moskou-tijd (Saratov)", + "Europe\/Simferopol": "Moskou-tijd (Simferopol)", + "Europe\/Skopje": "Midden-Europese tijd (Skopje)", + "Europe\/Sofia": "Oost-Europese tijd (Sofia)", + "Europe\/Stockholm": "Midden-Europese tijd (Stockholm)", + "Europe\/Tallinn": "Oost-Europese tijd (Tallinn)", + "Europe\/Tirane": "Midden-Europese tijd (Tirana)", + "Europe\/Ulyanovsk": "Moskou-tijd (Ulyanovsk)", + "Europe\/Uzhgorod": "Oost-Europese tijd (Oezjhorod)", + "Europe\/Vaduz": "Midden-Europese tijd (Vaduz)", + "Europe\/Vatican": "Midden-Europese tijd (Vaticaanstad)", + "Europe\/Vienna": "Midden-Europese tijd (Wenen)", + "Europe\/Vilnius": "Oost-Europese tijd (Vilnius)", + "Europe\/Volgograd": "Wolgograd-tijd (Wolgograd)", + "Europe\/Warsaw": "Midden-Europese tijd (Warschau)", + "Europe\/Zagreb": "Midden-Europese tijd (Zagreb)", + "Europe\/Zaporozhye": "Oost-Europese tijd (Zaporizja)", + "Europe\/Zurich": "Midden-Europese tijd (Zürich)", + "Indian\/Antananarivo": "Oost-Afrikaanse tijd (Antananarivo)", + "Indian\/Chagos": "Indische Oceaan-tijd (Chagosarchipel)", + "Indian\/Christmas": "Christmaseilandse tijd (Christmaseiland)", + "Indian\/Cocos": "Cocoseilandse tijd (Cocoseilanden)", + "Indian\/Comoro": "Oost-Afrikaanse tijd (Comoro)", + "Indian\/Kerguelen": "Franse zuidelijke en Antarctische tijd (Kerguelen)", + "Indian\/Mahe": "Seychelse tijd (Mahé)", + "Indian\/Maldives": "Maldivische tijd (Maldiven)", + "Indian\/Mauritius": "Mauritiaanse tijd (Mauritius)", + "Indian\/Mayotte": "Oost-Afrikaanse tijd (Mayotte)", + "Indian\/Reunion": "Réunionse tijd (Réunion)", + "MST7MDT": "Mountain-tijd", + "PST8PDT": "Pacific-tijd", + "Pacific\/Apia": "Apia-tijd (Apia)", + "Pacific\/Auckland": "Nieuw-Zeelandse tijd (Auckland)", + "Pacific\/Bougainville": "Papoea-Nieuw-Guineese tijd (Bougainville)", + "Pacific\/Chatham": "Chatham-tijd (Chatham)", + "Pacific\/Easter": "Paaseilandse tijd (Paaseiland)", + "Pacific\/Efate": "Vanuatuaanse tijd (Efate)", + "Pacific\/Enderbury": "Phoenixeilandse tijd (Enderbury)", + "Pacific\/Fakaofo": "Tokelau-eilandse tijd (Fakaofo)", + "Pacific\/Fiji": "Fijische tijd (Fiji)", + "Pacific\/Funafuti": "Tuvaluaanse tijd (Funafuti)", + "Pacific\/Galapagos": "Galapagoseilandse standaardtijd (Galapagos)", + "Pacific\/Gambier": "Gambiereilandse tijd (Îles Gambier)", + "Pacific\/Guadalcanal": "Salomonseilandse tijd (Guadalcanal)", + "Pacific\/Guam": "Chamorro-tijd (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleoetische tijd (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleoetische tijd (Johnston)", + "Pacific\/Kiritimati": "Line-eilandse tijd (Kiritimati)", + "Pacific\/Kosrae": "Kosraese tijd (Kosrae)", + "Pacific\/Kwajalein": "Marshalleilandse tijd (Kwajalein)", + "Pacific\/Majuro": "Marshalleilandse tijd (Majuro)", + "Pacific\/Marquesas": "Marquesaseilandse tijd (Marquesaseilanden)", + "Pacific\/Midway": "Samoaanse tijd (Midway)", + "Pacific\/Nauru": "Nauruaanse tijd (Nauru)", + "Pacific\/Niue": "Niuese tijd (Niue)", + "Pacific\/Norfolk": "Norfolkeilandse tijd (Norfolk)", + "Pacific\/Noumea": "Nieuw-Caledonische tijd (Nouméa)", + "Pacific\/Pago_Pago": "Samoaanse tijd (Pago Pago)", + "Pacific\/Palau": "Belause tijd (Palau)", + "Pacific\/Pitcairn": "Pitcairneilandse tijd (Pitcairn)", + "Pacific\/Ponape": "Pohnpei-tijd (Pohnpei)", + "Pacific\/Port_Moresby": "Papoea-Nieuw-Guineese tijd (Port Moresby)", + "Pacific\/Rarotonga": "Cookeilandse tijd (Rarotonga)", + "Pacific\/Saipan": "Chamorro-tijd (Saipan)", + "Pacific\/Tahiti": "Tahitiaanse tijd (Tahiti)", + "Pacific\/Tarawa": "Gilberteilandse tijd (Tarawa)", + "Pacific\/Tongatapu": "Tongaanse tijd (Tongatapu)", + "Pacific\/Truk": "Chuukse tijd (Chuuk)", + "Pacific\/Wake": "Wake-eilandse tijd (Wake)", + "Pacific\/Wallis": "Wallis en Futunase tijd (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/nl_SR.json b/src/Symfony/Component/Intl/Resources/data/timezones/nl_SR.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/nl_SR.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/nn.json b/src/Symfony/Component/Intl/Resources/data/timezones/nn.json new file mode 100644 index 0000000000000..186736d9b4c0d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/nn.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "Greenwich middeltid (Abidjan)", + "Africa\/Accra": "Greenwich middeltid (Accra)", + "Africa\/Addis_Ababa": "austafrikansk tid (Addis Abeba)", + "Africa\/Algiers": "sentraleuropeisk tid (Alger)", + "Africa\/Asmera": "austafrikansk tid (Asmara)", + "Africa\/Bamako": "Greenwich middeltid (Bamako)", + "Africa\/Bangui": "vestafrikansk tid (Bangui)", + "Africa\/Banjul": "Greenwich middeltid (Banjul)", + "Africa\/Bissau": "Greenwich middeltid (Bissau)", + "Africa\/Blantyre": "sentralafrikansk tid (Blantyre)", + "Africa\/Brazzaville": "vestafrikansk tid (Brazzaville)", + "Africa\/Bujumbura": "sentralafrikansk tid (Bujumbura)", + "Africa\/Cairo": "austeuropeisk tid (Kairo)", + "Africa\/Casablanca": "vesteuropeisk tid (Casablanca)", + "Africa\/Ceuta": "sentraleuropeisk tid (Ceuta)", + "Africa\/Conakry": "Greenwich middeltid (Conakry)", + "Africa\/Dakar": "Greenwich middeltid (Dakar)", + "Africa\/Dar_es_Salaam": "austafrikansk tid (Dar-es-Salaam)", + "Africa\/Djibouti": "austafrikansk tid (Djibouti)", + "Africa\/Douala": "vestafrikansk tid (Douala)", + "Africa\/El_Aaiun": "vesteuropeisk tid (El Aaiún)", + "Africa\/Freetown": "Greenwich middeltid (Freetown)", + "Africa\/Gaborone": "sentralafrikansk tid (Gaborone)", + "Africa\/Harare": "sentralafrikansk tid (Harare)", + "Africa\/Johannesburg": "sørafrikansk tid (Johannesburg)", + "Africa\/Juba": "austafrikansk tid (Juba)", + "Africa\/Kampala": "austafrikansk tid (Kampala)", + "Africa\/Khartoum": "sentralafrikansk tid (Khartoum)", + "Africa\/Kigali": "sentralafrikansk tid (Kigali)", + "Africa\/Kinshasa": "vestafrikansk tid (Kinshasa)", + "Africa\/Lagos": "vestafrikansk tid (Lagos)", + "Africa\/Libreville": "vestafrikansk tid (Libreville)", + "Africa\/Lome": "Greenwich middeltid (Lomé)", + "Africa\/Luanda": "vestafrikansk tid (Luanda)", + "Africa\/Lubumbashi": "sentralafrikansk tid (Lubumbashi)", + "Africa\/Lusaka": "sentralafrikansk tid (Lusaka)", + "Africa\/Malabo": "vestafrikansk tid (Malabo)", + "Africa\/Maputo": "sentralafrikansk tid (Maputo)", + "Africa\/Maseru": "sørafrikansk tid (Maseru)", + "Africa\/Mbabane": "sørafrikansk tid (Mbabane)", + "Africa\/Mogadishu": "austafrikansk tid (Mogadishu)", + "Africa\/Monrovia": "Greenwich middeltid (Monrovia)", + "Africa\/Nairobi": "austafrikansk tid (Nairobi)", + "Africa\/Ndjamena": "vestafrikansk tid (Ndjamena)", + "Africa\/Niamey": "vestafrikansk tid (Niamey)", + "Africa\/Nouakchott": "Greenwich middeltid (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich middeltid (Ouagadougou)", + "Africa\/Porto-Novo": "vestafrikansk tid (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich middeltid (São Tomé)", + "Africa\/Tripoli": "austeuropeisk tid (Tripoli)", + "Africa\/Tunis": "sentraleuropeisk tid (Tunis)", + "Africa\/Windhoek": "sentralafrikansk tid (Windhoek)", + "America\/Adak": "tidssone for Hawaii og Aleutene (Adak)", + "America\/Anchorage": "alaskisk tid (Anchorage)", + "America\/Anguilla": "tidssone for den nordamerikanske atlanterhavskysten (Anguilla)", + "America\/Antigua": "tidssone for den nordamerikanske atlanterhavskysten (Antigua)", + "America\/Araguaina": "tidssone for Brasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "argentinsk tid (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "argentinsk tid (Rio Gallegos)", + "America\/Argentina\/Salta": "argentinsk tid (Salta)", + "America\/Argentina\/San_Juan": "argentinsk tid (San Juan)", + "America\/Argentina\/San_Luis": "vestargentinsk tid (San Luis)", + "America\/Argentina\/Tucuman": "argentinsk tid (Tucumán)", + "America\/Argentina\/Ushuaia": "argentinsk tid (Ushuaia)", + "America\/Aruba": "tidssone for den nordamerikanske atlanterhavskysten (Aruba)", + "America\/Asuncion": "paraguayansk tid (Asunción)", + "America\/Bahia": "tidssone for Brasilia (Bahia)", + "America\/Bahia_Banderas": "tidssone for sentrale Nord-Amerika (Bahía Banderas)", + "America\/Barbados": "tidssone for den nordamerikanske atlanterhavskysten (Barbados)", + "America\/Belem": "tidssone for Brasilia (Belém)", + "America\/Belize": "tidssone for sentrale Nord-Amerika (Belize)", + "America\/Blanc-Sablon": "tidssone for den nordamerikanske atlanterhavskysten (Blanc-Sablon)", + "America\/Boa_Vista": "tidssone for Amazonas (Boa Vista)", + "America\/Bogota": "kolombiansk tid (Bogotá)", + "America\/Boise": "tidssone for Rocky Mountains (USA) (Boise)", + "America\/Buenos_Aires": "argentinsk tid (Buenos Aires)", + "America\/Cambridge_Bay": "tidssone for Rocky Mountains (USA) (Cambridge Bay)", + "America\/Campo_Grande": "tidssone for Amazonas (Campo Grande)", + "America\/Cancun": "tidssone for den nordamerikansk austkysten (Cancún)", + "America\/Caracas": "venezuelansk tid (Caracas)", + "America\/Catamarca": "argentinsk tid (Catamarca)", + "America\/Cayenne": "tidssone for Fransk Guyana (Cayenne)", + "America\/Cayman": "tidssone for den nordamerikansk austkysten (Caymanøyane)", + "America\/Chicago": "tidssone for sentrale Nord-Amerika (Chicago)", + "America\/Chihuahua": "tidssone for den meksikanske stillehavskysten (Chihuahua)", + "America\/Coral_Harbour": "tidssone for den nordamerikansk austkysten (Atikokan)", + "America\/Cordoba": "argentinsk tid (Córdoba)", + "America\/Costa_Rica": "tidssone for sentrale Nord-Amerika (Costa Rica)", + "America\/Creston": "tidssone for Rocky Mountains (USA) (Creston)", + "America\/Cuiaba": "tidssone for Amazonas (Cuiaba)", + "America\/Curacao": "tidssone for den nordamerikanske atlanterhavskysten (Curaçao)", + "America\/Danmarkshavn": "Greenwich middeltid (Danmarkshavn)", + "America\/Dawson": "tidssone for den nordamerikanske stillehavskysten (Dawson)", + "America\/Dawson_Creek": "tidssone for Rocky Mountains (USA) (Dawson Creek)", + "America\/Denver": "tidssone for Rocky Mountains (USA) (Denver)", + "America\/Detroit": "tidssone for den nordamerikansk austkysten (Detroit)", + "America\/Dominica": "tidssone for den nordamerikanske atlanterhavskysten (Dominica)", + "America\/Edmonton": "tidssone for Rocky Mountains (USA) (Edmonton)", + "America\/El_Salvador": "tidssone for sentrale Nord-Amerika (El Salvador)", + "America\/Fort_Nelson": "tidssone for Rocky Mountains (USA) (Fort Nelson)", + "America\/Fortaleza": "tidssone for Brasilia (Fortaleza)", + "America\/Glace_Bay": "tidssone for den nordamerikanske atlanterhavskysten (Glace Bay)", + "America\/Godthab": "vestgrønlandsk tid (Nuuk)", + "America\/Goose_Bay": "tidssone for den nordamerikanske atlanterhavskysten (Goose Bay)", + "America\/Grand_Turk": "tidssone for den nordamerikansk austkysten (Grand Turk)", + "America\/Grenada": "tidssone for den nordamerikanske atlanterhavskysten (Grenada)", + "America\/Guadeloupe": "tidssone for den nordamerikanske atlanterhavskysten (Guadeloupe)", + "America\/Guatemala": "tidssone for sentrale Nord-Amerika (Guatemala)", + "America\/Guayaquil": "ecuadoriansk tid (Guayaquil)", + "America\/Guyana": "guyansk tid (Guyana)", + "America\/Halifax": "tidssone for den nordamerikanske atlanterhavskysten (Halifax)", + "America\/Havana": "kubansk tid (Havana)", + "America\/Hermosillo": "tidssone for den meksikanske stillehavskysten (Hermosillo)", + "America\/Indiana\/Knox": "tidssone for sentrale Nord-Amerika (Knox, Indiana)", + "America\/Indiana\/Marengo": "tidssone for den nordamerikansk austkysten (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "tidssone for den nordamerikansk austkysten (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "tidssone for sentrale Nord-Amerika (Tell City, Indiana)", + "America\/Indiana\/Vevay": "tidssone for den nordamerikansk austkysten (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "tidssone for den nordamerikansk austkysten (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "tidssone for den nordamerikansk austkysten (Winamac, Indiana)", + "America\/Indianapolis": "tidssone for den nordamerikansk austkysten (Indianapolis)", + "America\/Inuvik": "tidssone for Rocky Mountains (USA) (Inuvik)", + "America\/Iqaluit": "tidssone for den nordamerikansk austkysten (Iqaluit)", + "America\/Jamaica": "tidssone for den nordamerikansk austkysten (Jamaica)", + "America\/Jujuy": "argentinsk tid (Jujuy)", + "America\/Juneau": "alaskisk tid (Juneau)", + "America\/Kentucky\/Monticello": "tidssone for den nordamerikansk austkysten (Monticello, Kentucky)", + "America\/Kralendijk": "tidssone for den nordamerikanske atlanterhavskysten (Kralendijk)", + "America\/La_Paz": "boliviansk tid (La Paz)", + "America\/Lima": "peruansk tid (Lima)", + "America\/Los_Angeles": "tidssone for den nordamerikanske stillehavskysten (Los Angeles)", + "America\/Louisville": "tidssone for den nordamerikansk austkysten (Louisville)", + "America\/Lower_Princes": "tidssone for den nordamerikanske atlanterhavskysten (Lower Prince’s Quarter)", + "America\/Maceio": "tidssone for Brasilia (Maceió)", + "America\/Managua": "tidssone for sentrale Nord-Amerika (Managua)", + "America\/Manaus": "tidssone for Amazonas (Manaus)", + "America\/Marigot": "tidssone for den nordamerikanske atlanterhavskysten (Marigot)", + "America\/Martinique": "tidssone for den nordamerikanske atlanterhavskysten (Martinique)", + "America\/Matamoros": "tidssone for sentrale Nord-Amerika (Matamoros)", + "America\/Mazatlan": "tidssone for den meksikanske stillehavskysten (Mazatlan)", + "America\/Mendoza": "argentinsk tid (Mendoza)", + "America\/Menominee": "tidssone for sentrale Nord-Amerika (Menominee)", + "America\/Merida": "tidssone for sentrale Nord-Amerika (Merida)", + "America\/Metlakatla": "alaskisk tid (Metlakatla)", + "America\/Mexico_City": "tidssone for sentrale Nord-Amerika (Mexico by)", + "America\/Miquelon": "tidssone for Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "tidssone for den nordamerikanske atlanterhavskysten (Moncton)", + "America\/Monterrey": "tidssone for sentrale Nord-Amerika (Monterrey)", + "America\/Montevideo": "uruguayansk tid (Montevideo)", + "America\/Montserrat": "tidssone for den nordamerikanske atlanterhavskysten (Montserrat)", + "America\/Nassau": "tidssone for den nordamerikansk austkysten (Nassau)", + "America\/New_York": "tidssone for den nordamerikansk austkysten (New York)", + "America\/Nipigon": "tidssone for den nordamerikansk austkysten (Nipigon)", + "America\/Nome": "alaskisk tid (Nome)", + "America\/Noronha": "tidssone for Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "tidssone for sentrale Nord-Amerika (Beulah, Nord-Dakota)", + "America\/North_Dakota\/Center": "tidssone for sentrale Nord-Amerika (Center, Nord-Dakota)", + "America\/North_Dakota\/New_Salem": "tidssone for sentrale Nord-Amerika (New Salem, Nord-Dakota)", + "America\/Ojinaga": "tidssone for Rocky Mountains (USA) (Ojinaga)", + "America\/Panama": "tidssone for den nordamerikansk austkysten (Panama)", + "America\/Pangnirtung": "tidssone for den nordamerikansk austkysten (Pangnirtung)", + "America\/Paramaribo": "surinamsk tid (Paramaribo)", + "America\/Phoenix": "tidssone for Rocky Mountains (USA) (Phoenix)", + "America\/Port-au-Prince": "tidssone for den nordamerikansk austkysten (Port-au-Prince)", + "America\/Port_of_Spain": "tidssone for den nordamerikanske atlanterhavskysten (Port of Spain)", + "America\/Porto_Velho": "tidssone for Amazonas (Porto Velho)", + "America\/Puerto_Rico": "tidssone for den nordamerikanske atlanterhavskysten (Puerto Rico)", + "America\/Punta_Arenas": "chilensk tid (Punta Arenas)", + "America\/Rainy_River": "tidssone for sentrale Nord-Amerika (Rainy River)", + "America\/Rankin_Inlet": "tidssone for sentrale Nord-Amerika (Rankin Inlet)", + "America\/Recife": "tidssone for Brasilia (Recife)", + "America\/Regina": "tidssone for sentrale Nord-Amerika (Regina)", + "America\/Resolute": "tidssone for sentrale Nord-Amerika (Resolute)", + "America\/Santa_Isabel": "tidssone for nordvestlege Mexico (Santa Isabel)", + "America\/Santarem": "tidssone for Brasilia (Santarém)", + "America\/Santiago": "chilensk tid (Santiago)", + "America\/Santo_Domingo": "tidssone for den nordamerikanske atlanterhavskysten (Santo Domingo)", + "America\/Sao_Paulo": "tidssone for Brasilia (São Paulo)", + "America\/Scoresbysund": "austgrønlandsk tid (Ittoqqortoormiit)", + "America\/Sitka": "alaskisk tid (Sitka)", + "America\/St_Barthelemy": "tidssone for den nordamerikanske atlanterhavskysten (Saint-Barthélemy)", + "America\/St_Johns": "tidssone for Newfoundland (St. John’s)", + "America\/St_Kitts": "tidssone for den nordamerikanske atlanterhavskysten (St. Kitts)", + "America\/St_Lucia": "tidssone for den nordamerikanske atlanterhavskysten (St. Lucia)", + "America\/St_Thomas": "tidssone for den nordamerikanske atlanterhavskysten (St. Thomas)", + "America\/St_Vincent": "tidssone for den nordamerikanske atlanterhavskysten (St. Vincent)", + "America\/Swift_Current": "tidssone for sentrale Nord-Amerika (Swift Current)", + "America\/Tegucigalpa": "tidssone for sentrale Nord-Amerika (Tegucigalpa)", + "America\/Thule": "tidssone for den nordamerikanske atlanterhavskysten (Thule)", + "America\/Thunder_Bay": "tidssone for den nordamerikansk austkysten (Thunder Bay)", + "America\/Tijuana": "tidssone for den nordamerikanske stillehavskysten (Tijuana)", + "America\/Toronto": "tidssone for den nordamerikansk austkysten (Toronto)", + "America\/Tortola": "tidssone for den nordamerikanske atlanterhavskysten (Tortola)", + "America\/Vancouver": "tidssone for den nordamerikanske stillehavskysten (Vancouver)", + "America\/Whitehorse": "tidssone for den nordamerikanske stillehavskysten (Whitehorse)", + "America\/Winnipeg": "tidssone for sentrale Nord-Amerika (Winnipeg)", + "America\/Yakutat": "alaskisk tid (Yakutat)", + "America\/Yellowknife": "tidssone for Rocky Mountains (USA) (Yellowknife)", + "Antarctica\/Casey": "vestaustralsk tid (Casey)", + "Antarctica\/Davis": "tidssone for Davis (Davis)", + "Antarctica\/DumontDUrville": "tidssone for Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "tidssone for Macquarieøya (Macquarie)", + "Antarctica\/Mawson": "tidssone for Mawson (Mawson)", + "Antarctica\/McMurdo": "nyzealandsk tid (McMurdo)", + "Antarctica\/Palmer": "chilensk tid (Palmer)", + "Antarctica\/Rothera": "tidssone for Rothera (Rothera)", + "Antarctica\/Syowa": "tidssone for Syowa (Syowa)", + "Antarctica\/Troll": "Greenwich middeltid (Troll)", + "Antarctica\/Vostok": "tidssone for Vostok (Vostok)", + "Arctic\/Longyearbyen": "sentraleuropeisk tid (Longyearbyen)", + "Asia\/Aden": "arabisk tid (Aden)", + "Asia\/Almaty": "austkasakhstansk tid (Almaty)", + "Asia\/Amman": "austeuropeisk tid (Amman)", + "Asia\/Aqtau": "vestkasakhstansk tid (Aktau)", + "Asia\/Aqtobe": "vestkasakhstansk tid (Aktobe)", + "Asia\/Ashgabat": "turkmensk tid (Asjgabat)", + "Asia\/Atyrau": "vestkasakhstansk tid (Atyrau)", + "Asia\/Baghdad": "arabisk tid (Bagdad)", + "Asia\/Bahrain": "arabisk tid (Bahrain)", + "Asia\/Baku": "aserbajdsjansk tid (Baku)", + "Asia\/Bangkok": "indokinesisk tid (Bangkok)", + "Asia\/Beirut": "austeuropeisk tid (Beirut)", + "Asia\/Bishkek": "kirgisisk tid (Bisjkek)", + "Asia\/Brunei": "tidssone for Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "indisk tid (Kolkata)", + "Asia\/Chita": "tidssone for Jakutsk (Tsjita)", + "Asia\/Choibalsan": "tidssone for Tsjojbalsan (Tsjojbalsan)", + "Asia\/Colombo": "indisk tid (Colombo)", + "Asia\/Damascus": "austeuropeisk tid (Damaskus)", + "Asia\/Dhaka": "bangladeshisk tid (Dhaka)", + "Asia\/Dili": "austtimoresisk tid (Dili)", + "Asia\/Dubai": "tidssone for Persiabukta (Dubai)", + "Asia\/Dushanbe": "tadsjikisk tid (Dusjanbe)", + "Asia\/Famagusta": "austeuropeisk tid (Famagusta)", + "Asia\/Gaza": "austeuropeisk tid (Gaza)", + "Asia\/Hebron": "austeuropeisk tid (Hebron)", + "Asia\/Hong_Kong": "hongkongkinesisk tid (Hongkong)", + "Asia\/Hovd": "tidssone for Khovd (Khovd)", + "Asia\/Irkutsk": "tidssone for Irkutsk (Irkutsk)", + "Asia\/Jakarta": "vestindonesisk tid (Jakarta)", + "Asia\/Jayapura": "austindonesisk tid (Jajapura)", + "Asia\/Jerusalem": "israelsk tid (Jerusalem)", + "Asia\/Kabul": "afghansk tid (Kabul)", + "Asia\/Karachi": "pakistansk tid (Karachi)", + "Asia\/Katmandu": "nepalsk tid (Katmandu)", + "Asia\/Khandyga": "tidssone for Jakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "tidssone for Krasnojarsk (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "malaysisk tid (Kuala Lumpur)", + "Asia\/Kuching": "malaysisk tid (Kuching)", + "Asia\/Kuwait": "arabisk tid (Kuwait)", + "Asia\/Macau": "kinesisk tid (Macao)", + "Asia\/Magadan": "tidssone for Magadan (Magadan)", + "Asia\/Makassar": "sentralindonesisk tid (Makassar)", + "Asia\/Manila": "filippinsk tid (Manila)", + "Asia\/Muscat": "tidssone for Persiabukta (Muskat)", + "Asia\/Nicosia": "austeuropeisk tid (Nikosia)", + "Asia\/Novokuznetsk": "tidssone for Krasnojarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "tidssone for Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "tidssone for Omsk (Omsk)", + "Asia\/Oral": "vestkasakhstansk tid (Oral)", + "Asia\/Phnom_Penh": "indokinesisk tid (Phnom Penh)", + "Asia\/Pontianak": "vestindonesisk tid (Pontianak)", + "Asia\/Pyongyang": "koreansk tid (Pyongyang)", + "Asia\/Qatar": "arabisk tid (Qatar)", + "Asia\/Qostanay": "austkasakhstansk tid (Qostanay)", + "Asia\/Qyzylorda": "vestkasakhstansk tid (Kyzylorda)", + "Asia\/Rangoon": "myanmarsk tid (Yangôn)", + "Asia\/Riyadh": "arabisk tid (Riyadh)", + "Asia\/Saigon": "indokinesisk tid (Ho Chi Minh-byen)", + "Asia\/Sakhalin": "tidssone for Sakhalin (Sakhalin)", + "Asia\/Samarkand": "usbekisk tid (Samarkand)", + "Asia\/Seoul": "koreansk tid (Seoul)", + "Asia\/Shanghai": "kinesisk tid (Shanghai)", + "Asia\/Singapore": "singaporsk tid (Singapore)", + "Asia\/Srednekolymsk": "tidssone for Magadan (Srednekolymsk)", + "Asia\/Taipei": "tidssone for Taipei (Taipei)", + "Asia\/Tashkent": "usbekisk tid (Tasjkent)", + "Asia\/Tbilisi": "georgisk tid (Tbilisi)", + "Asia\/Tehran": "iransk tid (Teheran)", + "Asia\/Thimphu": "bhutansk tid (Thimphu)", + "Asia\/Tokyo": "japansk tid (Tokyo)", + "Asia\/Ulaanbaatar": "tidssone for Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "tidssone for Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "indokinesisk tid (Vientiane)", + "Asia\/Vladivostok": "tidssone for Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "tidssone for Jakutsk (Jakutsk)", + "Asia\/Yekaterinburg": "tidssone for Jekaterinburg (Jekaterinburg)", + "Asia\/Yerevan": "armensk tid (Jerevan)", + "Atlantic\/Azores": "asorisk tid (Asorane)", + "Atlantic\/Bermuda": "tidssone for den nordamerikanske atlanterhavskysten (Bermuda)", + "Atlantic\/Canary": "vesteuropeisk tid (Kanariøyane)", + "Atlantic\/Cape_Verde": "kappverdisk tid (Kapp Verde)", + "Atlantic\/Faeroe": "vesteuropeisk tid (Færøyane)", + "Atlantic\/Madeira": "vesteuropeisk tid (Madeira)", + "Atlantic\/Reykjavik": "Greenwich middeltid (Reykjavík)", + "Atlantic\/South_Georgia": "tidssone for Sør-Georgia (Sør-Georgia)", + "Atlantic\/St_Helena": "Greenwich middeltid (St. Helena)", + "Atlantic\/Stanley": "tidssone for Falklandsøyane (Stanley)", + "Australia\/Adelaide": "sentralaustralsk tid (Adelaide)", + "Australia\/Brisbane": "austaustralsk tid (Brisbane)", + "Australia\/Broken_Hill": "sentralaustralsk tid (Broken Hill)", + "Australia\/Currie": "austaustralsk tid (Currie)", + "Australia\/Darwin": "sentralaustralsk tid (Darwin)", + "Australia\/Eucla": "vest-sentralaustralsk tid (Eucla)", + "Australia\/Hobart": "austaustralsk tid (Hobart)", + "Australia\/Lindeman": "austaustralsk tid (Lindeman)", + "Australia\/Lord_Howe": "tidssone for Lord Howe-øya (Lord Howe)", + "Australia\/Melbourne": "austaustralsk tid (Melbourne)", + "Australia\/Perth": "vestaustralsk tid (Perth)", + "Australia\/Sydney": "austaustralsk tid (Sydney)", + "CST6CDT": "tidssone for sentrale Nord-Amerika", + "EST5EDT": "tidssone for den nordamerikansk austkysten", + "Etc\/GMT": "Greenwich middeltid", + "Etc\/UTC": "koordinert universaltid", + "Europe\/Amsterdam": "sentraleuropeisk tid (Amsterdam)", + "Europe\/Andorra": "sentraleuropeisk tid (Andorra)", + "Europe\/Astrakhan": "tidssone for Moskva (Astrakhan)", + "Europe\/Athens": "austeuropeisk tid (Athen)", + "Europe\/Belgrade": "sentraleuropeisk tid (Beograd)", + "Europe\/Berlin": "sentraleuropeisk tid (Berlin)", + "Europe\/Bratislava": "sentraleuropeisk tid (Bratislava)", + "Europe\/Brussels": "sentraleuropeisk tid (Brussel)", + "Europe\/Bucharest": "austeuropeisk tid (București)", + "Europe\/Budapest": "sentraleuropeisk tid (Budapest)", + "Europe\/Busingen": "sentraleuropeisk tid (Büsingen)", + "Europe\/Chisinau": "austeuropeisk tid (Chișinău)", + "Europe\/Copenhagen": "sentraleuropeisk tid (København)", + "Europe\/Dublin": "Greenwich middeltid (Dublin)", + "Europe\/Gibraltar": "sentraleuropeisk tid (Gibraltar)", + "Europe\/Guernsey": "Greenwich middeltid (Guernsey)", + "Europe\/Helsinki": "austeuropeisk tid (Helsingfors)", + "Europe\/Isle_of_Man": "Greenwich middeltid (Man)", + "Europe\/Jersey": "Greenwich middeltid (Jersey)", + "Europe\/Kaliningrad": "austeuropeisk tid (Kaliningrad)", + "Europe\/Kiev": "austeuropeisk tid (Kiev)", + "Europe\/Lisbon": "vesteuropeisk tid (Lisboa)", + "Europe\/Ljubljana": "sentraleuropeisk tid (Ljubljana)", + "Europe\/London": "Greenwich middeltid (London)", + "Europe\/Luxembourg": "sentraleuropeisk tid (Luxemburg)", + "Europe\/Madrid": "sentraleuropeisk tid (Madrid)", + "Europe\/Malta": "sentraleuropeisk tid (Malta)", + "Europe\/Mariehamn": "austeuropeisk tid (Mariehamn)", + "Europe\/Minsk": "tidssone for Moskva (Minsk)", + "Europe\/Monaco": "sentraleuropeisk tid (Monaco)", + "Europe\/Moscow": "tidssone for Moskva (Moskva)", + "Europe\/Oslo": "sentraleuropeisk tid (Oslo)", + "Europe\/Paris": "sentraleuropeisk tid (Paris)", + "Europe\/Podgorica": "sentraleuropeisk tid (Podgorica)", + "Europe\/Prague": "sentraleuropeisk tid (Praha)", + "Europe\/Riga": "austeuropeisk tid (Riga)", + "Europe\/Rome": "sentraleuropeisk tid (Roma)", + "Europe\/San_Marino": "sentraleuropeisk tid (San Marino)", + "Europe\/Sarajevo": "sentraleuropeisk tid (Sarajevo)", + "Europe\/Saratov": "tidssone for Moskva (Saratov)", + "Europe\/Simferopol": "tidssone for Moskva (Simferopol)", + "Europe\/Skopje": "sentraleuropeisk tid (Skopje)", + "Europe\/Sofia": "austeuropeisk tid (Sofia)", + "Europe\/Stockholm": "sentraleuropeisk tid (Stockholm)", + "Europe\/Tallinn": "austeuropeisk tid (Tallinn)", + "Europe\/Tirane": "sentraleuropeisk tid (Tirana)", + "Europe\/Ulyanovsk": "tidssone for Moskva (Uljanovsk)", + "Europe\/Uzhgorod": "austeuropeisk tid (Uzjhorod)", + "Europe\/Vaduz": "sentraleuropeisk tid (Vaduz)", + "Europe\/Vatican": "sentraleuropeisk tid (Vatikanstaten)", + "Europe\/Vienna": "sentraleuropeisk tid (Wien)", + "Europe\/Vilnius": "austeuropeisk tid (Vilnius)", + "Europe\/Volgograd": "tidssone for Volgograd (Volgograd)", + "Europe\/Warsaw": "sentraleuropeisk tid (Warszawa)", + "Europe\/Zagreb": "sentraleuropeisk tid (Zagreb)", + "Europe\/Zaporozhye": "austeuropeisk tid (Zaporizjzja)", + "Europe\/Zurich": "sentraleuropeisk tid (Zürich)", + "Indian\/Antananarivo": "austafrikansk tid (Antananarivo)", + "Indian\/Chagos": "tidssone for Indiahavet (Chagos)", + "Indian\/Christmas": "tidssone for Christmasøya (Christmasøya)", + "Indian\/Cocos": "tidssone for Kokosøyane (Kokosøyane)", + "Indian\/Comoro": "austafrikansk tid (Komorene)", + "Indian\/Kerguelen": "tidssone for Dei franske sørterritoria (Kerguelen)", + "Indian\/Mahe": "seychellisk tid (Mahé)", + "Indian\/Maldives": "maldivisk tid (Maldivane)", + "Indian\/Mauritius": "mauritisk tid (Mauritius)", + "Indian\/Mayotte": "austafrikansk tid (Mayotte)", + "Indian\/Reunion": "tidssone for Réunion (Réunion)", + "MST7MDT": "tidssone for Rocky Mountains (USA)", + "PST8PDT": "tidssone for den nordamerikanske stillehavskysten", + "Pacific\/Apia": "tidssone for Apia (Apia)", + "Pacific\/Auckland": "nyzealandsk tid (Auckland)", + "Pacific\/Bougainville": "papuansk tid (Bougainville)", + "Pacific\/Chatham": "tidssone for Chatham (Chatham)", + "Pacific\/Easter": "tidssone for Påskeøya (Påskeøya)", + "Pacific\/Efate": "vanuatisk tid (Efate)", + "Pacific\/Enderbury": "tidssone for Phoenixøyane (Enderbury)", + "Pacific\/Fakaofo": "tidssone for Tokelau (Fakaofo)", + "Pacific\/Fiji": "fijiansk tid (Fiji)", + "Pacific\/Funafuti": "tuvalsk tid (Funafuti)", + "Pacific\/Galapagos": "tidssone for Galápagosøyane (Galápagosøyane)", + "Pacific\/Gambier": "tidssone for Gambier (Gambier)", + "Pacific\/Guadalcanal": "salomonsk tid (Guadalcanal)", + "Pacific\/Guam": "tidssone for Chamorro (Guam)", + "Pacific\/Honolulu": "tidssone for Hawaii og Aleutene (Honolulu)", + "Pacific\/Johnston": "tidssone for Hawaii og Aleutene (Johnston)", + "Pacific\/Kiritimati": "tidssone for Lineøyane (Kiritimati)", + "Pacific\/Kosrae": "tidssone for Kosrae (Kosrae)", + "Pacific\/Kwajalein": "marshallesisk tid (Kwajalein)", + "Pacific\/Majuro": "marshallesisk tid (Majuro)", + "Pacific\/Marquesas": "tidssone for Marquesasøyane (Marquesas)", + "Pacific\/Midway": "samoansk tid (Midway)", + "Pacific\/Nauru": "naurisk tid (Nauru)", + "Pacific\/Niue": "tidssone for Niue (Niue)", + "Pacific\/Norfolk": "tidssone for Norfolkøya (Norfolkøya)", + "Pacific\/Noumea": "kaledonsk tid (Nouméa)", + "Pacific\/Pago_Pago": "samoansk tid (Pago Pago)", + "Pacific\/Palau": "palauisk tid (Palau)", + "Pacific\/Pitcairn": "tidssone for Pitcairn (Pitcairn)", + "Pacific\/Ponape": "tidssone for Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "papuansk tid (Port Moresby)", + "Pacific\/Rarotonga": "tidssone for Cookøyane (Rarotonga)", + "Pacific\/Saipan": "tidssone for Chamorro (Saipan)", + "Pacific\/Tahiti": "tahitisk tid (Tahiti)", + "Pacific\/Tarawa": "tidssone for Gilbertøyane (Tarawa)", + "Pacific\/Tongatapu": "tongansk tid (Tongatapu)", + "Pacific\/Truk": "tidssone for Chuukøyane (Chuuk)", + "Pacific\/Wake": "tidssone for Wake Island (Wake)", + "Pacific\/Wallis": "tidssone for Wallis- og Futunaøyane (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/no.json b/src/Symfony/Component/Intl/Resources/data/timezones/no.json new file mode 100644 index 0000000000000..ef2dd45464cf5 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/no.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwich middeltid (Abidjan)", + "Africa\/Accra": "Greenwich middeltid (Accra)", + "Africa\/Addis_Ababa": "østafrikansk tid (Addis Abeba)", + "Africa\/Algiers": "sentraleuropeisk tid (Alger)", + "Africa\/Asmera": "østafrikansk tid (Asmara)", + "Africa\/Bamako": "Greenwich middeltid (Bamako)", + "Africa\/Bangui": "vestafrikansk tid (Bangui)", + "Africa\/Banjul": "Greenwich middeltid (Banjul)", + "Africa\/Bissau": "Greenwich middeltid (Bissau)", + "Africa\/Blantyre": "sentralafrikansk tid (Blantyre)", + "Africa\/Brazzaville": "vestafrikansk tid (Brazzaville)", + "Africa\/Bujumbura": "sentralafrikansk tid (Bujumbura)", + "Africa\/Cairo": "østeuropeisk tid (Kairo)", + "Africa\/Casablanca": "vesteuropeisk tid (Casablanca)", + "Africa\/Ceuta": "sentraleuropeisk tid (Ceuta)", + "Africa\/Conakry": "Greenwich middeltid (Conakry)", + "Africa\/Dakar": "Greenwich middeltid (Dakar)", + "Africa\/Dar_es_Salaam": "østafrikansk tid (Dar-es-Salaam)", + "Africa\/Djibouti": "østafrikansk tid (Djibouti)", + "Africa\/Douala": "vestafrikansk tid (Douala)", + "Africa\/El_Aaiun": "vesteuropeisk tid (El Aaiún)", + "Africa\/Freetown": "Greenwich middeltid (Freetown)", + "Africa\/Gaborone": "sentralafrikansk tid (Gaborone)", + "Africa\/Harare": "sentralafrikansk tid (Harare)", + "Africa\/Johannesburg": "sørafrikansk tid (Johannesburg)", + "Africa\/Juba": "østafrikansk tid (Juba)", + "Africa\/Kampala": "østafrikansk tid (Kampala)", + "Africa\/Khartoum": "sentralafrikansk tid (Khartoum)", + "Africa\/Kigali": "sentralafrikansk tid (Kigali)", + "Africa\/Kinshasa": "vestafrikansk tid (Kinshasa)", + "Africa\/Lagos": "vestafrikansk tid (Lagos)", + "Africa\/Libreville": "vestafrikansk tid (Libreville)", + "Africa\/Lome": "Greenwich middeltid (Lomé)", + "Africa\/Luanda": "vestafrikansk tid (Luanda)", + "Africa\/Lubumbashi": "sentralafrikansk tid (Lubumbashi)", + "Africa\/Lusaka": "sentralafrikansk tid (Lusaka)", + "Africa\/Malabo": "vestafrikansk tid (Malabo)", + "Africa\/Maputo": "sentralafrikansk tid (Maputo)", + "Africa\/Maseru": "sørafrikansk tid (Maseru)", + "Africa\/Mbabane": "sørafrikansk tid (Mbabane)", + "Africa\/Mogadishu": "østafrikansk tid (Mogadishu)", + "Africa\/Monrovia": "Greenwich middeltid (Monrovia)", + "Africa\/Nairobi": "østafrikansk tid (Nairobi)", + "Africa\/Ndjamena": "vestafrikansk tid (Ndjamena)", + "Africa\/Niamey": "vestafrikansk tid (Niamey)", + "Africa\/Nouakchott": "Greenwich middeltid (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich middeltid (Ouagadougou)", + "Africa\/Porto-Novo": "vestafrikansk tid (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich middeltid (São Tomé)", + "Africa\/Tripoli": "østeuropeisk tid (Tripoli)", + "Africa\/Tunis": "sentraleuropeisk tid (Tunis)", + "Africa\/Windhoek": "sentralafrikansk tid (Windhoek)", + "America\/Adak": "tidssone for Hawaii og Aleutene (Adak)", + "America\/Anchorage": "alaskisk tid (Anchorage)", + "America\/Anguilla": "tidssone for den nordamerikanske atlanterhavskysten (Anguilla)", + "America\/Antigua": "tidssone for den nordamerikanske atlanterhavskysten (Antigua)", + "America\/Araguaina": "tidssone for Brasilia (Araguaína)", + "America\/Argentina\/La_Rioja": "argentinsk tid (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "argentinsk tid (Rio Gallegos)", + "America\/Argentina\/Salta": "argentinsk tid (Salta)", + "America\/Argentina\/San_Juan": "argentinsk tid (San Juan)", + "America\/Argentina\/San_Luis": "vestargentinsk tid (San Luis)", + "America\/Argentina\/Tucuman": "argentinsk tid (Tucumán)", + "America\/Argentina\/Ushuaia": "argentinsk tid (Ushuaia)", + "America\/Aruba": "tidssone for den nordamerikanske atlanterhavskysten (Aruba)", + "America\/Asuncion": "paraguayansk tid (Asunción)", + "America\/Bahia": "tidssone for Brasilia (Bahia)", + "America\/Bahia_Banderas": "tidssone for det sentrale Nord-Amerika (Bahía Banderas)", + "America\/Barbados": "tidssone for den nordamerikanske atlanterhavskysten (Barbados)", + "America\/Belem": "tidssone for Brasilia (Belém)", + "America\/Belize": "tidssone for det sentrale Nord-Amerika (Belize)", + "America\/Blanc-Sablon": "tidssone for den nordamerikanske atlanterhavskysten (Blanc-Sablon)", + "America\/Boa_Vista": "tidssone for Amazonas (Boa Vista)", + "America\/Bogota": "colombiansk tid (Bogotá)", + "America\/Boise": "tidssone for Rocky Mountains (USA) (Boise)", + "America\/Buenos_Aires": "argentinsk tid (Buenos Aires)", + "America\/Cambridge_Bay": "tidssone for Rocky Mountains (USA) (Cambridge Bay)", + "America\/Campo_Grande": "tidssone for Amazonas (Campo Grande)", + "America\/Cancun": "tidssone for den nordamerikanske østkysten (Cancún)", + "America\/Caracas": "venezuelansk tid (Caracas)", + "America\/Catamarca": "argentinsk tid (Catamarca)", + "America\/Cayenne": "tidssone for Fransk Guyana (Cayenne)", + "America\/Cayman": "tidssone for den nordamerikanske østkysten (Caymanøyene)", + "America\/Chicago": "tidssone for det sentrale Nord-Amerika (Chicago)", + "America\/Chihuahua": "tidssone for den meksikanske Stillehavskysten (Chihuahua)", + "America\/Coral_Harbour": "tidssone for den nordamerikanske østkysten (Atikokan)", + "America\/Cordoba": "argentinsk tid (Córdoba)", + "America\/Costa_Rica": "tidssone for det sentrale Nord-Amerika (Costa Rica)", + "America\/Creston": "tidssone for Rocky Mountains (USA) (Creston)", + "America\/Cuiaba": "tidssone for Amazonas (Cuiabá)", + "America\/Curacao": "tidssone for den nordamerikanske atlanterhavskysten (Curaçao)", + "America\/Danmarkshavn": "Greenwich middeltid (Danmarkshavn)", + "America\/Dawson": "tidssone for den nordamerikanske Stillehavskysten (Dawson)", + "America\/Dawson_Creek": "tidssone for Rocky Mountains (USA) (Dawson Creek)", + "America\/Denver": "tidssone for Rocky Mountains (USA) (Denver)", + "America\/Detroit": "tidssone for den nordamerikanske østkysten (Detroit)", + "America\/Dominica": "tidssone for den nordamerikanske atlanterhavskysten (Dominica)", + "America\/Edmonton": "tidssone for Rocky Mountains (USA) (Edmonton)", + "America\/Eirunepe": "Acre-tid (Eirunepe)", + "America\/El_Salvador": "tidssone for det sentrale Nord-Amerika (El Salvador)", + "America\/Fort_Nelson": "tidssone for Rocky Mountains (USA) (Fort Nelson)", + "America\/Fortaleza": "tidssone for Brasilia (Fortaleza)", + "America\/Glace_Bay": "tidssone for den nordamerikanske atlanterhavskysten (Glace Bay)", + "America\/Godthab": "vestgrønlandsk tid (Nuuk)", + "America\/Goose_Bay": "tidssone for den nordamerikanske atlanterhavskysten (Goose Bay)", + "America\/Grand_Turk": "tidssone for den nordamerikanske østkysten (Grand Turk)", + "America\/Grenada": "tidssone for den nordamerikanske atlanterhavskysten (Grenada)", + "America\/Guadeloupe": "tidssone for den nordamerikanske atlanterhavskysten (Guadeloupe)", + "America\/Guatemala": "tidssone for det sentrale Nord-Amerika (Guatemala)", + "America\/Guayaquil": "ecuadoriansk tid (Guayaquil)", + "America\/Guyana": "guyansk tid (Guyana)", + "America\/Halifax": "tidssone for den nordamerikanske atlanterhavskysten (Halifax)", + "America\/Havana": "cubansk tid (Havana)", + "America\/Hermosillo": "tidssone for den meksikanske Stillehavskysten (Hermosillo)", + "America\/Indiana\/Knox": "tidssone for det sentrale Nord-Amerika (Knox, Indiana)", + "America\/Indiana\/Marengo": "tidssone for den nordamerikanske østkysten (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "tidssone for den nordamerikanske østkysten (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "tidssone for det sentrale Nord-Amerika (Tell City, Indiana)", + "America\/Indiana\/Vevay": "tidssone for den nordamerikanske østkysten (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "tidssone for den nordamerikanske østkysten (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "tidssone for den nordamerikanske østkysten (Winamac, Indiana)", + "America\/Indianapolis": "tidssone for den nordamerikanske østkysten (Indianapolis)", + "America\/Inuvik": "tidssone for Rocky Mountains (USA) (Inuvik)", + "America\/Iqaluit": "tidssone for den nordamerikanske østkysten (Iqaluit)", + "America\/Jamaica": "tidssone for den nordamerikanske østkysten (Jamaica)", + "America\/Jujuy": "argentinsk tid (Jujuy)", + "America\/Juneau": "alaskisk tid (Juneau)", + "America\/Kentucky\/Monticello": "tidssone for den nordamerikanske østkysten (Monticello, Kentucky)", + "America\/Kralendijk": "tidssone for den nordamerikanske atlanterhavskysten (Kralendijk)", + "America\/La_Paz": "boliviansk tid (La Paz)", + "America\/Lima": "peruansk tid (Lima)", + "America\/Los_Angeles": "tidssone for den nordamerikanske Stillehavskysten (Los Angeles)", + "America\/Louisville": "tidssone for den nordamerikanske østkysten (Louisville)", + "America\/Lower_Princes": "tidssone for den nordamerikanske atlanterhavskysten (Lower Prince’s Quarter)", + "America\/Maceio": "tidssone for Brasilia (Maceió)", + "America\/Managua": "tidssone for det sentrale Nord-Amerika (Managua)", + "America\/Manaus": "tidssone for Amazonas (Manaus)", + "America\/Marigot": "tidssone for den nordamerikanske atlanterhavskysten (Marigot)", + "America\/Martinique": "tidssone for den nordamerikanske atlanterhavskysten (Martinique)", + "America\/Matamoros": "tidssone for det sentrale Nord-Amerika (Matamoros)", + "America\/Mazatlan": "tidssone for den meksikanske Stillehavskysten (Mazatlan)", + "America\/Mendoza": "argentinsk tid (Mendoza)", + "America\/Menominee": "tidssone for det sentrale Nord-Amerika (Menominee)", + "America\/Merida": "tidssone for det sentrale Nord-Amerika (Mérida)", + "America\/Metlakatla": "alaskisk tid (Metlakatla)", + "America\/Mexico_City": "tidssone for det sentrale Nord-Amerika (Mexico by)", + "America\/Miquelon": "tidssone for Saint-Pierre-et-Miquelon (Miquelon)", + "America\/Moncton": "tidssone for den nordamerikanske atlanterhavskysten (Moncton)", + "America\/Monterrey": "tidssone for det sentrale Nord-Amerika (Monterrey)", + "America\/Montevideo": "uruguayansk tid (Montevideo)", + "America\/Montserrat": "tidssone for den nordamerikanske atlanterhavskysten (Montserrat)", + "America\/Nassau": "tidssone for den nordamerikanske østkysten (Nassau)", + "America\/New_York": "tidssone for den nordamerikanske østkysten (New York)", + "America\/Nipigon": "tidssone for den nordamerikanske østkysten (Nipigon)", + "America\/Nome": "alaskisk tid (Nome)", + "America\/Noronha": "tidssone for Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "tidssone for det sentrale Nord-Amerika (Beulah, Nord-Dakota)", + "America\/North_Dakota\/Center": "tidssone for det sentrale Nord-Amerika (Center, Nord-Dakota)", + "America\/North_Dakota\/New_Salem": "tidssone for det sentrale Nord-Amerika (New Salem, Nord-Dakota)", + "America\/Ojinaga": "tidssone for Rocky Mountains (USA) (Ojinaga)", + "America\/Panama": "tidssone for den nordamerikanske østkysten (Panama)", + "America\/Pangnirtung": "tidssone for den nordamerikanske østkysten (Pangnirtung)", + "America\/Paramaribo": "surinamsk tid (Paramaribo)", + "America\/Phoenix": "tidssone for Rocky Mountains (USA) (Phoenix)", + "America\/Port-au-Prince": "tidssone for den nordamerikanske østkysten (Port-au-Prince)", + "America\/Port_of_Spain": "tidssone for den nordamerikanske atlanterhavskysten (Port of Spain)", + "America\/Porto_Velho": "tidssone for Amazonas (Porto Velho)", + "America\/Puerto_Rico": "tidssone for den nordamerikanske atlanterhavskysten (Puerto Rico)", + "America\/Punta_Arenas": "chilensk tid (Punta Arenas)", + "America\/Rainy_River": "tidssone for det sentrale Nord-Amerika (Rainy River)", + "America\/Rankin_Inlet": "tidssone for det sentrale Nord-Amerika (Rankin Inlet)", + "America\/Recife": "tidssone for Brasilia (Recife)", + "America\/Regina": "tidssone for det sentrale Nord-Amerika (Regina)", + "America\/Resolute": "tidssone for det sentrale Nord-Amerika (Resolute)", + "America\/Rio_Branco": "Acre-tid (Rio Branco)", + "America\/Santa_Isabel": "tidssone for nordvestlige Mexico (Santa Isabel)", + "America\/Santarem": "tidssone for Brasilia (Santarém)", + "America\/Santiago": "chilensk tid (Santiago)", + "America\/Santo_Domingo": "tidssone for den nordamerikanske atlanterhavskysten (Santo Domingo)", + "America\/Sao_Paulo": "tidssone for Brasilia (São Paulo)", + "America\/Scoresbysund": "østgrønlandsk tid (Ittoqqortoormiit)", + "America\/Sitka": "alaskisk tid (Sitka)", + "America\/St_Barthelemy": "tidssone for den nordamerikanske atlanterhavskysten (Saint-Barthélemy)", + "America\/St_Johns": "tidssone for Newfoundland (St. John’s)", + "America\/St_Kitts": "tidssone for den nordamerikanske atlanterhavskysten (St. Kitts)", + "America\/St_Lucia": "tidssone for den nordamerikanske atlanterhavskysten (St. Lucia)", + "America\/St_Thomas": "tidssone for den nordamerikanske atlanterhavskysten (St. Thomas)", + "America\/St_Vincent": "tidssone for den nordamerikanske atlanterhavskysten (St. Vincent)", + "America\/Swift_Current": "tidssone for det sentrale Nord-Amerika (Swift Current)", + "America\/Tegucigalpa": "tidssone for det sentrale Nord-Amerika (Tegucigalpa)", + "America\/Thule": "tidssone for den nordamerikanske atlanterhavskysten (Thule)", + "America\/Thunder_Bay": "tidssone for den nordamerikanske østkysten (Thunder Bay)", + "America\/Tijuana": "tidssone for den nordamerikanske Stillehavskysten (Tijuana)", + "America\/Toronto": "tidssone for den nordamerikanske østkysten (Toronto)", + "America\/Tortola": "tidssone for den nordamerikanske atlanterhavskysten (Tortola)", + "America\/Vancouver": "tidssone for den nordamerikanske Stillehavskysten (Vancouver)", + "America\/Whitehorse": "tidssone for den nordamerikanske Stillehavskysten (Whitehorse)", + "America\/Winnipeg": "tidssone for det sentrale Nord-Amerika (Winnipeg)", + "America\/Yakutat": "alaskisk tid (Yakutat)", + "America\/Yellowknife": "tidssone for Rocky Mountains (USA) (Yellowknife)", + "Antarctica\/Casey": "vestaustralsk tid (Casey)", + "Antarctica\/Davis": "tidssone for Davis (Davis)", + "Antarctica\/DumontDUrville": "tidssone for Dumont d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "tidssone for Macquarieøya (Macquarie)", + "Antarctica\/Mawson": "tidssone for Mawson (Mawson)", + "Antarctica\/McMurdo": "newzealandsk tid (McMurdo)", + "Antarctica\/Palmer": "chilensk tid (Palmer)", + "Antarctica\/Rothera": "tidssone for Rothera (Rothera)", + "Antarctica\/Syowa": "tidssone for Syowa (Syowa)", + "Antarctica\/Troll": "Greenwich middeltid (Troll)", + "Antarctica\/Vostok": "tidssone for Vostok (Vostok)", + "Arctic\/Longyearbyen": "sentraleuropeisk tid (Longyearbyen)", + "Asia\/Aden": "arabisk tid (Aden)", + "Asia\/Almaty": "østkasakhstansk tid (Almaty)", + "Asia\/Amman": "østeuropeisk tid (Amman)", + "Asia\/Anadyr": "Russisk (Anadyr) tid (Anadyr)", + "Asia\/Aqtau": "vestkasakhstansk tid (Aktau)", + "Asia\/Aqtobe": "vestkasakhstansk tid (Aqtöbe)", + "Asia\/Ashgabat": "turkmensk tid (Asjkhabad)", + "Asia\/Atyrau": "vestkasakhstansk tid (Atyrau)", + "Asia\/Baghdad": "arabisk tid (Bagdad)", + "Asia\/Bahrain": "arabisk tid (Bahrain)", + "Asia\/Baku": "aserbajdsjansk tid (Baku)", + "Asia\/Bangkok": "indokinesisk tid (Bangkok)", + "Asia\/Beirut": "østeuropeisk tid (Beirut)", + "Asia\/Bishkek": "kirgisisk tid (Bisjkek)", + "Asia\/Brunei": "tidssone for Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "indisk tid (Kolkata)", + "Asia\/Chita": "tidssone for Jakutsk (Tsjita)", + "Asia\/Choibalsan": "tidssone for Tsjojbalsan (Choybalsan)", + "Asia\/Colombo": "indisk tid (Colombo)", + "Asia\/Damascus": "østeuropeisk tid (Damaskus)", + "Asia\/Dhaka": "bangladeshisk tid (Dhaka)", + "Asia\/Dili": "østtimoresisk tid (Dili)", + "Asia\/Dubai": "tidssone for Persiabukta (Dubai)", + "Asia\/Dushanbe": "tadsjikisk tid (Dusjanbe)", + "Asia\/Famagusta": "østeuropeisk tid (Famagusta)", + "Asia\/Gaza": "østeuropeisk tid (Gaza)", + "Asia\/Hebron": "østeuropeisk tid (Hebron)", + "Asia\/Hong_Kong": "tidssone for Hongkong (Hongkong)", + "Asia\/Hovd": "tidssone for Khovd (Hovd)", + "Asia\/Irkutsk": "tidssone for Irkutsk (Irkutsk)", + "Asia\/Jakarta": "vestindonesisk tid (Jakarta)", + "Asia\/Jayapura": "østindonesisk tid (Jajapura)", + "Asia\/Jerusalem": "israelsk tid (Jerusalem)", + "Asia\/Kabul": "afghansk tid (Kabul)", + "Asia\/Kamchatka": "Russisk (Petropavlovsk-Kamtsjatskij) tid (Kamtsjatka)", + "Asia\/Karachi": "pakistansk tid (Karachi)", + "Asia\/Katmandu": "nepalsk tid (Katmandu)", + "Asia\/Khandyga": "tidssone for Jakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "tidssone for Krasnojarsk (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "malaysisk tid (Kuala Lumpur)", + "Asia\/Kuching": "malaysisk tid (Kuching)", + "Asia\/Kuwait": "arabisk tid (Kuwait)", + "Asia\/Macau": "kinesisk tid (Macao)", + "Asia\/Magadan": "tidssone for Magadan (Magadan)", + "Asia\/Makassar": "sentralindonesisk tid (Makassar)", + "Asia\/Manila": "filippinsk tid (Manila)", + "Asia\/Muscat": "tidssone for Persiabukta (Muskat)", + "Asia\/Nicosia": "østeuropeisk tid (Nikosia)", + "Asia\/Novokuznetsk": "tidssone for Krasnojarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "tidssone for Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "tidssone for Omsk (Omsk)", + "Asia\/Oral": "vestkasakhstansk tid (Oral)", + "Asia\/Phnom_Penh": "indokinesisk tid (Phnom Penh)", + "Asia\/Pontianak": "vestindonesisk tid (Pontianak)", + "Asia\/Pyongyang": "koreansk tid (Pyongyang)", + "Asia\/Qatar": "arabisk tid (Qatar)", + "Asia\/Qostanay": "østkasakhstansk tid (Kostanay)", + "Asia\/Qyzylorda": "vestkasakhstansk tid (Kyzylorda)", + "Asia\/Rangoon": "myanmarsk tid (Yangon)", + "Asia\/Riyadh": "arabisk tid (Riyadh)", + "Asia\/Saigon": "indokinesisk tid (Ho Chi Minh-byen)", + "Asia\/Sakhalin": "tidssone for Sakhalin (Sakhalin)", + "Asia\/Samarkand": "usbekisk tid (Samarkand)", + "Asia\/Seoul": "koreansk tid (Seoul)", + "Asia\/Shanghai": "kinesisk tid (Shanghai)", + "Asia\/Singapore": "singaporsk tid (Singapore)", + "Asia\/Srednekolymsk": "tidssone for Magadan (Srednekolymsk)", + "Asia\/Taipei": "tidssone for Taipei (Taipei)", + "Asia\/Tashkent": "usbekisk tid (Tasjkent)", + "Asia\/Tbilisi": "georgisk tid (Tbilisi)", + "Asia\/Tehran": "iransk tid (Teheran)", + "Asia\/Thimphu": "bhutansk tid (Thimpu)", + "Asia\/Tokyo": "japansk tid (Tokyo)", + "Asia\/Ulaanbaatar": "tidssone for Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "tidssone for Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "indokinesisk tid (Vientiane)", + "Asia\/Vladivostok": "tidssone for Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "tidssone for Jakutsk (Jakutsk)", + "Asia\/Yekaterinburg": "tidssone for Jekaterinburg (Jekaterinburg)", + "Asia\/Yerevan": "armensk tid (Jerevan)", + "Atlantic\/Azores": "asorisk tid (Asorene)", + "Atlantic\/Bermuda": "tidssone for den nordamerikanske atlanterhavskysten (Bermuda)", + "Atlantic\/Canary": "vesteuropeisk tid (Kanariøyene)", + "Atlantic\/Cape_Verde": "kappverdisk tid (Kapp Verde)", + "Atlantic\/Faeroe": "vesteuropeisk tid (Færøyene)", + "Atlantic\/Madeira": "vesteuropeisk tid (Madeira)", + "Atlantic\/Reykjavik": "Greenwich middeltid (Reykjavík)", + "Atlantic\/South_Georgia": "tidssone for Sør-Georgia (Sør-Georgia)", + "Atlantic\/St_Helena": "Greenwich middeltid (St. Helena)", + "Atlantic\/Stanley": "tidssone for Falklandsøyene (Stanley)", + "Australia\/Adelaide": "sentralaustralsk tid (Adelaide)", + "Australia\/Brisbane": "østaustralsk tid (Brisbane)", + "Australia\/Broken_Hill": "sentralaustralsk tid (Broken Hill)", + "Australia\/Currie": "østaustralsk tid (Currie)", + "Australia\/Darwin": "sentralaustralsk tid (Darwin)", + "Australia\/Eucla": "vest-sentralaustralsk tid (Eucla)", + "Australia\/Hobart": "østaustralsk tid (Hobart)", + "Australia\/Lindeman": "østaustralsk tid (Lindeman)", + "Australia\/Lord_Howe": "tidssone for Lord Howe-øya (Lord Howe)", + "Australia\/Melbourne": "østaustralsk tid (Melbourne)", + "Australia\/Perth": "vestaustralsk tid (Perth)", + "Australia\/Sydney": "østaustralsk tid (Sydney)", + "CST6CDT": "tidssone for det sentrale Nord-Amerika", + "EST5EDT": "tidssone for den nordamerikanske østkysten", + "Etc\/GMT": "Greenwich middeltid", + "Etc\/UTC": "koordinert universaltid", + "Europe\/Amsterdam": "sentraleuropeisk tid (Amsterdam)", + "Europe\/Andorra": "sentraleuropeisk tid (Andorra)", + "Europe\/Astrakhan": "tidssone for Moskva (Astrakhan)", + "Europe\/Athens": "østeuropeisk tid (Athen)", + "Europe\/Belgrade": "sentraleuropeisk tid (Beograd)", + "Europe\/Berlin": "sentraleuropeisk tid (Berlin)", + "Europe\/Bratislava": "sentraleuropeisk tid (Bratislava)", + "Europe\/Brussels": "sentraleuropeisk tid (Brussel)", + "Europe\/Bucharest": "østeuropeisk tid (București)", + "Europe\/Budapest": "sentraleuropeisk tid (Budapest)", + "Europe\/Busingen": "sentraleuropeisk tid (Büsingen)", + "Europe\/Chisinau": "østeuropeisk tid (Chișinău)", + "Europe\/Copenhagen": "sentraleuropeisk tid (København)", + "Europe\/Dublin": "Greenwich middeltid (Dublin)", + "Europe\/Gibraltar": "sentraleuropeisk tid (Gibraltar)", + "Europe\/Guernsey": "Greenwich middeltid (Guernsey)", + "Europe\/Helsinki": "østeuropeisk tid (Helsingfors)", + "Europe\/Isle_of_Man": "Greenwich middeltid (Man)", + "Europe\/Jersey": "Greenwich middeltid (Jersey)", + "Europe\/Kaliningrad": "østeuropeisk tid (Kaliningrad)", + "Europe\/Kiev": "østeuropeisk tid (Kiev)", + "Europe\/Lisbon": "vesteuropeisk tid (Lisboa)", + "Europe\/Ljubljana": "sentraleuropeisk tid (Ljubljana)", + "Europe\/London": "Greenwich middeltid (London)", + "Europe\/Luxembourg": "sentraleuropeisk tid (Luxemburg)", + "Europe\/Madrid": "sentraleuropeisk tid (Madrid)", + "Europe\/Malta": "sentraleuropeisk tid (Malta)", + "Europe\/Mariehamn": "østeuropeisk tid (Mariehamn)", + "Europe\/Minsk": "tidssone for Moskva (Minsk)", + "Europe\/Monaco": "sentraleuropeisk tid (Monaco)", + "Europe\/Moscow": "tidssone for Moskva (Moskva)", + "Europe\/Oslo": "sentraleuropeisk tid (Oslo)", + "Europe\/Paris": "sentraleuropeisk tid (Paris)", + "Europe\/Podgorica": "sentraleuropeisk tid (Podgorica)", + "Europe\/Prague": "sentraleuropeisk tid (Praha)", + "Europe\/Riga": "østeuropeisk tid (Riga)", + "Europe\/Rome": "sentraleuropeisk tid (Roma)", + "Europe\/Samara": "Russisk (Samara) tid (Samara)", + "Europe\/San_Marino": "sentraleuropeisk tid (San Marino)", + "Europe\/Sarajevo": "sentraleuropeisk tid (Sarajevo)", + "Europe\/Saratov": "tidssone for Moskva (Saratov)", + "Europe\/Simferopol": "tidssone for Moskva (Simferopol)", + "Europe\/Skopje": "sentraleuropeisk tid (Skopje)", + "Europe\/Sofia": "østeuropeisk tid (Sofia)", + "Europe\/Stockholm": "sentraleuropeisk tid (Stockholm)", + "Europe\/Tallinn": "østeuropeisk tid (Tallinn)", + "Europe\/Tirane": "sentraleuropeisk tid (Tirana)", + "Europe\/Ulyanovsk": "tidssone for Moskva (Uljanovsk)", + "Europe\/Uzhgorod": "østeuropeisk tid (Uzjhorod)", + "Europe\/Vaduz": "sentraleuropeisk tid (Vaduz)", + "Europe\/Vatican": "sentraleuropeisk tid (Vatikanstaten)", + "Europe\/Vienna": "sentraleuropeisk tid (Wien)", + "Europe\/Vilnius": "østeuropeisk tid (Vilnius)", + "Europe\/Volgograd": "tidssone for Volgograd (Volgograd)", + "Europe\/Warsaw": "sentraleuropeisk tid (Warszawa)", + "Europe\/Zagreb": "sentraleuropeisk tid (Zagreb)", + "Europe\/Zaporozhye": "østeuropeisk tid (Zaporizjzja)", + "Europe\/Zurich": "sentraleuropeisk tid (Zürich)", + "Indian\/Antananarivo": "østafrikansk tid (Antananarivo)", + "Indian\/Chagos": "tidssone for Indiahavet (Chagos)", + "Indian\/Christmas": "tidssone for Christmasøya (Christmasøya)", + "Indian\/Cocos": "tidssone for Kokosøyene (Kokosøyene)", + "Indian\/Comoro": "østafrikansk tid (Komorene)", + "Indian\/Kerguelen": "tidssone for De franske sørterritorier (Kerguelen)", + "Indian\/Mahe": "seychellisk tid (Mahé)", + "Indian\/Maldives": "maldivisk tid (Maldivene)", + "Indian\/Mauritius": "mauritisk tid (Mauritius)", + "Indian\/Mayotte": "østafrikansk tid (Mayotte)", + "Indian\/Reunion": "tidssone for Réunion (Réunion)", + "MST7MDT": "tidssone for Rocky Mountains (USA)", + "PST8PDT": "tidssone for den nordamerikanske Stillehavskysten", + "Pacific\/Apia": "tidssone for Apia (Apia)", + "Pacific\/Auckland": "newzealandsk tid (Auckland)", + "Pacific\/Bougainville": "papuansk tid (Bougainville)", + "Pacific\/Chatham": "tidssone for Chatham (Chatham)", + "Pacific\/Easter": "tidssone for Påskeøya (Påskeøya)", + "Pacific\/Efate": "vanuatisk tid (Efate)", + "Pacific\/Enderbury": "tidssone for Phoenixøyene (Enderbury)", + "Pacific\/Fakaofo": "tidssone for Tokelau (Fakaofo)", + "Pacific\/Fiji": "fijiansk tid (Fiji)", + "Pacific\/Funafuti": "tuvalsk tid (Funafuti)", + "Pacific\/Galapagos": "tidssone for Galápagosøyene (Galápagosøyene)", + "Pacific\/Gambier": "tidssone for Gambier (Gambier)", + "Pacific\/Guadalcanal": "salomonsk tid (Guadalcanal)", + "Pacific\/Guam": "tidssone for Chamorro (Guam)", + "Pacific\/Honolulu": "tidssone for Hawaii og Aleutene (Honolulu)", + "Pacific\/Johnston": "tidssone for Hawaii og Aleutene (Johnston)", + "Pacific\/Kiritimati": "tidssone for Linjeøyene (Kiritimati)", + "Pacific\/Kosrae": "tidssone for Kosrae (Kosrae)", + "Pacific\/Kwajalein": "marshallesisk tid (Kwajalein)", + "Pacific\/Majuro": "marshallesisk tid (Majuro)", + "Pacific\/Marquesas": "tidssone for Marquesasøyene (Marquesas)", + "Pacific\/Midway": "samoansk tid (Midway)", + "Pacific\/Nauru": "naurisk tid (Nauru)", + "Pacific\/Niue": "tidssone for Niue (Niue)", + "Pacific\/Norfolk": "tidssone for Norfolkøya (Norfolkøya)", + "Pacific\/Noumea": "kaledonsk tid (Nouméa)", + "Pacific\/Pago_Pago": "samoansk tid (Pago Pago)", + "Pacific\/Palau": "palauisk tid (Palau)", + "Pacific\/Pitcairn": "tidssone for Pitcairn (Pitcairn)", + "Pacific\/Ponape": "tidssone for Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "papuansk tid (Port Moresby)", + "Pacific\/Rarotonga": "tidssone for Cookøyene (Rarotonga)", + "Pacific\/Saipan": "tidssone for Chamorro (Saipan)", + "Pacific\/Tahiti": "tahitisk tid (Tahiti)", + "Pacific\/Tarawa": "tidssone for Gilbertøyene (Tarawa)", + "Pacific\/Tongatapu": "tongansk tid (Tongatapu)", + "Pacific\/Truk": "tidssone for Chuukøyene (Chuuk)", + "Pacific\/Wake": "tidssone for Wake Island (Wake)", + "Pacific\/Wallis": "tidssone for Wallis- og Futunaøyene (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/om.json b/src/Symfony/Component/Intl/Resources/data/timezones/om.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/om.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/or.json b/src/Symfony/Component/Intl/Resources/data/timezones/or.json new file mode 100644 index 0000000000000..3f932dbd4575e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/or.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଆବିଦଜାନ)", + "Africa\/Accra": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଆକାରା)", + "Africa\/Addis_Ababa": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ଆଦିସ୍‌ ଆବାବା)", + "Africa\/Algiers": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଅଲଜିୟର୍ସ)", + "Africa\/Asmera": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ଅସମରା)", + "Africa\/Bamako": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ବାମାକୋ)", + "Africa\/Bangui": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ବାଙ୍ଗୁଇ)", + "Africa\/Banjul": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ବାଞ୍ଜୁଲ)", + "Africa\/Bissau": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ବିସାଉ)", + "Africa\/Blantyre": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ବ୍ଲାଣ୍ଟାୟାର୍‌)", + "Africa\/Brazzaville": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ବ୍ରାଜାଭିଲ୍ଲେ)", + "Africa\/Bujumbura": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ବୁଜୁମ୍ବୁରା)", + "Africa\/Cairo": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (କାଇରୋ)", + "Africa\/Casablanca": "ପଶ୍ଚିମାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (କାସାବ୍ଲାଙ୍କା)", + "Africa\/Ceuta": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ସେଉଟା)", + "Africa\/Conakry": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (କୋନାକ୍ରି)", + "Africa\/Dakar": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଡକାର)", + "Africa\/Dar_es_Salaam": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ଡର୍‌ ଇସ୍‌ ସାଲାମ)", + "Africa\/Djibouti": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ଜିବୋଟି)", + "Africa\/Douala": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ଡଉଲା)", + "Africa\/El_Aaiun": "ପଶ୍ଚିମାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଏଲ୍‌ ଏୟନ୍)", + "Africa\/Freetown": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଫ୍ରିଟାଉନ୍‌)", + "Africa\/Gaborone": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ଗାବୋର୍ଣ୍ଣ)", + "Africa\/Harare": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ହରାରେ)", + "Africa\/Johannesburg": "ଦକ୍ଷିଣ ଆଫ୍ରିକା ମାନାଙ୍କ ସମୟ (ଜୋହାନ୍ସବର୍ଗ)", + "Africa\/Juba": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ଜୁବା)", + "Africa\/Kampala": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (କାମ୍ପାଲା)", + "Africa\/Khartoum": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ଖରଟୌମ୍‌)", + "Africa\/Kigali": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (କିଗାଲି)", + "Africa\/Kinshasa": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (କିନସାସ୍‌)", + "Africa\/Lagos": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ଲାଗୋସ୍‌)", + "Africa\/Libreville": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ଲିବ୍ରେଭିଲ୍ଲେ)", + "Africa\/Lome": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଲୋମ୍‌)", + "Africa\/Luanda": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ଲୁଆଣ୍ଡା)", + "Africa\/Lubumbashi": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ଲୁବୁମ୍ବାଶି)", + "Africa\/Lusaka": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ଲୁସାକା)", + "Africa\/Malabo": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ମାଲାବୋ)", + "Africa\/Maputo": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ମାପୁତୋ)", + "Africa\/Maseru": "ଦକ୍ଷିଣ ଆଫ୍ରିକା ମାନାଙ୍କ ସମୟ (ମେସେରୁ)", + "Africa\/Mbabane": "ଦକ୍ଷିଣ ଆଫ୍ରିକା ମାନାଙ୍କ ସମୟ (ବାବେନ୍‌)", + "Africa\/Mogadishu": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ମୋଗାଡିଶୁ)", + "Africa\/Monrovia": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ମନରୋଭିଆ)", + "Africa\/Nairobi": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ନାଇରୋବି)", + "Africa\/Ndjamena": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ଜାମେନା)", + "Africa\/Niamey": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ନିଆମି)", + "Africa\/Nouakchott": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ନୌକାଚୋଟ)", + "Africa\/Ouagadougou": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଅଉଗାଡଉଗଉ)", + "Africa\/Porto-Novo": "ପଶ୍ଚିମ ଆଫ୍ରିକା ସମୟ (ପୋଟୋ-ନୋଭୋ)", + "Africa\/Sao_Tome": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ସାଓ ଟୋମେ)", + "Africa\/Tripoli": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ତ୍ରିପୋଲି)", + "Africa\/Tunis": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଟୁନିସ୍‌)", + "Africa\/Windhoek": "ମଧ୍ୟ ଆଫ୍ରିକା ସମୟ (ୱିଣ୍ଡହୋଏକ୍)", + "America\/Adak": "ହୱାଇ-ଆଲେଉଟିୟ ସମୟ (ଆଡାକ୍)", + "America\/Anchorage": "ଆଲାସ୍କା ସମୟ (ଆଙ୍କରେଜ୍)", + "America\/Anguilla": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଆଙ୍ଗୁଇଲା)", + "America\/Antigua": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଆଣ୍ଟିଗୁଆ)", + "America\/Araguaina": "ବ୍ରାସିଲିଆ ସମୟ (ଆରାଗୁଆନା)", + "America\/Argentina\/La_Rioja": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ଲା ରିଓଜା)", + "America\/Argentina\/Rio_Gallegos": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ରିଓ ଗାଲ୍ଲେଗସ୍‌)", + "America\/Argentina\/Salta": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ସଲ୍ଟା)", + "America\/Argentina\/San_Juan": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ସାନ୍‌ ଜୁଆନ)", + "America\/Argentina\/San_Luis": "ପଶ୍ଚିମ ଆର୍ଜେଣ୍ଟିନା ସମୟ (ସାନ୍‌ ଲୁଇସ୍‌)", + "America\/Argentina\/Tucuman": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ଟୁକୁମାନ୍‌)", + "America\/Argentina\/Ushuaia": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ଉଶୁୟା)", + "America\/Aruba": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଆରୁବା)", + "America\/Asuncion": "ପାରାଗୁଏ ସମୟ (ଆସନସିଅନ୍‌)", + "America\/Bahia": "ବ୍ରାସିଲିଆ ସମୟ (ବାହିଆ)", + "America\/Bahia_Banderas": "କେନ୍ଦ୍ରୀୟ ସମୟ (ବାହିଆ ବ୍ୟାଣ୍ଡେରାସ୍)", + "America\/Barbados": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ବାର୍ବାଡୋସ୍)", + "America\/Belem": "ବ୍ରାସିଲିଆ ସମୟ (ବେଲେମ)", + "America\/Belize": "କେନ୍ଦ୍ରୀୟ ସମୟ (ବେଲିଜେ)", + "America\/Blanc-Sablon": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ବ୍ଲାଙ୍କ-ସାବଲୋନ୍)", + "America\/Boa_Vista": "ଆମାଜନ୍ ସମୟ (ବୋଆ ଭିଷ୍ଟା)", + "America\/Bogota": "କଲମ୍ବିଆ ସମୟ (ବୋଗୋଟା)", + "America\/Boise": "ପାର୍ବତ୍ୟ ସମୟ (ବୋଇସେ)", + "America\/Buenos_Aires": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ବୁଏନସ୍‌ ଏରିସ୍‌)", + "America\/Cambridge_Bay": "ପାର୍ବତ୍ୟ ସମୟ (କେମ୍ଵ୍ରିଜ୍ ବେ)", + "America\/Campo_Grande": "ଆମାଜନ୍ ସମୟ (କାମ୍ପୋ ଗ୍ରାଣ୍ଡେ)", + "America\/Cancun": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (କାନକୁନ୍)", + "America\/Caracas": "ଭେନିଜୁଏଲା ସମୟ (କାରକାସ୍‌)", + "America\/Catamarca": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (କାଟାମାର୍କା)", + "America\/Cayenne": "ଫ୍ରେଞ୍ଚ ଗୁଆନା ସମୟ (କେୟେନ୍ନି)", + "America\/Cayman": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (କାୟମ୍ୟାନ୍)", + "America\/Chicago": "କେନ୍ଦ୍ରୀୟ ସମୟ (ଚିକାଗୋ)", + "America\/Chihuahua": "ମେକ୍ସିକାନ୍ ପାସିଫିକ୍ ସମୟ (ଚିହୁଆହୁଆ)", + "America\/Coral_Harbour": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଆଟିକୋକାନ୍)", + "America\/Cordoba": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (କୋର୍ଡୋବା)", + "America\/Costa_Rica": "କେନ୍ଦ୍ରୀୟ ସମୟ (କୋଷ୍ଟା ରିକା)", + "America\/Creston": "ପାର୍ବତ୍ୟ ସମୟ (କ୍ରେଷ୍ଟୋନ୍)", + "America\/Cuiaba": "ଆମାଜନ୍ ସମୟ (କୁଇବା)", + "America\/Curacao": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (କୁରାକୋ)", + "America\/Danmarkshavn": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଡାନମାର୍କସାଭନ୍)", + "America\/Dawson": "ପାସିଫିକ୍ ସମୟ (ଡସନ୍‌)", + "America\/Dawson_Creek": "ପାର୍ବତ୍ୟ ସମୟ (ଡୱସନ୍ କ୍ରିକ୍)", + "America\/Denver": "ପାର୍ବତ୍ୟ ସମୟ (ଡେନଭିର୍)", + "America\/Detroit": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଡେଟ୍ରୋଇଟ୍)", + "America\/Dominica": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଡୋମିନିକା)", + "America\/Edmonton": "ପାର୍ବତ୍ୟ ସମୟ (ଏଡମୋନଟୋନ୍)", + "America\/El_Salvador": "କେନ୍ଦ୍ରୀୟ ସମୟ (ଏଲ୍ ସାଲଭାଡୋର୍)", + "America\/Fort_Nelson": "ପାର୍ବତ୍ୟ ସମୟ (ଫୋର୍ଟ୍ ନେଲସନ୍)", + "America\/Fortaleza": "ବ୍ରାସିଲିଆ ସମୟ (ଫୋର୍ଟେଲେଜା)", + "America\/Glace_Bay": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଗ୍ଲାସେ ବେ)", + "America\/Godthab": "ପଶ୍ଚିମ ଗ୍ରୀନଲ୍ୟାଣ୍ଡ୍ ସମୟ (ନୁଉକ୍)", + "America\/Goose_Bay": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଗୁସ୍ ବେ)", + "America\/Grand_Turk": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଗ୍ରାଣ୍ଡ୍ ଟର୍କ୍)", + "America\/Grenada": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଗ୍ରେନାଡା)", + "America\/Guadeloupe": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଗୁଆଡେଲୋଉପେ)", + "America\/Guatemala": "କେନ୍ଦ୍ରୀୟ ସମୟ (ଗୁଆତେମାଲା)", + "America\/Guayaquil": "ଇକ୍ୱେଡର ସମୟ (ଗୁୟାକ୍ୱିଲ)", + "America\/Guyana": "ଗୁଏନା ସମୟ (ଗୁଏନା)", + "America\/Halifax": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ହାଲିଫ୍ୟାକ୍ସ୍)", + "America\/Havana": "କ୍ୟୁବା ସମୟ (ହାଭାନା)", + "America\/Hermosillo": "ମେକ୍ସିକାନ୍ ପାସିଫିକ୍ ସମୟ (ହେରମୋସିଲୋ)", + "America\/Indiana\/Knox": "କେନ୍ଦ୍ରୀୟ ସମୟ (କ୍ନୋକ୍ସ, ଇଣ୍ଡିଆନା)", + "America\/Indiana\/Marengo": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ମାରେନଗୋ, ଇଣ୍ଡିଆନା)", + "America\/Indiana\/Petersburg": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ପେଟେର୍ସବର୍ଗ୍, ଇଣ୍ଡିଆନା)", + "America\/Indiana\/Tell_City": "କେନ୍ଦ୍ରୀୟ ସମୟ (ଟେଲ୍ ସିଟି, ଇଣ୍ଡିଆନା)", + "America\/Indiana\/Vevay": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଭେଭାୟ, ଇଣ୍ଡିଆନା)", + "America\/Indiana\/Vincennes": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଭିନସେନ୍ନେସ୍, ଇଣ୍ଡିଆନା)", + "America\/Indiana\/Winamac": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ୱିନାମାକ୍, ଇଣ୍ଡିଆନା)", + "America\/Indianapolis": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଇଣ୍ଡିଆନାପୋଲିସ୍)", + "America\/Inuvik": "ପାର୍ବତ୍ୟ ସମୟ (ଇନୁଭିକ୍)", + "America\/Iqaluit": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଇକ୍ଵାଲୁଇଟ୍)", + "America\/Jamaica": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଜାମାଇକା)", + "America\/Jujuy": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ଜୁଜୁଇ)", + "America\/Juneau": "ଆଲାସ୍କା ସମୟ (ଜୁନେଆଉ)", + "America\/Kentucky\/Monticello": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ମୋଣ୍ଟିସେଲୋ, କେଣ୍ଟଉକିକେ)", + "America\/Kralendijk": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (କ୍ରାଲେଣ୍ଡଜିକ)", + "America\/La_Paz": "ବଲିଭିଆ ସମୟ (ଲା ପାଜ୍‌)", + "America\/Lima": "ପେରୁ ସମୟ (ଲିମା)", + "America\/Los_Angeles": "ପାସିଫିକ୍ ସମୟ (ଲସ୍ ଏଞ୍ଜେଲେସ୍)", + "America\/Louisville": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଲୌଇସଭିଲ୍ଲେ)", + "America\/Lower_Princes": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ନିମ୍ନ ପ୍ରିନ୍ସ’ର କ୍ଵାଟର୍)", + "America\/Maceio": "ବ୍ରାସିଲିଆ ସମୟ (ମାସିଓ)", + "America\/Managua": "କେନ୍ଦ୍ରୀୟ ସମୟ (ମାନାଗୁଆ)", + "America\/Manaus": "ଆମାଜନ୍ ସମୟ (ମାନାଉସ୍‌)", + "America\/Marigot": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ମାରିଗୋଟ୍)", + "America\/Martinique": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ମାର୍ଟିନିକ୍ୟୁ)", + "America\/Matamoros": "କେନ୍ଦ୍ରୀୟ ସମୟ (ମାଟାମୋରୋସ୍)", + "America\/Mazatlan": "ମେକ୍ସିକାନ୍ ପାସିଫିକ୍ ସମୟ (ମାନାଟଲାନ୍)", + "America\/Mendoza": "ଆର୍ଜେଣ୍ଟିନା ସମୟ (ମେଣ୍ଡୋଜା)", + "America\/Menominee": "କେନ୍ଦ୍ରୀୟ ସମୟ (ମେନୋମିନି)", + "America\/Merida": "କେନ୍ଦ୍ରୀୟ ସମୟ (ମେରିଡା)", + "America\/Metlakatla": "ଆଲାସ୍କା ସମୟ (ମାଟଲାକାଟଲା)", + "America\/Mexico_City": "କେନ୍ଦ୍ରୀୟ ସମୟ (ମେକ୍ସିକୋ ସିଟି)", + "America\/Miquelon": "ସେଣ୍ଟ. ପିଏରେ ଏବଂ ମିକ୍ୟୁଲୋନ୍ ସମୟ (ମିକ୍ଵେଲୋନ୍)", + "America\/Moncton": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ମାନକଟୋନ୍)", + "America\/Monterrey": "କେନ୍ଦ୍ରୀୟ ସମୟ (ମୋନଟେରିଏ)", + "America\/Montevideo": "ଉରୁଗୁଏ ସମୟ (ମଣ୍ଟେଭିଡିଓ)", + "America\/Montserrat": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ମୋନଟସେରରାଟ୍)", + "America\/Nassau": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ନାସାଉ)", + "America\/New_York": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ନ୍ୟୁ ୟୋର୍କ୍)", + "America\/Nipigon": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ନିପିଗୋନ୍)", + "America\/Nome": "ଆଲାସ୍କା ସମୟ (ନୋମେ)", + "America\/Noronha": "ଫର୍ଣ୍ଣାଣ୍ଡୋ ଡି ନୋରୋନ୍ନା ସମୟ (ନୋରୋନ୍ନା)", + "America\/North_Dakota\/Beulah": "କେନ୍ଦ୍ରୀୟ ସମୟ (ବେଉଲାହ, ଉତ୍ତର ଡାକୋଟା)", + "America\/North_Dakota\/Center": "କେନ୍ଦ୍ରୀୟ ସମୟ (କେନ୍ଦ୍ର, ଉତ୍ତର ଡାକୋଟା)", + "America\/North_Dakota\/New_Salem": "କେନ୍ଦ୍ରୀୟ ସମୟ (ନ୍ୟୁ ସାଲେମ୍, ଉତ୍ତର ଡାକୋଟା)", + "America\/Ojinaga": "ପାର୍ବତ୍ୟ ସମୟ (ଓଜିନାଗା)", + "America\/Panama": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ପାନାମା)", + "America\/Pangnirtung": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ପାଙ୍ଗନିର୍ଟୁଙ୍ଗ)", + "America\/Paramaribo": "ସୁରିନେମ୍‌ ସମୟ (ପାରାମାରିବୋ)", + "America\/Phoenix": "ପାର୍ବତ୍ୟ ସମୟ (ଫୋଇନିକ୍ସ)", + "America\/Port-au-Prince": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ପୋର୍ଟ୍-ଏୟୁ-ପ୍ରିନ୍ସ)", + "America\/Port_of_Spain": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ପୋର୍ଟ୍ ଅଫ୍ ସ୍ପେନ୍)", + "America\/Porto_Velho": "ଆମାଜନ୍ ସମୟ (ପୋର୍ଟୋ ଭେଲୋ)", + "America\/Puerto_Rico": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ପୁଏର୍ତୋ ରିକୋ)", + "America\/Punta_Arenas": "ଚିଲି ସମୟ (ପୁଣ୍ଟା ଏରିନାସ୍‌)", + "America\/Rainy_River": "କେନ୍ଦ୍ରୀୟ ସମୟ (ରେଇନି ରିଭର୍)", + "America\/Rankin_Inlet": "କେନ୍ଦ୍ରୀୟ ସମୟ (ରାନକିନ୍ ଇନଲେଟ୍)", + "America\/Recife": "ବ୍ରାସିଲିଆ ସମୟ (ରେସିଫି)", + "America\/Regina": "କେନ୍ଦ୍ରୀୟ ସମୟ (ରେଗିନା)", + "America\/Resolute": "କେନ୍ଦ୍ରୀୟ ସମୟ (ରିସୋଲୁଟେ)", + "America\/Santa_Isabel": "ଉତ୍ତରପଶ୍ଚିମ ମେକ୍ସିକୋ ସମୟ (Santa Isabel)", + "America\/Santarem": "ବ୍ରାସିଲିଆ ସମୟ (ସାଣ୍ଟାରେମ୍‌)", + "America\/Santiago": "ଚିଲି ସମୟ (ସାଣ୍ଟିଆଗୋ)", + "America\/Santo_Domingo": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ସାଣ୍ଟୋ ଡୋମିଙ୍ଗୋ)", + "America\/Sao_Paulo": "ବ୍ରାସିଲିଆ ସମୟ (ସାଓ ପାଓଲୋ)", + "America\/Scoresbysund": "ପୂର୍ବ ଗ୍ରୀନଲ୍ୟାଣ୍ଡ୍ ସମୟ (ଇଟ୍ଟୋକ୍ଵୋରଟୋରମିଟ୍)", + "America\/Sitka": "ଆଲାସ୍କା ସମୟ (ସିଟକା)", + "America\/St_Barthelemy": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ସେଣ୍ଟ୍. ବାର୍ଥେଲେମି)", + "America\/St_Johns": "ନ୍ୟୁଫାଉଣ୍ଡଲ୍ୟାଣ୍ଡ୍ ସମୟ (ସେଣ୍ଟ୍. ଜନସ୍)", + "America\/St_Kitts": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ସେଣ୍ଟ୍ କିଟ୍ସ୍)", + "America\/St_Lucia": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ସେଣ୍ଟ୍. ଲୁସିଆ)", + "America\/St_Thomas": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ସେଣ୍ଟ୍. ଥୋମାସ୍)", + "America\/St_Vincent": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ସେଣ୍ଟ୍. ଭିନସେଣ୍ଟ୍)", + "America\/Swift_Current": "କେନ୍ଦ୍ରୀୟ ସମୟ (ସୁଇଫ୍ଟ୍ କରେଣ୍ଟ୍)", + "America\/Tegucigalpa": "କେନ୍ଦ୍ରୀୟ ସମୟ (ଟେଗୁସିଗାଲପା)", + "America\/Thule": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଥୁଲେ)", + "America\/Thunder_Bay": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଥଣ୍ଡର୍ ବେ)", + "America\/Tijuana": "ପାସିଫିକ୍ ସମୟ (ତିଜୁଆନା)", + "America\/Toronto": "ପୂର୍ବାଞ୍ଚଳ ସମୟ (ଟୋରୋଣ୍ଟୋ)", + "America\/Tortola": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ଟୋରଟୋଲା)", + "America\/Vancouver": "ପାସିଫିକ୍ ସମୟ (ଭାଙ୍କୁଭର୍)", + "America\/Whitehorse": "ପାସିଫିକ୍ ସମୟ (ହ୍ଵାଇଟହର୍ସ୍)", + "America\/Winnipeg": "କେନ୍ଦ୍ରୀୟ ସମୟ (ୱିନିପେଗ୍)", + "America\/Yakutat": "ଆଲାସ୍କା ସମୟ (ୟାକୁଟାଟ୍)", + "America\/Yellowknife": "ପାର୍ବତ୍ୟ ସମୟ (ୟେଲ୍ଲୋନାଇଫ୍)", + "Antarctica\/Casey": "ପଶ୍ଚିମ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (କାସେ)", + "Antarctica\/Davis": "ଡେଭିସ୍‌ ସମୟ (ଡେଭିସ୍‌)", + "Antarctica\/DumontDUrville": "ଡୁମୋଣ୍ଟ-ଡି‘ଉରଭିଲ୍ଲେ ସମୟ (ଡୁମୋଣ୍ଟ ଡି‘ଉରଭିଲ୍ଲେ)", + "Antarctica\/Macquarie": "ମାକ୍ୱେରୀ ଦ୍ୱୀପ ସମୟ (ମାକ୍ୱେରୀ)", + "Antarctica\/Mawson": "ମାୱସନ୍‌ ସମୟ (ମାୱସନ୍)", + "Antarctica\/McMurdo": "ନ୍ୟୁଜିଲାଣ୍ଡ ସମୟ (ମ୍ୟାକ୍‌ମୁର୍ଡୋ)", + "Antarctica\/Palmer": "ଚିଲି ସମୟ (ପାଲମର୍‌)", + "Antarctica\/Rothera": "ରୋଥେରା ସମୟ (ରୋଥେରା)", + "Antarctica\/Syowa": "ସୋୱା ସମୟ (ସୋୱା)", + "Antarctica\/Troll": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଟ୍ରୋଲ୍)", + "Antarctica\/Vostok": "ଭୋଷ୍ଟୋକ୍‌ ସମୟ (ଭୋଷ୍ଟୋକ୍‌)", + "Arctic\/Longyearbyen": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଲଙ୍ଗୟେଆରବୟେନ୍)", + "Asia\/Aden": "ଆରବୀୟ ସମୟ (ଏଡେନ୍‌)", + "Asia\/Almaty": "ପୂର୍ବ କାଜାକସ୍ତାନ୍ ସମୟ (ଅଲମାଟି)", + "Asia\/Amman": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଅମ୍ମାନ)", + "Asia\/Aqtau": "ପଶ୍ଚିମ କାଜାକସ୍ତାନ ସମୟ (ଆକଟାଉ)", + "Asia\/Aqtobe": "ପଶ୍ଚିମ କାଜାକସ୍ତାନ ସମୟ (ଆକଟୋବ୍‌)", + "Asia\/Ashgabat": "ତୁର୍କମେନିସ୍ତାନ ସମୟ (ଆଶ୍‌ଗାବୋଟ୍‌)", + "Asia\/Atyrau": "ପଶ୍ଚିମ କାଜାକସ୍ତାନ ସମୟ (ଅତିରାଉ)", + "Asia\/Baghdad": "ଆରବୀୟ ସମୟ (ବାଗଦାଦ୍‌)", + "Asia\/Bahrain": "ଆରବୀୟ ସମୟ (ବାହାରିନ୍)", + "Asia\/Baku": "ଆଜେରବାଇଜାନ ସମୟ (ବାକୁ)", + "Asia\/Bangkok": "ଇଣ୍ଡୋଚାଇନା ସମୟ (ବ୍ୟାଙ୍ଗକକ୍‌)", + "Asia\/Beirut": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ବୀରୁଟ୍‌)", + "Asia\/Bishkek": "କିର୍ଗିସ୍ତାନ ସମୟ (ବିଶକେକ୍‌)", + "Asia\/Brunei": "ବ୍ରୁନେଇ ଡାରୁସାଲାମ ସମୟ (ବ୍ରୁନେଇ)", + "Asia\/Calcutta": "ଭାରତ ମାନାଙ୍କ ସମୟ (କୋଲକାତା)", + "Asia\/Chita": "ୟାକୁଟସ୍କ ସମୟ (ଚିଟା)", + "Asia\/Choibalsan": "ଚୋଇବାଲସାନ ସମୟ (ଚୋଇବାଲସାନ୍‌)", + "Asia\/Colombo": "ଭାରତ ମାନାଙ୍କ ସମୟ (କଲମ୍ବୋ)", + "Asia\/Damascus": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଡାମାସକସ୍‌)", + "Asia\/Dhaka": "ବାଂଲାଦେଶ ସମୟ (ଢାକା)", + "Asia\/Dili": "ପୂର୍ବ ତିମୋର୍‌ ସମୟ (ଦିଲ୍ଲୀ)", + "Asia\/Dubai": "ଗଲ୍ଫ ମାନାଙ୍କ ସମୟ (ଦୁବାଇ)", + "Asia\/Dushanbe": "ତାଜିକିସ୍ତାନ ସମୟ (ଦୁଶାନବେ)", + "Asia\/Famagusta": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଫାମାଗୁଷ୍ଟା)", + "Asia\/Gaza": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଗାଜା)", + "Asia\/Hebron": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ହେବ୍ରନ୍‌)", + "Asia\/Hong_Kong": "ହଂ କଂ ସମୟ (ହଂ କଂ)", + "Asia\/Hovd": "ହୋଭଡ୍‌ ସମୟ (ହୋଭଡ୍‌)", + "Asia\/Irkutsk": "ଇଅରକୁଟସ୍କ ସମୟ (ଇରକୁଟସ୍କ)", + "Asia\/Jakarta": "ପଶ୍ଚିମ ଇଣ୍ଡୋନେସିଆ ସମୟ (ଜାକର୍ତ୍ତା)", + "Asia\/Jayapura": "ପୂର୍ବ ଇଣ୍ଡୋନେସିଆ ସମୟ (ଜୟପୁରା)", + "Asia\/Jerusalem": "ଇସ୍ରାଏଲ ସମୟ (ଜେରୁଜେଲମ)", + "Asia\/Kabul": "ଆଫଗାନିସ୍ତାନ ସମୟ (କାବୁଲ)", + "Asia\/Karachi": "ପାକିସ୍ତାନ ସମୟ (କରାଚି)", + "Asia\/Katmandu": "ନେପାଳ ସମୟ (କାଠମାଣ୍ଡୁ)", + "Asia\/Khandyga": "ୟାକୁଟସ୍କ ସମୟ (ଖାନଡ୍ୟାଗା)", + "Asia\/Krasnoyarsk": "କ୍ରାସନୋୟାରସ୍କ ସମୟ (କ୍ରାସନୋୟାରସ୍କ)", + "Asia\/Kuala_Lumpur": "ମାଲେସିଆ ସମୟ (କ୍ୱାଲାଲମ୍ପୁର)", + "Asia\/Kuching": "ମାଲେସିଆ ସମୟ (କୁଚିଂ)", + "Asia\/Kuwait": "ଆରବୀୟ ସମୟ (କୁଏତ)", + "Asia\/Macau": "ଚୀନ ସମୟ (ମାକାଉ)", + "Asia\/Magadan": "ମାଗାଡାନ୍ ସମୟ (ମାଗାଡାନ୍)", + "Asia\/Makassar": "ମଧ୍ୟ ଇଣ୍ଡୋନେସିଆ ସମୟ (ମାକାସାର୍‌)", + "Asia\/Manila": "ଫିଲିପାଇନ୍‌ ସମୟ (ମାନିଲା)", + "Asia\/Muscat": "ଗଲ୍ଫ ମାନାଙ୍କ ସମୟ (ମସ୍କାଟ୍‌)", + "Asia\/Nicosia": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ନିକୋସିଆ)", + "Asia\/Novokuznetsk": "କ୍ରାସନୋୟାରସ୍କ ସମୟ (ନୋଭୋକୁଜନେଟସ୍କ)", + "Asia\/Novosibirsk": "ନୋଭୋସିବିରସ୍କ ସମୟ (ନୋଭୋସିବିରସ୍କ)", + "Asia\/Omsk": "ଓମସ୍କ ସମୟ (ଓମସ୍କ)", + "Asia\/Oral": "ପଶ୍ଚିମ କାଜାକସ୍ତାନ ସମୟ (ଓରାଲ୍‌)", + "Asia\/Phnom_Penh": "ଇଣ୍ଡୋଚାଇନା ସମୟ (ଫନୋମ୍‌ ପେନହ)", + "Asia\/Pontianak": "ପଶ୍ଚିମ ଇଣ୍ଡୋନେସିଆ ସମୟ (ପୋଣ୍ଟିଆନାକ୍‌)", + "Asia\/Pyongyang": "କୋରିୟ ସମୟ (ପୋୟଙ୍ଗୟାଙ୍ଗ)", + "Asia\/Qatar": "ଆରବୀୟ ସମୟ (କତାର୍)", + "Asia\/Qostanay": "ପୂର୍ବ କାଜାକସ୍ତାନ୍ ସମୟ (Qostanay)", + "Asia\/Qyzylorda": "ପଶ୍ଚିମ କାଜାକସ୍ତାନ ସମୟ (କୀଜିଲୋର୍ଡା)", + "Asia\/Rangoon": "ମିଆଁମାର୍‌ ସମୟ (ୟାଙ୍ଗୁନ୍‌)", + "Asia\/Riyadh": "ଆରବୀୟ ସମୟ (ରିଆଦ)", + "Asia\/Saigon": "ଇଣ୍ଡୋଚାଇନା ସମୟ (ହୋ ଚି ମିନ୍‌ ସିଟି)", + "Asia\/Sakhalin": "ସଖାଲିନ୍ ସମୟ (ସଖାଲିନ୍)", + "Asia\/Samarkand": "ଉଜବେକିସ୍ତାନ ସମୟ (ସମରକନ୍ଦ)", + "Asia\/Seoul": "କୋରିୟ ସମୟ (ସିଓଲ)", + "Asia\/Shanghai": "ଚୀନ ସମୟ (ସଂଘାଇ)", + "Asia\/Singapore": "ସିଙ୍ଗାପୁର୍‌ ମାନାଙ୍କ ସମୟ (ସିଙ୍ଗାପୁର୍‌)", + "Asia\/Srednekolymsk": "ମାଗାଡାନ୍ ସମୟ (ସ୍ରେଡନେକୋଲୟମସ୍କ)", + "Asia\/Taipei": "ତାଇପେଇ ସମୟ (ତାଇପେଇ)", + "Asia\/Tashkent": "ଉଜବେକିସ୍ତାନ ସମୟ (ତାଶକେଣ୍ଟ)", + "Asia\/Tbilisi": "ଜର୍ଜିଆ ସମୟ (ଟିବିଲିସି)", + "Asia\/Tehran": "ଇରାନ ସମୟ (ତେହେରାନ୍)", + "Asia\/Thimphu": "ଭୁଟାନ ସମୟ (ଥିମ୍ପୁ)", + "Asia\/Tokyo": "ଜାପାନ ସମୟ (ଟୋକିଓ)", + "Asia\/Ulaanbaatar": "ଉଲାନ୍‌ବାଟର୍‌ ସମୟ (ଉଲାନ୍‌ବାଟର୍‌)", + "Asia\/Ust-Nera": "ଭ୍ଲାଡିଭୋଷ୍ଟୋକ୍ ସମୟ (ୟୁଷ୍ଟ-ନେରା)", + "Asia\/Vientiane": "ଇଣ୍ଡୋଚାଇନା ସମୟ (ଭିଏଣ୍ଟିଏନ୍‌)", + "Asia\/Vladivostok": "ଭ୍ଲାଡିଭୋଷ୍ଟୋକ୍ ସମୟ (ଭ୍ଲାଡିଭୋଷ୍ଟୋକ୍)", + "Asia\/Yakutsk": "ୟାକୁଟସ୍କ ସମୟ (ୟାକୁଟସ୍କ)", + "Asia\/Yekaterinburg": "ୟେକାଟେରିନବର୍ଗ୍ ସମୟ (ୟେକାଟେରିନବର୍ଗ୍)", + "Asia\/Yerevan": "ଆର୍ମେନିଆ ସମୟ (ୟେରେଭାନ୍)", + "Atlantic\/Azores": "ଆଜୋରେସ୍ ସମୟ (ଆଜୋରେସ୍)", + "Atlantic\/Bermuda": "ଆଟଲାଣ୍ଟିକ୍ ସମୟ (ବର୍ମୁଡା)", + "Atlantic\/Canary": "ପଶ୍ଚିମାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (କାନାରେ)", + "Atlantic\/Cape_Verde": "କେପ୍‌ ଭର୍ଦେ ସମୟ (କେପ୍‌ ଭର୍ଦେ)", + "Atlantic\/Faeroe": "ପଶ୍ଚିମାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଫାରୋଏ)", + "Atlantic\/Madeira": "ପଶ୍ଚିମାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ମାଡେଇରା)", + "Atlantic\/Reykjavik": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ରେୟକଜାଭିକ୍)", + "Atlantic\/South_Georgia": "ଦକ୍ଷିଣ ଜର୍ଜିଆ ସମୟ (ଦକ୍ଷିଣ ଜର୍ଜିଆ)", + "Atlantic\/St_Helena": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ସେଣ୍ଟ୍‌ ହେଲିନା)", + "Atlantic\/Stanley": "ଫକଲ୍ୟାଣ୍ଡ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (ଷ୍ଟାନଲି)", + "Australia\/Adelaide": "ମଧ୍ୟ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ଆଡିଲେଡ୍‌)", + "Australia\/Brisbane": "ପୂର୍ବ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ବ୍ରିସବେନ୍‌)", + "Australia\/Broken_Hill": "ମଧ୍ୟ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ବ୍ରୋକେନ୍‌ ହିଲ୍‌)", + "Australia\/Currie": "ପୂର୍ବ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (କ୍ୟୁରୀ)", + "Australia\/Darwin": "ମଧ୍ୟ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ଡାରୱିନ୍‌)", + "Australia\/Eucla": "ଅଷ୍ଟ୍ରେଲିୟ ମଧ୍ୟ ପଶ୍ଚିମ ସମୟ (ୟୁକଲା)", + "Australia\/Hobart": "ପୂର୍ବ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ହୋବାର୍ଟ୍‌)", + "Australia\/Lindeman": "ପୂର୍ବ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ଲିଣ୍ଡେମ୍ୟାନ୍‌)", + "Australia\/Lord_Howe": "ଲର୍ଡ ହୋୱେ ସମୟ (ଲର୍ଡ ହୋୱେ)", + "Australia\/Melbourne": "ପୂର୍ବ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ମେଲବୋର୍ଣ୍ଣ)", + "Australia\/Perth": "ପଶ୍ଚିମ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ପର୍ଥ୍‌)", + "Australia\/Sydney": "ପୂର୍ବ ଅଷ୍ଟ୍ରେଲିଆ ସମୟ (ସିଡନୀ)", + "CST6CDT": "କେନ୍ଦ୍ରୀୟ ସମୟ", + "EST5EDT": "ପୂର୍ବାଞ୍ଚଳ ସମୟ", + "Etc\/GMT": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ", + "Etc\/UTC": "ସମନ୍ୱିତ ସାର୍ବଜନୀନ ସମୟ", + "Europe\/Amsterdam": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଆମଷ୍ଟ୍ରେଡାମ୍)", + "Europe\/Andorra": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଆନଡୋରା)", + "Europe\/Astrakhan": "ମସ୍କୋ ସମୟ (ଆଷ୍ଟ୍ରାଖାନ୍)", + "Europe\/Athens": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଏଥେନ୍ସ)", + "Europe\/Belgrade": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ବେଲଗ୍ରେଡେ)", + "Europe\/Berlin": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ବର୍ଲିନ୍)", + "Europe\/Bratislava": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ବ୍ରାଟିସଲାଭା)", + "Europe\/Brussels": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ବ୍ରସଲ୍ସ୍)", + "Europe\/Bucharest": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ବୁଚାରେଷ୍ଟ୍)", + "Europe\/Budapest": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ବୁଡାପେଷ୍ଟ୍)", + "Europe\/Busingen": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ବୁସିନଗେନ୍)", + "Europe\/Chisinau": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଚିସିନୌ)", + "Europe\/Copenhagen": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (କୋପେନହାଗେନ୍)", + "Europe\/Dublin": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଡବଲିନ୍)", + "Europe\/Gibraltar": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଜିବ୍ରାଲଟର୍‌)", + "Europe\/Guernsey": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଗୁଏରନସେ)", + "Europe\/Helsinki": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ହେଲସିନକି)", + "Europe\/Isle_of_Man": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଇସଲେ ଅଫ୍ ମେନ୍)", + "Europe\/Jersey": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଜର୍ସି)", + "Europe\/Kaliningrad": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (କାଲିନିନଗ୍ରାଡ୍)", + "Europe\/Kiev": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (କିଏଭ୍)", + "Europe\/Lisbon": "ପଶ୍ଚିମାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଲିସବୋନ୍)", + "Europe\/Ljubljana": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଲଜୁବ୍ଲଜାନ୍)", + "Europe\/London": "ଗ୍ରୀନୱିଚ୍ ମିନ୍ ସମୟ (ଲଣ୍ଡନ୍)", + "Europe\/Luxembourg": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଲକ୍ସମବର୍ଗ)", + "Europe\/Madrid": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ମାଡ୍ରିଡ୍)", + "Europe\/Malta": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ମାଲଟା)", + "Europe\/Mariehamn": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ମାରିଏହାମନ୍)", + "Europe\/Minsk": "ମସ୍କୋ ସମୟ (ମିନସ୍କ)", + "Europe\/Monaco": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ମୋନାକୋ)", + "Europe\/Moscow": "ମସ୍କୋ ସମୟ (ମସ୍କୋ)", + "Europe\/Oslo": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଓସଲୋ)", + "Europe\/Paris": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ପେରିସ୍)", + "Europe\/Podgorica": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ପୋଡଗୋରିକା)", + "Europe\/Prague": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ପ୍ରାଗ୍)", + "Europe\/Riga": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ରିଗା)", + "Europe\/Rome": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ରୋମ୍)", + "Europe\/San_Marino": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ସାନ୍ ମାରିନୋ)", + "Europe\/Sarajevo": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ସାରାଜେଭୋ)", + "Europe\/Saratov": "ମସ୍କୋ ସମୟ (ସାରାଟୋଭ୍)", + "Europe\/Simferopol": "ମସ୍କୋ ସମୟ (ସିମଫେରୋପୋଲ୍)", + "Europe\/Skopje": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ସ୍କୋପଜେ)", + "Europe\/Sofia": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ସୋଫିଆ)", + "Europe\/Stockholm": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଷ୍ଟକହୋମ୍‌)", + "Europe\/Tallinn": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଟାଲିନ୍ନ)", + "Europe\/Tirane": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଟିରାନେ)", + "Europe\/Ulyanovsk": "ମସ୍କୋ ସମୟ (ୟୁଲୟାନୋଭସ୍କ)", + "Europe\/Uzhgorod": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଉଜହୋରୋଦ୍)", + "Europe\/Vaduz": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଭାଡୁଜ)", + "Europe\/Vatican": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଭାଟିକାନ୍)", + "Europe\/Vienna": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଭିଏନା)", + "Europe\/Vilnius": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଭିଲନିଉସ୍)", + "Europe\/Volgograd": "ଭୋଲଗୋଗ୍ରାଡ୍ ସମୟ (ଭୋଲଗୋଗ୍ରାଡ୍)", + "Europe\/Warsaw": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ୱାରସୱା)", + "Europe\/Zagreb": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଜାଗ୍ରେବ୍)", + "Europe\/Zaporozhye": "ପୂର୍ବାଞ୍ଚଳ ୟୁରୋପୀୟ ସମୟ (ଜାପୋରୋଜହୟେ)", + "Europe\/Zurich": "କେନ୍ଦ୍ରୀୟ ୟୁରୋପୀୟ ସମୟ (ଜୁରିକ୍)", + "Indian\/Antananarivo": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ଆଣ୍ଟାନାନାରିଭୋ)", + "Indian\/Chagos": "ଭାରତ ମାହାସାଗର ସମୟ (ଚାଗୋସ୍‌)", + "Indian\/Christmas": "ଖ୍ରୀଷ୍ଟମାସ ଦ୍ୱୀପ ସମୟ (ଖ୍ରୀଷ୍ଟମାସ)", + "Indian\/Cocos": "କୋକୋସ୍‌ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (କୋକୋସ୍‌)", + "Indian\/Comoro": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (କୋମୋରୋ)", + "Indian\/Kerguelen": "ଫ୍ରେଞ୍ଚ ଦକ୍ଷିଣ ଏବଂ ଆଣ୍ଟାର୍କାଟିକ୍‌ ସମୟ (କେରୁଗେଲେନ)", + "Indian\/Mahe": "ସେଚେଲ୍ଲେସ୍‌ ସମୟ (ମାହେ)", + "Indian\/Maldives": "ମାଳଦ୍ୱୀପ ସମୟ (ମାଳଦ୍ୱୀପ)", + "Indian\/Mauritius": "ମୌରିସସ୍‌ ସମୟ (ମୌରିସସ୍)", + "Indian\/Mayotte": "ପୂର୍ବ ଆଫ୍ରିକା ସମୟ (ମାୟୋଟେ)", + "Indian\/Reunion": "ରିୟୁନିଅନ୍‌ ସମୟ (ରିୟୁନିଅନ୍‌)", + "MST7MDT": "ପାର୍ବତ୍ୟ ସମୟ", + "PST8PDT": "ପାସିଫିକ୍ ସମୟ", + "Pacific\/Apia": "ଆପିଆ ସମୟ (ଆପିଆ)", + "Pacific\/Auckland": "ନ୍ୟୁଜିଲାଣ୍ଡ ସମୟ (ଅକଲାଣ୍ଡ)", + "Pacific\/Bougainville": "ପପୁଆ ନ୍ୟୁ ଗୁନିଆ ସମୟ (ବୌଗେନ୍‌ଭିଲ୍ଲେ)", + "Pacific\/Chatham": "ଚାଥାମ୍‌ ସମୟ (ଚାଥାମ୍‌)", + "Pacific\/Easter": "ଇଷ୍ଟର୍‌ ଆଇଲ୍ୟାଣ୍ଡ ସମୟ (ଇଷ୍ଟର୍‌)", + "Pacific\/Efate": "ଭାନୁଆଟୁ ସମୟ (ଇଫେଟ୍‌)", + "Pacific\/Enderbury": "ଫୋନିକ୍ସ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (ଏଣ୍ଡେରବୁରି)", + "Pacific\/Fakaofo": "ଟୋକେଲାଉ ସମୟ (ଫାକାଓଫୋ)", + "Pacific\/Fiji": "ଫିଜି ସମୟ (ଫିଜି)", + "Pacific\/Funafuti": "ତୁଭାଲୁ ସମୟ (ଫୁନାଫୁଟି)", + "Pacific\/Galapagos": "ଗାଲାପାଗୋସ୍ ସମୟ (ଗାଲାପାଗୋସ)", + "Pacific\/Gambier": "ଗାମ୍ବିୟର୍ ସମୟ (ଗାମ୍ବିୟର୍‌)", + "Pacific\/Guadalcanal": "ସୋଲୋମନ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (ଗୁଆଡାଲକାନାଲ)", + "Pacific\/Guam": "ଚାମୋରୋ ମାନାଙ୍କ ସମୟ (ଗୁଆମ)", + "Pacific\/Honolulu": "ହୱାଇ-ଆଲେଉଟିୟ ସମୟ (ହୋନୋଲୁଲୁ)", + "Pacific\/Johnston": "ହୱାଇ-ଆଲେଉଟିୟ ସମୟ (ଜନଷ୍ଟନ୍)", + "Pacific\/Kiritimati": "ଲାଇନ୍‌ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (କିରିତିମାଟି)", + "Pacific\/Kosrae": "କୋସରେଇ ସମୟ (କୋସରେଇ)", + "Pacific\/Kwajalein": "ମାର୍ଶାଲ୍‌ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (କ୍ୱାଜାଲେଇନ୍)", + "Pacific\/Majuro": "ମାର୍ଶାଲ୍‌ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (ମାଜୁରୋ)", + "Pacific\/Marquesas": "ମାର୍କ୍ୱେସାସ୍‌ ସମୟ (ମାର୍କ୍ୱେସାସ୍‌)", + "Pacific\/Midway": "ସାମୋଆ ସମୟ (ମିଡ୍‌ୱେ)", + "Pacific\/Nauru": "ନାଉରୁ ସମୟ (ନାଉରୁ)", + "Pacific\/Niue": "ନିୟୁ ସମୟ (ନିୟୂ)", + "Pacific\/Norfolk": "ନରଫୋକ୍‌ ଦ୍ୱୀପ ସମୟ (ନରଫୋକ୍‌)", + "Pacific\/Noumea": "ନ୍ୟୁ କାଲେଡୋନିଆ ସମୟ (ନୌମିୟ)", + "Pacific\/Pago_Pago": "ସାମୋଆ ସମୟ (ପାଗୋ ପାଗୋ)", + "Pacific\/Palau": "ପାଲାଉ ସମୟ (ପାଲାଉ)", + "Pacific\/Pitcairn": "ପିଟକାରିନ୍‌ ସମୟ (ପିଟକାରିନ୍‌)", + "Pacific\/Ponape": "ପୋନାପେ ସମୟ (ପୋହନପେଇ)", + "Pacific\/Port_Moresby": "ପପୁଆ ନ୍ୟୁ ଗୁନିଆ ସମୟ (ପୋର୍ଟ୍‌ ମୋରେସବି)", + "Pacific\/Rarotonga": "କୁକ୍‌ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (ରାରୋଟୋଙ୍ଗା)", + "Pacific\/Saipan": "ଚାମୋରୋ ମାନାଙ୍କ ସମୟ (ସାଇପାନ୍)", + "Pacific\/Tahiti": "ତାହିତି ସମୟ (ତାହିତି)", + "Pacific\/Tarawa": "ଗିଲବର୍ଟ୍‌ ଦ୍ୱୀପପୁଞ୍ଜ ସମୟ (ତାରୱା)", + "Pacific\/Tongatapu": "ଟୋଙ୍ଗା ସମୟ (ଟୋଙ୍ଗାଟାପୁ)", + "Pacific\/Truk": "ଚୂକ୍‌ ସମୟ (ଚୂକ୍‌)", + "Pacific\/Wake": "ୱେକ୍‌ ଦ୍ୱୀପ ସମୟ (ୱେକ୍)", + "Pacific\/Wallis": "ୱାଲିସ୍‌ ଏବଂ ଫୁଟୁନା ସମୟ (ୱାଲିସ୍‌)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/os.json b/src/Symfony/Component/Intl/Resources/data/timezones/os.json new file mode 100644 index 0000000000000..6bdb419f41ce1 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/os.json @@ -0,0 +1,98 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "Гринвичы рӕстӕмбис рӕстӕг (Abidjan)", + "Africa\/Accra": "Гринвичы рӕстӕмбис рӕстӕг (Accra)", + "Africa\/Algiers": "Астӕуккаг Европӕйаг рӕстӕг (Algiers)", + "Africa\/Bamako": "Гринвичы рӕстӕмбис рӕстӕг (Bamako)", + "Africa\/Banjul": "Гринвичы рӕстӕмбис рӕстӕг (Banjul)", + "Africa\/Bissau": "Гринвичы рӕстӕмбис рӕстӕг (Bissau)", + "Africa\/Cairo": "Скӕсӕн Европӕйаг рӕстӕг (Cairo)", + "Africa\/Casablanca": "Ныгъуылӕн Европӕйаг рӕстӕг (Casablanca)", + "Africa\/Ceuta": "Астӕуккаг Европӕйаг рӕстӕг (Ceuta)", + "Africa\/Conakry": "Гринвичы рӕстӕмбис рӕстӕг (Conakry)", + "Africa\/Dakar": "Гринвичы рӕстӕмбис рӕстӕг (Dakar)", + "Africa\/El_Aaiun": "Ныгъуылӕн Европӕйаг рӕстӕг (El Aaiun)", + "Africa\/Freetown": "Гринвичы рӕстӕмбис рӕстӕг (Freetown)", + "Africa\/Lome": "Гринвичы рӕстӕмбис рӕстӕг (Lome)", + "Africa\/Monrovia": "Гринвичы рӕстӕмбис рӕстӕг (Monrovia)", + "Africa\/Nouakchott": "Гринвичы рӕстӕмбис рӕстӕг (Nouakchott)", + "Africa\/Ouagadougou": "Гринвичы рӕстӕмбис рӕстӕг (Ouagadougou)", + "Africa\/Sao_Tome": "Гринвичы рӕстӕмбис рӕстӕг (Sao Tome)", + "Africa\/Tripoli": "Скӕсӕн Европӕйаг рӕстӕг (Tripoli)", + "Africa\/Tunis": "Астӕуккаг Европӕйаг рӕстӕг (Tunis)", + "America\/Danmarkshavn": "Гринвичы рӕстӕмбис рӕстӕг (Danmarkshavn)", + "Antarctica\/Troll": "Гринвичы рӕстӕмбис рӕстӕг (Troll)", + "Arctic\/Longyearbyen": "Астӕуккаг Европӕйаг рӕстӕг (Longyearbyen)", + "Asia\/Amman": "Скӕсӕн Европӕйаг рӕстӕг (Amman)", + "Asia\/Beirut": "Скӕсӕн Европӕйаг рӕстӕг (Beirut)", + "Asia\/Damascus": "Скӕсӕн Европӕйаг рӕстӕг (Damascus)", + "Asia\/Famagusta": "Скӕсӕн Европӕйаг рӕстӕг (Famagusta)", + "Asia\/Gaza": "Скӕсӕн Европӕйаг рӕстӕг (Gaza)", + "Asia\/Hebron": "Скӕсӕн Европӕйаг рӕстӕг (Hebron)", + "Asia\/Nicosia": "Скӕсӕн Европӕйаг рӕстӕг (Nicosia)", + "Asia\/Tbilisi": "Гуырдзыстоны рӕстӕг (Тбилис)", + "Atlantic\/Canary": "Ныгъуылӕн Европӕйаг рӕстӕг (Canary)", + "Atlantic\/Faeroe": "Ныгъуылӕн Европӕйаг рӕстӕг (Faroe)", + "Atlantic\/Madeira": "Ныгъуылӕн Европӕйаг рӕстӕг (Madeira)", + "Atlantic\/Reykjavik": "Гринвичы рӕстӕмбис рӕстӕг (Reykjavik)", + "Atlantic\/St_Helena": "Гринвичы рӕстӕмбис рӕстӕг (St. Helena)", + "Etc\/GMT": "Гринвичы рӕстӕмбис рӕстӕг", + "Europe\/Amsterdam": "Астӕуккаг Европӕйаг рӕстӕг (Amsterdam)", + "Europe\/Andorra": "Астӕуккаг Европӕйаг рӕстӕг (Andorra)", + "Europe\/Astrakhan": "Мӕскуыйы рӕстӕг (Astrakhan)", + "Europe\/Athens": "Скӕсӕн Европӕйаг рӕстӕг (Athens)", + "Europe\/Belgrade": "Астӕуккаг Европӕйаг рӕстӕг (Belgrade)", + "Europe\/Berlin": "Астӕуккаг Европӕйаг рӕстӕг (Berlin)", + "Europe\/Bratislava": "Астӕуккаг Европӕйаг рӕстӕг (Bratislava)", + "Europe\/Brussels": "Астӕуккаг Европӕйаг рӕстӕг (Brussels)", + "Europe\/Bucharest": "Скӕсӕн Европӕйаг рӕстӕг (Bucharest)", + "Europe\/Budapest": "Астӕуккаг Европӕйаг рӕстӕг (Budapest)", + "Europe\/Busingen": "Астӕуккаг Европӕйаг рӕстӕг (Busingen)", + "Europe\/Chisinau": "Скӕсӕн Европӕйаг рӕстӕг (Chisinau)", + "Europe\/Copenhagen": "Астӕуккаг Европӕйаг рӕстӕг (Copenhagen)", + "Europe\/Dublin": "Гринвичы рӕстӕмбис рӕстӕг (Dublin)", + "Europe\/Gibraltar": "Астӕуккаг Европӕйаг рӕстӕг (Gibraltar)", + "Europe\/Guernsey": "Гринвичы рӕстӕмбис рӕстӕг (Guernsey)", + "Europe\/Helsinki": "Скӕсӕн Европӕйаг рӕстӕг (Helsinki)", + "Europe\/Isle_of_Man": "Гринвичы рӕстӕмбис рӕстӕг (Isle of Man)", + "Europe\/Jersey": "Гринвичы рӕстӕмбис рӕстӕг (Jersey)", + "Europe\/Kaliningrad": "Скӕсӕн Европӕйаг рӕстӕг (Kaliningrad)", + "Europe\/Kiev": "Скӕсӕн Европӕйаг рӕстӕг (Kiev)", + "Europe\/Lisbon": "Ныгъуылӕн Европӕйаг рӕстӕг (Lisbon)", + "Europe\/Ljubljana": "Астӕуккаг Европӕйаг рӕстӕг (Ljubljana)", + "Europe\/London": "Гринвичы рӕстӕмбис рӕстӕг (London)", + "Europe\/Luxembourg": "Астӕуккаг Европӕйаг рӕстӕг (Luxembourg)", + "Europe\/Madrid": "Астӕуккаг Европӕйаг рӕстӕг (Madrid)", + "Europe\/Malta": "Астӕуккаг Европӕйаг рӕстӕг (Malta)", + "Europe\/Mariehamn": "Скӕсӕн Европӕйаг рӕстӕг (Mariehamn)", + "Europe\/Minsk": "Мӕскуыйы рӕстӕг (Минск)", + "Europe\/Monaco": "Астӕуккаг Европӕйаг рӕстӕг (Monaco)", + "Europe\/Moscow": "Мӕскуыйы рӕстӕг (Мӕскуы)", + "Europe\/Oslo": "Астӕуккаг Европӕйаг рӕстӕг (Oslo)", + "Europe\/Paris": "Астӕуккаг Европӕйаг рӕстӕг (Paris)", + "Europe\/Podgorica": "Астӕуккаг Европӕйаг рӕстӕг (Podgorica)", + "Europe\/Prague": "Астӕуккаг Европӕйаг рӕстӕг (Prague)", + "Europe\/Riga": "Скӕсӕн Европӕйаг рӕстӕг (Riga)", + "Europe\/Rome": "Астӕуккаг Европӕйаг рӕстӕг (Rome)", + "Europe\/San_Marino": "Астӕуккаг Европӕйаг рӕстӕг (San Marino)", + "Europe\/Sarajevo": "Астӕуккаг Европӕйаг рӕстӕг (Sarajevo)", + "Europe\/Saratov": "Мӕскуыйы рӕстӕг (Saratov)", + "Europe\/Simferopol": "Мӕскуыйы рӕстӕг (Simferopol)", + "Europe\/Skopje": "Астӕуккаг Европӕйаг рӕстӕг (Skopje)", + "Europe\/Sofia": "Скӕсӕн Европӕйаг рӕстӕг (Sofia)", + "Europe\/Stockholm": "Астӕуккаг Европӕйаг рӕстӕг (Stockholm)", + "Europe\/Tallinn": "Скӕсӕн Европӕйаг рӕстӕг (Tallinn)", + "Europe\/Tirane": "Астӕуккаг Европӕйаг рӕстӕг (Tirane)", + "Europe\/Ulyanovsk": "Мӕскуыйы рӕстӕг (Ulyanovsk)", + "Europe\/Uzhgorod": "Скӕсӕн Европӕйаг рӕстӕг (Uzhgorod)", + "Europe\/Vaduz": "Астӕуккаг Европӕйаг рӕстӕг (Vaduz)", + "Europe\/Vatican": "Астӕуккаг Европӕйаг рӕстӕг (Vatican)", + "Europe\/Vienna": "Астӕуккаг Европӕйаг рӕстӕг (Vienna)", + "Europe\/Vilnius": "Скӕсӕн Европӕйаг рӕстӕг (Vilnius)", + "Europe\/Warsaw": "Астӕуккаг Европӕйаг рӕстӕг (Warsaw)", + "Europe\/Zagreb": "Астӕуккаг Европӕйаг рӕстӕг (Zagreb)", + "Europe\/Zaporozhye": "Скӕсӕн Европӕйаг рӕстӕг (Zaporozhye)", + "Europe\/Zurich": "Астӕуккаг Европӕйаг рӕстӕг (Zurich)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pa.json b/src/Symfony/Component/Intl/Resources/data/timezones/pa.json new file mode 100644 index 0000000000000..d11ad2f48e51f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pa.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.20", + "Names": { + "Africa\/Abidjan": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਅਬੀਦਜਾਨ)", + "Africa\/Accra": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਅੱਕਰਾ)", + "Africa\/Addis_Ababa": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਐਡਿਸ ਅਬਾਬਾ)", + "Africa\/Algiers": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਅਲਜੀਅਰਸ)", + "Africa\/Asmera": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਅਸਮਾਰਾ)", + "Africa\/Bamako": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਬਮੇਕੋ)", + "Africa\/Bangui": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਬਾਂਗੁਈ)", + "Africa\/Banjul": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਬਾਂਜੁਲ)", + "Africa\/Bissau": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਬਿਸਾਉ)", + "Africa\/Blantyre": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਬਲੰਟਾਇਰ)", + "Africa\/Brazzaville": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਬ੍ਰਾਜ਼ਾਵਿਲੇ)", + "Africa\/Bujumbura": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਬੁਜੁੰਬੁਰਾ)", + "Africa\/Cairo": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਕੈਰੋ)", + "Africa\/Casablanca": "ਪੱਛਮੀ ਯੂਰਪੀ ਵੇਲਾ (ਕਾਸਾਬਲਾਂਕਾ)", + "Africa\/Ceuta": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਸੀਊਟਾ)", + "Africa\/Conakry": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਕੋਨੇਕਰੀ)", + "Africa\/Dakar": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਡਕਾਰ)", + "Africa\/Dar_es_Salaam": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਦਾਰ ਏਸ ਸਲਾਮ)", + "Africa\/Djibouti": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਜ਼ੀਬੂਤੀ)", + "Africa\/Douala": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਡੌਆਲਾ)", + "Africa\/El_Aaiun": "ਪੱਛਮੀ ਯੂਰਪੀ ਵੇਲਾ (ਅਲ ਅਯੂਨ)", + "Africa\/Freetown": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਫਰੀਟਾਉਨ)", + "Africa\/Gaborone": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਗਾਬੋਰੋਨ)", + "Africa\/Harare": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਹਰਾਰੇ)", + "Africa\/Johannesburg": "ਦੱਖਣੀ ਅਫ਼ਰੀਕਾ ਮਿਆਰੀ ਵੇਲਾ (ਜੋਹਨਸਬਰਗ)", + "Africa\/Juba": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਜੂਬਾ)", + "Africa\/Kampala": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਕੰਪਾਲਾ)", + "Africa\/Khartoum": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਖਾਰਟੌਮ)", + "Africa\/Kigali": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਕਿਗਾਲੀ)", + "Africa\/Kinshasa": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਕਿੰਸ਼ਾਸਾ)", + "Africa\/Lagos": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਲਾਗੋਸ)", + "Africa\/Libreville": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਲਿਬਰਵਿਲੇ)", + "Africa\/Lome": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਲੋਮ)", + "Africa\/Luanda": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਲੁਆਂਡਾ)", + "Africa\/Lubumbashi": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਲੁਬੁਮਬਾਸ਼ੀ)", + "Africa\/Lusaka": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਲੁਸਾਕਾ)", + "Africa\/Malabo": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਮਾਲਾਬੋ)", + "Africa\/Maputo": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਮਾਪੁਟੋ)", + "Africa\/Maseru": "ਦੱਖਣੀ ਅਫ਼ਰੀਕਾ ਮਿਆਰੀ ਵੇਲਾ (ਮਸੇਰੂ)", + "Africa\/Mbabane": "ਦੱਖਣੀ ਅਫ਼ਰੀਕਾ ਮਿਆਰੀ ਵੇਲਾ (ਏਮਬਾਬਾਨੇ)", + "Africa\/Mogadishu": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਮੋਗਾਦਿਸ਼ੂ)", + "Africa\/Monrovia": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਮੋਨਰੋਵੀਆ)", + "Africa\/Nairobi": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਨੈਰੋਬੀ)", + "Africa\/Ndjamena": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਐਂਜਾਮੇਨਾ)", + "Africa\/Niamey": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਨਿਆਮੇ)", + "Africa\/Nouakchott": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਨੌਆਕਸ਼ਾਟ)", + "Africa\/Ouagadougou": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਉਆਗਾਡੂਗੂ)", + "Africa\/Porto-Novo": "ਪੱਛਮੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਪੋਰਟੋ-ਨੋਵੋ)", + "Africa\/Sao_Tome": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਸਾਓ ਟੋਮ)", + "Africa\/Tripoli": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਤ੍ਰਿਪੋਲੀ)", + "Africa\/Tunis": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਟੁਨਿਸ)", + "Africa\/Windhoek": "ਕੇਂਦਰੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਵਿੰਡਹੋਇਕ)", + "America\/Adak": "ਹਵਾਈ-ਅਲੇਯੂਸ਼ਿਅਨ ਵੇਲਾ (ਏਡਕ)", + "America\/Anchorage": "ਅਲਾਸਕਾ ਵੇਲਾ (ਐਂਕਰੇਜ)", + "America\/Anguilla": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਅੰਗੁਇਲਾ)", + "America\/Antigua": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਐਂਟੀਗੁਆ)", + "America\/Araguaina": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਆਰਗੁਆਇਨਾ)", + "America\/Argentina\/La_Rioja": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਲਾ ਰਿਉਜਾ)", + "America\/Argentina\/Rio_Gallegos": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਰਿਓ ਗੈਲੇਗੋਸ)", + "America\/Argentina\/Salta": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਸਾਲਟਾ)", + "America\/Argentina\/San_Juan": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਸੇਨ ਜੁਆਨ)", + "America\/Argentina\/San_Luis": "ਪੱਛਮੀ ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਸੇਨ ਲੂਈਸ)", + "America\/Argentina\/Tucuman": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਟੁਕੁਮਨ)", + "America\/Argentina\/Ushuaia": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਉਸ਼ਵਾਇਆ)", + "America\/Aruba": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਅਰੂਬਾ)", + "America\/Asuncion": "ਪੈਰਾਗਵੇ ਵੇਲਾ (ਐਸੁੰਕੀਅਨ)", + "America\/Bahia": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਬਾਹੀਆ)", + "America\/Bahia_Banderas": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਬਾਹੀਆ ਬਾਂਦੇਰਸ)", + "America\/Barbados": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਬਾਰਬਾਡੋਸ)", + "America\/Belem": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਬੇਲੇਮ)", + "America\/Belize": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਬੇਲੀਜ਼)", + "America\/Blanc-Sablon": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਬਲੈਂਕ-ਸੈਬਲਾਨ)", + "America\/Boa_Vista": "ਅਮੇਜ਼ਨ ਵੇਲਾ (ਬੋਆ ਵਿਸਟਾ)", + "America\/Bogota": "ਕੋਲੰਬੀਆ ਵੇਲਾ (ਬੋਗੋਟਾ)", + "America\/Boise": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਬੋਇਸ)", + "America\/Buenos_Aires": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਬੂਈਨਸ ਆਇਰਸ)", + "America\/Cambridge_Bay": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਕੈਮਬ੍ਰਿਜ ਬੇ)", + "America\/Campo_Grande": "ਅਮੇਜ਼ਨ ਵੇਲਾ (ਕੈਂਪੋ ਗ੍ਰਾਂਡੇ)", + "America\/Cancun": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਕੈਨਕੁਨ)", + "America\/Caracas": "ਵੈਨੇਜ਼ੂਏਲਾ ਵੇਲਾ (ਕੈਰਾਕਾਸ)", + "America\/Catamarca": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਕੈਟਾਮਾਰਕਾ)", + "America\/Cayenne": "ਫ੍ਰੈਂਚ ਗੁਏਨਾ ਵੇਲਾ (ਕੇਯੇਨੇ)", + "America\/Cayman": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਕੇਮੈਨ)", + "America\/Chicago": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਸ਼ਿਕਾਗੋ)", + "America\/Chihuahua": "ਮੈਕਸੀਕਨ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਚਿਹੁਆਹੁਆ)", + "America\/Coral_Harbour": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਐਟੀਕੋਕਨ)", + "America\/Cordoba": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਕੋਰਡੋਬਾ)", + "America\/Costa_Rica": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਕੋਸਟਾ ਰੀਕਾ)", + "America\/Creston": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਕ੍ਰੈਸਟਨ)", + "America\/Cuiaba": "ਅਮੇਜ਼ਨ ਵੇਲਾ (ਕਯੁਏਬਾ)", + "America\/Curacao": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਕੁਰਾਕਾਓ)", + "America\/Danmarkshavn": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਡੈਨਮਾਰਕਸ਼ੌਨ)", + "America\/Dawson": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਡੌਅਸਨ)", + "America\/Dawson_Creek": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਡੌਅਸਨ ਕ੍ਰੀਕ)", + "America\/Denver": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਡੇਨਵਰ)", + "America\/Detroit": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਡਿਟਰੋਇਟ)", + "America\/Dominica": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਡੋਮੀਨਿਕਾ)", + "America\/Edmonton": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਐਡਮੋਂਟਨ)", + "America\/El_Salvador": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਅਲ ਸਲਵਾਡੋਰ)", + "America\/Fort_Nelson": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਫੋਰਟ ਨੈਲਸਨ)", + "America\/Fortaleza": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਫੋਰਟਾਲੇਜ਼ਾ)", + "America\/Glace_Bay": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਗਲੇਸ ਬੇ)", + "America\/Godthab": "ਪੱਛਮੀ ਗ੍ਰੀਨਲੈਂਡ ਵੇਲਾ (ਨੂਕ)", + "America\/Goose_Bay": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਗੂਜ਼ ਬੇ)", + "America\/Grand_Turk": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਗਰਾਂਡ ਤੁਰਕ)", + "America\/Grenada": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਗ੍ਰੇਨਾਡਾ)", + "America\/Guadeloupe": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਗੁਆਡੇਲੋਪ)", + "America\/Guatemala": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਗੁਆਟੇਮਾਲਾ)", + "America\/Guayaquil": "ਇਕਵੇਡੋਰ ਵੇਲਾ (ਗੁਆਇਕਵਿਲ)", + "America\/Guyana": "ਗੁਯਾਨਾ ਵੇਲਾ (ਗੁਆਨਾ)", + "America\/Halifax": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਹੈਲੀਫੈਕਸ)", + "America\/Havana": "ਕਿਊਬਾ ਵੇਲਾ (ਹਵਾਨਾ)", + "America\/Hermosillo": "ਮੈਕਸੀਕਨ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਹਰਮੋਸਿੱਲੋ)", + "America\/Indiana\/Knox": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਨੋਕਸ, ਇੰਡੀਆਨਾ)", + "America\/Indiana\/Marengo": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਮਾਰੇਂਗੋ, ਇੰਡੀਆਨਾ)", + "America\/Indiana\/Petersburg": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਪੀਟਰਸਬਰਗ, ਇੰਡੀਆਨਾ)", + "America\/Indiana\/Tell_City": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਟੈਲ ਸਿਟੀ, ਇੰਡੀਆਨਾ)", + "America\/Indiana\/Vevay": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਵੇਵੇ, ਇੰਡੀਆਨਾ)", + "America\/Indiana\/Vincennes": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਵਿੰਸੇਨੇਸ, ਇੰਡੀਆਨਾ)", + "America\/Indiana\/Winamac": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਵਿਨਮੈਕ, ਇੰਡੀਆਨਾ)", + "America\/Indianapolis": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਇੰਡੀਆਨਾਪੋਲਿਸ)", + "America\/Inuvik": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਇਨੁਵਿਕ)", + "America\/Iqaluit": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਇਕਾਲੁਈਟ)", + "America\/Jamaica": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਜਮਾਇਕਾ)", + "America\/Jujuy": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਜੂਜੁਏ)", + "America\/Juneau": "ਅਲਾਸਕਾ ਵੇਲਾ (ਜਯੂਨੋ)", + "America\/Kentucky\/Monticello": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਮੋਂਟੀਸੈਲੋ, ਕੈਂਟਕੀ)", + "America\/Kralendijk": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਕ੍ਰਾਲੇਂਦਿਜਕ)", + "America\/La_Paz": "ਬੋਲੀਵੀਆ ਵੇਲਾ (ਲਾ ਪਾਜ਼)", + "America\/Lima": "ਪੇਰੂ ਵੇਲਾ (ਲੀਮਾ)", + "America\/Los_Angeles": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਲਾਸ ਐਂਜਲਸ)", + "America\/Louisville": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਲੁਈਸਵਿਲੇ)", + "America\/Lower_Princes": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਲੋਅਰ ਪ੍ਰਿੰਸ’ਸ ਕਵਾਰਟਰ)", + "America\/Maceio": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਮੈਸੀਓ)", + "America\/Managua": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਮਨਾਗੁਆ)", + "America\/Manaus": "ਅਮੇਜ਼ਨ ਵੇਲਾ (ਮਨੌਸ)", + "America\/Marigot": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਮੈਰੀਗੋਟ)", + "America\/Martinique": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਮਾਰਟੀਨਿਕ)", + "America\/Matamoros": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਮਾਟਾਮੋਰਸ)", + "America\/Mazatlan": "ਮੈਕਸੀਕਨ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਮਜ਼ੇਤਲਾਨ)", + "America\/Mendoza": "ਅਰਜਨਟੀਨਾ ਵੇਲਾ (ਮੈਂਡੋਜ਼ਾ)", + "America\/Menominee": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਮੈਨੋਮਿਨੀ)", + "America\/Merida": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਮੇਰਿਡਾ)", + "America\/Metlakatla": "ਅਲਾਸਕਾ ਵੇਲਾ (ਮੇਟਲਾਕਾਟਲਾ)", + "America\/Mexico_City": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਮੈਕਸੀਕੋ ਸਿਟੀ)", + "America\/Miquelon": "ਸੈਂਟ ਪੀਅਰੇ ਅਤੇ ਮਿਕੇਲਨ ਵੇਲਾ (ਮਿਕੇਲਨ)", + "America\/Moncton": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਮੋਂਕਟਨ)", + "America\/Monterrey": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਮੋਨਟੇਰੀ)", + "America\/Montevideo": "ਉਰੂਗਵੇ ਵੇਲਾ (ਮੋਂਟੇਵੀਡੀਓ)", + "America\/Montserrat": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਮੋਂਟਸੇਰਾਤ)", + "America\/Nassau": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਨਾਸਾਓ)", + "America\/New_York": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਨਿਊ ਯਾਰਕ)", + "America\/Nipigon": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਨਿਪਿਗੌਨ)", + "America\/Nome": "ਅਲਾਸਕਾ ਵੇਲਾ (ਨੋਮ)", + "America\/Noronha": "ਫਰਨਾਂਡੋ ਡੇ ਨੋਰੋਨਹਾ ਵੇਲਾ (ਨੌਰੋਨਹਾ)", + "America\/North_Dakota\/Beulah": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਬਿਉਲਾ, ਉੱਤਰੀ ਡਕੋਟਾ)", + "America\/North_Dakota\/Center": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਸੇਂਟਰ, ਉੱਤਰੀ ਡਕੋਟਾ)", + "America\/North_Dakota\/New_Salem": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਨਿਊ ਸਲੇਮ, ਉੱਤਰੀ ਡਕੋਟਾ)", + "America\/Ojinaga": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਓਜੀਨਾਗਾ)", + "America\/Panama": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਪਨਾਮਾ)", + "America\/Pangnirtung": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਪੈਂਗਨਿਰਟੰਗ)", + "America\/Paramaribo": "ਸੂਰੀਨਾਮ ਵੇਲਾ (ਪੈਰਾਮਰੀਬੋ)", + "America\/Phoenix": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਫਿਨਿਕਸ)", + "America\/Port-au-Prince": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਪੋਰਟ-ਔ-ਪ੍ਰਿੰਸ)", + "America\/Port_of_Spain": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਪੋਰਟ ਔਫ ਸਪੇਨ)", + "America\/Porto_Velho": "ਅਮੇਜ਼ਨ ਵੇਲਾ (ਪੋਰਟੋ ਵੇਲ੍ਹੋ)", + "America\/Puerto_Rico": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਪਿਊਰਟੋ ਰੀਕੋ)", + "America\/Punta_Arenas": "ਚਿਲੀ ਵੇਲਾ (ਪੰਟਾ ਅਰੇਨਸ)", + "America\/Rainy_River": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਰੇਨੀ ਰਿਵਰ)", + "America\/Rankin_Inlet": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਰੈਂਕਿਨ ਇਨਲੈਟ)", + "America\/Recife": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਰੇਸੀਫੇ)", + "America\/Regina": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਰੈਜੀਨਾ)", + "America\/Resolute": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਰੈਜ਼ੋਲਿਊਟ)", + "America\/Santa_Isabel": "ਉੱਤਰ ਪੱਛਮੀ ਮੈਕਸੀਕੋ ਵੇਲਾ (ਸੈਂਟਾ ਇਸਾਬੇਲ)", + "America\/Santarem": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਸੇਂਟਾਰਮ)", + "America\/Santiago": "ਚਿਲੀ ਵੇਲਾ (ਸੇਂਟੀਆਗੋ)", + "America\/Santo_Domingo": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਸੇਂਟੋ ਡੋਮਿੰਗੋ)", + "America\/Sao_Paulo": "ਬ੍ਰਾਜ਼ੀਲੀਆ ਵੇਲਾ (ਸਾਓ ਪੌਲੋ)", + "America\/Scoresbysund": "ਪੂਰਬੀ ਗ੍ਰੀਨਲੈਂਡ ਵੇਲਾ (ਇੱਟੋਕੋਰਟੂਰਮੀਟ)", + "America\/Sitka": "ਅਲਾਸਕਾ ਵੇਲਾ (ਸਿਟਕਾ)", + "America\/St_Barthelemy": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਸੇਂਟ ਬਾਰਥੇਲੇਮੀ)", + "America\/St_Johns": "ਨਿਊਫਾਉਂਡਲੈਂਡ ਵੇਲਾ (ਸੇਂਟ ਜੌਹਨਸ)", + "America\/St_Kitts": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਸੇਂਟ ਕਿਟਸ)", + "America\/St_Lucia": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਸੇਂਟ ਲੁਸੀਆ)", + "America\/St_Thomas": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਸੇਂਟ ਥੋਮਸ)", + "America\/St_Vincent": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਸੇਂਟ ਵਿਨਸੇਂਟ)", + "America\/Swift_Current": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਸਵਿਫਟ ਕਰੰਟ)", + "America\/Tegucigalpa": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਟੇਗੁਸੀਗਲਪਾ)", + "America\/Thule": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਥੁਲੇ)", + "America\/Thunder_Bay": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਥੰਡਰ ਬੇ)", + "America\/Tijuana": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਟਿਜੂਆਨਾ)", + "America\/Toronto": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ (ਟੋਰਾਂਟੋ)", + "America\/Tortola": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਟੋਰਟੋਲਾ)", + "America\/Vancouver": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਵੈਨਕੂਵਰ)", + "America\/Whitehorse": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੈਸਿਫਿਕ ਵੇਲਾ (ਵਾਈਟਹੌਰਸ)", + "America\/Winnipeg": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ (ਵਿਨੀਪੈਗ)", + "America\/Yakutat": "ਅਲਾਸਕਾ ਵੇਲਾ (ਯਕੁਤਤ)", + "America\/Yellowknife": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ (ਯੈਲੋਨਾਈਫ)", + "Antarctica\/Casey": "ਪੱਛਮੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਕਾਸੇ)", + "Antarctica\/Davis": "ਡੇਵਿਸ ਵੇਲਾ (ਡੇਵਿਸ)", + "Antarctica\/DumontDUrville": "ਡਿਉਮੋਂਟ ਡਿਉਰਵਿਲੇ ਵੇਲਾ (ਡਿਉਮੋਂਟ ਡਿਉਰਵਿਲੇ)", + "Antarctica\/Macquarie": "ਮੈਕਕਵੇਰੀ ਆਈਲੈਂਡ ਵੇਲਾ (ਮੈਕਕਵੈਰੀ)", + "Antarctica\/Mawson": "ਮੌਸਨ ਵੇਲਾ (ਮੌਸਨ)", + "Antarctica\/McMurdo": "ਨਿਊਜ਼ੀਲੈਂਡ ਵੇਲਾ (ਮੈਕਮੁਰਡੋ)", + "Antarctica\/Palmer": "ਚਿਲੀ ਵੇਲਾ (ਪਾਮਰ)", + "Antarctica\/Rothera": "ਰੋਥੇਰਾ ਵੇਲਾ (ਰੋਥੇਰਾ)", + "Antarctica\/Syowa": "ਸਿਓਵਾ ਵੇਲਾ (ਸਵੋਯਾ)", + "Antarctica\/Troll": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਟਰੋਲ)", + "Antarctica\/Vostok": "ਵੋਸਟੋਕ ਵੇਲਾ (ਵੋਸਟੋਕ)", + "Arctic\/Longyearbyen": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਲੋਂਗਈਅਰਬਾਇਨ)", + "Asia\/Aden": "ਅਰਬੀ ਵੇਲਾ (ਅਡੇਨ)", + "Asia\/Almaty": "ਪੂਰਬੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਅਲਮੇਟੀ)", + "Asia\/Amman": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਅਮਾਨ)", + "Asia\/Aqtau": "ਪੱਛਮੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਅਕਤੌ)", + "Asia\/Aqtobe": "ਪੱਛਮੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਅਕਤੋਬੇ)", + "Asia\/Ashgabat": "ਤੁਰਕਮੇਨਿਸਤਾਨ ਵੇਲਾ (ਅਸ਼ਗਾਬਾਟ)", + "Asia\/Atyrau": "ਪੱਛਮੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਏਤੇਰਾਓ)", + "Asia\/Baghdad": "ਅਰਬੀ ਵੇਲਾ (ਬਗਦਾਦ)", + "Asia\/Bahrain": "ਅਰਬੀ ਵੇਲਾ (ਬਹਿਰੀਨ)", + "Asia\/Baku": "ਅਜ਼ਰਬਾਈਜਾਨ ਵੇਲਾ (ਬਾਕੂ)", + "Asia\/Bangkok": "ਇੰਡੋਚਾਈਨਾ ਵੇਲਾ (ਬੈਂਕਾਕ)", + "Asia\/Beirut": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਬੈਰੂਤ)", + "Asia\/Bishkek": "ਕਿਰਗਿਸਤਾਨ ਵੇਲਾ (ਬਿਸ਼ਕੇਕ)", + "Asia\/Brunei": "ਬਰੂਨੇਈ ਦਾਰੂਸਲਾਮ ਵੇਲਾ (ਬਰੂਨੇਈ)", + "Asia\/Calcutta": "ਭਾਰਤੀ ਮਿਆਰੀ ਵੇਲਾ (ਕੋਲਕਾਤਾ)", + "Asia\/Chita": "ਯਕੁਤਸਕ ਵੇਲਾ (ਚਿਤਾ)", + "Asia\/Choibalsan": "ਚੌਇਬਾਲਸਨ ਵੇਲਾ (ਚੋਇਲਬਾਲਸਨ)", + "Asia\/Colombo": "ਭਾਰਤੀ ਮਿਆਰੀ ਵੇਲਾ (ਕੋਲੰਬੋ)", + "Asia\/Damascus": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਡੈਮਸਕਸ)", + "Asia\/Dhaka": "ਬੰਗਲਾਦੇਸ਼ ਵੇਲਾ (ਢਾਕਾ)", + "Asia\/Dili": "ਪੂਰਬੀ ਤਿਮੂਰ ਵੇਲਾ (ਡਿਲੀ)", + "Asia\/Dubai": "ਖਾੜੀ ਮਿਆਰੀ ਵੇਲਾ (ਦੁਬਈ)", + "Asia\/Dushanbe": "ਤਾਜਿਕਿਸਤਾਨ ਵੇਲਾ (ਦੁਸ਼ਾਂਬੇ)", + "Asia\/Famagusta": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਫਾਮਾਗੁਸਟਾ)", + "Asia\/Gaza": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਗਾਜ਼ਾ)", + "Asia\/Hebron": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਹੇਬਰਾਨ)", + "Asia\/Hong_Kong": "ਹਾਂਗ ਕਾਂਗ ਵੇਲਾ (ਹਾਂਗ ਕਾਂਗ)", + "Asia\/Hovd": "ਹੋਵਡ ਵੇਲਾ (ਹੋਵਡ)", + "Asia\/Irkutsk": "ਇਰਕੁਤਸਕ ਵੇਲਾ (ਇਰਕੁਤਸਕ)", + "Asia\/Jakarta": "ਪੱਛਮੀ ਇੰਡੋਨੇਸ਼ੀਆ ਵੇਲਾ (ਜਕਾਰਤਾ)", + "Asia\/Jayapura": "ਪੂਰਬੀ ਇੰਡੋਨੇਸ਼ੀਆ ਵੇਲਾ (ਜਯਾਪੁਰਾ)", + "Asia\/Jerusalem": "ਇਜ਼ਰਾਈਲ ਵੇਲਾ (ਜੇਰੂਸਲਮ)", + "Asia\/Kabul": "ਅਫ਼ਗਾਨਿਸਤਾਨ ਵੇਲਾ (ਕਾਬੁਲ)", + "Asia\/Karachi": "ਪਾਕਿਸਤਾਨ ਵੇਲਾ (ਕਰਾਚੀ)", + "Asia\/Katmandu": "ਨੇਪਾਲ ਵੇਲਾ (ਕਾਠਮਾਂਡੂ)", + "Asia\/Khandyga": "ਯਕੁਤਸਕ ਵੇਲਾ (ਖਾਨਡਿਗਾ)", + "Asia\/Krasnoyarsk": "ਕ੍ਰਾਸਨੋਯਾਰਸਕ ਵੇਲਾ (ਕਰੈਸਨੇਜਰਸ)", + "Asia\/Kuala_Lumpur": "ਮਲੇਸ਼ੀਆ ਵੇਲਾ (ਕੁਆਲਾਲੰਪੁਰ)", + "Asia\/Kuching": "ਮਲੇਸ਼ੀਆ ਵੇਲਾ (ਕੁਚਿੰਗ)", + "Asia\/Kuwait": "ਅਰਬੀ ਵੇਲਾ (ਕੁਵੈਤ)", + "Asia\/Macau": "ਚੀਨ ਵੇਲਾ (ਮਕਾਉ)", + "Asia\/Magadan": "ਮੈਗੇਡਨ ਵੇਲਾ (ਮੈਗੇਡਨ)", + "Asia\/Makassar": "ਮੱਧ ਇੰਡੋਨੇਸ਼ੀਆਈ ਵੇਲਾ (ਮਕਸਾਰ)", + "Asia\/Manila": "ਫਿਲਿਪੀਨੀ ਵੇਲਾ (ਮਨੀਲਾ)", + "Asia\/Muscat": "ਖਾੜੀ ਮਿਆਰੀ ਵੇਲਾ (ਮਸਕਟ)", + "Asia\/Nicosia": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਨਿਕੋਸੀਆ)", + "Asia\/Novokuznetsk": "ਕ੍ਰਾਸਨੋਯਾਰਸਕ ਵੇਲਾ (ਨੋਵੋਕੁਜ਼ਨੇਟਸਕ)", + "Asia\/Novosibirsk": "ਨੌਵੋਸਿਬੀਰਸਕ ਵੇਲਾ (ਨੋਵੋਸਿਬੀਰਸਕ)", + "Asia\/Omsk": "ਓਮਸਕ ਵੇਲਾ (ਓਮਸਕ)", + "Asia\/Oral": "ਪੱਛਮੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਓਰਲ)", + "Asia\/Phnom_Penh": "ਇੰਡੋਚਾਈਨਾ ਵੇਲਾ (ਫਨੋਮ ਪੇਨਹ)", + "Asia\/Pontianak": "ਪੱਛਮੀ ਇੰਡੋਨੇਸ਼ੀਆ ਵੇਲਾ (ਪੌਂਟੀਆਨਾਕ)", + "Asia\/Pyongyang": "ਕੋਰੀਆਈ ਵੇਲਾ (ਪਯੋਂਗਯਾਂਗ)", + "Asia\/Qatar": "ਅਰਬੀ ਵੇਲਾ (ਕਤਰ)", + "Asia\/Qostanay": "ਪੂਰਬੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਕੋਸਟਨੇਏ)", + "Asia\/Qyzylorda": "ਪੱਛਮੀ ਕਜ਼ਾਖ਼ਸਤਾਨ ਵੇਲਾ (ਕਿਜ਼ੀਲੋਰਡਾ)", + "Asia\/Rangoon": "ਮਿਆਂਮਾਰ ਵੇਲਾ (ਰੰਗੂਨ)", + "Asia\/Riyadh": "ਅਰਬੀ ਵੇਲਾ (ਰਿਆਧ)", + "Asia\/Saigon": "ਇੰਡੋਚਾਈਨਾ ਵੇਲਾ (ਹੋ ਚੀ ਮਿਨ੍ਹ ਸਿਟੀ)", + "Asia\/Sakhalin": "ਸਖਲੀਨ ਵੇਲਾ (ਸਖਲੀਨ)", + "Asia\/Samarkand": "ਉਜ਼ਬੇਕਿਸਤਾਨ ਵੇਲਾ (ਸਮਰਕੰਦ)", + "Asia\/Seoul": "ਕੋਰੀਆਈ ਵੇਲਾ (ਸਿਉਲ)", + "Asia\/Shanghai": "ਚੀਨ ਵੇਲਾ (ਸ਼ੰਘਾਈ)", + "Asia\/Singapore": "ਸਿੰਗਾਪੁਰ ਮਿਆਰੀ ਵੇਲਾ (ਸਿੰਗਾਪੁਰ)", + "Asia\/Srednekolymsk": "ਮੈਗੇਡਨ ਵੇਲਾ (ਸਰਿਡਨੀਕੋਲਿਸਕ)", + "Asia\/Taipei": "ਤੈਪਈ ਵੇਲਾ (ਤੈਪਈ)", + "Asia\/Tashkent": "ਉਜ਼ਬੇਕਿਸਤਾਨ ਵੇਲਾ (ਤਾਸ਼ਕੰਦ)", + "Asia\/Tbilisi": "ਜਾਰਜੀਆ ਵੇਲਾ (ਟਬਿਲਿਸੀ)", + "Asia\/Tehran": "ਈਰਾਨ ਵੇਲਾ (ਤੇਹਰਾਨ)", + "Asia\/Thimphu": "ਭੂਟਾਨ ਵੇਲਾ (ਥਿੰਫੂ)", + "Asia\/Tokyo": "ਜਪਾਨ ਵੇਲਾ (ਟੋਕੀਓ)", + "Asia\/Ulaanbaatar": "ਉਲਨ ਬਟੋਰ ਵੇਲਾ (ਉਲਾਨਬਾਤਰ)", + "Asia\/Ust-Nera": "ਵਲਾਦੀਵੋਸਤਕ ਵੇਲਾ (ਉਸਤ-ਨੇਰਾ)", + "Asia\/Vientiane": "ਇੰਡੋਚਾਈਨਾ ਵੇਲਾ (ਵਾਏਨਟਿਆਨੇ)", + "Asia\/Vladivostok": "ਵਲਾਦੀਵੋਸਤਕ ਵੇਲਾ (ਵਲਾਦੀਵੋਸਤਕ)", + "Asia\/Yakutsk": "ਯਕੁਤਸਕ ਵੇਲਾ (ਯਕੁਤਸਕ)", + "Asia\/Yekaterinburg": "ਯਕੇਤਰਿਨਬਰਗ ਵੇਲਾ (ਯਕੇਤਰਿਨਬਰਗ)", + "Asia\/Yerevan": "ਅਰਮੀਨੀਆ ਵੇਲਾ (ਯੇਰੇਵਨ)", + "Atlantic\/Azores": "ਅਜੋਰੇਸ ਵੇਲਾ (ਅਜੋਰੇਸ)", + "Atlantic\/Bermuda": "ਅਟਲਾਂਟਿਕ ਵੇਲਾ (ਬਰਮੂਡਾ)", + "Atlantic\/Canary": "ਪੱਛਮੀ ਯੂਰਪੀ ਵੇਲਾ (ਕੇਨੇਰੀ)", + "Atlantic\/Cape_Verde": "ਕੇਪ ਵਰਡ ਵੇਲਾ (ਕੇਪ ਵਰਡ)", + "Atlantic\/Faeroe": "ਪੱਛਮੀ ਯੂਰਪੀ ਵੇਲਾ (ਫੈਰੋ)", + "Atlantic\/Madeira": "ਪੱਛਮੀ ਯੂਰਪੀ ਵੇਲਾ (ਮਡੀਅਰਾ)", + "Atlantic\/Reykjavik": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਰੇਕਜਾਵਿਕ)", + "Atlantic\/South_Georgia": "ਦੱਖਣੀ ਜਾਰਜੀਆ ਵੇਲਾ (ਦੱਖਣੀ ਜਾਰਜੀਆ)", + "Atlantic\/St_Helena": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਸੇਂਟ ਹੇਲੇਨਾ)", + "Atlantic\/Stanley": "ਫ਼ਾਕਲੈਂਡ ਆਈਲੈਂਡਸ ਵੇਲਾ (ਸਟੇਨਲੀ)", + "Australia\/Adelaide": "ਕੇਂਦਰੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਐਡੀਲੇਡ)", + "Australia\/Brisbane": "ਪੂਰਬੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਬ੍ਰਿਸਬੇਨ)", + "Australia\/Broken_Hill": "ਕੇਂਦਰੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਬ੍ਰੋਕਨ ਹਿਲ)", + "Australia\/Currie": "ਪੂਰਬੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਕਰੀ)", + "Australia\/Darwin": "ਕੇਂਦਰੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਡਾਰਵਿਨ)", + "Australia\/Eucla": "ਆਸਟ੍ਰੇਲੀਆਈ ਕੇਂਦਰੀ ਪੱਛਮੀ ਵੇਲਾ (ਯੂਕਲਾ)", + "Australia\/Hobart": "ਪੂਰਬੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਹੋਬਾਰਟ)", + "Australia\/Lindeman": "ਪੂਰਬੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਲਿੰਡੇਮਨ)", + "Australia\/Lord_Howe": "ਲੌਰਡ ਹੋਵੇ ਵੇਲਾ (ਲੌਰਡ ਹੋਵੇ)", + "Australia\/Melbourne": "ਪੂਰਬੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਮੈਲਬੋਰਨ)", + "Australia\/Perth": "ਪੱਛਮੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਪਰਥ)", + "Australia\/Sydney": "ਪੂਰਬੀ ਆਸਟ੍ਰੇਲੀਆਈ ਵੇਲਾ (ਸਿਡਨੀ)", + "CST6CDT": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਕੇਂਦਰੀ ਵੇਲਾ", + "EST5EDT": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੂਰਬੀ ਵੇਲਾ", + "Etc\/GMT": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ", + "Etc\/UTC": "ਕੋਔਰਡੀਨੇਟੇਡ ਵਿਆਪਕ ਵੇਲਾ", + "Europe\/Amsterdam": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਐਮਸਟਰਡਮ)", + "Europe\/Andorra": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਅੰਡੋਰਾ)", + "Europe\/Astrakhan": "ਮਾਸਕੋ ਵੇਲਾ (ਆਸਟ੍ਰਾਖਾਨ)", + "Europe\/Athens": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਏਥਨਸ)", + "Europe\/Belgrade": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਬੈਲਗ੍ਰੇਡ)", + "Europe\/Berlin": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਬਰਲਿਨ)", + "Europe\/Bratislava": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਬ੍ਰਾਟਿਸਲਾਵਾ)", + "Europe\/Brussels": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਬਰੱਸਲਜ)", + "Europe\/Bucharest": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਬੂਕਾਰੈਸਟ)", + "Europe\/Budapest": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਬੁਡਾਪੈਸਟ)", + "Europe\/Busingen": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਬੁਸਿੰਜੇਨ)", + "Europe\/Chisinau": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਚਿਸਿਨੌ)", + "Europe\/Copenhagen": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਕੋਪਨਹੇਗਨ)", + "Europe\/Dublin": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਡਬਲਿਨ)", + "Europe\/Gibraltar": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਜਿਬਰਾਲਟਰ)", + "Europe\/Guernsey": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਗਰਨਜੀ)", + "Europe\/Helsinki": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਹੇਲਸਿੰਕੀ)", + "Europe\/Isle_of_Man": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਆਇਲ ਆਫ ਮੈਨ)", + "Europe\/Jersey": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਜਰਸੀ)", + "Europe\/Kaliningrad": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਕਲੀਨਿੰਗ੍ਰੇਡ)", + "Europe\/Kiev": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਕੀਵ)", + "Europe\/Lisbon": "ਪੱਛਮੀ ਯੂਰਪੀ ਵੇਲਾ (ਲਿਸਬਨ)", + "Europe\/Ljubljana": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਲਜੁਬਲਜਾਨਾ)", + "Europe\/London": "ਗ੍ਰੀਨਵਿਚ ਮੀਨ ਵੇਲਾ (ਲੰਡਨ)", + "Europe\/Luxembourg": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਲਕਜ਼ਮਬਰਗ)", + "Europe\/Madrid": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਮੈਡ੍ਰਿਡ)", + "Europe\/Malta": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਮਾਲਟਾ)", + "Europe\/Mariehamn": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਮਾਰੀਏਹਾਮੇਨ)", + "Europe\/Minsk": "ਮਾਸਕੋ ਵੇਲਾ (ਮਿੰਸਕ)", + "Europe\/Monaco": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਮੋਨਾਕੋ)", + "Europe\/Moscow": "ਮਾਸਕੋ ਵੇਲਾ (ਮਾਸਕੋ)", + "Europe\/Oslo": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਓਸਲੋ)", + "Europe\/Paris": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਪੈਰਿਸ)", + "Europe\/Podgorica": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਪੋਡਗੋਰੀਕਾ)", + "Europe\/Prague": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਪ੍ਰਾਗ)", + "Europe\/Riga": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਰਿਗਾ)", + "Europe\/Rome": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਰੋਮ)", + "Europe\/San_Marino": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਸੈਨ ਮਰੀਨੋ)", + "Europe\/Sarajevo": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਸਾਰਾਜੇਵੋ)", + "Europe\/Saratov": "ਮਾਸਕੋ ਵੇਲਾ (ਸੈਰਾਟੋਵ)", + "Europe\/Simferopol": "ਮਾਸਕੋ ਵੇਲਾ (ਸਿਮਫਰੋਪੋਲ)", + "Europe\/Skopje": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਸਕੋਪਜੇ)", + "Europe\/Sofia": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਸੋਫੀਆ)", + "Europe\/Stockholm": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਸਟਾਕਹੋਮ)", + "Europe\/Tallinn": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਟੱਲਿਨ)", + "Europe\/Tirane": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਤਿਰਾਨੇ)", + "Europe\/Ulyanovsk": "ਮਾਸਕੋ ਵੇਲਾ (ਯੁਲਿਆਨੋਸਕ)", + "Europe\/Uzhgorod": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਉਜ਼ਗੋਰੋਡ)", + "Europe\/Vaduz": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਵਾਡੁਜ਼)", + "Europe\/Vatican": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਵੈਟਿਕਨ)", + "Europe\/Vienna": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਵਿਆਨਾ)", + "Europe\/Vilnius": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਵਿਲਨਿਅਸ)", + "Europe\/Volgograd": "ਵੋਲਗੋਗ੍ਰੇਡ ਵੇਲਾ (ਵੋਲਗੋਗ੍ਰੇਡ)", + "Europe\/Warsaw": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਵਾਰਸਾਅ)", + "Europe\/Zagreb": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਜ਼ਗਰੇਬ)", + "Europe\/Zaporozhye": "ਪੂਰਬੀ ਯੂਰਪੀ ਵੇਲਾ (ਜਪੋਰੋਜ਼ਾਏ)", + "Europe\/Zurich": "ਮੱਧ ਯੂਰਪੀ ਵੇਲਾ (ਜਿਊਰਿਖ)", + "Indian\/Antananarivo": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਅੰਟਾਨਨੇਰਿਵੋ)", + "Indian\/Chagos": "ਹਿੰਦ ਮਹਾਂਸਾਗਰ ਵੇਲਾ (ਚਾਗੋਸ)", + "Indian\/Christmas": "ਕ੍ਰਿਸਮਸ ਆਈਲੈਂਡ ਵੇਲਾ (ਕ੍ਰਿਸਮਸ)", + "Indian\/Cocos": "ਕੋਕਸ ਆਈਲੈਂਡ ਵੇਲਾ (ਕੋਕੋਜ਼)", + "Indian\/Comoro": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਕੋਮੋਰੋ)", + "Indian\/Kerguelen": "ਫ੍ਰੈਂਚ ਦੱਖਣੀ ਅਤੇ ਐਂਟਾਰਟਿਕ ਵੇਲਾ (ਕਰਗਯੂਲੇਨ)", + "Indian\/Mahe": "ਸੇਸ਼ਲਸ ਵੇਲਾ (ਮਾਹੇ)", + "Indian\/Maldives": "ਮਾਲਦੀਵ ਵੇਲਾ (ਮਾਲਦੀਵ)", + "Indian\/Mauritius": "ਮੌਰਿਸ਼ਸ ਵੇਲਾ (ਮੌਰਿਸ਼ਸ)", + "Indian\/Mayotte": "ਪੂਰਬੀ ਅਫਰੀਕਾ ਵੇਲਾ (ਮਾਯੋਟੀ)", + "Indian\/Reunion": "ਰਿਯੂਨੀਅਨ ਵੇਲਾ (ਰਿਯੂਨੀਅਨ)", + "MST7MDT": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਮਾਉਂਟੇਨ ਵੇਲਾ", + "PST8PDT": "ਉੱਤਰੀ ਅਮਰੀਕੀ ਪੈਸਿਫਿਕ ਵੇਲਾ", + "Pacific\/Apia": "ਐਪੀਆ ਵੇਲਾ (ਐਪੀਆ)", + "Pacific\/Auckland": "ਨਿਊਜ਼ੀਲੈਂਡ ਵੇਲਾ (ਆਕਲੈਂਡ)", + "Pacific\/Bougainville": "ਪਾਪੂਆ ਨਿਊ ਗਿਨੀ ਵੇਲਾ (ਬੋਗਨਵਿਲੇ)", + "Pacific\/Chatham": "ਚੈਥਮ ਵੇਲਾ (ਚੈਥਮ)", + "Pacific\/Easter": "ਈਸਟਰ ਆਈਲੈਂਡ ਵੇਲਾ (ਈਸਟਰ)", + "Pacific\/Efate": "ਵਾਨੂਆਟੂ ਵੇਲਾ (ਇਫੇਟ)", + "Pacific\/Enderbury": "ਫਿਨਿਕਸ ਆਈਲੈਂਡ ਵੇਲਾ (ਏਂਡਰਬਰੀ)", + "Pacific\/Fakaofo": "ਟੋਕੇਲਾਉ ਵੇਲਾ (ਫਕਾਉਫੋ)", + "Pacific\/Fiji": "ਫ਼ਿਜ਼ੀ ਵੇਲਾ (ਫ਼ਿਜੀ)", + "Pacific\/Funafuti": "ਟੁਵਾਲੂ ਵੇਲਾ (ਫੁਨਾਫੁਟੀ)", + "Pacific\/Galapagos": "ਗਲਾਪਾਗੋਸ ਵੇਲਾ (ਗਲਪੇਗੋਸ)", + "Pacific\/Gambier": "ਗੈਂਬੀਅਰ ਵੇਲਾ (ਗੈਂਬੀਅਰ)", + "Pacific\/Guadalcanal": "ਸੋਲੋਮਨ ਆਈਲੈਂਡਸ ਵੇਲਾ (ਗੁਆਡਾਕੇਨਲ)", + "Pacific\/Guam": "ਚਾਮੋਰੋ ਮਿਆਰੀ ਵੇਲਾ (ਗੁਆਮ)", + "Pacific\/Honolulu": "ਹਵਾਈ-ਅਲੇਯੂਸ਼ਿਅਨ ਵੇਲਾ (ਹੋਨੋਲੁਲੂ)", + "Pacific\/Johnston": "ਹਵਾਈ-ਅਲੇਯੂਸ਼ਿਅਨ ਵੇਲਾ (ਜੋਨਸਟਨ)", + "Pacific\/Kiritimati": "ਲਾਈਨ ਆਈਲੈਂਡ ਵੇਲਾ (ਕਿਰਿਤਿਮਤੀ)", + "Pacific\/Kosrae": "ਕੋਸਰੇ ਵੇਲਾ (ਕੋਸ੍ਰਾਏ)", + "Pacific\/Kwajalein": "ਮਾਰਸ਼ਲ ਆਈਲੈਂਡ ਵੇਲਾ (ਕਵਾਜਾਲੀਨ)", + "Pacific\/Majuro": "ਮਾਰਸ਼ਲ ਆਈਲੈਂਡ ਵੇਲਾ (ਮੇਜੁਰੋ)", + "Pacific\/Marquesas": "ਮਾਰਕਿਸਾਸ ਵੇਲਾ (ਮਾਰਕਿਸਾਸ)", + "Pacific\/Midway": "ਸਾਮੋਆ ਵੇਲਾ (ਮਿਡਵੇ)", + "Pacific\/Nauru": "ਨਾਉਰੂ ਵੇਲਾ (ਨਾਉਰੂ)", + "Pacific\/Niue": "ਨੀਊ ਵੇਲਾ (ਨਿਯੂ)", + "Pacific\/Norfolk": "ਨੋਰਫੌਕ ਆਈਲੈਂਡ ਵੇਲਾ (ਨੋਰਫੌਕ)", + "Pacific\/Noumea": "ਨਿਊ ਕੈਲੇਡੋਨੀਆ ਵੇਲਾ (ਨੌਮਿਆ)", + "Pacific\/Pago_Pago": "ਸਾਮੋਆ ਵੇਲਾ (ਪਾਗੋ ਪਾਗੋ)", + "Pacific\/Palau": "ਪਲਾਉ ਵੇਲਾ (ਪਲਾਉ)", + "Pacific\/Pitcairn": "ਪਿਟਕੈਰਨ ਵੇਲਾ (ਪਿਟਕੈਰਨ)", + "Pacific\/Ponape": "ਪੋਨਾਪੇ ਵੇਲਾ (ਪੋਹਨਪੇਈ)", + "Pacific\/Port_Moresby": "ਪਾਪੂਆ ਨਿਊ ਗਿਨੀ ਵੇਲਾ (ਪੋਰਟ ਮੋਰੇਸਬੀ)", + "Pacific\/Rarotonga": "ਕੁੱਕ ਆਈਲੈਂਡ ਵੇਲਾ (ਰਾਰੋਟੋਂਗਾ)", + "Pacific\/Saipan": "ਚਾਮੋਰੋ ਮਿਆਰੀ ਵੇਲਾ (ਸੈਪਾਨ)", + "Pacific\/Tahiti": "ਤਾਹੀਤੀ ਵੇਲਾ (ਤਹਿਤੀ)", + "Pacific\/Tarawa": "ਗਿਲਬਰਟ ਆਈਲੈਂਡ ਵੇਲਾ (ਟਾਰਾਵਾ)", + "Pacific\/Tongatapu": "ਟੋਂਗਾ ਵੇਲਾ (ਟੋਂਗਾਟਾਪੂ)", + "Pacific\/Truk": "ਚੂਕ ਵੇਲਾ (ਚੂਕ)", + "Pacific\/Wake": "ਵੇਕ ਆਈਲੈਂਡ ਵੇਲਾ (ਵੇਕ)", + "Pacific\/Wallis": "ਵਾਲਿਸ ਅਤੇ ਫੁਟੂਨਾ ਵੇਲਾ (ਵਾਲਿਸ)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pl.json b/src/Symfony/Component/Intl/Resources/data/timezones/pl.json new file mode 100644 index 0000000000000..dd78de26b7d46 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pl.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "czas uniwersalny (Abidżan)", + "Africa\/Accra": "czas uniwersalny (Akra)", + "Africa\/Addis_Ababa": "czas wschodnioafrykański (Addis Abeba)", + "Africa\/Algiers": "czas środkowoeuropejski (Algier)", + "Africa\/Asmera": "czas wschodnioafrykański (Asmara)", + "Africa\/Bamako": "czas uniwersalny (Bamako)", + "Africa\/Bangui": "czas zachodnioafrykański (Bangi)", + "Africa\/Banjul": "czas uniwersalny (Bandżul)", + "Africa\/Bissau": "czas uniwersalny (Bissau)", + "Africa\/Blantyre": "czas środkowoafrykański (Blantyre)", + "Africa\/Brazzaville": "czas zachodnioafrykański (Brazzaville)", + "Africa\/Bujumbura": "czas środkowoafrykański (Bużumbura)", + "Africa\/Cairo": "czas wschodnioeuropejski (Kair)", + "Africa\/Casablanca": "czas zachodnioeuropejski (Casablanca)", + "Africa\/Ceuta": "czas środkowoeuropejski (Ceuta)", + "Africa\/Conakry": "czas uniwersalny (Konakry)", + "Africa\/Dakar": "czas uniwersalny (Dakar)", + "Africa\/Dar_es_Salaam": "czas wschodnioafrykański (Dar es Salaam)", + "Africa\/Djibouti": "czas wschodnioafrykański (Dżibuti)", + "Africa\/Douala": "czas zachodnioafrykański (Duala)", + "Africa\/El_Aaiun": "czas zachodnioeuropejski (Al-Ujun)", + "Africa\/Freetown": "czas uniwersalny (Freetown)", + "Africa\/Gaborone": "czas środkowoafrykański (Gaborone)", + "Africa\/Harare": "czas środkowoafrykański (Harare)", + "Africa\/Johannesburg": "czas południowoafrykański (Johannesburg)", + "Africa\/Juba": "czas wschodnioafrykański (Dżuba)", + "Africa\/Kampala": "czas wschodnioafrykański (Kampala)", + "Africa\/Khartoum": "czas środkowoafrykański (Chartum)", + "Africa\/Kigali": "czas środkowoafrykański (Kigali)", + "Africa\/Kinshasa": "czas zachodnioafrykański (Kinszasa)", + "Africa\/Lagos": "czas zachodnioafrykański (Lagos)", + "Africa\/Libreville": "czas zachodnioafrykański (Libreville)", + "Africa\/Lome": "czas uniwersalny (Lomé)", + "Africa\/Luanda": "czas zachodnioafrykański (Luanda)", + "Africa\/Lubumbashi": "czas środkowoafrykański (Lubumbashi)", + "Africa\/Lusaka": "czas środkowoafrykański (Lusaka)", + "Africa\/Malabo": "czas zachodnioafrykański (Malabo)", + "Africa\/Maputo": "czas środkowoafrykański (Maputo)", + "Africa\/Maseru": "czas południowoafrykański (Maseru)", + "Africa\/Mbabane": "czas południowoafrykański (Mbabane)", + "Africa\/Mogadishu": "czas wschodnioafrykański (Mogadiszu)", + "Africa\/Monrovia": "czas uniwersalny (Monrovia)", + "Africa\/Nairobi": "czas wschodnioafrykański (Nairobi)", + "Africa\/Ndjamena": "czas zachodnioafrykański (Ndżamena)", + "Africa\/Niamey": "czas zachodnioafrykański (Niamey)", + "Africa\/Nouakchott": "czas uniwersalny (Nawakszut)", + "Africa\/Ouagadougou": "czas uniwersalny (Wagadugu)", + "Africa\/Porto-Novo": "czas zachodnioafrykański (Porto Novo)", + "Africa\/Sao_Tome": "czas uniwersalny (São Tomé)", + "Africa\/Tripoli": "czas wschodnioeuropejski (Trypolis)", + "Africa\/Tunis": "czas środkowoeuropejski (Tunis)", + "Africa\/Windhoek": "czas środkowoafrykański (Windhuk)", + "America\/Adak": "Hawaje-Aleuty (Adak)", + "America\/Anchorage": "Alaska (Anchorage)", + "America\/Anguilla": "czas atlantycki (Anguilla)", + "America\/Antigua": "czas atlantycki (Antigua)", + "America\/Araguaina": "Brasília (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentyna (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentyna (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentyna (Salta)", + "America\/Argentina\/San_Juan": "Argentyna (San Juan)", + "America\/Argentina\/San_Luis": "Argentyna Zachodnia (San Luis)", + "America\/Argentina\/Tucuman": "Argentyna (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentyna (Ushuaia)", + "America\/Aruba": "czas atlantycki (Aruba)", + "America\/Asuncion": "Paragwaj (Asunción)", + "America\/Bahia": "Brasília (Salvador)", + "America\/Bahia_Banderas": "czas środkowoamerykański (Bahia Banderas)", + "America\/Barbados": "czas atlantycki (Barbados)", + "America\/Belem": "Brasília (Belém)", + "America\/Belize": "czas środkowoamerykański (Belize)", + "America\/Blanc-Sablon": "czas atlantycki (Blanc-Sablon)", + "America\/Boa_Vista": "czas amazoński (Boa Vista)", + "America\/Bogota": "Kolumbia (Bogota)", + "America\/Boise": "czas górski (Boise)", + "America\/Buenos_Aires": "Argentyna (Buenos Aires)", + "America\/Cambridge_Bay": "czas górski (Cambridge Bay)", + "America\/Campo_Grande": "czas amazoński (Campo Grande)", + "America\/Cancun": "czas wschodnioamerykański (Cancún)", + "America\/Caracas": "Wenezuela (Caracas)", + "America\/Catamarca": "Argentyna (Catamarca)", + "America\/Cayenne": "Gujana Francuska (Kajenna)", + "America\/Cayman": "czas wschodnioamerykański (Kajmany)", + "America\/Chicago": "czas środkowoamerykański (Chicago)", + "America\/Chihuahua": "Meksyk (czas pacyficzny) (Chihuahua)", + "America\/Coral_Harbour": "czas wschodnioamerykański (Atikokan)", + "America\/Cordoba": "Argentyna (Córdoba)", + "America\/Costa_Rica": "czas środkowoamerykański (Kostaryka)", + "America\/Creston": "czas górski (Creston)", + "America\/Cuiaba": "czas amazoński (Cuiabá)", + "America\/Curacao": "czas atlantycki (Curaçao)", + "America\/Danmarkshavn": "czas uniwersalny (Danmarkshavn)", + "America\/Dawson": "czas pacyficzny (Dawson)", + "America\/Dawson_Creek": "czas górski (Dawson Creek)", + "America\/Denver": "czas górski (Denver)", + "America\/Detroit": "czas wschodnioamerykański (Detroit)", + "America\/Dominica": "czas atlantycki (Dominika)", + "America\/Edmonton": "czas górski (Edmonton)", + "America\/El_Salvador": "czas środkowoamerykański (Salwador)", + "America\/Fort_Nelson": "czas górski (Fort Nelson)", + "America\/Fortaleza": "Brasília (Fortaleza)", + "America\/Glace_Bay": "czas atlantycki (Glace Bay)", + "America\/Godthab": "Grenlandia Zachodnia (Nuuk)", + "America\/Goose_Bay": "czas atlantycki (Goose Bay)", + "America\/Grand_Turk": "czas wschodnioamerykański (Grand Turk)", + "America\/Grenada": "czas atlantycki (Grenada)", + "America\/Guadeloupe": "czas atlantycki (Gwadelupa)", + "America\/Guatemala": "czas środkowoamerykański (Gwatemala)", + "America\/Guayaquil": "Ekwador (Guayaquil)", + "America\/Guyana": "Gujana (Gujana)", + "America\/Halifax": "czas atlantycki (Halifax)", + "America\/Havana": "Kuba (Hawana)", + "America\/Hermosillo": "Meksyk (czas pacyficzny) (Hermosillo)", + "America\/Indiana\/Knox": "czas środkowoamerykański (Knox, Indiana)", + "America\/Indiana\/Marengo": "czas wschodnioamerykański (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "czas wschodnioamerykański (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "czas środkowoamerykański (Tell City, Indiana)", + "America\/Indiana\/Vevay": "czas wschodnioamerykański (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "czas wschodnioamerykański (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "czas wschodnioamerykański (Winamac, Indiana)", + "America\/Indianapolis": "czas wschodnioamerykański (Indianapolis)", + "America\/Inuvik": "czas górski (Inuvik)", + "America\/Iqaluit": "czas wschodnioamerykański (Iqaluit)", + "America\/Jamaica": "czas wschodnioamerykański (Jamajka)", + "America\/Jujuy": "Argentyna (Jujuy)", + "America\/Juneau": "Alaska (Juneau)", + "America\/Kentucky\/Monticello": "czas wschodnioamerykański (Monticello)", + "America\/Kralendijk": "czas atlantycki (Kralendijk)", + "America\/La_Paz": "Boliwia (La Paz)", + "America\/Lima": "Peru (Lima)", + "America\/Los_Angeles": "czas pacyficzny (Los Angeles)", + "America\/Louisville": "czas wschodnioamerykański (Louisville)", + "America\/Lower_Princes": "czas atlantycki (Lower Prince’s Quarter)", + "America\/Maceio": "Brasília (Maceió)", + "America\/Managua": "czas środkowoamerykański (Managua)", + "America\/Manaus": "czas amazoński (Manaus)", + "America\/Marigot": "czas atlantycki (Marigot)", + "America\/Martinique": "czas atlantycki (Martynika)", + "America\/Matamoros": "czas środkowoamerykański (Matamoros)", + "America\/Mazatlan": "Meksyk (czas pacyficzny) (Mazatlan)", + "America\/Mendoza": "Argentyna (Mendoza)", + "America\/Menominee": "czas środkowoamerykański (Menominee)", + "America\/Merida": "czas środkowoamerykański (Merida)", + "America\/Metlakatla": "Alaska (Metlakatla)", + "America\/Mexico_City": "czas środkowoamerykański (Meksyk (miasto))", + "America\/Miquelon": "Saint-Pierre i Miquelon (Miquelon)", + "America\/Moncton": "czas atlantycki (Moncton)", + "America\/Monterrey": "czas środkowoamerykański (Monterrey)", + "America\/Montevideo": "Urugwaj (Montevideo)", + "America\/Montserrat": "czas atlantycki (Montserrat)", + "America\/Nassau": "czas wschodnioamerykański (Nassau)", + "America\/New_York": "czas wschodnioamerykański (Nowy Jork)", + "America\/Nipigon": "czas wschodnioamerykański (Nipigon)", + "America\/Nome": "Alaska (Nome)", + "America\/Noronha": "Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "czas środkowoamerykański (Beulah, Dakota Północna)", + "America\/North_Dakota\/Center": "czas środkowoamerykański (Center, Dakota Północna)", + "America\/North_Dakota\/New_Salem": "czas środkowoamerykański (New Salem, Dakota Północna)", + "America\/Ojinaga": "czas górski (Ojinaga)", + "America\/Panama": "czas wschodnioamerykański (Panama)", + "America\/Pangnirtung": "czas wschodnioamerykański (Pangnirtung)", + "America\/Paramaribo": "Surinam (Paramaribo)", + "America\/Phoenix": "czas górski (Phoenix)", + "America\/Port-au-Prince": "czas wschodnioamerykański (Port-au-Prince)", + "America\/Port_of_Spain": "czas atlantycki (Port-of-Spain)", + "America\/Porto_Velho": "czas amazoński (Porto Velho)", + "America\/Puerto_Rico": "czas atlantycki (Portoryko)", + "America\/Punta_Arenas": "Chile (Punta Arenas)", + "America\/Rainy_River": "czas środkowoamerykański (Rainy River)", + "America\/Rankin_Inlet": "czas środkowoamerykański (Rankin Inlet)", + "America\/Recife": "Brasília (Recife)", + "America\/Regina": "czas środkowoamerykański (Regina)", + "America\/Resolute": "czas środkowoamerykański (Resolute)", + "America\/Santa_Isabel": "Meksyk Północno-Zachodni (Santa Isabel)", + "America\/Santarem": "Brasília (Santarem)", + "America\/Santiago": "Chile (Santiago)", + "America\/Santo_Domingo": "czas atlantycki (Santo Domingo)", + "America\/Sao_Paulo": "Brasília (Sao Paulo)", + "America\/Scoresbysund": "Grenlandia Wschodnia (Ittoqqortoormiit)", + "America\/Sitka": "Alaska (Sitka)", + "America\/St_Barthelemy": "czas atlantycki (Saint-Barthélemy)", + "America\/St_Johns": "Nowa Fundlandia (St. John’s)", + "America\/St_Kitts": "czas atlantycki (Saint Kitts)", + "America\/St_Lucia": "czas atlantycki (Saint Lucia)", + "America\/St_Thomas": "czas atlantycki (Saint Thomas)", + "America\/St_Vincent": "czas atlantycki (Saint Vincent)", + "America\/Swift_Current": "czas środkowoamerykański (Swift Current)", + "America\/Tegucigalpa": "czas środkowoamerykański (Tegucigalpa)", + "America\/Thule": "czas atlantycki (Qaanaaq)", + "America\/Thunder_Bay": "czas wschodnioamerykański (Thunder Bay)", + "America\/Tijuana": "czas pacyficzny (Tijuana)", + "America\/Toronto": "czas wschodnioamerykański (Toronto)", + "America\/Tortola": "czas atlantycki (Tortola)", + "America\/Vancouver": "czas pacyficzny (Vancouver)", + "America\/Whitehorse": "czas pacyficzny (Whitehorse)", + "America\/Winnipeg": "czas środkowoamerykański (Winnipeg)", + "America\/Yakutat": "Alaska (Yakutat)", + "America\/Yellowknife": "czas górski (Yellowknife)", + "Antarctica\/Casey": "czas zachodnioaustralijski (Casey)", + "Antarctica\/Davis": "Davis (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie (Macquarie)", + "Antarctica\/Mawson": "Mawson (Mawson)", + "Antarctica\/McMurdo": "Nowa Zelandia (McMurdo)", + "Antarctica\/Palmer": "Chile (Palmer)", + "Antarctica\/Rothera": "Rothera (Rothera)", + "Antarctica\/Syowa": "Syowa (Syowa)", + "Antarctica\/Troll": "czas uniwersalny (Troll)", + "Antarctica\/Vostok": "Wostok (Wostok)", + "Arctic\/Longyearbyen": "czas środkowoeuropejski (Longyearbyen)", + "Asia\/Aden": "Półwysep Arabski (Aden)", + "Asia\/Almaty": "Kazachstan Wschodni (Ałmaty)", + "Asia\/Amman": "czas wschodnioeuropejski (Amman)", + "Asia\/Anadyr": "czas Anadyr (Anadyr)", + "Asia\/Aqtau": "Kazachstan Zachodni (Aktau)", + "Asia\/Aqtobe": "Kazachstan Zachodni (Aktiubińsk)", + "Asia\/Ashgabat": "Turkmenistan (Aszchabad)", + "Asia\/Atyrau": "Kazachstan Zachodni (Atyrau)", + "Asia\/Baghdad": "Półwysep Arabski (Bagdad)", + "Asia\/Bahrain": "Półwysep Arabski (Bahrajn)", + "Asia\/Baku": "Azerbejdżan (Baku)", + "Asia\/Bangkok": "czas indochiński (Bangkok)", + "Asia\/Beirut": "czas wschodnioeuropejski (Bejrut)", + "Asia\/Bishkek": "Kirgistan (Biszkek)", + "Asia\/Brunei": "Brunei (Brunei)", + "Asia\/Calcutta": "czas indyjski standardowy (Kalkuta)", + "Asia\/Chita": "Jakuck (Czyta)", + "Asia\/Choibalsan": "Czojbalsan (Czojbalsan)", + "Asia\/Colombo": "czas indyjski standardowy (Kolombo)", + "Asia\/Damascus": "czas wschodnioeuropejski (Damaszek)", + "Asia\/Dhaka": "Bangladesz (Dhaka)", + "Asia\/Dili": "Timor Wschodni (Dili)", + "Asia\/Dubai": "Zatoka Perska (Dubaj)", + "Asia\/Dushanbe": "Tadżykistan (Duszanbe)", + "Asia\/Famagusta": "czas wschodnioeuropejski (Famagusta)", + "Asia\/Gaza": "czas wschodnioeuropejski (Gaza)", + "Asia\/Hebron": "czas wschodnioeuropejski (Hebron)", + "Asia\/Hong_Kong": "Hongkong (Hongkong)", + "Asia\/Hovd": "Kobdo (Kobdo)", + "Asia\/Irkutsk": "Irkuck (Irkuck)", + "Asia\/Jakarta": "Indonezja Zachodnia (Dżakarta)", + "Asia\/Jayapura": "Indonezja Wschodnia (Jayapura)", + "Asia\/Jerusalem": "Izrael (Jerozolima)", + "Asia\/Kabul": "Afganistan (Kabul)", + "Asia\/Kamchatka": "czas Pietropawłowsk Kamczacki (Kamczatka)", + "Asia\/Karachi": "Pakistan (Karaczi)", + "Asia\/Katmandu": "Nepal (Katmandu)", + "Asia\/Khandyga": "Jakuck (Chandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsk (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malezja (Kuala Lumpur)", + "Asia\/Kuching": "Malezja (Kuching)", + "Asia\/Kuwait": "Półwysep Arabski (Kuwejt)", + "Asia\/Macau": "Chiny (Makau)", + "Asia\/Magadan": "Magadan (Magadan)", + "Asia\/Makassar": "Indonezja Środkowa (Makassar)", + "Asia\/Manila": "Filipiny (Manila)", + "Asia\/Muscat": "Zatoka Perska (Maskat)", + "Asia\/Nicosia": "czas wschodnioeuropejski (Nikozja)", + "Asia\/Novokuznetsk": "Krasnojarsk (Nowokuźnieck)", + "Asia\/Novosibirsk": "Nowosybirsk (Nowosybirsk)", + "Asia\/Omsk": "Omsk (Omsk)", + "Asia\/Oral": "Kazachstan Zachodni (Uralsk)", + "Asia\/Phnom_Penh": "czas indochiński (Phnom Penh)", + "Asia\/Pontianak": "Indonezja Zachodnia (Pontianak)", + "Asia\/Pyongyang": "Korea (Pjongjang)", + "Asia\/Qatar": "Półwysep Arabski (Katar)", + "Asia\/Qostanay": "Kazachstan Wschodni (Kustanaj)", + "Asia\/Qyzylorda": "Kazachstan Zachodni (Kyzyłorda)", + "Asia\/Rangoon": "Mjanma (Rangun)", + "Asia\/Riyadh": "Półwysep Arabski (Rijad)", + "Asia\/Saigon": "czas indochiński (Ho Chi Minh)", + "Asia\/Sakhalin": "Sachalin (Sachalin)", + "Asia\/Samarkand": "Uzbekistan (Samarkanda)", + "Asia\/Seoul": "Korea (Seul)", + "Asia\/Shanghai": "Chiny (Szanghaj)", + "Asia\/Singapore": "Singapur (Singapur)", + "Asia\/Srednekolymsk": "Magadan (Sriedniekołymsk)", + "Asia\/Taipei": "Tajpej (Tajpej)", + "Asia\/Tashkent": "Uzbekistan (Taszkient)", + "Asia\/Tbilisi": "Gruzja (Tbilisi)", + "Asia\/Tehran": "Iran (Teheran)", + "Asia\/Thimphu": "Bhutan (Thimphu)", + "Asia\/Tokyo": "Japonia (Tokio)", + "Asia\/Ulaanbaatar": "Ułan Bator (Ułan Bator)", + "Asia\/Ust-Nera": "Władywostok (Ust-Niera)", + "Asia\/Vientiane": "czas indochiński (Wientian)", + "Asia\/Vladivostok": "Władywostok (Władywostok)", + "Asia\/Yakutsk": "Jakuck (Jakuck)", + "Asia\/Yekaterinburg": "Jekaterynburg (Jekaterynburg)", + "Asia\/Yerevan": "Armenia (Erywań)", + "Atlantic\/Azores": "Azory (Azory)", + "Atlantic\/Bermuda": "czas atlantycki (Bermudy)", + "Atlantic\/Canary": "czas zachodnioeuropejski (Wyspy Kanaryjskie)", + "Atlantic\/Cape_Verde": "Wyspy Zielonego Przylądka (Republika Zielonego Przylądka)", + "Atlantic\/Faeroe": "czas zachodnioeuropejski (Wyspy Owcze)", + "Atlantic\/Madeira": "czas zachodnioeuropejski (Madera)", + "Atlantic\/Reykjavik": "czas uniwersalny (Reykjavik)", + "Atlantic\/South_Georgia": "Georgia Południowa (Georgia Południowa)", + "Atlantic\/St_Helena": "czas uniwersalny (Święta Helena)", + "Atlantic\/Stanley": "Falklandy (Stanley)", + "Australia\/Adelaide": "czas środkowoaustralijski (Adelaide)", + "Australia\/Brisbane": "czas wschodnioaustralijski (Brisbane)", + "Australia\/Broken_Hill": "czas środkowoaustralijski (Broken Hill)", + "Australia\/Currie": "czas wschodnioaustralijski (Currie)", + "Australia\/Darwin": "czas środkowoaustralijski (Darwin)", + "Australia\/Eucla": "czas środkowo-zachodnioaustralijski (Eucla)", + "Australia\/Hobart": "czas wschodnioaustralijski (Hobart)", + "Australia\/Lindeman": "czas wschodnioaustralijski (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe (Lord Howe)", + "Australia\/Melbourne": "czas wschodnioaustralijski (Melbourne)", + "Australia\/Perth": "czas zachodnioaustralijski (Perth)", + "Australia\/Sydney": "czas wschodnioaustralijski (Sydney)", + "CST6CDT": "czas środkowoamerykański", + "EST5EDT": "czas wschodnioamerykański", + "Etc\/GMT": "czas uniwersalny", + "Etc\/UTC": "uniwersalny czas koordynowany", + "Europe\/Amsterdam": "czas środkowoeuropejski (Amsterdam)", + "Europe\/Andorra": "czas środkowoeuropejski (Andora)", + "Europe\/Astrakhan": "Moskwa (Astrachań)", + "Europe\/Athens": "czas wschodnioeuropejski (Ateny)", + "Europe\/Belgrade": "czas środkowoeuropejski (Belgrad)", + "Europe\/Berlin": "czas środkowoeuropejski (Berlin)", + "Europe\/Bratislava": "czas środkowoeuropejski (Bratysława)", + "Europe\/Brussels": "czas środkowoeuropejski (Bruksela)", + "Europe\/Bucharest": "czas wschodnioeuropejski (Bukareszt)", + "Europe\/Budapest": "czas środkowoeuropejski (Budapeszt)", + "Europe\/Busingen": "czas środkowoeuropejski (Büsingen am Hochrhein)", + "Europe\/Chisinau": "czas wschodnioeuropejski (Kiszyniów)", + "Europe\/Copenhagen": "czas środkowoeuropejski (Kopenhaga)", + "Europe\/Dublin": "czas uniwersalny (Dublin)", + "Europe\/Gibraltar": "czas środkowoeuropejski (Gibraltar)", + "Europe\/Guernsey": "czas uniwersalny (Guernsey)", + "Europe\/Helsinki": "czas wschodnioeuropejski (Helsinki)", + "Europe\/Isle_of_Man": "czas uniwersalny (Wyspa Man)", + "Europe\/Jersey": "czas uniwersalny (Jersey)", + "Europe\/Kaliningrad": "czas wschodnioeuropejski (Kaliningrad)", + "Europe\/Kiev": "czas wschodnioeuropejski (Kijów)", + "Europe\/Lisbon": "czas zachodnioeuropejski (Lizbona)", + "Europe\/Ljubljana": "czas środkowoeuropejski (Lublana)", + "Europe\/London": "czas uniwersalny (Londyn)", + "Europe\/Luxembourg": "czas środkowoeuropejski (Luksemburg)", + "Europe\/Madrid": "czas środkowoeuropejski (Madryt)", + "Europe\/Malta": "czas środkowoeuropejski (Malta)", + "Europe\/Mariehamn": "czas wschodnioeuropejski (Maarianhamina)", + "Europe\/Minsk": "Moskwa (Mińsk)", + "Europe\/Monaco": "czas środkowoeuropejski (Monako)", + "Europe\/Moscow": "Moskwa (Moskwa)", + "Europe\/Oslo": "czas środkowoeuropejski (Oslo)", + "Europe\/Paris": "czas środkowoeuropejski (Paryż)", + "Europe\/Podgorica": "czas środkowoeuropejski (Podgorica)", + "Europe\/Prague": "czas środkowoeuropejski (Praga)", + "Europe\/Riga": "czas wschodnioeuropejski (Ryga)", + "Europe\/Rome": "czas środkowoeuropejski (Rzym)", + "Europe\/Samara": "czas Samara (Samara)", + "Europe\/San_Marino": "czas środkowoeuropejski (San Marino)", + "Europe\/Sarajevo": "czas środkowoeuropejski (Sarajewo)", + "Europe\/Saratov": "Moskwa (Saratów)", + "Europe\/Simferopol": "Moskwa (Symferopol)", + "Europe\/Skopje": "czas środkowoeuropejski (Skopje)", + "Europe\/Sofia": "czas wschodnioeuropejski (Sofia)", + "Europe\/Stockholm": "czas środkowoeuropejski (Sztokholm)", + "Europe\/Tallinn": "czas wschodnioeuropejski (Tallin)", + "Europe\/Tirane": "czas środkowoeuropejski (Tirana)", + "Europe\/Ulyanovsk": "Moskwa (Uljanowsk)", + "Europe\/Uzhgorod": "czas wschodnioeuropejski (Użgorod)", + "Europe\/Vaduz": "czas środkowoeuropejski (Vaduz)", + "Europe\/Vatican": "czas środkowoeuropejski (Watykan)", + "Europe\/Vienna": "czas środkowoeuropejski (Wiedeń)", + "Europe\/Vilnius": "czas wschodnioeuropejski (Wilno)", + "Europe\/Volgograd": "Wołgograd (Wołgograd)", + "Europe\/Warsaw": "czas środkowoeuropejski (Warszawa)", + "Europe\/Zagreb": "czas środkowoeuropejski (Zagrzeb)", + "Europe\/Zaporozhye": "czas wschodnioeuropejski (Zaporoże)", + "Europe\/Zurich": "czas środkowoeuropejski (Zurych)", + "Indian\/Antananarivo": "czas wschodnioafrykański (Antananarywa)", + "Indian\/Chagos": "Ocean Indyjski (Czagos)", + "Indian\/Christmas": "Wyspa Bożego Narodzenia (Wyspa Bożego Narodzenia)", + "Indian\/Cocos": "Wyspy Kokosowe (Wyspy Kokosowe)", + "Indian\/Comoro": "czas wschodnioafrykański (Komory)", + "Indian\/Kerguelen": "Francuskie Terytoria Południowe i Antarktyczne (Wyspy Kerguelena)", + "Indian\/Mahe": "Seszele (Mahé)", + "Indian\/Maldives": "Malediwy (Malediwy)", + "Indian\/Mauritius": "Mauritius (Mauritius)", + "Indian\/Mayotte": "czas wschodnioafrykański (Majotta)", + "Indian\/Reunion": "Reunion (Réunion)", + "MST7MDT": "czas górski", + "PST8PDT": "czas pacyficzny", + "Pacific\/Apia": "Apia (Apia)", + "Pacific\/Auckland": "Nowa Zelandia (Auckland)", + "Pacific\/Bougainville": "Papua-Nowa Gwinea (Wyspa Bougainville’a)", + "Pacific\/Chatham": "Chatham (Chatham)", + "Pacific\/Easter": "Wyspa Wielkanocna (Wyspa Wielkanocna)", + "Pacific\/Efate": "Vanuatu (Efate)", + "Pacific\/Enderbury": "Feniks (Enderbury)", + "Pacific\/Fakaofo": "Tokelau (Fakaofo)", + "Pacific\/Fiji": "Fidżi (Fidżi)", + "Pacific\/Funafuti": "Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Galapagos (Galapagos)", + "Pacific\/Gambier": "Wyspy Gambiera (Wyspy Gambiera)", + "Pacific\/Guadalcanal": "Wyspy Salomona (Guadalcanal)", + "Pacific\/Guam": "Czamorro (Guam)", + "Pacific\/Honolulu": "Hawaje-Aleuty (Honolulu)", + "Pacific\/Johnston": "Hawaje-Aleuty (Johnston)", + "Pacific\/Kiritimati": "Line Islands (Kiritimati)", + "Pacific\/Kosrae": "Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Wyspy Marshalla (Kwajalein)", + "Pacific\/Majuro": "Wyspy Marshalla (Majuro)", + "Pacific\/Marquesas": "Markizy (Markizy)", + "Pacific\/Midway": "Samoa (Midway)", + "Pacific\/Nauru": "Nauru (Nauru)", + "Pacific\/Niue": "Niue (Niue)", + "Pacific\/Norfolk": "Norfolk (Norfolk)", + "Pacific\/Noumea": "Nowa Kaledonia (Numea)", + "Pacific\/Pago_Pago": "Samoa (Pago Pago)", + "Pacific\/Palau": "Palau (Palau)", + "Pacific\/Pitcairn": "Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Pohnpei (Pohnpei)", + "Pacific\/Port_Moresby": "Papua-Nowa Gwinea (Port Moresby)", + "Pacific\/Rarotonga": "Wyspy Cooka (Rarotonga)", + "Pacific\/Saipan": "Czamorro (Saipan)", + "Pacific\/Tahiti": "Tahiti (Tahiti)", + "Pacific\/Tarawa": "Wyspy Gilberta (Tarawa)", + "Pacific\/Tongatapu": "Tonga (Tongatapu)", + "Pacific\/Truk": "Chuuk (Chuuk)", + "Pacific\/Wake": "Wake (Wake)", + "Pacific\/Wallis": "Wallis i Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ps.json b/src/Symfony/Component/Intl/Resources/data/timezones/ps.json new file mode 100644 index 0000000000000..3cf3a5cee49fd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ps.json @@ -0,0 +1,405 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "گرينويچ وخت (ابيجان)", + "Africa\/Accra": "گرينويچ وخت (اکرا)", + "Africa\/Addis_Ababa": "ختيځ افريقا وخت (اضافی ابابا)", + "Africa\/Algiers": "منځنۍ اروپا وخت (الګیرز)", + "Africa\/Asmera": "ختيځ افريقا وخت (اساماره)", + "Africa\/Bamako": "گرينويچ وخت (بامیکو)", + "Africa\/Bangui": "لوېديځ افريقا وخت (بنوګي)", + "Africa\/Banjul": "گرينويچ وخت (بانجول)", + "Africa\/Bissau": "گرينويچ وخت (بسو)", + "Africa\/Blantyre": "منځنی افريقا وخت (Blantyre)", + "Africa\/Brazzaville": "لوېديځ افريقا وخت (Brazzaville)", + "Africa\/Bujumbura": "منځنی افريقا وخت (بجوګورا)", + "Africa\/Casablanca": "لوېديزې اروپا وخت (کاسابلانکا)", + "Africa\/Ceuta": "منځنۍ اروپا وخت (Ceuta)", + "Africa\/Conakry": "گرينويچ وخت (کونکري)", + "Africa\/Dakar": "گرينويچ وخت (ډاکار)", + "Africa\/Dar_es_Salaam": "ختيځ افريقا وخت (دار السلام)", + "Africa\/Djibouti": "ختيځ افريقا وخت (جبوتي)", + "Africa\/Douala": "لوېديځ افريقا وخت (ډالاله)", + "Africa\/El_Aaiun": "لوېديزې اروپا وخت (الیون)", + "Africa\/Freetown": "گرينويچ وخت (فریټون)", + "Africa\/Gaborone": "منځنی افريقا وخت (ګابرون)", + "Africa\/Harare": "منځنی افريقا وخت (هرارې)", + "Africa\/Johannesburg": "جنوبي افريقا معياري وخت (جوهانبرګ)", + "Africa\/Juba": "ختيځ افريقا وخت (جوبا)", + "Africa\/Kampala": "ختيځ افريقا وخت (کمپاله)", + "Africa\/Khartoum": "منځنی افريقا وخت (خرتوم)", + "Africa\/Kigali": "منځنی افريقا وخت (کيگالي)", + "Africa\/Kinshasa": "لوېديځ افريقا وخت (کينشاسا)", + "Africa\/Lagos": "لوېديځ افريقا وخت (لاگوس)", + "Africa\/Libreville": "لوېديځ افريقا وخت (لیبریل)", + "Africa\/Lome": "گرينويچ وخت (لووم)", + "Africa\/Luanda": "لوېديځ افريقا وخت (لونده)", + "Africa\/Lubumbashi": "منځنی افريقا وخت (لبوباشي)", + "Africa\/Lusaka": "منځنی افريقا وخت (لسیکا)", + "Africa\/Malabo": "لوېديځ افريقا وخت (مالابو)", + "Africa\/Maputo": "منځنی افريقا وخت (ماپوټو)", + "Africa\/Maseru": "جنوبي افريقا معياري وخت (مسرو)", + "Africa\/Mbabane": "جنوبي افريقا معياري وخت (Mbabane)", + "Africa\/Mogadishu": "ختيځ افريقا وخت (موگديشو)", + "Africa\/Monrovia": "گرينويچ وخت (مونروفیا)", + "Africa\/Nairobi": "ختيځ افريقا وخت (نايروبي)", + "Africa\/Ndjamena": "لوېديځ افريقا وخت (نجامینا)", + "Africa\/Niamey": "لوېديځ افريقا وخت (نیمي)", + "Africa\/Nouakchott": "گرينويچ وخت (نوکوچټ)", + "Africa\/Ouagadougou": "گرينويچ وخت (اوواګاګواګو)", + "Africa\/Porto-Novo": "لوېديځ افريقا وخت (پورټو - نوو)", + "Africa\/Sao_Tome": "گرينويچ وخت (ساو ټوم)", + "Africa\/Tunis": "منځنۍ اروپا وخت (تونس)", + "Africa\/Windhoek": "منځنی افريقا وخت (وینهوک)", + "America\/Adak": "هوایی الیوتین وخت (اداک)", + "America\/Anchorage": "الاسکا وخت (اینکریج)", + "America\/Anguilla": "اتلانتیک د وخت (انګیلا)", + "America\/Antigua": "اتلانتیک د وخت (انټيګ)", + "America\/Araguaina": "برسلیا وخت (ارګینیا)", + "America\/Argentina\/La_Rioja": "ارجنټاین وخت (لا ریوج)", + "America\/Argentina\/Rio_Gallegos": "ارجنټاین وخت (ریو ګیلیلیګوس)", + "America\/Argentina\/Salta": "ارجنټاین وخت (سالټا)", + "America\/Argentina\/San_Juan": "ارجنټاین وخت (سان جوان)", + "America\/Argentina\/San_Luis": "غربي ارجنټاین وخت (سان لویس)", + "America\/Argentina\/Tucuman": "ارجنټاین وخت (ټيکووم)", + "America\/Argentina\/Ushuaia": "ارجنټاین وخت (اوشوایا)", + "America\/Aruba": "اتلانتیک د وخت (آروبا)", + "America\/Asuncion": "پاراګوای د وخت (اسونسيون)", + "America\/Bahia": "برسلیا وخت (بهیا)", + "America\/Bahia_Banderas": "مرکزي وخت (بهیا بینډراس)", + "America\/Barbados": "اتلانتیک د وخت (باربادوس)", + "America\/Belem": "برسلیا وخت (بلم)", + "America\/Belize": "مرکزي وخت (بلیز)", + "America\/Blanc-Sablon": "اتلانتیک د وخت (بلانک-سابلون)", + "America\/Boa_Vista": "ایمیزون وخت (بوا ویسټا)", + "America\/Bogota": "کولمبیا وخت (بوګټا)", + "America\/Boise": "د غره د وخت (بوز)", + "America\/Buenos_Aires": "ارجنټاین وخت (بينوس اييرز)", + "America\/Cambridge_Bay": "د غره د وخت (کیمبرج بي)", + "America\/Campo_Grande": "ایمیزون وخت (کمپو ګرډی)", + "America\/Cancun": "ختیځ وخت (کینن)", + "America\/Caracas": "وینزویلا وخت (کاراکاس)", + "America\/Catamarca": "ارجنټاین وخت (کټامارکا)", + "America\/Cayenne": "د فرانسوي ګانا وخت (کیین)", + "America\/Cayman": "ختیځ وخت (کیمن)", + "America\/Chicago": "مرکزي وخت (شیکاګو)", + "America\/Chihuahua": "مکسیکن پیسفک وخت (چھواھوا)", + "America\/Coral_Harbour": "ختیځ وخت (اتیکوکن)", + "America\/Cordoba": "ارجنټاین وخت (کوډوبا)", + "America\/Costa_Rica": "مرکزي وخت (کوستاریکا)", + "America\/Creston": "د غره د وخت (کرسټون)", + "America\/Cuiaba": "ایمیزون وخت (کویابا)", + "America\/Curacao": "اتلانتیک د وخت (کیکاو)", + "America\/Danmarkshavn": "گرينويچ وخت (ډنمارک هاربر)", + "America\/Dawson": "پیسفک وخت (داوسن)", + "America\/Dawson_Creek": "د غره د وخت (داسن کریک)", + "America\/Denver": "د غره د وخت (ډنور)", + "America\/Detroit": "ختیځ وخت (ډایټروټ)", + "America\/Dominica": "اتلانتیک د وخت (دومینیکا)", + "America\/Edmonton": "د غره د وخت (ایډمونټن)", + "America\/El_Salvador": "مرکزي وخت (ايل سلوادور)", + "America\/Fort_Nelson": "د غره د وخت (فورټ نیلسن)", + "America\/Fortaleza": "برسلیا وخت (فورتیلزا)", + "America\/Glace_Bay": "اتلانتیک د وخت (ګیسس بيی)", + "America\/Godthab": "لویدیځ ګرینلینډ وخت (Nuuk)", + "America\/Goose_Bay": "اتلانتیک د وخت (گوز بي)", + "America\/Grand_Turk": "ختیځ وخت (لوی ترک)", + "America\/Grenada": "اتلانتیک د وخت (ګرنادا)", + "America\/Guadeloupe": "اتلانتیک د وخت (ګالډیپ)", + "America\/Guatemala": "مرکزي وخت (ګواتمالا)", + "America\/Guayaquil": "د اکوادور وخت (ګویاګل)", + "America\/Guyana": "د ګوانانا وخت (ګیانا)", + "America\/Halifax": "اتلانتیک د وخت (هیلفکس)", + "America\/Havana": "کیوبا د وخت (هایانا)", + "America\/Hermosillo": "مکسیکن پیسفک وخت (هرموسیلو)", + "America\/Indiana\/Knox": "مرکزي وخت (نکس، اندیانا)", + "America\/Indiana\/Marengo": "ختیځ وخت (مارینګ، انډیانا)", + "America\/Indiana\/Petersburg": "ختیځ وخت (پیتربورګ، انډيانا)", + "America\/Indiana\/Tell_City": "مرکزي وخت (ښار، انډیا ته ووایی)", + "America\/Indiana\/Vevay": "ختیځ وخت (ویوی، انډیډا)", + "America\/Indiana\/Vincennes": "ختیځ وخت (وینینسین، انډا)", + "America\/Indiana\/Winamac": "ختیځ وخت (ویناماسک، انډی)", + "America\/Indianapolis": "ختیځ وخت (انډولپولیس)", + "America\/Inuvik": "د غره د وخت (انوک)", + "America\/Iqaluit": "ختیځ وخت (اقلیټ)", + "America\/Jamaica": "ختیځ وخت (جمایکه)", + "America\/Jujuy": "ارجنټاین وخت (جوجو)", + "America\/Juneau": "الاسکا وخت (جونو)", + "America\/Kentucky\/Monticello": "ختیځ وخت (مونټیکیلو، کینیسي)", + "America\/Kralendijk": "اتلانتیک د وخت (کلینډیزج)", + "America\/La_Paz": "بولیویا وخت (لا پاز)", + "America\/Lima": "پیرو وخت (لیما)", + "America\/Los_Angeles": "پیسفک وخت (لاس اینجلس)", + "America\/Louisville": "ختیځ وخت (لوئس ویل)", + "America\/Lower_Princes": "اتلانتیک د وخت (د کمتر شهزاده درې میاشتنۍ)", + "America\/Maceio": "برسلیا وخت (مایسیو)", + "America\/Managua": "مرکزي وخت (منګوا)", + "America\/Manaus": "ایمیزون وخت (منوس)", + "America\/Marigot": "اتلانتیک د وخت (مارګټ)", + "America\/Martinique": "اتلانتیک د وخت (مارټینیک)", + "America\/Matamoros": "مرکزي وخت (Matamoros)", + "America\/Mazatlan": "مکسیکن پیسفک وخت (مزاتلان)", + "America\/Mendoza": "ارجنټاین وخت (مینډوزا)", + "America\/Menominee": "مرکزي وخت (مینومین)", + "America\/Merida": "مرکزي وخت (مرده)", + "America\/Metlakatla": "الاسکا وخت (میتلاکاټلا)", + "America\/Mexico_City": "مرکزي وخت (مکسيکو ښار)", + "America\/Miquelon": "سینټ پییرا و ميکلين وخت (ميکلين)", + "America\/Moncton": "اتلانتیک د وخت (مونټون)", + "America\/Monterrey": "مرکزي وخت (منټرري)", + "America\/Montevideo": "یوروګوای وخت (مونټ وډیو)", + "America\/Montserrat": "اتلانتیک د وخت (مانټیسیرت)", + "America\/Nassau": "ختیځ وخت (نیساو)", + "America\/New_York": "ختیځ وخت (نیویارک)", + "America\/Nipigon": "ختیځ وخت (نیپګون)", + "America\/Nome": "الاسکا وخت (نوم)", + "America\/Noronha": "فرنانڈو دي نورونها وخت (نورونها)", + "America\/North_Dakota\/Beulah": "مرکزي وخت (بيلاه، شمالي داکوتا)", + "America\/North_Dakota\/Center": "مرکزي وخت (مرکز، د شمالي ټاپو)", + "America\/North_Dakota\/New_Salem": "مرکزي وخت (نوی سلیم، شمالي داکوتا)", + "America\/Ojinaga": "د غره د وخت (اوجنګا)", + "America\/Panama": "ختیځ وخت (پاناما)", + "America\/Pangnirtung": "ختیځ وخت (پيننټيرګ)", + "America\/Paramaribo": "سورینام وخت (پاراماربو)", + "America\/Phoenix": "د غره د وخت (فینکس)", + "America\/Port-au-Prince": "ختیځ وخت (پورټ ایو - پرنس)", + "America\/Port_of_Spain": "اتلانتیک د وخت (د اسپانیا بندر)", + "America\/Porto_Velho": "ایمیزون وخت (پورټو ویلهو)", + "America\/Puerto_Rico": "اتلانتیک د وخت (پورتو ریکو)", + "America\/Punta_Arenas": "چلی وخت (پنټا آریناس)", + "America\/Rainy_River": "مرکزي وخت (د باران باران)", + "America\/Rankin_Inlet": "مرکزي وخت (رانکين لط)", + "America\/Recife": "برسلیا وخت (ریسیفي)", + "America\/Regina": "مرکزي وخت (ریګینا)", + "America\/Resolute": "مرکزي وخت (غوڅ)", + "America\/Santa_Isabel": "د شمال لویدیځ مکسیکو وخت (Santa Isabel)", + "America\/Santarem": "برسلیا وخت (سناترم)", + "America\/Santiago": "چلی وخت (سنتياګو)", + "America\/Santo_Domingo": "اتلانتیک د وخت (سنتو ډومینګو)", + "America\/Sao_Paulo": "برسلیا وخت (ساو پاولو)", + "America\/Scoresbysund": "د ختیځ ګرینلینډ وخت (Ittoqqortoormiit)", + "America\/Sitka": "الاسکا وخت (سیټکا)", + "America\/St_Barthelemy": "اتلانتیک د وخت (سینټ بارټیلیم)", + "America\/St_Johns": "د نوي فیلډلینډ وخت (د سینټ جان)", + "America\/St_Kitts": "اتلانتیک د وخت (سینټ کټس)", + "America\/St_Lucia": "اتلانتیک د وخت (سینټ لوسیا)", + "America\/St_Thomas": "اتلانتیک د وخت (سایټ توماس)", + "America\/St_Vincent": "اتلانتیک د وخت (سېنټ ویسنټ)", + "America\/Swift_Current": "مرکزي وخت (اوسنی بدلون)", + "America\/Tegucigalpa": "مرکزي وخت (ټګسیګالپا)", + "America\/Thule": "اتلانتیک د وخت (تول)", + "America\/Thunder_Bay": "ختیځ وخت (د تندر خلیج)", + "America\/Tijuana": "پیسفک وخت (تجهان)", + "America\/Toronto": "ختیځ وخت (ټورنټو)", + "America\/Tortola": "اتلانتیک د وخت (ټورتولا)", + "America\/Vancouver": "پیسفک وخت (وینکوور)", + "America\/Whitehorse": "پیسفک وخت (سپین آس)", + "America\/Winnipeg": "مرکزي وخت (وینپیګ)", + "America\/Yakutat": "الاسکا وخت (یاکتټ)", + "America\/Yellowknife": "د غره د وخت (زرونیف)", + "Antarctica\/Casey": "د لویدیځ آسټرالیا وخت (کیسي)", + "Antarctica\/Davis": "دیوس وخت (دیویس)", + "Antarctica\/DumontDUrville": "ډومونټ-ډیریلوی وخت (ډومونټ ډي اوورول)", + "Antarctica\/Macquarie": "د مکاکري ټاپو وخت (مکاکري)", + "Antarctica\/Mawson": "دسونسن وخت (مسونسن)", + "Antarctica\/McMurdo": "د نیوزی لینڈ وخت (McMurdo)", + "Antarctica\/Palmer": "چلی وخت (پالر)", + "Antarctica\/Rothera": "د رورېټا وخت (رورها)", + "Antarctica\/Syowa": "سیوا وخت (سیوا)", + "Antarctica\/Troll": "گرينويچ وخت (ټول)", + "Antarctica\/Vostok": "د واستوک وخت (واستوک)", + "Arctic\/Longyearbyen": "منځنۍ اروپا وخت (لاندینبیبین)", + "Asia\/Aden": "عربي وخت (اډن)", + "Asia\/Almaty": "ختیځ د قزاقستان د وخت (الماتی)", + "Asia\/Aqtau": "لویدیځ قزاقستان وخت (اکاټو)", + "Asia\/Aqtobe": "لویدیځ قزاقستان وخت (اکتوب)", + "Asia\/Ashgabat": "ترکمانستان وخت (اشغ آباد)", + "Asia\/Atyrau": "لویدیځ قزاقستان وخت (اېټراو)", + "Asia\/Baghdad": "عربي وخت (بغداد)", + "Asia\/Bahrain": "عربي وخت (بحرین)", + "Asia\/Baku": "د آذربايجان وخت (باکو)", + "Asia\/Bangkok": "د اندوچینا وخت (بانکاک)", + "Asia\/Bishkek": "کرغیزستان وخت (بشکیک)", + "Asia\/Brunei": "د بروني درسلام وخت (برویني)", + "Asia\/Calcutta": "د هند معیاري وخت (کولکته)", + "Asia\/Chita": "ياکوټسک وخت (چيتا)", + "Asia\/Choibalsan": "چوئیبیلسن وخت (Choibalsan)", + "Asia\/Colombo": "د هند معیاري وخت (کولمبو)", + "Asia\/Dhaka": "بنگله دېش وخت (ډهاکه)", + "Asia\/Dili": "ختیځ ختیځ تیمور وخت (ديلي)", + "Asia\/Dubai": "د خلیج معياري وخت (دوبی)", + "Asia\/Dushanbe": "تاجکستان د وخت (دوشنبي)", + "Asia\/Hong_Kong": "د هانګ کانګ د وخت (هانګ کانګ)", + "Asia\/Hovd": "هاوډ وخت (Hovd)", + "Asia\/Irkutsk": "د ارکوټس وخت (ایرکوټس)", + "Asia\/Jakarta": "د لویدیځ اندونیزیا وخت (جاکارټا)", + "Asia\/Jayapura": "د اندونیزیا وخت (جاپورا)", + "Asia\/Jerusalem": "د اسراییل وخت (یهودان)", + "Asia\/Kabul": "افغانستان وخت (کابل)", + "Asia\/Karachi": "د پاکستان وخت (کراچي)", + "Asia\/Katmandu": "نیپال وخت (کټمنډو)", + "Asia\/Khandyga": "ياکوټسک وخت (خندګي)", + "Asia\/Krasnoyarsk": "کریسایویسسک وخت (کریسایویارسک)", + "Asia\/Kuala_Lumpur": "ملائیشیا وخت (کولالمپور)", + "Asia\/Kuching": "ملائیشیا وخت (کوچيګ)", + "Asia\/Kuwait": "عربي وخت (کویټ)", + "Asia\/Macau": "چين وخت (مکاو)", + "Asia\/Magadan": "د مګدان وخت (مګدان)", + "Asia\/Makassar": "د اندونیزیا مرکزي وخت (مکاسار)", + "Asia\/Manila": "د فلپین وخت (منیلا)", + "Asia\/Muscat": "د خلیج معياري وخت (مسکټ)", + "Asia\/Novokuznetsk": "کریسایویسسک وخت (نووکوزنیټک)", + "Asia\/Novosibirsk": "د نووسوسبیرک وخت (نووسوسبیرک)", + "Asia\/Omsk": "اوزک وخت (اوک)", + "Asia\/Oral": "لویدیځ قزاقستان وخت (اورل)", + "Asia\/Phnom_Penh": "د اندوچینا وخت (دوم قلم)", + "Asia\/Pontianak": "د لویدیځ اندونیزیا وخت (پونټینیک)", + "Asia\/Pyongyang": "کوريا وخت (پیونگګنګ)", + "Asia\/Qatar": "عربي وخت (قطر)", + "Asia\/Qostanay": "ختیځ د قزاقستان د وخت (Qostanay)", + "Asia\/Qyzylorda": "لویدیځ قزاقستان وخت (قزیلیلرا)", + "Asia\/Rangoon": "د میانمار وخت (یانګون)", + "Asia\/Riyadh": "عربي وخت (رياض)", + "Asia\/Saigon": "د اندوچینا وخت (هو چي مينه)", + "Asia\/Sakhalin": "د سخنین وخت (سخنین)", + "Asia\/Samarkand": "د ازبکستان وخت (سمرقند)", + "Asia\/Seoul": "کوريا وخت (سیول)", + "Asia\/Shanghai": "چين وخت (شنگھائی)", + "Asia\/Singapore": "د سنګاپور معیاري وخت (سینګاپور)", + "Asia\/Srednekolymsk": "د مګدان وخت (سنینیکولوژیک)", + "Asia\/Taipei": "تاپي وخت (تاپي)", + "Asia\/Tashkent": "د ازبکستان وخت (تاشکند)", + "Asia\/Tbilisi": "جورجیا وخت (تبلیسي)", + "Asia\/Tehran": "د ایران وخت (تهران)", + "Asia\/Thimphu": "د بوتان وخت (تهيمفو)", + "Asia\/Tokyo": "جاپان د وخت (ټوکیو)", + "Asia\/Ulaanbaatar": "دلانانباټ وخت (اللانبیر)", + "Asia\/Ust-Nera": "ولادیوستاک وخت (اوسترا)", + "Asia\/Vientiane": "د اندوچینا وخت (وینټینیا)", + "Asia\/Vladivostok": "ولادیوستاک وخت (ولادیوستاک)", + "Asia\/Yakutsk": "ياکوټسک وخت (یااکټس)", + "Asia\/Yekaterinburg": "د ياکيټرنبرګ وخت (یاراتینینګ برګ)", + "Asia\/Yerevan": "ارمنستان وخت (ییران)", + "Atlantic\/Bermuda": "اتلانتیک د وخت (برمودا)", + "Atlantic\/Canary": "لوېديزې اروپا وخت (کیري)", + "Atlantic\/Cape_Verde": "کیپ وردډ وخت (کېپ وردا)", + "Atlantic\/Faeroe": "لوېديزې اروپا وخت (فارو)", + "Atlantic\/Madeira": "لوېديزې اروپا وخت (مایررا)", + "Atlantic\/Reykjavik": "گرينويچ وخت (ريکسجيک)", + "Atlantic\/South_Georgia": "د سویل جورجیا وخت (سویل جورجیا)", + "Atlantic\/St_Helena": "گرينويچ وخت (سینټ هیلینا)", + "Atlantic\/Stanley": "د فوکلنډ ټاپو وخت (سټنلي)", + "Australia\/Adelaide": "د مرکزي آسټر وخت (اډیلایډ)", + "Australia\/Brisbane": "د ختیځ آسټر وخت (بریسبن)", + "Australia\/Broken_Hill": "د مرکزي آسټر وخت (مات شوی هیل)", + "Australia\/Currie": "د ختیځ آسټر وخت (کرري)", + "Australia\/Darwin": "د مرکزي آسټر وخت (ډارون)", + "Australia\/Eucla": "د آسټرالیا مرکزی لویدیځ وخت (ایولیکا)", + "Australia\/Hobart": "د ختیځ آسټر وخت (هوبارټ)", + "Australia\/Lindeman": "د ختیځ آسټر وخت (لینډامین)", + "Australia\/Lord_Howe": "رب های وخت (رب هیله)", + "Australia\/Melbourne": "د ختیځ آسټر وخت (میلبورن)", + "Australia\/Perth": "د لویدیځ آسټرالیا وخت (پورت)", + "Australia\/Sydney": "د ختیځ آسټر وخت (سډني)", + "CST6CDT": "مرکزي وخت", + "EST5EDT": "ختیځ وخت", + "Etc\/GMT": "گرينويچ وخت", + "Etc\/UTC": "همغږۍ نړیواله موده", + "Europe\/Amsterdam": "منځنۍ اروپا وخت (امستردام)", + "Europe\/Andorra": "منځنۍ اروپا وخت (اندورا)", + "Europe\/Astrakhan": "ماسکو وخت (آسترخان)", + "Europe\/Belgrade": "منځنۍ اروپا وخت (بلغاد)", + "Europe\/Berlin": "منځنۍ اروپا وخت (برلین)", + "Europe\/Bratislava": "منځنۍ اروپا وخت (براتسکوا)", + "Europe\/Brussels": "منځنۍ اروپا وخت (بروسلز)", + "Europe\/Budapest": "منځنۍ اروپا وخت (بوډاپیس)", + "Europe\/Busingen": "منځنۍ اروپا وخت (بسینګین)", + "Europe\/Copenhagen": "منځنۍ اروپا وخت (کوپینګنګ)", + "Europe\/Dublin": "گرينويچ وخت (ډوبلین)", + "Europe\/Gibraltar": "منځنۍ اروپا وخت (جبل الطارق)", + "Europe\/Guernsey": "گرينويچ وخت (ګرنسي)", + "Europe\/Isle_of_Man": "گرينويچ وخت (د آئل آف مین)", + "Europe\/Jersey": "گرينويچ وخت (جرسی)", + "Europe\/Lisbon": "لوېديزې اروپا وخت (لیسبون)", + "Europe\/Ljubljana": "منځنۍ اروپا وخت (لوججانا)", + "Europe\/London": "گرينويچ وخت (لندن)", + "Europe\/Luxembourg": "منځنۍ اروپا وخت (لوګزامبورګ)", + "Europe\/Madrid": "منځنۍ اروپا وخت (میډریډ)", + "Europe\/Malta": "منځنۍ اروپا وخت (مالتا)", + "Europe\/Minsk": "ماسکو وخت (منسک)", + "Europe\/Monaco": "منځنۍ اروپا وخت (موناکو)", + "Europe\/Moscow": "ماسکو وخت (ماسکو)", + "Europe\/Oslo": "منځنۍ اروپا وخت (اوسلو)", + "Europe\/Paris": "منځنۍ اروپا وخت (پاریس)", + "Europe\/Podgorica": "منځنۍ اروپا وخت (پوډورګویکا)", + "Europe\/Prague": "منځنۍ اروپا وخت (پراګ)", + "Europe\/Rome": "منځنۍ اروپا وخت (روم)", + "Europe\/San_Marino": "منځنۍ اروپا وخت (سان مارینو)", + "Europe\/Sarajevo": "منځنۍ اروپا وخت (سرجیو)", + "Europe\/Saratov": "ماسکو وخت (سراتف)", + "Europe\/Simferopol": "ماسکو وخت (سیمفروپول)", + "Europe\/Skopje": "منځنۍ اروپا وخت (سکپوګ)", + "Europe\/Stockholm": "منځنۍ اروپا وخت (استولوم)", + "Europe\/Tirane": "منځنۍ اروپا وخت (Tirane)", + "Europe\/Ulyanovsk": "ماسکو وخت (ایلیانوفس)", + "Europe\/Vaduz": "منځنۍ اروپا وخت (وادز)", + "Europe\/Vatican": "منځنۍ اروپا وخت (ویټیکان)", + "Europe\/Vienna": "منځنۍ اروپا وخت (ویانا)", + "Europe\/Volgograd": "د والګوګراد وخت (والګراډر)", + "Europe\/Warsaw": "منځنۍ اروپا وخت (وارسا)", + "Europe\/Zagreb": "منځنۍ اروپا وخت (زګرب)", + "Europe\/Zurich": "منځنۍ اروپا وخت (زریچ)", + "Indian\/Antananarivo": "ختيځ افريقا وخت (انتوننارو)", + "Indian\/Chagos": "د هند سمندر وخت (چارګوس)", + "Indian\/Christmas": "د کریسټ ټاپو وخت (کریمیس)", + "Indian\/Cocos": "د کوکوز ټاپوز وخت (کوکوس)", + "Indian\/Comoro": "ختيځ افريقا وخت (کومو)", + "Indian\/Kerguelen": "د فرانسې سویل او انټارټيک وخت (Kerguelen)", + "Indian\/Mahe": "سیچیلس وخت (مای)", + "Indian\/Maldives": "مالديف وخت (مالديپ)", + "Indian\/Mauritius": "ماریسیس وخت (ماوريشوس)", + "Indian\/Mayotte": "ختيځ افريقا وخت (میټوت)", + "Indian\/Reunion": "د غبرګون وخت (ریونیو)", + "MST7MDT": "د غره د وخت", + "PST8PDT": "پیسفک وخت", + "Pacific\/Apia": "د اپیا وخت (اپیا)", + "Pacific\/Auckland": "د نیوزی لینڈ وخت (اکلند)", + "Pacific\/Bougainville": "پاپوا نیو ګنی وخت (Bougainville)", + "Pacific\/Chatham": "چامام وخت (چامام)", + "Pacific\/Easter": "ايستر ټاپو وخت (ایسټر)", + "Pacific\/Efate": "د وناتو وخت (ایات)", + "Pacific\/Enderbury": "د فینکس ټاپو وخت (Enderbury)", + "Pacific\/Fakaofo": "توکیلاو وخت (فوکافو)", + "Pacific\/Fiji": "فجی وخت (في جي)", + "Pacific\/Funafuti": "د تووالو وخت (فرهفتی)", + "Pacific\/Galapagos": "ګالپګوس وخت (ګالپګوس)", + "Pacific\/Gambier": "د ګیمبریر وخت (ګيمبي)", + "Pacific\/Guadalcanal": "د سلیمان ټاپوګانو وخت (ګالالکنال)", + "Pacific\/Guam": "چمارو معياري وخت (ګوام)", + "Pacific\/Honolulu": "هوایی الیوتین وخت (هینولولو)", + "Pacific\/Johnston": "هوایی الیوتین وخت (جانستون)", + "Pacific\/Kiritimati": "د کرښې ټاټوبي وخت (Kiritimati)", + "Pacific\/Kosrae": "کوسیرا وخت (کوسیرا)", + "Pacific\/Kwajalein": "مارشیل ټاپو وخت (کجیجینین)", + "Pacific\/Majuro": "مارشیل ټاپو وخت (مجورو)", + "Pacific\/Marquesas": "مارکسس وخت (مارکسونه)", + "Pacific\/Midway": "سموا وخت (میډیا)", + "Pacific\/Nauru": "ناورو وخت (نایرو)", + "Pacific\/Niue": "نییو وخت (نیوو)", + "Pacific\/Norfolk": "د نورفکاس ټاپو وخت (نورفک)", + "Pacific\/Noumea": "د نیو کالیډونیا وخت (نواما)", + "Pacific\/Pago_Pago": "سموا وخت (پیگو پیگو)", + "Pacific\/Palau": "پالاو وخت (پلو)", + "Pacific\/Pitcairn": "پیټ کارین وخت (Pitcairn)", + "Pacific\/Ponape": "پونپپ وخت (پونپي)", + "Pacific\/Port_Moresby": "پاپوا نیو ګنی وخت (پور موورسبی)", + "Pacific\/Rarotonga": "د کوک ټاپوز وخت (راروتاګون)", + "Pacific\/Saipan": "چمارو معياري وخت (سيپان)", + "Pacific\/Tahiti": "ټیټيټي وخت (ټیټیټي)", + "Pacific\/Tarawa": "د ګیلبرټ جزیره وخت (ترارو)", + "Pacific\/Tongatapu": "ټونګا وخت (ټونګاتاپو)", + "Pacific\/Truk": "د چوکو وخت (چکوک)", + "Pacific\/Wake": "دک ټاپو وخت (ویک)", + "Pacific\/Wallis": "والیس او فوتونا وخت (والس)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ps_PK.json b/src/Symfony/Component/Intl/Resources/data/timezones/ps_PK.json new file mode 100644 index 0000000000000..5991e27db5ca9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ps_PK.json @@ -0,0 +1,13 @@ +{ + "Version": "2.1.49.34", + "Names": { + "Africa\/Casablanca": "لوېديزے اروپا وخت (Casablanca)", + "Africa\/El_Aaiun": "لوېديزے اروپا وخت (El Aaiun)", + "Atlantic\/Canary": "لوېديزے اروپا وخت (Canary)", + "Atlantic\/Faeroe": "لوېديزے اروپا وخت (Faroe)", + "Atlantic\/Madeira": "لوېديزے اروپا وخت (Madeira)", + "Europe\/Lisbon": "لوېديزے اروپا وخت (Lisbon)", + "Indian\/Kerguelen": "د فرانسے سویل او انټارټيک وخت (Kerguelen)", + "Pacific\/Kiritimati": "د کرښے ټاټوبي وخت (Kiritimati)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt.json new file mode 100644 index 0000000000000..f9fd7869c34b4 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Horário do Meridiano de Greenwich (Abidjan)", + "Africa\/Accra": "Horário do Meridiano de Greenwich (Acra)", + "Africa\/Addis_Ababa": "Horário da África Oriental (Adis Abeba)", + "Africa\/Algiers": "Horário da Europa Central (Argel)", + "Africa\/Asmera": "Horário da África Oriental (Asmara)", + "Africa\/Bamako": "Horário do Meridiano de Greenwich (Bamako)", + "Africa\/Bangui": "Horário da África Ocidental (Bangui)", + "Africa\/Banjul": "Horário do Meridiano de Greenwich (Banjul)", + "Africa\/Bissau": "Horário do Meridiano de Greenwich (Bissau)", + "Africa\/Blantyre": "Horário da África Central (Blantyre)", + "Africa\/Brazzaville": "Horário da África Ocidental (Brazzaville)", + "Africa\/Bujumbura": "Horário da África Central (Bujumbura)", + "Africa\/Cairo": "Horário da Europa Oriental (Cairo)", + "Africa\/Casablanca": "Horário da Europa Ocidental (Casablanca)", + "Africa\/Ceuta": "Horário da Europa Central (Ceuta)", + "Africa\/Conakry": "Horário do Meridiano de Greenwich (Conacri)", + "Africa\/Dakar": "Horário do Meridiano de Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Horário da África Oriental (Dar es Salaam)", + "Africa\/Djibouti": "Horário da África Oriental (Djibuti)", + "Africa\/Douala": "Horário da África Ocidental (Douala)", + "Africa\/El_Aaiun": "Horário da Europa Ocidental (El Aaiún)", + "Africa\/Freetown": "Horário do Meridiano de Greenwich (Freetown)", + "Africa\/Gaborone": "Horário da África Central (Gaborone)", + "Africa\/Harare": "Horário da África Central (Harare)", + "Africa\/Johannesburg": "Horário da África do Sul (Joanesburgo)", + "Africa\/Juba": "Horário da África Oriental (Juba)", + "Africa\/Kampala": "Horário da África Oriental (Kampala)", + "Africa\/Khartoum": "Horário da África Central (Cartum)", + "Africa\/Kigali": "Horário da África Central (Kigali)", + "Africa\/Kinshasa": "Horário da África Ocidental (Kinshasa)", + "Africa\/Lagos": "Horário da África Ocidental (Lagos)", + "Africa\/Libreville": "Horário da África Ocidental (Libreville)", + "Africa\/Lome": "Horário do Meridiano de Greenwich (Lomé)", + "Africa\/Luanda": "Horário da África Ocidental (Luanda)", + "Africa\/Lubumbashi": "Horário da África Central (Lubumbashi)", + "Africa\/Lusaka": "Horário da África Central (Lusaka)", + "Africa\/Malabo": "Horário da África Ocidental (Malabo)", + "Africa\/Maputo": "Horário da África Central (Maputo)", + "Africa\/Maseru": "Horário da África do Sul (Maseru)", + "Africa\/Mbabane": "Horário da África do Sul (Mbabane)", + "Africa\/Mogadishu": "Horário da África Oriental (Mogadíscio)", + "Africa\/Monrovia": "Horário do Meridiano de Greenwich (Monróvia)", + "Africa\/Nairobi": "Horário da África Oriental (Nairóbi)", + "Africa\/Ndjamena": "Horário da África Ocidental (N’Djamena)", + "Africa\/Niamey": "Horário da África Ocidental (Niamey)", + "Africa\/Nouakchott": "Horário do Meridiano de Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Horário do Meridiano de Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Horário da África Ocidental (Porto Novo)", + "Africa\/Sao_Tome": "Horário do Meridiano de Greenwich (São Tomé)", + "Africa\/Tripoli": "Horário da Europa Oriental (Trípoli)", + "Africa\/Tunis": "Horário da Europa Central (Túnis)", + "Africa\/Windhoek": "Horário da África Central (Windhoek)", + "America\/Adak": "Horário do Havaí e Ilhas Aleutas (Adak)", + "America\/Anchorage": "Horário do Alasca (Anchorage)", + "America\/Anguilla": "Horário do Atlântico (Anguilla)", + "America\/Antigua": "Horário do Atlântico (Antígua)", + "America\/Araguaina": "Horário de Brasília (Araguaína)", + "America\/Argentina\/La_Rioja": "Horário da Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Horário da Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Horário da Argentina (Salta)", + "America\/Argentina\/San_Juan": "Horário da Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Horário da Argentina Ocidental (San Luis)", + "America\/Argentina\/Tucuman": "Horário da Argentina (Tucumã)", + "America\/Argentina\/Ushuaia": "Horário da Argentina (Ushuaia)", + "America\/Aruba": "Horário do Atlântico (Aruba)", + "America\/Asuncion": "Horário do Paraguai (Assunção)", + "America\/Bahia": "Horário de Brasília (Bahia)", + "America\/Bahia_Banderas": "Horário Central (Bahia de Banderas)", + "America\/Barbados": "Horário do Atlântico (Barbados)", + "America\/Belem": "Horário de Brasília (Belém)", + "America\/Belize": "Horário Central (Belize)", + "America\/Blanc-Sablon": "Horário do Atlântico (Blanc-Sablon)", + "America\/Boa_Vista": "Horário do Amazonas (Boa Vista)", + "America\/Bogota": "Horário da Colômbia (Bogotá)", + "America\/Boise": "Horário das Montanhas (Boise)", + "America\/Buenos_Aires": "Horário da Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Horário das Montanhas (Cambridge Bay)", + "America\/Campo_Grande": "Horário do Amazonas (Campo Grande)", + "America\/Cancun": "Horário do Leste (Cancún)", + "America\/Caracas": "Horário da Venezuela (Caracas)", + "America\/Catamarca": "Horário da Argentina (Catamarca)", + "America\/Cayenne": "Horário da Guiana Francesa (Caiena)", + "America\/Cayman": "Horário do Leste (Cayman)", + "America\/Chicago": "Horário Central (Chicago)", + "America\/Chihuahua": "Horário do Pacífico Mexicano (Chihuahua)", + "America\/Coral_Harbour": "Horário do Leste (Atikokan)", + "America\/Cordoba": "Horário da Argentina (Córdoba)", + "America\/Costa_Rica": "Horário Central (Costa Rica)", + "America\/Creston": "Horário das Montanhas (Creston)", + "America\/Cuiaba": "Horário do Amazonas (Cuiabá)", + "America\/Curacao": "Horário do Atlântico (Curaçao)", + "America\/Danmarkshavn": "Horário do Meridiano de Greenwich (Danmarkshavn)", + "America\/Dawson": "Horário do Pacífico (Dawson)", + "America\/Dawson_Creek": "Horário das Montanhas (Dawson Creek)", + "America\/Denver": "Horário das Montanhas (Denver)", + "America\/Detroit": "Horário do Leste (Detroit)", + "America\/Dominica": "Horário do Atlântico (Dominica)", + "America\/Edmonton": "Horário das Montanhas (Edmonton)", + "America\/Eirunepe": "Horário do Acre (Eirunepé)", + "America\/El_Salvador": "Horário Central (El Salvador)", + "America\/Fort_Nelson": "Horário das Montanhas (Fort Nelson)", + "America\/Fortaleza": "Horário de Brasília (Fortaleza)", + "America\/Glace_Bay": "Horário do Atlântico (Glace Bay)", + "America\/Godthab": "Horário da Groenlândia Ocidental (Nuuk)", + "America\/Goose_Bay": "Horário do Atlântico (Goose Bay)", + "America\/Grand_Turk": "Horário do Leste (Grand Turk)", + "America\/Grenada": "Horário do Atlântico (Granada)", + "America\/Guadeloupe": "Horário do Atlântico (Guadalupe)", + "America\/Guatemala": "Horário Central (Guatemala)", + "America\/Guayaquil": "Horário do Equador (Guaiaquil)", + "America\/Guyana": "Horário da Guiana (Guiana)", + "America\/Halifax": "Horário do Atlântico (Halifax)", + "America\/Havana": "Horário de Cuba (Havana)", + "America\/Hermosillo": "Horário do Pacífico Mexicano (Hermosillo)", + "America\/Indiana\/Knox": "Horário Central (Knox, Indiana)", + "America\/Indiana\/Marengo": "Horário do Leste (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Horário do Leste (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Horário Central (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Horário do Leste (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Horário do Leste (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Horário do Leste (Winamac, Indiana)", + "America\/Indianapolis": "Horário do Leste (Indianápolis)", + "America\/Inuvik": "Horário das Montanhas (Inuvik)", + "America\/Iqaluit": "Horário do Leste (Iqaluit)", + "America\/Jamaica": "Horário do Leste (Jamaica)", + "America\/Jujuy": "Horário da Argentina (Jujuy)", + "America\/Juneau": "Horário do Alasca (Juneau)", + "America\/Kentucky\/Monticello": "Horário do Leste (Monticello, Kentucky)", + "America\/Kralendijk": "Horário do Atlântico (Kralendijk)", + "America\/La_Paz": "Horário da Bolívia (La Paz)", + "America\/Lima": "Horário do Peru (Lima)", + "America\/Los_Angeles": "Horário do Pacífico (Los Angeles)", + "America\/Louisville": "Horário do Leste (Louisville)", + "America\/Lower_Princes": "Horário do Atlântico (Lower Prince’s Quarter)", + "America\/Maceio": "Horário de Brasília (Maceió)", + "America\/Managua": "Horário Central (Manágua)", + "America\/Manaus": "Horário do Amazonas (Manaus)", + "America\/Marigot": "Horário do Atlântico (Marigot)", + "America\/Martinique": "Horário do Atlântico (Martinica)", + "America\/Matamoros": "Horário Central (Matamoros)", + "America\/Mazatlan": "Horário do Pacífico Mexicano (Mazatlan)", + "America\/Mendoza": "Horário da Argentina (Mendoza)", + "America\/Menominee": "Horário Central (Menominee)", + "America\/Merida": "Horário Central (Mérida)", + "America\/Metlakatla": "Horário do Alasca (Metlakatla)", + "America\/Mexico_City": "Horário Central (Cidade do México)", + "America\/Miquelon": "Horário de Saint Pierre e Miquelon (Miquelon)", + "America\/Moncton": "Horário do Atlântico (Moncton)", + "America\/Monterrey": "Horário Central (Monterrey)", + "America\/Montevideo": "Horário do Uruguai (Montevidéu)", + "America\/Montserrat": "Horário do Atlântico (Montserrat)", + "America\/Nassau": "Horário do Leste (Nassau)", + "America\/New_York": "Horário do Leste (Nova York)", + "America\/Nipigon": "Horário do Leste (Nipigon)", + "America\/Nome": "Horário do Alasca (Nome)", + "America\/Noronha": "Horário de Fernando de Noronha (Fernando de Noronha)", + "America\/North_Dakota\/Beulah": "Horário Central (Beulah, Dakota do Norte)", + "America\/North_Dakota\/Center": "Horário Central (Center, Dakota do Norte)", + "America\/North_Dakota\/New_Salem": "Horário Central (New Salen, Dakota do Norte)", + "America\/Ojinaga": "Horário das Montanhas (Ojinaga)", + "America\/Panama": "Horário do Leste (Panamá)", + "America\/Pangnirtung": "Horário do Leste (Pangnirtung)", + "America\/Paramaribo": "Horário do Suriname (Paramaribo)", + "America\/Phoenix": "Horário das Montanhas (Phoenix)", + "America\/Port-au-Prince": "Horário do Leste (Porto Príncipe)", + "America\/Port_of_Spain": "Horário do Atlântico (Port of Spain)", + "America\/Porto_Velho": "Horário do Amazonas (Porto Velho)", + "America\/Puerto_Rico": "Horário do Atlântico (Porto Rico)", + "America\/Punta_Arenas": "Horário do Chile (Punta Arenas)", + "America\/Rainy_River": "Horário Central (Rainy River)", + "America\/Rankin_Inlet": "Horário Central (Rankin Inlet)", + "America\/Recife": "Horário de Brasília (Recife)", + "America\/Regina": "Horário Central (Regina)", + "America\/Resolute": "Horário Central (Resolute)", + "America\/Rio_Branco": "Horário do Acre (Rio Branco)", + "America\/Santa_Isabel": "Horário do Noroeste do México (Santa Isabel)", + "America\/Santarem": "Horário de Brasília (Santarém)", + "America\/Santiago": "Horário do Chile (Santiago)", + "America\/Santo_Domingo": "Horário do Atlântico (Santo Domingo)", + "America\/Sao_Paulo": "Horário de Brasília (São Paulo)", + "America\/Scoresbysund": "Horário da Groelândia Oriental (Ittoqqortoormiit)", + "America\/Sitka": "Horário do Alasca (Sitka)", + "America\/St_Barthelemy": "Horário do Atlântico (São Bartolomeu)", + "America\/St_Johns": "Horário da Terra Nova (Saint John’s)", + "America\/St_Kitts": "Horário do Atlântico (São Cristóvão)", + "America\/St_Lucia": "Horário do Atlântico (Santa Lúcia)", + "America\/St_Thomas": "Horário do Atlântico (Saint Thomas)", + "America\/St_Vincent": "Horário do Atlântico (São Vicente)", + "America\/Swift_Current": "Horário Central (Swift Current)", + "America\/Tegucigalpa": "Horário Central (Tegucigalpa)", + "America\/Thule": "Horário do Atlântico (Thule)", + "America\/Thunder_Bay": "Horário do Leste (Thunder Bay)", + "America\/Tijuana": "Horário do Pacífico (Tijuana)", + "America\/Toronto": "Horário do Leste (Toronto)", + "America\/Tortola": "Horário do Atlântico (Tortola)", + "America\/Vancouver": "Horário do Pacífico (Vancouver)", + "America\/Whitehorse": "Horário do Pacífico (Whitehorse)", + "America\/Winnipeg": "Horário Central (Winnipeg)", + "America\/Yakutat": "Horário do Alasca (Yakutat)", + "America\/Yellowknife": "Horário das Montanhas (Yellowknife)", + "Antarctica\/Casey": "Horário da Austrália Ocidental (Casey)", + "Antarctica\/Davis": "Horário de Davis (Davis)", + "Antarctica\/DumontDUrville": "Horário de Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Horário da Ilha Macquarie (Macquarie)", + "Antarctica\/Mawson": "Horário de Mawson (Mawson)", + "Antarctica\/McMurdo": "Horário da Nova Zelândia (McMurdo)", + "Antarctica\/Palmer": "Horário do Chile (Palmer)", + "Antarctica\/Rothera": "Horário de Rothera (Rothera)", + "Antarctica\/Syowa": "Horário de Syowa (Showa)", + "Antarctica\/Troll": "Horário do Meridiano de Greenwich (Troll)", + "Antarctica\/Vostok": "Horário de Vostok (Vostok)", + "Arctic\/Longyearbyen": "Horário da Europa Central (Longyearbyen)", + "Asia\/Aden": "Horário da Arábia (Adem)", + "Asia\/Almaty": "Horário do Casaquistão Oriental (Almaty)", + "Asia\/Amman": "Horário da Europa Oriental (Amã)", + "Asia\/Anadyr": "Horário de Anadyr (Anadyr)", + "Asia\/Aqtau": "Horário do Casaquistão Ocidental (Aqtau)", + "Asia\/Aqtobe": "Horário do Casaquistão Ocidental (Aqtöbe)", + "Asia\/Ashgabat": "Horário do Turcomenistão (Asgabate)", + "Asia\/Atyrau": "Horário do Casaquistão Ocidental (Atyrau)", + "Asia\/Baghdad": "Horário da Arábia (Bagdá)", + "Asia\/Bahrain": "Horário da Arábia (Bahrein)", + "Asia\/Baku": "Horário do Arzeibaijão (Baku)", + "Asia\/Bangkok": "Horário da Indochina (Bangkok)", + "Asia\/Beirut": "Horário da Europa Oriental (Beirute)", + "Asia\/Bishkek": "Horário do Quirguistão (Bishkek)", + "Asia\/Brunei": "Horário de Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Horário Padrão da Índia (Kolkata)", + "Asia\/Chita": "Horário de Yakutsk (Chita)", + "Asia\/Choibalsan": "Horário de Choibalsan (Choibalsan)", + "Asia\/Colombo": "Horário Padrão da Índia (Colombo)", + "Asia\/Damascus": "Horário da Europa Oriental (Damasco)", + "Asia\/Dhaka": "Horário de Bangladesh (Dacca)", + "Asia\/Dili": "Horário do Timor-Leste (Dili)", + "Asia\/Dubai": "Horário do Golfo (Dubai)", + "Asia\/Dushanbe": "Horário do Tajiquistão (Duchambe)", + "Asia\/Famagusta": "Horário da Europa Oriental (Famagusta)", + "Asia\/Gaza": "Horário da Europa Oriental (Gaza)", + "Asia\/Hebron": "Horário da Europa Oriental (Hebrom)", + "Asia\/Hong_Kong": "Horário de Hong Kong (Hong Kong)", + "Asia\/Hovd": "Horário de Hovd (Hovd)", + "Asia\/Irkutsk": "Horário de Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Horário da Indonésia Ocidental (Jacarta)", + "Asia\/Jayapura": "Horário da Indonésia Oriental (Jayapura)", + "Asia\/Jerusalem": "Horário de Israel (Jerusalém)", + "Asia\/Kabul": "Horário do Afeganistão (Kabul)", + "Asia\/Kamchatka": "Horário de Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Horário do Paquistão (Carachi)", + "Asia\/Katmandu": "Horário do Nepal (Catmandu)", + "Asia\/Khandyga": "Horário de Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Horário de Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Horário da Malásia (Kuala Lampur)", + "Asia\/Kuching": "Horário da Malásia (Kuching)", + "Asia\/Kuwait": "Horário da Arábia (Kuwait)", + "Asia\/Macau": "Horário da China (Macau)", + "Asia\/Magadan": "Horário de Magadan (Magadan)", + "Asia\/Makassar": "Horário da Indonésia Central (Macáçar)", + "Asia\/Manila": "Horário das Filipinas (Manila)", + "Asia\/Muscat": "Horário do Golfo (Mascate)", + "Asia\/Nicosia": "Horário da Europa Oriental (Nicósia)", + "Asia\/Novokuznetsk": "Horário de Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Horário de Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Horário de Omsk (Omsk)", + "Asia\/Oral": "Horário do Casaquistão Ocidental (Oral)", + "Asia\/Phnom_Penh": "Horário da Indochina (Phnom Penh)", + "Asia\/Pontianak": "Horário da Indonésia Ocidental (Pontianak)", + "Asia\/Pyongyang": "Horário da Coreia (Pyongyang)", + "Asia\/Qatar": "Horário da Arábia (Qatar)", + "Asia\/Qostanay": "Horário do Casaquistão Oriental (Qostanay)", + "Asia\/Qyzylorda": "Horário do Casaquistão Ocidental (Qyzylorda)", + "Asia\/Rangoon": "Horário de Mianmar (Yangon)", + "Asia\/Riyadh": "Horário da Arábia (Riade)", + "Asia\/Saigon": "Horário da Indochina (Ho Chi Minh)", + "Asia\/Sakhalin": "Horário de Sacalina (Sacalina)", + "Asia\/Samarkand": "Horário do Uzbequistão (Samarcanda)", + "Asia\/Seoul": "Horário da Coreia (Seul)", + "Asia\/Shanghai": "Horário da China (Xangai)", + "Asia\/Singapore": "Horário Padrão de Cingapura (Cingapura)", + "Asia\/Srednekolymsk": "Horário de Magadan (Srednekolymsk)", + "Asia\/Taipei": "Horário de Taipei (Taipei)", + "Asia\/Tashkent": "Horário do Uzbequistão (Tashkent)", + "Asia\/Tbilisi": "Horário da Geórgia (Tbilisi)", + "Asia\/Tehran": "Horário do Irã (Teerã)", + "Asia\/Thimphu": "Horário do Butão (Timphu)", + "Asia\/Tokyo": "Horário do Japão (Tóquio)", + "Asia\/Ulaanbaatar": "Horário de Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "Horário de Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Horário da Indochina (Vientiane)", + "Asia\/Vladivostok": "Horário de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Horário de Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Horário de Ecaterimburgo (Ecaterimburgo)", + "Asia\/Yerevan": "Horário da Armênia (Yerevan)", + "Atlantic\/Azores": "Horário dos Açores (Açores)", + "Atlantic\/Bermuda": "Horário do Atlântico (Bermudas)", + "Atlantic\/Canary": "Horário da Europa Ocidental (Canárias)", + "Atlantic\/Cape_Verde": "Horário de Cabo Verde (Cabo Verde)", + "Atlantic\/Faeroe": "Horário da Europa Ocidental (Ilhas Faroe)", + "Atlantic\/Madeira": "Horário da Europa Ocidental (Madeira)", + "Atlantic\/Reykjavik": "Horário do Meridiano de Greenwich (Reykjavík)", + "Atlantic\/South_Georgia": "Horário da Geórgia do Sul (Geórgia do Sul)", + "Atlantic\/St_Helena": "Horário do Meridiano de Greenwich (Santa Helena)", + "Atlantic\/Stanley": "Horário das Ilhas Malvinas (Stanley)", + "Australia\/Adelaide": "Horário da Austrália Central (Adelaide)", + "Australia\/Brisbane": "Horário da Austrália Oriental (Brisbane)", + "Australia\/Broken_Hill": "Horário da Austrália Central (Broken Hill)", + "Australia\/Currie": "Horário da Austrália Oriental (Currie)", + "Australia\/Darwin": "Horário da Austrália Central (Darwin)", + "Australia\/Eucla": "Horário da Austrália Centro-Ocidental (Eucla)", + "Australia\/Hobart": "Horário da Austrália Oriental (Hobart)", + "Australia\/Lindeman": "Horário da Austrália Oriental (Lindeman)", + "Australia\/Lord_Howe": "Horário de Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Horário da Austrália Oriental (Melbourne)", + "Australia\/Perth": "Horário da Austrália Ocidental (Perth)", + "Australia\/Sydney": "Horário da Austrália Oriental (Sydney)", + "CST6CDT": "Horário Central", + "EST5EDT": "Horário do Leste", + "Etc\/GMT": "Horário do Meridiano de Greenwich", + "Etc\/UTC": "Horário Universal Coordenado", + "Europe\/Amsterdam": "Horário da Europa Central (Amsterdã)", + "Europe\/Andorra": "Horário da Europa Central (Andorra)", + "Europe\/Astrakhan": "Horário de Moscou (Astracã)", + "Europe\/Athens": "Horário da Europa Oriental (Atenas)", + "Europe\/Belgrade": "Horário da Europa Central (Belgrado)", + "Europe\/Berlin": "Horário da Europa Central (Berlim)", + "Europe\/Bratislava": "Horário da Europa Central (Bratislava)", + "Europe\/Brussels": "Horário da Europa Central (Bruxelas)", + "Europe\/Bucharest": "Horário da Europa Oriental (Bucareste)", + "Europe\/Budapest": "Horário da Europa Central (Budapeste)", + "Europe\/Busingen": "Horário da Europa Central (Büsingen)", + "Europe\/Chisinau": "Horário da Europa Oriental (Chisinau)", + "Europe\/Copenhagen": "Horário da Europa Central (Copenhague)", + "Europe\/Dublin": "Horário do Meridiano de Greenwich (Dublin)", + "Europe\/Gibraltar": "Horário da Europa Central (Gibraltar)", + "Europe\/Guernsey": "Horário do Meridiano de Greenwich (Guernsey)", + "Europe\/Helsinki": "Horário da Europa Oriental (Helsinque)", + "Europe\/Isle_of_Man": "Horário do Meridiano de Greenwich (Ilha de Man)", + "Europe\/Jersey": "Horário do Meridiano de Greenwich (Jersey)", + "Europe\/Kaliningrad": "Horário da Europa Oriental (Kaliningrado)", + "Europe\/Kiev": "Horário da Europa Oriental (Kiev)", + "Europe\/Lisbon": "Horário da Europa Ocidental (Lisboa)", + "Europe\/Ljubljana": "Horário da Europa Central (Liubliana)", + "Europe\/London": "Horário do Meridiano de Greenwich (Londres)", + "Europe\/Luxembourg": "Horário da Europa Central (Luxemburgo)", + "Europe\/Madrid": "Horário da Europa Central (Madri)", + "Europe\/Malta": "Horário da Europa Central (Malta)", + "Europe\/Mariehamn": "Horário da Europa Oriental (Mariehamn)", + "Europe\/Minsk": "Horário de Moscou (Minsk)", + "Europe\/Monaco": "Horário da Europa Central (Mônaco)", + "Europe\/Moscow": "Horário de Moscou (Moscou)", + "Europe\/Oslo": "Horário da Europa Central (Oslo)", + "Europe\/Paris": "Horário da Europa Central (Paris)", + "Europe\/Podgorica": "Horário da Europa Central (Podgorica)", + "Europe\/Prague": "Horário da Europa Central (Praga)", + "Europe\/Riga": "Horário da Europa Oriental (Riga)", + "Europe\/Rome": "Horário da Europa Central (Roma)", + "Europe\/Samara": "Horário de Samara (Samara)", + "Europe\/San_Marino": "Horário da Europa Central (San Marino)", + "Europe\/Sarajevo": "Horário da Europa Central (Sarajevo)", + "Europe\/Saratov": "Horário de Moscou (Saratov)", + "Europe\/Simferopol": "Horário de Moscou (Simferopol)", + "Europe\/Skopje": "Horário da Europa Central (Skopje)", + "Europe\/Sofia": "Horário da Europa Oriental (Sófia)", + "Europe\/Stockholm": "Horário da Europa Central (Estocolmo)", + "Europe\/Tallinn": "Horário da Europa Oriental (Tallinn)", + "Europe\/Tirane": "Horário da Europa Central (Tirana)", + "Europe\/Ulyanovsk": "Horário de Moscou (Ulianovsk)", + "Europe\/Uzhgorod": "Horário da Europa Oriental (Uzhgorod)", + "Europe\/Vaduz": "Horário da Europa Central (Vaduz)", + "Europe\/Vatican": "Horário da Europa Central (Vaticano)", + "Europe\/Vienna": "Horário da Europa Central (Viena)", + "Europe\/Vilnius": "Horário da Europa Oriental (Vilnius)", + "Europe\/Volgograd": "Horário de Volgogrado (Volgogrado)", + "Europe\/Warsaw": "Horário da Europa Central (Varsóvia)", + "Europe\/Zagreb": "Horário da Europa Central (Zagreb)", + "Europe\/Zaporozhye": "Horário da Europa Oriental (Zaporizhia)", + "Europe\/Zurich": "Horário da Europa Central (Zurique)", + "Indian\/Antananarivo": "Horário da África Oriental (Antananarivo)", + "Indian\/Chagos": "Horário do Oceano Índico (Chagos)", + "Indian\/Christmas": "Horário da Ilha Christmas (Christmas)", + "Indian\/Cocos": "Horário das Ilhas Coco (Cocos)", + "Indian\/Comoro": "Horário da África Oriental (Comores)", + "Indian\/Kerguelen": "Horário da Antártida e do Sul da França (Kerguelen)", + "Indian\/Mahe": "Horário de Seicheles (Mahé)", + "Indian\/Maldives": "Horário das Ilhas Maldivas (Maldivas)", + "Indian\/Mauritius": "Horário de Maurício (Maurício)", + "Indian\/Mayotte": "Horário da África Oriental (Mayotte)", + "Indian\/Reunion": "Horário de Reunião (Reunião)", + "MST7MDT": "Horário das Montanhas", + "PST8PDT": "Horário do Pacífico", + "Pacific\/Apia": "Horário de Apia (Ápia)", + "Pacific\/Auckland": "Horário da Nova Zelândia (Auckland)", + "Pacific\/Bougainville": "Horário de Papua Nova Guiné (Bougainville)", + "Pacific\/Chatham": "Horário de Chatham (Chatham)", + "Pacific\/Easter": "Horário da Ilha de Páscoa (Ilha de Páscoa)", + "Pacific\/Efate": "Horário de Vanuatu (Éfaté)", + "Pacific\/Enderbury": "Horário das Ilhas Fênix (Enderbury)", + "Pacific\/Fakaofo": "Horário de Tokelau (Fakaofo)", + "Pacific\/Fiji": "Horário de Fiji (Fiji)", + "Pacific\/Funafuti": "Horário de Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Horário de Galápagos (Galápagos)", + "Pacific\/Gambier": "Horário de Gambier (Gambier)", + "Pacific\/Guadalcanal": "Horário das Ilhas Salomão (Guadalcanal)", + "Pacific\/Guam": "Horário de Chamorro (Guam)", + "Pacific\/Honolulu": "Horário do Havaí e Ilhas Aleutas (Honolulu)", + "Pacific\/Johnston": "Horário do Havaí e Ilhas Aleutas (Johnston)", + "Pacific\/Kiritimati": "Horário das Ilhas Line (Kiritimati)", + "Pacific\/Kosrae": "Horário de Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Horário das Ilhas Marshall (Kwajalein)", + "Pacific\/Majuro": "Horário das Ilhas Marshall (Majuro)", + "Pacific\/Marquesas": "Horário das Marquesas (Marquesas)", + "Pacific\/Midway": "Horário de Samoa (Midway)", + "Pacific\/Nauru": "Horário de Nauru (Nauru)", + "Pacific\/Niue": "Horário de Niue (Niue)", + "Pacific\/Norfolk": "Horário da Ilha Norfolk (Norfolk)", + "Pacific\/Noumea": "Horário da Nova Caledônia (Nouméa)", + "Pacific\/Pago_Pago": "Horário de Samoa (Pago Pago)", + "Pacific\/Palau": "Horário de Palau (Palau)", + "Pacific\/Pitcairn": "Horário de Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Horário de Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Horário de Papua Nova Guiné (Port Moresby)", + "Pacific\/Rarotonga": "Horário das Ilhas Cook (Rarotonga)", + "Pacific\/Saipan": "Horário de Chamorro (Saipan)", + "Pacific\/Tahiti": "Horário do Taiti (Taiti)", + "Pacific\/Tarawa": "Horário das Ilhas Gilberto (Taraua)", + "Pacific\/Tongatapu": "Horário de Tonga (Tongatapu)", + "Pacific\/Truk": "Horário de Chuuk (Chuuk)", + "Pacific\/Wake": "Horário das Ilhas Wake (Wake)", + "Pacific\/Wallis": "Horário de Wallis e Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_AO.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_AO.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_AO.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_CV.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_CV.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_CV.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_GW.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_GW.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_GW.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_MO.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_MO.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_MO.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_MZ.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_MZ.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_MZ.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_PT.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_PT.json new file mode 100644 index 0000000000000..1a0c3336566ec --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_PT.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.47.89", + "Names": { + "Africa\/Abidjan": "Hora de Greenwich (Abidjan)", + "Africa\/Accra": "Hora de Greenwich (Accra)", + "Africa\/Addis_Ababa": "Hora da África Oriental (Adis-Abeba)", + "Africa\/Algiers": "Hora da Europa Central (Algiers)", + "Africa\/Asmera": "Hora da África Oriental (Asmara)", + "Africa\/Bamako": "Hora de Greenwich (Bamaco)", + "Africa\/Bangui": "Hora da África Ocidental (Bangui)", + "Africa\/Banjul": "Hora de Greenwich (Banjul)", + "Africa\/Bissau": "Hora de Greenwich (Bissau)", + "Africa\/Blantyre": "Hora da África Central (Blantyre)", + "Africa\/Brazzaville": "Hora da África Ocidental (Brazzaville)", + "Africa\/Bujumbura": "Hora da África Central (Bujumbura)", + "Africa\/Cairo": "Hora da Europa Oriental (Cairo)", + "Africa\/Casablanca": "Hora da Europa Ocidental (Casablanca)", + "Africa\/Ceuta": "Hora da Europa Central (Ceuta)", + "Africa\/Conakry": "Hora de Greenwich (Conakry)", + "Africa\/Dakar": "Hora de Greenwich (Dacar)", + "Africa\/Dar_es_Salaam": "Hora da África Oriental (Dar es Salaam)", + "Africa\/Djibouti": "Hora da África Oriental (Jibuti)", + "Africa\/Douala": "Hora da África Ocidental (Douala)", + "Africa\/El_Aaiun": "Hora da Europa Ocidental (El Aaiun)", + "Africa\/Freetown": "Hora de Greenwich (Freetown)", + "Africa\/Gaborone": "Hora da África Central (Gaborone)", + "Africa\/Harare": "Hora da África Central (Harare)", + "Africa\/Johannesburg": "Hora da África do Sul (Johannesburg)", + "Africa\/Juba": "Hora da África Oriental (Juba)", + "Africa\/Kampala": "Hora da África Oriental (Campala)", + "Africa\/Khartoum": "Hora da África Central (Khartoum)", + "Africa\/Kigali": "Hora da África Central (Kigali)", + "Africa\/Kinshasa": "Hora da África Ocidental (Kinshasa)", + "Africa\/Lagos": "Hora da África Ocidental (Lagos)", + "Africa\/Libreville": "Hora da África Ocidental (Libreville)", + "Africa\/Lome": "Hora de Greenwich (Lome)", + "Africa\/Luanda": "Hora da África Ocidental (Luanda)", + "Africa\/Lubumbashi": "Hora da África Central (Lubumbashi)", + "Africa\/Lusaka": "Hora da África Central (Lusaca)", + "Africa\/Malabo": "Hora da África Ocidental (Malabo)", + "Africa\/Maputo": "Hora da África Central (Maputo)", + "Africa\/Maseru": "Hora da África do Sul (Maseru)", + "Africa\/Mbabane": "Hora da África do Sul (Mbabane)", + "Africa\/Mogadishu": "Hora da África Oriental (Mogadishu)", + "Africa\/Monrovia": "Hora de Greenwich (Monrovia)", + "Africa\/Nairobi": "Hora da África Oriental (Nairobi)", + "Africa\/Ndjamena": "Hora da África Ocidental (Ndjamena)", + "Africa\/Niamey": "Hora da África Ocidental (Niamei)", + "Africa\/Nouakchott": "Hora de Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Hora de Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Hora da África Ocidental (Porto-Novo)", + "Africa\/Sao_Tome": "Hora de Greenwich (Sao Tome)", + "Africa\/Tripoli": "Hora da Europa Oriental (Tripoli)", + "Africa\/Tunis": "Hora da Europa Central (Tunes)", + "Africa\/Windhoek": "Hora da África Central (Windhoek)", + "America\/Adak": "Hora do Havai e Aleutas (Adak)", + "America\/Anchorage": "Hora do Alasca (Anchorage)", + "America\/Anguilla": "Hora do Atlântico (Anguila)", + "America\/Antigua": "Hora do Atlântico (Antigua)", + "America\/Araguaina": "Hora de Brasília (Araguaina)", + "America\/Argentina\/La_Rioja": "Hora da Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Hora da Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Hora da Argentina (Salta)", + "America\/Argentina\/San_Juan": "Hora da Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Hora da Argentina Ocidental (San Luis)", + "America\/Argentina\/Tucuman": "Hora da Argentina (Tucumán)", + "America\/Argentina\/Ushuaia": "Hora da Argentina (Ushuaia)", + "America\/Aruba": "Hora do Atlântico (Aruba)", + "America\/Asuncion": "Hora do Paraguai (Asuncion)", + "America\/Bahia": "Hora de Brasília (Baía)", + "America\/Bahia_Banderas": "Hora Central (Bahia Banderas)", + "America\/Barbados": "Hora do Atlântico (Barbados)", + "America\/Belem": "Hora de Brasília (Belem)", + "America\/Belize": "Hora Central (Belize)", + "America\/Blanc-Sablon": "Hora do Atlântico (Blanc-Sablon)", + "America\/Boa_Vista": "Hora do Amazonas (Boa Vista)", + "America\/Bogota": "Hora da Colômbia (Bogota)", + "America\/Boise": "Hora da Montanha (Boise)", + "America\/Buenos_Aires": "Hora da Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Hora da Montanha (Cambridge Bay)", + "America\/Campo_Grande": "Hora do Amazonas (Campo Grande)", + "America\/Cancun": "Hora Oriental (Cancun)", + "America\/Caracas": "Hora da Venezuela (Caracas)", + "America\/Catamarca": "Hora da Argentina (Catamarca)", + "America\/Cayenne": "Hora da Guiana Francesa (Cayenne)", + "America\/Cayman": "Hora Oriental (Caimão)", + "America\/Chicago": "Hora Central (Chicago)", + "America\/Chihuahua": "Hora do Pacífico Mexicano (Chihuahua)", + "America\/Coral_Harbour": "Hora Oriental (Atikokan)", + "America\/Cordoba": "Hora da Argentina (Cordoba)", + "America\/Costa_Rica": "Hora Central (Costa Rica)", + "America\/Creston": "Hora da Montanha (Creston)", + "America\/Cuiaba": "Hora do Amazonas (Cuiaba)", + "America\/Curacao": "Hora do Atlântico (Curaçau)", + "America\/Danmarkshavn": "Hora de Greenwich (Danmarkshavn)", + "America\/Dawson": "Hora do Pacífico (Dawson)", + "America\/Dawson_Creek": "Hora da Montanha (Dawson Creek)", + "America\/Denver": "Hora da Montanha (Denver)", + "America\/Detroit": "Hora Oriental (Detroit)", + "America\/Dominica": "Hora do Atlântico (Domínica)", + "America\/Edmonton": "Hora da Montanha (Edmonton)", + "America\/Eirunepe": "Hora do Acre (Eirunepe)", + "America\/El_Salvador": "Hora Central (El Salvador)", + "America\/Fort_Nelson": "Hora da Montanha (Fort Nelson)", + "America\/Fortaleza": "Hora de Brasília (Fortaleza)", + "America\/Glace_Bay": "Hora do Atlântico (Glace Bay)", + "America\/Godthab": "Hora da Gronelândia Ocidental (Nuuk)", + "America\/Goose_Bay": "Hora do Atlântico (Goose Bay)", + "America\/Grand_Turk": "Hora Oriental (Grand Turk)", + "America\/Grenada": "Hora do Atlântico (Grenada)", + "America\/Guadeloupe": "Hora do Atlântico (Guadeloupe)", + "America\/Guatemala": "Hora Central (Guatemala)", + "America\/Guayaquil": "Hora do Equador (Guayaquil)", + "America\/Guyana": "Hora da Guiana (Guyana)", + "America\/Halifax": "Hora do Atlântico (Halifax)", + "America\/Havana": "Hora de Cuba (Havana)", + "America\/Hermosillo": "Hora do Pacífico Mexicano (Hermosillo)", + "America\/Indiana\/Knox": "Hora Central (Knox, Indiana)", + "America\/Indiana\/Marengo": "Hora Oriental (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Hora Oriental (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Hora Central (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Hora Oriental (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Hora Oriental (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Hora Oriental (Winamac, Indiana)", + "America\/Indianapolis": "Hora Oriental (Indianapolis)", + "America\/Inuvik": "Hora da Montanha (Inuvik)", + "America\/Iqaluit": "Hora Oriental (Iqaluit)", + "America\/Jamaica": "Hora Oriental (Jamaica)", + "America\/Jujuy": "Hora da Argentina (Jujuy)", + "America\/Juneau": "Hora do Alasca (Juneau)", + "America\/Kentucky\/Monticello": "Hora Oriental (Monticello, Kentucky)", + "America\/Kralendijk": "Hora do Atlântico (Kralendijk)", + "America\/La_Paz": "Hora da Bolívia (La Paz)", + "America\/Lima": "Hora do Peru (Lima)", + "America\/Los_Angeles": "Hora do Pacífico (Los Angeles)", + "America\/Louisville": "Hora Oriental (Louisville)", + "America\/Lower_Princes": "Hora do Atlântico (Lower Prince’s Quarter)", + "America\/Maceio": "Hora de Brasília (Maceio)", + "America\/Managua": "Hora Central (Managua)", + "America\/Manaus": "Hora do Amazonas (Manaus)", + "America\/Marigot": "Hora do Atlântico (Marigot)", + "America\/Martinique": "Hora do Atlântico (Martinique)", + "America\/Matamoros": "Hora Central (Matamoros)", + "America\/Mazatlan": "Hora do Pacífico Mexicano (Mazatlan)", + "America\/Mendoza": "Hora da Argentina (Mendoza)", + "America\/Menominee": "Hora Central (Menominee)", + "America\/Merida": "Hora Central (Merida)", + "America\/Metlakatla": "Hora do Alasca (Metlakatla)", + "America\/Mexico_City": "Hora Central (Mexico City)", + "America\/Miquelon": "Hora de São Pedro e Miquelão (Miquelon)", + "America\/Moncton": "Hora do Atlântico (Moncton)", + "America\/Monterrey": "Hora Central (Monterrey)", + "America\/Montevideo": "Hora do Uruguai (Montevideu)", + "America\/Montserrat": "Hora do Atlântico (Monserrate)", + "America\/Nassau": "Hora Oriental (Nassau)", + "America\/New_York": "Hora Oriental (Nova Iorque)", + "America\/Nipigon": "Hora Oriental (Nipigon)", + "America\/Nome": "Hora do Alasca (Nome)", + "America\/Noronha": "Hora de Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Hora Central (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Hora Central (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Hora Central (New Salem, North Dakota)", + "America\/Ojinaga": "Hora da Montanha (Ojinaga)", + "America\/Panama": "Hora Oriental (Panama)", + "America\/Pangnirtung": "Hora Oriental (Pangnirtung)", + "America\/Paramaribo": "Hora do Suriname (Paramaribo)", + "America\/Phoenix": "Hora da Montanha (Phoenix)", + "America\/Port-au-Prince": "Hora Oriental (Port-au-Prince)", + "America\/Port_of_Spain": "Hora do Atlântico (Porto de Espanha)", + "America\/Porto_Velho": "Hora do Amazonas (Porto Velho)", + "America\/Puerto_Rico": "Hora do Atlântico (Puerto Rico)", + "America\/Punta_Arenas": "Hora do Chile (Punta Arenas)", + "America\/Rainy_River": "Hora Central (Rainy River)", + "America\/Rankin_Inlet": "Hora Central (Rankin Inlet)", + "America\/Recife": "Hora de Brasília (Recife)", + "America\/Regina": "Hora Central (Regina)", + "America\/Resolute": "Hora Central (Resolute)", + "America\/Rio_Branco": "Hora do Acre (Rio Branco)", + "America\/Santa_Isabel": "Hora do Noroeste do México (Santa Isabel)", + "America\/Santarem": "Hora de Brasília (Santarem)", + "America\/Santiago": "Hora do Chile (Santiago)", + "America\/Santo_Domingo": "Hora do Atlântico (Santo Domingo)", + "America\/Sao_Paulo": "Hora de Brasília (Sao Paulo)", + "America\/Scoresbysund": "Hora da Gronelândia Oriental (Ittoqqortoormiit)", + "America\/Sitka": "Hora do Alasca (Sitka)", + "America\/St_Barthelemy": "Hora do Atlântico (St. Barthelemy)", + "America\/St_Johns": "Hora da Terra Nova (St. John’s)", + "America\/St_Kitts": "Hora do Atlântico (St. Kitts)", + "America\/St_Lucia": "Hora do Atlântico (St. Lucia)", + "America\/St_Thomas": "Hora do Atlântico (St. Thomas)", + "America\/St_Vincent": "Hora do Atlântico (St. Vincent)", + "America\/Swift_Current": "Hora Central (Swift Current)", + "America\/Tegucigalpa": "Hora Central (Tegucigalpa)", + "America\/Thule": "Hora do Atlântico (Thule)", + "America\/Thunder_Bay": "Hora Oriental (Thunder Bay)", + "America\/Tijuana": "Hora do Pacífico (Tijuana)", + "America\/Toronto": "Hora Oriental (Toronto)", + "America\/Tortola": "Hora do Atlântico (Tortola)", + "America\/Vancouver": "Hora do Pacífico (Vancouver)", + "America\/Whitehorse": "Hora do Pacífico (Whitehorse)", + "America\/Winnipeg": "Hora Central (Winnipeg)", + "America\/Yakutat": "Hora do Alasca (Yakutat)", + "America\/Yellowknife": "Hora da Montanha (Yellowknife)", + "Antarctica\/Casey": "Hora da Austrália Ocidental (Casey)", + "Antarctica\/Davis": "Hora de Davis (Davis)", + "Antarctica\/DumontDUrville": "Hora de Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Hora da Ilha Macquarie (Macquarie)", + "Antarctica\/Mawson": "Hora de Mawson (Mawson)", + "Antarctica\/McMurdo": "Hora da Nova Zelândia (McMurdo)", + "Antarctica\/Palmer": "Hora do Chile (Palmer)", + "Antarctica\/Rothera": "Hora de Rothera (Rothera)", + "Antarctica\/Syowa": "Hora de Syowa (Syowa)", + "Antarctica\/Troll": "Hora de Greenwich (Troll)", + "Antarctica\/Vostok": "Hora de Vostok (Vostok)", + "Arctic\/Longyearbyen": "Hora da Europa Central (Longyearbyen)", + "Asia\/Aden": "Hora da Arábia (Aden)", + "Asia\/Almaty": "Hora do Cazaquistão Oriental (Almaty)", + "Asia\/Amman": "Hora da Europa Oriental (Amman)", + "Asia\/Anadyr": "Hora de Anadyr (Anadyr)", + "Asia\/Aqtau": "Hora do Cazaquistão Ocidental (Aqtau)", + "Asia\/Aqtobe": "Hora do Cazaquistão Ocidental (Aqtobe)", + "Asia\/Ashgabat": "Hora do Turquemenistão (Ashgabat)", + "Asia\/Atyrau": "Hora do Cazaquistão Ocidental (Atyrau)", + "Asia\/Baghdad": "Hora da Arábia (Bagdade)", + "Asia\/Bahrain": "Hora da Arábia (Barém)", + "Asia\/Baku": "Hora do Azerbaijão (Baku)", + "Asia\/Bangkok": "Hora da Indochina (Banguecoque)", + "Asia\/Beirut": "Hora da Europa Oriental (Beirut)", + "Asia\/Bishkek": "Hora do Quirguistão (Bishkek)", + "Asia\/Brunei": "Hora do Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Hora padrão da Índia (Calcutá)", + "Asia\/Chita": "Hora de Yakutsk (Chita)", + "Asia\/Choibalsan": "Hora de Choibalsan (Choibalsan)", + "Asia\/Colombo": "Hora padrão da Índia (Colombo)", + "Asia\/Damascus": "Hora da Europa Oriental (Damascus)", + "Asia\/Dhaka": "Hora do Bangladeche (Daca)", + "Asia\/Dili": "Hora de Timor Leste (Dili)", + "Asia\/Dubai": "Hora padrão do Golfo (Dubai)", + "Asia\/Dushanbe": "Hora do Tajiquistão (Dushanbe)", + "Asia\/Famagusta": "Hora da Europa Oriental (Famagusta)", + "Asia\/Gaza": "Hora da Europa Oriental (Gaza)", + "Asia\/Hebron": "Hora da Europa Oriental (Hebron)", + "Asia\/Hong_Kong": "Hora de Hong Kong (Hong Kong)", + "Asia\/Hovd": "Hora de Hovd (Hovd)", + "Asia\/Irkutsk": "Hora de Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Hora da Indonésia Ocidental (Jakarta)", + "Asia\/Jayapura": "Hora da Indonésia Oriental (Jayapura)", + "Asia\/Jerusalem": "Hora de Israel (Jerusalem)", + "Asia\/Kabul": "Hora do Afeganistão (Cabul)", + "Asia\/Kamchatka": "Hora de Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Hora do Paquistão (Karachi)", + "Asia\/Katmandu": "Hora do Nepal (Kathmandu)", + "Asia\/Khandyga": "Hora de Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Hora de Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Hora da Malásia (Kuala Lumpur)", + "Asia\/Kuching": "Hora da Malásia (Kuching)", + "Asia\/Kuwait": "Hora da Arábia (Koweit)", + "Asia\/Macau": "Hora da China (Macao)", + "Asia\/Magadan": "Hora de Magadan (Magadan)", + "Asia\/Makassar": "Hora da Indonésia Central (Macassar)", + "Asia\/Manila": "Hora das Filipinas (Manila)", + "Asia\/Muscat": "Hora padrão do Golfo (Muscat)", + "Asia\/Nicosia": "Hora da Europa Oriental (Nicosia)", + "Asia\/Novokuznetsk": "Hora de Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Hora de Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Hora de Omsk (Omsk)", + "Asia\/Oral": "Hora do Cazaquistão Ocidental (Oral)", + "Asia\/Phnom_Penh": "Hora da Indochina (Phnom Penh)", + "Asia\/Pontianak": "Hora da Indonésia Ocidental (Pontianak)", + "Asia\/Pyongyang": "Hora da Coreia (Pyongyang)", + "Asia\/Qatar": "Hora da Arábia (Catar)", + "Asia\/Qostanay": "Hora do Cazaquistão Oriental (Qostanay)", + "Asia\/Qyzylorda": "Hora do Cazaquistão Ocidental (Qyzylorda)", + "Asia\/Rangoon": "Hora de Mianmar (Yangon)", + "Asia\/Riyadh": "Hora da Arábia (Riyadh)", + "Asia\/Saigon": "Hora da Indochina (Cidade de Ho Chi Minh)", + "Asia\/Sakhalin": "Hora de Sacalina (Sakhalin)", + "Asia\/Samarkand": "Hora do Uzbequistão (Samarkand)", + "Asia\/Seoul": "Hora da Coreia (Seoul)", + "Asia\/Shanghai": "Hora da China (Shanghai)", + "Asia\/Singapore": "Hora padrão de Singapura (Singapura)", + "Asia\/Srednekolymsk": "Hora de Magadan (Srednekolymsk)", + "Asia\/Taipei": "Hora de Taipé (Taipé)", + "Asia\/Tashkent": "Hora do Uzbequistão (Tashkent)", + "Asia\/Tbilisi": "Hora da Geórgia (Tbilisi)", + "Asia\/Tehran": "Hora do Irão (Teerão)", + "Asia\/Thimphu": "Hora do Butão (Thimphu)", + "Asia\/Tokyo": "Hora do Japão (Tokyo)", + "Asia\/Ulaanbaatar": "Hora de Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Hora de Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Hora da Indochina (Vientiane)", + "Asia\/Vladivostok": "Hora de Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Hora de Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Hora de Ecaterimburgo (Yekaterinburg)", + "Asia\/Yerevan": "Hora da Arménia (Erevan)", + "Atlantic\/Azores": "Hora dos Açores (Azores)", + "Atlantic\/Bermuda": "Hora do Atlântico (Bermuda)", + "Atlantic\/Canary": "Hora da Europa Ocidental (Canary)", + "Atlantic\/Cape_Verde": "Hora de Cabo Verde (Cape Verde)", + "Atlantic\/Faeroe": "Hora da Europa Ocidental (Faroé)", + "Atlantic\/Madeira": "Hora da Europa Ocidental (Madeira)", + "Atlantic\/Reykjavik": "Hora de Greenwich (Reiquiavique)", + "Atlantic\/South_Georgia": "Hora da Geórgia do Sul (South Georgia)", + "Atlantic\/St_Helena": "Hora de Greenwich (St. Helena)", + "Atlantic\/Stanley": "Hora das Ilhas Falkland (Stanley)", + "Australia\/Adelaide": "Hora da Austrália Central (Adelaide)", + "Australia\/Brisbane": "Hora da Austrália Oriental (Brisbane)", + "Australia\/Broken_Hill": "Hora da Austrália Central (Broken Hill)", + "Australia\/Currie": "Hora da Austrália Oriental (Currie)", + "Australia\/Darwin": "Hora da Austrália Central (Darwin)", + "Australia\/Eucla": "Hora da Austrália Central Ocidental (Eucla)", + "Australia\/Hobart": "Hora da Austrália Oriental (Hobart)", + "Australia\/Lindeman": "Hora da Austrália Oriental (Lindeman)", + "Australia\/Lord_Howe": "Hora de Lord Howe (Ilha de Lord Howe)", + "Australia\/Melbourne": "Hora da Austrália Oriental (Melbourne)", + "Australia\/Perth": "Hora da Austrália Ocidental (Perth)", + "Australia\/Sydney": "Hora da Austrália Oriental (Sydney)", + "CST6CDT": "Hora Central", + "EST5EDT": "Hora Oriental", + "Etc\/GMT": "Hora de Greenwich", + "Etc\/UTC": "Hora Coordenada Universal", + "Europe\/Amsterdam": "Hora da Europa Central (Amesterdão)", + "Europe\/Andorra": "Hora da Europa Central (Andorra)", + "Europe\/Astrakhan": "Hora de Moscovo (Astrakhan)", + "Europe\/Athens": "Hora da Europa Oriental (Athens)", + "Europe\/Belgrade": "Hora da Europa Central (Belgrade)", + "Europe\/Berlin": "Hora da Europa Central (Berlin)", + "Europe\/Bratislava": "Hora da Europa Central (Bratislava)", + "Europe\/Brussels": "Hora da Europa Central (Brussels)", + "Europe\/Bucharest": "Hora da Europa Oriental (Bucharest)", + "Europe\/Budapest": "Hora da Europa Central (Budapest)", + "Europe\/Busingen": "Hora da Europa Central (Busingen)", + "Europe\/Chisinau": "Hora da Europa Oriental (Chisinau)", + "Europe\/Copenhagen": "Hora da Europa Central (Copenhaga)", + "Europe\/Dublin": "Hora de Greenwich (Dublin)", + "Europe\/Gibraltar": "Hora da Europa Central (Gibraltar)", + "Europe\/Guernsey": "Hora de Greenwich (Guernsey)", + "Europe\/Helsinki": "Hora da Europa Oriental (Helsínquia)", + "Europe\/Isle_of_Man": "Hora de Greenwich (Isle of Man)", + "Europe\/Jersey": "Hora de Greenwich (Jersey)", + "Europe\/Kaliningrad": "Hora da Europa Oriental (Caliningrado)", + "Europe\/Kiev": "Hora da Europa Oriental (Kiev)", + "Europe\/Lisbon": "Hora da Europa Ocidental (Lisbon)", + "Europe\/Ljubljana": "Hora da Europa Central (Ljubljana)", + "Europe\/London": "Hora de Greenwich (London)", + "Europe\/Luxembourg": "Hora da Europa Central (Luxembourg)", + "Europe\/Madrid": "Hora da Europa Central (Madrid)", + "Europe\/Malta": "Hora da Europa Central (Malta)", + "Europe\/Mariehamn": "Hora da Europa Oriental (Mariehamn)", + "Europe\/Minsk": "Hora de Moscovo (Minsk)", + "Europe\/Monaco": "Hora da Europa Central (Mónaco)", + "Europe\/Moscow": "Hora de Moscovo (Moscovo)", + "Europe\/Oslo": "Hora da Europa Central (Oslo)", + "Europe\/Paris": "Hora da Europa Central (Paris)", + "Europe\/Podgorica": "Hora da Europa Central (Podgorica)", + "Europe\/Prague": "Hora da Europa Central (Prague)", + "Europe\/Riga": "Hora da Europa Oriental (Riga)", + "Europe\/Rome": "Hora da Europa Central (Rome)", + "Europe\/Samara": "Hora de Samara (Samara)", + "Europe\/San_Marino": "Hora da Europa Central (São Marinho)", + "Europe\/Sarajevo": "Hora da Europa Central (Sarajevo)", + "Europe\/Saratov": "Hora de Moscovo (Saratov)", + "Europe\/Simferopol": "Hora de Moscovo (Simferopol)", + "Europe\/Skopje": "Hora da Europa Central (Skopje)", + "Europe\/Sofia": "Hora da Europa Oriental (Sofia)", + "Europe\/Stockholm": "Hora da Europa Central (Stockholm)", + "Europe\/Tallinn": "Hora da Europa Oriental (Tallinn)", + "Europe\/Tirane": "Hora da Europa Central (Tirane)", + "Europe\/Ulyanovsk": "Hora de Moscovo (Ulyanovsk)", + "Europe\/Uzhgorod": "Hora da Europa Oriental (Uzhgorod)", + "Europe\/Vaduz": "Hora da Europa Central (Vaduz)", + "Europe\/Vatican": "Hora da Europa Central (Vatican)", + "Europe\/Vienna": "Hora da Europa Central (Vienna)", + "Europe\/Vilnius": "Hora da Europa Oriental (Vilnius)", + "Europe\/Volgograd": "Hora de Volgogrado (Volgograd)", + "Europe\/Warsaw": "Hora da Europa Central (Warsaw)", + "Europe\/Zagreb": "Hora da Europa Central (Zagreb)", + "Europe\/Zaporozhye": "Hora da Europa Oriental (Zaporozhye)", + "Europe\/Zurich": "Hora da Europa Central (Zurich)", + "Indian\/Antananarivo": "Hora da África Oriental (Antananarivo)", + "Indian\/Chagos": "Hora do Oceano Índico (Chagos)", + "Indian\/Christmas": "Hora da Ilha do Natal (Ilha do Natal)", + "Indian\/Cocos": "Hora das Ilhas Cocos (Ilhas Cocos)", + "Indian\/Comoro": "Hora da África Oriental (Comoro)", + "Indian\/Kerguelen": "Hora das Terras Austrais e Antárcticas Francesas (Kerguelen)", + "Indian\/Mahe": "Hora das Seicheles (Mahe)", + "Indian\/Maldives": "Hora das Maldivas (Maldives)", + "Indian\/Mauritius": "Hora da Maurícia (Maurícia)", + "Indian\/Mayotte": "Hora da África Oriental (Mayotte)", + "Indian\/Reunion": "Hora de Reunião (Reunion)", + "MST7MDT": "Hora da Montanha", + "PST8PDT": "Hora do Pacífico", + "Pacific\/Apia": "Hora de Apia (Apia)", + "Pacific\/Auckland": "Hora da Nova Zelândia (Auckland)", + "Pacific\/Bougainville": "Hora de Papua Nova Guiné (Bougainville)", + "Pacific\/Chatham": "Hora de Chatham (Chatham)", + "Pacific\/Easter": "Hora da Ilha da Páscoa (Ilha da Páscoa)", + "Pacific\/Efate": "Hora do Vanuatu (Efate)", + "Pacific\/Enderbury": "Hora das Ilhas Fénix (Enderbury)", + "Pacific\/Fakaofo": "Hora de Tokelau (Fakaofo)", + "Pacific\/Fiji": "Hora de Fiji (Fiji)", + "Pacific\/Funafuti": "Hora de Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Hora das Galápagos (Galapagos)", + "Pacific\/Gambier": "Hora de Gambier (Gambier)", + "Pacific\/Guadalcanal": "Hora das Ilhas Salomão (Guadalcanal)", + "Pacific\/Guam": "Hora padrão de Chamorro (Guam)", + "Pacific\/Honolulu": "Hora do Havai e Aleutas (Honolulu)", + "Pacific\/Johnston": "Hora do Havai e Aleutas (Johnston)", + "Pacific\/Kiritimati": "Hora das Ilhas Line (Kiritimati)", + "Pacific\/Kosrae": "Hora de Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Hora das Ilhas Marshall (Kwajalein)", + "Pacific\/Majuro": "Hora das Ilhas Marshall (Majuro)", + "Pacific\/Marquesas": "Hora das Ilhas Marquesas (Marquesas)", + "Pacific\/Midway": "Hora de Samoa (Midway)", + "Pacific\/Nauru": "Hora de Nauru (Nauru)", + "Pacific\/Niue": "Hora de Niuê (Niue)", + "Pacific\/Norfolk": "Hora da Ilha Norfolk (Norfolk)", + "Pacific\/Noumea": "Hora da Nova Caledónia (Noumea)", + "Pacific\/Pago_Pago": "Hora de Samoa (Pago Pago)", + "Pacific\/Palau": "Hora de Palau (Palau)", + "Pacific\/Pitcairn": "Hora de Pitcairn (Ilhas Pitcairn)", + "Pacific\/Ponape": "Hora de Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Hora de Papua Nova Guiné (Port Moresby)", + "Pacific\/Rarotonga": "Hora das Ilhas Cook (Rarotonga)", + "Pacific\/Saipan": "Hora padrão de Chamorro (Saipan)", + "Pacific\/Tahiti": "Hora do Taiti (Tahiti)", + "Pacific\/Tarawa": "Hora das Ilhas Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Hora de Tonga (Tongatapu)", + "Pacific\/Truk": "Hora de Chuuk (Chuuk)", + "Pacific\/Wake": "Hora da Ilha Wake (Wake)", + "Pacific\/Wallis": "Hora de Wallis e Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_ST.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_ST.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_ST.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/pt_TL.json b/src/Symfony/Component/Intl/Resources/data/timezones/pt_TL.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/pt_TL.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/qu.json b/src/Symfony/Component/Intl/Resources/data/timezones/qu.json new file mode 100644 index 0000000000000..cedd0bc2d7112 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/qu.json @@ -0,0 +1,83 @@ +{ + "Version": "2.1.47.82", + "Names": { + "America\/Argentina\/La_Rioja": "Argentina Time (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentina Time (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentina Time (Salta)", + "America\/Argentina\/San_Juan": "Argentina Time (San Juan)", + "America\/Argentina\/Tucuman": "Argentina Time (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentina Time (Ushuaia)", + "America\/Asuncion": "Paraguay Time (Asuncion)", + "America\/Bogota": "Colombia Time (Bogota)", + "America\/Buenos_Aires": "Argentina Time (Buenos Aires)", + "America\/Catamarca": "Argentina Time (Catamarca)", + "America\/Cayenne": "French Guiana Time (Cayenne)", + "America\/Cordoba": "Argentina Time (Cordoba)", + "America\/Guayaquil": "Ecuador Time (Guayaquil)", + "America\/Havana": "Cuba Time (Havana)", + "America\/Jujuy": "Argentina Time (Jujuy)", + "America\/La_Paz": "Bolivia Time (La Paz)", + "America\/Mendoza": "Argentina Time (Mendoza)", + "America\/Punta_Arenas": "Chile Time (Punta Arenas)", + "America\/Santiago": "Chile Time (Santiago)", + "America\/Scoresbysund": "East Greenland Time (Ittoqqortoormiit)", + "Antarctica\/McMurdo": "New Zealand Time (McMurdo)", + "Antarctica\/Palmer": "Chile Time (Palmer)", + "Asia\/Almaty": "East Kazakhstan Time (Almaty)", + "Asia\/Aqtau": "West Kazakhstan Time (Aqtau)", + "Asia\/Aqtobe": "West Kazakhstan Time (Aqtobe)", + "Asia\/Ashgabat": "Turkmenistan Time (Ashgabat)", + "Asia\/Atyrau": "West Kazakhstan Time (Atyrau)", + "Asia\/Baku": "Azerbaijan Time (Baku)", + "Asia\/Brunei": "Brunei Darussalam Time (Brunei)", + "Asia\/Calcutta": "India Standard Time (Kolkata)", + "Asia\/Colombo": "India Standard Time (Colombo)", + "Asia\/Dhaka": "Bangladesh Time (Dhaka)", + "Asia\/Dushanbe": "Tajikistan Time (Dushanbe)", + "Asia\/Hong_Kong": "Hong Kong Time (Hong Kong)", + "Asia\/Jayapura": "Eastern Indonesia Time (Jayapura)", + "Asia\/Jerusalem": "Israel Time (Jerusalem)", + "Asia\/Kabul": "Afghanistan Time (Kabul)", + "Asia\/Karachi": "Pakistan Time (Karachi)", + "Asia\/Katmandu": "Nepal Time (Kathmandu)", + "Asia\/Kuala_Lumpur": "Malaysia Time (Kuala Lumpur)", + "Asia\/Kuching": "Malaysia Time (Kuching)", + "Asia\/Macau": "China Time (Macau)", + "Asia\/Makassar": "Central Indonesia Time (Makassar)", + "Asia\/Oral": "West Kazakhstan Time (Oral)", + "Asia\/Qostanay": "East Kazakhstan Time (Qostanay)", + "Asia\/Qyzylorda": "West Kazakhstan Time (Qyzylorda)", + "Asia\/Rangoon": "Myanmar Time (Rangoon)", + "Asia\/Samarkand": "Uzbekistan Time (Samarkand)", + "Asia\/Shanghai": "China Time (Shanghai)", + "Asia\/Singapore": "Singapore Standard Time (Singapore)", + "Asia\/Tashkent": "Uzbekistan Time (Tashkent)", + "Asia\/Tbilisi": "Georgia Time (Tbilisi)", + "Asia\/Tehran": "Iran Time (Tehran)", + "Asia\/Thimphu": "Bhutan Time (Thimphu)", + "Asia\/Tokyo": "Japan Time (Tokyo)", + "Asia\/Yerevan": "Armenia Time (Yerevan)", + "Atlantic\/Stanley": "Falkland Islands Time (Stanley)", + "Indian\/Mahe": "Seychelles Time (Mahe)", + "Indian\/Maldives": "Maldives Time (Maldives)", + "Indian\/Mauritius": "Mauritius Time (Mauritius)", + "Indian\/Reunion": "Reunion Time (Reunion)", + "Pacific\/Auckland": "New Zealand Time (Auckland)", + "Pacific\/Bougainville": "Papua New Guinea Time (Bougainville)", + "Pacific\/Efate": "Vanuatu Time (Efate)", + "Pacific\/Fakaofo": "Tokelau Time (Fakaofo)", + "Pacific\/Fiji": "Fiji Time (Fiji)", + "Pacific\/Funafuti": "Tuvalu Time (Funafuti)", + "Pacific\/Guadalcanal": "Solomon Islands Time (Guadalcanal)", + "Pacific\/Midway": "Samoa Time (Midway)", + "Pacific\/Nauru": "Nauru Time (Nauru)", + "Pacific\/Niue": "Niue Time (Niue)", + "Pacific\/Noumea": "New Caledonia Time (Noumea)", + "Pacific\/Pago_Pago": "Samoa Time (Pago Pago)", + "Pacific\/Palau": "Palau Time (Palau)", + "Pacific\/Port_Moresby": "Papua New Guinea Time (Port Moresby)", + "Pacific\/Rarotonga": "Cook Islands Time (Rarotonga)", + "Pacific\/Tongatapu": "Tonga Time (Tongatapu)", + "Pacific\/Wallis": "Wallis & Futuna Time (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/qu_BO.json b/src/Symfony/Component/Intl/Resources/data/timezones/qu_BO.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/qu_BO.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/qu_EC.json b/src/Symfony/Component/Intl/Resources/data/timezones/qu_EC.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/qu_EC.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/rm.json b/src/Symfony/Component/Intl/Resources/data/timezones/rm.json new file mode 100644 index 0000000000000..dfccb080ad6ae --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/rm.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.48.4", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ro.json b/src/Symfony/Component/Intl/Resources/data/timezones/ro.json new file mode 100644 index 0000000000000..be228ce8d967d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ro.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.20", + "Names": { + "Africa\/Abidjan": "Ora de Greenwhich (Abidjan)", + "Africa\/Accra": "Ora de Greenwhich (Accra)", + "Africa\/Addis_Ababa": "Ora Africii Orientale (Addis Abeba)", + "Africa\/Algiers": "Ora Europei Centrale (Alger)", + "Africa\/Asmera": "Ora Africii Orientale (Asmara)", + "Africa\/Bamako": "Ora de Greenwhich (Bamako)", + "Africa\/Bangui": "Ora Africii Occidentale (Bangui)", + "Africa\/Banjul": "Ora de Greenwhich (Banjul)", + "Africa\/Bissau": "Ora de Greenwhich (Bissau)", + "Africa\/Blantyre": "Ora Africii Centrale (Blantyre)", + "Africa\/Brazzaville": "Ora Africii Occidentale (Brazzaville)", + "Africa\/Bujumbura": "Ora Africii Centrale (Bujumbura)", + "Africa\/Cairo": "Ora Europei de Est (Cairo)", + "Africa\/Casablanca": "Ora Europei de Vest (Casablanca)", + "Africa\/Ceuta": "Ora Europei Centrale (Ceuta)", + "Africa\/Conakry": "Ora de Greenwhich (Conakry)", + "Africa\/Dakar": "Ora de Greenwhich (Dakar)", + "Africa\/Dar_es_Salaam": "Ora Africii Orientale (Dar es Salaam)", + "Africa\/Djibouti": "Ora Africii Orientale (Djibouti)", + "Africa\/Douala": "Ora Africii Occidentale (Douala)", + "Africa\/El_Aaiun": "Ora Europei de Vest (El Aaiun)", + "Africa\/Freetown": "Ora de Greenwhich (Freetown)", + "Africa\/Gaborone": "Ora Africii Centrale (Gaborone)", + "Africa\/Harare": "Ora Africii Centrale (Harare)", + "Africa\/Johannesburg": "Ora Africii Meridionale (Johannesburg)", + "Africa\/Juba": "Ora Africii Orientale (Juba)", + "Africa\/Kampala": "Ora Africii Orientale (Kampala)", + "Africa\/Khartoum": "Ora Africii Centrale (Khartoum)", + "Africa\/Kigali": "Ora Africii Centrale (Kigali)", + "Africa\/Kinshasa": "Ora Africii Occidentale (Kinshasa)", + "Africa\/Lagos": "Ora Africii Occidentale (Lagos)", + "Africa\/Libreville": "Ora Africii Occidentale (Libreville)", + "Africa\/Lome": "Ora de Greenwhich (Lome)", + "Africa\/Luanda": "Ora Africii Occidentale (Luanda)", + "Africa\/Lubumbashi": "Ora Africii Centrale (Lubumbashi)", + "Africa\/Lusaka": "Ora Africii Centrale (Lusaka)", + "Africa\/Malabo": "Ora Africii Occidentale (Malabo)", + "Africa\/Maputo": "Ora Africii Centrale (Maputo)", + "Africa\/Maseru": "Ora Africii Meridionale (Maseru)", + "Africa\/Mbabane": "Ora Africii Meridionale (Mbabane)", + "Africa\/Mogadishu": "Ora Africii Orientale (Mogadiscio)", + "Africa\/Monrovia": "Ora de Greenwhich (Monrovia)", + "Africa\/Nairobi": "Ora Africii Orientale (Nairobi)", + "Africa\/Ndjamena": "Ora Africii Occidentale (N’Djamena)", + "Africa\/Niamey": "Ora Africii Occidentale (Niamey)", + "Africa\/Nouakchott": "Ora de Greenwhich (Nouakchott)", + "Africa\/Ouagadougou": "Ora de Greenwhich (Ouagadougou)", + "Africa\/Porto-Novo": "Ora Africii Occidentale (Porto-Novo)", + "Africa\/Sao_Tome": "Ora de Greenwhich (Sao Tomé)", + "Africa\/Tripoli": "Ora Europei de Est (Tripoli)", + "Africa\/Tunis": "Ora Europei Centrale (Tunis)", + "Africa\/Windhoek": "Ora Africii Centrale (Windhoek)", + "America\/Adak": "Ora din Hawaii-Aleutine (Adak)", + "America\/Anchorage": "Ora din Alaska (Anchorage)", + "America\/Anguilla": "Ora zonei Atlantic nord-americane (Anguilla)", + "America\/Antigua": "Ora zonei Atlantic nord-americane (Antigua)", + "America\/Araguaina": "Ora Brasiliei (Araguaina)", + "America\/Argentina\/La_Rioja": "Ora Argentinei (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Ora Argentinei (Rio Gallegos)", + "America\/Argentina\/Salta": "Ora Argentinei (Salta)", + "America\/Argentina\/San_Juan": "Ora Argentinei (San Juan)", + "America\/Argentina\/San_Luis": "Ora Argentinei Occidentale (San Luis)", + "America\/Argentina\/Tucuman": "Ora Argentinei (Tucuman)", + "America\/Argentina\/Ushuaia": "Ora Argentinei (Ushuaia)", + "America\/Aruba": "Ora zonei Atlantic nord-americane (Aruba)", + "America\/Asuncion": "Ora din Paraguay (Asunción)", + "America\/Bahia": "Ora Brasiliei (Bahia)", + "America\/Bahia_Banderas": "Ora centrală nord-americană (Bahia Banderas)", + "America\/Barbados": "Ora zonei Atlantic nord-americane (Barbados)", + "America\/Belem": "Ora Brasiliei (Belem)", + "America\/Belize": "Ora centrală nord-americană (Belize)", + "America\/Blanc-Sablon": "Ora zonei Atlantic nord-americane (Blanc-Sablon)", + "America\/Boa_Vista": "Ora Amazonului (Boa Vista)", + "America\/Bogota": "Ora Columbiei (Bogota)", + "America\/Boise": "Ora zonei montane nord-americane (Boise)", + "America\/Buenos_Aires": "Ora Argentinei (Buenos Aires)", + "America\/Cambridge_Bay": "Ora zonei montane nord-americane (Cambridge Bay)", + "America\/Campo_Grande": "Ora Amazonului (Campo Grande)", + "America\/Cancun": "Ora orientală nord-americană (Cancun)", + "America\/Caracas": "Ora Venezuelei (Caracas)", + "America\/Catamarca": "Ora Argentinei (Catamarca)", + "America\/Cayenne": "Ora din Guyana Franceză (Cayenne)", + "America\/Cayman": "Ora orientală nord-americană (Cayman)", + "America\/Chicago": "Ora centrală nord-americană (Chicago)", + "America\/Chihuahua": "Ora zonei Pacific mexicane (Chihuahua)", + "America\/Coral_Harbour": "Ora orientală nord-americană (Atikokan)", + "America\/Cordoba": "Ora Argentinei (Cordoba)", + "America\/Costa_Rica": "Ora centrală nord-americană (Costa Rica)", + "America\/Creston": "Ora zonei montane nord-americane (Creston)", + "America\/Cuiaba": "Ora Amazonului (Cuiaba)", + "America\/Curacao": "Ora zonei Atlantic nord-americane (Curaçao)", + "America\/Danmarkshavn": "Ora de Greenwhich (Danmarkshavn)", + "America\/Dawson": "Ora zonei Pacific nord-americane (Dawson)", + "America\/Dawson_Creek": "Ora zonei montane nord-americane (Dawson Creek)", + "America\/Denver": "Ora zonei montane nord-americane (Denver)", + "America\/Detroit": "Ora orientală nord-americană (Detroit)", + "America\/Dominica": "Ora zonei Atlantic nord-americane (Dominica)", + "America\/Edmonton": "Ora zonei montane nord-americane (Edmonton)", + "America\/Eirunepe": "Ora Acre (Eirunepe)", + "America\/El_Salvador": "Ora centrală nord-americană (El Salvador)", + "America\/Fort_Nelson": "Ora zonei montane nord-americane (Fort Nelson)", + "America\/Fortaleza": "Ora Brasiliei (Fortaleza)", + "America\/Glace_Bay": "Ora zonei Atlantic nord-americane (Glace Bay)", + "America\/Godthab": "Ora Groenlandei occidentale (Nuuk)", + "America\/Goose_Bay": "Ora zonei Atlantic nord-americane (Goose Bay)", + "America\/Grand_Turk": "Ora orientală nord-americană (Grand Turk)", + "America\/Grenada": "Ora zonei Atlantic nord-americane (Grenada)", + "America\/Guadeloupe": "Ora zonei Atlantic nord-americane (Guadelupa)", + "America\/Guatemala": "Ora centrală nord-americană (Guatemala)", + "America\/Guayaquil": "Ora Ecuadorului (Guayaquil)", + "America\/Guyana": "Ora din Guyana (Guyana)", + "America\/Halifax": "Ora zonei Atlantic nord-americane (Halifax)", + "America\/Havana": "Ora Cubei (Havana)", + "America\/Hermosillo": "Ora zonei Pacific mexicane (Hermosillo)", + "America\/Indiana\/Knox": "Ora centrală nord-americană (Knox, Indiana)", + "America\/Indiana\/Marengo": "Ora orientală nord-americană (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Ora orientală nord-americană (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Ora centrală nord-americană (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Ora orientală nord-americană (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Ora orientală nord-americană (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Ora orientală nord-americană (Winamac, Indiana)", + "America\/Indianapolis": "Ora orientală nord-americană (Indianapolis)", + "America\/Inuvik": "Ora zonei montane nord-americane (Inuvik)", + "America\/Iqaluit": "Ora orientală nord-americană (Iqaluit)", + "America\/Jamaica": "Ora orientală nord-americană (Jamaica)", + "America\/Jujuy": "Ora Argentinei (Jujuy)", + "America\/Juneau": "Ora din Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Ora orientală nord-americană (Monticello, Kentucky)", + "America\/Kralendijk": "Ora zonei Atlantic nord-americane (Kralendijk)", + "America\/La_Paz": "Ora Boliviei (La Paz)", + "America\/Lima": "Ora din Peru (Lima)", + "America\/Los_Angeles": "Ora zonei Pacific nord-americane (Los Angeles)", + "America\/Louisville": "Ora orientală nord-americană (Louisville)", + "America\/Lower_Princes": "Ora zonei Atlantic nord-americane (Lower Prince’s Quarter)", + "America\/Maceio": "Ora Brasiliei (Maceio)", + "America\/Managua": "Ora centrală nord-americană (Managua)", + "America\/Manaus": "Ora Amazonului (Manaus)", + "America\/Marigot": "Ora zonei Atlantic nord-americane (Marigot)", + "America\/Martinique": "Ora zonei Atlantic nord-americane (Martinica)", + "America\/Matamoros": "Ora centrală nord-americană (Matamoros)", + "America\/Mazatlan": "Ora zonei Pacific mexicane (Mazatlan)", + "America\/Mendoza": "Ora Argentinei (Mendoza)", + "America\/Menominee": "Ora centrală nord-americană (Menominee)", + "America\/Merida": "Ora centrală nord-americană (Merida)", + "America\/Metlakatla": "Ora din Alaska (Metlakatla)", + "America\/Mexico_City": "Ora centrală nord-americană (Ciudad de Mexico)", + "America\/Miquelon": "Ora din Saint-Pierre și Miquelon (Miquelon)", + "America\/Moncton": "Ora zonei Atlantic nord-americane (Moncton)", + "America\/Monterrey": "Ora centrală nord-americană (Monterrey)", + "America\/Montevideo": "Ora Uruguayului (Montevideo)", + "America\/Montserrat": "Ora zonei Atlantic nord-americane (Montserrat)", + "America\/Nassau": "Ora orientală nord-americană (Nassau)", + "America\/New_York": "Ora orientală nord-americană (New York)", + "America\/Nipigon": "Ora orientală nord-americană (Nipigon)", + "America\/Nome": "Ora din Alaska (Nome)", + "America\/Noronha": "Ora din Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Ora centrală nord-americană (Beulah, Dakota de Nord)", + "America\/North_Dakota\/Center": "Ora centrală nord-americană (Center, Dakota de Nord)", + "America\/North_Dakota\/New_Salem": "Ora centrală nord-americană (New Salem, Dakota de Nord)", + "America\/Ojinaga": "Ora zonei montane nord-americane (Ojinaga)", + "America\/Panama": "Ora orientală nord-americană (Panama)", + "America\/Pangnirtung": "Ora orientală nord-americană (Pangnirtung)", + "America\/Paramaribo": "Ora Surinamului (Paramaribo)", + "America\/Phoenix": "Ora zonei montane nord-americane (Phoenix)", + "America\/Port-au-Prince": "Ora orientală nord-americană (Port-au-Prince)", + "America\/Port_of_Spain": "Ora zonei Atlantic nord-americane (Port of Spain)", + "America\/Porto_Velho": "Ora Amazonului (Porto Velho)", + "America\/Puerto_Rico": "Ora zonei Atlantic nord-americane (Puerto Rico)", + "America\/Punta_Arenas": "Ora din Chile (Punta Arenas)", + "America\/Rainy_River": "Ora centrală nord-americană (Rainy River)", + "America\/Rankin_Inlet": "Ora centrală nord-americană (Rankin Inlet)", + "America\/Recife": "Ora Brasiliei (Recife)", + "America\/Regina": "Ora centrală nord-americană (Regina)", + "America\/Resolute": "Ora centrală nord-americană (Resolute)", + "America\/Rio_Branco": "Ora Acre (Rio Branco)", + "America\/Santa_Isabel": "Ora Mexicului de nord-vest (Santa Isabel)", + "America\/Santarem": "Ora Brasiliei (Santarem)", + "America\/Santiago": "Ora din Chile (Santiago)", + "America\/Santo_Domingo": "Ora zonei Atlantic nord-americane (Santo Domingo)", + "America\/Sao_Paulo": "Ora Brasiliei (Sao Paulo)", + "America\/Scoresbysund": "Ora Groenlandei orientale (Ittoqqortoormiit)", + "America\/Sitka": "Ora din Alaska (Sitka)", + "America\/St_Barthelemy": "Ora zonei Atlantic nord-americane (Saint Barthélemy)", + "America\/St_Johns": "Ora din Newfoundland (St. John’s)", + "America\/St_Kitts": "Ora zonei Atlantic nord-americane (St. Kitts)", + "America\/St_Lucia": "Ora zonei Atlantic nord-americane (St. Lucia)", + "America\/St_Thomas": "Ora zonei Atlantic nord-americane (St. Thomas)", + "America\/St_Vincent": "Ora zonei Atlantic nord-americane (St. Vincent)", + "America\/Swift_Current": "Ora centrală nord-americană (Swift Current)", + "America\/Tegucigalpa": "Ora centrală nord-americană (Tegucigalpa)", + "America\/Thule": "Ora zonei Atlantic nord-americane (Thule)", + "America\/Thunder_Bay": "Ora orientală nord-americană (Thunder Bay)", + "America\/Tijuana": "Ora zonei Pacific nord-americane (Tijuana)", + "America\/Toronto": "Ora orientală nord-americană (Toronto)", + "America\/Tortola": "Ora zonei Atlantic nord-americane (Tortola)", + "America\/Vancouver": "Ora zonei Pacific nord-americane (Vancouver)", + "America\/Whitehorse": "Ora zonei Pacific nord-americane (Whitehorse)", + "America\/Winnipeg": "Ora centrală nord-americană (Winnipeg)", + "America\/Yakutat": "Ora din Alaska (Yakutat)", + "America\/Yellowknife": "Ora zonei montane nord-americane (Yellowknife)", + "Antarctica\/Casey": "Ora Australiei Occidentale (Casey)", + "Antarctica\/Davis": "Ora din Davis (Davis)", + "Antarctica\/DumontDUrville": "Ora din Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Ora din Macquarie (Macquarie)", + "Antarctica\/Mawson": "Ora din Mawson (Mawson)", + "Antarctica\/McMurdo": "Ora Noii Zeelande (McMurdo)", + "Antarctica\/Palmer": "Ora din Chile (Palmer)", + "Antarctica\/Rothera": "Ora din Rothera (Rothera)", + "Antarctica\/Syowa": "Ora din Syowa (Showa)", + "Antarctica\/Troll": "Ora de Greenwhich (Troll)", + "Antarctica\/Vostok": "Ora din Vostok (Vostok)", + "Arctic\/Longyearbyen": "Ora Europei Centrale (Longyearbyen)", + "Asia\/Aden": "Ora arabă (Aden)", + "Asia\/Almaty": "Ora din Kazahstanul de Est (Almatî)", + "Asia\/Amman": "Ora Europei de Est (Amman)", + "Asia\/Anadyr": "Ora din Anadyr (Anadir)", + "Asia\/Aqtau": "Ora din Kazahstanul de Vest (Aktau)", + "Asia\/Aqtobe": "Ora din Kazahstanul de Vest (Aktobe)", + "Asia\/Ashgabat": "Ora din Turkmenistan (Așgabat)", + "Asia\/Atyrau": "Ora din Kazahstanul de Vest (Atîrau)", + "Asia\/Baghdad": "Ora arabă (Bagdad)", + "Asia\/Bahrain": "Ora arabă (Bahrain)", + "Asia\/Baku": "Ora Azerbaidjanului (Baku)", + "Asia\/Bangkok": "Ora Indochinei (Bangkok)", + "Asia\/Beirut": "Ora Europei de Est (Beirut)", + "Asia\/Bishkek": "Ora din Kârgâzstan (Bișkek)", + "Asia\/Brunei": "Ora din Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Ora Indiei (Calcutta)", + "Asia\/Chita": "Ora din Iakuțk (Cita)", + "Asia\/Choibalsan": "Ora din Choibalsan (Choibalsan)", + "Asia\/Colombo": "Ora Indiei (Colombo)", + "Asia\/Damascus": "Ora Europei de Est (Damasc)", + "Asia\/Dhaka": "Ora din Bangladesh (Dacca)", + "Asia\/Dili": "Ora Timorului de Est (Dili)", + "Asia\/Dubai": "Ora standard a Golfului (Dubai)", + "Asia\/Dushanbe": "Ora din Tadjikistan (Dușanbe)", + "Asia\/Famagusta": "Ora Europei de Est (Famagusta)", + "Asia\/Gaza": "Ora Europei de Est (Gaza)", + "Asia\/Hebron": "Ora Europei de Est (Hebron)", + "Asia\/Hong_Kong": "Ora din Hong Kong (Hong Kong)", + "Asia\/Hovd": "Ora din Hovd (Hovd)", + "Asia\/Irkutsk": "Ora din Irkuțk (Irkuțk)", + "Asia\/Jakarta": "Ora Indoneziei de Vest (Jakarta)", + "Asia\/Jayapura": "Ora Indoneziei de Est (Jayapura)", + "Asia\/Jerusalem": "Ora Israelului (Ierusalim)", + "Asia\/Kabul": "Ora Afganistanului (Kabul)", + "Asia\/Kamchatka": "Ora din Petropavlovsk-Kamciațki (Kamciatka)", + "Asia\/Karachi": "Ora Pakistanului (Karachi)", + "Asia\/Katmandu": "Ora Nepalului (Kathmandu)", + "Asia\/Khandyga": "Ora din Iakuțk (Khandyga)", + "Asia\/Krasnoyarsk": "Ora din Krasnoiarsk (Krasnoiarsk)", + "Asia\/Kuala_Lumpur": "Ora din Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Ora din Malaysia (Kuching)", + "Asia\/Kuwait": "Ora arabă (Kuweit)", + "Asia\/Macau": "Ora Chinei (Macao)", + "Asia\/Magadan": "Ora din Magadan (Magadan)", + "Asia\/Makassar": "Ora Indoneziei Centrale (Makassar)", + "Asia\/Manila": "Ora din Filipine (Manila)", + "Asia\/Muscat": "Ora standard a Golfului (Muscat)", + "Asia\/Nicosia": "Ora Europei de Est (Nicosia)", + "Asia\/Novokuznetsk": "Ora din Krasnoiarsk (Novokuznețk)", + "Asia\/Novosibirsk": "Ora din Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Ora din Omsk (Omsk)", + "Asia\/Oral": "Ora din Kazahstanul de Vest (Uralsk)", + "Asia\/Phnom_Penh": "Ora Indochinei (Phnom Penh)", + "Asia\/Pontianak": "Ora Indoneziei de Vest (Pontianak)", + "Asia\/Pyongyang": "Ora Coreei (Phenian)", + "Asia\/Qatar": "Ora arabă (Qatar)", + "Asia\/Qostanay": "Ora din Kazahstanul de Est (Kostanay)", + "Asia\/Qyzylorda": "Ora din Kazahstanul de Vest (Kyzylorda)", + "Asia\/Rangoon": "Ora Myanmarului (Yangon)", + "Asia\/Riyadh": "Ora arabă (Riad)", + "Asia\/Saigon": "Ora Indochinei (Ho Și Min)", + "Asia\/Sakhalin": "Ora din Sahalin (Sahalin)", + "Asia\/Samarkand": "Ora din Uzbekistan (Samarkand)", + "Asia\/Seoul": "Ora Coreei (Seoul)", + "Asia\/Shanghai": "Ora Chinei (Shanghai)", + "Asia\/Singapore": "Ora din Singapore (Singapore)", + "Asia\/Srednekolymsk": "Ora din Magadan (Srednekolimsk)", + "Asia\/Taipei": "Ora din Taipei (Taipei)", + "Asia\/Tashkent": "Ora din Uzbekistan (Tașkent)", + "Asia\/Tbilisi": "Ora Georgiei (Tbilisi)", + "Asia\/Tehran": "Ora Iranului (Teheran)", + "Asia\/Thimphu": "Ora Bhutanului (Thimphu)", + "Asia\/Tokyo": "Ora Japoniei (Tokyo)", + "Asia\/Ulaanbaatar": "Ora din Ulan Bator (Ulan Bator)", + "Asia\/Ust-Nera": "Ora din Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Ora Indochinei (Vientiane)", + "Asia\/Vladivostok": "Ora din Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Ora din Iakuțk (Iakuțk)", + "Asia\/Yekaterinburg": "Ora din Ekaterinburg (Ekaterinburg)", + "Asia\/Yerevan": "Ora Armeniei (Erevan)", + "Atlantic\/Azores": "Ora din Azore (Azore)", + "Atlantic\/Bermuda": "Ora zonei Atlantic nord-americane (Bermuda)", + "Atlantic\/Canary": "Ora Europei de Vest (Canare)", + "Atlantic\/Cape_Verde": "Ora din Capul Verde (Capul Verde)", + "Atlantic\/Faeroe": "Ora Europei de Vest (Faroe)", + "Atlantic\/Madeira": "Ora Europei de Vest (Madeira)", + "Atlantic\/Reykjavik": "Ora de Greenwhich (Reykjavik)", + "Atlantic\/South_Georgia": "Ora Georgiei de Sud (Georgia de Sud)", + "Atlantic\/St_Helena": "Ora de Greenwhich (Sf. Elena)", + "Atlantic\/Stanley": "Ora din Insulele Falkland (Stanley)", + "Australia\/Adelaide": "Ora Australiei Centrale (Adelaide)", + "Australia\/Brisbane": "Ora Australiei Orientale (Brisbane)", + "Australia\/Broken_Hill": "Ora Australiei Centrale (Broken Hill)", + "Australia\/Currie": "Ora Australiei Orientale (Currie)", + "Australia\/Darwin": "Ora Australiei Centrale (Darwin)", + "Australia\/Eucla": "Ora Australiei Central Occidentale (Eucla)", + "Australia\/Hobart": "Ora Australiei Orientale (Hobart)", + "Australia\/Lindeman": "Ora Australiei Orientale (Lindeman)", + "Australia\/Lord_Howe": "Ora din Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Ora Australiei Orientale (Melbourne)", + "Australia\/Perth": "Ora Australiei Occidentale (Perth)", + "Australia\/Sydney": "Ora Australiei Orientale (Sydney)", + "CST6CDT": "Ora centrală nord-americană", + "EST5EDT": "Ora orientală nord-americană", + "Etc\/GMT": "Ora de Greenwhich", + "Etc\/UTC": "Timpul universal coordonat", + "Europe\/Amsterdam": "Ora Europei Centrale (Amsterdam)", + "Europe\/Andorra": "Ora Europei Centrale (Andorra)", + "Europe\/Astrakhan": "Ora Moscovei (Astrahan)", + "Europe\/Athens": "Ora Europei de Est (Atena)", + "Europe\/Belgrade": "Ora Europei Centrale (Belgrad)", + "Europe\/Berlin": "Ora Europei Centrale (Berlin)", + "Europe\/Bratislava": "Ora Europei Centrale (Bratislava)", + "Europe\/Brussels": "Ora Europei Centrale (Bruxelles)", + "Europe\/Bucharest": "Ora Europei de Est (București)", + "Europe\/Budapest": "Ora Europei Centrale (Budapesta)", + "Europe\/Busingen": "Ora Europei Centrale (Busingen)", + "Europe\/Chisinau": "Ora Europei de Est (Chișinău)", + "Europe\/Copenhagen": "Ora Europei Centrale (Copenhaga)", + "Europe\/Dublin": "Ora de Greenwhich (Dublin)", + "Europe\/Gibraltar": "Ora Europei Centrale (Gibraltar)", + "Europe\/Guernsey": "Ora de Greenwhich (Guernsey)", + "Europe\/Helsinki": "Ora Europei de Est (Helsinki)", + "Europe\/Isle_of_Man": "Ora de Greenwhich (Insula Man)", + "Europe\/Jersey": "Ora de Greenwhich (Jersey)", + "Europe\/Kaliningrad": "Ora Europei de Est (Kaliningrad)", + "Europe\/Kiev": "Ora Europei de Est (Kiev)", + "Europe\/Lisbon": "Ora Europei de Vest (Lisabona)", + "Europe\/Ljubljana": "Ora Europei Centrale (Ljubljana)", + "Europe\/London": "Ora de Greenwhich (Londra)", + "Europe\/Luxembourg": "Ora Europei Centrale (Luxemburg)", + "Europe\/Madrid": "Ora Europei Centrale (Madrid)", + "Europe\/Malta": "Ora Europei Centrale (Malta)", + "Europe\/Mariehamn": "Ora Europei de Est (Mariehamn)", + "Europe\/Minsk": "Ora Moscovei (Minsk)", + "Europe\/Monaco": "Ora Europei Centrale (Monaco)", + "Europe\/Moscow": "Ora Moscovei (Moscova)", + "Europe\/Oslo": "Ora Europei Centrale (Oslo)", + "Europe\/Paris": "Ora Europei Centrale (Paris)", + "Europe\/Podgorica": "Ora Europei Centrale (Podgorica)", + "Europe\/Prague": "Ora Europei Centrale (Praga)", + "Europe\/Riga": "Ora Europei de Est (Riga)", + "Europe\/Rome": "Ora Europei Centrale (Roma)", + "Europe\/Samara": "Ora din Samara (Samara)", + "Europe\/San_Marino": "Ora Europei Centrale (San Marino)", + "Europe\/Sarajevo": "Ora Europei Centrale (Sarajevo)", + "Europe\/Saratov": "Ora Moscovei (Saratov)", + "Europe\/Simferopol": "Ora Moscovei (Simferopol)", + "Europe\/Skopje": "Ora Europei Centrale (Skopje)", + "Europe\/Sofia": "Ora Europei de Est (Sofia)", + "Europe\/Stockholm": "Ora Europei Centrale (Stockholm)", + "Europe\/Tallinn": "Ora Europei de Est (Tallinn)", + "Europe\/Tirane": "Ora Europei Centrale (Tirana)", + "Europe\/Ulyanovsk": "Ora Moscovei (Ulianovsk)", + "Europe\/Uzhgorod": "Ora Europei de Est (Ujhorod)", + "Europe\/Vaduz": "Ora Europei Centrale (Vaduz)", + "Europe\/Vatican": "Ora Europei Centrale (Vatican)", + "Europe\/Vienna": "Ora Europei Centrale (Viena)", + "Europe\/Vilnius": "Ora Europei de Est (Vilnius)", + "Europe\/Volgograd": "Ora din Volgograd (Volgograd)", + "Europe\/Warsaw": "Ora Europei Centrale (Varșovia)", + "Europe\/Zagreb": "Ora Europei Centrale (Zagreb)", + "Europe\/Zaporozhye": "Ora Europei de Est (Zaporoje)", + "Europe\/Zurich": "Ora Europei Centrale (Zürich)", + "Indian\/Antananarivo": "Ora Africii Orientale (Antananarivo)", + "Indian\/Chagos": "Ora Oceanului Indian (Chagos)", + "Indian\/Christmas": "Ora din Insula Christmas (Christmas)", + "Indian\/Cocos": "Ora Insulelor Cocos (Cocos)", + "Indian\/Comoro": "Ora Africii Orientale (Comore)", + "Indian\/Kerguelen": "Ora din Teritoriile Australe și Antarctice Franceze (Kerguelen)", + "Indian\/Mahe": "Ora din Seychelles (Mahe)", + "Indian\/Maldives": "Ora din Maldive (Maldive)", + "Indian\/Mauritius": "Ora din Mauritius (Mauritius)", + "Indian\/Mayotte": "Ora Africii Orientale (Mayotte)", + "Indian\/Reunion": "Ora din Reunion (Réunion)", + "MST7MDT": "Ora zonei montane nord-americane", + "PST8PDT": "Ora zonei Pacific nord-americane", + "Pacific\/Apia": "Ora din Apia (Apia)", + "Pacific\/Auckland": "Ora Noii Zeelande (Auckland)", + "Pacific\/Bougainville": "Ora din Papua Noua Guinee (Bougainville)", + "Pacific\/Chatham": "Ora din Chatham (Chatham)", + "Pacific\/Easter": "Ora din Insula Paștelui (Insula Paștelui)", + "Pacific\/Efate": "Ora din Vanuatu (Efate)", + "Pacific\/Enderbury": "Ora Insulelor Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Ora din Tokelau (Fakaofo)", + "Pacific\/Fiji": "Ora din Fiji (Fiji)", + "Pacific\/Funafuti": "Ora din Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Ora din Galapagos (Galapagos)", + "Pacific\/Gambier": "Ora din Gambier (Gambier)", + "Pacific\/Guadalcanal": "Ora Insulelor Solomon (Guadalcanal)", + "Pacific\/Guam": "Ora din Chamorro (Guam)", + "Pacific\/Honolulu": "Ora din Hawaii-Aleutine (Honolulu)", + "Pacific\/Johnston": "Ora din Hawaii-Aleutine (Johnston)", + "Pacific\/Kiritimati": "Ora din Insulele Line (Kiritimati)", + "Pacific\/Kosrae": "Ora din Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Ora Insulelor Marshall (Kwajalein)", + "Pacific\/Majuro": "Ora Insulelor Marshall (Majuro)", + "Pacific\/Marquesas": "Ora Insulelor Marchize (Marchize)", + "Pacific\/Midway": "Ora din Samoa (Midway)", + "Pacific\/Nauru": "Ora din Nauru (Nauru)", + "Pacific\/Niue": "Ora din Niue (Niue)", + "Pacific\/Norfolk": "Ora Insulelor Norfolk (Norfolk)", + "Pacific\/Noumea": "Ora Noii Caledonii (Noumea)", + "Pacific\/Pago_Pago": "Ora din Samoa (Pago Pago)", + "Pacific\/Palau": "Ora din Palau (Palau)", + "Pacific\/Pitcairn": "Ora din Pitcairn (Insula Pitcairn)", + "Pacific\/Ponape": "Ora din Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Ora din Papua Noua Guinee (Port Moresby)", + "Pacific\/Rarotonga": "Ora Insulelor Cook (Rarotonga)", + "Pacific\/Saipan": "Ora din Chamorro (Saipan)", + "Pacific\/Tahiti": "Ora din Tahiti (Tahiti)", + "Pacific\/Tarawa": "Ora Insulelor Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Ora din Tonga (Tongatapu)", + "Pacific\/Truk": "Ora din Chuuk (Chuuk)", + "Pacific\/Wake": "Ora Insulei Wake (Wake)", + "Pacific\/Wallis": "Ora din Wallis și Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ru.json b/src/Symfony/Component/Intl/Resources/data/timezones/ru.json new file mode 100644 index 0000000000000..5cb4dc8b2dac8 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ru.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Среднее время по Гринвичу (Абиджан)", + "Africa\/Accra": "Среднее время по Гринвичу (Аккра)", + "Africa\/Addis_Ababa": "Восточная Африка (Аддис-Абеба)", + "Africa\/Algiers": "Центральная Европа (Алжир)", + "Africa\/Asmera": "Восточная Африка (Асмэра)", + "Africa\/Bamako": "Среднее время по Гринвичу (Бамако)", + "Africa\/Bangui": "Западная Африка (Банги)", + "Africa\/Banjul": "Среднее время по Гринвичу (Банжул)", + "Africa\/Bissau": "Среднее время по Гринвичу (Бисау)", + "Africa\/Blantyre": "Центральная Африка (Блантайр)", + "Africa\/Brazzaville": "Западная Африка (Браззавиль)", + "Africa\/Bujumbura": "Центральная Африка (Бужумбура)", + "Africa\/Cairo": "Восточная Европа (Каир)", + "Africa\/Casablanca": "Западная Европа (Касабланка)", + "Africa\/Ceuta": "Центральная Европа (Сеута)", + "Africa\/Conakry": "Среднее время по Гринвичу (Конакри)", + "Africa\/Dakar": "Среднее время по Гринвичу (Дакар)", + "Africa\/Dar_es_Salaam": "Восточная Африка (Дар-эс-Салам)", + "Africa\/Djibouti": "Восточная Африка (Джибути)", + "Africa\/Douala": "Западная Африка (Дуала)", + "Africa\/El_Aaiun": "Западная Европа (Эль-Аюн)", + "Africa\/Freetown": "Среднее время по Гринвичу (Фритаун)", + "Africa\/Gaborone": "Центральная Африка (Габороне)", + "Africa\/Harare": "Центральная Африка (Хараре)", + "Africa\/Johannesburg": "Южная Африка (Йоханнесбург)", + "Africa\/Juba": "Восточная Африка (Джуба)", + "Africa\/Kampala": "Восточная Африка (Кампала)", + "Africa\/Khartoum": "Центральная Африка (Хартум)", + "Africa\/Kigali": "Центральная Африка (Кигали)", + "Africa\/Kinshasa": "Западная Африка (Киншаса)", + "Africa\/Lagos": "Западная Африка (Лагос)", + "Africa\/Libreville": "Западная Африка (Либревиль)", + "Africa\/Lome": "Среднее время по Гринвичу (Ломе)", + "Africa\/Luanda": "Западная Африка (Луанда)", + "Africa\/Lubumbashi": "Центральная Африка (Лубумбаши)", + "Africa\/Lusaka": "Центральная Африка (Лусака)", + "Africa\/Malabo": "Западная Африка (Малабо)", + "Africa\/Maputo": "Центральная Африка (Мапуту)", + "Africa\/Maseru": "Южная Африка (Масеру)", + "Africa\/Mbabane": "Южная Африка (Мбабане)", + "Africa\/Mogadishu": "Восточная Африка (Могадишо)", + "Africa\/Monrovia": "Среднее время по Гринвичу (Монровия)", + "Africa\/Nairobi": "Восточная Африка (Найроби)", + "Africa\/Ndjamena": "Западная Африка (Нджамена)", + "Africa\/Niamey": "Западная Африка (Ниамей)", + "Africa\/Nouakchott": "Среднее время по Гринвичу (Нуакшот)", + "Africa\/Ouagadougou": "Среднее время по Гринвичу (Уагадугу)", + "Africa\/Porto-Novo": "Западная Африка (Порто-Ново)", + "Africa\/Sao_Tome": "Среднее время по Гринвичу (Сан-Томе)", + "Africa\/Tripoli": "Восточная Европа (Триполи)", + "Africa\/Tunis": "Центральная Европа (Тунис)", + "Africa\/Windhoek": "Центральная Африка (Виндхук)", + "America\/Adak": "Гавайско-алеутское время (Адак)", + "America\/Anchorage": "Аляска (Анкоридж)", + "America\/Anguilla": "Атлантическое время (Ангилья)", + "America\/Antigua": "Атлантическое время (Антигуа)", + "America\/Araguaina": "Бразилия (Арагуаина)", + "America\/Argentina\/La_Rioja": "Аргентина (Ла-Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аргентина (Рио-Гальегос)", + "America\/Argentina\/Salta": "Аргентина (Сальта)", + "America\/Argentina\/San_Juan": "Аргентина (Сан-Хуан)", + "America\/Argentina\/San_Luis": "Западная Аргентина (Сан-Луис)", + "America\/Argentina\/Tucuman": "Аргентина (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентина (Ушуая)", + "America\/Aruba": "Атлантическое время (Аруба)", + "America\/Asuncion": "Парагвай (Асунсьон)", + "America\/Bahia": "Бразилия (Баия)", + "America\/Bahia_Banderas": "Центральная Америка (Баия-де-Бандерас)", + "America\/Barbados": "Атлантическое время (Барбадос)", + "America\/Belem": "Бразилия (Белен)", + "America\/Belize": "Центральная Америка (Белиз)", + "America\/Blanc-Sablon": "Атлантическое время (Бланк-Саблон)", + "America\/Boa_Vista": "Амазонка (Боа-Виста)", + "America\/Bogota": "Колумбия (Богота)", + "America\/Boise": "Горное время (Северная Америка) (Бойсе)", + "America\/Buenos_Aires": "Аргентина (Буэнос-Айрес)", + "America\/Cambridge_Bay": "Горное время (Северная Америка) (Кеймбридж-Бей)", + "America\/Campo_Grande": "Амазонка (Кампу-Гранди)", + "America\/Cancun": "Восточная Америка (Канкун)", + "America\/Caracas": "Венесуэла (Каракас)", + "America\/Catamarca": "Аргентина (Катамарка)", + "America\/Cayenne": "Французская Гвиана (Кайенна)", + "America\/Cayman": "Восточная Америка (Острова Кайман)", + "America\/Chicago": "Центральная Америка (Чикаго)", + "America\/Chihuahua": "Тихоокеанское мексиканское время (Чиуауа)", + "America\/Coral_Harbour": "Восточная Америка (Корал-Харбор)", + "America\/Cordoba": "Аргентина (Кордова)", + "America\/Costa_Rica": "Центральная Америка (Коста-Рика)", + "America\/Creston": "Горное время (Северная Америка) (Крестон)", + "America\/Cuiaba": "Амазонка (Куяба)", + "America\/Curacao": "Атлантическое время (Кюрасао)", + "America\/Danmarkshavn": "Среднее время по Гринвичу (Денмарксхавн)", + "America\/Dawson": "Тихоокеанское время (Доусон)", + "America\/Dawson_Creek": "Горное время (Северная Америка) (Доусон-Крик)", + "America\/Denver": "Горное время (Северная Америка) (Денвер)", + "America\/Detroit": "Восточная Америка (Детройт)", + "America\/Dominica": "Атлантическое время (Доминика)", + "America\/Edmonton": "Горное время (Северная Америка) (Эдмонтон)", + "America\/Eirunepe": "Акри время (Эйрунепе)", + "America\/El_Salvador": "Центральная Америка (Сальвадор)", + "America\/Fort_Nelson": "Горное время (Северная Америка) (Форт Нельсон)", + "America\/Fortaleza": "Бразилия (Форталеза)", + "America\/Glace_Bay": "Атлантическое время (Глейс-Бей)", + "America\/Godthab": "Западная Гренландия (Нуук)", + "America\/Goose_Bay": "Атлантическое время (Гус-Бей)", + "America\/Grand_Turk": "Восточная Америка (Гранд-Терк)", + "America\/Grenada": "Атлантическое время (Гренада)", + "America\/Guadeloupe": "Атлантическое время (Гваделупа)", + "America\/Guatemala": "Центральная Америка (Гватемала)", + "America\/Guayaquil": "Эквадор (Гуаякиль)", + "America\/Guyana": "Гайана (Гайана)", + "America\/Halifax": "Атлантическое время (Галифакс)", + "America\/Havana": "Куба (Гавана)", + "America\/Hermosillo": "Тихоокеанское мексиканское время (Эрмосильо)", + "America\/Indiana\/Knox": "Центральная Америка (Нокс, Индиана)", + "America\/Indiana\/Marengo": "Восточная Америка (Маренго, Индиана)", + "America\/Indiana\/Petersburg": "Восточная Америка (Питерсберг, Индиана)", + "America\/Indiana\/Tell_City": "Центральная Америка (Телл-Сити)", + "America\/Indiana\/Vevay": "Восточная Америка (Вевей, Индиана)", + "America\/Indiana\/Vincennes": "Восточная Америка (Винсеннес)", + "America\/Indiana\/Winamac": "Восточная Америка (Уинамак)", + "America\/Indianapolis": "Восточная Америка (Индианаполис)", + "America\/Inuvik": "Горное время (Северная Америка) (Инувик)", + "America\/Iqaluit": "Восточная Америка (Икалуит)", + "America\/Jamaica": "Восточная Америка (Ямайка)", + "America\/Jujuy": "Аргентина (Жужуй)", + "America\/Juneau": "Аляска (Джуно)", + "America\/Kentucky\/Monticello": "Восточная Америка (Монтиселло, Кентукки)", + "America\/Kralendijk": "Атлантическое время (Кралендейк)", + "America\/La_Paz": "Боливия (Ла-Пас)", + "America\/Lima": "Перу (Лима)", + "America\/Los_Angeles": "Тихоокеанское время (Лос-Анджелес)", + "America\/Louisville": "Восточная Америка (Луисвилл)", + "America\/Lower_Princes": "Атлантическое время (Лоуэр-Принсес-Куортер)", + "America\/Maceio": "Бразилия (Масейо)", + "America\/Managua": "Центральная Америка (Манагуа)", + "America\/Manaus": "Амазонка (Манаус)", + "America\/Marigot": "Атлантическое время (Мариго)", + "America\/Martinique": "Атлантическое время (Мартиника)", + "America\/Matamoros": "Центральная Америка (Матаморос)", + "America\/Mazatlan": "Тихоокеанское мексиканское время (Масатлан)", + "America\/Mendoza": "Аргентина (Мендоса)", + "America\/Menominee": "Центральная Америка (Меномини)", + "America\/Merida": "Центральная Америка (Мерида)", + "America\/Metlakatla": "Аляска (Метлакатла)", + "America\/Mexico_City": "Центральная Америка (Мехико)", + "America\/Miquelon": "Сен-Пьер и Микелон (Микелон)", + "America\/Moncton": "Атлантическое время (Монктон)", + "America\/Monterrey": "Центральная Америка (Монтеррей)", + "America\/Montevideo": "Уругвай (Монтевидео)", + "America\/Montserrat": "Атлантическое время (Монтсеррат)", + "America\/Nassau": "Восточная Америка (Нассау)", + "America\/New_York": "Восточная Америка (Нью-Йорк)", + "America\/Nipigon": "Восточная Америка (Нипигон)", + "America\/Nome": "Аляска (Ном)", + "America\/Noronha": "Фернанду-ди-Норонья (Норонья)", + "America\/North_Dakota\/Beulah": "Центральная Америка (Бойла, Северная Дакота)", + "America\/North_Dakota\/Center": "Центральная Америка (Центр, Северная Дакота)", + "America\/North_Dakota\/New_Salem": "Центральная Америка (Нью-Сейлем, Северная Дакота)", + "America\/Ojinaga": "Горное время (Северная Америка) (Охинага)", + "America\/Panama": "Восточная Америка (Панама)", + "America\/Pangnirtung": "Восточная Америка (Пангниртунг)", + "America\/Paramaribo": "Суринам (Парамарибо)", + "America\/Phoenix": "Горное время (Северная Америка) (Финикс)", + "America\/Port-au-Prince": "Восточная Америка (Порт-о-Пренс)", + "America\/Port_of_Spain": "Атлантическое время (Порт-оф-Спейн)", + "America\/Porto_Velho": "Амазонка (Порту-Велью)", + "America\/Puerto_Rico": "Атлантическое время (Пуэрто-Рико)", + "America\/Punta_Arenas": "Чили (Пунта-Аренас)", + "America\/Rainy_River": "Центральная Америка (Рейни-Ривер)", + "America\/Rankin_Inlet": "Центральная Америка (Ранкин-Инлет)", + "America\/Recife": "Бразилия (Ресифи)", + "America\/Regina": "Центральная Америка (Реджайна)", + "America\/Resolute": "Центральная Америка (Резольют)", + "America\/Rio_Branco": "Акри время (Риу-Бранку)", + "America\/Santa_Isabel": "Северо-западное мексиканское время (Санта-Изабел)", + "America\/Santarem": "Бразилия (Сантарен)", + "America\/Santiago": "Чили (Сантьяго)", + "America\/Santo_Domingo": "Атлантическое время (Санто-Доминго)", + "America\/Sao_Paulo": "Бразилия (Сан-Паулу)", + "America\/Scoresbysund": "Восточная Гренландия (Скорсбисунн)", + "America\/Sitka": "Аляска (Ситка)", + "America\/St_Barthelemy": "Атлантическое время (Сен-Бартелеми)", + "America\/St_Johns": "Ньюфаундленд (Сент-Джонс)", + "America\/St_Kitts": "Атлантическое время (Сент-Китс)", + "America\/St_Lucia": "Атлантическое время (Сент-Люсия)", + "America\/St_Thomas": "Атлантическое время (Сент-Томас)", + "America\/St_Vincent": "Атлантическое время (Сент-Винсент)", + "America\/Swift_Current": "Центральная Америка (Свифт-Керрент)", + "America\/Tegucigalpa": "Центральная Америка (Тегусигальпа)", + "America\/Thule": "Атлантическое время (Туле)", + "America\/Thunder_Bay": "Восточная Америка (Тандер-Бей)", + "America\/Tijuana": "Тихоокеанское время (Тихуана)", + "America\/Toronto": "Восточная Америка (Торонто)", + "America\/Tortola": "Атлантическое время (Тортола)", + "America\/Vancouver": "Тихоокеанское время (Ванкувер)", + "America\/Whitehorse": "Тихоокеанское время (Уайтхорс)", + "America\/Winnipeg": "Центральная Америка (Виннипег)", + "America\/Yakutat": "Аляска (Якутат)", + "America\/Yellowknife": "Горное время (Северная Америка) (Йеллоунайф)", + "Antarctica\/Casey": "Западная Австралия (Кейси)", + "Antarctica\/Davis": "Дейвис (Дейвис)", + "Antarctica\/DumontDUrville": "Дюмон-д’Юрвиль (Дюмон-д’Юрвиль)", + "Antarctica\/Macquarie": "Маккуори (Маккуори)", + "Antarctica\/Mawson": "Моусон (Моусон)", + "Antarctica\/McMurdo": "Новая Зеландия (Мак-Мердо)", + "Antarctica\/Palmer": "Чили (Палмер)", + "Antarctica\/Rothera": "Ротера (Ротера)", + "Antarctica\/Syowa": "Сёва (Сёва)", + "Antarctica\/Troll": "Среднее время по Гринвичу (Тролль)", + "Antarctica\/Vostok": "Восток (Восток)", + "Arctic\/Longyearbyen": "Центральная Европа (Лонгйир)", + "Asia\/Aden": "Саудовская Аравия (Аден)", + "Asia\/Almaty": "Восточный Казахстан (Алматы)", + "Asia\/Amman": "Восточная Европа (Амман)", + "Asia\/Anadyr": "Время по Анадырю (Анадырь)", + "Asia\/Aqtau": "Западный Казахстан (Актау)", + "Asia\/Aqtobe": "Западный Казахстан (Актобе)", + "Asia\/Ashgabat": "Туркменистан (Ашхабад)", + "Asia\/Atyrau": "Западный Казахстан (Атырау)", + "Asia\/Baghdad": "Саудовская Аравия (Багдад)", + "Asia\/Bahrain": "Саудовская Аравия (Бахрейн)", + "Asia\/Baku": "Азербайджан (Баку)", + "Asia\/Bangkok": "Индокитай (Бангкок)", + "Asia\/Beirut": "Восточная Европа (Бейрут)", + "Asia\/Bishkek": "Киргизия (Бишкек)", + "Asia\/Brunei": "Бруней-Даруссалам (Бруней)", + "Asia\/Calcutta": "Индия (Калькутта)", + "Asia\/Chita": "Якутск (Чита)", + "Asia\/Choibalsan": "Чойбалсан (Чойбалсан)", + "Asia\/Colombo": "Индия (Коломбо)", + "Asia\/Damascus": "Восточная Европа (Дамаск)", + "Asia\/Dhaka": "Бангладеш (Дакка)", + "Asia\/Dili": "Восточный Тимор (Дили)", + "Asia\/Dubai": "Персидский залив (Дубай)", + "Asia\/Dushanbe": "Таджикистан (Душанбе)", + "Asia\/Famagusta": "Восточная Европа (Фамагуста)", + "Asia\/Gaza": "Восточная Европа (Газа)", + "Asia\/Hebron": "Восточная Европа (Хеврон)", + "Asia\/Hong_Kong": "Гонконг (Гонконг)", + "Asia\/Hovd": "Ховд (Ховд)", + "Asia\/Irkutsk": "Иркутск (Иркутск)", + "Asia\/Jakarta": "Западная Индонезия (Джакарта)", + "Asia\/Jayapura": "Восточная Индонезия (Джаяпура)", + "Asia\/Jerusalem": "Израиль (Иерусалим)", + "Asia\/Kabul": "Афганистан (Кабул)", + "Asia\/Kamchatka": "Петропавловск-Камчатский (Петропавловск-Камчатский)", + "Asia\/Karachi": "Пакистан (Карачи)", + "Asia\/Katmandu": "Непал (Катманду)", + "Asia\/Khandyga": "Якутск (Хандыга)", + "Asia\/Krasnoyarsk": "Красноярск (Красноярск)", + "Asia\/Kuala_Lumpur": "Малайзия (Куала-Лумпур)", + "Asia\/Kuching": "Малайзия (Кучинг)", + "Asia\/Kuwait": "Саудовская Аравия (Кувейт)", + "Asia\/Macau": "Китай (Макао)", + "Asia\/Magadan": "Магадан (Магадан)", + "Asia\/Makassar": "Центральная Индонезия (Макасар)", + "Asia\/Manila": "Филиппины (Манила)", + "Asia\/Muscat": "Персидский залив (Маскат)", + "Asia\/Nicosia": "Восточная Европа (Никосия)", + "Asia\/Novokuznetsk": "Красноярск (Новокузнецк)", + "Asia\/Novosibirsk": "Новосибирск (Новосибирск)", + "Asia\/Omsk": "Омск (Омск)", + "Asia\/Oral": "Западный Казахстан (Уральск)", + "Asia\/Phnom_Penh": "Индокитай (Пномпень)", + "Asia\/Pontianak": "Западная Индонезия (Понтианак)", + "Asia\/Pyongyang": "Корея (Пхеньян)", + "Asia\/Qatar": "Саудовская Аравия (Катар)", + "Asia\/Qostanay": "Восточный Казахстан (Костанай)", + "Asia\/Qyzylorda": "Западный Казахстан (Кызылорда)", + "Asia\/Rangoon": "Мьянма (Янгон)", + "Asia\/Riyadh": "Саудовская Аравия (Эр-Рияд)", + "Asia\/Saigon": "Индокитай (Хошимин)", + "Asia\/Sakhalin": "Сахалин (о-в Сахалин)", + "Asia\/Samarkand": "Узбекистан (Самарканд)", + "Asia\/Seoul": "Корея (Сеул)", + "Asia\/Shanghai": "Китай (Шанхай)", + "Asia\/Singapore": "Сингапур (Сингапур)", + "Asia\/Srednekolymsk": "Магадан (Среднеколымск)", + "Asia\/Taipei": "Тайвань (Тайбэй)", + "Asia\/Tashkent": "Узбекистан (Ташкент)", + "Asia\/Tbilisi": "Грузия (Тбилиси)", + "Asia\/Tehran": "Иран (Тегеран)", + "Asia\/Thimphu": "Бутан (Тхимпху)", + "Asia\/Tokyo": "Япония (Токио)", + "Asia\/Ulaanbaatar": "Улан-Батор (Улан-Батор)", + "Asia\/Ust-Nera": "Владивосток (Усть-Нера)", + "Asia\/Vientiane": "Индокитай (Вьентьян)", + "Asia\/Vladivostok": "Владивосток (Владивосток)", + "Asia\/Yakutsk": "Якутск (Якутск)", + "Asia\/Yekaterinburg": "Екатеринбург (Екатеринбург)", + "Asia\/Yerevan": "Армения (Ереван)", + "Atlantic\/Azores": "Азорские о-ва (Азорские о-ва)", + "Atlantic\/Bermuda": "Атлантическое время (Бермудские о-ва)", + "Atlantic\/Canary": "Западная Европа (Канарские о-ва)", + "Atlantic\/Cape_Verde": "Кабо-Верде (Кабо-Верде)", + "Atlantic\/Faeroe": "Западная Европа (Фарерские о-ва)", + "Atlantic\/Madeira": "Западная Европа (Мадейра)", + "Atlantic\/Reykjavik": "Среднее время по Гринвичу (Рейкьявик)", + "Atlantic\/South_Georgia": "Южная Георгия (Южная Георгия)", + "Atlantic\/St_Helena": "Среднее время по Гринвичу (о-в Святой Елены)", + "Atlantic\/Stanley": "Фолклендские о-ва (Стэнли)", + "Australia\/Adelaide": "Центральная Австралия (Аделаида)", + "Australia\/Brisbane": "Восточная Австралия (Брисбен)", + "Australia\/Broken_Hill": "Центральная Австралия (Брокен-Хилл)", + "Australia\/Currie": "Восточная Австралия (Керри)", + "Australia\/Darwin": "Центральная Австралия (Дарвин)", + "Australia\/Eucla": "Центральная Австралия, западное время (Юкла)", + "Australia\/Hobart": "Восточная Австралия (Хобарт)", + "Australia\/Lindeman": "Восточная Австралия (Линдеман)", + "Australia\/Lord_Howe": "Лорд-Хау (Лорд-Хау)", + "Australia\/Melbourne": "Восточная Австралия (Мельбурн)", + "Australia\/Perth": "Западная Австралия (Перт)", + "Australia\/Sydney": "Восточная Австралия (Сидней)", + "CST6CDT": "Центральная Америка", + "EST5EDT": "Восточная Америка", + "Etc\/GMT": "Среднее время по Гринвичу", + "Etc\/UTC": "Всемирное координированное время", + "Europe\/Amsterdam": "Центральная Европа (Амстердам)", + "Europe\/Andorra": "Центральная Европа (Андорра)", + "Europe\/Astrakhan": "Москва (Астрахань)", + "Europe\/Athens": "Восточная Европа (Афины)", + "Europe\/Belgrade": "Центральная Европа (Белград)", + "Europe\/Berlin": "Центральная Европа (Берлин)", + "Europe\/Bratislava": "Центральная Европа (Братислава)", + "Europe\/Brussels": "Центральная Европа (Брюссель)", + "Europe\/Bucharest": "Восточная Европа (Бухарест)", + "Europe\/Budapest": "Центральная Европа (Будапешт)", + "Europe\/Busingen": "Центральная Европа (Бюзинген-на-Верхнем-Рейне)", + "Europe\/Chisinau": "Восточная Европа (Кишинев)", + "Europe\/Copenhagen": "Центральная Европа (Копенгаген)", + "Europe\/Dublin": "Среднее время по Гринвичу (Дублин)", + "Europe\/Gibraltar": "Центральная Европа (Гибралтар)", + "Europe\/Guernsey": "Среднее время по Гринвичу (Гернси)", + "Europe\/Helsinki": "Восточная Европа (Хельсинки)", + "Europe\/Isle_of_Man": "Среднее время по Гринвичу (о-в Мэн)", + "Europe\/Jersey": "Среднее время по Гринвичу (Джерси)", + "Europe\/Kaliningrad": "Восточная Европа (Калининград)", + "Europe\/Kiev": "Восточная Европа (Киев)", + "Europe\/Lisbon": "Западная Европа (Лиссабон)", + "Europe\/Ljubljana": "Центральная Европа (Любляна)", + "Europe\/London": "Среднее время по Гринвичу (Лондон)", + "Europe\/Luxembourg": "Центральная Европа (Люксембург)", + "Europe\/Madrid": "Центральная Европа (Мадрид)", + "Europe\/Malta": "Центральная Европа (Мальта)", + "Europe\/Mariehamn": "Восточная Европа (Мариехамн)", + "Europe\/Minsk": "Москва (Минск)", + "Europe\/Monaco": "Центральная Европа (Монако)", + "Europe\/Moscow": "Москва (Москва)", + "Europe\/Oslo": "Центральная Европа (Осло)", + "Europe\/Paris": "Центральная Европа (Париж)", + "Europe\/Podgorica": "Центральная Европа (Подгорица)", + "Europe\/Prague": "Центральная Европа (Прага)", + "Europe\/Riga": "Восточная Европа (Рига)", + "Europe\/Rome": "Центральная Европа (Рим)", + "Europe\/Samara": "Время в Самаре (Самара)", + "Europe\/San_Marino": "Центральная Европа (Сан-Марино)", + "Europe\/Sarajevo": "Центральная Европа (Сараево)", + "Europe\/Saratov": "Москва (Саратов)", + "Europe\/Simferopol": "Москва (Симферополь)", + "Europe\/Skopje": "Центральная Европа (Скопье)", + "Europe\/Sofia": "Восточная Европа (София)", + "Europe\/Stockholm": "Центральная Европа (Стокгольм)", + "Europe\/Tallinn": "Восточная Европа (Таллин)", + "Europe\/Tirane": "Центральная Европа (Тирана)", + "Europe\/Ulyanovsk": "Москва (Ульяновск)", + "Europe\/Uzhgorod": "Восточная Европа (Ужгород)", + "Europe\/Vaduz": "Центральная Европа (Вадуц)", + "Europe\/Vatican": "Центральная Европа (Ватикан)", + "Europe\/Vienna": "Центральная Европа (Вена)", + "Europe\/Vilnius": "Восточная Европа (Вильнюс)", + "Europe\/Volgograd": "Волгоград (Волгоград)", + "Europe\/Warsaw": "Центральная Европа (Варшава)", + "Europe\/Zagreb": "Центральная Европа (Загреб)", + "Europe\/Zaporozhye": "Восточная Европа (Запорожье)", + "Europe\/Zurich": "Центральная Европа (Цюрих)", + "Indian\/Antananarivo": "Восточная Африка (Антананариву)", + "Indian\/Chagos": "Индийский океан (Чагос)", + "Indian\/Christmas": "о-в Рождества (о-в Рождества)", + "Indian\/Cocos": "Кокосовые о-ва (Кокосовые о-ва)", + "Indian\/Comoro": "Восточная Африка (Коморы)", + "Indian\/Kerguelen": "Французские Южные и Антарктические территории (Кергелен)", + "Indian\/Mahe": "Сейшельские Острова (Маэ)", + "Indian\/Maldives": "Мальдивы (Мальдивы)", + "Indian\/Mauritius": "Маврикий (Маврикий)", + "Indian\/Mayotte": "Восточная Африка (Майотта)", + "Indian\/Reunion": "Реюньон (Реюньон)", + "MST7MDT": "Горное время (Северная Америка)", + "PST8PDT": "Тихоокеанское время", + "Pacific\/Apia": "Апиа (Апиа)", + "Pacific\/Auckland": "Новая Зеландия (Окленд)", + "Pacific\/Bougainville": "Папуа – Новая Гвинея (Бугенвиль)", + "Pacific\/Chatham": "Чатем (Чатем)", + "Pacific\/Easter": "О-в Пасхи (о-в Пасхи)", + "Pacific\/Efate": "Вануату (Эфате)", + "Pacific\/Enderbury": "о-ва Феникс (о-в Эндербери)", + "Pacific\/Fakaofo": "Токелау (Факаофо)", + "Pacific\/Fiji": "Фиджи (Фиджи)", + "Pacific\/Funafuti": "Тувалу (Фунафути)", + "Pacific\/Galapagos": "Галапагосские о-ва (Галапагосские о-ва)", + "Pacific\/Gambier": "Гамбье (о-ва Гамбье)", + "Pacific\/Guadalcanal": "Соломоновы Острова (Гуадалканал)", + "Pacific\/Guam": "Чаморро (Гуам)", + "Pacific\/Honolulu": "Гавайско-алеутское время (Гонолулу)", + "Pacific\/Johnston": "Гавайско-алеутское время (Джонстон)", + "Pacific\/Kiritimati": "о-ва Лайн (Киритимати)", + "Pacific\/Kosrae": "Косрае (Косрае)", + "Pacific\/Kwajalein": "Маршалловы Острова (Кваджалейн)", + "Pacific\/Majuro": "Маршалловы Острова (Маджуро)", + "Pacific\/Marquesas": "Маркизские о-ва (Маркизские о-ва)", + "Pacific\/Midway": "Самоа (о-ва Мидуэй)", + "Pacific\/Nauru": "Науру (Науру)", + "Pacific\/Niue": "Ниуэ (Ниуэ)", + "Pacific\/Norfolk": "Норфолк (Норфолк)", + "Pacific\/Noumea": "Новая Каледония (Нумеа)", + "Pacific\/Pago_Pago": "Самоа (Паго-Паго)", + "Pacific\/Palau": "Палау (Палау)", + "Pacific\/Pitcairn": "Питкэрн (Питкэрн)", + "Pacific\/Ponape": "Понпеи (Понпеи)", + "Pacific\/Port_Moresby": "Папуа – Новая Гвинея (Порт-Морсби)", + "Pacific\/Rarotonga": "Острова Кука (Раротонга)", + "Pacific\/Saipan": "Чаморро (Сайпан)", + "Pacific\/Tahiti": "Таити (Таити)", + "Pacific\/Tarawa": "о-ва Гилберта (Тарава)", + "Pacific\/Tongatapu": "Тонга (Тонгатапу)", + "Pacific\/Truk": "Трук (Трук)", + "Pacific\/Wake": "Уэйк (Уэйк)", + "Pacific\/Wallis": "Уоллис и Футуна (Уоллис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/rw.json b/src/Symfony/Component/Intl/Resources/data/timezones/rw.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/rw.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sd.json b/src/Symfony/Component/Intl/Resources/data/timezones/sd.json new file mode 100644 index 0000000000000..3ae59f0d5ead0 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sd.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "گرين وچ مين ٽائيم (ابي جان)", + "Africa\/Accra": "گرين وچ مين ٽائيم (ايڪرا)", + "Africa\/Addis_Ababa": "اوڀر آفريڪا جو وقت (ايڊيس اببا)", + "Africa\/Algiers": "مرڪزي يورپي وقت (الجيرز)", + "Africa\/Asmera": "اوڀر آفريڪا جو وقت (ازمارا)", + "Africa\/Bamako": "گرين وچ مين ٽائيم (باماڪو)", + "Africa\/Bangui": "اولهه آفريقا جو وقت (بنگي)", + "Africa\/Banjul": "گرين وچ مين ٽائيم (بينجال)", + "Africa\/Bissau": "گرين وچ مين ٽائيم (بسائو)", + "Africa\/Blantyre": "مرڪزي آفريقا جو وقت (بلنٽائر)", + "Africa\/Brazzaville": "اولهه آفريقا جو وقت (برازاويل)", + "Africa\/Bujumbura": "مرڪزي آفريقا جو وقت (بوجمبورا)", + "Africa\/Cairo": "مشرقي يورپي وقت (قائرا)", + "Africa\/Casablanca": "مغربي يورپي وقت (ڪاسابلانڪا)", + "Africa\/Ceuta": "مرڪزي يورپي وقت (سيوٽا)", + "Africa\/Conakry": "گرين وچ مين ٽائيم (ڪوناڪري)", + "Africa\/Dakar": "گرين وچ مين ٽائيم (ڊاڪار)", + "Africa\/Dar_es_Salaam": "اوڀر آفريڪا جو وقت (دارالسلام)", + "Africa\/Djibouti": "اوڀر آفريڪا جو وقت (جبوتي)", + "Africa\/Douala": "اولهه آفريقا جو وقت (دوالا)", + "Africa\/El_Aaiun": "مغربي يورپي وقت (ال ايون)", + "Africa\/Freetown": "گرين وچ مين ٽائيم (فري ٽائون)", + "Africa\/Gaborone": "مرڪزي آفريقا جو وقت (گيبورون)", + "Africa\/Harare": "مرڪزي آفريقا جو وقت (هراري)", + "Africa\/Johannesburg": "ڏکڻ آفريڪا جو معياري وقت (جوهانسبرگ)", + "Africa\/Juba": "اوڀر آفريڪا جو وقت (جوبا)", + "Africa\/Kampala": "اوڀر آفريڪا جو وقت (ڪمپالا)", + "Africa\/Khartoum": "مرڪزي آفريقا جو وقت (خرطوم)", + "Africa\/Kigali": "مرڪزي آفريقا جو وقت (ڪيگالي)", + "Africa\/Kinshasa": "اولهه آفريقا جو وقت (ڪنشاسا)", + "Africa\/Lagos": "اولهه آفريقا جو وقت (لاگوس)", + "Africa\/Libreville": "اولهه آفريقا جو وقت (لیبرویلی)", + "Africa\/Lome": "گرين وچ مين ٽائيم (لوم)", + "Africa\/Luanda": "اولهه آفريقا جو وقت (لوانڊا)", + "Africa\/Lubumbashi": "مرڪزي آفريقا جو وقت (لوبمباشی)", + "Africa\/Lusaka": "مرڪزي آفريقا جو وقت (لوساڪا)", + "Africa\/Malabo": "اولهه آفريقا جو وقت (ملابو)", + "Africa\/Maputo": "مرڪزي آفريقا جو وقت (ماپوتو)", + "Africa\/Maseru": "ڏکڻ آفريڪا جو معياري وقت (ماسيرو)", + "Africa\/Mbabane": "ڏکڻ آفريڪا جو معياري وقت (مبابين)", + "Africa\/Mogadishu": "اوڀر آفريڪا جو وقت (موغادیشو)", + "Africa\/Monrovia": "گرين وچ مين ٽائيم (مونروویا)", + "Africa\/Nairobi": "اوڀر آفريڪا جو وقت (نيروبي)", + "Africa\/Ndjamena": "اولهه آفريقا جو وقت (نجامينا)", + "Africa\/Niamey": "اولهه آفريقا جو وقت (نيامي)", + "Africa\/Nouakchott": "گرين وچ مين ٽائيم (نواڪشوط)", + "Africa\/Ouagadougou": "گرين وچ مين ٽائيم (آئوگو ڊائوگو)", + "Africa\/Porto-Novo": "اولهه آفريقا جو وقت (پورٽو نوو)", + "Africa\/Sao_Tome": "گرين وچ مين ٽائيم (سائو ٽوم)", + "Africa\/Tripoli": "مشرقي يورپي وقت (ٽرپولي)", + "Africa\/Tunis": "مرڪزي يورپي وقت (تيونس)", + "Africa\/Windhoek": "مرڪزي آفريقا جو وقت (ونڊهوڪ)", + "America\/Adak": "هوائي اليوٽين جو وقت (ادڪ)", + "America\/Anchorage": "الاسڪا جو وقت (اينڪريج)", + "America\/Anguilla": "ايٽلانٽڪ جو وقت (انگويلا)", + "America\/Antigua": "ايٽلانٽڪ جو وقت (اينٽيگوا)", + "America\/Araguaina": "بريسيليائي وقت (اراگویانا)", + "America\/Argentina\/La_Rioja": "ارجنٽائن وقت (لا ریئوجا)", + "America\/Argentina\/Rio_Gallegos": "ارجنٽائن وقت (ریو گالیگوس)", + "America\/Argentina\/Salta": "ارجنٽائن وقت (سالٽا)", + "America\/Argentina\/San_Juan": "ارجنٽائن وقت (سان جوآن)", + "America\/Argentina\/San_Luis": "مغربي ارجنٽائن وقت (سان لوئیس)", + "America\/Argentina\/Tucuman": "ارجنٽائن وقت (ٽوڪومين)", + "America\/Argentina\/Ushuaia": "ارجنٽائن وقت (اوشوآئیا)", + "America\/Aruba": "ايٽلانٽڪ جو وقت (اروبا)", + "America\/Asuncion": "پيراگوئي جو وقت (اسانسیون)", + "America\/Bahia": "بريسيليائي وقت (باحيه)", + "America\/Bahia_Banderas": "مرڪزي وقت (باهیا بیندراس)", + "America\/Barbados": "ايٽلانٽڪ جو وقت (بارباڊوس)", + "America\/Belem": "بريسيليائي وقت (بیلم)", + "America\/Belize": "مرڪزي وقت (بیلیز)", + "America\/Blanc-Sablon": "ايٽلانٽڪ جو وقت (بلانڪ سبلون)", + "America\/Boa_Vista": "ايميزون جو وقت (بائو وستا)", + "America\/Bogota": "ڪولمبيا جو وقت (بگوٽا)", + "America\/Boise": "پهاڙي وقت (بوئس)", + "America\/Buenos_Aires": "ارجنٽائن وقت (بيونوس ايئرس)", + "America\/Cambridge_Bay": "پهاڙي وقت (ڪيمبرج بي)", + "America\/Campo_Grande": "ايميزون جو وقت (ڪيمپو گرانڊي)", + "America\/Cancun": "مشرقي وقت (ڪانڪون)", + "America\/Caracas": "وينزويلا جو وقت (ڪراڪس)", + "America\/Catamarca": "ارجنٽائن وقت (ڪيٽا مارڪا)", + "America\/Cayenne": "فرانسيسي گيانا جو وقت (ڪائين)", + "America\/Cayman": "مشرقي وقت (سيامن)", + "America\/Chicago": "مرڪزي وقت (شڪاگو)", + "America\/Chihuahua": "ميڪسيڪن پيسيفڪ وقت (چي هوا هوا)", + "America\/Coral_Harbour": "مشرقي وقت (اٽيڪوڪن)", + "America\/Cordoba": "ارجنٽائن وقت (ڪارڊوبا)", + "America\/Costa_Rica": "مرڪزي وقت (ڪوسٽا ريڪا)", + "America\/Creston": "پهاڙي وقت (ڪريسٽن)", + "America\/Cuiaba": "ايميزون جو وقت (ڪوئيابا)", + "America\/Curacao": "ايٽلانٽڪ جو وقت (ڪيوراسائو)", + "America\/Danmarkshavn": "گرين وچ مين ٽائيم (ڊينمارڪ شون)", + "America\/Dawson": "پيسيفڪ وقت (ڊاوسن)", + "America\/Dawson_Creek": "پهاڙي وقت (ڊاوسن ڪريڪ)", + "America\/Denver": "پهاڙي وقت (ڊينور)", + "America\/Detroit": "مشرقي وقت (ڊيٽرائيٽ)", + "America\/Dominica": "ايٽلانٽڪ جو وقت (ڊومينيڪا)", + "America\/Edmonton": "پهاڙي وقت (ايڊمونٽن)", + "America\/El_Salvador": "مرڪزي وقت (ايل سلواڊور)", + "America\/Fort_Nelson": "پهاڙي وقت (فورٽ نيلسن)", + "America\/Fortaleza": "بريسيليائي وقت (فورٽاليزا)", + "America\/Glace_Bay": "ايٽلانٽڪ جو وقت (گليس بي)", + "America\/Godthab": "مغربي گرين لينڊ جو وقت (نيوڪ)", + "America\/Goose_Bay": "ايٽلانٽڪ جو وقت (گوز بي)", + "America\/Grand_Turk": "مشرقي وقت (گرانڊ ترڪ)", + "America\/Grenada": "ايٽلانٽڪ جو وقت (گريناڊا)", + "America\/Guadeloupe": "ايٽلانٽڪ جو وقت (گواڊيلوپ)", + "America\/Guatemala": "مرڪزي وقت (گوئٽي مالا)", + "America\/Guayaquil": "ايڪواڊور جو وقت (گواياڪيل)", + "America\/Guyana": "گيانائي وقت (گيانا)", + "America\/Halifax": "ايٽلانٽڪ جو وقت (هيلي فيڪس)", + "America\/Havana": "ڪيوبا جو وقت (هوانا)", + "America\/Hermosillo": "ميڪسيڪن پيسيفڪ وقت (هرموسلو)", + "America\/Indiana\/Knox": "مرڪزي وقت (ناڪس، انڊيانا)", + "America\/Indiana\/Marengo": "مشرقي وقت (مرينگو، انڊيانا)", + "America\/Indiana\/Petersburg": "مشرقي وقت (پيٽرسبرگ، انڊيانا)", + "America\/Indiana\/Tell_City": "مرڪزي وقت (ٽيل سٽي، انڊيانا)", + "America\/Indiana\/Vevay": "مشرقي وقت (ويوي، انڊيانا)", + "America\/Indiana\/Vincennes": "مشرقي وقت (ونسینیز، انڊیانا)", + "America\/Indiana\/Winamac": "مشرقي وقت (ويناميڪ، انڊيانا)", + "America\/Indianapolis": "مشرقي وقت (انڊيانا پولس)", + "America\/Inuvik": "پهاڙي وقت (انووڪ)", + "America\/Iqaluit": "مشرقي وقت (اڪالوئٽ)", + "America\/Jamaica": "مشرقي وقت (جمائڪا)", + "America\/Jujuy": "ارجنٽائن وقت (ڪوڪوئي)", + "America\/Juneau": "الاسڪا جو وقت (جونئو)", + "America\/Kentucky\/Monticello": "مشرقي وقت (مونٽيسيلو، ڪينٽڪي)", + "America\/Kralendijk": "ايٽلانٽڪ جو وقت (ڪرالينڊڪ)", + "America\/La_Paz": "بولويائي وقت (لا پز)", + "America\/Lima": "پيرو جو وقت (ليما)", + "America\/Los_Angeles": "پيسيفڪ وقت (لاس اينجلس)", + "America\/Louisville": "مشرقي وقت (لوئي ويل)", + "America\/Lower_Princes": "ايٽلانٽڪ جو وقت (لوئر پرنسز ڪوارٽر)", + "America\/Maceio": "بريسيليائي وقت (میسیئو)", + "America\/Managua": "مرڪزي وقت (ماناگوا)", + "America\/Manaus": "ايميزون جو وقت (منائوس)", + "America\/Marigot": "ايٽلانٽڪ جو وقت (ميريگوٽ)", + "America\/Martinique": "ايٽلانٽڪ جو وقت (مارٽينڪ)", + "America\/Matamoros": "مرڪزي وقت (متاموروس)", + "America\/Mazatlan": "ميڪسيڪن پيسيفڪ وقت (مزاٽلان)", + "America\/Mendoza": "ارجنٽائن وقت (مينڊوزا)", + "America\/Menominee": "مرڪزي وقت (مینومیني)", + "America\/Merida": "مرڪزي وقت (ميريڊا)", + "America\/Metlakatla": "الاسڪا جو وقت (ميٽلاڪاٽالا)", + "America\/Mexico_City": "مرڪزي وقت (ميڪسيڪو شهر)", + "America\/Miquelon": "سينٽ پيئر ائن ميڪوئلون جو وقت (میڪوئیلون)", + "America\/Moncton": "ايٽلانٽڪ جو وقت (مانڪٽن)", + "America\/Monterrey": "مرڪزي وقت (مانٽيري)", + "America\/Montevideo": "يوروگائي جو وقت (مونٽي ويڊيو)", + "America\/Montserrat": "ايٽلانٽڪ جو وقت (مانٽسريٽ)", + "America\/Nassau": "مشرقي وقت (ناسائو)", + "America\/New_York": "مشرقي وقت (نيويارڪ)", + "America\/Nipigon": "مشرقي وقت (نپيگان)", + "America\/Nome": "الاسڪا جو وقت (نوم)", + "America\/Noronha": "فرنانڊو دي نورونها جو وقت (نورانهيا)", + "America\/North_Dakota\/Beulah": "مرڪزي وقت (بيولاه، اتر ڊڪوٽا)", + "America\/North_Dakota\/Center": "مرڪزي وقت (سينٽر، اتر ڊڪوٽا)", + "America\/North_Dakota\/New_Salem": "مرڪزي وقت (نيو سيلم، اتر ڊڪوٽا)", + "America\/Ojinaga": "پهاڙي وقت (اوڪيناگا)", + "America\/Panama": "مشرقي وقت (پناما)", + "America\/Pangnirtung": "مشرقي وقت (پینگنرٽنگ)", + "America\/Paramaribo": "سوري نام جو وقت (پيراميريبو)", + "America\/Phoenix": "پهاڙي وقت (فونيڪس)", + "America\/Port-au-Prince": "مشرقي وقت (پورٽ او پرنس)", + "America\/Port_of_Spain": "ايٽلانٽڪ جو وقت (اسپين جو ٻيٽ)", + "America\/Porto_Velho": "ايميزون جو وقت (پورٽو ويلهو)", + "America\/Puerto_Rico": "ايٽلانٽڪ جو وقت (پورٽو ريڪو)", + "America\/Punta_Arenas": "چلي جو وقت (پنٽا اريناس)", + "America\/Rainy_River": "مرڪزي وقت (ريني رور)", + "America\/Rankin_Inlet": "مرڪزي وقت (رينڪن انليٽ)", + "America\/Recife": "بريسيليائي وقت (هيسيفي)", + "America\/Regina": "مرڪزي وقت (ریجینا)", + "America\/Resolute": "مرڪزي وقت (ريزوليوٽ)", + "America\/Santa_Isabel": "شمالي مغربي ميڪسيڪو جو وقت (Santa Isabel)", + "America\/Santarem": "بريسيليائي وقت (سنٽاريم)", + "America\/Santiago": "چلي جو وقت (سينٽياگو)", + "America\/Santo_Domingo": "ايٽلانٽڪ جو وقت (سينٽو ڊومينگو)", + "America\/Sao_Paulo": "بريسيليائي وقت (سائو پولو)", + "America\/Scoresbysund": "مشرقي گرين لينڊ جو وقت (اٽوڪورٽومائٽ)", + "America\/Sitka": "الاسڪا جو وقت (سٽڪا)", + "America\/St_Barthelemy": "ايٽلانٽڪ جو وقت (سينٽ برٿليمي)", + "America\/St_Johns": "نيو فائونڊ لينڊ جو وقت (سينٽ جانز)", + "America\/St_Kitts": "ايٽلانٽڪ جو وقت (سينٽ ڪٽس)", + "America\/St_Lucia": "ايٽلانٽڪ جو وقت (سينٽ لوسيا)", + "America\/St_Thomas": "ايٽلانٽڪ جو وقت (سينٽ ٿامس)", + "America\/St_Vincent": "ايٽلانٽڪ جو وقت (سينٽ ونسينٽ)", + "America\/Swift_Current": "مرڪزي وقت (سوئفٽ ڪرنٽ)", + "America\/Tegucigalpa": "مرڪزي وقت (ٽيگوسيگلپا)", + "America\/Thule": "ايٽلانٽڪ جو وقت (ٿولي)", + "America\/Thunder_Bay": "مشرقي وقت (ٿنڊر بي)", + "America\/Tijuana": "پيسيفڪ وقت (تيجوانا)", + "America\/Toronto": "مشرقي وقت (ٽورنٽو)", + "America\/Tortola": "ايٽلانٽڪ جو وقت (ٽورٽولا)", + "America\/Vancouver": "پيسيفڪ وقت (وينڪوور)", + "America\/Whitehorse": "پيسيفڪ وقت (وائيٽ هائوس)", + "America\/Winnipeg": "مرڪزي وقت (وني پيگ)", + "America\/Yakutat": "الاسڪا جو وقت (ياڪوتات)", + "America\/Yellowknife": "پهاڙي وقت (ييلو نائيف)", + "Antarctica\/Casey": "مغربي آسٽريليا جو وقت (ڪيسي)", + "Antarctica\/Davis": "ڊيوس جو وقت (ڊيوس)", + "Antarctica\/DumontDUrville": "ڊومانٽ درويئل جو وقت (ڊومانٽ درويئل)", + "Antarctica\/Macquarie": "مڪوائري آئي لينڊ جو وقت (مڪوائري)", + "Antarctica\/Mawson": "مائوسن جو وقت (موسن)", + "Antarctica\/McMurdo": "نيوزيلينڊ جو وقت (ميڪ مرڊو)", + "Antarctica\/Palmer": "چلي جو وقت (پامر)", + "Antarctica\/Rothera": "روٿيرا جو وقت (روڌرا)", + "Antarctica\/Syowa": "سائيوا جو وقت (سيووا)", + "Antarctica\/Troll": "گرين وچ مين ٽائيم (ٽرول)", + "Antarctica\/Vostok": "ووسٽوڪ جو وقت (ووستوڪ)", + "Arctic\/Longyearbyen": "مرڪزي يورپي وقت (لانگ ائيربن)", + "Asia\/Aden": "عربين جو وقت (عدن)", + "Asia\/Almaty": "اوڀر قزاقستان جو وقت (الماتي)", + "Asia\/Amman": "مشرقي يورپي وقت (امان)", + "Asia\/Aqtau": "اولهه قزاقستان جو وقت (اڪٽائو)", + "Asia\/Aqtobe": "اولهه قزاقستان جو وقت (ايڪٽوب)", + "Asia\/Ashgabat": "ترڪمانستان جو وقت (آشگاباد)", + "Asia\/Atyrau": "اولهه قزاقستان جو وقت (آتيرائو)", + "Asia\/Baghdad": "عربين جو وقت (بغداد)", + "Asia\/Bahrain": "عربين جو وقت (بحرين)", + "Asia\/Baku": "آذربائيجان جو وقت (باڪو)", + "Asia\/Bangkok": "انڊو چائنا جو وقت (بئنڪاڪ)", + "Asia\/Beirut": "مشرقي يورپي وقت (بيروت)", + "Asia\/Bishkek": "ڪرگزستان جو وقت (بشڪيڪ)", + "Asia\/Brunei": "برونائي داروالسلام جو وقت (برونائي)", + "Asia\/Calcutta": "ڀارت جو معياري وقت (ڪلڪتا)", + "Asia\/Chita": "ياڪتسڪ جو وقت (چيتا)", + "Asia\/Choibalsan": "چوئي بيلسن جو وقت (چوئي بيلسن)", + "Asia\/Colombo": "ڀارت جو معياري وقت (ڪولمبو)", + "Asia\/Damascus": "مشرقي يورپي وقت (دمشق)", + "Asia\/Dhaka": "بنگلاديش جو وقت (ڍاڪا)", + "Asia\/Dili": "اوڀر تيمور جو وقت (دلي)", + "Asia\/Dubai": "خلج معياري وقت (دبئي)", + "Asia\/Dushanbe": "تاجڪستان جو وقت (دوشانبي)", + "Asia\/Famagusta": "مشرقي يورپي وقت (فاماگوستا)", + "Asia\/Gaza": "مشرقي يورپي وقت (غزه)", + "Asia\/Hebron": "مشرقي يورپي وقت (هيبرون)", + "Asia\/Hong_Kong": "هانگ ڪانگ جو وقت (هانگ ڪانگ)", + "Asia\/Hovd": "هووڊ جو وقت (هووڊ)", + "Asia\/Irkutsk": "ارڪتسڪ جو وقت (ارڪتسڪ)", + "Asia\/Jakarta": "اولهه انڊونيشيا جو وقت (جڪارتا)", + "Asia\/Jayapura": "اوڀر انڊونيشيا جو وقت (جياپورا)", + "Asia\/Jerusalem": "اسرائيل جو وقت (يوروشلم)", + "Asia\/Kabul": "افغانستان جو وقت (ڪابل)", + "Asia\/Karachi": "پاڪستان جو وقت (ڪراچي)", + "Asia\/Katmandu": "نيپال جو وقت (کٽمنڊو)", + "Asia\/Khandyga": "ياڪتسڪ جو وقت (کندياگا)", + "Asia\/Krasnoyarsk": "ڪریسنویارسڪ جو وقت (ڪريسنويارسڪ)", + "Asia\/Kuala_Lumpur": "ملائيشيا جو وقت (ڪوللمپور)", + "Asia\/Kuching": "ملائيشيا جو وقت (کوچنگ)", + "Asia\/Kuwait": "عربين جو وقت (ڪويت)", + "Asia\/Macau": "چائنا جو وقت (مڪائو)", + "Asia\/Magadan": "مگادان جو وقت (مگادان)", + "Asia\/Makassar": "مرڪزي انڊونيشيا جو وقت (ميڪاسر)", + "Asia\/Manila": "فلپائن جو وقت (منيلا)", + "Asia\/Muscat": "خلج معياري وقت (مسقط)", + "Asia\/Nicosia": "مشرقي يورپي وقت (نيڪوسيا)", + "Asia\/Novokuznetsk": "ڪریسنویارسڪ جو وقت (نووڪزنيتسڪ)", + "Asia\/Novosibirsk": "نوواسبئيرسڪ جو وقت (نوواسبئيرسڪ)", + "Asia\/Omsk": "اومسڪ جو وقت (اومسڪ)", + "Asia\/Oral": "اولهه قزاقستان جو وقت (زباني)", + "Asia\/Phnom_Penh": "انڊو چائنا جو وقت (فنام پينه)", + "Asia\/Pontianak": "اولهه انڊونيشيا جو وقت (پونٽيانڪ)", + "Asia\/Pyongyang": "ڪوريا جو وقت (شيانگ يانگ)", + "Asia\/Qatar": "عربين جو وقت (قطر)", + "Asia\/Qostanay": "اوڀر قزاقستان جو وقت (Qostanay)", + "Asia\/Qyzylorda": "اولهه قزاقستان جو وقت (ڪيزلورڊا)", + "Asia\/Rangoon": "ميانمار جو وقت (رنگون)", + "Asia\/Riyadh": "عربين جو وقت (رياض)", + "Asia\/Saigon": "انڊو چائنا جو وقت (هوچي من)", + "Asia\/Sakhalin": "سخالين جو وقت (شخالين)", + "Asia\/Samarkand": "ازبڪستان جو وقت (سمرقند)", + "Asia\/Seoul": "ڪوريا جو وقت (سيول)", + "Asia\/Shanghai": "چائنا جو وقت (شنگهائي)", + "Asia\/Singapore": "سنگاپور جو معياري وقت (سنگاپور)", + "Asia\/Srednekolymsk": "مگادان جو وقت (سريديڪوليمسڪ)", + "Asia\/Taipei": "تائپي جو وقت (تائپي)", + "Asia\/Tashkent": "ازبڪستان جو وقت (تاشقنت)", + "Asia\/Tbilisi": "جارجيا جو وقت (تبليسي)", + "Asia\/Tehran": "ايران جو وقت (تهران)", + "Asia\/Thimphu": "ڀوٽان جو وقت (ٿمفو)", + "Asia\/Tokyo": "جاپان جو وقت (ٽوڪيو)", + "Asia\/Ulaanbaatar": "اولان باتر جو وقت (اولان باتر)", + "Asia\/Ust-Nera": "ولادووستوڪ جو وقت (اسٽ نيرا)", + "Asia\/Vientiane": "انڊو چائنا جو وقت (وينٽيان)", + "Asia\/Vladivostok": "ولادووستوڪ جو وقت (ولادووستوڪ)", + "Asia\/Yakutsk": "ياڪتسڪ جو وقت (ياڪتسڪ)", + "Asia\/Yekaterinburg": "يڪاٽيرنبرگ جو وقت (یڪاٽرنبرگ)", + "Asia\/Yerevan": "آرمينيا جو وقت (يريوان)", + "Atlantic\/Azores": "ازورز جو وقت (ازورز)", + "Atlantic\/Bermuda": "ايٽلانٽڪ جو وقت (برمودا)", + "Atlantic\/Canary": "مغربي يورپي وقت (ڪينري)", + "Atlantic\/Cape_Verde": "ڪيپ ورڊ جو وقت (ڪيپ ورڊي)", + "Atlantic\/Faeroe": "مغربي يورپي وقت (فيرو)", + "Atlantic\/Madeira": "مغربي يورپي وقت (ماڊيرا)", + "Atlantic\/Reykjavik": "گرين وچ مين ٽائيم (ريڪيوڪ)", + "Atlantic\/South_Georgia": "ڏکڻ جارجيا جو وقت (ڏکڻ جورجيا)", + "Atlantic\/St_Helena": "گرين وچ مين ٽائيم (سينٽ هيلينا)", + "Atlantic\/Stanley": "فاڪ لينڊ آئي لينڊ جو وقت (اسٽينلي)", + "Australia\/Adelaide": "مرڪزي آسٽريليا جو وقت (ايڊيلينڊ)", + "Australia\/Brisbane": "اوڀر آسٽريليا جو وقت (برسبين)", + "Australia\/Broken_Hill": "مرڪزي آسٽريليا جو وقت (بروڪن هل)", + "Australia\/Currie": "اوڀر آسٽريليا جو وقت (ڪري)", + "Australia\/Darwin": "مرڪزي آسٽريليا جو وقت (ڊارون)", + "Australia\/Eucla": "آسٽريليا جو مرڪزي مغربي وقت (يوڪلا)", + "Australia\/Hobart": "اوڀر آسٽريليا جو وقت (هوبارٽ)", + "Australia\/Lindeman": "اوڀر آسٽريليا جو وقت (لنڊمين)", + "Australia\/Lord_Howe": "لورڊ هووي جو وقت (لارڊ هائو)", + "Australia\/Melbourne": "اوڀر آسٽريليا جو وقت (ميلبورن)", + "Australia\/Perth": "مغربي آسٽريليا جو وقت (پرٿ)", + "Australia\/Sydney": "اوڀر آسٽريليا جو وقت (سڊني)", + "CST6CDT": "مرڪزي وقت", + "EST5EDT": "مشرقي وقت", + "Etc\/GMT": "گرين وچ مين ٽائيم", + "Etc\/UTC": "گڏيل دنياوي وقت", + "Europe\/Amsterdam": "مرڪزي يورپي وقت (ايمسٽرڊيم)", + "Europe\/Andorra": "مرڪزي يورپي وقت (اندورا)", + "Europe\/Astrakhan": "ماسڪو جو وقت (آستراخان)", + "Europe\/Athens": "مشرقي يورپي وقت (ايٿنز)", + "Europe\/Belgrade": "مرڪزي يورپي وقت (بلغراد)", + "Europe\/Berlin": "مرڪزي يورپي وقت (برلن)", + "Europe\/Bratislava": "مرڪزي يورپي وقت (براتيسلوا)", + "Europe\/Brussels": "مرڪزي يورپي وقت (برسلز)", + "Europe\/Bucharest": "مشرقي يورپي وقت (بخاريسٽ)", + "Europe\/Budapest": "مرڪزي يورپي وقت (بداپيسٽ)", + "Europe\/Busingen": "مرڪزي يورپي وقت (بزيجين)", + "Europe\/Chisinau": "مشرقي يورپي وقت (چسينائو)", + "Europe\/Copenhagen": "مرڪزي يورپي وقت (ڪوپن هيگن)", + "Europe\/Dublin": "گرين وچ مين ٽائيم (ڊبلن)", + "Europe\/Gibraltar": "مرڪزي يورپي وقت (جبرالٽر)", + "Europe\/Guernsey": "گرين وچ مين ٽائيم (گرنزي)", + "Europe\/Helsinki": "مشرقي يورپي وقت (هيلسنڪي)", + "Europe\/Isle_of_Man": "گرين وچ مين ٽائيم (آئيزل آف مين)", + "Europe\/Jersey": "گرين وچ مين ٽائيم (جرسي)", + "Europe\/Kaliningrad": "مشرقي يورپي وقت (ڪلينن گراڊ)", + "Europe\/Kiev": "مشرقي يورپي وقت (ڪيف)", + "Europe\/Lisbon": "مغربي يورپي وقت (لسبن)", + "Europe\/Ljubljana": "مرڪزي يورپي وقت (لبليانا)", + "Europe\/London": "گرين وچ مين ٽائيم (لنڊن)", + "Europe\/Luxembourg": "مرڪزي يورپي وقت (لگزمبرگ)", + "Europe\/Madrid": "مرڪزي يورپي وقت (ميڊرڊ)", + "Europe\/Malta": "مرڪزي يورپي وقت (مالٽا)", + "Europe\/Mariehamn": "مشرقي يورپي وقت (ميريهام)", + "Europe\/Minsk": "ماسڪو جو وقت (منسڪ)", + "Europe\/Monaco": "مرڪزي يورپي وقت (موناڪو)", + "Europe\/Moscow": "ماسڪو جو وقت (ماسڪو)", + "Europe\/Oslo": "مرڪزي يورپي وقت (اوسلو)", + "Europe\/Paris": "مرڪزي يورپي وقت (پئرس)", + "Europe\/Podgorica": "مرڪزي يورپي وقت (پوڊگورسيا)", + "Europe\/Prague": "مرڪزي يورپي وقت (پراگ)", + "Europe\/Riga": "مشرقي يورپي وقت (رگا)", + "Europe\/Rome": "مرڪزي يورپي وقت (روم)", + "Europe\/San_Marino": "مرڪزي يورپي وقت (سين مرينو)", + "Europe\/Sarajevo": "مرڪزي يورپي وقت (سراجیوو)", + "Europe\/Saratov": "ماسڪو جو وقت (سراتو)", + "Europe\/Simferopol": "ماسڪو جو وقت (سمفروپول)", + "Europe\/Skopje": "مرڪزي يورپي وقت (اسڪوپي)", + "Europe\/Sofia": "مشرقي يورپي وقت (سوفيا)", + "Europe\/Stockholm": "مرڪزي يورپي وقت (اسٽاڪ هوم)", + "Europe\/Tallinn": "مشرقي يورپي وقت (ٽالن)", + "Europe\/Tirane": "مرڪزي يورپي وقت (اراني)", + "Europe\/Ulyanovsk": "ماسڪو جو وقت (اليانوسڪ)", + "Europe\/Uzhgorod": "مشرقي يورپي وقت (ازهارڊ)", + "Europe\/Vaduz": "مرڪزي يورپي وقت (وڊوز)", + "Europe\/Vatican": "مرڪزي يورپي وقت (وئٽيڪن)", + "Europe\/Vienna": "مرڪزي يورپي وقت (وينا)", + "Europe\/Vilnius": "مشرقي يورپي وقت (ويلنيس)", + "Europe\/Volgograd": "وولگوگراد جو وقت (وولگوگراد)", + "Europe\/Warsaw": "مرڪزي يورپي وقت (وارسا)", + "Europe\/Zagreb": "مرڪزي يورپي وقت (زغرب)", + "Europe\/Zaporozhye": "مشرقي يورپي وقت (زيپروزهايا)", + "Europe\/Zurich": "مرڪزي يورپي وقت (زيورخ)", + "Indian\/Antananarivo": "اوڀر آفريڪا جو وقت (انتاناناريوو)", + "Indian\/Chagos": "هند سمنڊ جو وقت (چاگوس)", + "Indian\/Christmas": "ڪرسمس آئي لينڊ جو وقت (ڪرسمس)", + "Indian\/Cocos": "ڪوڪوس آئي لينڊ جو وقت (ڪوڪوس)", + "Indian\/Comoro": "اوڀر آفريڪا جو وقت (ڪومورو)", + "Indian\/Kerguelen": "فرانسيسي ڏاکڻي ۽ انٽارڪٽڪ جو وقت (ڪرگيولين)", + "Indian\/Mahe": "شي شلز جو وقت (ماهي)", + "Indian\/Maldives": "مالديپ جو وقت (مالديپ)", + "Indian\/Mauritius": "موريشيس جو وقت (موريشس)", + "Indian\/Mayotte": "اوڀر آفريڪا جو وقت (مياٽي)", + "Indian\/Reunion": "ري يونين جو وقت (ري يونين)", + "MST7MDT": "پهاڙي وقت", + "PST8PDT": "پيسيفڪ وقت", + "Pacific\/Apia": "اپيا جو وقت (اپيا)", + "Pacific\/Auckland": "نيوزيلينڊ جو وقت (آڪلينڊ)", + "Pacific\/Bougainville": "پاپوا نيو گني جو وقت (بوگين ويليا)", + "Pacific\/Chatham": "چئٿم جو وقت (چئٿم)", + "Pacific\/Easter": "ايسٽر آئي لينڊ جو وقت (ايسٽر)", + "Pacific\/Efate": "وانواتو جو وقت (افاتي)", + "Pacific\/Enderbury": "فونيڪس آئي لينڊ جو وقت (اينڊربري)", + "Pacific\/Fakaofo": "ٽوڪيلائو جو وقت (فڪائوفو)", + "Pacific\/Fiji": "فجي جو وقت (فجي)", + "Pacific\/Funafuti": "تووالو جو وقت (فنافوٽي)", + "Pacific\/Galapagos": "گالاپاگوز جو وقت (گالاپاگوز)", + "Pacific\/Gambier": "گيمبيئر جو وقت (گيمبيئر)", + "Pacific\/Guadalcanal": "سولومن آئي لينڊ جو وقت (گواڊل ڪينال)", + "Pacific\/Guam": "چمورو جو معياري وقت (گوام)", + "Pacific\/Honolulu": "هوائي اليوٽين جو وقت (هونو لولو)", + "Pacific\/Johnston": "هوائي اليوٽين جو وقت (جانسٹن)", + "Pacific\/Kiritimati": "لائن آئي لينڊ جو وقت (ڪريٽمٽي)", + "Pacific\/Kosrae": "ڪوسرائي جو وقت (ڪوسرائي)", + "Pacific\/Kwajalein": "مارشل آئي لينڊ جو وقت (ڪواجلين)", + "Pacific\/Majuro": "مارشل آئي لينڊ جو وقت (مجورو)", + "Pacific\/Marquesas": "مرڪيوسس جو وقت (مرڪيوسس)", + "Pacific\/Midway": "ساموا جو وقت (مڊوي)", + "Pacific\/Nauru": "نائورو جو وقت (نائرو)", + "Pacific\/Niue": "نيووي جو وقت (نيووي)", + "Pacific\/Norfolk": "نار فوڪ آئي لينڊ جو وقت (نار فوڪ)", + "Pacific\/Noumea": "نيو ڪيليڊونيا جو وقت (نائوميا)", + "Pacific\/Pago_Pago": "ساموا جو وقت (پاگو پاگو)", + "Pacific\/Palau": "پلائو جو وقت (پلائو)", + "Pacific\/Pitcairn": "پٽڪيرن جو وقت (پٽڪيرن)", + "Pacific\/Ponape": "پوناپي جو وقت (پونپیئي)", + "Pacific\/Port_Moresby": "پاپوا نيو گني جو وقت (پورٽ مورسبي)", + "Pacific\/Rarotonga": "ڪوڪ آئي لينڊ جو وقت (راروٽونگا)", + "Pacific\/Saipan": "چمورو جو معياري وقت (سيپن)", + "Pacific\/Tahiti": "تاهيٽي جو وقت (تاهٽي)", + "Pacific\/Tarawa": "گلبرٽ آئي لينڊ جو وقت (تراوا)", + "Pacific\/Tongatapu": "ٽونگا جو وقت (ٽونگاٽاپو)", + "Pacific\/Truk": "چيوڪ جو وقت (چيوڪ)", + "Pacific\/Wake": "ويڪ آئي لينڊ جو وقت (ويڪ)", + "Pacific\/Wallis": "ويلس ۽ فتونا جو وقت (ويلس)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/se.json b/src/Symfony/Component/Intl/Resources/data/timezones/se.json new file mode 100644 index 0000000000000..5234f10252653 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/se.json @@ -0,0 +1,97 @@ +{ + "Version": "2.1.48.4", + "Names": { + "Africa\/Abidjan": "Greenwich gaskka áigi (Abidjan)", + "Africa\/Accra": "Greenwich gaskka áigi (Accra)", + "Africa\/Algiers": "gaska-Eurohpá áigi (Algiers)", + "Africa\/Bamako": "Greenwich gaskka áigi (Bamako)", + "Africa\/Banjul": "Greenwich gaskka áigi (Banjul)", + "Africa\/Bissau": "Greenwich gaskka áigi (Bissau)", + "Africa\/Cairo": "nuorti-Eurohpá áigi (Cairo)", + "Africa\/Casablanca": "oarje-Eurohpá áigi (Casablanca)", + "Africa\/Ceuta": "gaska-Eurohpá áigi (Ceuta)", + "Africa\/Conakry": "Greenwich gaskka áigi (Conakry)", + "Africa\/Dakar": "Greenwich gaskka áigi (Dakar)", + "Africa\/El_Aaiun": "oarje-Eurohpá áigi (El Aaiun)", + "Africa\/Freetown": "Greenwich gaskka áigi (Freetown)", + "Africa\/Lome": "Greenwich gaskka áigi (Lome)", + "Africa\/Monrovia": "Greenwich gaskka áigi (Monrovia)", + "Africa\/Nouakchott": "Greenwich gaskka áigi (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich gaskka áigi (Ouagadougou)", + "Africa\/Sao_Tome": "Greenwich gaskka áigi (Sao Tome)", + "Africa\/Tripoli": "nuorti-Eurohpá áigi (Tripoli)", + "Africa\/Tunis": "gaska-Eurohpá áigi (Tunis)", + "America\/Danmarkshavn": "Greenwich gaskka áigi (Danmarkshavn)", + "Antarctica\/Troll": "Greenwich gaskka áigi (Troll)", + "Arctic\/Longyearbyen": "gaska-Eurohpá áigi (Longyearbyen)", + "Asia\/Amman": "nuorti-Eurohpá áigi (Amman)", + "Asia\/Beirut": "nuorti-Eurohpá áigi (Beirut)", + "Asia\/Damascus": "nuorti-Eurohpá áigi (Damascus)", + "Asia\/Famagusta": "nuorti-Eurohpá áigi (Famagusta)", + "Asia\/Gaza": "nuorti-Eurohpá áigi (Gaza)", + "Asia\/Hebron": "nuorti-Eurohpá áigi (Hebron)", + "Asia\/Nicosia": "nuorti-Eurohpá áigi (Nicosia)", + "Atlantic\/Canary": "oarje-Eurohpá áigi (Canary)", + "Atlantic\/Faeroe": "oarje-Eurohpá áigi (Faroe)", + "Atlantic\/Madeira": "oarje-Eurohpá áigi (Madeira)", + "Atlantic\/Reykjavik": "Greenwich gaskka áigi (Reykjavik)", + "Atlantic\/St_Helena": "Greenwich gaskka áigi (St. Helena)", + "Etc\/GMT": "Greenwich gaskka áigi", + "Europe\/Amsterdam": "gaska-Eurohpá áigi (Amsterdam)", + "Europe\/Andorra": "gaska-Eurohpá áigi (Andorra)", + "Europe\/Astrakhan": "Moskva-áigi (Astrakhan)", + "Europe\/Athens": "nuorti-Eurohpá áigi (Athens)", + "Europe\/Belgrade": "gaska-Eurohpá áigi (Belgrade)", + "Europe\/Berlin": "gaska-Eurohpá áigi (Berlin)", + "Europe\/Bratislava": "gaska-Eurohpá áigi (Bratislava)", + "Europe\/Brussels": "gaska-Eurohpá áigi (Brussels)", + "Europe\/Bucharest": "nuorti-Eurohpá áigi (Bucharest)", + "Europe\/Budapest": "gaska-Eurohpá áigi (Budapest)", + "Europe\/Busingen": "gaska-Eurohpá áigi (Busingen)", + "Europe\/Chisinau": "nuorti-Eurohpá áigi (Chisinau)", + "Europe\/Copenhagen": "gaska-Eurohpá áigi (Copenhagen)", + "Europe\/Dublin": "Greenwich gaskka áigi (Dublin)", + "Europe\/Gibraltar": "gaska-Eurohpá áigi (Gibraltar)", + "Europe\/Guernsey": "Greenwich gaskka áigi (Guernsey)", + "Europe\/Helsinki": "nuorti-Eurohpá áigi (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich gaskka áigi (Isle of Man)", + "Europe\/Jersey": "Greenwich gaskka áigi (Jersey)", + "Europe\/Kaliningrad": "nuorti-Eurohpá áigi (Kaliningrad)", + "Europe\/Kiev": "nuorti-Eurohpá áigi (Kiev)", + "Europe\/Lisbon": "oarje-Eurohpá áigi (Lisbon)", + "Europe\/Ljubljana": "gaska-Eurohpá áigi (Ljubljana)", + "Europe\/London": "Greenwich gaskka áigi (London)", + "Europe\/Luxembourg": "gaska-Eurohpá áigi (Luxembourg)", + "Europe\/Madrid": "gaska-Eurohpá áigi (Madrid)", + "Europe\/Malta": "gaska-Eurohpá áigi (Malta)", + "Europe\/Mariehamn": "nuorti-Eurohpá áigi (Mariehamn)", + "Europe\/Minsk": "Moskva-áigi (Minsk)", + "Europe\/Monaco": "gaska-Eurohpá áigi (Monaco)", + "Europe\/Moscow": "Moskva-áigi (Moscow)", + "Europe\/Oslo": "gaska-Eurohpá áigi (Oslo)", + "Europe\/Paris": "gaska-Eurohpá áigi (Paris)", + "Europe\/Podgorica": "gaska-Eurohpá áigi (Podgorica)", + "Europe\/Prague": "gaska-Eurohpá áigi (Prague)", + "Europe\/Riga": "nuorti-Eurohpá áigi (Riga)", + "Europe\/Rome": "gaska-Eurohpá áigi (Rome)", + "Europe\/San_Marino": "gaska-Eurohpá áigi (San Marino)", + "Europe\/Sarajevo": "gaska-Eurohpá áigi (Sarajevo)", + "Europe\/Saratov": "Moskva-áigi (Saratov)", + "Europe\/Simferopol": "Moskva-áigi (Simferopol)", + "Europe\/Skopje": "gaska-Eurohpá áigi (Skopje)", + "Europe\/Sofia": "nuorti-Eurohpá áigi (Sofia)", + "Europe\/Stockholm": "gaska-Eurohpá áigi (Stockholm)", + "Europe\/Tallinn": "nuorti-Eurohpá áigi (Tallinn)", + "Europe\/Tirane": "gaska-Eurohpá áigi (Tirane)", + "Europe\/Ulyanovsk": "Moskva-áigi (Ulyanovsk)", + "Europe\/Uzhgorod": "nuorti-Eurohpá áigi (Uzhgorod)", + "Europe\/Vaduz": "gaska-Eurohpá áigi (Vaduz)", + "Europe\/Vatican": "gaska-Eurohpá áigi (Vatican)", + "Europe\/Vienna": "gaska-Eurohpá áigi (Vienna)", + "Europe\/Vilnius": "nuorti-Eurohpá áigi (Vilnius)", + "Europe\/Warsaw": "gaska-Eurohpá áigi (Warsaw)", + "Europe\/Zagreb": "gaska-Eurohpá áigi (Zagreb)", + "Europe\/Zaporozhye": "nuorti-Eurohpá áigi (Zaporozhye)", + "Europe\/Zurich": "gaska-Eurohpá áigi (Zurich)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/se_FI.json b/src/Symfony/Component/Intl/Resources/data/timezones/se_FI.json new file mode 100644 index 0000000000000..ad34028efee9d --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/se_FI.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.47.83", + "Names": { + "Africa\/Abidjan": "Greenwicha áigi (Abidjan)", + "Africa\/Accra": "Greenwicha áigi (Accra)", + "Africa\/Addis_Ababa": "Nuorta-Afrihká áigi (Addis Ababa)", + "Africa\/Algiers": "Gaska-Eurohpá áigi (Algiers)", + "Africa\/Asmera": "Nuorta-Afrihká áigi (Asmara)", + "Africa\/Bamako": "Greenwicha áigi (Bamako)", + "Africa\/Bangui": "Oarje-Afrihká áigi (Bangui)", + "Africa\/Banjul": "Greenwicha áigi (Banjul)", + "Africa\/Bissau": "Greenwicha áigi (Bissau)", + "Africa\/Blantyre": "Gaska-Afrihká áigi (Blantyre)", + "Africa\/Brazzaville": "Oarje-Afrihká áigi (Brazzaville)", + "Africa\/Bujumbura": "Gaska-Afrihká áigi (Bujumbura)", + "Africa\/Cairo": "Nuorta-Eurohpa áigi (Kairo)", + "Africa\/Casablanca": "Oarje-Eurohpá áigi (Casablanca)", + "Africa\/Ceuta": "Gaska-Eurohpá áigi (Ceuta)", + "Africa\/Conakry": "Greenwicha áigi (Conakry)", + "Africa\/Dakar": "Greenwicha áigi (Dakar)", + "Africa\/Dar_es_Salaam": "Nuorta-Afrihká áigi (Dar es Salaam)", + "Africa\/Djibouti": "Nuorta-Afrihká áigi (Djibouti)", + "Africa\/Douala": "Oarje-Afrihká áigi (Douala)", + "Africa\/El_Aaiun": "Oarje-Eurohpá áigi (El Aaiun)", + "Africa\/Freetown": "Greenwicha áigi (Freetown)", + "Africa\/Gaborone": "Gaska-Afrihká áigi (Gaborone)", + "Africa\/Harare": "Gaska-Afrihká áigi (Harare)", + "Africa\/Johannesburg": "Lulli-Afrihká dálveáigi (Johannesburg)", + "Africa\/Juba": "Nuorta-Afrihká áigi (Juba)", + "Africa\/Kampala": "Nuorta-Afrihká áigi (Kampala)", + "Africa\/Khartoum": "Gaska-Afrihká áigi (Khartoum)", + "Africa\/Kigali": "Gaska-Afrihká áigi (Kigali)", + "Africa\/Kinshasa": "Oarje-Afrihká áigi (Kinshasa)", + "Africa\/Lagos": "Oarje-Afrihká áigi (Lagos)", + "Africa\/Libreville": "Oarje-Afrihká áigi (Libreville)", + "Africa\/Lome": "Greenwicha áigi (Lome)", + "Africa\/Luanda": "Oarje-Afrihká áigi (Luanda)", + "Africa\/Lubumbashi": "Gaska-Afrihká áigi (Lubumbashi)", + "Africa\/Lusaka": "Gaska-Afrihká áigi (Lusaka)", + "Africa\/Malabo": "Oarje-Afrihká áigi (Malabo)", + "Africa\/Maputo": "Gaska-Afrihká áigi (Maputo)", + "Africa\/Maseru": "Lulli-Afrihká dálveáigi (Maseru)", + "Africa\/Mbabane": "Lulli-Afrihká dálveáigi (Mbabane)", + "Africa\/Mogadishu": "Nuorta-Afrihká áigi (Mogadishu)", + "Africa\/Monrovia": "Greenwicha áigi (Monrovia)", + "Africa\/Nairobi": "Nuorta-Afrihká áigi (Nairobi)", + "Africa\/Ndjamena": "Oarje-Afrihká áigi (Ndjamena)", + "Africa\/Niamey": "Oarje-Afrihká áigi (Niamey)", + "Africa\/Nouakchott": "Greenwicha áigi (Nouakchott)", + "Africa\/Ouagadougou": "Greenwicha áigi (Ouagadougou)", + "Africa\/Porto-Novo": "Oarje-Afrihká áigi (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwicha áigi (Sao Tome)", + "Africa\/Tripoli": "Nuorta-Eurohpa áigi (Tripoli)", + "Africa\/Tunis": "Gaska-Eurohpá áigi (Tunis)", + "Africa\/Windhoek": "Gaska-Afrihká áigi (Windhoek)", + "America\/Adak": "Hawaii-aleuhtalaš áigi (Adak)", + "America\/Anchorage": "Alaska áigi (Anchorage)", + "America\/Anguilla": "atlántalaš áigi (Anguilla)", + "America\/Antigua": "atlántalaš áigi (Antigua)", + "America\/Araguaina": "Brasilia áigi (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentina áigi (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentina áigi (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentina áigi (Salta)", + "America\/Argentina\/San_Juan": "Argentina áigi (San Juan)", + "America\/Argentina\/San_Luis": "Oarje-Argentina áigi (San Luis)", + "America\/Argentina\/Tucuman": "Argentina áigi (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentina áigi (Ushuaia)", + "America\/Aruba": "atlántalaš áigi (Aruba)", + "America\/Asuncion": "Paraguaya áigi (Asuncion)", + "America\/Bahia": "Brasilia áigi (Bahia)", + "America\/Bahia_Banderas": "dábálašáigi (Bahia Banderas)", + "America\/Barbados": "atlántalaš áigi (Barbados)", + "America\/Belem": "Brasilia áigi (Belem)", + "America\/Belize": "dábálašáigi (Belize)", + "America\/Blanc-Sablon": "atlántalaš áigi (Blanc-Sablon)", + "America\/Boa_Vista": "Amazona áigi (Boa Vista)", + "America\/Bogota": "Colombia áigi (Bogota)", + "America\/Boise": "duottaráigi (Boise)", + "America\/Buenos_Aires": "Argentina áigi (Buenos Aires)", + "America\/Cambridge_Bay": "duottaráigi (Cambridge Bay)", + "America\/Campo_Grande": "Amazona áigi (Campo Grande)", + "America\/Cancun": "áigi nuortan (Cancun)", + "America\/Caracas": "Venezuela áigi (Caracas)", + "America\/Catamarca": "Argentina áigi (Catamarca)", + "America\/Cayenne": "Frankriikka Guyana áigi (Cayenne)", + "America\/Cayman": "áigi nuortan (Cayman)", + "America\/Chicago": "dábálašáigi (Chicago)", + "America\/Chihuahua": "Meksiko Jáskesábi áigi (Chihuahua)", + "America\/Coral_Harbour": "áigi nuortan (Atikokan)", + "America\/Cordoba": "Argentina áigi (Cordoba)", + "America\/Costa_Rica": "dábálašáigi (Costa Rica)", + "America\/Creston": "duottaráigi (Creston)", + "America\/Cuiaba": "Amazona áigi (Cuiaba)", + "America\/Curacao": "atlántalaš áigi (Curacao)", + "America\/Danmarkshavn": "Greenwicha áigi (Dánmárkkuhámman)", + "America\/Dawson": "Jaskesábi áigi (Dawson)", + "America\/Dawson_Creek": "duottaráigi (Dawson Creek)", + "America\/Denver": "duottaráigi (Denver)", + "America\/Detroit": "áigi nuortan (Detroit)", + "America\/Dominica": "atlántalaš áigi (Dominica)", + "America\/Edmonton": "duottaráigi (Edmonton)", + "America\/El_Salvador": "dábálašáigi (El Salvador)", + "America\/Fort_Nelson": "duottaráigi (Fort Nelson)", + "America\/Fortaleza": "Brasilia áigi (Fortaleza)", + "America\/Glace_Bay": "atlántalaš áigi (Glace Bay)", + "America\/Godthab": "Oarje-Ruonáeatnama áigi (Nuuk)", + "America\/Goose_Bay": "atlántalaš áigi (Goose Bay)", + "America\/Grand_Turk": "áigi nuortan (Grand Turk)", + "America\/Grenada": "atlántalaš áigi (Grenada)", + "America\/Guadeloupe": "atlántalaš áigi (Guadeloupe)", + "America\/Guatemala": "dábálašáigi (Guatemala)", + "America\/Guayaquil": "Ecuadora áigi (Guayaquil)", + "America\/Guyana": "Guyana áigi (Guyana)", + "America\/Halifax": "atlántalaš áigi (Halifax)", + "America\/Havana": "Cuba áigi (Havana)", + "America\/Hermosillo": "Meksiko Jáskesábi áigi (Hermosillo)", + "America\/Indiana\/Knox": "dábálašáigi (Knox, Indiana)", + "America\/Indiana\/Marengo": "áigi nuortan (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "áigi nuortan (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "dábálašáigi (Tell City, Indiana)", + "America\/Indiana\/Vevay": "áigi nuortan (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "áigi nuortan (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "áigi nuortan (Winamac, Indiana)", + "America\/Indianapolis": "áigi nuortan (Indianapolis)", + "America\/Inuvik": "duottaráigi (Inuvik)", + "America\/Iqaluit": "áigi nuortan (Iqaluit)", + "America\/Jamaica": "áigi nuortan (Jamaica)", + "America\/Jujuy": "Argentina áigi (Jujuy)", + "America\/Juneau": "Alaska áigi (Juneau)", + "America\/Kentucky\/Monticello": "áigi nuortan (Monticello, Kentucky)", + "America\/Kralendijk": "atlántalaš áigi (Kralendijk)", + "America\/La_Paz": "Bolivia áigi (La Paz)", + "America\/Lima": "Peru áigi (Lima)", + "America\/Los_Angeles": "Jaskesábi áigi (Los Angeles)", + "America\/Louisville": "áigi nuortan (Louisville)", + "America\/Lower_Princes": "atlántalaš áigi (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilia áigi (Maceio)", + "America\/Managua": "dábálašáigi (Managua)", + "America\/Manaus": "Amazona áigi (Manaus)", + "America\/Marigot": "atlántalaš áigi (Marigot)", + "America\/Martinique": "atlántalaš áigi (Martinique)", + "America\/Matamoros": "dábálašáigi (Matamoros)", + "America\/Mazatlan": "Meksiko Jáskesábi áigi (Mazatlan)", + "America\/Mendoza": "Argentina áigi (Mendoza)", + "America\/Menominee": "dábálašáigi (Menominee)", + "America\/Merida": "dábálašáigi (Merida)", + "America\/Metlakatla": "Alaska áigi (Metlakatla)", + "America\/Mexico_City": "dábálašáigi (Mexico City)", + "America\/Miquelon": "St. Pierre & Miquelo áigi (Miquelon)", + "America\/Moncton": "atlántalaš áigi (Moncton)", + "America\/Monterrey": "dábálašáigi (Monterrey)", + "America\/Montevideo": "Uruguaya áigi (Montevideo)", + "America\/Montserrat": "atlántalaš áigi (Montserrat)", + "America\/Nassau": "áigi nuortan (Nassau)", + "America\/New_York": "áigi nuortan (New York)", + "America\/Nipigon": "áigi nuortan (Nipigon)", + "America\/Nome": "Alaska áigi (Nome)", + "America\/Noronha": "Fernando de Noronha áigi (Noronha)", + "America\/North_Dakota\/Beulah": "dábálašáigi (Beulah, Davvi-Dakota)", + "America\/North_Dakota\/Center": "dábálašáigi (Guovddáš, Davvi-Dakota)", + "America\/North_Dakota\/New_Salem": "dábálašáigi (New Salem, Davvi-Dakota)", + "America\/Ojinaga": "duottaráigi (Ojinaga)", + "America\/Panama": "áigi nuortan (Panama)", + "America\/Pangnirtung": "áigi nuortan (Pangnirtung)", + "America\/Paramaribo": "Suriname áigi (Paramaribo)", + "America\/Phoenix": "duottaráigi (Phoenix)", + "America\/Port-au-Prince": "áigi nuortan (Port-au-Prince)", + "America\/Port_of_Spain": "atlántalaš áigi (Port of Spain)", + "America\/Porto_Velho": "Amazona áigi (Porto Velho)", + "America\/Puerto_Rico": "atlántalaš áigi (Puerto Rico)", + "America\/Punta_Arenas": "Chile áigi (Punta Arenas)", + "America\/Rainy_River": "dábálašáigi (Rainy River)", + "America\/Rankin_Inlet": "dábálašáigi (Rankin Inlet)", + "America\/Recife": "Brasilia áigi (Recife)", + "America\/Regina": "dábálašáigi (Regina)", + "America\/Resolute": "dábálašáigi (Resolute)", + "America\/Santa_Isabel": "Oarjedavvi-Meksiko áigi (Santa Isabel)", + "America\/Santarem": "Brasilia áigi (Santarem)", + "America\/Santiago": "Chile áigi (Santiago)", + "America\/Santo_Domingo": "atlántalaš áigi (Santo Domingo)", + "America\/Sao_Paulo": "Brasilia áigi (Sao Paulo)", + "America\/Scoresbysund": "Nuorta-Ruonáeatnama áigi (Ittoqqortoormiit)", + "America\/Sitka": "Alaska áigi (Sitka)", + "America\/St_Barthelemy": "atlántalaš áigi (St. Barthelemy)", + "America\/St_Johns": "Newfoundlanda áigi (St. John’s)", + "America\/St_Kitts": "atlántalaš áigi (St. Kitts)", + "America\/St_Lucia": "atlántalaš áigi (St. Lucia)", + "America\/St_Thomas": "atlántalaš áigi (St. Thomas)", + "America\/St_Vincent": "atlántalaš áigi (St. Vincent)", + "America\/Swift_Current": "dábálašáigi (Swift Current)", + "America\/Tegucigalpa": "dábálašáigi (Tegucigalpa)", + "America\/Thule": "atlántalaš áigi (Thule)", + "America\/Thunder_Bay": "áigi nuortan (Thunder Bay)", + "America\/Tijuana": "Jaskesábi áigi (Tijuana)", + "America\/Toronto": "áigi nuortan (Toronto)", + "America\/Tortola": "atlántalaš áigi (Tortola)", + "America\/Vancouver": "Jaskesábi áigi (Vancouver)", + "America\/Whitehorse": "Jaskesábi áigi (Whitehorse)", + "America\/Winnipeg": "dábálašáigi (Winnipeg)", + "America\/Yakutat": "Alaska áigi (Yakutat)", + "America\/Yellowknife": "duottaráigi (Yellowknife)", + "Antarctica\/Casey": "Oarje-Austrália áigi (Casey)", + "Antarctica\/Davis": "Davisa áigi (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville áigi (Dumont d’Urville)", + "Antarctica\/Macquarie": "MacQuarie sullo áigi (Macquarie)", + "Antarctica\/Mawson": "Mawsona áigi (Mawson)", + "Antarctica\/McMurdo": "Ođđa-Selánda áigi (McMurdo)", + "Antarctica\/Palmer": "Chile áigi (Palmer)", + "Antarctica\/Rothera": "Rothera áigi (Rothera)", + "Antarctica\/Syowa": "Syowa áigi (Syowa)", + "Antarctica\/Troll": "Greenwicha áigi (Troll)", + "Antarctica\/Vostok": "Vostoka áigi (Vostok)", + "Arctic\/Longyearbyen": "Gaska-Eurohpá áigi (Longyearbyen)", + "Asia\/Aden": "Arábia áigi (Aden)", + "Asia\/Almaty": "Nuorta-Kasakstana áigi (Almaty)", + "Asia\/Amman": "Nuorta-Eurohpa áigi (Amman)", + "Asia\/Aqtau": "Oarje-Kasakstana áigi (Aqtau)", + "Asia\/Aqtobe": "Oarje-Kasakstana áigi (Aqtobe)", + "Asia\/Ashgabat": "Turkmenistana áigi (Ashgabat)", + "Asia\/Atyrau": "Oarje-Kasakstana áigi (Atyrau)", + "Asia\/Baghdad": "Arábia áigi (Baghdad)", + "Asia\/Bahrain": "Arábia áigi (Bahrain)", + "Asia\/Baku": "Aserbaižana áigi (Baku)", + "Asia\/Bangkok": "Indokiinná áigi (Bangkok)", + "Asia\/Beirut": "Nuorta-Eurohpa áigi (Beirut)", + "Asia\/Bishkek": "Kirgisia áigi (Bishkek)", + "Asia\/Brunei": "Brunei Darussalama áigi (Brunei)", + "Asia\/Calcutta": "India dálveáigi (Kolkata)", + "Asia\/Chita": "Jakucka áigi (Chita)", + "Asia\/Choibalsan": "Choibolsana áigi (Choibalsan)", + "Asia\/Colombo": "India dálveáigi (Colombo)", + "Asia\/Damascus": "Nuorta-Eurohpa áigi (Damaskos)", + "Asia\/Dhaka": "Bangladesha áigi (Dhaka)", + "Asia\/Dili": "Nuorta-Timora áigi (Dili)", + "Asia\/Dubai": "Golfa dálveáigi (Dubai)", + "Asia\/Dushanbe": "Tažikistana áigi (Dushanbe)", + "Asia\/Famagusta": "Nuorta-Eurohpa áigi (Famagusta)", + "Asia\/Gaza": "Nuorta-Eurohpa áigi (Gaza)", + "Asia\/Hebron": "Nuorta-Eurohpa áigi (Hebron)", + "Asia\/Hong_Kong": "Hong Konga áigi (Hong Kong)", + "Asia\/Hovd": "Hovda áigi (Hovd)", + "Asia\/Irkutsk": "Irkucka áigi (Irkuck)", + "Asia\/Jakarta": "Oarje-Indonesia áigi (Jakarta)", + "Asia\/Jayapura": "Nuorta-Indonesia áigi (Jayapura)", + "Asia\/Jerusalem": "Israela áigi (Jerusalem)", + "Asia\/Kabul": "Afganisthana áigi (Kabul)", + "Asia\/Karachi": "Pakistana áigi (Karachi)", + "Asia\/Katmandu": "Nepala áigi (Kathmandu)", + "Asia\/Khandyga": "Jakucka áigi (Khandyga)", + "Asia\/Krasnoyarsk": "Krasnojarska áigi (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malesia áigi (Kuala Lumpur)", + "Asia\/Kuching": "Malesia áigi (Kuching)", + "Asia\/Kuwait": "Arábia áigi (Kuwait)", + "Asia\/Macau": "Kiinná áigi (Macao)", + "Asia\/Magadan": "Magadana áigi (Magadan)", + "Asia\/Makassar": "Gaska-Indonesia áigi (Makassar)", + "Asia\/Manila": "Filippiinnaid áigi (Manila)", + "Asia\/Muscat": "Golfa dálveáigi (Muscat)", + "Asia\/Nicosia": "Nuorta-Eurohpa áigi (Nicosia)", + "Asia\/Novokuznetsk": "Krasnojarska áigi (Novokusneck)", + "Asia\/Novosibirsk": "Novosibirska áigi (Novosibirsk)", + "Asia\/Omsk": "Omska áigi (Omsk)", + "Asia\/Oral": "Oarje-Kasakstana áigi (Oral)", + "Asia\/Phnom_Penh": "Indokiinná áigi (Phnom Penh)", + "Asia\/Pontianak": "Oarje-Indonesia áigi (Pontianak)", + "Asia\/Pyongyang": "Korea áigi (Pyongyang)", + "Asia\/Qatar": "Arábia áigi (Qatar)", + "Asia\/Qostanay": "Nuorta-Kasakstana áigi (Qostanay)", + "Asia\/Qyzylorda": "Oarje-Kasakstana áigi (Qyzylorda)", + "Asia\/Rangoon": "Myanmara áigi (Rangoon)", + "Asia\/Riyadh": "Arábia áigi (Riyadh)", + "Asia\/Saigon": "Indokiinná áigi (Ho Chi Minh)", + "Asia\/Sakhalin": "Sahalina áigi (Sahalin)", + "Asia\/Samarkand": "Usbekistana áigi (Samarkand)", + "Asia\/Seoul": "Korea áigi (Seoul)", + "Asia\/Shanghai": "Kiinná áigi (Shanghai)", + "Asia\/Singapore": "Singapore dálveáigi (Singapore)", + "Asia\/Srednekolymsk": "Magadana áigi (Srednekolymsk)", + "Asia\/Taipei": "Taipeia áigi (Taipei)", + "Asia\/Tashkent": "Usbekistana áigi (Tashkent)", + "Asia\/Tbilisi": "Georgia áigi (Tbilisi)", + "Asia\/Tehran": "Irana áigi (Teheran)", + "Asia\/Thimphu": "Bhutana áigi (Thimphu)", + "Asia\/Tokyo": "Japána áigi (Tokyo)", + "Asia\/Ulaanbaatar": "Ulan-Batora áigi (Ulan-Bator)", + "Asia\/Ust-Nera": "Vladivostoka áigi (Ust-Nera)", + "Asia\/Vientiane": "Indokiinná áigi (Vientiane)", + "Asia\/Vladivostok": "Vladivostoka áigi (Vladivostok)", + "Asia\/Yakutsk": "Jakucka áigi (Jakuck)", + "Asia\/Yekaterinburg": "Jekaterinburga áigi (Jekaterinburg)", + "Asia\/Yerevan": "Armenia áigi (Jerevan)", + "Atlantic\/Azores": "Azoraid áigi (Azorat)", + "Atlantic\/Bermuda": "atlántalaš áigi (Bermuda)", + "Atlantic\/Canary": "Oarje-Eurohpá áigi (Kanária)", + "Atlantic\/Cape_Verde": "Kap Verde áigi (Kap Verde)", + "Atlantic\/Faeroe": "Oarje-Eurohpá áigi (Faroe)", + "Atlantic\/Madeira": "Oarje-Eurohpá áigi (Madeira)", + "Atlantic\/Reykjavik": "Greenwicha áigi (Reykjavik)", + "Atlantic\/South_Georgia": "Lulli-Georgia áigi (Lulli-Georgia)", + "Atlantic\/St_Helena": "Greenwicha áigi (St. Helena)", + "Atlantic\/Stanley": "Falklandsulluid áigi (Stanley)", + "Australia\/Adelaide": "Gaska-Austrália áigi (Adelaide)", + "Australia\/Brisbane": "Nuorta-Austrália áigi (Brisbane)", + "Australia\/Broken_Hill": "Gaska-Austrália áigi (Broken Hill)", + "Australia\/Currie": "Nuorta-Austrália áigi (Currie)", + "Australia\/Darwin": "Gaska-Austrália áigi (Darwin)", + "Australia\/Eucla": "Gaska-Austrália oarjjabeali áigi (Eucla)", + "Australia\/Hobart": "Nuorta-Austrália áigi (Hobart)", + "Australia\/Lindeman": "Nuorta-Austrália áigi (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe áigi (Lord Howe)", + "Australia\/Melbourne": "Nuorta-Austrália áigi (Melbourne)", + "Australia\/Perth": "Oarje-Austrália áigi (Perth)", + "Australia\/Sydney": "Nuorta-Austrália áigi (Sydney)", + "CST6CDT": "dábálašáigi", + "EST5EDT": "áigi nuortan", + "Etc\/GMT": "Greenwicha áigi", + "Etc\/UTC": "koordinerejuvvon oktasaš áigi", + "Europe\/Amsterdam": "Gaska-Eurohpá áigi (Amsterdam)", + "Europe\/Andorra": "Gaska-Eurohpá áigi (Andorra)", + "Europe\/Astrakhan": "Moskva áigi (Astrakhan)", + "Europe\/Athens": "Nuorta-Eurohpa áigi (Athena)", + "Europe\/Belgrade": "Gaska-Eurohpá áigi (Belgrad)", + "Europe\/Berlin": "Gaska-Eurohpá áigi (Berlin)", + "Europe\/Bratislava": "Gaska-Eurohpá áigi (Bratislava)", + "Europe\/Brussels": "Gaska-Eurohpá áigi (Brüssel)", + "Europe\/Bucharest": "Nuorta-Eurohpa áigi (Bukarest)", + "Europe\/Budapest": "Gaska-Eurohpá áigi (Budapest)", + "Europe\/Busingen": "Gaska-Eurohpá áigi (Busingen)", + "Europe\/Chisinau": "Nuorta-Eurohpa áigi (Chisinau)", + "Europe\/Copenhagen": "Gaska-Eurohpá áigi (København)", + "Europe\/Dublin": "Greenwicha áigi (Dublin)", + "Europe\/Gibraltar": "Gaska-Eurohpá áigi (Gibraltar)", + "Europe\/Guernsey": "Greenwicha áigi (Guernsey)", + "Europe\/Helsinki": "Nuorta-Eurohpa áigi (Helsset)", + "Europe\/Isle_of_Man": "Greenwicha áigi (Mansuolu)", + "Europe\/Jersey": "Greenwicha áigi (Jersey)", + "Europe\/Kaliningrad": "Nuorta-Eurohpa áigi (Kaliningrad)", + "Europe\/Kiev": "Nuorta-Eurohpa áigi (Kiev)", + "Europe\/Lisbon": "Oarje-Eurohpá áigi (Lisboa)", + "Europe\/Ljubljana": "Gaska-Eurohpá áigi (Ljubljana)", + "Europe\/London": "Greenwicha áigi (London)", + "Europe\/Luxembourg": "Gaska-Eurohpá áigi (Luxenburg)", + "Europe\/Madrid": "Gaska-Eurohpá áigi (Madrid)", + "Europe\/Malta": "Gaska-Eurohpá áigi (Malta)", + "Europe\/Mariehamn": "Nuorta-Eurohpa áigi (Mariehamn)", + "Europe\/Minsk": "Moskva áigi (Minsk)", + "Europe\/Monaco": "Gaska-Eurohpá áigi (Monaco)", + "Europe\/Moscow": "Moskva áigi (Moskva)", + "Europe\/Oslo": "Gaska-Eurohpá áigi (Oslo)", + "Europe\/Paris": "Gaska-Eurohpá áigi (Paris)", + "Europe\/Podgorica": "Gaska-Eurohpá áigi (Podgorica)", + "Europe\/Prague": "Gaska-Eurohpá áigi (Praha)", + "Europe\/Riga": "Nuorta-Eurohpa áigi (Riga)", + "Europe\/Rome": "Gaska-Eurohpá áigi (Roma)", + "Europe\/San_Marino": "Gaska-Eurohpá áigi (San Marino)", + "Europe\/Sarajevo": "Gaska-Eurohpá áigi (Sarajevo)", + "Europe\/Saratov": "Moskva áigi (Saratov)", + "Europe\/Simferopol": "Moskva áigi (Simferopol)", + "Europe\/Skopje": "Gaska-Eurohpá áigi (Skopje)", + "Europe\/Sofia": "Nuorta-Eurohpa áigi (Sofia)", + "Europe\/Stockholm": "Gaska-Eurohpá áigi (Stockholm)", + "Europe\/Tallinn": "Nuorta-Eurohpa áigi (Tallinn)", + "Europe\/Tirane": "Gaska-Eurohpá áigi (Tirana)", + "Europe\/Ulyanovsk": "Moskva áigi (Uljanovsk)", + "Europe\/Uzhgorod": "Nuorta-Eurohpa áigi (Uzhgorod)", + "Europe\/Vaduz": "Gaska-Eurohpá áigi (Vaduz)", + "Europe\/Vatican": "Gaska-Eurohpá áigi (Vatican)", + "Europe\/Vienna": "Gaska-Eurohpá áigi (Wien)", + "Europe\/Vilnius": "Nuorta-Eurohpa áigi (Vilnius)", + "Europe\/Volgograd": "Volgograda áigi (Volgograd)", + "Europe\/Warsaw": "Gaska-Eurohpá áigi (Warsawa)", + "Europe\/Zagreb": "Gaska-Eurohpá áigi (Zagreb)", + "Europe\/Zaporozhye": "Nuorta-Eurohpa áigi (Zaporozhye)", + "Europe\/Zurich": "Gaska-Eurohpá áigi (Zürich)", + "Indian\/Antananarivo": "Nuorta-Afrihká áigi (Antananarivo)", + "Indian\/Chagos": "Indiaábi áigi (Chagos)", + "Indian\/Christmas": "Juovlasullo áigi (Juovlasuolu)", + "Indian\/Cocos": "Kokossulloid áigi (Kokos)", + "Indian\/Comoro": "Nuorta-Afrihká áigi (Comoro)", + "Indian\/Kerguelen": "Frankriikka lulli & antárktisa áigi (Kerguelen)", + "Indian\/Mahe": "Seychellaid áigi (Mahe)", + "Indian\/Maldives": "Malediivvaid áigi (Malediivvat)", + "Indian\/Mauritius": "Mauritiusa áigi (Mauritius)", + "Indian\/Mayotte": "Nuorta-Afrihká áigi (Mayotte)", + "Indian\/Reunion": "Reuniona áigi (Reunion)", + "MST7MDT": "duottaráigi", + "PST8PDT": "Jaskesábi áigi", + "Pacific\/Apia": "Apia áigi (Apia)", + "Pacific\/Auckland": "Ođđa-Selánda áigi (Auckland)", + "Pacific\/Bougainville": "Papua Ođđa-Guinea áigi (Bougainville)", + "Pacific\/Chatham": "Chathama áigi (Chatham)", + "Pacific\/Easter": "Beassášsullo áigi (Easter)", + "Pacific\/Efate": "Vanuatu áigi (Efate)", + "Pacific\/Enderbury": "Phoenixsulloid áigi (Enderbury)", + "Pacific\/Fakaofo": "Tokelaua áigi (Fakaofo)", + "Pacific\/Fiji": "Fiji áigi (Fiji)", + "Pacific\/Funafuti": "Tuvalu áigi (Funafuti)", + "Pacific\/Galapagos": "Galapagosa áigi (Galapagos)", + "Pacific\/Gambier": "Gambiera áigi (Gambier)", + "Pacific\/Guadalcanal": "Salomonsulloid áigi (Guadalcanal)", + "Pacific\/Guam": "Čamorro dálveáigi (Guam)", + "Pacific\/Honolulu": "Hawaii-aleuhtalaš áigi (Honolulu)", + "Pacific\/Johnston": "Hawaii-aleuhtalaš áigi (Johnston)", + "Pacific\/Kiritimati": "Linesulloid áigi (Kiritimati)", + "Pacific\/Kosrae": "Kosraea áigi (Kosrae)", + "Pacific\/Kwajalein": "Marshallsulloid áigi (Kwajalein)", + "Pacific\/Majuro": "Marshallsulloid áigi (Majuro)", + "Pacific\/Marquesas": "Marquesasiid áigi (Marquesasat)", + "Pacific\/Midway": "Samoa áigi (Midway)", + "Pacific\/Nauru": "Nauru áigi (Nauru)", + "Pacific\/Niue": "Niuea áigi (Niue)", + "Pacific\/Norfolk": "Norfolksullo áigi (Norfolk)", + "Pacific\/Noumea": "Ođđa-Kaledonia áigi (Noumea)", + "Pacific\/Pago_Pago": "Samoa áigi (Pago Pago)", + "Pacific\/Palau": "Palaua áigi (Palau)", + "Pacific\/Pitcairn": "Pitcairnsulloid áigi (Pitcairn)", + "Pacific\/Ponape": "Ponape áigi (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Ođđa-Guinea áigi (Port Moresby)", + "Pacific\/Rarotonga": "Cooksulloid áigi (Rarotonga)", + "Pacific\/Saipan": "Čamorro dálveáigi (Saipan)", + "Pacific\/Tahiti": "Tahiti áigi (Tahiti)", + "Pacific\/Tarawa": "Gilbertsulloid áigi (Tarawa)", + "Pacific\/Tongatapu": "Tonga áigi (Tongatapu)", + "Pacific\/Truk": "Chuuka áigi (Chuuk)", + "Pacific\/Wake": "Wakesullo áigi (Wake)", + "Pacific\/Wallis": "Wallis- ja Futuna áigi (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sh.json b/src/Symfony/Component/Intl/Resources/data/timezones/sh.json new file mode 100644 index 0000000000000..5622892f4b22a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sh.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.77", + "Names": { + "Africa\/Abidjan": "Srednje vreme po Griniču (Abidžan)", + "Africa\/Accra": "Srednje vreme po Griniču (Akra)", + "Africa\/Addis_Ababa": "Istočno-afričko vreme (Adis Abeba)", + "Africa\/Algiers": "Srednjeevropsko vreme (Alžir)", + "Africa\/Asmera": "Istočno-afričko vreme (Asmera)", + "Africa\/Bamako": "Srednje vreme po Griniču (Bamako)", + "Africa\/Bangui": "Zapadno-afričko vreme (Bangui)", + "Africa\/Banjul": "Srednje vreme po Griniču (Banžul)", + "Africa\/Bissau": "Srednje vreme po Griniču (Bisao)", + "Africa\/Blantyre": "Centralno-afričko vreme (Blantir)", + "Africa\/Brazzaville": "Zapadno-afričko vreme (Brazavil)", + "Africa\/Bujumbura": "Centralno-afričko vreme (Budžumbura)", + "Africa\/Cairo": "Istočnoevropsko vreme (Kairo)", + "Africa\/Casablanca": "Zapadnoevropsko vreme (Kazablanka)", + "Africa\/Ceuta": "Srednjeevropsko vreme (Seuta)", + "Africa\/Conakry": "Srednje vreme po Griniču (Konakri)", + "Africa\/Dakar": "Srednje vreme po Griniču (Dakar)", + "Africa\/Dar_es_Salaam": "Istočno-afričko vreme (Dar-es-Salam)", + "Africa\/Djibouti": "Istočno-afričko vreme (Džibuti)", + "Africa\/Douala": "Zapadno-afričko vreme (Duala)", + "Africa\/El_Aaiun": "Zapadnoevropsko vreme (El Ajun)", + "Africa\/Freetown": "Srednje vreme po Griniču (Fritaun)", + "Africa\/Gaborone": "Centralno-afričko vreme (Gaboron)", + "Africa\/Harare": "Centralno-afričko vreme (Harare)", + "Africa\/Johannesburg": "Južno-afričko vreme (Johanesburg)", + "Africa\/Juba": "Istočno-afričko vreme (Džuba)", + "Africa\/Kampala": "Istočno-afričko vreme (Kampala)", + "Africa\/Khartoum": "Centralno-afričko vreme (Kartum)", + "Africa\/Kigali": "Centralno-afričko vreme (Kigali)", + "Africa\/Kinshasa": "Zapadno-afričko vreme (Kinšasa)", + "Africa\/Lagos": "Zapadno-afričko vreme (Lagos)", + "Africa\/Libreville": "Zapadno-afričko vreme (Librevil)", + "Africa\/Lome": "Srednje vreme po Griniču (Lome)", + "Africa\/Luanda": "Zapadno-afričko vreme (Luanda)", + "Africa\/Lubumbashi": "Centralno-afričko vreme (Lubumbaši)", + "Africa\/Lusaka": "Centralno-afričko vreme (Lusaka)", + "Africa\/Malabo": "Zapadno-afričko vreme (Malabo)", + "Africa\/Maputo": "Centralno-afričko vreme (Maputo)", + "Africa\/Maseru": "Južno-afričko vreme (Maseru)", + "Africa\/Mbabane": "Južno-afričko vreme (Mbabane)", + "Africa\/Mogadishu": "Istočno-afričko vreme (Mogadiš)", + "Africa\/Monrovia": "Srednje vreme po Griniču (Monrovija)", + "Africa\/Nairobi": "Istočno-afričko vreme (Najrobi)", + "Africa\/Ndjamena": "Zapadno-afričko vreme (Ndžamena)", + "Africa\/Niamey": "Zapadno-afričko vreme (Nijamej)", + "Africa\/Nouakchott": "Srednje vreme po Griniču (Nuakšot)", + "Africa\/Ouagadougou": "Srednje vreme po Griniču (Uagadugu)", + "Africa\/Porto-Novo": "Zapadno-afričko vreme (Porto Novo)", + "Africa\/Sao_Tome": "Srednje vreme po Griniču (Sao Tome)", + "Africa\/Tripoli": "Istočnoevropsko vreme (Tripoli)", + "Africa\/Tunis": "Srednjeevropsko vreme (Tunis)", + "Africa\/Windhoek": "Centralno-afričko vreme (Vindhuk)", + "America\/Adak": "Havajsko-aleutsko vreme (Adak)", + "America\/Anchorage": "Aljaska (Enkoridž)", + "America\/Anguilla": "Atlantsko vreme (Angvila)", + "America\/Antigua": "Atlantsko vreme (Antigva)", + "America\/Araguaina": "Brazilija vreme (Aragvajana)", + "America\/Argentina\/La_Rioja": "Argentina vreme (La Rioha)", + "America\/Argentina\/Rio_Gallegos": "Argentina vreme (Rio Galjegos)", + "America\/Argentina\/Salta": "Argentina vreme (Salta)", + "America\/Argentina\/San_Juan": "Argentina vreme (San Huan)", + "America\/Argentina\/San_Luis": "Zapadna Argentina vreme (San Lui)", + "America\/Argentina\/Tucuman": "Argentina vreme (Tukuman)", + "America\/Argentina\/Ushuaia": "Argentina vreme (Ušuaija)", + "America\/Aruba": "Atlantsko vreme (Aruba)", + "America\/Asuncion": "Paragvaj vreme (Asunsion)", + "America\/Bahia": "Brazilija vreme (Baija)", + "America\/Bahia_Banderas": "Severnoameričko centralno vreme (Baija Banderas)", + "America\/Barbados": "Atlantsko vreme (Barbados)", + "America\/Belem": "Brazilija vreme (Belem)", + "America\/Belize": "Severnoameričko centralno vreme (Belize)", + "America\/Blanc-Sablon": "Atlantsko vreme (Blank-Sejblon)", + "America\/Boa_Vista": "Amazon vreme (Boa Vista)", + "America\/Bogota": "Kolumbija vreme (Bogota)", + "America\/Boise": "Severnoameričko planinsko vreme (Bojzi)", + "America\/Buenos_Aires": "Argentina vreme (Buenos Ajres)", + "America\/Cambridge_Bay": "Severnoameričko planinsko vreme (Kembridž Bej)", + "America\/Campo_Grande": "Amazon vreme (Kampo Grande)", + "America\/Cancun": "Severnoameričko istočno vreme (Kankun)", + "America\/Caracas": "Venecuela vreme (Karakas)", + "America\/Catamarca": "Argentina vreme (Katamarka)", + "America\/Cayenne": "Francuska Gvajana vreme (Kajen)", + "America\/Cayman": "Severnoameričko istočno vreme (Kajmanska Ostrva)", + "America\/Chicago": "Severnoameričko centralno vreme (Čikago)", + "America\/Chihuahua": "Meksički Pacifik (Čihuahua)", + "America\/Coral_Harbour": "Severnoameričko istočno vreme (Koral Harbur)", + "America\/Cordoba": "Argentina vreme (Kordoba)", + "America\/Costa_Rica": "Severnoameričko centralno vreme (Kostarika)", + "America\/Creston": "Severnoameričko planinsko vreme (Kreston)", + "America\/Cuiaba": "Amazon vreme (Kuiaba)", + "America\/Curacao": "Atlantsko vreme (Kiraso)", + "America\/Danmarkshavn": "Srednje vreme po Griniču (Danmarkshagen)", + "America\/Dawson": "Severnoameričko pacifičko vreme (Doson)", + "America\/Dawson_Creek": "Severnoameričko planinsko vreme (Doson Krik)", + "America\/Denver": "Severnoameričko planinsko vreme (Denver)", + "America\/Detroit": "Severnoameričko istočno vreme (Detroit)", + "America\/Dominica": "Atlantsko vreme (Dominika)", + "America\/Edmonton": "Severnoameričko planinsko vreme (Edmonton)", + "America\/Eirunepe": "Akre vreme (Eirunepe)", + "America\/El_Salvador": "Severnoameričko centralno vreme (Salvador)", + "America\/Fort_Nelson": "Severnoameričko planinsko vreme (Fort Nelson)", + "America\/Fortaleza": "Brazilija vreme (Fortaleza)", + "America\/Glace_Bay": "Atlantsko vreme (Glejs Bej)", + "America\/Godthab": "Zapadni Grenland (Gothab)", + "America\/Goose_Bay": "Atlantsko vreme (Gus Bej)", + "America\/Grand_Turk": "Severnoameričko istočno vreme (Grand Turk)", + "America\/Grenada": "Atlantsko vreme (Grenada)", + "America\/Guadeloupe": "Atlantsko vreme (Gvadalupe)", + "America\/Guatemala": "Severnoameričko centralno vreme (Gvatemala)", + "America\/Guayaquil": "Ekvador vreme (Gvajakil)", + "America\/Guyana": "Gvajana vreme (Gvajana)", + "America\/Halifax": "Atlantsko vreme (Halifaks)", + "America\/Havana": "Kuba (Havana)", + "America\/Hermosillo": "Meksički Pacifik (Hermosiljo)", + "America\/Indiana\/Knox": "Severnoameričko centralno vreme (Noks, Indijana)", + "America\/Indiana\/Marengo": "Severnoameričko istočno vreme (Marengo, Indijana)", + "America\/Indiana\/Petersburg": "Severnoameričko istočno vreme (Pitersburg, Indijana)", + "America\/Indiana\/Tell_City": "Severnoameričko centralno vreme (Tel Siti, Indijana)", + "America\/Indiana\/Vevay": "Severnoameričko istočno vreme (Vevaj, Indijana)", + "America\/Indiana\/Vincennes": "Severnoameričko istočno vreme (Vincenes, Indijana)", + "America\/Indiana\/Winamac": "Severnoameričko istočno vreme (Vinamak, Indijana)", + "America\/Indianapolis": "Severnoameričko istočno vreme (Indianapolis)", + "America\/Inuvik": "Severnoameričko planinsko vreme (Inuvik)", + "America\/Iqaluit": "Severnoameričko istočno vreme (Ikvaluit)", + "America\/Jamaica": "Severnoameričko istočno vreme (Jamajka)", + "America\/Jujuy": "Argentina vreme (Žužui)", + "America\/Juneau": "Aljaska (Žuno)", + "America\/Kentucky\/Monticello": "Severnoameričko istočno vreme (Montičelo, Kentaki)", + "America\/Kralendijk": "Atlantsko vreme (Kralendajk)", + "America\/La_Paz": "Bolivija vreme (La Paz)", + "America\/Lima": "Peru vreme (Lima)", + "America\/Los_Angeles": "Severnoameričko pacifičko vreme (Los Anđeles)", + "America\/Louisville": "Severnoameričko istočno vreme (Luivile)", + "America\/Lower_Princes": "Atlantsko vreme (Louer Prinsiz Kvorter)", + "America\/Maceio": "Brazilija vreme (Masejo)", + "America\/Managua": "Severnoameričko centralno vreme (Managva)", + "America\/Manaus": "Amazon vreme (Manaus)", + "America\/Marigot": "Atlantsko vreme (Marigo)", + "America\/Martinique": "Atlantsko vreme (Martinik)", + "America\/Matamoros": "Severnoameričko centralno vreme (Matamoros)", + "America\/Mazatlan": "Meksički Pacifik (Mazatlan)", + "America\/Mendoza": "Argentina vreme (Mendosa)", + "America\/Menominee": "Severnoameričko centralno vreme (Menomini)", + "America\/Merida": "Severnoameričko centralno vreme (Merida)", + "America\/Metlakatla": "Aljaska (Metlakatla)", + "America\/Mexico_City": "Severnoameričko centralno vreme (Meksiko Siti)", + "America\/Miquelon": "Sen Pjer i Mikelon (Mikelon)", + "America\/Moncton": "Atlantsko vreme (Monkton)", + "America\/Monterrey": "Severnoameričko centralno vreme (Monterej)", + "America\/Montevideo": "Urugvaj vreme (Montevideo)", + "America\/Montserrat": "Atlantsko vreme (Montserat)", + "America\/Nassau": "Severnoameričko istočno vreme (Nasau)", + "America\/New_York": "Severnoameričko istočno vreme (Njujork)", + "America\/Nipigon": "Severnoameričko istočno vreme (Nipigon)", + "America\/Nome": "Aljaska (Nom)", + "America\/Noronha": "Fernando de Noronja vreme (Noronja)", + "America\/North_Dakota\/Beulah": "Severnoameričko centralno vreme (Bijula, Severna Dakota)", + "America\/North_Dakota\/Center": "Severnoameričko centralno vreme (Centar, Severna Dakota)", + "America\/North_Dakota\/New_Salem": "Severnoameričko centralno vreme (Novi Salem, Severna Dakota)", + "America\/Ojinaga": "Severnoameričko planinsko vreme (Ohinaga)", + "America\/Panama": "Severnoameričko istočno vreme (Panama)", + "America\/Pangnirtung": "Severnoameričko istočno vreme (Pangnirtung)", + "America\/Paramaribo": "Surinam vreme (Paramaribo)", + "America\/Phoenix": "Severnoameričko planinsko vreme (Finiks)", + "America\/Port-au-Prince": "Severnoameričko istočno vreme (Port o Prens)", + "America\/Port_of_Spain": "Atlantsko vreme (Port of Spejn)", + "America\/Porto_Velho": "Amazon vreme (Porto Veljo)", + "America\/Puerto_Rico": "Atlantsko vreme (Porto Riko)", + "America\/Punta_Arenas": "Čile vreme (Punta Arenas)", + "America\/Rainy_River": "Severnoameričko centralno vreme (Rejni River)", + "America\/Rankin_Inlet": "Severnoameričko centralno vreme (Rankin Inlet)", + "America\/Recife": "Brazilija vreme (Resife)", + "America\/Regina": "Severnoameričko centralno vreme (Regina)", + "America\/Resolute": "Severnoameričko centralno vreme (Resolut)", + "America\/Rio_Branco": "Akre vreme (Rio Branko)", + "America\/Santa_Isabel": "Severozapadni Meksiko (Santa Izabel)", + "America\/Santarem": "Brazilija vreme (Santarem)", + "America\/Santiago": "Čile vreme (Santjago)", + "America\/Santo_Domingo": "Atlantsko vreme (Santo Domingo)", + "America\/Sao_Paulo": "Brazilija vreme (Sao Paolo)", + "America\/Scoresbysund": "Istočni Grenland (Skorezbisund)", + "America\/Sitka": "Aljaska (Sitka)", + "America\/St_Barthelemy": "Atlantsko vreme (Sv. Bartolomej)", + "America\/St_Johns": "Njufaundlend (Sv. Džon)", + "America\/St_Kitts": "Atlantsko vreme (Sent Kits)", + "America\/St_Lucia": "Atlantsko vreme (Sv. Lucija)", + "America\/St_Thomas": "Atlantsko vreme (Sv. Toma)", + "America\/St_Vincent": "Atlantsko vreme (Sent Vinsent)", + "America\/Swift_Current": "Severnoameričko centralno vreme (Svift Kurent)", + "America\/Tegucigalpa": "Severnoameričko centralno vreme (Tegusigalpa)", + "America\/Thule": "Atlantsko vreme (Tul)", + "America\/Thunder_Bay": "Severnoameričko istočno vreme (Tander Bej)", + "America\/Tijuana": "Severnoameričko pacifičko vreme (Tihuana)", + "America\/Toronto": "Severnoameričko istočno vreme (Toronto)", + "America\/Tortola": "Atlantsko vreme (Tortola)", + "America\/Vancouver": "Severnoameričko pacifičko vreme (Vankuver)", + "America\/Whitehorse": "Severnoameričko pacifičko vreme (Vajthors)", + "America\/Winnipeg": "Severnoameričko centralno vreme (Vinipeg)", + "America\/Yakutat": "Aljaska (Jakutat)", + "America\/Yellowknife": "Severnoameričko planinsko vreme (Jelounajf)", + "Antarctica\/Casey": "Australijsko zapadno vreme (Kejsi)", + "Antarctica\/Davis": "Dejvis vreme (Dejvis)", + "Antarctica\/DumontDUrville": "Dimon d’Urvil vreme (Dimon d’Urvil)", + "Antarctica\/Macquarie": "Ostrvo Makveri vreme (Mekvori)", + "Antarctica\/Mawson": "Moson vreme (Moson)", + "Antarctica\/McMurdo": "Novi Zeland vreme (Makmurdo)", + "Antarctica\/Palmer": "Čile vreme (Palmer)", + "Antarctica\/Rothera": "Rotera vreme (Rotera)", + "Antarctica\/Syowa": "Šova vreme (Šova)", + "Antarctica\/Troll": "Srednje vreme po Griniču (Trol)", + "Antarctica\/Vostok": "Vostok vreme (Vostok)", + "Arctic\/Longyearbyen": "Srednjeevropsko vreme (Longjerbjen)", + "Asia\/Aden": "Arabijsko vreme (Aden)", + "Asia\/Almaty": "Istočno-kazahstansko vreme (Almati)", + "Asia\/Amman": "Istočnoevropsko vreme (Aman)", + "Asia\/Anadyr": "Anadir vreme (Anadir)", + "Asia\/Aqtau": "Zapadno-kazahstansko vreme (Aktau)", + "Asia\/Aqtobe": "Zapadno-kazahstansko vreme (Akutobe)", + "Asia\/Ashgabat": "Turkmenistan vreme (Ašhabad)", + "Asia\/Atyrau": "Zapadno-kazahstansko vreme (Atirau)", + "Asia\/Baghdad": "Arabijsko vreme (Bagdad)", + "Asia\/Bahrain": "Arabijsko vreme (Bahrein)", + "Asia\/Baku": "Azerbejdžan vreme (Baku)", + "Asia\/Bangkok": "Indokina vreme (Bangkok)", + "Asia\/Beirut": "Istočnoevropsko vreme (Bejrut)", + "Asia\/Bishkek": "Kirgistan vreme (Biškek)", + "Asia\/Brunei": "Brunej Darusalum vreme (Brunej)", + "Asia\/Calcutta": "Indijsko standardno vreme (Kalkuta)", + "Asia\/Chita": "Jakutsk vreme (Čita)", + "Asia\/Choibalsan": "Čojbalsan vreme (Čojbalsan)", + "Asia\/Colombo": "Indijsko standardno vreme (Kolombo)", + "Asia\/Damascus": "Istočnoevropsko vreme (Damask)", + "Asia\/Dhaka": "Bangladeš vreme (Daka)", + "Asia\/Dili": "Istočni timor vreme (Dili)", + "Asia\/Dubai": "Zalivsko vreme (Dubai)", + "Asia\/Dushanbe": "Tadžikistan vreme (Dušanbe)", + "Asia\/Famagusta": "Istočnoevropsko vreme (Famagusta)", + "Asia\/Gaza": "Istočnoevropsko vreme (Gaza)", + "Asia\/Hebron": "Istočnoevropsko vreme (Hebron)", + "Asia\/Hong_Kong": "Hong Kong vreme (Hongkong)", + "Asia\/Hovd": "Hovd vreme (Hovd)", + "Asia\/Irkutsk": "Irkuck vreme (Irkuck)", + "Asia\/Jakarta": "Zapadno-indonezijsko vreme (Džakarta)", + "Asia\/Jayapura": "Istočno-indonezijsko vreme (Džajapura)", + "Asia\/Jerusalem": "Izraelsko vreme (Jerusalim)", + "Asia\/Kabul": "Avganistan vreme (Kabul)", + "Asia\/Kamchatka": "Petropavlovsko-kamčatsko vreme (Kamčatka)", + "Asia\/Karachi": "Pakistan vreme (Karači)", + "Asia\/Katmandu": "Nepal vreme (Katmandu)", + "Asia\/Khandyga": "Jakutsk vreme (Handiga)", + "Asia\/Krasnoyarsk": "Krasnojarsk vreme (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malezija vreme (Kuala Lumpur)", + "Asia\/Kuching": "Malezija vreme (Kučing)", + "Asia\/Kuwait": "Arabijsko vreme (Kuvajt)", + "Asia\/Macau": "Kina vreme (Makao)", + "Asia\/Magadan": "Magadan vreme (Magadan)", + "Asia\/Makassar": "Centralno-indonezijsko vreme (Makasar)", + "Asia\/Manila": "Filipini vreme (Manila)", + "Asia\/Muscat": "Zalivsko vreme (Muskat)", + "Asia\/Nicosia": "Istočnoevropsko vreme (Nikozija)", + "Asia\/Novokuznetsk": "Krasnojarsk vreme (Novokuznjeck)", + "Asia\/Novosibirsk": "Novosibirsk vreme (Novosibirsk)", + "Asia\/Omsk": "Omsk vreme (Omsk)", + "Asia\/Oral": "Zapadno-kazahstansko vreme (Oral)", + "Asia\/Phnom_Penh": "Indokina vreme (Pnom Pen)", + "Asia\/Pontianak": "Zapadno-indonezijsko vreme (Pontijanak)", + "Asia\/Pyongyang": "Korejsko vreme (Pjongjang)", + "Asia\/Qatar": "Arabijsko vreme (Katar)", + "Asia\/Qostanay": "Istočno-kazahstansko vreme (Qostanay)", + "Asia\/Qyzylorda": "Zapadno-kazahstansko vreme (Kizilorda)", + "Asia\/Rangoon": "Mijanmar vreme (Rangun)", + "Asia\/Riyadh": "Arabijsko vreme (Rijad)", + "Asia\/Saigon": "Indokina vreme (Ho Ši Min)", + "Asia\/Sakhalin": "Sahalin vreme (Sahalin)", + "Asia\/Samarkand": "Uzbekistan vreme (Samarkand)", + "Asia\/Seoul": "Korejsko vreme (Seul)", + "Asia\/Shanghai": "Kina vreme (Šangaj)", + "Asia\/Singapore": "Singapur, standardno vreme (Singapur)", + "Asia\/Srednekolymsk": "Magadan vreme (Srednjekolimsk)", + "Asia\/Taipei": "Tajpej vreme (Tajpej)", + "Asia\/Tashkent": "Uzbekistan vreme (Taškent)", + "Asia\/Tbilisi": "Gruzija vreme (Tbilisi)", + "Asia\/Tehran": "Iran vreme (Teheran)", + "Asia\/Thimphu": "Butan vreme (Timpu)", + "Asia\/Tokyo": "Japansko vreme (Tokio)", + "Asia\/Ulaanbaatar": "Ulan Bator vreme (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostok vreme (Ust-Nera)", + "Asia\/Vientiane": "Indokina vreme (Vijentijan)", + "Asia\/Vladivostok": "Vladivostok vreme (Vladivostok)", + "Asia\/Yakutsk": "Jakutsk vreme (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburg vreme (Jekaterinburg)", + "Asia\/Yerevan": "Jermenija vreme (Jerevan)", + "Atlantic\/Azores": "Azori vreme (Azori)", + "Atlantic\/Bermuda": "Atlantsko vreme (Bermuda)", + "Atlantic\/Canary": "Zapadnoevropsko vreme (Kanarska ostrva)", + "Atlantic\/Cape_Verde": "Zelenortska Ostrva vreme (Zelenortska Ostrva)", + "Atlantic\/Faeroe": "Zapadnoevropsko vreme (Farska Ostrva)", + "Atlantic\/Madeira": "Zapadnoevropsko vreme (Madeira)", + "Atlantic\/Reykjavik": "Srednje vreme po Griniču (Rejkjavik)", + "Atlantic\/South_Georgia": "Južna Džordžija vreme (Južna Džordžija)", + "Atlantic\/St_Helena": "Srednje vreme po Griniču (Sveta Jelena)", + "Atlantic\/Stanley": "Folklandska Ostrva vreme (Stenli)", + "Australia\/Adelaide": "Australijsko centralno vreme (Adelejd)", + "Australia\/Brisbane": "Australijsko istočno vreme (Brizbejn)", + "Australia\/Broken_Hill": "Australijsko centralno vreme (Broken Hil)", + "Australia\/Currie": "Australijsko istočno vreme (Kari)", + "Australia\/Darwin": "Australijsko centralno vreme (Darvin)", + "Australia\/Eucla": "Australijsko centralno zapadno vreme (Iukla)", + "Australia\/Hobart": "Australijsko istočno vreme (Hobart)", + "Australia\/Lindeman": "Australijsko istočno vreme (Lindeman)", + "Australia\/Lord_Howe": "Lord Hov vreme (Lord Hau)", + "Australia\/Melbourne": "Australijsko istočno vreme (Melburn)", + "Australia\/Perth": "Australijsko zapadno vreme (Pert)", + "Australia\/Sydney": "Australijsko istočno vreme (Sidnej)", + "CST6CDT": "Severnoameričko centralno vreme", + "EST5EDT": "Severnoameričko istočno vreme", + "Etc\/GMT": "Srednje vreme po Griniču", + "Etc\/UTC": "Koordinisano univerzalno vreme", + "Europe\/Amsterdam": "Srednjeevropsko vreme (Amsterdam)", + "Europe\/Andorra": "Srednjeevropsko vreme (Andora)", + "Europe\/Astrakhan": "Moskva vreme (Astrakan)", + "Europe\/Athens": "Istočnoevropsko vreme (Atina)", + "Europe\/Belgrade": "Srednjeevropsko vreme (Beograd)", + "Europe\/Berlin": "Srednjeevropsko vreme (Berlin)", + "Europe\/Bratislava": "Srednjeevropsko vreme (Bratislava)", + "Europe\/Brussels": "Srednjeevropsko vreme (Brisel)", + "Europe\/Bucharest": "Istočnoevropsko vreme (Bukurešt)", + "Europe\/Budapest": "Srednjeevropsko vreme (Budimpešta)", + "Europe\/Busingen": "Srednjeevropsko vreme (Bisingen)", + "Europe\/Chisinau": "Istočnoevropsko vreme (Kišinjev)", + "Europe\/Copenhagen": "Srednjeevropsko vreme (Kopenhagen)", + "Europe\/Dublin": "Srednje vreme po Griniču (Dablin)", + "Europe\/Gibraltar": "Srednjeevropsko vreme (Gibraltar)", + "Europe\/Guernsey": "Srednje vreme po Griniču (Gernzi)", + "Europe\/Helsinki": "Istočnoevropsko vreme (Helsinki)", + "Europe\/Isle_of_Man": "Srednje vreme po Griniču (Ostrvo Man)", + "Europe\/Jersey": "Srednje vreme po Griniču (Džersi)", + "Europe\/Kaliningrad": "Istočnoevropsko vreme (Kalinjingrad)", + "Europe\/Kiev": "Istočnoevropsko vreme (Kijev)", + "Europe\/Lisbon": "Zapadnoevropsko vreme (Lisabon)", + "Europe\/Ljubljana": "Srednjeevropsko vreme (Ljubljana)", + "Europe\/London": "Srednje vreme po Griniču (London)", + "Europe\/Luxembourg": "Srednjeevropsko vreme (Luksemburg)", + "Europe\/Madrid": "Srednjeevropsko vreme (Madrid)", + "Europe\/Malta": "Srednjeevropsko vreme (Malta)", + "Europe\/Mariehamn": "Istočnoevropsko vreme (Marihamn)", + "Europe\/Minsk": "Moskva vreme (Minsk)", + "Europe\/Monaco": "Srednjeevropsko vreme (Monako)", + "Europe\/Moscow": "Moskva vreme (Moskva)", + "Europe\/Oslo": "Srednjeevropsko vreme (Oslo)", + "Europe\/Paris": "Srednjeevropsko vreme (Pariz)", + "Europe\/Podgorica": "Srednjeevropsko vreme (Podgorica)", + "Europe\/Prague": "Srednjeevropsko vreme (Prag)", + "Europe\/Riga": "Istočnoevropsko vreme (Riga)", + "Europe\/Rome": "Srednjeevropsko vreme (Rim)", + "Europe\/Samara": "Samara vreme (Samara)", + "Europe\/San_Marino": "Srednjeevropsko vreme (San Marino)", + "Europe\/Sarajevo": "Srednjeevropsko vreme (Sarajevo)", + "Europe\/Saratov": "Moskva vreme (Saratov)", + "Europe\/Simferopol": "Moskva vreme (Simferopolj)", + "Europe\/Skopje": "Srednjeevropsko vreme (Skoplje)", + "Europe\/Sofia": "Istočnoevropsko vreme (Sofija)", + "Europe\/Stockholm": "Srednjeevropsko vreme (Stokholm)", + "Europe\/Tallinn": "Istočnoevropsko vreme (Talin)", + "Europe\/Tirane": "Srednjeevropsko vreme (Tirana)", + "Europe\/Ulyanovsk": "Moskva vreme (Uljanovsk)", + "Europe\/Uzhgorod": "Istočnoevropsko vreme (Užgorod)", + "Europe\/Vaduz": "Srednjeevropsko vreme (Vaduz)", + "Europe\/Vatican": "Srednjeevropsko vreme (Vatikan)", + "Europe\/Vienna": "Srednjeevropsko vreme (Beč)", + "Europe\/Vilnius": "Istočnoevropsko vreme (Vilnjus)", + "Europe\/Volgograd": "Volgograd vreme (Volgograd)", + "Europe\/Warsaw": "Srednjeevropsko vreme (Varšava)", + "Europe\/Zagreb": "Srednjeevropsko vreme (Zagreb)", + "Europe\/Zaporozhye": "Istočnoevropsko vreme (Zaporožje)", + "Europe\/Zurich": "Srednjeevropsko vreme (Cirih)", + "Indian\/Antananarivo": "Istočno-afričko vreme (Antananarivo)", + "Indian\/Chagos": "Indijsko okeansko vreme (Čagos)", + "Indian\/Christmas": "Božićno ostrvo vreme (Božić)", + "Indian\/Cocos": "Kokos (Keling) Ostrva vreme (Kokos)", + "Indian\/Comoro": "Istočno-afričko vreme (Komoro)", + "Indian\/Kerguelen": "Francusko južno i antarktičko vreme (Kergelen)", + "Indian\/Mahe": "Sejšeli vreme (Mahe)", + "Indian\/Maldives": "Maldivi vreme (Maldivi)", + "Indian\/Mauritius": "Mauricijus vreme (Mauricijus)", + "Indian\/Mayotte": "Istočno-afričko vreme (Majot)", + "Indian\/Reunion": "Reinion vreme (Reunion)", + "MST7MDT": "Severnoameričko planinsko vreme", + "PST8PDT": "Severnoameričko pacifičko vreme", + "Pacific\/Apia": "Apija vreme (Apija)", + "Pacific\/Auckland": "Novi Zeland vreme (Okland)", + "Pacific\/Bougainville": "Papua Nova Gvineja vreme (Buganvil)", + "Pacific\/Chatham": "Čatam vreme (Čatam)", + "Pacific\/Easter": "Uskršnja ostrva vreme (Uskršnje ostrvo)", + "Pacific\/Efate": "Vanuatu vreme (Efat)", + "Pacific\/Enderbury": "Feniks ostrva vreme (Enderberi)", + "Pacific\/Fakaofo": "Tokelau vreme (Fakaofo)", + "Pacific\/Fiji": "Fidži vreme (Fidži)", + "Pacific\/Funafuti": "Tuvalu vreme (Funafuti)", + "Pacific\/Galapagos": "Galapagos vreme (Galapagos)", + "Pacific\/Gambier": "Gambije vreme (Gambije)", + "Pacific\/Guadalcanal": "Solomonska Ostrva vreme (Gvadalkanal)", + "Pacific\/Guam": "Čamoro vreme (Guam)", + "Pacific\/Honolulu": "Havajsko-aleutsko vreme (Honolulu)", + "Pacific\/Johnston": "Havajsko-aleutsko vreme (Džonston)", + "Pacific\/Kiritimati": "Ostrva Lajn vreme (Kiritimati)", + "Pacific\/Kosrae": "Košre vreme (Košre)", + "Pacific\/Kwajalein": "Maršalska Ostrva vreme (Kvadžalejin)", + "Pacific\/Majuro": "Maršalska Ostrva vreme (Majuro)", + "Pacific\/Marquesas": "Markiz vreme (Markiz)", + "Pacific\/Midway": "Samoa vreme (Midvej)", + "Pacific\/Nauru": "Nauru vreme (Nauru)", + "Pacific\/Niue": "Niue vreme (Niue)", + "Pacific\/Norfolk": "Norfolk Ostrvo vreme (Norfolk)", + "Pacific\/Noumea": "Nova Kaledonija vreme (Numea)", + "Pacific\/Pago_Pago": "Samoa vreme (Pago Pago)", + "Pacific\/Palau": "Palau vreme (Palau)", + "Pacific\/Pitcairn": "Pitkern vreme (Pitkern)", + "Pacific\/Ponape": "Ponpej vreme (Ponape)", + "Pacific\/Port_Moresby": "Papua Nova Gvineja vreme (Port Morzbi)", + "Pacific\/Rarotonga": "Kukova ostrva vreme (Rarotonga)", + "Pacific\/Saipan": "Čamoro vreme (Sajpan)", + "Pacific\/Tahiti": "Tahiti vreme (Tahiti)", + "Pacific\/Tarawa": "Gilbert ostrva vreme (Tarava)", + "Pacific\/Tongatapu": "Tonga vreme (Tongatapu)", + "Pacific\/Truk": "Čuuk vreme (Truk)", + "Pacific\/Wake": "Vejk ostrvo vreme (Vejk)", + "Pacific\/Wallis": "Valis i Futuna Ostrva vreme (Valis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/si.json b/src/Symfony/Component/Intl/Resources/data/timezones/si.json new file mode 100644 index 0000000000000..760a633736922 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/si.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "ග්‍රිනිච් මධ්‍යම වේලාව (අබිජාන්)", + "Africa\/Accra": "ග්‍රිනිච් මධ්‍යම වේලාව (අක්රා)", + "Africa\/Addis_Ababa": "නැගෙනහිර අප්‍රිකානු වේලාව (අඩිස් අබාබා)", + "Africa\/Algiers": "මධ්‍යම යුරෝපීය වේලාව (ඇල්ජියර්ස්)", + "Africa\/Asmera": "නැගෙනහිර අප්‍රිකානු වේලාව (අස්මාරා)", + "Africa\/Bamako": "ග්‍රිනිච් මධ්‍යම වේලාව (බමකො)", + "Africa\/Bangui": "බටහිර අප්‍රිකානු වේලාව (බන්ගුයි)", + "Africa\/Banjul": "ග්‍රිනිච් මධ්‍යම වේලාව (බන්ජුල්)", + "Africa\/Bissau": "ග්‍රිනිච් මධ්‍යම වේලාව (බිසෝ)", + "Africa\/Blantyre": "මධ්‍යම අප්‍රිකානු වේලාව (බ්ලන්ටයර්)", + "Africa\/Brazzaville": "බටහිර අප්‍රිකානු වේලාව (බ්‍රසාවිල්)", + "Africa\/Bujumbura": "මධ්‍යම අප්‍රිකානු වේලාව (බුජුම්බුරා)", + "Africa\/Cairo": "නැගෙනහිර යුරෝපීය වේලාව (කයිරෝ)", + "Africa\/Casablanca": "බටහිර යුරෝපීය වේලාව (කැසබ්ලන්කා)", + "Africa\/Ceuta": "මධ්‍යම යුරෝපීය වේලාව (සෙයුටා)", + "Africa\/Conakry": "ග්‍රිනිච් මධ්‍යම වේලාව (කොනක්‍රි)", + "Africa\/Dakar": "ග්‍රිනිච් මධ්‍යම වේලාව (ඩකර්)", + "Africa\/Dar_es_Salaam": "නැගෙනහිර අප්‍රිකානු වේලාව (දාර් එස් සලාම්)", + "Africa\/Djibouti": "නැගෙනහිර අප්‍රිකානු වේලාව (ජිබුටි)", + "Africa\/Douala": "බටහිර අප්‍රිකානු වේලාව (දෞඅලා)", + "Africa\/El_Aaiun": "බටහිර යුරෝපීය වේලාව (එල් ආයුන්)", + "Africa\/Freetown": "ග්‍රිනිච් මධ්‍යම වේලාව (ෆ්‍රීටවුන්)", + "Africa\/Gaborone": "මධ්‍යම අප්‍රිකානු වේලාව (ගැබරෝන්)", + "Africa\/Harare": "මධ්‍යම අප්‍රිකානු වේලාව (හරාරේ)", + "Africa\/Johannesburg": "දකුණු අප්‍රිකානු වේලාව (ජොහන්නස්බර්ග්)", + "Africa\/Juba": "නැගෙනහිර අප්‍රිකානු වේලාව (ජුබා)", + "Africa\/Kampala": "නැගෙනහිර අප්‍රිකානු වේලාව (කම්පාලා)", + "Africa\/Khartoum": "මධ්‍යම අප්‍රිකානු වේලාව (කාර්ටොම්)", + "Africa\/Kigali": "මධ්‍යම අප්‍රිකානු වේලාව (කිගාලි)", + "Africa\/Kinshasa": "බටහිර අප්‍රිකානු වේලාව (කින්ශාසා)", + "Africa\/Lagos": "බටහිර අප්‍රිකානු වේලාව (ලාගෝස්)", + "Africa\/Libreville": "බටහිර අප්‍රිකානු වේලාව (ලිබ්රවිල්)", + "Africa\/Lome": "ග්‍රිනිච් මධ්‍යම වේලාව (ලෝම්)", + "Africa\/Luanda": "බටහිර අප්‍රිකානු වේලාව (ලුවන්ඩා)", + "Africa\/Lubumbashi": "මධ්‍යම අප්‍රිකානු වේලාව (ලුබුම්බාශි)", + "Africa\/Lusaka": "මධ්‍යම අප්‍රිකානු වේලාව (ලුසාකා)", + "Africa\/Malabo": "බටහිර අප්‍රිකානු වේලාව (මලබෝ)", + "Africa\/Maputo": "මධ්‍යම අප්‍රිකානු වේලාව (මපුටෝ)", + "Africa\/Maseru": "දකුණු අප්‍රිකානු වේලාව (මසේරු)", + "Africa\/Mbabane": "දකුණු අප්‍රිකානු වේලාව (ම්බබානේ)", + "Africa\/Mogadishu": "නැගෙනහිර අප්‍රිකානු වේලාව (මොගඩිෂු)", + "Africa\/Monrovia": "ග්‍රිනිච් මධ්‍යම වේලාව (මොන්රොවියා)", + "Africa\/Nairobi": "නැගෙනහිර අප්‍රිකානු වේලාව (නයිරෝබි)", + "Africa\/Ndjamena": "බටහිර අප්‍රිකානු වේලාව (ද්ජමෙනා)", + "Africa\/Niamey": "බටහිර අප්‍රිකානු වේලාව (නියාමේ)", + "Africa\/Nouakchott": "ග්‍රිනිච් මධ්‍යම වේලාව (නුආක්චොට්)", + "Africa\/Ouagadougou": "ග්‍රිනිච් මධ්‍යම වේලාව (ඔආගඩොගො)", + "Africa\/Porto-Novo": "බටහිර අප්‍රිකානු වේලාව (පොර්තෝ-නොවෝ)", + "Africa\/Sao_Tome": "ග්‍රිනිච් මධ්‍යම වේලාව (සාඕ තෝම්)", + "Africa\/Tripoli": "නැගෙනහිර යුරෝපීය වේලාව (ට්‍රිපොලි)", + "Africa\/Tunis": "මධ්‍යම යුරෝපීය වේලාව (ටියුනිස්)", + "Africa\/Windhoek": "මධ්‍යම අප්‍රිකානු වේලාව (වින්ඩ්හොඑක්)", + "America\/Adak": "හවායි-අලෙයුතියාන් වේලාව (ඇඩක්)", + "America\/Anchorage": "ඇලස්කා වේලාව (ඇනකොරාජ්)", + "America\/Anguilla": "අත්ලාන්තික් වේලාව (ඇන්ගුයිලාව)", + "America\/Antigua": "අත්ලාන්තික් වේලාව (ඇන්ටිගුවා)", + "America\/Araguaina": "බ්‍රසීල වේලාව (ඇරගුඅයිනා)", + "America\/Argentina\/La_Rioja": "ආර්ජන්ටිනා වේලාව (ලා රිජෝලා)", + "America\/Argentina\/Rio_Gallegos": "ආර්ජන්ටිනා වේලාව (රියෝ ගලෙගොස්)", + "America\/Argentina\/Salta": "ආර්ජන්ටිනා වේලාව (සොල්ටා)", + "America\/Argentina\/San_Juan": "ආර්ජන්ටිනා වේලාව (සැන් ජුවාන්)", + "America\/Argentina\/San_Luis": "බටහිර ආර්ජන්ටිනා වේලාව (සැන් ලුවිස්)", + "America\/Argentina\/Tucuman": "ආර්ජන්ටිනා වේලාව (ටුකුමන්)", + "America\/Argentina\/Ushuaia": "ආර්ජන්ටිනා වේලාව (උෂුඅයියා)", + "America\/Aruba": "අත්ලාන්තික් වේලාව (අරූබා)", + "America\/Asuncion": "පැරගුවේ වේලාව (අසුන්සියොන්)", + "America\/Bahia": "බ්‍රසීල වේලාව (බහියා)", + "America\/Bahia_Banderas": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (බහියා බන්දෙරාස්)", + "America\/Barbados": "අත්ලාන්තික් වේලාව (බාබඩෝස්)", + "America\/Belem": "බ්‍රසීල වේලාව (බෙලෙම්)", + "America\/Belize": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (බෙලීස්)", + "America\/Blanc-Sablon": "අත්ලාන්තික් වේලාව (බ්ලැන්ක්-සැබ්ලන්)", + "America\/Boa_Vista": "ඇමර්සන් වේලාව (බොආ විස්ටා)", + "America\/Bogota": "කොලොම්බියා වේලාව (බොගොටා)", + "America\/Boise": "උතුරු ඇමරිකානු කඳුකර වේලාව (බොයිසි)", + "America\/Buenos_Aires": "ආර්ජන්ටිනා වේලාව (බුවනෝස් අයර්ස්)", + "America\/Cambridge_Bay": "උතුරු ඇමරිකානු කඳුකර වේලාව (කේම්බ්‍රිජ් බොක්ක)", + "America\/Campo_Grande": "ඇමර්සන් වේලාව (කම්පෝ ග්‍රෑන්ඩ්)", + "America\/Cancun": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (කැන්කුන්)", + "America\/Caracas": "වෙනිසියුලා වේලාව (කරකස්)", + "America\/Catamarca": "ආර්ජන්ටිනා වේලාව (කටමර්කා)", + "America\/Cayenne": "ප්‍රංශ ගයනා වේලාව (කේයෙන්)", + "America\/Cayman": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (කේමන්)", + "America\/Chicago": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (චිකාගෝ)", + "America\/Chihuahua": "මෙක්සිකෝ පැසිෆික් වේලාව (චිහුආහුආ)", + "America\/Coral_Harbour": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ඇටිකොකන්)", + "America\/Cordoba": "ආර්ජන්ටිනා වේලාව (කොර්දොබා)", + "America\/Costa_Rica": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (කොස්ටරිකා)", + "America\/Creston": "උතුරු ඇමරිකානු කඳුකර වේලාව (ක්‍රෙස්ටන්)", + "America\/Cuiaba": "ඇමර්සන් වේලාව (කුයිඅබා)", + "America\/Curacao": "අත්ලාන්තික් වේලාව (කුරකාවෝ)", + "America\/Danmarkshavn": "ග්‍රිනිච් මධ්‍යම වේලාව (ඩෙන්මාර්ක්ශව්න්)", + "America\/Dawson": "උතුරු ඇමරිකානු පැසිෆික් වේලාව (ඩෝසන්)", + "America\/Dawson_Creek": "උතුරු ඇමරිකානු කඳුකර වේලාව (ඩෝසන් ක්‍රීක්)", + "America\/Denver": "උතුරු ඇමරිකානු කඳුකර වේලාව (ඩෙන්වර්)", + "America\/Detroit": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ඩෙත්රුවා)", + "America\/Dominica": "අත්ලාන්තික් වේලාව (ඩොමිනිකා)", + "America\/Edmonton": "උතුරු ඇමරිකානු කඳුකර වේලාව (එඩ්මන්ටන්)", + "America\/El_Salvador": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (එල්සැල්වදෝර්)", + "America\/Fort_Nelson": "උතුරු ඇමරිකානු කඳුකර වේලාව (ෆෝට් නෙල්සන්)", + "America\/Fortaleza": "බ්‍රසීල වේලාව (ෆොර්ටලේසා)", + "America\/Glace_Bay": "අත්ලාන්තික් වේලාව (ග්ලේස් බොක්ක)", + "America\/Godthab": "බටහිර ග්‍රීන්ලන්ත වේලාව (නූක්)", + "America\/Goose_Bay": "අත්ලාන්තික් වේලාව (ගූස් බොක්ක)", + "America\/Grand_Turk": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ග්රෑන්ඩ් ටර්ක්)", + "America\/Grenada": "අත්ලාන්තික් වේලාව (ග්‍රැනඩා)", + "America\/Guadeloupe": "අත්ලාන්තික් වේලාව (ග්වාඩ්ලෝප්)", + "America\/Guatemala": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (ගෝතමාලාව)", + "America\/Guayaquil": "ඉක්වදෝර් වේලාව (ගුඅයාකුයිල්)", + "America\/Guyana": "ගයනා වේලාව (ගයනාව)", + "America\/Halifax": "අත්ලාන්තික් වේලාව (හලිෆැක්ස්)", + "America\/Havana": "කියුබානු වේලාව (හවානා)", + "America\/Hermosillo": "මෙක්සිකෝ පැසිෆික් වේලාව (හෙමොසිලෝ)", + "America\/Indiana\/Knox": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (නොක්ස්, ඉන්දියානා)", + "America\/Indiana\/Marengo": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (මරෙන්ගෝ, ඉන්දියානා)", + "America\/Indiana\/Petersburg": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (පීටර්ස්බර්ග්, ඉන්දියානා)", + "America\/Indiana\/Tell_City": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (ටෙල් නගරය, ඉන්දියානා)", + "America\/Indiana\/Vevay": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (වෙවේ, ඉන්දියානා)", + "America\/Indiana\/Vincennes": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (වින්සනස්, ඉන්දියානා)", + "America\/Indiana\/Winamac": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (විනමැක්, ඉන්දියානා)", + "America\/Indianapolis": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ඉන්ඩියානපොලිස්)", + "America\/Inuvik": "උතුරු ඇමරිකානු කඳුකර වේලාව (ඉනුවික්)", + "America\/Iqaluit": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ඉකාලුයිට්)", + "America\/Jamaica": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ජැමෙයිකා)", + "America\/Jujuy": "ආර්ජන්ටිනා වේලාව (ජුජුයි)", + "America\/Juneau": "ඇලස්කා වේලාව (ජූනෝ)", + "America\/Kentucky\/Monticello": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (මොන්ටිසෙලෝ, කෙන්ටකි)", + "America\/Kralendijk": "අත්ලාන්තික් වේලාව (ක්‍රලෙන්දිජ්ක්)", + "America\/La_Paz": "බොලිවියා වේලාව (ලා පස්)", + "America\/Lima": "පේරු වේලාව (ලීමා)", + "America\/Los_Angeles": "උතුරු ඇමරිකානු පැසිෆික් වේලාව (ලොස් ඇන්ජලීස්)", + "America\/Louisville": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ලුවිස්විල්)", + "America\/Lower_Princes": "අත්ලාන්තික් වේලාව (ලෝවර් ප්‍රින්සස් ක්වාටර්)", + "America\/Maceio": "බ්‍රසීල වේලාව (මසේයියෝ)", + "America\/Managua": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මනගුආ)", + "America\/Manaus": "ඇමර්සන් වේලාව (මැනෝස්)", + "America\/Marigot": "අත්ලාන්තික් වේලාව (මැරිගොට්)", + "America\/Martinique": "අත්ලාන්තික් වේලාව (මාටිනික්)", + "America\/Matamoros": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මටමොරොස්)", + "America\/Mazatlan": "මෙක්සිකෝ පැසිෆික් වේලාව (මසට්ලාන්)", + "America\/Mendoza": "ආර්ජන්ටිනා වේලාව (මෙන්ඩෝසා)", + "America\/Menominee": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මෙනොමිනී)", + "America\/Merida": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මෙරිඩා)", + "America\/Metlakatla": "ඇලස්කා වේලාව (මෙට්ලකට්ලා)", + "America\/Mexico_City": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මෙක්සිකෝ නගරය)", + "America\/Miquelon": "ශාන්ත පියරේ සහ මැකෝලන් වේලාව (මිකියුලන්)", + "America\/Moncton": "අත්ලාන්තික් වේලාව (මොන්ක්ටන්)", + "America\/Monterrey": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මොන්ටෙරේ)", + "America\/Montevideo": "උරුගුවේ වේලාව (මොන්ටෙවිඩියෝ)", + "America\/Montserrat": "අත්ලාන්තික් වේලාව (මොන්ට්සේරාට්)", + "America\/Nassau": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (නස්සෝ)", + "America\/New_York": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (නිව්යෝක්)", + "America\/Nipigon": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (නිපිගන්)", + "America\/Nome": "ඇලස්කා වේලාව (නෝම්)", + "America\/Noronha": "ෆර්නැන්ඩෝ ඩි නොරොන්හා වේලාව (නොරොන්හා)", + "America\/North_Dakota\/Beulah": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (බියුලා, උතුරු ඩකෝටා)", + "America\/North_Dakota\/Center": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (මධ්‍යම, උතුරු ඩකෝටා)", + "America\/North_Dakota\/New_Salem": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (නව සලෙම්ම, උතුරු ඩකෝටා)", + "America\/Ojinaga": "උතුරු ඇමරිකානු කඳුකර වේලාව (ඔජිනගා)", + "America\/Panama": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (පැනමා)", + "America\/Pangnirtung": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (පැන්නීටන්)", + "America\/Paramaribo": "සුරිනාම වේලාව (පැරාමරිබෝ)", + "America\/Phoenix": "උතුරු ඇමරිකානු කඳුකර වේලාව (ෆීනික්ස්)", + "America\/Port-au-Prince": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (පොර්ට්-ඕ-ප්‍රින්ස්)", + "America\/Port_of_Spain": "අත්ලාන්තික් වේලාව (පොර්ට් ඔෆ් ස්පෙයින්)", + "America\/Porto_Velho": "ඇමර්සන් වේලාව (පොර්තෝ වෙල්හෝ)", + "America\/Puerto_Rico": "අත්ලාන්තික් වේලාව (පුවටොරිකෝව)", + "America\/Punta_Arenas": "චිලී වේලාව (පුන්ටා ඇරිනාස්)", + "America\/Rainy_River": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (රෙයිනි ගඟ)", + "America\/Rankin_Inlet": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (රැන්කින් පිවිසුම)", + "America\/Recife": "බ්‍රසීල වේලාව (රෙසිෆ්)", + "America\/Regina": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (රෙජිනා)", + "America\/Resolute": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (රෙසොලුට්)", + "America\/Santa_Isabel": "වයඹ මෙක්සිකෝ වේලාව (සැන්ටා ඉසබෙල්)", + "America\/Santarem": "බ්‍රසීල වේලාව (සන්ටරේම්)", + "America\/Santiago": "චිලී වේලාව (සන්තියාගෝ)", + "America\/Santo_Domingo": "අත්ලාන්තික් වේලාව (සැන්ටෝ ඩොමින්ගෝ)", + "America\/Sao_Paulo": "බ්‍රසීල වේලාව (සාවෝ පෝලො)", + "America\/Scoresbysund": "නැගෙනහිර ග්‍රීන්ලන්ත වේලාව (ඉටොකොර්ටෝමිට්)", + "America\/Sitka": "ඇලස්කා වේලාව (සිට්කා)", + "America\/St_Barthelemy": "අත්ලාන්තික් වේලාව (ශාන්ත බර්තලෙමි)", + "America\/St_Johns": "නිව්ෆවුන්ලන්ත වේලාව (ශාන්ත ජෝන්ගේ)", + "America\/St_Kitts": "අත්ලාන්තික් වේලාව (ශාන්ත කිට්ස්)", + "America\/St_Lucia": "අත්ලාන්තික් වේලාව (ශාන්ත ලුසියා)", + "America\/St_Thomas": "අත්ලාන්තික් වේලාව (ශාන්ත තෝමස්)", + "America\/St_Vincent": "අත්ලාන්තික් වේලාව (ශාන්ත වින්ට්සන්)", + "America\/Swift_Current": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (ස්විෆ්ට් කරන්ට්)", + "America\/Tegucigalpa": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (ටෙගුසිගල්පා)", + "America\/Thule": "අත්ලාන්තික් වේලාව (තුලේ)", + "America\/Thunder_Bay": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (තන්ඩර් බොක්ක)", + "America\/Tijuana": "උතුරු ඇමරිකානු පැසිෆික් වේලාව (ටිජුආනා)", + "America\/Toronto": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව (ටොරන්ටෝ)", + "America\/Tortola": "අත්ලාන්තික් වේලාව (ටොර්ටෝලා)", + "America\/Vancouver": "උතුරු ඇමරිකානු පැසිෆික් වේලාව (වැන්කුවර්)", + "America\/Whitehorse": "උතුරු ඇමරිකානු පැසිෆික් වේලාව (වයිට්හෝර්ස්)", + "America\/Winnipeg": "උතුරු ඇමරිකානු මධ්‍යම වේලාව (විනිපෙග්)", + "America\/Yakutat": "ඇලස්කා වේලාව (යකුටට්)", + "America\/Yellowknife": "උතුරු ඇමරිකානු කඳුකර වේලාව (යෙලෝනයිෆ්)", + "Antarctica\/Casey": "බටහිර ඕස්ට්‍රේලියානු වේලාව (කැසේ)", + "Antarctica\/Davis": "ඩාවිස් වේලාව (ඩේවිස්)", + "Antarctica\/DumontDUrville": "දුමොන්ත්-ඩ්උර්විල් වේලාව (ඩුමොන්ට් ඩු‘ර්විල්)", + "Antarctica\/Macquarie": "මැක්කුඅරි දුපත් වේලාව (මක්කුවරි)", + "Antarctica\/Mawson": "මොව්සන් වේලාව (මව්සන්)", + "Antarctica\/McMurdo": "නවසීලන්ත වේලාව (මැක්මුර්ඩෝ)", + "Antarctica\/Palmer": "චිලී වේලාව (පැල්මර්)", + "Antarctica\/Rothera": "රොතෙරා වේලාව (රොතෙරා)", + "Antarctica\/Syowa": "ස්යෝවා වේලාව (සියෝවා)", + "Antarctica\/Troll": "ග්‍රිනිච් මධ්‍යම වේලාව (ට්‍රෝල්)", + "Antarctica\/Vostok": "වොස්ටොක් වේලාව (වොස්ටොක්)", + "Arctic\/Longyearbyen": "මධ්‍යම යුරෝපීය වේලාව (ලෝන්ග්ඉයර්බියෙන්)", + "Asia\/Aden": "අරාබි වේලාව (ඒඩ්න්)", + "Asia\/Almaty": "නැගෙනහිර කසකස්තාන වේලාව (අල්මටි)", + "Asia\/Amman": "නැගෙනහිර යුරෝපීය වේලාව (අම්මාන්)", + "Asia\/Aqtau": "බටහිර කසකස්තාන වේලාව (අක්ටෝ)", + "Asia\/Aqtobe": "බටහිර කසකස්තාන වේලාව (අක්ටෝබ්)", + "Asia\/Ashgabat": "ටර්ක්මෙනිස්තාන වේලාව (අශ්ගබැට්)", + "Asia\/Atyrau": "බටහිර කසකස්තාන වේලාව (ඇටිරවු)", + "Asia\/Baghdad": "අරාබි වේලාව (බැග්ඩෑඩ්)", + "Asia\/Bahrain": "අරාබි වේලාව (බහරේන්)", + "Asia\/Baku": "අසර්බයිජාන් වේලාව (බාකු)", + "Asia\/Bangkok": "ඉන්දුචීන වේලාව (බැංකොක්)", + "Asia\/Beirut": "නැගෙනහිර යුරෝපීය වේලාව (බීරුට්)", + "Asia\/Bishkek": "කිර්ගිස්තාන වේලාව (බිශ්කෙක්)", + "Asia\/Brunei": "බෘනායි දරුස්සලාම් වේලාව (බෲනායි)", + "Asia\/Calcutta": "ඉන්දියානු වේලාව (කල්කටා)", + "Asia\/Chita": "යකුට්ස්ක් වේලාව (චිටා)", + "Asia\/Choibalsan": "චොයිබල්සාන් වේලාව (චොයිබල්සාන්)", + "Asia\/Colombo": "ඉන්දියානු වේලාව (කොළඹ)", + "Asia\/Damascus": "නැගෙනහිර යුරෝපීය වේලාව (ඩැමස්කස්)", + "Asia\/Dhaka": "බංගලාදේශ වේලාව (ඩකා)", + "Asia\/Dili": "නැගෙනහිර ටිමෝර් වේලාව (ඩිලි)", + "Asia\/Dubai": "ගල්ෆ් වේලාව (ඩුබායි)", + "Asia\/Dushanbe": "ටජිකිස්තාන වේලාව (ඩුශන්බේ)", + "Asia\/Famagusta": "නැගෙනහිර යුරෝපීය වේලාව (ෆැමගුස්ටා)", + "Asia\/Gaza": "නැගෙනහිර යුරෝපීය වේලාව (ගාසා)", + "Asia\/Hebron": "නැගෙනහිර යුරෝපීය වේලාව (හෙබ්රෝන්)", + "Asia\/Hong_Kong": "හොංකොං වේලාව (හොංකොං)", + "Asia\/Hovd": "හොව්ඩ් වේලාව (හොව්ඩ්)", + "Asia\/Irkutsk": "ඉර්කුට්ස්ක් වේලාව (ඉරකුට්ස්ක්)", + "Asia\/Jakarta": "බටහිර ඉන්දුනීසියානු වේලාව (ජකර්තා)", + "Asia\/Jayapura": "නැගෙනහිර ඉන්දුනීසියානු වේලාව (ජයපුර)", + "Asia\/Jerusalem": "ඊශ්‍රායල වේලාව (ජෙරුසලම)", + "Asia\/Kabul": "ඇෆ්ගනිස්ථාන වේලාව (කාබුල්)", + "Asia\/Karachi": "පාකිස්ථාන වේලාව (කරච්චිචි)", + "Asia\/Katmandu": "නේපාල වේලාව (කත්මන්ඩු)", + "Asia\/Khandyga": "යකුට්ස්ක් වේලාව (ඛන්ඩිගා)", + "Asia\/Krasnoyarsk": "ක්‍රස්නොයාර්ස්ක් වේලාව (ක්‍රස්නෝයාර්ස්ක්)", + "Asia\/Kuala_Lumpur": "මැලේසියානු වේලාව (ක්වාලාලම්පූර්)", + "Asia\/Kuching": "මැලේසියානු වේලාව (කුචිං)", + "Asia\/Kuwait": "අරාබි වේලාව (කුවේට්)", + "Asia\/Macau": "චීන වේලාව (මැකාවු)", + "Asia\/Magadan": "මෙගඩන් වේලාව (මගඩන්)", + "Asia\/Makassar": "මධ්‍යම ඉන්දුනීසියානු වේලාව (මක්ස්සාර්)", + "Asia\/Manila": "පිලිපීන වේලාව (මැනිලා)", + "Asia\/Muscat": "ගල්ෆ් වේලාව (මස්කට්)", + "Asia\/Nicosia": "නැගෙනහිර යුරෝපීය වේලාව (නිකෝසියා)", + "Asia\/Novokuznetsk": "ක්‍රස්නොයාර්ස්ක් වේලාව (නොවොකුස්නේට්ස්ක්)", + "Asia\/Novosibirsk": "නොවසිබිර්ස්ක් වේලාව (නොවොසිබර්ස්ක්)", + "Asia\/Omsk": "ඔම්ස්ක් වේලාව (ඔම්ස්ක්)", + "Asia\/Oral": "බටහිර කසකස්තාන වේලාව (ඔරාල්)", + "Asia\/Phnom_Penh": "ඉන්දුචීන වේලාව (නොම් පෙන්)", + "Asia\/Pontianak": "බටහිර ඉන්දුනීසියානු වේලාව (පොන්ටියනක්)", + "Asia\/Pyongyang": "කොරියානු වේලාව (ප්යෝන්ග්යැන්ග්)", + "Asia\/Qatar": "අරාබි වේලාව (කටාර්)", + "Asia\/Qostanay": "නැගෙනහිර කසකස්තාන වේලාව (Qostanay)", + "Asia\/Qyzylorda": "බටහිර කසකස්තාන වේලාව (ක්යිසිලෝර්ඩා)", + "Asia\/Rangoon": "මියන්මාර් වේලාව (රැංගුන්)", + "Asia\/Riyadh": "අරාබි වේලාව (රියාද්)", + "Asia\/Saigon": "ඉන්දුචීන වේලාව (හෝචි මිං නගරය)", + "Asia\/Sakhalin": "සඛලින් වේලාව (සක්හලින්)", + "Asia\/Samarkand": "උස්බෙකිස්තාන වේලාව (සාමාර්කන්ඩ්)", + "Asia\/Seoul": "කොරියානු වේලාව (සෝල්)", + "Asia\/Shanghai": "චීන වේලාව (ෂැන්හයි)", + "Asia\/Singapore": "සිංගප්පුරු වේලාව (සිංගප්පූරුව)", + "Asia\/Srednekolymsk": "මෙගඩන් වේලාව (ශ්‍රෙඩ්නෙකෝලිම්සක්)", + "Asia\/Taipei": "තායිපේ වේලාව (තායිපෙ)", + "Asia\/Tashkent": "උස්බෙකිස්තාන වේලාව (ටෂ්කෙන්ට්)", + "Asia\/Tbilisi": "ජෝර්ජියානු වේලාව (ට්බිලිසි)", + "Asia\/Tehran": "ඉරාන වේලාව (ටෙහෙරාන්)", + "Asia\/Thimphu": "භුතාන වේලාව (තිම්පු)", + "Asia\/Tokyo": "ජපාන වේලාව (ටෝකියෝ)", + "Asia\/Ulaanbaatar": "උලාන් බාටර් වේලාව (උලාන්බාටර්)", + "Asia\/Ust-Nera": "ව්ලදිවෝස්ටෝක් වේලාව (උස්ට්-නෙරා)", + "Asia\/Vientiane": "ඉන්දුචීන වේලාව (වියැන්ටියන්)", + "Asia\/Vladivostok": "ව්ලදිවෝස්ටෝක් වේලාව (ව්ලඩිවොස්ටොක්)", + "Asia\/Yakutsk": "යකුට්ස්ක් වේලාව (යකුට්ස්ක්)", + "Asia\/Yekaterinburg": "යෙකටෙරින්බර්ග් වේලාව (යෙකටරින්බර්ග්)", + "Asia\/Yerevan": "ආමේනියානු වේලාව (යෙරෙවන්)", + "Atlantic\/Azores": "ඇසොර්ස් වේලාව (ඇසොරේ)", + "Atlantic\/Bermuda": "අත්ලාන්තික් වේලාව (බර්මියුඩා)", + "Atlantic\/Canary": "බටහිර යුරෝපීය වේලාව (කැනරි)", + "Atlantic\/Cape_Verde": "කේප්වේඩ් වේලාව (කේප් වර්ඩ්)", + "Atlantic\/Faeroe": "බටහිර යුරෝපීය වේලාව (ෆාරෝ)", + "Atlantic\/Madeira": "බටහිර යුරෝපීය වේලාව (මඩෙයිරා)", + "Atlantic\/Reykjavik": "ග්‍රිනිච් මධ්‍යම වේලාව (රෙයික්ජාවික්)", + "Atlantic\/South_Georgia": "දකුණු ජෝජියා වේලාව (දකුණු ජෝර්ජියාව)", + "Atlantic\/St_Helena": "ග්‍රිනිච් මධ්‍යම වේලාව (ශා. හෙලේනා)", + "Atlantic\/Stanley": "ෆෝක්ලන්ඩ් දූපත් වේලාව (ස්ටැන්ලි)", + "Australia\/Adelaide": "මධ්‍යම ඕස්ට්‍රේලියානු වේලාව (ඇඩිලේඩ්)", + "Australia\/Brisbane": "නැගෙනහිර ඕස්ට්‍රේලියානු වේලාව (බ්‍රිස්බේන්)", + "Australia\/Broken_Hill": "මධ්‍යම ඕස්ට්‍රේලියානු වේලාව (බ්‍රෝකන් හිල්)", + "Australia\/Currie": "නැගෙනහිර ඕස්ට්‍රේලියානු වේලාව (කුරී)", + "Australia\/Darwin": "මධ්‍යම ඕස්ට්‍රේලියානු වේලාව (ඩාවින්)", + "Australia\/Eucla": "මධ්‍යම බටහිර ඔස්ට්‍රේලියානු වේලාව (ඉයුක්ලා)", + "Australia\/Hobart": "නැගෙනහිර ඕස්ට්‍රේලියානු වේලාව (හෝබාර්ට්)", + "Australia\/Lindeman": "නැගෙනහිර ඕස්ට්‍රේලියානු වේලාව (ලින්ඩේමන්)", + "Australia\/Lord_Howe": "ලෝර්ඩ් හෝව් වේලාව (ලෝර්ඩ් හෝව්)", + "Australia\/Melbourne": "නැගෙනහිර ඕස්ට්‍රේලියානු වේලාව (මෙල්බෝර්න්)", + "Australia\/Perth": "බටහිර ඕස්ට්‍රේලියානු වේලාව (පර්ත්)", + "Australia\/Sydney": "නැගෙනහිර ඕස්ට්‍රේලියානු වේලාව (සිඩ්නි)", + "CST6CDT": "උතුරු ඇමරිකානු මධ්‍යම වේලාව", + "EST5EDT": "උතුරු ඇමරිකානු නැගෙනහිර වේලාව", + "Etc\/GMT": "ග්‍රිනිච් මධ්‍යම වේලාව", + "Etc\/UTC": "සමකක්ෂ සාර්ව වේලාව", + "Europe\/Amsterdam": "මධ්‍යම යුරෝපීය වේලාව (ඇම්ස්ටර්ඩෑම්)", + "Europe\/Andorra": "මධ්‍යම යුරෝපීය වේලාව (ඇන්ඩෝරාව)", + "Europe\/Astrakhan": "මොස්කව් වේලාව (අස්ට්‍රඛාන්)", + "Europe\/Athens": "නැගෙනහිර යුරෝපීය වේලාව (ඇතැන්ස්)", + "Europe\/Belgrade": "මධ්‍යම යුරෝපීය වේලාව (බෙල්ග්‍රේඩ්ඩ්)", + "Europe\/Berlin": "මධ්‍යම යුරෝපීය වේලාව (බර්ලින්)", + "Europe\/Bratislava": "මධ්‍යම යුරෝපීය වේලාව (බ්‍රටිස්ලවා)", + "Europe\/Brussels": "මධ්‍යම යුරෝපීය වේලාව (බ්‍රසල්ස්)", + "Europe\/Bucharest": "නැගෙනහිර යුරෝපීය වේලාව (බුකාරෙස්ට්)", + "Europe\/Budapest": "මධ්‍යම යුරෝපීය වේලාව (බුඩාපෙස්ට්)", + "Europe\/Busingen": "මධ්‍යම යුරෝපීය වේලාව (බුසින්ජෙන්)", + "Europe\/Chisinau": "නැගෙනහිර යුරෝපීය වේලාව (චිසිනෝ)", + "Europe\/Copenhagen": "මධ්‍යම යුරෝපීය වේලාව (කෝපන්හේගන්)", + "Europe\/Dublin": "ග්‍රිනිච් මධ්‍යම වේලාව (ඩබ්ලින්)", + "Europe\/Gibraltar": "මධ්‍යම යුරෝපීය වේලාව (ජිබ්රෝල්ටා)", + "Europe\/Guernsey": "ග්‍රිනිච් මධ්‍යම වේලාව (ගුවන්සේ)", + "Europe\/Helsinki": "නැගෙනහිර යුරෝපීය වේලාව (හෙල්සින්කි)", + "Europe\/Isle_of_Man": "ග්‍රිනිච් මධ්‍යම වේලාව (අයිල් ඔෆ් මෑන්)", + "Europe\/Jersey": "ග්‍රිනිච් මධ්‍යම වේලාව (ජර්සි)", + "Europe\/Kaliningrad": "නැගෙනහිර යුරෝපීය වේලාව (කලිනින්ග්‍රෑඩ්)", + "Europe\/Kiev": "නැගෙනහිර යුරෝපීය වේලාව (කිව්)", + "Europe\/Lisbon": "බටහිර යුරෝපීය වේලාව (ලිස්බන්)", + "Europe\/Ljubljana": "මධ්‍යම යුරෝපීය වේලාව (ල්ජුබුල්ජනා)", + "Europe\/London": "ග්‍රිනිච් මධ්‍යම වේලාව (ලන්ඩන්)", + "Europe\/Luxembourg": "මධ්‍යම යුරෝපීය වේලාව (ලක්සැම්බර්ග්)", + "Europe\/Madrid": "මධ්‍යම යුරෝපීය වේලාව (මැඩ්රිඩ්)", + "Europe\/Malta": "මධ්‍යම යුරෝපීය වේලාව (මෝල්ටා)", + "Europe\/Mariehamn": "නැගෙනහිර යුරෝපීය වේලාව (මරියෙහම්න්)", + "Europe\/Minsk": "මොස්කව් වේලාව (මින්ස්ක්)", + "Europe\/Monaco": "මධ්‍යම යුරෝපීය වේලාව (මොනැකෝ)", + "Europe\/Moscow": "මොස්කව් වේලාව (මොස්කව්)", + "Europe\/Oslo": "මධ්‍යම යුරෝපීය වේලාව (ඔස්ලෝ)", + "Europe\/Paris": "මධ්‍යම යුරෝපීය වේලාව (පැරිස්)", + "Europe\/Podgorica": "මධ්‍යම යුරෝපීය වේලාව (පොඩ්ගොරිකා)", + "Europe\/Prague": "මධ්‍යම යුරෝපීය වේලාව (ප්‍රෙග්)", + "Europe\/Riga": "නැගෙනහිර යුරෝපීය වේලාව (රිගා)", + "Europe\/Rome": "මධ්‍යම යුරෝපීය වේලාව (රෝමය)", + "Europe\/San_Marino": "මධ්‍යම යුරෝපීය වේලාව (සැන් මැරිනෝ)", + "Europe\/Sarajevo": "මධ්‍යම යුරෝපීය වේලාව (සරාජෙවෝ)", + "Europe\/Saratov": "මොස්කව් වේලාව (සරටොව්)", + "Europe\/Simferopol": "මොස්කව් වේලාව (සිම්ෆෙරෝපොල්)", + "Europe\/Skopje": "මධ්‍යම යුරෝපීය වේලාව (ස්කොප්ජේ)", + "Europe\/Sofia": "නැගෙනහිර යුරෝපීය වේලාව (සොෆියා)", + "Europe\/Stockholm": "මධ්‍යම යුරෝපීය වේලාව (ස්ටොක්හෝම්)", + "Europe\/Tallinn": "නැගෙනහිර යුරෝපීය වේලාව (ටලින්)", + "Europe\/Tirane": "මධ්‍යම යුරෝපීය වේලාව (ටිරානේ)", + "Europe\/Ulyanovsk": "මොස්කව් වේලාව (උල්යනොව්ස්ක්)", + "Europe\/Uzhgorod": "නැගෙනහිර යුරෝපීය වේලාව (උස්ගොරෝඩ්)", + "Europe\/Vaduz": "මධ්‍යම යුරෝපීය වේලාව (වඩුස්)", + "Europe\/Vatican": "මධ්‍යම යුරෝපීය වේලාව (වතිකානුව)", + "Europe\/Vienna": "මධ්‍යම යුරෝපීය වේලාව (වියනා)", + "Europe\/Vilnius": "නැගෙනහිර යුරෝපීය වේලාව (විල්නියුස්)", + "Europe\/Volgograd": "වොල්ගොග්‍රාඩ් වේලාව (වොල්ගොග්‍රෑඩ්)", + "Europe\/Warsaw": "මධ්‍යම යුරෝපීය වේලාව (වර්සෝ)", + "Europe\/Zagreb": "මධ්‍යම යුරෝපීය වේලාව (සග්රෙබ්)", + "Europe\/Zaporozhye": "නැගෙනහිර යුරෝපීය වේලාව (සපොරෝසියේ)", + "Europe\/Zurich": "මධ්‍යම යුරෝපීය වේලාව (සූරිච්)", + "Indian\/Antananarivo": "නැගෙනහිර අප්‍රිකානු වේලාව (ඇන්ටනානරිවෝ)", + "Indian\/Chagos": "ඉන්දියන් සාගර වේලාව (චාගොස්)", + "Indian\/Christmas": "ක්‍රිස්මස් දුපත් වේලාව (ක්‍රිස්මස්)", + "Indian\/Cocos": "කොකෝස් දුපත් වේලාව (කොකොස්)", + "Indian\/Comoro": "නැගෙනහිර අප්‍රිකානු වේලාව (කොමොරෝ)", + "Indian\/Kerguelen": "ප්‍රංශ දකුණුදිග සහ ඇන්ටාර්ක්ටික් වේලාව (කෙර්ගුඑලෙන්)", + "Indian\/Mahe": "සීෂෙල්ස් වේලාව (මාහේ)", + "Indian\/Maldives": "මාලදිවයින් වේලාව (මාල දිවයින)", + "Indian\/Mauritius": "මුරුසි වේලාව (මුරුසිය)", + "Indian\/Mayotte": "නැගෙනහිර අප්‍රිකානු වේලාව (මයෝටි)", + "Indian\/Reunion": "රියුනියන් වේලාව (රියුනියන්)", + "MST7MDT": "උතුරු ඇමරිකානු කඳුකර වේලාව", + "PST8PDT": "උතුරු ඇමරිකානු පැසිෆික් වේලාව", + "Pacific\/Apia": "අපියා වේලාව (ඇපියා)", + "Pacific\/Auckland": "නවසීලන්ත වේලාව (ඕක්ලන්ඩ්)", + "Pacific\/Bougainville": "පැපුවා නිව් ගිනීයා වේලාව (බෝගන්විලා)", + "Pacific\/Chatham": "චැතම් වේලාව (චැතම්)", + "Pacific\/Easter": "ඊස්ටර් දූපත් වේලාව (ඊස්ටර්)", + "Pacific\/Efate": "වනුආටු වේලාව (එෆාත්)", + "Pacific\/Enderbury": "ෆීනික්ස් දුපත් වේලාව (එන්ඩර්බරි)", + "Pacific\/Fakaofo": "ටොකෙලාවු වේලාව (ෆාකාඕෆෝ)", + "Pacific\/Fiji": "ෆිජි වේලාව (ෆීජි)", + "Pacific\/Funafuti": "ටුවාලු වේලාව (ෆුනෆුටි)", + "Pacific\/Galapagos": "ගලපගොස් වේලාව (ගලපගෝස්)", + "Pacific\/Gambier": "ගැම්බියර් වේලාව (ගම්බියෙර්)", + "Pacific\/Guadalcanal": "සොලොමන් දූපත් වේලාව (ගුවාඩල්කැනල්)", + "Pacific\/Guam": "චමොරෝ වේලාව (ගුවාම්)", + "Pacific\/Honolulu": "හවායි-අලෙයුතියාන් වේලාව (හොනොලුලු)", + "Pacific\/Johnston": "හවායි-අලෙයුතියාන් වේලාව (ජොන්ස්ටන්)", + "Pacific\/Kiritimati": "ලයින් දුපත් වේලාව (කිරිමටි)", + "Pacific\/Kosrae": "කොස්රේ වේලාව (කොස්රේ)", + "Pacific\/Kwajalein": "මාර්ෂල් දුපත් වේලාව (ක්වාජලෙයින්)", + "Pacific\/Majuro": "මාර්ෂල් දුපත් වේලාව (මජුරෝ)", + "Pacific\/Marquesas": "මාර්කුඑසාස් වේලාව (මාකුවෙසාස්)", + "Pacific\/Midway": "සැමෝවා වේලාව (මිඩ්වේ)", + "Pacific\/Nauru": "නාවුරු වේලාව (නවුරු)", + "Pacific\/Niue": "නියු වේලාව (නියු)", + "Pacific\/Norfolk": "නොෆොල්ක් දුපත් වේලාව (නෝෆෝක්)", + "Pacific\/Noumea": "නව සෙලඩොනියානු වේලාව (නෝමියා)", + "Pacific\/Pago_Pago": "සැමෝවා වේලාව (පගෝ පගෝ)", + "Pacific\/Palau": "පලාවු වේලාව (පලාවු)", + "Pacific\/Pitcairn": "පිට්කෙයාන් වේලාව (පිට්කෙයාන්)", + "Pacific\/Ponape": "පොනපේ වේලාව (පොන්පෙයි)", + "Pacific\/Port_Moresby": "පැපුවා නිව් ගිනීයා වේලාව (පොර්ට් මොරෙස්බි)", + "Pacific\/Rarotonga": "කුක් දුපත් වේලාව (රරෝටෝන්ගා)", + "Pacific\/Saipan": "චමොරෝ වේලාව (සයිපාන්)", + "Pacific\/Tahiti": "ටාහිටි වේලාව (ටහිති)", + "Pacific\/Tarawa": "ගිල්බර්ට් දුපත් වේලාව (ටරාවා)", + "Pacific\/Tongatapu": "ටොංගා වේලාව (ටොන්ගටාපු)", + "Pacific\/Truk": "චුක් වේලාව (චූක්)", + "Pacific\/Wake": "වේක් දූපත් වේලාව (වේක්)", + "Pacific\/Wallis": "වැලිස් සහ ෆුටුනා වේලාව (වැලිස්)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sk.json b/src/Symfony/Component/Intl/Resources/data/timezones/sk.json new file mode 100644 index 0000000000000..9331fff8fd30f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sk.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "greenwichský čas (Abidjan)", + "Africa\/Accra": "greenwichský čas (Accra)", + "Africa\/Addis_Ababa": "východoafrický čas (Addis Abeba)", + "Africa\/Algiers": "stredoeurópsky čas (Alžír)", + "Africa\/Asmera": "východoafrický čas (Asmara)", + "Africa\/Bamako": "greenwichský čas (Bamako)", + "Africa\/Bangui": "západoafrický čas (Bangui)", + "Africa\/Banjul": "greenwichský čas (Banjul)", + "Africa\/Bissau": "greenwichský čas (Bissau)", + "Africa\/Blantyre": "stredoafrický čas (Blantyre)", + "Africa\/Brazzaville": "západoafrický čas (Brazzaville)", + "Africa\/Bujumbura": "stredoafrický čas (Bujumbura)", + "Africa\/Cairo": "východoeurópsky čas (Káhira)", + "Africa\/Casablanca": "západoeurópsky čas (Casablanca)", + "Africa\/Ceuta": "stredoeurópsky čas (Ceuta)", + "Africa\/Conakry": "greenwichský čas (Conakry)", + "Africa\/Dakar": "greenwichský čas (Dakar)", + "Africa\/Dar_es_Salaam": "východoafrický čas (Dar es Salaam)", + "Africa\/Djibouti": "východoafrický čas (Džibuti)", + "Africa\/Douala": "západoafrický čas (Douala)", + "Africa\/El_Aaiun": "západoeurópsky čas (El-Aaiún)", + "Africa\/Freetown": "greenwichský čas (Freetown)", + "Africa\/Gaborone": "stredoafrický čas (Gaborone)", + "Africa\/Harare": "stredoafrický čas (Harare)", + "Africa\/Johannesburg": "juhoafrický čas (Johannesburg)", + "Africa\/Juba": "východoafrický čas (Juba)", + "Africa\/Kampala": "východoafrický čas (Kampala)", + "Africa\/Khartoum": "stredoafrický čas (Chartúm)", + "Africa\/Kigali": "stredoafrický čas (Kigali)", + "Africa\/Kinshasa": "západoafrický čas (Kinshasa)", + "Africa\/Lagos": "západoafrický čas (Lagos)", + "Africa\/Libreville": "západoafrický čas (Libreville)", + "Africa\/Lome": "greenwichský čas (Lomé)", + "Africa\/Luanda": "západoafrický čas (Luanda)", + "Africa\/Lubumbashi": "stredoafrický čas (Lubumbashi)", + "Africa\/Lusaka": "stredoafrický čas (Lusaka)", + "Africa\/Malabo": "západoafrický čas (Malabo)", + "Africa\/Maputo": "stredoafrický čas (Maputo)", + "Africa\/Maseru": "juhoafrický čas (Maseru)", + "Africa\/Mbabane": "juhoafrický čas (Mbabane)", + "Africa\/Mogadishu": "východoafrický čas (Mogadišo)", + "Africa\/Monrovia": "greenwichský čas (Monrovia)", + "Africa\/Nairobi": "východoafrický čas (Nairobi)", + "Africa\/Ndjamena": "západoafrický čas (N’Djamena)", + "Africa\/Niamey": "západoafrický čas (Niamey)", + "Africa\/Nouakchott": "greenwichský čas (Nouakchott)", + "Africa\/Ouagadougou": "greenwichský čas (Ouagadougou)", + "Africa\/Porto-Novo": "západoafrický čas (Porto-Novo)", + "Africa\/Sao_Tome": "greenwichský čas (Svätý Tomáš)", + "Africa\/Tripoli": "východoeurópsky čas (Tripolis)", + "Africa\/Tunis": "stredoeurópsky čas (Tunis)", + "Africa\/Windhoek": "stredoafrický čas (Windhoek)", + "America\/Adak": "havajsko-aleutský čas (Adak)", + "America\/Anchorage": "aljašský čas (Anchorage)", + "America\/Anguilla": "atlantický čas (Anguilla)", + "America\/Antigua": "atlantický čas (Antigua)", + "America\/Araguaina": "brazílsky čas (Araguaina)", + "America\/Argentina\/La_Rioja": "argentínsky čas (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "argentínsky čas (Rio Gallegos)", + "America\/Argentina\/Salta": "argentínsky čas (Salta)", + "America\/Argentina\/San_Juan": "argentínsky čas (San Juan)", + "America\/Argentina\/San_Luis": "západoargentínsky čas (San Luis)", + "America\/Argentina\/Tucuman": "argentínsky čas (Tucuman)", + "America\/Argentina\/Ushuaia": "argentínsky čas (Ushuaia)", + "America\/Aruba": "atlantický čas (Aruba)", + "America\/Asuncion": "paraguajský čas (Asunción)", + "America\/Bahia": "brazílsky čas (Bahia)", + "America\/Bahia_Banderas": "severoamerický centrálny čas (Bahia Banderas)", + "America\/Barbados": "atlantický čas (Barbados)", + "America\/Belem": "brazílsky čas (Belém)", + "America\/Belize": "severoamerický centrálny čas (Belize)", + "America\/Blanc-Sablon": "atlantický čas (Blanc-Sablon)", + "America\/Boa_Vista": "amazonský čas (Boa Vista)", + "America\/Bogota": "kolumbijský čas (Bogotá)", + "America\/Boise": "severoamerický horský čas (Boise)", + "America\/Buenos_Aires": "argentínsky čas (Buenos Aires)", + "America\/Cambridge_Bay": "severoamerický horský čas (Cambridge Bay)", + "America\/Campo_Grande": "amazonský čas (Campo Grande)", + "America\/Cancun": "severoamerický východný čas (Cancún)", + "America\/Caracas": "venezuelský čas (Caracas)", + "America\/Catamarca": "argentínsky čas (Catamarca)", + "America\/Cayenne": "francúzskoguyanský čas (Cayenne)", + "America\/Cayman": "severoamerický východný čas (Kajmanie ostrovy)", + "America\/Chicago": "severoamerický centrálny čas (Chicago)", + "America\/Chihuahua": "mexický tichomorský čas (Chihuahua)", + "America\/Coral_Harbour": "severoamerický východný čas (Atikokan)", + "America\/Cordoba": "argentínsky čas (Córdoba)", + "America\/Costa_Rica": "severoamerický centrálny čas (Kostarika)", + "America\/Creston": "severoamerický horský čas (Creston)", + "America\/Cuiaba": "amazonský čas (Cuiabá)", + "America\/Curacao": "atlantický čas (Curaçao)", + "America\/Danmarkshavn": "greenwichský čas (Danmarkshavn)", + "America\/Dawson": "severoamerický tichomorský čas (Dawson)", + "America\/Dawson_Creek": "severoamerický horský čas (Dawson Creek)", + "America\/Denver": "severoamerický horský čas (Denver)", + "America\/Detroit": "severoamerický východný čas (Detroit)", + "America\/Dominica": "atlantický čas (Dominika)", + "America\/Edmonton": "severoamerický horský čas (Edmonton)", + "America\/Eirunepe": "acrejský čas (Eirunepé)", + "America\/El_Salvador": "severoamerický centrálny čas (Salvádor)", + "America\/Fort_Nelson": "severoamerický horský čas (Fort Nelson)", + "America\/Fortaleza": "brazílsky čas (Fortaleza)", + "America\/Glace_Bay": "atlantický čas (Glace Bay)", + "America\/Godthab": "západogrónsky čas (Nuuk)", + "America\/Goose_Bay": "atlantický čas (Goose Bay)", + "America\/Grand_Turk": "severoamerický východný čas (Grand Turk)", + "America\/Grenada": "atlantický čas (Grenada)", + "America\/Guadeloupe": "atlantický čas (Guadeloupe)", + "America\/Guatemala": "severoamerický centrálny čas (Guatemala)", + "America\/Guayaquil": "ekvádorský čas (Guayaquil)", + "America\/Guyana": "guyanský čas (Guyana)", + "America\/Halifax": "atlantický čas (Halifax)", + "America\/Havana": "kubánsky čas (Havana)", + "America\/Hermosillo": "mexický tichomorský čas (Hermosillo)", + "America\/Indiana\/Knox": "severoamerický centrálny čas (Knox, Indiana)", + "America\/Indiana\/Marengo": "severoamerický východný čas (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "severoamerický východný čas (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "severoamerický centrálny čas (Tell City, Indiana)", + "America\/Indiana\/Vevay": "severoamerický východný čas (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "severoamerický východný čas (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "severoamerický východný čas (Winamac, Indiana)", + "America\/Indianapolis": "severoamerický východný čas (Indianapolis)", + "America\/Inuvik": "severoamerický horský čas (Inuvik)", + "America\/Iqaluit": "severoamerický východný čas (Iqaluit)", + "America\/Jamaica": "severoamerický východný čas (Jamajka)", + "America\/Jujuy": "argentínsky čas (Jujuy)", + "America\/Juneau": "aljašský čas (Juneau)", + "America\/Kentucky\/Monticello": "severoamerický východný čas (Monticello, Kentucky)", + "America\/Kralendijk": "atlantický čas (Kralendijk)", + "America\/La_Paz": "bolívijský čas (La Paz)", + "America\/Lima": "peruánsky čas (Lima)", + "America\/Los_Angeles": "severoamerický tichomorský čas (Los Angeles)", + "America\/Louisville": "severoamerický východný čas (Louisville)", + "America\/Lower_Princes": "atlantický čas (Lower Prince’s Quarter)", + "America\/Maceio": "brazílsky čas (Maceió)", + "America\/Managua": "severoamerický centrálny čas (Managua)", + "America\/Manaus": "amazonský čas (Manaus)", + "America\/Marigot": "atlantický čas (Marigot)", + "America\/Martinique": "atlantický čas (Martinik)", + "America\/Matamoros": "severoamerický centrálny čas (Matamoros)", + "America\/Mazatlan": "mexický tichomorský čas (Mazatlán)", + "America\/Mendoza": "argentínsky čas (Mendoza)", + "America\/Menominee": "severoamerický centrálny čas (Menominee)", + "America\/Merida": "severoamerický centrálny čas (Mérida)", + "America\/Metlakatla": "aljašský čas (Metlakatla)", + "America\/Mexico_City": "severoamerický centrálny čas (México)", + "America\/Miquelon": "pierre-miquelonský čas (Miquelon)", + "America\/Moncton": "atlantický čas (Moncton)", + "America\/Monterrey": "severoamerický centrálny čas (Monterrey)", + "America\/Montevideo": "uruguajský čas (Montevideo)", + "America\/Montserrat": "atlantický čas (Montserrat)", + "America\/Nassau": "severoamerický východný čas (Nassau)", + "America\/New_York": "severoamerický východný čas (New York)", + "America\/Nipigon": "severoamerický východný čas (Nipigon)", + "America\/Nome": "aljašský čas (Nome)", + "America\/Noronha": "čas súostrovia Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "severoamerický centrálny čas (Beulah, Severná Dakota)", + "America\/North_Dakota\/Center": "severoamerický centrálny čas (Center, Severná Dakota)", + "America\/North_Dakota\/New_Salem": "severoamerický centrálny čas (New Salem, Severná Dakota)", + "America\/Ojinaga": "severoamerický horský čas (Ojinaga)", + "America\/Panama": "severoamerický východný čas (Panama)", + "America\/Pangnirtung": "severoamerický východný čas (Pangnirtung)", + "America\/Paramaribo": "surinamský čas (Paramaribo)", + "America\/Phoenix": "severoamerický horský čas (Phoenix)", + "America\/Port-au-Prince": "severoamerický východný čas (Port-au-Prince)", + "America\/Port_of_Spain": "atlantický čas (Port of Spain)", + "America\/Porto_Velho": "amazonský čas (Porto Velho)", + "America\/Puerto_Rico": "atlantický čas (Portoriko)", + "America\/Punta_Arenas": "čilský čas (Punta Arenas)", + "America\/Rainy_River": "severoamerický centrálny čas (Rainy River)", + "America\/Rankin_Inlet": "severoamerický centrálny čas (Rankin Inlet)", + "America\/Recife": "brazílsky čas (Recife)", + "America\/Regina": "severoamerický centrálny čas (Regina)", + "America\/Resolute": "severoamerický centrálny čas (Resolute)", + "America\/Rio_Branco": "acrejský čas (Rio Branco)", + "America\/Santa_Isabel": "severozápadný mexický čas (Santa Isabel)", + "America\/Santarem": "brazílsky čas (Santarém)", + "America\/Santiago": "čilský čas (Santiago)", + "America\/Santo_Domingo": "atlantický čas (Santo Domingo)", + "America\/Sao_Paulo": "brazílsky čas (São Paulo)", + "America\/Scoresbysund": "východogrónsky čas (Ittoqqortoormiit)", + "America\/Sitka": "aljašský čas (Sitka)", + "America\/St_Barthelemy": "atlantický čas (Svätý Bartolomej)", + "America\/St_Johns": "newfoundlandský čas (St. John’s)", + "America\/St_Kitts": "atlantický čas (St. Kitts)", + "America\/St_Lucia": "atlantický čas (Svätá Lucia)", + "America\/St_Thomas": "atlantický čas (Sv. Tomáš)", + "America\/St_Vincent": "atlantický čas (Sv. Vincent)", + "America\/Swift_Current": "severoamerický centrálny čas (Swift Current)", + "America\/Tegucigalpa": "severoamerický centrálny čas (Tegucigalpa)", + "America\/Thule": "atlantický čas (Thule)", + "America\/Thunder_Bay": "severoamerický východný čas (Thunder Bay)", + "America\/Tijuana": "severoamerický tichomorský čas (Tijuana)", + "America\/Toronto": "severoamerický východný čas (Toronto)", + "America\/Tortola": "atlantický čas (Tortola)", + "America\/Vancouver": "severoamerický tichomorský čas (Vancouver)", + "America\/Whitehorse": "severoamerický tichomorský čas (Whitehorse)", + "America\/Winnipeg": "severoamerický centrálny čas (Winnipeg)", + "America\/Yakutat": "aljašský čas (Yakutat)", + "America\/Yellowknife": "severoamerický horský čas (Yellowknife)", + "Antarctica\/Casey": "západoaustrálsky čas (Casey)", + "Antarctica\/Davis": "čas Davisovej stanice (Davis)", + "Antarctica\/DumontDUrville": "čas stanice Dumonta d’Urvillea (Dumont d’Urville)", + "Antarctica\/Macquarie": "čas ostrova Macquarie (Macquarie)", + "Antarctica\/Mawson": "čas Mawsonovej stanice (Mawson)", + "Antarctica\/McMurdo": "novozélandský čas (McMurdo)", + "Antarctica\/Palmer": "čilský čas (Palmer)", + "Antarctica\/Rothera": "čas Rotherovej stanice (Rothera)", + "Antarctica\/Syowa": "čas stanice Šówa (Šówa)", + "Antarctica\/Troll": "greenwichský čas (Troll)", + "Antarctica\/Vostok": "čas stanice Vostok (Vostok)", + "Arctic\/Longyearbyen": "stredoeurópsky čas (Longyearbyen)", + "Asia\/Aden": "arabský čas (Aden)", + "Asia\/Almaty": "východokazachstanský čas (Almaty)", + "Asia\/Amman": "východoeurópsky čas (Ammán)", + "Asia\/Anadyr": "Anadyrský čas (Anadyr)", + "Asia\/Aqtau": "západokazachstanský čas (Aktau)", + "Asia\/Aqtobe": "západokazachstanský čas (Aktobe)", + "Asia\/Ashgabat": "turkménsky čas (Ašchabad)", + "Asia\/Atyrau": "západokazachstanský čas (Atyrau)", + "Asia\/Baghdad": "arabský čas (Bagdad)", + "Asia\/Bahrain": "arabský čas (Bahrajn)", + "Asia\/Baku": "azerbajdžanský čas (Baku)", + "Asia\/Bangkok": "indočínsky čas (Bangkok)", + "Asia\/Beirut": "východoeurópsky čas (Bejrút)", + "Asia\/Bishkek": "kirgizský čas (Biškek)", + "Asia\/Brunei": "brunejský čas (Brunej)", + "Asia\/Calcutta": "indický čas (Kalkata)", + "Asia\/Chita": "jakutský čas (Čita)", + "Asia\/Choibalsan": "čojbalsanský čas (Čojbalsan)", + "Asia\/Colombo": "indický čas (Kolombo)", + "Asia\/Damascus": "východoeurópsky čas (Damask)", + "Asia\/Dhaka": "bangladéšsky čas (Dháka)", + "Asia\/Dili": "východotimorský čas (Dili)", + "Asia\/Dubai": "štandardný čas Perzského zálivu (Dubaj)", + "Asia\/Dushanbe": "tadžický čas (Dušanbe)", + "Asia\/Famagusta": "východoeurópsky čas (Famagusta)", + "Asia\/Gaza": "východoeurópsky čas (Gaza)", + "Asia\/Hebron": "východoeurópsky čas (Hebron)", + "Asia\/Hong_Kong": "hongkonský čas (Hongkong)", + "Asia\/Hovd": "chovdský čas (Chovd)", + "Asia\/Irkutsk": "irkutský čas (Irkutsk)", + "Asia\/Jakarta": "západoindonézsky čas (Jakarta)", + "Asia\/Jayapura": "východoindonézsky čas (Jayapura)", + "Asia\/Jerusalem": "izraelský čas (Jeruzalem)", + "Asia\/Kabul": "afganský čas (Kábul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamčatský čas (Kamčatka)", + "Asia\/Karachi": "pakistanský čas (Karáči)", + "Asia\/Katmandu": "nepálsky čas (Káthmandu)", + "Asia\/Khandyga": "jakutský čas (Chandyga)", + "Asia\/Krasnoyarsk": "krasnojarský čas (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "malajzijský čas (Kuala Lumpur)", + "Asia\/Kuching": "malajzijský čas (Kučing)", + "Asia\/Kuwait": "arabský čas (Kuvajt)", + "Asia\/Macau": "čínsky čas (Macao)", + "Asia\/Magadan": "magadanský čas (Magadan)", + "Asia\/Makassar": "stredoindonézsky čas (Makassar)", + "Asia\/Manila": "filipínsky čas (Manila)", + "Asia\/Muscat": "štandardný čas Perzského zálivu (Maskat)", + "Asia\/Nicosia": "východoeurópsky čas (Nikózia)", + "Asia\/Novokuznetsk": "krasnojarský čas (Novokuzneck)", + "Asia\/Novosibirsk": "novosibirský čas (Novosibirsk)", + "Asia\/Omsk": "omský čas (Omsk)", + "Asia\/Oral": "západokazachstanský čas (Uraľsk)", + "Asia\/Phnom_Penh": "indočínsky čas (Phnom Pénh)", + "Asia\/Pontianak": "západoindonézsky čas (Pontianak)", + "Asia\/Pyongyang": "kórejský čas (Pchjongjang)", + "Asia\/Qatar": "arabský čas (Katar)", + "Asia\/Qostanay": "východokazachstanský čas (Kostanaj)", + "Asia\/Qyzylorda": "západokazachstanský čas (Kyzylorda)", + "Asia\/Rangoon": "mjanmarský čas (Rangún)", + "Asia\/Riyadh": "arabský čas (Rijád)", + "Asia\/Saigon": "indočínsky čas (Hočiminovo Mesto)", + "Asia\/Sakhalin": "sachalinský čas (Sachalin)", + "Asia\/Samarkand": "uzbecký čas (Samarkand)", + "Asia\/Seoul": "kórejský čas (Soul)", + "Asia\/Shanghai": "čínsky čas (Šanghaj)", + "Asia\/Singapore": "singapurský štandardný čas (Singapur)", + "Asia\/Srednekolymsk": "magadanský čas (Srednekolymsk)", + "Asia\/Taipei": "tchajpejský čas (Tchaj-pej)", + "Asia\/Tashkent": "uzbecký čas (Taškent)", + "Asia\/Tbilisi": "gruzínsky čas (Tbilisi)", + "Asia\/Tehran": "iránsky čas (Teherán)", + "Asia\/Thimphu": "bhutánsky čas (Thimphu)", + "Asia\/Tokyo": "japonský čas (Tokio)", + "Asia\/Ulaanbaatar": "ulanbátarský čas (Ulanbátar)", + "Asia\/Ust-Nera": "vladivostocký čas (Usť-Nera)", + "Asia\/Vientiane": "indočínsky čas (Vientian)", + "Asia\/Vladivostok": "vladivostocký čas (Vladivostok)", + "Asia\/Yakutsk": "jakutský čas (Jakutsk)", + "Asia\/Yekaterinburg": "jekaterinburský čas (Jekaterinburg)", + "Asia\/Yerevan": "arménsky čas (Jerevan)", + "Atlantic\/Azores": "azorský čas (Azory)", + "Atlantic\/Bermuda": "atlantický čas (Bermudy)", + "Atlantic\/Canary": "západoeurópsky čas (Kanárske ostrovy)", + "Atlantic\/Cape_Verde": "kapverdský čas (Kapverdy)", + "Atlantic\/Faeroe": "západoeurópsky čas (Faerské ostrovy)", + "Atlantic\/Madeira": "západoeurópsky čas (Madeira)", + "Atlantic\/Reykjavik": "greenwichský čas (Reykjavík)", + "Atlantic\/South_Georgia": "čas Južnej Georgie (Južná Georgia)", + "Atlantic\/St_Helena": "greenwichský čas (Svätá Helena)", + "Atlantic\/Stanley": "falklandský čas (Stanley)", + "Australia\/Adelaide": "stredoaustrálsky čas (Adelaide)", + "Australia\/Brisbane": "východoaustrálsky čas (Brisbane)", + "Australia\/Broken_Hill": "stredoaustrálsky čas (Broken Hill)", + "Australia\/Currie": "východoaustrálsky čas (Currie)", + "Australia\/Darwin": "stredoaustrálsky čas (Darwin)", + "Australia\/Eucla": "stredozápadný austrálsky čas (Eucla)", + "Australia\/Hobart": "východoaustrálsky čas (Hobart)", + "Australia\/Lindeman": "východoaustrálsky čas (Lindeman)", + "Australia\/Lord_Howe": "čas ostrova lorda Howa (Lord Howe)", + "Australia\/Melbourne": "východoaustrálsky čas (Melbourne)", + "Australia\/Perth": "západoaustrálsky čas (Perth)", + "Australia\/Sydney": "východoaustrálsky čas (Sydney)", + "CST6CDT": "severoamerický centrálny čas", + "EST5EDT": "severoamerický východný čas", + "Etc\/GMT": "greenwichský čas", + "Etc\/UTC": "koordinovaný svetový čas", + "Europe\/Amsterdam": "stredoeurópsky čas (Amsterdam)", + "Europe\/Andorra": "stredoeurópsky čas (Andorra)", + "Europe\/Astrakhan": "moskovský čas (Astrachán)", + "Europe\/Athens": "východoeurópsky čas (Atény)", + "Europe\/Belgrade": "stredoeurópsky čas (Belehrad)", + "Europe\/Berlin": "stredoeurópsky čas (Berlín)", + "Europe\/Bratislava": "stredoeurópsky čas (Bratislava)", + "Europe\/Brussels": "stredoeurópsky čas (Brusel)", + "Europe\/Bucharest": "východoeurópsky čas (Bukurešť)", + "Europe\/Budapest": "stredoeurópsky čas (Budapešť)", + "Europe\/Busingen": "stredoeurópsky čas (Büsingen)", + "Europe\/Chisinau": "východoeurópsky čas (Kišiňov)", + "Europe\/Copenhagen": "stredoeurópsky čas (Kodaň)", + "Europe\/Dublin": "greenwichský čas (Dublin)", + "Europe\/Gibraltar": "stredoeurópsky čas (Gibraltár)", + "Europe\/Guernsey": "greenwichský čas (Guernsey)", + "Europe\/Helsinki": "východoeurópsky čas (Helsinki)", + "Europe\/Isle_of_Man": "greenwichský čas (Ostrov Man)", + "Europe\/Jersey": "greenwichský čas (Jersey)", + "Europe\/Kaliningrad": "východoeurópsky čas (Kaliningrad)", + "Europe\/Kiev": "východoeurópsky čas (Kyjev)", + "Europe\/Lisbon": "západoeurópsky čas (Lisabon)", + "Europe\/Ljubljana": "stredoeurópsky čas (Ľubľana)", + "Europe\/London": "greenwichský čas (Londýn)", + "Europe\/Luxembourg": "stredoeurópsky čas (Luxembursko)", + "Europe\/Madrid": "stredoeurópsky čas (Madrid)", + "Europe\/Malta": "stredoeurópsky čas (Malta)", + "Europe\/Mariehamn": "východoeurópsky čas (Mariehamn)", + "Europe\/Minsk": "moskovský čas (Minsk)", + "Europe\/Monaco": "stredoeurópsky čas (Monako)", + "Europe\/Moscow": "moskovský čas (Moskva)", + "Europe\/Oslo": "stredoeurópsky čas (Oslo)", + "Europe\/Paris": "stredoeurópsky čas (Paríž)", + "Europe\/Podgorica": "stredoeurópsky čas (Podgorica)", + "Europe\/Prague": "stredoeurópsky čas (Praha)", + "Europe\/Riga": "východoeurópsky čas (Riga)", + "Europe\/Rome": "stredoeurópsky čas (Rím)", + "Europe\/Samara": "Samarský čas (Samara)", + "Europe\/San_Marino": "stredoeurópsky čas (San Maríno)", + "Europe\/Sarajevo": "stredoeurópsky čas (Sarajevo)", + "Europe\/Saratov": "moskovský čas (Saratov)", + "Europe\/Simferopol": "moskovský čas (Simferopol)", + "Europe\/Skopje": "stredoeurópsky čas (Skopje)", + "Europe\/Sofia": "východoeurópsky čas (Sofia)", + "Europe\/Stockholm": "stredoeurópsky čas (Štokholm)", + "Europe\/Tallinn": "východoeurópsky čas (Tallinn)", + "Europe\/Tirane": "stredoeurópsky čas (Tirana)", + "Europe\/Ulyanovsk": "moskovský čas (Uľjanovsk)", + "Europe\/Uzhgorod": "východoeurópsky čas (Užhorod)", + "Europe\/Vaduz": "stredoeurópsky čas (Vaduz)", + "Europe\/Vatican": "stredoeurópsky čas (Vatikán)", + "Europe\/Vienna": "stredoeurópsky čas (Viedeň)", + "Europe\/Vilnius": "východoeurópsky čas (Vilnius)", + "Europe\/Volgograd": "volgogradský čas (Volgograd)", + "Europe\/Warsaw": "stredoeurópsky čas (Varšava)", + "Europe\/Zagreb": "stredoeurópsky čas (Záhreb)", + "Europe\/Zaporozhye": "východoeurópsky čas (Záporožie)", + "Europe\/Zurich": "stredoeurópsky čas (Zürich)", + "Indian\/Antananarivo": "východoafrický čas (Antananarivo)", + "Indian\/Chagos": "indickooceánsky čas (Chagos)", + "Indian\/Christmas": "čas Vianočného ostrova (Vianočný ostrov)", + "Indian\/Cocos": "čas Kokosových ostrovov (Kokosové ostrovy)", + "Indian\/Comoro": "východoafrický čas (Komory)", + "Indian\/Kerguelen": "čas Francúzskych južných a antarktických území (Kergueleny)", + "Indian\/Mahe": "seychelský čas (Mahé)", + "Indian\/Maldives": "maldivský čas (Maldivy)", + "Indian\/Mauritius": "maurícijský čas (Maurícius)", + "Indian\/Mayotte": "východoafrický čas (Mayotte)", + "Indian\/Reunion": "réunionský čas (Réunion)", + "MST7MDT": "severoamerický horský čas", + "PST8PDT": "severoamerický tichomorský čas", + "Pacific\/Apia": "apijský čas (Apia)", + "Pacific\/Auckland": "novozélandský čas (Auckland)", + "Pacific\/Bougainville": "čas Papuy-Novej Guiney (Bougainville)", + "Pacific\/Chatham": "chathamský čas (Chatham)", + "Pacific\/Easter": "čas Veľkonočného ostrova (Veľkonočný ostrov)", + "Pacific\/Efate": "vanuatský čas (Efate)", + "Pacific\/Enderbury": "čas Fénixových ostrovov (Enderbury)", + "Pacific\/Fakaofo": "tokelauský čas (Fakaofo)", + "Pacific\/Fiji": "fidžijský čas (Fidži)", + "Pacific\/Funafuti": "tuvalský čas (Funafuti)", + "Pacific\/Galapagos": "galapágsky čas (Galapágy)", + "Pacific\/Gambier": "gambierský čas (Gambier)", + "Pacific\/Guadalcanal": "čas Šalamúnových ostrovov (Guadalcanal)", + "Pacific\/Guam": "chamorrský čas (Guam)", + "Pacific\/Honolulu": "havajsko-aleutský čas (Honolulu)", + "Pacific\/Johnston": "havajsko-aleutský čas (Johnston)", + "Pacific\/Kiritimati": "čas Rovníkových ostrovov (Kiritimati)", + "Pacific\/Kosrae": "kosrajský čas (Kosrae)", + "Pacific\/Kwajalein": "čas Marshallových ostrovov (Kwajalein)", + "Pacific\/Majuro": "čas Marshallových ostrovov (Majuro)", + "Pacific\/Marquesas": "markézsky čas (Markézy)", + "Pacific\/Midway": "samojský čas (Midway)", + "Pacific\/Nauru": "nauruský čas (Nauru)", + "Pacific\/Niue": "niuejský čas (Niue)", + "Pacific\/Norfolk": "norfolský čas (Norfolk)", + "Pacific\/Noumea": "novokaledónsky čas (Nouméa)", + "Pacific\/Pago_Pago": "samojský čas (Pago Pago)", + "Pacific\/Palau": "palauský čas (Palau)", + "Pacific\/Pitcairn": "čas Pitcairnových ostrovov (Pitcairn)", + "Pacific\/Ponape": "ponapský čas (Pohnpei)", + "Pacific\/Port_Moresby": "čas Papuy-Novej Guiney (Port Moresby)", + "Pacific\/Rarotonga": "čas Cookových ostrovov (Rarotonga)", + "Pacific\/Saipan": "chamorrský čas (Saipan)", + "Pacific\/Tahiti": "tahitský čas (Tahiti)", + "Pacific\/Tarawa": "čas Gilbertových ostrovov (Tarawa)", + "Pacific\/Tongatapu": "tonžský čas (Tongatapu)", + "Pacific\/Truk": "chuukský čas (Chuuk)", + "Pacific\/Wake": "čas ostrova Wake (Wake)", + "Pacific\/Wallis": "čas ostrovov Wallis a Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sl.json b/src/Symfony/Component/Intl/Resources/data/timezones/sl.json new file mode 100644 index 0000000000000..0fa9c88b93581 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sl.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwiški srednji čas (Abidžan)", + "Africa\/Accra": "Greenwiški srednji čas (Akra)", + "Africa\/Addis_Ababa": "Vzhodnoafriški čas (Adis Abeba)", + "Africa\/Algiers": "Srednjeevropski čas (Alžir)", + "Africa\/Asmera": "Vzhodnoafriški čas (Asmara)", + "Africa\/Bamako": "Greenwiški srednji čas (Bamako)", + "Africa\/Bangui": "Zahodnoafriški čas (Bangui)", + "Africa\/Banjul": "Greenwiški srednji čas (Banjul)", + "Africa\/Bissau": "Greenwiški srednji čas (Bissau)", + "Africa\/Blantyre": "Centralnoafriški čas (Blantyre)", + "Africa\/Brazzaville": "Zahodnoafriški čas (Brazzaville)", + "Africa\/Bujumbura": "Centralnoafriški čas (Bujumbura)", + "Africa\/Cairo": "Vzhodnoevropski čas (Kairo)", + "Africa\/Casablanca": "Zahodnoevropski čas (Casablanca)", + "Africa\/Ceuta": "Srednjeevropski čas (Ceuta)", + "Africa\/Conakry": "Greenwiški srednji čas (Conakry)", + "Africa\/Dakar": "Greenwiški srednji čas (Dakar)", + "Africa\/Dar_es_Salaam": "Vzhodnoafriški čas (Dar es Salaam)", + "Africa\/Djibouti": "Vzhodnoafriški čas (Džibuti)", + "Africa\/Douala": "Zahodnoafriški čas (Douala)", + "Africa\/El_Aaiun": "Zahodnoevropski čas (El Aaiun)", + "Africa\/Freetown": "Greenwiški srednji čas (Freetown)", + "Africa\/Gaborone": "Centralnoafriški čas (Gaborone)", + "Africa\/Harare": "Centralnoafriški čas (Harare)", + "Africa\/Johannesburg": "Južnoafriški čas (Johannesburg)", + "Africa\/Juba": "Vzhodnoafriški čas (Juba)", + "Africa\/Kampala": "Vzhodnoafriški čas (Kampala)", + "Africa\/Khartoum": "Centralnoafriški čas (Kartum)", + "Africa\/Kigali": "Centralnoafriški čas (Kigali)", + "Africa\/Kinshasa": "Zahodnoafriški čas (Kinšasa)", + "Africa\/Lagos": "Zahodnoafriški čas (Lagos)", + "Africa\/Libreville": "Zahodnoafriški čas (Libreville)", + "Africa\/Lome": "Greenwiški srednji čas (Lome)", + "Africa\/Luanda": "Zahodnoafriški čas (Luanda)", + "Africa\/Lubumbashi": "Centralnoafriški čas (Lubumbaši)", + "Africa\/Lusaka": "Centralnoafriški čas (Lusaka)", + "Africa\/Malabo": "Zahodnoafriški čas (Malabo)", + "Africa\/Maputo": "Centralnoafriški čas (Maputo)", + "Africa\/Maseru": "Južnoafriški čas (Maseru)", + "Africa\/Mbabane": "Južnoafriški čas (Mbabane)", + "Africa\/Mogadishu": "Vzhodnoafriški čas (Mogadišu)", + "Africa\/Monrovia": "Greenwiški srednji čas (Monrovia)", + "Africa\/Nairobi": "Vzhodnoafriški čas (Nairobi)", + "Africa\/Ndjamena": "Zahodnoafriški čas (Ndjamena)", + "Africa\/Niamey": "Zahodnoafriški čas (Niamey)", + "Africa\/Nouakchott": "Greenwiški srednji čas (Nouakchott)", + "Africa\/Ouagadougou": "Greenwiški srednji čas (Ouagadougou)", + "Africa\/Porto-Novo": "Zahodnoafriški čas (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwiški srednji čas (São Tomé)", + "Africa\/Tripoli": "Vzhodnoevropski čas (Tripoli)", + "Africa\/Tunis": "Srednjeevropski čas (Tunis)", + "Africa\/Windhoek": "Centralnoafriški čas (Windhoek)", + "America\/Adak": "Havajski aleutski čas (Adak)", + "America\/Anchorage": "Aljaški čas (Anchorage)", + "America\/Anguilla": "Atlantski čas (Angvila)", + "America\/Antigua": "Atlantski čas (Antigua)", + "America\/Araguaina": "Brasilski čas (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentinski čas (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Argentinski čas (Rio Gallegos)", + "America\/Argentina\/Salta": "Argentinski čas (Salta)", + "America\/Argentina\/San_Juan": "Argentinski čas (San Juan)", + "America\/Argentina\/San_Luis": "Argentinski zahodni čas (San Luis)", + "America\/Argentina\/Tucuman": "Argentinski čas (Tucuman)", + "America\/Argentina\/Ushuaia": "Argentinski čas (Ushuaia)", + "America\/Aruba": "Atlantski čas (Aruba)", + "America\/Asuncion": "Paragvajski čas (Asunción)", + "America\/Bahia": "Brasilski čas (Bahia)", + "America\/Bahia_Banderas": "Centralni čas (Bahia Banderas)", + "America\/Barbados": "Atlantski čas (Barbados)", + "America\/Belem": "Brasilski čas (Belem)", + "America\/Belize": "Centralni čas (Belize)", + "America\/Blanc-Sablon": "Atlantski čas (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonski čas (Boa Vista)", + "America\/Bogota": "Kolumbijski čas (Bogota)", + "America\/Boise": "Gorski čas (Boise)", + "America\/Buenos_Aires": "Argentinski čas (Buenos Aires)", + "America\/Cambridge_Bay": "Gorski čas (Cambridge Bay)", + "America\/Campo_Grande": "Amazonski čas (Campo Grande)", + "America\/Cancun": "Vzhodni čas (Cancun)", + "America\/Caracas": "Venezuelski čas (Caracas)", + "America\/Catamarca": "Argentinski čas (Catamarca)", + "America\/Cayenne": "Čas: Francoska Gvajana (Cayenne)", + "America\/Cayman": "Vzhodni čas (Kajman)", + "America\/Chicago": "Centralni čas (Chicago)", + "America\/Chihuahua": "Mehiški pacifiški čas (Chihuahua)", + "America\/Coral_Harbour": "Vzhodni čas (Atikokan)", + "America\/Cordoba": "Argentinski čas (Cordoba)", + "America\/Costa_Rica": "Centralni čas (Kostarika)", + "America\/Creston": "Gorski čas (Creston)", + "America\/Cuiaba": "Amazonski čas (Cuiaba)", + "America\/Curacao": "Atlantski čas (Curaçao)", + "America\/Danmarkshavn": "Greenwiški srednji čas (Danmarkshavn)", + "America\/Dawson": "Pacifiški čas (Dawson)", + "America\/Dawson_Creek": "Gorski čas (Dawson Creek)", + "America\/Denver": "Gorski čas (Denver)", + "America\/Detroit": "Vzhodni čas (Detroit)", + "America\/Dominica": "Atlantski čas (Dominika)", + "America\/Edmonton": "Gorski čas (Edmonton)", + "America\/El_Salvador": "Centralni čas (Salvador)", + "America\/Fort_Nelson": "Gorski čas (Fort Nelson)", + "America\/Fortaleza": "Brasilski čas (Fortaleza)", + "America\/Glace_Bay": "Atlantski čas (Glace Bay)", + "America\/Godthab": "Zahodnogrenlandski čas (Nuuk)", + "America\/Goose_Bay": "Atlantski čas (Goose Bay)", + "America\/Grand_Turk": "Vzhodni čas (Grand Turk)", + "America\/Grenada": "Atlantski čas (Grenada)", + "America\/Guadeloupe": "Atlantski čas (Guadeloupe)", + "America\/Guatemala": "Centralni čas (Gvatemala)", + "America\/Guayaquil": "Ekvadorski čas (Guayaquil)", + "America\/Guyana": "Gvajanski čas (Gvajana)", + "America\/Halifax": "Atlantski čas (Halifax)", + "America\/Havana": "Kubanski čas (Havana)", + "America\/Hermosillo": "Mehiški pacifiški čas (Hermosillo)", + "America\/Indiana\/Knox": "Centralni čas (Knox, Indiana)", + "America\/Indiana\/Marengo": "Vzhodni čas (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Vzhodni čas (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Centralni čas (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Vzhodni čas (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Vzhodni čas (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Vzhodni čas (Winamac, Indiana)", + "America\/Indianapolis": "Vzhodni čas (Indianapolis)", + "America\/Inuvik": "Gorski čas (Inuvik)", + "America\/Iqaluit": "Vzhodni čas (Iqaluit)", + "America\/Jamaica": "Vzhodni čas (Jamajka)", + "America\/Jujuy": "Argentinski čas (Jujuy)", + "America\/Juneau": "Aljaški čas (Juneau)", + "America\/Kentucky\/Monticello": "Vzhodni čas (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantski čas (Kralendijk)", + "America\/La_Paz": "Bolivijski čas (La Paz)", + "America\/Lima": "Perujski čas (Lima)", + "America\/Los_Angeles": "Pacifiški čas (Los Angeles)", + "America\/Louisville": "Vzhodni čas (Louisville)", + "America\/Lower_Princes": "Atlantski čas (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilski čas (Maceio)", + "America\/Managua": "Centralni čas (Managua)", + "America\/Manaus": "Amazonski čas (Manaus)", + "America\/Marigot": "Atlantski čas (Marigot)", + "America\/Martinique": "Atlantski čas (Martinik)", + "America\/Matamoros": "Centralni čas (Matamoros)", + "America\/Mazatlan": "Mehiški pacifiški čas (Mazatlan)", + "America\/Mendoza": "Argentinski čas (Mendoza)", + "America\/Menominee": "Centralni čas (Menominee)", + "America\/Merida": "Centralni čas (Merida)", + "America\/Metlakatla": "Aljaški čas (Metlakatla)", + "America\/Mexico_City": "Centralni čas (Ciudad de Mexico)", + "America\/Miquelon": "Čas: Saint Pierre in Miquelon (Miquelon)", + "America\/Moncton": "Atlantski čas (Moncton)", + "America\/Monterrey": "Centralni čas (Monterrey)", + "America\/Montevideo": "Urugvajski čas (Montevideo)", + "America\/Montserrat": "Atlantski čas (Montserrat)", + "America\/Nassau": "Vzhodni čas (Nassau)", + "America\/New_York": "Vzhodni čas (New York)", + "America\/Nipigon": "Vzhodni čas (Nipigon)", + "America\/Nome": "Aljaški čas (Nome)", + "America\/Noronha": "Fernando de Noronški čas (Noronha)", + "America\/North_Dakota\/Beulah": "Centralni čas (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Centralni čas (Center, Severna Dakota)", + "America\/North_Dakota\/New_Salem": "Centralni čas (New Salem, Severna Dakota)", + "America\/Ojinaga": "Gorski čas (Ojinaga)", + "America\/Panama": "Vzhodni čas (Panama)", + "America\/Pangnirtung": "Vzhodni čas (Pangnirtung)", + "America\/Paramaribo": "Surinamski čas (Paramaribo)", + "America\/Phoenix": "Gorski čas (Phoenix)", + "America\/Port-au-Prince": "Vzhodni čas (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantski čas (Port of Spain)", + "America\/Porto_Velho": "Amazonski čas (Porto Velho)", + "America\/Puerto_Rico": "Atlantski čas (Portoriko)", + "America\/Punta_Arenas": "Čilski čas (Punta Arenas)", + "America\/Rainy_River": "Centralni čas (Rainy River)", + "America\/Rankin_Inlet": "Centralni čas (Rankin Inlet)", + "America\/Recife": "Brasilski čas (Recife)", + "America\/Regina": "Centralni čas (Regina)", + "America\/Resolute": "Centralni čas (Resolute)", + "America\/Santa_Isabel": "Mehiški severozahodni čas (Santa Isabel)", + "America\/Santarem": "Brasilski čas (Santarem)", + "America\/Santiago": "Čilski čas (Santiago)", + "America\/Santo_Domingo": "Atlantski čas (Santo Domingo)", + "America\/Sao_Paulo": "Brasilski čas (Sao Paulo)", + "America\/Scoresbysund": "Vzhodnogrenlandski čas (Ittoqqortoormiit)", + "America\/Sitka": "Aljaški čas (Sitka)", + "America\/St_Barthelemy": "Atlantski čas (Saint Barthélemy)", + "America\/St_Johns": "Novofundlandski čas (St. John’s)", + "America\/St_Kitts": "Atlantski čas (St. Kitts)", + "America\/St_Lucia": "Atlantski čas (St. Lucia)", + "America\/St_Thomas": "Atlantski čas (St. Thomas)", + "America\/St_Vincent": "Atlantski čas (St. Vincent)", + "America\/Swift_Current": "Centralni čas (Swift Current)", + "America\/Tegucigalpa": "Centralni čas (Tegucigalpa)", + "America\/Thule": "Atlantski čas (Thule)", + "America\/Thunder_Bay": "Vzhodni čas (Thunder Bay)", + "America\/Tijuana": "Pacifiški čas (Tijuana)", + "America\/Toronto": "Vzhodni čas (Toronto)", + "America\/Tortola": "Atlantski čas (Tortola)", + "America\/Vancouver": "Pacifiški čas (Vancouver)", + "America\/Whitehorse": "Pacifiški čas (Whitehorse)", + "America\/Winnipeg": "Centralni čas (Winnipeg)", + "America\/Yakutat": "Aljaški čas (Yakutat)", + "America\/Yellowknife": "Gorski čas (Yellowknife)", + "Antarctica\/Casey": "Avstralski zahodni čas (Casey)", + "Antarctica\/Davis": "Čas: Davis (Davis)", + "Antarctica\/DumontDUrville": "Čas: Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarieski čas (Macquarie)", + "Antarctica\/Mawson": "Mawsonski čas (Mawson)", + "Antarctica\/McMurdo": "Novozelandski čas (McMurdo)", + "Antarctica\/Palmer": "Čilski čas (Palmer)", + "Antarctica\/Rothera": "Rotherski čas (Rothera)", + "Antarctica\/Syowa": "Čas: Syowa (Syowa)", + "Antarctica\/Troll": "Greenwiški srednji čas (Troll)", + "Antarctica\/Vostok": "Vostoški čas (Vostok)", + "Arctic\/Longyearbyen": "Srednjeevropski čas (Longyearbyen)", + "Asia\/Aden": "Arabski čas (Aden)", + "Asia\/Almaty": "Vzhodni kazahstanski čas (Almati)", + "Asia\/Amman": "Vzhodnoevropski čas (Aman)", + "Asia\/Anadyr": "Anadirski čas (Anadir)", + "Asia\/Aqtau": "Zahodni kazahstanski čas (Aktau)", + "Asia\/Aqtobe": "Zahodni kazahstanski čas (Aktobe)", + "Asia\/Ashgabat": "Turkmenistanski čas (Ašhabad)", + "Asia\/Atyrau": "Zahodni kazahstanski čas (Atyrau)", + "Asia\/Baghdad": "Arabski čas (Bagdad)", + "Asia\/Bahrain": "Arabski čas (Bahrajn)", + "Asia\/Baku": "Azerbajdžanski čas (Baku)", + "Asia\/Bangkok": "Indokitajski čas (Bangkok)", + "Asia\/Beirut": "Vzhodnoevropski čas (Bejrut)", + "Asia\/Bishkek": "Kirgizistanski čas (Biškek)", + "Asia\/Brunei": "Brunejski čas (Brunej)", + "Asia\/Calcutta": "Indijski standardni čas (Kolkata)", + "Asia\/Chita": "Jakutski čas (Čita)", + "Asia\/Choibalsan": "Čojbalsanski čas (Čojbalsan)", + "Asia\/Colombo": "Indijski standardni čas (Colombo)", + "Asia\/Damascus": "Vzhodnoevropski čas (Damask)", + "Asia\/Dhaka": "Bangladeški čas (Daka)", + "Asia\/Dili": "Vzhodnotimorski čas (Dili)", + "Asia\/Dubai": "Zalivski standardni čas (Dubaj)", + "Asia\/Dushanbe": "Tadžikistanski čas (Dušanbe)", + "Asia\/Famagusta": "Vzhodnoevropski čas (Famagusta)", + "Asia\/Gaza": "Vzhodnoevropski čas (Gaza)", + "Asia\/Hebron": "Vzhodnoevropski čas (Hebron)", + "Asia\/Hong_Kong": "Hongkonški čas (Hongkong)", + "Asia\/Hovd": "Hovdski čas (Hovd)", + "Asia\/Irkutsk": "Irkutski čas (Irkutsk)", + "Asia\/Jakarta": "Indonezijski zahodni čas (Džakarta)", + "Asia\/Jayapura": "Indonezijski vzhodni čas (Jayapura)", + "Asia\/Jerusalem": "Izraelski čas (Jeruzalem)", + "Asia\/Kabul": "Afganistanski čas (Kabul)", + "Asia\/Kamchatka": "Petropavlovsk-Kamčatski čas (Kamčatka)", + "Asia\/Karachi": "Pakistanski čas (Karači)", + "Asia\/Katmandu": "Nepalski čas (Katmandu)", + "Asia\/Khandyga": "Jakutski čas (Handiga)", + "Asia\/Krasnoyarsk": "Krasnojarski čas (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malezijski čas (Kuala Lumpur)", + "Asia\/Kuching": "Malezijski čas (Kuching)", + "Asia\/Kuwait": "Arabski čas (Kuvajt)", + "Asia\/Macau": "Kitajski čas (Macao)", + "Asia\/Magadan": "Magadanski čas (Magadan)", + "Asia\/Makassar": "Indonezijski osrednji čas (Makasar)", + "Asia\/Manila": "Filipinski čas (Manila)", + "Asia\/Muscat": "Zalivski standardni čas (Muškat)", + "Asia\/Nicosia": "Vzhodnoevropski čas (Nikozija)", + "Asia\/Novokuznetsk": "Krasnojarski čas (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirski čas (Novosibirsk)", + "Asia\/Omsk": "Omski čas (Omsk)", + "Asia\/Oral": "Zahodni kazahstanski čas (Uralsk)", + "Asia\/Phnom_Penh": "Indokitajski čas (Phnom Penh)", + "Asia\/Pontianak": "Indonezijski zahodni čas (Pontianak)", + "Asia\/Pyongyang": "Korejski čas (Pjongjang)", + "Asia\/Qatar": "Arabski čas (Katar)", + "Asia\/Qostanay": "Vzhodni kazahstanski čas (Qostanay)", + "Asia\/Qyzylorda": "Zahodni kazahstanski čas (Kizlorda)", + "Asia\/Rangoon": "Mjanmarski čas (Rangun)", + "Asia\/Riyadh": "Arabski čas (Rijad)", + "Asia\/Saigon": "Indokitajski čas (Hošiminh)", + "Asia\/Sakhalin": "Sahalinski čas (Sahalin)", + "Asia\/Samarkand": "Uzbekistanski čas (Samarkand)", + "Asia\/Seoul": "Korejski čas (Seul)", + "Asia\/Shanghai": "Kitajski čas (Šanghaj)", + "Asia\/Singapore": "Singapurski standardni čas (Singapur)", + "Asia\/Srednekolymsk": "Magadanski čas (Srednekolimsk)", + "Asia\/Taipei": "Tajpejski čas (Tajpej)", + "Asia\/Tashkent": "Uzbekistanski čas (Taškent)", + "Asia\/Tbilisi": "Gruzijski čas (Tbilisi)", + "Asia\/Tehran": "Iranski čas (Teheran)", + "Asia\/Thimphu": "Butanski čas (Timpu)", + "Asia\/Tokyo": "Japonski čas (Tokio)", + "Asia\/Ulaanbaatar": "Ulanbatorski čas (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostoški čas (Ust-Nera)", + "Asia\/Vientiane": "Indokitajski čas (Vientiane)", + "Asia\/Vladivostok": "Vladivostoški čas (Vladivostok)", + "Asia\/Yakutsk": "Jakutski čas (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburški čas (Jekaterinburg)", + "Asia\/Yerevan": "Armenski čas (Erevan)", + "Atlantic\/Azores": "Azorski čas (Azori)", + "Atlantic\/Bermuda": "Atlantski čas (Bermudi)", + "Atlantic\/Canary": "Zahodnoevropski čas (Kanarski otoki)", + "Atlantic\/Cape_Verde": "Kapverdski čas (Zelenortski otoki)", + "Atlantic\/Faeroe": "Zahodnoevropski čas (Faroe)", + "Atlantic\/Madeira": "Zahodnoevropski čas (Madeira)", + "Atlantic\/Reykjavik": "Greenwiški srednji čas (Reykjavik)", + "Atlantic\/South_Georgia": "Južnogeorgijski čas (Južna Georgia)", + "Atlantic\/St_Helena": "Greenwiški srednji čas (St. Helena)", + "Atlantic\/Stanley": "Čas: Falklandsko otočje (Stanley)", + "Australia\/Adelaide": "Avstralski centralni čas (Adelaide)", + "Australia\/Brisbane": "Avstralski vzhodni čas (Brisbane)", + "Australia\/Broken_Hill": "Avstralski centralni čas (Broken Hill)", + "Australia\/Currie": "Avstralski vzhodni čas (Currie)", + "Australia\/Darwin": "Avstralski centralni čas (Darwin)", + "Australia\/Eucla": "Avstralski centralni zahodni čas (Eucla)", + "Australia\/Hobart": "Avstralski vzhodni čas (Hobart)", + "Australia\/Lindeman": "Avstralski vzhodni čas (Lindeman)", + "Australia\/Lord_Howe": "Čas otoka Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Avstralski vzhodni čas (Melbourne)", + "Australia\/Perth": "Avstralski zahodni čas (Perth)", + "Australia\/Sydney": "Avstralski vzhodni čas (Sydney)", + "CST6CDT": "Centralni čas", + "EST5EDT": "Vzhodni čas", + "Etc\/GMT": "Greenwiški srednji čas", + "Etc\/UTC": "univerzalni koordinirani čas", + "Europe\/Amsterdam": "Srednjeevropski čas (Amsterdam)", + "Europe\/Andorra": "Srednjeevropski čas (Andora)", + "Europe\/Astrakhan": "Moskovski čas (Astrahan)", + "Europe\/Athens": "Vzhodnoevropski čas (Atene)", + "Europe\/Belgrade": "Srednjeevropski čas (Beograd)", + "Europe\/Berlin": "Srednjeevropski čas (Berlin)", + "Europe\/Bratislava": "Srednjeevropski čas (Bratislava)", + "Europe\/Brussels": "Srednjeevropski čas (Bruselj)", + "Europe\/Bucharest": "Vzhodnoevropski čas (Bukarešta)", + "Europe\/Budapest": "Srednjeevropski čas (Budimpešta)", + "Europe\/Busingen": "Srednjeevropski čas (Busingen)", + "Europe\/Chisinau": "Vzhodnoevropski čas (Kišinjev)", + "Europe\/Copenhagen": "Srednjeevropski čas (Köbenhavn)", + "Europe\/Dublin": "Greenwiški srednji čas (Dublin)", + "Europe\/Gibraltar": "Srednjeevropski čas (Gibraltar)", + "Europe\/Guernsey": "Greenwiški srednji čas (Guernsey)", + "Europe\/Helsinki": "Vzhodnoevropski čas (Helsinki)", + "Europe\/Isle_of_Man": "Greenwiški srednji čas (Otok Man)", + "Europe\/Jersey": "Greenwiški srednji čas (Jersey)", + "Europe\/Kaliningrad": "Vzhodnoevropski čas (Kaliningrad)", + "Europe\/Kiev": "Vzhodnoevropski čas (Kijev)", + "Europe\/Lisbon": "Zahodnoevropski čas (Lizbona)", + "Europe\/Ljubljana": "Srednjeevropski čas (Ljubljana)", + "Europe\/London": "Greenwiški srednji čas (London)", + "Europe\/Luxembourg": "Srednjeevropski čas (Luksemburg)", + "Europe\/Madrid": "Srednjeevropski čas (Madrid)", + "Europe\/Malta": "Srednjeevropski čas (Malta)", + "Europe\/Mariehamn": "Vzhodnoevropski čas (Mariehamn)", + "Europe\/Minsk": "Moskovski čas (Minsk)", + "Europe\/Monaco": "Srednjeevropski čas (Monako)", + "Europe\/Moscow": "Moskovski čas (Moskva)", + "Europe\/Oslo": "Srednjeevropski čas (Oslo)", + "Europe\/Paris": "Srednjeevropski čas (Pariz)", + "Europe\/Podgorica": "Srednjeevropski čas (Podgorica)", + "Europe\/Prague": "Srednjeevropski čas (Praga)", + "Europe\/Riga": "Vzhodnoevropski čas (Riga)", + "Europe\/Rome": "Srednjeevropski čas (Rim)", + "Europe\/Samara": "Samarski čas (Samara)", + "Europe\/San_Marino": "Srednjeevropski čas (San Marino)", + "Europe\/Sarajevo": "Srednjeevropski čas (Sarajevo)", + "Europe\/Saratov": "Moskovski čas (Saratov)", + "Europe\/Simferopol": "Moskovski čas (Simferopol)", + "Europe\/Skopje": "Srednjeevropski čas (Skopje)", + "Europe\/Sofia": "Vzhodnoevropski čas (Sofija)", + "Europe\/Stockholm": "Srednjeevropski čas (Stockholm)", + "Europe\/Tallinn": "Vzhodnoevropski čas (Talin)", + "Europe\/Tirane": "Srednjeevropski čas (Tirana)", + "Europe\/Ulyanovsk": "Moskovski čas (Uljanovsk)", + "Europe\/Uzhgorod": "Vzhodnoevropski čas (Užgorod)", + "Europe\/Vaduz": "Srednjeevropski čas (Vaduz)", + "Europe\/Vatican": "Srednjeevropski čas (Vatikan)", + "Europe\/Vienna": "Srednjeevropski čas (Dunaj)", + "Europe\/Vilnius": "Vzhodnoevropski čas (Vilna)", + "Europe\/Volgograd": "Volgograjski čas (Volgograd)", + "Europe\/Warsaw": "Srednjeevropski čas (Varšava)", + "Europe\/Zagreb": "Srednjeevropski čas (Zagreb)", + "Europe\/Zaporozhye": "Vzhodnoevropski čas (Zaporožje)", + "Europe\/Zurich": "Srednjeevropski čas (Zürich)", + "Indian\/Antananarivo": "Vzhodnoafriški čas (Antananarivo)", + "Indian\/Chagos": "Indijskooceanski čas (Chagos)", + "Indian\/Christmas": "Božičnootoški čas (Božični otok)", + "Indian\/Cocos": "Čas: Kokosovi otoki (Kokosovi otoki)", + "Indian\/Comoro": "Vzhodnoafriški čas (Komori)", + "Indian\/Kerguelen": "Francoski južni in antarktični čas (Kerguelen)", + "Indian\/Mahe": "Sejšelski čas (Mahe)", + "Indian\/Maldives": "Maldivski čas (Maldivi)", + "Indian\/Mauritius": "Mauricijski čas (Mauritius)", + "Indian\/Mayotte": "Vzhodnoafriški čas (Mayotte)", + "Indian\/Reunion": "Reunionski čas (Reunion)", + "MST7MDT": "Gorski čas", + "PST8PDT": "Pacifiški čas", + "Pacific\/Apia": "Čas: Apia (Apia)", + "Pacific\/Auckland": "Novozelandski čas (Auckland)", + "Pacific\/Bougainville": "Papuanski čas (Bougainville)", + "Pacific\/Chatham": "Čatamski čas (Chatham)", + "Pacific\/Easter": "Čas: Velikonočni otok (Velikonočni otok)", + "Pacific\/Efate": "Vanuatujski čas (Efate)", + "Pacific\/Enderbury": "Čas: Otočje Feniks (Enderbury)", + "Pacific\/Fakaofo": "Tokelavski čas (Fakaofo)", + "Pacific\/Fiji": "Fidžijski čas (Fidži)", + "Pacific\/Funafuti": "Tuvalujski čas (Funafuti)", + "Pacific\/Galapagos": "Galapaški čas (Galapagos)", + "Pacific\/Gambier": "Gambierski čas (Gambier)", + "Pacific\/Guadalcanal": "Salomonovootoški čas (Guadalcanal)", + "Pacific\/Guam": "Čamorski standardni čas (Guam)", + "Pacific\/Honolulu": "Havajski aleutski čas (Honolulu)", + "Pacific\/Johnston": "Havajski aleutski čas (Johnston)", + "Pacific\/Kiritimati": "Ekvatorski otoki: Čas (Kiritimati)", + "Pacific\/Kosrae": "Kosrajški čas (Kosrae)", + "Pacific\/Kwajalein": "Čas: Marshallovi otoki (Kwajalein)", + "Pacific\/Majuro": "Čas: Marshallovi otoki (Majuro)", + "Pacific\/Marquesas": "Čas: Markizni otoki (Marquesas)", + "Pacific\/Midway": "Samoanski čas (Midway)", + "Pacific\/Nauru": "Naurujski čas (Nauru)", + "Pacific\/Niue": "Niuejski čas (Niue)", + "Pacific\/Norfolk": "Čas: Norfolški otoki (Norfolk)", + "Pacific\/Noumea": "Novokaledonijski čas (Noumea)", + "Pacific\/Pago_Pago": "Samoanski čas (Pago Pago)", + "Pacific\/Palau": "Palavski čas (Palau)", + "Pacific\/Pitcairn": "Pitcairnski čas (Pitcairn)", + "Pacific\/Ponape": "Ponapski čas (Pohnpei)", + "Pacific\/Port_Moresby": "Papuanski čas (Port Moresby)", + "Pacific\/Rarotonga": "Cookovootoški čas (Rarotonga)", + "Pacific\/Saipan": "Čamorski standardni čas (Saipan)", + "Pacific\/Tahiti": "Tahitijski čas (Tahiti)", + "Pacific\/Tarawa": "Čas: Gilbertovi otoki (Tarawa)", + "Pacific\/Tongatapu": "Tongovski čas (Tongatapu)", + "Pacific\/Truk": "Čas: Otok Chuuk (Chuuk)", + "Pacific\/Wake": "Čas: Otok Wake (Wake)", + "Pacific\/Wallis": "Čas: Wallis in Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/so.json b/src/Symfony/Component/Intl/Resources/data/timezones/so.json new file mode 100644 index 0000000000000..8b1c08ddeafd9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/so.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Waqtiga Celceliska Giriinwij (Abidjaan)", + "Africa\/Accra": "Waqtiga Celceliska Giriinwij (Akra)", + "Africa\/Addis_Ababa": "Waqtiga Bariga Afrika (Addis Ababa)", + "Africa\/Algiers": "Waqtiga Bartamaha Yurub (Aljeeris)", + "Africa\/Asmera": "Waqtiga Bariga Afrika (Asmara)", + "Africa\/Bamako": "Waqtiga Celceliska Giriinwij (Bamaako)", + "Africa\/Bangui": "Waqtiga Galbeedka Afrika (Baagi)", + "Africa\/Banjul": "Waqtiga Celceliska Giriinwij (Banjul)", + "Africa\/Bissau": "Waqtiga Celceliska Giriinwij (Bisaaw)", + "Africa\/Blantyre": "Waqtiga Bartamaha Afrika (Balantire)", + "Africa\/Brazzaville": "Waqtiga Galbeedka Afrika (Barasafil)", + "Africa\/Bujumbura": "Waqtiga Bartamaha Afrika (Bujumbura)", + "Africa\/Cairo": "Waqtiga Bariga Yurub (Qaahira)", + "Africa\/Casablanca": "Waqtiga Galbeedka Yurub (Kasabalaanka)", + "Africa\/Ceuta": "Waqtiga Bartamaha Yurub (Seuta)", + "Africa\/Conakry": "Waqtiga Celceliska Giriinwij (Conakri)", + "Africa\/Dakar": "Waqtiga Celceliska Giriinwij (Dakar)", + "Africa\/Dar_es_Salaam": "Waqtiga Bariga Afrika (Daresalaam)", + "Africa\/Djibouti": "Waqtiga Bariga Afrika (Jibuuti)", + "Africa\/Douala": "Waqtiga Galbeedka Afrika (Douaala)", + "Africa\/El_Aaiun": "Waqtiga Galbeedka Yurub (El Ceyuun)", + "Africa\/Freetown": "Waqtiga Celceliska Giriinwij (Firiitawn)", + "Africa\/Gaborone": "Waqtiga Bartamaha Afrika (Gabroon)", + "Africa\/Harare": "Waqtiga Bartamaha Afrika (Haraare)", + "Africa\/Johannesburg": "Waqtiyada Caadiga Ah ee Koonfur Afrika (Johansbaag)", + "Africa\/Juba": "Waqtiga Bariga Afrika (Juba)", + "Africa\/Kampala": "Waqtiga Bariga Afrika (Kambaala)", + "Africa\/Khartoum": "Waqtiga Bartamaha Afrika (Khartuum)", + "Africa\/Kigali": "Waqtiga Bartamaha Afrika (Kigali)", + "Africa\/Kinshasa": "Waqtiga Galbeedka Afrika (Kinshasa)", + "Africa\/Lagos": "Waqtiga Galbeedka Afrika (Laagoos)", + "Africa\/Libreville": "Waqtiga Galbeedka Afrika (Librefil)", + "Africa\/Lome": "Waqtiga Celceliska Giriinwij (Loom)", + "Africa\/Luanda": "Waqtiga Galbeedka Afrika (Luwaanda)", + "Africa\/Lubumbashi": "Waqtiga Bartamaha Afrika (Lubumbaashi)", + "Africa\/Lusaka": "Waqtiga Bartamaha Afrika (Lusaaka)", + "Africa\/Malabo": "Waqtiga Galbeedka Afrika (Malabo)", + "Africa\/Maputo": "Waqtiga Bartamaha Afrika (Mabuuto)", + "Africa\/Maseru": "Waqtiyada Caadiga Ah ee Koonfur Afrika (Maseero)", + "Africa\/Mbabane": "Waqtiyada Caadiga Ah ee Koonfur Afrika (Mababaane)", + "Africa\/Mogadishu": "Waqtiga Bariga Afrika (Muqdisho)", + "Africa\/Monrovia": "Waqtiga Celceliska Giriinwij (Monrofiya)", + "Africa\/Nairobi": "Waqtiga Bariga Afrika (Nayroobi)", + "Africa\/Ndjamena": "Waqtiga Galbeedka Afrika (Injamina)", + "Africa\/Niamey": "Waqtiga Galbeedka Afrika (Nijame)", + "Africa\/Nouakchott": "Waqtiga Celceliska Giriinwij (Nookjot)", + "Africa\/Ouagadougou": "Waqtiga Celceliska Giriinwij (Wagadugu)", + "Africa\/Porto-Novo": "Waqtiga Galbeedka Afrika (Boorto-Noofo)", + "Africa\/Sao_Tome": "Waqtiga Celceliska Giriinwij (Saw Toom)", + "Africa\/Tripoli": "Waqtiga Bariga Yurub (Tiribooli)", + "Africa\/Tunis": "Waqtiga Bartamaha Yurub (Tuunis)", + "Africa\/Windhoek": "Waqtiga Bartamaha Afrika (Windhook)", + "America\/Adak": "Waqtiga Hawaay-Alutiyaan (Adak)", + "America\/Anchorage": "Waqtiga Alaska (Anjorage)", + "America\/Anguilla": "Waqtiga Atlantika ee Waqooyiga Ameerika (Anguwila)", + "America\/Antigua": "Waqtiga Atlantika ee Waqooyiga Ameerika (Antiguwa)", + "America\/Araguaina": "Waqtiga Baraasiliya (Araguwayna)", + "America\/Argentina\/La_Rioja": "Waqtia Arjentiina (La Riyoja)", + "America\/Argentina\/Rio_Gallegos": "Waqtia Arjentiina (Riyo Jalejos)", + "America\/Argentina\/Salta": "Waqtia Arjentiina (Salta)", + "America\/Argentina\/San_Juan": "Waqtia Arjentiina (San Juwaan)", + "America\/Argentina\/San_Luis": "Waqtiga Galbeedka Arjentiina (San Luwis)", + "America\/Argentina\/Tucuman": "Waqtia Arjentiina (Tukuumaan)", + "America\/Argentina\/Ushuaia": "Waqtia Arjentiina (Ushuaay)", + "America\/Aruba": "Waqtiga Atlantika ee Waqooyiga Ameerika (Aruba)", + "America\/Asuncion": "Waqtiga Baragwaay (Asunkiyon)", + "America\/Bahia": "Waqtiga Baraasiliya (Baahiya)", + "America\/Bahia_Banderas": "Waqtiga Bartamaha Waqooyiga Ameerika (Bahiya Banderas)", + "America\/Barbados": "Waqtiga Atlantika ee Waqooyiga Ameerika (Barbados)", + "America\/Belem": "Waqtiga Baraasiliya (Belem)", + "America\/Belize": "Waqtiga Bartamaha Waqooyiga Ameerika (Beliise)", + "America\/Blanc-Sablon": "Waqtiga Atlantika ee Waqooyiga Ameerika (Balank-Sablon)", + "America\/Boa_Vista": "Waqtiga Amason (Bow Fista)", + "America\/Bogota": "Waqtiga Kolambiya (Bogota)", + "America\/Boise": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Boyse)", + "America\/Buenos_Aires": "Waqtia Arjentiina (Buwenos Ayris)", + "America\/Cambridge_Bay": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Kambiriij Baay)", + "America\/Campo_Grande": "Waqtiga Amason (Kaambo Garandi)", + "America\/Cancun": "Waqtiga Bariga ee Waqooyiga Ameerika (Kaankuun)", + "America\/Caracas": "Waqtiga Fenezuweela (Karakaas)", + "America\/Catamarca": "Waqtia Arjentiina (Katamaarka)", + "America\/Cayenne": "Waqtiga Ferenj Guyana (Kayeen)", + "America\/Cayman": "Waqtiga Bariga ee Waqooyiga Ameerika (Keymaan)", + "America\/Chicago": "Waqtiga Bartamaha Waqooyiga Ameerika (Jikaago)", + "America\/Chihuahua": "Waqtiga Baasifikada Meksiko (Jiwaahuu)", + "America\/Coral_Harbour": "Waqtiga Bariga ee Waqooyiga Ameerika (Atikokaan)", + "America\/Cordoba": "Waqtia Arjentiina (Kordooba)", + "America\/Costa_Rica": "Waqtiga Bartamaha Waqooyiga Ameerika (Kosta Riika)", + "America\/Creston": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Karestoon)", + "America\/Cuiaba": "Waqtiga Amason (Kuyaaba)", + "America\/Curacao": "Waqtiga Atlantika ee Waqooyiga Ameerika (Kurakoow)", + "America\/Danmarkshavn": "Waqtiga Celceliska Giriinwij (Daanmaakshaan)", + "America\/Dawson": "Waqtiga Basifika ee Waqooyiga Ameerika (Doosan)", + "America\/Dawson_Creek": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Doosan Kireek)", + "America\/Denver": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Denfar)", + "America\/Detroit": "Waqtiga Bariga ee Waqooyiga Ameerika (Detoroyt)", + "America\/Dominica": "Waqtiga Atlantika ee Waqooyiga Ameerika (Dominiika)", + "America\/Edmonton": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Edmonton)", + "America\/El_Salvador": "Waqtiga Bartamaha Waqooyiga Ameerika (El Salfadoor)", + "America\/Fort_Nelson": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Foot Nelson)", + "America\/Fortaleza": "Waqtiga Baraasiliya (Footalesa)", + "America\/Glace_Bay": "Waqtiga Atlantika ee Waqooyiga Ameerika (Galeys Baay)", + "America\/Godthab": "Waqtiga Galbeedka Giriinlaan (Nuuk)", + "America\/Goose_Bay": "Waqtiga Atlantika ee Waqooyiga Ameerika (Guus Baay)", + "America\/Grand_Turk": "Waqtiga Bariga ee Waqooyiga Ameerika (Garaan Turk)", + "America\/Grenada": "Waqtiga Atlantika ee Waqooyiga Ameerika (Garenaada)", + "America\/Guadeloupe": "Waqtiga Atlantika ee Waqooyiga Ameerika (Guwadeluub)", + "America\/Guatemala": "Waqtiga Bartamaha Waqooyiga Ameerika (Guwatemaala)", + "America\/Guayaquil": "Waqtiga Ekuwadoor (Guwayaquwil)", + "America\/Guyana": "Waqtiga Guyaana (Guyaana)", + "America\/Halifax": "Waqtiga Atlantika ee Waqooyiga Ameerika (Halifakas)", + "America\/Havana": "Waqtiga Kuuba (Hafaana)", + "America\/Hermosillo": "Waqtiga Baasifikada Meksiko (Harmosilo)", + "America\/Indiana\/Knox": "Waqtiga Bartamaha Waqooyiga Ameerika (Nokis, Indiyaana)", + "America\/Indiana\/Marengo": "Waqtiga Bariga ee Waqooyiga Ameerika (Mareengo, Indiyaana)", + "America\/Indiana\/Petersburg": "Waqtiga Bariga ee Waqooyiga Ameerika (Betesbaag, Indiyaana)", + "America\/Indiana\/Tell_City": "Waqtiga Bartamaha Waqooyiga Ameerika (Tel Siti, Indiyaana)", + "America\/Indiana\/Vevay": "Waqtiga Bariga ee Waqooyiga Ameerika (Feefaay, Indiyaana)", + "America\/Indiana\/Vincennes": "Waqtiga Bariga ee Waqooyiga Ameerika (Finseenes, Indiyaana)", + "America\/Indiana\/Winamac": "Waqtiga Bariga ee Waqooyiga Ameerika (Winaamak, Indiyaana)", + "America\/Indianapolis": "Waqtiga Bariga ee Waqooyiga Ameerika (Indiyaanabolis)", + "America\/Inuvik": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Inuufik)", + "America\/Iqaluit": "Waqtiga Bariga ee Waqooyiga Ameerika (Iqaaluut)", + "America\/Jamaica": "Waqtiga Bariga ee Waqooyiga Ameerika (Jamayka)", + "America\/Jujuy": "Waqtia Arjentiina (Jujuy)", + "America\/Juneau": "Waqtiga Alaska (Juniyuu)", + "America\/Kentucky\/Monticello": "Waqtiga Bariga ee Waqooyiga Ameerika (Montiseelo, Kentaki)", + "America\/Kralendijk": "Waqtiga Atlantika ee Waqooyiga Ameerika (Kiraalendik)", + "America\/La_Paz": "Waqtiga Boliifiya (Laa Baas)", + "America\/Lima": "Waqtiga Beeru (Liima)", + "America\/Los_Angeles": "Waqtiga Basifika ee Waqooyiga Ameerika (Loos Anjalis)", + "America\/Louisville": "Waqtiga Bariga ee Waqooyiga Ameerika (Luusfile)", + "America\/Lower_Princes": "Waqtiga Atlantika ee Waqooyiga Ameerika (Loowa Birinses Kuwaata)", + "America\/Maceio": "Waqtiga Baraasiliya (Maasiiyo)", + "America\/Managua": "Waqtiga Bartamaha Waqooyiga Ameerika (Manaaguwa)", + "America\/Manaus": "Waqtiga Amason (Manaauus)", + "America\/Marigot": "Waqtiga Atlantika ee Waqooyiga Ameerika (Maarigot)", + "America\/Martinique": "Waqtiga Atlantika ee Waqooyiga Ameerika (Maartiniikuyuu)", + "America\/Matamoros": "Waqtiga Bartamaha Waqooyiga Ameerika (Matamoros)", + "America\/Mazatlan": "Waqtiga Baasifikada Meksiko (Mazaatlan)", + "America\/Mendoza": "Waqtia Arjentiina (Meendoosa)", + "America\/Menominee": "Waqtiga Bartamaha Waqooyiga Ameerika (Menoominee)", + "America\/Merida": "Waqtiga Bartamaha Waqooyiga Ameerika (Meriida)", + "America\/Metlakatla": "Waqtiga Alaska (Metlaakatla)", + "America\/Mexico_City": "Waqtiga Bartamaha Waqooyiga Ameerika (Meksiko Siti)", + "America\/Miquelon": "Waqtiga St. Beere & Mikiwelon (Miiquulon)", + "America\/Moncton": "Waqtiga Atlantika ee Waqooyiga Ameerika (Moonktoon)", + "America\/Monterrey": "Waqtiga Bartamaha Waqooyiga Ameerika (Moonteerey)", + "America\/Montevideo": "Waqtiga Urugwaay (Moontafiidiyo)", + "America\/Montserrat": "Waqtiga Atlantika ee Waqooyiga Ameerika (Moontseraat)", + "America\/Nassau": "Waqtiga Bariga ee Waqooyiga Ameerika (Nasaaw)", + "America\/New_York": "Waqtiga Bariga ee Waqooyiga Ameerika (Niyuu Yook)", + "America\/Nipigon": "Waqtiga Bariga ee Waqooyiga Ameerika (Nibiigoon)", + "America\/Nome": "Waqtiga Alaska (Noom)", + "America\/Noronha": "Waqtiga Farnaando de Noronha (Noroonha)", + "America\/North_Dakota\/Beulah": "Waqtiga Bartamaha Waqooyiga Ameerika (Biyuulah, Waqooyiga Dakoota)", + "America\/North_Dakota\/Center": "Waqtiga Bartamaha Waqooyiga Ameerika (Bartamaha, Waqooyiga Dakoota)", + "America\/North_Dakota\/New_Salem": "Waqtiga Bartamaha Waqooyiga Ameerika (Niyuu Saalem, Waqooyiga Dakoota)", + "America\/Ojinaga": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Ojinaaga)", + "America\/Panama": "Waqtiga Bariga ee Waqooyiga Ameerika (Banaama)", + "America\/Pangnirtung": "Waqtiga Bariga ee Waqooyiga Ameerika (Bangnirtuung)", + "America\/Paramaribo": "Waqtiga Surineym (Baramaribo)", + "America\/Phoenix": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Foonikis)", + "America\/Port-au-Prince": "Waqtiga Bariga ee Waqooyiga Ameerika (Boort-aw-Biriins)", + "America\/Port_of_Spain": "Waqtiga Atlantika ee Waqooyiga Ameerika (Boort of Isbayn)", + "America\/Porto_Velho": "Waqtiga Amason (Boorto Felho)", + "America\/Puerto_Rico": "Waqtiga Atlantika ee Waqooyiga Ameerika (Boorta Riiko)", + "America\/Punta_Arenas": "Waqtiga Jili (Bunta Arinaas)", + "America\/Rainy_River": "Waqtiga Bartamaha Waqooyiga Ameerika (Reyni Rifer)", + "America\/Rankin_Inlet": "Waqtiga Bartamaha Waqooyiga Ameerika (Raankin Inleet)", + "America\/Recife": "Waqtiga Baraasiliya (Receyf)", + "America\/Regina": "Waqtiga Bartamaha Waqooyiga Ameerika (Rejiina)", + "America\/Resolute": "Waqtiga Bartamaha Waqooyiga Ameerika (Resoluut)", + "America\/Santa_Isabel": "Waqtiga Waqooyi-Galbeed Meksiko (Santa Isabel)", + "America\/Santarem": "Waqtiga Baraasiliya (Santareem)", + "America\/Santiago": "Waqtiga Jili (Santiyaago)", + "America\/Santo_Domingo": "Waqtiga Atlantika ee Waqooyiga Ameerika (Saanto Domingo)", + "America\/Sao_Paulo": "Waqtiga Baraasiliya (Saaw Boolo)", + "America\/Scoresbysund": "Waqtiga Bariga ee Giriinlaan (Itoqortoomiit)", + "America\/Sitka": "Waqtiga Alaska (Siitka)", + "America\/St_Barthelemy": "Waqtiga Atlantika ee Waqooyiga Ameerika (St. Baartelemi)", + "America\/St_Johns": "Waqtiga Niyuufoonlaan (St. Joon)", + "America\/St_Kitts": "Waqtiga Atlantika ee Waqooyiga Ameerika (St. Kitis)", + "America\/St_Lucia": "Waqtiga Atlantika ee Waqooyiga Ameerika (St. Lusiya)", + "America\/St_Thomas": "Waqtiga Atlantika ee Waqooyiga Ameerika (St. Toomas)", + "America\/St_Vincent": "Waqtiga Atlantika ee Waqooyiga Ameerika (St. Finsent)", + "America\/Swift_Current": "Waqtiga Bartamaha Waqooyiga Ameerika (Iswift Karent)", + "America\/Tegucigalpa": "Waqtiga Bartamaha Waqooyiga Ameerika (Tegusigalba)", + "America\/Thule": "Waqtiga Atlantika ee Waqooyiga Ameerika (Tuul)", + "America\/Thunder_Bay": "Waqtiga Bariga ee Waqooyiga Ameerika (Tanda Baay)", + "America\/Tijuana": "Waqtiga Basifika ee Waqooyiga Ameerika (Tijuwaana)", + "America\/Toronto": "Waqtiga Bariga ee Waqooyiga Ameerika (Toronto)", + "America\/Tortola": "Waqtiga Atlantika ee Waqooyiga Ameerika (Tortoola)", + "America\/Vancouver": "Waqtiga Basifika ee Waqooyiga Ameerika (Fankuufar)", + "America\/Whitehorse": "Waqtiga Basifika ee Waqooyiga Ameerika (Waythoras)", + "America\/Winnipeg": "Waqtiga Bartamaha Waqooyiga Ameerika (Winibeg)", + "America\/Yakutat": "Waqtiga Alaska (Yakutaat)", + "America\/Yellowknife": "Waqtiga Buuraleyda ee Waqooyiga Ameerika (Yelowneyf)", + "Antarctica\/Casey": "Waqtiga Galbeedka Astaraaliya (Kaysee)", + "Antarctica\/Davis": "Waqtiga Dafis (Dafis)", + "Antarctica\/DumontDUrville": "Waqtiga Dumont - d’urfille (Dumont d’urfile)", + "Antarctica\/Macquarie": "Waqtiga Makquwariy Aylaan (Makquwariy)", + "Antarctica\/Mawson": "Waqtiga Mawson (Mawson)", + "Antarctica\/McMurdo": "Waqtiga Niyuu Si’laan (MakMurdo)", + "Antarctica\/Palmer": "Waqtiga Jili (Baamar)", + "Antarctica\/Rothera": "Waqtiga Rotera (Rotera)", + "Antarctica\/Syowa": "Waqtiga Siyowa (Siyowa)", + "Antarctica\/Troll": "Waqtiga Celceliska Giriinwij (Torool)", + "Antarctica\/Vostok": "Waqtiga Fostok (Fostok)", + "Arctic\/Longyearbyen": "Waqtiga Bartamaha Yurub (Lonjirbyeen)", + "Asia\/Aden": "Waqtiga Carabta (Cadan)", + "Asia\/Almaty": "Waqtiga Bariga Kasakhistaan (Almati)", + "Asia\/Amman": "Waqtiga Bariga Yurub (Ammaan)", + "Asia\/Aqtau": "Waqtiga Koonfurta Kasakhistan (Aktaw)", + "Asia\/Aqtobe": "Waqtiga Koonfurta Kasakhistan (Aqtobe)", + "Asia\/Ashgabat": "Waqtiga Turkmenistaan (Ashgabat)", + "Asia\/Atyrau": "Waqtiga Koonfurta Kasakhistan (Atiyraw)", + "Asia\/Baghdad": "Waqtiga Carabta (Baqdaad)", + "Asia\/Bahrain": "Waqtiga Carabta (Baxreyn)", + "Asia\/Baku": "Waqtiga Asarbeyjan (Baku)", + "Asia\/Bangkok": "Waqtiga Indoshiina (Bangkook)", + "Asia\/Beirut": "Waqtiga Bariga Yurub (Beyruud)", + "Asia\/Bishkek": "Waqtiga Kiyrigistaan (Bishkek)", + "Asia\/Brunei": "Waqtiga Buruney Daarusalaam (Buruney)", + "Asia\/Calcutta": "Waqtiga Caadiga Ah ee Hindiya (Kolkaata)", + "Asia\/Chita": "Waqtiyada Yakut (Jiita)", + "Asia\/Choibalsan": "Waqtiga Joybalsan (Joybalsan)", + "Asia\/Colombo": "Waqtiga Caadiga Ah ee Hindiya (Kolombo)", + "Asia\/Damascus": "Waqtiga Bariga Yurub (Dimishiq)", + "Asia\/Dhaka": "Waqtiga Bangledeesh (Dhaaka)", + "Asia\/Dili": "Waqtiga Iist Timoor (Dili)", + "Asia\/Dubai": "Waqtiga Gacanka (Dubay)", + "Asia\/Dushanbe": "Waqtiga Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Waqtiga Bariga Yurub (Famagusta)", + "Asia\/Gaza": "Waqtiga Bariga Yurub (Qasa)", + "Asia\/Hebron": "Waqtiga Bariga Yurub (Hebron)", + "Asia\/Hong_Kong": "Waqtiga Hoong Koong (Hoong Koong)", + "Asia\/Hovd": "Waqtiga Hofud (Hofud)", + "Asia\/Irkutsk": "Waqtiga Irkutsik (Irkutsik)", + "Asia\/Jakarta": "Waqtiga Galbeedka Indoneeysiya (Jakaarta)", + "Asia\/Jayapura": "Waqtiga Indoneeysiya (Jayabura)", + "Asia\/Jerusalem": "Waqtiga Israaiil (Jeerusaalem)", + "Asia\/Kabul": "Waqtiga Afggaanistaan (Kaabuul)", + "Asia\/Karachi": "Waqtiga Bakistaan (Karaaji)", + "Asia\/Katmandu": "Waqtiga Neebaal (Katmandu)", + "Asia\/Khandyga": "Waqtiyada Yakut (Khandiyga)", + "Asia\/Krasnoyarsk": "Waqtiga Karasnoyarsik (Karasnoyarska)", + "Asia\/Kuala_Lumpur": "Waqtiga Maleyshiya (Kuala Lambuur)", + "Asia\/Kuching": "Waqtiga Maleyshiya (Kujing)", + "Asia\/Kuwait": "Waqtiga Carabta (Kuweyt)", + "Asia\/Macau": "Waqtiga Shiinaha (Makow)", + "Asia\/Magadan": "Watiga Magedan (Magedan)", + "Asia\/Makassar": "Waqtiga Bartamaha Indoneeysiya (Makasar)", + "Asia\/Manila": "Waqtiga Filibiin (Maniila)", + "Asia\/Muscat": "Waqtiga Gacanka (Muskat)", + "Asia\/Nicosia": "Waqtiga Bariga Yurub (Nikosiya)", + "Asia\/Novokuznetsk": "Waqtiga Karasnoyarsik (Nofokusnetsik)", + "Asia\/Novosibirsk": "Waqtiga Nofosibirsik (Nofosibirsik)", + "Asia\/Omsk": "Waqtiga Omsk (Omsk)", + "Asia\/Oral": "Waqtiga Koonfurta Kasakhistan (Oral)", + "Asia\/Phnom_Penh": "Waqtiga Indoshiina (Benom Ben)", + "Asia\/Pontianak": "Waqtiga Galbeedka Indoneeysiya (Botiyaanak)", + "Asia\/Pyongyang": "Waqtiga Kuuriya (Boyongyang)", + "Asia\/Qatar": "Waqtiga Carabta (Qaddar)", + "Asia\/Qostanay": "Waqtiga Bariga Kasakhistaan (Kostanay)", + "Asia\/Qyzylorda": "Waqtiga Koonfurta Kasakhistan (Qiyslorda)", + "Asia\/Rangoon": "Waqtiga Mayanmaar (Yangon)", + "Asia\/Riyadh": "Waqtiga Carabta (Riyaad)", + "Asia\/Saigon": "Waqtiga Indoshiina (Hoo Ji Mih Siti)", + "Asia\/Sakhalin": "Waqtiga Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Waqtiga Usbekistan (Samarkaan)", + "Asia\/Seoul": "Waqtiga Kuuriya (Soul)", + "Asia\/Shanghai": "Waqtiga Shiinaha (Shanghaay)", + "Asia\/Singapore": "Waqtiga Singabuur (Singabuur)", + "Asia\/Srednekolymsk": "Watiga Magedan (Sarednokoleymisk)", + "Asia\/Taipei": "Waqtiga Teybey (Teybey)", + "Asia\/Tashkent": "Waqtiga Usbekistan (Toshkeent)", + "Asia\/Tbilisi": "Waqtiga Joorjiya (Tibilisi)", + "Asia\/Tehran": "Waqtiga Iiraan (Tehraan)", + "Asia\/Thimphu": "Waqtiga Butaan (Timbu)", + "Asia\/Tokyo": "Waqtiga Jabaan (Tokyo)", + "Asia\/Ulaanbaatar": "Waqtiga Ulaanbaataar (Ulaanbaatar)", + "Asia\/Ust-Nera": "Waqtiga Faladifostok (Ust-Nera)", + "Asia\/Vientiane": "Waqtiga Indoshiina (Fiyaantiyaan)", + "Asia\/Vladivostok": "Waqtiga Faladifostok (Faladifostok)", + "Asia\/Yakutsk": "Waqtiyada Yakut (Yakut)", + "Asia\/Yekaterinburg": "Waqtiga Yekaterinbaag (Yekaterinbaag)", + "Asia\/Yerevan": "Waqtiga Armeeniya (Yerefan)", + "Atlantic\/Azores": "Waqtiga Asores (Asores)", + "Atlantic\/Bermuda": "Waqtiga Atlantika ee Waqooyiga Ameerika (Barmuuda)", + "Atlantic\/Canary": "Waqtiga Galbeedka Yurub (Kanari)", + "Atlantic\/Cape_Verde": "Waqtiga Keyb Faarde (Keyb Faarde)", + "Atlantic\/Faeroe": "Waqtiga Galbeedka Yurub (Farow)", + "Atlantic\/Madeira": "Waqtiga Galbeedka Yurub (Madeera)", + "Atlantic\/Reykjavik": "Waqtiga Celceliska Giriinwij (Reykjafik)", + "Atlantic\/South_Georgia": "Waqtiga Sowt Joorjiya (Sowt Joorjiya)", + "Atlantic\/St_Helena": "Waqtiga Celceliska Giriinwij (St. Helena)", + "Atlantic\/Stanley": "Waqtiga Faalklaan Aylaanis (Istaanley)", + "Australia\/Adelaide": "Waqtiga Bartamaha Astaraaliya (Adelayde)", + "Australia\/Brisbane": "Waqtiga Bariga Astaraaliya (Birisban)", + "Australia\/Broken_Hill": "Waqtiga Bartamaha Astaraaliya (Boroken Hil)", + "Australia\/Currie": "Waqtiga Bariga Astaraaliya (Kuriy)", + "Australia\/Darwin": "Waqtiga Bartamaha Astaraaliya (Darwin)", + "Australia\/Eucla": "Waqtiga Bartamaha Galbeedka Astaraaliya (Yukla)", + "Australia\/Hobart": "Waqtiga Bariga Astaraaliya (Hubaart)", + "Australia\/Lindeman": "Waqtiga Bariga Astaraaliya (Lindeman)", + "Australia\/Lord_Howe": "Waqtiga Lod How (Lod How)", + "Australia\/Melbourne": "Waqtiga Bariga Astaraaliya (Melboon)", + "Australia\/Perth": "Waqtiga Galbeedka Astaraaliya (Bert)", + "Australia\/Sydney": "Waqtiga Bariga Astaraaliya (Sidney)", + "CST6CDT": "Waqtiga Bartamaha Waqooyiga Ameerika", + "EST5EDT": "Waqtiga Bariga ee Waqooyiga Ameerika", + "Etc\/GMT": "Waqtiga Celceliska Giriinwij", + "Etc\/UTC": "Waqtiga Isku-xiran ee Caalamka", + "Europe\/Amsterdam": "Waqtiga Bartamaha Yurub (Amsterdaam)", + "Europe\/Andorra": "Waqtiga Bartamaha Yurub (Andoora)", + "Europe\/Astrakhan": "Waqtiga Moskow (Astarakhaan)", + "Europe\/Athens": "Waqtiga Bariga Yurub (Atens)", + "Europe\/Belgrade": "Waqtiga Bartamaha Yurub (Bilgaraydh)", + "Europe\/Berlin": "Waqtiga Bartamaha Yurub (Barliin)", + "Europe\/Bratislava": "Waqtiga Bartamaha Yurub (Baratislafa)", + "Europe\/Brussels": "Waqtiga Bartamaha Yurub (Barasalis)", + "Europe\/Bucharest": "Waqtiga Bariga Yurub (Bujarest)", + "Europe\/Budapest": "Waqtiga Bartamaha Yurub (Budabest)", + "Europe\/Busingen": "Waqtiga Bartamaha Yurub (Busingeen)", + "Europe\/Chisinau": "Waqtiga Bariga Yurub (Jisinaaw)", + "Europe\/Copenhagen": "Waqtiga Bartamaha Yurub (Kobenhaagan)", + "Europe\/Dublin": "Waqtiga Celceliska Giriinwij (Dhaablin)", + "Europe\/Gibraltar": "Waqtiga Bartamaha Yurub (Gibraltar)", + "Europe\/Guernsey": "Waqtiga Celceliska Giriinwij (Geernisi)", + "Europe\/Helsinki": "Waqtiga Bariga Yurub (Heleniski)", + "Europe\/Isle_of_Man": "Waqtiga Celceliska Giriinwij (Ayle of Maan)", + "Europe\/Jersey": "Waqtiga Celceliska Giriinwij (Jaarsey)", + "Europe\/Kaliningrad": "Waqtiga Bariga Yurub (Kaliningrad)", + "Europe\/Kiev": "Waqtiga Bariga Yurub (Kiyf)", + "Europe\/Lisbon": "Waqtiga Galbeedka Yurub (Lisbon)", + "Europe\/Ljubljana": "Waqtiga Bartamaha Yurub (Lubalaana)", + "Europe\/London": "Waqtiga Celceliska Giriinwij (Landan)", + "Europe\/Luxembourg": "Waqtiga Bartamaha Yurub (Luksembaag)", + "Europe\/Madrid": "Waqtiga Bartamaha Yurub (Maadriid)", + "Europe\/Malta": "Waqtiga Bartamaha Yurub (Malta)", + "Europe\/Mariehamn": "Waqtiga Bariga Yurub (Maarihaam)", + "Europe\/Minsk": "Waqtiga Moskow (Minisk)", + "Europe\/Monaco": "Waqtiga Bartamaha Yurub (Monako)", + "Europe\/Moscow": "Waqtiga Moskow (Moskow)", + "Europe\/Oslo": "Waqtiga Bartamaha Yurub (Oslo)", + "Europe\/Paris": "Waqtiga Bartamaha Yurub (Baariis)", + "Europe\/Podgorica": "Waqtiga Bartamaha Yurub (Bodgorika)", + "Europe\/Prague": "Waqtiga Bartamaha Yurub (Baraag)", + "Europe\/Riga": "Waqtiga Bariga Yurub (Riija)", + "Europe\/Rome": "Waqtiga Bartamaha Yurub (Rooma)", + "Europe\/San_Marino": "Waqtiga Bartamaha Yurub (San Mariino)", + "Europe\/Sarajevo": "Waqtiga Bartamaha Yurub (Sarayeefo)", + "Europe\/Saratov": "Waqtiga Moskow (Saratoof)", + "Europe\/Simferopol": "Waqtiga Moskow (Simferobol)", + "Europe\/Skopje": "Waqtiga Bartamaha Yurub (Iskoobje)", + "Europe\/Sofia": "Waqtiga Bariga Yurub (Sofiya)", + "Europe\/Stockholm": "Waqtiga Bartamaha Yurub (Istokhoom)", + "Europe\/Tallinn": "Waqtiga Bariga Yurub (Taalin)", + "Europe\/Tirane": "Waqtiga Bartamaha Yurub (Tiraane)", + "Europe\/Ulyanovsk": "Waqtiga Moskow (Ulyanofisk)", + "Europe\/Uzhgorod": "Waqtiga Bariga Yurub (Usgorod)", + "Europe\/Vaduz": "Waqtiga Bartamaha Yurub (Faduus)", + "Europe\/Vatican": "Waqtiga Bartamaha Yurub (Fatikaan)", + "Europe\/Vienna": "Waqtiga Bartamaha Yurub (Fiyaana)", + "Europe\/Vilnius": "Waqtiga Bariga Yurub (Finiyuus)", + "Europe\/Volgograd": "Waqtiga Folgograd (Folgograd)", + "Europe\/Warsaw": "Waqtiga Bartamaha Yurub (Warsaw)", + "Europe\/Zagreb": "Waqtiga Bartamaha Yurub (Sagreb)", + "Europe\/Zaporozhye": "Waqtiga Bariga Yurub (Saborosey)", + "Europe\/Zurich": "Waqtiga Bartamaha Yurub (Surij)", + "Indian\/Antananarivo": "Waqtiga Bariga Afrika (Antananarifo)", + "Indian\/Chagos": "Waqtiga Badweynta Hindiya (Jagos)", + "Indian\/Christmas": "Waqtiga Kirismas Aylaan (Kiristmas)", + "Indian\/Cocos": "Waqtiga Kokos Aylaan (Kokos)", + "Indian\/Comoro": "Waqtiga Bariga Afrika (Komoro)", + "Indian\/Kerguelen": "Waqtiga Koonfurta Faransiiska & Antaarktik (Kergalen)", + "Indian\/Mahe": "Waqtiga Siishalis (Mahe)", + "Indian\/Maldives": "Waqtiga Maldifis (Maldifis)", + "Indian\/Mauritius": "Waqtiga Morishiyaas (Morishiyaas)", + "Indian\/Mayotte": "Waqtiga Bariga Afrika (Mayoote)", + "Indian\/Reunion": "Waqtiga Riyuuniyon (Riyuuniyon)", + "MST7MDT": "Waqtiga Buuraleyda ee Waqooyiga Ameerika", + "PST8PDT": "Waqtiga Basifika ee Waqooyiga Ameerika", + "Pacific\/Apia": "Waqtiga Abiya (Abiya)", + "Pacific\/Auckland": "Waqtiga Niyuu Si’laan (Owklaan)", + "Pacific\/Bougainville": "Waqtiga Babuw Niyuu Giniya (Boogaynfil)", + "Pacific\/Chatham": "Waqtiga Jaatam (Jatam)", + "Pacific\/Easter": "Waqtiga Iistar Aylaan (Iistar)", + "Pacific\/Efate": "Waqtiga Fanuutu (Efate)", + "Pacific\/Enderbury": "Waqtiga Foonikis Aylaanis (Enderburi)", + "Pacific\/Fakaofo": "Waqtiga Tokeluu (fakofo)", + "Pacific\/Fiji": "Waqtiga Fiji (Fiji)", + "Pacific\/Funafuti": "Waqtiga Tufalu (Funafuti)", + "Pacific\/Galapagos": "Waqtiga Galabagos (Galabagos)", + "Pacific\/Gambier": "Waqtiga Gambiyar (Gambiyr)", + "Pacific\/Guadalcanal": "Waqtiga Solomon Aylaanis (Cuadalkanal)", + "Pacific\/Guam": "Waqtiga Jamoro (Guwam)", + "Pacific\/Honolulu": "Waqtiga Hawaay-Alutiyaan (Honolulu)", + "Pacific\/Johnston": "Waqtiga Hawaay-Alutiyaan (Joonston)", + "Pacific\/Kiritimati": "Waqtiga Leyn Aylaan (Kiritimaati)", + "Pacific\/Kosrae": "Waqtiga Kosriy (Kosrii)", + "Pacific\/Kwajalein": "Waqtiga Maarshaal Aylaanis (Kuwajaleyn)", + "Pacific\/Majuro": "Waqtiga Maarshaal Aylaanis (Majro)", + "Pacific\/Marquesas": "Waqtiga Marquwesas (Marquwesas)", + "Pacific\/Midway": "Waqtiga Samoa (Midway)", + "Pacific\/Nauru": "Waqtiga Nawroo (Nawroo)", + "Pacific\/Niue": "Waqtiga Niyuu (Niyuu)", + "Pacific\/Norfolk": "Waqtiga Noorfek Aylaan (Noorfek)", + "Pacific\/Noumea": "Waqtiga Niyuu Kaledonya (Noomiya)", + "Pacific\/Pago_Pago": "Waqtiga Samoa (Bago Bago)", + "Pacific\/Palau": "Waqtiga Balaw (Balaw)", + "Pacific\/Pitcairn": "Waqtiga Bitkeen (Bitkayrn)", + "Pacific\/Ponape": "Waqtiga Bonabe (Bonbey)", + "Pacific\/Port_Moresby": "Waqtiga Babuw Niyuu Giniya (Boort Moresbi)", + "Pacific\/Rarotonga": "Waqtiga Kuuk Aylaanis (Rarotonga)", + "Pacific\/Saipan": "Waqtiga Jamoro (Seyban)", + "Pacific\/Tahiti": "Waqtiga Tahiti (Tahiti)", + "Pacific\/Tarawa": "Waqtiga Jilbeert Aylaan (Tarawa)", + "Pacific\/Tongatapu": "Waqtiga Tonga (Tongatabu)", + "Pacific\/Truk": "Waqtiga Juuk (Juuk)", + "Pacific\/Wake": "Waqtiga Wayk Iylaanis (Wake)", + "Pacific\/Wallis": "Waqtiga Walis & Futuna (Walis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sq.json b/src/Symfony/Component/Intl/Resources/data/timezones/sq.json new file mode 100644 index 0000000000000..c09ff8a5506c8 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sq.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Ora e Grinuiçit (Abixhan)", + "Africa\/Accra": "Ora e Grinuiçit (Akra)", + "Africa\/Addis_Ababa": "Ora e Afrikës Lindore (Adis-Ababë)", + "Africa\/Algiers": "Ora e Evropës Qendrore (Algjer)", + "Africa\/Asmera": "Ora e Afrikës Lindore (Asmarë)", + "Africa\/Bamako": "Ora e Grinuiçit (Bamako)", + "Africa\/Bangui": "Ora e Afrikës Perëndimore (Bangui)", + "Africa\/Banjul": "Ora e Grinuiçit (Banxhul)", + "Africa\/Bissau": "Ora e Grinuiçit (Bisau)", + "Africa\/Blantyre": "Ora e Afrikës Qendrore (Blantirë)", + "Africa\/Brazzaville": "Ora e Afrikës Perëndimore (Brazavillë)", + "Africa\/Bujumbura": "Ora e Afrikës Qendrore (Buxhumburë)", + "Africa\/Cairo": "Ora e Evropës Lindore (Kajro)", + "Africa\/Casablanca": "Ora e Evropës Perëndimore (Kazablankë)", + "Africa\/Ceuta": "Ora e Evropës Qendrore (Theuta)", + "Africa\/Conakry": "Ora e Grinuiçit (Konakri)", + "Africa\/Dakar": "Ora e Grinuiçit (Dakar)", + "Africa\/Dar_es_Salaam": "Ora e Afrikës Lindore (Dar-es-Salam)", + "Africa\/Djibouti": "Ora e Afrikës Lindore (Xhibuti)", + "Africa\/Douala": "Ora e Afrikës Perëndimore (Douala)", + "Africa\/El_Aaiun": "Ora e Evropës Perëndimore (El Ajun)", + "Africa\/Freetown": "Ora e Grinuiçit (Fritaun)", + "Africa\/Gaborone": "Ora e Afrikës Qendrore (Gaborone)", + "Africa\/Harare": "Ora e Afrikës Qendrore (Harare)", + "Africa\/Johannesburg": "Ora standarde e Afrikës Jugore (Johanesburg)", + "Africa\/Juba": "Ora e Afrikës Lindore (Xhuba)", + "Africa\/Kampala": "Ora e Afrikës Lindore (Kampala)", + "Africa\/Khartoum": "Ora e Afrikës Qendrore (Kartum)", + "Africa\/Kigali": "Ora e Afrikës Qendrore (Kigali)", + "Africa\/Kinshasa": "Ora e Afrikës Perëndimore (Kinshasa)", + "Africa\/Lagos": "Ora e Afrikës Perëndimore (Lagos)", + "Africa\/Libreville": "Ora e Afrikës Perëndimore (Librevilë)", + "Africa\/Lome": "Ora e Grinuiçit (Lome)", + "Africa\/Luanda": "Ora e Afrikës Perëndimore (Luanda)", + "Africa\/Lubumbashi": "Ora e Afrikës Qendrore (Lubumbashi)", + "Africa\/Lusaka": "Ora e Afrikës Qendrore (Lusaka)", + "Africa\/Malabo": "Ora e Afrikës Perëndimore (Malabo)", + "Africa\/Maputo": "Ora e Afrikës Qendrore (Maputo)", + "Africa\/Maseru": "Ora standarde e Afrikës Jugore (Maseru)", + "Africa\/Mbabane": "Ora standarde e Afrikës Jugore (Mbabane)", + "Africa\/Mogadishu": "Ora e Afrikës Lindore (Mogadishu)", + "Africa\/Monrovia": "Ora e Grinuiçit (Monrovia)", + "Africa\/Nairobi": "Ora e Afrikës Lindore (Nairobi)", + "Africa\/Ndjamena": "Ora e Afrikës Perëndimore (Ndjamena)", + "Africa\/Niamey": "Ora e Afrikës Perëndimore (Niamej)", + "Africa\/Nouakchott": "Ora e Grinuiçit (Nouakot)", + "Africa\/Ouagadougou": "Ora e Grinuiçit (Uagëdugu)", + "Africa\/Porto-Novo": "Ora e Afrikës Perëndimore (Porto-Novo)", + "Africa\/Sao_Tome": "Ora e Grinuiçit (Sao-Tome)", + "Africa\/Tripoli": "Ora e Evropës Lindore (Tripoli)", + "Africa\/Tunis": "Ora e Evropës Qendrore (Tuniz)", + "Africa\/Windhoek": "Ora e Afrikës Qendrore (Vint’huk)", + "America\/Adak": "Ora e Ishujve Hauai-Aleutian (Adak)", + "America\/Anchorage": "Ora e Alaskës (Ankorejxh)", + "America\/Anguilla": "Ora e Atlantikut (Anguilë)", + "America\/Antigua": "Ora e Atlantikut (Antigua)", + "America\/Araguaina": "Ora e Brazilisë (Araguajana)", + "America\/Argentina\/La_Rioja": "Ora e Argjentinës (La Rioha)", + "America\/Argentina\/Rio_Gallegos": "Ora e Argjentinës (Rio-Galegos)", + "America\/Argentina\/Salta": "Ora e Argjentinës (Saltë)", + "America\/Argentina\/San_Juan": "Ora e Argjentinës (San-Huan)", + "America\/Argentina\/San_Luis": "Ora e Argjentinës Perëndimore (Shën-Luis)", + "America\/Argentina\/Tucuman": "Ora e Argjentinës (Tukuman)", + "America\/Argentina\/Ushuaia": "Ora e Argjentinës (Ushuaja)", + "America\/Aruba": "Ora e Atlantikut (Arubë)", + "America\/Asuncion": "Ora e Paraguait (Asunsion)", + "America\/Bahia": "Ora e Brazilisë (Bahia)", + "America\/Bahia_Banderas": "Ora e SHBA-së Qendrore (Bahia-Banderas)", + "America\/Barbados": "Ora e Atlantikut (Barbados)", + "America\/Belem": "Ora e Brazilisë (Belem)", + "America\/Belize": "Ora e SHBA-së Qendrore (Belizë)", + "America\/Blanc-Sablon": "Ora e Atlantikut (Blank-Sablon)", + "America\/Boa_Vista": "Ora e Amazonës (Boa-Vista)", + "America\/Bogota": "Ora e Kolumbisë (Bogotë)", + "America\/Boise": "Ora e Territoreve Amerikane të Brezit Malor (Boizë)", + "America\/Buenos_Aires": "Ora e Argjentinës (Buenos-Ajres)", + "America\/Cambridge_Bay": "Ora e Territoreve Amerikane të Brezit Malor (Gjiri i Kembrixhit)", + "America\/Campo_Grande": "Ora e Amazonës (Kampo-Grande)", + "America\/Cancun": "Ora e SHBA-së Lindore (Kankun)", + "America\/Caracas": "Ora e Venezuelës (Karakas)", + "America\/Catamarca": "Ora e Argjentinës (Katamarka)", + "America\/Cayenne": "Ora e Guajanës Franceze (Kajenë)", + "America\/Cayman": "Ora e SHBA-së Lindore (Kajman)", + "America\/Chicago": "Ora e SHBA-së Qendrore (Çikago)", + "America\/Chihuahua": "Ora e Territoreve Meksikane të Bregut të Paqësorit (Çihahua)", + "America\/Coral_Harbour": "Ora e SHBA-së Lindore (Atikokan)", + "America\/Cordoba": "Ora e Argjentinës (Kordoba)", + "America\/Costa_Rica": "Ora e SHBA-së Qendrore (Kosta-Rikë)", + "America\/Creston": "Ora e Territoreve Amerikane të Brezit Malor (Kreston)", + "America\/Cuiaba": "Ora e Amazonës (Kujaba)", + "America\/Curacao": "Ora e Atlantikut (Kurasao)", + "America\/Danmarkshavn": "Ora e Grinuiçit (Denmarkshavën)", + "America\/Dawson": "Ora e Territoreve Amerikane të Bregut të Paqësorit (Douson)", + "America\/Dawson_Creek": "Ora e Territoreve Amerikane të Brezit Malor (Gjiri i Dousonit)", + "America\/Denver": "Ora e Territoreve Amerikane të Brezit Malor (Denver)", + "America\/Detroit": "Ora e SHBA-së Lindore (Detroit)", + "America\/Dominica": "Ora e Atlantikut (Dominikë)", + "America\/Edmonton": "Ora e Territoreve Amerikane të Brezit Malor (Edmonton)", + "America\/Eirunepe": "Ora e Ejkrit [Ako] (Ejrunep)", + "America\/El_Salvador": "Ora e SHBA-së Qendrore (Salvador)", + "America\/Fort_Nelson": "Ora e Territoreve Amerikane të Brezit Malor (Fort-Nelson)", + "America\/Fortaleza": "Ora e Brazilisë (Fortaleza)", + "America\/Glace_Bay": "Ora e Atlantikut (Gjiri i Ngrirë)", + "America\/Godthab": "Ora e Grënlandës Perëndimore (Njuk)", + "America\/Goose_Bay": "Ora e Atlantikut (Gjiri i Patës)", + "America\/Grand_Turk": "Ora e SHBA-së Lindore (Turku i Madh)", + "America\/Grenada": "Ora e Atlantikut (Granadë)", + "America\/Guadeloupe": "Ora e Atlantikut (Guadelupë)", + "America\/Guatemala": "Ora e SHBA-së Qendrore (Guatemalë)", + "America\/Guayaquil": "Ora e Ekuadorit (Guajakuil)", + "America\/Guyana": "Ora e Guajanës (Guajanë)", + "America\/Halifax": "Ora e Atlantikut (Halifaks)", + "America\/Havana": "Ora e Kubës (Havanë)", + "America\/Hermosillo": "Ora e Territoreve Meksikane të Bregut të Paqësorit (Hermosijo)", + "America\/Indiana\/Knox": "Ora e SHBA-së Qendrore (Knoks, Indiana)", + "America\/Indiana\/Marengo": "Ora e SHBA-së Lindore (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Ora e SHBA-së Lindore (Petërsburg, Indiana)", + "America\/Indiana\/Tell_City": "Ora e SHBA-së Qendrore (Tell-Siti, Indiana)", + "America\/Indiana\/Vevay": "Ora e SHBA-së Lindore (Vevëj, Indiana)", + "America\/Indiana\/Vincennes": "Ora e SHBA-së Lindore (Vincenes, Indiana)", + "America\/Indiana\/Winamac": "Ora e SHBA-së Lindore (Uinamak, Indiana)", + "America\/Indianapolis": "Ora e SHBA-së Lindore (Indianapolis)", + "America\/Inuvik": "Ora e Territoreve Amerikane të Brezit Malor (Inuvik)", + "America\/Iqaluit": "Ora e SHBA-së Lindore (Ikaluit)", + "America\/Jamaica": "Ora e SHBA-së Lindore (Xhamajkë)", + "America\/Jujuy": "Ora e Argjentinës (Huhui)", + "America\/Juneau": "Ora e Alaskës (Xhunou)", + "America\/Kentucky\/Monticello": "Ora e SHBA-së Lindore (Montiçelo, Kentaki)", + "America\/Kralendijk": "Ora e Atlantikut (Kralendijk)", + "America\/La_Paz": "Ora e Bolivisë (La Paz)", + "America\/Lima": "Ora e Perusë (Limë)", + "America\/Los_Angeles": "Ora e Territoreve Amerikane të Bregut të Paqësorit (Los Anxhelos)", + "America\/Louisville": "Ora e SHBA-së Lindore (Luizvilë)", + "America\/Lower_Princes": "Ora e Atlantikut (Louer-Prinsis-Kuortër)", + "America\/Maceio": "Ora e Brazilisë (Makejo)", + "America\/Managua": "Ora e SHBA-së Qendrore (Managua)", + "America\/Manaus": "Ora e Amazonës (Manaus)", + "America\/Marigot": "Ora e Atlantikut (Marigot)", + "America\/Martinique": "Ora e Atlantikut (Martinikë)", + "America\/Matamoros": "Ora e SHBA-së Qendrore (Matamoros)", + "America\/Mazatlan": "Ora e Territoreve Meksikane të Bregut të Paqësorit (Mazatlan)", + "America\/Mendoza": "Ora e Argjentinës (Mendoza)", + "America\/Menominee": "Ora e SHBA-së Qendrore (Menomini)", + "America\/Merida": "Ora e SHBA-së Qendrore (Merida)", + "America\/Metlakatla": "Ora e Alaskës (Metlakatla)", + "America\/Mexico_City": "Ora e SHBA-së Qendrore (Qyteti i Meksikës)", + "America\/Miquelon": "Ora e Shën-Pier dhe Mikelon (Mikelon)", + "America\/Moncton": "Ora e Atlantikut (Monkton)", + "America\/Monterrey": "Ora e SHBA-së Qendrore (Monterrej)", + "America\/Montevideo": "Ora e Uruguait (Montevideo)", + "America\/Montserrat": "Ora e Atlantikut (Montserat)", + "America\/Nassau": "Ora e SHBA-së Lindore (Nasao)", + "America\/New_York": "Ora e SHBA-së Lindore (Nju-Jork)", + "America\/Nipigon": "Ora e SHBA-së Lindore (Nipigon)", + "America\/Nome": "Ora e Alaskës (Nome)", + "America\/Noronha": "Ora e Fernando-de-Noronjës (Noronja)", + "America\/North_Dakota\/Beulah": "Ora e SHBA-së Qendrore (Beula, Dakota e Veriut)", + "America\/North_Dakota\/Center": "Ora e SHBA-së Qendrore (Qendër, Dakota e Veriut)", + "America\/North_Dakota\/New_Salem": "Ora e SHBA-së Qendrore (Nju-Salem, Dakota e Veriut)", + "America\/Ojinaga": "Ora e Territoreve Amerikane të Brezit Malor (Ohinaga)", + "America\/Panama": "Ora e SHBA-së Lindore (Panama)", + "America\/Pangnirtung": "Ora e SHBA-së Lindore (Pangnirtung)", + "America\/Paramaribo": "Ora e Surinamit (Paramaribo)", + "America\/Phoenix": "Ora e Territoreve Amerikane të Brezit Malor (Feniks)", + "America\/Port-au-Prince": "Ora e SHBA-së Lindore (Port-o-Prins)", + "America\/Port_of_Spain": "Ora e Atlantikut (Port of Spain)", + "America\/Porto_Velho": "Ora e Amazonës (Porto-Velho)", + "America\/Puerto_Rico": "Ora e Atlantikut (Porto-Riko)", + "America\/Punta_Arenas": "Ora e Kilit (Punta-Arenas)", + "America\/Rainy_River": "Ora e SHBA-së Qendrore (Lumi i Shirave)", + "America\/Rankin_Inlet": "Ora e SHBA-së Qendrore (Gryka Inlet)", + "America\/Recife": "Ora e Brazilisë (Recife)", + "America\/Regina": "Ora e SHBA-së Qendrore (Rexhina)", + "America\/Resolute": "Ora e SHBA-së Qendrore (Resolute)", + "America\/Rio_Branco": "Ora e Ejkrit [Ako] (Rio-Branko)", + "America\/Santa_Isabel": "Ora e Meksikës Veriperëndimore (Santa-Izabela)", + "America\/Santarem": "Ora e Brazilisë (Santarem)", + "America\/Santiago": "Ora e Kilit (Santiago)", + "America\/Santo_Domingo": "Ora e Atlantikut (Santo-Domingo)", + "America\/Sao_Paulo": "Ora e Brazilisë (Sao-Paulo)", + "America\/Scoresbysund": "Ora e Grenlandës Lindore (Itokorturmit)", + "America\/Sitka": "Ora e Alaskës (Sitka)", + "America\/St_Barthelemy": "Ora e Atlantikut (Sen-Bartelemi)", + "America\/St_Johns": "Ora e Njufaundlendit [Tokës së Re] (Shën-Gjon)", + "America\/St_Kitts": "Ora e Atlantikut (Shën-Kits)", + "America\/St_Lucia": "Ora e Atlantikut (Shën-Luçia)", + "America\/St_Thomas": "Ora e Atlantikut (Shën-Tomas)", + "America\/St_Vincent": "Ora e Atlantikut (Shën-Vincent)", + "America\/Swift_Current": "Ora e SHBA-së Qendrore (Rryma e Shpejtë)", + "America\/Tegucigalpa": "Ora e SHBA-së Qendrore (Tegusigalpa)", + "America\/Thule": "Ora e Atlantikut (Dhule)", + "America\/Thunder_Bay": "Ora e SHBA-së Lindore (Gjiri i Bubullimës)", + "America\/Tijuana": "Ora e Territoreve Amerikane të Bregut të Paqësorit (Tihuana)", + "America\/Toronto": "Ora e SHBA-së Lindore (Toronto)", + "America\/Tortola": "Ora e Atlantikut (Tortolë)", + "America\/Vancouver": "Ora e Territoreve Amerikane të Bregut të Paqësorit (Vankuver)", + "America\/Whitehorse": "Ora e Territoreve Amerikane të Bregut të Paqësorit (Uajt’hors)", + "America\/Winnipeg": "Ora e SHBA-së Qendrore (Uinipeg)", + "America\/Yakutat": "Ora e Alaskës (Jakutat)", + "America\/Yellowknife": "Ora e Territoreve Amerikane të Brezit Malor (Jellounajf)", + "Antarctica\/Casey": "Ora e Australisë Perëndimore (Kejsi)", + "Antarctica\/Davis": "Ora e Dejvisit (Dejvis)", + "Antarctica\/DumontDUrville": "Ora e Dumont-d’Urvilës (Dumont-d’Urvilë)", + "Antarctica\/Macquarie": "Ora e Ishullit Makuari (Mekuari)", + "Antarctica\/Mawson": "Ora e Mausonit (Mauson)", + "Antarctica\/McMurdo": "Ora e Zelandës së Re (Mekmurdo)", + "Antarctica\/Palmer": "Ora e Kilit (Palmer)", + "Antarctica\/Rothera": "Ora e Rodherës (Rodherë)", + "Antarctica\/Syowa": "Ora e Sjouit (Sjoua)", + "Antarctica\/Troll": "Ora e Grinuiçit (Troll)", + "Antarctica\/Vostok": "Ora e Vostokut (Vostok)", + "Arctic\/Longyearbyen": "Ora e Evropës Qendrore (Long’jëbjen)", + "Asia\/Aden": "Ora arabe (Aden)", + "Asia\/Almaty": "Ora e Kazakistanit Lindor (Almati)", + "Asia\/Amman": "Ora e Evropës Lindore (Aman)", + "Asia\/Anadyr": "Ora e Anadirit (Anadir)", + "Asia\/Aqtau": "Ora e Kazakistanit Perëndimor (Aktau)", + "Asia\/Aqtobe": "Ora e Kazakistanit Perëndimor (Aktobe)", + "Asia\/Ashgabat": "Ora e Turkmenistanit (Ashgabat)", + "Asia\/Atyrau": "Ora e Kazakistanit Perëndimor (Atirau)", + "Asia\/Baghdad": "Ora arabe (Bagdad)", + "Asia\/Bahrain": "Ora arabe (Bahrejn)", + "Asia\/Baku": "Ora e Azerbajxhanit (Baku)", + "Asia\/Bangkok": "Ora e Indokinës (Bangkok)", + "Asia\/Beirut": "Ora e Evropës Lindore (Bejrut)", + "Asia\/Bishkek": "Ora e Kirgizisë (Bishkek)", + "Asia\/Brunei": "Ora e Brunei-Durasalamit (Brunei)", + "Asia\/Calcutta": "Ora standarde e Indisë (Kalkutë)", + "Asia\/Chita": "Ora e Jakutskut (Çita)", + "Asia\/Choibalsan": "Ora e Çoibalsanit (Çoibalsan)", + "Asia\/Colombo": "Ora standarde e Indisë (Kolombo)", + "Asia\/Damascus": "Ora e Evropës Lindore (Damask)", + "Asia\/Dhaka": "Ora e Bangladeshit (Daka)", + "Asia\/Dili": "Ora e Timorit Lindor (Dili)", + "Asia\/Dubai": "Ora e Gjirit (Dubai)", + "Asia\/Dushanbe": "Ora e Taxhikistanit (Dushanbe)", + "Asia\/Famagusta": "Ora e Evropës Lindore (Famagustë)", + "Asia\/Gaza": "Ora e Evropës Lindore (Gaza)", + "Asia\/Hebron": "Ora e Evropës Lindore (Hebron)", + "Asia\/Hong_Kong": "Ora e Hong-Kongut (Hong-Kong)", + "Asia\/Hovd": "Ora e Hovdit (Hovd)", + "Asia\/Irkutsk": "Ora e Irkutskut (Irkutsk)", + "Asia\/Jakarta": "Ora e Indonezisë Perëndimore (Xhakartë)", + "Asia\/Jayapura": "Ora e Indonezisë Lindore (Xhajapurë)", + "Asia\/Jerusalem": "Ora e Izraelit (Jerusalem)", + "Asia\/Kabul": "Ora e Afganistanit (Kabul)", + "Asia\/Kamchatka": "Ora e Petropavllovsk-Kamçatkës (Kamçatkë)", + "Asia\/Karachi": "Ora e Pakistanit (Karaçi)", + "Asia\/Katmandu": "Ora e Nepalit (Katmandu)", + "Asia\/Khandyga": "Ora e Jakutskut (Kandigë)", + "Asia\/Krasnoyarsk": "Ora e Krasnojarskut (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Ora e Malajzisë (Kuala-Lumpur)", + "Asia\/Kuching": "Ora e Malajzisë (Kuçing)", + "Asia\/Kuwait": "Ora arabe (Kuvajt)", + "Asia\/Macau": "Ora e Kinës (Makao)", + "Asia\/Magadan": "Ora e Magadanit (Magadan)", + "Asia\/Makassar": "Ora e Indonezisë Qendrore (Makasar)", + "Asia\/Manila": "Ora e Filipineve (Manilë)", + "Asia\/Muscat": "Ora e Gjirit (Muskat)", + "Asia\/Nicosia": "Ora e Evropës Lindore (Nikozia)", + "Asia\/Novokuznetsk": "Ora e Krasnojarskut (Novokuznetsk)", + "Asia\/Novosibirsk": "Ora e Novosibirskut (Novosibirsk)", + "Asia\/Omsk": "Ora e Omskut (Omsk)", + "Asia\/Oral": "Ora e Kazakistanit Perëndimor (Oral)", + "Asia\/Phnom_Penh": "Ora e Indokinës (Pnom-Pen)", + "Asia\/Pontianak": "Ora e Indonezisë Perëndimore (Pontianak)", + "Asia\/Pyongyang": "Ora koreane (Penian)", + "Asia\/Qatar": "Ora arabe (Katar)", + "Asia\/Qostanay": "Ora e Kazakistanit Lindor (Qostanay)", + "Asia\/Qyzylorda": "Ora e Kazakistanit Perëndimor (Kizilorda)", + "Asia\/Rangoon": "Ora e Mianmarit (Rangun)", + "Asia\/Riyadh": "Ora arabe (Riad)", + "Asia\/Saigon": "Ora e Indokinës (Ho-Çi-Min)", + "Asia\/Sakhalin": "Ora e Sakalinit (Sakalin)", + "Asia\/Samarkand": "Ora e Uzbekistanit (Samarkand)", + "Asia\/Seoul": "Ora koreane (Seul)", + "Asia\/Shanghai": "Ora e Kinës (Shangai)", + "Asia\/Singapore": "Ora e Singaporit (Singapor)", + "Asia\/Srednekolymsk": "Ora e Magadanit (Srednekolimsk)", + "Asia\/Taipei": "Ora e Tajpeit (Tajpej)", + "Asia\/Tashkent": "Ora e Uzbekistanit (Tashkent)", + "Asia\/Tbilisi": "Ora e Gjeorgjisë (Tbilis)", + "Asia\/Tehran": "Ora e Iranit (Teheran)", + "Asia\/Thimphu": "Ora e Butanit (Thimpu)", + "Asia\/Tokyo": "Ora e Japonisë (Tokio)", + "Asia\/Ulaanbaatar": "Ora e Ulan-Batorit (Ulanbatar)", + "Asia\/Ust-Nera": "Ora e Vladivostokut (Ust-Nera)", + "Asia\/Vientiane": "Ora e Indokinës (Vjentianë)", + "Asia\/Vladivostok": "Ora e Vladivostokut (Vladivostok)", + "Asia\/Yakutsk": "Ora e Jakutskut (Jakutsk)", + "Asia\/Yekaterinburg": "Ora e Ekaterinburgut (Ekaterinburg)", + "Asia\/Yerevan": "Ora e Armenisë (Jerevan)", + "Atlantic\/Azores": "Ora e Azoreve (Azore)", + "Atlantic\/Bermuda": "Ora e Atlantikut (Bermude)", + "Atlantic\/Canary": "Ora e Evropës Perëndimore (Kanari)", + "Atlantic\/Cape_Verde": "Ora e Kepit të Gjelbër (Kepi i Gjelbër)", + "Atlantic\/Faeroe": "Ora e Evropës Perëndimore (Faroe)", + "Atlantic\/Madeira": "Ora e Evropës Perëndimore (Madeira)", + "Atlantic\/Reykjavik": "Ora e Grinuiçit (Reikjavik)", + "Atlantic\/South_Georgia": "Ora e Xhorxhas të Jugut (Xhorxha e Jugut)", + "Atlantic\/St_Helena": "Ora e Grinuiçit (Shën-Elenë)", + "Atlantic\/Stanley": "Ora e Ishujve Falkland (Stenli)", + "Australia\/Adelaide": "Ora e Australisë Qendrore (Adelajde)", + "Australia\/Brisbane": "Ora e Australisë Lindore (Brisbejn)", + "Australia\/Broken_Hill": "Ora e Australisë Qendrore (Brokën-Hill)", + "Australia\/Currie": "Ora e Australisë Lindore (Kuri)", + "Australia\/Darwin": "Ora e Australisë Qendrore (Darvin)", + "Australia\/Eucla": "Ora e Australisë Qendroro-Perëndimore (Eukla)", + "Australia\/Hobart": "Ora e Australisë Lindore (Hobart)", + "Australia\/Lindeman": "Ora e Australisë Lindore (Lindëmen)", + "Australia\/Lord_Howe": "Ora e Lord-Houit (Lord-Houi)", + "Australia\/Melbourne": "Ora e Australisë Lindore (Melburn)", + "Australia\/Perth": "Ora e Australisë Perëndimore (Përth)", + "Australia\/Sydney": "Ora e Australisë Lindore (Sidnej)", + "CST6CDT": "Ora e SHBA-së Qendrore", + "EST5EDT": "Ora e SHBA-së Lindore", + "Etc\/GMT": "Ora e Grinuiçit", + "Etc\/UTC": "Ora universale e koordinuar", + "Europe\/Amsterdam": "Ora e Evropës Qendrore (Amsterdam)", + "Europe\/Andorra": "Ora e Evropës Qendrore (Andorrë)", + "Europe\/Astrakhan": "Ora e Moskës (Astrakan)", + "Europe\/Athens": "Ora e Evropës Lindore (Athinë)", + "Europe\/Belgrade": "Ora e Evropës Qendrore (Beograd)", + "Europe\/Berlin": "Ora e Evropës Qendrore (Berlin)", + "Europe\/Bratislava": "Ora e Evropës Qendrore (Bratislavë)", + "Europe\/Brussels": "Ora e Evropës Qendrore (Bruksel)", + "Europe\/Bucharest": "Ora e Evropës Lindore (Bukuresht)", + "Europe\/Budapest": "Ora e Evropës Qendrore (Budapest)", + "Europe\/Busingen": "Ora e Evropës Qendrore (Busingen)", + "Europe\/Chisinau": "Ora e Evropës Lindore (Kishineu)", + "Europe\/Copenhagen": "Ora e Evropës Qendrore (Kopenhagen)", + "Europe\/Dublin": "Ora e Grinuiçit (Dublin)", + "Europe\/Gibraltar": "Ora e Evropës Qendrore (Gjibraltar)", + "Europe\/Guernsey": "Ora e Grinuiçit (Gernsej)", + "Europe\/Helsinki": "Ora e Evropës Lindore (Helsinki)", + "Europe\/Isle_of_Man": "Ora e Grinuiçit (Ishulli i Manit)", + "Europe\/Jersey": "Ora e Grinuiçit (Xhersej)", + "Europe\/Kaliningrad": "Ora e Evropës Lindore (Kaliningrad)", + "Europe\/Kiev": "Ora e Evropës Lindore (Kiev)", + "Europe\/Lisbon": "Ora e Evropës Perëndimore (Lisbonë)", + "Europe\/Ljubljana": "Ora e Evropës Qendrore (Lubjanë)", + "Europe\/London": "Ora e Grinuiçit (Londër)", + "Europe\/Luxembourg": "Ora e Evropës Qendrore (Luksemburg)", + "Europe\/Madrid": "Ora e Evropës Qendrore (Madrid)", + "Europe\/Malta": "Ora e Evropës Qendrore (Maltë)", + "Europe\/Mariehamn": "Ora e Evropës Lindore (Mariehamn)", + "Europe\/Minsk": "Ora e Moskës (Minsk)", + "Europe\/Monaco": "Ora e Evropës Qendrore (Monako)", + "Europe\/Moscow": "Ora e Moskës (Moskë)", + "Europe\/Oslo": "Ora e Evropës Qendrore (Oslo)", + "Europe\/Paris": "Ora e Evropës Qendrore (Paris)", + "Europe\/Podgorica": "Ora e Evropës Qendrore (Podgoricë)", + "Europe\/Prague": "Ora e Evropës Qendrore (Pragë)", + "Europe\/Riga": "Ora e Evropës Lindore (Rigë)", + "Europe\/Rome": "Ora e Evropës Qendrore (Romë)", + "Europe\/Samara": "Ora e Samarës (Samara)", + "Europe\/San_Marino": "Ora e Evropës Qendrore (San-Marino)", + "Europe\/Sarajevo": "Ora e Evropës Qendrore (Sarajevë)", + "Europe\/Saratov": "Ora e Moskës (Saratov)", + "Europe\/Simferopol": "Ora e Moskës (Simferopol)", + "Europe\/Skopje": "Ora e Evropës Qendrore (Shkup)", + "Europe\/Sofia": "Ora e Evropës Lindore (Sofje)", + "Europe\/Stockholm": "Ora e Evropës Qendrore (Stokholm)", + "Europe\/Tallinn": "Ora e Evropës Lindore (Talin)", + "Europe\/Tirane": "Ora e Evropës Qendrore (Tiranë)", + "Europe\/Ulyanovsk": "Ora e Moskës (Uljanovsk)", + "Europe\/Uzhgorod": "Ora e Evropës Lindore (Uzhgorod)", + "Europe\/Vaduz": "Ora e Evropës Qendrore (Vaduz)", + "Europe\/Vatican": "Ora e Evropës Qendrore (Vatikan)", + "Europe\/Vienna": "Ora e Evropës Qendrore (Vjenë)", + "Europe\/Vilnius": "Ora e Evropës Lindore (Vilnius)", + "Europe\/Volgograd": "Ora e Volgogradit (Volgograd)", + "Europe\/Warsaw": "Ora e Evropës Qendrore (Varshavë)", + "Europe\/Zagreb": "Ora e Evropës Qendrore (Zagreb)", + "Europe\/Zaporozhye": "Ora e Evropës Lindore (Zaporozhje)", + "Europe\/Zurich": "Ora e Evropës Qendrore (Zyrih)", + "Indian\/Antananarivo": "Ora e Afrikës Lindore (Antananarivo)", + "Indian\/Chagos": "Ora e Oqeanit Indian (Çagos)", + "Indian\/Christmas": "Ora e Ishullit të Krishtlindjeve (Krishtlindje)", + "Indian\/Cocos": "Ora e Ishujve Kokos (Kokos)", + "Indian\/Comoro": "Ora e Afrikës Lindore (Komore)", + "Indian\/Kerguelen": "Ora e Territoreve Jugore dhe Antarktike Franceze (Kerguelen)", + "Indian\/Mahe": "Ora e Sejshelleve (Mahe)", + "Indian\/Maldives": "Ora e Maldiveve (Maldive)", + "Indian\/Mauritius": "Ora e Mauritiusit (Mauritius)", + "Indian\/Mayotte": "Ora e Afrikës Lindore (Majotë)", + "Indian\/Reunion": "Ora e Reunionit (Reunion)", + "MST7MDT": "Ora e Territoreve Amerikane të Brezit Malor", + "PST8PDT": "Ora e Territoreve Amerikane të Bregut të Paqësorit", + "Pacific\/Apia": "Ora e Apias (Apia)", + "Pacific\/Auckland": "Ora e Zelandës së Re (Okland)", + "Pacific\/Bougainville": "Ora e Guinesë së Re-Papua (Bunganvilë)", + "Pacific\/Chatham": "Ora e Katamit (Çatman)", + "Pacific\/Easter": "Ora e Ishullit të Pashkës (Pashkë)", + "Pacific\/Efate": "Ora e Vanuatusë (Efate)", + "Pacific\/Enderbury": "Ora e Ishujve Feniks (Enderbur)", + "Pacific\/Fakaofo": "Ora e Tokelaut (Fakaofo)", + "Pacific\/Fiji": "Ora e Fixhit (Fixhi)", + "Pacific\/Funafuti": "Ora e Tuvalusë (Funafuti)", + "Pacific\/Galapagos": "Ora e Galapagosit (Galapagos)", + "Pacific\/Gambier": "Ora e Gambierit (Gambier)", + "Pacific\/Guadalcanal": "Ora e Ishujve Solomon (Guadalkanal)", + "Pacific\/Guam": "Ora e Kamorros (Guam)", + "Pacific\/Honolulu": "Ora e Ishujve Hauai-Aleutian (Honolulu)", + "Pacific\/Johnston": "Ora e Ishujve Hauai-Aleutian (Xhonston)", + "Pacific\/Kiritimati": "Ora e Ishujve Sporadikë Ekuatorialë (Kiritimat)", + "Pacific\/Kosrae": "Ora e Kosrës (Kosre)", + "Pacific\/Kwajalein": "Ora e Ishujve Marshall (Kuaxhalein)", + "Pacific\/Majuro": "Ora e Ishujve Marshall (Mahuro)", + "Pacific\/Marquesas": "Ora e Ishujve Markezë (Markez)", + "Pacific\/Midway": "Ora e Samoas (Miduej)", + "Pacific\/Nauru": "Ora e Naurusë (Nauru)", + "Pacific\/Niue": "Ora e Niuesë (Niue)", + "Pacific\/Norfolk": "Ora e Ishullit Norfolk (Norfolk)", + "Pacific\/Noumea": "Ora e Kaledonisë së Re (Noumea)", + "Pacific\/Pago_Pago": "Ora e Samoas (Pago-Pago)", + "Pacific\/Palau": "Ora e Palaut (Palau)", + "Pacific\/Pitcairn": "Ora e Pitkernit (Pitkern)", + "Pacific\/Ponape": "Ora e Ponapeit (Ponapei)", + "Pacific\/Port_Moresby": "Ora e Guinesë së Re-Papua (Port-Moresbi)", + "Pacific\/Rarotonga": "Ora e Ishujve Kuk (Rarotongë)", + "Pacific\/Saipan": "Ora e Kamorros (Saipan)", + "Pacific\/Tahiti": "Ora e Tahitit (Tahiti)", + "Pacific\/Tarawa": "Ora e Ishujve Gilbert (Taravë)", + "Pacific\/Tongatapu": "Ora e Tongës (Tongatapu)", + "Pacific\/Truk": "Ora e Çukut (Çuk)", + "Pacific\/Wake": "Ora e Ishullit Uejk (Uejk)", + "Pacific\/Wallis": "Ora e Uollisit dhe Futunës (Uollis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sr.json b/src/Symfony/Component/Intl/Resources/data/timezones/sr.json new file mode 100644 index 0000000000000..8733823eebdbb --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sr.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Средње време по Гриничу (Абиџан)", + "Africa\/Accra": "Средње време по Гриничу (Акра)", + "Africa\/Addis_Ababa": "Источно-афричко време (Адис Абеба)", + "Africa\/Algiers": "Средњеевропско време (Алжир)", + "Africa\/Asmera": "Источно-афричко време (Асмера)", + "Africa\/Bamako": "Средње време по Гриничу (Бамако)", + "Africa\/Bangui": "Западно-афричко време (Бангуи)", + "Africa\/Banjul": "Средње време по Гриничу (Банжул)", + "Africa\/Bissau": "Средње време по Гриничу (Бисао)", + "Africa\/Blantyre": "Централно-афричко време (Блантир)", + "Africa\/Brazzaville": "Западно-афричко време (Бразавил)", + "Africa\/Bujumbura": "Централно-афричко време (Буџумбура)", + "Africa\/Cairo": "Источноевропско време (Каиро)", + "Africa\/Casablanca": "Западноевропско време (Казабланка)", + "Africa\/Ceuta": "Средњеевропско време (Сеута)", + "Africa\/Conakry": "Средње време по Гриничу (Конакри)", + "Africa\/Dakar": "Средње време по Гриничу (Дакар)", + "Africa\/Dar_es_Salaam": "Источно-афричко време (Дар-ес-Салам)", + "Africa\/Djibouti": "Источно-афричко време (Џибути)", + "Africa\/Douala": "Западно-афричко време (Дуала)", + "Africa\/El_Aaiun": "Западноевропско време (Ел Ајун)", + "Africa\/Freetown": "Средње време по Гриничу (Фритаун)", + "Africa\/Gaborone": "Централно-афричко време (Габорон)", + "Africa\/Harare": "Централно-афричко време (Хараре)", + "Africa\/Johannesburg": "Јужно-афричко време (Јоханесбург)", + "Africa\/Juba": "Источно-афричко време (Џуба)", + "Africa\/Kampala": "Источно-афричко време (Кампала)", + "Africa\/Khartoum": "Централно-афричко време (Картум)", + "Africa\/Kigali": "Централно-афричко време (Кигали)", + "Africa\/Kinshasa": "Западно-афричко време (Киншаса)", + "Africa\/Lagos": "Западно-афричко време (Лагос)", + "Africa\/Libreville": "Западно-афричко време (Либревил)", + "Africa\/Lome": "Средње време по Гриничу (Ломе)", + "Africa\/Luanda": "Западно-афричко време (Луанда)", + "Africa\/Lubumbashi": "Централно-афричко време (Лубумбаши)", + "Africa\/Lusaka": "Централно-афричко време (Лусака)", + "Africa\/Malabo": "Западно-афричко време (Малабо)", + "Africa\/Maputo": "Централно-афричко време (Мапуто)", + "Africa\/Maseru": "Јужно-афричко време (Масеру)", + "Africa\/Mbabane": "Јужно-афричко време (Мбабане)", + "Africa\/Mogadishu": "Источно-афричко време (Могадиш)", + "Africa\/Monrovia": "Средње време по Гриничу (Монровија)", + "Africa\/Nairobi": "Источно-афричко време (Најроби)", + "Africa\/Ndjamena": "Западно-афричко време (Нџамена)", + "Africa\/Niamey": "Западно-афричко време (Нијамеј)", + "Africa\/Nouakchott": "Средње време по Гриничу (Нуакшот)", + "Africa\/Ouagadougou": "Средње време по Гриничу (Уагадугу)", + "Africa\/Porto-Novo": "Западно-афричко време (Порто Ново)", + "Africa\/Sao_Tome": "Средње време по Гриничу (Сао Томе)", + "Africa\/Tripoli": "Источноевропско време (Триполи)", + "Africa\/Tunis": "Средњеевропско време (Тунис)", + "Africa\/Windhoek": "Централно-афричко време (Виндхук)", + "America\/Adak": "Хавајско-алеутско време (Адак)", + "America\/Anchorage": "Аљаска (Енкориџ)", + "America\/Anguilla": "Атлантско време (Ангвила)", + "America\/Antigua": "Атлантско време (Антигва)", + "America\/Araguaina": "Бразилија време (Арагвајана)", + "America\/Argentina\/La_Rioja": "Аргентина време (Ла Риоха)", + "America\/Argentina\/Rio_Gallegos": "Аргентина време (Рио Гаљегос)", + "America\/Argentina\/Salta": "Аргентина време (Салта)", + "America\/Argentina\/San_Juan": "Аргентина време (Сан Хуан)", + "America\/Argentina\/San_Luis": "Западна Аргентина време (Сан Луи)", + "America\/Argentina\/Tucuman": "Аргентина време (Тукуман)", + "America\/Argentina\/Ushuaia": "Аргентина време (Ушуаија)", + "America\/Aruba": "Атлантско време (Аруба)", + "America\/Asuncion": "Парагвај време (Асунсион)", + "America\/Bahia": "Бразилија време (Баија)", + "America\/Bahia_Banderas": "Северноамеричко централно време (Баија Бандерас)", + "America\/Barbados": "Атлантско време (Барбадос)", + "America\/Belem": "Бразилија време (Белем)", + "America\/Belize": "Северноамеричко централно време (Белизе)", + "America\/Blanc-Sablon": "Атлантско време (Бланк-Сејблон)", + "America\/Boa_Vista": "Амазон време (Боа Виста)", + "America\/Bogota": "Колумбија време (Богота)", + "America\/Boise": "Северноамеричко планинско време (Бојзи)", + "America\/Buenos_Aires": "Аргентина време (Буенос Ајрес)", + "America\/Cambridge_Bay": "Северноамеричко планинско време (Кембриџ Беј)", + "America\/Campo_Grande": "Амазон време (Кампо Гранде)", + "America\/Cancun": "Северноамеричко источно време (Канкун)", + "America\/Caracas": "Венецуела време (Каракас)", + "America\/Catamarca": "Аргентина време (Катамарка)", + "America\/Cayenne": "Француска Гвајана време (Кајен)", + "America\/Cayman": "Северноамеричко источно време (Кајманска Острва)", + "America\/Chicago": "Северноамеричко централно време (Чикаго)", + "America\/Chihuahua": "Мексички Пацифик (Чихуахуа)", + "America\/Coral_Harbour": "Северноамеричко источно време (Корал Харбур)", + "America\/Cordoba": "Аргентина време (Кордоба)", + "America\/Costa_Rica": "Северноамеричко централно време (Костарика)", + "America\/Creston": "Северноамеричко планинско време (Крестон)", + "America\/Cuiaba": "Амазон време (Куиаба)", + "America\/Curacao": "Атлантско време (Кирасо)", + "America\/Danmarkshavn": "Средње време по Гриничу (Данмарксхаген)", + "America\/Dawson": "Северноамеричко пацифичко време (Досон)", + "America\/Dawson_Creek": "Северноамеричко планинско време (Досон Крик)", + "America\/Denver": "Северноамеричко планинско време (Денвер)", + "America\/Detroit": "Северноамеричко источно време (Детроит)", + "America\/Dominica": "Атлантско време (Доминика)", + "America\/Edmonton": "Северноамеричко планинско време (Едмонтон)", + "America\/Eirunepe": "Акре време (Еирунепе)", + "America\/El_Salvador": "Северноамеричко централно време (Салвадор)", + "America\/Fort_Nelson": "Северноамеричко планинско време (Форт Нелсон)", + "America\/Fortaleza": "Бразилија време (Форталеза)", + "America\/Glace_Bay": "Атлантско време (Глејс Беј)", + "America\/Godthab": "Западни Гренланд (Готхаб)", + "America\/Goose_Bay": "Атлантско време (Гус Беј)", + "America\/Grand_Turk": "Северноамеричко источно време (Гранд Турк)", + "America\/Grenada": "Атлантско време (Гренада)", + "America\/Guadeloupe": "Атлантско време (Гвадалупе)", + "America\/Guatemala": "Северноамеричко централно време (Гватемала)", + "America\/Guayaquil": "Еквадор време (Гвајакил)", + "America\/Guyana": "Гвајана време (Гвајана)", + "America\/Halifax": "Атлантско време (Халифакс)", + "America\/Havana": "Куба (Хавана)", + "America\/Hermosillo": "Мексички Пацифик (Хермосиљо)", + "America\/Indiana\/Knox": "Северноамеричко централно време (Нокс, Индијана)", + "America\/Indiana\/Marengo": "Северноамеричко источно време (Маренго, Индијана)", + "America\/Indiana\/Petersburg": "Северноамеричко источно време (Питерсбург, Индијана)", + "America\/Indiana\/Tell_City": "Северноамеричко централно време (Тел Сити, Индијана)", + "America\/Indiana\/Vevay": "Северноамеричко источно време (Вевај, Индијана)", + "America\/Indiana\/Vincennes": "Северноамеричко источно време (Винценес, Индијана)", + "America\/Indiana\/Winamac": "Северноамеричко источно време (Винамак, Индијана)", + "America\/Indianapolis": "Северноамеричко источно време (Индианаполис)", + "America\/Inuvik": "Северноамеричко планинско време (Инувик)", + "America\/Iqaluit": "Северноамеричко источно време (Иквалуит)", + "America\/Jamaica": "Северноамеричко источно време (Јамајка)", + "America\/Jujuy": "Аргентина време (Жужуи)", + "America\/Juneau": "Аљаска (Жуно)", + "America\/Kentucky\/Monticello": "Северноамеричко источно време (Монтичело, Кентаки)", + "America\/Kralendijk": "Атлантско време (Кралендајк)", + "America\/La_Paz": "Боливија време (Ла Паз)", + "America\/Lima": "Перу време (Лима)", + "America\/Los_Angeles": "Северноамеричко пацифичко време (Лос Анђелес)", + "America\/Louisville": "Северноамеричко источно време (Луивиле)", + "America\/Lower_Princes": "Атлантско време (Лоуер Принсиз Квортер)", + "America\/Maceio": "Бразилија време (Масејо)", + "America\/Managua": "Северноамеричко централно време (Манагва)", + "America\/Manaus": "Амазон време (Манаус)", + "America\/Marigot": "Атлантско време (Мариго)", + "America\/Martinique": "Атлантско време (Мартиник)", + "America\/Matamoros": "Северноамеричко централно време (Матаморос)", + "America\/Mazatlan": "Мексички Пацифик (Мазатлан)", + "America\/Mendoza": "Аргентина време (Мендоса)", + "America\/Menominee": "Северноамеричко централно време (Меномини)", + "America\/Merida": "Северноамеричко централно време (Мерида)", + "America\/Metlakatla": "Аљаска (Метлакатла)", + "America\/Mexico_City": "Северноамеричко централно време (Мексико Сити)", + "America\/Miquelon": "Сен Пјер и Микелон (Микелон)", + "America\/Moncton": "Атлантско време (Монктон)", + "America\/Monterrey": "Северноамеричко централно време (Монтереј)", + "America\/Montevideo": "Уругвај време (Монтевидео)", + "America\/Montserrat": "Атлантско време (Монтсерат)", + "America\/Nassau": "Северноамеричко источно време (Насау)", + "America\/New_York": "Северноамеричко источно време (Њујорк)", + "America\/Nipigon": "Северноамеричко источно време (Нипигон)", + "America\/Nome": "Аљаска (Ном)", + "America\/Noronha": "Фернандо де Нороња време (Нороња)", + "America\/North_Dakota\/Beulah": "Северноамеричко централно време (Бијула, Северна Дакота)", + "America\/North_Dakota\/Center": "Северноамеричко централно време (Центар, Северна Дакота)", + "America\/North_Dakota\/New_Salem": "Северноамеричко централно време (Нови Салем, Северна Дакота)", + "America\/Ojinaga": "Северноамеричко планинско време (Охинага)", + "America\/Panama": "Северноамеричко источно време (Панама)", + "America\/Pangnirtung": "Северноамеричко источно време (Пангниртунг)", + "America\/Paramaribo": "Суринам време (Парамарибо)", + "America\/Phoenix": "Северноамеричко планинско време (Финикс)", + "America\/Port-au-Prince": "Северноамеричко источно време (Порт о Пренс)", + "America\/Port_of_Spain": "Атлантско време (Порт оф Спејн)", + "America\/Porto_Velho": "Амазон време (Порто Вељо)", + "America\/Puerto_Rico": "Атлантско време (Порто Рико)", + "America\/Punta_Arenas": "Чиле време (Пунта Аренас)", + "America\/Rainy_River": "Северноамеричко централно време (Рејни Ривер)", + "America\/Rankin_Inlet": "Северноамеричко централно време (Ранкин Инлет)", + "America\/Recife": "Бразилија време (Ресифе)", + "America\/Regina": "Северноамеричко централно време (Регина)", + "America\/Resolute": "Северноамеричко централно време (Ресолут)", + "America\/Rio_Branco": "Акре време (Рио Бранко)", + "America\/Santa_Isabel": "Северозападни Мексико (Санта Изабел)", + "America\/Santarem": "Бразилија време (Сантарем)", + "America\/Santiago": "Чиле време (Сантјаго)", + "America\/Santo_Domingo": "Атлантско време (Санто Доминго)", + "America\/Sao_Paulo": "Бразилија време (Сао Паоло)", + "America\/Scoresbysund": "Источни Гренланд (Скорезбисунд)", + "America\/Sitka": "Аљаска (Ситка)", + "America\/St_Barthelemy": "Атлантско време (Св. Бартоломeј)", + "America\/St_Johns": "Њуфаундленд (Св. Џон)", + "America\/St_Kitts": "Атлантско време (Сент Китс)", + "America\/St_Lucia": "Атлантско време (Св. Луција)", + "America\/St_Thomas": "Атлантско време (Св. Тома)", + "America\/St_Vincent": "Атлантско време (Сент Винсент)", + "America\/Swift_Current": "Северноамеричко централно време (Свифт Курент)", + "America\/Tegucigalpa": "Северноамеричко централно време (Тегусигалпа)", + "America\/Thule": "Атлантско време (Тул)", + "America\/Thunder_Bay": "Северноамеричко источно време (Тандер Беј)", + "America\/Tijuana": "Северноамеричко пацифичко време (Тихуана)", + "America\/Toronto": "Северноамеричко источно време (Торонто)", + "America\/Tortola": "Атлантско време (Тортола)", + "America\/Vancouver": "Северноамеричко пацифичко време (Ванкувер)", + "America\/Whitehorse": "Северноамеричко пацифичко време (Вајтхорс)", + "America\/Winnipeg": "Северноамеричко централно време (Винипег)", + "America\/Yakutat": "Аљаска (Јакутат)", + "America\/Yellowknife": "Северноамеричко планинско време (Јелоунајф)", + "Antarctica\/Casey": "Аустралијско западно време (Кејси)", + "Antarctica\/Davis": "Дејвис време (Дејвис)", + "Antarctica\/DumontDUrville": "Димон д’Урвил време (Димон д’Урвил)", + "Antarctica\/Macquarie": "Острво Маквери време (Меквори)", + "Antarctica\/Mawson": "Мосон време (Мосон)", + "Antarctica\/McMurdo": "Нови Зеланд време (Макмурдо)", + "Antarctica\/Palmer": "Чиле време (Палмер)", + "Antarctica\/Rothera": "Ротера време (Ротера)", + "Antarctica\/Syowa": "Шова време (Шова)", + "Antarctica\/Troll": "Средње време по Гриничу (Трол)", + "Antarctica\/Vostok": "Восток време (Восток)", + "Arctic\/Longyearbyen": "Средњеевропско време (Лонгјербјен)", + "Asia\/Aden": "Арабијско време (Аден)", + "Asia\/Almaty": "Источно-казахстанско време (Алмати)", + "Asia\/Amman": "Источноевропско време (Аман)", + "Asia\/Anadyr": "Анадир време (Анадир)", + "Asia\/Aqtau": "Западно-казахстанско време (Актау)", + "Asia\/Aqtobe": "Западно-казахстанско време (Акутобе)", + "Asia\/Ashgabat": "Туркменистан време (Ашхабад)", + "Asia\/Atyrau": "Западно-казахстанско време (Атирау)", + "Asia\/Baghdad": "Арабијско време (Багдад)", + "Asia\/Bahrain": "Арабијско време (Бахреин)", + "Asia\/Baku": "Азербејџан време (Баку)", + "Asia\/Bangkok": "Индокина време (Бангкок)", + "Asia\/Beirut": "Источноевропско време (Бејрут)", + "Asia\/Bishkek": "Киргистан време (Бишкек)", + "Asia\/Brunei": "Брунеј Дарусалум време (Брунеј)", + "Asia\/Calcutta": "Индијско стандардно време (Калкута)", + "Asia\/Chita": "Јакутск време (Чита)", + "Asia\/Choibalsan": "Чојбалсан време (Чојбалсан)", + "Asia\/Colombo": "Индијско стандардно време (Коломбо)", + "Asia\/Damascus": "Источноевропско време (Дамаск)", + "Asia\/Dhaka": "Бангладеш време (Дака)", + "Asia\/Dili": "Источни тимор време (Дили)", + "Asia\/Dubai": "Заливско време (Дубаи)", + "Asia\/Dushanbe": "Таџикистан време (Душанбе)", + "Asia\/Famagusta": "Источноевропско време (Фамагуста)", + "Asia\/Gaza": "Источноевропско време (Газа)", + "Asia\/Hebron": "Источноевропско време (Хеброн)", + "Asia\/Hong_Kong": "Хонг Конг време (Хонгконг)", + "Asia\/Hovd": "Ховд време (Ховд)", + "Asia\/Irkutsk": "Иркуцк време (Иркуцк)", + "Asia\/Jakarta": "Западно-индонезијско време (Џакарта)", + "Asia\/Jayapura": "Источно-индонезијско време (Џајапура)", + "Asia\/Jerusalem": "Израелско време (Јерусалим)", + "Asia\/Kabul": "Авганистан време (Кабул)", + "Asia\/Kamchatka": "Петропавловско-камчатско време (Камчатка)", + "Asia\/Karachi": "Пакистан време (Карачи)", + "Asia\/Katmandu": "Непал време (Катманду)", + "Asia\/Khandyga": "Јакутск време (Хандига)", + "Asia\/Krasnoyarsk": "Краснојарск време (Краснојарск)", + "Asia\/Kuala_Lumpur": "Малезија време (Куала Лумпур)", + "Asia\/Kuching": "Малезија време (Кучинг)", + "Asia\/Kuwait": "Арабијско време (Кувајт)", + "Asia\/Macau": "Кина време (Макао)", + "Asia\/Magadan": "Магадан време (Магадан)", + "Asia\/Makassar": "Централно-индонезијско време (Макасар)", + "Asia\/Manila": "Филипини време (Манила)", + "Asia\/Muscat": "Заливско време (Мускат)", + "Asia\/Nicosia": "Источноевропско време (Никозија)", + "Asia\/Novokuznetsk": "Краснојарск време (Новокузњецк)", + "Asia\/Novosibirsk": "Новосибирск време (Новосибирск)", + "Asia\/Omsk": "Омск време (Омск)", + "Asia\/Oral": "Западно-казахстанско време (Орал)", + "Asia\/Phnom_Penh": "Индокина време (Пном Пен)", + "Asia\/Pontianak": "Западно-индонезијско време (Понтијанак)", + "Asia\/Pyongyang": "Корејско време (Пјонгјанг)", + "Asia\/Qatar": "Арабијско време (Катар)", + "Asia\/Qostanay": "Источно-казахстанско време (Qostanay)", + "Asia\/Qyzylorda": "Западно-казахстанско време (Кизилорда)", + "Asia\/Rangoon": "Мијанмар време (Рангун)", + "Asia\/Riyadh": "Арабијско време (Ријад)", + "Asia\/Saigon": "Индокина време (Хо Ши Мин)", + "Asia\/Sakhalin": "Сахалин време (Сахалин)", + "Asia\/Samarkand": "Узбекистан време (Самарканд)", + "Asia\/Seoul": "Корејско време (Сеул)", + "Asia\/Shanghai": "Кина време (Шангај)", + "Asia\/Singapore": "Сингапур, стандардно време (Сингапур)", + "Asia\/Srednekolymsk": "Магадан време (Средњеколимск)", + "Asia\/Taipei": "Тајпеј време (Тајпеј)", + "Asia\/Tashkent": "Узбекистан време (Ташкент)", + "Asia\/Tbilisi": "Грузија време (Тбилиси)", + "Asia\/Tehran": "Иран време (Техеран)", + "Asia\/Thimphu": "Бутан време (Тимпу)", + "Asia\/Tokyo": "Јапанско време (Токио)", + "Asia\/Ulaanbaatar": "Улан Батор време (Улан Батор)", + "Asia\/Ust-Nera": "Владивосток време (Уст-Нера)", + "Asia\/Vientiane": "Индокина време (Вијентијан)", + "Asia\/Vladivostok": "Владивосток време (Владивосток)", + "Asia\/Yakutsk": "Јакутск време (Јакутск)", + "Asia\/Yekaterinburg": "Јекатеринбург време (Јекатеринбург)", + "Asia\/Yerevan": "Јерменија време (Јереван)", + "Atlantic\/Azores": "Азори време (Азори)", + "Atlantic\/Bermuda": "Атлантско време (Бермуда)", + "Atlantic\/Canary": "Западноевропско време (Канарска острва)", + "Atlantic\/Cape_Verde": "Зеленортска Острва време (Зеленортска Острва)", + "Atlantic\/Faeroe": "Западноевропско време (Фарска Острва)", + "Atlantic\/Madeira": "Западноевропско време (Мадеира)", + "Atlantic\/Reykjavik": "Средње време по Гриничу (Рејкјавик)", + "Atlantic\/South_Georgia": "Јужна Џорџија време (Јужна Џорџија)", + "Atlantic\/St_Helena": "Средње време по Гриничу (Света Јелена)", + "Atlantic\/Stanley": "Фолкландска Острва време (Стенли)", + "Australia\/Adelaide": "Аустралијско централно време (Аделејд)", + "Australia\/Brisbane": "Аустралијско источно време (Бризбејн)", + "Australia\/Broken_Hill": "Аустралијско централно време (Брокен Хил)", + "Australia\/Currie": "Аустралијско источно време (Кари)", + "Australia\/Darwin": "Аустралијско централно време (Дарвин)", + "Australia\/Eucla": "Аустралијско централно западно време (Иукла)", + "Australia\/Hobart": "Аустралијско источно време (Хобарт)", + "Australia\/Lindeman": "Аустралијско источно време (Линдеман)", + "Australia\/Lord_Howe": "Лорд Хов време (Лорд Хау)", + "Australia\/Melbourne": "Аустралијско источно време (Мелбурн)", + "Australia\/Perth": "Аустралијско западно време (Перт)", + "Australia\/Sydney": "Аустралијско источно време (Сиднеј)", + "CST6CDT": "Северноамеричко централно време", + "EST5EDT": "Северноамеричко источно време", + "Etc\/GMT": "Средње време по Гриничу", + "Etc\/UTC": "Координисано универзално време", + "Europe\/Amsterdam": "Средњеевропско време (Амстердам)", + "Europe\/Andorra": "Средњеевропско време (Андора)", + "Europe\/Astrakhan": "Москва време (Астракан)", + "Europe\/Athens": "Источноевропско време (Атина)", + "Europe\/Belgrade": "Средњеевропско време (Београд)", + "Europe\/Berlin": "Средњеевропско време (Берлин)", + "Europe\/Bratislava": "Средњеевропско време (Братислава)", + "Europe\/Brussels": "Средњеевропско време (Брисел)", + "Europe\/Bucharest": "Источноевропско време (Букурешт)", + "Europe\/Budapest": "Средњеевропско време (Будимпешта)", + "Europe\/Busingen": "Средњеевропско време (Бисинген)", + "Europe\/Chisinau": "Источноевропско време (Кишињев)", + "Europe\/Copenhagen": "Средњеевропско време (Копенхаген)", + "Europe\/Dublin": "Средње време по Гриничу (Даблин)", + "Europe\/Gibraltar": "Средњеевропско време (Гибралтар)", + "Europe\/Guernsey": "Средње време по Гриничу (Гернзи)", + "Europe\/Helsinki": "Источноевропско време (Хелсинки)", + "Europe\/Isle_of_Man": "Средње време по Гриничу (Острво Ман)", + "Europe\/Jersey": "Средње време по Гриничу (Џерси)", + "Europe\/Kaliningrad": "Источноевропско време (Калињинград)", + "Europe\/Kiev": "Источноевропско време (Кијев)", + "Europe\/Lisbon": "Западноевропско време (Лисабон)", + "Europe\/Ljubljana": "Средњеевропско време (Љубљана)", + "Europe\/London": "Средње време по Гриничу (Лондон)", + "Europe\/Luxembourg": "Средњеевропско време (Луксембург)", + "Europe\/Madrid": "Средњеевропско време (Мадрид)", + "Europe\/Malta": "Средњеевропско време (Малта)", + "Europe\/Mariehamn": "Источноевропско време (Марихамн)", + "Europe\/Minsk": "Москва време (Минск)", + "Europe\/Monaco": "Средњеевропско време (Монако)", + "Europe\/Moscow": "Москва време (Москва)", + "Europe\/Oslo": "Средњеевропско време (Осло)", + "Europe\/Paris": "Средњеевропско време (Париз)", + "Europe\/Podgorica": "Средњеевропско време (Подгорица)", + "Europe\/Prague": "Средњеевропско време (Праг)", + "Europe\/Riga": "Источноевропско време (Рига)", + "Europe\/Rome": "Средњеевропско време (Рим)", + "Europe\/Samara": "Самара време (Самара)", + "Europe\/San_Marino": "Средњеевропско време (Сан Марино)", + "Europe\/Sarajevo": "Средњеевропско време (Сарајево)", + "Europe\/Saratov": "Москва време (Саратов)", + "Europe\/Simferopol": "Москва време (Симферопољ)", + "Europe\/Skopje": "Средњеевропско време (Скопље)", + "Europe\/Sofia": "Источноевропско време (Софија)", + "Europe\/Stockholm": "Средњеевропско време (Стокхолм)", + "Europe\/Tallinn": "Источноевропско време (Талин)", + "Europe\/Tirane": "Средњеевропско време (Тирана)", + "Europe\/Ulyanovsk": "Москва време (Уљановск)", + "Europe\/Uzhgorod": "Источноевропско време (Ужгород)", + "Europe\/Vaduz": "Средњеевропско време (Вадуз)", + "Europe\/Vatican": "Средњеевропско време (Ватикан)", + "Europe\/Vienna": "Средњеевропско време (Беч)", + "Europe\/Vilnius": "Источноевропско време (Вилњус)", + "Europe\/Volgograd": "Волгоград време (Волгоград)", + "Europe\/Warsaw": "Средњеевропско време (Варшава)", + "Europe\/Zagreb": "Средњеевропско време (Загреб)", + "Europe\/Zaporozhye": "Источноевропско време (Запорожје)", + "Europe\/Zurich": "Средњеевропско време (Цирих)", + "Indian\/Antananarivo": "Источно-афричко време (Антананариво)", + "Indian\/Chagos": "Индијско океанско време (Чагос)", + "Indian\/Christmas": "Божићно острво време (Божић)", + "Indian\/Cocos": "Кокос (Келинг) Острва време (Кокос)", + "Indian\/Comoro": "Источно-афричко време (Коморо)", + "Indian\/Kerguelen": "Француско јужно и антарктичко време (Кергелен)", + "Indian\/Mahe": "Сејшели време (Махе)", + "Indian\/Maldives": "Малдиви време (Малдиви)", + "Indian\/Mauritius": "Маурицијус време (Маурицијус)", + "Indian\/Mayotte": "Источно-афричко време (Мајот)", + "Indian\/Reunion": "Реинион време (Реунион)", + "MST7MDT": "Северноамеричко планинско време", + "PST8PDT": "Северноамеричко пацифичко време", + "Pacific\/Apia": "Апија време (Апија)", + "Pacific\/Auckland": "Нови Зеланд време (Окланд)", + "Pacific\/Bougainville": "Папуа Нова Гвинеја време (Буганвил)", + "Pacific\/Chatham": "Чатам време (Чатам)", + "Pacific\/Easter": "Ускршња острва време (Ускршње острво)", + "Pacific\/Efate": "Вануату време (Ефат)", + "Pacific\/Enderbury": "Феникс острва време (Ендербери)", + "Pacific\/Fakaofo": "Токелау време (Факаофо)", + "Pacific\/Fiji": "Фиџи време (Фиџи)", + "Pacific\/Funafuti": "Тувалу време (Фунафути)", + "Pacific\/Galapagos": "Галапагос време (Галапагос)", + "Pacific\/Gambier": "Гамбије време (Гамбије)", + "Pacific\/Guadalcanal": "Соломонска Острва време (Гвадалканал)", + "Pacific\/Guam": "Чаморо време (Гуам)", + "Pacific\/Honolulu": "Хавајско-алеутско време (Хонолулу)", + "Pacific\/Johnston": "Хавајско-алеутско време (Џонстон)", + "Pacific\/Kiritimati": "Острва Лајн време (Киритимати)", + "Pacific\/Kosrae": "Кошре време (Кошре)", + "Pacific\/Kwajalein": "Маршалска Острва време (Кваџалејин)", + "Pacific\/Majuro": "Маршалска Острва време (Мајуро)", + "Pacific\/Marquesas": "Маркиз време (Маркиз)", + "Pacific\/Midway": "Самоа време (Мидвеј)", + "Pacific\/Nauru": "Науру време (Науру)", + "Pacific\/Niue": "Ниуе време (Ниуе)", + "Pacific\/Norfolk": "Норфолк Острво време (Норфолк)", + "Pacific\/Noumea": "Нова Каледонија време (Нумеа)", + "Pacific\/Pago_Pago": "Самоа време (Паго Паго)", + "Pacific\/Palau": "Палау време (Палау)", + "Pacific\/Pitcairn": "Питкерн време (Питкерн)", + "Pacific\/Ponape": "Понпеј време (Понапе)", + "Pacific\/Port_Moresby": "Папуа Нова Гвинеја време (Порт Морзби)", + "Pacific\/Rarotonga": "Кукова острва време (Раротонга)", + "Pacific\/Saipan": "Чаморо време (Сајпан)", + "Pacific\/Tahiti": "Тахити време (Тахити)", + "Pacific\/Tarawa": "Гилберт острва време (Тарава)", + "Pacific\/Tongatapu": "Тонга време (Тонгатапу)", + "Pacific\/Truk": "Чуук време (Трук)", + "Pacific\/Wake": "Вејк острво време (Вејк)", + "Pacific\/Wallis": "Валис и Футуна Острва време (Валис)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sr_Latn.json b/src/Symfony/Component/Intl/Resources/data/timezones/sr_Latn.json new file mode 100644 index 0000000000000..5622892f4b22a --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sr_Latn.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.77", + "Names": { + "Africa\/Abidjan": "Srednje vreme po Griniču (Abidžan)", + "Africa\/Accra": "Srednje vreme po Griniču (Akra)", + "Africa\/Addis_Ababa": "Istočno-afričko vreme (Adis Abeba)", + "Africa\/Algiers": "Srednjeevropsko vreme (Alžir)", + "Africa\/Asmera": "Istočno-afričko vreme (Asmera)", + "Africa\/Bamako": "Srednje vreme po Griniču (Bamako)", + "Africa\/Bangui": "Zapadno-afričko vreme (Bangui)", + "Africa\/Banjul": "Srednje vreme po Griniču (Banžul)", + "Africa\/Bissau": "Srednje vreme po Griniču (Bisao)", + "Africa\/Blantyre": "Centralno-afričko vreme (Blantir)", + "Africa\/Brazzaville": "Zapadno-afričko vreme (Brazavil)", + "Africa\/Bujumbura": "Centralno-afričko vreme (Budžumbura)", + "Africa\/Cairo": "Istočnoevropsko vreme (Kairo)", + "Africa\/Casablanca": "Zapadnoevropsko vreme (Kazablanka)", + "Africa\/Ceuta": "Srednjeevropsko vreme (Seuta)", + "Africa\/Conakry": "Srednje vreme po Griniču (Konakri)", + "Africa\/Dakar": "Srednje vreme po Griniču (Dakar)", + "Africa\/Dar_es_Salaam": "Istočno-afričko vreme (Dar-es-Salam)", + "Africa\/Djibouti": "Istočno-afričko vreme (Džibuti)", + "Africa\/Douala": "Zapadno-afričko vreme (Duala)", + "Africa\/El_Aaiun": "Zapadnoevropsko vreme (El Ajun)", + "Africa\/Freetown": "Srednje vreme po Griniču (Fritaun)", + "Africa\/Gaborone": "Centralno-afričko vreme (Gaboron)", + "Africa\/Harare": "Centralno-afričko vreme (Harare)", + "Africa\/Johannesburg": "Južno-afričko vreme (Johanesburg)", + "Africa\/Juba": "Istočno-afričko vreme (Džuba)", + "Africa\/Kampala": "Istočno-afričko vreme (Kampala)", + "Africa\/Khartoum": "Centralno-afričko vreme (Kartum)", + "Africa\/Kigali": "Centralno-afričko vreme (Kigali)", + "Africa\/Kinshasa": "Zapadno-afričko vreme (Kinšasa)", + "Africa\/Lagos": "Zapadno-afričko vreme (Lagos)", + "Africa\/Libreville": "Zapadno-afričko vreme (Librevil)", + "Africa\/Lome": "Srednje vreme po Griniču (Lome)", + "Africa\/Luanda": "Zapadno-afričko vreme (Luanda)", + "Africa\/Lubumbashi": "Centralno-afričko vreme (Lubumbaši)", + "Africa\/Lusaka": "Centralno-afričko vreme (Lusaka)", + "Africa\/Malabo": "Zapadno-afričko vreme (Malabo)", + "Africa\/Maputo": "Centralno-afričko vreme (Maputo)", + "Africa\/Maseru": "Južno-afričko vreme (Maseru)", + "Africa\/Mbabane": "Južno-afričko vreme (Mbabane)", + "Africa\/Mogadishu": "Istočno-afričko vreme (Mogadiš)", + "Africa\/Monrovia": "Srednje vreme po Griniču (Monrovija)", + "Africa\/Nairobi": "Istočno-afričko vreme (Najrobi)", + "Africa\/Ndjamena": "Zapadno-afričko vreme (Ndžamena)", + "Africa\/Niamey": "Zapadno-afričko vreme (Nijamej)", + "Africa\/Nouakchott": "Srednje vreme po Griniču (Nuakšot)", + "Africa\/Ouagadougou": "Srednje vreme po Griniču (Uagadugu)", + "Africa\/Porto-Novo": "Zapadno-afričko vreme (Porto Novo)", + "Africa\/Sao_Tome": "Srednje vreme po Griniču (Sao Tome)", + "Africa\/Tripoli": "Istočnoevropsko vreme (Tripoli)", + "Africa\/Tunis": "Srednjeevropsko vreme (Tunis)", + "Africa\/Windhoek": "Centralno-afričko vreme (Vindhuk)", + "America\/Adak": "Havajsko-aleutsko vreme (Adak)", + "America\/Anchorage": "Aljaska (Enkoridž)", + "America\/Anguilla": "Atlantsko vreme (Angvila)", + "America\/Antigua": "Atlantsko vreme (Antigva)", + "America\/Araguaina": "Brazilija vreme (Aragvajana)", + "America\/Argentina\/La_Rioja": "Argentina vreme (La Rioha)", + "America\/Argentina\/Rio_Gallegos": "Argentina vreme (Rio Galjegos)", + "America\/Argentina\/Salta": "Argentina vreme (Salta)", + "America\/Argentina\/San_Juan": "Argentina vreme (San Huan)", + "America\/Argentina\/San_Luis": "Zapadna Argentina vreme (San Lui)", + "America\/Argentina\/Tucuman": "Argentina vreme (Tukuman)", + "America\/Argentina\/Ushuaia": "Argentina vreme (Ušuaija)", + "America\/Aruba": "Atlantsko vreme (Aruba)", + "America\/Asuncion": "Paragvaj vreme (Asunsion)", + "America\/Bahia": "Brazilija vreme (Baija)", + "America\/Bahia_Banderas": "Severnoameričko centralno vreme (Baija Banderas)", + "America\/Barbados": "Atlantsko vreme (Barbados)", + "America\/Belem": "Brazilija vreme (Belem)", + "America\/Belize": "Severnoameričko centralno vreme (Belize)", + "America\/Blanc-Sablon": "Atlantsko vreme (Blank-Sejblon)", + "America\/Boa_Vista": "Amazon vreme (Boa Vista)", + "America\/Bogota": "Kolumbija vreme (Bogota)", + "America\/Boise": "Severnoameričko planinsko vreme (Bojzi)", + "America\/Buenos_Aires": "Argentina vreme (Buenos Ajres)", + "America\/Cambridge_Bay": "Severnoameričko planinsko vreme (Kembridž Bej)", + "America\/Campo_Grande": "Amazon vreme (Kampo Grande)", + "America\/Cancun": "Severnoameričko istočno vreme (Kankun)", + "America\/Caracas": "Venecuela vreme (Karakas)", + "America\/Catamarca": "Argentina vreme (Katamarka)", + "America\/Cayenne": "Francuska Gvajana vreme (Kajen)", + "America\/Cayman": "Severnoameričko istočno vreme (Kajmanska Ostrva)", + "America\/Chicago": "Severnoameričko centralno vreme (Čikago)", + "America\/Chihuahua": "Meksički Pacifik (Čihuahua)", + "America\/Coral_Harbour": "Severnoameričko istočno vreme (Koral Harbur)", + "America\/Cordoba": "Argentina vreme (Kordoba)", + "America\/Costa_Rica": "Severnoameričko centralno vreme (Kostarika)", + "America\/Creston": "Severnoameričko planinsko vreme (Kreston)", + "America\/Cuiaba": "Amazon vreme (Kuiaba)", + "America\/Curacao": "Atlantsko vreme (Kiraso)", + "America\/Danmarkshavn": "Srednje vreme po Griniču (Danmarkshagen)", + "America\/Dawson": "Severnoameričko pacifičko vreme (Doson)", + "America\/Dawson_Creek": "Severnoameričko planinsko vreme (Doson Krik)", + "America\/Denver": "Severnoameričko planinsko vreme (Denver)", + "America\/Detroit": "Severnoameričko istočno vreme (Detroit)", + "America\/Dominica": "Atlantsko vreme (Dominika)", + "America\/Edmonton": "Severnoameričko planinsko vreme (Edmonton)", + "America\/Eirunepe": "Akre vreme (Eirunepe)", + "America\/El_Salvador": "Severnoameričko centralno vreme (Salvador)", + "America\/Fort_Nelson": "Severnoameričko planinsko vreme (Fort Nelson)", + "America\/Fortaleza": "Brazilija vreme (Fortaleza)", + "America\/Glace_Bay": "Atlantsko vreme (Glejs Bej)", + "America\/Godthab": "Zapadni Grenland (Gothab)", + "America\/Goose_Bay": "Atlantsko vreme (Gus Bej)", + "America\/Grand_Turk": "Severnoameričko istočno vreme (Grand Turk)", + "America\/Grenada": "Atlantsko vreme (Grenada)", + "America\/Guadeloupe": "Atlantsko vreme (Gvadalupe)", + "America\/Guatemala": "Severnoameričko centralno vreme (Gvatemala)", + "America\/Guayaquil": "Ekvador vreme (Gvajakil)", + "America\/Guyana": "Gvajana vreme (Gvajana)", + "America\/Halifax": "Atlantsko vreme (Halifaks)", + "America\/Havana": "Kuba (Havana)", + "America\/Hermosillo": "Meksički Pacifik (Hermosiljo)", + "America\/Indiana\/Knox": "Severnoameričko centralno vreme (Noks, Indijana)", + "America\/Indiana\/Marengo": "Severnoameričko istočno vreme (Marengo, Indijana)", + "America\/Indiana\/Petersburg": "Severnoameričko istočno vreme (Pitersburg, Indijana)", + "America\/Indiana\/Tell_City": "Severnoameričko centralno vreme (Tel Siti, Indijana)", + "America\/Indiana\/Vevay": "Severnoameričko istočno vreme (Vevaj, Indijana)", + "America\/Indiana\/Vincennes": "Severnoameričko istočno vreme (Vincenes, Indijana)", + "America\/Indiana\/Winamac": "Severnoameričko istočno vreme (Vinamak, Indijana)", + "America\/Indianapolis": "Severnoameričko istočno vreme (Indianapolis)", + "America\/Inuvik": "Severnoameričko planinsko vreme (Inuvik)", + "America\/Iqaluit": "Severnoameričko istočno vreme (Ikvaluit)", + "America\/Jamaica": "Severnoameričko istočno vreme (Jamajka)", + "America\/Jujuy": "Argentina vreme (Žužui)", + "America\/Juneau": "Aljaska (Žuno)", + "America\/Kentucky\/Monticello": "Severnoameričko istočno vreme (Montičelo, Kentaki)", + "America\/Kralendijk": "Atlantsko vreme (Kralendajk)", + "America\/La_Paz": "Bolivija vreme (La Paz)", + "America\/Lima": "Peru vreme (Lima)", + "America\/Los_Angeles": "Severnoameričko pacifičko vreme (Los Anđeles)", + "America\/Louisville": "Severnoameričko istočno vreme (Luivile)", + "America\/Lower_Princes": "Atlantsko vreme (Louer Prinsiz Kvorter)", + "America\/Maceio": "Brazilija vreme (Masejo)", + "America\/Managua": "Severnoameričko centralno vreme (Managva)", + "America\/Manaus": "Amazon vreme (Manaus)", + "America\/Marigot": "Atlantsko vreme (Marigo)", + "America\/Martinique": "Atlantsko vreme (Martinik)", + "America\/Matamoros": "Severnoameričko centralno vreme (Matamoros)", + "America\/Mazatlan": "Meksički Pacifik (Mazatlan)", + "America\/Mendoza": "Argentina vreme (Mendosa)", + "America\/Menominee": "Severnoameričko centralno vreme (Menomini)", + "America\/Merida": "Severnoameričko centralno vreme (Merida)", + "America\/Metlakatla": "Aljaska (Metlakatla)", + "America\/Mexico_City": "Severnoameričko centralno vreme (Meksiko Siti)", + "America\/Miquelon": "Sen Pjer i Mikelon (Mikelon)", + "America\/Moncton": "Atlantsko vreme (Monkton)", + "America\/Monterrey": "Severnoameričko centralno vreme (Monterej)", + "America\/Montevideo": "Urugvaj vreme (Montevideo)", + "America\/Montserrat": "Atlantsko vreme (Montserat)", + "America\/Nassau": "Severnoameričko istočno vreme (Nasau)", + "America\/New_York": "Severnoameričko istočno vreme (Njujork)", + "America\/Nipigon": "Severnoameričko istočno vreme (Nipigon)", + "America\/Nome": "Aljaska (Nom)", + "America\/Noronha": "Fernando de Noronja vreme (Noronja)", + "America\/North_Dakota\/Beulah": "Severnoameričko centralno vreme (Bijula, Severna Dakota)", + "America\/North_Dakota\/Center": "Severnoameričko centralno vreme (Centar, Severna Dakota)", + "America\/North_Dakota\/New_Salem": "Severnoameričko centralno vreme (Novi Salem, Severna Dakota)", + "America\/Ojinaga": "Severnoameričko planinsko vreme (Ohinaga)", + "America\/Panama": "Severnoameričko istočno vreme (Panama)", + "America\/Pangnirtung": "Severnoameričko istočno vreme (Pangnirtung)", + "America\/Paramaribo": "Surinam vreme (Paramaribo)", + "America\/Phoenix": "Severnoameričko planinsko vreme (Finiks)", + "America\/Port-au-Prince": "Severnoameričko istočno vreme (Port o Prens)", + "America\/Port_of_Spain": "Atlantsko vreme (Port of Spejn)", + "America\/Porto_Velho": "Amazon vreme (Porto Veljo)", + "America\/Puerto_Rico": "Atlantsko vreme (Porto Riko)", + "America\/Punta_Arenas": "Čile vreme (Punta Arenas)", + "America\/Rainy_River": "Severnoameričko centralno vreme (Rejni River)", + "America\/Rankin_Inlet": "Severnoameričko centralno vreme (Rankin Inlet)", + "America\/Recife": "Brazilija vreme (Resife)", + "America\/Regina": "Severnoameričko centralno vreme (Regina)", + "America\/Resolute": "Severnoameričko centralno vreme (Resolut)", + "America\/Rio_Branco": "Akre vreme (Rio Branko)", + "America\/Santa_Isabel": "Severozapadni Meksiko (Santa Izabel)", + "America\/Santarem": "Brazilija vreme (Santarem)", + "America\/Santiago": "Čile vreme (Santjago)", + "America\/Santo_Domingo": "Atlantsko vreme (Santo Domingo)", + "America\/Sao_Paulo": "Brazilija vreme (Sao Paolo)", + "America\/Scoresbysund": "Istočni Grenland (Skorezbisund)", + "America\/Sitka": "Aljaska (Sitka)", + "America\/St_Barthelemy": "Atlantsko vreme (Sv. Bartolomej)", + "America\/St_Johns": "Njufaundlend (Sv. Džon)", + "America\/St_Kitts": "Atlantsko vreme (Sent Kits)", + "America\/St_Lucia": "Atlantsko vreme (Sv. Lucija)", + "America\/St_Thomas": "Atlantsko vreme (Sv. Toma)", + "America\/St_Vincent": "Atlantsko vreme (Sent Vinsent)", + "America\/Swift_Current": "Severnoameričko centralno vreme (Svift Kurent)", + "America\/Tegucigalpa": "Severnoameričko centralno vreme (Tegusigalpa)", + "America\/Thule": "Atlantsko vreme (Tul)", + "America\/Thunder_Bay": "Severnoameričko istočno vreme (Tander Bej)", + "America\/Tijuana": "Severnoameričko pacifičko vreme (Tihuana)", + "America\/Toronto": "Severnoameričko istočno vreme (Toronto)", + "America\/Tortola": "Atlantsko vreme (Tortola)", + "America\/Vancouver": "Severnoameričko pacifičko vreme (Vankuver)", + "America\/Whitehorse": "Severnoameričko pacifičko vreme (Vajthors)", + "America\/Winnipeg": "Severnoameričko centralno vreme (Vinipeg)", + "America\/Yakutat": "Aljaska (Jakutat)", + "America\/Yellowknife": "Severnoameričko planinsko vreme (Jelounajf)", + "Antarctica\/Casey": "Australijsko zapadno vreme (Kejsi)", + "Antarctica\/Davis": "Dejvis vreme (Dejvis)", + "Antarctica\/DumontDUrville": "Dimon d’Urvil vreme (Dimon d’Urvil)", + "Antarctica\/Macquarie": "Ostrvo Makveri vreme (Mekvori)", + "Antarctica\/Mawson": "Moson vreme (Moson)", + "Antarctica\/McMurdo": "Novi Zeland vreme (Makmurdo)", + "Antarctica\/Palmer": "Čile vreme (Palmer)", + "Antarctica\/Rothera": "Rotera vreme (Rotera)", + "Antarctica\/Syowa": "Šova vreme (Šova)", + "Antarctica\/Troll": "Srednje vreme po Griniču (Trol)", + "Antarctica\/Vostok": "Vostok vreme (Vostok)", + "Arctic\/Longyearbyen": "Srednjeevropsko vreme (Longjerbjen)", + "Asia\/Aden": "Arabijsko vreme (Aden)", + "Asia\/Almaty": "Istočno-kazahstansko vreme (Almati)", + "Asia\/Amman": "Istočnoevropsko vreme (Aman)", + "Asia\/Anadyr": "Anadir vreme (Anadir)", + "Asia\/Aqtau": "Zapadno-kazahstansko vreme (Aktau)", + "Asia\/Aqtobe": "Zapadno-kazahstansko vreme (Akutobe)", + "Asia\/Ashgabat": "Turkmenistan vreme (Ašhabad)", + "Asia\/Atyrau": "Zapadno-kazahstansko vreme (Atirau)", + "Asia\/Baghdad": "Arabijsko vreme (Bagdad)", + "Asia\/Bahrain": "Arabijsko vreme (Bahrein)", + "Asia\/Baku": "Azerbejdžan vreme (Baku)", + "Asia\/Bangkok": "Indokina vreme (Bangkok)", + "Asia\/Beirut": "Istočnoevropsko vreme (Bejrut)", + "Asia\/Bishkek": "Kirgistan vreme (Biškek)", + "Asia\/Brunei": "Brunej Darusalum vreme (Brunej)", + "Asia\/Calcutta": "Indijsko standardno vreme (Kalkuta)", + "Asia\/Chita": "Jakutsk vreme (Čita)", + "Asia\/Choibalsan": "Čojbalsan vreme (Čojbalsan)", + "Asia\/Colombo": "Indijsko standardno vreme (Kolombo)", + "Asia\/Damascus": "Istočnoevropsko vreme (Damask)", + "Asia\/Dhaka": "Bangladeš vreme (Daka)", + "Asia\/Dili": "Istočni timor vreme (Dili)", + "Asia\/Dubai": "Zalivsko vreme (Dubai)", + "Asia\/Dushanbe": "Tadžikistan vreme (Dušanbe)", + "Asia\/Famagusta": "Istočnoevropsko vreme (Famagusta)", + "Asia\/Gaza": "Istočnoevropsko vreme (Gaza)", + "Asia\/Hebron": "Istočnoevropsko vreme (Hebron)", + "Asia\/Hong_Kong": "Hong Kong vreme (Hongkong)", + "Asia\/Hovd": "Hovd vreme (Hovd)", + "Asia\/Irkutsk": "Irkuck vreme (Irkuck)", + "Asia\/Jakarta": "Zapadno-indonezijsko vreme (Džakarta)", + "Asia\/Jayapura": "Istočno-indonezijsko vreme (Džajapura)", + "Asia\/Jerusalem": "Izraelsko vreme (Jerusalim)", + "Asia\/Kabul": "Avganistan vreme (Kabul)", + "Asia\/Kamchatka": "Petropavlovsko-kamčatsko vreme (Kamčatka)", + "Asia\/Karachi": "Pakistan vreme (Karači)", + "Asia\/Katmandu": "Nepal vreme (Katmandu)", + "Asia\/Khandyga": "Jakutsk vreme (Handiga)", + "Asia\/Krasnoyarsk": "Krasnojarsk vreme (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "Malezija vreme (Kuala Lumpur)", + "Asia\/Kuching": "Malezija vreme (Kučing)", + "Asia\/Kuwait": "Arabijsko vreme (Kuvajt)", + "Asia\/Macau": "Kina vreme (Makao)", + "Asia\/Magadan": "Magadan vreme (Magadan)", + "Asia\/Makassar": "Centralno-indonezijsko vreme (Makasar)", + "Asia\/Manila": "Filipini vreme (Manila)", + "Asia\/Muscat": "Zalivsko vreme (Muskat)", + "Asia\/Nicosia": "Istočnoevropsko vreme (Nikozija)", + "Asia\/Novokuznetsk": "Krasnojarsk vreme (Novokuznjeck)", + "Asia\/Novosibirsk": "Novosibirsk vreme (Novosibirsk)", + "Asia\/Omsk": "Omsk vreme (Omsk)", + "Asia\/Oral": "Zapadno-kazahstansko vreme (Oral)", + "Asia\/Phnom_Penh": "Indokina vreme (Pnom Pen)", + "Asia\/Pontianak": "Zapadno-indonezijsko vreme (Pontijanak)", + "Asia\/Pyongyang": "Korejsko vreme (Pjongjang)", + "Asia\/Qatar": "Arabijsko vreme (Katar)", + "Asia\/Qostanay": "Istočno-kazahstansko vreme (Qostanay)", + "Asia\/Qyzylorda": "Zapadno-kazahstansko vreme (Kizilorda)", + "Asia\/Rangoon": "Mijanmar vreme (Rangun)", + "Asia\/Riyadh": "Arabijsko vreme (Rijad)", + "Asia\/Saigon": "Indokina vreme (Ho Ši Min)", + "Asia\/Sakhalin": "Sahalin vreme (Sahalin)", + "Asia\/Samarkand": "Uzbekistan vreme (Samarkand)", + "Asia\/Seoul": "Korejsko vreme (Seul)", + "Asia\/Shanghai": "Kina vreme (Šangaj)", + "Asia\/Singapore": "Singapur, standardno vreme (Singapur)", + "Asia\/Srednekolymsk": "Magadan vreme (Srednjekolimsk)", + "Asia\/Taipei": "Tajpej vreme (Tajpej)", + "Asia\/Tashkent": "Uzbekistan vreme (Taškent)", + "Asia\/Tbilisi": "Gruzija vreme (Tbilisi)", + "Asia\/Tehran": "Iran vreme (Teheran)", + "Asia\/Thimphu": "Butan vreme (Timpu)", + "Asia\/Tokyo": "Japansko vreme (Tokio)", + "Asia\/Ulaanbaatar": "Ulan Bator vreme (Ulan Bator)", + "Asia\/Ust-Nera": "Vladivostok vreme (Ust-Nera)", + "Asia\/Vientiane": "Indokina vreme (Vijentijan)", + "Asia\/Vladivostok": "Vladivostok vreme (Vladivostok)", + "Asia\/Yakutsk": "Jakutsk vreme (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburg vreme (Jekaterinburg)", + "Asia\/Yerevan": "Jermenija vreme (Jerevan)", + "Atlantic\/Azores": "Azori vreme (Azori)", + "Atlantic\/Bermuda": "Atlantsko vreme (Bermuda)", + "Atlantic\/Canary": "Zapadnoevropsko vreme (Kanarska ostrva)", + "Atlantic\/Cape_Verde": "Zelenortska Ostrva vreme (Zelenortska Ostrva)", + "Atlantic\/Faeroe": "Zapadnoevropsko vreme (Farska Ostrva)", + "Atlantic\/Madeira": "Zapadnoevropsko vreme (Madeira)", + "Atlantic\/Reykjavik": "Srednje vreme po Griniču (Rejkjavik)", + "Atlantic\/South_Georgia": "Južna Džordžija vreme (Južna Džordžija)", + "Atlantic\/St_Helena": "Srednje vreme po Griniču (Sveta Jelena)", + "Atlantic\/Stanley": "Folklandska Ostrva vreme (Stenli)", + "Australia\/Adelaide": "Australijsko centralno vreme (Adelejd)", + "Australia\/Brisbane": "Australijsko istočno vreme (Brizbejn)", + "Australia\/Broken_Hill": "Australijsko centralno vreme (Broken Hil)", + "Australia\/Currie": "Australijsko istočno vreme (Kari)", + "Australia\/Darwin": "Australijsko centralno vreme (Darvin)", + "Australia\/Eucla": "Australijsko centralno zapadno vreme (Iukla)", + "Australia\/Hobart": "Australijsko istočno vreme (Hobart)", + "Australia\/Lindeman": "Australijsko istočno vreme (Lindeman)", + "Australia\/Lord_Howe": "Lord Hov vreme (Lord Hau)", + "Australia\/Melbourne": "Australijsko istočno vreme (Melburn)", + "Australia\/Perth": "Australijsko zapadno vreme (Pert)", + "Australia\/Sydney": "Australijsko istočno vreme (Sidnej)", + "CST6CDT": "Severnoameričko centralno vreme", + "EST5EDT": "Severnoameričko istočno vreme", + "Etc\/GMT": "Srednje vreme po Griniču", + "Etc\/UTC": "Koordinisano univerzalno vreme", + "Europe\/Amsterdam": "Srednjeevropsko vreme (Amsterdam)", + "Europe\/Andorra": "Srednjeevropsko vreme (Andora)", + "Europe\/Astrakhan": "Moskva vreme (Astrakan)", + "Europe\/Athens": "Istočnoevropsko vreme (Atina)", + "Europe\/Belgrade": "Srednjeevropsko vreme (Beograd)", + "Europe\/Berlin": "Srednjeevropsko vreme (Berlin)", + "Europe\/Bratislava": "Srednjeevropsko vreme (Bratislava)", + "Europe\/Brussels": "Srednjeevropsko vreme (Brisel)", + "Europe\/Bucharest": "Istočnoevropsko vreme (Bukurešt)", + "Europe\/Budapest": "Srednjeevropsko vreme (Budimpešta)", + "Europe\/Busingen": "Srednjeevropsko vreme (Bisingen)", + "Europe\/Chisinau": "Istočnoevropsko vreme (Kišinjev)", + "Europe\/Copenhagen": "Srednjeevropsko vreme (Kopenhagen)", + "Europe\/Dublin": "Srednje vreme po Griniču (Dablin)", + "Europe\/Gibraltar": "Srednjeevropsko vreme (Gibraltar)", + "Europe\/Guernsey": "Srednje vreme po Griniču (Gernzi)", + "Europe\/Helsinki": "Istočnoevropsko vreme (Helsinki)", + "Europe\/Isle_of_Man": "Srednje vreme po Griniču (Ostrvo Man)", + "Europe\/Jersey": "Srednje vreme po Griniču (Džersi)", + "Europe\/Kaliningrad": "Istočnoevropsko vreme (Kalinjingrad)", + "Europe\/Kiev": "Istočnoevropsko vreme (Kijev)", + "Europe\/Lisbon": "Zapadnoevropsko vreme (Lisabon)", + "Europe\/Ljubljana": "Srednjeevropsko vreme (Ljubljana)", + "Europe\/London": "Srednje vreme po Griniču (London)", + "Europe\/Luxembourg": "Srednjeevropsko vreme (Luksemburg)", + "Europe\/Madrid": "Srednjeevropsko vreme (Madrid)", + "Europe\/Malta": "Srednjeevropsko vreme (Malta)", + "Europe\/Mariehamn": "Istočnoevropsko vreme (Marihamn)", + "Europe\/Minsk": "Moskva vreme (Minsk)", + "Europe\/Monaco": "Srednjeevropsko vreme (Monako)", + "Europe\/Moscow": "Moskva vreme (Moskva)", + "Europe\/Oslo": "Srednjeevropsko vreme (Oslo)", + "Europe\/Paris": "Srednjeevropsko vreme (Pariz)", + "Europe\/Podgorica": "Srednjeevropsko vreme (Podgorica)", + "Europe\/Prague": "Srednjeevropsko vreme (Prag)", + "Europe\/Riga": "Istočnoevropsko vreme (Riga)", + "Europe\/Rome": "Srednjeevropsko vreme (Rim)", + "Europe\/Samara": "Samara vreme (Samara)", + "Europe\/San_Marino": "Srednjeevropsko vreme (San Marino)", + "Europe\/Sarajevo": "Srednjeevropsko vreme (Sarajevo)", + "Europe\/Saratov": "Moskva vreme (Saratov)", + "Europe\/Simferopol": "Moskva vreme (Simferopolj)", + "Europe\/Skopje": "Srednjeevropsko vreme (Skoplje)", + "Europe\/Sofia": "Istočnoevropsko vreme (Sofija)", + "Europe\/Stockholm": "Srednjeevropsko vreme (Stokholm)", + "Europe\/Tallinn": "Istočnoevropsko vreme (Talin)", + "Europe\/Tirane": "Srednjeevropsko vreme (Tirana)", + "Europe\/Ulyanovsk": "Moskva vreme (Uljanovsk)", + "Europe\/Uzhgorod": "Istočnoevropsko vreme (Užgorod)", + "Europe\/Vaduz": "Srednjeevropsko vreme (Vaduz)", + "Europe\/Vatican": "Srednjeevropsko vreme (Vatikan)", + "Europe\/Vienna": "Srednjeevropsko vreme (Beč)", + "Europe\/Vilnius": "Istočnoevropsko vreme (Vilnjus)", + "Europe\/Volgograd": "Volgograd vreme (Volgograd)", + "Europe\/Warsaw": "Srednjeevropsko vreme (Varšava)", + "Europe\/Zagreb": "Srednjeevropsko vreme (Zagreb)", + "Europe\/Zaporozhye": "Istočnoevropsko vreme (Zaporožje)", + "Europe\/Zurich": "Srednjeevropsko vreme (Cirih)", + "Indian\/Antananarivo": "Istočno-afričko vreme (Antananarivo)", + "Indian\/Chagos": "Indijsko okeansko vreme (Čagos)", + "Indian\/Christmas": "Božićno ostrvo vreme (Božić)", + "Indian\/Cocos": "Kokos (Keling) Ostrva vreme (Kokos)", + "Indian\/Comoro": "Istočno-afričko vreme (Komoro)", + "Indian\/Kerguelen": "Francusko južno i antarktičko vreme (Kergelen)", + "Indian\/Mahe": "Sejšeli vreme (Mahe)", + "Indian\/Maldives": "Maldivi vreme (Maldivi)", + "Indian\/Mauritius": "Mauricijus vreme (Mauricijus)", + "Indian\/Mayotte": "Istočno-afričko vreme (Majot)", + "Indian\/Reunion": "Reinion vreme (Reunion)", + "MST7MDT": "Severnoameričko planinsko vreme", + "PST8PDT": "Severnoameričko pacifičko vreme", + "Pacific\/Apia": "Apija vreme (Apija)", + "Pacific\/Auckland": "Novi Zeland vreme (Okland)", + "Pacific\/Bougainville": "Papua Nova Gvineja vreme (Buganvil)", + "Pacific\/Chatham": "Čatam vreme (Čatam)", + "Pacific\/Easter": "Uskršnja ostrva vreme (Uskršnje ostrvo)", + "Pacific\/Efate": "Vanuatu vreme (Efat)", + "Pacific\/Enderbury": "Feniks ostrva vreme (Enderberi)", + "Pacific\/Fakaofo": "Tokelau vreme (Fakaofo)", + "Pacific\/Fiji": "Fidži vreme (Fidži)", + "Pacific\/Funafuti": "Tuvalu vreme (Funafuti)", + "Pacific\/Galapagos": "Galapagos vreme (Galapagos)", + "Pacific\/Gambier": "Gambije vreme (Gambije)", + "Pacific\/Guadalcanal": "Solomonska Ostrva vreme (Gvadalkanal)", + "Pacific\/Guam": "Čamoro vreme (Guam)", + "Pacific\/Honolulu": "Havajsko-aleutsko vreme (Honolulu)", + "Pacific\/Johnston": "Havajsko-aleutsko vreme (Džonston)", + "Pacific\/Kiritimati": "Ostrva Lajn vreme (Kiritimati)", + "Pacific\/Kosrae": "Košre vreme (Košre)", + "Pacific\/Kwajalein": "Maršalska Ostrva vreme (Kvadžalejin)", + "Pacific\/Majuro": "Maršalska Ostrva vreme (Majuro)", + "Pacific\/Marquesas": "Markiz vreme (Markiz)", + "Pacific\/Midway": "Samoa vreme (Midvej)", + "Pacific\/Nauru": "Nauru vreme (Nauru)", + "Pacific\/Niue": "Niue vreme (Niue)", + "Pacific\/Norfolk": "Norfolk Ostrvo vreme (Norfolk)", + "Pacific\/Noumea": "Nova Kaledonija vreme (Numea)", + "Pacific\/Pago_Pago": "Samoa vreme (Pago Pago)", + "Pacific\/Palau": "Palau vreme (Palau)", + "Pacific\/Pitcairn": "Pitkern vreme (Pitkern)", + "Pacific\/Ponape": "Ponpej vreme (Ponape)", + "Pacific\/Port_Moresby": "Papua Nova Gvineja vreme (Port Morzbi)", + "Pacific\/Rarotonga": "Kukova ostrva vreme (Rarotonga)", + "Pacific\/Saipan": "Čamoro vreme (Sajpan)", + "Pacific\/Tahiti": "Tahiti vreme (Tahiti)", + "Pacific\/Tarawa": "Gilbert ostrva vreme (Tarava)", + "Pacific\/Tongatapu": "Tonga vreme (Tongatapu)", + "Pacific\/Truk": "Čuuk vreme (Truk)", + "Pacific\/Wake": "Vejk ostrvo vreme (Vejk)", + "Pacific\/Wallis": "Valis i Futuna Ostrva vreme (Valis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sv.json b/src/Symfony/Component/Intl/Resources/data/timezones/sv.json new file mode 100644 index 0000000000000..6c36cc6c297fa --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sv.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.90", + "Names": { + "Africa\/Abidjan": "Greenwichtid (Abidjan)", + "Africa\/Accra": "Greenwichtid (Accra)", + "Africa\/Addis_Ababa": "östafrikansk tid (Addis Abeba)", + "Africa\/Algiers": "centraleuropeisk tid (Alger)", + "Africa\/Asmera": "östafrikansk tid (Asmara)", + "Africa\/Bamako": "Greenwichtid (Bamako)", + "Africa\/Bangui": "västafrikansk tid (Bangui)", + "Africa\/Banjul": "Greenwichtid (Banjul)", + "Africa\/Bissau": "Greenwichtid (Bissau)", + "Africa\/Blantyre": "centralafrikansk tid (Blantyre)", + "Africa\/Brazzaville": "västafrikansk tid (Brazzaville)", + "Africa\/Bujumbura": "centralafrikansk tid (Bujumbura)", + "Africa\/Cairo": "östeuropeisk tid (Kairo)", + "Africa\/Casablanca": "västeuropeisk tid (Casablanca)", + "Africa\/Ceuta": "centraleuropeisk tid (Ceuta)", + "Africa\/Conakry": "Greenwichtid (Conakry)", + "Africa\/Dakar": "Greenwichtid (Dakar)", + "Africa\/Dar_es_Salaam": "östafrikansk tid (Dar es-Salaam)", + "Africa\/Djibouti": "östafrikansk tid (Djibouti)", + "Africa\/Douala": "västafrikansk tid (Douala)", + "Africa\/El_Aaiun": "västeuropeisk tid (El-Aaiún)", + "Africa\/Freetown": "Greenwichtid (Freetown)", + "Africa\/Gaborone": "centralafrikansk tid (Gaborone)", + "Africa\/Harare": "centralafrikansk tid (Harare)", + "Africa\/Johannesburg": "sydafrikansk tid (Johannesburg)", + "Africa\/Juba": "östafrikansk tid (Juba)", + "Africa\/Kampala": "östafrikansk tid (Kampala)", + "Africa\/Khartoum": "centralafrikansk tid (Khartoum)", + "Africa\/Kigali": "centralafrikansk tid (Kigali)", + "Africa\/Kinshasa": "västafrikansk tid (Kinshasa)", + "Africa\/Lagos": "västafrikansk tid (Lagos)", + "Africa\/Libreville": "västafrikansk tid (Libreville)", + "Africa\/Lome": "Greenwichtid (Lomé)", + "Africa\/Luanda": "västafrikansk tid (Luanda)", + "Africa\/Lubumbashi": "centralafrikansk tid (Lubumbashi)", + "Africa\/Lusaka": "centralafrikansk tid (Lusaka)", + "Africa\/Malabo": "västafrikansk tid (Malabo)", + "Africa\/Maputo": "centralafrikansk tid (Maputo)", + "Africa\/Maseru": "sydafrikansk tid (Maseru)", + "Africa\/Mbabane": "sydafrikansk tid (Mbabane)", + "Africa\/Mogadishu": "östafrikansk tid (Mogadishu)", + "Africa\/Monrovia": "Greenwichtid (Monrovia)", + "Africa\/Nairobi": "östafrikansk tid (Nairobi)", + "Africa\/Ndjamena": "västafrikansk tid (N’Djamena)", + "Africa\/Niamey": "västafrikansk tid (Niamey)", + "Africa\/Nouakchott": "Greenwichtid (Nouakchott)", + "Africa\/Ouagadougou": "Greenwichtid (Ouagadougou)", + "Africa\/Porto-Novo": "västafrikansk tid (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwichtid (São Tomé)", + "Africa\/Tripoli": "östeuropeisk tid (Tripoli)", + "Africa\/Tunis": "centraleuropeisk tid (Tunis)", + "Africa\/Windhoek": "centralafrikansk tid (Windhoek)", + "America\/Adak": "Honolulutid (Adak)", + "America\/Anchorage": "Alaskatid (Anchorage)", + "America\/Anguilla": "nordamerikansk atlanttid (Anguilla)", + "America\/Antigua": "nordamerikansk atlanttid (Antigua)", + "America\/Araguaina": "Brasiliatid (Araguaína)", + "America\/Argentina\/La_Rioja": "östargentinsk tid (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "östargentinsk tid (Río Gallegos)", + "America\/Argentina\/Salta": "östargentinsk tid (Salta)", + "America\/Argentina\/San_Juan": "östargentinsk tid (San Juan)", + "America\/Argentina\/San_Luis": "västargentinsk tid (San Luis)", + "America\/Argentina\/Tucuman": "östargentinsk tid (Tucumán)", + "America\/Argentina\/Ushuaia": "östargentinsk tid (Ushuaia)", + "America\/Aruba": "nordamerikansk atlanttid (Aruba)", + "America\/Asuncion": "paraguayansk tid (Asunción)", + "America\/Bahia": "Brasiliatid (Bahia)", + "America\/Bahia_Banderas": "centralnordamerikansk tid (Bahía de Banderas)", + "America\/Barbados": "nordamerikansk atlanttid (Barbados)", + "America\/Belem": "Brasiliatid (Belém)", + "America\/Belize": "centralnordamerikansk tid (Belize)", + "America\/Blanc-Sablon": "nordamerikansk atlanttid (Blanc-Sablon)", + "America\/Boa_Vista": "Amazonastid (Boa Vista)", + "America\/Bogota": "colombiansk tid (Bogotá)", + "America\/Boise": "Klippiga bergentid (Boise)", + "America\/Buenos_Aires": "östargentinsk tid (Buenos Aires)", + "America\/Cambridge_Bay": "Klippiga bergentid (Cambridge Bay)", + "America\/Campo_Grande": "Amazonastid (Campo Grande)", + "America\/Cancun": "östnordamerikansk tid (Cancún)", + "America\/Caracas": "venezuelansk tid (Caracas)", + "America\/Catamarca": "östargentinsk tid (Catamarca)", + "America\/Cayenne": "Franska Guyanatid (Cayenne)", + "America\/Cayman": "östnordamerikansk tid (Caymanöarna)", + "America\/Chicago": "centralnordamerikansk tid (Chicago)", + "America\/Chihuahua": "mexikansk stillahavstid (Chihuahua)", + "America\/Coral_Harbour": "östnordamerikansk tid (Atikokan)", + "America\/Cordoba": "östargentinsk tid (Córdoba)", + "America\/Costa_Rica": "centralnordamerikansk tid (Costa Rica)", + "America\/Creston": "Klippiga bergentid (Creston)", + "America\/Cuiaba": "Amazonastid (Cuiabá)", + "America\/Curacao": "nordamerikansk atlanttid (Curaçao)", + "America\/Danmarkshavn": "Greenwichtid (Danmarkshavn)", + "America\/Dawson": "västnordamerikansk tid (Dawson)", + "America\/Dawson_Creek": "Klippiga bergentid (Dawson Creek)", + "America\/Denver": "Klippiga bergentid (Denver)", + "America\/Detroit": "östnordamerikansk tid (Detroit)", + "America\/Dominica": "nordamerikansk atlanttid (Dominica)", + "America\/Edmonton": "Klippiga bergentid (Edmonton)", + "America\/Eirunepe": "västbrasiliansk tid (Eirunepé)", + "America\/El_Salvador": "centralnordamerikansk tid (El Salvador)", + "America\/Fort_Nelson": "Klippiga bergentid (Fort Nelson)", + "America\/Fortaleza": "Brasiliatid (Fortaleza)", + "America\/Glace_Bay": "nordamerikansk atlanttid (Glace Bay)", + "America\/Godthab": "västgrönländsk tid (Nuuk)", + "America\/Goose_Bay": "nordamerikansk atlanttid (Goose Bay)", + "America\/Grand_Turk": "östnordamerikansk tid (Grand Turk)", + "America\/Grenada": "nordamerikansk atlanttid (Grenada)", + "America\/Guadeloupe": "nordamerikansk atlanttid (Guadeloupe)", + "America\/Guatemala": "centralnordamerikansk tid (Guatemala)", + "America\/Guayaquil": "ecuadoriansk tid (Guayaquil)", + "America\/Guyana": "Guyanatid (Guyana)", + "America\/Halifax": "nordamerikansk atlanttid (Halifax)", + "America\/Havana": "kubansk tid (Havanna)", + "America\/Hermosillo": "mexikansk stillahavstid (Hermosillo)", + "America\/Indiana\/Knox": "centralnordamerikansk tid (Knox, Indiana)", + "America\/Indiana\/Marengo": "östnordamerikansk tid (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "östnordamerikansk tid (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "centralnordamerikansk tid (Tell City, Indiana)", + "America\/Indiana\/Vevay": "östnordamerikansk tid (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "östnordamerikansk tid (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "östnordamerikansk tid (Winamac, Indiana)", + "America\/Indianapolis": "östnordamerikansk tid (Indianapolis)", + "America\/Inuvik": "Klippiga bergentid (Inuvik)", + "America\/Iqaluit": "östnordamerikansk tid (Iqaluit)", + "America\/Jamaica": "östnordamerikansk tid (Jamaica)", + "America\/Jujuy": "östargentinsk tid (San Salvador de Jujuy)", + "America\/Juneau": "Alaskatid (Juneau)", + "America\/Kentucky\/Monticello": "östnordamerikansk tid (Monticello, Kentucky)", + "America\/Kralendijk": "nordamerikansk atlanttid (Kralendijk)", + "America\/La_Paz": "boliviansk tid (La Paz)", + "America\/Lima": "peruansk tid (Lima)", + "America\/Los_Angeles": "västnordamerikansk tid (Los Angeles)", + "America\/Louisville": "östnordamerikansk tid (Louisville)", + "America\/Lower_Princes": "nordamerikansk atlanttid (Lower Prince’s Quarter)", + "America\/Maceio": "Brasiliatid (Maceió)", + "America\/Managua": "centralnordamerikansk tid (Managua)", + "America\/Manaus": "Amazonastid (Manaus)", + "America\/Marigot": "nordamerikansk atlanttid (Marigot)", + "America\/Martinique": "nordamerikansk atlanttid (Martinique)", + "America\/Matamoros": "centralnordamerikansk tid (Matamoros)", + "America\/Mazatlan": "mexikansk stillahavstid (Mazatlán)", + "America\/Mendoza": "östargentinsk tid (Mendoza)", + "America\/Menominee": "centralnordamerikansk tid (Menominee)", + "America\/Merida": "centralnordamerikansk tid (Mérida)", + "America\/Metlakatla": "Alaskatid (Metlakatla)", + "America\/Mexico_City": "centralnordamerikansk tid (Mexiko City)", + "America\/Miquelon": "S:t Pierre och Miquelontid (Miquelon)", + "America\/Moncton": "nordamerikansk atlanttid (Moncton)", + "America\/Monterrey": "centralnordamerikansk tid (Monterrey)", + "America\/Montevideo": "uruguayansk tid (Montevideo)", + "America\/Montserrat": "nordamerikansk atlanttid (Montserrat)", + "America\/Nassau": "östnordamerikansk tid (Nassau)", + "America\/New_York": "östnordamerikansk tid (New York)", + "America\/Nipigon": "östnordamerikansk tid (Nipigon)", + "America\/Nome": "Alaskatid (Nome)", + "America\/Noronha": "Fernando de Noronhatid (Fernando de Noronha)", + "America\/North_Dakota\/Beulah": "centralnordamerikansk tid (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "centralnordamerikansk tid (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "centralnordamerikansk tid (New Salem, North Dakota)", + "America\/Ojinaga": "Klippiga bergentid (Ojinaga)", + "America\/Panama": "östnordamerikansk tid (Panama)", + "America\/Pangnirtung": "östnordamerikansk tid (Pangnirtung)", + "America\/Paramaribo": "Surinamtid (Paramaribo)", + "America\/Phoenix": "Klippiga bergentid (Phoenix)", + "America\/Port-au-Prince": "östnordamerikansk tid (Port-au-Prince)", + "America\/Port_of_Spain": "nordamerikansk atlanttid (Port of Spain)", + "America\/Porto_Velho": "Amazonastid (Porto Velho)", + "America\/Puerto_Rico": "nordamerikansk atlanttid (Puerto Rico)", + "America\/Punta_Arenas": "chilensk tid (Punta Arenas)", + "America\/Rainy_River": "centralnordamerikansk tid (Rainy River)", + "America\/Rankin_Inlet": "centralnordamerikansk tid (Rankin Inlet)", + "America\/Recife": "Brasiliatid (Recife)", + "America\/Regina": "centralnordamerikansk tid (Regina)", + "America\/Resolute": "centralnordamerikansk tid (Resolute)", + "America\/Rio_Branco": "västbrasiliansk tid (Rio Branco)", + "America\/Santa_Isabel": "nordvästmexikansk tid (Santa Isabel)", + "America\/Santarem": "Brasiliatid (Santarém)", + "America\/Santiago": "chilensk tid (Santiago)", + "America\/Santo_Domingo": "nordamerikansk atlanttid (Santo Domingo)", + "America\/Sao_Paulo": "Brasiliatid (São Paulo)", + "America\/Scoresbysund": "östgrönländsk tid (Ittoqqortoormiit)", + "America\/Sitka": "Alaskatid (Sitka)", + "America\/St_Barthelemy": "nordamerikansk atlanttid (S:t Barthélemy)", + "America\/St_Johns": "Newfoundlandtid (S:t Johns)", + "America\/St_Kitts": "nordamerikansk atlanttid (S:t Kitts)", + "America\/St_Lucia": "nordamerikansk atlanttid (S:t Lucia)", + "America\/St_Thomas": "nordamerikansk atlanttid (S:t Thomas)", + "America\/St_Vincent": "nordamerikansk atlanttid (S:t Vincent)", + "America\/Swift_Current": "centralnordamerikansk tid (Swift Current)", + "America\/Tegucigalpa": "centralnordamerikansk tid (Tegucigalpa)", + "America\/Thule": "nordamerikansk atlanttid (Qaanaaq)", + "America\/Thunder_Bay": "östnordamerikansk tid (Thunder Bay)", + "America\/Tijuana": "västnordamerikansk tid (Tijuana)", + "America\/Toronto": "östnordamerikansk tid (Toronto)", + "America\/Tortola": "nordamerikansk atlanttid (Tortola)", + "America\/Vancouver": "västnordamerikansk tid (Vancouver)", + "America\/Whitehorse": "västnordamerikansk tid (Whitehorse)", + "America\/Winnipeg": "centralnordamerikansk tid (Winnipeg)", + "America\/Yakutat": "Alaskatid (Yakutat)", + "America\/Yellowknife": "Klippiga bergentid (Yellowknife)", + "Antarctica\/Casey": "västaustralisk tid (Casey)", + "Antarctica\/Davis": "Davistid (Davis)", + "Antarctica\/DumontDUrville": "Dumont d’Urville-tid (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarietid (Macquarie)", + "Antarctica\/Mawson": "Mawsontid (Mawson)", + "Antarctica\/McMurdo": "nyzeeländsk tid (McMurdo)", + "Antarctica\/Palmer": "chilensk tid (Palmer)", + "Antarctica\/Rothera": "Rotheratid (Rothera)", + "Antarctica\/Syowa": "Syowatid (Syowa)", + "Antarctica\/Troll": "Greenwichtid (Troll)", + "Antarctica\/Vostok": "Vostoktid (Vostok)", + "Arctic\/Longyearbyen": "centraleuropeisk tid (Longyearbyen)", + "Asia\/Aden": "saudiarabisk tid (Aden)", + "Asia\/Almaty": "östkazakstansk tid (Almaty)", + "Asia\/Amman": "östeuropeisk tid (Amman)", + "Asia\/Anadyr": "Anadyrtid (Anadyr)", + "Asia\/Aqtau": "västkazakstansk tid (Aktau)", + "Asia\/Aqtobe": "västkazakstansk tid (Aqtöbe)", + "Asia\/Ashgabat": "turkmensk tid (Asjchabad)", + "Asia\/Atyrau": "västkazakstansk tid (Atyrau)", + "Asia\/Baghdad": "saudiarabisk tid (Bagdad)", + "Asia\/Bahrain": "saudiarabisk tid (Bahrain)", + "Asia\/Baku": "azerbajdzjansk tid (Baku)", + "Asia\/Bangkok": "indokinesisk tid (Bangkok)", + "Asia\/Beirut": "östeuropeisk tid (Beirut)", + "Asia\/Bishkek": "kirgizisk tid (Bisjkek)", + "Asia\/Brunei": "Bruneitid (Brunei)", + "Asia\/Calcutta": "indisk tid (Kolkata)", + "Asia\/Chita": "Jakutsktid (Tjita)", + "Asia\/Choibalsan": "Tjojbalsantid (Tjojbalsan)", + "Asia\/Colombo": "indisk tid (Colombo)", + "Asia\/Damascus": "östeuropeisk tid (Damaskus)", + "Asia\/Dhaka": "bangladeshisk tid (Dhaka)", + "Asia\/Dili": "östtimorisk tid (Dili)", + "Asia\/Dubai": "Persiska vikentid (Dubai)", + "Asia\/Dushanbe": "Tadzjikistantid (Dusjanbe)", + "Asia\/Famagusta": "östeuropeisk tid (Famagusta)", + "Asia\/Gaza": "östeuropeisk tid (Gaza)", + "Asia\/Hebron": "östeuropeisk tid (Hebron)", + "Asia\/Hong_Kong": "Hongkongtid (Hongkong)", + "Asia\/Hovd": "Chovdtid (Chovd)", + "Asia\/Irkutsk": "Irkutsktid (Irkutsk)", + "Asia\/Jakarta": "västindonesisk tid (Jakarta)", + "Asia\/Jayapura": "östindonesisk tid (Jayapura)", + "Asia\/Jerusalem": "israelisk tid (Jerusalem)", + "Asia\/Kabul": "afghansk tid (Kabul)", + "Asia\/Kamchatka": "Kamtjatkatid (Kamtjatka)", + "Asia\/Karachi": "pakistansk tid (Karachi)", + "Asia\/Katmandu": "nepalesisk tid (Katmandu)", + "Asia\/Khandyga": "Jakutsktid (Chandyga)", + "Asia\/Krasnoyarsk": "Krasnojarsktid (Krasnojarsk)", + "Asia\/Kuala_Lumpur": "malaysisk tid (Kuala Lumpur)", + "Asia\/Kuching": "malaysisk tid (Kuching)", + "Asia\/Kuwait": "saudiarabisk tid (Kuwait)", + "Asia\/Macau": "kinesisk tid (Macao)", + "Asia\/Magadan": "Magadantid (Magadan)", + "Asia\/Makassar": "centralindonesisk tid (Makassar)", + "Asia\/Manila": "filippinsk tid (Manilla)", + "Asia\/Muscat": "Persiska vikentid (Muskat)", + "Asia\/Nicosia": "östeuropeisk tid (Nicosia)", + "Asia\/Novokuznetsk": "Krasnojarsktid (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsktid (Novosibirsk)", + "Asia\/Omsk": "Omsktid (Omsk)", + "Asia\/Oral": "västkazakstansk tid (Oral)", + "Asia\/Phnom_Penh": "indokinesisk tid (Phnom Penh)", + "Asia\/Pontianak": "västindonesisk tid (Pontianak)", + "Asia\/Pyongyang": "koreansk tid (Pyongyang)", + "Asia\/Qatar": "saudiarabisk tid (Qatar)", + "Asia\/Qostanay": "östkazakstansk tid (Kostanaj)", + "Asia\/Qyzylorda": "västkazakstansk tid (Qyzylorda)", + "Asia\/Rangoon": "burmesisk tid (Rangoon)", + "Asia\/Riyadh": "saudiarabisk tid (Riyadh)", + "Asia\/Saigon": "indokinesisk tid (Ho Chi Minh-staden)", + "Asia\/Sakhalin": "Sachalintid (Sachalin)", + "Asia\/Samarkand": "uzbekisk tid (Samarkand)", + "Asia\/Seoul": "koreansk tid (Söul)", + "Asia\/Shanghai": "kinesisk tid (Shanghai)", + "Asia\/Singapore": "Singaporetid (Singapore)", + "Asia\/Srednekolymsk": "Magadantid (Srednekolymsk)", + "Asia\/Taipei": "Taipeitid (Taipei)", + "Asia\/Tashkent": "uzbekisk tid (Tasjkent)", + "Asia\/Tbilisi": "georgisk tid (Tbilisi)", + "Asia\/Tehran": "iransk tid (Teheran)", + "Asia\/Thimphu": "bhutansk tid (Thimphu)", + "Asia\/Tokyo": "japansk tid (Tokyo)", + "Asia\/Ulaanbaatar": "Ulaanbaatartid (Ulaanbaatar)", + "Asia\/Ust-Nera": "Vladivostoktid (Ust-Nera)", + "Asia\/Vientiane": "indokinesisk tid (Vientiane)", + "Asia\/Vladivostok": "Vladivostoktid (Vladivostok)", + "Asia\/Yakutsk": "Jakutsktid (Jakutsk)", + "Asia\/Yekaterinburg": "Jekaterinburgtid (Jekaterinburg)", + "Asia\/Yerevan": "armenisk tid (Jerevan)", + "Atlantic\/Azores": "azorisk tid (Azorerna)", + "Atlantic\/Bermuda": "nordamerikansk atlanttid (Bermuda)", + "Atlantic\/Canary": "västeuropeisk tid (Kanarieöarna)", + "Atlantic\/Cape_Verde": "Kap Verdetid (Kap Verde)", + "Atlantic\/Faeroe": "västeuropeisk tid (Torshamn)", + "Atlantic\/Madeira": "västeuropeisk tid (Madeira)", + "Atlantic\/Reykjavik": "Greenwichtid (Reykjavik)", + "Atlantic\/South_Georgia": "sydgeorgisk tid (Sydgeorgien)", + "Atlantic\/St_Helena": "Greenwichtid (S:t Helena)", + "Atlantic\/Stanley": "Falklandsöarnas tid (Stanley)", + "Australia\/Adelaide": "centralaustralisk tid (Adelaide)", + "Australia\/Brisbane": "östaustralisk tid (Brisbane)", + "Australia\/Broken_Hill": "centralaustralisk tid (Broken Hill)", + "Australia\/Currie": "östaustralisk tid (Currie)", + "Australia\/Darwin": "centralaustralisk tid (Darwin)", + "Australia\/Eucla": "västcentralaustralisk tid (Eucla)", + "Australia\/Hobart": "östaustralisk tid (Hobart)", + "Australia\/Lindeman": "östaustralisk tid (Lindeman)", + "Australia\/Lord_Howe": "Lord Howetid (Lord Howe)", + "Australia\/Melbourne": "östaustralisk tid (Melbourne)", + "Australia\/Perth": "västaustralisk tid (Perth)", + "Australia\/Sydney": "östaustralisk tid (Sydney)", + "CST6CDT": "centralnordamerikansk tid", + "EST5EDT": "östnordamerikansk tid", + "Etc\/GMT": "Greenwichtid", + "Etc\/UTC": "Koordinerad universell tid", + "Europe\/Amsterdam": "centraleuropeisk tid (Amsterdam)", + "Europe\/Andorra": "centraleuropeisk tid (Andorra)", + "Europe\/Astrakhan": "Moskvatid (Astrakhan)", + "Europe\/Athens": "östeuropeisk tid (Aten)", + "Europe\/Belgrade": "centraleuropeisk tid (Belgrad)", + "Europe\/Berlin": "centraleuropeisk tid (Berlin)", + "Europe\/Bratislava": "centraleuropeisk tid (Bratislava)", + "Europe\/Brussels": "centraleuropeisk tid (Bryssel)", + "Europe\/Bucharest": "östeuropeisk tid (Bukarest)", + "Europe\/Budapest": "centraleuropeisk tid (Budapest)", + "Europe\/Busingen": "centraleuropeisk tid (Büsingen am Hochrhein)", + "Europe\/Chisinau": "östeuropeisk tid (Chișinău)", + "Europe\/Copenhagen": "centraleuropeisk tid (Köpenhamn)", + "Europe\/Dublin": "Greenwichtid (Dublin)", + "Europe\/Gibraltar": "centraleuropeisk tid (Gibraltar)", + "Europe\/Guernsey": "Greenwichtid (Guernsey)", + "Europe\/Helsinki": "östeuropeisk tid (Helsingfors)", + "Europe\/Isle_of_Man": "Greenwichtid (Isle of Man)", + "Europe\/Jersey": "Greenwichtid (Jersey)", + "Europe\/Kaliningrad": "östeuropeisk tid (Kaliningrad)", + "Europe\/Kiev": "östeuropeisk tid (Kiev)", + "Europe\/Lisbon": "västeuropeisk tid (Lissabon)", + "Europe\/Ljubljana": "centraleuropeisk tid (Ljubljana)", + "Europe\/London": "Greenwichtid (London)", + "Europe\/Luxembourg": "centraleuropeisk tid (Luxemburg)", + "Europe\/Madrid": "centraleuropeisk tid (Madrid)", + "Europe\/Malta": "centraleuropeisk tid (Malta)", + "Europe\/Mariehamn": "östeuropeisk tid (Mariehamn)", + "Europe\/Minsk": "Moskvatid (Minsk)", + "Europe\/Monaco": "centraleuropeisk tid (Monaco)", + "Europe\/Moscow": "Moskvatid (Moskva)", + "Europe\/Oslo": "centraleuropeisk tid (Oslo)", + "Europe\/Paris": "centraleuropeisk tid (Paris)", + "Europe\/Podgorica": "centraleuropeisk tid (Podgorica)", + "Europe\/Prague": "centraleuropeisk tid (Prag)", + "Europe\/Riga": "östeuropeisk tid (Riga)", + "Europe\/Rome": "centraleuropeisk tid (Rom)", + "Europe\/Samara": "Samaratid (Samara)", + "Europe\/San_Marino": "centraleuropeisk tid (San Marino)", + "Europe\/Sarajevo": "centraleuropeisk tid (Sarajevo)", + "Europe\/Saratov": "Moskvatid (Saratov)", + "Europe\/Simferopol": "Moskvatid (Simferopol)", + "Europe\/Skopje": "centraleuropeisk tid (Skopje)", + "Europe\/Sofia": "östeuropeisk tid (Sofia)", + "Europe\/Stockholm": "centraleuropeisk tid (Stockholm)", + "Europe\/Tallinn": "östeuropeisk tid (Tallinn)", + "Europe\/Tirane": "centraleuropeisk tid (Tirana)", + "Europe\/Ulyanovsk": "Moskvatid (Uljanovsk)", + "Europe\/Uzhgorod": "östeuropeisk tid (Uzjhorod)", + "Europe\/Vaduz": "centraleuropeisk tid (Vaduz)", + "Europe\/Vatican": "centraleuropeisk tid (Vatikanen)", + "Europe\/Vienna": "centraleuropeisk tid (Wien)", + "Europe\/Vilnius": "östeuropeisk tid (Vilnius)", + "Europe\/Volgograd": "Volgogradtid (Volgograd)", + "Europe\/Warsaw": "centraleuropeisk tid (Warszawa)", + "Europe\/Zagreb": "centraleuropeisk tid (Zagreb)", + "Europe\/Zaporozhye": "östeuropeisk tid (Zaporizjzja)", + "Europe\/Zurich": "centraleuropeisk tid (Zürich)", + "Indian\/Antananarivo": "östafrikansk tid (Antananarivo)", + "Indian\/Chagos": "Brittiska Indiska oceanöarnas tid (Chagosöarna)", + "Indian\/Christmas": "Julöns tid (Julön)", + "Indian\/Cocos": "Keelingöarnas tid (Kokosöarna)", + "Indian\/Comoro": "östafrikansk tid (Komorerna)", + "Indian\/Kerguelen": "Franska Sydterritoriernas tid (Kerguelenöarna)", + "Indian\/Mahe": "Seychellernatid (Mahé)", + "Indian\/Maldives": "Maldivernatid (Maldiverna)", + "Indian\/Mauritius": "Mauritiustid (Mauritius)", + "Indian\/Mayotte": "östafrikansk tid (Mayotte)", + "Indian\/Reunion": "Réuniontid (Réunion)", + "MST7MDT": "Klippiga bergentid", + "PST8PDT": "västnordamerikansk tid", + "Pacific\/Apia": "Apiatid (Apia)", + "Pacific\/Auckland": "nyzeeländsk tid (Auckland)", + "Pacific\/Bougainville": "Papua Nya Guineas tid (Bougainville)", + "Pacific\/Chatham": "Chathamtid (Chatham)", + "Pacific\/Easter": "Påskötid (Påskön)", + "Pacific\/Efate": "Vanuatutid (Efate)", + "Pacific\/Enderbury": "Enderburytid (Enderbury)", + "Pacific\/Fakaofo": "Tokelautid (Fakaofo)", + "Pacific\/Fiji": "Fijitid (Fiji)", + "Pacific\/Funafuti": "Tuvalutid (Funafuti)", + "Pacific\/Galapagos": "Galápagostid (Galápagos)", + "Pacific\/Gambier": "Gambiertid (Gambieröarna)", + "Pacific\/Guadalcanal": "Salomonöarnas tid (Guadalcanal)", + "Pacific\/Guam": "Chamorrotid (Guam)", + "Pacific\/Honolulu": "Honolulutid (Honolulu)", + "Pacific\/Johnston": "Honolulutid (Johnstonatollen)", + "Pacific\/Kiritimati": "Lineöarnas tid (Kiritimati)", + "Pacific\/Kosrae": "Kosraetid (Kosrae)", + "Pacific\/Kwajalein": "Marshallöarnas tid (Kwajalein)", + "Pacific\/Majuro": "Marshallöarnas tid (Majuro)", + "Pacific\/Marquesas": "Marquesastid (Marquesasöarna)", + "Pacific\/Midway": "samoansk tid (Midwayöarna)", + "Pacific\/Nauru": "Naurutid (Nauru)", + "Pacific\/Niue": "Niuetid (Niue)", + "Pacific\/Norfolk": "Norfolköns tid (Norfolk)", + "Pacific\/Noumea": "Nya Kaledonientid (Nouméa)", + "Pacific\/Pago_Pago": "samoansk tid (Pago Pago)", + "Pacific\/Palau": "Palautid (Palau)", + "Pacific\/Pitcairn": "Pitcairntid (Pitcairnöarna)", + "Pacific\/Ponape": "Ponapetid (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Nya Guineas tid (Port Moresby)", + "Pacific\/Rarotonga": "Cooköarnas tid (Rarotonga)", + "Pacific\/Saipan": "Chamorrotid (Saipan)", + "Pacific\/Tahiti": "Tahititid (Tahiti)", + "Pacific\/Tarawa": "Kiribatitid (Tarawa)", + "Pacific\/Tongatapu": "Tongatid (Tongatapu)", + "Pacific\/Truk": "Chuuktid (Chuuk)", + "Pacific\/Wake": "Wakeöarnas tid (Wake)", + "Pacific\/Wallis": "Wallis- och Futunaöarnas tid (Wallisön)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/sw.json b/src/Symfony/Component/Intl/Resources/data/timezones/sw.json new file mode 100644 index 0000000000000..2b3d84bfb6254 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/sw.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Saa za Greenwich (Abidjan)", + "Africa\/Accra": "Saa za Greenwich (Accra)", + "Africa\/Addis_Ababa": "Saa za Afrika Mashariki (Addis Ababa)", + "Africa\/Algiers": "Saa za Ulaya ya Kati (Algiers)", + "Africa\/Asmera": "Saa za Afrika Mashariki (Asmara)", + "Africa\/Bamako": "Saa za Greenwich (Bamako)", + "Africa\/Bangui": "Saa za Afrika Magharibi (Bangui)", + "Africa\/Banjul": "Saa za Greenwich (Banjul)", + "Africa\/Bissau": "Saa za Greenwich (Bissau)", + "Africa\/Blantyre": "Saa za Afrika ya Kati (Blantyre)", + "Africa\/Brazzaville": "Saa za Afrika Magharibi (Brazzaville)", + "Africa\/Bujumbura": "Saa za Afrika ya Kati (Bujumbura)", + "Africa\/Cairo": "Saa za Mashariki mwa Ulaya (Cairo)", + "Africa\/Casablanca": "Saa za Magharibi mwa Ulaya (Casablanca)", + "Africa\/Ceuta": "Saa za Ulaya ya Kati (Ceuta)", + "Africa\/Conakry": "Saa za Greenwich (Conakry)", + "Africa\/Dakar": "Saa za Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Saa za Afrika Mashariki (Dar es Salaam)", + "Africa\/Djibouti": "Saa za Afrika Mashariki (Djibouti)", + "Africa\/Douala": "Saa za Afrika Magharibi (Douala)", + "Africa\/El_Aaiun": "Saa za Magharibi mwa Ulaya (El Aaiun)", + "Africa\/Freetown": "Saa za Greenwich (Freetown)", + "Africa\/Gaborone": "Saa za Afrika ya Kati (Gaborone)", + "Africa\/Harare": "Saa za Afrika ya Kati (Harare)", + "Africa\/Johannesburg": "Saa za Wastani za Afrika Kusini (Johannesburg)", + "Africa\/Juba": "Saa za Afrika Mashariki (Juba)", + "Africa\/Kampala": "Saa za Afrika Mashariki (Kampala)", + "Africa\/Khartoum": "Saa za Afrika ya Kati (Khartoum)", + "Africa\/Kigali": "Saa za Afrika ya Kati (Kigali)", + "Africa\/Kinshasa": "Saa za Afrika Magharibi (Kinshasa)", + "Africa\/Lagos": "Saa za Afrika Magharibi (Lagos)", + "Africa\/Libreville": "Saa za Afrika Magharibi (Libreville)", + "Africa\/Lome": "Saa za Greenwich (Lome)", + "Africa\/Luanda": "Saa za Afrika Magharibi (Luanda)", + "Africa\/Lubumbashi": "Saa za Afrika ya Kati (Lubumbashi)", + "Africa\/Lusaka": "Saa za Afrika ya Kati (Lusaka)", + "Africa\/Malabo": "Saa za Afrika Magharibi (Malabo)", + "Africa\/Maputo": "Saa za Afrika ya Kati (Maputo)", + "Africa\/Maseru": "Saa za Wastani za Afrika Kusini (Maseru)", + "Africa\/Mbabane": "Saa za Wastani za Afrika Kusini (Mbabane)", + "Africa\/Mogadishu": "Saa za Afrika Mashariki (Mogadishu)", + "Africa\/Monrovia": "Saa za Greenwich (Monrovia)", + "Africa\/Nairobi": "Saa za Afrika Mashariki (Nairobi)", + "Africa\/Ndjamena": "Saa za Afrika Magharibi (Ndjamena)", + "Africa\/Niamey": "Saa za Afrika Magharibi (Niamey)", + "Africa\/Nouakchott": "Saa za Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Saa za Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Saa za Afrika Magharibi (Porto-Novo)", + "Africa\/Sao_Tome": "Saa za Greenwich (Sao Tome)", + "Africa\/Tripoli": "Saa za Mashariki mwa Ulaya (Tripoli)", + "Africa\/Tunis": "Saa za Ulaya ya Kati (Tunis)", + "Africa\/Windhoek": "Saa za Afrika ya Kati (Windhoek)", + "America\/Adak": "Saa za Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Saa za Alaska (Anchorage)", + "America\/Anguilla": "Saa za Atlantiki (Anguilla)", + "America\/Antigua": "Saa za Atlantiki (Antigua)", + "America\/Araguaina": "Saa za Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "Saa za Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Saa za Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Saa za Argentina (Salta)", + "America\/Argentina\/San_Juan": "Saa za Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Saa za Magharibi mwa Argentina (San Luis)", + "America\/Argentina\/Tucuman": "Saa za Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Saa za Argentina (Ushuaia)", + "America\/Aruba": "Saa za Atlantiki (Aruba)", + "America\/Asuncion": "Saa za Paraguay (Asuncion)", + "America\/Bahia": "Saa za Brasilia (Bahia)", + "America\/Bahia_Banderas": "Saa za Kati (Bahia Banderas)", + "America\/Barbados": "Saa za Atlantiki (Barbados)", + "America\/Belem": "Saa za Brasilia (Belem)", + "America\/Belize": "Saa za Kati (Belize)", + "America\/Blanc-Sablon": "Saa za Atlantiki (Blanc-Sablon)", + "America\/Boa_Vista": "Saa za Amazon (Boa Vista)", + "America\/Bogota": "Saa za Colombia (Bogota)", + "America\/Boise": "Saa za Mountain (Boise)", + "America\/Buenos_Aires": "Saa za Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Saa za Mountain (Cambridge Bay)", + "America\/Campo_Grande": "Saa za Amazon (Campo Grande)", + "America\/Cancun": "Saa za Mashariki (Cancun)", + "America\/Caracas": "Saa za Venezuela (Caracas)", + "America\/Catamarca": "Saa za Argentina (Catamarca)", + "America\/Cayenne": "Saa za Guiana ya Ufaransa (Cayenne)", + "America\/Cayman": "Saa za Mashariki (Cayman)", + "America\/Chicago": "Saa za Kati (Chicago)", + "America\/Chihuahua": "Saa za pasifiki za Mexico (Chihuahua)", + "America\/Coral_Harbour": "Saa za Mashariki (Atikokan)", + "America\/Cordoba": "Saa za Argentina (Cordoba)", + "America\/Costa_Rica": "Saa za Kati (Costa Rica)", + "America\/Creston": "Saa za Mountain (Creston)", + "America\/Cuiaba": "Saa za Amazon (Cuiaba)", + "America\/Curacao": "Saa za Atlantiki (Curacao)", + "America\/Danmarkshavn": "Saa za Greenwich (Danmarkshavn)", + "America\/Dawson": "Saa za Pasifiki (Dawson)", + "America\/Dawson_Creek": "Saa za Mountain (Dawson Creek)", + "America\/Denver": "Saa za Mountain (Denver)", + "America\/Detroit": "Saa za Mashariki (Detroit)", + "America\/Dominica": "Saa za Atlantiki (Dominica)", + "America\/Edmonton": "Saa za Mountain (Edmonton)", + "America\/El_Salvador": "Saa za Kati (El Salvador)", + "America\/Fort_Nelson": "Saa za Mountain (Fort Nelson)", + "America\/Fortaleza": "Saa za Brasilia (Fortaleza)", + "America\/Glace_Bay": "Saa za Atlantiki (Glace Bay)", + "America\/Godthab": "Saa za Greenland Magharibi (Nuuk)", + "America\/Goose_Bay": "Saa za Atlantiki (Goose Bay)", + "America\/Grand_Turk": "Saa za Mashariki (Grand Turk)", + "America\/Grenada": "Saa za Atlantiki (Grenada)", + "America\/Guadeloupe": "Saa za Atlantiki (Guadeloupe)", + "America\/Guatemala": "Saa za Kati (Guatemala)", + "America\/Guayaquil": "Saa za Ecuador (Guayaquil)", + "America\/Guyana": "Saa za Guyana (Guyana)", + "America\/Halifax": "Saa za Atlantiki (Halifax)", + "America\/Havana": "Saa za Cuba (Havana)", + "America\/Hermosillo": "Saa za pasifiki za Mexico (Hermosillo)", + "America\/Indiana\/Knox": "Saa za Kati (Knox, Indiana)", + "America\/Indiana\/Marengo": "Saa za Mashariki (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Saa za Mashariki (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Saa za Kati (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Saa za Mashariki (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Saa za Mashariki (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Saa za Mashariki (Winamac, Indiana)", + "America\/Indianapolis": "Saa za Mashariki (Indianapolis)", + "America\/Inuvik": "Saa za Mountain (Inuvik)", + "America\/Iqaluit": "Saa za Mashariki (Iqaluit)", + "America\/Jamaica": "Saa za Mashariki (Jamaica)", + "America\/Jujuy": "Saa za Argentina (Jujuy)", + "America\/Juneau": "Saa za Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Saa za Mashariki (Monticello, Kentucky)", + "America\/Kralendijk": "Saa za Atlantiki (Kralendijk)", + "America\/La_Paz": "Saa za Bolivia (La Paz)", + "America\/Lima": "Saa za Peru (Lima)", + "America\/Los_Angeles": "Saa za Pasifiki (Los Angeles)", + "America\/Louisville": "Saa za Mashariki (Louisville)", + "America\/Lower_Princes": "Saa za Atlantiki (Lower Prince’s Quarter)", + "America\/Maceio": "Saa za Brasilia (Maceio)", + "America\/Managua": "Saa za Kati (Managua)", + "America\/Manaus": "Saa za Amazon (Manaus)", + "America\/Marigot": "Saa za Atlantiki (Marigot)", + "America\/Martinique": "Saa za Atlantiki (Martinique)", + "America\/Matamoros": "Saa za Kati (Matamoros)", + "America\/Mazatlan": "Saa za pasifiki za Mexico (Mazatlan)", + "America\/Mendoza": "Saa za Argentina (Mendoza)", + "America\/Menominee": "Saa za Kati (Menominee)", + "America\/Merida": "Saa za Kati (Merida)", + "America\/Metlakatla": "Saa za Alaska (Metlakatla)", + "America\/Mexico_City": "Saa za Kati (Jiji la Mexico)", + "America\/Miquelon": "Saa za Saint-Pierre na Miquelon (Miquelon)", + "America\/Moncton": "Saa za Atlantiki (Moncton)", + "America\/Monterrey": "Saa za Kati (Monterrey)", + "America\/Montevideo": "Saa za Uruguay (Montevideo)", + "America\/Montserrat": "Saa za Atlantiki (Montserrat)", + "America\/Nassau": "Saa za Mashariki (Nassau)", + "America\/New_York": "Saa za Mashariki (New York)", + "America\/Nipigon": "Saa za Mashariki (Nipigon)", + "America\/Nome": "Saa za Alaska (Nome)", + "America\/Noronha": "Saa za Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Saa za Kati (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Saa za Kati (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Saa za Kati (New Salem, North Dakota)", + "America\/Ojinaga": "Saa za Mountain (Ojinaga)", + "America\/Panama": "Saa za Mashariki (Panama)", + "America\/Pangnirtung": "Saa za Mashariki (Pangnirtung)", + "America\/Paramaribo": "Saa za Suriname (Paramaribo)", + "America\/Phoenix": "Saa za Mountain (Phoenix)", + "America\/Port-au-Prince": "Saa za Mashariki (Port-au-Prince)", + "America\/Port_of_Spain": "Saa za Atlantiki (Port of Spain)", + "America\/Porto_Velho": "Saa za Amazon (Porto Velho)", + "America\/Puerto_Rico": "Saa za Atlantiki (Puerto Rico)", + "America\/Punta_Arenas": "Saa za Chile (Punta Arenas)", + "America\/Rainy_River": "Saa za Kati (Rainy River)", + "America\/Rankin_Inlet": "Saa za Kati (Rankin Inlet)", + "America\/Recife": "Saa za Brasilia (Recife)", + "America\/Regina": "Saa za Kati (Regina)", + "America\/Resolute": "Saa za Kati (Resolute)", + "America\/Santa_Isabel": "Saa za Mexico Kaskazini Magharibi (Santa Isabel)", + "America\/Santarem": "Saa za Brasilia (Santarem)", + "America\/Santiago": "Saa za Chile (Santiago)", + "America\/Santo_Domingo": "Saa za Atlantiki (Santo Domingo)", + "America\/Sao_Paulo": "Saa za Brasilia (Sao Paulo)", + "America\/Scoresbysund": "Saa za Greenland Mashariki (Ittoqqortoormiit)", + "America\/Sitka": "Saa za Alaska (Sitka)", + "America\/St_Barthelemy": "Saa za Atlantiki (St. Barthelemy)", + "America\/St_Johns": "Saa za Newfoundland (St. John’s)", + "America\/St_Kitts": "Saa za Atlantiki (St. Kitts)", + "America\/St_Lucia": "Saa za Atlantiki (St. Lucia)", + "America\/St_Thomas": "Saa za Atlantiki (St. Thomas)", + "America\/St_Vincent": "Saa za Atlantiki (St. Vincent)", + "America\/Swift_Current": "Saa za Kati (Swift Current)", + "America\/Tegucigalpa": "Saa za Kati (Tegucigalpa)", + "America\/Thule": "Saa za Atlantiki (Thule)", + "America\/Thunder_Bay": "Saa za Mashariki (Thunder Bay)", + "America\/Tijuana": "Saa za Pasifiki (Tijuana)", + "America\/Toronto": "Saa za Mashariki (Toronto)", + "America\/Tortola": "Saa za Atlantiki (Tortola)", + "America\/Vancouver": "Saa za Pasifiki (Vancouver)", + "America\/Whitehorse": "Saa za Pasifiki (Whitehorse)", + "America\/Winnipeg": "Saa za Kati (Winnipeg)", + "America\/Yakutat": "Saa za Alaska (Yakutat)", + "America\/Yellowknife": "Saa za Mountain (Yellowknife)", + "Antarctica\/Casey": "Saa za Australia Magharibi (Casey)", + "Antarctica\/Davis": "Saa za Davis (Davis)", + "Antarctica\/DumontDUrville": "Saa za Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Saa za kisiwa cha Macquarie (Macquarie)", + "Antarctica\/Mawson": "Saa za Mawson (Mawson)", + "Antarctica\/McMurdo": "Saa za New Zealand (McMurdo)", + "Antarctica\/Palmer": "Saa za Chile (Palmer)", + "Antarctica\/Rothera": "Saa za Rothera (Rothera)", + "Antarctica\/Syowa": "Saa za Syowa (Syowa)", + "Antarctica\/Troll": "Saa za Greenwich (Troll)", + "Antarctica\/Vostok": "Saa za Vostok (Vostok)", + "Arctic\/Longyearbyen": "Saa za Ulaya ya Kati (Longyearbyen)", + "Asia\/Aden": "Saa za Uarabuni (Aden)", + "Asia\/Almaty": "Saa za Kazakhstan Mashariki (Almaty)", + "Asia\/Amman": "Saa za Mashariki mwa Ulaya (Amman)", + "Asia\/Anadyr": "Saa za Anadyr (Anadyr)", + "Asia\/Aqtau": "Saa za Kazakhstan Magharibi (Aqtau)", + "Asia\/Aqtobe": "Saa za Kazakhstan Magharibi (Aqtobe)", + "Asia\/Ashgabat": "Saa za Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Saa za Kazakhstan Magharibi (Atyrau)", + "Asia\/Baghdad": "Saa za Uarabuni (Baghdad)", + "Asia\/Bahrain": "Saa za Uarabuni (Bahrain)", + "Asia\/Baku": "Saa za Azerbaijan (Baku)", + "Asia\/Bangkok": "Saa za Indochina (Bangkok)", + "Asia\/Beirut": "Saa za Mashariki mwa Ulaya (Beirut)", + "Asia\/Bishkek": "Saa za Kyrgystan (Bishkek)", + "Asia\/Brunei": "Saa za Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Saa Wastani za India (Kolkata)", + "Asia\/Chita": "Saa za Yakutsk (Chita)", + "Asia\/Choibalsan": "Saa za Choibalsan (Choibalsan)", + "Asia\/Colombo": "Saa Wastani za India (Colombo)", + "Asia\/Damascus": "Saa za Mashariki mwa Ulaya (Damascus)", + "Asia\/Dhaka": "Saa za Bangladesh (Dhaka)", + "Asia\/Dili": "Saa za Timor Mashariki (Dili)", + "Asia\/Dubai": "Saa za Wastani za Gulf (Dubai)", + "Asia\/Dushanbe": "Saa za Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Saa za Mashariki mwa Ulaya (Famagusta)", + "Asia\/Gaza": "Saa za Mashariki mwa Ulaya (Gaza)", + "Asia\/Hebron": "Saa za Mashariki mwa Ulaya (Hebron)", + "Asia\/Hong_Kong": "Saa za Hong Kong (Hong Kong)", + "Asia\/Hovd": "Saa za Hovd (Hovd)", + "Asia\/Irkutsk": "Saa za Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Saa za Magharibi mwa Indonesia (Jakarta)", + "Asia\/Jayapura": "Saa za Mashariki mwa Indonesia (Jayapura)", + "Asia\/Jerusalem": "Saa za Israeli (Jerusalem)", + "Asia\/Kabul": "Saa za Afghanistan (Kabul)", + "Asia\/Kamchatka": "Saa za Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Saa za Pakistan (Karachi)", + "Asia\/Katmandu": "Saa za Nepal (Kathmandu)", + "Asia\/Khandyga": "Saa za Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Saa za Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Saa za Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Saa za Malaysia (Kuching)", + "Asia\/Kuwait": "Saa za Uarabuni (Kuwait)", + "Asia\/Macau": "Saa za Uchina (Macau)", + "Asia\/Magadan": "Saa za Magadan (Magadan)", + "Asia\/Makassar": "Saa za Indonesia ya Kati (Makassar)", + "Asia\/Manila": "Saa za Ufilipino (Manila)", + "Asia\/Muscat": "Saa za Wastani za Gulf (Muscat)", + "Asia\/Nicosia": "Saa za Mashariki mwa Ulaya (Nicosia)", + "Asia\/Novokuznetsk": "Saa za Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Saa za Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Saa za Omsk (Omsk)", + "Asia\/Oral": "Saa za Kazakhstan Magharibi (Oral)", + "Asia\/Phnom_Penh": "Saa za Indochina (Phnom Penh)", + "Asia\/Pontianak": "Saa za Magharibi mwa Indonesia (Pontianak)", + "Asia\/Pyongyang": "Saa za Korea (Pyongyang)", + "Asia\/Qatar": "Saa za Uarabuni (Qatar)", + "Asia\/Qostanay": "Saa za Kazakhstan Mashariki (Qostanay)", + "Asia\/Qyzylorda": "Saa za Kazakhstan Magharibi (Qyzylorda)", + "Asia\/Rangoon": "Saa za Myanmar (Rangoon)", + "Asia\/Riyadh": "Saa za Uarabuni (Riyadh)", + "Asia\/Saigon": "Saa za Indochina (Ho Chi Minh)", + "Asia\/Sakhalin": "Saa za Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Saa za Uzbekistan (Samarkand)", + "Asia\/Seoul": "Saa za Korea (Seoul)", + "Asia\/Shanghai": "Saa za Uchina (Shanghai)", + "Asia\/Singapore": "Saa za Wastani za Singapore (Singapore)", + "Asia\/Srednekolymsk": "Saa za Magadan (Srednekolymsk)", + "Asia\/Taipei": "Saa za Taipei (Taipei)", + "Asia\/Tashkent": "Saa za Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Saa za Georgia (Tbilisi)", + "Asia\/Tehran": "Saa za Iran (Tehran)", + "Asia\/Thimphu": "Saa za Bhutan (Thimphu)", + "Asia\/Tokyo": "Saa za Japan (Tokyo)", + "Asia\/Ulaanbaatar": "Saa za Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Saa za Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Saa za Indochina (Vientiane)", + "Asia\/Vladivostok": "Saa za Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Saa za Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Saa za Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Saa za Armenia (Yerevan)", + "Atlantic\/Azores": "Saa za Azores (Azores)", + "Atlantic\/Bermuda": "Saa za Atlantiki (Bermuda)", + "Atlantic\/Canary": "Saa za Magharibi mwa Ulaya (Canary)", + "Atlantic\/Cape_Verde": "Saa za Cape Verde (Cape Verde)", + "Atlantic\/Faeroe": "Saa za Magharibi mwa Ulaya (Faroe)", + "Atlantic\/Madeira": "Saa za Magharibi mwa Ulaya (Madeira)", + "Atlantic\/Reykjavik": "Saa za Greenwich (Reykjavik)", + "Atlantic\/South_Georgia": "Saa za Georgia Kusini (Georgia Kusini)", + "Atlantic\/St_Helena": "Saa za Greenwich (St. Helena)", + "Atlantic\/Stanley": "Saa za Visiwa vya Falkland (Stanley)", + "Australia\/Adelaide": "Saa za Australia ya Kati (Adelaide)", + "Australia\/Brisbane": "Saa za Australia Mashariki (Brisbane)", + "Australia\/Broken_Hill": "Saa za Australia ya Kati (Broken Hill)", + "Australia\/Currie": "Saa za Australia Mashariki (Currie)", + "Australia\/Darwin": "Saa za Australia ya Kati (Darwin)", + "Australia\/Eucla": "Saa za Magharibi ya Kati ya Australia (Eucla)", + "Australia\/Hobart": "Saa za Australia Mashariki (Hobart)", + "Australia\/Lindeman": "Saa za Australia Mashariki (Lindeman)", + "Australia\/Lord_Howe": "Saa za Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Saa za Australia Mashariki (Melbourne)", + "Australia\/Perth": "Saa za Australia Magharibi (Perth)", + "Australia\/Sydney": "Saa za Australia Mashariki (Sydney)", + "CST6CDT": "Saa za Kati", + "EST5EDT": "Saa za Mashariki", + "Etc\/GMT": "Saa za Greenwich", + "Etc\/UTC": "Mfumo wa kuratibu saa ulimwenguni", + "Europe\/Amsterdam": "Saa za Ulaya ya Kati (Amsterdam)", + "Europe\/Andorra": "Saa za Ulaya ya Kati (Andorra)", + "Europe\/Astrakhan": "Saa za Moscow (Astrakhan)", + "Europe\/Athens": "Saa za Mashariki mwa Ulaya (Athens)", + "Europe\/Belgrade": "Saa za Ulaya ya Kati (Belgrade)", + "Europe\/Berlin": "Saa za Ulaya ya Kati (Berlin)", + "Europe\/Bratislava": "Saa za Ulaya ya Kati (Bratislava)", + "Europe\/Brussels": "Saa za Ulaya ya Kati (Brussels)", + "Europe\/Bucharest": "Saa za Mashariki mwa Ulaya (Bucharest)", + "Europe\/Budapest": "Saa za Ulaya ya Kati (Budapest)", + "Europe\/Busingen": "Saa za Ulaya ya Kati (Busingen)", + "Europe\/Chisinau": "Saa za Mashariki mwa Ulaya (Chisinau)", + "Europe\/Copenhagen": "Saa za Ulaya ya Kati (Copenhagen)", + "Europe\/Dublin": "Saa za Greenwich (Dublin)", + "Europe\/Gibraltar": "Saa za Ulaya ya Kati (Gibraltar)", + "Europe\/Guernsey": "Saa za Greenwich (Guernsey)", + "Europe\/Helsinki": "Saa za Mashariki mwa Ulaya (Helsinki)", + "Europe\/Isle_of_Man": "Saa za Greenwich (Isle of Man)", + "Europe\/Jersey": "Saa za Greenwich (Jersey)", + "Europe\/Kaliningrad": "Saa za Mashariki mwa Ulaya (Kaliningrad)", + "Europe\/Kiev": "Saa za Mashariki mwa Ulaya (Kiev)", + "Europe\/Lisbon": "Saa za Magharibi mwa Ulaya (Lisbon)", + "Europe\/Ljubljana": "Saa za Ulaya ya Kati (Ljubljana)", + "Europe\/London": "Saa za Greenwich (London)", + "Europe\/Luxembourg": "Saa za Ulaya ya Kati (Luxembourg)", + "Europe\/Madrid": "Saa za Ulaya ya Kati (Madrid)", + "Europe\/Malta": "Saa za Ulaya ya Kati (Malta)", + "Europe\/Mariehamn": "Saa za Mashariki mwa Ulaya (Mariehamn)", + "Europe\/Minsk": "Saa za Moscow (Minsk)", + "Europe\/Monaco": "Saa za Ulaya ya Kati (Monaco)", + "Europe\/Moscow": "Saa za Moscow (Moscow)", + "Europe\/Oslo": "Saa za Ulaya ya Kati (Oslo)", + "Europe\/Paris": "Saa za Ulaya ya Kati (Paris)", + "Europe\/Podgorica": "Saa za Ulaya ya Kati (Podgorica)", + "Europe\/Prague": "Saa za Ulaya ya Kati (Prague)", + "Europe\/Riga": "Saa za Mashariki mwa Ulaya (Riga)", + "Europe\/Rome": "Saa za Ulaya ya Kati (Rome)", + "Europe\/Samara": "Saa za Samara (Samara)", + "Europe\/San_Marino": "Saa za Ulaya ya Kati (San Marino)", + "Europe\/Sarajevo": "Saa za Ulaya ya Kati (Sarajevo)", + "Europe\/Saratov": "Saa za Moscow (Saratov)", + "Europe\/Simferopol": "Saa za Moscow (Simferopol)", + "Europe\/Skopje": "Saa za Ulaya ya Kati (Skopje)", + "Europe\/Sofia": "Saa za Mashariki mwa Ulaya (Sofia)", + "Europe\/Stockholm": "Saa za Ulaya ya Kati (Stockholm)", + "Europe\/Tallinn": "Saa za Mashariki mwa Ulaya (Tallinn)", + "Europe\/Tirane": "Saa za Ulaya ya Kati (Tirane)", + "Europe\/Ulyanovsk": "Saa za Moscow (Ulyanovsk)", + "Europe\/Uzhgorod": "Saa za Mashariki mwa Ulaya (Uzhgorod)", + "Europe\/Vaduz": "Saa za Ulaya ya Kati (Vaduz)", + "Europe\/Vatican": "Saa za Ulaya ya Kati (Vatican)", + "Europe\/Vienna": "Saa za Ulaya ya Kati (Vienna)", + "Europe\/Vilnius": "Saa za Mashariki mwa Ulaya (Vilnius)", + "Europe\/Volgograd": "Saa za Volgograd (Volgograd)", + "Europe\/Warsaw": "Saa za Ulaya ya Kati (Warsaw)", + "Europe\/Zagreb": "Saa za Ulaya ya Kati (Zagreb)", + "Europe\/Zaporozhye": "Saa za Mashariki mwa Ulaya (Zaporozhye)", + "Europe\/Zurich": "Saa za Ulaya ya Kati (Zurich)", + "Indian\/Antananarivo": "Saa za Afrika Mashariki (Antananarivo)", + "Indian\/Chagos": "Saa za Bahari Hindi (Chagos)", + "Indian\/Christmas": "Saa za Kisiwa cha Christmas (Christmas)", + "Indian\/Cocos": "Saa za Visiwa vya Cocos (Cocos)", + "Indian\/Comoro": "Saa za Afrika Mashariki (Comoro)", + "Indian\/Kerguelen": "Saa za Kusini mwa Ufaransa na Antaktiki (Kerguelen)", + "Indian\/Mahe": "Saa za Ushelisheli (Mahe)", + "Indian\/Maldives": "Saa za Maldives (Maldives)", + "Indian\/Mauritius": "Saa za Mauritius (Mauritius)", + "Indian\/Mayotte": "Saa za Afrika Mashariki (Mayotte)", + "Indian\/Reunion": "Saa za Reunion (Reunion)", + "MST7MDT": "Saa za Mountain", + "PST8PDT": "Saa za Pasifiki", + "Pacific\/Apia": "Saa za Apia (Apia)", + "Pacific\/Auckland": "Saa za New Zealand (Auckland)", + "Pacific\/Bougainville": "Saa za Papua New Guinea (Bougainville)", + "Pacific\/Chatham": "Saa za Chatham (Chatham)", + "Pacific\/Easter": "Saa za Kisiwa cha Easter (Easter)", + "Pacific\/Efate": "Saa za Vanuatu (Efate)", + "Pacific\/Enderbury": "Saa za Visiwa vya Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Saa za Tokelau (Fakaofo)", + "Pacific\/Fiji": "Saa za Fiji (Fiji)", + "Pacific\/Funafuti": "Saa za Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Saa za Galapagos (Galapagos)", + "Pacific\/Gambier": "Saa za Gambier (Gambier)", + "Pacific\/Guadalcanal": "Saa za Visiwa vya Solomon (Guadalcanal)", + "Pacific\/Guam": "Saa za Wastani za Chamorro (Guam)", + "Pacific\/Honolulu": "Saa za Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Saa za Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Saa za Visiwa vya Line (Kiritimati)", + "Pacific\/Kosrae": "Saa za Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Saa za Visiwa vya Marshall (Kwajalein)", + "Pacific\/Majuro": "Saa za Visiwa vya Marshall (Majuro)", + "Pacific\/Marquesas": "Saa za Marquesas (Marquesas)", + "Pacific\/Midway": "Saa za Samoa (Midway)", + "Pacific\/Nauru": "Saa za Nauru (Nauru)", + "Pacific\/Niue": "Saa za Niue (Niue)", + "Pacific\/Norfolk": "Saa za Kisiwa cha Norfolk (Norfolk)", + "Pacific\/Noumea": "Saa za New Caledonia (Noumea)", + "Pacific\/Pago_Pago": "Saa za Samoa (Pago Pago)", + "Pacific\/Palau": "Saa za Palau (Palau)", + "Pacific\/Pitcairn": "Saa za Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Saa za Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Saa za Papua New Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Saa za Visiwa vya Cook (Rarotonga)", + "Pacific\/Saipan": "Saa za Wastani za Chamorro (Saipan)", + "Pacific\/Tahiti": "Saa za Tahiti (Tahiti)", + "Pacific\/Tarawa": "Saa za Visiwa vya Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Saa za Tonga (Tongatapu)", + "Pacific\/Truk": "Saa za Chuuk (Chuuk)", + "Pacific\/Wake": "Saa za Kisiwa cha Wake (Wake)", + "Pacific\/Wallis": "Saa za Wallis na Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ta.json b/src/Symfony/Component/Intl/Resources/data/timezones/ta.json new file mode 100644 index 0000000000000..3efd614146c80 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ta.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "கிரீன்விச் சராசரி நேரம் (அபிட்ஜான்)", + "Africa\/Accra": "கிரீன்விச் சராசரி நேரம் (அக்ரா)", + "Africa\/Addis_Ababa": "கிழக்கு ஆப்பிரிக்க நேரம் (அடிஸ் அபாபா)", + "Africa\/Algiers": "மத்திய ஐரோப்பிய நேரம் (அல்ஜியர்ஸ்)", + "Africa\/Asmera": "கிழக்கு ஆப்பிரிக்க நேரம் (அஸ்மாரா)", + "Africa\/Bamako": "கிரீன்விச் சராசரி நேரம் (பமாகோ)", + "Africa\/Bangui": "மேற்கு ஆப்பிரிக்க நேரம் (பாங்குயீ)", + "Africa\/Banjul": "கிரீன்விச் சராசரி நேரம் (பஞ்சுல்)", + "Africa\/Bissau": "கிரீன்விச் சராசரி நேரம் (பிஸாவ்)", + "Africa\/Blantyre": "மத்திய ஆப்பிரிக்க நேரம் (பிளான்டையர்)", + "Africa\/Brazzaville": "மேற்கு ஆப்பிரிக்க நேரம் (பிராஸாவில்லி)", + "Africa\/Bujumbura": "மத்திய ஆப்பிரிக்க நேரம் (புஜும்புரா)", + "Africa\/Cairo": "கிழக்கத்திய ஐரோப்பிய நேரம் (கெய்ரோ)", + "Africa\/Casablanca": "மேற்கத்திய ஐரோப்பிய நேரம் (காஸாபிளான்கா)", + "Africa\/Ceuta": "மத்திய ஐரோப்பிய நேரம் (சியூட்டா)", + "Africa\/Conakry": "கிரீன்விச் சராசரி நேரம் (கோனக்ரே)", + "Africa\/Dakar": "கிரீன்விச் சராசரி நேரம் (டாகர்)", + "Africa\/Dar_es_Salaam": "கிழக்கு ஆப்பிரிக்க நேரம் (தார் எஸ் சலாம்)", + "Africa\/Djibouti": "கிழக்கு ஆப்பிரிக்க நேரம் (ஜிபௌட்டி)", + "Africa\/Douala": "மேற்கு ஆப்பிரிக்க நேரம் (தவுலா)", + "Africa\/El_Aaiun": "மேற்கத்திய ஐரோப்பிய நேரம் (எல் ஆயுன்)", + "Africa\/Freetown": "கிரீன்விச் சராசரி நேரம் (ஃப்ரீடவுன்)", + "Africa\/Gaborone": "மத்திய ஆப்பிரிக்க நேரம் (கபோரோன்)", + "Africa\/Harare": "மத்திய ஆப்பிரிக்க நேரம் (ஹராரே)", + "Africa\/Johannesburg": "தென் ஆப்பிரிக்க நிலையான நேரம் (ஜோஹன்னஸ்பெர்க்)", + "Africa\/Juba": "கிழக்கு ஆப்பிரிக்க நேரம் (ஜுபா)", + "Africa\/Kampala": "கிழக்கு ஆப்பிரிக்க நேரம் (கம்பாலா)", + "Africa\/Khartoum": "மத்திய ஆப்பிரிக்க நேரம் (கார்டோம்)", + "Africa\/Kigali": "மத்திய ஆப்பிரிக்க நேரம் (கிகலி)", + "Africa\/Kinshasa": "மேற்கு ஆப்பிரிக்க நேரம் (கின்ஷசா)", + "Africa\/Lagos": "மேற்கு ஆப்பிரிக்க நேரம் (லாகோஸ்)", + "Africa\/Libreville": "மேற்கு ஆப்பிரிக்க நேரம் (லிப்ரேவில்லே)", + "Africa\/Lome": "கிரீன்விச் சராசரி நேரம் (லோம்)", + "Africa\/Luanda": "மேற்கு ஆப்பிரிக்க நேரம் (லுவான்டா)", + "Africa\/Lubumbashi": "மத்திய ஆப்பிரிக்க நேரம் (லுபும்பாஷி)", + "Africa\/Lusaka": "மத்திய ஆப்பிரிக்க நேரம் (லுசாகா)", + "Africa\/Malabo": "மேற்கு ஆப்பிரிக்க நேரம் (மாலபோ)", + "Africa\/Maputo": "மத்திய ஆப்பிரிக்க நேரம் (மபுடோ)", + "Africa\/Maseru": "தென் ஆப்பிரிக்க நிலையான நேரம் (மசேரு)", + "Africa\/Mbabane": "தென் ஆப்பிரிக்க நிலையான நேரம் (பபான்)", + "Africa\/Mogadishu": "கிழக்கு ஆப்பிரிக்க நேரம் (மொகாதிஷு)", + "Africa\/Monrovia": "கிரீன்விச் சராசரி நேரம் (மான்ரோவியா)", + "Africa\/Nairobi": "கிழக்கு ஆப்பிரிக்க நேரம் (நைரோபி)", + "Africa\/Ndjamena": "மேற்கு ஆப்பிரிக்க நேரம் (ஜமேனா)", + "Africa\/Niamey": "மேற்கு ஆப்பிரிக்க நேரம் (நியாமே)", + "Africa\/Nouakchott": "கிரீன்விச் சராசரி நேரம் (நோவாக்சோட்)", + "Africa\/Ouagadougou": "கிரீன்விச் சராசரி நேரம் (அவுகடவ்கு)", + "Africa\/Porto-Novo": "மேற்கு ஆப்பிரிக்க நேரம் (போர்ட்டோ-நோவோ)", + "Africa\/Sao_Tome": "கிரீன்விச் சராசரி நேரம் (சாவோ டோமே)", + "Africa\/Tripoli": "கிழக்கத்திய ஐரோப்பிய நேரம் (த்ரிபோலி)", + "Africa\/Tunis": "மத்திய ஐரோப்பிய நேரம் (டுனிஸ்)", + "Africa\/Windhoek": "மத்திய ஆப்பிரிக்க நேரம் (வைண்ட்ஹோக்)", + "America\/Adak": "ஹவாய்-அலேஷியன் நேரம் (அடக்)", + "America\/Anchorage": "அலாஸ்கா நேரம் (அங்கோரேஜ்)", + "America\/Anguilla": "அட்லாண்டிக் நேரம் (அங்குயுலா)", + "America\/Antigua": "அட்லாண்டிக் நேரம் (ஆன்டிகுவா)", + "America\/Araguaina": "பிரேசிலியா நேரம் (அரகுவாய்னா)", + "America\/Argentina\/La_Rioja": "அர்ஜென்டினா நேரம் (லா ரியோஜா)", + "America\/Argentina\/Rio_Gallegos": "அர்ஜென்டினா நேரம் (ரியோ கேலெகோஸ்)", + "America\/Argentina\/Salta": "அர்ஜென்டினா நேரம் (சால்டா)", + "America\/Argentina\/San_Juan": "அர்ஜென்டினா நேரம் (சான் ஜுவான்)", + "America\/Argentina\/San_Luis": "மேற்கத்திய அர்ஜென்டினா நேரம் (சான் லூயிஸ்)", + "America\/Argentina\/Tucuman": "அர்ஜென்டினா நேரம் (டுகுமன்)", + "America\/Argentina\/Ushuaia": "அர்ஜென்டினா நேரம் (உஷுவாயா)", + "America\/Aruba": "அட்லாண்டிக் நேரம் (அரூபா)", + "America\/Asuncion": "பராகுவே நேரம் (அஸன்சியன்)", + "America\/Bahia": "பிரேசிலியா நேரம் (பாஹியா)", + "America\/Bahia_Banderas": "மத்திய நேரம் (பஹியா பந்தேராஸ்)", + "America\/Barbados": "அட்லாண்டிக் நேரம் (பார்படாஸ்)", + "America\/Belem": "பிரேசிலியா நேரம் (பெலெம்)", + "America\/Belize": "மத்திய நேரம் (பெலிஸ்)", + "America\/Blanc-Sablon": "அட்லாண்டிக் நேரம் (ப்லாங்க்-சப்லான்)", + "America\/Boa_Vista": "அமேசான் நேரம் (போவா விஸ்டா)", + "America\/Bogota": "கொலம்பியா நேரம் (போகோடா)", + "America\/Boise": "மவுன்டைன் நேரம் (போய்ஸ்)", + "America\/Buenos_Aires": "அர்ஜென்டினா நேரம் (ப்யூனோஸ் ஏர்ஸ்)", + "America\/Cambridge_Bay": "மவுன்டைன் நேரம் (கேம்பிரிட்ஜ் வளைகுடா)", + "America\/Campo_Grande": "அமேசான் நேரம் (கேம்போ கிராண்டே)", + "America\/Cancun": "கிழக்கத்திய நேரம் (கன்குன்)", + "America\/Caracas": "வெனிசுலா நேரம் (கரகாஸ்)", + "America\/Catamarca": "அர்ஜென்டினா நேரம் (கடமார்கா)", + "America\/Cayenne": "ஃபிரஞ்சு கயானா நேரம் (கெய்ன்)", + "America\/Cayman": "கிழக்கத்திய நேரம் (கேமன்)", + "America\/Chicago": "மத்திய நேரம் (சிகாகோ)", + "America\/Chihuahua": "மெக்ஸிகன் பசிபிக் நேரம் (சுவாவா)", + "America\/Coral_Harbour": "கிழக்கத்திய நேரம் (அடிகோகன்)", + "America\/Cordoba": "அர்ஜென்டினா நேரம் (கார்டோபா)", + "America\/Costa_Rica": "மத்திய நேரம் (கோஸ்டா ரிகா)", + "America\/Creston": "மவுன்டைன் நேரம் (க்ரெஸ்டான்)", + "America\/Cuiaba": "அமேசான் நேரம் (குயாபே)", + "America\/Curacao": "அட்லாண்டிக் நேரம் (க்யூராகோ)", + "America\/Danmarkshavn": "கிரீன்விச் சராசரி நேரம் (டென்மார்க்ஷாவ்ன்)", + "America\/Dawson": "பசிபிக் நேரம் (டாவ்சன்)", + "America\/Dawson_Creek": "மவுன்டைன் நேரம் (டாவ்சன் கிரீக்)", + "America\/Denver": "மவுன்டைன் நேரம் (டென்வர்)", + "America\/Detroit": "கிழக்கத்திய நேரம் (டெட்ராய்ட்)", + "America\/Dominica": "அட்லாண்டிக் நேரம் (டொமினிகா)", + "America\/Edmonton": "மவுன்டைன் நேரம் (எட்மான்டான்)", + "America\/Eirunepe": "அக்ரே நேரம் (ஈருனெபே)", + "America\/El_Salvador": "மத்திய நேரம் (எல் சால்வடோர்)", + "America\/Fort_Nelson": "மவுன்டைன் நேரம் (ஃபோர்ட் நெல்சன்)", + "America\/Fortaleza": "பிரேசிலியா நேரம் (ஃபோர்டாலெசா)", + "America\/Glace_Bay": "அட்லாண்டிக் நேரம் (கிலேஸ் வளைகுடா)", + "America\/Godthab": "மேற்கு கிரீன்லாந்து நேரம் (நூக்)", + "America\/Goose_Bay": "அட்லாண்டிக் நேரம் (கூஸ் பே)", + "America\/Grand_Turk": "கிழக்கத்திய நேரம் (கிராண்ட் டர்க்)", + "America\/Grenada": "அட்லாண்டிக் நேரம் (கிரனடா)", + "America\/Guadeloupe": "அட்லாண்டிக் நேரம் (கவுடேலூப்)", + "America\/Guatemala": "மத்திய நேரம் (கவுதமாலா)", + "America\/Guayaquil": "ஈக்வடார் நேரம் (குவாயகில்)", + "America\/Guyana": "கயானா நேரம் (கயானா)", + "America\/Halifax": "அட்லாண்டிக் நேரம் (ஹலிஃபேக்ஸ்)", + "America\/Havana": "கியூபா நேரம் (ஹவானா)", + "America\/Hermosillo": "மெக்ஸிகன் பசிபிக் நேரம் (ஹெர்மோசிலோ)", + "America\/Indiana\/Knox": "மத்திய நேரம் (நாக்ஸ், இண்டியானா)", + "America\/Indiana\/Marengo": "கிழக்கத்திய நேரம் (மரென்கோ, இண்டியானா)", + "America\/Indiana\/Petersburg": "கிழக்கத்திய நேரம் (பீட்டர்ஸ்பெர்க், இண்டியானா)", + "America\/Indiana\/Tell_City": "மத்திய நேரம் (டெல் சிட்டி, இண்டியானா)", + "America\/Indiana\/Vevay": "கிழக்கத்திய நேரம் (வேவே, இண்டியானா)", + "America\/Indiana\/Vincennes": "கிழக்கத்திய நேரம் (வின்செனேஸ், இண்டியானா)", + "America\/Indiana\/Winamac": "கிழக்கத்திய நேரம் (வினாமேக், இண்டியானா)", + "America\/Indianapolis": "கிழக்கத்திய நேரம் (இண்டியானாபொலிஸ்)", + "America\/Inuvik": "மவுன்டைன் நேரம் (இனுவிக்)", + "America\/Iqaluit": "கிழக்கத்திய நேரம் (இகாலூயித்)", + "America\/Jamaica": "கிழக்கத்திய நேரம் (ஜமைக்கா)", + "America\/Jujuy": "அர்ஜென்டினா நேரம் (ஜூஜுய்)", + "America\/Juneau": "அலாஸ்கா நேரம் (ஜுனியூ)", + "America\/Kentucky\/Monticello": "கிழக்கத்திய நேரம் (மான்டிசெல்லோ, கென்டகி)", + "America\/Kralendijk": "அட்லாண்டிக் நேரம் (கிரெலன்டிஜ்)", + "America\/La_Paz": "பொலிவியா நேரம் (லா பாஸ்)", + "America\/Lima": "பெரு நேரம் (லிமா)", + "America\/Los_Angeles": "பசிபிக் நேரம் (லாஸ் ஏஞ்சல்ஸ்)", + "America\/Louisville": "கிழக்கத்திய நேரம் (லூயிஸ்வில்லே)", + "America\/Lower_Princes": "அட்லாண்டிக் நேரம் (லோயர் பிரின்ஸஸ் குவார்ட்டர்)", + "America\/Maceio": "பிரேசிலியா நேரம் (மேசியோ)", + "America\/Managua": "மத்திய நேரம் (மானாகுவா)", + "America\/Manaus": "அமேசான் நேரம் (மனாஸ்)", + "America\/Marigot": "அட்லாண்டிக் நேரம் (மாரிகாட்)", + "America\/Martinique": "அட்லாண்டிக் நேரம் (மார்ட்டினிக்)", + "America\/Matamoros": "மத்திய நேரம் (மடமோராஸ்)", + "America\/Mazatlan": "மெக்ஸிகன் பசிபிக் நேரம் (மஸட்லன்)", + "America\/Mendoza": "அர்ஜென்டினா நேரம் (மென்டோஸா)", + "America\/Menominee": "மத்திய நேரம் (மெனோமினி)", + "America\/Merida": "மத்திய நேரம் (மெரிடா)", + "America\/Metlakatla": "அலாஸ்கா நேரம் (மெட்லகட்லா)", + "America\/Mexico_City": "மத்திய நேரம் (மெக்ஸிகோ நகரம்)", + "America\/Miquelon": "செயின்ட் பியரி & மிக்குயிலான் நேரம் (மிக்யூலன்)", + "America\/Moncton": "அட்லாண்டிக் நேரம் (மாங்டான்)", + "America\/Monterrey": "மத்திய நேரம் (மான்டெர்ரே)", + "America\/Montevideo": "உருகுவே நேரம் (மான்டேவீடியோ)", + "America\/Montserrat": "அட்லாண்டிக் நேரம் (மான்செரேட்)", + "America\/Nassau": "கிழக்கத்திய நேரம் (நசவ்)", + "America\/New_York": "கிழக்கத்திய நேரம் (நியூயார்க்)", + "America\/Nipigon": "கிழக்கத்திய நேரம் (நிபிகான்)", + "America\/Nome": "அலாஸ்கா நேரம் (நோம்)", + "America\/Noronha": "பெர்னாண்டோ டி நோரன்ஹா நேரம் (நோரன்ஹா)", + "America\/North_Dakota\/Beulah": "மத்திய நேரம் (பெவுலா, வடக்கு டகோட்டா)", + "America\/North_Dakota\/Center": "மத்திய நேரம் (சென்டர், வடக்கு டகோடா)", + "America\/North_Dakota\/New_Salem": "மத்திய நேரம் (நியூ சலேம், வடக்கு டகோடா)", + "America\/Ojinaga": "மவுன்டைன் நேரம் (ஒஜினகா)", + "America\/Panama": "கிழக்கத்திய நேரம் (பனாமா)", + "America\/Pangnirtung": "கிழக்கத்திய நேரம் (பாங்னிர்துங்)", + "America\/Paramaribo": "சுரினாம் நேரம் (பரமரிபோ)", + "America\/Phoenix": "மவுன்டைன் நேரம் (ஃபோனிக்ஸ்)", + "America\/Port-au-Prince": "கிழக்கத்திய நேரம் (போர்ட்-அவ்-பிரின்ஸ்)", + "America\/Port_of_Spain": "அட்லாண்டிக் நேரம் (போர்ட் ஆஃப் ஸ்பெயின்)", + "America\/Porto_Velho": "அமேசான் நேரம் (போர்ட்டோ வெல்ஹோ)", + "America\/Puerto_Rico": "அட்லாண்டிக் நேரம் (பியூர்டோ ரிகோ)", + "America\/Punta_Arenas": "சிலி நேரம் (புன்டா அரீனாஸ்)", + "America\/Rainy_River": "மத்திய நேரம் (ரெய்னி ரிவர்)", + "America\/Rankin_Inlet": "மத்திய நேரம் (ரான்கின் இன்லெட்)", + "America\/Recife": "பிரேசிலியா நேரம் (ரெஸிஃபி)", + "America\/Regina": "மத்திய நேரம் (ரெஜினா)", + "America\/Resolute": "மத்திய நேரம் (ரெசலூட்)", + "America\/Rio_Branco": "அக்ரே நேரம் (ரியோ பிரான்கோ)", + "America\/Santa_Isabel": "வடமேற்கு மெக்ஸிகோ நேரம் (சான்டா இசபெல்)", + "America\/Santarem": "பிரேசிலியா நேரம் (சான்டரெம்)", + "America\/Santiago": "சிலி நேரம் (சாண்டியாகோ)", + "America\/Santo_Domingo": "அட்லாண்டிக் நேரம் (சாண்டோ டோமிங்கோ)", + "America\/Sao_Paulo": "பிரேசிலியா நேரம் (சாவோ பவுலோ)", + "America\/Scoresbysund": "கிழக்கு கிரீன்லாந்து நேரம் (இடோகோர்டோர்மிட்)", + "America\/Sitka": "அலாஸ்கா நேரம் (சிட்கா)", + "America\/St_Barthelemy": "அட்லாண்டிக் நேரம் (செயின்ட் பார்தேலெமி)", + "America\/St_Johns": "நியூஃபவுண்ட்லாந்து நேரம் (செயின்ட் ஜான்ஸ்)", + "America\/St_Kitts": "அட்லாண்டிக் நேரம் (செயின்ட் கீட்ஸ்)", + "America\/St_Lucia": "அட்லாண்டிக் நேரம் (செயின்ட் லூசியா)", + "America\/St_Thomas": "அட்லாண்டிக் நேரம் (செயின்ட் தாமஸ்)", + "America\/St_Vincent": "அட்லாண்டிக் நேரம் (செயின்ட் வின்சென்ட்)", + "America\/Swift_Current": "மத்திய நேரம் (ஸ்விஃப்ட் கரண்ட்)", + "America\/Tegucigalpa": "மத்திய நேரம் (தெகுசிகல்பா)", + "America\/Thule": "அட்லாண்டிக் நேரம் (துலே)", + "America\/Thunder_Bay": "கிழக்கத்திய நேரம் (தண்டர் பே)", + "America\/Tijuana": "பசிபிக் நேரம் (டிஜுவானா)", + "America\/Toronto": "கிழக்கத்திய நேரம் (டொரொன்டோ)", + "America\/Tortola": "அட்லாண்டிக் நேரம் (டோர்டோலா)", + "America\/Vancouver": "பசிபிக் நேரம் (வான்கூவர்)", + "America\/Whitehorse": "பசிபிக் நேரம் (வொயிட்ஹார்ஸ்)", + "America\/Winnipeg": "மத்திய நேரம் (வின்னிபெக்)", + "America\/Yakutat": "அலாஸ்கா நேரம் (யகுடட்)", + "America\/Yellowknife": "மவுன்டைன் நேரம் (யெல்லோநைஃப்)", + "Antarctica\/Casey": "மேற்கத்திய ஆஸ்திரேலிய நேரம் (கேஸி)", + "Antarctica\/Davis": "டேவிஸ் நேரம் (டேவிஸ்)", + "Antarctica\/DumontDUrville": "டுமோண்ட்-டி உர்வில்லே நேரம் (டுமோண்ட்-டி உர்வில்லே)", + "Antarctica\/Macquarie": "மாக்கியூரி தீவு நேரம் (மாக்கியூரி)", + "Antarctica\/Mawson": "மாசன் நேரம் (மாசன்)", + "Antarctica\/McMurdo": "நியூசிலாந்து நேரம் (மெக்மர்டோ)", + "Antarctica\/Palmer": "சிலி நேரம் (பால்மர்)", + "Antarctica\/Rothera": "ரோதேரா நேரம் (ரோதேரா)", + "Antarctica\/Syowa": "ஸ்யோவா நேரம் (ஸ்யோவா)", + "Antarctica\/Troll": "கிரீன்விச் சராசரி நேரம் (ட்ரோல்)", + "Antarctica\/Vostok": "வோஸ்டோக் நேரம் (வோஸ்டோக்)", + "Arctic\/Longyearbyen": "மத்திய ஐரோப்பிய நேரம் (லாங்இயர்பியன்)", + "Asia\/Aden": "அரேபிய நேரம் (ஏடன்)", + "Asia\/Almaty": "கிழக்கு கஜகஸ்தான் நேரம் (அல்மாதி)", + "Asia\/Amman": "கிழக்கத்திய ஐரோப்பிய நேரம் (அம்மான்)", + "Asia\/Anadyr": "அனடீர் நேரம் (அனடீர்)", + "Asia\/Aqtau": "மேற்கு கஜகஸ்தான் நேரம் (அக்தவ்)", + "Asia\/Aqtobe": "மேற்கு கஜகஸ்தான் நேரம் (அக்டோப்)", + "Asia\/Ashgabat": "துர்க்மெனிஸ்தான் நேரம் (அஷ்காபாத்)", + "Asia\/Atyrau": "மேற்கு கஜகஸ்தான் நேரம் (அடிரா)", + "Asia\/Baghdad": "அரேபிய நேரம் (பாக்தாத்)", + "Asia\/Bahrain": "அரேபிய நேரம் (பஹ்ரைன்)", + "Asia\/Baku": "அசர்பைஜான் நேரம் (பாக்கூ)", + "Asia\/Bangkok": "இந்தோசீன நேரம் (பாங்காக்)", + "Asia\/Beirut": "கிழக்கத்திய ஐரோப்பிய நேரம் (பெய்ரூட்)", + "Asia\/Bishkek": "கிர்கிஸ்தான் நேரம் (பிஷ்கெக்)", + "Asia\/Brunei": "புருனே டருஸ்ஸலாம் நேரம் (புருனே)", + "Asia\/Calcutta": "இந்திய நிலையான நேரம் (கொல்கத்தா)", + "Asia\/Chita": "யகுட்ஸ்க் நேரம் (சிடா)", + "Asia\/Choibalsan": "சோய்பால்சன் நேரம் (சோய்பால்சான்)", + "Asia\/Colombo": "இந்திய நிலையான நேரம் (கொழும்பு)", + "Asia\/Damascus": "கிழக்கத்திய ஐரோப்பிய நேரம் (டமாஸ்கஸ்)", + "Asia\/Dhaka": "வங்கதேச நேரம் (டாக்கா)", + "Asia\/Dili": "கிழக்கு திமோர் நேரம் (டிலி)", + "Asia\/Dubai": "வளைகுடா நிலையான நேரம் (துபாய்)", + "Asia\/Dushanbe": "தஜிகிஸ்தான் நேரம் (துஷன்பே)", + "Asia\/Famagusta": "கிழக்கத்திய ஐரோப்பிய நேரம் (ஃபாமகுஸ்டா)", + "Asia\/Gaza": "கிழக்கத்திய ஐரோப்பிய நேரம் (காஸா)", + "Asia\/Hebron": "கிழக்கத்திய ஐரோப்பிய நேரம் (ஹெப்ரான்)", + "Asia\/Hong_Kong": "ஹாங்காங் நேரம் (ஹாங்காங்)", + "Asia\/Hovd": "ஹோவ்த் நேரம் (ஹோவ்த்)", + "Asia\/Irkutsk": "இர்குட்ஸ்க் நேரம் (இர்குட்ஸ்க்)", + "Asia\/Jakarta": "மேற்கத்திய இந்தோனேசிய நேரம் (ஜகார்த்தா)", + "Asia\/Jayapura": "கிழக்கத்திய இந்தோனேசிய நேரம் (ஜெயபூரா)", + "Asia\/Jerusalem": "இஸ்ரேல் நேரம் (ஜெருசலேம்)", + "Asia\/Kabul": "ஆஃப்கானிஸ்தான் நேரம் (காபூல்)", + "Asia\/Kamchatka": "பெட்ரோபவ்லோவ்ஸ்க் கம்சட்ஸ்கி நேரம் (காம்சட்கா)", + "Asia\/Karachi": "பாகிஸ்தான் நேரம் (கராச்சி)", + "Asia\/Katmandu": "நேபாள நேரம் (காத்மாண்டு)", + "Asia\/Khandyga": "யகுட்ஸ்க் நேரம் (கான்டிகா)", + "Asia\/Krasnoyarsk": "க்ரஸ்னோயார்ஸ்க் நேரம் (கிராஸ்னோயார்க்ஸ்)", + "Asia\/Kuala_Lumpur": "மலேஷிய நேரம் (கோலாலம்பூர்)", + "Asia\/Kuching": "மலேஷிய நேரம் (குசிங்)", + "Asia\/Kuwait": "அரேபிய நேரம் (குவைத்)", + "Asia\/Macau": "சீன நேரம் (மகாவு)", + "Asia\/Magadan": "மகதன் நேரம் (மகதன்)", + "Asia\/Makassar": "மத்திய இந்தோனேசிய நேரம் (மக்கஸர்)", + "Asia\/Manila": "பிலிப்பைன் நேரம் (மணிலா)", + "Asia\/Muscat": "வளைகுடா நிலையான நேரம் (மஸ்கட்)", + "Asia\/Nicosia": "கிழக்கத்திய ஐரோப்பிய நேரம் (நிகோசியா)", + "Asia\/Novokuznetsk": "க்ரஸ்னோயார்ஸ்க் நேரம் (நோவோகுஸ்நெட்ஸ்க்)", + "Asia\/Novosibirsk": "நோவோசிபிரிஸ்க் நேரம் (நோவோசீபிர்ஸ்க்)", + "Asia\/Omsk": "ஓம்ஸ்க் நேரம் (ஓம்ஸ்க்)", + "Asia\/Oral": "மேற்கு கஜகஸ்தான் நேரம் (ஓரல்)", + "Asia\/Phnom_Penh": "இந்தோசீன நேரம் (ஃப்னோம் பென்)", + "Asia\/Pontianak": "மேற்கத்திய இந்தோனேசிய நேரம் (போன்டியானாக்)", + "Asia\/Pyongyang": "கொரிய நேரம் (பியாங்யாங்)", + "Asia\/Qatar": "அரேபிய நேரம் (கத்தார்)", + "Asia\/Qostanay": "கிழக்கு கஜகஸ்தான் நேரம் (கோஸ்டானே)", + "Asia\/Qyzylorda": "மேற்கு கஜகஸ்தான் நேரம் (கிஸிலோர்டா)", + "Asia\/Rangoon": "மியான்மர் நேரம் (ரங்கூன்)", + "Asia\/Riyadh": "அரேபிய நேரம் (ரியாத்)", + "Asia\/Saigon": "இந்தோசீன நேரம் (ஹோ சி மின் சிட்டி)", + "Asia\/Sakhalin": "சகலின் நேரம் (சகலின்)", + "Asia\/Samarkand": "உஸ்பெகிஸ்தான் நேரம் (சமார்கண்ட்)", + "Asia\/Seoul": "கொரிய நேரம் (சியோல்)", + "Asia\/Shanghai": "சீன நேரம் (ஷாங்காய்)", + "Asia\/Singapore": "சிங்கப்பூர் நிலையான நேரம் (சிங்கப்பூர்)", + "Asia\/Srednekolymsk": "மகதன் நேரம் (ஸ்ரெட்நிகோலிம்ஸ்க்)", + "Asia\/Taipei": "தாய்பே நேரம் (தாய்பே)", + "Asia\/Tashkent": "உஸ்பெகிஸ்தான் நேரம் (தாஷ்கண்ட்)", + "Asia\/Tbilisi": "ஜார்ஜியா நேரம் (த்பிலிசி)", + "Asia\/Tehran": "ஈரான் நேரம் (டெஹ்ரான்)", + "Asia\/Thimphu": "பூடான் நேரம் (திம்பு)", + "Asia\/Tokyo": "ஜப்பான் நேரம் (டோக்கியோ)", + "Asia\/Ulaanbaatar": "உலன் பாடர் நேரம் (உலான்பாட்டர்)", + "Asia\/Ust-Nera": "விளாடிவோஸ்டோக் நேரம் (உஸ்ட்-நேரா)", + "Asia\/Vientiane": "இந்தோசீன நேரம் (வியன்டியன்)", + "Asia\/Vladivostok": "விளாடிவோஸ்டோக் நேரம் (விளாடிவொஸ்தோக்)", + "Asia\/Yakutsk": "யகுட்ஸ்க் நேரம் (யகுட்ஸ்க்)", + "Asia\/Yekaterinburg": "யேகாடெரின்பர்க் நேரம் (யெகாடிரின்பர்க்)", + "Asia\/Yerevan": "ஆர்மேனிய நேரம் (ஏரேவன்)", + "Atlantic\/Azores": "அசோரஸ் நேரம் (அசோரஸ்)", + "Atlantic\/Bermuda": "அட்லாண்டிக் நேரம் (பெர்முடா)", + "Atlantic\/Canary": "மேற்கத்திய ஐரோப்பிய நேரம் (கேனரி)", + "Atlantic\/Cape_Verde": "கேப் வெர்டே நேரம் (கேப் வெர்டே)", + "Atlantic\/Faeroe": "மேற்கத்திய ஐரோப்பிய நேரம் (ஃபரோ)", + "Atlantic\/Madeira": "மேற்கத்திய ஐரோப்பிய நேரம் (மடிரா)", + "Atlantic\/Reykjavik": "கிரீன்விச் சராசரி நேரம் (ரேக்ஜாவிக்)", + "Atlantic\/South_Georgia": "தெற்கு ஜார்ஜியா நேரம் (தெற்கு ஜார்ஜியா)", + "Atlantic\/St_Helena": "கிரீன்விச் சராசரி நேரம் (செயின்ட் ஹெலெனா)", + "Atlantic\/Stanley": "ஃபாக்லாந்து தீவுகள் நேரம் (ஸ்டேன்லி)", + "Australia\/Adelaide": "மத்திய ஆஸ்திரேலிய நேரம் (அடிலெய்ட்)", + "Australia\/Brisbane": "கிழக்கத்திய ஆஸ்திரேலிய நேரம் (பிரிஸ்பேன்)", + "Australia\/Broken_Hill": "மத்திய ஆஸ்திரேலிய நேரம் (புரோக்கன் ஹில்)", + "Australia\/Currie": "கிழக்கத்திய ஆஸ்திரேலிய நேரம் (கியூரி)", + "Australia\/Darwin": "மத்திய ஆஸ்திரேலிய நேரம் (டார்வின்)", + "Australia\/Eucla": "ஆஸ்திரேலியன் மத்திய மேற்கத்திய நேரம் (யூக்லா)", + "Australia\/Hobart": "கிழக்கத்திய ஆஸ்திரேலிய நேரம் (ஹோபர்ட்)", + "Australia\/Lindeman": "கிழக்கத்திய ஆஸ்திரேலிய நேரம் (லின்டெமன்)", + "Australia\/Lord_Howe": "லார்ட் ஹோவ் நேரம் (லார்ட் ஹோவே)", + "Australia\/Melbourne": "கிழக்கத்திய ஆஸ்திரேலிய நேரம் (மெல்போர்ன்)", + "Australia\/Perth": "மேற்கத்திய ஆஸ்திரேலிய நேரம் (பெர்த்)", + "Australia\/Sydney": "கிழக்கத்திய ஆஸ்திரேலிய நேரம் (சிட்னி)", + "CST6CDT": "மத்திய நேரம்", + "EST5EDT": "கிழக்கத்திய நேரம்", + "Etc\/GMT": "கிரீன்விச் சராசரி நேரம்", + "Etc\/UTC": "ஒருங்கிணைந்த சர்வதேச நேரம்", + "Europe\/Amsterdam": "மத்திய ஐரோப்பிய நேரம் (ஆம்ஸ்ட்ரடாம்)", + "Europe\/Andorra": "மத்திய ஐரோப்பிய நேரம் (அண்டோரா)", + "Europe\/Astrakhan": "மாஸ்கோ நேரம் (அஸ்ட்ராகான்)", + "Europe\/Athens": "கிழக்கத்திய ஐரோப்பிய நேரம் (ஏதன்ஸ்)", + "Europe\/Belgrade": "மத்திய ஐரோப்பிய நேரம் (பெல்கிரேட்)", + "Europe\/Berlin": "மத்திய ஐரோப்பிய நேரம் (பெர்லின்)", + "Europe\/Bratislava": "மத்திய ஐரோப்பிய நேரம் (பிரடிஸ்லாவா)", + "Europe\/Brussels": "மத்திய ஐரோப்பிய நேரம் (புரூசல்ஸ்)", + "Europe\/Bucharest": "கிழக்கத்திய ஐரோப்பிய நேரம் (புசாரெஸ்ட்)", + "Europe\/Budapest": "மத்திய ஐரோப்பிய நேரம் (புடாபெஸ்ட்)", + "Europe\/Busingen": "மத்திய ஐரோப்பிய நேரம் (பசிங்ஜென்)", + "Europe\/Chisinau": "கிழக்கத்திய ஐரோப்பிய நேரம் (சிசினவ்)", + "Europe\/Copenhagen": "மத்திய ஐரோப்பிய நேரம் (கோபன்ஹேகன்)", + "Europe\/Dublin": "கிரீன்விச் சராசரி நேரம் (டப்ளின்)", + "Europe\/Gibraltar": "மத்திய ஐரோப்பிய நேரம் (ஜிப்ரால்டர்)", + "Europe\/Guernsey": "கிரீன்விச் சராசரி நேரம் (கர்னஸே)", + "Europe\/Helsinki": "கிழக்கத்திய ஐரோப்பிய நேரம் (ஹெல்சிங்கி)", + "Europe\/Isle_of_Man": "கிரீன்விச் சராசரி நேரம் (ஐல் ஆஃப் மேன்)", + "Europe\/Jersey": "கிரீன்விச் சராசரி நேரம் (ஜெர்சி)", + "Europe\/Kaliningrad": "கிழக்கத்திய ஐரோப்பிய நேரம் (கலினின்கிராட்)", + "Europe\/Kiev": "கிழக்கத்திய ஐரோப்பிய நேரம் (கீவ்)", + "Europe\/Lisbon": "மேற்கத்திய ஐரோப்பிய நேரம் (லிஸ்பன்)", + "Europe\/Ljubljana": "மத்திய ஐரோப்பிய நேரம் (ஜுப்லானா)", + "Europe\/London": "கிரீன்விச் சராசரி நேரம் (லண்டன்)", + "Europe\/Luxembourg": "மத்திய ஐரோப்பிய நேரம் (லக்சம்பர்க்)", + "Europe\/Madrid": "மத்திய ஐரோப்பிய நேரம் (மேட்ரிட்)", + "Europe\/Malta": "மத்திய ஐரோப்பிய நேரம் (மால்டா)", + "Europe\/Mariehamn": "கிழக்கத்திய ஐரோப்பிய நேரம் (மரிஹம்)", + "Europe\/Minsk": "மாஸ்கோ நேரம் (மின்ஸ்க்)", + "Europe\/Monaco": "மத்திய ஐரோப்பிய நேரம் (மொனாக்கோ)", + "Europe\/Moscow": "மாஸ்கோ நேரம் (மாஸ்கோ)", + "Europe\/Oslo": "மத்திய ஐரோப்பிய நேரம் (ஓஸ்லோ)", + "Europe\/Paris": "மத்திய ஐரோப்பிய நேரம் (பாரீஸ்)", + "Europe\/Podgorica": "மத்திய ஐரோப்பிய நேரம் (போட்கோரிகா)", + "Europe\/Prague": "மத்திய ஐரோப்பிய நேரம் (ப்ராக்)", + "Europe\/Riga": "கிழக்கத்திய ஐரோப்பிய நேரம் (ரிகா)", + "Europe\/Rome": "மத்திய ஐரோப்பிய நேரம் (ரோம்)", + "Europe\/Samara": "சமரா நேரம் (சமாரா)", + "Europe\/San_Marino": "மத்திய ஐரோப்பிய நேரம் (சான் மரினோ)", + "Europe\/Sarajevo": "மத்திய ஐரோப்பிய நேரம் (சரயேவோ)", + "Europe\/Saratov": "மாஸ்கோ நேரம் (சரடோவ்)", + "Europe\/Simferopol": "மாஸ்கோ நேரம் (சிம்ஃபெரோபோல்)", + "Europe\/Skopje": "மத்திய ஐரோப்பிய நேரம் (ஸ்கோப்ஜே)", + "Europe\/Sofia": "கிழக்கத்திய ஐரோப்பிய நேரம் (சோஃபியா)", + "Europe\/Stockholm": "மத்திய ஐரோப்பிய நேரம் (ஸ்டாக்ஹோம்)", + "Europe\/Tallinn": "கிழக்கத்திய ஐரோப்பிய நேரம் (டலின்)", + "Europe\/Tirane": "மத்திய ஐரோப்பிய நேரம் (திரானே)", + "Europe\/Ulyanovsk": "மாஸ்கோ நேரம் (உல்யானோஸ்க்)", + "Europe\/Uzhgorod": "கிழக்கத்திய ஐரோப்பிய நேரம் (உஷோரோட்)", + "Europe\/Vaduz": "மத்திய ஐரோப்பிய நேரம் (வதுஸ்)", + "Europe\/Vatican": "மத்திய ஐரோப்பிய நேரம் (வாடிகன்)", + "Europe\/Vienna": "மத்திய ஐரோப்பிய நேரம் (வியன்னா)", + "Europe\/Vilnius": "கிழக்கத்திய ஐரோப்பிய நேரம் (வில்னியஸ்)", + "Europe\/Volgograd": "வோல்கோக்ராட் நேரம் (வோல்கோகிராட்)", + "Europe\/Warsaw": "மத்திய ஐரோப்பிய நேரம் (வார்ஸா)", + "Europe\/Zagreb": "மத்திய ஐரோப்பிய நேரம் (ஸக்ரெப்)", + "Europe\/Zaporozhye": "கிழக்கத்திய ஐரோப்பிய நேரம் (ஜபோரோஸியே)", + "Europe\/Zurich": "மத்திய ஐரோப்பிய நேரம் (ஜூரிச்)", + "Indian\/Antananarivo": "கிழக்கு ஆப்பிரிக்க நேரம் (ஆண்டனநரிவோ)", + "Indian\/Chagos": "இந்தியப் பெருங்கடல் நேரம் (சாகோஸ்)", + "Indian\/Christmas": "கிறிஸ்துமஸ் தீவு நேரம் (கிறிஸ்துமஸ்)", + "Indian\/Cocos": "கோகோஸ் தீவுகள் நேரம் (கோகோஸ்)", + "Indian\/Comoro": "கிழக்கு ஆப்பிரிக்க நேரம் (கொமரோ)", + "Indian\/Kerguelen": "பிரெஞ்சு தெற்கத்திய & அண்டார்டிக் நேரம் (கெர்யூலென்)", + "Indian\/Mahe": "சீசெல்ஸ் நேரம் (மாஹே)", + "Indian\/Maldives": "மாலத்தீவுகள் நேரம் (மாலத்தீவுகள்)", + "Indian\/Mauritius": "மொரிஷியஸ் நேரம் (மொரிஷியஸ்)", + "Indian\/Mayotte": "கிழக்கு ஆப்பிரிக்க நேரம் (மயோட்டி)", + "Indian\/Reunion": "ரீயூனியன் நேரம் (ரீயூனியன்)", + "MST7MDT": "மவுன்டைன் நேரம்", + "PST8PDT": "பசிபிக் நேரம்", + "Pacific\/Apia": "ஏபியா நேரம் (அபியா)", + "Pacific\/Auckland": "நியூசிலாந்து நேரம் (ஆக்லாந்து)", + "Pacific\/Bougainville": "பபுவா நியூ கினியா நேரம் (போகெய்ன்வில்லே)", + "Pacific\/Chatham": "சத்தாம் நேரம் (சத்தாம்)", + "Pacific\/Easter": "ஈஸ்டர் தீவு நேரம் (ஈஸ்டர்)", + "Pacific\/Efate": "வனுவாட்டு நேரம் (ஈஃபேட்)", + "Pacific\/Enderbury": "ஃபோனிக்ஸ் தீவுகள் நேரம் (எண்டர்பரி)", + "Pacific\/Fakaofo": "டோக்கெலாவ் நேரம் (ஃபகாஃபோ)", + "Pacific\/Fiji": "ஃபிஜி நேரம் (ஃபிஜி)", + "Pacific\/Funafuti": "துவாலு நேரம் (ஃபுனாஃபுடி)", + "Pacific\/Galapagos": "கலபகோஸ் நேரம் (கலபகோஸ்)", + "Pacific\/Gambier": "கேம்பியர் நேரம் (கேம்பியர்)", + "Pacific\/Guadalcanal": "சாலமன் தீவுகள் நேரம் (க்வாடால்கேனல்)", + "Pacific\/Guam": "சாமோரோ நிலையான நேரம் (குவாம்)", + "Pacific\/Honolulu": "ஹவாய்-அலேஷியன் நேரம் (ஹோனோலூலூ)", + "Pacific\/Johnston": "ஹவாய்-அலேஷியன் நேரம் (ஜோன்ஸ்டன்)", + "Pacific\/Kiritimati": "லைன் தீவுகள் நேரம் (கிரிடிமாட்டி)", + "Pacific\/Kosrae": "கோஸ்ரே நேரம் (கோஸ்ரே)", + "Pacific\/Kwajalein": "மார்ஷல் தீவுகள் நேரம் (க்வாஜாலீயன்)", + "Pacific\/Majuro": "மார்ஷல் தீவுகள் நேரம் (மஜுரோ)", + "Pacific\/Marquesas": "மார்கியூசாஸ் நேரம் (மார்கியூசாஸ்)", + "Pacific\/Midway": "சமோவா நேரம் (மிட்வே)", + "Pacific\/Nauru": "நவ்ரூ நேரம் (நவ்ரூ)", + "Pacific\/Niue": "நியு நேரம் (நியு)", + "Pacific\/Norfolk": "நார்ஃபோக் தீவு நேரம் (நார்ஃபோக்)", + "Pacific\/Noumea": "நியூ கலிடோனியா நேரம் (நோவுமியா)", + "Pacific\/Pago_Pago": "சமோவா நேரம் (பேகோ பேகோ)", + "Pacific\/Palau": "பாலவ் நேரம் (பாலவ்)", + "Pacific\/Pitcairn": "பிட்கெய்ர்ன் நேரம் (பிட்கெய்ர்ன்)", + "Pacific\/Ponape": "போனாபே நேரம் (ஃபோன்பெய்)", + "Pacific\/Port_Moresby": "பபுவா நியூ கினியா நேரம் (போர்ட் மோர்ஸ்பை)", + "Pacific\/Rarotonga": "குக் தீவுகள் நேரம் (ரரோடோங்கா)", + "Pacific\/Saipan": "சாமோரோ நிலையான நேரம் (சைபன்)", + "Pacific\/Tahiti": "தஹிதி நேரம் (தஹிதி)", + "Pacific\/Tarawa": "கில்பர்ட் தீவுகள் நேரம் (தராவா)", + "Pacific\/Tongatapu": "டோங்கா நேரம் (டோன்கடப்பு)", + "Pacific\/Truk": "சுக் நேரம் (சுக்)", + "Pacific\/Wake": "வேக் தீவு நேரம் (வேக்)", + "Pacific\/Wallis": "வாலிஸ் மற்றும் ஃப்யூடுனா நேரம் (வாலிஸ்)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ta_MY.json b/src/Symfony/Component/Intl/Resources/data/timezones/ta_MY.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ta_MY.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ta_SG.json b/src/Symfony/Component/Intl/Resources/data/timezones/ta_SG.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ta_SG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/te.json b/src/Symfony/Component/Intl/Resources/data/timezones/te.json new file mode 100644 index 0000000000000..6533acdf1003b --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/te.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "గ్రీన్‌విచ్ సగటు సమయం (అబిడ్జాన్)", + "Africa\/Accra": "గ్రీన్‌విచ్ సగటు సమయం (అక్రా)", + "Africa\/Addis_Ababa": "తూర్పు ఆఫ్రికా సమయం (యాడిస్ అబాబా)", + "Africa\/Algiers": "సెంట్రల్ యూరోపియన్ సమయం (అల్జియర్స్)", + "Africa\/Asmera": "తూర్పు ఆఫ్రికా సమయం (అస్మారా)", + "Africa\/Bamako": "గ్రీన్‌విచ్ సగటు సమయం (బామాకో)", + "Africa\/Bangui": "పశ్చిమ ఆఫ్రికా సమయం (బాంగుయ్)", + "Africa\/Banjul": "గ్రీన్‌విచ్ సగటు సమయం (బంజూల్)", + "Africa\/Bissau": "గ్రీన్‌విచ్ సగటు సమయం (బిస్సావ్)", + "Africa\/Blantyre": "సెంట్రల్ ఆఫ్రికా సమయం (బ్లాన్టైర్)", + "Africa\/Brazzaville": "పశ్చిమ ఆఫ్రికా సమయం (బ్రాజావిల్లే)", + "Africa\/Bujumbura": "సెంట్రల్ ఆఫ్రికా సమయం (బుజమ్బురా)", + "Africa\/Cairo": "తూర్పు యూరోపియన్ సమయం (కైరో)", + "Africa\/Casablanca": "పశ్చిమ యూరోపియన్ సమయం (కాసాబ్లాంకా)", + "Africa\/Ceuta": "సెంట్రల్ యూరోపియన్ సమయం (స్యూటా)", + "Africa\/Conakry": "గ్రీన్‌విచ్ సగటు సమయం (కోనాక్రీ)", + "Africa\/Dakar": "గ్రీన్‌విచ్ సగటు సమయం (డకార్)", + "Africa\/Dar_es_Salaam": "తూర్పు ఆఫ్రికా సమయం (దార్ ఎస్ సలామ్)", + "Africa\/Djibouti": "తూర్పు ఆఫ్రికా సమయం (డిజ్బౌటి)", + "Africa\/Douala": "పశ్చిమ ఆఫ్రికా సమయం (డౌలా)", + "Africa\/El_Aaiun": "పశ్చిమ యూరోపియన్ సమయం (ఎల్ ఎయున్)", + "Africa\/Freetown": "గ్రీన్‌విచ్ సగటు సమయం (ఫ్రీటౌన్)", + "Africa\/Gaborone": "సెంట్రల్ ఆఫ్రికా సమయం (గబోరోన్)", + "Africa\/Harare": "సెంట్రల్ ఆఫ్రికా సమయం (హరారే)", + "Africa\/Johannesburg": "దక్షిణ ఆఫ్రికా ప్రామాణిక సమయం (జొహెన్స్‌బర్గ్)", + "Africa\/Juba": "తూర్పు ఆఫ్రికా సమయం (జుబా)", + "Africa\/Kampala": "తూర్పు ఆఫ్రికా సమయం (కంపాలా)", + "Africa\/Khartoum": "సెంట్రల్ ఆఫ్రికా సమయం (ఖార్టోమ్)", + "Africa\/Kigali": "సెంట్రల్ ఆఫ్రికా సమయం (కీగలి)", + "Africa\/Kinshasa": "పశ్చిమ ఆఫ్రికా సమయం (కిన్షాసా)", + "Africa\/Lagos": "పశ్చిమ ఆఫ్రికా సమయం (లాగోస్)", + "Africa\/Libreville": "పశ్చిమ ఆఫ్రికా సమయం (లెబర్విల్లే)", + "Africa\/Lome": "గ్రీన్‌విచ్ సగటు సమయం (లోమ్)", + "Africa\/Luanda": "పశ్చిమ ఆఫ్రికా సమయం (లువాండా)", + "Africa\/Lubumbashi": "సెంట్రల్ ఆఫ్రికా సమయం (లుబంబాషి)", + "Africa\/Lusaka": "సెంట్రల్ ఆఫ్రికా సమయం (లుసాకా)", + "Africa\/Malabo": "పశ్చిమ ఆఫ్రికా సమయం (మలాబో)", + "Africa\/Maputo": "సెంట్రల్ ఆఫ్రికా సమయం (మాపుటో)", + "Africa\/Maseru": "దక్షిణ ఆఫ్రికా ప్రామాణిక సమయం (మసేరు)", + "Africa\/Mbabane": "దక్షిణ ఆఫ్రికా ప్రామాణిక సమయం (బాబెన్)", + "Africa\/Mogadishu": "తూర్పు ఆఫ్రికా సమయం (మోగాదిషు)", + "Africa\/Monrovia": "గ్రీన్‌విచ్ సగటు సమయం (మోన్రోవియా)", + "Africa\/Nairobi": "తూర్పు ఆఫ్రికా సమయం (నైరోబీ)", + "Africa\/Ndjamena": "పశ్చిమ ఆఫ్రికా సమయం (డ్జామెనా)", + "Africa\/Niamey": "పశ్చిమ ఆఫ్రికా సమయం (నియామే)", + "Africa\/Nouakchott": "గ్రీన్‌విచ్ సగటు సమయం (న్వాక్షోట్)", + "Africa\/Ouagadougou": "గ్రీన్‌విచ్ సగటు సమయం (ఔగాడౌగోవ్)", + "Africa\/Porto-Novo": "పశ్చిమ ఆఫ్రికా సమయం (పోర్టో-నోవో)", + "Africa\/Sao_Tome": "గ్రీన్‌విచ్ సగటు సమయం (సావో టోమ్)", + "Africa\/Tripoli": "తూర్పు యూరోపియన్ సమయం (ట్రిపోలి)", + "Africa\/Tunis": "సెంట్రల్ యూరోపియన్ సమయం (ట్యునిస్)", + "Africa\/Windhoek": "సెంట్రల్ ఆఫ్రికా సమయం (విండ్హోక్)", + "America\/Adak": "హవాయ్-అల్యూషియన్ సమయం (అడాక్)", + "America\/Anchorage": "అలాస్కా సమయం (యాంకరేజ్)", + "America\/Anguilla": "అట్లాంటిక్ సమయం (ఆంగ్విల్లా)", + "America\/Antigua": "అట్లాంటిక్ సమయం (ఆంటిగ్వా)", + "America\/Araguaina": "బ్రెజిలియా సమయం (అరాగ్వేయీనా)", + "America\/Argentina\/La_Rioja": "అర్జెంటీనా సమయం (లా రియోజ)", + "America\/Argentina\/Rio_Gallegos": "అర్జెంటీనా సమయం (రియో గల్లేగోస్)", + "America\/Argentina\/Salta": "అర్జెంటీనా సమయం (సాల్టా)", + "America\/Argentina\/San_Juan": "అర్జెంటీనా సమయం (శాన్ జ్యూన్)", + "America\/Argentina\/San_Luis": "పశ్చిమ అర్జెంటీనా సమయం (శాన్ లూయిస్)", + "America\/Argentina\/Tucuman": "అర్జెంటీనా సమయం (టుకుమన్)", + "America\/Argentina\/Ushuaia": "అర్జెంటీనా సమయం (ఉష్యూయ)", + "America\/Aruba": "అట్లాంటిక్ సమయం (అరుబా)", + "America\/Asuncion": "పరాగ్వే సమయం (అసున్సియోన్)", + "America\/Bahia": "బ్రెజిలియా సమయం (బహియ)", + "America\/Bahia_Banderas": "మధ్యమ సమయం (బహియా బండరాస్)", + "America\/Barbados": "అట్లాంటిక్ సమయం (బార్బడోస్)", + "America\/Belem": "బ్రెజిలియా సమయం (బెలెమ్)", + "America\/Belize": "మధ్యమ సమయం (బెలీజ్)", + "America\/Blanc-Sablon": "అట్లాంటిక్ సమయం (బ్లాంక్-సబ్లోన్)", + "America\/Boa_Vista": "అమెజాన్ సమయం (బోవా విస్టా)", + "America\/Bogota": "కొలంబియా సమయం (బగోటా)", + "America\/Boise": "మౌంటెయిన్ సమయం (బొయిసీ)", + "America\/Buenos_Aires": "అర్జెంటీనా సమయం (బ్యూనోస్ ఎయిర్స్)", + "America\/Cambridge_Bay": "మౌంటెయిన్ సమయం (కేంబ్రిడ్జ్ బే)", + "America\/Campo_Grande": "అమెజాన్ సమయం (కాంపో గ్రాండ్)", + "America\/Cancun": "తూర్పు సమయం (కన్‌కూన్)", + "America\/Caracas": "వెనిజులా సమయం (కారాకస్)", + "America\/Catamarca": "అర్జెంటీనా సమయం (కటమార్కా)", + "America\/Cayenne": "ఫ్రెంచ్ గయానా సమయం (కయేన్)", + "America\/Cayman": "తూర్పు సమయం (కేమాన్)", + "America\/Chicago": "మధ్యమ సమయం (చికాగో)", + "America\/Chihuahua": "మెక్సికన్ పసిఫిక్ సమయం (చువావా)", + "America\/Coral_Harbour": "తూర్పు సమయం (అటికోకన్)", + "America\/Cordoba": "అర్జెంటీనా సమయం (కోర్డోబా)", + "America\/Costa_Rica": "మధ్యమ సమయం (కోస్టా రికా)", + "America\/Creston": "మౌంటెయిన్ సమయం (క్రెస్టన్)", + "America\/Cuiaba": "అమెజాన్ సమయం (కుయబా)", + "America\/Curacao": "అట్లాంటిక్ సమయం (కురాకవో)", + "America\/Danmarkshavn": "గ్రీన్‌విచ్ సగటు సమయం (డెన్మార్క్‌షాన్)", + "America\/Dawson": "పసిఫిక్ సమయం (డాసన్)", + "America\/Dawson_Creek": "మౌంటెయిన్ సమయం (డాసన్ క్రీక్)", + "America\/Denver": "మౌంటెయిన్ సమయం (డెన్వెర్)", + "America\/Detroit": "తూర్పు సమయం (డిట్రోయిట్)", + "America\/Dominica": "అట్లాంటిక్ సమయం (డొమినికా)", + "America\/Edmonton": "మౌంటెయిన్ సమయం (ఎడ్మోంటన్)", + "America\/Eirunepe": "ఏకర్ సమయం (ఇరునెప్)", + "America\/El_Salvador": "మధ్యమ సమయం (ఎల్ సాల్వడోర్)", + "America\/Fort_Nelson": "మౌంటెయిన్ సమయం (ఫోర్ట్ నెల్సన్)", + "America\/Fortaleza": "బ్రెజిలియా సమయం (ఫోర్టలేజా)", + "America\/Glace_Bay": "అట్లాంటిక్ సమయం (గ్లేస్ బే)", + "America\/Godthab": "పశ్చిమ గ్రీన్‌ల్యాండ్ సమయం (నూక్)", + "America\/Goose_Bay": "అట్లాంటిక్ సమయం (గూస్ బే)", + "America\/Grand_Turk": "తూర్పు సమయం (గ్రాండ్ టర్క్)", + "America\/Grenada": "అట్లాంటిక్ సమయం (గ్రెనడా)", + "America\/Guadeloupe": "అట్లాంటిక్ సమయం (గ్వాడెలోప్)", + "America\/Guatemala": "మధ్యమ సమయం (గ్వాటిమాలా)", + "America\/Guayaquil": "ఈక్వడార్ సమయం (గయాక్విల్)", + "America\/Guyana": "గయానా సమయం (గయానా)", + "America\/Halifax": "అట్లాంటిక్ సమయం (హాలిఫాక్స్)", + "America\/Havana": "క్యూబా సమయం (హవానా)", + "America\/Hermosillo": "మెక్సికన్ పసిఫిక్ సమయం (హెర్మోసిల్లో)", + "America\/Indiana\/Knox": "మధ్యమ సమయం (నోక్స్, ఇండియాన)", + "America\/Indiana\/Marengo": "తూర్పు సమయం (మరెంగో, ఇండియాన)", + "America\/Indiana\/Petersburg": "తూర్పు సమయం (పీటర్స్‌బర్గ్, ఇండియాన)", + "America\/Indiana\/Tell_City": "మధ్యమ సమయం (టెల్ నగరం, ఇండియాన)", + "America\/Indiana\/Vevay": "తూర్పు సమయం (వెవయ్, ఇండియాన)", + "America\/Indiana\/Vincennes": "తూర్పు సమయం (విన్‌సెన్నెస్, ఇండియాన)", + "America\/Indiana\/Winamac": "తూర్పు సమయం (వినామాక్, ఇండియాన)", + "America\/Indianapolis": "తూర్పు సమయం (ఇండియానపోలిస్)", + "America\/Inuvik": "మౌంటెయిన్ సమయం (ఇనువిక్)", + "America\/Iqaluit": "తూర్పు సమయం (ఇక్వాలిట్)", + "America\/Jamaica": "తూర్పు సమయం (జమైకా)", + "America\/Jujuy": "అర్జెంటీనా సమయం (జుజుయ్)", + "America\/Juneau": "అలాస్కా సమయం (జూనో)", + "America\/Kentucky\/Monticello": "తూర్పు సమయం (మోంటిసెల్లో, కెన్‌టుక్కీ)", + "America\/Kralendijk": "అట్లాంటిక్ సమయం (క్రలెండ్జిక్)", + "America\/La_Paz": "బొలీవియా సమయం (లా పాజ్)", + "America\/Lima": "పెరూ సమయం (లిమా)", + "America\/Los_Angeles": "పసిఫిక్ సమయం (లాస్ ఏంజల్స్)", + "America\/Louisville": "తూర్పు సమయం (లూయివిల్)", + "America\/Lower_Princes": "అట్లాంటిక్ సమయం (లోయర్ ప్రిన్స్ క్వార్టర్)", + "America\/Maceio": "బ్రెజిలియా సమయం (మాసియో)", + "America\/Managua": "మధ్యమ సమయం (మనాగువా)", + "America\/Manaus": "అమెజాన్ సమయం (మనాస్)", + "America\/Marigot": "అట్లాంటిక్ సమయం (మారిగోట్)", + "America\/Martinique": "అట్లాంటిక్ సమయం (మార్టినీక్)", + "America\/Matamoros": "మధ్యమ సమయం (మాటమొరోస్)", + "America\/Mazatlan": "మెక్సికన్ పసిఫిక్ సమయం (మాసట్‌లాన్)", + "America\/Mendoza": "అర్జెంటీనా సమయం (మెండోజా)", + "America\/Menominee": "మధ్యమ సమయం (మెనోమినీ)", + "America\/Merida": "మధ్యమ సమయం (మెరిడా)", + "America\/Metlakatla": "అలాస్కా సమయం (మెట్లకట్ల)", + "America\/Mexico_City": "మధ్యమ సమయం (మెక్సికో నగరం)", + "America\/Miquelon": "సెయింట్ పియెర్ మరియు మిక్వెలాన్ సమయం (మికెలాన్)", + "America\/Moncton": "అట్లాంటిక్ సమయం (మోన్‌క్టోన్)", + "America\/Monterrey": "మధ్యమ సమయం (మోంటెర్రే)", + "America\/Montevideo": "ఉరుగ్వే సమయం (మోంటెవీడియో)", + "America\/Montserrat": "అట్లాంటిక్ సమయం (మాంట్సెరాట్)", + "America\/Nassau": "తూర్పు సమయం (నాస్సావ్)", + "America\/New_York": "తూర్పు సమయం (న్యూయార్క్)", + "America\/Nipigon": "తూర్పు సమయం (నిపిగోన్)", + "America\/Nome": "అలాస్కా సమయం (నోమ్)", + "America\/Noronha": "ఫెర్నాండో డి నొరోన్హా సమయం (నరోన్హా)", + "America\/North_Dakota\/Beulah": "మధ్యమ సమయం (బ్యులా, ఉత్తర డకోట)", + "America\/North_Dakota\/Center": "మధ్యమ సమయం (సెంటర్, ఉత్తర డకోటా)", + "America\/North_Dakota\/New_Salem": "మధ్యమ సమయం (న్యూ సలేమ్, ఉత్తర డకోట)", + "America\/Ojinaga": "మౌంటెయిన్ సమయం (ఒజినగ)", + "America\/Panama": "తూర్పు సమయం (పనామా)", + "America\/Pangnirtung": "తూర్పు సమయం (పాంగ్‌నీర్‌టుంగ్)", + "America\/Paramaribo": "సూరినామ్ సమయం (పరామారిబో)", + "America\/Phoenix": "మౌంటెయిన్ సమయం (ఫినిక్స్)", + "America\/Port-au-Prince": "తూర్పు సమయం (పోర్ట్-అవ్-ప్రిన్స్)", + "America\/Port_of_Spain": "అట్లాంటిక్ సమయం (పోర్ట్ ఆఫ్ స్పెయిన్)", + "America\/Porto_Velho": "అమెజాన్ సమయం (పోర్టో వెల్హో)", + "America\/Puerto_Rico": "అట్లాంటిక్ సమయం (ప్యూర్టో రికో)", + "America\/Punta_Arenas": "చిలీ సమయం (పుంటా అరీనస్)", + "America\/Rainy_River": "మధ్యమ సమయం (రెయినీ రివర్)", + "America\/Rankin_Inlet": "మధ్యమ సమయం (రన్‌కిన్ ఇన్‌లెట్)", + "America\/Recife": "బ్రెజిలియా సమయం (రెసిఫీ)", + "America\/Regina": "మధ్యమ సమయం (రెజీనా)", + "America\/Resolute": "మధ్యమ సమయం (రిజల్యూట్)", + "America\/Rio_Branco": "ఏకర్ సమయం (రియో బ్రాంకో)", + "America\/Santa_Isabel": "వాయువ్య మెక్సికో సమయం (శాంటా ఇసబెల్)", + "America\/Santarem": "బ్రెజిలియా సమయం (సాంటరెమ్)", + "America\/Santiago": "చిలీ సమయం (శాంటియాగో)", + "America\/Santo_Domingo": "అట్లాంటిక్ సమయం (శాంటో డోమింగో)", + "America\/Sao_Paulo": "బ్రెజిలియా సమయం (సావో పాలో)", + "America\/Scoresbysund": "తూర్పు గ్రీన్‌ల్యాండ్ సమయం (ఇటోక్కోర్టూర్మిట్)", + "America\/Sitka": "అలాస్కా సమయం (సిట్కా)", + "America\/St_Barthelemy": "అట్లాంటిక్ సమయం (సెయింట్ బర్తెలెమీ)", + "America\/St_Johns": "న్యూఫౌండ్‌ల్యాండ్ సమయం (సెయింట్ జాన్స్)", + "America\/St_Kitts": "అట్లాంటిక్ సమయం (సెయింట్ కిట్స్)", + "America\/St_Lucia": "అట్లాంటిక్ సమయం (సెయింట్ లూసియా)", + "America\/St_Thomas": "అట్లాంటిక్ సమయం (సెయింట్ థామస్)", + "America\/St_Vincent": "అట్లాంటిక్ సమయం (సెయింట్ విన్సెంట్)", + "America\/Swift_Current": "మధ్యమ సమయం (స్విఫ్ట్ కరెంట్)", + "America\/Tegucigalpa": "మధ్యమ సమయం (తెగుసిగల్పా)", + "America\/Thule": "అట్లాంటిక్ సమయం (థులే)", + "America\/Thunder_Bay": "తూర్పు సమయం (థండర్ బే)", + "America\/Tijuana": "పసిఫిక్ సమయం (టిజువానా)", + "America\/Toronto": "తూర్పు సమయం (టొరంటో)", + "America\/Tortola": "అట్లాంటిక్ సమయం (టోర్టోలా)", + "America\/Vancouver": "పసిఫిక్ సమయం (వాన్కూవర్)", + "America\/Whitehorse": "పసిఫిక్ సమయం (వైట్‌హార్స్)", + "America\/Winnipeg": "మధ్యమ సమయం (విన్నిపెగ్)", + "America\/Yakutat": "అలాస్కా సమయం (యకుటాట్)", + "America\/Yellowknife": "మౌంటెయిన్ సమయం (ఎల్లోనైఫ్)", + "Antarctica\/Casey": "పశ్చిమ ఆస్ట్రేలియా సమయం (కేసీ)", + "Antarctica\/Davis": "డేవిస్ సమయం (డెవిస్)", + "Antarctica\/DumontDUrville": "డ్యూమాంట్-డి’ఉర్విల్లే సమయం (డ్యూమాంట్ డి’ఉర్విల్లే)", + "Antarctica\/Macquarie": "మాక్క్వారీ దీవి సమయం (మకారీ)", + "Antarctica\/Mawson": "మాసన్ సమయం (మాసన్)", + "Antarctica\/McMurdo": "న్యూజిల్యాండ్ సమయం (మెక్‌ముర్డో)", + "Antarctica\/Palmer": "చిలీ సమయం (పాల్మర్)", + "Antarctica\/Rothera": "రొతేరా సమయం (రొతేరా)", + "Antarctica\/Syowa": "స్యోవా సమయం (స్యోవా)", + "Antarctica\/Troll": "గ్రీన్‌విచ్ సగటు సమయం (ట్రోల్)", + "Antarctica\/Vostok": "వోస్టోక్ సమయం (వోస్టోక్)", + "Arctic\/Longyearbyen": "సెంట్రల్ యూరోపియన్ సమయం (లాంగ్‌యియర్‌బైయన్)", + "Asia\/Aden": "అరేబియన్ సమయం (ఎడెన్)", + "Asia\/Almaty": "తూర్పు కజకి‌స్తాన్ సమయం (ఆల్మాటి)", + "Asia\/Amman": "తూర్పు యూరోపియన్ సమయం (అమ్మన్)", + "Asia\/Anadyr": "అనడైర్ సమయం (అనడైర్)", + "Asia\/Aqtau": "పశ్చిమ కజకిస్తాన్ సమయం (అక్టావ్)", + "Asia\/Aqtobe": "పశ్చిమ కజకిస్తాన్ సమయం (అక్టోబ్)", + "Asia\/Ashgabat": "తుర్క్‌మెనిస్తాన్ సమయం (యాష్గాబాట్)", + "Asia\/Atyrau": "పశ్చిమ కజకిస్తాన్ సమయం (ఆటిరా)", + "Asia\/Baghdad": "అరేబియన్ సమయం (బాగ్దాద్)", + "Asia\/Bahrain": "అరేబియన్ సమయం (బహ్రెయిన్)", + "Asia\/Baku": "అజర్బైజాన్ సమయం (బాకు)", + "Asia\/Bangkok": "ఇండోచైనా సమయం (బ్యాంకాక్)", + "Asia\/Beirut": "తూర్పు యూరోపియన్ సమయం (బీరట్)", + "Asia\/Bishkek": "కిర్గిస్తాన్ సమయం (బిష్కెక్)", + "Asia\/Brunei": "బ్రూనే దరుసలామ్ సమయం (బ్రూనై)", + "Asia\/Calcutta": "భారతదేశ సమయం (కోల్‌కతా)", + "Asia\/Chita": "యాకుట్స్క్ సమయం (చితా)", + "Asia\/Choibalsan": "చోయిబల్సాన్ సమయం (చోయిబాల్సన్)", + "Asia\/Colombo": "భారతదేశ సమయం (కొలంబో)", + "Asia\/Damascus": "తూర్పు యూరోపియన్ సమయం (డమాస్కస్)", + "Asia\/Dhaka": "బంగ్లాదేశ్ సమయం (ఢాకా)", + "Asia\/Dili": "తూర్పు తైమూర్ సమయం (డిలి)", + "Asia\/Dubai": "గల్ఫ్ ప్రామాణిక సమయం (దుబాయి)", + "Asia\/Dushanbe": "తజికిస్తాన్ సమయం (డుషన్బీ)", + "Asia\/Famagusta": "తూర్పు యూరోపియన్ సమయం (ఫామగుస్టా)", + "Asia\/Gaza": "తూర్పు యూరోపియన్ సమయం (గాజా)", + "Asia\/Hebron": "తూర్పు యూరోపియన్ సమయం (హెబ్రాన్)", + "Asia\/Hong_Kong": "హాంకాంగ్ సమయం (హాంకాంగ్)", + "Asia\/Hovd": "హోవ్డ్ సమయం (హోవ్డ్)", + "Asia\/Irkutsk": "ఇర్కుట్స్క్ సమయం (ఇర్కుట్స్క్)", + "Asia\/Jakarta": "పశ్చిమ ఇండోనేషియా సమయం (జకార్తా)", + "Asia\/Jayapura": "తూర్పు ఇండోనేషియా సమయం (జయపుర)", + "Asia\/Jerusalem": "ఇజ్రాయిల్ సమయం (జరూసలేం)", + "Asia\/Kabul": "ఆఫ్ఘనిస్తాన్ సమయం (కాబుల్)", + "Asia\/Kamchatka": "పెట్రోపావ్లోవ్స్క్-కామ్ఛాట్స్కి సమయం (కమ్‌చత్కా)", + "Asia\/Karachi": "పాకిస్తాన్ సమయం (కరాచీ)", + "Asia\/Katmandu": "నేపాల్ సమయం (ఖాట్మండు)", + "Asia\/Khandyga": "యాకుట్స్క్ సమయం (కంద్యాగ)", + "Asia\/Krasnoyarsk": "క్రాస్నోయార్స్క్ సమయం (క్రసనోయార్స్క్)", + "Asia\/Kuala_Lumpur": "మలేషియా సమయం (కౌలాలంపూర్)", + "Asia\/Kuching": "మలేషియా సమయం (కుచింగ్)", + "Asia\/Kuwait": "అరేబియన్ సమయం (కువైట్)", + "Asia\/Macau": "చైనా సమయం (మకావ్)", + "Asia\/Magadan": "మగడాన్ సమయం (మగడాన్)", + "Asia\/Makassar": "సెంట్రల్ ఇండోనేషియా సమయం (మకాస్సర్)", + "Asia\/Manila": "ఫిలిప్పైన్ సమయం (మనీలా)", + "Asia\/Muscat": "గల్ఫ్ ప్రామాణిక సమయం (మస్కట్)", + "Asia\/Nicosia": "తూర్పు యూరోపియన్ సమయం (నికోసియా)", + "Asia\/Novokuznetsk": "క్రాస్నోయార్స్క్ సమయం (నొవొకుజ్‌నెట్‌స్క్)", + "Asia\/Novosibirsk": "నోవోసిబిర్స్క్ సమయం (నవోసిబిర్స్క్)", + "Asia\/Omsk": "ఓమ్స్క్ సమయం (ఓమ్స్క్)", + "Asia\/Oral": "పశ్చిమ కజకిస్తాన్ సమయం (ఓరల్)", + "Asia\/Phnom_Penh": "ఇండోచైనా సమయం (నోమ్‌పెన్హ్)", + "Asia\/Pontianak": "పశ్చిమ ఇండోనేషియా సమయం (పొన్టియనాక్)", + "Asia\/Pyongyang": "కొరియన్ సమయం (ప్యోంగాంగ్)", + "Asia\/Qatar": "అరేబియన్ సమయం (ఖతార్)", + "Asia\/Qostanay": "తూర్పు కజకి‌స్తాన్ సమయం (కోస్తానే)", + "Asia\/Qyzylorda": "పశ్చిమ కజకిస్తాన్ సమయం (క్విజిలోర్డా)", + "Asia\/Rangoon": "మయన్మార్ సమయం (యాంగన్)", + "Asia\/Riyadh": "అరేబియన్ సమయం (రియాధ్)", + "Asia\/Saigon": "ఇండోచైనా సమయం (హో చి మిన్హ్ నగరం)", + "Asia\/Sakhalin": "సఖాలిన్ సమయం (సఖాలిన్)", + "Asia\/Samarkand": "ఉజ్బెకిస్తాన్ సమయం (సమర్కాండ్)", + "Asia\/Seoul": "కొరియన్ సమయం (సియోల్)", + "Asia\/Shanghai": "చైనా సమయం (షాంఘై)", + "Asia\/Singapore": "సింగపూర్ ప్రామాణిక సమయం (సింగపూర్)", + "Asia\/Srednekolymsk": "మగడాన్ సమయం (స్రెడ్నెకొలిమ్స్క్)", + "Asia\/Taipei": "తైపీ సమయం (తైపీ)", + "Asia\/Tashkent": "ఉజ్బెకిస్తాన్ సమయం (తాష్కెంట్)", + "Asia\/Tbilisi": "జార్జియా సమయం (టిబిలిసి)", + "Asia\/Tehran": "ఇరాన్ సమయం (టెహ్రాన్)", + "Asia\/Thimphu": "భూటాన్ సమయం (థింఫు)", + "Asia\/Tokyo": "జపాన్ సమయం (టోక్యో)", + "Asia\/Ulaanbaatar": "ఉలన్ బతోర్ సమయం (ఉలాన్బాటర్)", + "Asia\/Ust-Nera": "వ్లాడివోస్టోక్ సమయం (అస్ట్-నెరా)", + "Asia\/Vientiane": "ఇండోచైనా సమయం (వియన్టైన్)", + "Asia\/Vladivostok": "వ్లాడివోస్టోక్ సమయం (వ్లాడివోస్టోక్)", + "Asia\/Yakutsk": "యాకుట్స్క్ సమయం (యకుట్స్క్)", + "Asia\/Yekaterinburg": "యెకటెరిన్‌బర్గ్ సమయం (యెకటెరింబర్గ్)", + "Asia\/Yerevan": "ఆర్మేనియా సమయం (యెరెవన్)", + "Atlantic\/Azores": "అజోర్స్ సమయం (అజోర్స్)", + "Atlantic\/Bermuda": "అట్లాంటిక్ సమయం (బెర్ముడా)", + "Atlantic\/Canary": "పశ్చిమ యూరోపియన్ సమయం (కెనరీ)", + "Atlantic\/Cape_Verde": "కేప్ వెర్డె సమయం (కేప్ వెర్డె)", + "Atlantic\/Faeroe": "పశ్చిమ యూరోపియన్ సమయం (ఫారో)", + "Atlantic\/Madeira": "పశ్చిమ యూరోపియన్ సమయం (మదైరా)", + "Atlantic\/Reykjavik": "గ్రీన్‌విచ్ సగటు సమయం (రెక్జావిక్)", + "Atlantic\/South_Georgia": "దక్షిణ జార్జియా సమయం (దక్షిణ జార్జియా)", + "Atlantic\/St_Helena": "గ్రీన్‌విచ్ సగటు సమయం (సెయింట్ హెలెనా)", + "Atlantic\/Stanley": "ఫాక్‌ల్యాండ్ దీవుల సమయం (స్టాన్లీ)", + "Australia\/Adelaide": "ఆస్ట్రేలియా మధ్యమ సమయం (అడెలైడ్)", + "Australia\/Brisbane": "తూర్పు ఆస్ట్రేలియా సమయం (బ్రిస్‌బెయిన్)", + "Australia\/Broken_Hill": "ఆస్ట్రేలియా మధ్యమ సమయం (బ్రోకెన్ హిల్)", + "Australia\/Currie": "తూర్పు ఆస్ట్రేలియా సమయం (కర్రీ)", + "Australia\/Darwin": "ఆస్ట్రేలియా మధ్యమ సమయం (డార్విన్)", + "Australia\/Eucla": "ఆస్ట్రేలియా మధ్యమ పశ్చిమ సమయం (యుక్లా)", + "Australia\/Hobart": "తూర్పు ఆస్ట్రేలియా సమయం (హోబర్ట్)", + "Australia\/Lindeman": "తూర్పు ఆస్ట్రేలియా సమయం (లిండెమాన్)", + "Australia\/Lord_Howe": "లార్డ్ హోవ్ సమయం (లార్డ్ హౌ)", + "Australia\/Melbourne": "తూర్పు ఆస్ట్రేలియా సమయం (మెల్బోర్న్)", + "Australia\/Perth": "పశ్చిమ ఆస్ట్రేలియా సమయం (పెర్త్)", + "Australia\/Sydney": "తూర్పు ఆస్ట్రేలియా సమయం (సిడ్నీ)", + "CST6CDT": "మధ్యమ సమయం", + "EST5EDT": "తూర్పు సమయం", + "Etc\/GMT": "గ్రీన్‌విచ్ సగటు సమయం", + "Etc\/UTC": "సమన్వయ సార్వజనీన సమయం", + "Europe\/Amsterdam": "సెంట్రల్ యూరోపియన్ సమయం (ఆమ్‌స్టర్‌డామ్)", + "Europe\/Andorra": "సెంట్రల్ యూరోపియన్ సమయం (అండోరా)", + "Europe\/Astrakhan": "మాస్కో సమయం (అస్ట్రఖాన్)", + "Europe\/Athens": "తూర్పు యూరోపియన్ సమయం (ఏథెన్స్)", + "Europe\/Belgrade": "సెంట్రల్ యూరోపియన్ సమయం (బెల్‌గ్రేడ్)", + "Europe\/Berlin": "సెంట్రల్ యూరోపియన్ సమయం (బెర్లిన్)", + "Europe\/Bratislava": "సెంట్రల్ యూరోపియన్ సమయం (బ్రాటిస్లావా)", + "Europe\/Brussels": "సెంట్రల్ యూరోపియన్ సమయం (బ్రస్సెల్స్)", + "Europe\/Bucharest": "తూర్పు యూరోపియన్ సమయం (బుకారెస్ట్)", + "Europe\/Budapest": "సెంట్రల్ యూరోపియన్ సమయం (బుడాపెస్ట్)", + "Europe\/Busingen": "సెంట్రల్ యూరోపియన్ సమయం (బసింజన్)", + "Europe\/Chisinau": "తూర్పు యూరోపియన్ సమయం (చిసినావ్)", + "Europe\/Copenhagen": "సెంట్రల్ యూరోపియన్ సమయం (కోపెన్హాగన్)", + "Europe\/Dublin": "గ్రీన్‌విచ్ సగటు సమయం (డబ్లిన్)", + "Europe\/Gibraltar": "సెంట్రల్ యూరోపియన్ సమయం (జిబ్రాల్టర్)", + "Europe\/Guernsey": "గ్రీన్‌విచ్ సగటు సమయం (గ్వెర్న్సే)", + "Europe\/Helsinki": "తూర్పు యూరోపియన్ సమయం (హెల్సింకి)", + "Europe\/Isle_of_Man": "గ్రీన్‌విచ్ సగటు సమయం (ఐల్ ఆఫ్ మేన్)", + "Europe\/Jersey": "గ్రీన్‌విచ్ సగటు సమయం (జెర్సీ)", + "Europe\/Kaliningrad": "తూర్పు యూరోపియన్ సమయం (కలినిన్‌గ్రద్)", + "Europe\/Kiev": "తూర్పు యూరోపియన్ సమయం (కీవ్)", + "Europe\/Lisbon": "పశ్చిమ యూరోపియన్ సమయం (లిస్బన్)", + "Europe\/Ljubljana": "సెంట్రల్ యూరోపియన్ సమయం (ల్యూబ్ల్యానా)", + "Europe\/London": "గ్రీన్‌విచ్ సగటు సమయం (లండన్)", + "Europe\/Luxembourg": "సెంట్రల్ యూరోపియన్ సమయం (లక్సెంబర్గ్)", + "Europe\/Madrid": "సెంట్రల్ యూరోపియన్ సమయం (మాడ్రిడ్)", + "Europe\/Malta": "సెంట్రల్ యూరోపియన్ సమయం (మాల్టా)", + "Europe\/Mariehamn": "తూర్పు యూరోపియన్ సమయం (మారీయుహమ్)", + "Europe\/Minsk": "మాస్కో సమయం (మిన్స్క్)", + "Europe\/Monaco": "సెంట్రల్ యూరోపియన్ సమయం (మొనాకో)", + "Europe\/Moscow": "మాస్కో సమయం (మాస్కో)", + "Europe\/Oslo": "సెంట్రల్ యూరోపియన్ సమయం (ఓస్లో)", + "Europe\/Paris": "సెంట్రల్ యూరోపియన్ సమయం (ప్యారిస్)", + "Europe\/Podgorica": "సెంట్రల్ యూరోపియన్ సమయం (పోడ్గోరికా)", + "Europe\/Prague": "సెంట్రల్ యూరోపియన్ సమయం (ప్రాగ్)", + "Europe\/Riga": "తూర్పు యూరోపియన్ సమయం (రీగా)", + "Europe\/Rome": "సెంట్రల్ యూరోపియన్ సమయం (రోమ్)", + "Europe\/Samara": "సమారా సమయం (సమార)", + "Europe\/San_Marino": "సెంట్రల్ యూరోపియన్ సమయం (శాన్ మారినో)", + "Europe\/Sarajevo": "సెంట్రల్ యూరోపియన్ సమయం (సరాజోవో)", + "Europe\/Saratov": "మాస్కో సమయం (సరాటవ్)", + "Europe\/Simferopol": "మాస్కో సమయం (సిమ్‌ఫెరోపోల్)", + "Europe\/Skopje": "సెంట్రల్ యూరోపియన్ సమయం (స్కోప్‌యే)", + "Europe\/Sofia": "తూర్పు యూరోపియన్ సమయం (సోఫియా)", + "Europe\/Stockholm": "సెంట్రల్ యూరోపియన్ సమయం (స్టాక్హోమ్)", + "Europe\/Tallinn": "తూర్పు యూరోపియన్ సమయం (తాల్లిన్)", + "Europe\/Tirane": "సెంట్రల్ యూరోపియన్ సమయం (టిరేన్)", + "Europe\/Ulyanovsk": "మాస్కో సమయం (ఉల్యనోవ్స్క్)", + "Europe\/Uzhgorod": "తూర్పు యూరోపియన్ సమయం (ఉజ్‌హోరోడ్)", + "Europe\/Vaduz": "సెంట్రల్ యూరోపియన్ సమయం (వాడుజ్)", + "Europe\/Vatican": "సెంట్రల్ యూరోపియన్ సమయం (వాటికన్)", + "Europe\/Vienna": "సెంట్రల్ యూరోపియన్ సమయం (వియన్నా)", + "Europe\/Vilnius": "తూర్పు యూరోపియన్ సమయం (విల్నియస్)", + "Europe\/Volgograd": "వోల్గోగ్రాడ్ సమయం (వోల్గోగ్రాడ్)", + "Europe\/Warsaw": "సెంట్రల్ యూరోపియన్ సమయం (వార్షా)", + "Europe\/Zagreb": "సెంట్రల్ యూరోపియన్ సమయం (జాగ్రెబ్)", + "Europe\/Zaporozhye": "తూర్పు యూరోపియన్ సమయం (జపరోజై)", + "Europe\/Zurich": "సెంట్రల్ యూరోపియన్ సమయం (జ్యూరిచ్)", + "Indian\/Antananarivo": "తూర్పు ఆఫ్రికా సమయం (అంటానానారివో)", + "Indian\/Chagos": "హిందూ మహా సముద్ర సమయం (చాగోస్)", + "Indian\/Christmas": "క్రిస్మస్ దీవి సమయం (క్రిస్మస్)", + "Indian\/Cocos": "కోకోస్ దీవుల సమయం (కోకోస్)", + "Indian\/Comoro": "తూర్పు ఆఫ్రికా సమయం (కొమోరో)", + "Indian\/Kerguelen": "ఫ్రెంచ్ దక్షిణ మరియు అంటార్కిటిక్ సమయం (కెర్గ్యూలెన్)", + "Indian\/Mahe": "సీషెల్స్ సమయం (మాహె)", + "Indian\/Maldives": "మాల్దీవుల సమయం (మాల్దీవులు)", + "Indian\/Mauritius": "మారిషస్ సమయం (మారిషస్)", + "Indian\/Mayotte": "తూర్పు ఆఫ్రికా సమయం (మయోట్)", + "Indian\/Reunion": "రీయూనియన్ సమయం (రీయూనియన్)", + "MST7MDT": "మౌంటెయిన్ సమయం", + "PST8PDT": "పసిఫిక్ సమయం", + "Pacific\/Apia": "ఏపియా సమయం (ఏపియా)", + "Pacific\/Auckland": "న్యూజిల్యాండ్ సమయం (ఆక్లాండ్)", + "Pacific\/Bougainville": "పాపువా న్యూ గినియా సమయం (బొగెయిన్‌విల్లే)", + "Pacific\/Chatham": "చాథమ్ సమయం (చాథమ్)", + "Pacific\/Easter": "ఈస్టర్ దీవి సమయం (ఈస్టర్)", + "Pacific\/Efate": "వనౌటు సమయం (ఇఫేట్)", + "Pacific\/Enderbury": "ఫినిక్స్ దీవుల సమయం (ఎండర్బెరీ)", + "Pacific\/Fakaofo": "టోకెలావ్ సమయం (ఫాకోఫో)", + "Pacific\/Fiji": "ఫిజీ సమయం (ఫీజీ)", + "Pacific\/Funafuti": "తువాలు సమయం (ఫునాఫుటి)", + "Pacific\/Galapagos": "గాలాపాగోస్ సమయం (గాలాపాగోస్)", + "Pacific\/Gambier": "గాంబియర్ సమయం (గాంబియేర్)", + "Pacific\/Guadalcanal": "సోలమన్ దీవుల సమయం (గ్వాడల్కెనాల్)", + "Pacific\/Guam": "చామర్రో ప్రామాణిక సమయం (గ్వామ్)", + "Pacific\/Honolulu": "హవాయ్-అల్యూషియన్ సమయం (హోనోలులు)", + "Pacific\/Johnston": "హవాయ్-అల్యూషియన్ సమయం (జాన్సటన్)", + "Pacific\/Kiritimati": "లైన్ దీవుల సమయం (కిరీటిమాటి)", + "Pacific\/Kosrae": "కోస్రాయి సమయం (కోస్రే)", + "Pacific\/Kwajalein": "మార్షల్ దీవుల సమయం (క్వాజాలైన్)", + "Pacific\/Majuro": "మార్షల్ దీవుల సమయం (మజురో)", + "Pacific\/Marquesas": "మార్క్వేసాస్ సమయం (మార్క్వేసాస్)", + "Pacific\/Midway": "సమోవా సమయం (మిడ్వే)", + "Pacific\/Nauru": "నౌరు సమయం (నౌరు)", + "Pacific\/Niue": "నియూ సమయం (నియూ)", + "Pacific\/Norfolk": "నార్ఫోక్ దీవి సమయం (నోర్ఫోక్)", + "Pacific\/Noumea": "న్యూ కాలెడోనియా సమయం (నౌమియా)", + "Pacific\/Pago_Pago": "సమోవా సమయం (పాగో పాగో)", + "Pacific\/Palau": "పాలావ్ సమయం (పాలావ్)", + "Pacific\/Pitcairn": "పిట్‌కైర్న్ సమయం (పిట్‌కైర్న్)", + "Pacific\/Ponape": "పొనేప్ సమయం (పోన్‌పై)", + "Pacific\/Port_Moresby": "పాపువా న్యూ గినియా సమయం (పోర్ట్ మోరెస్బే)", + "Pacific\/Rarotonga": "కుక్ దీవుల సమయం (రరోటోంగా)", + "Pacific\/Saipan": "చామర్రో ప్రామాణిక సమయం (సాయ్పాన్)", + "Pacific\/Tahiti": "తహితి సమయం (తహితి)", + "Pacific\/Tarawa": "గిల్బర్ట్ దీవుల సమయం (టరావా)", + "Pacific\/Tongatapu": "టాంగా సమయం (టోంగాటాపు)", + "Pacific\/Truk": "చక్ సమయం (చుక్)", + "Pacific\/Wake": "వేక్ దీవి సమయం (వేక్)", + "Pacific\/Wallis": "వాలీస్ మరియు ఫుటునా సమయం (వాల్లిస్)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/tg.json b/src/Symfony/Component/Intl/Resources/data/timezones/tg.json new file mode 100644 index 0000000000000..70221b6fa922c --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/tg.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.47.96", + "Names": { + "Africa\/Abidjan": "Ба вақти Гринвич (Abidjan)", + "Africa\/Accra": "Ба вақти Гринвич (Accra)", + "Africa\/Algiers": "Вақти аврупоии марказӣ (Algiers)", + "Africa\/Bamako": "Ба вақти Гринвич (Bamako)", + "Africa\/Banjul": "Ба вақти Гринвич (Banjul)", + "Africa\/Bissau": "Ба вақти Гринвич (Bissau)", + "Africa\/Cairo": "Вақти аврупоии шарқӣ (Cairo)", + "Africa\/Casablanca": "Вақти аврупоии ғарбӣ (Casablanca)", + "Africa\/Ceuta": "Вақти аврупоии марказӣ (Ceuta)", + "Africa\/Conakry": "Ба вақти Гринвич (Conakry)", + "Africa\/Dakar": "Ба вақти Гринвич (Dakar)", + "Africa\/El_Aaiun": "Вақти аврупоии ғарбӣ (El Aaiun)", + "Africa\/Freetown": "Ба вақти Гринвич (Freetown)", + "Africa\/Lome": "Ба вақти Гринвич (Lome)", + "Africa\/Monrovia": "Ба вақти Гринвич (Monrovia)", + "Africa\/Nouakchott": "Ба вақти Гринвич (Nouakchott)", + "Africa\/Ouagadougou": "Ба вақти Гринвич (Ouagadougou)", + "Africa\/Sao_Tome": "Ба вақти Гринвич (Sao Tome)", + "Africa\/Tripoli": "Вақти аврупоии шарқӣ (Tripoli)", + "Africa\/Tunis": "Вақти аврупоии марказӣ (Tunis)", + "America\/Anguilla": "Вақти атлантикӣ (Anguilla)", + "America\/Antigua": "Вақти атлантикӣ (Antigua)", + "America\/Aruba": "Вақти атлантикӣ (Aruba)", + "America\/Bahia_Banderas": "Вақти марказӣ (Bahia Banderas)", + "America\/Barbados": "Вақти атлантикӣ (Barbados)", + "America\/Belize": "Вақти марказӣ (Belize)", + "America\/Blanc-Sablon": "Вақти атлантикӣ (Blanc-Sablon)", + "America\/Boise": "Вақти кӯҳӣ (Boise)", + "America\/Cambridge_Bay": "Вақти кӯҳӣ (Cambridge Bay)", + "America\/Cancun": "Вақти шарқӣ (Cancun)", + "America\/Cayman": "Вақти шарқӣ (Cayman)", + "America\/Chicago": "Вақти марказӣ (Chicago)", + "America\/Coral_Harbour": "Вақти шарқӣ (Atikokan)", + "America\/Costa_Rica": "Вақти марказӣ (Costa Rica)", + "America\/Creston": "Вақти кӯҳӣ (Creston)", + "America\/Curacao": "Вақти атлантикӣ (Curacao)", + "America\/Danmarkshavn": "Ба вақти Гринвич (Danmarkshavn)", + "America\/Dawson": "Вақти Уёнуси Ором (Dawson)", + "America\/Dawson_Creek": "Вақти кӯҳӣ (Dawson Creek)", + "America\/Denver": "Вақти кӯҳӣ (Denver)", + "America\/Detroit": "Вақти шарқӣ (Detroit)", + "America\/Dominica": "Вақти атлантикӣ (Dominica)", + "America\/Edmonton": "Вақти кӯҳӣ (Edmonton)", + "America\/El_Salvador": "Вақти марказӣ (El Salvador)", + "America\/Fort_Nelson": "Вақти кӯҳӣ (Fort Nelson)", + "America\/Glace_Bay": "Вақти атлантикӣ (Glace Bay)", + "America\/Goose_Bay": "Вақти атлантикӣ (Goose Bay)", + "America\/Grand_Turk": "Вақти шарқӣ (Grand Turk)", + "America\/Grenada": "Вақти атлантикӣ (Grenada)", + "America\/Guadeloupe": "Вақти атлантикӣ (Guadeloupe)", + "America\/Guatemala": "Вақти марказӣ (Guatemala)", + "America\/Halifax": "Вақти атлантикӣ (Halifax)", + "America\/Indiana\/Knox": "Вақти марказӣ (Knox, Indiana)", + "America\/Indiana\/Marengo": "Вақти шарқӣ (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Вақти шарқӣ (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Вақти марказӣ (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Вақти шарқӣ (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Вақти шарқӣ (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Вақти шарқӣ (Winamac, Indiana)", + "America\/Indianapolis": "Вақти шарқӣ (Indianapolis)", + "America\/Inuvik": "Вақти кӯҳӣ (Inuvik)", + "America\/Iqaluit": "Вақти шарқӣ (Iqaluit)", + "America\/Jamaica": "Вақти шарқӣ (Jamaica)", + "America\/Kentucky\/Monticello": "Вақти шарқӣ (Monticello, Kentucky)", + "America\/Kralendijk": "Вақти атлантикӣ (Kralendijk)", + "America\/Los_Angeles": "Вақти Уёнуси Ором (Los Angeles)", + "America\/Louisville": "Вақти шарқӣ (Louisville)", + "America\/Lower_Princes": "Вақти атлантикӣ (Lower Prince’s Quarter)", + "America\/Managua": "Вақти марказӣ (Managua)", + "America\/Marigot": "Вақти атлантикӣ (Marigot)", + "America\/Martinique": "Вақти атлантикӣ (Martinique)", + "America\/Matamoros": "Вақти марказӣ (Matamoros)", + "America\/Menominee": "Вақти марказӣ (Menominee)", + "America\/Merida": "Вақти марказӣ (Merida)", + "America\/Mexico_City": "Вақти марказӣ (Mexico City)", + "America\/Moncton": "Вақти атлантикӣ (Moncton)", + "America\/Monterrey": "Вақти марказӣ (Monterrey)", + "America\/Montserrat": "Вақти атлантикӣ (Montserrat)", + "America\/Nassau": "Вақти шарқӣ (Nassau)", + "America\/New_York": "Вақти шарқӣ (New York)", + "America\/Nipigon": "Вақти шарқӣ (Nipigon)", + "America\/North_Dakota\/Beulah": "Вақти марказӣ (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Вақти марказӣ (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Вақти марказӣ (New Salem, North Dakota)", + "America\/Ojinaga": "Вақти кӯҳӣ (Ojinaga)", + "America\/Panama": "Вақти шарқӣ (Panama)", + "America\/Pangnirtung": "Вақти шарқӣ (Pangnirtung)", + "America\/Phoenix": "Вақти кӯҳӣ (Phoenix)", + "America\/Port-au-Prince": "Вақти шарқӣ (Port-au-Prince)", + "America\/Port_of_Spain": "Вақти атлантикӣ (Port of Spain)", + "America\/Puerto_Rico": "Вақти атлантикӣ (Puerto Rico)", + "America\/Rainy_River": "Вақти марказӣ (Rainy River)", + "America\/Rankin_Inlet": "Вақти марказӣ (Rankin Inlet)", + "America\/Regina": "Вақти марказӣ (Regina)", + "America\/Resolute": "Вақти марказӣ (Resolute)", + "America\/Santo_Domingo": "Вақти атлантикӣ (Santo Domingo)", + "America\/St_Barthelemy": "Вақти атлантикӣ (St. Barthelemy)", + "America\/St_Kitts": "Вақти атлантикӣ (St. Kitts)", + "America\/St_Lucia": "Вақти атлантикӣ (St. Lucia)", + "America\/St_Thomas": "Вақти атлантикӣ (St. Thomas)", + "America\/St_Vincent": "Вақти атлантикӣ (St. Vincent)", + "America\/Swift_Current": "Вақти марказӣ (Swift Current)", + "America\/Tegucigalpa": "Вақти марказӣ (Tegucigalpa)", + "America\/Thule": "Вақти атлантикӣ (Thule)", + "America\/Thunder_Bay": "Вақти шарқӣ (Thunder Bay)", + "America\/Tijuana": "Вақти Уёнуси Ором (Tijuana)", + "America\/Toronto": "Вақти шарқӣ (Toronto)", + "America\/Tortola": "Вақти атлантикӣ (Tortola)", + "America\/Vancouver": "Вақти Уёнуси Ором (Vancouver)", + "America\/Whitehorse": "Вақти Уёнуси Ором (Whitehorse)", + "America\/Winnipeg": "Вақти марказӣ (Winnipeg)", + "America\/Yellowknife": "Вақти кӯҳӣ (Yellowknife)", + "Antarctica\/Troll": "Ба вақти Гринвич (Troll)", + "Arctic\/Longyearbyen": "Вақти аврупоии марказӣ (Longyearbyen)", + "Asia\/Amman": "Вақти аврупоии шарқӣ (Amman)", + "Asia\/Beirut": "Вақти аврупоии шарқӣ (Beirut)", + "Asia\/Damascus": "Вақти аврупоии шарқӣ (Damascus)", + "Asia\/Famagusta": "Вақти аврупоии шарқӣ (Famagusta)", + "Asia\/Gaza": "Вақти аврупоии шарқӣ (Gaza)", + "Asia\/Hebron": "Вақти аврупоии шарқӣ (Hebron)", + "Asia\/Nicosia": "Вақти аврупоии шарқӣ (Nicosia)", + "Atlantic\/Bermuda": "Вақти атлантикӣ (Bermuda)", + "Atlantic\/Canary": "Вақти аврупоии ғарбӣ (Canary)", + "Atlantic\/Faeroe": "Вақти аврупоии ғарбӣ (Faroe)", + "Atlantic\/Madeira": "Вақти аврупоии ғарбӣ (Madeira)", + "Atlantic\/Reykjavik": "Ба вақти Гринвич (Reykjavik)", + "Atlantic\/St_Helena": "Ба вақти Гринвич (St. Helena)", + "CST6CDT": "Вақти марказӣ", + "EST5EDT": "Вақти шарқӣ", + "Etc\/GMT": "Ба вақти Гринвич", + "Etc\/UTC": "Вақти ҷаҳонии ҳамоҳангсозӣ", + "Europe\/Amsterdam": "Вақти аврупоии марказӣ (Amsterdam)", + "Europe\/Andorra": "Вақти аврупоии марказӣ (Andorra)", + "Europe\/Athens": "Вақти аврупоии шарқӣ (Athens)", + "Europe\/Belgrade": "Вақти аврупоии марказӣ (Belgrade)", + "Europe\/Berlin": "Вақти аврупоии марказӣ (Berlin)", + "Europe\/Bratislava": "Вақти аврупоии марказӣ (Bratislava)", + "Europe\/Brussels": "Вақти аврупоии марказӣ (Brussels)", + "Europe\/Bucharest": "Вақти аврупоии шарқӣ (Bucharest)", + "Europe\/Budapest": "Вақти аврупоии марказӣ (Budapest)", + "Europe\/Busingen": "Вақти аврупоии марказӣ (Busingen)", + "Europe\/Chisinau": "Вақти аврупоии шарқӣ (Chisinau)", + "Europe\/Copenhagen": "Вақти аврупоии марказӣ (Copenhagen)", + "Europe\/Dublin": "Ба вақти Гринвич (Dublin)", + "Europe\/Gibraltar": "Вақти аврупоии марказӣ (Gibraltar)", + "Europe\/Guernsey": "Ба вақти Гринвич (Guernsey)", + "Europe\/Helsinki": "Вақти аврупоии шарқӣ (Helsinki)", + "Europe\/Isle_of_Man": "Ба вақти Гринвич (Isle of Man)", + "Europe\/Jersey": "Ба вақти Гринвич (Jersey)", + "Europe\/Kaliningrad": "Вақти аврупоии шарқӣ (Kaliningrad)", + "Europe\/Kiev": "Вақти аврупоии шарқӣ (Kiev)", + "Europe\/Lisbon": "Вақти аврупоии ғарбӣ (Lisbon)", + "Europe\/Ljubljana": "Вақти аврупоии марказӣ (Ljubljana)", + "Europe\/London": "Ба вақти Гринвич (London)", + "Europe\/Luxembourg": "Вақти аврупоии марказӣ (Luxembourg)", + "Europe\/Madrid": "Вақти аврупоии марказӣ (Madrid)", + "Europe\/Malta": "Вақти аврупоии марказӣ (Malta)", + "Europe\/Mariehamn": "Вақти аврупоии шарқӣ (Mariehamn)", + "Europe\/Monaco": "Вақти аврупоии марказӣ (Monaco)", + "Europe\/Oslo": "Вақти аврупоии марказӣ (Oslo)", + "Europe\/Paris": "Вақти аврупоии марказӣ (Paris)", + "Europe\/Podgorica": "Вақти аврупоии марказӣ (Podgorica)", + "Europe\/Prague": "Вақти аврупоии марказӣ (Prague)", + "Europe\/Riga": "Вақти аврупоии шарқӣ (Riga)", + "Europe\/Rome": "Вақти аврупоии марказӣ (Rome)", + "Europe\/San_Marino": "Вақти аврупоии марказӣ (San Marino)", + "Europe\/Sarajevo": "Вақти аврупоии марказӣ (Sarajevo)", + "Europe\/Skopje": "Вақти аврупоии марказӣ (Skopje)", + "Europe\/Sofia": "Вақти аврупоии шарқӣ (Sofia)", + "Europe\/Stockholm": "Вақти аврупоии марказӣ (Stockholm)", + "Europe\/Tallinn": "Вақти аврупоии шарқӣ (Tallinn)", + "Europe\/Tirane": "Вақти аврупоии марказӣ (Tirane)", + "Europe\/Uzhgorod": "Вақти аврупоии шарқӣ (Uzhgorod)", + "Europe\/Vaduz": "Вақти аврупоии марказӣ (Vaduz)", + "Europe\/Vatican": "Вақти аврупоии марказӣ (Vatican)", + "Europe\/Vienna": "Вақти аврупоии марказӣ (Vienna)", + "Europe\/Vilnius": "Вақти аврупоии шарқӣ (Vilnius)", + "Europe\/Warsaw": "Вақти аврупоии марказӣ (Warsaw)", + "Europe\/Zagreb": "Вақти аврупоии марказӣ (Zagreb)", + "Europe\/Zaporozhye": "Вақти аврупоии шарқӣ (Zaporozhye)", + "Europe\/Zurich": "Вақти аврупоии марказӣ (Zurich)", + "MST7MDT": "Вақти кӯҳӣ", + "PST8PDT": "Вақти Уёнуси Ором" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/th.json b/src/Symfony/Component/Intl/Resources/data/timezones/th.json new file mode 100644 index 0000000000000..6537c926f0883 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/th.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.86", + "Names": { + "Africa\/Abidjan": "เวลามาตรฐานกรีนิช (อาบีจาน)", + "Africa\/Accra": "เวลามาตรฐานกรีนิช (อักกรา)", + "Africa\/Addis_Ababa": "เวลาแอฟริกาตะวันออก (แอดดิสอาบาบา)", + "Africa\/Algiers": "เวลายุโรปกลาง (แอลเจียร์)", + "Africa\/Asmera": "เวลาแอฟริกาตะวันออก (แอสมารา)", + "Africa\/Bamako": "เวลามาตรฐานกรีนิช (บามาโก)", + "Africa\/Bangui": "เวลาแอฟริกาตะวันตก (บังกี)", + "Africa\/Banjul": "เวลามาตรฐานกรีนิช (บันจูล)", + "Africa\/Bissau": "เวลามาตรฐานกรีนิช (บิสเซา)", + "Africa\/Blantyre": "เวลาแอฟริกากลาง (แบลนไทร์)", + "Africa\/Brazzaville": "เวลาแอฟริกาตะวันตก (บราซซาวิล)", + "Africa\/Bujumbura": "เวลาแอฟริกากลาง (บูจุมบูรา)", + "Africa\/Cairo": "เวลายุโรปตะวันออก (ไคโร)", + "Africa\/Casablanca": "เวลายุโรปตะวันตก (คาสซาบลางก้า)", + "Africa\/Ceuta": "เวลายุโรปกลาง (เซวตา)", + "Africa\/Conakry": "เวลามาตรฐานกรีนิช (โกนากรี)", + "Africa\/Dakar": "เวลามาตรฐานกรีนิช (ดาการ์)", + "Africa\/Dar_es_Salaam": "เวลาแอฟริกาตะวันออก (ดาร์เอสซาลาม)", + "Africa\/Djibouti": "เวลาแอฟริกาตะวันออก (จิบูตี)", + "Africa\/Douala": "เวลาแอฟริกาตะวันตก (ดูอาลา)", + "Africa\/El_Aaiun": "เวลายุโรปตะวันตก (เอลไอย์อุง)", + "Africa\/Freetown": "เวลามาตรฐานกรีนิช (ฟรีทาวน์)", + "Africa\/Gaborone": "เวลาแอฟริกากลาง (กาโบโรเน)", + "Africa\/Harare": "เวลาแอฟริกากลาง (ฮาราเร)", + "Africa\/Johannesburg": "เวลาแอฟริกาใต้ (โจฮันเนสเบอร์ก)", + "Africa\/Juba": "เวลาแอฟริกาตะวันออก (จูบา)", + "Africa\/Kampala": "เวลาแอฟริกาตะวันออก (คัมพาลา)", + "Africa\/Khartoum": "เวลาแอฟริกากลาง (คาร์ทูม)", + "Africa\/Kigali": "เวลาแอฟริกากลาง (คิกาลี)", + "Africa\/Kinshasa": "เวลาแอฟริกาตะวันตก (กินชาซา)", + "Africa\/Lagos": "เวลาแอฟริกาตะวันตก (ลากอส)", + "Africa\/Libreville": "เวลาแอฟริกาตะวันตก (ลีเบรอวิล)", + "Africa\/Lome": "เวลามาตรฐานกรีนิช (โลเม)", + "Africa\/Luanda": "เวลาแอฟริกาตะวันตก (ลูอันดา)", + "Africa\/Lubumbashi": "เวลาแอฟริกากลาง (ลูบัมบาชิ)", + "Africa\/Lusaka": "เวลาแอฟริกากลาง (ลูซากา)", + "Africa\/Malabo": "เวลาแอฟริกาตะวันตก (มาลาโบ)", + "Africa\/Maputo": "เวลาแอฟริกากลาง (มาปูโต)", + "Africa\/Maseru": "เวลาแอฟริกาใต้ (มาเซรู)", + "Africa\/Mbabane": "เวลาแอฟริกาใต้ (อัมบาบาเน)", + "Africa\/Mogadishu": "เวลาแอฟริกาตะวันออก (โมกาดิชู)", + "Africa\/Monrovia": "เวลามาตรฐานกรีนิช (มันโรเวีย)", + "Africa\/Nairobi": "เวลาแอฟริกาตะวันออก (ไนโรเบีย)", + "Africa\/Ndjamena": "เวลาแอฟริกาตะวันตก (เอ็นจาเมนา)", + "Africa\/Niamey": "เวลาแอฟริกาตะวันตก (นีอาเมย์)", + "Africa\/Nouakchott": "เวลามาตรฐานกรีนิช (นูแอกชอต)", + "Africa\/Ouagadougou": "เวลามาตรฐานกรีนิช (วากาดูกู)", + "Africa\/Porto-Novo": "เวลาแอฟริกาตะวันตก (ปอร์โต-โนโว)", + "Africa\/Sao_Tome": "เวลามาตรฐานกรีนิช (เซาตูเม)", + "Africa\/Tripoli": "เวลายุโรปตะวันออก (ตรีโปลี)", + "Africa\/Tunis": "เวลายุโรปกลาง (ตูนิส)", + "Africa\/Windhoek": "เวลาแอฟริกากลาง (วินด์ฮุก)", + "America\/Adak": "เวลาฮาวาย-อะลูเชียน (เอดัก)", + "America\/Anchorage": "เวลาอะแลสกา (แองเคอเรจ)", + "America\/Anguilla": "เวลาแอตแลนติก (แองกิลลา)", + "America\/Antigua": "เวลาแอตแลนติก (แอนติกา)", + "America\/Araguaina": "เวลาบราซิเลีย (อารากัวนา)", + "America\/Argentina\/La_Rioja": "เวลาอาร์เจนตินา (ลาริโอจา)", + "America\/Argentina\/Rio_Gallegos": "เวลาอาร์เจนตินา (ริโอกาลเลกอส)", + "America\/Argentina\/Salta": "เวลาอาร์เจนตินา (ซัลตา)", + "America\/Argentina\/San_Juan": "เวลาอาร์เจนตินา (ซานฮวน)", + "America\/Argentina\/San_Luis": "เวลาตะวันตกของอาร์เจนตินา (ซันลูอิส)", + "America\/Argentina\/Tucuman": "เวลาอาร์เจนตินา (ทูคูแมน)", + "America\/Argentina\/Ushuaia": "เวลาอาร์เจนตินา (อูชูเอีย)", + "America\/Aruba": "เวลาแอตแลนติก (อารูบา)", + "America\/Asuncion": "เวลาปารากวัย (อะซุนซิออง)", + "America\/Bahia": "เวลาบราซิเลีย (บาเยีย)", + "America\/Bahia_Banderas": "เวลาตอนกลางในอเมริกาเหนือ (บาเอียบันเดรัส)", + "America\/Barbados": "เวลาแอตแลนติก (บาร์เบโดส)", + "America\/Belem": "เวลาบราซิเลีย (เบเลง)", + "America\/Belize": "เวลาตอนกลางในอเมริกาเหนือ (เบลีซ)", + "America\/Blanc-Sablon": "เวลาแอตแลนติก (บลังค์-ซาบลอน)", + "America\/Boa_Vista": "เวลาแอมะซอน (บัววีชตา)", + "America\/Bogota": "เวลาโคลอมเบีย (โบโกตา)", + "America\/Boise": "เวลาแถบภูเขาในอเมริกาเหนือ (บอยซี)", + "America\/Buenos_Aires": "เวลาอาร์เจนตินา (บัวโนสไอเรส)", + "America\/Cambridge_Bay": "เวลาแถบภูเขาในอเมริกาเหนือ (อ่าวแคมบริดจ์)", + "America\/Campo_Grande": "เวลาแอมะซอน (กัมปูกรันดี)", + "America\/Cancun": "เวลาทางตะวันออกในอเมริกาเหนือ (แคนคุน)", + "America\/Caracas": "เวลาเวเนซุเอลา (คาราคัส)", + "America\/Catamarca": "เวลาอาร์เจนตินา (กาตามาร์กา)", + "America\/Cayenne": "เวลาเฟรนช์เกียนา (กาแยน)", + "America\/Cayman": "เวลาทางตะวันออกในอเมริกาเหนือ (เคย์แมน)", + "America\/Chicago": "เวลาตอนกลางในอเมริกาเหนือ (ชิคาโก)", + "America\/Chihuahua": "เวลาแปซิฟิกเม็กซิโก (ชีวาวา)", + "America\/Coral_Harbour": "เวลาทางตะวันออกในอเมริกาเหนือ (คอรัลฮาร์เบอร์)", + "America\/Cordoba": "เวลาอาร์เจนตินา (คอร์โดบา)", + "America\/Costa_Rica": "เวลาตอนกลางในอเมริกาเหนือ (คอสตาริกา)", + "America\/Creston": "เวลาแถบภูเขาในอเมริกาเหนือ (เครสตัน)", + "America\/Cuiaba": "เวลาแอมะซอน (กุยาบา)", + "America\/Curacao": "เวลาแอตแลนติก (คูราเซา)", + "America\/Danmarkshavn": "เวลามาตรฐานกรีนิช (ดานมาร์กสฮาวน์)", + "America\/Dawson": "เวลาแปซิฟิกในอเมริกาเหนือ (ดอว์สัน)", + "America\/Dawson_Creek": "เวลาแถบภูเขาในอเมริกาเหนือ (ดอว์สัน ครีก)", + "America\/Denver": "เวลาแถบภูเขาในอเมริกาเหนือ (เดนเวอร์)", + "America\/Detroit": "เวลาทางตะวันออกในอเมริกาเหนือ (ดีทรอยต์)", + "America\/Dominica": "เวลาแอตแลนติก (โดมินิกา)", + "America\/Edmonton": "เวลาแถบภูเขาในอเมริกาเหนือ (เอดมันตัน)", + "America\/Eirunepe": "เวลาอาเกร (เอรูเนเป)", + "America\/El_Salvador": "เวลาตอนกลางในอเมริกาเหนือ (เอลซัลวาดอร์)", + "America\/Fort_Nelson": "เวลาแถบภูเขาในอเมริกาเหนือ (ฟอร์ตเนลสัน)", + "America\/Fortaleza": "เวลาบราซิเลีย (ฟอร์ตาเลซา)", + "America\/Glace_Bay": "เวลาแอตแลนติก (เกลซเบย์)", + "America\/Godthab": "เวลากรีนแลนด์ตะวันตก (กอดแธบ)", + "America\/Goose_Bay": "เวลาแอตแลนติก (กูสเบย์)", + "America\/Grand_Turk": "เวลาทางตะวันออกในอเมริกาเหนือ (แกรนด์เติร์ก)", + "America\/Grenada": "เวลาแอตแลนติก (เกรนาดา)", + "America\/Guadeloupe": "เวลาแอตแลนติก (กวาเดอลูป)", + "America\/Guatemala": "เวลาตอนกลางในอเมริกาเหนือ (กัวเตมาลา)", + "America\/Guayaquil": "เวลาเอกวาดอร์ (กัวยากิล)", + "America\/Guyana": "เวลากายอานา (กายอานา)", + "America\/Halifax": "เวลาแอตแลนติก (แฮลิแฟกซ์)", + "America\/Havana": "เวลาคิวบา (ฮาวานา)", + "America\/Hermosillo": "เวลาแปซิฟิกเม็กซิโก (เอร์โมซีโย)", + "America\/Indiana\/Knox": "เวลาตอนกลางในอเมริกาเหนือ (นอกซ์, อินดีแอนา)", + "America\/Indiana\/Marengo": "เวลาทางตะวันออกในอเมริกาเหนือ (มาเรงโก, อินดีแอนา)", + "America\/Indiana\/Petersburg": "เวลาทางตะวันออกในอเมริกาเหนือ (ปีเตอร์สเบิร์ก, อินดีแอนา)", + "America\/Indiana\/Tell_City": "เวลาตอนกลางในอเมริกาเหนือ (เทลล์ซิตี, อินดีแอนา)", + "America\/Indiana\/Vevay": "เวลาทางตะวันออกในอเมริกาเหนือ (วีเวย์, อินดีแอนา)", + "America\/Indiana\/Vincennes": "เวลาทางตะวันออกในอเมริกาเหนือ (วินเซนเนส, อินดีแอนา)", + "America\/Indiana\/Winamac": "เวลาทางตะวันออกในอเมริกาเหนือ (วินาแมค, อินดีแอนา)", + "America\/Indianapolis": "เวลาทางตะวันออกในอเมริกาเหนือ (อินเดียแนโพลิส)", + "America\/Inuvik": "เวลาแถบภูเขาในอเมริกาเหนือ (อินูวิก)", + "America\/Iqaluit": "เวลาทางตะวันออกในอเมริกาเหนือ (อีกวาลิต)", + "America\/Jamaica": "เวลาทางตะวันออกในอเมริกาเหนือ (จาเมกา)", + "America\/Jujuy": "เวลาอาร์เจนตินา (จูจิว)", + "America\/Juneau": "เวลาอะแลสกา (จูโน)", + "America\/Kentucky\/Monticello": "เวลาทางตะวันออกในอเมริกาเหนือ (มอนติเซลโล, เคนตักกี)", + "America\/Kralendijk": "เวลาแอตแลนติก (คราเลนดิจค์)", + "America\/La_Paz": "เวลาโบลิเวีย (ลาปาซ)", + "America\/Lima": "เวลาเปรู (ลิมา)", + "America\/Los_Angeles": "เวลาแปซิฟิกในอเมริกาเหนือ (ลอสแองเจลิส)", + "America\/Louisville": "เวลาทางตะวันออกในอเมริกาเหนือ (ลูส์วิลล์)", + "America\/Lower_Princes": "เวลาแอตแลนติก (โลเวอร์พรินซ์ ควอเตอร์)", + "America\/Maceio": "เวลาบราซิเลีย (มาเซโอ)", + "America\/Managua": "เวลาตอนกลางในอเมริกาเหนือ (มานากัว)", + "America\/Manaus": "เวลาแอมะซอน (มาเนาส์)", + "America\/Marigot": "เวลาแอตแลนติก (มาริโกต์)", + "America\/Martinique": "เวลาแอตแลนติก (มาร์ตินีก)", + "America\/Matamoros": "เวลาตอนกลางในอเมริกาเหนือ (มาตาโมรอส)", + "America\/Mazatlan": "เวลาแปซิฟิกเม็กซิโก (มาซาทลาน)", + "America\/Mendoza": "เวลาอาร์เจนตินา (เมนดูซา)", + "America\/Menominee": "เวลาตอนกลางในอเมริกาเหนือ (เมโนมินี)", + "America\/Merida": "เวลาตอนกลางในอเมริกาเหนือ (เมรีดา)", + "America\/Metlakatla": "เวลาอะแลสกา (เมทลากาตละ)", + "America\/Mexico_City": "เวลาตอนกลางในอเมริกาเหนือ (เม็กซิโกซิตี)", + "America\/Miquelon": "เวลาแซงปีแยร์และมีเกอลง (มีเกอลง)", + "America\/Moncton": "เวลาแอตแลนติก (มองตัน)", + "America\/Monterrey": "เวลาตอนกลางในอเมริกาเหนือ (มอนเตร์เรย์)", + "America\/Montevideo": "เวลาอุรุกวัย (มอนเตวิเดโอ)", + "America\/Montserrat": "เวลาแอตแลนติก (มอนเซอร์รัต)", + "America\/Nassau": "เวลาทางตะวันออกในอเมริกาเหนือ (แนสซอ)", + "America\/New_York": "เวลาทางตะวันออกในอเมริกาเหนือ (นิวยอร์ก)", + "America\/Nipigon": "เวลาทางตะวันออกในอเมริกาเหนือ (นิปิกอน)", + "America\/Nome": "เวลาอะแลสกา (นอม)", + "America\/Noronha": "เวลาหมู่เกาะเฟอร์นันโด (โนรอนฮา)", + "America\/North_Dakota\/Beulah": "เวลาตอนกลางในอเมริกาเหนือ (โบลาห์, นอร์ทดาโคตา)", + "America\/North_Dakota\/Center": "เวลาตอนกลางในอเมริกาเหนือ (เซนเตอร์, นอร์ทดาโคตา)", + "America\/North_Dakota\/New_Salem": "เวลาตอนกลางในอเมริกาเหนือ (นิวเซเลม, นอร์ทดาโคตา)", + "America\/Ojinaga": "เวลาแถบภูเขาในอเมริกาเหนือ (โอจินากา)", + "America\/Panama": "เวลาทางตะวันออกในอเมริกาเหนือ (ปานามา)", + "America\/Pangnirtung": "เวลาทางตะวันออกในอเมริกาเหนือ (พางนีทัง)", + "America\/Paramaribo": "เวลาซูรินาเม (ปารามาริโบ)", + "America\/Phoenix": "เวลาแถบภูเขาในอเมริกาเหนือ (ฟินิกซ์)", + "America\/Port-au-Prince": "เวลาทางตะวันออกในอเมริกาเหนือ (ปอร์โตแปรงซ์)", + "America\/Port_of_Spain": "เวลาแอตแลนติก (พอร์ทออฟสเปน)", + "America\/Porto_Velho": "เวลาแอมะซอน (ปอร์ตูเวลโย)", + "America\/Puerto_Rico": "เวลาแอตแลนติก (เปอโตริโก)", + "America\/Punta_Arenas": "เวลาชิลี (ปุนตาอาเรนัส)", + "America\/Rainy_River": "เวลาตอนกลางในอเมริกาเหนือ (เรนนี่ริเวอร์)", + "America\/Rankin_Inlet": "เวลาตอนกลางในอเมริกาเหนือ (แรงกินอินเล็ต)", + "America\/Recife": "เวลาบราซิเลีย (เรซีเฟ)", + "America\/Regina": "เวลาตอนกลางในอเมริกาเหนือ (ริไจนา)", + "America\/Resolute": "เวลาตอนกลางในอเมริกาเหนือ (เรโซลูท)", + "America\/Rio_Branco": "เวลาอาเกร (รีโอบรังโก)", + "America\/Santa_Isabel": "เวลาเม็กซิโกตะวันตกเฉียงเหนือ (ซานตาอิซาเบล)", + "America\/Santarem": "เวลาบราซิเลีย (ซันตาเรม)", + "America\/Santiago": "เวลาชิลี (ซันติอาโก)", + "America\/Santo_Domingo": "เวลาแอตแลนติก (ซานโต โดมิงโก)", + "America\/Sao_Paulo": "เวลาบราซิเลีย (เซาเปาลู)", + "America\/Scoresbysund": "เวลากรีนแลนด์ตะวันออก (สกอเรสไบซันด์)", + "America\/Sitka": "เวลาอะแลสกา (ซิตกา)", + "America\/St_Barthelemy": "เวลาแอตแลนติก (เซนต์บาร์เธเลมี)", + "America\/St_Johns": "เวลานิวฟันด์แลนด์ (เซนต์จอนส์)", + "America\/St_Kitts": "เวลาแอตแลนติก (เซนต์คิตส์)", + "America\/St_Lucia": "เวลาแอตแลนติก (เซนต์ลูเซีย)", + "America\/St_Thomas": "เวลาแอตแลนติก (เซนต์โธมัส)", + "America\/St_Vincent": "เวลาแอตแลนติก (เซนต์วินเซนต์)", + "America\/Swift_Current": "เวลาตอนกลางในอเมริกาเหนือ (สวิฟต์เคอร์เรนต์)", + "America\/Tegucigalpa": "เวลาตอนกลางในอเมริกาเหนือ (เตกูซิกัลปา)", + "America\/Thule": "เวลาแอตแลนติก (ทูเล)", + "America\/Thunder_Bay": "เวลาทางตะวันออกในอเมริกาเหนือ (ทันเดอร์เบย์)", + "America\/Tijuana": "เวลาแปซิฟิกในอเมริกาเหนือ (ทิฮัวนา)", + "America\/Toronto": "เวลาทางตะวันออกในอเมริกาเหนือ (โทรอนโต)", + "America\/Tortola": "เวลาแอตแลนติก (ตอร์โตลา)", + "America\/Vancouver": "เวลาแปซิฟิกในอเมริกาเหนือ (แวนคูเวอร์)", + "America\/Whitehorse": "เวลาแปซิฟิกในอเมริกาเหนือ (ไวต์ฮอร์ส)", + "America\/Winnipeg": "เวลาตอนกลางในอเมริกาเหนือ (วินนิเพก)", + "America\/Yakutat": "เวลาอะแลสกา (ยากูทัต)", + "America\/Yellowknife": "เวลาแถบภูเขาในอเมริกาเหนือ (เยลโลว์ไนฟ์)", + "Antarctica\/Casey": "เวลาออสเตรเลียตะวันตก (เคซีย์)", + "Antarctica\/Davis": "เวลาเดวิส (เดวิส)", + "Antarctica\/DumontDUrville": "เวลาดูมองต์ดูร์วิลล์ (ดูมองต์ดูร์วิลล์)", + "Antarctica\/Macquarie": "เวลาเกาะแมกควอรี (แมคควอรี)", + "Antarctica\/Mawson": "เวลามอว์สัน (มอว์สัน)", + "Antarctica\/McMurdo": "เวลานิวซีแลนด์ (แมคมัวโด)", + "Antarctica\/Palmer": "เวลาชิลี (พาล์เมอร์)", + "Antarctica\/Rothera": "เวลาโรธีรา (โรธีรา)", + "Antarctica\/Syowa": "เวลาไซโยวา (ไซโยวา)", + "Antarctica\/Troll": "เวลามาตรฐานกรีนิช (โทรล)", + "Antarctica\/Vostok": "เวลาวอสตอค (วอสตอค)", + "Arctic\/Longyearbyen": "เวลายุโรปกลาง (ลองเยียร์เบียน)", + "Asia\/Aden": "เวลาอาหรับ (เอเดน)", + "Asia\/Almaty": "เวลาคาซัคสถานตะวันออก (อัลมาตี)", + "Asia\/Amman": "เวลายุโรปตะวันออก (อัมมาน)", + "Asia\/Anadyr": "เวลาอะนาดีร์ (อานาดีร์)", + "Asia\/Aqtau": "เวลาคาซัคสถานตะวันตก (อัคตาอู)", + "Asia\/Aqtobe": "เวลาคาซัคสถานตะวันตก (อัคโทบี)", + "Asia\/Ashgabat": "เวลาเติร์กเมนิสถาน (อาชกาบัต)", + "Asia\/Atyrau": "เวลาคาซัคสถานตะวันตก (อทีราว)", + "Asia\/Baghdad": "เวลาอาหรับ (แบกแดด)", + "Asia\/Bahrain": "เวลาอาหรับ (บาห์เรน)", + "Asia\/Baku": "เวลาอาเซอร์ไบจาน (บากู)", + "Asia\/Bangkok": "เวลาอินโดจีน (กรุงเทพ)", + "Asia\/Beirut": "เวลายุโรปตะวันออก (เบรุต)", + "Asia\/Bishkek": "เวลาคีร์กีซสถาน (บิชเคก)", + "Asia\/Brunei": "เวลาบรูไนดารุสซาลาม (บรูไน)", + "Asia\/Calcutta": "เวลาอินเดีย (โกลกาตา)", + "Asia\/Chita": "เวลายาคุตสค์ (ชิตา)", + "Asia\/Choibalsan": "เวลาชอยปาลชาน (ชอยบาลซาน)", + "Asia\/Colombo": "เวลาอินเดีย (โคลัมโบ)", + "Asia\/Damascus": "เวลายุโรปตะวันออก (ดามัสกัส)", + "Asia\/Dhaka": "เวลาบังกลาเทศ (ดากา)", + "Asia\/Dili": "เวลาติมอร์ตะวันออก (ดิลี)", + "Asia\/Dubai": "เวลากัลฟ์ (ดูไบ)", + "Asia\/Dushanbe": "เวลาทาจิกิสถาน (ดูชานเบ)", + "Asia\/Famagusta": "เวลายุโรปตะวันออก (แฟมากุสตา)", + "Asia\/Gaza": "เวลายุโรปตะวันออก (กาซา)", + "Asia\/Hebron": "เวลายุโรปตะวันออก (เฮบรอน)", + "Asia\/Hong_Kong": "เวลาฮ่องกง (ฮ่องกง)", + "Asia\/Hovd": "เวลาฮอฟด์ (ฮอฟด์)", + "Asia\/Irkutsk": "เวลาอีร์คุตสค์ (อีร์คุตสค์)", + "Asia\/Jakarta": "เวลาอินโดนีเซียฝั่งตะวันตก (จาการ์ตา)", + "Asia\/Jayapura": "เวลาอินโดนีเซียฝั่งตะวันออก (จายาปุระ)", + "Asia\/Jerusalem": "เวลาอิสราเอล (เยรูซาเลม)", + "Asia\/Kabul": "เวลาอัฟกานิสถาน (คาบูล)", + "Asia\/Kamchatka": "เวลาคัมชัตคา (คามชัตกา)", + "Asia\/Karachi": "เวลาปากีสถาน (การาจี)", + "Asia\/Katmandu": "เวลาเนปาล (กาตมันดุ)", + "Asia\/Khandyga": "เวลายาคุตสค์ (ฮันดืยกา)", + "Asia\/Krasnoyarsk": "เวลาครัสโนยาสค์ (ครัสโนยาร์สก์)", + "Asia\/Kuala_Lumpur": "เวลามาเลเซีย (กัวลาลัมเปอร์)", + "Asia\/Kuching": "เวลามาเลเซีย (กูชิง)", + "Asia\/Kuwait": "เวลาอาหรับ (คูเวต)", + "Asia\/Macau": "เวลาจีน (มาเก๊า)", + "Asia\/Magadan": "เวลามากาดาน (มากาดาน)", + "Asia\/Makassar": "เวลาอินโดนีเซียตอนกลาง (มากัสซาร์)", + "Asia\/Manila": "เวลาฟิลิปปินส์ (มะนิลา)", + "Asia\/Muscat": "เวลากัลฟ์ (มัสกัต)", + "Asia\/Nicosia": "เวลายุโรปตะวันออก (นิโคเซีย)", + "Asia\/Novokuznetsk": "เวลาครัสโนยาสค์ (โนโวคุซเนตสค์)", + "Asia\/Novosibirsk": "เวลาโนโวซีบีสค์ (โนโวซิบิร์สก์)", + "Asia\/Omsk": "เวลาออมสค์ (โอมสก์)", + "Asia\/Oral": "เวลาคาซัคสถานตะวันตก (ออรัล)", + "Asia\/Phnom_Penh": "เวลาอินโดจีน (พนมเปญ)", + "Asia\/Pontianak": "เวลาอินโดนีเซียฝั่งตะวันตก (พอนเทียนัก)", + "Asia\/Pyongyang": "เวลาเกาหลี (เปียงยาง)", + "Asia\/Qatar": "เวลาอาหรับ (กาตาร์)", + "Asia\/Qostanay": "เวลาคาซัคสถานตะวันออก (คอสตาเนย์)", + "Asia\/Qyzylorda": "เวลาคาซัคสถานตะวันตก (ไคซีลอร์ดา)", + "Asia\/Rangoon": "เวลาพม่า (ย่างกุ้ง)", + "Asia\/Riyadh": "เวลาอาหรับ (ริยาร์ด)", + "Asia\/Saigon": "เวลาอินโดจีน (นครโฮจิมินห์)", + "Asia\/Sakhalin": "เวลาซาคาลิน (ซาคาลิน)", + "Asia\/Samarkand": "เวลาอุซเบกิสถาน (ซามาร์กานด์)", + "Asia\/Seoul": "เวลาเกาหลี (โซล)", + "Asia\/Shanghai": "เวลาจีน (เซี่ยงไฮ้)", + "Asia\/Singapore": "เวลาสิงคโปร์ (สิงคโปร์)", + "Asia\/Srednekolymsk": "เวลามากาดาน (ซเรดเนคโคลิมสก์)", + "Asia\/Taipei": "เวลาไทเป (ไทเป)", + "Asia\/Tashkent": "เวลาอุซเบกิสถาน (ทาชเคนต์)", + "Asia\/Tbilisi": "เวลาจอร์เจีย (ทบิลิซิ)", + "Asia\/Tehran": "เวลาอิหร่าน (เตหะราน)", + "Asia\/Thimphu": "เวลาภูฏาน (ทิมพู)", + "Asia\/Tokyo": "เวลาญี่ปุ่น (โตเกียว)", + "Asia\/Ulaanbaatar": "เวลาอูลานบาตอร์ (อูลานบาตอร์)", + "Asia\/Ust-Nera": "เวลาวลาดีวอสตอค (อุสต์เนรา)", + "Asia\/Vientiane": "เวลาอินโดจีน (เวียงจันทน์)", + "Asia\/Vladivostok": "เวลาวลาดีวอสตอค (วลาดิโวสต็อก)", + "Asia\/Yakutsk": "เวลายาคุตสค์ (ยาคุตสค์)", + "Asia\/Yekaterinburg": "เวลาเยคาเตรินบูร์ก (ยีคาเตอรินเบิร์ก)", + "Asia\/Yerevan": "เวลาอาร์เมเนีย (เยเรวาน)", + "Atlantic\/Azores": "เวลาอะโซร์ส (อาซอเรส)", + "Atlantic\/Bermuda": "เวลาแอตแลนติก (เบอร์มิวดา)", + "Atlantic\/Canary": "เวลายุโรปตะวันตก (คะเนรี)", + "Atlantic\/Cape_Verde": "เวลาเคปเวิร์ด (เคปเวิร์ด)", + "Atlantic\/Faeroe": "เวลายุโรปตะวันตก (แฟโร)", + "Atlantic\/Madeira": "เวลายุโรปตะวันตก (มาเดรา)", + "Atlantic\/Reykjavik": "เวลามาตรฐานกรีนิช (เรคยาวิก)", + "Atlantic\/South_Georgia": "เวลาเซาท์จอร์เจีย (เซาท์ จอร์เจีย)", + "Atlantic\/St_Helena": "เวลามาตรฐานกรีนิช (เซนต์เฮเลนา)", + "Atlantic\/Stanley": "เวลาหมู่เกาะฟอล์กแลนด์ (สแตนลีย์)", + "Australia\/Adelaide": "เวลาออสเตรเลียกลาง (แอดิเลด)", + "Australia\/Brisbane": "เวลาออสเตรเลียตะวันออก (บริสเบน)", + "Australia\/Broken_Hill": "เวลาออสเตรเลียกลาง (โบรกเคนฮิลล์)", + "Australia\/Currie": "เวลาออสเตรเลียตะวันออก (คูร์รี)", + "Australia\/Darwin": "เวลาออสเตรเลียกลาง (ดาร์วิน)", + "Australia\/Eucla": "เวลาทางตะวันตกตอนกลางของออสเตรเลีย (ยูคลา)", + "Australia\/Hobart": "เวลาออสเตรเลียตะวันออก (โฮบาร์ต)", + "Australia\/Lindeman": "เวลาออสเตรเลียตะวันออก (ลินดีแมน)", + "Australia\/Lord_Howe": "เวลาลอร์ดโฮว์ (ลอร์ดโฮว์)", + "Australia\/Melbourne": "เวลาออสเตรเลียตะวันออก (เมลเบิร์น)", + "Australia\/Perth": "เวลาออสเตรเลียตะวันตก (เพิร์ท)", + "Australia\/Sydney": "เวลาออสเตรเลียตะวันออก (ซิดนีย์)", + "CST6CDT": "เวลาตอนกลางในอเมริกาเหนือ", + "EST5EDT": "เวลาทางตะวันออกในอเมริกาเหนือ", + "Etc\/GMT": "เวลามาตรฐานกรีนิช", + "Etc\/UTC": "เวลาสากลเชิงพิกัด", + "Europe\/Amsterdam": "เวลายุโรปกลาง (อัมสเตอดัม)", + "Europe\/Andorra": "เวลายุโรปกลาง (อันดอร์รา)", + "Europe\/Astrakhan": "เวลามอสโก (แอสตราคาน)", + "Europe\/Athens": "เวลายุโรปตะวันออก (เอเธนส์)", + "Europe\/Belgrade": "เวลายุโรปกลาง (เบลเกรด)", + "Europe\/Berlin": "เวลายุโรปกลาง (เบอร์ลิน)", + "Europe\/Bratislava": "เวลายุโรปกลาง (บราติสลาวา)", + "Europe\/Brussels": "เวลายุโรปกลาง (บรัสเซลส์)", + "Europe\/Bucharest": "เวลายุโรปตะวันออก (บูคาเรส)", + "Europe\/Budapest": "เวลายุโรปกลาง (บูดาเปส)", + "Europe\/Busingen": "เวลายุโรปกลาง (บุสซิงเง็น)", + "Europe\/Chisinau": "เวลายุโรปตะวันออก (คีชีเนา)", + "Europe\/Copenhagen": "เวลายุโรปกลาง (โคเปนเฮเกน)", + "Europe\/Dublin": "เวลามาตรฐานกรีนิช (ดับบลิน)", + "Europe\/Gibraltar": "เวลายุโรปกลาง (ยิบรอลตาร์)", + "Europe\/Guernsey": "เวลามาตรฐานกรีนิช (เกิร์นซีย์)", + "Europe\/Helsinki": "เวลายุโรปตะวันออก (เฮลซิงกิ)", + "Europe\/Isle_of_Man": "เวลามาตรฐานกรีนิช (เกาะแมน)", + "Europe\/Jersey": "เวลามาตรฐานกรีนิช (เจอร์ซีย์)", + "Europe\/Kaliningrad": "เวลายุโรปตะวันออก (คาลินิงกราด)", + "Europe\/Kiev": "เวลายุโรปตะวันออก (เคียฟ)", + "Europe\/Lisbon": "เวลายุโรปตะวันตก (ลิสบอน)", + "Europe\/Ljubljana": "เวลายุโรปกลาง (ลูบลิยานา)", + "Europe\/London": "เวลามาตรฐานกรีนิช (ลอนดอน)", + "Europe\/Luxembourg": "เวลายุโรปกลาง (ลักเซมเบิร์ก)", + "Europe\/Madrid": "เวลายุโรปกลาง (มาดริด)", + "Europe\/Malta": "เวลายุโรปกลาง (มอลตา)", + "Europe\/Mariehamn": "เวลายุโรปตะวันออก (มารีฮามน์)", + "Europe\/Minsk": "เวลามอสโก (มินสก์)", + "Europe\/Monaco": "เวลายุโรปกลาง (โมนาโก)", + "Europe\/Moscow": "เวลามอสโก (มอสโก)", + "Europe\/Oslo": "เวลายุโรปกลาง (ออสโล)", + "Europe\/Paris": "เวลายุโรปกลาง (ปารีส)", + "Europe\/Podgorica": "เวลายุโรปกลาง (พอดกอรีตซา)", + "Europe\/Prague": "เวลายุโรปกลาง (ปราก)", + "Europe\/Riga": "เวลายุโรปตะวันออก (ริกา)", + "Europe\/Rome": "เวลายุโรปกลาง (โรม)", + "Europe\/Samara": "เวลาซามารา (ซามารา)", + "Europe\/San_Marino": "เวลายุโรปกลาง (ซานมารีโน)", + "Europe\/Sarajevo": "เวลายุโรปกลาง (ซาราเยโว)", + "Europe\/Saratov": "เวลามอสโก (ซาราทอฟ)", + "Europe\/Simferopol": "เวลามอสโก (ซิมเฟอโรโปล)", + "Europe\/Skopje": "เวลายุโรปกลาง (สโกเปีย)", + "Europe\/Sofia": "เวลายุโรปตะวันออก (โซเฟีย)", + "Europe\/Stockholm": "เวลายุโรปกลาง (สตอกโฮล์ม)", + "Europe\/Tallinn": "เวลายุโรปตะวันออก (ทาลลินน์)", + "Europe\/Tirane": "เวลายุโรปกลาง (ติรานา)", + "Europe\/Ulyanovsk": "เวลามอสโก (อะลิยานอฟ)", + "Europe\/Uzhgorod": "เวลายุโรปตะวันออก (อัซโกร็อด)", + "Europe\/Vaduz": "เวลายุโรปกลาง (วาดุซ)", + "Europe\/Vatican": "เวลายุโรปกลาง (วาติกัน)", + "Europe\/Vienna": "เวลายุโรปกลาง (เวียนนา)", + "Europe\/Vilnius": "เวลายุโรปตะวันออก (วิลนีอุส)", + "Europe\/Volgograd": "เวลาวอลโกกราด (วอลโกกราด)", + "Europe\/Warsaw": "เวลายุโรปกลาง (วอร์ซอ)", + "Europe\/Zagreb": "เวลายุโรปกลาง (ซาเกร็บ)", + "Europe\/Zaporozhye": "เวลายุโรปตะวันออก (ซาโปโรซี)", + "Europe\/Zurich": "เวลายุโรปกลาง (ซูริค)", + "Indian\/Antananarivo": "เวลาแอฟริกาตะวันออก (อันตานานาริโว)", + "Indian\/Chagos": "เวลามหาสมุทรอินเดีย (ชากัส)", + "Indian\/Christmas": "เวลาเกาะคริสต์มาส (คริสต์มาส)", + "Indian\/Cocos": "เวลาหมู่เกาะโคโคส (โคโคส)", + "Indian\/Comoro": "เวลาแอฟริกาตะวันออก (โคโมโร)", + "Indian\/Kerguelen": "เวลาเฟรนช์เซาเทิร์นและแอนตาร์กติก (แกร์เกอลอง)", + "Indian\/Mahe": "เวลาเซเชลส์ (มาเอ)", + "Indian\/Maldives": "เวลามัลดีฟส์ (มัลดีฟส์)", + "Indian\/Mauritius": "เวลามอริเชียส (มอริเชียส)", + "Indian\/Mayotte": "เวลาแอฟริกาตะวันออก (มาโยเต)", + "Indian\/Reunion": "เวลาเรอูนียง (เรอูนียง)", + "MST7MDT": "เวลาแถบภูเขาในอเมริกาเหนือ", + "PST8PDT": "เวลาแปซิฟิกในอเมริกาเหนือ", + "Pacific\/Apia": "เวลาอาปีอา (อาปีอา)", + "Pacific\/Auckland": "เวลานิวซีแลนด์ (โอคแลนด์)", + "Pacific\/Bougainville": "เวลาปาปัวนิวกินี (บูเกนวิลล์)", + "Pacific\/Chatham": "เวลาแชทัม (แชทัม)", + "Pacific\/Easter": "เวลาเกาะอีสเตอร์ (อีสเตอร์)", + "Pacific\/Efate": "เวลาวานูอาตู (เอฟาเต)", + "Pacific\/Enderbury": "เวลาหมู่เกาะฟินิกซ์ (เอนเดอร์เบอรี)", + "Pacific\/Fakaofo": "เวลาโตเกเลา (ฟาเคาโฟ)", + "Pacific\/Fiji": "เวลาฟิจิ (ฟิจิ)", + "Pacific\/Funafuti": "เวลาตูวาลู (ฟูนะฟูตี)", + "Pacific\/Galapagos": "เวลากาลาปาโกส (กาลาปาโกส)", + "Pacific\/Gambier": "เวลาแกมเบียร์ (แกมเบียร์)", + "Pacific\/Guadalcanal": "เวลาหมู่เกาะโซโลมอน (กัวดัลคานัล)", + "Pacific\/Guam": "เวลาชามอร์โร (กวม)", + "Pacific\/Honolulu": "เวลาฮาวาย-อะลูเชียน (โฮโนลูลู)", + "Pacific\/Johnston": "เวลาฮาวาย-อะลูเชียน (จอห์นสตัน)", + "Pacific\/Kiritimati": "เวลาหมู่เกาะไลน์ (คิริทิมาตี)", + "Pacific\/Kosrae": "เวลาคอสไร (คอสไร)", + "Pacific\/Kwajalein": "เวลาหมู่เกาะมาร์แชลล์ (ควาจาเลน)", + "Pacific\/Majuro": "เวลาหมู่เกาะมาร์แชลล์ (มาจูโร)", + "Pacific\/Marquesas": "เวลามาร์เคซัส (มาร์เคซัส)", + "Pacific\/Midway": "เวลาซามัว (มิดเวย์)", + "Pacific\/Nauru": "เวลานาอูรู (นาอูรู)", + "Pacific\/Niue": "เวลานีอูเอ (นีอูเอ)", + "Pacific\/Norfolk": "เวลาเกาะนอร์ฟอล์ก (นอร์ฟอล์ก)", + "Pacific\/Noumea": "เวลานิวแคลิโดเนีย (นูเมอา)", + "Pacific\/Pago_Pago": "เวลาซามัว (ปาโก ปาโก)", + "Pacific\/Palau": "เวลาปาเลา (ปาเลา)", + "Pacific\/Pitcairn": "เวลาพิตแคร์น (พิตแคร์น)", + "Pacific\/Ponape": "เวลาโปนาเป (โปนาเป)", + "Pacific\/Port_Moresby": "เวลาปาปัวนิวกินี (พอร์ตมอร์สบี)", + "Pacific\/Rarotonga": "เวลาหมู่เกาะคุก (ราโรตองกา)", + "Pacific\/Saipan": "เวลาชามอร์โร (ไซปัน)", + "Pacific\/Tahiti": "เวลาตาฮีตี (ตาฮีตี)", + "Pacific\/Tarawa": "เวลาหมู่เกาะกิลเบิร์ต (ตาระวา)", + "Pacific\/Tongatapu": "เวลาตองกา (ตองกาตาปู)", + "Pacific\/Truk": "เวลาชุก (ทรัก)", + "Pacific\/Wake": "เวลาเกาะเวก (เวก)", + "Pacific\/Wallis": "เวลาวาลลิสและฟุตูนา (วาลลิส)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ti.json b/src/Symfony/Component/Intl/Resources/data/timezones/ti.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ti.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/tk.json b/src/Symfony/Component/Intl/Resources/data/timezones/tk.json new file mode 100644 index 0000000000000..a2214ade959d8 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/tk.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.86", + "Names": { + "Africa\/Abidjan": "Grinwiç boýunça orta wagt (Abijan)", + "Africa\/Accra": "Grinwiç boýunça orta wagt (Akkra)", + "Africa\/Addis_Ababa": "Gündogar Afrika wagty (Addis-Abeba)", + "Africa\/Algiers": "Merkezi Ýewropa wagty (Alžir)", + "Africa\/Asmera": "Gündogar Afrika wagty (Asmera)", + "Africa\/Bamako": "Grinwiç boýunça orta wagt (Bamako)", + "Africa\/Bangui": "Günbatar Afrika wagty (Bangi)", + "Africa\/Banjul": "Grinwiç boýunça orta wagt (Banjul)", + "Africa\/Bissau": "Grinwiç boýunça orta wagt (Bisau)", + "Africa\/Blantyre": "Merkezi Afrika wagty (Blantaýr)", + "Africa\/Brazzaville": "Günbatar Afrika wagty (Brazzawil)", + "Africa\/Bujumbura": "Merkezi Afrika wagty (Bujumbura)", + "Africa\/Cairo": "Gündogar Ýewropa wagty (Kair)", + "Africa\/Casablanca": "Günbatar Ýewropa wagty (Kasablanka)", + "Africa\/Ceuta": "Merkezi Ýewropa wagty (Seuta)", + "Africa\/Conakry": "Grinwiç boýunça orta wagt (Konakri)", + "Africa\/Dakar": "Grinwiç boýunça orta wagt (Dakar)", + "Africa\/Dar_es_Salaam": "Gündogar Afrika wagty (Dar-es-Salam)", + "Africa\/Djibouti": "Gündogar Afrika wagty (Jibuti)", + "Africa\/Douala": "Günbatar Afrika wagty (Duala)", + "Africa\/El_Aaiun": "Günbatar Ýewropa wagty (El-Aýun)", + "Africa\/Freetown": "Grinwiç boýunça orta wagt (Fritaun)", + "Africa\/Gaborone": "Merkezi Afrika wagty (Gaborone)", + "Africa\/Harare": "Merkezi Afrika wagty (Harare)", + "Africa\/Johannesburg": "Günorta Afrika standart wagty (Ýohannesburg)", + "Africa\/Juba": "Gündogar Afrika wagty (Juba)", + "Africa\/Kampala": "Gündogar Afrika wagty (Kampala)", + "Africa\/Khartoum": "Merkezi Afrika wagty (Hartum)", + "Africa\/Kigali": "Merkezi Afrika wagty (Kigali)", + "Africa\/Kinshasa": "Günbatar Afrika wagty (Kinşasa)", + "Africa\/Lagos": "Günbatar Afrika wagty (Lagos)", + "Africa\/Libreville": "Günbatar Afrika wagty (Librewil)", + "Africa\/Lome": "Grinwiç boýunça orta wagt (Lome)", + "Africa\/Luanda": "Günbatar Afrika wagty (Luanda)", + "Africa\/Lubumbashi": "Merkezi Afrika wagty (Lubumbaşi)", + "Africa\/Lusaka": "Merkezi Afrika wagty (Lusaka)", + "Africa\/Malabo": "Günbatar Afrika wagty (Malabo)", + "Africa\/Maputo": "Merkezi Afrika wagty (Maputo)", + "Africa\/Maseru": "Günorta Afrika standart wagty (Maseru)", + "Africa\/Mbabane": "Günorta Afrika standart wagty (Mbabane)", + "Africa\/Mogadishu": "Gündogar Afrika wagty (Mogadişo)", + "Africa\/Monrovia": "Grinwiç boýunça orta wagt (Monrowiýa)", + "Africa\/Nairobi": "Gündogar Afrika wagty (Naýrobi)", + "Africa\/Ndjamena": "Günbatar Afrika wagty (Jamena)", + "Africa\/Niamey": "Günbatar Afrika wagty (Niameý)", + "Africa\/Nouakchott": "Grinwiç boýunça orta wagt (Nuakşot)", + "Africa\/Ouagadougou": "Grinwiç boýunça orta wagt (Uagadugu)", + "Africa\/Porto-Novo": "Günbatar Afrika wagty (Porto-Nowo)", + "Africa\/Sao_Tome": "Grinwiç boýunça orta wagt (San-Tome)", + "Africa\/Tripoli": "Gündogar Ýewropa wagty (Tripoli)", + "Africa\/Tunis": "Merkezi Ýewropa wagty (Tunis)", + "Africa\/Windhoek": "Merkezi Afrika wagty (Windhuk)", + "America\/Adak": "Gawaý-Aleut wagty (Adak adasy)", + "America\/Anchorage": "Alýaska wagty (Ankoridž)", + "America\/Anguilla": "Atlantik wagty (Angilýa)", + "America\/Antigua": "Atlantik wagty (Antigua)", + "America\/Araguaina": "Braziliýa wagty (Araguaýna)", + "America\/Argentina\/La_Rioja": "Argentina wagty (La-Rioha)", + "America\/Argentina\/Rio_Gallegos": "Argentina wagty (Rio-Galegos)", + "America\/Argentina\/Salta": "Argentina wagty (Salta)", + "America\/Argentina\/San_Juan": "Argentina wagty (San-Huan)", + "America\/Argentina\/San_Luis": "Günbatar Argentina wagty (San-Luis)", + "America\/Argentina\/Tucuman": "Argentina wagty (Tukuman)", + "America\/Argentina\/Ushuaia": "Argentina wagty (Uşuaýa)", + "America\/Aruba": "Atlantik wagty (Aruba)", + "America\/Asuncion": "Paragwaý wagty (Asunsýon)", + "America\/Bahia": "Braziliýa wagty (Baiýa)", + "America\/Bahia_Banderas": "Merkezi Amerika (Baiýa-de-Banderas)", + "America\/Barbados": "Atlantik wagty (Barbados)", + "America\/Belem": "Braziliýa wagty (Belen)", + "America\/Belize": "Merkezi Amerika (Beliz)", + "America\/Blanc-Sablon": "Atlantik wagty (Blank-Sablon)", + "America\/Boa_Vista": "Amazon wagty (Boa-Wista)", + "America\/Bogota": "Kolumbiýa wagty (Bogota)", + "America\/Boise": "Demirgazyk Amerika dag wagty (Boýse)", + "America\/Buenos_Aires": "Argentina wagty (Buenos-Aýres)", + "America\/Cambridge_Bay": "Demirgazyk Amerika dag wagty (Kembrij-Beý)", + "America\/Campo_Grande": "Amazon wagty (Kampu-Grandi)", + "America\/Cancun": "Demirgazyk Amerika gündogar wagty (Kankun)", + "America\/Caracas": "Wenesuela wagty (Karakas)", + "America\/Catamarca": "Argentina wagty (Katamarka)", + "America\/Cayenne": "Fransuz Gwianasy wagty (Kaýenna)", + "America\/Cayman": "Demirgazyk Amerika gündogar wagty (Kaýman adalary)", + "America\/Chicago": "Merkezi Amerika (Çikago)", + "America\/Chihuahua": "Meksikan Ýuwaş umman wagty (Çihuahua)", + "America\/Coral_Harbour": "Demirgazyk Amerika gündogar wagty (Atikokan)", + "America\/Cordoba": "Argentina wagty (Kordowa)", + "America\/Costa_Rica": "Merkezi Amerika (Kosta-Rika)", + "America\/Creston": "Demirgazyk Amerika dag wagty (Kreston)", + "America\/Cuiaba": "Amazon wagty (Kuýaba)", + "America\/Curacao": "Atlantik wagty (Kýurasao)", + "America\/Danmarkshavn": "Grinwiç boýunça orta wagt (Denmarkshawn)", + "America\/Dawson": "Demirgazyk Amerika Ýuwaş umman wagty (Douson)", + "America\/Dawson_Creek": "Demirgazyk Amerika dag wagty (Douson-Krik)", + "America\/Denver": "Demirgazyk Amerika dag wagty (Denwer)", + "America\/Detroit": "Demirgazyk Amerika gündogar wagty (Detroýt)", + "America\/Dominica": "Atlantik wagty (Dominika)", + "America\/Edmonton": "Demirgazyk Amerika dag wagty (Edmonton)", + "America\/El_Salvador": "Merkezi Amerika (Salwador)", + "America\/Fort_Nelson": "Demirgazyk Amerika dag wagty (Fort Nelson)", + "America\/Fortaleza": "Braziliýa wagty (Fortaleza)", + "America\/Glace_Bay": "Atlantik wagty (Gleýs-Beý)", + "America\/Godthab": "Günbatar Grenlandiýa wagty (Nuk)", + "America\/Goose_Bay": "Atlantik wagty (Gus-Beý)", + "America\/Grand_Turk": "Demirgazyk Amerika gündogar wagty (Grand-Terk)", + "America\/Grenada": "Atlantik wagty (Grenada)", + "America\/Guadeloupe": "Atlantik wagty (Gwadelupa)", + "America\/Guatemala": "Merkezi Amerika (Gwatemala)", + "America\/Guayaquil": "Ekwador wagty (Guýakil)", + "America\/Guyana": "Gaýana wagty (Gaýana)", + "America\/Halifax": "Atlantik wagty (Galifaks)", + "America\/Havana": "Kuba wagty (Gawana)", + "America\/Hermosillo": "Meksikan Ýuwaş umman wagty (Ermosilo)", + "America\/Indiana\/Knox": "Merkezi Amerika (Noks, Indiana)", + "America\/Indiana\/Marengo": "Demirgazyk Amerika gündogar wagty (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Demirgazyk Amerika gündogar wagty (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Merkezi Amerika (Tell-Siti, Indiana)", + "America\/Indiana\/Vevay": "Demirgazyk Amerika gündogar wagty (Wiweý, Indiana)", + "America\/Indiana\/Vincennes": "Demirgazyk Amerika gündogar wagty (Winsens, Indiana)", + "America\/Indiana\/Winamac": "Demirgazyk Amerika gündogar wagty (Winamak, Indiana)", + "America\/Indianapolis": "Demirgazyk Amerika gündogar wagty (Indianapolis)", + "America\/Inuvik": "Demirgazyk Amerika dag wagty (Inuwik)", + "America\/Iqaluit": "Demirgazyk Amerika gündogar wagty (Ikaluit)", + "America\/Jamaica": "Demirgazyk Amerika gündogar wagty (Ýamaýka)", + "America\/Jujuy": "Argentina wagty (Žužuý)", + "America\/Juneau": "Alýaska wagty (Džuno)", + "America\/Kentucky\/Monticello": "Demirgazyk Amerika gündogar wagty (Montisello, Kentuki)", + "America\/Kralendijk": "Atlantik wagty (Kralendeýk)", + "America\/La_Paz": "Boliwiýa wagty (La-Pas)", + "America\/Lima": "Peru wagty (Lima)", + "America\/Los_Angeles": "Demirgazyk Amerika Ýuwaş umman wagty (Los-Anjeles)", + "America\/Louisville": "Demirgazyk Amerika gündogar wagty (Luiswill)", + "America\/Lower_Princes": "Atlantik wagty (Lower-Prinses-Kuorter)", + "America\/Maceio": "Braziliýa wagty (Maseýo)", + "America\/Managua": "Merkezi Amerika (Managua)", + "America\/Manaus": "Amazon wagty (Manaus)", + "America\/Marigot": "Atlantik wagty (Marigo)", + "America\/Martinique": "Atlantik wagty (Martinika)", + "America\/Matamoros": "Merkezi Amerika (Matamoros)", + "America\/Mazatlan": "Meksikan Ýuwaş umman wagty (Mazatlan)", + "America\/Mendoza": "Argentina wagty (Mendosa)", + "America\/Menominee": "Merkezi Amerika (Menomini)", + "America\/Merida": "Merkezi Amerika (Merida)", + "America\/Metlakatla": "Alýaska wagty (Metlakatla)", + "America\/Mexico_City": "Merkezi Amerika (Mehiko)", + "America\/Miquelon": "Sen-Pýer we Mikelon (Mikelon)", + "America\/Moncton": "Atlantik wagty (Monkton)", + "America\/Monterrey": "Merkezi Amerika (Monterreý)", + "America\/Montevideo": "Urugwaý wagty (Montewideo)", + "America\/Montserrat": "Atlantik wagty (Monserrat)", + "America\/Nassau": "Demirgazyk Amerika gündogar wagty (Nassau)", + "America\/New_York": "Demirgazyk Amerika gündogar wagty (Nýu-Ýork)", + "America\/Nipigon": "Demirgazyk Amerika gündogar wagty (Nipigon)", + "America\/Nome": "Alýaska wagty (Nom)", + "America\/Noronha": "Fernandu-di-Noronýa wagty (Noronha)", + "America\/North_Dakota\/Beulah": "Merkezi Amerika (Boýla, Demirgazyk Dakota)", + "America\/North_Dakota\/Center": "Merkezi Amerika (Sentr, Demirgazyk Dakota)", + "America\/North_Dakota\/New_Salem": "Merkezi Amerika (Nýu-Salem, D.g. Dakota)", + "America\/Ojinaga": "Demirgazyk Amerika dag wagty (Ohinaga)", + "America\/Panama": "Demirgazyk Amerika gündogar wagty (Panama)", + "America\/Pangnirtung": "Demirgazyk Amerika gündogar wagty (Pangnirtang)", + "America\/Paramaribo": "Surinam wagty (Paramaribo)", + "America\/Phoenix": "Demirgazyk Amerika dag wagty (Feniks)", + "America\/Port-au-Prince": "Demirgazyk Amerika gündogar wagty (Port-o-Prens)", + "America\/Port_of_Spain": "Atlantik wagty (Port-of-Speýn)", + "America\/Porto_Velho": "Amazon wagty (Portu-Welýu)", + "America\/Puerto_Rico": "Atlantik wagty (Puerto-Riko)", + "America\/Punta_Arenas": "Çili wagty (Punta-Arenas)", + "America\/Rainy_River": "Merkezi Amerika (Reýni-Riwer)", + "America\/Rankin_Inlet": "Merkezi Amerika (Rankin-Inlet)", + "America\/Recife": "Braziliýa wagty (Resifi)", + "America\/Regina": "Merkezi Amerika (Rejaýna)", + "America\/Resolute": "Merkezi Amerika (Rozulýut)", + "America\/Santa_Isabel": "Demirgazyk-günbatar Meksika wagty (Santa-Izabel)", + "America\/Santarem": "Braziliýa wagty (Santarem)", + "America\/Santiago": "Çili wagty (Santýago)", + "America\/Santo_Domingo": "Atlantik wagty (Santo-Domingo)", + "America\/Sao_Paulo": "Braziliýa wagty (San-Paulu)", + "America\/Scoresbysund": "Gündogar Grenlandiýa wagty (Illokkortoormiut)", + "America\/Sitka": "Alýaska wagty (Sitka)", + "America\/St_Barthelemy": "Atlantik wagty (Sen-Bartelemi)", + "America\/St_Johns": "Nýufaundlend wagty (Sent-Džons)", + "America\/St_Kitts": "Atlantik wagty (Sent-Kits)", + "America\/St_Lucia": "Atlantik wagty (Sent-Lýusiýa)", + "America\/St_Thomas": "Atlantik wagty (Sent-Tomas)", + "America\/St_Vincent": "Atlantik wagty (Sent-Winsent)", + "America\/Swift_Current": "Merkezi Amerika (Swift-Karent)", + "America\/Tegucigalpa": "Merkezi Amerika (Tegusigalpa)", + "America\/Thule": "Atlantik wagty (Tule)", + "America\/Thunder_Bay": "Demirgazyk Amerika gündogar wagty (Tander-Beý)", + "America\/Tijuana": "Demirgazyk Amerika Ýuwaş umman wagty (Tihuana)", + "America\/Toronto": "Demirgazyk Amerika gündogar wagty (Toronto)", + "America\/Tortola": "Atlantik wagty (Tortola)", + "America\/Vancouver": "Demirgazyk Amerika Ýuwaş umman wagty (Wankuwer)", + "America\/Whitehorse": "Demirgazyk Amerika Ýuwaş umman wagty (Waýthors)", + "America\/Winnipeg": "Merkezi Amerika (Winipeg)", + "America\/Yakutat": "Alýaska wagty (Ýakutat)", + "America\/Yellowknife": "Demirgazyk Amerika dag wagty (Ýellounaýf)", + "Antarctica\/Casey": "Günbatar Awstraliýa wagty (Keýsi)", + "Antarctica\/Davis": "Deýwis wagty (Deýwis)", + "Antarctica\/DumontDUrville": "Dýumon-d-Ýurwil wagty (Dýumon-d-Ýurwil)", + "Antarctica\/Macquarie": "Makkuori adasy wagty (Makkuori)", + "Antarctica\/Mawson": "Mouson wagty (Mouson)", + "Antarctica\/McMurdo": "Täze Zelandiýa wagty (Mak-Merdo)", + "Antarctica\/Palmer": "Çili wagty (Palmer)", + "Antarctica\/Rothera": "Rotera wagty (Rotera)", + "Antarctica\/Syowa": "Sýowa wagty (Sýowa)", + "Antarctica\/Troll": "Grinwiç boýunça orta wagt (Trol)", + "Antarctica\/Vostok": "Wostok wagty (Wostok)", + "Arctic\/Longyearbyen": "Merkezi Ýewropa wagty (Longir)", + "Asia\/Aden": "Arap ýurtlary wagty (Aden)", + "Asia\/Almaty": "Gündogar Gazagystan wagty (Almaty)", + "Asia\/Amman": "Gündogar Ýewropa wagty (Amman)", + "Asia\/Aqtau": "Günbatar Gazagystan wagty (Aktau)", + "Asia\/Aqtobe": "Günbatar Gazagystan wagty (Aktobe)", + "Asia\/Ashgabat": "Türkmenistan wagty (Aşgabat)", + "Asia\/Atyrau": "Günbatar Gazagystan wagty (Atyrau)", + "Asia\/Baghdad": "Arap ýurtlary wagty (Bagdat)", + "Asia\/Bahrain": "Arap ýurtlary wagty (Bahreýn)", + "Asia\/Baku": "Azerbaýjan wagty (Baku)", + "Asia\/Bangkok": "Hindihytaý wagty (Bangkok)", + "Asia\/Beirut": "Gündogar Ýewropa wagty (Beýrut)", + "Asia\/Bishkek": "Gyrgyzystan wagty (Bişkek)", + "Asia\/Brunei": "Bruneý-Darussalam wagty (Bruneý)", + "Asia\/Calcutta": "Hindistan standart wagty (Kalkutta)", + "Asia\/Chita": "Ýakutsk wagty (Çita)", + "Asia\/Choibalsan": "Çoýbalsan wagty (Çoýbalsan)", + "Asia\/Colombo": "Hindistan standart wagty (Kolombo)", + "Asia\/Damascus": "Gündogar Ýewropa wagty (Damask)", + "Asia\/Dhaka": "Bangladeş wagty (Dakka)", + "Asia\/Dili": "Gündogar Timor wagty (Dili)", + "Asia\/Dubai": "Pars aýlagy standart wagty (Dubaý)", + "Asia\/Dushanbe": "Täjigistan wagty (Duşanbe)", + "Asia\/Famagusta": "Gündogar Ýewropa wagty (Famagusta)", + "Asia\/Gaza": "Gündogar Ýewropa wagty (Gaza)", + "Asia\/Hebron": "Gündogar Ýewropa wagty (Hewron)", + "Asia\/Hong_Kong": "Gonkong wagty (Gonkong)", + "Asia\/Hovd": "Howd wagty (Howd)", + "Asia\/Irkutsk": "Irkutsk wagty (Irkutsk)", + "Asia\/Jakarta": "Günbatar Indoneziýa wagty (Jakarta)", + "Asia\/Jayapura": "Gündogar Indoneziýa wagty (Jaýapura)", + "Asia\/Jerusalem": "Ysraýyl wagty (Iýerusalim)", + "Asia\/Kabul": "Owganystan wagty (Kabul)", + "Asia\/Karachi": "Pakistan wagty (Karaçi)", + "Asia\/Katmandu": "Nepal wagty (Katmandu)", + "Asia\/Khandyga": "Ýakutsk wagty (Handyga)", + "Asia\/Krasnoyarsk": "Krasnoýarsk wagty (Krasnoýarsk)", + "Asia\/Kuala_Lumpur": "Malaýziýa wagty (Kuala-Lumpur)", + "Asia\/Kuching": "Malaýziýa wagty (Kuçing)", + "Asia\/Kuwait": "Arap ýurtlary wagty (Kuweýt)", + "Asia\/Macau": "Hytaý wagty (Makao)", + "Asia\/Magadan": "Magadan wagty (Magadan)", + "Asia\/Makassar": "Merkezi Indoneziýa wagty (Makasar)", + "Asia\/Manila": "Filippinler wagty (Manila)", + "Asia\/Muscat": "Pars aýlagy standart wagty (Maskat)", + "Asia\/Nicosia": "Gündogar Ýewropa wagty (Nikosiýa)", + "Asia\/Novokuznetsk": "Krasnoýarsk wagty (Nowokuznetsk)", + "Asia\/Novosibirsk": "Nowosibirsk wagty (Nowosibirsk)", + "Asia\/Omsk": "Omsk wagty (Omsk)", + "Asia\/Oral": "Günbatar Gazagystan wagty (Oral)", + "Asia\/Phnom_Penh": "Hindihytaý wagty (Pnompen)", + "Asia\/Pontianak": "Günbatar Indoneziýa wagty (Pontianak)", + "Asia\/Pyongyang": "Koreýa wagty (Phenýan)", + "Asia\/Qatar": "Arap ýurtlary wagty (Katar)", + "Asia\/Qostanay": "Gündogar Gazagystan wagty (Qostanay)", + "Asia\/Qyzylorda": "Günbatar Gazagystan wagty (Gyzylorda)", + "Asia\/Rangoon": "Mýanma wagty (Rangun)", + "Asia\/Riyadh": "Arap ýurtlary wagty (Er-Riýad)", + "Asia\/Saigon": "Hindihytaý wagty (Hoşimin)", + "Asia\/Sakhalin": "Sahalin wagty (Sahalin)", + "Asia\/Samarkand": "Özbegistan wagty (Samarkand)", + "Asia\/Seoul": "Koreýa wagty (Seul)", + "Asia\/Shanghai": "Hytaý wagty (Şanhaý)", + "Asia\/Singapore": "Singapur wagty (Singapur)", + "Asia\/Srednekolymsk": "Magadan wagty (Srednekolymsk)", + "Asia\/Taipei": "Taýbeý wagty (Taýbeý)", + "Asia\/Tashkent": "Özbegistan wagty (Taşkent)", + "Asia\/Tbilisi": "Gruziýa wagty (Tbilisi)", + "Asia\/Tehran": "Eýran wagty (Tähran)", + "Asia\/Thimphu": "Butan wagty (Timpu)", + "Asia\/Tokyo": "Ýaponiýa wagty (Tokio)", + "Asia\/Ulaanbaatar": "Ulan-Bator wagty (Ulan-Bator)", + "Asia\/Ust-Nera": "Wladiwostok wagty (Ust-Nera)", + "Asia\/Vientiane": "Hindihytaý wagty (Wýentýan)", + "Asia\/Vladivostok": "Wladiwostok wagty (Wladiwostok)", + "Asia\/Yakutsk": "Ýakutsk wagty (Ýakutsk)", + "Asia\/Yekaterinburg": "Ýekaterinburg wagty (Ýekaterinburg)", + "Asia\/Yerevan": "Ermenistan wagty (Ýerewan)", + "Atlantic\/Azores": "Azor adalary wagty (Azor adalary)", + "Atlantic\/Bermuda": "Atlantik wagty (Bermuda)", + "Atlantic\/Canary": "Günbatar Ýewropa wagty (Kanar adalary)", + "Atlantic\/Cape_Verde": "Kabo-Werde wagty (Kabo-Werde)", + "Atlantic\/Faeroe": "Günbatar Ýewropa wagty (Farer adalary)", + "Atlantic\/Madeira": "Günbatar Ýewropa wagty (Madeýra adalary)", + "Atlantic\/Reykjavik": "Grinwiç boýunça orta wagt (Reýkýawik)", + "Atlantic\/South_Georgia": "Günorta Georgiýa wagty (Günorta Georgiýa)", + "Atlantic\/St_Helena": "Grinwiç boýunça orta wagt (Keramatly Ýelena adasy)", + "Atlantic\/Stanley": "Folklend adalary wagty (Stenli)", + "Australia\/Adelaide": "Merkezi Awstraliýa wagty (Adelaida)", + "Australia\/Brisbane": "Gündogar Awstraliýa wagty (Brisben)", + "Australia\/Broken_Hill": "Merkezi Awstraliýa wagty (Broken-Hil)", + "Australia\/Currie": "Gündogar Awstraliýa wagty (Kerri)", + "Australia\/Darwin": "Merkezi Awstraliýa wagty (Darwin)", + "Australia\/Eucla": "Merkezi Awstraliýa günbatar wagty (Ýukla)", + "Australia\/Hobart": "Gündogar Awstraliýa wagty (Hobart)", + "Australia\/Lindeman": "Gündogar Awstraliýa wagty (Lindeman)", + "Australia\/Lord_Howe": "Lord-Hau wagty (Lord-Hau)", + "Australia\/Melbourne": "Gündogar Awstraliýa wagty (Melburn)", + "Australia\/Perth": "Günbatar Awstraliýa wagty (Pert)", + "Australia\/Sydney": "Gündogar Awstraliýa wagty (Sidneý)", + "CST6CDT": "Merkezi Amerika", + "EST5EDT": "Demirgazyk Amerika gündogar wagty", + "Etc\/GMT": "Grinwiç boýunça orta wagt", + "Etc\/UTC": "Utgaşdyrylýan ähliumumy wagt", + "Europe\/Amsterdam": "Merkezi Ýewropa wagty (Amsterdam)", + "Europe\/Andorra": "Merkezi Ýewropa wagty (Andorra)", + "Europe\/Astrakhan": "Moskwa wagty (Astrahan)", + "Europe\/Athens": "Gündogar Ýewropa wagty (Afiny)", + "Europe\/Belgrade": "Merkezi Ýewropa wagty (Belgrad)", + "Europe\/Berlin": "Merkezi Ýewropa wagty (Berlin)", + "Europe\/Bratislava": "Merkezi Ýewropa wagty (Bratislawa)", + "Europe\/Brussels": "Merkezi Ýewropa wagty (Brýussel)", + "Europe\/Bucharest": "Gündogar Ýewropa wagty (Buharest)", + "Europe\/Budapest": "Merkezi Ýewropa wagty (Budapeşt)", + "Europe\/Busingen": "Merkezi Ýewropa wagty (Býuzingen)", + "Europe\/Chisinau": "Gündogar Ýewropa wagty (Kişinýow)", + "Europe\/Copenhagen": "Merkezi Ýewropa wagty (Kopengagen)", + "Europe\/Dublin": "Grinwiç boýunça orta wagt (Dublin)", + "Europe\/Gibraltar": "Merkezi Ýewropa wagty (Gibraltar)", + "Europe\/Guernsey": "Grinwiç boýunça orta wagt (Gernsi)", + "Europe\/Helsinki": "Gündogar Ýewropa wagty (Helsinki)", + "Europe\/Isle_of_Man": "Grinwiç boýunça orta wagt (Men adasy)", + "Europe\/Jersey": "Grinwiç boýunça orta wagt (Jersi)", + "Europe\/Kaliningrad": "Gündogar Ýewropa wagty (Kaliningrad)", + "Europe\/Kiev": "Gündogar Ýewropa wagty (Kiýew)", + "Europe\/Lisbon": "Günbatar Ýewropa wagty (Lissabon)", + "Europe\/Ljubljana": "Merkezi Ýewropa wagty (Lýublýana)", + "Europe\/London": "Grinwiç boýunça orta wagt (London)", + "Europe\/Luxembourg": "Merkezi Ýewropa wagty (Lýuksemburg)", + "Europe\/Madrid": "Merkezi Ýewropa wagty (Madrid)", + "Europe\/Malta": "Merkezi Ýewropa wagty (Malta)", + "Europe\/Mariehamn": "Gündogar Ýewropa wagty (Mariýehamn)", + "Europe\/Minsk": "Moskwa wagty (Minsk)", + "Europe\/Monaco": "Merkezi Ýewropa wagty (Monako)", + "Europe\/Moscow": "Moskwa wagty (Moskwa)", + "Europe\/Oslo": "Merkezi Ýewropa wagty (Oslo)", + "Europe\/Paris": "Merkezi Ýewropa wagty (Pariž)", + "Europe\/Podgorica": "Merkezi Ýewropa wagty (Podgorisa)", + "Europe\/Prague": "Merkezi Ýewropa wagty (Praga)", + "Europe\/Riga": "Gündogar Ýewropa wagty (Riga)", + "Europe\/Rome": "Merkezi Ýewropa wagty (Rim)", + "Europe\/San_Marino": "Merkezi Ýewropa wagty (San-Marino)", + "Europe\/Sarajevo": "Merkezi Ýewropa wagty (Saraýewo)", + "Europe\/Saratov": "Moskwa wagty (Saratow)", + "Europe\/Simferopol": "Moskwa wagty (Simferopol)", + "Europe\/Skopje": "Merkezi Ýewropa wagty (Skopýe)", + "Europe\/Sofia": "Gündogar Ýewropa wagty (Sofiýa)", + "Europe\/Stockholm": "Merkezi Ýewropa wagty (Stokgolm)", + "Europe\/Tallinn": "Gündogar Ýewropa wagty (Tallin)", + "Europe\/Tirane": "Merkezi Ýewropa wagty (Tirana)", + "Europe\/Ulyanovsk": "Moskwa wagty (Ulýanowsk)", + "Europe\/Uzhgorod": "Gündogar Ýewropa wagty (Užgorod)", + "Europe\/Vaduz": "Merkezi Ýewropa wagty (Waduz)", + "Europe\/Vatican": "Merkezi Ýewropa wagty (Watikan)", + "Europe\/Vienna": "Merkezi Ýewropa wagty (Wena)", + "Europe\/Vilnius": "Gündogar Ýewropa wagty (Wilnýus)", + "Europe\/Volgograd": "Wolgograd wagty (Wolgograd)", + "Europe\/Warsaw": "Merkezi Ýewropa wagty (Warşawa)", + "Europe\/Zagreb": "Merkezi Ýewropa wagty (Zagreb)", + "Europe\/Zaporozhye": "Gündogar Ýewropa wagty (Zaporožýe)", + "Europe\/Zurich": "Merkezi Ýewropa wagty (Sýurih)", + "Indian\/Antananarivo": "Gündogar Afrika wagty (Antananariwu)", + "Indian\/Chagos": "Hindi ummany wagty (Çagos)", + "Indian\/Christmas": "Roždestwo adasy wagty (Roždestwo)", + "Indian\/Cocos": "Kokos adalary wagty (Kokos)", + "Indian\/Comoro": "Gündogar Afrika wagty (Komor adalary)", + "Indian\/Kerguelen": "Fransuz Günorta we Antarktika ýerleri wagty (Kergelen)", + "Indian\/Mahe": "Seýşel adalary wagty (Maýe)", + "Indian\/Maldives": "Maldiwler wagty (Maldiwler)", + "Indian\/Mauritius": "Mawrikiý wagty (Mawrikiý)", + "Indian\/Mayotte": "Gündogar Afrika wagty (Maýotta)", + "Indian\/Reunion": "Reýunýon wagty (Reýunýon)", + "MST7MDT": "Demirgazyk Amerika dag wagty", + "PST8PDT": "Demirgazyk Amerika Ýuwaş umman wagty", + "Pacific\/Apia": "Apia wagty (Apia)", + "Pacific\/Auckland": "Täze Zelandiýa wagty (Oklend)", + "Pacific\/Bougainville": "Papua - Täze Gwineýa wagty (Bugenwil)", + "Pacific\/Chatham": "Çatem wagty (Çatem)", + "Pacific\/Easter": "Pasha adasy wagty (Pashi adasy)", + "Pacific\/Efate": "Wanuatu wagty (Efate)", + "Pacific\/Enderbury": "Feniks adalary wagty (Enderberi)", + "Pacific\/Fakaofo": "Tokelau wagty (Fakaofo)", + "Pacific\/Fiji": "Fiji wagty (Fiji)", + "Pacific\/Funafuti": "Tuwalu wagty (Funafuti)", + "Pacific\/Galapagos": "Galapagos adalary wagty (Galapagos adalary)", + "Pacific\/Gambier": "Gambýe wagty (Gambýe)", + "Pacific\/Guadalcanal": "Solomon adalary wagty (Gwadalkanal)", + "Pacific\/Guam": "Çamorro wagty (Guam)", + "Pacific\/Honolulu": "Gawaý-Aleut wagty (Gonolulu)", + "Pacific\/Johnston": "Gawaý-Aleut wagty (Jonston)", + "Pacific\/Kiritimati": "Laýn adalary wagty (Kiritimati)", + "Pacific\/Kosrae": "Kosraýe wagty (Kosraýe)", + "Pacific\/Kwajalein": "Marşall adalary wagty (Kwajaleýn)", + "Pacific\/Majuro": "Marşall adalary wagty (Majuro)", + "Pacific\/Marquesas": "Markiz adalary wagty (Markiz adalary)", + "Pacific\/Midway": "Samoa wagty (Midueý)", + "Pacific\/Nauru": "Nauru wagty (Nauru)", + "Pacific\/Niue": "Niue wagty (Niue)", + "Pacific\/Norfolk": "Norfolk adasy wagty (Norfolk)", + "Pacific\/Noumea": "Täze Kaledoniýa wagty (Numea)", + "Pacific\/Pago_Pago": "Samoa wagty (Pago-Pago)", + "Pacific\/Palau": "Palau wagty (Palau)", + "Pacific\/Pitcairn": "Pitkern wagty (Pitkern)", + "Pacific\/Ponape": "Ponape wagty (Ponape)", + "Pacific\/Port_Moresby": "Papua - Täze Gwineýa wagty (Port-Morsbi)", + "Pacific\/Rarotonga": "Kuk adalary wagty (Rarotonga)", + "Pacific\/Saipan": "Çamorro wagty (Saýpan)", + "Pacific\/Tahiti": "Taiti wagty (Taiti)", + "Pacific\/Tarawa": "Gilberta adalary wagty (Tarawa)", + "Pacific\/Tongatapu": "Tonga wagty (Tongatapu)", + "Pacific\/Truk": "Çuuk wagty (Çuuk)", + "Pacific\/Wake": "Weýk adasy wagty (Weýk)", + "Pacific\/Wallis": "Uollis we Futuna wagty (Uollis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/tl.json b/src/Symfony/Component/Intl/Resources/data/timezones/tl.json new file mode 100644 index 0000000000000..b9c2b3d9c3e56 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/tl.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.20", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Addis_Ababa": "Oras sa Silangang Africa (Addis Ababa)", + "Africa\/Algiers": "Oras sa Gitnang Europe (Algiers)", + "Africa\/Asmera": "Oras sa Silangang Africa (Asmara)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Bangui": "Oras sa Kanlurang Africa (Bangui)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Blantyre": "Oras sa Gitnang Africa (Blantyre)", + "Africa\/Brazzaville": "Oras sa Kanlurang Africa (Brazzaville)", + "Africa\/Bujumbura": "Oras sa Gitnang Africa (Bujumbura)", + "Africa\/Cairo": "Oras sa Silangang Europe (Cairo)", + "Africa\/Casablanca": "Oras sa Kanlurang Europe (Casablanca)", + "Africa\/Ceuta": "Oras sa Gitnang Europe (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/Dar_es_Salaam": "Oras sa Silangang Africa (Dar es Salaam)", + "Africa\/Djibouti": "Oras sa Silangang Africa (Djibouti)", + "Africa\/Douala": "Oras sa Kanlurang Africa (Douala)", + "Africa\/El_Aaiun": "Oras sa Kanlurang Europe (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Gaborone": "Oras sa Gitnang Africa (Gaborone)", + "Africa\/Harare": "Oras sa Gitnang Africa (Harare)", + "Africa\/Johannesburg": "Oras sa Timog Africa (Johannesburg)", + "Africa\/Juba": "Oras sa Silangang Africa (Juba)", + "Africa\/Kampala": "Oras sa Silangang Africa (Kampala)", + "Africa\/Khartoum": "Oras sa Gitnang Africa (Khartoum)", + "Africa\/Kigali": "Oras sa Gitnang Africa (Kigali)", + "Africa\/Kinshasa": "Oras sa Kanlurang Africa (Kinshasa)", + "Africa\/Lagos": "Oras sa Kanlurang Africa (Lagos)", + "Africa\/Libreville": "Oras sa Kanlurang Africa (Libreville)", + "Africa\/Lome": "Greenwich Mean Time (Lome)", + "Africa\/Luanda": "Oras sa Kanlurang Africa (Luanda)", + "Africa\/Lubumbashi": "Oras sa Gitnang Africa (Lubumbashi)", + "Africa\/Lusaka": "Oras sa Gitnang Africa (Lusaka)", + "Africa\/Malabo": "Oras sa Kanlurang Africa (Malabo)", + "Africa\/Maputo": "Oras sa Gitnang Africa (Maputo)", + "Africa\/Maseru": "Oras sa Timog Africa (Maseru)", + "Africa\/Mbabane": "Oras sa Timog Africa (Mbabane)", + "Africa\/Mogadishu": "Oras sa Silangang Africa (Mogadishu)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nairobi": "Oras sa Silangang Africa (Nairobi)", + "Africa\/Ndjamena": "Oras sa Kanlurang Africa (Ndjamena)", + "Africa\/Niamey": "Oras sa Kanlurang Africa (Niamey)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Porto-Novo": "Oras sa Kanlurang Africa (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tome)", + "Africa\/Tripoli": "Oras sa Silangang Europe (Tripoli)", + "Africa\/Tunis": "Oras sa Gitnang Europe (Tunis)", + "Africa\/Windhoek": "Oras sa Gitnang Africa (Windhoek)", + "America\/Adak": "Oras sa Hawaii-Aleutian (Adak)", + "America\/Anchorage": "Oras sa Alaska (Anchorage)", + "America\/Anguilla": "Oras sa Atlantiko (Anguilla)", + "America\/Antigua": "Oras sa Atlantiko (Antigua)", + "America\/Araguaina": "Oras sa Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "Oras sa Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Oras sa Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Oras sa Argentina (Salta)", + "America\/Argentina\/San_Juan": "Oras sa Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Oras sa Kanlurang Argentina (San Luis)", + "America\/Argentina\/Tucuman": "Oras sa Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Oras sa Argentina (Ushuaia)", + "America\/Aruba": "Oras sa Atlantiko (Aruba)", + "America\/Asuncion": "Oras sa Paraguay (Asunción)", + "America\/Bahia": "Oras sa Brasilia (Bahia)", + "America\/Bahia_Banderas": "Sentral na Oras (Bahia Banderas)", + "America\/Barbados": "Oras sa Atlantiko (Barbados)", + "America\/Belem": "Oras sa Brasilia (Belem)", + "America\/Belize": "Sentral na Oras (Belize)", + "America\/Blanc-Sablon": "Oras sa Atlantiko (Blanc-Sablon)", + "America\/Boa_Vista": "Oras sa Amazon (Boa Vista)", + "America\/Bogota": "Oras sa Colombia (Bogota)", + "America\/Boise": "Oras sa Bundok (Boise)", + "America\/Buenos_Aires": "Oras sa Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Oras sa Bundok (Cambridge Bay)", + "America\/Campo_Grande": "Oras sa Amazon (Campo Grande)", + "America\/Cancun": "Eastern Time (Cancun)", + "America\/Caracas": "Oras sa Venezuela (Caracas)", + "America\/Catamarca": "Oras sa Argentina (Catamarca)", + "America\/Cayenne": "Oras sa French Guiana (Cayenne)", + "America\/Cayman": "Eastern Time (Cayman)", + "America\/Chicago": "Sentral na Oras (Chicago)", + "America\/Chihuahua": "Oras sa Pasipiko ng Mexico (Chihuahua)", + "America\/Coral_Harbour": "Eastern Time (Atikokan)", + "America\/Cordoba": "Oras sa Argentina (Cordoba)", + "America\/Costa_Rica": "Sentral na Oras (Costa Rica)", + "America\/Creston": "Oras sa Bundok (Creston)", + "America\/Cuiaba": "Oras sa Amazon (Cuiaba)", + "America\/Curacao": "Oras sa Atlantiko (Curacao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Oras sa Pasipiko (Dawson)", + "America\/Dawson_Creek": "Oras sa Bundok (Dawson Creek)", + "America\/Denver": "Oras sa Bundok (Denver)", + "America\/Detroit": "Eastern Time (Detroit)", + "America\/Dominica": "Oras sa Atlantiko (Dominica)", + "America\/Edmonton": "Oras sa Bundok (Edmonton)", + "America\/El_Salvador": "Sentral na Oras (El Salvador)", + "America\/Fort_Nelson": "Oras sa Bundok (Fort Nelson)", + "America\/Fortaleza": "Oras sa Brasilia (Fortaleza)", + "America\/Glace_Bay": "Oras sa Atlantiko (Glace Bay)", + "America\/Godthab": "Oras sa Kanlurang Greenland (Nuuk)", + "America\/Goose_Bay": "Oras sa Atlantiko (Goose Bay)", + "America\/Grand_Turk": "Eastern Time (Grand Turk)", + "America\/Grenada": "Oras sa Atlantiko (Grenada)", + "America\/Guadeloupe": "Oras sa Atlantiko (Guadeloupe)", + "America\/Guatemala": "Sentral na Oras (Guatemala)", + "America\/Guayaquil": "Oras sa Ecuador (Guayaquil)", + "America\/Guyana": "Oras sa Guyana (Guyana)", + "America\/Halifax": "Oras sa Atlantiko (Halifax)", + "America\/Havana": "Oras sa Cuba (Havana)", + "America\/Hermosillo": "Oras sa Pasipiko ng Mexico (Hermosillo)", + "America\/Indiana\/Knox": "Sentral na Oras (Knox, Indiana)", + "America\/Indiana\/Marengo": "Eastern Time (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Eastern Time (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Sentral na Oras (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Eastern Time (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Eastern Time (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Eastern Time (Winamac, Indiana)", + "America\/Indianapolis": "Eastern Time (Indianapolis)", + "America\/Inuvik": "Oras sa Bundok (Inuvik)", + "America\/Iqaluit": "Eastern Time (Iqaluit)", + "America\/Jamaica": "Eastern Time (Jamaica)", + "America\/Jujuy": "Oras sa Argentina (Jujuy)", + "America\/Juneau": "Oras sa Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Eastern Time (Monticello, Kentucky)", + "America\/Kralendijk": "Oras sa Atlantiko (Kralendijk)", + "America\/La_Paz": "Oras sa Bolivia (La Paz)", + "America\/Lima": "Oras sa Peru (Lima)", + "America\/Los_Angeles": "Oras sa Pasipiko (Los Angeles)", + "America\/Louisville": "Eastern Time (Louisville)", + "America\/Lower_Princes": "Oras sa Atlantiko (Lower Prince’s Quarter)", + "America\/Maceio": "Oras sa Brasilia (Maceio)", + "America\/Managua": "Sentral na Oras (Managua)", + "America\/Manaus": "Oras sa Amazon (Manaus)", + "America\/Marigot": "Oras sa Atlantiko (Marigot)", + "America\/Martinique": "Oras sa Atlantiko (Martinique)", + "America\/Matamoros": "Sentral na Oras (Matamoros)", + "America\/Mazatlan": "Oras sa Pasipiko ng Mexico (Mazatlan)", + "America\/Mendoza": "Oras sa Argentina (Mendoza)", + "America\/Menominee": "Sentral na Oras (Menominee)", + "America\/Merida": "Sentral na Oras (Merida)", + "America\/Metlakatla": "Oras sa Alaska (Metlakatla)", + "America\/Mexico_City": "Sentral na Oras (Lungsod ng Mexico)", + "America\/Miquelon": "Oras sa Saint Pierre & Miquelon (Miquelon)", + "America\/Moncton": "Oras sa Atlantiko (Moncton)", + "America\/Monterrey": "Sentral na Oras (Monterrey)", + "America\/Montevideo": "Oras sa Uruguay (Montevideo)", + "America\/Montserrat": "Oras sa Atlantiko (Montserrat)", + "America\/Nassau": "Eastern Time (Nassau)", + "America\/New_York": "Eastern Time (New York)", + "America\/Nipigon": "Eastern Time (Nipigon)", + "America\/Nome": "Oras sa Alaska (Nome)", + "America\/Noronha": "Oras sa Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Sentral na Oras (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Sentral na Oras (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Sentral na Oras (New Salem, North Dakota)", + "America\/Ojinaga": "Oras sa Bundok (Ojinaga)", + "America\/Panama": "Eastern Time (Panama)", + "America\/Pangnirtung": "Eastern Time (Pangnirtung)", + "America\/Paramaribo": "Oras sa Suriname (Paramaribo)", + "America\/Phoenix": "Oras sa Bundok (Phoenix)", + "America\/Port-au-Prince": "Eastern Time (Port-au-Prince)", + "America\/Port_of_Spain": "Oras sa Atlantiko (Puwerto ng Espanya)", + "America\/Porto_Velho": "Oras sa Amazon (Porto Velho)", + "America\/Puerto_Rico": "Oras sa Atlantiko (Puerto Rico)", + "America\/Punta_Arenas": "Oras sa Chile (Punta Arenas)", + "America\/Rainy_River": "Sentral na Oras (Rainy River)", + "America\/Rankin_Inlet": "Sentral na Oras (Makipot na Look ng Rankin)", + "America\/Recife": "Oras sa Brasilia (Recife)", + "America\/Regina": "Sentral na Oras (Regina)", + "America\/Resolute": "Sentral na Oras (Resolute)", + "America\/Santa_Isabel": "Oras sa Hilagang-kanlurang Mexico (Santa Isabel)", + "America\/Santarem": "Oras sa Brasilia (Santarem)", + "America\/Santiago": "Oras sa Chile (Santiago)", + "America\/Santo_Domingo": "Oras sa Atlantiko (Santo Domingo)", + "America\/Sao_Paulo": "Oras sa Brasilia (Sao Paulo)", + "America\/Scoresbysund": "Oras sa Silangang Greenland (Ittoqqortoormiit)", + "America\/Sitka": "Oras sa Alaska (Sitka)", + "America\/St_Barthelemy": "Oras sa Atlantiko (St. Barthélemy)", + "America\/St_Johns": "Oras sa Newfoundland (St. John’s)", + "America\/St_Kitts": "Oras sa Atlantiko (St. Kitts)", + "America\/St_Lucia": "Oras sa Atlantiko (St. Lucia)", + "America\/St_Thomas": "Oras sa Atlantiko (St. Thomas)", + "America\/St_Vincent": "Oras sa Atlantiko (St. Vincent)", + "America\/Swift_Current": "Sentral na Oras (Swift Current)", + "America\/Tegucigalpa": "Sentral na Oras (Tegucigalpa)", + "America\/Thule": "Oras sa Atlantiko (Thule)", + "America\/Thunder_Bay": "Eastern Time (Thunder Bay)", + "America\/Tijuana": "Oras sa Pasipiko (Tijuana)", + "America\/Toronto": "Eastern Time (Toronto)", + "America\/Tortola": "Oras sa Atlantiko (Tortola)", + "America\/Vancouver": "Oras sa Pasipiko (Vancouver)", + "America\/Whitehorse": "Oras sa Pasipiko (Whitehorse)", + "America\/Winnipeg": "Sentral na Oras (Winnipeg)", + "America\/Yakutat": "Oras sa Alaska (Yakutat)", + "America\/Yellowknife": "Oras sa Bundok (Yellowknife)", + "Antarctica\/Casey": "Oras sa Kanlurang Australya (Casey)", + "Antarctica\/Davis": "Oras sa Davis (Davis)", + "Antarctica\/DumontDUrville": "Oras sa Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Oras sa Macquarie Island (Macquarie)", + "Antarctica\/Mawson": "Oras sa Mawson (Mawson)", + "Antarctica\/McMurdo": "Oras sa New Zealand (McMurdo)", + "Antarctica\/Palmer": "Oras sa Chile (Palmer)", + "Antarctica\/Rothera": "Oras sa Rothera (Rothera)", + "Antarctica\/Syowa": "Oras sa Syowa (Syowa)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Antarctica\/Vostok": "Oras sa Vostok (Vostok)", + "Arctic\/Longyearbyen": "Oras sa Gitnang Europe (Longyearbyen)", + "Asia\/Aden": "Oras sa Arabia (Aden)", + "Asia\/Almaty": "Oras sa Silangang Kazakhstan (Almaty)", + "Asia\/Amman": "Oras sa Silangang Europe (Amman)", + "Asia\/Anadyr": "Oras sa Anadyr (Anadyr)", + "Asia\/Aqtau": "Oras sa Kanlurang Kazakhstan (Aqtau)", + "Asia\/Aqtobe": "Oras sa Kanlurang Kazakhstan (Aqtobe)", + "Asia\/Ashgabat": "Oras sa Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Oras sa Kanlurang Kazakhstan (Atyrau)", + "Asia\/Baghdad": "Oras sa Arabia (Baghdad)", + "Asia\/Bahrain": "Oras sa Arabia (Bahrain)", + "Asia\/Baku": "Oras sa Azerbaijan (Baku)", + "Asia\/Bangkok": "Oras sa Indochina (Bangkok)", + "Asia\/Beirut": "Oras sa Silangang Europe (Beirut)", + "Asia\/Bishkek": "Oras sa Kyrgystan (Bishkek)", + "Asia\/Brunei": "Oras sa Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Standard na Oras sa Bhutan (Kolkata)", + "Asia\/Chita": "Oras sa Yakutsk (Chita)", + "Asia\/Choibalsan": "Oras sa Choibalsan (Choibalsan)", + "Asia\/Colombo": "Standard na Oras sa Bhutan (Colombo)", + "Asia\/Damascus": "Oras sa Silangang Europe (Damascus)", + "Asia\/Dhaka": "Oras sa Bangladesh (Dhaka)", + "Asia\/Dili": "Oras sa East Timor (Dili)", + "Asia\/Dubai": "Oras sa Gulf (Dubai)", + "Asia\/Dushanbe": "Oras sa Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Oras sa Silangang Europe (Famagusta)", + "Asia\/Gaza": "Oras sa Silangang Europe (Gaza)", + "Asia\/Hebron": "Oras sa Silangang Europe (Hebron)", + "Asia\/Hong_Kong": "Oras sa Hong Kong (Hong Kong)", + "Asia\/Hovd": "Oras sa Hovd (Hovd)", + "Asia\/Irkutsk": "Oras sa Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Oras sa Kanlurang Indonesia (Jakarta)", + "Asia\/Jayapura": "Oras sa Silangang Indonesia (Jayapura)", + "Asia\/Jerusalem": "Oras sa Israel (Jerusalem)", + "Asia\/Kabul": "Oras sa Afghanistan (Kabul)", + "Asia\/Kamchatka": "Oras sa Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Oras sa Pakistan (Karachi)", + "Asia\/Katmandu": "Oras sa Nepal (Kathmandu)", + "Asia\/Khandyga": "Oras sa Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Oras sa Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Oras sa Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Oras sa Malaysia (Kuching)", + "Asia\/Kuwait": "Oras sa Arabia (Kuwait)", + "Asia\/Macau": "Oras sa China (Macau)", + "Asia\/Magadan": "Oras sa Magadan (Magadan)", + "Asia\/Makassar": "Oras sa Gitnang Indonesia (Makassar)", + "Asia\/Manila": "Oras sa Pilipinas (Manila)", + "Asia\/Muscat": "Oras sa Gulf (Muscat)", + "Asia\/Nicosia": "Oras sa Silangang Europe (Nicosia)", + "Asia\/Novokuznetsk": "Oras sa Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Oras sa Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Oras sa Omsk (Omsk)", + "Asia\/Oral": "Oras sa Kanlurang Kazakhstan (Oral)", + "Asia\/Phnom_Penh": "Oras sa Indochina (Phnom Penh)", + "Asia\/Pontianak": "Oras sa Kanlurang Indonesia (Pontianak)", + "Asia\/Pyongyang": "Oras sa Korea (Pyongyang)", + "Asia\/Qatar": "Oras sa Arabia (Qatar)", + "Asia\/Qostanay": "Oras sa Silangang Kazakhstan (Kostanay)", + "Asia\/Qyzylorda": "Oras sa Kanlurang Kazakhstan (Qyzylorda)", + "Asia\/Rangoon": "Oras sa Myanmar (Rangoon)", + "Asia\/Riyadh": "Oras sa Arabia (Riyadh)", + "Asia\/Saigon": "Oras sa Indochina (Lungsod ng Ho Chi Minh)", + "Asia\/Sakhalin": "Oras sa Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Oras sa Uzbekistan (Samarkand)", + "Asia\/Seoul": "Oras sa Korea (Seoul)", + "Asia\/Shanghai": "Oras sa China (Shanghai)", + "Asia\/Singapore": "Standard na Oras sa Singapore (Singapore)", + "Asia\/Srednekolymsk": "Oras sa Magadan (Srednekolymsk)", + "Asia\/Taipei": "Oras sa Taipei (Taipei)", + "Asia\/Tashkent": "Oras sa Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Oras sa Georgia (Tbilisi)", + "Asia\/Tehran": "Oras sa Iran (Tehran)", + "Asia\/Thimphu": "Oras sa Bhutan (Thimphu)", + "Asia\/Tokyo": "Oras sa Japan (Tokyo)", + "Asia\/Ulaanbaatar": "Oras sa Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Oras sa Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Oras sa Indochina (Vientiane)", + "Asia\/Vladivostok": "Oras sa Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Oras sa Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Oras sa Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Oras sa Armenia (Yerevan)", + "Atlantic\/Azores": "Oras sa Azores (Azores)", + "Atlantic\/Bermuda": "Oras sa Atlantiko (Bermuda)", + "Atlantic\/Canary": "Oras sa Kanlurang Europe (Canary)", + "Atlantic\/Cape_Verde": "Oras sa Cape Verde (Cape Verde)", + "Atlantic\/Faeroe": "Oras sa Kanlurang Europe (Faroe)", + "Atlantic\/Madeira": "Oras sa Kanlurang Europe (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/South_Georgia": "Oras sa Timog Georgia (South Georgia)", + "Atlantic\/St_Helena": "Greenwich Mean Time (St. Helena)", + "Atlantic\/Stanley": "Oras sa Falkland Islands (Stanley)", + "Australia\/Adelaide": "Oras sa Gitnang Australya (Adelaide)", + "Australia\/Brisbane": "Oras sa Silangang Australya (Brisbane)", + "Australia\/Broken_Hill": "Oras sa Gitnang Australya (Broken Hill)", + "Australia\/Currie": "Oras sa Silangang Australya (Currie)", + "Australia\/Darwin": "Oras sa Gitnang Australya (Darwin)", + "Australia\/Eucla": "Oras ng Gitnang Kanluran ng Australya (Eucla)", + "Australia\/Hobart": "Oras sa Silangang Australya (Hobart)", + "Australia\/Lindeman": "Oras sa Silangang Australya (Lindeman)", + "Australia\/Lord_Howe": "Oras sa Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Oras sa Silangang Australya (Melbourne)", + "Australia\/Perth": "Oras sa Kanlurang Australya (Perth)", + "Australia\/Sydney": "Oras sa Silangang Australya (Sydney)", + "CST6CDT": "Sentral na Oras", + "EST5EDT": "Eastern Time", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Coordinated Universal Time", + "Europe\/Amsterdam": "Oras sa Gitnang Europe (Amsterdam)", + "Europe\/Andorra": "Oras sa Gitnang Europe (Andorra)", + "Europe\/Astrakhan": "Oras sa Moscow (Astrakhan)", + "Europe\/Athens": "Oras sa Silangang Europe (Athens)", + "Europe\/Belgrade": "Oras sa Gitnang Europe (Belgrade)", + "Europe\/Berlin": "Oras sa Gitnang Europe (Berlin)", + "Europe\/Bratislava": "Oras sa Gitnang Europe (Bratislava)", + "Europe\/Brussels": "Oras sa Gitnang Europe (Brussels)", + "Europe\/Bucharest": "Oras sa Silangang Europe (Bucharest)", + "Europe\/Budapest": "Oras sa Gitnang Europe (Budapest)", + "Europe\/Busingen": "Oras sa Gitnang Europe (Busingen)", + "Europe\/Chisinau": "Oras sa Silangang Europe (Chisinau)", + "Europe\/Copenhagen": "Oras sa Gitnang Europe (Copenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Oras sa Gitnang Europe (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Oras sa Silangang Europe (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Oras sa Silangang Europe (Kaliningrad)", + "Europe\/Kiev": "Oras sa Silangang Europe (Kiev)", + "Europe\/Lisbon": "Oras sa Kanlurang Europe (Lisbon)", + "Europe\/Ljubljana": "Oras sa Gitnang Europe (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (London)", + "Europe\/Luxembourg": "Oras sa Gitnang Europe (Luxembourg)", + "Europe\/Madrid": "Oras sa Gitnang Europe (Madrid)", + "Europe\/Malta": "Oras sa Gitnang Europe (Malta)", + "Europe\/Mariehamn": "Oras sa Silangang Europe (Mariehamn)", + "Europe\/Minsk": "Oras sa Moscow (Minsk)", + "Europe\/Monaco": "Oras sa Gitnang Europe (Monaco)", + "Europe\/Moscow": "Oras sa Moscow (Moscow)", + "Europe\/Oslo": "Oras sa Gitnang Europe (Oslo)", + "Europe\/Paris": "Oras sa Gitnang Europe (Paris)", + "Europe\/Podgorica": "Oras sa Gitnang Europe (Podgorica)", + "Europe\/Prague": "Oras sa Gitnang Europe (Prague)", + "Europe\/Riga": "Oras sa Silangang Europe (Riga)", + "Europe\/Rome": "Oras sa Gitnang Europe (Rome)", + "Europe\/Samara": "Oras sa Samara (Samara)", + "Europe\/San_Marino": "Oras sa Gitnang Europe (San Marino)", + "Europe\/Sarajevo": "Oras sa Gitnang Europe (Sarajevo)", + "Europe\/Saratov": "Oras sa Moscow (Saratov)", + "Europe\/Simferopol": "Oras sa Moscow (Simferopol)", + "Europe\/Skopje": "Oras sa Gitnang Europe (Skopje)", + "Europe\/Sofia": "Oras sa Silangang Europe (Sofia)", + "Europe\/Stockholm": "Oras sa Gitnang Europe (Stockholm)", + "Europe\/Tallinn": "Oras sa Silangang Europe (Tallinn)", + "Europe\/Tirane": "Oras sa Gitnang Europe (Tirane)", + "Europe\/Ulyanovsk": "Oras sa Moscow (Ulyanovsk)", + "Europe\/Uzhgorod": "Oras sa Silangang Europe (Uzhgorod)", + "Europe\/Vaduz": "Oras sa Gitnang Europe (Vaduz)", + "Europe\/Vatican": "Oras sa Gitnang Europe (Vatican)", + "Europe\/Vienna": "Oras sa Gitnang Europe (Vienna)", + "Europe\/Vilnius": "Oras sa Silangang Europe (Vilnius)", + "Europe\/Volgograd": "Oras sa Volgograd (Volgograd)", + "Europe\/Warsaw": "Oras sa Gitnang Europe (Warsaw)", + "Europe\/Zagreb": "Oras sa Gitnang Europe (Zagreb)", + "Europe\/Zaporozhye": "Oras sa Silangang Europe (Zaporozhye)", + "Europe\/Zurich": "Oras sa Gitnang Europe (Zurich)", + "Indian\/Antananarivo": "Oras sa Silangang Africa (Antananarivo)", + "Indian\/Chagos": "Oras sa Indian Ocean (Chagos)", + "Indian\/Christmas": "Oras sa Christmas Island (Christmas)", + "Indian\/Cocos": "Oras sa Cocos Islands (Cocos)", + "Indian\/Comoro": "Oras sa Silangang Africa (Comoro)", + "Indian\/Kerguelen": "Oras sa Katimugang France at Antartiko (Kerguelen)", + "Indian\/Mahe": "Oras sa Seychelles (Mahe)", + "Indian\/Maldives": "Oras sa Maldives (Maldives)", + "Indian\/Mauritius": "Oras sa Mauritius (Mauritius)", + "Indian\/Mayotte": "Oras sa Silangang Africa (Mayotte)", + "Indian\/Reunion": "Oras sa Reunion (Réunion)", + "MST7MDT": "Oras sa Bundok", + "PST8PDT": "Oras sa Pasipiko", + "Pacific\/Apia": "Oras sa Apia (Apia)", + "Pacific\/Auckland": "Oras sa New Zealand (Auckland)", + "Pacific\/Bougainville": "Oras sa Papua New Guinea (Bougainville)", + "Pacific\/Chatham": "Oras sa Chatham (Chatham)", + "Pacific\/Easter": "Oras sa Easter Island (Easter)", + "Pacific\/Efate": "Oras sa Vanuatu (Efate)", + "Pacific\/Enderbury": "Oras sa Phoenix Islands (Enderbury)", + "Pacific\/Fakaofo": "Oras sa Tokelau (Fakaofo)", + "Pacific\/Fiji": "Oras sa Fiji (Fiji)", + "Pacific\/Funafuti": "Oras sa Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Oras sa Galapagos (Galapagos)", + "Pacific\/Gambier": "Oras sa Gambier (Gambier)", + "Pacific\/Guadalcanal": "Oras sa Solomon Islands (Guadalcanal)", + "Pacific\/Guam": "Standard na Oras sa Chamorro (Guam)", + "Pacific\/Honolulu": "Oras sa Hawaii-Aleutian (Honolulu)", + "Pacific\/Johnston": "Oras sa Hawaii-Aleutian (Johnston)", + "Pacific\/Kiritimati": "Oras sa Line Islands (Kiritimati)", + "Pacific\/Kosrae": "Oras sa Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Oras sa Marshall Islands (Kwajalein)", + "Pacific\/Majuro": "Oras sa Marshall Islands (Majuro)", + "Pacific\/Marquesas": "Oras sa Marquesas (Marquesas)", + "Pacific\/Midway": "Oras sa Samoa (Midway)", + "Pacific\/Nauru": "Oras sa Nauru (Nauru)", + "Pacific\/Niue": "Oras sa Niue (Niue)", + "Pacific\/Norfolk": "Oras sa Norfolk Island (Norfolk)", + "Pacific\/Noumea": "Oras sa New Caledonia (Noumea)", + "Pacific\/Pago_Pago": "Oras sa Samoa (Pago Pago)", + "Pacific\/Palau": "Oras sa Palau (Palau)", + "Pacific\/Pitcairn": "Oras sa Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Oras sa Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Oras sa Papua New Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Oras sa Cook Islands (Rarotonga)", + "Pacific\/Saipan": "Standard na Oras sa Chamorro (Saipan)", + "Pacific\/Tahiti": "Oras sa Tahiti (Tahiti)", + "Pacific\/Tarawa": "Oras sa Gilbert Islands (Tarawa)", + "Pacific\/Tongatapu": "Oras sa Tonga (Tongatapu)", + "Pacific\/Truk": "Oras sa Chuuk (Chuuk)", + "Pacific\/Wake": "Oras sa Wake Island (Wake)", + "Pacific\/Wallis": "Oras sa Wallis & Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/to.json b/src/Symfony/Component/Intl/Resources/data/timezones/to.json new file mode 100644 index 0000000000000..24f9f4855b5b9 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/to.json @@ -0,0 +1,432 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "houa fakakiliniuisi mālie (Abidjan)", + "Africa\/Accra": "houa fakakiliniuisi mālie (Accra)", + "Africa\/Addis_Ababa": "houa fakaʻafelika-hahake (Addis Ababa)", + "Africa\/Algiers": "houa fakaʻeulope-loto (Algiers)", + "Africa\/Asmera": "houa fakaʻafelika-hahake (Asmara)", + "Africa\/Bamako": "houa fakakiliniuisi mālie (Bamako)", + "Africa\/Bangui": "houa fakaʻafelika-hihifo (Bangui)", + "Africa\/Banjul": "houa fakakiliniuisi mālie (Banjul)", + "Africa\/Bissau": "houa fakakiliniuisi mālie (Bissau)", + "Africa\/Blantyre": "houa fakaʻafelika-loto (Blantyre)", + "Africa\/Brazzaville": "houa fakaʻafelika-hihifo (Brazzaville)", + "Africa\/Bujumbura": "houa fakaʻafelika-loto (Bujumbura)", + "Africa\/Cairo": "houa fakaʻeulope-hahake (Cairo)", + "Africa\/Casablanca": "houa fakaʻeulope-hihifo (Casablanca)", + "Africa\/Ceuta": "houa fakaʻeulope-loto (Ceuta)", + "Africa\/Conakry": "houa fakakiliniuisi mālie (Conakry)", + "Africa\/Dakar": "houa fakakiliniuisi mālie (Dakar)", + "Africa\/Dar_es_Salaam": "houa fakaʻafelika-hahake (Dar es Salaam)", + "Africa\/Djibouti": "houa fakaʻafelika-hahake (Djibouti)", + "Africa\/Douala": "houa fakaʻafelika-hihifo (Douala)", + "Africa\/El_Aaiun": "houa fakaʻeulope-hihifo (El Aaiun)", + "Africa\/Freetown": "houa fakakiliniuisi mālie (Freetown)", + "Africa\/Gaborone": "houa fakaʻafelika-loto (Gaborone)", + "Africa\/Harare": "houa fakaʻafelika-loto (Harare)", + "Africa\/Johannesburg": "houa fakaʻafelika-tonga (Johannesburg)", + "Africa\/Juba": "houa fakaʻafelika-hahake (Juba)", + "Africa\/Kampala": "houa fakaʻafelika-hahake (Kampala)", + "Africa\/Khartoum": "houa fakaʻafelika-loto (Khartoum)", + "Africa\/Kigali": "houa fakaʻafelika-loto (Kigali)", + "Africa\/Kinshasa": "houa fakaʻafelika-hihifo (Kinshasa)", + "Africa\/Lagos": "houa fakaʻafelika-hihifo (Lagos)", + "Africa\/Libreville": "houa fakaʻafelika-hihifo (Libreville)", + "Africa\/Lome": "houa fakakiliniuisi mālie (Lome)", + "Africa\/Luanda": "houa fakaʻafelika-hihifo (Luanda)", + "Africa\/Lubumbashi": "houa fakaʻafelika-loto (Lubumbashi)", + "Africa\/Lusaka": "houa fakaʻafelika-loto (Lusaka)", + "Africa\/Malabo": "houa fakaʻafelika-hihifo (Malabo)", + "Africa\/Maputo": "houa fakaʻafelika-loto (Maputo)", + "Africa\/Maseru": "houa fakaʻafelika-tonga (Maseru)", + "Africa\/Mbabane": "houa fakaʻafelika-tonga (Mbabane)", + "Africa\/Mogadishu": "houa fakaʻafelika-hahake (Mogadishu)", + "Africa\/Monrovia": "houa fakakiliniuisi mālie (Monrovia)", + "Africa\/Nairobi": "houa fakaʻafelika-hahake (Nairobi)", + "Africa\/Ndjamena": "houa fakaʻafelika-hihifo (Ndjamena)", + "Africa\/Niamey": "houa fakaʻafelika-hihifo (Niamey)", + "Africa\/Nouakchott": "houa fakakiliniuisi mālie (Nouakchott)", + "Africa\/Ouagadougou": "houa fakakiliniuisi mālie (Ouagadougou)", + "Africa\/Porto-Novo": "houa fakaʻafelika-hihifo (Porto-Novo)", + "Africa\/Sao_Tome": "houa fakakiliniuisi mālie (Sao Tomé)", + "Africa\/Tripoli": "houa fakaʻeulope-hahake (Tripoli)", + "Africa\/Tunis": "houa fakaʻeulope-loto (Tunis)", + "Africa\/Windhoek": "houa fakaʻafelika-loto (Windhoek)", + "America\/Adak": "houa fakahauaʻi (Adak)", + "America\/Anchorage": "houa fakaʻalasika (Anchorage)", + "America\/Anguilla": "houa fakaʻamelika-tokelau ʻatalanitiki (Anguilla)", + "America\/Antigua": "houa fakaʻamelika-tokelau ʻatalanitiki (Antigua)", + "America\/Araguaina": "houa fakapalāsila (Araguaina)", + "America\/Argentina\/La_Rioja": "houa fakaʻasenitina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "houa fakaʻasenitina (Rio Gallegos)", + "America\/Argentina\/Salta": "houa fakaʻasenitina (Salta)", + "America\/Argentina\/San_Juan": "houa fakaʻasenitina (San Juan)", + "America\/Argentina\/San_Luis": "houa fakaʻasenitina-hihifo (San Luis)", + "America\/Argentina\/Tucuman": "houa fakaʻasenitina (Tucuman)", + "America\/Argentina\/Ushuaia": "houa fakaʻasenitina (Ushuaia)", + "America\/Aruba": "houa fakaʻamelika-tokelau ʻatalanitiki (Aruba)", + "America\/Asuncion": "houa fakapalakuai (Asunción)", + "America\/Bahia": "houa fakapalāsila (Bahia)", + "America\/Bahia_Banderas": "houa fakaʻamelika-tokelau loto (Bahia Banderas)", + "America\/Barbados": "houa fakaʻamelika-tokelau ʻatalanitiki (Barbados)", + "America\/Belem": "houa fakapalāsila (Belem)", + "America\/Belize": "houa fakaʻamelika-tokelau loto (Belize)", + "America\/Blanc-Sablon": "houa fakaʻamelika-tokelau ʻatalanitiki (Blanc-Sablon)", + "America\/Boa_Vista": "houa fakaʻamasōne (Boa Vista)", + "America\/Bogota": "houa fakakolomipia (Bogota)", + "America\/Boise": "houa fakaʻamelika-tokelau moʻunga (Boise)", + "America\/Buenos_Aires": "houa fakaʻasenitina (Buenos Aires)", + "America\/Cambridge_Bay": "houa fakaʻamelika-tokelau moʻunga (Cambridge Bay)", + "America\/Campo_Grande": "houa fakaʻamasōne (Campo Grande)", + "America\/Cancun": "houa fakaʻamelika-tokelau hahake (Cancun)", + "America\/Caracas": "houa fakavenesuela (Caracas)", + "America\/Catamarca": "houa fakaʻasenitina (Catamarca)", + "America\/Cayenne": "houa fakakuiana-fakafalanisē (Cayenne)", + "America\/Cayman": "houa fakaʻamelika-tokelau hahake (Cayman)", + "America\/Chicago": "houa fakaʻamelika-tokelau loto (Chicago)", + "America\/Chihuahua": "houa fakamekisikou-pasifika (Chihuahua)", + "America\/Coral_Harbour": "houa fakaʻamelika-tokelau hahake (Atikokan)", + "America\/Cordoba": "houa fakaʻasenitina (Cordoba)", + "America\/Costa_Rica": "houa fakaʻamelika-tokelau loto (Costa Rica)", + "America\/Creston": "houa fakaʻamelika-tokelau moʻunga (Creston)", + "America\/Cuiaba": "houa fakaʻamasōne (Cuiaba)", + "America\/Curacao": "houa fakaʻamelika-tokelau ʻatalanitiki (Curaçao)", + "America\/Danmarkshavn": "houa fakakiliniuisi mālie (Danmarkshavn)", + "America\/Dawson": "houa fakaʻamelika-tokelau pasifika (Dawson)", + "America\/Dawson_Creek": "houa fakaʻamelika-tokelau moʻunga (Dawson Creek)", + "America\/Denver": "houa fakaʻamelika-tokelau moʻunga (Denver)", + "America\/Detroit": "houa fakaʻamelika-tokelau hahake (Detroit)", + "America\/Dominica": "houa fakaʻamelika-tokelau ʻatalanitiki (Dominica)", + "America\/Edmonton": "houa fakaʻamelika-tokelau moʻunga (Edmonton)", + "America\/Eirunepe": "houa fakaʻakelī (Eirunepe)", + "America\/El_Salvador": "houa fakaʻamelika-tokelau loto (El Salvador)", + "America\/Fort_Nelson": "houa fakaʻamelika-tokelau moʻunga (Fort Nelson)", + "America\/Fortaleza": "houa fakapalāsila (Fortaleza)", + "America\/Glace_Bay": "houa fakaʻamelika-tokelau ʻatalanitiki (Glace Bay)", + "America\/Godthab": "houa fakafonuamata-hihifo (Nuuk)", + "America\/Goose_Bay": "houa fakaʻamelika-tokelau ʻatalanitiki (Goose Bay)", + "America\/Grand_Turk": "houa fakaʻamelika-tokelau hahake (Grand Turk)", + "America\/Grenada": "houa fakaʻamelika-tokelau ʻatalanitiki (Grenada)", + "America\/Guadeloupe": "houa fakaʻamelika-tokelau ʻatalanitiki (Guadeloupe)", + "America\/Guatemala": "houa fakaʻamelika-tokelau loto (Guatemala)", + "America\/Guayaquil": "houa fakaʻekuetoa (Guayaquil)", + "America\/Guyana": "houa fakakuiana (Guyana)", + "America\/Halifax": "houa fakaʻamelika-tokelau ʻatalanitiki (Halifax)", + "America\/Havana": "houa fakakiupa (Havana)", + "America\/Hermosillo": "houa fakamekisikou-pasifika (Hermosillo)", + "America\/Indiana\/Knox": "houa fakaʻamelika-tokelau loto (Knox, Indiana)", + "America\/Indiana\/Marengo": "houa fakaʻamelika-tokelau hahake (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "houa fakaʻamelika-tokelau hahake (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "houa fakaʻamelika-tokelau loto (Tell City, Indiana)", + "America\/Indiana\/Vevay": "houa fakaʻamelika-tokelau hahake (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "houa fakaʻamelika-tokelau hahake (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "houa fakaʻamelika-tokelau hahake (Winamac, Indiana)", + "America\/Indianapolis": "houa fakaʻamelika-tokelau hahake (Indianapolis)", + "America\/Inuvik": "houa fakaʻamelika-tokelau moʻunga (Inuvik)", + "America\/Iqaluit": "houa fakaʻamelika-tokelau hahake (Iqaluit)", + "America\/Jamaica": "houa fakaʻamelika-tokelau hahake (Jamaica)", + "America\/Jujuy": "houa fakaʻasenitina (Jujuy)", + "America\/Juneau": "houa fakaʻalasika (Juneau)", + "America\/Kentucky\/Monticello": "houa fakaʻamelika-tokelau hahake (Monticello, Kentucky)", + "America\/Kralendijk": "houa fakaʻamelika-tokelau ʻatalanitiki (Kralendijk)", + "America\/La_Paz": "houa fakapolīvia (La Paz)", + "America\/Lima": "houa fakapelū (Lima)", + "America\/Los_Angeles": "houa fakaʻamelika-tokelau pasifika (Los Angeles)", + "America\/Louisville": "houa fakaʻamelika-tokelau hahake (Louisville)", + "America\/Lower_Princes": "houa fakaʻamelika-tokelau ʻatalanitiki (Lower Prince’s Quarter)", + "America\/Maceio": "houa fakapalāsila (Maceio)", + "America\/Managua": "houa fakaʻamelika-tokelau loto (Managua)", + "America\/Manaus": "houa fakaʻamasōne (Manaus)", + "America\/Marigot": "houa fakaʻamelika-tokelau ʻatalanitiki (Marigot)", + "America\/Martinique": "houa fakaʻamelika-tokelau ʻatalanitiki (Martinique)", + "America\/Matamoros": "houa fakaʻamelika-tokelau loto (Matamoros)", + "America\/Mazatlan": "houa fakamekisikou-pasifika (Mazatlan)", + "America\/Mendoza": "houa fakaʻasenitina (Mendoza)", + "America\/Menominee": "houa fakaʻamelika-tokelau loto (Menominee)", + "America\/Merida": "houa fakaʻamelika-tokelau loto (Merida)", + "America\/Metlakatla": "houa fakaʻalasika (Metlakatla)", + "America\/Mexico_City": "houa fakaʻamelika-tokelau loto (Mexico City)", + "America\/Miquelon": "houa fakasā-piea-mo-mikeloni (Miquelon)", + "America\/Moncton": "houa fakaʻamelika-tokelau ʻatalanitiki (Moncton)", + "America\/Monterrey": "houa fakaʻamelika-tokelau loto (Monterrey)", + "America\/Montevideo": "houa fakaʻulukuai (Montevideo)", + "America\/Montserrat": "houa fakaʻamelika-tokelau ʻatalanitiki (Montserrat)", + "America\/Nassau": "houa fakaʻamelika-tokelau hahake (Nassau)", + "America\/New_York": "houa fakaʻamelika-tokelau hahake (Niu ʻIoke)", + "America\/Nipigon": "houa fakaʻamelika-tokelau hahake (Nipigon)", + "America\/Nome": "houa fakaʻalasika (Nome)", + "America\/Noronha": "houa fakafēnanito-te-nolōnia (Noronha)", + "America\/North_Dakota\/Beulah": "houa fakaʻamelika-tokelau loto (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "houa fakaʻamelika-tokelau loto (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "houa fakaʻamelika-tokelau loto (New Salem, North Dakota)", + "America\/Ojinaga": "houa fakaʻamelika-tokelau moʻunga (Ojinaga)", + "America\/Panama": "houa fakaʻamelika-tokelau hahake (Panama)", + "America\/Pangnirtung": "houa fakaʻamelika-tokelau hahake (Pangnirtung)", + "America\/Paramaribo": "houa fakasuliname (Paramaribo)", + "America\/Phoenix": "houa fakaʻamelika-tokelau moʻunga (Phoenix)", + "America\/Port-au-Prince": "houa fakaʻamelika-tokelau hahake (Port-au-Prince)", + "America\/Port_of_Spain": "houa fakaʻamelika-tokelau ʻatalanitiki (Port of Spain)", + "America\/Porto_Velho": "houa fakaʻamasōne (Porto Velho)", + "America\/Puerto_Rico": "houa fakaʻamelika-tokelau ʻatalanitiki (Puerto Rico)", + "America\/Punta_Arenas": "houa fakasili (Punta Arenas)", + "America\/Rainy_River": "houa fakaʻamelika-tokelau loto (Rainy River)", + "America\/Rankin_Inlet": "houa fakaʻamelika-tokelau loto (Rankin Inlet)", + "America\/Recife": "houa fakapalāsila (Recife)", + "America\/Regina": "houa fakaʻamelika-tokelau loto (Regina)", + "America\/Resolute": "houa fakaʻamelika-tokelau loto (Resolute)", + "America\/Rio_Branco": "houa fakaʻakelī (Rio Branco)", + "America\/Santa_Isabel": "houa fakamekisikou-tokelauhihifo (Santa Isabel)", + "America\/Santarem": "houa fakapalāsila (Santarem)", + "America\/Santiago": "houa fakasili (Santiago)", + "America\/Santo_Domingo": "houa fakaʻamelika-tokelau ʻatalanitiki (Santo Domingo)", + "America\/Sao_Paulo": "houa fakapalāsila (Sao Paulo)", + "America\/Scoresbysund": "houa fakafonuamata-hahake (Ittoqqortoormiit)", + "America\/Sitka": "houa fakaʻalasika (Sitka)", + "America\/St_Barthelemy": "houa fakaʻamelika-tokelau ʻatalanitiki (St. Barthélemy)", + "America\/St_Johns": "houa fakafonuaʻilofoʻou (St. John’s)", + "America\/St_Kitts": "houa fakaʻamelika-tokelau ʻatalanitiki (St. Kitts)", + "America\/St_Lucia": "houa fakaʻamelika-tokelau ʻatalanitiki (St. Lucia)", + "America\/St_Thomas": "houa fakaʻamelika-tokelau ʻatalanitiki (St. Thomas)", + "America\/St_Vincent": "houa fakaʻamelika-tokelau ʻatalanitiki (St. Vincent)", + "America\/Swift_Current": "houa fakaʻamelika-tokelau loto (Swift Current)", + "America\/Tegucigalpa": "houa fakaʻamelika-tokelau loto (Tegucigalpa)", + "America\/Thule": "houa fakaʻamelika-tokelau ʻatalanitiki (Thule)", + "America\/Thunder_Bay": "houa fakaʻamelika-tokelau hahake (Thunder Bay)", + "America\/Tijuana": "houa fakaʻamelika-tokelau pasifika (Tijuana)", + "America\/Toronto": "houa fakaʻamelika-tokelau hahake (Toronto)", + "America\/Tortola": "houa fakaʻamelika-tokelau ʻatalanitiki (Tortola)", + "America\/Vancouver": "houa fakaʻamelika-tokelau pasifika (Vancouver)", + "America\/Whitehorse": "houa fakaʻamelika-tokelau pasifika (Whitehorse)", + "America\/Winnipeg": "houa fakaʻamelika-tokelau loto (Winnipeg)", + "America\/Yakutat": "houa fakaʻalasika (Yakutat)", + "America\/Yellowknife": "houa fakaʻamelika-tokelau moʻunga (Yellowknife)", + "Antarctica\/Casey": "houa fakaʻaositelēlia-hihifo (Casey)", + "Antarctica\/Davis": "houa fakatavisi (Davis)", + "Antarctica\/DumontDUrville": "houa fakatūmoni-tūvile (Dumont d’Urville)", + "Antarctica\/Macquarie": "houa fakamotumakuali (Macquarie)", + "Antarctica\/Mawson": "houa fakamausoni (Mawson)", + "Antarctica\/McMurdo": "houa fakanuʻusila (McMurdo)", + "Antarctica\/Palmer": "houa fakasili (Palmer)", + "Antarctica\/Rothera": "houa fakalotela (Rothera)", + "Antarctica\/Syowa": "houa fakasioua (Syowa)", + "Antarctica\/Troll": "houa fakakiliniuisi mālie (Troll)", + "Antarctica\/Vostok": "houa fakavositoki (Vostok)", + "Arctic\/Longyearbyen": "houa fakaʻeulope-loto (Longyearbyen)", + "Asia\/Aden": "houa fakaʻalepea (Aden)", + "Asia\/Almaty": "houa fakakasakitani-hahake (Almaty)", + "Asia\/Amman": "houa fakaʻeulope-hahake (Amman)", + "Asia\/Anadyr": "houa fakalūsia-ʻanatili (Anadyr)", + "Asia\/Aqtau": "houa fakakasakitani-hihifo (Aqtau)", + "Asia\/Aqtobe": "houa fakakasakitani-hihifo (Aqtobe)", + "Asia\/Ashgabat": "houa fakatūkimenisitani (Ashgabat)", + "Asia\/Atyrau": "houa fakakasakitani-hihifo (Atyrau)", + "Asia\/Baghdad": "houa fakaʻalepea (Baghdad)", + "Asia\/Bahrain": "houa fakaʻalepea (Bahrain)", + "Asia\/Baku": "houa fakaʻasapaisani (Baku)", + "Asia\/Bangkok": "houa fakaʻinitosiaina (Bangkok)", + "Asia\/Beirut": "houa fakaʻeulope-hahake (Beirut)", + "Asia\/Bishkek": "houa fakakīkisitani (Bishkek)", + "Asia\/Brunei": "houa fakapulunei (Brunei)", + "Asia\/Calcutta": "houa fakaʻinitia (Kolkata)", + "Asia\/Chita": "houa fakalūsia-ʻiākutisiki (Chita)", + "Asia\/Choibalsan": "houa fakakoipalisani (Choibalsan)", + "Asia\/Colombo": "houa fakaʻinitia (Colombo)", + "Asia\/Damascus": "houa fakaʻeulope-hahake (Damascus)", + "Asia\/Dhaka": "houa fakapāngilātesi (Dhaka)", + "Asia\/Dili": "houa fakatimoa-hahake (Dili)", + "Asia\/Dubai": "houa fakakūlifi (Dubai)", + "Asia\/Dushanbe": "houa fakatasikitani (Dushanbe)", + "Asia\/Famagusta": "houa fakaʻeulope-hahake (Famagusta)", + "Asia\/Gaza": "houa fakaʻeulope-hahake (Gaza)", + "Asia\/Hebron": "houa fakaʻeulope-hahake (Hebron)", + "Asia\/Hong_Kong": "houa fakahongi-kongi (Hong Kong)", + "Asia\/Hovd": "houa fakahovite (Hovd)", + "Asia\/Irkutsk": "houa fakalūsia-ʻīkutisiki (Irkutsk)", + "Asia\/Jakarta": "houa fakaʻinitonisia-hihifo (Jakarta)", + "Asia\/Jayapura": "houa fakaʻinitonisia-hahake (Jayapura)", + "Asia\/Jerusalem": "houa fakaʻisileli (Selūsalema)", + "Asia\/Kabul": "houa fakaʻafikānisitani (Kabul)", + "Asia\/Kamchatka": "houa fakalūsia-petelopavilovisiki (Kamchatka)", + "Asia\/Karachi": "houa fakapākisitani (Karachi)", + "Asia\/Katmandu": "houa fakanepali (Kathmandu)", + "Asia\/Khandyga": "houa fakalūsia-ʻiākutisiki (Khandyga)", + "Asia\/Krasnoyarsk": "houa fakalūsia-kalasinoiāsiki (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "houa fakamaleisia (Kuala Lumpur)", + "Asia\/Kuching": "houa fakamaleisia (Kuching)", + "Asia\/Kuwait": "houa fakaʻalepea (Kuwait)", + "Asia\/Macau": "houa fakasiaina (Macau)", + "Asia\/Magadan": "houa fakalūsia-makatani (Magadan)", + "Asia\/Makassar": "houa fakaʻinitonisia-loto (Makassar)", + "Asia\/Manila": "houa fakafilipaine (Manila)", + "Asia\/Muscat": "houa fakakūlifi (Muscat)", + "Asia\/Nicosia": "houa fakaʻeulope-hahake (Nicosia)", + "Asia\/Novokuznetsk": "houa fakalūsia-kalasinoiāsiki (Novokuznetsk)", + "Asia\/Novosibirsk": "houa fakalūsia-novosipīsiki (Novosibirsk)", + "Asia\/Omsk": "houa fakalūsia-ʻomisiki (Omsk)", + "Asia\/Oral": "houa fakakasakitani-hihifo (Oral)", + "Asia\/Phnom_Penh": "houa fakaʻinitosiaina (Phnom Penh)", + "Asia\/Pontianak": "houa fakaʻinitonisia-hihifo (Pontianak)", + "Asia\/Pyongyang": "houa fakakōlea (Pyongyang)", + "Asia\/Qatar": "houa fakaʻalepea (Qatar)", + "Asia\/Qostanay": "houa fakakasakitani-hahake (Qostanay)", + "Asia\/Qyzylorda": "houa fakakasakitani-hihifo (Qyzylorda)", + "Asia\/Rangoon": "houa fakapema (Rangoon)", + "Asia\/Riyadh": "houa fakaʻalepea (Riyadh)", + "Asia\/Saigon": "houa fakaʻinitosiaina (Ho Chi Minh)", + "Asia\/Sakhalin": "houa fakalūsia-sakāline (Sakhalin)", + "Asia\/Samarkand": "houa fakaʻusipekitani (Samarkand)", + "Asia\/Seoul": "houa fakakōlea (Seoul)", + "Asia\/Shanghai": "houa fakasiaina (Shanghai)", + "Asia\/Singapore": "houa fakasingapoa (Singapore)", + "Asia\/Srednekolymsk": "houa fakalūsia-makatani (Srednekolymsk)", + "Asia\/Taipei": "houa fakataipei (Taipei)", + "Asia\/Tashkent": "houa fakaʻusipekitani (Tashkent)", + "Asia\/Tbilisi": "houa fakaseōsia (Tbilisi)", + "Asia\/Tehran": "houa fakaʻilaani (Tehran)", + "Asia\/Thimphu": "houa fakapūtani (Thimphu)", + "Asia\/Tokyo": "houa fakasiapani (Tokyo)", + "Asia\/Ulaanbaatar": "houa fakaʻulānipātā (Ulaanbaatar)", + "Asia\/Ust-Nera": "houa fakalūsia-valativositoki (Ust-Nera)", + "Asia\/Vientiane": "houa fakaʻinitosiaina (Vientiane)", + "Asia\/Vladivostok": "houa fakalūsia-valativositoki (Vladivostok)", + "Asia\/Yakutsk": "houa fakalūsia-ʻiākutisiki (Yakutsk)", + "Asia\/Yekaterinburg": "houa fakalūsia-ʻiekatelinepūki (Yekaterinburg)", + "Asia\/Yerevan": "houa fakaʻāmenia (Yerevan)", + "Atlantic\/Azores": "houa fakaʻāsolesi (Azores)", + "Atlantic\/Bermuda": "houa fakaʻamelika-tokelau ʻatalanitiki (Bermuda)", + "Atlantic\/Canary": "houa fakaʻeulope-hihifo (Canary)", + "Atlantic\/Cape_Verde": "houa fakamuiʻi-vēte (Cape Verde)", + "Atlantic\/Faeroe": "houa fakaʻeulope-hihifo (Faroe)", + "Atlantic\/Madeira": "houa fakaʻeulope-hihifo (Madeira)", + "Atlantic\/Reykjavik": "houa fakakiliniuisi mālie (Reykjavik)", + "Atlantic\/South_Georgia": "houa fakasiosiatonga (South Georgia)", + "Atlantic\/St_Helena": "houa fakakiliniuisi mālie (St. Helena)", + "Atlantic\/Stanley": "houa fakaʻotumotu-fokulani (Stanley)", + "Australia\/Adelaide": "houa fakaʻaositelēlia-loto (Atelaite)", + "Australia\/Brisbane": "houa fakaʻaositelēlia-hahake (Pelisipane)", + "Australia\/Broken_Hill": "houa fakaʻaositelēlia-loto (Broken Hill)", + "Australia\/Currie": "houa fakaʻaositelēlia-hahake (Currie)", + "Australia\/Darwin": "houa fakaʻaositelēlia-loto (Darwin)", + "Australia\/Eucla": "houa fakaʻaositelēlia-loto-hihifo (Eucla)", + "Australia\/Hobart": "houa fakaʻaositelēlia-hahake (Hobart)", + "Australia\/Lindeman": "houa fakaʻaositelēlia-hahake (Lindeman)", + "Australia\/Lord_Howe": "houa fakamotuʻeikihoue (Lord Howe)", + "Australia\/Melbourne": "houa fakaʻaositelēlia-hahake (Melipoane)", + "Australia\/Perth": "houa fakaʻaositelēlia-hihifo (Perth)", + "Australia\/Sydney": "houa fakaʻaositelēlia-hahake (Senē)", + "CST6CDT": "houa fakaʻamelika-tokelau loto", + "EST5EDT": "houa fakaʻamelika-tokelau hahake", + "Etc\/GMT": "houa fakakiliniuisi mālie", + "Europe\/Amsterdam": "houa fakaʻeulope-loto (Amsterdam)", + "Europe\/Andorra": "houa fakaʻeulope-loto (Andorra)", + "Europe\/Astrakhan": "houa fakalūsia-mosikou (Astrakhan)", + "Europe\/Athens": "houa fakaʻeulope-hahake (ʻAtenisi)", + "Europe\/Belgrade": "houa fakaʻeulope-loto (Belgrade)", + "Europe\/Berlin": "houa fakaʻeulope-loto (Berlin)", + "Europe\/Bratislava": "houa fakaʻeulope-loto (Bratislava)", + "Europe\/Brussels": "houa fakaʻeulope-loto (Brussels)", + "Europe\/Bucharest": "houa fakaʻeulope-hahake (Bucharest)", + "Europe\/Budapest": "houa fakaʻeulope-loto (Budapest)", + "Europe\/Busingen": "houa fakaʻeulope-loto (Busingen)", + "Europe\/Chisinau": "houa fakaʻeulope-hahake (Chisinau)", + "Europe\/Copenhagen": "houa fakaʻeulope-loto (Copenhagen)", + "Europe\/Dublin": "houa fakakiliniuisi mālie (Dublin)", + "Europe\/Gibraltar": "houa fakaʻeulope-loto (Gibraltar)", + "Europe\/Guernsey": "houa fakakiliniuisi mālie (Guernsey)", + "Europe\/Helsinki": "houa fakaʻeulope-hahake (Helsinki)", + "Europe\/Isle_of_Man": "houa fakakiliniuisi mālie (Isle of Man)", + "Europe\/Jersey": "houa fakakiliniuisi mālie (Jersey)", + "Europe\/Kaliningrad": "houa fakaʻeulope-hahake (Kaliningrad)", + "Europe\/Kiev": "houa fakaʻeulope-hahake (Kiev)", + "Europe\/Lisbon": "houa fakaʻeulope-hihifo (Lisbon)", + "Europe\/Ljubljana": "houa fakaʻeulope-loto (Ljubljana)", + "Europe\/London": "houa fakakiliniuisi mālie (Lonitoni)", + "Europe\/Luxembourg": "houa fakaʻeulope-loto (Luxembourg)", + "Europe\/Madrid": "houa fakaʻeulope-loto (Madrid)", + "Europe\/Malta": "houa fakaʻeulope-loto (Malta)", + "Europe\/Mariehamn": "houa fakaʻeulope-hahake (Mariehamn)", + "Europe\/Minsk": "houa fakalūsia-mosikou (Minsk)", + "Europe\/Monaco": "houa fakaʻeulope-loto (Monaco)", + "Europe\/Moscow": "houa fakalūsia-mosikou (Mosikou)", + "Europe\/Oslo": "houa fakaʻeulope-loto (Oslo)", + "Europe\/Paris": "houa fakaʻeulope-loto (Palesi)", + "Europe\/Podgorica": "houa fakaʻeulope-loto (Podgorica)", + "Europe\/Prague": "houa fakaʻeulope-loto (Prague)", + "Europe\/Riga": "houa fakaʻeulope-hahake (Riga)", + "Europe\/Rome": "houa fakaʻeulope-loto (Loma)", + "Europe\/Samara": "houa fakalūsia-samala (Samara)", + "Europe\/San_Marino": "houa fakaʻeulope-loto (San Marino)", + "Europe\/Sarajevo": "houa fakaʻeulope-loto (Sarajevo)", + "Europe\/Saratov": "houa fakalūsia-mosikou (Saratov)", + "Europe\/Simferopol": "houa fakalūsia-mosikou (Simferopol)", + "Europe\/Skopje": "houa fakaʻeulope-loto (Skopje)", + "Europe\/Sofia": "houa fakaʻeulope-hahake (Sofia)", + "Europe\/Stockholm": "houa fakaʻeulope-loto (Stockholm)", + "Europe\/Tallinn": "houa fakaʻeulope-hahake (Tallinn)", + "Europe\/Tirane": "houa fakaʻeulope-loto (Tirane)", + "Europe\/Ulyanovsk": "houa fakalūsia-mosikou (Ulyanovsk)", + "Europe\/Uzhgorod": "houa fakaʻeulope-hahake (Uzhhorod)", + "Europe\/Vaduz": "houa fakaʻeulope-loto (Vaduz)", + "Europe\/Vatican": "houa fakaʻeulope-loto (Vatikani)", + "Europe\/Vienna": "houa fakaʻeulope-loto (Vienna)", + "Europe\/Vilnius": "houa fakaʻeulope-hahake (Vilnius)", + "Europe\/Volgograd": "houa fakalūsia-volikokalati (Volgograd)", + "Europe\/Warsaw": "houa fakaʻeulope-loto (Warsaw)", + "Europe\/Zagreb": "houa fakaʻeulope-loto (Zagreb)", + "Europe\/Zaporozhye": "houa fakaʻeulope-hahake (Zaporozhye)", + "Europe\/Zurich": "houa fakaʻeulope-loto (Zurich)", + "Indian\/Antananarivo": "houa fakaʻafelika-hahake (Antananarivo)", + "Indian\/Chagos": "houa fakamoanaʻinitia (Chagos)", + "Indian\/Christmas": "houa fakamotukilisimasi (Christmas)", + "Indian\/Cocos": "houa fakamotukokosi (Cocos)", + "Indian\/Comoro": "houa fakaʻafelika-hahake (Comoro)", + "Indian\/Kerguelen": "houa fakaʻanetātikafalanisē (Kerguelen)", + "Indian\/Mahe": "houa fakaʻotumotu-seiseli (Mahe)", + "Indian\/Maldives": "houa fakamalativisi (Maldives)", + "Indian\/Mauritius": "houa fakamaulitiusi (Mauritius)", + "Indian\/Mayotte": "houa fakaʻafelika-hahake (Mayotte)", + "Indian\/Reunion": "houa fakalēunioni (Réunion)", + "MST7MDT": "houa fakaʻamelika-tokelau moʻunga", + "PST8PDT": "houa fakaʻamelika-tokelau pasifika", + "Pacific\/Apia": "houa fakaapia (Apia)", + "Pacific\/Auckland": "houa fakanuʻusila (ʻAokalani)", + "Pacific\/Bougainville": "houa fakapapuaniukini (Bougainville)", + "Pacific\/Chatham": "houa fakasatihami (Chatham)", + "Pacific\/Easter": "houa fakalapanui (Lapanui)", + "Pacific\/Efate": "houa fakavanuatu (Efate)", + "Pacific\/Enderbury": "houa fakaʻotumotufoinikisi (Enderbury)", + "Pacific\/Fakaofo": "houa fakatokelau (Fakaofo)", + "Pacific\/Fiji": "houa fakafisi (Fisi)", + "Pacific\/Funafuti": "houa fakatūvalu (Funafuti)", + "Pacific\/Galapagos": "houa fakakalapakosi (Galapagos)", + "Pacific\/Gambier": "houa fakakamipiē (Gambier)", + "Pacific\/Guadalcanal": "houa fakaʻotumotusolomone (Guadalcanal)", + "Pacific\/Guam": "houa fakakamolo (Kuami)", + "Pacific\/Honolulu": "houa fakahauaʻi (Honolulu)", + "Pacific\/Johnston": "houa fakahauaʻi (Johnston)", + "Pacific\/Kiritimati": "houa fakaʻotumotulaine (Kiritimati)", + "Pacific\/Kosrae": "houa fakakosilae (Kosilae)", + "Pacific\/Kwajalein": "houa fakaʻotumotumasolo (Kwajalein)", + "Pacific\/Majuro": "houa fakaʻotumotumasolo (Majuro)", + "Pacific\/Marquesas": "houa fakamākesasi (Marquesas)", + "Pacific\/Midway": "houa fakahaʻamoa (Midway)", + "Pacific\/Nauru": "houa fakanaulu (Naulu)", + "Pacific\/Niue": "houa fakaniuē (Niuē)", + "Pacific\/Norfolk": "houa fakanoafōki (Noafōki)", + "Pacific\/Noumea": "houa fakakaletōniafoʻou (Noumea)", + "Pacific\/Pago_Pago": "houa fakahaʻamoa (Pangopango)", + "Pacific\/Palau": "houa fakapalau (Palau)", + "Pacific\/Pitcairn": "houa fakapitikani (Pitcairn)", + "Pacific\/Ponape": "houa fakapōnapē (Ponapē)", + "Pacific\/Port_Moresby": "houa fakapapuaniukini (Port Moresby)", + "Pacific\/Rarotonga": "houa fakaʻotumotukuki (Lalotonga)", + "Pacific\/Saipan": "houa fakakamolo (Saipan)", + "Pacific\/Tahiti": "houa fakatahisi (Tahisi)", + "Pacific\/Tarawa": "houa fakakilipasi (Talava)", + "Pacific\/Tongatapu": "houa fakatonga (Tongatapu)", + "Pacific\/Truk": "houa fakatūke (Tūke)", + "Pacific\/Wake": "houa fakamotuueke (Wake)", + "Pacific\/Wallis": "houa fakaʻuvea mo futuna (ʻUvea)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/tr.json b/src/Symfony/Component/Intl/Resources/data/timezones/tr.json new file mode 100644 index 0000000000000..6a87655c42c25 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/tr.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Greenwich Ortalama Saati (Abidjan)", + "Africa\/Accra": "Greenwich Ortalama Saati (Akra)", + "Africa\/Addis_Ababa": "Doğu Afrika Saati (Addis Ababa)", + "Africa\/Algiers": "Orta Avrupa Saati (Cezayir)", + "Africa\/Asmera": "Doğu Afrika Saati (Asmara)", + "Africa\/Bamako": "Greenwich Ortalama Saati (Bamako)", + "Africa\/Bangui": "Batı Afrika Saati (Bangui)", + "Africa\/Banjul": "Greenwich Ortalama Saati (Banjul)", + "Africa\/Bissau": "Greenwich Ortalama Saati (Bissau)", + "Africa\/Blantyre": "Orta Afrika Saati (Blantyre)", + "Africa\/Brazzaville": "Batı Afrika Saati (Brazzavil)", + "Africa\/Bujumbura": "Orta Afrika Saati (Bujumbura)", + "Africa\/Cairo": "Doğu Avrupa Saati (Kahire)", + "Africa\/Casablanca": "Batı Avrupa Saati (Kazablanka)", + "Africa\/Ceuta": "Orta Avrupa Saati (Septe)", + "Africa\/Conakry": "Greenwich Ortalama Saati (Konakri)", + "Africa\/Dakar": "Greenwich Ortalama Saati (Dakar)", + "Africa\/Dar_es_Salaam": "Doğu Afrika Saati (Darüsselam)", + "Africa\/Djibouti": "Doğu Afrika Saati (Cibuti)", + "Africa\/Douala": "Batı Afrika Saati (Douala)", + "Africa\/El_Aaiun": "Batı Avrupa Saati (Layun)", + "Africa\/Freetown": "Greenwich Ortalama Saati (Freetown)", + "Africa\/Gaborone": "Orta Afrika Saati (Gaborone)", + "Africa\/Harare": "Orta Afrika Saati (Harare)", + "Africa\/Johannesburg": "Güney Afrika Standart Saati (Johannesburg)", + "Africa\/Juba": "Doğu Afrika Saati (Cuba)", + "Africa\/Kampala": "Doğu Afrika Saati (Kampala)", + "Africa\/Khartoum": "Orta Afrika Saati (Hartum)", + "Africa\/Kigali": "Orta Afrika Saati (Kigali)", + "Africa\/Kinshasa": "Batı Afrika Saati (Kinşasa)", + "Africa\/Lagos": "Batı Afrika Saati (Lagos)", + "Africa\/Libreville": "Batı Afrika Saati (Librevil)", + "Africa\/Lome": "Greenwich Ortalama Saati (Lome)", + "Africa\/Luanda": "Batı Afrika Saati (Luanda)", + "Africa\/Lubumbashi": "Orta Afrika Saati (Lubumbashi)", + "Africa\/Lusaka": "Orta Afrika Saati (Lusaka)", + "Africa\/Malabo": "Batı Afrika Saati (Malabo)", + "Africa\/Maputo": "Orta Afrika Saati (Maputo)", + "Africa\/Maseru": "Güney Afrika Standart Saati (Maseru)", + "Africa\/Mbabane": "Güney Afrika Standart Saati (Mbabane)", + "Africa\/Mogadishu": "Doğu Afrika Saati (Mogadişu)", + "Africa\/Monrovia": "Greenwich Ortalama Saati (Monrovia)", + "Africa\/Nairobi": "Doğu Afrika Saati (Nairobi)", + "Africa\/Ndjamena": "Batı Afrika Saati (Ndjamena)", + "Africa\/Niamey": "Batı Afrika Saati (Niamey)", + "Africa\/Nouakchott": "Greenwich Ortalama Saati (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Ortalama Saati (Ouagadougou)", + "Africa\/Porto-Novo": "Batı Afrika Saati (Porto-Novo)", + "Africa\/Sao_Tome": "Greenwich Ortalama Saati (Sao Tome)", + "Africa\/Tripoli": "Doğu Avrupa Saati (Trablus)", + "Africa\/Tunis": "Orta Avrupa Saati (Tunus)", + "Africa\/Windhoek": "Orta Afrika Saati (Windhoek)", + "America\/Adak": "Hawaii-Aleut Saati (Adak)", + "America\/Anchorage": "Alaska Saati (Anchorage)", + "America\/Anguilla": "Atlantik Saati (Anguilla)", + "America\/Antigua": "Atlantik Saati (Antigua)", + "America\/Araguaina": "Brasilia Saati (Araguaina)", + "America\/Argentina\/La_Rioja": "Arjantin Saati (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Arjantin Saati (Rio Gallegos)", + "America\/Argentina\/Salta": "Arjantin Saati (Salta)", + "America\/Argentina\/San_Juan": "Arjantin Saati (San Juan)", + "America\/Argentina\/San_Luis": "Batı Arjantin Saati (San Luis)", + "America\/Argentina\/Tucuman": "Arjantin Saati (Tucuman)", + "America\/Argentina\/Ushuaia": "Arjantin Saati (Ushuaia)", + "America\/Aruba": "Atlantik Saati (Aruba)", + "America\/Asuncion": "Paraguay Saati (Asunción)", + "America\/Bahia": "Brasilia Saati (Bahia)", + "America\/Bahia_Banderas": "Kuzey Amerika Merkezi Saati (Bahia Banderas)", + "America\/Barbados": "Atlantik Saati (Barbados)", + "America\/Belem": "Brasilia Saati (Belem)", + "America\/Belize": "Kuzey Amerika Merkezi Saati (Belize)", + "America\/Blanc-Sablon": "Atlantik Saati (Blanc-Sablon)", + "America\/Boa_Vista": "Amazon Saati (Boa Vista)", + "America\/Bogota": "Kolombiya Saati (Bogota)", + "America\/Boise": "Kuzey Amerika Dağ Saati (Boise)", + "America\/Buenos_Aires": "Arjantin Saati (Buenos Aires)", + "America\/Cambridge_Bay": "Kuzey Amerika Dağ Saati (Cambridge Bay)", + "America\/Campo_Grande": "Amazon Saati (Campo Grande)", + "America\/Cancun": "Kuzey Amerika Doğu Saati (Cancun)", + "America\/Caracas": "Venezuela Saati (Caracas)", + "America\/Catamarca": "Arjantin Saati (Catamarca)", + "America\/Cayenne": "Fransız Guyanası Saati (Cayenne)", + "America\/Cayman": "Kuzey Amerika Doğu Saati (Cayman)", + "America\/Chicago": "Kuzey Amerika Merkezi Saati (Chicago)", + "America\/Chihuahua": "Meksika Pasifik Kıyısı Saati (Chihuahua)", + "America\/Coral_Harbour": "Kuzey Amerika Doğu Saati (Atikokan)", + "America\/Cordoba": "Arjantin Saati (Cordoba)", + "America\/Costa_Rica": "Kuzey Amerika Merkezi Saati (Kosta Rika)", + "America\/Creston": "Kuzey Amerika Dağ Saati (Creston)", + "America\/Cuiaba": "Amazon Saati (Cuiaba)", + "America\/Curacao": "Atlantik Saati (Curaçao)", + "America\/Danmarkshavn": "Greenwich Ortalama Saati (Danmarkshavn)", + "America\/Dawson": "Kuzey Amerika Pasifik Saati (Dawson)", + "America\/Dawson_Creek": "Kuzey Amerika Dağ Saati (Dawson Creek)", + "America\/Denver": "Kuzey Amerika Dağ Saati (Denver)", + "America\/Detroit": "Kuzey Amerika Doğu Saati (Detroit)", + "America\/Dominica": "Atlantik Saati (Dominika)", + "America\/Edmonton": "Kuzey Amerika Dağ Saati (Edmonton)", + "America\/Eirunepe": "Acre Saati (Eirunepe)", + "America\/El_Salvador": "Kuzey Amerika Merkezi Saati (El Salvador)", + "America\/Fort_Nelson": "Kuzey Amerika Dağ Saati (Fort Nelson)", + "America\/Fortaleza": "Brasilia Saati (Fortaleza)", + "America\/Glace_Bay": "Atlantik Saati (Glace Bay)", + "America\/Godthab": "Batı Grönland Saati (Nuuk)", + "America\/Goose_Bay": "Atlantik Saati (Goose Bay)", + "America\/Grand_Turk": "Kuzey Amerika Doğu Saati (Grand Turk)", + "America\/Grenada": "Atlantik Saati (Grenada)", + "America\/Guadeloupe": "Atlantik Saati (Guadeloupe)", + "America\/Guatemala": "Kuzey Amerika Merkezi Saati (Guatemala)", + "America\/Guayaquil": "Ekvador Saati (Guayaquil)", + "America\/Guyana": "Guyana Saati (Guyana)", + "America\/Halifax": "Atlantik Saati (Halifax)", + "America\/Havana": "Küba Saati (Havana)", + "America\/Hermosillo": "Meksika Pasifik Kıyısı Saati (Hermosillo)", + "America\/Indiana\/Knox": "Kuzey Amerika Merkezi Saati (Knox, Indiana)", + "America\/Indiana\/Marengo": "Kuzey Amerika Doğu Saati (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Kuzey Amerika Doğu Saati (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Kuzey Amerika Merkezi Saati (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Kuzey Amerika Doğu Saati (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Kuzey Amerika Doğu Saati (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Kuzey Amerika Doğu Saati (Winamac, Indiana)", + "America\/Indianapolis": "Kuzey Amerika Doğu Saati (Indianapolis)", + "America\/Inuvik": "Kuzey Amerika Dağ Saati (Inuvik)", + "America\/Iqaluit": "Kuzey Amerika Doğu Saati (Iqaluit)", + "America\/Jamaica": "Kuzey Amerika Doğu Saati (Jamaika)", + "America\/Jujuy": "Arjantin Saati (Jujuy)", + "America\/Juneau": "Alaska Saati (Juneau)", + "America\/Kentucky\/Monticello": "Kuzey Amerika Doğu Saati (Monticello, Kentucky)", + "America\/Kralendijk": "Atlantik Saati (Kralendijk)", + "America\/La_Paz": "Bolivya Saati (La Paz)", + "America\/Lima": "Peru Saati (Lima)", + "America\/Los_Angeles": "Kuzey Amerika Pasifik Saati (Los Angeles)", + "America\/Louisville": "Kuzey Amerika Doğu Saati (Louisville)", + "America\/Lower_Princes": "Atlantik Saati (Lower Prince’s Quarter)", + "America\/Maceio": "Brasilia Saati (Maceio)", + "America\/Managua": "Kuzey Amerika Merkezi Saati (Managua)", + "America\/Manaus": "Amazon Saati (Manaus)", + "America\/Marigot": "Atlantik Saati (Marigot)", + "America\/Martinique": "Atlantik Saati (Martinique)", + "America\/Matamoros": "Kuzey Amerika Merkezi Saati (Matamoros)", + "America\/Mazatlan": "Meksika Pasifik Kıyısı Saati (Mazatlan)", + "America\/Mendoza": "Arjantin Saati (Mendoza)", + "America\/Menominee": "Kuzey Amerika Merkezi Saati (Menominee)", + "America\/Merida": "Kuzey Amerika Merkezi Saati (Merida)", + "America\/Metlakatla": "Alaska Saati (Metlakatla)", + "America\/Mexico_City": "Kuzey Amerika Merkezi Saati (Mexico City)", + "America\/Miquelon": "Saint Pierre ve Miquelon Saati (Miquelon)", + "America\/Moncton": "Atlantik Saati (Moncton)", + "America\/Monterrey": "Kuzey Amerika Merkezi Saati (Monterrey)", + "America\/Montevideo": "Uruguay Saati (Montevideo)", + "America\/Montserrat": "Atlantik Saati (Montserrat)", + "America\/Nassau": "Kuzey Amerika Doğu Saati (Nassau)", + "America\/New_York": "Kuzey Amerika Doğu Saati (New York)", + "America\/Nipigon": "Kuzey Amerika Doğu Saati (Nipigon)", + "America\/Nome": "Alaska Saati (Nome)", + "America\/Noronha": "Fernando de Noronha Saati (Noronha)", + "America\/North_Dakota\/Beulah": "Kuzey Amerika Merkezi Saati (Beulah, Kuzey Dakota)", + "America\/North_Dakota\/Center": "Kuzey Amerika Merkezi Saati (Merkez, Kuzey Dakota)", + "America\/North_Dakota\/New_Salem": "Kuzey Amerika Merkezi Saati (New Salem, Kuzey Dakota)", + "America\/Ojinaga": "Kuzey Amerika Dağ Saati (Ojinaga)", + "America\/Panama": "Kuzey Amerika Doğu Saati (Panama)", + "America\/Pangnirtung": "Kuzey Amerika Doğu Saati (Pangnirtung)", + "America\/Paramaribo": "Surinam Saati (Paramaribo)", + "America\/Phoenix": "Kuzey Amerika Dağ Saati (Phoenix)", + "America\/Port-au-Prince": "Kuzey Amerika Doğu Saati (Port-au-Prince)", + "America\/Port_of_Spain": "Atlantik Saati (Port of Spain)", + "America\/Porto_Velho": "Amazon Saati (Porto Velho)", + "America\/Puerto_Rico": "Atlantik Saati (Porto Riko)", + "America\/Punta_Arenas": "Şili Saati (Punta Arenas)", + "America\/Rainy_River": "Kuzey Amerika Merkezi Saati (Rainy River)", + "America\/Rankin_Inlet": "Kuzey Amerika Merkezi Saati (Rankin Inlet)", + "America\/Recife": "Brasilia Saati (Recife)", + "America\/Regina": "Kuzey Amerika Merkezi Saati (Regina)", + "America\/Resolute": "Kuzey Amerika Merkezi Saati (Resolute)", + "America\/Rio_Branco": "Acre Saati (Rio Branco)", + "America\/Santa_Isabel": "Kuzeybatı Meksika Saati (Santa Isabel)", + "America\/Santarem": "Brasilia Saati (Santarem)", + "America\/Santiago": "Şili Saati (Santiago)", + "America\/Santo_Domingo": "Atlantik Saati (Santo Domingo)", + "America\/Sao_Paulo": "Brasilia Saati (Sao Paulo)", + "America\/Scoresbysund": "Doğu Grönland Saati (Ittoqqortoormiit)", + "America\/Sitka": "Alaska Saati (Sitka)", + "America\/St_Barthelemy": "Atlantik Saati (Saint Barthélemy)", + "America\/St_Johns": "Newfoundland Saati (St. John’s)", + "America\/St_Kitts": "Atlantik Saati (St. Kitts)", + "America\/St_Lucia": "Atlantik Saati (St. Lucia)", + "America\/St_Thomas": "Atlantik Saati (St. Thomas)", + "America\/St_Vincent": "Atlantik Saati (St. Vincent)", + "America\/Swift_Current": "Kuzey Amerika Merkezi Saati (Swift Current)", + "America\/Tegucigalpa": "Kuzey Amerika Merkezi Saati (Tegucigalpa)", + "America\/Thule": "Atlantik Saati (Thule)", + "America\/Thunder_Bay": "Kuzey Amerika Doğu Saati (Thunder Bay)", + "America\/Tijuana": "Kuzey Amerika Pasifik Saati (Tijuana)", + "America\/Toronto": "Kuzey Amerika Doğu Saati (Toronto)", + "America\/Tortola": "Atlantik Saati (Tortola)", + "America\/Vancouver": "Kuzey Amerika Pasifik Saati (Vancouver)", + "America\/Whitehorse": "Kuzey Amerika Pasifik Saati (Whitehorse)", + "America\/Winnipeg": "Kuzey Amerika Merkezi Saati (Winnipeg)", + "America\/Yakutat": "Alaska Saati (Yakutat)", + "America\/Yellowknife": "Kuzey Amerika Dağ Saati (Yellowknife)", + "Antarctica\/Casey": "Batı Avustralya Saati (Casey)", + "Antarctica\/Davis": "Davis Saati (Davis)", + "Antarctica\/DumontDUrville": "Dumont-d’Urville Saati (Dumont d’Urville)", + "Antarctica\/Macquarie": "Macquarie Adası Saati (Macquarie)", + "Antarctica\/Mawson": "Mawson Saati (Mawson)", + "Antarctica\/McMurdo": "Yeni Zelanda Saati (McMurdo)", + "Antarctica\/Palmer": "Şili Saati (Palmer)", + "Antarctica\/Rothera": "Rothera Saati (Rothera)", + "Antarctica\/Syowa": "Showa Saati (Showa)", + "Antarctica\/Troll": "Greenwich Ortalama Saati (Troll)", + "Antarctica\/Vostok": "Vostok Saati (Vostok)", + "Arctic\/Longyearbyen": "Orta Avrupa Saati (Longyearbyen)", + "Asia\/Aden": "Arabistan Saati (Aden)", + "Asia\/Almaty": "Doğu Kazakistan Saati (Almatı)", + "Asia\/Amman": "Doğu Avrupa Saati (Amman)", + "Asia\/Anadyr": "Anadyr Saati (Anadır)", + "Asia\/Aqtau": "Batı Kazakistan Saati (Aktav)", + "Asia\/Aqtobe": "Batı Kazakistan Saati (Aktöbe)", + "Asia\/Ashgabat": "Türkmenistan Saati (Aşkabat)", + "Asia\/Atyrau": "Batı Kazakistan Saati (Atırav)", + "Asia\/Baghdad": "Arabistan Saati (Bağdat)", + "Asia\/Bahrain": "Arabistan Saati (Bahreyn)", + "Asia\/Baku": "Azerbaycan Saati (Bakü)", + "Asia\/Bangkok": "Hindiçin Saati (Bangkok)", + "Asia\/Beirut": "Doğu Avrupa Saati (Beyrut)", + "Asia\/Bishkek": "Kırgızistan Saati (Bişkek)", + "Asia\/Brunei": "Brunei Darü’s-Selam Saati (Brunei)", + "Asia\/Calcutta": "Hindistan Standart Saati (Kalküta)", + "Asia\/Chita": "Yakutsk Saati (Çita)", + "Asia\/Choibalsan": "Çoybalsan Saati (Çoybalsan)", + "Asia\/Colombo": "Hindistan Standart Saati (Kolombo)", + "Asia\/Damascus": "Doğu Avrupa Saati (Şam)", + "Asia\/Dhaka": "Bangladeş Saati (Dakka)", + "Asia\/Dili": "Doğu Timor Saati (Dili)", + "Asia\/Dubai": "Körfez Saati (Dubai)", + "Asia\/Dushanbe": "Tacikistan Saati (Duşanbe)", + "Asia\/Famagusta": "Doğu Avrupa Saati (Gazimağusa)", + "Asia\/Gaza": "Doğu Avrupa Saati (Gazze)", + "Asia\/Hebron": "Doğu Avrupa Saati (El Halil)", + "Asia\/Hong_Kong": "Hong Kong Saati (Hong Kong)", + "Asia\/Hovd": "Hovd Saati (Hovd)", + "Asia\/Irkutsk": "İrkutsk Saati (İrkutsk)", + "Asia\/Jakarta": "Batı Endonezya Saati (Cakarta)", + "Asia\/Jayapura": "Doğu Endonezya Saati (Jayapura)", + "Asia\/Jerusalem": "İsrail Saati (Kudüs)", + "Asia\/Kabul": "Afganistan Saati (Kabil)", + "Asia\/Kamchatka": "Petropavlovsk-Kamçatski Saati (Kamçatka)", + "Asia\/Karachi": "Pakistan Saati (Karaçi)", + "Asia\/Katmandu": "Nepal Saati (Katmandu)", + "Asia\/Khandyga": "Yakutsk Saati (Handiga)", + "Asia\/Krasnoyarsk": "Krasnoyarsk Saati (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malezya Saati (Kuala Lumpur)", + "Asia\/Kuching": "Malezya Saati (Kuçing)", + "Asia\/Kuwait": "Arabistan Saati (Kuveyt)", + "Asia\/Macau": "Çin Saati (Makao)", + "Asia\/Magadan": "Magadan Saati (Magadan)", + "Asia\/Makassar": "Orta Endonezya Saati (Makassar)", + "Asia\/Manila": "Filipinler Saati (Manila)", + "Asia\/Muscat": "Körfez Saati (Maskat)", + "Asia\/Nicosia": "Doğu Avrupa Saati (Lefkoşa)", + "Asia\/Novokuznetsk": "Krasnoyarsk Saati (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk Saati (Novosibirsk)", + "Asia\/Omsk": "Omsk Saati (Omsk)", + "Asia\/Oral": "Batı Kazakistan Saati (Oral)", + "Asia\/Phnom_Penh": "Hindiçin Saati (Phnom Penh)", + "Asia\/Pontianak": "Batı Endonezya Saati (Pontianak)", + "Asia\/Pyongyang": "Kore Saati (Pyongyang)", + "Asia\/Qatar": "Arabistan Saati (Katar)", + "Asia\/Qostanay": "Doğu Kazakistan Saati (Qostanay)", + "Asia\/Qyzylorda": "Batı Kazakistan Saati (Kızılorda)", + "Asia\/Rangoon": "Myanmar Saati (Yangon)", + "Asia\/Riyadh": "Arabistan Saati (Riyad)", + "Asia\/Saigon": "Hindiçin Saati (Ho Chi Minh Kenti)", + "Asia\/Sakhalin": "Sahalin Saati (Sahalin)", + "Asia\/Samarkand": "Özbekistan Saati (Semerkand)", + "Asia\/Seoul": "Kore Saati (Seul)", + "Asia\/Shanghai": "Çin Saati (Şanghay)", + "Asia\/Singapore": "Singapur Standart Saati (Singapur)", + "Asia\/Srednekolymsk": "Magadan Saati (Srednekolymsk)", + "Asia\/Taipei": "Taipei Saati (Taipei)", + "Asia\/Tashkent": "Özbekistan Saati (Taşkent)", + "Asia\/Tbilisi": "Gürcistan Saati (Tiflis)", + "Asia\/Tehran": "İran Saati (Tahran)", + "Asia\/Thimphu": "Butan Saati (Thimphu)", + "Asia\/Tokyo": "Japonya Saati (Tokyo)", + "Asia\/Ulaanbaatar": "Ulan Batur Saati (Ulan Batur)", + "Asia\/Ust-Nera": "Vladivostok Saati (Ust-Nera)", + "Asia\/Vientiane": "Hindiçin Saati (Vientiane)", + "Asia\/Vladivostok": "Vladivostok Saati (Vladivostok)", + "Asia\/Yakutsk": "Yakutsk Saati (Yakutsk)", + "Asia\/Yekaterinburg": "Yekaterinburg Saati (Yekaterinburg)", + "Asia\/Yerevan": "Ermenistan Saati (Erivan)", + "Atlantic\/Azores": "Azorlar Saati (Azor Adaları)", + "Atlantic\/Bermuda": "Atlantik Saati (Bermuda)", + "Atlantic\/Canary": "Batı Avrupa Saati (Kanarya Adaları)", + "Atlantic\/Cape_Verde": "Cape Verde Saati (Cape Verde)", + "Atlantic\/Faeroe": "Batı Avrupa Saati (Faroe)", + "Atlantic\/Madeira": "Batı Avrupa Saati (Madeira Adaları)", + "Atlantic\/Reykjavik": "Greenwich Ortalama Saati (Reykjavik)", + "Atlantic\/South_Georgia": "Güney Georgia Saati (Güney Georgia)", + "Atlantic\/St_Helena": "Greenwich Ortalama Saati (St. Helena)", + "Atlantic\/Stanley": "Falkland Adaları Saati (Stanley)", + "Australia\/Adelaide": "Orta Avustralya Saati (Adelaide)", + "Australia\/Brisbane": "Doğu Avustralya Saati (Brisbane)", + "Australia\/Broken_Hill": "Orta Avustralya Saati (Broken Hill)", + "Australia\/Currie": "Doğu Avustralya Saati (Currie)", + "Australia\/Darwin": "Orta Avustralya Saati (Darwin)", + "Australia\/Eucla": "İç Batı Avustralya Saati (Eucla)", + "Australia\/Hobart": "Doğu Avustralya Saati (Hobart)", + "Australia\/Lindeman": "Doğu Avustralya Saati (Lindeman)", + "Australia\/Lord_Howe": "Lord Howe Saati (Lord Howe)", + "Australia\/Melbourne": "Doğu Avustralya Saati (Melbourne)", + "Australia\/Perth": "Batı Avustralya Saati (Perth)", + "Australia\/Sydney": "Doğu Avustralya Saati (Sidney)", + "CST6CDT": "Kuzey Amerika Merkezi Saati", + "EST5EDT": "Kuzey Amerika Doğu Saati", + "Etc\/GMT": "Greenwich Ortalama Saati", + "Etc\/UTC": "Eş Güdümlü Evrensel Zaman", + "Europe\/Amsterdam": "Orta Avrupa Saati (Amsterdam)", + "Europe\/Andorra": "Orta Avrupa Saati (Andorra)", + "Europe\/Astrakhan": "Moskova Saati (Astrahan)", + "Europe\/Athens": "Doğu Avrupa Saati (Atina)", + "Europe\/Belgrade": "Orta Avrupa Saati (Belgrad)", + "Europe\/Berlin": "Orta Avrupa Saati (Berlin)", + "Europe\/Bratislava": "Orta Avrupa Saati (Bratislava)", + "Europe\/Brussels": "Orta Avrupa Saati (Brüksel)", + "Europe\/Bucharest": "Doğu Avrupa Saati (Bükreş)", + "Europe\/Budapest": "Orta Avrupa Saati (Budapeşte)", + "Europe\/Busingen": "Orta Avrupa Saati (Büsingen)", + "Europe\/Chisinau": "Doğu Avrupa Saati (Kişinev)", + "Europe\/Copenhagen": "Orta Avrupa Saati (Kopenhag)", + "Europe\/Dublin": "Greenwich Ortalama Saati (Dublin)", + "Europe\/Gibraltar": "Orta Avrupa Saati (Cebelitarık)", + "Europe\/Guernsey": "Greenwich Ortalama Saati (Guernsey)", + "Europe\/Helsinki": "Doğu Avrupa Saati (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Ortalama Saati (Man Adası)", + "Europe\/Jersey": "Greenwich Ortalama Saati (Jersey)", + "Europe\/Kaliningrad": "Doğu Avrupa Saati (Kaliningrad)", + "Europe\/Kiev": "Doğu Avrupa Saati (Kiev)", + "Europe\/Lisbon": "Batı Avrupa Saati (Lizbon)", + "Europe\/Ljubljana": "Orta Avrupa Saati (Ljubljana)", + "Europe\/London": "Greenwich Ortalama Saati (Londra)", + "Europe\/Luxembourg": "Orta Avrupa Saati (Lüksemburg)", + "Europe\/Madrid": "Orta Avrupa Saati (Madrid)", + "Europe\/Malta": "Orta Avrupa Saati (Malta)", + "Europe\/Mariehamn": "Doğu Avrupa Saati (Mariehamn)", + "Europe\/Minsk": "Moskova Saati (Minsk)", + "Europe\/Monaco": "Orta Avrupa Saati (Monako)", + "Europe\/Moscow": "Moskova Saati (Moskova)", + "Europe\/Oslo": "Orta Avrupa Saati (Oslo)", + "Europe\/Paris": "Orta Avrupa Saati (Paris)", + "Europe\/Podgorica": "Orta Avrupa Saati (Podgorica)", + "Europe\/Prague": "Orta Avrupa Saati (Prag)", + "Europe\/Riga": "Doğu Avrupa Saati (Riga)", + "Europe\/Rome": "Orta Avrupa Saati (Roma)", + "Europe\/Samara": "Samara Saati (Samara)", + "Europe\/San_Marino": "Orta Avrupa Saati (San Marino)", + "Europe\/Sarajevo": "Orta Avrupa Saati (Saraybosna)", + "Europe\/Saratov": "Moskova Saati (Saratov)", + "Europe\/Simferopol": "Moskova Saati (Simferopol)", + "Europe\/Skopje": "Orta Avrupa Saati (Üsküp)", + "Europe\/Sofia": "Doğu Avrupa Saati (Sofya)", + "Europe\/Stockholm": "Orta Avrupa Saati (Stokholm)", + "Europe\/Tallinn": "Doğu Avrupa Saati (Tallinn)", + "Europe\/Tirane": "Orta Avrupa Saati (Tiran)", + "Europe\/Ulyanovsk": "Moskova Saati (Ulyanovsk)", + "Europe\/Uzhgorod": "Doğu Avrupa Saati (Ujgorod)", + "Europe\/Vaduz": "Orta Avrupa Saati (Vaduz)", + "Europe\/Vatican": "Orta Avrupa Saati (Vatikan)", + "Europe\/Vienna": "Orta Avrupa Saati (Viyana)", + "Europe\/Vilnius": "Doğu Avrupa Saati (Vilnius)", + "Europe\/Volgograd": "Volgograd Saati (Volgograd)", + "Europe\/Warsaw": "Orta Avrupa Saati (Varşova)", + "Europe\/Zagreb": "Orta Avrupa Saati (Zagreb)", + "Europe\/Zaporozhye": "Doğu Avrupa Saati (Zaporojye)", + "Europe\/Zurich": "Orta Avrupa Saati (Zürih)", + "Indian\/Antananarivo": "Doğu Afrika Saati (Antananarivo)", + "Indian\/Chagos": "Hint Okyanusu Saati (Chagos)", + "Indian\/Christmas": "Christmas Adası Saati (Christmas)", + "Indian\/Cocos": "Cocos Adaları Saati (Cocos)", + "Indian\/Comoro": "Doğu Afrika Saati (Komor)", + "Indian\/Kerguelen": "Fransız Güney ve Antarktika Saati (Kerguelen)", + "Indian\/Mahe": "Seyşeller Saati (Mahe)", + "Indian\/Maldives": "Maldivler Saati (Maldivler)", + "Indian\/Mauritius": "Mauritius Saati (Mauritius)", + "Indian\/Mayotte": "Doğu Afrika Saati (Mayotte)", + "Indian\/Reunion": "Reunion Saati (Reunion)", + "MST7MDT": "Kuzey Amerika Dağ Saati", + "PST8PDT": "Kuzey Amerika Pasifik Saati", + "Pacific\/Apia": "Apia Saati (Apia)", + "Pacific\/Auckland": "Yeni Zelanda Saati (Auckland)", + "Pacific\/Bougainville": "Papua Yeni Gine Saati (Bougainville)", + "Pacific\/Chatham": "Chatham Saati (Chatham)", + "Pacific\/Easter": "Paskalya Adası Saati (Paskalya Adası)", + "Pacific\/Efate": "Vanuatu Saati (Efate)", + "Pacific\/Enderbury": "Phoenix Adaları Saati (Enderbury)", + "Pacific\/Fakaofo": "Tokelau Saati (Fakaofo)", + "Pacific\/Fiji": "Fiji Saati (Fiji)", + "Pacific\/Funafuti": "Tuvalu Saati (Funafuti)", + "Pacific\/Galapagos": "Galapagos Saati (Galapagos)", + "Pacific\/Gambier": "Gambier Saati (Gambier)", + "Pacific\/Guadalcanal": "Solomon Adaları Saati (Guadalcanal)", + "Pacific\/Guam": "Chamorro Saati (Guam)", + "Pacific\/Honolulu": "Hawaii-Aleut Saati (Honolulu)", + "Pacific\/Johnston": "Hawaii-Aleut Saati (Johnston)", + "Pacific\/Kiritimati": "Line Adaları Saati (Kiritimati)", + "Pacific\/Kosrae": "Kosrae Saati (Kosrae)", + "Pacific\/Kwajalein": "Marshall Adaları Saati (Kwajalein)", + "Pacific\/Majuro": "Marshall Adaları Saati (Majuro)", + "Pacific\/Marquesas": "Markiz Adaları Saati (Markiz Adaları)", + "Pacific\/Midway": "Samoa Saati (Midway)", + "Pacific\/Nauru": "Nauru Saati (Nauru)", + "Pacific\/Niue": "Niue Saati (Niue)", + "Pacific\/Norfolk": "Norfolk Adası Saati (Norfolk)", + "Pacific\/Noumea": "Yeni Kaledonya Saati (Noumea)", + "Pacific\/Pago_Pago": "Samoa Saati (Pago Pago)", + "Pacific\/Palau": "Palau Saati (Palau)", + "Pacific\/Pitcairn": "Pitcairn Saati (Pitcairn)", + "Pacific\/Ponape": "Ponape Saati (Pohnpei)", + "Pacific\/Port_Moresby": "Papua Yeni Gine Saati (Port Moresby)", + "Pacific\/Rarotonga": "Cook Adaları Saati (Rarotonga)", + "Pacific\/Saipan": "Chamorro Saati (Saipan)", + "Pacific\/Tahiti": "Tahiti Saati (Tahiti)", + "Pacific\/Tarawa": "Gilbert Adaları Saati (Tarawa)", + "Pacific\/Tongatapu": "Tonga Saati (Tongatapu)", + "Pacific\/Truk": "Chuuk Saati (Chuuk)", + "Pacific\/Wake": "Wake Adası Saati (Wake)", + "Pacific\/Wallis": "Wallis ve Futuna Saati (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/tt.json b/src/Symfony/Component/Intl/Resources/data/timezones/tt.json new file mode 100644 index 0000000000000..66cceaa23a9a5 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/tt.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.47.85", + "Names": { + "Africa\/Abidjan": "Гринвич уртача вакыты (Abidjan)", + "Africa\/Accra": "Гринвич уртача вакыты (Accra)", + "Africa\/Algiers": "Үзәк Европа вакыты (Algiers)", + "Africa\/Bamako": "Гринвич уртача вакыты (Bamako)", + "Africa\/Banjul": "Гринвич уртача вакыты (Banjul)", + "Africa\/Bissau": "Гринвич уртача вакыты (Bissau)", + "Africa\/Cairo": "Көнчыгыш Европа вакыты (Cairo)", + "Africa\/Casablanca": "Көнбатыш Европа вакыты (Casablanca)", + "Africa\/Ceuta": "Үзәк Европа вакыты (Ceuta)", + "Africa\/Conakry": "Гринвич уртача вакыты (Conakry)", + "Africa\/Dakar": "Гринвич уртача вакыты (Dakar)", + "Africa\/El_Aaiun": "Көнбатыш Европа вакыты (El Aaiun)", + "Africa\/Freetown": "Гринвич уртача вакыты (Freetown)", + "Africa\/Lome": "Гринвич уртача вакыты (Lome)", + "Africa\/Monrovia": "Гринвич уртача вакыты (Monrovia)", + "Africa\/Nouakchott": "Гринвич уртача вакыты (Nouakchott)", + "Africa\/Ouagadougou": "Гринвич уртача вакыты (Ouagadougou)", + "Africa\/Sao_Tome": "Гринвич уртача вакыты (Sao Tome)", + "Africa\/Tripoli": "Көнчыгыш Европа вакыты (Tripoli)", + "Africa\/Tunis": "Үзәк Европа вакыты (Tunis)", + "America\/Anguilla": "Төньяк Америка атлантик вакыты (Anguilla)", + "America\/Antigua": "Төньяк Америка атлантик вакыты (Antigua)", + "America\/Aruba": "Төньяк Америка атлантик вакыты (Aruba)", + "America\/Bahia_Banderas": "Төньяк Америка үзәк вакыты (Bahia Banderas)", + "America\/Barbados": "Төньяк Америка атлантик вакыты (Barbados)", + "America\/Belize": "Төньяк Америка үзәк вакыты (Belize)", + "America\/Blanc-Sablon": "Төньяк Америка атлантик вакыты (Blanc-Sablon)", + "America\/Boise": "Төньяк Америка тау вакыты (Boise)", + "America\/Cambridge_Bay": "Төньяк Америка тау вакыты (Cambridge Bay)", + "America\/Cancun": "Төньяк Америка көнчыгыш вакыты (Cancun)", + "America\/Cayman": "Төньяк Америка көнчыгыш вакыты (Cayman)", + "America\/Chicago": "Төньяк Америка үзәк вакыты (Chicago)", + "America\/Coral_Harbour": "Төньяк Америка көнчыгыш вакыты (Atikokan)", + "America\/Costa_Rica": "Төньяк Америка үзәк вакыты (Costa Rica)", + "America\/Creston": "Төньяк Америка тау вакыты (Creston)", + "America\/Curacao": "Төньяк Америка атлантик вакыты (Curacao)", + "America\/Danmarkshavn": "Гринвич уртача вакыты (Danmarkshavn)", + "America\/Dawson": "Төньяк Америка Тын океан вакыты (Dawson)", + "America\/Dawson_Creek": "Төньяк Америка тау вакыты (Dawson Creek)", + "America\/Denver": "Төньяк Америка тау вакыты (Denver)", + "America\/Detroit": "Төньяк Америка көнчыгыш вакыты (Detroit)", + "America\/Dominica": "Төньяк Америка атлантик вакыты (Dominica)", + "America\/Edmonton": "Төньяк Америка тау вакыты (Edmonton)", + "America\/El_Salvador": "Төньяк Америка үзәк вакыты (El Salvador)", + "America\/Fort_Nelson": "Төньяк Америка тау вакыты (Fort Nelson)", + "America\/Glace_Bay": "Төньяк Америка атлантик вакыты (Glace Bay)", + "America\/Goose_Bay": "Төньяк Америка атлантик вакыты (Goose Bay)", + "America\/Grand_Turk": "Төньяк Америка көнчыгыш вакыты (Grand Turk)", + "America\/Grenada": "Төньяк Америка атлантик вакыты (Grenada)", + "America\/Guadeloupe": "Төньяк Америка атлантик вакыты (Guadeloupe)", + "America\/Guatemala": "Төньяк Америка үзәк вакыты (Guatemala)", + "America\/Halifax": "Төньяк Америка атлантик вакыты (Halifax)", + "America\/Indiana\/Knox": "Төньяк Америка үзәк вакыты (Knox, Indiana)", + "America\/Indiana\/Marengo": "Төньяк Америка көнчыгыш вакыты (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Төньяк Америка көнчыгыш вакыты (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Төньяк Америка үзәк вакыты (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Төньяк Америка көнчыгыш вакыты (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Төньяк Америка көнчыгыш вакыты (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Төньяк Америка көнчыгыш вакыты (Winamac, Indiana)", + "America\/Indianapolis": "Төньяк Америка көнчыгыш вакыты (Indianapolis)", + "America\/Inuvik": "Төньяк Америка тау вакыты (Inuvik)", + "America\/Iqaluit": "Төньяк Америка көнчыгыш вакыты (Iqaluit)", + "America\/Jamaica": "Төньяк Америка көнчыгыш вакыты (Jamaica)", + "America\/Kentucky\/Monticello": "Төньяк Америка көнчыгыш вакыты (Monticello, Kentucky)", + "America\/Kralendijk": "Төньяк Америка атлантик вакыты (Kralendijk)", + "America\/Los_Angeles": "Төньяк Америка Тын океан вакыты (Los Angeles)", + "America\/Louisville": "Төньяк Америка көнчыгыш вакыты (Louisville)", + "America\/Lower_Princes": "Төньяк Америка атлантик вакыты (Lower Prince’s Quarter)", + "America\/Managua": "Төньяк Америка үзәк вакыты (Managua)", + "America\/Marigot": "Төньяк Америка атлантик вакыты (Marigot)", + "America\/Martinique": "Төньяк Америка атлантик вакыты (Martinique)", + "America\/Matamoros": "Төньяк Америка үзәк вакыты (Matamoros)", + "America\/Menominee": "Төньяк Америка үзәк вакыты (Menominee)", + "America\/Merida": "Төньяк Америка үзәк вакыты (Merida)", + "America\/Mexico_City": "Төньяк Америка үзәк вакыты (Mexico City)", + "America\/Moncton": "Төньяк Америка атлантик вакыты (Moncton)", + "America\/Monterrey": "Төньяк Америка үзәк вакыты (Monterrey)", + "America\/Montserrat": "Төньяк Америка атлантик вакыты (Montserrat)", + "America\/Nassau": "Төньяк Америка көнчыгыш вакыты (Nassau)", + "America\/New_York": "Төньяк Америка көнчыгыш вакыты (New York)", + "America\/Nipigon": "Төньяк Америка көнчыгыш вакыты (Nipigon)", + "America\/North_Dakota\/Beulah": "Төньяк Америка үзәк вакыты (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Төньяк Америка үзәк вакыты (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Төньяк Америка үзәк вакыты (New Salem, North Dakota)", + "America\/Ojinaga": "Төньяк Америка тау вакыты (Ojinaga)", + "America\/Panama": "Төньяк Америка көнчыгыш вакыты (Panama)", + "America\/Pangnirtung": "Төньяк Америка көнчыгыш вакыты (Pangnirtung)", + "America\/Phoenix": "Төньяк Америка тау вакыты (Phoenix)", + "America\/Port-au-Prince": "Төньяк Америка көнчыгыш вакыты (Port-au-Prince)", + "America\/Port_of_Spain": "Төньяк Америка атлантик вакыты (Port of Spain)", + "America\/Puerto_Rico": "Төньяк Америка атлантик вакыты (Puerto Rico)", + "America\/Rainy_River": "Төньяк Америка үзәк вакыты (Rainy River)", + "America\/Rankin_Inlet": "Төньяк Америка үзәк вакыты (Rankin Inlet)", + "America\/Regina": "Төньяк Америка үзәк вакыты (Regina)", + "America\/Resolute": "Төньяк Америка үзәк вакыты (Resolute)", + "America\/Santo_Domingo": "Төньяк Америка атлантик вакыты (Santo Domingo)", + "America\/St_Barthelemy": "Төньяк Америка атлантик вакыты (St. Barthelemy)", + "America\/St_Kitts": "Төньяк Америка атлантик вакыты (St. Kitts)", + "America\/St_Lucia": "Төньяк Америка атлантик вакыты (St. Lucia)", + "America\/St_Thomas": "Төньяк Америка атлантик вакыты (St. Thomas)", + "America\/St_Vincent": "Төньяк Америка атлантик вакыты (St. Vincent)", + "America\/Swift_Current": "Төньяк Америка үзәк вакыты (Swift Current)", + "America\/Tegucigalpa": "Төньяк Америка үзәк вакыты (Tegucigalpa)", + "America\/Thule": "Төньяк Америка атлантик вакыты (Thule)", + "America\/Thunder_Bay": "Төньяк Америка көнчыгыш вакыты (Thunder Bay)", + "America\/Tijuana": "Төньяк Америка Тын океан вакыты (Tijuana)", + "America\/Toronto": "Төньяк Америка көнчыгыш вакыты (Toronto)", + "America\/Tortola": "Төньяк Америка атлантик вакыты (Tortola)", + "America\/Vancouver": "Төньяк Америка Тын океан вакыты (Vancouver)", + "America\/Whitehorse": "Төньяк Америка Тын океан вакыты (Whitehorse)", + "America\/Winnipeg": "Төньяк Америка үзәк вакыты (Winnipeg)", + "America\/Yellowknife": "Төньяк Америка тау вакыты (Yellowknife)", + "Antarctica\/Troll": "Гринвич уртача вакыты (Troll)", + "Arctic\/Longyearbyen": "Үзәк Европа вакыты (Longyearbyen)", + "Asia\/Amman": "Көнчыгыш Европа вакыты (Amman)", + "Asia\/Beirut": "Көнчыгыш Европа вакыты (Beirut)", + "Asia\/Damascus": "Көнчыгыш Европа вакыты (Damascus)", + "Asia\/Famagusta": "Көнчыгыш Европа вакыты (Famagusta)", + "Asia\/Gaza": "Көнчыгыш Европа вакыты (Gaza)", + "Asia\/Hebron": "Көнчыгыш Европа вакыты (Hebron)", + "Asia\/Nicosia": "Көнчыгыш Европа вакыты (Nicosia)", + "Atlantic\/Bermuda": "Төньяк Америка атлантик вакыты (Bermuda)", + "Atlantic\/Canary": "Көнбатыш Европа вакыты (Canary)", + "Atlantic\/Faeroe": "Көнбатыш Европа вакыты (Faroe)", + "Atlantic\/Madeira": "Көнбатыш Европа вакыты (Madeira)", + "Atlantic\/Reykjavik": "Гринвич уртача вакыты (Reykjavik)", + "Atlantic\/St_Helena": "Гринвич уртача вакыты (St. Helena)", + "CST6CDT": "Төньяк Америка үзәк вакыты", + "EST5EDT": "Төньяк Америка көнчыгыш вакыты", + "Etc\/GMT": "Гринвич уртача вакыты", + "Etc\/UTC": "Бөтендөнья килештерелгән вакыты", + "Europe\/Amsterdam": "Үзәк Европа вакыты (Amsterdam)", + "Europe\/Andorra": "Үзәк Европа вакыты (Andorra)", + "Europe\/Athens": "Көнчыгыш Европа вакыты (Athens)", + "Europe\/Belgrade": "Үзәк Европа вакыты (Belgrade)", + "Europe\/Berlin": "Үзәк Европа вакыты (Berlin)", + "Europe\/Bratislava": "Үзәк Европа вакыты (Bratislava)", + "Europe\/Brussels": "Үзәк Европа вакыты (Brussels)", + "Europe\/Bucharest": "Көнчыгыш Европа вакыты (Bucharest)", + "Europe\/Budapest": "Үзәк Европа вакыты (Budapest)", + "Europe\/Busingen": "Үзәк Европа вакыты (Busingen)", + "Europe\/Chisinau": "Көнчыгыш Европа вакыты (Chisinau)", + "Europe\/Copenhagen": "Үзәк Европа вакыты (Copenhagen)", + "Europe\/Dublin": "Гринвич уртача вакыты (Dublin)", + "Europe\/Gibraltar": "Үзәк Европа вакыты (Gibraltar)", + "Europe\/Guernsey": "Гринвич уртача вакыты (Guernsey)", + "Europe\/Helsinki": "Көнчыгыш Европа вакыты (Helsinki)", + "Europe\/Isle_of_Man": "Гринвич уртача вакыты (Isle of Man)", + "Europe\/Jersey": "Гринвич уртача вакыты (Jersey)", + "Europe\/Kaliningrad": "Көнчыгыш Европа вакыты (Kaliningrad)", + "Europe\/Kiev": "Көнчыгыш Европа вакыты (Kiev)", + "Europe\/Lisbon": "Көнбатыш Европа вакыты (Lisbon)", + "Europe\/Ljubljana": "Үзәк Европа вакыты (Ljubljana)", + "Europe\/London": "Гринвич уртача вакыты (London)", + "Europe\/Luxembourg": "Үзәк Европа вакыты (Luxembourg)", + "Europe\/Madrid": "Үзәк Европа вакыты (Madrid)", + "Europe\/Malta": "Үзәк Европа вакыты (Malta)", + "Europe\/Mariehamn": "Көнчыгыш Европа вакыты (Mariehamn)", + "Europe\/Monaco": "Үзәк Европа вакыты (Monaco)", + "Europe\/Oslo": "Үзәк Европа вакыты (Oslo)", + "Europe\/Paris": "Үзәк Европа вакыты (Paris)", + "Europe\/Podgorica": "Үзәк Европа вакыты (Podgorica)", + "Europe\/Prague": "Үзәк Европа вакыты (Prague)", + "Europe\/Riga": "Көнчыгыш Европа вакыты (Riga)", + "Europe\/Rome": "Үзәк Европа вакыты (Rome)", + "Europe\/San_Marino": "Үзәк Европа вакыты (San Marino)", + "Europe\/Sarajevo": "Үзәк Европа вакыты (Sarajevo)", + "Europe\/Skopje": "Үзәк Европа вакыты (Skopje)", + "Europe\/Sofia": "Көнчыгыш Европа вакыты (Sofia)", + "Europe\/Stockholm": "Үзәк Европа вакыты (Stockholm)", + "Europe\/Tallinn": "Көнчыгыш Европа вакыты (Tallinn)", + "Europe\/Tirane": "Үзәк Европа вакыты (Tirane)", + "Europe\/Uzhgorod": "Көнчыгыш Европа вакыты (Uzhgorod)", + "Europe\/Vaduz": "Үзәк Европа вакыты (Vaduz)", + "Europe\/Vatican": "Үзәк Европа вакыты (Vatican)", + "Europe\/Vienna": "Үзәк Европа вакыты (Vienna)", + "Europe\/Vilnius": "Көнчыгыш Европа вакыты (Vilnius)", + "Europe\/Warsaw": "Үзәк Европа вакыты (Warsaw)", + "Europe\/Zagreb": "Үзәк Европа вакыты (Zagreb)", + "Europe\/Zaporozhye": "Көнчыгыш Европа вакыты (Zaporozhye)", + "Europe\/Zurich": "Үзәк Европа вакыты (Zurich)", + "MST7MDT": "Төньяк Америка тау вакыты", + "PST8PDT": "Төньяк Америка Тын океан вакыты" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ug.json b/src/Symfony/Component/Intl/Resources/data/timezones/ug.json new file mode 100644 index 0000000000000..a6e26d8d4b2da --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ug.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.47.82", + "Names": { + "Africa\/Abidjan": "گىرىنۋىچ ۋاقتى (Abidjan)", + "Africa\/Accra": "گىرىنۋىچ ۋاقتى (Accra)", + "Africa\/Addis_Ababa": "شەرقىي ئافرىقا ۋاقتى (Addis Ababa)", + "Africa\/Algiers": "ئوتتۇرا ياۋروپا ۋاقتى (Algiers)", + "Africa\/Asmera": "شەرقىي ئافرىقا ۋاقتى (Asmara)", + "Africa\/Bamako": "گىرىنۋىچ ۋاقتى (Bamako)", + "Africa\/Bangui": "غەربىي ئافرىقا ۋاقتى (Bangui)", + "Africa\/Banjul": "گىرىنۋىچ ۋاقتى (Banjul)", + "Africa\/Bissau": "گىرىنۋىچ ۋاقتى (Bissau)", + "Africa\/Blantyre": "ئوتتۇرا ئافرىقا ۋاقتى (Blantyre)", + "Africa\/Brazzaville": "غەربىي ئافرىقا ۋاقتى (Brazzaville)", + "Africa\/Bujumbura": "ئوتتۇرا ئافرىقا ۋاقتى (Bujumbura)", + "Africa\/Cairo": "شەرقىي ياۋروپا ۋاقتى (Cairo)", + "Africa\/Casablanca": "غەربىي ياۋروپا ۋاقتى (Casablanca)", + "Africa\/Ceuta": "ئوتتۇرا ياۋروپا ۋاقتى (Ceuta)", + "Africa\/Conakry": "گىرىنۋىچ ۋاقتى (Conakry)", + "Africa\/Dakar": "گىرىنۋىچ ۋاقتى (Dakar)", + "Africa\/Dar_es_Salaam": "شەرقىي ئافرىقا ۋاقتى (Dar es Salaam)", + "Africa\/Djibouti": "شەرقىي ئافرىقا ۋاقتى (Djibouti)", + "Africa\/Douala": "غەربىي ئافرىقا ۋاقتى (Douala)", + "Africa\/El_Aaiun": "غەربىي ياۋروپا ۋاقتى (El Aaiun)", + "Africa\/Freetown": "گىرىنۋىچ ۋاقتى (Freetown)", + "Africa\/Gaborone": "ئوتتۇرا ئافرىقا ۋاقتى (Gaborone)", + "Africa\/Harare": "ئوتتۇرا ئافرىقا ۋاقتى (Harare)", + "Africa\/Johannesburg": "جەنۇبىي ئافرىقا ئۆلچەملىك ۋاقتى (Johannesburg)", + "Africa\/Juba": "شەرقىي ئافرىقا ۋاقتى (Juba)", + "Africa\/Kampala": "شەرقىي ئافرىقا ۋاقتى (Kampala)", + "Africa\/Khartoum": "ئوتتۇرا ئافرىقا ۋاقتى (Khartoum)", + "Africa\/Kigali": "ئوتتۇرا ئافرىقا ۋاقتى (Kigali)", + "Africa\/Kinshasa": "غەربىي ئافرىقا ۋاقتى (Kinshasa)", + "Africa\/Lagos": "غەربىي ئافرىقا ۋاقتى (Lagos)", + "Africa\/Libreville": "غەربىي ئافرىقا ۋاقتى (Libreville)", + "Africa\/Lome": "گىرىنۋىچ ۋاقتى (Lome)", + "Africa\/Luanda": "غەربىي ئافرىقا ۋاقتى (Luanda)", + "Africa\/Lubumbashi": "ئوتتۇرا ئافرىقا ۋاقتى (Lubumbashi)", + "Africa\/Lusaka": "ئوتتۇرا ئافرىقا ۋاقتى (Lusaka)", + "Africa\/Malabo": "غەربىي ئافرىقا ۋاقتى (Malabo)", + "Africa\/Maputo": "ئوتتۇرا ئافرىقا ۋاقتى (Maputo)", + "Africa\/Maseru": "جەنۇبىي ئافرىقا ئۆلچەملىك ۋاقتى (Maseru)", + "Africa\/Mbabane": "جەنۇبىي ئافرىقا ئۆلچەملىك ۋاقتى (Mbabane)", + "Africa\/Mogadishu": "شەرقىي ئافرىقا ۋاقتى (Mogadishu)", + "Africa\/Monrovia": "گىرىنۋىچ ۋاقتى (Monrovia)", + "Africa\/Nairobi": "شەرقىي ئافرىقا ۋاقتى (Nairobi)", + "Africa\/Ndjamena": "غەربىي ئافرىقا ۋاقتى (Ndjamena)", + "Africa\/Niamey": "غەربىي ئافرىقا ۋاقتى (Niamey)", + "Africa\/Nouakchott": "گىرىنۋىچ ۋاقتى (Nouakchott)", + "Africa\/Ouagadougou": "گىرىنۋىچ ۋاقتى (Ouagadougou)", + "Africa\/Porto-Novo": "غەربىي ئافرىقا ۋاقتى (Porto-Novo)", + "Africa\/Sao_Tome": "گىرىنۋىچ ۋاقتى (سان-تومې)", + "Africa\/Tripoli": "شەرقىي ياۋروپا ۋاقتى (Tripoli)", + "Africa\/Tunis": "ئوتتۇرا ياۋروپا ۋاقتى (Tunis)", + "Africa\/Windhoek": "ئوتتۇرا ئافرىقا ۋاقتى (Windhoek)", + "America\/Adak": "ھاۋاي-ئالېيۇت ۋاقتى (Adak)", + "America\/Anchorage": "ئالياسكا ۋاقتى (Anchorage)", + "America\/Anguilla": "ئاتلانتىك ئوكيان ۋاقتى (Anguilla)", + "America\/Antigua": "ئاتلانتىك ئوكيان ۋاقتى (Antigua)", + "America\/Araguaina": "بىرازىلىيە ۋاقتى (Araguaina)", + "America\/Argentina\/La_Rioja": "ئارگېنتىنا ۋاقتى (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "ئارگېنتىنا ۋاقتى (Rio Gallegos)", + "America\/Argentina\/Salta": "ئارگېنتىنا ۋاقتى (Salta)", + "America\/Argentina\/San_Juan": "ئارگېنتىنا ۋاقتى (San Juan)", + "America\/Argentina\/San_Luis": "غەربىي ئارگېنتىنا ۋاقتى (San Luis)", + "America\/Argentina\/Tucuman": "ئارگېنتىنا ۋاقتى (Tucuman)", + "America\/Argentina\/Ushuaia": "ئارگېنتىنا ۋاقتى (Ushuaia)", + "America\/Aruba": "ئاتلانتىك ئوكيان ۋاقتى (Aruba)", + "America\/Asuncion": "پاراگۋاي ۋاقتى (ئاسۇنسىيون)", + "America\/Bahia": "بىرازىلىيە ۋاقتى (Bahia)", + "America\/Bahia_Banderas": "ئوتتۇرا قىسىم ۋاقتى (Bahia Banderas)", + "America\/Barbados": "ئاتلانتىك ئوكيان ۋاقتى (Barbados)", + "America\/Belem": "بىرازىلىيە ۋاقتى (Belem)", + "America\/Belize": "ئوتتۇرا قىسىم ۋاقتى (Belize)", + "America\/Blanc-Sablon": "ئاتلانتىك ئوكيان ۋاقتى (Blanc-Sablon)", + "America\/Boa_Vista": "ئامازون ۋاقتى (Boa Vista)", + "America\/Bogota": "كولومبىيە ۋاقتى (Bogota)", + "America\/Boise": "تاغ ۋاقتى (Boise)", + "America\/Buenos_Aires": "ئارگېنتىنا ۋاقتى (Buenos Aires)", + "America\/Cambridge_Bay": "تاغ ۋاقتى (Cambridge Bay)", + "America\/Campo_Grande": "ئامازون ۋاقتى (Campo Grande)", + "America\/Cancun": "شەرقىي قىسىم ۋاقتى (Cancun)", + "America\/Caracas": "ۋېنېزۇئېلا ۋاقتى (Caracas)", + "America\/Catamarca": "ئارگېنتىنا ۋاقتى (Catamarca)", + "America\/Cayenne": "فىرانسىيەگە قاراشلىق گىۋىيانا ۋاقتى (Cayenne)", + "America\/Cayman": "شەرقىي قىسىم ۋاقتى (Cayman)", + "America\/Chicago": "ئوتتۇرا قىسىم ۋاقتى (Chicago)", + "America\/Chihuahua": "مېكسىكا تىنچ ئوكيان ۋاقتى (Chihuahua)", + "America\/Coral_Harbour": "شەرقىي قىسىم ۋاقتى (Atikokan)", + "America\/Cordoba": "ئارگېنتىنا ۋاقتى (Cordoba)", + "America\/Costa_Rica": "ئوتتۇرا قىسىم ۋاقتى (Costa Rica)", + "America\/Creston": "تاغ ۋاقتى (Creston)", + "America\/Cuiaba": "ئامازون ۋاقتى (Cuiaba)", + "America\/Curacao": "ئاتلانتىك ئوكيان ۋاقتى (كۇراسو)", + "America\/Danmarkshavn": "گىرىنۋىچ ۋاقتى (Danmarkshavn)", + "America\/Dawson": "تىنچ ئوكيان ۋاقتى (Dawson)", + "America\/Dawson_Creek": "تاغ ۋاقتى (Dawson Creek)", + "America\/Denver": "تاغ ۋاقتى (Denver)", + "America\/Detroit": "شەرقىي قىسىم ۋاقتى (Detroit)", + "America\/Dominica": "ئاتلانتىك ئوكيان ۋاقتى (Dominica)", + "America\/Edmonton": "تاغ ۋاقتى (Edmonton)", + "America\/Eirunepe": "ئاكرې ۋاقتى (Eirunepe)", + "America\/El_Salvador": "ئوتتۇرا قىسىم ۋاقتى (El Salvador)", + "America\/Fort_Nelson": "تاغ ۋاقتى (Fort Nelson)", + "America\/Fortaleza": "بىرازىلىيە ۋاقتى (Fortaleza)", + "America\/Glace_Bay": "ئاتلانتىك ئوكيان ۋاقتى (Glace Bay)", + "America\/Godthab": "غەربىي گىرېنلاند ۋاقتى (Nuuk)", + "America\/Goose_Bay": "ئاتلانتىك ئوكيان ۋاقتى (Goose Bay)", + "America\/Grand_Turk": "شەرقىي قىسىم ۋاقتى (Grand Turk)", + "America\/Grenada": "ئاتلانتىك ئوكيان ۋاقتى (Grenada)", + "America\/Guadeloupe": "ئاتلانتىك ئوكيان ۋاقتى (Guadeloupe)", + "America\/Guatemala": "ئوتتۇرا قىسىم ۋاقتى (Guatemala)", + "America\/Guayaquil": "ئېكۋادور ۋاقتى (Guayaquil)", + "America\/Guyana": "گىۋىيانا ۋاقتى (Guyana)", + "America\/Halifax": "ئاتلانتىك ئوكيان ۋاقتى (Halifax)", + "America\/Havana": "كۇبا ۋاقتى (Havana)", + "America\/Hermosillo": "مېكسىكا تىنچ ئوكيان ۋاقتى (Hermosillo)", + "America\/Indiana\/Knox": "ئوتتۇرا قىسىم ۋاقتى (Knox, Indiana)", + "America\/Indiana\/Marengo": "شەرقىي قىسىم ۋاقتى (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "شەرقىي قىسىم ۋاقتى (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "ئوتتۇرا قىسىم ۋاقتى (Tell City, Indiana)", + "America\/Indiana\/Vevay": "شەرقىي قىسىم ۋاقتى (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "شەرقىي قىسىم ۋاقتى (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "شەرقىي قىسىم ۋاقتى (Winamac, Indiana)", + "America\/Indianapolis": "شەرقىي قىسىم ۋاقتى (Indianapolis)", + "America\/Inuvik": "تاغ ۋاقتى (Inuvik)", + "America\/Iqaluit": "شەرقىي قىسىم ۋاقتى (Iqaluit)", + "America\/Jamaica": "شەرقىي قىسىم ۋاقتى (Jamaica)", + "America\/Jujuy": "ئارگېنتىنا ۋاقتى (Jujuy)", + "America\/Juneau": "ئالياسكا ۋاقتى (Juneau)", + "America\/Kentucky\/Monticello": "شەرقىي قىسىم ۋاقتى (Monticello, Kentucky)", + "America\/Kralendijk": "ئاتلانتىك ئوكيان ۋاقتى (Kralendijk)", + "America\/La_Paz": "بولىۋىيە ۋاقتى (La Paz)", + "America\/Lima": "پېرۇ ۋاقتى (Lima)", + "America\/Los_Angeles": "تىنچ ئوكيان ۋاقتى (Los Angeles)", + "America\/Louisville": "شەرقىي قىسىم ۋاقتى (Louisville)", + "America\/Lower_Princes": "ئاتلانتىك ئوكيان ۋاقتى (Lower Prince’s Quarter)", + "America\/Maceio": "بىرازىلىيە ۋاقتى (Maceio)", + "America\/Managua": "ئوتتۇرا قىسىم ۋاقتى (Managua)", + "America\/Manaus": "ئامازون ۋاقتى (Manaus)", + "America\/Marigot": "ئاتلانتىك ئوكيان ۋاقتى (Marigot)", + "America\/Martinique": "ئاتلانتىك ئوكيان ۋاقتى (Martinique)", + "America\/Matamoros": "ئوتتۇرا قىسىم ۋاقتى (Matamoros)", + "America\/Mazatlan": "مېكسىكا تىنچ ئوكيان ۋاقتى (Mazatlan)", + "America\/Mendoza": "ئارگېنتىنا ۋاقتى (Mendoza)", + "America\/Menominee": "ئوتتۇرا قىسىم ۋاقتى (Menominee)", + "America\/Merida": "ئوتتۇرا قىسىم ۋاقتى (Merida)", + "America\/Metlakatla": "ئالياسكا ۋاقتى (Metlakatla)", + "America\/Mexico_City": "ئوتتۇرا قىسىم ۋاقتى (Mexico City)", + "America\/Miquelon": "ساينىت پىئېر ۋە مىكېلون ۋاقتى (Miquelon)", + "America\/Moncton": "ئاتلانتىك ئوكيان ۋاقتى (Moncton)", + "America\/Monterrey": "ئوتتۇرا قىسىم ۋاقتى (Monterrey)", + "America\/Montevideo": "ئۇرۇگۋاي ۋاقتى (Montevideo)", + "America\/Montserrat": "ئاتلانتىك ئوكيان ۋاقتى (Montserrat)", + "America\/Nassau": "شەرقىي قىسىم ۋاقتى (Nassau)", + "America\/New_York": "شەرقىي قىسىم ۋاقتى (New York)", + "America\/Nipigon": "شەرقىي قىسىم ۋاقتى (Nipigon)", + "America\/Nome": "ئالياسكا ۋاقتى (Nome)", + "America\/Noronha": "فېرناندو-نورونخا ۋاقتى (Noronha)", + "America\/North_Dakota\/Beulah": "ئوتتۇرا قىسىم ۋاقتى (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "ئوتتۇرا قىسىم ۋاقتى (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "ئوتتۇرا قىسىم ۋاقتى (New Salem, North Dakota)", + "America\/Ojinaga": "تاغ ۋاقتى (Ojinaga)", + "America\/Panama": "شەرقىي قىسىم ۋاقتى (Panama)", + "America\/Pangnirtung": "شەرقىي قىسىم ۋاقتى (Pangnirtung)", + "America\/Paramaribo": "سۇرىنام ۋاقتى (Paramaribo)", + "America\/Phoenix": "تاغ ۋاقتى (Phoenix)", + "America\/Port-au-Prince": "شەرقىي قىسىم ۋاقتى (Port-au-Prince)", + "America\/Port_of_Spain": "ئاتلانتىك ئوكيان ۋاقتى (Port of Spain)", + "America\/Porto_Velho": "ئامازون ۋاقتى (Porto Velho)", + "America\/Puerto_Rico": "ئاتلانتىك ئوكيان ۋاقتى (Puerto Rico)", + "America\/Punta_Arenas": "چىلى ۋاقتى (Punta Arenas)", + "America\/Rainy_River": "ئوتتۇرا قىسىم ۋاقتى (Rainy River)", + "America\/Rankin_Inlet": "ئوتتۇرا قىسىم ۋاقتى (Rankin Inlet)", + "America\/Recife": "بىرازىلىيە ۋاقتى (Recife)", + "America\/Regina": "ئوتتۇرا قىسىم ۋاقتى (Regina)", + "America\/Resolute": "ئوتتۇرا قىسىم ۋاقتى (Resolute)", + "America\/Rio_Branco": "ئاكرې ۋاقتى (Rio Branco)", + "America\/Santa_Isabel": "مېكسىكا غەربىي شىمالىي قىسىم ۋاقتى (Santa Isabel)", + "America\/Santarem": "بىرازىلىيە ۋاقتى (Santarem)", + "America\/Santiago": "چىلى ۋاقتى (Santiago)", + "America\/Santo_Domingo": "ئاتلانتىك ئوكيان ۋاقتى (Santo Domingo)", + "America\/Sao_Paulo": "بىرازىلىيە ۋاقتى (Sao Paulo)", + "America\/Scoresbysund": "شەرقىي گىرېنلاند ۋاقتى (Ittoqqortoormiit)", + "America\/Sitka": "ئالياسكا ۋاقتى (Sitka)", + "America\/St_Barthelemy": "ئاتلانتىك ئوكيان ۋاقتى (ساينىت-بارتھېلەمىي)", + "America\/St_Johns": "نىۋفوئۇنلاند ۋاقتى (St. John’s)", + "America\/St_Kitts": "ئاتلانتىك ئوكيان ۋاقتى (St. Kitts)", + "America\/St_Lucia": "ئاتلانتىك ئوكيان ۋاقتى (St. Lucia)", + "America\/St_Thomas": "ئاتلانتىك ئوكيان ۋاقتى (St. Thomas)", + "America\/St_Vincent": "ئاتلانتىك ئوكيان ۋاقتى (St. Vincent)", + "America\/Swift_Current": "ئوتتۇرا قىسىم ۋاقتى (Swift Current)", + "America\/Tegucigalpa": "ئوتتۇرا قىسىم ۋاقتى (Tegucigalpa)", + "America\/Thule": "ئاتلانتىك ئوكيان ۋاقتى (Thule)", + "America\/Thunder_Bay": "شەرقىي قىسىم ۋاقتى (Thunder Bay)", + "America\/Tijuana": "تىنچ ئوكيان ۋاقتى (Tijuana)", + "America\/Toronto": "شەرقىي قىسىم ۋاقتى (Toronto)", + "America\/Tortola": "ئاتلانتىك ئوكيان ۋاقتى (Tortola)", + "America\/Vancouver": "تىنچ ئوكيان ۋاقتى (Vancouver)", + "America\/Whitehorse": "تىنچ ئوكيان ۋاقتى (Whitehorse)", + "America\/Winnipeg": "ئوتتۇرا قىسىم ۋاقتى (Winnipeg)", + "America\/Yakutat": "ئالياسكا ۋاقتى (Yakutat)", + "America\/Yellowknife": "تاغ ۋاقتى (Yellowknife)", + "Antarctica\/Casey": "ئاۋسترالىيە غەربىي قىسىم ۋاقتى (Casey)", + "Antarctica\/Davis": "داۋىس ۋاقتى (Davis)", + "Antarctica\/DumontDUrville": "دۇمونت-دۇرۋىل ۋاقتى (دۇمونت دۇرۋىللې)", + "Antarctica\/Macquarie": "ماككۇۋارى ئاراللىرى ۋاقتى (Macquarie)", + "Antarctica\/Mawson": "ماۋسون ۋاقتى (Mawson)", + "Antarctica\/McMurdo": "يېڭى زېلاندىيە ۋاقتى (McMurdo)", + "Antarctica\/Palmer": "چىلى ۋاقتى (Palmer)", + "Antarctica\/Rothera": "روتېرا ۋاقتى (Rothera)", + "Antarctica\/Syowa": "شوۋا ۋاقتى (Syowa)", + "Antarctica\/Troll": "گىرىنۋىچ ۋاقتى (Troll)", + "Antarctica\/Vostok": "ۋوستوك ۋاقتى (Vostok)", + "Arctic\/Longyearbyen": "ئوتتۇرا ياۋروپا ۋاقتى (Longyearbyen)", + "Asia\/Aden": "ئەرەب ۋاقتى (Aden)", + "Asia\/Almaty": "شەرقىي قازاقىستان ۋاقتى (Almaty)", + "Asia\/Amman": "شەرقىي ياۋروپا ۋاقتى (Amman)", + "Asia\/Anadyr": "ئانادىر ۋاقتى (Anadyr)", + "Asia\/Aqtau": "غەربىي قازاقىستان ۋاقتى (Aqtau)", + "Asia\/Aqtobe": "غەربىي قازاقىستان ۋاقتى (Aqtobe)", + "Asia\/Ashgabat": "تۈركمەنىستان ۋاقتى (Ashgabat)", + "Asia\/Atyrau": "غەربىي قازاقىستان ۋاقتى (Atyrau)", + "Asia\/Baghdad": "ئەرەب ۋاقتى (Baghdad)", + "Asia\/Bahrain": "ئەرەب ۋاقتى (Bahrain)", + "Asia\/Baku": "ئەزەربەيجان ۋاقتى (Baku)", + "Asia\/Bangkok": "ھىندى چىنى ۋاقتى (Bangkok)", + "Asia\/Beirut": "شەرقىي ياۋروپا ۋاقتى (Beirut)", + "Asia\/Bishkek": "قىرغىزىستان ۋاقتى (Bishkek)", + "Asia\/Brunei": "بىرۇنىي دارۇسسالام ۋاقتى (Brunei)", + "Asia\/Calcutta": "ھىندىستان ئۆلچەملىك ۋاقتى (Kolkata)", + "Asia\/Chita": "ياكۇتسك ۋاقتى (Chita)", + "Asia\/Choibalsan": "چويبالسان ۋاقتى (Choibalsan)", + "Asia\/Colombo": "ھىندىستان ئۆلچەملىك ۋاقتى (Colombo)", + "Asia\/Damascus": "شەرقىي ياۋروپا ۋاقتى (Damascus)", + "Asia\/Dhaka": "باڭلادىش ۋاقتى (Dhaka)", + "Asia\/Dili": "شەرقىي تىمور ۋاقتى (Dili)", + "Asia\/Dubai": "گۇلف ئۆلچەملىك ۋاقتى (Dubai)", + "Asia\/Dushanbe": "تاجىكىستان ۋاقتى (Dushanbe)", + "Asia\/Famagusta": "شەرقىي ياۋروپا ۋاقتى (Famagusta)", + "Asia\/Gaza": "شەرقىي ياۋروپا ۋاقتى (Gaza)", + "Asia\/Hebron": "شەرقىي ياۋروپا ۋاقتى (Hebron)", + "Asia\/Hong_Kong": "شياڭگاڭ ۋاقتى (Hong Kong)", + "Asia\/Hovd": "خوۋد ۋاقتى (Hovd)", + "Asia\/Irkutsk": "ئىركۇتسك ۋاقتى (Irkutsk)", + "Asia\/Jakarta": "غەربىي ھىندونېزىيە ۋاقتى (Jakarta)", + "Asia\/Jayapura": "شەرقىي ھىندونېزىيە ۋاقتى (Jayapura)", + "Asia\/Jerusalem": "ئىسرائىلىيە ۋاقتى (Jerusalem)", + "Asia\/Kabul": "ئافغانىستان ۋاقتى (Kabul)", + "Asia\/Kamchatka": "پېتروپاۋلوۋسك-كامچاتكسكى ۋاقتى (Kamchatka)", + "Asia\/Karachi": "پاكىستان ۋاقتى (Karachi)", + "Asia\/Katmandu": "نېپال ۋاقتى (Kathmandu)", + "Asia\/Khandyga": "ياكۇتسك ۋاقتى (Khandyga)", + "Asia\/Krasnoyarsk": "كىراسنويارسك ۋاقتى (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "مالايشىيا ۋاقتى (Kuala Lumpur)", + "Asia\/Kuching": "مالايشىيا ۋاقتى (Kuching)", + "Asia\/Kuwait": "ئەرەب ۋاقتى (Kuwait)", + "Asia\/Macau": "جۇڭگو ۋاقتى (Macao)", + "Asia\/Magadan": "ماگادان ۋاقتى (Magadan)", + "Asia\/Makassar": "ئوتتۇرا ھىندونېزىيە ۋاقتى (Makassar)", + "Asia\/Manila": "فىلىپپىن ۋاقتى (Manila)", + "Asia\/Muscat": "گۇلف ئۆلچەملىك ۋاقتى (Muscat)", + "Asia\/Nicosia": "شەرقىي ياۋروپا ۋاقتى (Nicosia)", + "Asia\/Novokuznetsk": "كىراسنويارسك ۋاقتى (Novokuznetsk)", + "Asia\/Novosibirsk": "نوۋوسىبىرسك ۋاقتى (Novosibirsk)", + "Asia\/Omsk": "ئومسك ۋاقتى (Omsk)", + "Asia\/Oral": "غەربىي قازاقىستان ۋاقتى (Oral)", + "Asia\/Phnom_Penh": "ھىندى چىنى ۋاقتى (Phnom Penh)", + "Asia\/Pontianak": "غەربىي ھىندونېزىيە ۋاقتى (Pontianak)", + "Asia\/Pyongyang": "كورىيە ۋاقتى (Pyongyang)", + "Asia\/Qatar": "ئەرەب ۋاقتى (Qatar)", + "Asia\/Qostanay": "شەرقىي قازاقىستان ۋاقتى (Qostanay)", + "Asia\/Qyzylorda": "غەربىي قازاقىستان ۋاقتى (Qyzylorda)", + "Asia\/Rangoon": "بىرما ۋاقتى (Yangon)", + "Asia\/Riyadh": "ئەرەب ۋاقتى (Riyadh)", + "Asia\/Saigon": "ھىندى چىنى ۋاقتى (خوچىمىن شەھىرى)", + "Asia\/Sakhalin": "ساخارىن ۋاقتى (Sakhalin)", + "Asia\/Samarkand": "ئۆزبېكىستان ۋاقتى (Samarkand)", + "Asia\/Seoul": "كورىيە ۋاقتى (Seoul)", + "Asia\/Shanghai": "جۇڭگو ۋاقتى (Shanghai)", + "Asia\/Singapore": "سىنگاپور ۋاقتى (Singapore)", + "Asia\/Srednekolymsk": "ماگادان ۋاقتى (Srednekolymsk)", + "Asia\/Taipei": "تەيبېي ۋاقتى (Taipei)", + "Asia\/Tashkent": "ئۆزبېكىستان ۋاقتى (Tashkent)", + "Asia\/Tbilisi": "گىرۇزىيە ۋاقتى (Tbilisi)", + "Asia\/Tehran": "ئىران ۋاقتى (Tehran)", + "Asia\/Thimphu": "بۇتان ۋاقتى (Thimphu)", + "Asia\/Tokyo": "ياپونىيە ۋاقتى (Tokyo)", + "Asia\/Ulaanbaatar": "ئۇلانباتور ۋاقتى (Ulaanbaatar)", + "Asia\/Ust-Nera": "ۋىلادىۋوستوك ۋاقتى (Ust-Nera)", + "Asia\/Vientiane": "ھىندى چىنى ۋاقتى (Vientiane)", + "Asia\/Vladivostok": "ۋىلادىۋوستوك ۋاقتى (Vladivostok)", + "Asia\/Yakutsk": "ياكۇتسك ۋاقتى (Yakutsk)", + "Asia\/Yekaterinburg": "يېكاتېرىنبۇرگ ۋاقتى (Yekaterinburg)", + "Asia\/Yerevan": "ئەرمېنىيە ۋاقتى (Yerevan)", + "Atlantic\/Azores": "ئازور ۋاقتى (Azores)", + "Atlantic\/Bermuda": "ئاتلانتىك ئوكيان ۋاقتى (Bermuda)", + "Atlantic\/Canary": "غەربىي ياۋروپا ۋاقتى (Canary)", + "Atlantic\/Cape_Verde": "يېشىل تۇمشۇق ۋاقتى (Cape Verde)", + "Atlantic\/Faeroe": "غەربىي ياۋروپا ۋاقتى (Faroe)", + "Atlantic\/Madeira": "غەربىي ياۋروپا ۋاقتى (Madeira)", + "Atlantic\/Reykjavik": "گىرىنۋىچ ۋاقتى (Reykjavik)", + "Atlantic\/South_Georgia": "جەنۇبىي جورجىيە ۋاقتى (South Georgia)", + "Atlantic\/St_Helena": "گىرىنۋىچ ۋاقتى (St. Helena)", + "Atlantic\/Stanley": "فالكلاند ئاراللىرى ۋاقتى (Stanley)", + "Australia\/Adelaide": "ئاۋسترالىيە ئوتتۇرا قىسىم ۋاقتى (Adelaide)", + "Australia\/Brisbane": "ئاۋسترالىيە شەرقىي قىسىم ۋاقتى (Brisbane)", + "Australia\/Broken_Hill": "ئاۋسترالىيە ئوتتۇرا قىسىم ۋاقتى (Broken Hill)", + "Australia\/Currie": "ئاۋسترالىيە شەرقىي قىسىم ۋاقتى (Currie)", + "Australia\/Darwin": "ئاۋسترالىيە ئوتتۇرا قىسىم ۋاقتى (Darwin)", + "Australia\/Eucla": "ئاۋسترالىيە ئوتتۇرا غەربىي قىسىم ۋاقتى (Eucla)", + "Australia\/Hobart": "ئاۋسترالىيە شەرقىي قىسىم ۋاقتى (Hobart)", + "Australia\/Lindeman": "ئاۋسترالىيە شەرقىي قىسىم ۋاقتى (Lindeman)", + "Australia\/Lord_Howe": "لورد-خاي ۋاقتى (Lord Howe)", + "Australia\/Melbourne": "ئاۋسترالىيە شەرقىي قىسىم ۋاقتى (Melbourne)", + "Australia\/Perth": "ئاۋسترالىيە غەربىي قىسىم ۋاقتى (Perth)", + "Australia\/Sydney": "ئاۋسترالىيە شەرقىي قىسىم ۋاقتى (Sydney)", + "CST6CDT": "ئوتتۇرا قىسىم ۋاقتى", + "EST5EDT": "شەرقىي قىسىم ۋاقتى", + "Etc\/GMT": "گىرىنۋىچ ۋاقتى", + "Europe\/Amsterdam": "ئوتتۇرا ياۋروپا ۋاقتى (Amsterdam)", + "Europe\/Andorra": "ئوتتۇرا ياۋروپا ۋاقتى (Andorra)", + "Europe\/Astrakhan": "موسكۋا ۋاقتى (Astrakhan)", + "Europe\/Athens": "شەرقىي ياۋروپا ۋاقتى (Athens)", + "Europe\/Belgrade": "ئوتتۇرا ياۋروپا ۋاقتى (Belgrade)", + "Europe\/Berlin": "ئوتتۇرا ياۋروپا ۋاقتى (Berlin)", + "Europe\/Bratislava": "ئوتتۇرا ياۋروپا ۋاقتى (Bratislava)", + "Europe\/Brussels": "ئوتتۇرا ياۋروپا ۋاقتى (Brussels)", + "Europe\/Bucharest": "شەرقىي ياۋروپا ۋاقتى (Bucharest)", + "Europe\/Budapest": "ئوتتۇرا ياۋروپا ۋاقتى (Budapest)", + "Europe\/Busingen": "ئوتتۇرا ياۋروپا ۋاقتى (Busingen)", + "Europe\/Chisinau": "شەرقىي ياۋروپا ۋاقتى (Chisinau)", + "Europe\/Copenhagen": "ئوتتۇرا ياۋروپا ۋاقتى (Copenhagen)", + "Europe\/Dublin": "گىرىنۋىچ ۋاقتى (Dublin)", + "Europe\/Gibraltar": "ئوتتۇرا ياۋروپا ۋاقتى (Gibraltar)", + "Europe\/Guernsey": "گىرىنۋىچ ۋاقتى (Guernsey)", + "Europe\/Helsinki": "شەرقىي ياۋروپا ۋاقتى (Helsinki)", + "Europe\/Isle_of_Man": "گىرىنۋىچ ۋاقتى (Isle of Man)", + "Europe\/Jersey": "گىرىنۋىچ ۋاقتى (Jersey)", + "Europe\/Kaliningrad": "شەرقىي ياۋروپا ۋاقتى (Kaliningrad)", + "Europe\/Kiev": "شەرقىي ياۋروپا ۋاقتى (Kiev)", + "Europe\/Lisbon": "غەربىي ياۋروپا ۋاقتى (Lisbon)", + "Europe\/Ljubljana": "ئوتتۇرا ياۋروپا ۋاقتى (Ljubljana)", + "Europe\/London": "گىرىنۋىچ ۋاقتى (London)", + "Europe\/Luxembourg": "ئوتتۇرا ياۋروپا ۋاقتى (Luxembourg)", + "Europe\/Madrid": "ئوتتۇرا ياۋروپا ۋاقتى (Madrid)", + "Europe\/Malta": "ئوتتۇرا ياۋروپا ۋاقتى (Malta)", + "Europe\/Mariehamn": "شەرقىي ياۋروپا ۋاقتى (Mariehamn)", + "Europe\/Minsk": "موسكۋا ۋاقتى (Minsk)", + "Europe\/Monaco": "ئوتتۇرا ياۋروپا ۋاقتى (Monaco)", + "Europe\/Moscow": "موسكۋا ۋاقتى (Moscow)", + "Europe\/Oslo": "ئوتتۇرا ياۋروپا ۋاقتى (Oslo)", + "Europe\/Paris": "ئوتتۇرا ياۋروپا ۋاقتى (Paris)", + "Europe\/Podgorica": "ئوتتۇرا ياۋروپا ۋاقتى (Podgorica)", + "Europe\/Prague": "ئوتتۇرا ياۋروپا ۋاقتى (Prague)", + "Europe\/Riga": "شەرقىي ياۋروپا ۋاقتى (Riga)", + "Europe\/Rome": "ئوتتۇرا ياۋروپا ۋاقتى (Rome)", + "Europe\/Samara": "سامارا ۋاقتى (Samara)", + "Europe\/San_Marino": "ئوتتۇرا ياۋروپا ۋاقتى (San Marino)", + "Europe\/Sarajevo": "ئوتتۇرا ياۋروپا ۋاقتى (Sarajevo)", + "Europe\/Saratov": "موسكۋا ۋاقتى (Saratov)", + "Europe\/Simferopol": "موسكۋا ۋاقتى (Simferopol)", + "Europe\/Skopje": "ئوتتۇرا ياۋروپا ۋاقتى (Skopje)", + "Europe\/Sofia": "شەرقىي ياۋروپا ۋاقتى (Sofia)", + "Europe\/Stockholm": "ئوتتۇرا ياۋروپا ۋاقتى (Stockholm)", + "Europe\/Tallinn": "شەرقىي ياۋروپا ۋاقتى (Tallinn)", + "Europe\/Tirane": "ئوتتۇرا ياۋروپا ۋاقتى (Tirane)", + "Europe\/Ulyanovsk": "موسكۋا ۋاقتى (Ulyanovsk)", + "Europe\/Uzhgorod": "شەرقىي ياۋروپا ۋاقتى (Uzhgorod)", + "Europe\/Vaduz": "ئوتتۇرا ياۋروپا ۋاقتى (Vaduz)", + "Europe\/Vatican": "ئوتتۇرا ياۋروپا ۋاقتى (Vatican)", + "Europe\/Vienna": "ئوتتۇرا ياۋروپا ۋاقتى (Vienna)", + "Europe\/Vilnius": "شەرقىي ياۋروپا ۋاقتى (Vilnius)", + "Europe\/Volgograd": "ۋولگاگراد ۋاقتى (Volgograd)", + "Europe\/Warsaw": "ئوتتۇرا ياۋروپا ۋاقتى (Warsaw)", + "Europe\/Zagreb": "ئوتتۇرا ياۋروپا ۋاقتى (Zagreb)", + "Europe\/Zaporozhye": "شەرقىي ياۋروپا ۋاقتى (Zaporozhye)", + "Europe\/Zurich": "ئوتتۇرا ياۋروپا ۋاقتى (Zurich)", + "Indian\/Antananarivo": "شەرقىي ئافرىقا ۋاقتى (Antananarivo)", + "Indian\/Chagos": "ھىندى ئوكيان ۋاقتى (Chagos)", + "Indian\/Christmas": "روژدېستۋو ئارىلى ۋاقتى (Christmas)", + "Indian\/Cocos": "كوكۇس ئارىلى ۋاقتى (Cocos)", + "Indian\/Comoro": "شەرقىي ئافرىقا ۋاقتى (Comoro)", + "Indian\/Kerguelen": "فىرانسىيەگە قاراشلىق جەنۇبىي ۋە ئانتاركتىكا ۋاقتى (Kerguelen)", + "Indian\/Mahe": "سېيشېل ۋاقتى (Mahe)", + "Indian\/Maldives": "مالدىۋې ۋاقتى (Maldives)", + "Indian\/Mauritius": "ماۋرىتىئۇس ۋاقتى (Mauritius)", + "Indian\/Mayotte": "شەرقىي ئافرىقا ۋاقتى (Mayotte)", + "Indian\/Reunion": "رېئونىيون ۋاقتى (رېئونىيون)", + "MST7MDT": "تاغ ۋاقتى", + "PST8PDT": "تىنچ ئوكيان ۋاقتى", + "Pacific\/Auckland": "يېڭى زېلاندىيە ۋاقتى (Auckland)", + "Pacific\/Bougainville": "پاپۇئا يېڭى گىۋىنېيەسى ۋاقتى (Bougainville)", + "Pacific\/Chatham": "چاتام ۋاقتى (Chatham)", + "Pacific\/Easter": "ئېستېر ئارىلى ۋاقتى (Easter)", + "Pacific\/Efate": "ۋانۇئاتۇ ۋاقتى (Efate)", + "Pacific\/Enderbury": "فېنىكس ئاراللىرى ۋاقتى (Enderbury)", + "Pacific\/Fakaofo": "توكېلاۋ ۋاقتى (Fakaofo)", + "Pacific\/Fiji": "فىجى ۋاقتى (Fiji)", + "Pacific\/Funafuti": "تۇۋالۇ ۋاقتى (Funafuti)", + "Pacific\/Galapagos": "گالاپاگوس ۋاقتى (Galapagos)", + "Pacific\/Gambier": "گامبىيېر ۋاقتى (Gambier)", + "Pacific\/Guadalcanal": "سولومون ئاراللىرى ۋاقتى (Guadalcanal)", + "Pacific\/Guam": "چاموررو ئۆلچەملىك ۋاقتى (Guam)", + "Pacific\/Honolulu": "ھاۋاي-ئالېيۇت ۋاقتى (Honolulu)", + "Pacific\/Johnston": "ھاۋاي-ئالېيۇت ۋاقتى (Johnston)", + "Pacific\/Kiritimati": "لاين ئاراللىرى ۋاقتى (Kiritimati)", + "Pacific\/Kosrae": "كوسرائې ۋاقتى (Kosrae)", + "Pacific\/Kwajalein": "مارشال ئاراللىرى ۋاقتى (Kwajalein)", + "Pacific\/Majuro": "مارشال ئاراللىرى ۋاقتى (Majuro)", + "Pacific\/Marquesas": "ماركىز ۋاقتى (Marquesas)", + "Pacific\/Midway": "ساموئا ۋاقتى (Midway)", + "Pacific\/Nauru": "ناۋرۇ ۋاقتى (Nauru)", + "Pacific\/Niue": "نىيۇئې ۋاقتى (Niue)", + "Pacific\/Norfolk": "نورفولك ئاراللىرى ۋاقتى (Norfolk)", + "Pacific\/Noumea": "يېڭى كالېدونىيە ۋاقتى (Noumea)", + "Pacific\/Pago_Pago": "ساموئا ۋاقتى (Pago Pago)", + "Pacific\/Palau": "پالاۋ ۋاقتى (Palau)", + "Pacific\/Pitcairn": "پىتكاير ۋاقتى (Pitcairn)", + "Pacific\/Ponape": "پونپېي ۋاقتى (Pohnpei)", + "Pacific\/Port_Moresby": "پاپۇئا يېڭى گىۋىنېيەسى ۋاقتى (Port Moresby)", + "Pacific\/Rarotonga": "كۇك ئاراللىرى ۋاقتى (Rarotonga)", + "Pacific\/Saipan": "چاموررو ئۆلچەملىك ۋاقتى (Saipan)", + "Pacific\/Tahiti": "تايتى ۋاقتى (Tahiti)", + "Pacific\/Tarawa": "گىلبېرت ئاراللىرى ۋاقتى (Tarawa)", + "Pacific\/Tongatapu": "تونگا ۋاقتى (Tongatapu)", + "Pacific\/Truk": "چۇك ۋاقتى (Chuuk)", + "Pacific\/Wake": "ۋېيك ئارىلى ۋاقتى (Wake)", + "Pacific\/Wallis": "ۋاللىس ۋە فۇتۇنا ۋاقتى (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/uk.json b/src/Symfony/Component/Intl/Resources/data/timezones/uk.json new file mode 100644 index 0000000000000..27fb443c0c595 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/uk.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "за Ґрінвічем (Абіджан)", + "Africa\/Accra": "за Ґрінвічем (Аккра)", + "Africa\/Addis_Ababa": "за східноафриканським часом (Аддис-Абеба)", + "Africa\/Algiers": "за центральноєвропейським часом (Алжир)", + "Africa\/Asmera": "за східноафриканським часом (Асмера)", + "Africa\/Bamako": "за Ґрінвічем (Бамако)", + "Africa\/Bangui": "за західноафриканським часом (Банґі)", + "Africa\/Banjul": "за Ґрінвічем (Банжул)", + "Africa\/Bissau": "за Ґрінвічем (Бісау)", + "Africa\/Blantyre": "за центральноафриканським часом (Блантайр)", + "Africa\/Brazzaville": "за західноафриканським часом (Браззавіль)", + "Africa\/Bujumbura": "за центральноафриканським часом (Бужумбура)", + "Africa\/Cairo": "за східноєвропейським часом (Каїр)", + "Africa\/Casablanca": "за західноєвропейським часом (Касабланка)", + "Africa\/Ceuta": "за центральноєвропейським часом (Сеута)", + "Africa\/Conakry": "за Ґрінвічем (Конакрі)", + "Africa\/Dakar": "за Ґрінвічем (Дакар)", + "Africa\/Dar_es_Salaam": "за східноафриканським часом (Дар-ес-Салам)", + "Africa\/Djibouti": "за східноафриканським часом (Джібуті)", + "Africa\/Douala": "за західноафриканським часом (Дуала)", + "Africa\/El_Aaiun": "за західноєвропейським часом (Ель-Аюн)", + "Africa\/Freetown": "за Ґрінвічем (Фрітаун)", + "Africa\/Gaborone": "за центральноафриканським часом (Ґабороне)", + "Africa\/Harare": "за центральноафриканським часом (Хараре)", + "Africa\/Johannesburg": "за південноафриканським часом (Йоганнесбурґ)", + "Africa\/Juba": "за східноафриканським часом (Джуба)", + "Africa\/Kampala": "за східноафриканським часом (Кампала)", + "Africa\/Khartoum": "за центральноафриканським часом (Хартум)", + "Africa\/Kigali": "за центральноафриканським часом (Кігалі)", + "Africa\/Kinshasa": "за західноафриканським часом (Кіншаса)", + "Africa\/Lagos": "за західноафриканським часом (Лаґос)", + "Africa\/Libreville": "за західноафриканським часом (Лібревіль)", + "Africa\/Lome": "за Ґрінвічем (Ломе)", + "Africa\/Luanda": "за західноафриканським часом (Луанда)", + "Africa\/Lubumbashi": "за центральноафриканським часом (Лубумбаші)", + "Africa\/Lusaka": "за центральноафриканським часом (Лусака)", + "Africa\/Malabo": "за західноафриканським часом (Малабо)", + "Africa\/Maputo": "за центральноафриканським часом (Мапуту)", + "Africa\/Maseru": "за південноафриканським часом (Масеру)", + "Africa\/Mbabane": "за південноафриканським часом (Мбабане)", + "Africa\/Mogadishu": "за східноафриканським часом (Моґадішо)", + "Africa\/Monrovia": "за Ґрінвічем (Монровія)", + "Africa\/Nairobi": "за східноафриканським часом (Найробі)", + "Africa\/Ndjamena": "за західноафриканським часом (Нджамена)", + "Africa\/Niamey": "за західноафриканським часом (Ніамей)", + "Africa\/Nouakchott": "за Ґрінвічем (Нуакшотт)", + "Africa\/Ouagadougou": "за Ґрінвічем (Уаґадуґу)", + "Africa\/Porto-Novo": "за західноафриканським часом (Порто-Ново)", + "Africa\/Sao_Tome": "за Ґрінвічем (Сан-Томе)", + "Africa\/Tripoli": "за східноєвропейським часом (Тріполі)", + "Africa\/Tunis": "за центральноєвропейським часом (Туніс)", + "Africa\/Windhoek": "за центральноафриканським часом (Віндгук)", + "America\/Adak": "за гавайсько-алеутським часом (Адак)", + "America\/Anchorage": "за часом на Алясці (Анкоридж)", + "America\/Anguilla": "за атлантичним часом (Анґілья)", + "America\/Antigua": "за атлантичним часом (Антиґуа)", + "America\/Araguaina": "за бразильським часом (Араґуаіна)", + "America\/Argentina\/La_Rioja": "за аргентинським часом (Ла-Ріоха)", + "America\/Argentina\/Rio_Gallegos": "за аргентинським часом (Ріо-Ґальєґос)", + "America\/Argentina\/Salta": "за аргентинським часом (Сальта)", + "America\/Argentina\/San_Juan": "за аргентинським часом (Сан-Хуан)", + "America\/Argentina\/San_Luis": "за західноаргентинським часом (Сан-Луїс)", + "America\/Argentina\/Tucuman": "за аргентинським часом (Тукуман)", + "America\/Argentina\/Ushuaia": "за аргентинським часом (Ушуая)", + "America\/Aruba": "за атлантичним часом (Аруба)", + "America\/Asuncion": "за параґвайським часом (Асунсьйон)", + "America\/Bahia": "за бразильським часом (Байя)", + "America\/Bahia_Banderas": "за північноамериканським центральним часом (Баїя Бандерас)", + "America\/Barbados": "за атлантичним часом (Барбадос)", + "America\/Belem": "за бразильським часом (Белен)", + "America\/Belize": "за північноамериканським центральним часом (Беліз)", + "America\/Blanc-Sablon": "за атлантичним часом (Блан-Саблон)", + "America\/Boa_Vista": "за часом на Амазонці (Боа-Віста)", + "America\/Bogota": "за колумбійським часом (Боґота)", + "America\/Boise": "за північноамериканським гірським часом (Бойсе)", + "America\/Buenos_Aires": "за аргентинським часом (Буенос-Айрес)", + "America\/Cambridge_Bay": "за північноамериканським гірським часом (Кеймбрідж-Бей)", + "America\/Campo_Grande": "за часом на Амазонці (Кампу-Ґранді)", + "America\/Cancun": "за північноамериканським східним часом (Канкун)", + "America\/Caracas": "за часом у Венесуелі (Каракас)", + "America\/Catamarca": "за аргентинським часом (Катамарка)", + "America\/Cayenne": "за часом Французької Гвіани (Каєнна)", + "America\/Cayman": "за північноамериканським східним часом (Кайманові Острови)", + "America\/Chicago": "за північноамериканським центральним часом (Чікаґо)", + "America\/Chihuahua": "за тихоокеанським часом у Мексиці (Чіуауа)", + "America\/Coral_Harbour": "за північноамериканським східним часом (Атікокан)", + "America\/Cordoba": "за аргентинським часом (Кордова)", + "America\/Costa_Rica": "за північноамериканським центральним часом (Коста-Ріка)", + "America\/Creston": "за північноамериканським гірським часом (Крестон)", + "America\/Cuiaba": "за часом на Амазонці (Куяба)", + "America\/Curacao": "за атлантичним часом (Кюрасао)", + "America\/Danmarkshavn": "за Ґрінвічем (Денмарксхавн)", + "America\/Dawson": "за північноамериканським тихоокеанським часом (Доусон)", + "America\/Dawson_Creek": "за північноамериканським гірським часом (Доусон-Крік)", + "America\/Denver": "за північноамериканським гірським часом (Денвер)", + "America\/Detroit": "за північноамериканським східним часом (Детройт)", + "America\/Dominica": "за атлантичним часом (Домініка)", + "America\/Edmonton": "за північноамериканським гірським часом (Едмонтон)", + "America\/Eirunepe": "час: Акрі (Ейрунепе)", + "America\/El_Salvador": "за північноамериканським центральним часом (Сальвадор)", + "America\/Fort_Nelson": "за північноамериканським гірським часом (Форт Нельсон)", + "America\/Fortaleza": "за бразильським часом (Форталеза)", + "America\/Glace_Bay": "за атлантичним часом (Ґлейс-Бей)", + "America\/Godthab": "за західним часом у Ґренландії (Нуук)", + "America\/Goose_Bay": "за атлантичним часом (Ґус-Бей)", + "America\/Grand_Turk": "за північноамериканським східним часом (Ґранд-Терк)", + "America\/Grenada": "за атлантичним часом (Ґренада)", + "America\/Guadeloupe": "за атлантичним часом (Ґваделупа)", + "America\/Guatemala": "за північноамериканським центральним часом (Ґватемала)", + "America\/Guayaquil": "за часом в Еквадорі (Ґуаякіль)", + "America\/Guyana": "за часом у Ґаяні (Ґайана)", + "America\/Halifax": "за атлантичним часом (Галіфакс)", + "America\/Havana": "за часом на Кубі (Гавана)", + "America\/Hermosillo": "за тихоокеанським часом у Мексиці (Ермосільйо)", + "America\/Indiana\/Knox": "за північноамериканським центральним часом (Нокс, Індіана)", + "America\/Indiana\/Marengo": "за північноамериканським східним часом (Маренго, Індіана)", + "America\/Indiana\/Petersburg": "за північноамериканським східним часом (Пітерсберг, Індіана)", + "America\/Indiana\/Tell_City": "за північноамериканським центральним часом (Телл-Сіті, Індіана)", + "America\/Indiana\/Vevay": "за північноамериканським східним часом (Вівей, Індіана)", + "America\/Indiana\/Vincennes": "за північноамериканським східним часом (Вінсенс, Індіана)", + "America\/Indiana\/Winamac": "за північноамериканським східним часом (Вінамак, Індіана)", + "America\/Indianapolis": "за північноамериканським східним часом (Індіанаполіс)", + "America\/Inuvik": "за північноамериканським гірським часом (Інувік)", + "America\/Iqaluit": "за північноамериканським східним часом (Ікалуїт)", + "America\/Jamaica": "за північноамериканським східним часом (Ямайка)", + "America\/Jujuy": "за аргентинським часом (Жужуй)", + "America\/Juneau": "за часом на Алясці (Джуно)", + "America\/Kentucky\/Monticello": "за північноамериканським східним часом (Монтіселло, Кентуккі)", + "America\/Kralendijk": "за атлантичним часом (Кралендейк)", + "America\/La_Paz": "за болівійським часом (Ла-Пас)", + "America\/Lima": "за часом у Перу (Ліма)", + "America\/Los_Angeles": "за північноамериканським тихоокеанським часом (Лос-Анджелес)", + "America\/Louisville": "за північноамериканським східним часом (Луїсвілл)", + "America\/Lower_Princes": "за атлантичним часом (Лоуер-Принсес-Квотер)", + "America\/Maceio": "за бразильським часом (Масейо)", + "America\/Managua": "за північноамериканським центральним часом (Манаґуа)", + "America\/Manaus": "за часом на Амазонці (Манаус)", + "America\/Marigot": "за атлантичним часом (Маріґо)", + "America\/Martinique": "за атлантичним часом (Мартініка)", + "America\/Matamoros": "за північноамериканським центральним часом (Матаморос)", + "America\/Mazatlan": "за тихоокеанським часом у Мексиці (Масатлан)", + "America\/Mendoza": "за аргентинським часом (Мендоса)", + "America\/Menominee": "за північноамериканським центральним часом (Меноміні)", + "America\/Merida": "за північноамериканським центральним часом (Меріда)", + "America\/Metlakatla": "за часом на Алясці (Метлакатла)", + "America\/Mexico_City": "за північноамериканським центральним часом (Мехіко)", + "America\/Miquelon": "за часом на островах Сен-П’єр і Мікелон (Мікелон)", + "America\/Moncton": "за атлантичним часом (Монктон)", + "America\/Monterrey": "за північноамериканським центральним часом (Монтерей)", + "America\/Montevideo": "за часом в Уруґваї (Монтевідео)", + "America\/Montserrat": "за атлантичним часом (Монтсеррат)", + "America\/Nassau": "за північноамериканським східним часом (Насау)", + "America\/New_York": "за північноамериканським східним часом (Нью-Йорк)", + "America\/Nipigon": "за північноамериканським східним часом (Ніпігон)", + "America\/Nome": "за часом на Алясці (Ном)", + "America\/Noronha": "за часом на архіпелазі Фернанду-ді-Норонья (Норонья)", + "America\/North_Dakota\/Beulah": "за північноамериканським центральним часом (Бʼюла, Північна Дакота)", + "America\/North_Dakota\/Center": "за північноамериканським центральним часом (Сентр, Північна Дакота)", + "America\/North_Dakota\/New_Salem": "за північноамериканським центральним часом (Нью-Салем, Північна Дакота)", + "America\/Ojinaga": "за північноамериканським гірським часом (Охінаґа)", + "America\/Panama": "за північноамериканським східним часом (Панама)", + "America\/Pangnirtung": "за північноамериканським східним часом (Панґніртанґ)", + "America\/Paramaribo": "за часом у Суринамі (Парамарибо)", + "America\/Phoenix": "за північноамериканським гірським часом (Фінікс)", + "America\/Port-au-Prince": "за північноамериканським східним часом (Порт-о-Пренс)", + "America\/Port_of_Spain": "за атлантичним часом (Порт-оф-Спейн)", + "America\/Porto_Velho": "за часом на Амазонці (Порту-Велью)", + "America\/Puerto_Rico": "за атлантичним часом (Пуерто-Ріко)", + "America\/Punta_Arenas": "за чилійським часом (Пунта-Аренас)", + "America\/Rainy_River": "за північноамериканським центральним часом (Рейні-Рівер)", + "America\/Rankin_Inlet": "за північноамериканським центральним часом (Ренкін-Інлет)", + "America\/Recife": "за бразильським часом (Ресіфі)", + "America\/Regina": "за північноамериканським центральним часом (Реджайна)", + "America\/Resolute": "за північноамериканським центральним часом (Резольют)", + "America\/Rio_Branco": "час: Акрі (Ріо-Бранко)", + "America\/Santa_Isabel": "за північнозахідним часом у Мексиці (Санта-Ісабель)", + "America\/Santarem": "за бразильським часом (Сантарен)", + "America\/Santiago": "за чилійським часом (Сантьяґо)", + "America\/Santo_Domingo": "за атлантичним часом (Санто-Домінґо)", + "America\/Sao_Paulo": "за бразильським часом (Сан-Паулу)", + "America\/Scoresbysund": "за східним часом у Ґренландії (Іттоккортоорміут)", + "America\/Sitka": "за часом на Алясці (Сітка)", + "America\/St_Barthelemy": "за атлантичним часом (Сен-Бартелемі)", + "America\/St_Johns": "за часом на острові Ньюфаундленд (Сент-Джонс)", + "America\/St_Kitts": "за атлантичним часом (Сент-Кіттс)", + "America\/St_Lucia": "за атлантичним часом (Сент-Люсія)", + "America\/St_Thomas": "за атлантичним часом (Сент-Томас)", + "America\/St_Vincent": "за атлантичним часом (Сент-Вінсент)", + "America\/Swift_Current": "за північноамериканським центральним часом (Свіфт-Каррент)", + "America\/Tegucigalpa": "за північноамериканським центральним часом (Теґусіґальпа)", + "America\/Thule": "за атлантичним часом (Туле)", + "America\/Thunder_Bay": "за північноамериканським східним часом (Тандер-Бей)", + "America\/Tijuana": "за північноамериканським тихоокеанським часом (Тіхуана)", + "America\/Toronto": "за північноамериканським східним часом (Торонто)", + "America\/Tortola": "за атлантичним часом (Тортола)", + "America\/Vancouver": "за північноамериканським тихоокеанським часом (Ванкувер)", + "America\/Whitehorse": "за північноамериканським тихоокеанським часом (Вайтгорс)", + "America\/Winnipeg": "за північноамериканським центральним часом (Вінніпеґ)", + "America\/Yakutat": "за часом на Алясці (Якутат)", + "America\/Yellowknife": "за північноамериканським гірським часом (Єллоунайф)", + "Antarctica\/Casey": "за західноавстралійським часом (Кейсі)", + "Antarctica\/Davis": "за часом у Девіс (Девіс)", + "Antarctica\/DumontDUrville": "за часом у Дюмон дʼЮрвіль (Дюмон-дʼЮрвіль)", + "Antarctica\/Macquarie": "за часом на острові Маккуорі (Маккуорі)", + "Antarctica\/Mawson": "за часом на станції Моусон (Моусон)", + "Antarctica\/McMurdo": "за часом у Новій Зеландії (Мак-Мердо)", + "Antarctica\/Palmer": "за чилійським часом (Палмер)", + "Antarctica\/Rothera": "за часом на станції Ротера (Ротера)", + "Antarctica\/Syowa": "за часом на станції Сева (Сьова)", + "Antarctica\/Troll": "за Ґрінвічем (Тролл)", + "Antarctica\/Vostok": "за часом на станції Восток (Восток)", + "Arctic\/Longyearbyen": "за центральноєвропейським часом (Лонґйїр)", + "Asia\/Aden": "за арабським часом (Аден)", + "Asia\/Almaty": "за східним часом у Казахстані (Алмати)", + "Asia\/Amman": "за східноєвропейським часом (Амман)", + "Asia\/Anadyr": "час: Анадир (Анадир)", + "Asia\/Aqtau": "за західним часом у Казахстані (Актау)", + "Asia\/Aqtobe": "за західним часом у Казахстані (Актобе)", + "Asia\/Ashgabat": "за часом у Туркменістані (Ашгабат)", + "Asia\/Atyrau": "за західним часом у Казахстані (Атирау)", + "Asia\/Baghdad": "за арабським часом (Багдад)", + "Asia\/Bahrain": "за арабським часом (Бахрейн)", + "Asia\/Baku": "за часом в Азербайджані (Баку)", + "Asia\/Bangkok": "за часом в Індокитаї (Банґкок)", + "Asia\/Beirut": "за східноєвропейським часом (Бейрут)", + "Asia\/Bishkek": "за часом у Киргизстані (Бішкек)", + "Asia\/Brunei": "за часом у Брунеї (Бруней)", + "Asia\/Calcutta": "за індійським стандартним часом (Колката)", + "Asia\/Chita": "за якутським часом (Чита)", + "Asia\/Choibalsan": "за часом у Чойбалсані (Чойбалсан)", + "Asia\/Colombo": "за індійським стандартним часом (Коломбо)", + "Asia\/Damascus": "за східноєвропейським часом (Дамаск)", + "Asia\/Dhaka": "за часом у Бангладеш (Дакка)", + "Asia\/Dili": "за часом у Східному Тиморі (Ділі)", + "Asia\/Dubai": "за часом Перської затоки (Дубай)", + "Asia\/Dushanbe": "за часом у Таджикистані (Душанбе)", + "Asia\/Famagusta": "за східноєвропейським часом (Фамагуста)", + "Asia\/Gaza": "за східноєвропейським часом (Газа)", + "Asia\/Hebron": "за східноєвропейським часом (Хеврон)", + "Asia\/Hong_Kong": "за часом у Гонконзі (Гонконґ)", + "Asia\/Hovd": "за часом у Ховді (Ховд)", + "Asia\/Irkutsk": "за іркутським часом (Іркутськ)", + "Asia\/Jakarta": "за західноіндонезійським часом (Джакарта)", + "Asia\/Jayapura": "за східноіндонезійським часом (Джайпур)", + "Asia\/Jerusalem": "за ізраїльським часом (Єрусалим)", + "Asia\/Kabul": "за часом в Афганістані (Кабул)", + "Asia\/Kamchatka": "за камчатським часом (Камчатка)", + "Asia\/Karachi": "за часом у Пакистані (Карачі)", + "Asia\/Katmandu": "за часом у Непалі (Катманду)", + "Asia\/Khandyga": "за якутським часом (Хандига)", + "Asia\/Krasnoyarsk": "за красноярським часом (Красноярськ)", + "Asia\/Kuala_Lumpur": "за часом у Малайзії (Куала-Лумпур)", + "Asia\/Kuching": "за часом у Малайзії (Кучінґ)", + "Asia\/Kuwait": "за арабським часом (Кувейт)", + "Asia\/Macau": "за китайським часом (Макао)", + "Asia\/Magadan": "за магаданським часом (Магадан)", + "Asia\/Makassar": "за центральноіндонезійським часом (Макассар)", + "Asia\/Manila": "за часом на Філіппінах (Маніла)", + "Asia\/Muscat": "за часом Перської затоки (Маскат)", + "Asia\/Nicosia": "за східноєвропейським часом (Нікосія)", + "Asia\/Novokuznetsk": "за красноярським часом (Новокузнецьк)", + "Asia\/Novosibirsk": "за новосибірським часом (Новосибірськ)", + "Asia\/Omsk": "за омським часом (Омськ)", + "Asia\/Oral": "за західним часом у Казахстані (Орал)", + "Asia\/Phnom_Penh": "за часом в Індокитаї (Пномпень)", + "Asia\/Pontianak": "за західноіндонезійським часом (Понтіанак)", + "Asia\/Pyongyang": "за корейським часом (Пхеньян)", + "Asia\/Qatar": "за арабським часом (Катар)", + "Asia\/Qostanay": "за східним часом у Казахстані (Qostanay)", + "Asia\/Qyzylorda": "за західним часом у Казахстані (Кизилорда)", + "Asia\/Rangoon": "за часом у Мʼянмі (Янґон)", + "Asia\/Riyadh": "за арабським часом (Ер-Ріяд)", + "Asia\/Saigon": "за часом в Індокитаї (Хошимін)", + "Asia\/Sakhalin": "за сахалінським часом (Сахалін)", + "Asia\/Samarkand": "за часом в Узбекистані (Самарканд)", + "Asia\/Seoul": "за корейським часом (Сеул)", + "Asia\/Shanghai": "за китайським часом (Шанхай)", + "Asia\/Singapore": "за часом у Сінґапурі (Сінґапур)", + "Asia\/Srednekolymsk": "за магаданським часом (Середньоколимськ)", + "Asia\/Taipei": "за часом у Тайбеї (Тайбей)", + "Asia\/Tashkent": "за часом в Узбекистані (Ташкент)", + "Asia\/Tbilisi": "за часом у Грузії (Тбілісі)", + "Asia\/Tehran": "за іранським часом (Тегеран)", + "Asia\/Thimphu": "за часом у Бутані (Тхімпху)", + "Asia\/Tokyo": "за японським часом (Токіо)", + "Asia\/Ulaanbaatar": "за часом в Улан-Баторі (Улан-Батор)", + "Asia\/Ust-Nera": "за владивостоцьким часом (Усть-Нера)", + "Asia\/Vientiane": "за часом в Індокитаї (Вʼєнтьян)", + "Asia\/Vladivostok": "за владивостоцьким часом (Владивосток)", + "Asia\/Yakutsk": "за якутським часом (Якутськ)", + "Asia\/Yekaterinburg": "за єкатеринбурзьким часом (Єкатеринбург)", + "Asia\/Yerevan": "за вірменським часом (Єреван)", + "Atlantic\/Azores": "за часом на Азорських Островах (Азорські Острови)", + "Atlantic\/Bermuda": "за атлантичним часом (Бермуди)", + "Atlantic\/Canary": "за західноєвропейським часом (Канарські Острови)", + "Atlantic\/Cape_Verde": "за часом на островах Кабо-Верде (Кабо-Верде)", + "Atlantic\/Faeroe": "за західноєвропейським часом (Фарерські Острови)", + "Atlantic\/Madeira": "за західноєвропейським часом (Мадейра)", + "Atlantic\/Reykjavik": "за Ґрінвічем (Рейкʼявік)", + "Atlantic\/South_Georgia": "за часом на острові Південна Джорджія (Південна Джорджія)", + "Atlantic\/St_Helena": "за Ґрінвічем (Острів Святої Єлени)", + "Atlantic\/Stanley": "за часом на Фолклендських Островах (Стенлі)", + "Australia\/Adelaide": "за центральноавстралійським часом (Аделаїда)", + "Australia\/Brisbane": "за східноавстралійським часом (Брісбен)", + "Australia\/Broken_Hill": "за центральноавстралійським часом (Брокен-Хілл)", + "Australia\/Currie": "за східноавстралійським часом (Каррі)", + "Australia\/Darwin": "за центральноавстралійським часом (Дарвін)", + "Australia\/Eucla": "за центральнозахідним австралійським часом (Евкла)", + "Australia\/Hobart": "за східноавстралійським часом (Гобарт)", + "Australia\/Lindeman": "за східноавстралійським часом (Ліндеман)", + "Australia\/Lord_Howe": "за часом на острові Лорд-Хау (Лорд-Хау)", + "Australia\/Melbourne": "за східноавстралійським часом (Мельбурн)", + "Australia\/Perth": "за західноавстралійським часом (Перт)", + "Australia\/Sydney": "за східноавстралійським часом (Сідней)", + "CST6CDT": "за північноамериканським центральним часом", + "EST5EDT": "за північноамериканським східним часом", + "Etc\/GMT": "за Ґрінвічем", + "Etc\/UTC": "за всесвітнім координованим часом", + "Europe\/Amsterdam": "за центральноєвропейським часом (Амстердам)", + "Europe\/Andorra": "за центральноєвропейським часом (Андорра)", + "Europe\/Astrakhan": "за московським часом (Астрахань)", + "Europe\/Athens": "за східноєвропейським часом (Афіни)", + "Europe\/Belgrade": "за центральноєвропейським часом (Белґрад)", + "Europe\/Berlin": "за центральноєвропейським часом (Берлін)", + "Europe\/Bratislava": "за центральноєвропейським часом (Братислава)", + "Europe\/Brussels": "за центральноєвропейським часом (Брюссель)", + "Europe\/Bucharest": "за східноєвропейським часом (Бухарест)", + "Europe\/Budapest": "за центральноєвропейським часом (Будапешт)", + "Europe\/Busingen": "за центральноєвропейським часом (Бюзінген)", + "Europe\/Chisinau": "за східноєвропейським часом (Кишинів)", + "Europe\/Copenhagen": "за центральноєвропейським часом (Копенгаґен)", + "Europe\/Dublin": "за Ґрінвічем (Дублін)", + "Europe\/Gibraltar": "за центральноєвропейським часом (Ґібралтар)", + "Europe\/Guernsey": "за Ґрінвічем (Ґернсі)", + "Europe\/Helsinki": "за східноєвропейським часом (Гельсінкі)", + "Europe\/Isle_of_Man": "за Ґрінвічем (Острів Мен)", + "Europe\/Jersey": "за Ґрінвічем (Джерсі)", + "Europe\/Kaliningrad": "за східноєвропейським часом (Калінінград)", + "Europe\/Kiev": "за східноєвропейським часом (Київ)", + "Europe\/Lisbon": "за західноєвропейським часом (Лісабон)", + "Europe\/Ljubljana": "за центральноєвропейським часом (Любляна)", + "Europe\/London": "за Ґрінвічем (Лондон)", + "Europe\/Luxembourg": "за центральноєвропейським часом (Люксембурґ)", + "Europe\/Madrid": "за центральноєвропейським часом (Мадрид)", + "Europe\/Malta": "за центральноєвропейським часом (Мальта)", + "Europe\/Mariehamn": "за східноєвропейським часом (Марієгамн)", + "Europe\/Minsk": "за московським часом (Мінськ)", + "Europe\/Monaco": "за центральноєвропейським часом (Монако)", + "Europe\/Moscow": "за московським часом (Москва)", + "Europe\/Oslo": "за центральноєвропейським часом (Осло)", + "Europe\/Paris": "за центральноєвропейським часом (Париж)", + "Europe\/Podgorica": "за центральноєвропейським часом (Подгориця)", + "Europe\/Prague": "за центральноєвропейським часом (Прага)", + "Europe\/Riga": "за східноєвропейським часом (Рига)", + "Europe\/Rome": "за центральноєвропейським часом (Рим)", + "Europe\/Samara": "за самарським часом (Самара)", + "Europe\/San_Marino": "за центральноєвропейським часом (Сан-Маріно)", + "Europe\/Sarajevo": "за центральноєвропейським часом (Сараєво)", + "Europe\/Saratov": "за московським часом (Саратов)", + "Europe\/Simferopol": "за московським часом (Сімферополь)", + "Europe\/Skopje": "за центральноєвропейським часом (Скопʼє)", + "Europe\/Sofia": "за східноєвропейським часом (Софія)", + "Europe\/Stockholm": "за центральноєвропейським часом (Стокгольм)", + "Europe\/Tallinn": "за східноєвропейським часом (Таллінн)", + "Europe\/Tirane": "за центральноєвропейським часом (Тирана)", + "Europe\/Ulyanovsk": "за московським часом (Ульяновськ)", + "Europe\/Uzhgorod": "за східноєвропейським часом (Ужгород)", + "Europe\/Vaduz": "за центральноєвропейським часом (Вадуц)", + "Europe\/Vatican": "за центральноєвропейським часом (Ватикан)", + "Europe\/Vienna": "за центральноєвропейським часом (Відень)", + "Europe\/Vilnius": "за східноєвропейським часом (Вільнюс)", + "Europe\/Volgograd": "за волгоградським часом (Волгоград)", + "Europe\/Warsaw": "за центральноєвропейським часом (Варшава)", + "Europe\/Zagreb": "за центральноєвропейським часом (Заґреб)", + "Europe\/Zaporozhye": "за східноєвропейським часом (Запоріжжя)", + "Europe\/Zurich": "за центральноєвропейським часом (Цюріх)", + "Indian\/Antananarivo": "за східноафриканським часом (Антананаріву)", + "Indian\/Chagos": "за часом в Індійському Океані (Чаґос)", + "Indian\/Christmas": "за часом на острові Різдва (Острів Різдва)", + "Indian\/Cocos": "за часом на Кокосових Островах (Кокосові Острови)", + "Indian\/Comoro": "за східноафриканським часом (Комори)", + "Indian\/Kerguelen": "за часом на Французьких Південних і Антарктичних територіях (Керґелен)", + "Indian\/Mahe": "за часом на Сейшельських Островах (Махе)", + "Indian\/Maldives": "за часом на Мальдівах (Мальдіви)", + "Indian\/Mauritius": "за часом на острові Маврікій (Маврікій)", + "Indian\/Mayotte": "за східноафриканським часом (Майотта)", + "Indian\/Reunion": "за часом на острові Реюньйон (Реюньйон)", + "MST7MDT": "за північноамериканським гірським часом", + "PST8PDT": "за північноамериканським тихоокеанським часом", + "Pacific\/Apia": "за часом в Апіа (Апіа)", + "Pacific\/Auckland": "за часом у Новій Зеландії (Окленд)", + "Pacific\/Bougainville": "за часом на островах Папуа-Нова Ґвінея (Буґенвіль)", + "Pacific\/Chatham": "за часом на архіпелазі Чатем (Чатем)", + "Pacific\/Easter": "за часом на острові Пасхи (Острів Пасхи)", + "Pacific\/Efate": "за часом на островах Вануату (Ефате)", + "Pacific\/Enderbury": "за часом на островах Фенікс (Ендербері)", + "Pacific\/Fakaofo": "за часом на островах Токелау (Факаофо)", + "Pacific\/Fiji": "за часом на Фіджі (Фіджі)", + "Pacific\/Funafuti": "за часом на островах Тувалу (Фунафуті)", + "Pacific\/Galapagos": "за часом Ґалапаґосу (Ґалапаґос)", + "Pacific\/Gambier": "за часом на острові Ґамбʼє (Ґамбʼєр)", + "Pacific\/Guadalcanal": "за часом на Соломонових Островах (Ґуадалканал)", + "Pacific\/Guam": "за часом на Північних Маріанських островах (Ґуам)", + "Pacific\/Honolulu": "за гавайсько-алеутським часом (Гонолулу)", + "Pacific\/Johnston": "за гавайсько-алеутським часом (Джонстон)", + "Pacific\/Kiritimati": "за часом на острові Лайн (Кірітіматі)", + "Pacific\/Kosrae": "за часом на острові Косрае (Косрае)", + "Pacific\/Kwajalein": "за часом на Маршаллових Островах (Кваджалейн)", + "Pacific\/Majuro": "за часом на Маршаллових Островах (Маджуро)", + "Pacific\/Marquesas": "за часом на Маркізьких островах (Маркізькі острови)", + "Pacific\/Midway": "за часом на острові Самоа (Мідвей)", + "Pacific\/Nauru": "за часом на острові Науру (Науру)", + "Pacific\/Niue": "за часом на острові Ніуе (Ніуе)", + "Pacific\/Norfolk": "за часом на острові Норфолк (Норфолк)", + "Pacific\/Noumea": "за часом на островах Нової Каледонії (Нумеа)", + "Pacific\/Pago_Pago": "за часом на острові Самоа (Паго-Паго)", + "Pacific\/Palau": "за часом на острові Палау (Палау)", + "Pacific\/Pitcairn": "за часом на островах Піткерн (Піткерн)", + "Pacific\/Ponape": "за часом на острові Понапе (Понапе)", + "Pacific\/Port_Moresby": "за часом на островах Папуа-Нова Ґвінея (Порт-Морсбі)", + "Pacific\/Rarotonga": "за часом на Островах Кука (Раротонґа)", + "Pacific\/Saipan": "за часом на Північних Маріанських островах (Сайпан)", + "Pacific\/Tahiti": "за часом на острові Таїті (Таїті)", + "Pacific\/Tarawa": "за часом на островах Гілберта (Тарава)", + "Pacific\/Tongatapu": "за часом на островах Тонґа (Тонґатапу)", + "Pacific\/Truk": "за часом на островах Чуук (Чуук)", + "Pacific\/Wake": "за часом на острові Вейк (Вейк)", + "Pacific\/Wallis": "за часом на островах Уолліс і Футуна (Уолліс)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ur.json b/src/Symfony/Component/Intl/Resources/data/timezones/ur.json new file mode 100644 index 0000000000000..faf08402c5a24 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ur.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.20", + "Names": { + "Africa\/Abidjan": "گرین وچ کا اصل وقت (عابدجان)", + "Africa\/Accra": "گرین وچ کا اصل وقت (اکّرا)", + "Africa\/Addis_Ababa": "مشرقی افریقہ ٹائم (عدیس ابابا)", + "Africa\/Algiers": "وسط یورپ کا وقت (الجیئرس)", + "Africa\/Asmera": "مشرقی افریقہ ٹائم (اسمارا)", + "Africa\/Bamako": "گرین وچ کا اصل وقت (بماکو)", + "Africa\/Bangui": "مغربی افریقہ ٹائم (بنگوئی)", + "Africa\/Banjul": "گرین وچ کا اصل وقت (بنجول)", + "Africa\/Bissau": "گرین وچ کا اصل وقت (بِساؤ)", + "Africa\/Blantyre": "وسطی افریقہ ٹائم (بلینٹائر)", + "Africa\/Brazzaville": "مغربی افریقہ ٹائم (برازاویلے)", + "Africa\/Bujumbura": "وسطی افریقہ ٹائم (بجمبرا)", + "Africa\/Cairo": "مشرقی یورپ کا وقت (قاہرہ)", + "Africa\/Casablanca": "مغربی یورپ کا وقت (کیسا بلانکا)", + "Africa\/Ceuta": "وسط یورپ کا وقت (سیوٹا)", + "Africa\/Conakry": "گرین وچ کا اصل وقت (کونکری)", + "Africa\/Dakar": "گرین وچ کا اصل وقت (ڈکار)", + "Africa\/Dar_es_Salaam": "مشرقی افریقہ ٹائم (دار السلام)", + "Africa\/Djibouti": "مشرقی افریقہ ٹائم (جبوتی)", + "Africa\/Douala": "مغربی افریقہ ٹائم (ڈوآلا)", + "Africa\/El_Aaiun": "مغربی یورپ کا وقت (العیون)", + "Africa\/Freetown": "گرین وچ کا اصل وقت (فری ٹاؤن)", + "Africa\/Gaborone": "وسطی افریقہ ٹائم (گبرون)", + "Africa\/Harare": "وسطی افریقہ ٹائم (ہرارے)", + "Africa\/Johannesburg": "جنوبی افریقہ سٹینڈرڈ ٹائم (جوہانسبرگ)", + "Africa\/Juba": "مشرقی افریقہ ٹائم (جوبا)", + "Africa\/Kampala": "مشرقی افریقہ ٹائم (کیمپالا)", + "Africa\/Khartoum": "وسطی افریقہ ٹائم (خرطوم)", + "Africa\/Kigali": "وسطی افریقہ ٹائم (کگالی)", + "Africa\/Kinshasa": "مغربی افریقہ ٹائم (کنشاسا)", + "Africa\/Lagos": "مغربی افریقہ ٹائم (لاگوس)", + "Africa\/Libreville": "مغربی افریقہ ٹائم (لبرے ویلے)", + "Africa\/Lome": "گرین وچ کا اصل وقت (لوم)", + "Africa\/Luanda": "مغربی افریقہ ٹائم (لوانڈا)", + "Africa\/Lubumbashi": "وسطی افریقہ ٹائم (لوبمباشی)", + "Africa\/Lusaka": "وسطی افریقہ ٹائم (لیوساکا)", + "Africa\/Malabo": "مغربی افریقہ ٹائم (ملابو)", + "Africa\/Maputo": "وسطی افریقہ ٹائم (مپوٹو)", + "Africa\/Maseru": "جنوبی افریقہ سٹینڈرڈ ٹائم (مسیرو)", + "Africa\/Mbabane": "جنوبی افریقہ سٹینڈرڈ ٹائم (مبابین)", + "Africa\/Mogadishu": "مشرقی افریقہ ٹائم (موگادیشو)", + "Africa\/Monrovia": "گرین وچ کا اصل وقت (مونروویا)", + "Africa\/Nairobi": "مشرقی افریقہ ٹائم (نیروبی)", + "Africa\/Ndjamena": "مغربی افریقہ ٹائم (اینجامینا)", + "Africa\/Niamey": "مغربی افریقہ ٹائم (نیامی)", + "Africa\/Nouakchott": "گرین وچ کا اصل وقت (نواکشوط)", + "Africa\/Ouagadougou": "گرین وچ کا اصل وقت (اؤگاڈؤگوو)", + "Africa\/Porto-Novo": "مغربی افریقہ ٹائم (پورٹو نووو)", + "Africa\/Sao_Tome": "گرین وچ کا اصل وقت (ساؤ ٹوم)", + "Africa\/Tripoli": "مشرقی یورپ کا وقت (ٹریپولی)", + "Africa\/Tunis": "وسط یورپ کا وقت (تیونس)", + "Africa\/Windhoek": "وسطی افریقہ ٹائم (ونڈہوک)", + "America\/Adak": "ہوائی الیوٹیئن ٹائم (اداک)", + "America\/Anchorage": "الاسکا ٹائم (اینکریج)", + "America\/Anguilla": "اٹلانٹک ٹائم (انگویلا)", + "America\/Antigua": "اٹلانٹک ٹائم (انٹیگوا)", + "America\/Araguaina": "برازیلیا ٹائم (اراگویانا)", + "America\/Argentina\/La_Rioja": "ارجنٹینا ٹائم (لا ریئوجا)", + "America\/Argentina\/Rio_Gallegos": "ارجنٹینا ٹائم (ریو گالیگوس)", + "America\/Argentina\/Salta": "ارجنٹینا ٹائم (سالٹا)", + "America\/Argentina\/San_Juan": "ارجنٹینا ٹائم (سان جوآن)", + "America\/Argentina\/San_Luis": "مغربی ارجنٹینا کا وقت (سان لوئس)", + "America\/Argentina\/Tucuman": "ارجنٹینا ٹائم (ٹوکومین)", + "America\/Argentina\/Ushuaia": "ارجنٹینا ٹائم (اوشوآئیا)", + "America\/Aruba": "اٹلانٹک ٹائم (اروبا)", + "America\/Asuncion": "پیراگوئے کا وقت (اسنسیئن)", + "America\/Bahia": "برازیلیا ٹائم (باہیا)", + "America\/Bahia_Banderas": "سنٹرل ٹائم (بہیا بندراز)", + "America\/Barbados": "اٹلانٹک ٹائم (بارباڈوس)", + "America\/Belem": "برازیلیا ٹائم (بیلیم)", + "America\/Belize": "سنٹرل ٹائم (بیلائز)", + "America\/Blanc-Sablon": "اٹلانٹک ٹائم (بلانک سبلون)", + "America\/Boa_Vista": "امیزون ٹائم (بوآ وسٹا)", + "America\/Bogota": "کولمبیا ٹائم (بگوٹا)", + "America\/Boise": "ماؤنٹین ٹائم (بوائس)", + "America\/Buenos_Aires": "ارجنٹینا ٹائم (بیونس آئرس)", + "America\/Cambridge_Bay": "ماؤنٹین ٹائم (کیمبرج کی کھاڑی)", + "America\/Campo_Grande": "امیزون ٹائم (کیمپو گرینڈ)", + "America\/Cancun": "ایسٹرن ٹائم (کنکیون)", + "America\/Caracas": "وینزوئیلا کا وقت (کراکاس)", + "America\/Catamarca": "ارجنٹینا ٹائم (کیٹامارکا)", + "America\/Cayenne": "فرینچ گیانا کا وقت (کائین)", + "America\/Cayman": "ایسٹرن ٹائم (کیمین)", + "America\/Chicago": "سنٹرل ٹائم (شکاگو)", + "America\/Chihuahua": "میکسیکن پیسفک ٹائم (چیہوآہوآ)", + "America\/Coral_Harbour": "ایسٹرن ٹائم (اٹیکوکن)", + "America\/Cordoba": "ارجنٹینا ٹائم (کورڈوبا)", + "America\/Costa_Rica": "سنٹرل ٹائم (کوسٹا ریکا)", + "America\/Creston": "ماؤنٹین ٹائم (کریسٹون)", + "America\/Cuiaba": "امیزون ٹائم (کوئیابا)", + "America\/Curacao": "اٹلانٹک ٹائم (کیوراکاؤ)", + "America\/Danmarkshavn": "گرین وچ کا اصل وقت (ڈنمارک شاون)", + "America\/Dawson": "پیسفک ٹائم (ڈاؤسن)", + "America\/Dawson_Creek": "ماؤنٹین ٹائم (ڈاؤسن کریک)", + "America\/Denver": "ماؤنٹین ٹائم (ڈینور)", + "America\/Detroit": "ایسٹرن ٹائم (ڈیٹرائٹ)", + "America\/Dominica": "اٹلانٹک ٹائم (ڈومنیکا)", + "America\/Edmonton": "ماؤنٹین ٹائم (ایڈمونٹن)", + "America\/El_Salvador": "سنٹرل ٹائم (ال سلواڈور)", + "America\/Fort_Nelson": "ماؤنٹین ٹائم (فورٹ نیلسن)", + "America\/Fortaleza": "برازیلیا ٹائم (فورٹالیزا)", + "America\/Glace_Bay": "اٹلانٹک ٹائم (گلیس کی کھاڑی)", + "America\/Godthab": "مغربی گرین لینڈ ٹائم (نوک)", + "America\/Goose_Bay": "اٹلانٹک ٹائم (گوس کی کھاڑی)", + "America\/Grand_Turk": "ایسٹرن ٹائم (عظیم ترک)", + "America\/Grenada": "اٹلانٹک ٹائم (غرناطہ)", + "America\/Guadeloupe": "اٹلانٹک ٹائم (گواڈیلوپ)", + "America\/Guatemala": "سنٹرل ٹائم (گواٹے مالا)", + "America\/Guayaquil": "ایکواڈور کا وقت (گوآیاکوئل)", + "America\/Guyana": "گیانا کا وقت (گیانا)", + "America\/Halifax": "اٹلانٹک ٹائم (ہیلیفیکس)", + "America\/Havana": "کیوبا ٹائم (ہوانا)", + "America\/Hermosillo": "میکسیکن پیسفک ٹائم (ہرموسیلو)", + "America\/Indiana\/Knox": "سنٹرل ٹائم (کنوکس، انڈیانا)", + "America\/Indiana\/Marengo": "ایسٹرن ٹائم (مرینگو، انڈیانا)", + "America\/Indiana\/Petersburg": "ایسٹرن ٹائم (پیٹرزبرگ، انڈیانا)", + "America\/Indiana\/Tell_City": "سنٹرل ٹائم (ٹیل سٹی، انڈیانا)", + "America\/Indiana\/Vevay": "ایسٹرن ٹائم (ویوے، انڈیانا)", + "America\/Indiana\/Vincennes": "ایسٹرن ٹائم (ونسینیز، انڈیانا)", + "America\/Indiana\/Winamac": "ایسٹرن ٹائم (وینامیک، انڈیانا)", + "America\/Indianapolis": "ایسٹرن ٹائم (انڈیاناپولس)", + "America\/Inuvik": "ماؤنٹین ٹائم (انووِک)", + "America\/Iqaluit": "ایسٹرن ٹائم (ایکالوئٹ)", + "America\/Jamaica": "ایسٹرن ٹائم (جمائیکا)", + "America\/Jujuy": "ارجنٹینا ٹائم (جوجوئی)", + "America\/Juneau": "الاسکا ٹائم (جونیئو)", + "America\/Kentucky\/Monticello": "ایسٹرن ٹائم (مونٹیسیلو، کینٹوکی)", + "America\/Kralendijk": "اٹلانٹک ٹائم (کرالینڈیجک)", + "America\/La_Paz": "بولیویا کا وقت (لا پاز)", + "America\/Lima": "پیرو کا وقت (لیما)", + "America\/Los_Angeles": "پیسفک ٹائم (لاس اینجلس)", + "America\/Louisville": "ایسٹرن ٹائم (لوئس ویلے)", + "America\/Lower_Princes": "اٹلانٹک ٹائم (لوور پرنسس کوارٹر)", + "America\/Maceio": "برازیلیا ٹائم (میسیئو)", + "America\/Managua": "سنٹرل ٹائم (مناگوآ)", + "America\/Manaus": "امیزون ٹائم (مناؤس)", + "America\/Marigot": "اٹلانٹک ٹائم (میریگوٹ)", + "America\/Martinique": "اٹلانٹک ٹائم (مارٹینک)", + "America\/Matamoros": "سنٹرل ٹائم (میٹاموروس)", + "America\/Mazatlan": "میکسیکن پیسفک ٹائم (میزٹلان)", + "America\/Mendoza": "ارجنٹینا ٹائم (مینڈوزا)", + "America\/Menominee": "سنٹرل ٹائم (مینومینی)", + "America\/Merida": "سنٹرل ٹائم (میریڈا)", + "America\/Metlakatla": "الاسکا ٹائم (میٹلا کاٹلا)", + "America\/Mexico_City": "سنٹرل ٹائم (میکسیکو سٹی)", + "America\/Miquelon": "سینٹ پیئر اور مکلیئون ٹائم (میکلیئون)", + "America\/Moncton": "اٹلانٹک ٹائم (مونکٹن)", + "America\/Monterrey": "سنٹرل ٹائم (مونٹیری)", + "America\/Montevideo": "یوروگوئے کا وقت (مونٹی ویڈیو)", + "America\/Montserrat": "اٹلانٹک ٹائم (مونٹسیراٹ)", + "America\/Nassau": "ایسٹرن ٹائم (نساؤ)", + "America\/New_York": "ایسٹرن ٹائم (نیو یارک)", + "America\/Nipigon": "ایسٹرن ٹائم (نپیگون)", + "America\/Nome": "الاسکا ٹائم (نوم)", + "America\/Noronha": "فرنانڈو ڈی نورنہا کا وقت (نورونہا)", + "America\/North_Dakota\/Beulah": "سنٹرل ٹائم (بیولاہ، شمالی ڈکوٹا)", + "America\/North_Dakota\/Center": "سنٹرل ٹائم (وسط، شمالی ڈکوٹا)", + "America\/North_Dakota\/New_Salem": "سنٹرل ٹائم (نیو سلیم، شمالی ڈکوٹا)", + "America\/Ojinaga": "ماؤنٹین ٹائم (اوجیناگا)", + "America\/Panama": "ایسٹرن ٹائم (پنامہ)", + "America\/Pangnirtung": "ایسٹرن ٹائم (پینگنِرٹنگ)", + "America\/Paramaribo": "سورینام کا وقت (پراماریبو)", + "America\/Phoenix": "ماؤنٹین ٹائم (فینکس)", + "America\/Port-au-Prince": "ایسٹرن ٹائم (پورٹ او پرنس)", + "America\/Port_of_Spain": "اٹلانٹک ٹائم (پورٹ آف اسپین)", + "America\/Porto_Velho": "امیزون ٹائم (پورٹو ویلہو)", + "America\/Puerto_Rico": "اٹلانٹک ٹائم (پیورٹو ریکو)", + "America\/Punta_Arenas": "چلی کا وقت (پنٹا یریناس)", + "America\/Rainy_River": "سنٹرل ٹائم (رینی ریور)", + "America\/Rankin_Inlet": "سنٹرل ٹائم (رینکن انلیٹ)", + "America\/Recife": "برازیلیا ٹائم (ریسائف)", + "America\/Regina": "سنٹرل ٹائم (ریجینا)", + "America\/Resolute": "سنٹرل ٹائم (ریزولیوٹ)", + "America\/Santa_Isabel": "شمال مغربی میکسیکو ٹائم (سانتا ایزابیل)", + "America\/Santarem": "برازیلیا ٹائم (سنٹارین)", + "America\/Santiago": "چلی کا وقت (سنٹیاگو)", + "America\/Santo_Domingo": "اٹلانٹک ٹائم (سانتو ڈومنگو)", + "America\/Sao_Paulo": "برازیلیا ٹائم (ساؤ پالو)", + "America\/Scoresbysund": "مشرقی گرین لینڈ ٹائم (اسکورز بائی سنڈ)", + "America\/Sitka": "الاسکا ٹائم (سیٹکا)", + "America\/St_Barthelemy": "اٹلانٹک ٹائم (سینٹ برتھیلمی)", + "America\/St_Johns": "نیو فاؤنڈ لینڈ ٹائم (سینٹ جانز)", + "America\/St_Kitts": "اٹلانٹک ٹائم (سینٹ کٹس)", + "America\/St_Lucia": "اٹلانٹک ٹائم (سینٹ لوسیا)", + "America\/St_Thomas": "اٹلانٹک ٹائم (سینٹ تھامس)", + "America\/St_Vincent": "اٹلانٹک ٹائم (سینٹ ونسنٹ)", + "America\/Swift_Current": "سنٹرل ٹائم (سوِفٹ کرنٹ)", + "America\/Tegucigalpa": "سنٹرل ٹائم (ٹیگوسیگالپے)", + "America\/Thule": "اٹلانٹک ٹائم (تھولو)", + "America\/Thunder_Bay": "ایسٹرن ٹائم (تھنڈر بے)", + "America\/Tijuana": "پیسفک ٹائم (تیجوآنا)", + "America\/Toronto": "ایسٹرن ٹائم (ٹورنٹو)", + "America\/Tortola": "اٹلانٹک ٹائم (ٹورٹولا)", + "America\/Vancouver": "پیسفک ٹائم (وینکوور)", + "America\/Whitehorse": "پیسفک ٹائم (وہائٹ ہارس)", + "America\/Winnipeg": "سنٹرل ٹائم (ونّیپیگ)", + "America\/Yakutat": "الاسکا ٹائم (یکوٹیٹ)", + "America\/Yellowknife": "ماؤنٹین ٹائم (ایلو نائف)", + "Antarctica\/Casey": "ویسٹرن آسٹریلیا ٹائم (کیسی)", + "Antarctica\/Davis": "ڈیوس ٹائم (ڈیوس)", + "Antarctica\/DumontDUrville": "ڈومونٹ-ڈی’ارویلے ٹائم (ڈومونٹ ڈی ارویلے)", + "Antarctica\/Macquarie": "مکوآری آئلینڈ کا وقت (میکواری)", + "Antarctica\/Mawson": "ماؤسن ٹائم (ماؤسن)", + "Antarctica\/McMurdo": "نیوزی لینڈ کا وقت (میک مرڈو)", + "Antarctica\/Palmer": "چلی کا وقت (پلمیر)", + "Antarctica\/Rothera": "روتھیرا کا وقت (روتھیرا)", + "Antarctica\/Syowa": "سیووا ٹائم (سیووا)", + "Antarctica\/Troll": "گرین وچ کا اصل وقت (ٹرول)", + "Antarctica\/Vostok": "ووسٹاک کا وقت (ووستوک)", + "Arctic\/Longyearbyen": "وسط یورپ کا وقت (لانگ ایئر بین)", + "Asia\/Aden": "عرب کا وقت (عدن)", + "Asia\/Almaty": "مشرقی قزاخستان کا وقت (الماٹی)", + "Asia\/Amman": "مشرقی یورپ کا وقت (امّان)", + "Asia\/Anadyr": "انیدر ٹائم (انیدر)", + "Asia\/Aqtau": "مغربی قزاخستان کا وقت (اکتاؤ)", + "Asia\/Aqtobe": "مغربی قزاخستان کا وقت (اکٹوب)", + "Asia\/Ashgabat": "ترکمانستان کا وقت (اشغبت)", + "Asia\/Atyrau": "مغربی قزاخستان کا وقت (آتیراؤ)", + "Asia\/Baghdad": "عرب کا وقت (بغداد)", + "Asia\/Bahrain": "عرب کا وقت (بحرین)", + "Asia\/Baku": "آذربائیجان کا وقت (باکو)", + "Asia\/Bangkok": "ہند چین ٹائم (بنکاک)", + "Asia\/Beirut": "مشرقی یورپ کا وقت (بیروت)", + "Asia\/Bishkek": "کرغستان کا وقت (بشکیک)", + "Asia\/Brunei": "برونئی دارالسلام ٹائم (برونئی)", + "Asia\/Calcutta": "ہندوستان کا معیاری وقت (کولکاتا)", + "Asia\/Chita": "یکوتسک ٹائم (چیتا)", + "Asia\/Choibalsan": "کوئبلسان ٹائم (چوئبالسان)", + "Asia\/Colombo": "ہندوستان کا معیاری وقت (کولمبو)", + "Asia\/Damascus": "مشرقی یورپ کا وقت (دمشق)", + "Asia\/Dhaka": "بنگلہ دیش کا وقت (ڈھاکہ)", + "Asia\/Dili": "مشرقی تیمور ٹائم (ڈلی)", + "Asia\/Dubai": "خلیج کا معیاری وقت (دبئی)", + "Asia\/Dushanbe": "تاجکستان کا وقت (دوشانبے)", + "Asia\/Famagusta": "مشرقی یورپ کا وقت (فاماگوسٹا)", + "Asia\/Gaza": "مشرقی یورپ کا وقت (غزہ)", + "Asia\/Hebron": "مشرقی یورپ کا وقت (ہیبرون)", + "Asia\/Hong_Kong": "ہانگ کانگ ٹائم (ہانگ کانگ)", + "Asia\/Hovd": "ہووڈ ٹائم (ہووارڈ)", + "Asia\/Irkutsk": "ارکتسک ٹائم (ارکتسک)", + "Asia\/Jakarta": "مغربی انڈونیشیا ٹائم (جکارتہ)", + "Asia\/Jayapura": "مشرقی انڈونیشیا ٹائم (جے پورہ)", + "Asia\/Jerusalem": "اسرائیل کا وقت (یروشلم)", + "Asia\/Kabul": "افغانستان کا وقت (کابل)", + "Asia\/Kamchatka": "پیٹروپاؤلووسک-کیمچسکی ٹائم (کیمچٹکا)", + "Asia\/Karachi": "پاکستان کا وقت (کراچی)", + "Asia\/Katmandu": "نیپال کا وقت (کاٹھمنڈو)", + "Asia\/Khandyga": "یکوتسک ٹائم (خندیگا)", + "Asia\/Krasnoyarsk": "کریسنویارسک ٹائم (کریسنویارسک)", + "Asia\/Kuala_Lumpur": "ملیشیا ٹائم (کوالا لمپور)", + "Asia\/Kuching": "ملیشیا ٹائم (کیوچنگ)", + "Asia\/Kuwait": "عرب کا وقت (کویت)", + "Asia\/Macau": "چین ٹائم (مکاؤ)", + "Asia\/Magadan": "میگیدن ٹائم (میگیدن)", + "Asia\/Makassar": "وسطی انڈونیشیا ٹائم (مکاسر)", + "Asia\/Manila": "فلپائن ٹائم (منیلا)", + "Asia\/Muscat": "خلیج کا معیاری وقت (مسقط)", + "Asia\/Nicosia": "مشرقی یورپ کا وقت (نکوسیا)", + "Asia\/Novokuznetsk": "کریسنویارسک ٹائم (نوووکیوزنیسک)", + "Asia\/Novosibirsk": "نوووسیبرسک ٹائم (نوووسِبِرسک)", + "Asia\/Omsk": "اومسک ٹائم (اومسک)", + "Asia\/Oral": "مغربی قزاخستان کا وقت (اورال)", + "Asia\/Phnom_Penh": "ہند چین ٹائم (پنوم پن)", + "Asia\/Pontianak": "مغربی انڈونیشیا ٹائم (پونٹیانک)", + "Asia\/Pyongyang": "کوریا ٹائم (پیونگ یانگ)", + "Asia\/Qatar": "عرب کا وقت (قطر)", + "Asia\/Qostanay": "مشرقی قزاخستان کا وقت (کوستانے)", + "Asia\/Qyzylorda": "مغربی قزاخستان کا وقت (کیزیلورڈا)", + "Asia\/Rangoon": "میانمار ٹائم (رنگون)", + "Asia\/Riyadh": "عرب کا وقت (ریاض)", + "Asia\/Saigon": "ہند چین ٹائم (ہو چی منہ سٹی)", + "Asia\/Sakhalin": "سخالین ٹائم (سخالین)", + "Asia\/Samarkand": "ازبکستان کا وقت (سمرقند)", + "Asia\/Seoul": "کوریا ٹائم (سیئول)", + "Asia\/Shanghai": "چین ٹائم (شنگھائی)", + "Asia\/Singapore": "سنگاپور سٹینڈرڈ ٹائم (سنگاپور)", + "Asia\/Srednekolymsk": "میگیدن ٹائم (سرہدنیکولیمسک)", + "Asia\/Taipei": "تائی پیئی ٹائم (تائپے)", + "Asia\/Tashkent": "ازبکستان کا وقت (تاشقند)", + "Asia\/Tbilisi": "جارجیا کا وقت (طبلیسی)", + "Asia\/Tehran": "ایران کا وقت (تہران)", + "Asia\/Thimphu": "بھوٹان کا وقت (تھمپو)", + "Asia\/Tokyo": "جاپان ٹائم (ٹوکیو)", + "Asia\/Ulaanbaatar": "یولان بیتور ٹائم (اولان باتار)", + "Asia\/Ust-Nera": "ولادی ووستک ٹائم (اوست-نیرا)", + "Asia\/Vientiane": "ہند چین ٹائم (وینٹیانا)", + "Asia\/Vladivostok": "ولادی ووستک ٹائم (ولادی ووستک)", + "Asia\/Yakutsk": "یکوتسک ٹائم (یکوتسک)", + "Asia\/Yekaterinburg": "یکاٹیرِنبرگ ٹائم (یکاٹیرِنبرگ)", + "Asia\/Yerevan": "آرمینیا کا وقت (یریوان)", + "Atlantic\/Azores": "ازوریس کا وقت (ازوریس)", + "Atlantic\/Bermuda": "اٹلانٹک ٹائم (برمودا)", + "Atlantic\/Canary": "مغربی یورپ کا وقت (کینری)", + "Atlantic\/Cape_Verde": "کیپ ورڈی ٹائم (کیپ ورڈی)", + "Atlantic\/Faeroe": "مغربی یورپ کا وقت (فارو)", + "Atlantic\/Madeira": "مغربی یورپ کا وقت (مڈیئرا)", + "Atlantic\/Reykjavik": "گرین وچ کا اصل وقت (ریکجاوک)", + "Atlantic\/South_Georgia": "جنوبی جارجیا ٹائم (جنوبی جارجیا)", + "Atlantic\/St_Helena": "گرین وچ کا اصل وقت (سینٹ ہیلینا)", + "Atlantic\/Stanley": "فاک لینڈ آئلینڈز کا وقت (اسٹینلے)", + "Australia\/Adelaide": "سنٹرل آسٹریلیا ٹائم (اڈیلائڈ)", + "Australia\/Brisbane": "ایسٹرن آسٹریلیا ٹائم (برسبین)", + "Australia\/Broken_Hill": "سنٹرل آسٹریلیا ٹائم (بروکن ہِل)", + "Australia\/Currie": "ایسٹرن آسٹریلیا ٹائم (کیوری)", + "Australia\/Darwin": "سنٹرل آسٹریلیا ٹائم (ڈارون)", + "Australia\/Eucla": "آسٹریلین سنٹرل ویسٹرن ٹائم (ایوکلا)", + "Australia\/Hobart": "ایسٹرن آسٹریلیا ٹائم (ہوبارٹ)", + "Australia\/Lindeman": "ایسٹرن آسٹریلیا ٹائم (لِنڈمین)", + "Australia\/Lord_Howe": "لارڈ ہووے ٹائم (لارڈ ہووے)", + "Australia\/Melbourne": "ایسٹرن آسٹریلیا ٹائم (ملبورن)", + "Australia\/Perth": "ویسٹرن آسٹریلیا ٹائم (پرتھ)", + "Australia\/Sydney": "ایسٹرن آسٹریلیا ٹائم (سڈنی)", + "CST6CDT": "سنٹرل ٹائم", + "EST5EDT": "ایسٹرن ٹائم", + "Etc\/GMT": "گرین وچ کا اصل وقت", + "Etc\/UTC": "کوآرڈینیٹڈ یونیورسل ٹائم", + "Europe\/Amsterdam": "وسط یورپ کا وقت (ایمسٹرڈم)", + "Europe\/Andorra": "وسط یورپ کا وقت (انڈورا)", + "Europe\/Astrakhan": "ماسکو ٹائم (استراخان)", + "Europe\/Athens": "مشرقی یورپ کا وقت (ایتھنز)", + "Europe\/Belgrade": "وسط یورپ کا وقت (بلغراد)", + "Europe\/Berlin": "وسط یورپ کا وقت (برلن)", + "Europe\/Bratislava": "وسط یورپ کا وقت (بریٹِسلاوا)", + "Europe\/Brussels": "وسط یورپ کا وقت (برسلز)", + "Europe\/Bucharest": "مشرقی یورپ کا وقت (بخارسٹ)", + "Europe\/Budapest": "وسط یورپ کا وقت (بڈاپسٹ)", + "Europe\/Busingen": "وسط یورپ کا وقت (بزنجن)", + "Europe\/Chisinau": "مشرقی یورپ کا وقت (چیسیناؤ)", + "Europe\/Copenhagen": "وسط یورپ کا وقت (کوپن ہیگن)", + "Europe\/Dublin": "گرین وچ کا اصل وقت (ڈبلن)", + "Europe\/Gibraltar": "وسط یورپ کا وقت (جبل الطارق)", + "Europe\/Guernsey": "گرین وچ کا اصل وقت (گرنزی)", + "Europe\/Helsinki": "مشرقی یورپ کا وقت (ہیلسنکی)", + "Europe\/Isle_of_Man": "گرین وچ کا اصل وقت (آئل آف مین)", + "Europe\/Jersey": "گرین وچ کا اصل وقت (جرسی)", + "Europe\/Kaliningrad": "مشرقی یورپ کا وقت (کالينينغراد)", + "Europe\/Kiev": "مشرقی یورپ کا وقت (کیوو)", + "Europe\/Lisbon": "مغربی یورپ کا وقت (لسبن)", + "Europe\/Ljubljana": "وسط یورپ کا وقت (لیوبلیانا)", + "Europe\/London": "گرین وچ کا اصل وقت (لندن)", + "Europe\/Luxembourg": "وسط یورپ کا وقت (لگژمبرگ)", + "Europe\/Madrid": "وسط یورپ کا وقت (میڈرڈ)", + "Europe\/Malta": "وسط یورپ کا وقت (مالٹا)", + "Europe\/Mariehamn": "مشرقی یورپ کا وقت (میریہام)", + "Europe\/Minsk": "ماسکو ٹائم (مِنسک)", + "Europe\/Monaco": "وسط یورپ کا وقت (موناکو)", + "Europe\/Moscow": "ماسکو ٹائم (ماسکو)", + "Europe\/Oslo": "وسط یورپ کا وقت (اوسلو)", + "Europe\/Paris": "وسط یورپ کا وقت (پیرس)", + "Europe\/Podgorica": "وسط یورپ کا وقت (پوڈگورسیا)", + "Europe\/Prague": "وسط یورپ کا وقت (پراگ)", + "Europe\/Riga": "مشرقی یورپ کا وقت (ریگا)", + "Europe\/Rome": "وسط یورپ کا وقت (روم)", + "Europe\/Samara": "سمارا ٹائم (سمارا)", + "Europe\/San_Marino": "وسط یورپ کا وقت (سان ماریانو)", + "Europe\/Sarajevo": "وسط یورپ کا وقت (سراجیوو)", + "Europe\/Saratov": "ماسکو ٹائم (سیراٹو)", + "Europe\/Simferopol": "ماسکو ٹائم (سمفروپول)", + "Europe\/Skopje": "وسط یورپ کا وقت (اسکوپجے)", + "Europe\/Sofia": "مشرقی یورپ کا وقت (صوفیہ)", + "Europe\/Stockholm": "وسط یورپ کا وقت (اسٹاک ہوم)", + "Europe\/Tallinn": "مشرقی یورپ کا وقت (ٹالن)", + "Europe\/Tirane": "وسط یورپ کا وقت (ٹیرانی)", + "Europe\/Ulyanovsk": "ماسکو ٹائم (الیانوسک)", + "Europe\/Uzhgorod": "مشرقی یورپ کا وقت (ازگوروڈ)", + "Europe\/Vaduz": "وسط یورپ کا وقت (ویڈوز)", + "Europe\/Vatican": "وسط یورپ کا وقت (واٹیکن)", + "Europe\/Vienna": "وسط یورپ کا وقت (ویانا)", + "Europe\/Vilnius": "مشرقی یورپ کا وقت (وِلنیئس)", + "Europe\/Volgograd": "وولگوگراد ٹائم (وولگوگراد)", + "Europe\/Warsaw": "وسط یورپ کا وقت (وارسا)", + "Europe\/Zagreb": "وسط یورپ کا وقت (زیگریب)", + "Europe\/Zaporozhye": "مشرقی یورپ کا وقت (زیپوروزائی)", + "Europe\/Zurich": "وسط یورپ کا وقت (زیورخ)", + "Indian\/Antananarivo": "مشرقی افریقہ ٹائم (انٹاناناریوو)", + "Indian\/Chagos": "بحر ہند ٹائم (چاگوس)", + "Indian\/Christmas": "کرسمس آئلینڈ ٹائم (کرسمس)", + "Indian\/Cocos": "کوکوس آئلینڈز ٹائم (کوکوس)", + "Indian\/Comoro": "مشرقی افریقہ ٹائم (کومورو)", + "Indian\/Kerguelen": "فرینچ جنوبی اور انٹارکٹک ٹائم (کرگیولین)", + "Indian\/Mahe": "سیشلیز ٹائم (ماہی)", + "Indian\/Maldives": "مالدیپ کا وقت (مالدیپ)", + "Indian\/Mauritius": "ماریشس ٹائم (ماریشس)", + "Indian\/Mayotte": "مشرقی افریقہ ٹائم (مایوٹ)", + "Indian\/Reunion": "ری یونین ٹائم (ری یونین)", + "MST7MDT": "ماؤنٹین ٹائم", + "PST8PDT": "پیسفک ٹائم", + "Pacific\/Apia": "ایپیا ٹائم (اپیا)", + "Pacific\/Auckland": "نیوزی لینڈ کا وقت (آکلینڈ)", + "Pacific\/Bougainville": "پاپوآ نیو گنی ٹائم (بوگینولے)", + "Pacific\/Chatham": "چیتھم ٹائم (چیتھم)", + "Pacific\/Easter": "ایسٹر آئلینڈ کا وقت (ایسٹر)", + "Pacific\/Efate": "وانوآٹو ٹائم (ایفیٹ)", + "Pacific\/Enderbury": "فینکس آئلینڈز ٹائم (اینڈربری)", + "Pacific\/Fakaofo": "ٹوکیلاؤ ٹائم (فکاؤفو)", + "Pacific\/Fiji": "فجی ٹائم (فجی)", + "Pacific\/Funafuti": "ٹوالو ٹائم (فیونافیوٹی)", + "Pacific\/Galapagos": "گالاپاگوز کا وقت (گیلاپیگوس)", + "Pacific\/Gambier": "گیمبیئر ٹائم (گامبیئر)", + "Pacific\/Guadalcanal": "سولمن آئلینڈز ٹائم (گواڈل کینال)", + "Pacific\/Guam": "چامورو سٹینڈرڈ ٹائم (گوآم)", + "Pacific\/Honolulu": "ہوائی الیوٹیئن ٹائم (ہونولولو)", + "Pacific\/Johnston": "ہوائی الیوٹیئن ٹائم (جانسٹن)", + "Pacific\/Kiritimati": "لائن آئلینڈز ٹائم (کریتیماٹی)", + "Pacific\/Kosrae": "کوسرے ٹائم (کوسرائی)", + "Pacific\/Kwajalein": "مارشل آئلینڈز ٹائم (کواجیلین)", + "Pacific\/Majuro": "مارشل آئلینڈز ٹائم (مجورو)", + "Pacific\/Marquesas": "مارکیسس ٹائم (مارکیساس)", + "Pacific\/Midway": "ساموآ ٹائم (مڈوے)", + "Pacific\/Nauru": "ناؤرو ٹائم (ناؤرو)", + "Pacific\/Niue": "نیئو ٹائم (نیئو)", + "Pacific\/Norfolk": "نارفوک آئلینڈ کا وقت (نورفوک)", + "Pacific\/Noumea": "نیو کیلیڈونیا ٹائم (نؤمیا)", + "Pacific\/Pago_Pago": "ساموآ ٹائم (پاگو پاگو)", + "Pacific\/Palau": "پلاؤ ٹائم (پلاؤ)", + "Pacific\/Pitcairn": "پٹکائرن ٹائم (پٹکائرن)", + "Pacific\/Ponape": "پوناپے ٹائم (پونپیئی)", + "Pacific\/Port_Moresby": "پاپوآ نیو گنی ٹائم (پورٹ موریسبی)", + "Pacific\/Rarotonga": "کک آئلینڈز ٹائم (راروٹونگا)", + "Pacific\/Saipan": "چامورو سٹینڈرڈ ٹائم (سائپین)", + "Pacific\/Tahiti": "تاہیتی ٹائم (تاہیتی)", + "Pacific\/Tarawa": "جلبرٹ آئلینڈز ٹائم (ٹراوا)", + "Pacific\/Tongatapu": "ٹونگا ٹائم (ٹونگاٹاپو)", + "Pacific\/Truk": "چوک ٹائم (چیوک)", + "Pacific\/Wake": "ویک آئلینڈ ٹائم (ویک)", + "Pacific\/Wallis": "والیز اور فٹونا ٹائم (ولّیس)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/ur_IN.json b/src/Symfony/Component/Intl/Resources/data/timezones/ur_IN.json new file mode 100644 index 0000000000000..53c61f7f2d0cc --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/ur_IN.json @@ -0,0 +1,132 @@ +{ + "Version": "2.1.47.71", + "Names": { + "Africa\/Abidjan": "گرین وچ مین ٹائم (Abidjan)", + "Africa\/Accra": "گرین وچ مین ٹائم (اکرا)", + "Africa\/Algiers": "وسطی یورپ کا وقت (Algiers)", + "Africa\/Bamako": "گرین وچ مین ٹائم (Bamako)", + "Africa\/Banjul": "گرین وچ مین ٹائم (Banjul)", + "Africa\/Bissau": "گرین وچ مین ٹائم (Bissau)", + "Africa\/Ceuta": "وسطی یورپ کا وقت (Ceuta)", + "Africa\/Conakry": "گرین وچ مین ٹائم (Conakry)", + "Africa\/Dakar": "گرین وچ مین ٹائم (Dakar)", + "Africa\/Freetown": "گرین وچ مین ٹائم (Freetown)", + "Africa\/Lome": "گرین وچ مین ٹائم (Lome)", + "Africa\/Monrovia": "گرین وچ مین ٹائم (Monrovia)", + "Africa\/Nouakchott": "گرین وچ مین ٹائم (Nouakchott)", + "Africa\/Ouagadougou": "گرین وچ مین ٹائم (Ouagadougou)", + "Africa\/Sao_Tome": "گرین وچ مین ٹائم (Sao Tome)", + "Africa\/Tunis": "وسطی یورپ کا وقت (Tunis)", + "America\/Araguaina": "برازیلیا ٹائم (Araguaina)", + "America\/Argentina\/San_Luis": "مغربی ارجنٹینا ٹائم (San Luis)", + "America\/Asuncion": "پیراگوئے ٹائم (Asuncion)", + "America\/Bahia": "برازیلیا ٹائم (Bahia)", + "America\/Belem": "برازیلیا ٹائم (Belem)", + "America\/Boa_Vista": "ایمیزون ٹائم (Boa Vista)", + "America\/Bogota": "کولمبیا ٹائم (Bogota)", + "America\/Campo_Grande": "ایمیزون ٹائم (Campo Grande)", + "America\/Caracas": "وینزوئیلا ٹائم (Caracas)", + "America\/Cayenne": "فرینچ گیانا ٹائم (Cayenne)", + "America\/Cuiaba": "ایمیزون ٹائم (Cuiaba)", + "America\/Danmarkshavn": "گرین وچ مین ٹائم (Danmarkshavn)", + "America\/Fortaleza": "برازیلیا ٹائم (Fortaleza)", + "America\/Guayaquil": "ایکواڈور ٹائم (Guayaquil)", + "America\/Guyana": "گیانا ٹائم (Guyana)", + "America\/La_Paz": "بولیویا ٹائم (La Paz)", + "America\/Lima": "پیرو ٹائم (Lima)", + "America\/Maceio": "برازیلیا ٹائم (Maceio)", + "America\/Manaus": "ایمیزون ٹائم (Manaus)", + "America\/Montevideo": "یوروگوئے ٹائم (Montevideo)", + "America\/Noronha": "فرنانڈو ڈی نورنہا ٹائم (Noronha)", + "America\/Paramaribo": "سورینام ٹائم (Paramaribo)", + "America\/Porto_Velho": "ایمیزون ٹائم (Porto Velho)", + "America\/Punta_Arenas": "چلی ٹائم (Punta Arenas)", + "America\/Recife": "برازیلیا ٹائم (Recife)", + "America\/Santarem": "برازیلیا ٹائم (Santarem)", + "America\/Santiago": "چلی ٹائم (Santiago)", + "America\/Sao_Paulo": "برازیلیا ٹائم (Sao Paulo)", + "Antarctica\/Macquarie": "مکوآری آئلینڈ ٹائم (Macquarie)", + "Antarctica\/McMurdo": "نیوزی لینڈ ٹائم (McMurdo)", + "Antarctica\/Palmer": "چلی ٹائم (Palmer)", + "Antarctica\/Rothera": "روتھیرا ٹائم (Rothera)", + "Antarctica\/Troll": "گرین وچ مین ٹائم (Troll)", + "Antarctica\/Vostok": "ووسٹاک ٹائم (Vostok)", + "Arctic\/Longyearbyen": "وسطی یورپ کا وقت (Longyearbyen)", + "Asia\/Aden": "عرب ٹائم (Aden)", + "Asia\/Almaty": "مشرقی قزاخستان ٹائم (Almaty)", + "Asia\/Aqtau": "مغربی قزاخستان ٹائم (Aqtau)", + "Asia\/Aqtobe": "مغربی قزاخستان ٹائم (Aqtobe)", + "Asia\/Ashgabat": "ترکمانستان ٹائم (Ashgabat)", + "Asia\/Atyrau": "مغربی قزاخستان ٹائم (Atyrau)", + "Asia\/Baghdad": "عرب ٹائم (Baghdad)", + "Asia\/Bahrain": "عرب ٹائم (Bahrain)", + "Asia\/Baku": "آذربائیجان ٹائم (Baku)", + "Asia\/Bishkek": "کرغستان ٹائم (Bishkek)", + "Asia\/Calcutta": "انڈیا سٹینڈرڈ ٹائم (Kolkata)", + "Asia\/Colombo": "انڈیا سٹینڈرڈ ٹائم (Colombo)", + "Asia\/Dhaka": "بنگلہ دیش ٹائم (Dhaka)", + "Asia\/Dubai": "خلیج سٹینڈرڈ ٹائم (Dubai)", + "Asia\/Dushanbe": "تاجکستان ٹائم (Dushanbe)", + "Asia\/Jerusalem": "اسرائیل ٹائم (Jerusalem)", + "Asia\/Kabul": "افغانستان ٹائم (Kabul)", + "Asia\/Karachi": "پاکستان ٹائم (Karachi)", + "Asia\/Katmandu": "نیپال ٹائم (Kathmandu)", + "Asia\/Kuwait": "عرب ٹائم (Kuwait)", + "Asia\/Muscat": "خلیج سٹینڈرڈ ٹائم (Muscat)", + "Asia\/Oral": "مغربی قزاخستان ٹائم (Oral)", + "Asia\/Qatar": "عرب ٹائم (Qatar)", + "Asia\/Qostanay": "مشرقی قزاخستان ٹائم (Qostanay)", + "Asia\/Qyzylorda": "مغربی قزاخستان ٹائم (Qyzylorda)", + "Asia\/Riyadh": "عرب ٹائم (Riyadh)", + "Asia\/Samarkand": "ازبکستان ٹائم (Samarkand)", + "Asia\/Tashkent": "ازبکستان ٹائم (Tashkent)", + "Asia\/Tbilisi": "جارجیا ٹائم (Tbilisi)", + "Asia\/Tehran": "ایران ٹائم (Tehran)", + "Asia\/Thimphu": "بھوٹان ٹائم (Thimphu)", + "Asia\/Yerevan": "آرمینیا ٹائم (Yerevan)", + "Atlantic\/Reykjavik": "گرین وچ مین ٹائم (Reykjavik)", + "Atlantic\/St_Helena": "گرین وچ مین ٹائم (St. Helena)", + "Atlantic\/Stanley": "فاک لینڈ آئلینڈز ٹائم (Stanley)", + "Etc\/GMT": "گرین وچ مین ٹائم", + "Europe\/Amsterdam": "وسطی یورپ کا وقت (Amsterdam)", + "Europe\/Andorra": "وسطی یورپ کا وقت (Andorra)", + "Europe\/Belgrade": "وسطی یورپ کا وقت (Belgrade)", + "Europe\/Berlin": "وسطی یورپ کا وقت (Berlin)", + "Europe\/Bratislava": "وسطی یورپ کا وقت (Bratislava)", + "Europe\/Brussels": "وسطی یورپ کا وقت (Brussels)", + "Europe\/Budapest": "وسطی یورپ کا وقت (بوڈاپیسٹ)", + "Europe\/Busingen": "وسطی یورپ کا وقت (Busingen)", + "Europe\/Copenhagen": "وسطی یورپ کا وقت (Copenhagen)", + "Europe\/Dublin": "گرین وچ مین ٹائم (Dublin)", + "Europe\/Gibraltar": "وسطی یورپ کا وقت (Gibraltar)", + "Europe\/Guernsey": "گرین وچ مین ٹائم (Guernsey)", + "Europe\/Isle_of_Man": "گرین وچ مین ٹائم (Isle of Man)", + "Europe\/Jersey": "گرین وچ مین ٹائم (Jersey)", + "Europe\/Ljubljana": "وسطی یورپ کا وقت (Ljubljana)", + "Europe\/London": "گرین وچ مین ٹائم (London)", + "Europe\/Luxembourg": "وسطی یورپ کا وقت (Luxembourg)", + "Europe\/Madrid": "وسطی یورپ کا وقت (Madrid)", + "Europe\/Malta": "وسطی یورپ کا وقت (Malta)", + "Europe\/Monaco": "وسطی یورپ کا وقت (Monaco)", + "Europe\/Oslo": "وسطی یورپ کا وقت (Oslo)", + "Europe\/Paris": "وسطی یورپ کا وقت (Paris)", + "Europe\/Podgorica": "وسطی یورپ کا وقت (Podgorica)", + "Europe\/Prague": "وسطی یورپ کا وقت (Prague)", + "Europe\/Rome": "وسطی یورپ کا وقت (Rome)", + "Europe\/San_Marino": "وسطی یورپ کا وقت (San Marino)", + "Europe\/Sarajevo": "وسطی یورپ کا وقت (Sarajevo)", + "Europe\/Skopje": "وسطی یورپ کا وقت (Skopje)", + "Europe\/Stockholm": "وسطی یورپ کا وقت (Stockholm)", + "Europe\/Tirane": "وسطی یورپ کا وقت (Tirane)", + "Europe\/Vaduz": "وسطی یورپ کا وقت (Vaduz)", + "Europe\/Vatican": "وسطی یورپ کا وقت (Vatican)", + "Europe\/Vienna": "وسطی یورپ کا وقت (Vienna)", + "Europe\/Warsaw": "وسطی یورپ کا وقت (Warsaw)", + "Europe\/Zagreb": "وسطی یورپ کا وقت (Zagreb)", + "Europe\/Zurich": "وسطی یورپ کا وقت (Zurich)", + "Indian\/Maldives": "مالدیپ ٹائم (Maldives)", + "Pacific\/Auckland": "نیوزی لینڈ ٹائم (Auckland)", + "Pacific\/Easter": "ایسٹر آئلینڈ ٹائم (Easter)", + "Pacific\/Galapagos": "گالاپاگوز ٹائم (Galapagos)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/uz.json b/src/Symfony/Component/Intl/Resources/data/timezones/uz.json new file mode 100644 index 0000000000000..102b4b20bd3b8 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/uz.json @@ -0,0 +1,428 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Grinvich o‘rtacha vaqti (Abidjan)", + "Africa\/Accra": "Grinvich o‘rtacha vaqti (Akkra)", + "Africa\/Addis_Ababa": "Sharqiy Afrika vaqti (Addis-Abeba)", + "Africa\/Algiers": "Markaziy Yevropa vaqti (Jazoir)", + "Africa\/Asmera": "Sharqiy Afrika vaqti (Asmera)", + "Africa\/Bamako": "Grinvich o‘rtacha vaqti (Bamako)", + "Africa\/Bangui": "Gʻarbiy Afrika vaqti (Bangi)", + "Africa\/Banjul": "Grinvich o‘rtacha vaqti (Banjul)", + "Africa\/Bissau": "Grinvich o‘rtacha vaqti (Bisau)", + "Africa\/Blantyre": "Markaziy Afrika vaqti (Blantayr)", + "Africa\/Brazzaville": "Gʻarbiy Afrika vaqti (Brazzavil)", + "Africa\/Bujumbura": "Markaziy Afrika vaqti (Bujumbura)", + "Africa\/Cairo": "Sharqiy Yevropa vaqti (Qohira)", + "Africa\/Casablanca": "G‘arbiy Yevropa vaqti (Kasablanka)", + "Africa\/Ceuta": "Markaziy Yevropa vaqti (Seuta)", + "Africa\/Conakry": "Grinvich o‘rtacha vaqti (Konakri)", + "Africa\/Dakar": "Grinvich o‘rtacha vaqti (Dakar)", + "Africa\/Dar_es_Salaam": "Sharqiy Afrika vaqti (Dor-us-Salom)", + "Africa\/Djibouti": "Sharqiy Afrika vaqti (Jibuti)", + "Africa\/Douala": "Gʻarbiy Afrika vaqti (Duala)", + "Africa\/El_Aaiun": "G‘arbiy Yevropa vaqti (Al-Ayun)", + "Africa\/Freetown": "Grinvich o‘rtacha vaqti (Fritaun)", + "Africa\/Gaborone": "Markaziy Afrika vaqti (Gaborone)", + "Africa\/Harare": "Markaziy Afrika vaqti (Xarare)", + "Africa\/Johannesburg": "Janubiy Afrika standart vaqti (Yoxannesburg)", + "Africa\/Juba": "Sharqiy Afrika vaqti (Juba)", + "Africa\/Kampala": "Sharqiy Afrika vaqti (Kampala)", + "Africa\/Khartoum": "Markaziy Afrika vaqti (Xartum)", + "Africa\/Kigali": "Markaziy Afrika vaqti (Kigali)", + "Africa\/Kinshasa": "Gʻarbiy Afrika vaqti (Kinshasa)", + "Africa\/Lagos": "Gʻarbiy Afrika vaqti (Lagos)", + "Africa\/Libreville": "Gʻarbiy Afrika vaqti (Librevil)", + "Africa\/Lome": "Grinvich o‘rtacha vaqti (Lome)", + "Africa\/Luanda": "Gʻarbiy Afrika vaqti (Luanda)", + "Africa\/Lubumbashi": "Markaziy Afrika vaqti (Lubumbashi)", + "Africa\/Lusaka": "Markaziy Afrika vaqti (Lusaka)", + "Africa\/Malabo": "Gʻarbiy Afrika vaqti (Malabo)", + "Africa\/Maputo": "Markaziy Afrika vaqti (Maputu)", + "Africa\/Maseru": "Janubiy Afrika standart vaqti (Maseru)", + "Africa\/Mbabane": "Janubiy Afrika standart vaqti (Mbabane)", + "Africa\/Mogadishu": "Sharqiy Afrika vaqti (Mogadisho)", + "Africa\/Monrovia": "Grinvich o‘rtacha vaqti (Monroviya)", + "Africa\/Nairobi": "Sharqiy Afrika vaqti (Nayrobi)", + "Africa\/Ndjamena": "Gʻarbiy Afrika vaqti (Ndjamena)", + "Africa\/Niamey": "Gʻarbiy Afrika vaqti (Niamey)", + "Africa\/Nouakchott": "Grinvich o‘rtacha vaqti (Nouakchott)", + "Africa\/Ouagadougou": "Grinvich o‘rtacha vaqti (Uagadugu)", + "Africa\/Porto-Novo": "Gʻarbiy Afrika vaqti (Porto-Novo)", + "Africa\/Sao_Tome": "Grinvich o‘rtacha vaqti (San-Tome)", + "Africa\/Tripoli": "Sharqiy Yevropa vaqti (Tripoli)", + "Africa\/Tunis": "Markaziy Yevropa vaqti (Tunis)", + "Africa\/Windhoek": "Markaziy Afrika vaqti (Vindxuk)", + "America\/Adak": "Gavayi-aleut vaqti (Adak oroli)", + "America\/Anchorage": "Alyaska vaqti (Ankorij)", + "America\/Anguilla": "Atlantika vaqti (Angilya)", + "America\/Antigua": "Atlantika vaqti (Antigua)", + "America\/Araguaina": "Braziliya vaqti (Araguaina)", + "America\/Argentina\/La_Rioja": "Argentina vaqti (La-Rioxa)", + "America\/Argentina\/Rio_Gallegos": "Argentina vaqti (Rio-Galyegos)", + "America\/Argentina\/Salta": "Argentina vaqti (Salta)", + "America\/Argentina\/San_Juan": "Argentina vaqti (San-Xuan)", + "America\/Argentina\/San_Luis": "Gʻarbiy Argentina vaqti (San-Luis)", + "America\/Argentina\/Tucuman": "Argentina vaqti (Tukuman)", + "America\/Argentina\/Ushuaia": "Argentina vaqti (Ushuaya)", + "America\/Aruba": "Atlantika vaqti (Aruba)", + "America\/Asuncion": "Paragvay vaqti (Asunson)", + "America\/Bahia": "Braziliya vaqti (Baiya)", + "America\/Bahia_Banderas": "Markaziy Amerika vaqti (Bahiya-Banderas)", + "America\/Barbados": "Atlantika vaqti (Barbados)", + "America\/Belem": "Braziliya vaqti (Belem)", + "America\/Belize": "Markaziy Amerika vaqti (Beliz)", + "America\/Blanc-Sablon": "Atlantika vaqti (Blank-Sablon)", + "America\/Boa_Vista": "Amazonka vaqti (Boa-Vista)", + "America\/Bogota": "Kolumbiya vaqti (Bogota)", + "America\/Boise": "Tog‘ vaqti (AQSH) (Boyse)", + "America\/Buenos_Aires": "Argentina vaqti (Buenos-Ayres)", + "America\/Cambridge_Bay": "Tog‘ vaqti (AQSH) (Kembrij-Bey)", + "America\/Campo_Grande": "Amazonka vaqti (Kampu-Grandi)", + "America\/Cancun": "Sharqiy Amerika vaqti (Kankun)", + "America\/Caracas": "Venesuela vaqti (Karakas)", + "America\/Catamarca": "Argentina vaqti (Katamarka)", + "America\/Cayenne": "Fransuz Gvianasi vaqti (Kayenna)", + "America\/Cayman": "Sharqiy Amerika vaqti (Kayman orollari)", + "America\/Chicago": "Markaziy Amerika vaqti (Chikago)", + "America\/Chihuahua": "Meksika Tinch okeani vaqti (Chihuahua)", + "America\/Coral_Harbour": "Sharqiy Amerika vaqti (Koral-Xarbor)", + "America\/Cordoba": "Argentina vaqti (Kordoba)", + "America\/Costa_Rica": "Markaziy Amerika vaqti (Kosta-Rika)", + "America\/Creston": "Tog‘ vaqti (AQSH) (Kreston)", + "America\/Cuiaba": "Amazonka vaqti (Kuyaba)", + "America\/Curacao": "Atlantika vaqti (Kyurasao)", + "America\/Danmarkshavn": "Grinvich o‘rtacha vaqti (Denmarksxavn)", + "America\/Dawson": "Tinch okeani vaqti (Douson)", + "America\/Dawson_Creek": "Tog‘ vaqti (AQSH) (Douson-Krik)", + "America\/Denver": "Tog‘ vaqti (AQSH) (Denver)", + "America\/Detroit": "Sharqiy Amerika vaqti (Detroyt)", + "America\/Dominica": "Atlantika vaqti (Dominika)", + "America\/Edmonton": "Tog‘ vaqti (AQSH) (Edmonton)", + "America\/El_Salvador": "Markaziy Amerika vaqti (Salvador)", + "America\/Fort_Nelson": "Tog‘ vaqti (AQSH) (Fort Nelson)", + "America\/Fortaleza": "Braziliya vaqti (Fortaleza)", + "America\/Glace_Bay": "Atlantika vaqti (Gleys-Bey)", + "America\/Godthab": "G‘arbiy Grenlandiya vaqti (Gotxob)", + "America\/Goose_Bay": "Atlantika vaqti (Gus-Bey)", + "America\/Grand_Turk": "Sharqiy Amerika vaqti (Grand Turk)", + "America\/Grenada": "Atlantika vaqti (Grenada)", + "America\/Guadeloupe": "Atlantika vaqti (Gvadelupa)", + "America\/Guatemala": "Markaziy Amerika vaqti (Gvatemala)", + "America\/Guayaquil": "Ekvador vaqti (Guayakil)", + "America\/Guyana": "Gayana vaqti (Gayana)", + "America\/Halifax": "Atlantika vaqti (Galifaks)", + "America\/Havana": "Kuba vaqti (Gavana)", + "America\/Hermosillo": "Meksika Tinch okeani vaqti (Ermosillo)", + "America\/Indiana\/Knox": "Markaziy Amerika vaqti (Noks, Indiana)", + "America\/Indiana\/Marengo": "Sharqiy Amerika vaqti (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Sharqiy Amerika vaqti (Pitersberg, Indiana)", + "America\/Indiana\/Tell_City": "Markaziy Amerika vaqti (Tell-Siti, Indiana)", + "America\/Indiana\/Vevay": "Sharqiy Amerika vaqti (Vivey, Indiana)", + "America\/Indiana\/Vincennes": "Sharqiy Amerika vaqti (Vinsens, Indiana)", + "America\/Indiana\/Winamac": "Sharqiy Amerika vaqti (Vinamak, Indiana)", + "America\/Indianapolis": "Sharqiy Amerika vaqti (Indianapolis)", + "America\/Inuvik": "Tog‘ vaqti (AQSH) (Inuvik)", + "America\/Iqaluit": "Sharqiy Amerika vaqti (Ikaluit)", + "America\/Jamaica": "Sharqiy Amerika vaqti (Yamayka)", + "America\/Jujuy": "Argentina vaqti (Jujuy)", + "America\/Juneau": "Alyaska vaqti (Juno)", + "America\/Kentucky\/Monticello": "Sharqiy Amerika vaqti (Montisello, Kentukki)", + "America\/Kralendijk": "Atlantika vaqti (Kralendeyk)", + "America\/La_Paz": "Boliviya vaqti (La-Pas)", + "America\/Lima": "Peru vaqti (Lima)", + "America\/Los_Angeles": "Tinch okeani vaqti (Los-Anjeles)", + "America\/Louisville": "Sharqiy Amerika vaqti (Luisvill)", + "America\/Lower_Princes": "Atlantika vaqti (Louer-Prinses-Kuorter)", + "America\/Maceio": "Braziliya vaqti (Maseyo)", + "America\/Managua": "Markaziy Amerika vaqti (Managua)", + "America\/Manaus": "Amazonka vaqti (Manaus)", + "America\/Marigot": "Atlantika vaqti (Marigo)", + "America\/Martinique": "Atlantika vaqti (Martinika)", + "America\/Matamoros": "Markaziy Amerika vaqti (Matamoros)", + "America\/Mazatlan": "Meksika Tinch okeani vaqti (Masatlan)", + "America\/Mendoza": "Argentina vaqti (Mendoza)", + "America\/Menominee": "Markaziy Amerika vaqti (Menomini)", + "America\/Merida": "Markaziy Amerika vaqti (Merida)", + "America\/Metlakatla": "Alyaska vaqti (Metlakatla)", + "America\/Mexico_City": "Markaziy Amerika vaqti (Mexiko)", + "America\/Miquelon": "Sen-Pyer va Mikelon vaqti (Mikelon)", + "America\/Moncton": "Atlantika vaqti (Monkton)", + "America\/Monterrey": "Markaziy Amerika vaqti (Monterrey)", + "America\/Montevideo": "Urugvay vaqti (Montevideo)", + "America\/Montserrat": "Atlantika vaqti (Montserrat)", + "America\/Nassau": "Sharqiy Amerika vaqti (Nassau)", + "America\/New_York": "Sharqiy Amerika vaqti (Nyu-York)", + "America\/Nipigon": "Sharqiy Amerika vaqti (Nipigon)", + "America\/Nome": "Alyaska vaqti (Nom)", + "America\/Noronha": "Fernandu-di-Noronya vaqti (Noronya)", + "America\/North_Dakota\/Beulah": "Markaziy Amerika vaqti (Boyla, Shimoliy Dakota)", + "America\/North_Dakota\/Center": "Markaziy Amerika vaqti (Markaz, Shimoliy Dakota)", + "America\/North_Dakota\/New_Salem": "Markaziy Amerika vaqti (Nyu-Salem, Shimoliy Dakota)", + "America\/Ojinaga": "Tog‘ vaqti (AQSH) (Oxinaga)", + "America\/Panama": "Sharqiy Amerika vaqti (Panama)", + "America\/Pangnirtung": "Sharqiy Amerika vaqti (Pangnirtang)", + "America\/Paramaribo": "Surinam vaqti (Paramaribo)", + "America\/Phoenix": "Tog‘ vaqti (AQSH) (Feniks)", + "America\/Port-au-Prince": "Sharqiy Amerika vaqti (Port-o-Prens)", + "America\/Port_of_Spain": "Atlantika vaqti (Port-of-Speyn)", + "America\/Porto_Velho": "Amazonka vaqti (Portu-Velyu)", + "America\/Puerto_Rico": "Atlantika vaqti (Puerto-Riko)", + "America\/Punta_Arenas": "Chili vaqti (Punta-Arenas)", + "America\/Rainy_River": "Markaziy Amerika vaqti (Reyni-River)", + "America\/Rankin_Inlet": "Markaziy Amerika vaqti (Rankin-Inlet)", + "America\/Recife": "Braziliya vaqti (Resifi)", + "America\/Regina": "Markaziy Amerika vaqti (Rejayna)", + "America\/Resolute": "Markaziy Amerika vaqti (Rezolyut)", + "America\/Santa_Isabel": "Shimoli-g‘arbiy Meksika vaqti (Santa-Izabel)", + "America\/Santarem": "Braziliya vaqti (Santarem)", + "America\/Santiago": "Chili vaqti (Santyago)", + "America\/Santo_Domingo": "Atlantika vaqti (Santo-Domingo)", + "America\/Sao_Paulo": "Braziliya vaqti (San-Paulu)", + "America\/Scoresbysund": "Sharqiy Grenlandiya vaqti (Ittokkortoormiut)", + "America\/Sitka": "Alyaska vaqti (Sitka)", + "America\/St_Barthelemy": "Atlantika vaqti (Sen-Bartelemi)", + "America\/St_Johns": "Nyufaundlend vaqti (Sent-Jons)", + "America\/St_Kitts": "Atlantika vaqti (Sent-Kits)", + "America\/St_Lucia": "Atlantika vaqti (Sent-Lyusiya)", + "America\/St_Thomas": "Atlantika vaqti (Sent-Tomas)", + "America\/St_Vincent": "Atlantika vaqti (Sent-Vinsent)", + "America\/Swift_Current": "Markaziy Amerika vaqti (Svift-Karrent)", + "America\/Tegucigalpa": "Markaziy Amerika vaqti (Tegusigalpa)", + "America\/Thule": "Atlantika vaqti (Tule)", + "America\/Thunder_Bay": "Sharqiy Amerika vaqti (Tander-Bey)", + "America\/Tijuana": "Tinch okeani vaqti (Tixuana)", + "America\/Toronto": "Sharqiy Amerika vaqti (Toronto)", + "America\/Tortola": "Atlantika vaqti (Tortola)", + "America\/Vancouver": "Tinch okeani vaqti (Vankuver)", + "America\/Whitehorse": "Tinch okeani vaqti (Uaytxors)", + "America\/Winnipeg": "Markaziy Amerika vaqti (Vinnipeg)", + "America\/Yakutat": "Alyaska vaqti (Yakutat)", + "America\/Yellowknife": "Tog‘ vaqti (AQSH) (Yellounayf)", + "Antarctica\/Casey": "G‘arbiy Avstraliya vaqti (Keysi)", + "Antarctica\/Davis": "Deyvis vaqti (Deyvis)", + "Antarctica\/DumontDUrville": "Dyumon-d’Yurvil vaqti (Dyumon-d’Yurvil)", + "Antarctica\/Macquarie": "Makkuori oroli vaqti (Makkuori)", + "Antarctica\/Mawson": "Mouson vaqti (Mouson)", + "Antarctica\/McMurdo": "Yangi Zelandiya vaqti (Mak-Merdo)", + "Antarctica\/Palmer": "Chili vaqti (Palmer)", + "Antarctica\/Rothera": "Rotera vaqti (Rotera)", + "Antarctica\/Syowa": "Syova vaqti (Syova)", + "Antarctica\/Troll": "Grinvich o‘rtacha vaqti (Troll)", + "Antarctica\/Vostok": "Vostok vaqti (Vostok)", + "Arctic\/Longyearbyen": "Markaziy Yevropa vaqti (Longyir)", + "Asia\/Aden": "Saudiya Arabistoni vaqti (Adan)", + "Asia\/Almaty": "Sharqiy Qozogʻiston vaqti (Almati)", + "Asia\/Amman": "Sharqiy Yevropa vaqti (Ammon)", + "Asia\/Aqtau": "Gʻarbiy Qozogʻiston vaqti (Oqtov)", + "Asia\/Aqtobe": "Gʻarbiy Qozogʻiston vaqti (Oqto‘ba)", + "Asia\/Ashgabat": "Turkmaniston vaqti (Ashxobod)", + "Asia\/Atyrau": "Gʻarbiy Qozogʻiston vaqti (Atirau)", + "Asia\/Baghdad": "Saudiya Arabistoni vaqti (Bag‘dod)", + "Asia\/Bahrain": "Saudiya Arabistoni vaqti (Bahrayn)", + "Asia\/Baku": "Ozarbayjon vaqti (Boku)", + "Asia\/Bangkok": "Hindixitoy vaqti (Bangkok)", + "Asia\/Beirut": "Sharqiy Yevropa vaqti (Bayrut)", + "Asia\/Bishkek": "Qirgʻiziston vaqti (Bishkek)", + "Asia\/Brunei": "Bruney-Dorussalom vaqti (Bruney)", + "Asia\/Calcutta": "Hindiston standart vaqti (Kalkutta)", + "Asia\/Chita": "Yakutsk vaqti (Chita)", + "Asia\/Choibalsan": "Choybalsan vaqti (Choybalsan)", + "Asia\/Colombo": "Hindiston standart vaqti (Kolombo)", + "Asia\/Damascus": "Sharqiy Yevropa vaqti (Damashq)", + "Asia\/Dhaka": "Bangladesh vaqti (Dakka)", + "Asia\/Dili": "Sharqiy Timor vaqti (Dili)", + "Asia\/Dubai": "Fors ko‘rfazi standart vaqti (Dubay)", + "Asia\/Dushanbe": "Tojikiston vaqti (Dushanbe)", + "Asia\/Famagusta": "Sharqiy Yevropa vaqti (Famagusta)", + "Asia\/Gaza": "Sharqiy Yevropa vaqti (G‘azo)", + "Asia\/Hebron": "Sharqiy Yevropa vaqti (Xevron)", + "Asia\/Hong_Kong": "Gonkong vaqti (Gonkong)", + "Asia\/Hovd": "Xovd vaqti (Xovd)", + "Asia\/Irkutsk": "Irkutsk vaqti (Irkutsk)", + "Asia\/Jakarta": "Gʻarbiy Indoneziya vaqti (Jakarta)", + "Asia\/Jayapura": "Sharqiy Indoneziya vaqti (Jaypur)", + "Asia\/Jerusalem": "Isroil vaqti (Quddus)", + "Asia\/Kabul": "Afgʻoniston vaqti (Qobul)", + "Asia\/Karachi": "Pokiston vaqti (Karachi)", + "Asia\/Katmandu": "Nepal vaqti (Katmandu)", + "Asia\/Khandyga": "Yakutsk vaqti (Xandiga)", + "Asia\/Krasnoyarsk": "Krasnoyarsk vaqti (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Malayziya vaqti (Kuala-Lumpur)", + "Asia\/Kuching": "Malayziya vaqti (Kuching)", + "Asia\/Kuwait": "Saudiya Arabistoni vaqti (Quvayt)", + "Asia\/Macau": "Xitoy vaqti (Makao)", + "Asia\/Magadan": "Magadan vaqti (Magadan)", + "Asia\/Makassar": "Markaziy Indoneziya vaqti (Makasar)", + "Asia\/Manila": "Filippin vaqti (Manila)", + "Asia\/Muscat": "Fors ko‘rfazi standart vaqti (Maskat)", + "Asia\/Nicosia": "Sharqiy Yevropa vaqti (Nikosiya)", + "Asia\/Novokuznetsk": "Krasnoyarsk vaqti (Novokuznetsk)", + "Asia\/Novosibirsk": "Novosibirsk vaqti (Novosibirsk)", + "Asia\/Omsk": "Omsk vaqti (Omsk)", + "Asia\/Oral": "Gʻarbiy Qozogʻiston vaqti (Uralsk)", + "Asia\/Phnom_Penh": "Hindixitoy vaqti (Pnompen)", + "Asia\/Pontianak": "Gʻarbiy Indoneziya vaqti (Pontianak)", + "Asia\/Pyongyang": "Koreya vaqti (Pxenyan)", + "Asia\/Qatar": "Saudiya Arabistoni vaqti (Qatar)", + "Asia\/Qostanay": "Sharqiy Qozogʻiston vaqti (Qostanay)", + "Asia\/Qyzylorda": "Gʻarbiy Qozogʻiston vaqti (Qizilo‘rda)", + "Asia\/Rangoon": "Myanma vaqti (Rangun)", + "Asia\/Riyadh": "Saudiya Arabistoni vaqti (Ar-Riyod)", + "Asia\/Saigon": "Hindixitoy vaqti (Xoshimin)", + "Asia\/Sakhalin": "Saxalin vaqti (Saxalin)", + "Asia\/Samarkand": "O‘zbekiston vaqti (Samarqand)", + "Asia\/Seoul": "Koreya vaqti (Seul)", + "Asia\/Shanghai": "Xitoy vaqti (Shanxay)", + "Asia\/Singapore": "Singapur vaqti (Singapur)", + "Asia\/Srednekolymsk": "Magadan vaqti (Srednekolimsk)", + "Asia\/Taipei": "Tayvan vaqti (Taypey)", + "Asia\/Tashkent": "O‘zbekiston vaqti (Toshkent)", + "Asia\/Tbilisi": "Gruziya vaqti (Tbilisi)", + "Asia\/Tehran": "Eron vaqti (Tehron)", + "Asia\/Thimphu": "Butan vaqti (Thimphu)", + "Asia\/Tokyo": "Yaponiya vaqti (Tokio)", + "Asia\/Ulaanbaatar": "Ulan-Bator vaqti (Ulan-Bator)", + "Asia\/Ust-Nera": "Vladivostok vaqti (Ust-Nera)", + "Asia\/Vientiane": "Hindixitoy vaqti (Vyentyan)", + "Asia\/Vladivostok": "Vladivostok vaqti (Vladivostok)", + "Asia\/Yakutsk": "Yakutsk vaqti (Yakutsk)", + "Asia\/Yekaterinburg": "Yekaterinburg vaqti (Yekaterinburg)", + "Asia\/Yerevan": "Armaniston vaqti (Yerevan)", + "Atlantic\/Azores": "Azor orollari vaqti (Azor orollari)", + "Atlantic\/Bermuda": "Atlantika vaqti (Bermuda orollari)", + "Atlantic\/Canary": "G‘arbiy Yevropa vaqti (Kanar orollari)", + "Atlantic\/Cape_Verde": "Kabo-Verde vaqti (Kabo-Verde)", + "Atlantic\/Faeroe": "G‘arbiy Yevropa vaqti (Farer orollari)", + "Atlantic\/Madeira": "G‘arbiy Yevropa vaqti (Madeyra oroli)", + "Atlantic\/Reykjavik": "Grinvich o‘rtacha vaqti (Reykyavik)", + "Atlantic\/South_Georgia": "Janubiy Georgiya vaqti (Janubiy Georgiya)", + "Atlantic\/St_Helena": "Grinvich o‘rtacha vaqti (Muqaddas Yelena oroli)", + "Atlantic\/Stanley": "Folklend orollari vaqti (Stenli)", + "Australia\/Adelaide": "Markaziy Avstraliya vaqti (Adelaida)", + "Australia\/Brisbane": "Sharqiy Avstraliya vaqti (Brisben)", + "Australia\/Broken_Hill": "Markaziy Avstraliya vaqti (Broken-Xill)", + "Australia\/Currie": "Sharqiy Avstraliya vaqti (Kerri)", + "Australia\/Darwin": "Markaziy Avstraliya vaqti (Darvin)", + "Australia\/Eucla": "Markaziy Avstraliya g‘arbiy vaqti (Evkla)", + "Australia\/Hobart": "Sharqiy Avstraliya vaqti (Xobart)", + "Australia\/Lindeman": "Sharqiy Avstraliya vaqti (Lindeman)", + "Australia\/Lord_Howe": "Lord-Xau vaqti (Lord-Xau oroli)", + "Australia\/Melbourne": "Sharqiy Avstraliya vaqti (Melburn)", + "Australia\/Perth": "G‘arbiy Avstraliya vaqti (Pert)", + "Australia\/Sydney": "Sharqiy Avstraliya vaqti (Sidney)", + "CST6CDT": "Markaziy Amerika vaqti", + "EST5EDT": "Sharqiy Amerika vaqti", + "Etc\/GMT": "Grinvich o‘rtacha vaqti", + "Etc\/UTC": "Koordinatali universal vaqt", + "Europe\/Amsterdam": "Markaziy Yevropa vaqti (Amsterdam)", + "Europe\/Andorra": "Markaziy Yevropa vaqti (Andorra)", + "Europe\/Astrakhan": "Moskva vaqti (Astraxan)", + "Europe\/Athens": "Sharqiy Yevropa vaqti (Afina)", + "Europe\/Belgrade": "Markaziy Yevropa vaqti (Belgrad)", + "Europe\/Berlin": "Markaziy Yevropa vaqti (Berlin)", + "Europe\/Bratislava": "Markaziy Yevropa vaqti (Bratislava)", + "Europe\/Brussels": "Markaziy Yevropa vaqti (Bryussel)", + "Europe\/Bucharest": "Sharqiy Yevropa vaqti (Buxarest)", + "Europe\/Budapest": "Markaziy Yevropa vaqti (Budapesht)", + "Europe\/Busingen": "Markaziy Yevropa vaqti (Byuzingen)", + "Europe\/Chisinau": "Sharqiy Yevropa vaqti (Kishinyov)", + "Europe\/Copenhagen": "Markaziy Yevropa vaqti (Kopengagen)", + "Europe\/Dublin": "Grinvich o‘rtacha vaqti (Dublin)", + "Europe\/Gibraltar": "Markaziy Yevropa vaqti (Gibraltar)", + "Europe\/Guernsey": "Grinvich o‘rtacha vaqti (Gernsi)", + "Europe\/Helsinki": "Sharqiy Yevropa vaqti (Xelsinki)", + "Europe\/Isle_of_Man": "Grinvich o‘rtacha vaqti (Men oroli)", + "Europe\/Jersey": "Grinvich o‘rtacha vaqti (Jersi)", + "Europe\/Kaliningrad": "Sharqiy Yevropa vaqti (Kaliningrad)", + "Europe\/Kiev": "Sharqiy Yevropa vaqti (Kiyev)", + "Europe\/Lisbon": "G‘arbiy Yevropa vaqti (Lissabon)", + "Europe\/Ljubljana": "Markaziy Yevropa vaqti (Lyublyana)", + "Europe\/London": "Grinvich o‘rtacha vaqti (London)", + "Europe\/Luxembourg": "Markaziy Yevropa vaqti (Lyuksemburg)", + "Europe\/Madrid": "Markaziy Yevropa vaqti (Madrid)", + "Europe\/Malta": "Markaziy Yevropa vaqti (Malta)", + "Europe\/Mariehamn": "Sharqiy Yevropa vaqti (Mariyexamn)", + "Europe\/Minsk": "Moskva vaqti (Minsk)", + "Europe\/Monaco": "Markaziy Yevropa vaqti (Monako)", + "Europe\/Moscow": "Moskva vaqti (Moskva)", + "Europe\/Oslo": "Markaziy Yevropa vaqti (Oslo)", + "Europe\/Paris": "Markaziy Yevropa vaqti (Parij)", + "Europe\/Podgorica": "Markaziy Yevropa vaqti (Podgoritsa)", + "Europe\/Prague": "Markaziy Yevropa vaqti (Praga)", + "Europe\/Riga": "Sharqiy Yevropa vaqti (Riga)", + "Europe\/Rome": "Markaziy Yevropa vaqti (Rim)", + "Europe\/San_Marino": "Markaziy Yevropa vaqti (San-Marino)", + "Europe\/Sarajevo": "Markaziy Yevropa vaqti (Sarayevo)", + "Europe\/Saratov": "Moskva vaqti (Saratov)", + "Europe\/Simferopol": "Moskva vaqti (Simferopol)", + "Europe\/Skopje": "Markaziy Yevropa vaqti (Skopye)", + "Europe\/Sofia": "Sharqiy Yevropa vaqti (Sofiya)", + "Europe\/Stockholm": "Markaziy Yevropa vaqti (Stokgolm)", + "Europe\/Tallinn": "Sharqiy Yevropa vaqti (Tallin)", + "Europe\/Tirane": "Markaziy Yevropa vaqti (Tirana)", + "Europe\/Ulyanovsk": "Moskva vaqti (Ulyanovsk)", + "Europe\/Uzhgorod": "Sharqiy Yevropa vaqti (Ujgorod)", + "Europe\/Vaduz": "Markaziy Yevropa vaqti (Vaduts)", + "Europe\/Vatican": "Markaziy Yevropa vaqti (Vatikan)", + "Europe\/Vienna": "Markaziy Yevropa vaqti (Vena)", + "Europe\/Vilnius": "Sharqiy Yevropa vaqti (Vilnyus)", + "Europe\/Volgograd": "Volgograd vaqti (Volgograd)", + "Europe\/Warsaw": "Markaziy Yevropa vaqti (Varshava)", + "Europe\/Zagreb": "Markaziy Yevropa vaqti (Zagreb)", + "Europe\/Zaporozhye": "Sharqiy Yevropa vaqti (Zaporojye)", + "Europe\/Zurich": "Markaziy Yevropa vaqti (Syurix)", + "Indian\/Antananarivo": "Sharqiy Afrika vaqti (Antananarivu)", + "Indian\/Chagos": "Hind okeani vaqti (Chagos)", + "Indian\/Christmas": "Rojdestvo oroli vaqti (Rojdestvo oroli)", + "Indian\/Cocos": "Kokos orollari vaqti (Kokos orollari)", + "Indian\/Comoro": "Sharqiy Afrika vaqti (Komor orollari)", + "Indian\/Kerguelen": "Fransuz Janubiy hududlari va Antarktika vaqti (Kergelen)", + "Indian\/Mahe": "Seyshel orollari vaqti (Mae)", + "Indian\/Maldives": "Maldiv orollari vaqti (Maldiv orollari)", + "Indian\/Mauritius": "Mavrikiy vaqti (Mavrikiy)", + "Indian\/Mayotte": "Sharqiy Afrika vaqti (Mayorka)", + "Indian\/Reunion": "Reyunion vaqti (Reyunion)", + "MST7MDT": "Tog‘ vaqti (AQSH)", + "PST8PDT": "Tinch okeani vaqti", + "Pacific\/Apia": "Apia vaqti (Apia)", + "Pacific\/Auckland": "Yangi Zelandiya vaqti (Oklend)", + "Pacific\/Bougainville": "Papua-Yangi Gvineya vaqti (Bugenvil)", + "Pacific\/Chatham": "Chatem vaqti (Chatem oroli)", + "Pacific\/Easter": "Pasxa oroli vaqti (Pasxa oroli)", + "Pacific\/Efate": "Vanuatu vaqti (Efate)", + "Pacific\/Enderbury": "Feniks orollari vaqti (Enderberi oroli)", + "Pacific\/Fakaofo": "Tokelau vaqti (Fakaofo)", + "Pacific\/Fiji": "Fiji vaqti (Fiji)", + "Pacific\/Funafuti": "Tuvalu vaqti (Funafuti)", + "Pacific\/Galapagos": "Galapagos vaqti (Galapagos)", + "Pacific\/Gambier": "Gambye vaqti (Gambye oroli)", + "Pacific\/Guadalcanal": "Solomon orollari vaqti (Gvadalkanal)", + "Pacific\/Guam": "Chamorro standart vaqti (Guam)", + "Pacific\/Honolulu": "Gavayi-aleut vaqti (Gonolulu)", + "Pacific\/Johnston": "Gavayi-aleut vaqti (Jonston)", + "Pacific\/Kiritimati": "Layn orollari vaqti (Kiritimati)", + "Pacific\/Kosrae": "Kosrae vaqti (Kosrae)", + "Pacific\/Kwajalein": "Marshall orollari vaqti (Kvajaleyn)", + "Pacific\/Majuro": "Marshall orollari vaqti (Majuro)", + "Pacific\/Marquesas": "Markiz orollari vaqti (Markiz orollari)", + "Pacific\/Midway": "Samoa vaqti (Midvey orollari)", + "Pacific\/Nauru": "Nauru vaqti (Nauru)", + "Pacific\/Niue": "Niuye vaqti (Niue)", + "Pacific\/Norfolk": "Norfolk oroli vaqti (Norfolk)", + "Pacific\/Noumea": "Yangi Kaledoniya vaqti (Numea)", + "Pacific\/Pago_Pago": "Samoa vaqti (Pago-Pago)", + "Pacific\/Palau": "Palau vaqti (Palau)", + "Pacific\/Pitcairn": "Pitkern vaqti (Pitkern)", + "Pacific\/Ponape": "Ponape vaqti (Ponpei oroli)", + "Pacific\/Port_Moresby": "Papua-Yangi Gvineya vaqti (Port-Morsbi)", + "Pacific\/Rarotonga": "Kuk orollari vaqti (Rarotonga)", + "Pacific\/Saipan": "Chamorro standart vaqti (Saypan)", + "Pacific\/Tahiti": "Taiti vaqti (Taiti oroli)", + "Pacific\/Tarawa": "Gilbert orollari vaqti (Tarava)", + "Pacific\/Tongatapu": "Tonga vaqti (Tongatapu)", + "Pacific\/Truk": "Chuuk vaqti (Truk orollari)", + "Pacific\/Wake": "Ueyk oroli vaqti (Ueyk oroli)", + "Pacific\/Wallis": "Uollis va Futuna vaqti (Uollis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/uz_Arab.json b/src/Symfony/Component/Intl/Resources/data/timezones/uz_Arab.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/uz_Arab.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/uz_Cyrl.json b/src/Symfony/Component/Intl/Resources/data/timezones/uz_Cyrl.json new file mode 100644 index 0000000000000..096167514915f --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/uz_Cyrl.json @@ -0,0 +1,422 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Гринвич вақти (Abidjan)", + "Africa\/Accra": "Гринвич вақти (Accra)", + "Africa\/Addis_Ababa": "Шарқий Африка вақти (Addis Ababa)", + "Africa\/Algiers": "Марказий Европа вақти (Algiers)", + "Africa\/Asmera": "Шарқий Африка вақти (Asmara)", + "Africa\/Bamako": "Гринвич вақти (Bamako)", + "Africa\/Bangui": "Ғарбий Африка вақти (Bangui)", + "Africa\/Banjul": "Гринвич вақти (Banjul)", + "Africa\/Bissau": "Гринвич вақти (Bissau)", + "Africa\/Blantyre": "Марказий Африка вақти (Blantyre)", + "Africa\/Brazzaville": "Ғарбий Африка вақти (Brazzaville)", + "Africa\/Bujumbura": "Марказий Африка вақти (Bujumbura)", + "Africa\/Cairo": "Шарқий Европа вақти (Cairo)", + "Africa\/Casablanca": "Ғарбий Европа вақти (Casablanca)", + "Africa\/Ceuta": "Марказий Европа вақти (Ceuta)", + "Africa\/Conakry": "Гринвич вақти (Conakry)", + "Africa\/Dakar": "Гринвич вақти (Dakar)", + "Africa\/Dar_es_Salaam": "Шарқий Африка вақти (Dar es Salaam)", + "Africa\/Djibouti": "Шарқий Африка вақти (Djibouti)", + "Africa\/Douala": "Ғарбий Африка вақти (Douala)", + "Africa\/El_Aaiun": "Ғарбий Европа вақти (El Aaiun)", + "Africa\/Freetown": "Гринвич вақти (Freetown)", + "Africa\/Gaborone": "Марказий Африка вақти (Gaborone)", + "Africa\/Harare": "Марказий Африка вақти (Harare)", + "Africa\/Johannesburg": "Жанубий Африка вақти (Johannesburg)", + "Africa\/Juba": "Шарқий Африка вақти (Juba)", + "Africa\/Kampala": "Шарқий Африка вақти (Kampala)", + "Africa\/Khartoum": "Марказий Африка вақти (Khartoum)", + "Africa\/Kigali": "Марказий Африка вақти (Kigali)", + "Africa\/Kinshasa": "Ғарбий Африка вақти (Kinshasa)", + "Africa\/Lagos": "Ғарбий Африка вақти (Lagos)", + "Africa\/Libreville": "Ғарбий Африка вақти (Libreville)", + "Africa\/Lome": "Гринвич вақти (Lome)", + "Africa\/Luanda": "Ғарбий Африка вақти (Luanda)", + "Africa\/Lubumbashi": "Марказий Африка вақти (Lubumbashi)", + "Africa\/Lusaka": "Марказий Африка вақти (Lusaka)", + "Africa\/Malabo": "Ғарбий Африка вақти (Malabo)", + "Africa\/Maputo": "Марказий Африка вақти (Maputo)", + "Africa\/Maseru": "Жанубий Африка вақти (Maseru)", + "Africa\/Mbabane": "Жанубий Африка вақти (Mbabane)", + "Africa\/Mogadishu": "Шарқий Африка вақти (Mogadishu)", + "Africa\/Monrovia": "Гринвич вақти (Monrovia)", + "Africa\/Nairobi": "Шарқий Африка вақти (Nairobi)", + "Africa\/Ndjamena": "Ғарбий Африка вақти (Ndjamena)", + "Africa\/Niamey": "Ғарбий Африка вақти (Niamey)", + "Africa\/Nouakchott": "Гринвич вақти (Nouakchott)", + "Africa\/Ouagadougou": "Гринвич вақти (Ouagadougou)", + "Africa\/Porto-Novo": "Ғарбий Африка вақти (Porto-Novo)", + "Africa\/Sao_Tome": "Гринвич вақти (Sao Tome)", + "Africa\/Tripoli": "Шарқий Европа вақти (Tripoli)", + "Africa\/Tunis": "Марказий Европа вақти (Tunis)", + "Africa\/Windhoek": "Марказий Африка вақти (Windhoek)", + "America\/Adak": "Гавайи-алеут вақти (Adak)", + "America\/Anchorage": "Аляска вақти (Anchorage)", + "America\/Anguilla": "Атлантика вақти (Anguilla)", + "America\/Antigua": "Атлантика вақти (Antigua)", + "America\/Araguaina": "Бразилия вақти (Araguaina)", + "America\/Argentina\/La_Rioja": "Аргентина вақти (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Аргентина вақти (Rio Gallegos)", + "America\/Argentina\/Salta": "Аргентина вақти (Salta)", + "America\/Argentina\/San_Juan": "Аргентина вақти (San Juan)", + "America\/Argentina\/San_Luis": "Ғарбий Аргентина вақти (San Luis)", + "America\/Argentina\/Tucuman": "Аргентина вақти (Tucuman)", + "America\/Argentina\/Ushuaia": "Аргентина вақти (Ushuaia)", + "America\/Aruba": "Атлантика вақти (Aruba)", + "America\/Asuncion": "Парагвай вақти (Asuncion)", + "America\/Bahia": "Бразилия вақти (Bahia)", + "America\/Bahia_Banderas": "Шимолий Америка (Bahia Banderas)", + "America\/Barbados": "Атлантика вақти (Barbados)", + "America\/Belem": "Бразилия вақти (Belem)", + "America\/Belize": "Шимолий Америка (Belize)", + "America\/Blanc-Sablon": "Атлантика вақти (Blanc-Sablon)", + "America\/Boa_Vista": "Амазонка вақти (Boa Vista)", + "America\/Bogota": "Колумбия вақти (Bogota)", + "America\/Boise": "Шимолий Америка тоғ вақти (Boise)", + "America\/Buenos_Aires": "Аргентина вақти (Buenos Aires)", + "America\/Cambridge_Bay": "Шимолий Америка тоғ вақти (Cambridge Bay)", + "America\/Campo_Grande": "Амазонка вақти (Campo Grande)", + "America\/Cancun": "Шимолий Америка шарқий вақти (Cancun)", + "America\/Caracas": "Венесуэла вақти (Caracas)", + "America\/Catamarca": "Аргентина вақти (Catamarca)", + "America\/Cayenne": "Француз Гвианаси вақти (Cayenne)", + "America\/Cayman": "Шимолий Америка шарқий вақти (Cayman)", + "America\/Chicago": "Шимолий Америка (Chicago)", + "America\/Coral_Harbour": "Шимолий Америка шарқий вақти (Atikokan)", + "America\/Cordoba": "Аргентина вақти (Cordoba)", + "America\/Costa_Rica": "Шимолий Америка (Costa Rica)", + "America\/Creston": "Шимолий Америка тоғ вақти (Creston)", + "America\/Cuiaba": "Амазонка вақти (Cuiaba)", + "America\/Curacao": "Атлантика вақти (Curacao)", + "America\/Danmarkshavn": "Гринвич вақти (Danmarkshavn)", + "America\/Dawson": "Шимолий Америка тинч океани вақти (Dawson)", + "America\/Dawson_Creek": "Шимолий Америка тоғ вақти (Dawson Creek)", + "America\/Denver": "Шимолий Америка тоғ вақти (Denver)", + "America\/Detroit": "Шимолий Америка шарқий вақти (Detroit)", + "America\/Dominica": "Атлантика вақти (Dominica)", + "America\/Edmonton": "Шимолий Америка тоғ вақти (Edmonton)", + "America\/El_Salvador": "Шимолий Америка (El Salvador)", + "America\/Fort_Nelson": "Шимолий Америка тоғ вақти (Fort Nelson)", + "America\/Fortaleza": "Бразилия вақти (Fortaleza)", + "America\/Glace_Bay": "Атлантика вақти (Glace Bay)", + "America\/Godthab": "Ғарбий Гренландия вақти (Nuuk)", + "America\/Goose_Bay": "Атлантика вақти (Goose Bay)", + "America\/Grand_Turk": "Шимолий Америка шарқий вақти (Grand Turk)", + "America\/Grenada": "Атлантика вақти (Grenada)", + "America\/Guadeloupe": "Атлантика вақти (Guadeloupe)", + "America\/Guatemala": "Шимолий Америка (Guatemala)", + "America\/Guayaquil": "Эквадор вақти (Guayaquil)", + "America\/Guyana": "Гайана вақти (Guyana)", + "America\/Halifax": "Атлантика вақти (Halifax)", + "America\/Havana": "Куба вақти (Havana)", + "America\/Indiana\/Knox": "Шимолий Америка (Knox, Indiana)", + "America\/Indiana\/Marengo": "Шимолий Америка шарқий вақти (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Шимолий Америка шарқий вақти (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Шимолий Америка (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Шимолий Америка шарқий вақти (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Шимолий Америка шарқий вақти (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Шимолий Америка шарқий вақти (Winamac, Indiana)", + "America\/Indianapolis": "Шимолий Америка шарқий вақти (Indianapolis)", + "America\/Inuvik": "Шимолий Америка тоғ вақти (Inuvik)", + "America\/Iqaluit": "Шимолий Америка шарқий вақти (Iqaluit)", + "America\/Jamaica": "Шимолий Америка шарқий вақти (Jamaica)", + "America\/Jujuy": "Аргентина вақти (Jujuy)", + "America\/Juneau": "Аляска вақти (Juneau)", + "America\/Kentucky\/Monticello": "Шимолий Америка шарқий вақти (Monticello, Kentucky)", + "America\/Kralendijk": "Атлантика вақти (Kralendijk)", + "America\/La_Paz": "Боливия вақти (La Paz)", + "America\/Lima": "Перу вақти (Lima)", + "America\/Los_Angeles": "Шимолий Америка тинч океани вақти (Los Angeles)", + "America\/Louisville": "Шимолий Америка шарқий вақти (Louisville)", + "America\/Lower_Princes": "Атлантика вақти (Lower Princeʼs Quarter)", + "America\/Maceio": "Бразилия вақти (Maceio)", + "America\/Managua": "Шимолий Америка (Managua)", + "America\/Manaus": "Амазонка вақти (Manaus)", + "America\/Marigot": "Атлантика вақти (Marigot)", + "America\/Martinique": "Атлантика вақти (Martinique)", + "America\/Matamoros": "Шимолий Америка (Matamoros)", + "America\/Mendoza": "Аргентина вақти (Mendoza)", + "America\/Menominee": "Шимолий Америка (Menominee)", + "America\/Merida": "Шимолий Америка (Merida)", + "America\/Metlakatla": "Аляска вақти (Metlakatla)", + "America\/Mexico_City": "Шимолий Америка (Mexico City)", + "America\/Miquelon": "Сент-Пьер ва Микелон вақти (Miquelon)", + "America\/Moncton": "Атлантика вақти (Moncton)", + "America\/Monterrey": "Шимолий Америка (Monterrey)", + "America\/Montevideo": "Уругвай вақти (Montevideo)", + "America\/Montserrat": "Атлантика вақти (Montserrat)", + "America\/Nassau": "Шимолий Америка шарқий вақти (Nassau)", + "America\/New_York": "Шимолий Америка шарқий вақти (New York)", + "America\/Nipigon": "Шимолий Америка шарқий вақти (Nipigon)", + "America\/Nome": "Аляска вақти (Nome)", + "America\/Noronha": "Фернандо де Норонья вақти (Noronha)", + "America\/North_Dakota\/Beulah": "Шимолий Америка (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Шимолий Америка (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Шимолий Америка (New Salem, North Dakota)", + "America\/Ojinaga": "Шимолий Америка тоғ вақти (Ojinaga)", + "America\/Panama": "Шимолий Америка шарқий вақти (Panama)", + "America\/Pangnirtung": "Шимолий Америка шарқий вақти (Pangnirtung)", + "America\/Paramaribo": "Суринам вақти (Paramaribo)", + "America\/Phoenix": "Шимолий Америка тоғ вақти (Phoenix)", + "America\/Port-au-Prince": "Шимолий Америка шарқий вақти (Port-au-Prince)", + "America\/Port_of_Spain": "Атлантика вақти (Port of Spain)", + "America\/Porto_Velho": "Амазонка вақти (Porto Velho)", + "America\/Puerto_Rico": "Атлантика вақти (Puerto Rico)", + "America\/Punta_Arenas": "Чили вақти (Punta Arenas)", + "America\/Rainy_River": "Шимолий Америка (Rainy River)", + "America\/Rankin_Inlet": "Шимолий Америка (Rankin Inlet)", + "America\/Recife": "Бразилия вақти (Recife)", + "America\/Regina": "Шимолий Америка (Regina)", + "America\/Resolute": "Шимолий Америка (Resolute)", + "America\/Santarem": "Бразилия вақти (Santarem)", + "America\/Santiago": "Чили вақти (Santiago)", + "America\/Santo_Domingo": "Атлантика вақти (Santo Domingo)", + "America\/Sao_Paulo": "Бразилия вақти (Sao Paulo)", + "America\/Scoresbysund": "Шарқий Гренландия вақти (Ittoqqortoormiit)", + "America\/Sitka": "Аляска вақти (Sitka)", + "America\/St_Barthelemy": "Атлантика вақти (St. Barthelemy)", + "America\/St_Johns": "Ньюфаундленд вақти (St. John’s)", + "America\/St_Kitts": "Атлантика вақти (St. Kitts)", + "America\/St_Lucia": "Атлантика вақти (St. Lucia)", + "America\/St_Thomas": "Атлантика вақти (St. Thomas)", + "America\/St_Vincent": "Атлантика вақти (St. Vincent)", + "America\/Swift_Current": "Шимолий Америка (Swift Current)", + "America\/Tegucigalpa": "Шимолий Америка (Tegucigalpa)", + "America\/Thule": "Атлантика вақти (Thule)", + "America\/Thunder_Bay": "Шимолий Америка шарқий вақти (Thunder Bay)", + "America\/Tijuana": "Шимолий Америка тинч океани вақти (Tijuana)", + "America\/Toronto": "Шимолий Америка шарқий вақти (Toronto)", + "America\/Tortola": "Атлантика вақти (Tortola)", + "America\/Vancouver": "Шимолий Америка тинч океани вақти (Vancouver)", + "America\/Whitehorse": "Шимолий Америка тинч океани вақти (Whitehorse)", + "America\/Winnipeg": "Шимолий Америка (Winnipeg)", + "America\/Yakutat": "Аляска вақти (Yakutat)", + "America\/Yellowknife": "Шимолий Америка тоғ вақти (Yellowknife)", + "Antarctica\/Casey": "Ғарбий Австралия вақти (Casey)", + "Antarctica\/Davis": "Дэвис вақти (Davis)", + "Antarctica\/DumontDUrville": "Думонт-д-Урвил вақти (Dumont d’Urville)", + "Antarctica\/Macquarie": "Маквари ороли вақти (Macquarie)", + "Antarctica\/Mawson": "Моувсон вақти (Mawson)", + "Antarctica\/McMurdo": "Янги Зеландия вақти (McMurdo)", + "Antarctica\/Palmer": "Чили вақти (Palmer)", + "Antarctica\/Rothera": "Ротера вақти (Rothera)", + "Antarctica\/Syowa": "Сьова вақти (Syowa)", + "Antarctica\/Troll": "Гринвич вақти (Troll)", + "Antarctica\/Vostok": "Восток вақти (Vostok)", + "Arctic\/Longyearbyen": "Марказий Европа вақти (Longyearbyen)", + "Asia\/Aden": "Арабистон вақти (Aden)", + "Asia\/Almaty": "Шарқий Қозоғистон вақти (Almaty)", + "Asia\/Amman": "Шарқий Европа вақти (Amman)", + "Asia\/Aqtau": "Ғарбий Қозоғистон вақти (Aqtau)", + "Asia\/Aqtobe": "Ғарбий Қозоғистон вақти (Aqtobe)", + "Asia\/Ashgabat": "Туркманистон вақти (Ashgabat)", + "Asia\/Atyrau": "Ғарбий Қозоғистон вақти (Atyrau)", + "Asia\/Baghdad": "Арабистон вақти (Baghdad)", + "Asia\/Bahrain": "Арабистон вақти (Bahrain)", + "Asia\/Baku": "Озарбайжон вақти (Baku)", + "Asia\/Bangkok": "Ҳинд-Хитой вақти (Bangkok)", + "Asia\/Beirut": "Шарқий Европа вақти (Beirut)", + "Asia\/Bishkek": "Қирғизистон вақти (Bishkek)", + "Asia\/Brunei": "Бруней Даруссалом вақти (Brunei)", + "Asia\/Calcutta": "Ҳиндистон вақти (Kolkata)", + "Asia\/Chita": "Якутск вақти (Chita)", + "Asia\/Choibalsan": "Чойбалсан вақти (Choibalsan)", + "Asia\/Colombo": "Ҳиндистон вақти (Colombo)", + "Asia\/Damascus": "Шарқий Европа вақти (Damascus)", + "Asia\/Dhaka": "Бангладеш вақти (Dhaka)", + "Asia\/Dili": "Шарқий Тимор вақти (Dili)", + "Asia\/Dubai": "Кўрфаз вақти (Dubai)", + "Asia\/Dushanbe": "Тожикистон вақти (Dushanbe)", + "Asia\/Famagusta": "Шарқий Европа вақти (Famagusta)", + "Asia\/Gaza": "Шарқий Европа вақти (Gaza)", + "Asia\/Hebron": "Шарқий Европа вақти (Hebron)", + "Asia\/Hong_Kong": "Гонконг вақти (Hong Kong)", + "Asia\/Hovd": "Ховд вақти (Hovd)", + "Asia\/Irkutsk": "Иркутск вақти (Irkutsk)", + "Asia\/Jakarta": "Ғарбий Индонезия вақти (Jakarta)", + "Asia\/Jayapura": "Шарқий Индонезия вақти (Jayapura)", + "Asia\/Jerusalem": "Исроил вақти (Jerusalem)", + "Asia\/Kabul": "Афғонистон вақти (Kabul)", + "Asia\/Karachi": "Покистон вақти (Karachi)", + "Asia\/Katmandu": "Непал вақти (Kathmandu)", + "Asia\/Khandyga": "Якутск вақти (Khandyga)", + "Asia\/Krasnoyarsk": "Красноярск вақти (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Малайзия вақти (Kuala Lumpur)", + "Asia\/Kuching": "Малайзия вақти (Kuching)", + "Asia\/Kuwait": "Арабистон вақти (Kuwait)", + "Asia\/Macau": "Хитой вақти (Macao)", + "Asia\/Magadan": "Магадан вақти (Magadan)", + "Asia\/Makassar": "Марказий Индонезия вақти (Makassar)", + "Asia\/Manila": "Филиппин вақти (Manila)", + "Asia\/Muscat": "Кўрфаз вақти (Muscat)", + "Asia\/Nicosia": "Шарқий Европа вақти (Nicosia)", + "Asia\/Novokuznetsk": "Красноярск вақти (Novokuznetsk)", + "Asia\/Novosibirsk": "Новосибирск вақти (Novosibirsk)", + "Asia\/Omsk": "Омск вақти (Omsk)", + "Asia\/Oral": "Ғарбий Қозоғистон вақти (Oral)", + "Asia\/Phnom_Penh": "Ҳинд-Хитой вақти (Phnom Penh)", + "Asia\/Pontianak": "Ғарбий Индонезия вақти (Pontianak)", + "Asia\/Pyongyang": "Корея вақти (Pyongyang)", + "Asia\/Qatar": "Арабистон вақти (Qatar)", + "Asia\/Qostanay": "Шарқий Қозоғистон вақти (Qostanay)", + "Asia\/Qyzylorda": "Ғарбий Қозоғистон вақти (Qyzylorda)", + "Asia\/Rangoon": "Мьянма вақти (Yangon)", + "Asia\/Riyadh": "Арабистон вақти (Riyadh)", + "Asia\/Saigon": "Ҳинд-Хитой вақти (Ho Chi Minh)", + "Asia\/Sakhalin": "Сахалин вақти (Sakhalin)", + "Asia\/Samarkand": "Ўзбекистон вақти (Samarkand)", + "Asia\/Seoul": "Корея вақти (Seoul)", + "Asia\/Shanghai": "Хитой вақти (Shanghai)", + "Asia\/Singapore": "Сингапур вақти (Singapore)", + "Asia\/Srednekolymsk": "Магадан вақти (Srednekolymsk)", + "Asia\/Taipei": "Тайпей вақти (Taipei)", + "Asia\/Tashkent": "Ўзбекистон вақти (Tashkent)", + "Asia\/Tbilisi": "Грузия вақти (Tbilisi)", + "Asia\/Tehran": "Эрон вақти (Tehran)", + "Asia\/Thimphu": "Бутан вақти (Thimphu)", + "Asia\/Tokyo": "Япония вақти (Tokyo)", + "Asia\/Ulaanbaatar": "Улан-Батор вақти (Ulaanbaatar)", + "Asia\/Ust-Nera": "Владивосток вақти (Ust-Nera)", + "Asia\/Vientiane": "Ҳинд-Хитой вақти (Vientiane)", + "Asia\/Vladivostok": "Владивосток вақти (Vladivostok)", + "Asia\/Yakutsk": "Якутск вақти (Yakutsk)", + "Asia\/Yekaterinburg": "Екатеринбург вақти (Yekaterinburg)", + "Asia\/Yerevan": "Арамнистон вақти (Yerevan)", + "Atlantic\/Azores": "Азор вақти (Azores)", + "Atlantic\/Bermuda": "Атлантика вақти (Bermuda)", + "Atlantic\/Canary": "Ғарбий Европа вақти (Canary)", + "Atlantic\/Cape_Verde": "Кабо-Верде вақти (Cape Verde)", + "Atlantic\/Faeroe": "Ғарбий Европа вақти (Faroe)", + "Atlantic\/Madeira": "Ғарбий Европа вақти (Madeira)", + "Atlantic\/Reykjavik": "Гринвич вақти (Reykjavik)", + "Atlantic\/South_Georgia": "Жанубий Джорджия вақти (South Georgia)", + "Atlantic\/St_Helena": "Гринвич вақти (St. Helena)", + "Atlantic\/Stanley": "Фолькленд ороллари вақти (Stanley)", + "Australia\/Adelaide": "Марказий Австралия вақти (Adelaide)", + "Australia\/Brisbane": "Шарқий Австралия вақти (Brisbane)", + "Australia\/Broken_Hill": "Марказий Австралия вақти (Broken Hill)", + "Australia\/Currie": "Шарқий Австралия вақти (Currie)", + "Australia\/Darwin": "Марказий Австралия вақти (Darwin)", + "Australia\/Eucla": "Марказий Австралия Ғарбий вақти (Eucla)", + "Australia\/Hobart": "Шарқий Австралия вақти (Hobart)", + "Australia\/Lindeman": "Шарқий Австралия вақти (Lindeman)", + "Australia\/Lord_Howe": "Лорд Хове вақти (Lord Howe)", + "Australia\/Melbourne": "Шарқий Австралия вақти (Melbourne)", + "Australia\/Perth": "Ғарбий Австралия вақти (Perth)", + "Australia\/Sydney": "Шарқий Австралия вақти (Sydney)", + "CST6CDT": "Шимолий Америка", + "EST5EDT": "Шимолий Америка шарқий вақти", + "Etc\/GMT": "Гринвич вақти", + "Europe\/Amsterdam": "Марказий Европа вақти (Amsterdam)", + "Europe\/Andorra": "Марказий Европа вақти (Andorra)", + "Europe\/Astrakhan": "Москва вақти (Astrakhan)", + "Europe\/Athens": "Шарқий Европа вақти (Athens)", + "Europe\/Belgrade": "Марказий Европа вақти (Belgrade)", + "Europe\/Berlin": "Марказий Европа вақти (Berlin)", + "Europe\/Bratislava": "Марказий Европа вақти (Bratislava)", + "Europe\/Brussels": "Марказий Европа вақти (Brussels)", + "Europe\/Bucharest": "Шарқий Европа вақти (Bucharest)", + "Europe\/Budapest": "Марказий Европа вақти (Budapest)", + "Europe\/Busingen": "Марказий Европа вақти (Busingen)", + "Europe\/Chisinau": "Шарқий Европа вақти (Chisinau)", + "Europe\/Copenhagen": "Марказий Европа вақти (Copenhagen)", + "Europe\/Dublin": "Гринвич вақти (Dublin)", + "Europe\/Gibraltar": "Марказий Европа вақти (Gibraltar)", + "Europe\/Guernsey": "Гринвич вақти (Guernsey)", + "Europe\/Helsinki": "Шарқий Европа вақти (Helsinki)", + "Europe\/Isle_of_Man": "Гринвич вақти (Isle of Man)", + "Europe\/Jersey": "Гринвич вақти (Jersey)", + "Europe\/Kaliningrad": "Шарқий Европа вақти (Kaliningrad)", + "Europe\/Kiev": "Шарқий Европа вақти (Kiev)", + "Europe\/Lisbon": "Ғарбий Европа вақти (Lisbon)", + "Europe\/Ljubljana": "Марказий Европа вақти (Ljubljana)", + "Europe\/London": "Гринвич вақти (London)", + "Europe\/Luxembourg": "Марказий Европа вақти (Luxembourg)", + "Europe\/Madrid": "Марказий Европа вақти (Madrid)", + "Europe\/Malta": "Марказий Европа вақти (Malta)", + "Europe\/Mariehamn": "Шарқий Европа вақти (Mariehamn)", + "Europe\/Minsk": "Москва вақти (Minsk)", + "Europe\/Monaco": "Марказий Европа вақти (Monaco)", + "Europe\/Moscow": "Москва вақти (Moscow)", + "Europe\/Oslo": "Марказий Европа вақти (Oslo)", + "Europe\/Paris": "Марказий Европа вақти (Paris)", + "Europe\/Podgorica": "Марказий Европа вақти (Podgorica)", + "Europe\/Prague": "Марказий Европа вақти (Prague)", + "Europe\/Riga": "Шарқий Европа вақти (Riga)", + "Europe\/Rome": "Марказий Европа вақти (Rome)", + "Europe\/San_Marino": "Марказий Европа вақти (San Marino)", + "Europe\/Sarajevo": "Марказий Европа вақти (Sarajevo)", + "Europe\/Saratov": "Москва вақти (Saratov)", + "Europe\/Simferopol": "Москва вақти (Simferopol)", + "Europe\/Skopje": "Марказий Европа вақти (Skopje)", + "Europe\/Sofia": "Шарқий Европа вақти (Sofia)", + "Europe\/Stockholm": "Марказий Европа вақти (Stockholm)", + "Europe\/Tallinn": "Шарқий Европа вақти (Tallinn)", + "Europe\/Tirane": "Марказий Европа вақти (Tirane)", + "Europe\/Ulyanovsk": "Москва вақти (Ulyanovsk)", + "Europe\/Uzhgorod": "Шарқий Европа вақти (Uzhgorod)", + "Europe\/Vaduz": "Марказий Европа вақти (Vaduz)", + "Europe\/Vatican": "Марказий Европа вақти (Vatican)", + "Europe\/Vienna": "Марказий Европа вақти (Vienna)", + "Europe\/Vilnius": "Шарқий Европа вақти (Vilnius)", + "Europe\/Volgograd": "Волгоград вақти (Volgograd)", + "Europe\/Warsaw": "Марказий Европа вақти (Warsaw)", + "Europe\/Zagreb": "Марказий Европа вақти (Zagreb)", + "Europe\/Zaporozhye": "Шарқий Европа вақти (Zaporozhye)", + "Europe\/Zurich": "Марказий Европа вақти (Zurich)", + "Indian\/Antananarivo": "Шарқий Африка вақти (Antananarivo)", + "Indian\/Chagos": "Ҳинд океани вақти (Chagos)", + "Indian\/Christmas": "Рождество ороли вақти (Christmas)", + "Indian\/Cocos": "Кокос ороллари вақти (Cocos)", + "Indian\/Comoro": "Шарқий Африка вақти (Comoro)", + "Indian\/Kerguelen": "Француз жанубий ва Антарктика вақти (Kerguelen)", + "Indian\/Mahe": "Сейшел ороллари вақти (Mahe)", + "Indian\/Maldives": "Мальдив ороллар (Maldives)", + "Indian\/Mauritius": "Маврикий вақти (Mauritius)", + "Indian\/Mayotte": "Шарқий Африка вақти (Mayotte)", + "Indian\/Reunion": "Реюньон вақти (Reunion)", + "MST7MDT": "Шимолий Америка тоғ вақти", + "PST8PDT": "Шимолий Америка тинч океани вақти", + "Pacific\/Auckland": "Янги Зеландия вақти (Auckland)", + "Pacific\/Bougainville": "Папуа-Янги Гвинея вақти (Bougainville)", + "Pacific\/Chatham": "Чатхам вақти (Chatham)", + "Pacific\/Easter": "Пасхи Ороли вақти (Easter)", + "Pacific\/Efate": "Вануату вақти (Efate)", + "Pacific\/Enderbury": "Феникс ороллари вақти (Enderbury)", + "Pacific\/Fakaofo": "Токелау вақти (Fakaofo)", + "Pacific\/Fiji": "Фижи вақти (Fiji)", + "Pacific\/Funafuti": "Тувалу вақти (Funafuti)", + "Pacific\/Galapagos": "Галапагос вақти (Galapagos)", + "Pacific\/Gambier": "Гамбиер вақти (Gambier)", + "Pacific\/Guadalcanal": "Соломон ороллари вақти (Guadalcanal)", + "Pacific\/Guam": "Каморро вақти (Guam)", + "Pacific\/Honolulu": "Гавайи-алеут вақти (Honolulu)", + "Pacific\/Johnston": "Гавайи-алеут вақти (Johnston)", + "Pacific\/Kiritimati": "Лайн ороллари вақти (Kiritimati)", + "Pacific\/Kosrae": "Косрае вақти (Kosrae)", + "Pacific\/Kwajalein": "Маршалл ороллари вақти (Kwajalein)", + "Pacific\/Majuro": "Маршалл ороллари вақти (Majuro)", + "Pacific\/Marquesas": "Маркезас вақти (Marquesas)", + "Pacific\/Midway": "Самоа вақти (Midway)", + "Pacific\/Nauru": "Науру вақти (Nauru)", + "Pacific\/Niue": "Ниуе вақти (Niue)", + "Pacific\/Norfolk": "Норфолк ороли вақти (Norfolk)", + "Pacific\/Noumea": "Янги Каледония вақти (Noumea)", + "Pacific\/Pago_Pago": "Самоа вақти (Pago Pago)", + "Pacific\/Palau": "Палау вақти (Palau)", + "Pacific\/Pitcairn": "Питкерн вақти (Pitcairn)", + "Pacific\/Ponape": "Понапе вақти (Pohnpei)", + "Pacific\/Port_Moresby": "Папуа-Янги Гвинея вақти (Port Moresby)", + "Pacific\/Rarotonga": "Кук ороллари вақти (Rarotonga)", + "Pacific\/Saipan": "Каморро вақти (Saipan)", + "Pacific\/Tahiti": "Таити вақти (Tahiti)", + "Pacific\/Tarawa": "Гилберт ороллари вақти (Tarawa)", + "Pacific\/Tongatapu": "Тонга вақти (Tongatapu)", + "Pacific\/Truk": "Чуук вақти (Chuuk)", + "Pacific\/Wake": "Уэйк ороли вақти (Wake)", + "Pacific\/Wallis": "Уэллис ва Футуна вақти (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/vi.json b/src/Symfony/Component/Intl/Resources/data/timezones/vi.json new file mode 100644 index 0000000000000..2a3ad3843250c --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/vi.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "Giờ Trung bình Greenwich (Abidjan)", + "Africa\/Accra": "Giờ Trung bình Greenwich (Accra)", + "Africa\/Addis_Ababa": "Giờ Đông Phi (Addis Ababa)", + "Africa\/Algiers": "Giờ Trung Âu (Algiers)", + "Africa\/Asmera": "Giờ Đông Phi (Asmara)", + "Africa\/Bamako": "Giờ Trung bình Greenwich (Bamako)", + "Africa\/Bangui": "Giờ Tây Phi (Bangui)", + "Africa\/Banjul": "Giờ Trung bình Greenwich (Banjul)", + "Africa\/Bissau": "Giờ Trung bình Greenwich (Bissau)", + "Africa\/Blantyre": "Giờ Trung Phi (Blantyre)", + "Africa\/Brazzaville": "Giờ Tây Phi (Brazzaville)", + "Africa\/Bujumbura": "Giờ Trung Phi (Bujumbura)", + "Africa\/Cairo": "Giờ Đông Âu (Cairo)", + "Africa\/Casablanca": "Giờ Tây Âu (Casablanca)", + "Africa\/Ceuta": "Giờ Trung Âu (Ceuta)", + "Africa\/Conakry": "Giờ Trung bình Greenwich (Conakry)", + "Africa\/Dakar": "Giờ Trung bình Greenwich (Dakar)", + "Africa\/Dar_es_Salaam": "Giờ Đông Phi (Dar es Salaam)", + "Africa\/Djibouti": "Giờ Đông Phi (Djibouti)", + "Africa\/Douala": "Giờ Tây Phi (Douala)", + "Africa\/El_Aaiun": "Giờ Tây Âu (El Aaiun)", + "Africa\/Freetown": "Giờ Trung bình Greenwich (Freetown)", + "Africa\/Gaborone": "Giờ Trung Phi (Gaborone)", + "Africa\/Harare": "Giờ Trung Phi (Harare)", + "Africa\/Johannesburg": "Giờ Chuẩn Nam Phi (Johannesburg)", + "Africa\/Juba": "Giờ Đông Phi (Juba)", + "Africa\/Kampala": "Giờ Đông Phi (Kampala)", + "Africa\/Khartoum": "Giờ Trung Phi (Khartoum)", + "Africa\/Kigali": "Giờ Trung Phi (Kigali)", + "Africa\/Kinshasa": "Giờ Tây Phi (Kinshasa)", + "Africa\/Lagos": "Giờ Tây Phi (Lagos)", + "Africa\/Libreville": "Giờ Tây Phi (Libreville)", + "Africa\/Lome": "Giờ Trung bình Greenwich (Lome)", + "Africa\/Luanda": "Giờ Tây Phi (Luanda)", + "Africa\/Lubumbashi": "Giờ Trung Phi (Lubumbashi)", + "Africa\/Lusaka": "Giờ Trung Phi (Lusaka)", + "Africa\/Malabo": "Giờ Tây Phi (Malabo)", + "Africa\/Maputo": "Giờ Trung Phi (Maputo)", + "Africa\/Maseru": "Giờ Chuẩn Nam Phi (Maseru)", + "Africa\/Mbabane": "Giờ Chuẩn Nam Phi (Mbabane)", + "Africa\/Mogadishu": "Giờ Đông Phi (Mogadishu)", + "Africa\/Monrovia": "Giờ Trung bình Greenwich (Monrovia)", + "Africa\/Nairobi": "Giờ Đông Phi (Nairobi)", + "Africa\/Ndjamena": "Giờ Tây Phi (Ndjamena)", + "Africa\/Niamey": "Giờ Tây Phi (Niamey)", + "Africa\/Nouakchott": "Giờ Trung bình Greenwich (Nouakchott)", + "Africa\/Ouagadougou": "Giờ Trung bình Greenwich (Ouagadougou)", + "Africa\/Porto-Novo": "Giờ Tây Phi (Porto-Novo)", + "Africa\/Sao_Tome": "Giờ Trung bình Greenwich (São Tomé)", + "Africa\/Tripoli": "Giờ Đông Âu (Tripoli)", + "Africa\/Tunis": "Giờ Trung Âu (Tunis)", + "Africa\/Windhoek": "Giờ Trung Phi (Windhoek)", + "America\/Adak": "Giờ Hawaii-Aleut (Adak)", + "America\/Anchorage": "Giờ Alaska (Anchorage)", + "America\/Anguilla": "Giờ Đại Tây Dương (Anguilla)", + "America\/Antigua": "Giờ Đại Tây Dương (Antigua)", + "America\/Araguaina": "Giờ Brasilia (Araguaina)", + "America\/Argentina\/La_Rioja": "Giờ Argentina (La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Giờ Argentina (Rio Gallegos)", + "America\/Argentina\/Salta": "Giờ Argentina (Salta)", + "America\/Argentina\/San_Juan": "Giờ Argentina (San Juan)", + "America\/Argentina\/San_Luis": "Giờ miền tây Argentina (San Luis)", + "America\/Argentina\/Tucuman": "Giờ Argentina (Tucuman)", + "America\/Argentina\/Ushuaia": "Giờ Argentina (Ushuaia)", + "America\/Aruba": "Giờ Đại Tây Dương (Aruba)", + "America\/Asuncion": "Giờ Paraguay (Asunción)", + "America\/Bahia": "Giờ Brasilia (Bahia)", + "America\/Bahia_Banderas": "Giờ miền Trung (Bahia Banderas)", + "America\/Barbados": "Giờ Đại Tây Dương (Barbados)", + "America\/Belem": "Giờ Brasilia (Belem)", + "America\/Belize": "Giờ miền Trung (Belize)", + "America\/Blanc-Sablon": "Giờ Đại Tây Dương (Blanc-Sablon)", + "America\/Boa_Vista": "Giờ Amazon (Boa Vista)", + "America\/Bogota": "Giờ Colombia (Bogota)", + "America\/Boise": "Giờ miền núi (Boise)", + "America\/Buenos_Aires": "Giờ Argentina (Buenos Aires)", + "America\/Cambridge_Bay": "Giờ miền núi (Cambridge Bay)", + "America\/Campo_Grande": "Giờ Amazon (Campo Grande)", + "America\/Cancun": "Giờ miền Đông (Cancun)", + "America\/Caracas": "Giờ Venezuela (Caracas)", + "America\/Catamarca": "Giờ Argentina (Catamarca)", + "America\/Cayenne": "Giờ Guiana thuộc Pháp (Cayenne)", + "America\/Cayman": "Giờ miền Đông (Cayman)", + "America\/Chicago": "Giờ miền Trung (Chicago)", + "America\/Chihuahua": "Giờ Thái Bình Dương Mexico (Chihuahua)", + "America\/Coral_Harbour": "Giờ miền Đông (Atikokan)", + "America\/Cordoba": "Giờ Argentina (Cordoba)", + "America\/Costa_Rica": "Giờ miền Trung (Costa Rica)", + "America\/Creston": "Giờ miền núi (Creston)", + "America\/Cuiaba": "Giờ Amazon (Cuiaba)", + "America\/Curacao": "Giờ Đại Tây Dương (Curaçao)", + "America\/Danmarkshavn": "Giờ Trung bình Greenwich (Danmarkshavn)", + "America\/Dawson": "Giờ Thái Bình Dương (Dawson)", + "America\/Dawson_Creek": "Giờ miền núi (Dawson Creek)", + "America\/Denver": "Giờ miền núi (Denver)", + "America\/Detroit": "Giờ miền Đông (Detroit)", + "America\/Dominica": "Giờ Đại Tây Dương (Dominica)", + "America\/Edmonton": "Giờ miền núi (Edmonton)", + "America\/Eirunepe": "Giờ Acre (Eirunepe)", + "America\/El_Salvador": "Giờ miền Trung (El Salvador)", + "America\/Fort_Nelson": "Giờ miền núi (Fort Nelson)", + "America\/Fortaleza": "Giờ Brasilia (Fortaleza)", + "America\/Glace_Bay": "Giờ Đại Tây Dương (Glace Bay)", + "America\/Godthab": "Giờ Miền Tây Greenland (Nuuk)", + "America\/Goose_Bay": "Giờ Đại Tây Dương (Goose Bay)", + "America\/Grand_Turk": "Giờ miền Đông (Grand Turk)", + "America\/Grenada": "Giờ Đại Tây Dương (Grenada)", + "America\/Guadeloupe": "Giờ Đại Tây Dương (Guadeloupe)", + "America\/Guatemala": "Giờ miền Trung (Guatemala)", + "America\/Guayaquil": "Giờ Ecuador (Guayaquil)", + "America\/Guyana": "Giờ Guyana (Guyana)", + "America\/Halifax": "Giờ Đại Tây Dương (Halifax)", + "America\/Havana": "Giờ Cuba (Havana)", + "America\/Hermosillo": "Giờ Thái Bình Dương Mexico (Hermosillo)", + "America\/Indiana\/Knox": "Giờ miền Trung (Knox, Indiana)", + "America\/Indiana\/Marengo": "Giờ miền Đông (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Giờ miền Đông (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Giờ miền Trung (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Giờ miền Đông (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Giờ miền Đông (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Giờ miền Đông (Winamac, Indiana)", + "America\/Indianapolis": "Giờ miền Đông (Indianapolis)", + "America\/Inuvik": "Giờ miền núi (Inuvik)", + "America\/Iqaluit": "Giờ miền Đông (Iqaluit)", + "America\/Jamaica": "Giờ miền Đông (Jamaica)", + "America\/Jujuy": "Giờ Argentina (Jujuy)", + "America\/Juneau": "Giờ Alaska (Juneau)", + "America\/Kentucky\/Monticello": "Giờ miền Đông (Monticello, Kentucky)", + "America\/Kralendijk": "Giờ Đại Tây Dương (Kralendijk)", + "America\/La_Paz": "Giờ Bolivia (La Paz)", + "America\/Lima": "Giờ Peru (Lima)", + "America\/Los_Angeles": "Giờ Thái Bình Dương (Los Angeles)", + "America\/Louisville": "Giờ miền Đông (Louisville)", + "America\/Lower_Princes": "Giờ Đại Tây Dương (Lower Prince’s Quarter)", + "America\/Maceio": "Giờ Brasilia (Maceio)", + "America\/Managua": "Giờ miền Trung (Managua)", + "America\/Manaus": "Giờ Amazon (Manaus)", + "America\/Marigot": "Giờ Đại Tây Dương (Marigot)", + "America\/Martinique": "Giờ Đại Tây Dương (Martinique)", + "America\/Matamoros": "Giờ miền Trung (Matamoros)", + "America\/Mazatlan": "Giờ Thái Bình Dương Mexico (Mazatlan)", + "America\/Mendoza": "Giờ Argentina (Mendoza)", + "America\/Menominee": "Giờ miền Trung (Menominee)", + "America\/Merida": "Giờ miền Trung (Merida)", + "America\/Metlakatla": "Giờ Alaska (Metlakatla)", + "America\/Mexico_City": "Giờ miền Trung (Mexico City)", + "America\/Miquelon": "Giờ St. Pierre và Miquelon (Miquelon)", + "America\/Moncton": "Giờ Đại Tây Dương (Moncton)", + "America\/Monterrey": "Giờ miền Trung (Monterrey)", + "America\/Montevideo": "Giờ Uruguay (Montevideo)", + "America\/Montserrat": "Giờ Đại Tây Dương (Montserrat)", + "America\/Nassau": "Giờ miền Đông (Nassau)", + "America\/New_York": "Giờ miền Đông (New York)", + "America\/Nipigon": "Giờ miền Đông (Nipigon)", + "America\/Nome": "Giờ Alaska (Nome)", + "America\/Noronha": "Giờ Fernando de Noronha (Noronha)", + "America\/North_Dakota\/Beulah": "Giờ miền Trung (Beulah, Bắc Dakota)", + "America\/North_Dakota\/Center": "Giờ miền Trung (Center, Bắc Dakota)", + "America\/North_Dakota\/New_Salem": "Giờ miền Trung (New Salem, Bắc Dakota)", + "America\/Ojinaga": "Giờ miền núi (Ojinaga)", + "America\/Panama": "Giờ miền Đông (Panama)", + "America\/Pangnirtung": "Giờ miền Đông (Pangnirtung)", + "America\/Paramaribo": "Giờ Suriname (Paramaribo)", + "America\/Phoenix": "Giờ miền núi (Phoenix)", + "America\/Port-au-Prince": "Giờ miền Đông (Port-au-Prince)", + "America\/Port_of_Spain": "Giờ Đại Tây Dương (Port of Spain)", + "America\/Porto_Velho": "Giờ Amazon (Porto Velho)", + "America\/Puerto_Rico": "Giờ Đại Tây Dương (Puerto Rico)", + "America\/Punta_Arenas": "Giờ Chile (Punta Arenas)", + "America\/Rainy_River": "Giờ miền Trung (Rainy River)", + "America\/Rankin_Inlet": "Giờ miền Trung (Rankin Inlet)", + "America\/Recife": "Giờ Brasilia (Recife)", + "America\/Regina": "Giờ miền Trung (Regina)", + "America\/Resolute": "Giờ miền Trung (Resolute)", + "America\/Rio_Branco": "Giờ Acre (Rio Branco)", + "America\/Santa_Isabel": "Giờ Tây Bắc Mexico (Santa Isabel)", + "America\/Santarem": "Giờ Brasilia (Santarem)", + "America\/Santiago": "Giờ Chile (Santiago)", + "America\/Santo_Domingo": "Giờ Đại Tây Dương (Santo Domingo)", + "America\/Sao_Paulo": "Giờ Brasilia (Sao Paulo)", + "America\/Scoresbysund": "Giờ Miền Đông Greenland (Ittoqqortoormiit)", + "America\/Sitka": "Giờ Alaska (Sitka)", + "America\/St_Barthelemy": "Giờ Đại Tây Dương (St. Barthélemy)", + "America\/St_Johns": "Giờ Newfoundland (St. John’s)", + "America\/St_Kitts": "Giờ Đại Tây Dương (St. Kitts)", + "America\/St_Lucia": "Giờ Đại Tây Dương (St. Lucia)", + "America\/St_Thomas": "Giờ Đại Tây Dương (St. Thomas)", + "America\/St_Vincent": "Giờ Đại Tây Dương (St. Vincent)", + "America\/Swift_Current": "Giờ miền Trung (Swift Current)", + "America\/Tegucigalpa": "Giờ miền Trung (Tegucigalpa)", + "America\/Thule": "Giờ Đại Tây Dương (Thule)", + "America\/Thunder_Bay": "Giờ miền Đông (Thunder Bay)", + "America\/Tijuana": "Giờ Thái Bình Dương (Tijuana)", + "America\/Toronto": "Giờ miền Đông (Toronto)", + "America\/Tortola": "Giờ Đại Tây Dương (Tortola)", + "America\/Vancouver": "Giờ Thái Bình Dương (Vancouver)", + "America\/Whitehorse": "Giờ Thái Bình Dương (Whitehorse)", + "America\/Winnipeg": "Giờ miền Trung (Winnipeg)", + "America\/Yakutat": "Giờ Alaska (Yakutat)", + "America\/Yellowknife": "Giờ miền núi (Yellowknife)", + "Antarctica\/Casey": "Giờ Miền Tây Australia (Casey)", + "Antarctica\/Davis": "Giờ Davis (Davis)", + "Antarctica\/DumontDUrville": "Giờ Dumont-d’Urville (Dumont d’Urville)", + "Antarctica\/Macquarie": "Giờ đảo Macquarie (Macquarie)", + "Antarctica\/Mawson": "Giờ Mawson (Mawson)", + "Antarctica\/McMurdo": "Giờ New Zealand (McMurdo)", + "Antarctica\/Palmer": "Giờ Chile (Palmer)", + "Antarctica\/Rothera": "Giờ Rothera (Rothera)", + "Antarctica\/Syowa": "Giờ Syowa (Syowa)", + "Antarctica\/Troll": "Giờ Trung bình Greenwich (Troll)", + "Antarctica\/Vostok": "Giờ Vostok (Vostok)", + "Arctic\/Longyearbyen": "Giờ Trung Âu (Longyearbyen)", + "Asia\/Aden": "Giờ Ả Rập (Aden)", + "Asia\/Almaty": "Giờ Miền Đông Kazakhstan (Almaty)", + "Asia\/Amman": "Giờ Đông Âu (Amman)", + "Asia\/Anadyr": "Giờ Anadyr (Anadyr)", + "Asia\/Aqtau": "Giờ Miền Tây Kazakhstan (Aqtau)", + "Asia\/Aqtobe": "Giờ Miền Tây Kazakhstan (Aqtobe)", + "Asia\/Ashgabat": "Giờ Turkmenistan (Ashgabat)", + "Asia\/Atyrau": "Giờ Miền Tây Kazakhstan (Atyrau)", + "Asia\/Baghdad": "Giờ Ả Rập (Baghdad)", + "Asia\/Bahrain": "Giờ Ả Rập (Bahrain)", + "Asia\/Baku": "Giờ Azerbaijan (Baku)", + "Asia\/Bangkok": "Giờ Đông Dương (Bangkok)", + "Asia\/Beirut": "Giờ Đông Âu (Beirut)", + "Asia\/Bishkek": "Giờ Kyrgystan (Bishkek)", + "Asia\/Brunei": "Giờ Brunei Darussalam (Brunei)", + "Asia\/Calcutta": "Giờ Chuẩn Ấn Độ (Kolkata)", + "Asia\/Chita": "Giờ Yakutsk (Chita)", + "Asia\/Choibalsan": "Giờ Choibalsan (Choibalsan)", + "Asia\/Colombo": "Giờ Chuẩn Ấn Độ (Colombo)", + "Asia\/Damascus": "Giờ Đông Âu (Damascus)", + "Asia\/Dhaka": "Giờ Bangladesh (Dhaka)", + "Asia\/Dili": "Giờ Đông Timor (Dili)", + "Asia\/Dubai": "Giờ Chuẩn Vùng Vịnh (Dubai)", + "Asia\/Dushanbe": "Giờ Tajikistan (Dushanbe)", + "Asia\/Famagusta": "Giờ Đông Âu (Famagusta)", + "Asia\/Gaza": "Giờ Đông Âu (Gaza)", + "Asia\/Hebron": "Giờ Đông Âu (Hebron)", + "Asia\/Hong_Kong": "Giờ Hồng Kông (Hồng Kông)", + "Asia\/Hovd": "Giờ Hovd (Hovd)", + "Asia\/Irkutsk": "Giờ Irkutsk (Irkutsk)", + "Asia\/Jakarta": "Giờ Miền Tây Indonesia (Jakarta)", + "Asia\/Jayapura": "Giờ Miền Đông Indonesia (Jayapura)", + "Asia\/Jerusalem": "Giờ Israel (Jerusalem)", + "Asia\/Kabul": "Giờ Afghanistan (Kabul)", + "Asia\/Kamchatka": "Giờ Petropavlovsk-Kamchatski (Kamchatka)", + "Asia\/Karachi": "Giờ Pakistan (Karachi)", + "Asia\/Katmandu": "Giờ Nepal (Kathmandu)", + "Asia\/Khandyga": "Giờ Yakutsk (Khandyga)", + "Asia\/Krasnoyarsk": "Giờ Krasnoyarsk (Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Giờ Malaysia (Kuala Lumpur)", + "Asia\/Kuching": "Giờ Malaysia (Kuching)", + "Asia\/Kuwait": "Giờ Ả Rập (Kuwait)", + "Asia\/Macau": "Giờ Trung Quốc (Ma Cao)", + "Asia\/Magadan": "Giờ Magadan (Magadan)", + "Asia\/Makassar": "Giờ Miền Trung Indonesia (Makassar)", + "Asia\/Manila": "Giờ Philippin (Manila)", + "Asia\/Muscat": "Giờ Chuẩn Vùng Vịnh (Muscat)", + "Asia\/Nicosia": "Giờ Đông Âu (Nicosia)", + "Asia\/Novokuznetsk": "Giờ Krasnoyarsk (Novokuznetsk)", + "Asia\/Novosibirsk": "Giờ Novosibirsk (Novosibirsk)", + "Asia\/Omsk": "Giờ Omsk (Omsk)", + "Asia\/Oral": "Giờ Miền Tây Kazakhstan (Oral)", + "Asia\/Phnom_Penh": "Giờ Đông Dương (Phnom Penh)", + "Asia\/Pontianak": "Giờ Miền Tây Indonesia (Pontianak)", + "Asia\/Pyongyang": "Giờ Hàn Quốc (Bình Nhưỡng)", + "Asia\/Qatar": "Giờ Ả Rập (Qatar)", + "Asia\/Qostanay": "Giờ Miền Đông Kazakhstan (Qostanay)", + "Asia\/Qyzylorda": "Giờ Miền Tây Kazakhstan (Qyzylorda)", + "Asia\/Rangoon": "Giờ Myanmar (Rangoon)", + "Asia\/Riyadh": "Giờ Ả Rập (Riyadh)", + "Asia\/Saigon": "Giờ Đông Dương (TP Hồ Chí Minh)", + "Asia\/Sakhalin": "Giờ Sakhalin (Sakhalin)", + "Asia\/Samarkand": "Giờ Uzbekistan (Samarkand)", + "Asia\/Seoul": "Giờ Hàn Quốc (Seoul)", + "Asia\/Shanghai": "Giờ Trung Quốc (Thượng Hải)", + "Asia\/Singapore": "Giờ Singapore (Singapore)", + "Asia\/Srednekolymsk": "Giờ Magadan (Srednekolymsk)", + "Asia\/Taipei": "Giờ Đài Bắc (Đài Bắc)", + "Asia\/Tashkent": "Giờ Uzbekistan (Tashkent)", + "Asia\/Tbilisi": "Giờ Gruzia (Tbilisi)", + "Asia\/Tehran": "Giờ Iran (Tehran)", + "Asia\/Thimphu": "Giờ Bhutan (Thimphu)", + "Asia\/Tokyo": "Giờ Nhật Bản (Tokyo)", + "Asia\/Ulaanbaatar": "Giờ Ulan Bator (Ulaanbaatar)", + "Asia\/Ust-Nera": "Giờ Vladivostok (Ust-Nera)", + "Asia\/Vientiane": "Giờ Đông Dương (Viêng Chăn)", + "Asia\/Vladivostok": "Giờ Vladivostok (Vladivostok)", + "Asia\/Yakutsk": "Giờ Yakutsk (Yakutsk)", + "Asia\/Yekaterinburg": "Giờ Yekaterinburg (Yekaterinburg)", + "Asia\/Yerevan": "Giờ Armenia (Yerevan)", + "Atlantic\/Azores": "Giờ Azores (Azores)", + "Atlantic\/Bermuda": "Giờ Đại Tây Dương (Bermuda)", + "Atlantic\/Canary": "Giờ Tây Âu (Canary)", + "Atlantic\/Cape_Verde": "Giờ Cape Verde (Cape Verde)", + "Atlantic\/Faeroe": "Giờ Tây Âu (Faroe)", + "Atlantic\/Madeira": "Giờ Tây Âu (Madeira)", + "Atlantic\/Reykjavik": "Giờ Trung bình Greenwich (Reykjavik)", + "Atlantic\/South_Georgia": "Giờ Nam Georgia (Nam Georgia)", + "Atlantic\/St_Helena": "Giờ Trung bình Greenwich (St. Helena)", + "Atlantic\/Stanley": "Giờ Quần Đảo Falkland (Stanley)", + "Australia\/Adelaide": "Giờ Miền Trung Australia (Adelaide)", + "Australia\/Brisbane": "Giờ Miền Đông Australia (Brisbane)", + "Australia\/Broken_Hill": "Giờ Miền Trung Australia (Broken Hill)", + "Australia\/Currie": "Giờ Miền Đông Australia (Currie)", + "Australia\/Darwin": "Giờ Miền Trung Australia (Darwin)", + "Australia\/Eucla": "Giờ Miền Trung Tây Australia (Eucla)", + "Australia\/Hobart": "Giờ Miền Đông Australia (Hobart)", + "Australia\/Lindeman": "Giờ Miền Đông Australia (Lindeman)", + "Australia\/Lord_Howe": "Giờ Lord Howe (Lord Howe)", + "Australia\/Melbourne": "Giờ Miền Đông Australia (Melbourne)", + "Australia\/Perth": "Giờ Miền Tây Australia (Perth)", + "Australia\/Sydney": "Giờ Miền Đông Australia (Sydney)", + "CST6CDT": "Giờ miền Trung", + "EST5EDT": "Giờ miền Đông", + "Etc\/GMT": "Giờ Trung bình Greenwich", + "Etc\/UTC": "Giờ Phối hợp Quốc tế", + "Europe\/Amsterdam": "Giờ Trung Âu (Amsterdam)", + "Europe\/Andorra": "Giờ Trung Âu (Andorra)", + "Europe\/Astrakhan": "Giờ Matxcơva (Astrakhan)", + "Europe\/Athens": "Giờ Đông Âu (Athens)", + "Europe\/Belgrade": "Giờ Trung Âu (Belgrade)", + "Europe\/Berlin": "Giờ Trung Âu (Berlin)", + "Europe\/Bratislava": "Giờ Trung Âu (Bratislava)", + "Europe\/Brussels": "Giờ Trung Âu (Brussels)", + "Europe\/Bucharest": "Giờ Đông Âu (Bucharest)", + "Europe\/Budapest": "Giờ Trung Âu (Budapest)", + "Europe\/Busingen": "Giờ Trung Âu (Busingen)", + "Europe\/Chisinau": "Giờ Đông Âu (Chisinau)", + "Europe\/Copenhagen": "Giờ Trung Âu (Copenhagen)", + "Europe\/Dublin": "Giờ Trung bình Greenwich (Dublin)", + "Europe\/Gibraltar": "Giờ Trung Âu (Gibraltar)", + "Europe\/Guernsey": "Giờ Trung bình Greenwich (Guernsey)", + "Europe\/Helsinki": "Giờ Đông Âu (Helsinki)", + "Europe\/Isle_of_Man": "Giờ Trung bình Greenwich (Đảo Man)", + "Europe\/Jersey": "Giờ Trung bình Greenwich (Jersey)", + "Europe\/Kaliningrad": "Giờ Đông Âu (Kaliningrad)", + "Europe\/Kiev": "Giờ Đông Âu (Kiev)", + "Europe\/Lisbon": "Giờ Tây Âu (Lisbon)", + "Europe\/Ljubljana": "Giờ Trung Âu (Ljubljana)", + "Europe\/London": "Giờ Trung bình Greenwich (London)", + "Europe\/Luxembourg": "Giờ Trung Âu (Luxembourg)", + "Europe\/Madrid": "Giờ Trung Âu (Madrid)", + "Europe\/Malta": "Giờ Trung Âu (Malta)", + "Europe\/Mariehamn": "Giờ Đông Âu (Mariehamn)", + "Europe\/Minsk": "Giờ Matxcơva (Minsk)", + "Europe\/Monaco": "Giờ Trung Âu (Monaco)", + "Europe\/Moscow": "Giờ Matxcơva (Mát-xcơ-va)", + "Europe\/Oslo": "Giờ Trung Âu (Oslo)", + "Europe\/Paris": "Giờ Trung Âu (Paris)", + "Europe\/Podgorica": "Giờ Trung Âu (Podgorica)", + "Europe\/Prague": "Giờ Trung Âu (Praha)", + "Europe\/Riga": "Giờ Đông Âu (Riga)", + "Europe\/Rome": "Giờ Trung Âu (Rome)", + "Europe\/Samara": "Giờ Samara (Samara)", + "Europe\/San_Marino": "Giờ Trung Âu (San Marino)", + "Europe\/Sarajevo": "Giờ Trung Âu (Sarajevo)", + "Europe\/Saratov": "Giờ Matxcơva (Saratov)", + "Europe\/Simferopol": "Giờ Matxcơva (Simferopol)", + "Europe\/Skopje": "Giờ Trung Âu (Skopje)", + "Europe\/Sofia": "Giờ Đông Âu (Sofia)", + "Europe\/Stockholm": "Giờ Trung Âu (Stockholm)", + "Europe\/Tallinn": "Giờ Đông Âu (Tallinn)", + "Europe\/Tirane": "Giờ Trung Âu (Tirane)", + "Europe\/Ulyanovsk": "Giờ Matxcơva (Ulyanovsk)", + "Europe\/Uzhgorod": "Giờ Đông Âu (Uzhhorod)", + "Europe\/Vaduz": "Giờ Trung Âu (Vaduz)", + "Europe\/Vatican": "Giờ Trung Âu (Vatican)", + "Europe\/Vienna": "Giờ Trung Âu (Vienna)", + "Europe\/Vilnius": "Giờ Đông Âu (Vilnius)", + "Europe\/Volgograd": "Giờ Volgograd (Volgograd)", + "Europe\/Warsaw": "Giờ Trung Âu (Warsaw)", + "Europe\/Zagreb": "Giờ Trung Âu (Zagreb)", + "Europe\/Zaporozhye": "Giờ Đông Âu (Zaporozhye)", + "Europe\/Zurich": "Giờ Trung Âu (Zurich)", + "Indian\/Antananarivo": "Giờ Đông Phi (Antananarivo)", + "Indian\/Chagos": "Giờ Ấn Độ Dương (Chagos)", + "Indian\/Christmas": "Giờ Đảo Christmas (Christmas)", + "Indian\/Cocos": "Giờ Quần Đảo Cocos (Cocos)", + "Indian\/Comoro": "Giờ Đông Phi (Comoro)", + "Indian\/Kerguelen": "Giờ Nam Cực và Nam Nước Pháp (Kerguelen)", + "Indian\/Mahe": "Giờ Seychelles (Mahe)", + "Indian\/Maldives": "Giờ Maldives (Maldives)", + "Indian\/Mauritius": "Giờ Mauritius (Mauritius)", + "Indian\/Mayotte": "Giờ Đông Phi (Mayotte)", + "Indian\/Reunion": "Giờ Reunion (Réunion)", + "MST7MDT": "Giờ miền núi", + "PST8PDT": "Giờ Thái Bình Dương", + "Pacific\/Apia": "Giờ Apia (Apia)", + "Pacific\/Auckland": "Giờ New Zealand (Auckland)", + "Pacific\/Bougainville": "Giờ Papua New Guinea (Bougainville)", + "Pacific\/Chatham": "Giờ Chatham (Chatham)", + "Pacific\/Easter": "Giờ Đảo Phục Sinh (Easter)", + "Pacific\/Efate": "Giờ Vanuatu (Efate)", + "Pacific\/Enderbury": "Giờ Quần Đảo Phoenix (Enderbury)", + "Pacific\/Fakaofo": "Giờ Tokelau (Fakaofo)", + "Pacific\/Fiji": "Giờ Fiji (Fiji)", + "Pacific\/Funafuti": "Giờ Tuvalu (Funafuti)", + "Pacific\/Galapagos": "Giờ Galapagos (Galapagos)", + "Pacific\/Gambier": "Giờ Gambier (Gambier)", + "Pacific\/Guadalcanal": "Giờ Quần Đảo Solomon (Guadalcanal)", + "Pacific\/Guam": "Giờ Chamorro (Guam)", + "Pacific\/Honolulu": "Giờ Hawaii-Aleut (Honolulu)", + "Pacific\/Johnston": "Giờ Hawaii-Aleut (Johnston)", + "Pacific\/Kiritimati": "Giờ Quần Đảo Line (Kiritimati)", + "Pacific\/Kosrae": "Giờ Kosrae (Kosrae)", + "Pacific\/Kwajalein": "Giờ Quần Đảo Marshall (Kwajalein)", + "Pacific\/Majuro": "Giờ Quần Đảo Marshall (Majuro)", + "Pacific\/Marquesas": "Giờ Marquesas (Marquesas)", + "Pacific\/Midway": "Giờ Samoa (Midway)", + "Pacific\/Nauru": "Giờ Nauru (Nauru)", + "Pacific\/Niue": "Giờ Niue (Niue)", + "Pacific\/Norfolk": "Giờ đảo Norfolk (Norfolk)", + "Pacific\/Noumea": "Giờ New Caledonia (Noumea)", + "Pacific\/Pago_Pago": "Giờ Samoa (Pago Pago)", + "Pacific\/Palau": "Giờ Palau (Palau)", + "Pacific\/Pitcairn": "Giờ Pitcairn (Pitcairn)", + "Pacific\/Ponape": "Giờ Ponape (Pohnpei)", + "Pacific\/Port_Moresby": "Giờ Papua New Guinea (Port Moresby)", + "Pacific\/Rarotonga": "Giờ Quần Đảo Cook (Rarotonga)", + "Pacific\/Saipan": "Giờ Chamorro (Saipan)", + "Pacific\/Tahiti": "Giờ Tahiti (Tahiti)", + "Pacific\/Tarawa": "Giờ Quần Đảo Gilbert (Tarawa)", + "Pacific\/Tongatapu": "Giờ Tonga (Tongatapu)", + "Pacific\/Truk": "Giờ Chuuk (Chuuk)", + "Pacific\/Wake": "Giờ Đảo Wake (Wake)", + "Pacific\/Wallis": "Giờ Wallis và Futuna (Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/wo.json b/src/Symfony/Component/Intl/Resources/data/timezones/wo.json new file mode 100644 index 0000000000000..55c03ee9fcb28 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/wo.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.47.84", + "Names": { + "Africa\/Abidjan": "GMT (waxtu Greenwich) (Abidjan)", + "Africa\/Accra": "GMT (waxtu Greenwich) (Accra)", + "Africa\/Algiers": "CTE (waxtu ëroop sàntaraal) (Algiers)", + "Africa\/Bamako": "GMT (waxtu Greenwich) (Bamako)", + "Africa\/Banjul": "GMT (waxtu Greenwich) (Banjul)", + "Africa\/Bissau": "GMT (waxtu Greenwich) (Bissau)", + "Africa\/Cairo": "EET (waxtu ëroop u penku) (Cairo)", + "Africa\/Casablanca": "WET (waxtu ëroop u sowwu-jant (Casablanca)", + "Africa\/Ceuta": "CTE (waxtu ëroop sàntaraal) (Ceuta)", + "Africa\/Conakry": "GMT (waxtu Greenwich) (Conakry)", + "Africa\/Dakar": "GMT (waxtu Greenwich) (Dakar)", + "Africa\/El_Aaiun": "WET (waxtu ëroop u sowwu-jant (El Aaiun)", + "Africa\/Freetown": "GMT (waxtu Greenwich) (Freetown)", + "Africa\/Lome": "GMT (waxtu Greenwich) (Lome)", + "Africa\/Monrovia": "GMT (waxtu Greenwich) (Monrovia)", + "Africa\/Nouakchott": "GMT (waxtu Greenwich) (Nouakchott)", + "Africa\/Ouagadougou": "GMT (waxtu Greenwich) (Ouagadougou)", + "Africa\/Sao_Tome": "GMT (waxtu Greenwich) (Sao Tome)", + "Africa\/Tripoli": "EET (waxtu ëroop u penku) (Tripoli)", + "Africa\/Tunis": "CTE (waxtu ëroop sàntaraal) (Tunis)", + "America\/Anguilla": "AT (waxtu atlàntik) (Anguilla)", + "America\/Antigua": "AT (waxtu atlàntik) (Antigua)", + "America\/Aruba": "AT (waxtu atlàntik) (Aruba)", + "America\/Bahia_Banderas": "CT (waxtu sàntaral) (Bahia Banderas)", + "America\/Barbados": "AT (waxtu atlàntik) (Barbados)", + "America\/Belize": "CT (waxtu sàntaral) (Belize)", + "America\/Blanc-Sablon": "AT (waxtu atlàntik) (Blanc-Sablon)", + "America\/Boise": "MT (waxtu tundu) (Boise)", + "America\/Cambridge_Bay": "MT (waxtu tundu) (Cambridge Bay)", + "America\/Cancun": "ET waxtu penku (Cancun)", + "America\/Cayman": "ET waxtu penku (Cayman)", + "America\/Chicago": "CT (waxtu sàntaral) (Chicago)", + "America\/Coral_Harbour": "ET waxtu penku (Atikokan)", + "America\/Costa_Rica": "CT (waxtu sàntaral) (Costa Rica)", + "America\/Creston": "MT (waxtu tundu) (Creston)", + "America\/Curacao": "AT (waxtu atlàntik) (Curacao)", + "America\/Danmarkshavn": "GMT (waxtu Greenwich) (Danmarkshavn)", + "America\/Dawson": "PT (waxtu pasifik) (Dawson)", + "America\/Dawson_Creek": "MT (waxtu tundu) (Dawson Creek)", + "America\/Denver": "MT (waxtu tundu) (Denver)", + "America\/Detroit": "ET waxtu penku (Detroit)", + "America\/Dominica": "AT (waxtu atlàntik) (Dominica)", + "America\/Edmonton": "MT (waxtu tundu) (Edmonton)", + "America\/El_Salvador": "CT (waxtu sàntaral) (El Salvador)", + "America\/Fort_Nelson": "MT (waxtu tundu) (Fort Nelson)", + "America\/Glace_Bay": "AT (waxtu atlàntik) (Glace Bay)", + "America\/Goose_Bay": "AT (waxtu atlàntik) (Goose Bay)", + "America\/Grand_Turk": "ET waxtu penku (Grand Turk)", + "America\/Grenada": "AT (waxtu atlàntik) (Grenada)", + "America\/Guadeloupe": "AT (waxtu atlàntik) (Guadeloupe)", + "America\/Guatemala": "CT (waxtu sàntaral) (Guatemala)", + "America\/Halifax": "AT (waxtu atlàntik) (Halifax)", + "America\/Indiana\/Knox": "CT (waxtu sàntaral) (Knox, Indiana)", + "America\/Indiana\/Marengo": "ET waxtu penku (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "ET waxtu penku (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "CT (waxtu sàntaral) (Tell City, Indiana)", + "America\/Indiana\/Vevay": "ET waxtu penku (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "ET waxtu penku (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "ET waxtu penku (Winamac, Indiana)", + "America\/Indianapolis": "ET waxtu penku (Indianapolis)", + "America\/Inuvik": "MT (waxtu tundu) (Inuvik)", + "America\/Iqaluit": "ET waxtu penku (Iqaluit)", + "America\/Jamaica": "ET waxtu penku (Jamaica)", + "America\/Kentucky\/Monticello": "ET waxtu penku (Monticello, Kentucky)", + "America\/Kralendijk": "AT (waxtu atlàntik) (Kralendijk)", + "America\/Los_Angeles": "PT (waxtu pasifik) (Los Angeles)", + "America\/Louisville": "ET waxtu penku (Louisville)", + "America\/Lower_Princes": "AT (waxtu atlàntik) (Lower Prince’s Quarter)", + "America\/Managua": "CT (waxtu sàntaral) (Managua)", + "America\/Marigot": "AT (waxtu atlàntik) (Marigot)", + "America\/Martinique": "AT (waxtu atlàntik) (Martinique)", + "America\/Matamoros": "CT (waxtu sàntaral) (Matamoros)", + "America\/Menominee": "CT (waxtu sàntaral) (Menominee)", + "America\/Merida": "CT (waxtu sàntaral) (Merida)", + "America\/Mexico_City": "CT (waxtu sàntaral) (Mexico City)", + "America\/Moncton": "AT (waxtu atlàntik) (Moncton)", + "America\/Monterrey": "CT (waxtu sàntaral) (Monterrey)", + "America\/Montserrat": "AT (waxtu atlàntik) (Montserrat)", + "America\/Nassau": "ET waxtu penku (Nassau)", + "America\/New_York": "ET waxtu penku (New York)", + "America\/Nipigon": "ET waxtu penku (Nipigon)", + "America\/North_Dakota\/Beulah": "CT (waxtu sàntaral) (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "CT (waxtu sàntaral) (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "CT (waxtu sàntaral) (New Salem, North Dakota)", + "America\/Ojinaga": "MT (waxtu tundu) (Ojinaga)", + "America\/Panama": "ET waxtu penku (Panama)", + "America\/Pangnirtung": "ET waxtu penku (Pangnirtung)", + "America\/Phoenix": "MT (waxtu tundu) (Phoenix)", + "America\/Port-au-Prince": "ET waxtu penku (Port-au-Prince)", + "America\/Port_of_Spain": "AT (waxtu atlàntik) (Port of Spain)", + "America\/Puerto_Rico": "AT (waxtu atlàntik) (Puerto Rico)", + "America\/Rainy_River": "CT (waxtu sàntaral) (Rainy River)", + "America\/Rankin_Inlet": "CT (waxtu sàntaral) (Rankin Inlet)", + "America\/Regina": "CT (waxtu sàntaral) (Regina)", + "America\/Resolute": "CT (waxtu sàntaral) (Resolute)", + "America\/Santo_Domingo": "AT (waxtu atlàntik) (Santo Domingo)", + "America\/St_Barthelemy": "AT (waxtu atlàntik) (St. Barthelemy)", + "America\/St_Kitts": "AT (waxtu atlàntik) (St. Kitts)", + "America\/St_Lucia": "AT (waxtu atlàntik) (St. Lucia)", + "America\/St_Thomas": "AT (waxtu atlàntik) (St. Thomas)", + "America\/St_Vincent": "AT (waxtu atlàntik) (St. Vincent)", + "America\/Swift_Current": "CT (waxtu sàntaral) (Swift Current)", + "America\/Tegucigalpa": "CT (waxtu sàntaral) (Tegucigalpa)", + "America\/Thule": "AT (waxtu atlàntik) (Thule)", + "America\/Thunder_Bay": "ET waxtu penku (Thunder Bay)", + "America\/Tijuana": "PT (waxtu pasifik) (Tijuana)", + "America\/Toronto": "ET waxtu penku (Toronto)", + "America\/Tortola": "AT (waxtu atlàntik) (Tortola)", + "America\/Vancouver": "PT (waxtu pasifik) (Vancouver)", + "America\/Whitehorse": "PT (waxtu pasifik) (Whitehorse)", + "America\/Winnipeg": "CT (waxtu sàntaral) (Winnipeg)", + "America\/Yellowknife": "MT (waxtu tundu) (Yellowknife)", + "Antarctica\/Troll": "GMT (waxtu Greenwich) (Troll)", + "Arctic\/Longyearbyen": "CTE (waxtu ëroop sàntaraal) (Longyearbyen)", + "Asia\/Amman": "EET (waxtu ëroop u penku) (Amman)", + "Asia\/Beirut": "EET (waxtu ëroop u penku) (Beirut)", + "Asia\/Damascus": "EET (waxtu ëroop u penku) (Damascus)", + "Asia\/Famagusta": "EET (waxtu ëroop u penku) (Famagusta)", + "Asia\/Gaza": "EET (waxtu ëroop u penku) (Gaza)", + "Asia\/Hebron": "EET (waxtu ëroop u penku) (Hebron)", + "Asia\/Nicosia": "EET (waxtu ëroop u penku) (Nicosia)", + "Atlantic\/Bermuda": "AT (waxtu atlàntik) (Bermuda)", + "Atlantic\/Canary": "WET (waxtu ëroop u sowwu-jant (Canary)", + "Atlantic\/Faeroe": "WET (waxtu ëroop u sowwu-jant (Faroe)", + "Atlantic\/Madeira": "WET (waxtu ëroop u sowwu-jant (Madeira)", + "Atlantic\/Reykjavik": "GMT (waxtu Greenwich) (Reykjavik)", + "Atlantic\/St_Helena": "GMT (waxtu Greenwich) (St. Helena)", + "CST6CDT": "CT (waxtu sàntaral)", + "EST5EDT": "ET waxtu penku", + "Etc\/GMT": "GMT (waxtu Greenwich)", + "Etc\/UTC": "CUT (waxtu iniwelsel yuñ boole)", + "Europe\/Amsterdam": "CTE (waxtu ëroop sàntaraal) (Amsterdam)", + "Europe\/Andorra": "CTE (waxtu ëroop sàntaraal) (Andorra)", + "Europe\/Athens": "EET (waxtu ëroop u penku) (Athens)", + "Europe\/Belgrade": "CTE (waxtu ëroop sàntaraal) (Belgrade)", + "Europe\/Berlin": "CTE (waxtu ëroop sàntaraal) (Berlin)", + "Europe\/Bratislava": "CTE (waxtu ëroop sàntaraal) (Bratislava)", + "Europe\/Brussels": "CTE (waxtu ëroop sàntaraal) (Brussels)", + "Europe\/Bucharest": "EET (waxtu ëroop u penku) (Bucharest)", + "Europe\/Budapest": "CTE (waxtu ëroop sàntaraal) (Budapest)", + "Europe\/Busingen": "CTE (waxtu ëroop sàntaraal) (Busingen)", + "Europe\/Chisinau": "EET (waxtu ëroop u penku) (Chisinau)", + "Europe\/Copenhagen": "CTE (waxtu ëroop sàntaraal) (Copenhagen)", + "Europe\/Dublin": "GMT (waxtu Greenwich) (Dublin)", + "Europe\/Gibraltar": "CTE (waxtu ëroop sàntaraal) (Gibraltar)", + "Europe\/Guernsey": "GMT (waxtu Greenwich) (Guernsey)", + "Europe\/Helsinki": "EET (waxtu ëroop u penku) (Helsinki)", + "Europe\/Isle_of_Man": "GMT (waxtu Greenwich) (Isle of Man)", + "Europe\/Jersey": "GMT (waxtu Greenwich) (Jersey)", + "Europe\/Kaliningrad": "EET (waxtu ëroop u penku) (Kaliningrad)", + "Europe\/Kiev": "EET (waxtu ëroop u penku) (Kiev)", + "Europe\/Lisbon": "WET (waxtu ëroop u sowwu-jant (Lisbon)", + "Europe\/Ljubljana": "CTE (waxtu ëroop sàntaraal) (Ljubljana)", + "Europe\/London": "GMT (waxtu Greenwich) (London)", + "Europe\/Luxembourg": "CTE (waxtu ëroop sàntaraal) (Luxembourg)", + "Europe\/Madrid": "CTE (waxtu ëroop sàntaraal) (Madrid)", + "Europe\/Malta": "CTE (waxtu ëroop sàntaraal) (Malta)", + "Europe\/Mariehamn": "EET (waxtu ëroop u penku) (Mariehamn)", + "Europe\/Monaco": "CTE (waxtu ëroop sàntaraal) (Monaco)", + "Europe\/Oslo": "CTE (waxtu ëroop sàntaraal) (Oslo)", + "Europe\/Paris": "CTE (waxtu ëroop sàntaraal) (Paris)", + "Europe\/Podgorica": "CTE (waxtu ëroop sàntaraal) (Podgorica)", + "Europe\/Prague": "CTE (waxtu ëroop sàntaraal) (Prague)", + "Europe\/Riga": "EET (waxtu ëroop u penku) (Riga)", + "Europe\/Rome": "CTE (waxtu ëroop sàntaraal) (Rome)", + "Europe\/San_Marino": "CTE (waxtu ëroop sàntaraal) (San Marino)", + "Europe\/Sarajevo": "CTE (waxtu ëroop sàntaraal) (Sarajevo)", + "Europe\/Skopje": "CTE (waxtu ëroop sàntaraal) (Skopje)", + "Europe\/Sofia": "EET (waxtu ëroop u penku) (Sofia)", + "Europe\/Stockholm": "CTE (waxtu ëroop sàntaraal) (Stockholm)", + "Europe\/Tallinn": "EET (waxtu ëroop u penku) (Tallinn)", + "Europe\/Tirane": "CTE (waxtu ëroop sàntaraal) (Tirane)", + "Europe\/Uzhgorod": "EET (waxtu ëroop u penku) (Uzhgorod)", + "Europe\/Vaduz": "CTE (waxtu ëroop sàntaraal) (Vaduz)", + "Europe\/Vatican": "CTE (waxtu ëroop sàntaraal) (Vatican)", + "Europe\/Vienna": "CTE (waxtu ëroop sàntaraal) (Vienna)", + "Europe\/Vilnius": "EET (waxtu ëroop u penku) (Vilnius)", + "Europe\/Warsaw": "CTE (waxtu ëroop sàntaraal) (Warsaw)", + "Europe\/Zagreb": "CTE (waxtu ëroop sàntaraal) (Zagreb)", + "Europe\/Zaporozhye": "EET (waxtu ëroop u penku) (Zaporozhye)", + "Europe\/Zurich": "CTE (waxtu ëroop sàntaraal) (Zurich)", + "MST7MDT": "MT (waxtu tundu)", + "PST8PDT": "PT (waxtu pasifik)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/yi.json b/src/Symfony/Component/Intl/Resources/data/timezones/yi.json new file mode 100644 index 0000000000000..88abd9051e5bd --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/yi.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.82", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/yo.json b/src/Symfony/Component/Intl/Resources/data/timezones/yo.json new file mode 100644 index 0000000000000..a33a403004a00 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/yo.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Algiers": "Àkókò Àárin Europe (Algiers)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Cairo": "Àkókò Ìhà Ìlà Oòrùn Europe (Cairo)", + "Africa\/Casablanca": "Àkókò Ìwọ Oòrùn Europe (Casablanca)", + "Africa\/Ceuta": "Àkókò Àárin Europe (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/El_Aaiun": "Àkókò Ìwọ Oòrùn Europe (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Lome": "Greenwich Mean Time (Lome)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tome)", + "Africa\/Tripoli": "Àkókò Ìhà Ìlà Oòrùn Europe (Tripoli)", + "Africa\/Tunis": "Àkókò Àárin Europe (Tunis)", + "America\/Anguilla": "Àkókò Àtìláńtíìkì (Anguilla)", + "America\/Antigua": "Àkókò Àtìláńtíìkì (Antigua)", + "America\/Aruba": "Àkókò Àtìláńtíìkì (Aruba)", + "America\/Bahia_Banderas": "àkókò àárín gbùngbùn (Bahia Banderas)", + "America\/Barbados": "Àkókò Àtìláńtíìkì (Barbados)", + "America\/Belize": "àkókò àárín gbùngbùn (Belize)", + "America\/Blanc-Sablon": "Àkókò Àtìláńtíìkì (Blanc-Sablon)", + "America\/Boise": "Àkókò òkè (Boise)", + "America\/Cambridge_Bay": "Àkókò òkè (Cambridge Bay)", + "America\/Cancun": "Àkókò ìhà ìlà oòrùn (Cancun)", + "America\/Cayman": "Àkókò ìhà ìlà oòrùn (Cayman)", + "America\/Chicago": "àkókò àárín gbùngbùn (Chicago)", + "America\/Coral_Harbour": "Àkókò ìhà ìlà oòrùn (Atikokan)", + "America\/Costa_Rica": "àkókò àárín gbùngbùn (Costa Rica)", + "America\/Creston": "Àkókò òkè (Creston)", + "America\/Curacao": "Àkókò Àtìláńtíìkì (Curacao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Àkókò Pàsífíìkì (Dawson)", + "America\/Dawson_Creek": "Àkókò òkè (Dawson Creek)", + "America\/Denver": "Àkókò òkè (Denver)", + "America\/Detroit": "Àkókò ìhà ìlà oòrùn (Detroit)", + "America\/Dominica": "Àkókò Àtìláńtíìkì (Dominica)", + "America\/Edmonton": "Àkókò òkè (Edmonton)", + "America\/El_Salvador": "àkókò àárín gbùngbùn (El Salvador)", + "America\/Fort_Nelson": "Àkókò òkè (Fort Nelson)", + "America\/Glace_Bay": "Àkókò Àtìláńtíìkì (Glace Bay)", + "America\/Goose_Bay": "Àkókò Àtìláńtíìkì (Goose Bay)", + "America\/Grand_Turk": "Àkókò ìhà ìlà oòrùn (Grand Turk)", + "America\/Grenada": "Àkókò Àtìláńtíìkì (Grenada)", + "America\/Guadeloupe": "Àkókò Àtìláńtíìkì (Guadeloupe)", + "America\/Guatemala": "àkókò àárín gbùngbùn (Guatemala)", + "America\/Halifax": "Àkókò Àtìláńtíìkì (Halifax)", + "America\/Indiana\/Knox": "àkókò àárín gbùngbùn (Knox, Indiana)", + "America\/Indiana\/Marengo": "Àkókò ìhà ìlà oòrùn (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Àkókò ìhà ìlà oòrùn (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "àkókò àárín gbùngbùn (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Àkókò ìhà ìlà oòrùn (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Àkókò ìhà ìlà oòrùn (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Àkókò ìhà ìlà oòrùn (Winamac, Indiana)", + "America\/Indianapolis": "Àkókò ìhà ìlà oòrùn (Indianapolis)", + "America\/Inuvik": "Àkókò òkè (Inuvik)", + "America\/Iqaluit": "Àkókò ìhà ìlà oòrùn (Iqaluit)", + "America\/Jamaica": "Àkókò ìhà ìlà oòrùn (Jamaica)", + "America\/Kentucky\/Monticello": "Àkókò ìhà ìlà oòrùn (Monticello, Kentucky)", + "America\/Kralendijk": "Àkókò Àtìláńtíìkì (Kralendijk)", + "America\/Los_Angeles": "Àkókò Pàsífíìkì (Los Angeles)", + "America\/Louisville": "Àkókò ìhà ìlà oòrùn (Louisville)", + "America\/Lower_Princes": "Àkókò Àtìláńtíìkì (Lower Prince’s Quarter)", + "America\/Managua": "àkókò àárín gbùngbùn (Managua)", + "America\/Marigot": "Àkókò Àtìláńtíìkì (Marigot)", + "America\/Martinique": "Àkókò Àtìláńtíìkì (Martinique)", + "America\/Matamoros": "àkókò àárín gbùngbùn (Matamoros)", + "America\/Menominee": "àkókò àárín gbùngbùn (Menominee)", + "America\/Merida": "àkókò àárín gbùngbùn (Merida)", + "America\/Mexico_City": "àkókò àárín gbùngbùn (Mexico City)", + "America\/Moncton": "Àkókò Àtìláńtíìkì (Moncton)", + "America\/Monterrey": "àkókò àárín gbùngbùn (Monterrey)", + "America\/Montserrat": "Àkókò Àtìláńtíìkì (Montserrat)", + "America\/Nassau": "Àkókò ìhà ìlà oòrùn (Nassau)", + "America\/New_York": "Àkókò ìhà ìlà oòrùn (New York)", + "America\/Nipigon": "Àkókò ìhà ìlà oòrùn (Nipigon)", + "America\/North_Dakota\/Beulah": "àkókò àárín gbùngbùn (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "àkókò àárín gbùngbùn (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "àkókò àárín gbùngbùn (New Salem, North Dakota)", + "America\/Ojinaga": "Àkókò òkè (Ojinaga)", + "America\/Panama": "Àkókò ìhà ìlà oòrùn (Panama)", + "America\/Pangnirtung": "Àkókò ìhà ìlà oòrùn (Pangnirtung)", + "America\/Phoenix": "Àkókò òkè (Phoenix)", + "America\/Port-au-Prince": "Àkókò ìhà ìlà oòrùn (Port-au-Prince)", + "America\/Port_of_Spain": "Àkókò Àtìláńtíìkì (Port of Spain)", + "America\/Puerto_Rico": "Àkókò Àtìláńtíìkì (Puerto Rico)", + "America\/Rainy_River": "àkókò àárín gbùngbùn (Rainy River)", + "America\/Rankin_Inlet": "àkókò àárín gbùngbùn (Rankin Inlet)", + "America\/Regina": "àkókò àárín gbùngbùn (Regina)", + "America\/Resolute": "àkókò àárín gbùngbùn (Resolute)", + "America\/Santo_Domingo": "Àkókò Àtìláńtíìkì (Santo Domingo)", + "America\/St_Barthelemy": "Àkókò Àtìláńtíìkì (St. Barthelemy)", + "America\/St_Kitts": "Àkókò Àtìláńtíìkì (St. Kitts)", + "America\/St_Lucia": "Àkókò Àtìláńtíìkì (St. Lucia)", + "America\/St_Thomas": "Àkókò Àtìláńtíìkì (St. Thomas)", + "America\/St_Vincent": "Àkókò Àtìláńtíìkì (St. Vincent)", + "America\/Swift_Current": "àkókò àárín gbùngbùn (Swift Current)", + "America\/Tegucigalpa": "àkókò àárín gbùngbùn (Tegucigalpa)", + "America\/Thule": "Àkókò Àtìláńtíìkì (Thule)", + "America\/Thunder_Bay": "Àkókò ìhà ìlà oòrùn (Thunder Bay)", + "America\/Tijuana": "Àkókò Pàsífíìkì (Tijuana)", + "America\/Toronto": "Àkókò ìhà ìlà oòrùn (Toronto)", + "America\/Tortola": "Àkókò Àtìláńtíìkì (Tortola)", + "America\/Vancouver": "Àkókò Pàsífíìkì (Vancouver)", + "America\/Whitehorse": "Àkókò Pàsífíìkì (Whitehorse)", + "America\/Winnipeg": "àkókò àárín gbùngbùn (Winnipeg)", + "America\/Yellowknife": "Àkókò òkè (Yellowknife)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Arctic\/Longyearbyen": "Àkókò Àárin Europe (Longyearbyen)", + "Asia\/Amman": "Àkókò Ìhà Ìlà Oòrùn Europe (Amman)", + "Asia\/Beirut": "Àkókò Ìhà Ìlà Oòrùn Europe (Beirut)", + "Asia\/Damascus": "Àkókò Ìhà Ìlà Oòrùn Europe (Damascus)", + "Asia\/Famagusta": "Àkókò Ìhà Ìlà Oòrùn Europe (Famagusta)", + "Asia\/Gaza": "Àkókò Ìhà Ìlà Oòrùn Europe (Gaza)", + "Asia\/Hebron": "Àkókò Ìhà Ìlà Oòrùn Europe (Hebron)", + "Asia\/Nicosia": "Àkókò Ìhà Ìlà Oòrùn Europe (Nicosia)", + "Atlantic\/Bermuda": "Àkókò Àtìláńtíìkì (Bermuda)", + "Atlantic\/Canary": "Àkókò Ìwọ Oòrùn Europe (Canary)", + "Atlantic\/Faeroe": "Àkókò Ìwọ Oòrùn Europe (Faroe)", + "Atlantic\/Madeira": "Àkókò Ìwọ Oòrùn Europe (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/St_Helena": "Greenwich Mean Time (St. Helena)", + "CST6CDT": "àkókò àárín gbùngbùn", + "EST5EDT": "Àkókò ìhà ìlà oòrùn", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Àpapọ̀ Àkókò Àgbáyé", + "Europe\/Amsterdam": "Àkókò Àárin Europe (Amsterdam)", + "Europe\/Andorra": "Àkókò Àárin Europe (Andorra)", + "Europe\/Athens": "Àkókò Ìhà Ìlà Oòrùn Europe (Athens)", + "Europe\/Belgrade": "Àkókò Àárin Europe (Belgrade)", + "Europe\/Berlin": "Àkókò Àárin Europe (Berlin)", + "Europe\/Bratislava": "Àkókò Àárin Europe (Bratislava)", + "Europe\/Brussels": "Àkókò Àárin Europe (Brussels)", + "Europe\/Bucharest": "Àkókò Ìhà Ìlà Oòrùn Europe (Bucharest)", + "Europe\/Budapest": "Àkókò Àárin Europe (Budapest)", + "Europe\/Busingen": "Àkókò Àárin Europe (Busingen)", + "Europe\/Chisinau": "Àkókò Ìhà Ìlà Oòrùn Europe (Chisinau)", + "Europe\/Copenhagen": "Àkókò Àárin Europe (Copenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Àkókò Àárin Europe (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Àkókò Ìhà Ìlà Oòrùn Europe (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Àkókò Ìhà Ìlà Oòrùn Europe (Kaliningrad)", + "Europe\/Kiev": "Àkókò Ìhà Ìlà Oòrùn Europe (Kiev)", + "Europe\/Lisbon": "Àkókò Ìwọ Oòrùn Europe (Lisbon)", + "Europe\/Ljubljana": "Àkókò Àárin Europe (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (London)", + "Europe\/Luxembourg": "Àkókò Àárin Europe (Luxembourg)", + "Europe\/Madrid": "Àkókò Àárin Europe (Madrid)", + "Europe\/Malta": "Àkókò Àárin Europe (Malta)", + "Europe\/Mariehamn": "Àkókò Ìhà Ìlà Oòrùn Europe (Mariehamn)", + "Europe\/Monaco": "Àkókò Àárin Europe (Monaco)", + "Europe\/Oslo": "Àkókò Àárin Europe (Oslo)", + "Europe\/Paris": "Àkókò Àárin Europe (Paris)", + "Europe\/Podgorica": "Àkókò Àárin Europe (Podgorica)", + "Europe\/Prague": "Àkókò Àárin Europe (Prague)", + "Europe\/Riga": "Àkókò Ìhà Ìlà Oòrùn Europe (Riga)", + "Europe\/Rome": "Àkókò Àárin Europe (Rome)", + "Europe\/San_Marino": "Àkókò Àárin Europe (San Marino)", + "Europe\/Sarajevo": "Àkókò Àárin Europe (Sarajevo)", + "Europe\/Skopje": "Àkókò Àárin Europe (Skopje)", + "Europe\/Sofia": "Àkókò Ìhà Ìlà Oòrùn Europe (Sofia)", + "Europe\/Stockholm": "Àkókò Àárin Europe (Stockholm)", + "Europe\/Tallinn": "Àkókò Ìhà Ìlà Oòrùn Europe (Tallinn)", + "Europe\/Tirane": "Àkókò Àárin Europe (Tirane)", + "Europe\/Uzhgorod": "Àkókò Ìhà Ìlà Oòrùn Europe (Uzhgorod)", + "Europe\/Vaduz": "Àkókò Àárin Europe (Vaduz)", + "Europe\/Vatican": "Àkókò Àárin Europe (Vatican)", + "Europe\/Vienna": "Àkókò Àárin Europe (Vienna)", + "Europe\/Vilnius": "Àkókò Ìhà Ìlà Oòrùn Europe (Vilnius)", + "Europe\/Warsaw": "Àkókò Àárin Europe (Warsaw)", + "Europe\/Zagreb": "Àkókò Àárin Europe (Zagreb)", + "Europe\/Zaporozhye": "Àkókò Ìhà Ìlà Oòrùn Europe (Zaporozhye)", + "Europe\/Zurich": "Àkókò Àárin Europe (Zurich)", + "MST7MDT": "Àkókò òkè", + "PST8PDT": "Àkókò Pàsífíìkì" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/yo_BJ.json b/src/Symfony/Component/Intl/Resources/data/timezones/yo_BJ.json new file mode 100644 index 0000000000000..da12288ed3594 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/yo_BJ.json @@ -0,0 +1,188 @@ +{ + "Version": "2.1.48.77", + "Names": { + "Africa\/Abidjan": "Greenwich Mean Time (Abidjan)", + "Africa\/Accra": "Greenwich Mean Time (Accra)", + "Africa\/Algiers": "Àkókò Àárin Europe (Algiers)", + "Africa\/Bamako": "Greenwich Mean Time (Bamako)", + "Africa\/Banjul": "Greenwich Mean Time (Banjul)", + "Africa\/Bissau": "Greenwich Mean Time (Bissau)", + "Africa\/Cairo": "Àkókò Ìhà Ìlà Oòrùn Europe (Cairo)", + "Africa\/Casablanca": "Àkókò Ìwɔ Oòrùn Europe (Casablanca)", + "Africa\/Ceuta": "Àkókò Àárin Europe (Ceuta)", + "Africa\/Conakry": "Greenwich Mean Time (Conakry)", + "Africa\/Dakar": "Greenwich Mean Time (Dakar)", + "Africa\/El_Aaiun": "Àkókò Ìwɔ Oòrùn Europe (El Aaiun)", + "Africa\/Freetown": "Greenwich Mean Time (Freetown)", + "Africa\/Lome": "Greenwich Mean Time (Lome)", + "Africa\/Monrovia": "Greenwich Mean Time (Monrovia)", + "Africa\/Nouakchott": "Greenwich Mean Time (Nouakchott)", + "Africa\/Ouagadougou": "Greenwich Mean Time (Ouagadougou)", + "Africa\/Sao_Tome": "Greenwich Mean Time (Sao Tome)", + "Africa\/Tripoli": "Àkókò Ìhà Ìlà Oòrùn Europe (Tripoli)", + "Africa\/Tunis": "Àkókò Àárin Europe (Tunis)", + "America\/Anguilla": "Àkókò Àtìláńtíìkì (Anguilla)", + "America\/Antigua": "Àkókò Àtìláńtíìkì (Antigua)", + "America\/Aruba": "Àkókò Àtìláńtíìkì (Aruba)", + "America\/Bahia_Banderas": "àkókò àárín gbùngbùn (Bahia Banderas)", + "America\/Barbados": "Àkókò Àtìláńtíìkì (Barbados)", + "America\/Belize": "àkókò àárín gbùngbùn (Belize)", + "America\/Blanc-Sablon": "Àkókò Àtìláńtíìkì (Blanc-Sablon)", + "America\/Boise": "Àkókò òkè (Boise)", + "America\/Cambridge_Bay": "Àkókò òkè (Cambridge Bay)", + "America\/Cancun": "Àkókò ìhà ìlà oòrùn (Cancun)", + "America\/Cayman": "Àkókò ìhà ìlà oòrùn (Cayman)", + "America\/Chicago": "àkókò àárín gbùngbùn (Chicago)", + "America\/Coral_Harbour": "Àkókò ìhà ìlà oòrùn (Atikokan)", + "America\/Costa_Rica": "àkókò àárín gbùngbùn (Costa Rica)", + "America\/Creston": "Àkókò òkè (Creston)", + "America\/Curacao": "Àkókò Àtìláńtíìkì (Curacao)", + "America\/Danmarkshavn": "Greenwich Mean Time (Danmarkshavn)", + "America\/Dawson": "Àkókò Pàsífíìkì (Dawson)", + "America\/Dawson_Creek": "Àkókò òkè (Dawson Creek)", + "America\/Denver": "Àkókò òkè (Denver)", + "America\/Detroit": "Àkókò ìhà ìlà oòrùn (Detroit)", + "America\/Dominica": "Àkókò Àtìláńtíìkì (Dominica)", + "America\/Edmonton": "Àkókò òkè (Edmonton)", + "America\/El_Salvador": "àkókò àárín gbùngbùn (El Salvador)", + "America\/Fort_Nelson": "Àkókò òkè (Fort Nelson)", + "America\/Glace_Bay": "Àkókò Àtìláńtíìkì (Glace Bay)", + "America\/Goose_Bay": "Àkókò Àtìláńtíìkì (Goose Bay)", + "America\/Grand_Turk": "Àkókò ìhà ìlà oòrùn (Grand Turk)", + "America\/Grenada": "Àkókò Àtìláńtíìkì (Grenada)", + "America\/Guadeloupe": "Àkókò Àtìláńtíìkì (Guadeloupe)", + "America\/Guatemala": "àkókò àárín gbùngbùn (Guatemala)", + "America\/Halifax": "Àkókò Àtìláńtíìkì (Halifax)", + "America\/Indiana\/Knox": "àkókò àárín gbùngbùn (Knox, Indiana)", + "America\/Indiana\/Marengo": "Àkókò ìhà ìlà oòrùn (Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Àkókò ìhà ìlà oòrùn (Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "àkókò àárín gbùngbùn (Tell City, Indiana)", + "America\/Indiana\/Vevay": "Àkókò ìhà ìlà oòrùn (Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Àkókò ìhà ìlà oòrùn (Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Àkókò ìhà ìlà oòrùn (Winamac, Indiana)", + "America\/Indianapolis": "Àkókò ìhà ìlà oòrùn (Indianapolis)", + "America\/Inuvik": "Àkókò òkè (Inuvik)", + "America\/Iqaluit": "Àkókò ìhà ìlà oòrùn (Iqaluit)", + "America\/Jamaica": "Àkókò ìhà ìlà oòrùn (Jamaica)", + "America\/Kentucky\/Monticello": "Àkókò ìhà ìlà oòrùn (Monticello, Kentucky)", + "America\/Kralendijk": "Àkókò Àtìláńtíìkì (Kralendijk)", + "America\/Los_Angeles": "Àkókò Pàsífíìkì (Los Angeles)", + "America\/Louisville": "Àkókò ìhà ìlà oòrùn (Louisville)", + "America\/Lower_Princes": "Àkókò Àtìláńtíìkì (Lower Prince’s Quarter)", + "America\/Managua": "àkókò àárín gbùngbùn (Managua)", + "America\/Marigot": "Àkókò Àtìláńtíìkì (Marigot)", + "America\/Martinique": "Àkókò Àtìláńtíìkì (Martinique)", + "America\/Matamoros": "àkókò àárín gbùngbùn (Matamoros)", + "America\/Menominee": "àkókò àárín gbùngbùn (Menominee)", + "America\/Merida": "àkókò àárín gbùngbùn (Merida)", + "America\/Mexico_City": "àkókò àárín gbùngbùn (Mexico City)", + "America\/Moncton": "Àkókò Àtìláńtíìkì (Moncton)", + "America\/Monterrey": "àkókò àárín gbùngbùn (Monterrey)", + "America\/Montserrat": "Àkókò Àtìláńtíìkì (Montserrat)", + "America\/Nassau": "Àkókò ìhà ìlà oòrùn (Nassau)", + "America\/New_York": "Àkókò ìhà ìlà oòrùn (New York)", + "America\/Nipigon": "Àkókò ìhà ìlà oòrùn (Nipigon)", + "America\/North_Dakota\/Beulah": "àkókò àárín gbùngbùn (Beulah, North Dakota)", + "America\/North_Dakota\/Center": "àkókò àárín gbùngbùn (Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "àkókò àárín gbùngbùn (New Salem, North Dakota)", + "America\/Ojinaga": "Àkókò òkè (Ojinaga)", + "America\/Panama": "Àkókò ìhà ìlà oòrùn (Panama)", + "America\/Pangnirtung": "Àkókò ìhà ìlà oòrùn (Pangnirtung)", + "America\/Phoenix": "Àkókò òkè (Phoenix)", + "America\/Port-au-Prince": "Àkókò ìhà ìlà oòrùn (Port-au-Prince)", + "America\/Port_of_Spain": "Àkókò Àtìláńtíìkì (Port of Spain)", + "America\/Puerto_Rico": "Àkókò Àtìláńtíìkì (Puerto Rico)", + "America\/Rainy_River": "àkókò àárín gbùngbùn (Rainy River)", + "America\/Rankin_Inlet": "àkókò àárín gbùngbùn (Rankin Inlet)", + "America\/Regina": "àkókò àárín gbùngbùn (Regina)", + "America\/Resolute": "àkókò àárín gbùngbùn (Resolute)", + "America\/Santo_Domingo": "Àkókò Àtìláńtíìkì (Santo Domingo)", + "America\/St_Barthelemy": "Àkókò Àtìláńtíìkì (St. Barthelemy)", + "America\/St_Kitts": "Àkókò Àtìláńtíìkì (St. Kitts)", + "America\/St_Lucia": "Àkókò Àtìláńtíìkì (St. Lucia)", + "America\/St_Thomas": "Àkókò Àtìláńtíìkì (St. Thomas)", + "America\/St_Vincent": "Àkókò Àtìláńtíìkì (St. Vincent)", + "America\/Swift_Current": "àkókò àárín gbùngbùn (Swift Current)", + "America\/Tegucigalpa": "àkókò àárín gbùngbùn (Tegucigalpa)", + "America\/Thule": "Àkókò Àtìláńtíìkì (Thule)", + "America\/Thunder_Bay": "Àkókò ìhà ìlà oòrùn (Thunder Bay)", + "America\/Tijuana": "Àkókò Pàsífíìkì (Tijuana)", + "America\/Toronto": "Àkókò ìhà ìlà oòrùn (Toronto)", + "America\/Tortola": "Àkókò Àtìláńtíìkì (Tortola)", + "America\/Vancouver": "Àkókò Pàsífíìkì (Vancouver)", + "America\/Whitehorse": "Àkókò Pàsífíìkì (Whitehorse)", + "America\/Winnipeg": "àkókò àárín gbùngbùn (Winnipeg)", + "America\/Yellowknife": "Àkókò òkè (Yellowknife)", + "Antarctica\/Troll": "Greenwich Mean Time (Troll)", + "Arctic\/Longyearbyen": "Àkókò Àárin Europe (Longyearbyen)", + "Asia\/Amman": "Àkókò Ìhà Ìlà Oòrùn Europe (Amman)", + "Asia\/Beirut": "Àkókò Ìhà Ìlà Oòrùn Europe (Beirut)", + "Asia\/Damascus": "Àkókò Ìhà Ìlà Oòrùn Europe (Damascus)", + "Asia\/Famagusta": "Àkókò Ìhà Ìlà Oòrùn Europe (Famagusta)", + "Asia\/Gaza": "Àkókò Ìhà Ìlà Oòrùn Europe (Gaza)", + "Asia\/Hebron": "Àkókò Ìhà Ìlà Oòrùn Europe (Hebron)", + "Asia\/Nicosia": "Àkókò Ìhà Ìlà Oòrùn Europe (Nicosia)", + "Atlantic\/Bermuda": "Àkókò Àtìláńtíìkì (Bermuda)", + "Atlantic\/Canary": "Àkókò Ìwɔ Oòrùn Europe (Canary)", + "Atlantic\/Faeroe": "Àkókò Ìwɔ Oòrùn Europe (Faroe)", + "Atlantic\/Madeira": "Àkókò Ìwɔ Oòrùn Europe (Madeira)", + "Atlantic\/Reykjavik": "Greenwich Mean Time (Reykjavik)", + "Atlantic\/St_Helena": "Greenwich Mean Time (St. Helena)", + "CST6CDT": "àkókò àárín gbùngbùn", + "EST5EDT": "Àkókò ìhà ìlà oòrùn", + "Etc\/GMT": "Greenwich Mean Time", + "Etc\/UTC": "Àpapɔ̀ Àkókò Àgbáyé", + "Europe\/Amsterdam": "Àkókò Àárin Europe (Amsterdam)", + "Europe\/Andorra": "Àkókò Àárin Europe (Andorra)", + "Europe\/Athens": "Àkókò Ìhà Ìlà Oòrùn Europe (Athens)", + "Europe\/Belgrade": "Àkókò Àárin Europe (Belgrade)", + "Europe\/Berlin": "Àkókò Àárin Europe (Berlin)", + "Europe\/Bratislava": "Àkókò Àárin Europe (Bratislava)", + "Europe\/Brussels": "Àkókò Àárin Europe (Brussels)", + "Europe\/Bucharest": "Àkókò Ìhà Ìlà Oòrùn Europe (Bucharest)", + "Europe\/Budapest": "Àkókò Àárin Europe (Budapest)", + "Europe\/Busingen": "Àkókò Àárin Europe (Busingen)", + "Europe\/Chisinau": "Àkókò Ìhà Ìlà Oòrùn Europe (Chisinau)", + "Europe\/Copenhagen": "Àkókò Àárin Europe (Copenhagen)", + "Europe\/Dublin": "Greenwich Mean Time (Dublin)", + "Europe\/Gibraltar": "Àkókò Àárin Europe (Gibraltar)", + "Europe\/Guernsey": "Greenwich Mean Time (Guernsey)", + "Europe\/Helsinki": "Àkókò Ìhà Ìlà Oòrùn Europe (Helsinki)", + "Europe\/Isle_of_Man": "Greenwich Mean Time (Isle of Man)", + "Europe\/Jersey": "Greenwich Mean Time (Jersey)", + "Europe\/Kaliningrad": "Àkókò Ìhà Ìlà Oòrùn Europe (Kaliningrad)", + "Europe\/Kiev": "Àkókò Ìhà Ìlà Oòrùn Europe (Kiev)", + "Europe\/Lisbon": "Àkókò Ìwɔ Oòrùn Europe (Lisbon)", + "Europe\/Ljubljana": "Àkókò Àárin Europe (Ljubljana)", + "Europe\/London": "Greenwich Mean Time (London)", + "Europe\/Luxembourg": "Àkókò Àárin Europe (Luxembourg)", + "Europe\/Madrid": "Àkókò Àárin Europe (Madrid)", + "Europe\/Malta": "Àkókò Àárin Europe (Malta)", + "Europe\/Mariehamn": "Àkókò Ìhà Ìlà Oòrùn Europe (Mariehamn)", + "Europe\/Monaco": "Àkókò Àárin Europe (Monaco)", + "Europe\/Oslo": "Àkókò Àárin Europe (Oslo)", + "Europe\/Paris": "Àkókò Àárin Europe (Paris)", + "Europe\/Podgorica": "Àkókò Àárin Europe (Podgorica)", + "Europe\/Prague": "Àkókò Àárin Europe (Prague)", + "Europe\/Riga": "Àkókò Ìhà Ìlà Oòrùn Europe (Riga)", + "Europe\/Rome": "Àkókò Àárin Europe (Rome)", + "Europe\/San_Marino": "Àkókò Àárin Europe (San Marino)", + "Europe\/Sarajevo": "Àkókò Àárin Europe (Sarajevo)", + "Europe\/Skopje": "Àkókò Àárin Europe (Skopje)", + "Europe\/Sofia": "Àkókò Ìhà Ìlà Oòrùn Europe (Sofia)", + "Europe\/Stockholm": "Àkókò Àárin Europe (Stockholm)", + "Europe\/Tallinn": "Àkókò Ìhà Ìlà Oòrùn Europe (Tallinn)", + "Europe\/Tirane": "Àkókò Àárin Europe (Tirane)", + "Europe\/Uzhgorod": "Àkókò Ìhà Ìlà Oòrùn Europe (Uzhgorod)", + "Europe\/Vaduz": "Àkókò Àárin Europe (Vaduz)", + "Europe\/Vatican": "Àkókò Àárin Europe (Vatican)", + "Europe\/Vienna": "Àkókò Àárin Europe (Vienna)", + "Europe\/Vilnius": "Àkókò Ìhà Ìlà Oòrùn Europe (Vilnius)", + "Europe\/Warsaw": "Àkókò Àárin Europe (Warsaw)", + "Europe\/Zagreb": "Àkókò Àárin Europe (Zagreb)", + "Europe\/Zaporozhye": "Àkókò Ìhà Ìlà Oòrùn Europe (Zaporozhye)", + "Europe\/Zurich": "Àkókò Àárin Europe (Zurich)", + "MST7MDT": "Àkókò òkè", + "PST8PDT": "Àkókò Pàsífíìkì" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zh.json b/src/Symfony/Component/Intl/Resources/data/timezones/zh.json new file mode 100644 index 0000000000000..312d1217d3d16 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zh.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "格林尼治标准时间 (阿比让)", + "Africa\/Accra": "格林尼治标准时间 (阿克拉)", + "Africa\/Addis_Ababa": "东部非洲时间 (亚的斯亚贝巴)", + "Africa\/Algiers": "中欧时间 (阿尔及尔)", + "Africa\/Asmera": "东部非洲时间 (阿斯马拉)", + "Africa\/Bamako": "格林尼治标准时间 (巴马科)", + "Africa\/Bangui": "西部非洲时间 (班吉)", + "Africa\/Banjul": "格林尼治标准时间 (班珠尔)", + "Africa\/Bissau": "格林尼治标准时间 (比绍)", + "Africa\/Blantyre": "中部非洲时间 (布兰太尔)", + "Africa\/Brazzaville": "西部非洲时间 (布拉柴维尔)", + "Africa\/Bujumbura": "中部非洲时间 (布琼布拉)", + "Africa\/Cairo": "东欧时间 (开罗)", + "Africa\/Casablanca": "西欧时间 (卡萨布兰卡)", + "Africa\/Ceuta": "中欧时间 (休达)", + "Africa\/Conakry": "格林尼治标准时间 (科纳克里)", + "Africa\/Dakar": "格林尼治标准时间 (达喀尔)", + "Africa\/Dar_es_Salaam": "东部非洲时间 (达累斯萨拉姆)", + "Africa\/Djibouti": "东部非洲时间 (吉布提)", + "Africa\/Douala": "西部非洲时间 (杜阿拉)", + "Africa\/El_Aaiun": "西欧时间 (阿尤恩)", + "Africa\/Freetown": "格林尼治标准时间 (弗里敦)", + "Africa\/Gaborone": "中部非洲时间 (哈博罗内)", + "Africa\/Harare": "中部非洲时间 (哈拉雷)", + "Africa\/Johannesburg": "南非标准时间 (约翰内斯堡)", + "Africa\/Juba": "东部非洲时间 (朱巴)", + "Africa\/Kampala": "东部非洲时间 (坎帕拉)", + "Africa\/Khartoum": "中部非洲时间 (喀土穆)", + "Africa\/Kigali": "中部非洲时间 (基加利)", + "Africa\/Kinshasa": "西部非洲时间 (金沙萨)", + "Africa\/Lagos": "西部非洲时间 (拉各斯)", + "Africa\/Libreville": "西部非洲时间 (利伯维尔)", + "Africa\/Lome": "格林尼治标准时间 (洛美)", + "Africa\/Luanda": "西部非洲时间 (罗安达)", + "Africa\/Lubumbashi": "中部非洲时间 (卢本巴希)", + "Africa\/Lusaka": "中部非洲时间 (卢萨卡)", + "Africa\/Malabo": "西部非洲时间 (马拉博)", + "Africa\/Maputo": "中部非洲时间 (马普托)", + "Africa\/Maseru": "南非标准时间 (马塞卢)", + "Africa\/Mbabane": "南非标准时间 (姆巴巴纳)", + "Africa\/Mogadishu": "东部非洲时间 (摩加迪沙)", + "Africa\/Monrovia": "格林尼治标准时间 (蒙罗维亚)", + "Africa\/Nairobi": "东部非洲时间 (内罗毕)", + "Africa\/Ndjamena": "西部非洲时间 (恩贾梅纳)", + "Africa\/Niamey": "西部非洲时间 (尼亚美)", + "Africa\/Nouakchott": "格林尼治标准时间 (努瓦克肖特)", + "Africa\/Ouagadougou": "格林尼治标准时间 (瓦加杜古)", + "Africa\/Porto-Novo": "西部非洲时间 (波多诺伏)", + "Africa\/Sao_Tome": "格林尼治标准时间 (圣多美)", + "Africa\/Tripoli": "东欧时间 (的黎波里)", + "Africa\/Tunis": "中欧时间 (突尼斯)", + "Africa\/Windhoek": "中部非洲时间 (温得和克)", + "America\/Adak": "夏威夷-阿留申时间 (埃达克)", + "America\/Anchorage": "阿拉斯加时间 (安克雷奇)", + "America\/Anguilla": "大西洋时间 (安圭拉)", + "America\/Antigua": "大西洋时间 (安提瓜)", + "America\/Araguaina": "巴西利亚时间 (阿拉瓜伊纳)", + "America\/Argentina\/La_Rioja": "阿根廷时间 (拉里奥哈)", + "America\/Argentina\/Rio_Gallegos": "阿根廷时间 (里奥加耶戈斯)", + "America\/Argentina\/Salta": "阿根廷时间 (萨尔塔)", + "America\/Argentina\/San_Juan": "阿根廷时间 (圣胡安)", + "America\/Argentina\/San_Luis": "阿根廷西部时间 (圣路易斯)", + "America\/Argentina\/Tucuman": "阿根廷时间 (图库曼)", + "America\/Argentina\/Ushuaia": "阿根廷时间 (乌斯怀亚)", + "America\/Aruba": "大西洋时间 (阿鲁巴)", + "America\/Asuncion": "巴拉圭时间 (亚松森)", + "America\/Bahia": "巴西利亚时间 (巴伊亚)", + "America\/Bahia_Banderas": "北美中部时间 (巴伊亚班德拉斯)", + "America\/Barbados": "大西洋时间 (巴巴多斯)", + "America\/Belem": "巴西利亚时间 (贝伦)", + "America\/Belize": "北美中部时间 (伯利兹)", + "America\/Blanc-Sablon": "大西洋时间 (布兰克萨布隆)", + "America\/Boa_Vista": "亚马逊时间 (博阿维斯塔)", + "America\/Bogota": "哥伦比亚时间 (波哥大)", + "America\/Boise": "北美山区时间 (博伊西)", + "America\/Buenos_Aires": "阿根廷时间 (布宜诺斯艾利斯)", + "America\/Cambridge_Bay": "北美山区时间 (剑桥湾)", + "America\/Campo_Grande": "亚马逊时间 (大坎普)", + "America\/Cancun": "北美东部时间 (坎昆)", + "America\/Caracas": "委内瑞拉时间 (加拉加斯)", + "America\/Catamarca": "阿根廷时间 (卡塔马卡)", + "America\/Cayenne": "法属圭亚那标准时间 (卡宴)", + "America\/Cayman": "北美东部时间 (开曼)", + "America\/Chicago": "北美中部时间 (芝加哥)", + "America\/Chihuahua": "墨西哥太平洋时间 (奇瓦瓦)", + "America\/Coral_Harbour": "北美东部时间 (阿蒂科肯)", + "America\/Cordoba": "阿根廷时间 (科尔多瓦)", + "America\/Costa_Rica": "北美中部时间 (哥斯达黎加)", + "America\/Creston": "北美山区时间 (克雷斯顿)", + "America\/Cuiaba": "亚马逊时间 (库亚巴)", + "America\/Curacao": "大西洋时间 (库拉索)", + "America\/Danmarkshavn": "格林尼治标准时间 (丹马沙文)", + "America\/Dawson": "北美太平洋时间 (道森)", + "America\/Dawson_Creek": "北美山区时间 (道森克里克)", + "America\/Denver": "北美山区时间 (丹佛)", + "America\/Detroit": "北美东部时间 (底特律)", + "America\/Dominica": "大西洋时间 (多米尼加)", + "America\/Edmonton": "北美山区时间 (埃德蒙顿)", + "America\/Eirunepe": "阿克里时间 (依伦尼贝)", + "America\/El_Salvador": "北美中部时间 (萨尔瓦多)", + "America\/Fort_Nelson": "北美山区时间 (纳尔逊堡)", + "America\/Fortaleza": "巴西利亚时间 (福塔雷萨)", + "America\/Glace_Bay": "大西洋时间 (格莱斯贝)", + "America\/Godthab": "格陵兰岛西部时间 (努克)", + "America\/Goose_Bay": "大西洋时间 (古斯湾)", + "America\/Grand_Turk": "北美东部时间 (大特克)", + "America\/Grenada": "大西洋时间 (格林纳达)", + "America\/Guadeloupe": "大西洋时间 (瓜德罗普)", + "America\/Guatemala": "北美中部时间 (危地马拉)", + "America\/Guayaquil": "厄瓜多尔标准时间 (瓜亚基尔)", + "America\/Guyana": "圭亚那时间 (圭亚那)", + "America\/Halifax": "大西洋时间 (哈利法克斯)", + "America\/Havana": "古巴时间 (哈瓦那)", + "America\/Hermosillo": "墨西哥太平洋时间 (埃莫西约)", + "America\/Indiana\/Knox": "北美中部时间 (印第安纳州诺克斯)", + "America\/Indiana\/Marengo": "北美东部时间 (印第安纳州马伦戈)", + "America\/Indiana\/Petersburg": "北美东部时间 (印第安纳州彼得斯堡)", + "America\/Indiana\/Tell_City": "北美中部时间 (印第安纳州特尔城)", + "America\/Indiana\/Vevay": "北美东部时间 (印第安纳州维维市)", + "America\/Indiana\/Vincennes": "北美东部时间 (印第安纳州温森斯)", + "America\/Indiana\/Winamac": "北美东部时间 (印第安纳州威纳马克)", + "America\/Indianapolis": "北美东部时间 (印第安纳波利斯)", + "America\/Inuvik": "北美山区时间 (伊努维克)", + "America\/Iqaluit": "北美东部时间 (伊魁特)", + "America\/Jamaica": "北美东部时间 (牙买加)", + "America\/Jujuy": "阿根廷时间 (胡胡伊)", + "America\/Juneau": "阿拉斯加时间 (朱诺)", + "America\/Kentucky\/Monticello": "北美东部时间 (肯塔基州蒙蒂塞洛)", + "America\/Kralendijk": "大西洋时间 (克拉伦代克)", + "America\/La_Paz": "玻利维亚标准时间 (拉巴斯)", + "America\/Lima": "秘鲁时间 (利马)", + "America\/Los_Angeles": "北美太平洋时间 (洛杉矶)", + "America\/Louisville": "北美东部时间 (路易斯维尔)", + "America\/Lower_Princes": "大西洋时间 (下太子区)", + "America\/Maceio": "巴西利亚时间 (马塞约)", + "America\/Managua": "北美中部时间 (马那瓜)", + "America\/Manaus": "亚马逊时间 (马瑙斯)", + "America\/Marigot": "大西洋时间 (马里戈特)", + "America\/Martinique": "大西洋时间 (马提尼克)", + "America\/Matamoros": "北美中部时间 (马塔莫罗斯)", + "America\/Mazatlan": "墨西哥太平洋时间 (马萨特兰)", + "America\/Mendoza": "阿根廷时间 (门多萨)", + "America\/Menominee": "北美中部时间 (梅诺米尼)", + "America\/Merida": "北美中部时间 (梅里达)", + "America\/Metlakatla": "阿拉斯加时间 (梅特拉卡特拉)", + "America\/Mexico_City": "北美中部时间 (墨西哥城)", + "America\/Miquelon": "圣皮埃尔和密克隆群岛时间 (密克隆)", + "America\/Moncton": "大西洋时间 (蒙克顿)", + "America\/Monterrey": "北美中部时间 (蒙特雷)", + "America\/Montevideo": "乌拉圭时间 (蒙得维的亚)", + "America\/Montserrat": "大西洋时间 (蒙特塞拉特)", + "America\/Nassau": "北美东部时间 (拿骚)", + "America\/New_York": "北美东部时间 (纽约)", + "America\/Nipigon": "北美东部时间 (尼皮贡)", + "America\/Nome": "阿拉斯加时间 (诺姆)", + "America\/Noronha": "费尔南多-迪诺罗尼亚岛时间 (洛罗尼亚)", + "America\/North_Dakota\/Beulah": "北美中部时间 (北达科他州比尤拉)", + "America\/North_Dakota\/Center": "北美中部时间 (北达科他州申特)", + "America\/North_Dakota\/New_Salem": "北美中部时间 (北达科他州新塞勒姆)", + "America\/Ojinaga": "北美山区时间 (奥希纳加)", + "America\/Panama": "北美东部时间 (巴拿马)", + "America\/Pangnirtung": "北美东部时间 (旁涅唐)", + "America\/Paramaribo": "苏里南时间 (帕拉马里博)", + "America\/Phoenix": "北美山区时间 (凤凰城)", + "America\/Port-au-Prince": "北美东部时间 (太子港)", + "America\/Port_of_Spain": "大西洋时间 (西班牙港)", + "America\/Porto_Velho": "亚马逊时间 (波多韦柳)", + "America\/Puerto_Rico": "大西洋时间 (波多黎各)", + "America\/Punta_Arenas": "智利时间 (蓬塔阿雷纳斯)", + "America\/Rainy_River": "北美中部时间 (雷尼河)", + "America\/Rankin_Inlet": "北美中部时间 (兰今湾)", + "America\/Recife": "巴西利亚时间 (累西腓)", + "America\/Regina": "北美中部时间 (里贾纳)", + "America\/Resolute": "北美中部时间 (雷索卢特)", + "America\/Rio_Branco": "阿克里时间 (里奥布郎库)", + "America\/Santa_Isabel": "墨西哥西北部时间 (圣伊萨贝尔)", + "America\/Santarem": "巴西利亚时间 (圣塔伦)", + "America\/Santiago": "智利时间 (圣地亚哥)", + "America\/Santo_Domingo": "大西洋时间 (圣多明各)", + "America\/Sao_Paulo": "巴西利亚时间 (圣保罗)", + "America\/Scoresbysund": "格陵兰岛东部时间 (斯科列斯比桑德)", + "America\/Sitka": "阿拉斯加时间 (锡特卡)", + "America\/St_Barthelemy": "大西洋时间 (圣巴泰勒米岛)", + "America\/St_Johns": "纽芬兰时间 (圣约翰斯)", + "America\/St_Kitts": "大西洋时间 (圣基茨)", + "America\/St_Lucia": "大西洋时间 (圣卢西亚)", + "America\/St_Thomas": "大西洋时间 (圣托马斯)", + "America\/St_Vincent": "大西洋时间 (圣文森特)", + "America\/Swift_Current": "北美中部时间 (斯威夫特卡伦特)", + "America\/Tegucigalpa": "北美中部时间 (特古西加尔巴)", + "America\/Thule": "大西洋时间 (图勒)", + "America\/Thunder_Bay": "北美东部时间 (桑德贝)", + "America\/Tijuana": "北美太平洋时间 (蒂华纳)", + "America\/Toronto": "北美东部时间 (多伦多)", + "America\/Tortola": "大西洋时间 (托尔托拉)", + "America\/Vancouver": "北美太平洋时间 (温哥华)", + "America\/Whitehorse": "北美太平洋时间 (怀特霍斯)", + "America\/Winnipeg": "北美中部时间 (温尼伯)", + "America\/Yakutat": "阿拉斯加时间 (亚库塔特)", + "America\/Yellowknife": "北美山区时间 (耶洛奈夫)", + "Antarctica\/Casey": "澳大利亚西部时间 (卡塞)", + "Antarctica\/Davis": "戴维斯时间 (戴维斯)", + "Antarctica\/DumontDUrville": "迪蒙迪尔维尔时间 (迪蒙迪尔维尔)", + "Antarctica\/Macquarie": "麦夸里岛时间 (麦格理)", + "Antarctica\/Mawson": "莫森时间 (莫森)", + "Antarctica\/McMurdo": "新西兰时间 (麦克默多)", + "Antarctica\/Palmer": "智利时间 (帕默尔)", + "Antarctica\/Rothera": "罗瑟拉时间 (罗瑟拉)", + "Antarctica\/Syowa": "昭和时间 (昭和)", + "Antarctica\/Troll": "格林尼治标准时间 (特罗尔)", + "Antarctica\/Vostok": "沃斯托克时间 (沃斯托克)", + "Arctic\/Longyearbyen": "中欧时间 (朗伊尔城)", + "Asia\/Aden": "阿拉伯时间 (亚丁)", + "Asia\/Almaty": "哈萨克斯坦东部时间 (阿拉木图)", + "Asia\/Amman": "东欧时间 (安曼)", + "Asia\/Anadyr": "阿纳德尔时间 (阿纳德尔)", + "Asia\/Aqtau": "哈萨克斯坦西部时间 (阿克套)", + "Asia\/Aqtobe": "哈萨克斯坦西部时间 (阿克托别)", + "Asia\/Ashgabat": "土库曼斯坦时间 (阿什哈巴德)", + "Asia\/Atyrau": "哈萨克斯坦西部时间 (阿特劳)", + "Asia\/Baghdad": "阿拉伯时间 (巴格达)", + "Asia\/Bahrain": "阿拉伯时间 (巴林)", + "Asia\/Baku": "阿塞拜疆时间 (巴库)", + "Asia\/Bangkok": "印度支那时间 (曼谷)", + "Asia\/Beirut": "东欧时间 (贝鲁特)", + "Asia\/Bishkek": "吉尔吉斯斯坦时间 (比什凯克)", + "Asia\/Brunei": "文莱达鲁萨兰时间 (文莱)", + "Asia\/Calcutta": "印度时间 (加尔各答)", + "Asia\/Chita": "雅库茨克时间 (赤塔)", + "Asia\/Choibalsan": "乔巴山时间 (乔巴山)", + "Asia\/Colombo": "印度时间 (科伦坡)", + "Asia\/Damascus": "东欧时间 (大马士革)", + "Asia\/Dhaka": "孟加拉时间 (达卡)", + "Asia\/Dili": "东帝汶时间 (帝力)", + "Asia\/Dubai": "海湾标准时间 (迪拜)", + "Asia\/Dushanbe": "塔吉克斯坦时间 (杜尚别)", + "Asia\/Famagusta": "东欧时间 (法马古斯塔)", + "Asia\/Gaza": "东欧时间 (加沙)", + "Asia\/Hebron": "东欧时间 (希伯伦)", + "Asia\/Hong_Kong": "香港时间 (香港)", + "Asia\/Hovd": "科布多时间 (科布多)", + "Asia\/Irkutsk": "伊尔库茨克时间 (伊尔库茨克)", + "Asia\/Jakarta": "印度尼西亚西部时间 (雅加达)", + "Asia\/Jayapura": "印度尼西亚东部时间 (查亚普拉)", + "Asia\/Jerusalem": "以色列时间 (耶路撒冷)", + "Asia\/Kabul": "阿富汗时间 (喀布尔)", + "Asia\/Kamchatka": "彼得罗巴甫洛夫斯克-堪察加时间 (堪察加)", + "Asia\/Karachi": "巴基斯坦时间 (卡拉奇)", + "Asia\/Katmandu": "尼泊尔时间 (加德满都)", + "Asia\/Khandyga": "雅库茨克时间 (汉德加)", + "Asia\/Krasnoyarsk": "克拉斯诺亚尔斯克时间 (克拉斯诺亚尔斯克)", + "Asia\/Kuala_Lumpur": "马来西亚时间 (吉隆坡)", + "Asia\/Kuching": "马来西亚时间 (古晋)", + "Asia\/Kuwait": "阿拉伯时间 (科威特)", + "Asia\/Macau": "中国时间 (澳门)", + "Asia\/Magadan": "马加丹时间 (马加丹)", + "Asia\/Makassar": "印度尼西亚中部时间 (望加锡)", + "Asia\/Manila": "菲律宾时间 (马尼拉)", + "Asia\/Muscat": "海湾标准时间 (马斯喀特)", + "Asia\/Nicosia": "东欧时间 (尼科西亚)", + "Asia\/Novokuznetsk": "克拉斯诺亚尔斯克时间 (新库兹涅茨克)", + "Asia\/Novosibirsk": "新西伯利亚时间 (诺沃西比尔斯克)", + "Asia\/Omsk": "鄂木斯克时间 (鄂木斯克)", + "Asia\/Oral": "哈萨克斯坦西部时间 (乌拉尔)", + "Asia\/Phnom_Penh": "印度支那时间 (金边)", + "Asia\/Pontianak": "印度尼西亚西部时间 (坤甸)", + "Asia\/Pyongyang": "韩国时间 (平壤)", + "Asia\/Qatar": "阿拉伯时间 (卡塔尔)", + "Asia\/Qostanay": "哈萨克斯坦东部时间 (库斯塔奈)", + "Asia\/Qyzylorda": "哈萨克斯坦西部时间 (克孜洛尔达)", + "Asia\/Rangoon": "缅甸时间 (仰光)", + "Asia\/Riyadh": "阿拉伯时间 (利雅得)", + "Asia\/Saigon": "印度支那时间 (胡志明市)", + "Asia\/Sakhalin": "库页岛时间 (萨哈林)", + "Asia\/Samarkand": "乌兹别克斯坦时间 (撒马尔罕)", + "Asia\/Seoul": "韩国时间 (首尔)", + "Asia\/Shanghai": "中国时间 (上海)", + "Asia\/Singapore": "新加坡标准时间 (新加坡)", + "Asia\/Srednekolymsk": "马加丹时间 (中科雷姆斯克)", + "Asia\/Taipei": "台北时间 (台北)", + "Asia\/Tashkent": "乌兹别克斯坦时间 (塔什干)", + "Asia\/Tbilisi": "格鲁吉亚时间 (第比利斯)", + "Asia\/Tehran": "伊朗时间 (德黑兰)", + "Asia\/Thimphu": "不丹时间 (廷布)", + "Asia\/Tokyo": "日本时间 (东京)", + "Asia\/Ulaanbaatar": "乌兰巴托时间 (乌兰巴托)", + "Asia\/Ust-Nera": "海参崴时间 (乌斯内拉)", + "Asia\/Vientiane": "印度支那时间 (万象)", + "Asia\/Vladivostok": "海参崴时间 (符拉迪沃斯托克)", + "Asia\/Yakutsk": "雅库茨克时间 (雅库茨克)", + "Asia\/Yekaterinburg": "叶卡捷琳堡时间 (叶卡捷琳堡)", + "Asia\/Yerevan": "亚美尼亚时间 (埃里温)", + "Atlantic\/Azores": "亚速尔群岛时间 (亚速尔群岛)", + "Atlantic\/Bermuda": "大西洋时间 (百慕大)", + "Atlantic\/Canary": "西欧时间 (加那利)", + "Atlantic\/Cape_Verde": "佛得角时间 (佛得角)", + "Atlantic\/Faeroe": "西欧时间 (法罗)", + "Atlantic\/Madeira": "西欧时间 (马德拉)", + "Atlantic\/Reykjavik": "格林尼治标准时间 (雷克雅未克)", + "Atlantic\/South_Georgia": "南乔治亚岛时间 (南乔治亚)", + "Atlantic\/St_Helena": "格林尼治标准时间 (圣赫勒拿)", + "Atlantic\/Stanley": "福克兰群岛时间 (斯坦利)", + "Australia\/Adelaide": "澳大利亚中部时间 (阿德莱德)", + "Australia\/Brisbane": "澳大利亚东部时间 (布里斯班)", + "Australia\/Broken_Hill": "澳大利亚中部时间 (布罗肯希尔)", + "Australia\/Currie": "澳大利亚东部时间 (库利)", + "Australia\/Darwin": "澳大利亚中部时间 (达尔文)", + "Australia\/Eucla": "澳大利亚中西部时间 (尤克拉)", + "Australia\/Hobart": "澳大利亚东部时间 (霍巴特)", + "Australia\/Lindeman": "澳大利亚东部时间 (林德曼)", + "Australia\/Lord_Howe": "豪勋爵岛时间 (豪勋爵)", + "Australia\/Melbourne": "澳大利亚东部时间 (墨尔本)", + "Australia\/Perth": "澳大利亚西部时间 (珀斯)", + "Australia\/Sydney": "澳大利亚东部时间 (悉尼)", + "CST6CDT": "北美中部时间", + "EST5EDT": "北美东部时间", + "Etc\/GMT": "格林尼治标准时间", + "Etc\/UTC": "协调世界时", + "Europe\/Amsterdam": "中欧时间 (阿姆斯特丹)", + "Europe\/Andorra": "中欧时间 (安道尔)", + "Europe\/Astrakhan": "莫斯科时间 (阿斯特拉罕)", + "Europe\/Athens": "东欧时间 (雅典)", + "Europe\/Belgrade": "中欧时间 (贝尔格莱德)", + "Europe\/Berlin": "中欧时间 (柏林)", + "Europe\/Bratislava": "中欧时间 (布拉迪斯拉发)", + "Europe\/Brussels": "中欧时间 (布鲁塞尔)", + "Europe\/Bucharest": "东欧时间 (布加勒斯特)", + "Europe\/Budapest": "中欧时间 (布达佩斯)", + "Europe\/Busingen": "中欧时间 (布辛根)", + "Europe\/Chisinau": "东欧时间 (基希讷乌)", + "Europe\/Copenhagen": "中欧时间 (哥本哈根)", + "Europe\/Dublin": "格林尼治标准时间 (都柏林)", + "Europe\/Gibraltar": "中欧时间 (直布罗陀)", + "Europe\/Guernsey": "格林尼治标准时间 (根西岛)", + "Europe\/Helsinki": "东欧时间 (赫尔辛基)", + "Europe\/Isle_of_Man": "格林尼治标准时间 (曼岛)", + "Europe\/Jersey": "格林尼治标准时间 (泽西岛)", + "Europe\/Kaliningrad": "东欧时间 (加里宁格勒)", + "Europe\/Kiev": "东欧时间 (基辅)", + "Europe\/Lisbon": "西欧时间 (里斯本)", + "Europe\/Ljubljana": "中欧时间 (卢布尔雅那)", + "Europe\/London": "格林尼治标准时间 (伦敦)", + "Europe\/Luxembourg": "中欧时间 (卢森堡)", + "Europe\/Madrid": "中欧时间 (马德里)", + "Europe\/Malta": "中欧时间 (马耳他)", + "Europe\/Mariehamn": "东欧时间 (玛丽港)", + "Europe\/Minsk": "莫斯科时间 (明斯克)", + "Europe\/Monaco": "中欧时间 (摩纳哥)", + "Europe\/Moscow": "莫斯科时间 (莫斯科)", + "Europe\/Oslo": "中欧时间 (奥斯陆)", + "Europe\/Paris": "中欧时间 (巴黎)", + "Europe\/Podgorica": "中欧时间 (波德戈里察)", + "Europe\/Prague": "中欧时间 (布拉格)", + "Europe\/Riga": "东欧时间 (里加)", + "Europe\/Rome": "中欧时间 (罗马)", + "Europe\/Samara": "萨马拉时间 (萨马拉)", + "Europe\/San_Marino": "中欧时间 (圣马力诺)", + "Europe\/Sarajevo": "中欧时间 (萨拉热窝)", + "Europe\/Saratov": "莫斯科时间 (萨拉托夫)", + "Europe\/Simferopol": "莫斯科时间 (辛菲罗波尔)", + "Europe\/Skopje": "中欧时间 (斯科普里)", + "Europe\/Sofia": "东欧时间 (索非亚)", + "Europe\/Stockholm": "中欧时间 (斯德哥尔摩)", + "Europe\/Tallinn": "东欧时间 (塔林)", + "Europe\/Tirane": "中欧时间 (地拉那)", + "Europe\/Ulyanovsk": "莫斯科时间 (乌里扬诺夫斯克)", + "Europe\/Uzhgorod": "东欧时间 (乌日哥罗德)", + "Europe\/Vaduz": "中欧时间 (瓦杜兹)", + "Europe\/Vatican": "中欧时间 (梵蒂冈)", + "Europe\/Vienna": "中欧时间 (维也纳)", + "Europe\/Vilnius": "东欧时间 (维尔纽斯)", + "Europe\/Volgograd": "伏尔加格勒时间 (伏尔加格勒)", + "Europe\/Warsaw": "中欧时间 (华沙)", + "Europe\/Zagreb": "中欧时间 (萨格勒布)", + "Europe\/Zaporozhye": "东欧时间 (扎波罗热)", + "Europe\/Zurich": "中欧时间 (苏黎世)", + "Indian\/Antananarivo": "东部非洲时间 (安塔那那利佛)", + "Indian\/Chagos": "印度洋时间 (查戈斯)", + "Indian\/Christmas": "圣诞岛时间 (圣诞岛)", + "Indian\/Cocos": "科科斯群岛时间 (可可斯)", + "Indian\/Comoro": "东部非洲时间 (科摩罗)", + "Indian\/Kerguelen": "法属南方和南极领地时间 (凯尔盖朗)", + "Indian\/Mahe": "塞舌尔时间 (马埃岛)", + "Indian\/Maldives": "马尔代夫时间 (马尔代夫)", + "Indian\/Mauritius": "毛里求斯时间 (毛里求斯)", + "Indian\/Mayotte": "东部非洲时间 (马约特)", + "Indian\/Reunion": "留尼汪时间 (留尼汪)", + "MST7MDT": "北美山区时间", + "PST8PDT": "北美太平洋时间", + "Pacific\/Apia": "阿皮亚时间 (阿皮亚)", + "Pacific\/Auckland": "新西兰时间 (奥克兰)", + "Pacific\/Bougainville": "巴布亚新几内亚时间 (布干维尔)", + "Pacific\/Chatham": "查坦时间 (查塔姆)", + "Pacific\/Easter": "复活节岛时间 (复活节岛)", + "Pacific\/Efate": "瓦努阿图时间 (埃法特)", + "Pacific\/Enderbury": "菲尼克斯群岛时间 (恩德伯里)", + "Pacific\/Fakaofo": "托克劳时间 (法考福)", + "Pacific\/Fiji": "斐济时间 (斐济)", + "Pacific\/Funafuti": "图瓦卢时间 (富纳富提)", + "Pacific\/Galapagos": "加拉帕戈斯时间 (加拉帕戈斯)", + "Pacific\/Gambier": "甘比尔时间 (甘比尔)", + "Pacific\/Guadalcanal": "所罗门群岛时间 (瓜达尔卡纳尔)", + "Pacific\/Guam": "查莫罗时间 (关岛)", + "Pacific\/Honolulu": "夏威夷-阿留申时间 (檀香山)", + "Pacific\/Johnston": "夏威夷-阿留申时间 (约翰斯顿)", + "Pacific\/Kiritimati": "莱恩群岛时间 (基里地马地岛)", + "Pacific\/Kosrae": "科斯雷时间 (库赛埃)", + "Pacific\/Kwajalein": "马绍尔群岛时间 (夸贾林)", + "Pacific\/Majuro": "马绍尔群岛时间 (马朱罗)", + "Pacific\/Marquesas": "马克萨斯群岛时间 (马克萨斯)", + "Pacific\/Midway": "萨摩亚时间 (中途岛)", + "Pacific\/Nauru": "瑙鲁时间 (瑙鲁)", + "Pacific\/Niue": "纽埃时间 (纽埃)", + "Pacific\/Norfolk": "诺福克岛时间 (诺福克)", + "Pacific\/Noumea": "新喀里多尼亚时间 (努美阿)", + "Pacific\/Pago_Pago": "萨摩亚时间 (帕果帕果)", + "Pacific\/Palau": "帕劳时间 (帕劳)", + "Pacific\/Pitcairn": "皮特凯恩时间 (皮特凯恩)", + "Pacific\/Ponape": "波纳佩时间 (波纳佩岛)", + "Pacific\/Port_Moresby": "巴布亚新几内亚时间 (莫尔兹比港)", + "Pacific\/Rarotonga": "库克群岛时间 (拉罗汤加)", + "Pacific\/Saipan": "查莫罗时间 (塞班)", + "Pacific\/Tahiti": "塔希提岛时间 (塔希提)", + "Pacific\/Tarawa": "吉尔伯特群岛时间 (塔拉瓦)", + "Pacific\/Tongatapu": "汤加时间 (东加塔布)", + "Pacific\/Truk": "楚克时间 (特鲁克群岛)", + "Pacific\/Wake": "威克岛时间 (威克)", + "Pacific\/Wallis": "瓦利斯和富图纳时间 (瓦利斯)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zh_HK.json b/src/Symfony/Component/Intl/Resources/data/timezones/zh_HK.json new file mode 100644 index 0000000000000..b5e8d5dd36181 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zh_HK.json @@ -0,0 +1,116 @@ +{ + "Version": "2.1.47.86", + "Names": { + "Africa\/Johannesburg": "南非時間 (約翰內斯堡)", + "Africa\/Maseru": "南非時間 (馬塞魯)", + "Africa\/Mbabane": "南非時間 (Mbabane)", + "America\/Adak": "夏威夷-阿留申時間 (埃達克)", + "America\/Bahia_Banderas": "北美中部時間 (巴伊亞德班德拉斯)", + "America\/Belize": "北美中部時間 (伯利茲)", + "America\/Boise": "北美山區時間 (博伊西)", + "America\/Cambridge_Bay": "北美山區時間 (Cambridge Bay)", + "America\/Cancun": "北美東部時間 (Cancun)", + "America\/Cayman": "北美東部時間 (Cayman)", + "America\/Chicago": "北美中部時間 (Chicago)", + "America\/Coral_Harbour": "北美東部時間 (Atikokan)", + "America\/Costa_Rica": "北美中部時間 (哥斯達黎加)", + "America\/Creston": "北美山區時間 (Creston)", + "America\/Dawson": "北美太平洋時間 (Dawson)", + "America\/Dawson_Creek": "北美山區時間 (道森灣)", + "America\/Denver": "北美山區時間 (Denver)", + "America\/Detroit": "北美東部時間 (Detroit)", + "America\/Edmonton": "北美山區時間 (愛民頓)", + "America\/El_Salvador": "北美中部時間 (El Salvador)", + "America\/Fort_Nelson": "北美山區時間 (Fort Nelson)", + "America\/Grand_Turk": "北美東部時間 (Grand Turk)", + "America\/Guatemala": "北美中部時間 (危地馬拉)", + "America\/Guayaquil": "厄瓜多爾時間 (Guayaquil)", + "America\/Guyana": "圭亞那時間 (圭亞那)", + "America\/Indiana\/Knox": "北美中部時間 (印第安納州諾克斯)", + "America\/Indiana\/Marengo": "北美東部時間 (印第安納州馬倫哥)", + "America\/Indiana\/Petersburg": "北美東部時間 (印第安納州彼得堡)", + "America\/Indiana\/Tell_City": "北美中部時間 (印第安納州特爾城)", + "America\/Indiana\/Vevay": "北美東部時間 (印第安納州韋韋)", + "America\/Indiana\/Vincennes": "北美東部時間 (印第安納州溫森斯)", + "America\/Indiana\/Winamac": "北美東部時間 (印第安納州威納馬克)", + "America\/Indianapolis": "北美東部時間 (印第安納波利斯)", + "America\/Inuvik": "北美山區時間 (伊努維克)", + "America\/Iqaluit": "北美東部時間 (Iqaluit)", + "America\/Jamaica": "北美東部時間 (Jamaica)", + "America\/Kentucky\/Monticello": "北美東部時間 (Monticello, Kentucky)", + "America\/Los_Angeles": "北美太平洋時間 (Los Angeles)", + "America\/Louisville": "北美東部時間 (路易維爾)", + "America\/Managua": "北美中部時間 (馬那瓜)", + "America\/Matamoros": "北美中部時間 (Matamoros)", + "America\/Menominee": "北美中部時間 (梅諾米尼)", + "America\/Merida": "北美中部時間 (Merida)", + "America\/Mexico_City": "北美中部時間 (墨西哥城)", + "America\/Monterrey": "北美中部時間 (蒙特雷)", + "America\/Nassau": "北美東部時間 (拿騷)", + "America\/New_York": "北美東部時間 (New York)", + "America\/Nipigon": "北美東部時間 (尼皮貢)", + "America\/Noronha": "費爾南多迪諾羅尼亞時間 (諾羅尼亞)", + "America\/North_Dakota\/Beulah": "北美中部時間 (北達科他州比尤拉)", + "America\/North_Dakota\/Center": "北美中部時間 (北達科他州中心市)", + "America\/North_Dakota\/New_Salem": "北美中部時間 (北達科他州新薩勒姆)", + "America\/Ojinaga": "北美山區時間 (Ojinaga)", + "America\/Panama": "北美東部時間 (Panama)", + "America\/Pangnirtung": "北美東部時間 (Pangnirtung)", + "America\/Paramaribo": "蘇里南時間 (Paramaribo)", + "America\/Phoenix": "北美山區時間 (Phoenix)", + "America\/Port-au-Prince": "北美東部時間 (Port-au-Prince)", + "America\/Rainy_River": "北美中部時間 (Rainy River)", + "America\/Rankin_Inlet": "北美中部時間 (Rankin Inlet)", + "America\/Regina": "北美中部時間 (Regina)", + "America\/Resolute": "北美中部時間 (Resolute)", + "America\/Swift_Current": "北美中部時間 (Swift Current)", + "America\/Tegucigalpa": "北美中部時間 (特古西加爾巴)", + "America\/Thunder_Bay": "北美東部時間 (雷灣)", + "America\/Tijuana": "北美太平洋時間 (蒂華納)", + "America\/Toronto": "北美東部時間 (Toronto)", + "America\/Vancouver": "北美太平洋時間 (Vancouver)", + "America\/Whitehorse": "北美太平洋時間 (白馬市)", + "America\/Winnipeg": "北美中部時間 (Winnipeg)", + "America\/Yellowknife": "北美山區時間 (黃刀鎮)", + "Antarctica\/DumontDUrville": "迪蒙迪維爾時間 (杜蒙迪維爾站)", + "Antarctica\/Macquarie": "麥夸里群島時間 (麥夸里)", + "Asia\/Baku": "亞塞拜疆時間 (Baku)", + "Asia\/Bangkok": "中南半島時間 (Bangkok)", + "Asia\/Calcutta": "印度時間 (Kolkata)", + "Asia\/Chita": "雅庫茨克時間 (Chita)", + "Asia\/Colombo": "印度時間 (科倫坡)", + "Asia\/Dubai": "波斯灣海域時間 (Dubai)", + "Asia\/Irkutsk": "伊爾庫茨克時間 (伊爾庫茨克)", + "Asia\/Khandyga": "雅庫茨克時間 (Khandyga)", + "Asia\/Muscat": "波斯灣海域時間 (馬斯喀特)", + "Asia\/Phnom_Penh": "中南半島時間 (Phnom Penh)", + "Asia\/Saigon": "中南半島時間 (Ho Chi Minh)", + "Asia\/Singapore": "新加坡時間 (Singapore)", + "Asia\/Tbilisi": "格魯吉亞時間 (Tbilisi)", + "Asia\/Vientiane": "中南半島時間 (Vientiane)", + "Asia\/Yakutsk": "雅庫茨克時間 (雅庫茨克)", + "Atlantic\/Cape_Verde": "佛得角時間 (佛得角)", + "CST6CDT": "北美中部時間", + "EST5EDT": "北美東部時間", + "Indian\/Cocos": "可可斯群島時間 (可可斯群島)", + "Indian\/Mahe": "塞舌爾時間 (Mahe)", + "Indian\/Maldives": "馬爾代夫時間 (馬爾代夫)", + "Indian\/Mauritius": "毛里裘斯時間 (毛里裘斯)", + "MST7MDT": "北美山區時間", + "PST8PDT": "北美太平洋時間", + "Pacific\/Bougainville": "巴布亞新畿內亞時間 (布干維爾島)", + "Pacific\/Efate": "瓦努阿圖時間 (Efate)", + "Pacific\/Funafuti": "圖瓦盧時間 (Funafuti)", + "Pacific\/Galapagos": "加拉帕戈群島時間 (Galapagos)", + "Pacific\/Guadalcanal": "所羅門群島時間 (瓜達爾卡納爾島)", + "Pacific\/Honolulu": "夏威夷-阿留申時間 (Honolulu)", + "Pacific\/Johnston": "夏威夷-阿留申時間 (約翰斯頓環礁)", + "Pacific\/Kosrae": "科斯雷時間 (科斯雷)", + "Pacific\/Marquesas": "馬克薩斯時間 (馬克薩斯群島)", + "Pacific\/Nauru": "瑙魯時間 (瑙魯)", + "Pacific\/Noumea": "新喀里多尼亞時間 (努美阿)", + "Pacific\/Pitcairn": "皮特康時間 (皮特康群島)", + "Pacific\/Port_Moresby": "巴布亞新畿內亞時間 (Port Moresby)", + "Pacific\/Tongatapu": "湯加時間 (湯加塔布島)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hans_SG.json b/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hans_SG.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hans_SG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant.json b/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant.json new file mode 100644 index 0000000000000..51097debd1b37 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant.json @@ -0,0 +1,433 @@ +{ + "Version": "2.1.48.42", + "Names": { + "Africa\/Abidjan": "格林威治標準時間 (阿比讓)", + "Africa\/Accra": "格林威治標準時間 (阿克拉)", + "Africa\/Addis_Ababa": "東非時間 (阿迪斯阿貝巴)", + "Africa\/Algiers": "中歐時間 (阿爾及爾)", + "Africa\/Asmera": "東非時間 (阿斯瑪拉)", + "Africa\/Bamako": "格林威治標準時間 (巴馬科)", + "Africa\/Bangui": "西非時間 (班吉)", + "Africa\/Banjul": "格林威治標準時間 (班竹)", + "Africa\/Bissau": "格林威治標準時間 (比紹)", + "Africa\/Blantyre": "中非時間 (布蘭太爾)", + "Africa\/Brazzaville": "西非時間 (布拉柴維爾)", + "Africa\/Bujumbura": "中非時間 (布松布拉)", + "Africa\/Cairo": "東歐時間 (開羅)", + "Africa\/Casablanca": "西歐時間 (卡薩布蘭卡)", + "Africa\/Ceuta": "中歐時間 (休達)", + "Africa\/Conakry": "格林威治標準時間 (柯那克里)", + "Africa\/Dakar": "格林威治標準時間 (達喀爾)", + "Africa\/Dar_es_Salaam": "東非時間 (沙蘭港)", + "Africa\/Djibouti": "東非時間 (吉布地)", + "Africa\/Douala": "西非時間 (杜阿拉)", + "Africa\/El_Aaiun": "西歐時間 (阿尤恩)", + "Africa\/Freetown": "格林威治標準時間 (自由城)", + "Africa\/Gaborone": "中非時間 (嘉柏隆里)", + "Africa\/Harare": "中非時間 (哈拉雷)", + "Africa\/Johannesburg": "南非標準時間 (約翰尼斯堡)", + "Africa\/Juba": "東非時間 (朱巴)", + "Africa\/Kampala": "東非時間 (坎帕拉)", + "Africa\/Khartoum": "中非時間 (喀土穆)", + "Africa\/Kigali": "中非時間 (基加利)", + "Africa\/Kinshasa": "西非時間 (金夏沙)", + "Africa\/Lagos": "西非時間 (拉哥斯)", + "Africa\/Libreville": "西非時間 (自由市)", + "Africa\/Lome": "格林威治標準時間 (洛美)", + "Africa\/Luanda": "西非時間 (羅安達)", + "Africa\/Lubumbashi": "中非時間 (盧本巴希)", + "Africa\/Lusaka": "中非時間 (路沙卡)", + "Africa\/Malabo": "西非時間 (馬拉博)", + "Africa\/Maputo": "中非時間 (馬普托)", + "Africa\/Maseru": "南非標準時間 (馬賽魯)", + "Africa\/Mbabane": "南非標準時間 (墨巴本)", + "Africa\/Mogadishu": "東非時間 (摩加迪休)", + "Africa\/Monrovia": "格林威治標準時間 (蒙羅維亞)", + "Africa\/Nairobi": "東非時間 (奈洛比)", + "Africa\/Ndjamena": "西非時間 (恩賈梅納)", + "Africa\/Niamey": "西非時間 (尼亞美)", + "Africa\/Nouakchott": "格林威治標準時間 (諾克少)", + "Africa\/Ouagadougou": "格林威治標準時間 (瓦加杜古)", + "Africa\/Porto-Novo": "西非時間 (波多諾佛)", + "Africa\/Sao_Tome": "格林威治標準時間 (聖多美)", + "Africa\/Tripoli": "東歐時間 (的黎波里)", + "Africa\/Tunis": "中歐時間 (突尼斯)", + "Africa\/Windhoek": "中非時間 (溫得和克)", + "America\/Adak": "夏威夷-阿留申時間 (艾達克)", + "America\/Anchorage": "阿拉斯加時間 (安克拉治)", + "America\/Anguilla": "大西洋時間 (安奎拉)", + "America\/Antigua": "大西洋時間 (安地卡)", + "America\/Araguaina": "巴西利亞時間 (阿拉圭那)", + "America\/Argentina\/La_Rioja": "阿根廷時間 (拉略哈)", + "America\/Argentina\/Rio_Gallegos": "阿根廷時間 (里奧加耶戈斯)", + "America\/Argentina\/Salta": "阿根廷時間 (薩爾塔)", + "America\/Argentina\/San_Juan": "阿根廷時間 (聖胡安)", + "America\/Argentina\/San_Luis": "阿根廷西部時間 (聖路易)", + "America\/Argentina\/Tucuman": "阿根廷時間 (吐庫曼)", + "America\/Argentina\/Ushuaia": "阿根廷時間 (烏斯懷亞)", + "America\/Aruba": "大西洋時間 (荷屬阿魯巴)", + "America\/Asuncion": "巴拉圭時間 (亞松森)", + "America\/Bahia": "巴西利亞時間 (巴伊阿)", + "America\/Bahia_Banderas": "中部時間 (巴伊亞班德拉斯)", + "America\/Barbados": "大西洋時間 (巴貝多)", + "America\/Belem": "巴西利亞時間 (貝倫)", + "America\/Belize": "中部時間 (貝里斯)", + "America\/Blanc-Sablon": "大西洋時間 (白朗薩布隆)", + "America\/Boa_Vista": "亞馬遜時間 (保維斯塔)", + "America\/Bogota": "哥倫比亞時間 (波哥大)", + "America\/Boise": "山區時間 (波夕)", + "America\/Buenos_Aires": "阿根廷時間 (布宜諾斯艾利斯)", + "America\/Cambridge_Bay": "山區時間 (劍橋灣)", + "America\/Campo_Grande": "亞馬遜時間 (格蘭場)", + "America\/Cancun": "東部時間 (坎昆)", + "America\/Caracas": "委內瑞拉時間 (卡拉卡斯)", + "America\/Catamarca": "阿根廷時間 (卡塔馬卡)", + "America\/Cayenne": "法屬圭亞那時間 (開雲)", + "America\/Cayman": "東部時間 (開曼群島)", + "America\/Chicago": "中部時間 (芝加哥)", + "America\/Chihuahua": "墨西哥太平洋時間 (奇華華)", + "America\/Coral_Harbour": "東部時間 (阿蒂科肯)", + "America\/Cordoba": "阿根廷時間 (哥多華)", + "America\/Costa_Rica": "中部時間 (哥斯大黎加)", + "America\/Creston": "山區時間 (克雷斯頓)", + "America\/Cuiaba": "亞馬遜時間 (古雅巴)", + "America\/Curacao": "大西洋時間 (庫拉索)", + "America\/Danmarkshavn": "格林威治標準時間 (丹馬沙文)", + "America\/Dawson": "太平洋時間 (道森)", + "America\/Dawson_Creek": "山區時間 (道森克里克)", + "America\/Denver": "山區時間 (丹佛)", + "America\/Detroit": "東部時間 (底特律)", + "America\/Dominica": "大西洋時間 (多米尼克)", + "America\/Edmonton": "山區時間 (艾德蒙吞)", + "America\/Eirunepe": "艾克時間 (艾魯內佩)", + "America\/El_Salvador": "中部時間 (薩爾瓦多)", + "America\/Fort_Nelson": "山區時間 (納爾遜堡)", + "America\/Fortaleza": "巴西利亞時間 (福塔力莎)", + "America\/Glace_Bay": "大西洋時間 (格雷斯貝)", + "America\/Godthab": "格陵蘭西部時間 (努克)", + "America\/Goose_Bay": "大西洋時間 (鵝灣)", + "America\/Grand_Turk": "東部時間 (大特克島)", + "America\/Grenada": "大西洋時間 (格瑞納達)", + "America\/Guadeloupe": "大西洋時間 (瓜地洛普)", + "America\/Guatemala": "中部時間 (瓜地馬拉)", + "America\/Guayaquil": "厄瓜多時間 (瓜亞基爾)", + "America\/Guyana": "蓋亞那時間 (蓋亞那)", + "America\/Halifax": "大西洋時間 (哈里法克斯)", + "America\/Havana": "古巴時間 (哈瓦那)", + "America\/Hermosillo": "墨西哥太平洋時間 (埃莫西約)", + "America\/Indiana\/Knox": "中部時間 (印第安那州諾克斯)", + "America\/Indiana\/Marengo": "東部時間 (印第安那州馬倫哥)", + "America\/Indiana\/Petersburg": "東部時間 (印第安那州彼得堡)", + "America\/Indiana\/Tell_City": "中部時間 (印第安那州泰爾城)", + "America\/Indiana\/Vevay": "東部時間 (印第安那州維威)", + "America\/Indiana\/Vincennes": "東部時間 (印第安那州溫森斯)", + "America\/Indiana\/Winamac": "東部時間 (印第安那州威納馬克)", + "America\/Indianapolis": "東部時間 (印第安那波里斯)", + "America\/Inuvik": "山區時間 (伊奴維克)", + "America\/Iqaluit": "東部時間 (伊魁特)", + "America\/Jamaica": "東部時間 (牙買加)", + "America\/Jujuy": "阿根廷時間 (胡胡伊)", + "America\/Juneau": "阿拉斯加時間 (朱諾)", + "America\/Kentucky\/Monticello": "東部時間 (肯塔基州蒙地卻羅)", + "America\/Kralendijk": "大西洋時間 (克拉倫代克)", + "America\/La_Paz": "玻利維亞時間 (拉巴斯)", + "America\/Lima": "秘魯時間 (利馬)", + "America\/Los_Angeles": "太平洋時間 (洛杉磯)", + "America\/Louisville": "東部時間 (路易斯維爾)", + "America\/Lower_Princes": "大西洋時間 (下太子區)", + "America\/Maceio": "巴西利亞時間 (馬瑟歐)", + "America\/Managua": "中部時間 (馬拿瓜)", + "America\/Manaus": "亞馬遜時間 (瑪瑙斯)", + "America\/Marigot": "大西洋時間 (馬里戈特)", + "America\/Martinique": "大西洋時間 (馬丁尼克)", + "America\/Matamoros": "中部時間 (馬塔莫羅斯)", + "America\/Mazatlan": "墨西哥太平洋時間 (馬薩特蘭)", + "America\/Mendoza": "阿根廷時間 (門多薩)", + "America\/Menominee": "中部時間 (美諾米尼)", + "America\/Merida": "中部時間 (梅里達)", + "America\/Metlakatla": "阿拉斯加時間 (梅特拉卡特拉)", + "America\/Mexico_City": "中部時間 (墨西哥市)", + "America\/Miquelon": "聖皮埃與密克隆群島時間 (密啟崙)", + "America\/Moncton": "大西洋時間 (蒙克頓)", + "America\/Monterrey": "中部時間 (蒙特瑞)", + "America\/Montevideo": "烏拉圭時間 (蒙特維多)", + "America\/Montserrat": "大西洋時間 (蒙哲臘)", + "America\/Nassau": "東部時間 (拿索)", + "America\/New_York": "東部時間 (紐約)", + "America\/Nipigon": "東部時間 (尼皮岡)", + "America\/Nome": "阿拉斯加時間 (諾姆)", + "America\/Noronha": "費爾南多 - 迪諾羅尼亞時間 (諾倫哈)", + "America\/North_Dakota\/Beulah": "中部時間 (北達科他州布由拉)", + "America\/North_Dakota\/Center": "中部時間 (北達科他州中心)", + "America\/North_Dakota\/New_Salem": "中部時間 (北達科他州紐沙倫)", + "America\/Ojinaga": "山區時間 (奧希納加)", + "America\/Panama": "東部時間 (巴拿馬)", + "America\/Pangnirtung": "東部時間 (潘尼爾東)", + "America\/Paramaribo": "蘇利南時間 (巴拉馬利波)", + "America\/Phoenix": "山區時間 (鳳凰城)", + "America\/Port-au-Prince": "東部時間 (太子港)", + "America\/Port_of_Spain": "大西洋時間 (西班牙港)", + "America\/Porto_Velho": "亞馬遜時間 (維留港)", + "America\/Puerto_Rico": "大西洋時間 (波多黎各)", + "America\/Punta_Arenas": "智利時間 (蓬塔阿雷納斯)", + "America\/Rainy_River": "中部時間 (雨河鎮)", + "America\/Rankin_Inlet": "中部時間 (蘭今灣)", + "America\/Recife": "巴西利亞時間 (雷西非)", + "America\/Regina": "中部時間 (里賈納)", + "America\/Resolute": "中部時間 (羅斯魯特)", + "America\/Rio_Branco": "艾克時間 (里約布蘭)", + "America\/Santa_Isabel": "墨西哥西北部時間 (聖伊薩貝爾)", + "America\/Santarem": "巴西利亞時間 (聖塔倫)", + "America\/Santiago": "智利時間 (聖地牙哥)", + "America\/Santo_Domingo": "大西洋時間 (聖多明哥)", + "America\/Sao_Paulo": "巴西利亞時間 (聖保羅)", + "America\/Scoresbysund": "格陵蘭東部時間 (伊托科爾托米特)", + "America\/Sitka": "阿拉斯加時間 (錫特卡)", + "America\/St_Barthelemy": "大西洋時間 (聖巴托洛繆島)", + "America\/St_Johns": "紐芬蘭時間 (聖約翰)", + "America\/St_Kitts": "大西洋時間 (聖基茨)", + "America\/St_Lucia": "大西洋時間 (聖露西亞)", + "America\/St_Thomas": "大西洋時間 (聖托馬斯)", + "America\/St_Vincent": "大西洋時間 (聖文森)", + "America\/Swift_Current": "中部時間 (斯威夫特卡倫特)", + "America\/Tegucigalpa": "中部時間 (德古斯加巴)", + "America\/Thule": "大西洋時間 (杜里)", + "America\/Thunder_Bay": "東部時間 (珊德灣)", + "America\/Tijuana": "太平洋時間 (提華納)", + "America\/Toronto": "東部時間 (多倫多)", + "America\/Tortola": "大西洋時間 (托爾托拉)", + "America\/Vancouver": "太平洋時間 (溫哥華)", + "America\/Whitehorse": "太平洋時間 (懷特霍斯)", + "America\/Winnipeg": "中部時間 (溫尼伯)", + "America\/Yakutat": "阿拉斯加時間 (雅庫塔)", + "America\/Yellowknife": "山區時間 (耶洛奈夫)", + "Antarctica\/Casey": "澳洲西部時間 (凱西)", + "Antarctica\/Davis": "戴維斯時間 (戴維斯)", + "Antarctica\/DumontDUrville": "杜蒙杜比爾時間 (杜蒙杜比爾)", + "Antarctica\/Macquarie": "麥覺理時間 (麥覺理)", + "Antarctica\/Mawson": "莫森時間 (莫森)", + "Antarctica\/McMurdo": "紐西蘭時間 (麥克默多)", + "Antarctica\/Palmer": "智利時間 (帕麥)", + "Antarctica\/Rothera": "羅瑟拉時間 (羅瑟拉)", + "Antarctica\/Syowa": "昭和基地時間 (昭和基地)", + "Antarctica\/Troll": "格林威治標準時間 (綽爾)", + "Antarctica\/Vostok": "沃斯托克時間 (沃斯托克)", + "Arctic\/Longyearbyen": "中歐時間 (隆意耳拜恩)", + "Asia\/Aden": "阿拉伯時間 (亞丁)", + "Asia\/Almaty": "東哈薩克時間 (阿拉木圖)", + "Asia\/Amman": "東歐時間 (安曼)", + "Asia\/Anadyr": "阿納德爾時間 (阿那底)", + "Asia\/Aqtau": "西哈薩克時間 (阿克套)", + "Asia\/Aqtobe": "西哈薩克時間 (阿克托比)", + "Asia\/Ashgabat": "土庫曼時間 (阿什哈巴特)", + "Asia\/Atyrau": "西哈薩克時間 (阿特勞)", + "Asia\/Baghdad": "阿拉伯時間 (巴格達)", + "Asia\/Bahrain": "阿拉伯時間 (巴林)", + "Asia\/Baku": "亞塞拜然時間 (巴庫)", + "Asia\/Bangkok": "印度支那時間 (曼谷)", + "Asia\/Beirut": "東歐時間 (貝魯特)", + "Asia\/Bishkek": "吉爾吉斯時間 (比什凱克)", + "Asia\/Brunei": "汶萊時間 (汶萊)", + "Asia\/Calcutta": "印度標準時間 (加爾各答)", + "Asia\/Chita": "雅庫次克時間 (赤塔)", + "Asia\/Choibalsan": "喬巴山時間 (喬巴山)", + "Asia\/Colombo": "印度標準時間 (可倫坡)", + "Asia\/Damascus": "東歐時間 (大馬士革)", + "Asia\/Dhaka": "孟加拉時間 (達卡)", + "Asia\/Dili": "東帝汶時間 (帝力)", + "Asia\/Dubai": "波斯灣海域標準時間 (杜拜)", + "Asia\/Dushanbe": "塔吉克時間 (杜桑貝)", + "Asia\/Famagusta": "東歐時間 (法馬古斯塔)", + "Asia\/Gaza": "東歐時間 (加薩)", + "Asia\/Hebron": "東歐時間 (赫布隆)", + "Asia\/Hong_Kong": "香港時間 (香港)", + "Asia\/Hovd": "科布多時間 (科布多)", + "Asia\/Irkutsk": "伊爾庫次克時間 (伊爾庫次克)", + "Asia\/Jakarta": "印尼西部時間 (雅加達)", + "Asia\/Jayapura": "印尼東部時間 (加亞布拉)", + "Asia\/Jerusalem": "以色列時間 (耶路撒冷)", + "Asia\/Kabul": "阿富汗時間 (喀布爾)", + "Asia\/Kamchatka": "彼得羅巴甫洛夫斯克時間 (堪察加)", + "Asia\/Karachi": "巴基斯坦時間 (喀拉蚩)", + "Asia\/Katmandu": "尼泊爾時間 (加德滿都)", + "Asia\/Khandyga": "雅庫次克時間 (堪地加)", + "Asia\/Krasnoyarsk": "克拉斯諾亞爾斯克時間 (克拉斯諾亞爾斯克)", + "Asia\/Kuala_Lumpur": "馬來西亞時間 (吉隆坡)", + "Asia\/Kuching": "馬來西亞時間 (古晉)", + "Asia\/Kuwait": "阿拉伯時間 (科威特)", + "Asia\/Macau": "中國時間 (澳門)", + "Asia\/Magadan": "馬加丹時間 (馬加丹)", + "Asia\/Makassar": "印尼中部時間 (馬卡沙爾)", + "Asia\/Manila": "菲律賓時間 (馬尼拉)", + "Asia\/Muscat": "波斯灣海域標準時間 (馬斯開特)", + "Asia\/Nicosia": "東歐時間 (尼古西亞)", + "Asia\/Novokuznetsk": "克拉斯諾亞爾斯克時間 (新庫茲涅茨克)", + "Asia\/Novosibirsk": "新西伯利亞時間 (新西伯利亞)", + "Asia\/Omsk": "鄂木斯克時間 (鄂木斯克)", + "Asia\/Oral": "西哈薩克時間 (烏拉爾)", + "Asia\/Phnom_Penh": "印度支那時間 (金邊)", + "Asia\/Pontianak": "印尼西部時間 (坤甸)", + "Asia\/Pyongyang": "韓國時間 (平壤)", + "Asia\/Qatar": "阿拉伯時間 (卡達)", + "Asia\/Qostanay": "東哈薩克時間 (庫斯塔奈)", + "Asia\/Qyzylorda": "西哈薩克時間 (克孜勒奧爾達)", + "Asia\/Rangoon": "緬甸時間 (仰光)", + "Asia\/Riyadh": "阿拉伯時間 (利雅德)", + "Asia\/Saigon": "印度支那時間 (胡志明市)", + "Asia\/Sakhalin": "庫頁島時間 (庫頁島)", + "Asia\/Samarkand": "烏茲別克時間 (撒馬爾罕)", + "Asia\/Seoul": "韓國時間 (首爾)", + "Asia\/Shanghai": "中國時間 (上海)", + "Asia\/Singapore": "新加坡標準時間 (新加坡)", + "Asia\/Srednekolymsk": "馬加丹時間 (中科雷姆斯克)", + "Asia\/Taipei": "台北時間 (台北)", + "Asia\/Tashkent": "烏茲別克時間 (塔什干)", + "Asia\/Tbilisi": "喬治亞時間 (第比利斯)", + "Asia\/Tehran": "伊朗時間 (德黑蘭)", + "Asia\/Thimphu": "不丹時間 (廷布)", + "Asia\/Tokyo": "日本時間 (東京)", + "Asia\/Ulaanbaatar": "烏蘭巴托時間 (烏蘭巴托)", + "Asia\/Ust-Nera": "海參崴時間 (烏斯內拉)", + "Asia\/Vientiane": "印度支那時間 (永珍)", + "Asia\/Vladivostok": "海參崴時間 (海參崴)", + "Asia\/Yakutsk": "雅庫次克時間 (雅庫次克)", + "Asia\/Yekaterinburg": "葉卡捷琳堡時間 (葉卡捷林堡)", + "Asia\/Yerevan": "亞美尼亞時間 (葉里溫)", + "Atlantic\/Azores": "亞速爾群島時間 (亞速爾群島)", + "Atlantic\/Bermuda": "大西洋時間 (百慕達)", + "Atlantic\/Canary": "西歐時間 (加納利)", + "Atlantic\/Cape_Verde": "維德角時間 (維德角)", + "Atlantic\/Faeroe": "西歐時間 (法羅群島)", + "Atlantic\/Madeira": "西歐時間 (馬得拉群島)", + "Atlantic\/Reykjavik": "格林威治標準時間 (雷克雅維克)", + "Atlantic\/South_Georgia": "南喬治亞時間 (南喬治亞)", + "Atlantic\/St_Helena": "格林威治標準時間 (聖赫勒拿島)", + "Atlantic\/Stanley": "福克蘭群島時間 (史坦利)", + "Australia\/Adelaide": "澳洲中部時間 (阿得雷德)", + "Australia\/Brisbane": "澳洲東部時間 (布利斯班)", + "Australia\/Broken_Hill": "澳洲中部時間 (布羅肯希爾)", + "Australia\/Currie": "澳洲東部時間 (克黎)", + "Australia\/Darwin": "澳洲中部時間 (達爾文)", + "Australia\/Eucla": "澳洲中西部時間 (尤克拉)", + "Australia\/Hobart": "澳洲東部時間 (荷巴特)", + "Australia\/Lindeman": "澳洲東部時間 (林德曼)", + "Australia\/Lord_Howe": "豪勳爵島時間 (豪勳爵島)", + "Australia\/Melbourne": "澳洲東部時間 (墨爾本)", + "Australia\/Perth": "澳洲西部時間 (伯斯)", + "Australia\/Sydney": "澳洲東部時間 (雪梨)", + "CST6CDT": "中部時間", + "EST5EDT": "東部時間", + "Etc\/GMT": "格林威治標準時間", + "Etc\/UTC": "世界標準時間", + "Europe\/Amsterdam": "中歐時間 (阿姆斯特丹)", + "Europe\/Andorra": "中歐時間 (安道爾)", + "Europe\/Astrakhan": "莫斯科時間 (阿斯特拉罕)", + "Europe\/Athens": "東歐時間 (雅典)", + "Europe\/Belgrade": "中歐時間 (貝爾格勒)", + "Europe\/Berlin": "中歐時間 (柏林)", + "Europe\/Bratislava": "中歐時間 (布拉提斯拉瓦)", + "Europe\/Brussels": "中歐時間 (布魯塞爾)", + "Europe\/Bucharest": "東歐時間 (布加勒斯特)", + "Europe\/Budapest": "中歐時間 (布達佩斯)", + "Europe\/Busingen": "中歐時間 (布辛根)", + "Europe\/Chisinau": "東歐時間 (基西紐)", + "Europe\/Copenhagen": "中歐時間 (哥本哈根)", + "Europe\/Dublin": "格林威治標準時間 (都柏林)", + "Europe\/Gibraltar": "中歐時間 (直布羅陀)", + "Europe\/Guernsey": "格林威治標準時間 (根息島)", + "Europe\/Helsinki": "東歐時間 (赫爾辛基)", + "Europe\/Isle_of_Man": "格林威治標準時間 (曼島)", + "Europe\/Jersey": "格林威治標準時間 (澤西島)", + "Europe\/Kaliningrad": "東歐時間 (加里寧格勒)", + "Europe\/Kiev": "東歐時間 (基輔)", + "Europe\/Lisbon": "西歐時間 (里斯本)", + "Europe\/Ljubljana": "中歐時間 (盧比安納)", + "Europe\/London": "格林威治標準時間 (倫敦)", + "Europe\/Luxembourg": "中歐時間 (盧森堡)", + "Europe\/Madrid": "中歐時間 (馬德里)", + "Europe\/Malta": "中歐時間 (馬爾他)", + "Europe\/Mariehamn": "東歐時間 (瑪麗港)", + "Europe\/Minsk": "莫斯科時間 (明斯克)", + "Europe\/Monaco": "中歐時間 (摩納哥)", + "Europe\/Moscow": "莫斯科時間 (莫斯科)", + "Europe\/Oslo": "中歐時間 (奧斯陸)", + "Europe\/Paris": "中歐時間 (巴黎)", + "Europe\/Podgorica": "中歐時間 (波多里察)", + "Europe\/Prague": "中歐時間 (布拉格)", + "Europe\/Riga": "東歐時間 (里加)", + "Europe\/Rome": "中歐時間 (羅馬)", + "Europe\/Samara": "薩馬拉時間 (沙馬拉)", + "Europe\/San_Marino": "中歐時間 (聖馬利諾)", + "Europe\/Sarajevo": "中歐時間 (塞拉耶佛)", + "Europe\/Saratov": "莫斯科時間 (薩拉托夫)", + "Europe\/Simferopol": "莫斯科時間 (辛非洛浦)", + "Europe\/Skopje": "中歐時間 (史高比耶)", + "Europe\/Sofia": "東歐時間 (索菲亞)", + "Europe\/Stockholm": "中歐時間 (斯德哥爾摩)", + "Europe\/Tallinn": "東歐時間 (塔林)", + "Europe\/Tirane": "中歐時間 (地拉那)", + "Europe\/Ulyanovsk": "莫斯科時間 (烏里揚諾夫斯克)", + "Europe\/Uzhgorod": "東歐時間 (烏茲哥洛)", + "Europe\/Vaduz": "中歐時間 (瓦都茲)", + "Europe\/Vatican": "中歐時間 (梵蒂岡)", + "Europe\/Vienna": "中歐時間 (維也納)", + "Europe\/Vilnius": "東歐時間 (維爾紐斯)", + "Europe\/Volgograd": "伏爾加格勒時間 (伏爾加格勒)", + "Europe\/Warsaw": "中歐時間 (華沙)", + "Europe\/Zagreb": "中歐時間 (札格瑞布)", + "Europe\/Zaporozhye": "東歐時間 (札波羅結)", + "Europe\/Zurich": "中歐時間 (蘇黎世)", + "Indian\/Antananarivo": "東非時間 (安塔那那利弗)", + "Indian\/Chagos": "印度洋時間 (查戈斯)", + "Indian\/Christmas": "聖誕島時間 (聖誕島)", + "Indian\/Cocos": "科科斯群島時間 (科科斯群島)", + "Indian\/Comoro": "東非時間 (科摩羅群島)", + "Indian\/Kerguelen": "法國南方及南極時間 (凱爾蓋朗島)", + "Indian\/Mahe": "塞席爾時間 (馬埃島)", + "Indian\/Maldives": "馬爾地夫時間 (馬爾地夫)", + "Indian\/Mauritius": "模里西斯時間 (模里西斯)", + "Indian\/Mayotte": "東非時間 (馬約特島)", + "Indian\/Reunion": "留尼旺時間 (留尼旺島)", + "MST7MDT": "山區時間", + "PST8PDT": "太平洋時間", + "Pacific\/Apia": "阿皮亞時間 (阿皮亞)", + "Pacific\/Auckland": "紐西蘭時間 (奧克蘭)", + "Pacific\/Bougainville": "巴布亞紐幾內亞時間 (布干維爾)", + "Pacific\/Chatham": "查坦群島時間 (查坦)", + "Pacific\/Easter": "復活節島時間 (復活島)", + "Pacific\/Efate": "萬那杜時間 (埃法特)", + "Pacific\/Enderbury": "鳳凰群島時間 (恩得伯理島)", + "Pacific\/Fakaofo": "托克勞群島時間 (法考福)", + "Pacific\/Fiji": "斐濟時間 (斐濟)", + "Pacific\/Funafuti": "吐瓦魯時間 (富那富提)", + "Pacific\/Galapagos": "加拉巴哥群島時間 (加拉巴哥群島)", + "Pacific\/Gambier": "甘比爾群島時間 (甘比爾群島)", + "Pacific\/Guadalcanal": "索羅門群島時間 (瓜達康納爾島)", + "Pacific\/Guam": "查莫洛時間 (關島)", + "Pacific\/Honolulu": "夏威夷-阿留申時間 (檀香山)", + "Pacific\/Johnston": "夏威夷-阿留申時間 (強斯頓)", + "Pacific\/Kiritimati": "萊恩群島時間 (基里地馬地島)", + "Pacific\/Kosrae": "科斯瑞時間 (科斯瑞)", + "Pacific\/Kwajalein": "馬紹爾群島時間 (瓜加林島)", + "Pacific\/Majuro": "馬紹爾群島時間 (馬朱諾)", + "Pacific\/Marquesas": "馬可薩斯時間 (馬可薩斯島)", + "Pacific\/Midway": "薩摩亞時間 (中途島)", + "Pacific\/Nauru": "諾魯時間 (諾魯)", + "Pacific\/Niue": "紐埃島時間 (紐埃島)", + "Pacific\/Norfolk": "諾福克島時間 (諾福克)", + "Pacific\/Noumea": "新喀里多尼亞時間 (諾美亞)", + "Pacific\/Pago_Pago": "薩摩亞時間 (巴哥巴哥)", + "Pacific\/Palau": "帛琉時間 (帛琉)", + "Pacific\/Pitcairn": "皮特肯時間 (皮特肯群島)", + "Pacific\/Ponape": "波納佩時間 (波納佩)", + "Pacific\/Port_Moresby": "巴布亞紐幾內亞時間 (莫士比港)", + "Pacific\/Rarotonga": "庫克群島時間 (拉羅湯加)", + "Pacific\/Saipan": "查莫洛時間 (塞班)", + "Pacific\/Tahiti": "大溪地時間 (大溪地)", + "Pacific\/Tarawa": "吉爾伯特群島時間 (塔拉瓦)", + "Pacific\/Tongatapu": "東加時間 (東加塔布島)", + "Pacific\/Truk": "楚克島時間 (楚克)", + "Pacific\/Wake": "威克島時間 (威克)", + "Pacific\/Wallis": "瓦利斯和富圖納群島時間 (瓦利斯)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant_HK.json b/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant_HK.json new file mode 100644 index 0000000000000..b5e8d5dd36181 --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zh_Hant_HK.json @@ -0,0 +1,116 @@ +{ + "Version": "2.1.47.86", + "Names": { + "Africa\/Johannesburg": "南非時間 (約翰內斯堡)", + "Africa\/Maseru": "南非時間 (馬塞魯)", + "Africa\/Mbabane": "南非時間 (Mbabane)", + "America\/Adak": "夏威夷-阿留申時間 (埃達克)", + "America\/Bahia_Banderas": "北美中部時間 (巴伊亞德班德拉斯)", + "America\/Belize": "北美中部時間 (伯利茲)", + "America\/Boise": "北美山區時間 (博伊西)", + "America\/Cambridge_Bay": "北美山區時間 (Cambridge Bay)", + "America\/Cancun": "北美東部時間 (Cancun)", + "America\/Cayman": "北美東部時間 (Cayman)", + "America\/Chicago": "北美中部時間 (Chicago)", + "America\/Coral_Harbour": "北美東部時間 (Atikokan)", + "America\/Costa_Rica": "北美中部時間 (哥斯達黎加)", + "America\/Creston": "北美山區時間 (Creston)", + "America\/Dawson": "北美太平洋時間 (Dawson)", + "America\/Dawson_Creek": "北美山區時間 (道森灣)", + "America\/Denver": "北美山區時間 (Denver)", + "America\/Detroit": "北美東部時間 (Detroit)", + "America\/Edmonton": "北美山區時間 (愛民頓)", + "America\/El_Salvador": "北美中部時間 (El Salvador)", + "America\/Fort_Nelson": "北美山區時間 (Fort Nelson)", + "America\/Grand_Turk": "北美東部時間 (Grand Turk)", + "America\/Guatemala": "北美中部時間 (危地馬拉)", + "America\/Guayaquil": "厄瓜多爾時間 (Guayaquil)", + "America\/Guyana": "圭亞那時間 (圭亞那)", + "America\/Indiana\/Knox": "北美中部時間 (印第安納州諾克斯)", + "America\/Indiana\/Marengo": "北美東部時間 (印第安納州馬倫哥)", + "America\/Indiana\/Petersburg": "北美東部時間 (印第安納州彼得堡)", + "America\/Indiana\/Tell_City": "北美中部時間 (印第安納州特爾城)", + "America\/Indiana\/Vevay": "北美東部時間 (印第安納州韋韋)", + "America\/Indiana\/Vincennes": "北美東部時間 (印第安納州溫森斯)", + "America\/Indiana\/Winamac": "北美東部時間 (印第安納州威納馬克)", + "America\/Indianapolis": "北美東部時間 (印第安納波利斯)", + "America\/Inuvik": "北美山區時間 (伊努維克)", + "America\/Iqaluit": "北美東部時間 (Iqaluit)", + "America\/Jamaica": "北美東部時間 (Jamaica)", + "America\/Kentucky\/Monticello": "北美東部時間 (Monticello, Kentucky)", + "America\/Los_Angeles": "北美太平洋時間 (Los Angeles)", + "America\/Louisville": "北美東部時間 (路易維爾)", + "America\/Managua": "北美中部時間 (馬那瓜)", + "America\/Matamoros": "北美中部時間 (Matamoros)", + "America\/Menominee": "北美中部時間 (梅諾米尼)", + "America\/Merida": "北美中部時間 (Merida)", + "America\/Mexico_City": "北美中部時間 (墨西哥城)", + "America\/Monterrey": "北美中部時間 (蒙特雷)", + "America\/Nassau": "北美東部時間 (拿騷)", + "America\/New_York": "北美東部時間 (New York)", + "America\/Nipigon": "北美東部時間 (尼皮貢)", + "America\/Noronha": "費爾南多迪諾羅尼亞時間 (諾羅尼亞)", + "America\/North_Dakota\/Beulah": "北美中部時間 (北達科他州比尤拉)", + "America\/North_Dakota\/Center": "北美中部時間 (北達科他州中心市)", + "America\/North_Dakota\/New_Salem": "北美中部時間 (北達科他州新薩勒姆)", + "America\/Ojinaga": "北美山區時間 (Ojinaga)", + "America\/Panama": "北美東部時間 (Panama)", + "America\/Pangnirtung": "北美東部時間 (Pangnirtung)", + "America\/Paramaribo": "蘇里南時間 (Paramaribo)", + "America\/Phoenix": "北美山區時間 (Phoenix)", + "America\/Port-au-Prince": "北美東部時間 (Port-au-Prince)", + "America\/Rainy_River": "北美中部時間 (Rainy River)", + "America\/Rankin_Inlet": "北美中部時間 (Rankin Inlet)", + "America\/Regina": "北美中部時間 (Regina)", + "America\/Resolute": "北美中部時間 (Resolute)", + "America\/Swift_Current": "北美中部時間 (Swift Current)", + "America\/Tegucigalpa": "北美中部時間 (特古西加爾巴)", + "America\/Thunder_Bay": "北美東部時間 (雷灣)", + "America\/Tijuana": "北美太平洋時間 (蒂華納)", + "America\/Toronto": "北美東部時間 (Toronto)", + "America\/Vancouver": "北美太平洋時間 (Vancouver)", + "America\/Whitehorse": "北美太平洋時間 (白馬市)", + "America\/Winnipeg": "北美中部時間 (Winnipeg)", + "America\/Yellowknife": "北美山區時間 (黃刀鎮)", + "Antarctica\/DumontDUrville": "迪蒙迪維爾時間 (杜蒙迪維爾站)", + "Antarctica\/Macquarie": "麥夸里群島時間 (麥夸里)", + "Asia\/Baku": "亞塞拜疆時間 (Baku)", + "Asia\/Bangkok": "中南半島時間 (Bangkok)", + "Asia\/Calcutta": "印度時間 (Kolkata)", + "Asia\/Chita": "雅庫茨克時間 (Chita)", + "Asia\/Colombo": "印度時間 (科倫坡)", + "Asia\/Dubai": "波斯灣海域時間 (Dubai)", + "Asia\/Irkutsk": "伊爾庫茨克時間 (伊爾庫茨克)", + "Asia\/Khandyga": "雅庫茨克時間 (Khandyga)", + "Asia\/Muscat": "波斯灣海域時間 (馬斯喀特)", + "Asia\/Phnom_Penh": "中南半島時間 (Phnom Penh)", + "Asia\/Saigon": "中南半島時間 (Ho Chi Minh)", + "Asia\/Singapore": "新加坡時間 (Singapore)", + "Asia\/Tbilisi": "格魯吉亞時間 (Tbilisi)", + "Asia\/Vientiane": "中南半島時間 (Vientiane)", + "Asia\/Yakutsk": "雅庫茨克時間 (雅庫茨克)", + "Atlantic\/Cape_Verde": "佛得角時間 (佛得角)", + "CST6CDT": "北美中部時間", + "EST5EDT": "北美東部時間", + "Indian\/Cocos": "可可斯群島時間 (可可斯群島)", + "Indian\/Mahe": "塞舌爾時間 (Mahe)", + "Indian\/Maldives": "馬爾代夫時間 (馬爾代夫)", + "Indian\/Mauritius": "毛里裘斯時間 (毛里裘斯)", + "MST7MDT": "北美山區時間", + "PST8PDT": "北美太平洋時間", + "Pacific\/Bougainville": "巴布亞新畿內亞時間 (布干維爾島)", + "Pacific\/Efate": "瓦努阿圖時間 (Efate)", + "Pacific\/Funafuti": "圖瓦盧時間 (Funafuti)", + "Pacific\/Galapagos": "加拉帕戈群島時間 (Galapagos)", + "Pacific\/Guadalcanal": "所羅門群島時間 (瓜達爾卡納爾島)", + "Pacific\/Honolulu": "夏威夷-阿留申時間 (Honolulu)", + "Pacific\/Johnston": "夏威夷-阿留申時間 (約翰斯頓環礁)", + "Pacific\/Kosrae": "科斯雷時間 (科斯雷)", + "Pacific\/Marquesas": "馬克薩斯時間 (馬克薩斯群島)", + "Pacific\/Nauru": "瑙魯時間 (瑙魯)", + "Pacific\/Noumea": "新喀里多尼亞時間 (努美阿)", + "Pacific\/Pitcairn": "皮特康時間 (皮特康群島)", + "Pacific\/Port_Moresby": "巴布亞新畿內亞時間 (Port Moresby)", + "Pacific\/Tongatapu": "湯加時間 (湯加塔布島)" + } +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zh_SG.json b/src/Symfony/Component/Intl/Resources/data/timezones/zh_SG.json new file mode 100644 index 0000000000000..83feb5ee4545e --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zh_SG.json @@ -0,0 +1,4 @@ +{ + "Version": "2.1.47.71", + "Names": [] +} diff --git a/src/Symfony/Component/Intl/Resources/data/timezones/zu.json b/src/Symfony/Component/Intl/Resources/data/timezones/zu.json new file mode 100644 index 0000000000000..5ec27a4ca91ff --- /dev/null +++ b/src/Symfony/Component/Intl/Resources/data/timezones/zu.json @@ -0,0 +1,431 @@ +{ + "Version": "2.1.48.17", + "Names": { + "Africa\/Abidjan": "Isikhathi sase-Greenwich Mean (i-Abidjan)", + "Africa\/Accra": "Isikhathi sase-Greenwich Mean (i-Accra)", + "Africa\/Addis_Ababa": "Isikhathi saseMpumalanga Afrika (i-Addis Ababa)", + "Africa\/Algiers": "Isikhathi sase-Central Europe (i-Algiers)", + "Africa\/Asmera": "Isikhathi saseMpumalanga Afrika (i-Asmara)", + "Africa\/Bamako": "Isikhathi sase-Greenwich Mean (i-Bamako)", + "Africa\/Bangui": "Isikhathi saseNtshonalanga Afrika (i-Bangui)", + "Africa\/Banjul": "Isikhathi sase-Greenwich Mean (i-Banjul)", + "Africa\/Bissau": "Isikhathi sase-Greenwich Mean (i-Bissau)", + "Africa\/Blantyre": "Isikhathi sase-Central Africa (i-Blantyre)", + "Africa\/Brazzaville": "Isikhathi saseNtshonalanga Afrika (i-Brazzaville)", + "Africa\/Bujumbura": "Isikhathi sase-Central Africa (i-Bujumbura)", + "Africa\/Cairo": "Isikhathi sase-Eastern Europe (i-Cairo)", + "Africa\/Casablanca": "Isikhathi sase-Western Europe (i-Casablanca)", + "Africa\/Ceuta": "Isikhathi sase-Central Europe (i-Ceuta)", + "Africa\/Conakry": "Isikhathi sase-Greenwich Mean (i-Conakry)", + "Africa\/Dakar": "Isikhathi sase-Greenwich Mean (i-Dakar)", + "Africa\/Dar_es_Salaam": "Isikhathi saseMpumalanga Afrika (i-Dar es Salaam)", + "Africa\/Djibouti": "Isikhathi saseMpumalanga Afrika (i-Djibouti)", + "Africa\/Douala": "Isikhathi saseNtshonalanga Afrika (i-Douala)", + "Africa\/El_Aaiun": "Isikhathi sase-Western Europe (i-El Aaiun)", + "Africa\/Freetown": "Isikhathi sase-Greenwich Mean (i-Freetown)", + "Africa\/Gaborone": "Isikhathi sase-Central Africa (i-Gaborone)", + "Africa\/Harare": "Isikhathi sase-Central Africa (i-Harare)", + "Africa\/Johannesburg": "Isikhathi esijwayelekile saseNingizimu Afrika (i-Johannesburg)", + "Africa\/Juba": "Isikhathi saseMpumalanga Afrika (iJuba)", + "Africa\/Kampala": "Isikhathi saseMpumalanga Afrika (i-Kampala)", + "Africa\/Khartoum": "Isikhathi sase-Central Africa (i-Khartoum)", + "Africa\/Kigali": "Isikhathi sase-Central Africa (i-Kigali)", + "Africa\/Kinshasa": "Isikhathi saseNtshonalanga Afrika (i-Kinshasa)", + "Africa\/Lagos": "Isikhathi saseNtshonalanga Afrika (i-Lagos)", + "Africa\/Libreville": "Isikhathi saseNtshonalanga Afrika (i-Libreville)", + "Africa\/Lome": "Isikhathi sase-Greenwich Mean (i-Lome)", + "Africa\/Luanda": "Isikhathi saseNtshonalanga Afrika (i-Luanda)", + "Africa\/Lubumbashi": "Isikhathi sase-Central Africa (i-Lubumbashi)", + "Africa\/Lusaka": "Isikhathi sase-Central Africa (iLusaka)", + "Africa\/Malabo": "Isikhathi saseNtshonalanga Afrika (iMalabo)", + "Africa\/Maputo": "Isikhathi sase-Central Africa (iMaputo)", + "Africa\/Maseru": "Isikhathi esijwayelekile saseNingizimu Afrika (iMaseru)", + "Africa\/Mbabane": "Isikhathi esijwayelekile saseNingizimu Afrika (iMbabane)", + "Africa\/Mogadishu": "Isikhathi saseMpumalanga Afrika (i-Mogadishu)", + "Africa\/Monrovia": "Isikhathi sase-Greenwich Mean (i-Monrovia)", + "Africa\/Nairobi": "Isikhathi saseMpumalanga Afrika (i-Nairobi)", + "Africa\/Ndjamena": "Isikhathi saseNtshonalanga Afrika (i-Ndjamena)", + "Africa\/Niamey": "Isikhathi saseNtshonalanga Afrika (i-Niamey)", + "Africa\/Nouakchott": "Isikhathi sase-Greenwich Mean (i-Nouakchott)", + "Africa\/Ouagadougou": "Isikhathi sase-Greenwich Mean (i-Ouagadougou)", + "Africa\/Porto-Novo": "Isikhathi saseNtshonalanga Afrika (i-Porto-Novo)", + "Africa\/Sao_Tome": "Isikhathi sase-Greenwich Mean (i-São Tomé)", + "Africa\/Tripoli": "Isikhathi sase-Eastern Europe (i-Tripoli)", + "Africa\/Tunis": "Isikhathi sase-Central Europe (i-Tunis)", + "Africa\/Windhoek": "Isikhathi sase-Central Africa (i-Windhoek)", + "America\/Adak": "Isikhathi sase-Hawaii-Aleutia (i-Adak)", + "America\/Anchorage": "Isikhathi sase-Alaska (i-Anchorage)", + "America\/Anguilla": "Isikhathi sase-Atlantic (i-Anguilla)", + "America\/Antigua": "Isikhathi sase-Atlantic (i-Antigua)", + "America\/Araguaina": "Isikhathi sase-Brasilia (i-Araguaina)", + "America\/Argentina\/La_Rioja": "Isikhathi sase-Argentina (i-La Rioja)", + "America\/Argentina\/Rio_Gallegos": "Isikhathi sase-Argentina (i-Rio Gallegos)", + "America\/Argentina\/Salta": "Isikhathi sase-Argentina (i-Salta)", + "America\/Argentina\/San_Juan": "Isikhathi sase-Argentina (i-San Juan)", + "America\/Argentina\/San_Luis": "Isikhathi saseNyakatho ne-Argentina (i-San Luis)", + "America\/Argentina\/Tucuman": "Isikhathi sase-Argentina (i-Tucuman)", + "America\/Argentina\/Ushuaia": "Isikhathi sase-Argentina (i-Ushuaia)", + "America\/Aruba": "Isikhathi sase-Atlantic (i-Aruba)", + "America\/Asuncion": "Isikhathi sase-Paraguay (i-Asunción)", + "America\/Bahia": "Isikhathi sase-Brasilia (i-Bahia)", + "America\/Bahia_Banderas": "Isikhathi sase-North American Central (i-Bahia Banderas)", + "America\/Barbados": "Isikhathi sase-Atlantic (i-Barbados)", + "America\/Belem": "Isikhathi sase-Brasilia (i-Belem)", + "America\/Belize": "Isikhathi sase-North American Central (i-Belize)", + "America\/Blanc-Sablon": "Isikhathi sase-Atlantic (i-Blanc-Sablon)", + "America\/Boa_Vista": "Isikhathi sase-Amazon (i-Boa Vista)", + "America\/Bogota": "Isikhathi sase-Colombia (i-Bogota)", + "America\/Boise": "Isikhathi sase-North American Mountain (i-Boise)", + "America\/Buenos_Aires": "Isikhathi sase-Argentina (i-Buenos Aires)", + "America\/Cambridge_Bay": "Isikhathi sase-North American Mountain (i-Cambridge Bay)", + "America\/Campo_Grande": "Isikhathi sase-Amazon (i-Campo Grande)", + "America\/Cancun": "Isikhathi sase-North American East (i-Cancun)", + "America\/Caracas": "Isikhathi sase-Venezuela (i-Caracas)", + "America\/Catamarca": "Isikhathi sase-Argentina (i-Catamarca)", + "America\/Cayenne": "Isikhathi sase-French Guiana (i-Cayenne)", + "America\/Cayman": "Isikhathi sase-North American East (i-Cayman)", + "America\/Chicago": "Isikhathi sase-North American Central (i-Chicago)", + "America\/Chihuahua": "Isikhathi sase-Mexican Pacific (i-Chihuahua)", + "America\/Coral_Harbour": "Isikhathi sase-North American East (i-Atikokan)", + "America\/Cordoba": "Isikhathi sase-Argentina (i-Cordoba)", + "America\/Costa_Rica": "Isikhathi sase-North American Central (i-Costa Rica)", + "America\/Creston": "Isikhathi sase-North American Mountain (i-Creston)", + "America\/Cuiaba": "Isikhathi sase-Amazon (i-Cuiaba)", + "America\/Curacao": "Isikhathi sase-Atlantic (i-Curaçao)", + "America\/Danmarkshavn": "Isikhathi sase-Greenwich Mean (i-Danmarkshavn)", + "America\/Dawson": "Isikhathi sase-North American Pacific (i-Dawson)", + "America\/Dawson_Creek": "Isikhathi sase-North American Mountain (i-Dawson Creek)", + "America\/Denver": "Isikhathi sase-North American Mountain (i-Denver)", + "America\/Detroit": "Isikhathi sase-North American East (i-Detroit)", + "America\/Dominica": "Isikhathi sase-Atlantic (i-Dominica)", + "America\/Edmonton": "Isikhathi sase-North American Mountain (i-Edmonton)", + "America\/El_Salvador": "Isikhathi sase-North American Central (i-El Salvador)", + "America\/Fort_Nelson": "Isikhathi sase-North American Mountain (i-Fort Nelson)", + "America\/Fortaleza": "Isikhathi sase-Brasilia (i-Fortaleza)", + "America\/Glace_Bay": "Isikhathi sase-Atlantic (i-Glace Bay)", + "America\/Godthab": "Isikhathi sase-West Greenland (i-Nuuk)", + "America\/Goose_Bay": "Isikhathi sase-Atlantic (i-Goose Bay)", + "America\/Grand_Turk": "Isikhathi sase-North American East (i-Grand Turk)", + "America\/Grenada": "Isikhathi sase-Atlantic (i-Grenada)", + "America\/Guadeloupe": "Isikhathi sase-Atlantic (i-Guadeloupe)", + "America\/Guatemala": "Isikhathi sase-North American Central (i-Guatemala)", + "America\/Guayaquil": "Isikhathi sase-Ecuador (i-Guayaquil)", + "America\/Guyana": "Isikhathi sase-Guyana (i-Guyana)", + "America\/Halifax": "Isikhathi sase-Atlantic (i-Halifax)", + "America\/Havana": "Isikhathi sase-Cuba (i-Havana)", + "America\/Hermosillo": "Isikhathi sase-Mexican Pacific (i-Hermosillo)", + "America\/Indiana\/Knox": "Isikhathi sase-North American Central (i-Knox, Indiana)", + "America\/Indiana\/Marengo": "Isikhathi sase-North American East (i-Marengo, Indiana)", + "America\/Indiana\/Petersburg": "Isikhathi sase-North American East (i-Petersburg, Indiana)", + "America\/Indiana\/Tell_City": "Isikhathi sase-North American Central (i-Tell City, Indiana)", + "America\/Indiana\/Vevay": "Isikhathi sase-North American East (i-Vevay, Indiana)", + "America\/Indiana\/Vincennes": "Isikhathi sase-North American East (i-Vincennes, Indiana)", + "America\/Indiana\/Winamac": "Isikhathi sase-North American East (i-Winamac, Indiana)", + "America\/Indianapolis": "Isikhathi sase-North American East (i-Indianapolis)", + "America\/Inuvik": "Isikhathi sase-North American Mountain (i-Inuvik)", + "America\/Iqaluit": "Isikhathi sase-North American East (i-Iqaluit)", + "America\/Jamaica": "Isikhathi sase-North American East (i-Jamaica)", + "America\/Jujuy": "Isikhathi sase-Argentina (i-Jujuy)", + "America\/Juneau": "Isikhathi sase-Alaska (i-Juneau)", + "America\/Kentucky\/Monticello": "Isikhathi sase-North American East (i-Monticello, Kentucky)", + "America\/Kralendijk": "Isikhathi sase-Atlantic (i-Kralendijk)", + "America\/La_Paz": "Isikhathi sase-Bolivia (i-La Paz)", + "America\/Lima": "Isikhathi sase-Peru (i-Lima)", + "America\/Los_Angeles": "Isikhathi sase-North American Pacific (i-Los Angeles)", + "America\/Louisville": "Isikhathi sase-North American East (i-Louisville)", + "America\/Lower_Princes": "Isikhathi sase-Atlantic (i-Lower Prince’s Quarter)", + "America\/Maceio": "Isikhathi sase-Brasilia (i-Maceio)", + "America\/Managua": "Isikhathi sase-North American Central (i-Managua)", + "America\/Manaus": "Isikhathi sase-Amazon (i-Manaus)", + "America\/Marigot": "Isikhathi sase-Atlantic (i-Marigot)", + "America\/Martinique": "Isikhathi sase-Atlantic (i-Martinique)", + "America\/Matamoros": "Isikhathi sase-North American Central (i-Matamoros)", + "America\/Mazatlan": "Isikhathi sase-Mexican Pacific (i-Mazatlan)", + "America\/Mendoza": "Isikhathi sase-Argentina (i-Mendoza)", + "America\/Menominee": "Isikhathi sase-North American Central (i-Menominee)", + "America\/Merida": "Isikhathi sase-North American Central (i-Merida)", + "America\/Metlakatla": "Isikhathi sase-Alaska (i-Metlakatla)", + "America\/Mexico_City": "Isikhathi sase-North American Central (i-Mexico City)", + "America\/Miquelon": "Isikhathi sase-Saint Pierre nase-Miquelon (i-Miquelon)", + "America\/Moncton": "Isikhathi sase-Atlantic (i-Moncton)", + "America\/Monterrey": "Isikhathi sase-North American Central (i-Monterrey)", + "America\/Montevideo": "Isikhathi sase-Uruguay (i-Montevideo)", + "America\/Montserrat": "Isikhathi sase-Atlantic (i-Montserrat)", + "America\/Nassau": "Isikhathi sase-North American East (i-Nassau)", + "America\/New_York": "Isikhathi sase-North American East (i-New York)", + "America\/Nipigon": "Isikhathi sase-North American East (i-Nipigon)", + "America\/Nome": "Isikhathi sase-Alaska (i-Nome)", + "America\/Noronha": "Isikhathi sase-Fernando de Noronha (i-Noronha)", + "America\/North_Dakota\/Beulah": "Isikhathi sase-North American Central (i-Beulah, North Dakota)", + "America\/North_Dakota\/Center": "Isikhathi sase-North American Central (i-Center, North Dakota)", + "America\/North_Dakota\/New_Salem": "Isikhathi sase-North American Central (i-New Salem, North Dakota)", + "America\/Ojinaga": "Isikhathi sase-North American Mountain (i-Ojinaga)", + "America\/Panama": "Isikhathi sase-North American East (i-Panama)", + "America\/Pangnirtung": "Isikhathi sase-North American East (i-Pangnirtung)", + "America\/Paramaribo": "Isikhathi sase-Suriname (i-Paramaribo)", + "America\/Phoenix": "Isikhathi sase-North American Mountain (i-Phoenix)", + "America\/Port-au-Prince": "Isikhathi sase-North American East (i-Port-au-Prince)", + "America\/Port_of_Spain": "Isikhathi sase-Atlantic (i-Port of Spain)", + "America\/Porto_Velho": "Isikhathi sase-Amazon (i-Porto Velho)", + "America\/Puerto_Rico": "Isikhathi sase-Atlantic (i-Puerto Rico)", + "America\/Punta_Arenas": "Isikhathi sase-Chile (i-Punta Arenas)", + "America\/Rainy_River": "Isikhathi sase-North American Central (i-Rainy River)", + "America\/Rankin_Inlet": "Isikhathi sase-North American Central (i-Rankin Inlet)", + "America\/Recife": "Isikhathi sase-Brasilia (i-Recife)", + "America\/Regina": "Isikhathi sase-North American Central (i-Regina)", + "America\/Resolute": "Isikhathi sase-North American Central (i-Resolute)", + "America\/Santa_Isabel": "Isikhathi sase-Northwest Mexico (i-Santa Isabel)", + "America\/Santarem": "Isikhathi sase-Brasilia (i-Santarem)", + "America\/Santiago": "Isikhathi sase-Chile (i-Santiago)", + "America\/Santo_Domingo": "Isikhathi sase-Atlantic (i-Santo Domingo)", + "America\/Sao_Paulo": "Isikhathi sase-Brasilia (i-Sao Paulo)", + "America\/Scoresbysund": "Isikhathi sase-East Greenland (i-Ittoqqortoormiit)", + "America\/Sitka": "Isikhathi sase-Alaska (i-Sitka)", + "America\/St_Barthelemy": "Isikhathi sase-Atlantic (i-St. Barthélemy)", + "America\/St_Johns": "Isikhathi sase-Newfoundland (i-St. John’s)", + "America\/St_Kitts": "Isikhathi sase-Atlantic (i-St. Kitts)", + "America\/St_Lucia": "Isikhathi sase-Atlantic (i-)", + "America\/St_Thomas": "Isikhathi sase-Atlantic (i-St. Thomas)", + "America\/St_Vincent": "Isikhathi sase-Atlantic (i-St. Vincent)", + "America\/Swift_Current": "Isikhathi sase-North American Central (i-Swift Current)", + "America\/Tegucigalpa": "Isikhathi sase-North American Central (i-Tegucigalpa)", + "America\/Thule": "Isikhathi sase-Atlantic (i-Thule)", + "America\/Thunder_Bay": "Isikhathi sase-North American East (i-Thunder Bay)", + "America\/Tijuana": "Isikhathi sase-North American Pacific (i-Tijuana)", + "America\/Toronto": "Isikhathi sase-North American East (i-Toronto)", + "America\/Tortola": "Isikhathi sase-Atlantic (i-Tortola)", + "America\/Vancouver": "Isikhathi sase-North American Pacific (i-Vancouver)", + "America\/Whitehorse": "Isikhathi sase-North American Pacific (i-Whitehorse)", + "America\/Winnipeg": "Isikhathi sase-North American Central (i-Winnipeg)", + "America\/Yakutat": "Isikhathi sase-Alaska (i-Yakutat)", + "America\/Yellowknife": "Isikhathi sase-North American Mountain (i-Yellowknife)", + "Antarctica\/Casey": "Isikhathi sase-Western Australia (i-Casey)", + "Antarctica\/Davis": "Isikhathi sase-Davis (i-Davis)", + "Antarctica\/DumontDUrville": "Isikhathi sase-Dumont-d’Urville (i-Dumont d’Urville)", + "Antarctica\/Macquarie": "Isikhathi sase-Macquarie Island (i-Macquarie)", + "Antarctica\/Mawson": "Isikhathi sase-Mawson (i-Mawson)", + "Antarctica\/McMurdo": "Isikhathi sase-New Zealand (i-McMurdo)", + "Antarctica\/Palmer": "Isikhathi sase-Chile (i-Palmer)", + "Antarctica\/Rothera": "Isikhathi sase-Rothera (i-Rothera)", + "Antarctica\/Syowa": "Isikhathi sase-Syowa (i-Syowa)", + "Antarctica\/Troll": "Isikhathi sase-Greenwich Mean (i-Troll)", + "Antarctica\/Vostok": "Isikhathi sase-Vostok (i-Vostok)", + "Arctic\/Longyearbyen": "Isikhathi sase-Central Europe (i-Longyearbyen)", + "Asia\/Aden": "Isikhathi sase-Arabian (i-Aden)", + "Asia\/Almaty": "Isikhathi sase-Mpumalanga ne-Kazakhstan (i-Almaty)", + "Asia\/Amman": "Isikhathi sase-Eastern Europe (i-Amman)", + "Asia\/Anadyr": "esase-Anadyr Time (i-Anadyr)", + "Asia\/Aqtau": "Isikhathi saseNtshonalanga ne-Kazakhstan (i-Aqtau)", + "Asia\/Aqtobe": "Isikhathi saseNtshonalanga ne-Kazakhstan (i-Aqtobe)", + "Asia\/Ashgabat": "Isikhathi sase-Turkmenistan (i-Ashgabat)", + "Asia\/Atyrau": "Isikhathi saseNtshonalanga ne-Kazakhstan (Atyrau)", + "Asia\/Baghdad": "Isikhathi sase-Arabian (i-Baghdad)", + "Asia\/Bahrain": "Isikhathi sase-Arabian (i-Bahrain)", + "Asia\/Baku": "Isikhathi sase-Azerbaijan (i-Baku)", + "Asia\/Bangkok": "Isikhathi sase-Indochina (i-Bangkok)", + "Asia\/Beirut": "Isikhathi sase-Eastern Europe (i-Beirut)", + "Asia\/Bishkek": "Isikhathi sase-Kyrgystan (i-Bishkek)", + "Asia\/Brunei": "Isikhathi sase-Brunei Darussalam (i-Brunei)", + "Asia\/Calcutta": "Isikhathi sase-India esivamile (i-Kolkata)", + "Asia\/Chita": "Isikhathi sase-Yakutsk (i-Chita)", + "Asia\/Choibalsan": "Isikhathi sase-Choibalsan (i-Choibalsan)", + "Asia\/Colombo": "Isikhathi sase-India esivamile (i-Colombo)", + "Asia\/Damascus": "Isikhathi sase-Eastern Europe (i-Damascus)", + "Asia\/Dhaka": "Isikhathi sase-Bangladesh (i-Dhaka)", + "Asia\/Dili": "Isikhathi sase-East Timor (i-Dili)", + "Asia\/Dubai": "Isikhathi esivamile sase-Gulf (i-Dubai)", + "Asia\/Dushanbe": "Isikhathi sase-Tajikistan (i-Dushanbe)", + "Asia\/Famagusta": "Isikhathi sase-Eastern Europe (Famagusta)", + "Asia\/Gaza": "Isikhathi sase-Eastern Europe (iGaza)", + "Asia\/Hebron": "Isikhathi sase-Eastern Europe (i-Hebron)", + "Asia\/Hong_Kong": "Isikhathi sase-Hong Kong (i-Hong Kong)", + "Asia\/Hovd": "Isikhathi sase-Hovd (i-Hovd)", + "Asia\/Irkutsk": "Isikhathi sase-Irkutsk (i-Irkutsk)", + "Asia\/Jakarta": "Isikhathi sase-Western Indonesia (i-Jakarta)", + "Asia\/Jayapura": "Isikhathi sase-Eastern Indonesia (i-Jayapura)", + "Asia\/Jerusalem": "Isikhathi sase-Israel (i-Jerusalem)", + "Asia\/Kabul": "Isikhathi sase-Afghanistan (i-Kabul)", + "Asia\/Kamchatka": "esase-Petropavlovsk-Kamchatski Time (i-Kamchatka)", + "Asia\/Karachi": "Isikhathi sase-Pakistan (i-Karachi)", + "Asia\/Katmandu": "Isikhathi sase-Nepal (i-Kathmandu)", + "Asia\/Khandyga": "Isikhathi sase-Yakutsk (i-Khandyga)", + "Asia\/Krasnoyarsk": "Isikhathi sase-Krasnoyarsk (i-Krasnoyarsk)", + "Asia\/Kuala_Lumpur": "Isikhathi sase-Malaysia (i-Kuala Lumpur)", + "Asia\/Kuching": "Isikhathi sase-Malaysia (i-Kuching)", + "Asia\/Kuwait": "Isikhathi sase-Arabian (i-Kuwait)", + "Asia\/Macau": "Isikhathi sase-China (i-Macau)", + "Asia\/Magadan": "Isikhathi sase-Magadan (i-Magadan)", + "Asia\/Makassar": "Isikhathi sase-Central Indonesia (i-Makassar)", + "Asia\/Manila": "Isikhathi sase-Philippine (i-Manila)", + "Asia\/Muscat": "Isikhathi esivamile sase-Gulf (i-Muscat)", + "Asia\/Nicosia": "Isikhathi sase-Eastern Europe (i-Nicosia)", + "Asia\/Novokuznetsk": "Isikhathi sase-Krasnoyarsk (i-Novokuznetsk)", + "Asia\/Novosibirsk": "Isikhathi sase-Novosibirsk (i-Novosibirsk)", + "Asia\/Omsk": "Isikhathi sase-Omsk (i-Omsk)", + "Asia\/Oral": "Isikhathi saseNtshonalanga ne-Kazakhstan (i-Oral)", + "Asia\/Phnom_Penh": "Isikhathi sase-Indochina (i-Phnom Penh)", + "Asia\/Pontianak": "Isikhathi sase-Western Indonesia (i-Pontianak)", + "Asia\/Pyongyang": "Isikhathi sase-Korea (i-Pyongyang)", + "Asia\/Qatar": "Isikhathi sase-Arabian (i-Qatar)", + "Asia\/Qostanay": "Isikhathi sase-Mpumalanga ne-Kazakhstan (Qostanay)", + "Asia\/Qyzylorda": "Isikhathi saseNtshonalanga ne-Kazakhstan (i-Qyzylorda)", + "Asia\/Rangoon": "Isikhathi sase-Myanmar (i-Rangoon)", + "Asia\/Riyadh": "Isikhathi sase-Arabian (i-Riyadh)", + "Asia\/Saigon": "Isikhathi sase-Indochina (i-Ho Chi Minh City)", + "Asia\/Sakhalin": "Isikhathi sase-Sakhalin (i-Sakhalin)", + "Asia\/Samarkand": "Isikhathi sase-Uzbekistan (i-Samarkand)", + "Asia\/Seoul": "Isikhathi sase-Korea (i-Seoul)", + "Asia\/Shanghai": "Isikhathi sase-China (i-Shanghai)", + "Asia\/Singapore": "Isikhathi esivamile sase-Singapore (i-Singapore)", + "Asia\/Srednekolymsk": "Isikhathi sase-Magadan (i-Srednekolymsk)", + "Asia\/Taipei": "Isikhathi sase-Taipei (i-Taipei)", + "Asia\/Tashkent": "Isikhathi sase-Uzbekistan (i-Tashkent)", + "Asia\/Tbilisi": "Isikhathi sase-Georgia (i-Tbilisi)", + "Asia\/Tehran": "Isikhathi sase-Iran (i-Tehran)", + "Asia\/Thimphu": "Isikhathi sase-Bhutan (i-Thimphu)", + "Asia\/Tokyo": "Isikhathi sase-Japan (i-Tokyo)", + "Asia\/Ulaanbaatar": "Isikhathi sase-Ulan Bator (i-Ulaanbaatar)", + "Asia\/Ust-Nera": "Isikhathi sase-Vladivostok (i-Ust-Nera)", + "Asia\/Vientiane": "Isikhathi sase-Indochina (i-Vientiane)", + "Asia\/Vladivostok": "Isikhathi sase-Vladivostok (i-Vladivostok)", + "Asia\/Yakutsk": "Isikhathi sase-Yakutsk (i-Yakutsk)", + "Asia\/Yekaterinburg": "Isikhathi sase-Yekaterinburg (i-Yekaterinburg)", + "Asia\/Yerevan": "Isikhathi saseArmenia (i-Yerevan)", + "Atlantic\/Azores": "Isikhathi sase-Azores (i-Azores)", + "Atlantic\/Bermuda": "Isikhathi sase-Atlantic (i-Bermuda)", + "Atlantic\/Canary": "Isikhathi sase-Western Europe (i-Canary)", + "Atlantic\/Cape_Verde": "Isikhathi sase-Cape Verde (i-Cape Verde)", + "Atlantic\/Faeroe": "Isikhathi sase-Western Europe (i-Faroe)", + "Atlantic\/Madeira": "Isikhathi sase-Western Europe (i-Madeira)", + "Atlantic\/Reykjavik": "Isikhathi sase-Greenwich Mean (i-Reykjavik)", + "Atlantic\/South_Georgia": "Isikhathi sase-South Georgia (i-South Georgia)", + "Atlantic\/St_Helena": "Isikhathi sase-Greenwich Mean (i-St. Helena)", + "Atlantic\/Stanley": "Isikhathi sase-Falkland Islands (i-Stanley)", + "Australia\/Adelaide": "Isikhathi sase-Central Australia (i-Adelaide)", + "Australia\/Brisbane": "Isikhathi sase-Eastern Australia (i-Brisbane)", + "Australia\/Broken_Hill": "Isikhathi sase-Central Australia (i-Broken Hill)", + "Australia\/Currie": "Isikhathi sase-Eastern Australia (i-Currie)", + "Australia\/Darwin": "Isikhathi sase-Central Australia (i-Darwin)", + "Australia\/Eucla": "Isikhathi sase-Australian Central West (i-Eucla)", + "Australia\/Hobart": "Isikhathi sase-Eastern Australia (i-Hobart)", + "Australia\/Lindeman": "Isikhathi sase-Eastern Australia (i-Lindeman)", + "Australia\/Lord_Howe": "Isikhathi sase-Lord Howe (i-Lord Howe)", + "Australia\/Melbourne": "Isikhathi sase-Eastern Australia (i-Melbourne)", + "Australia\/Perth": "Isikhathi sase-Western Australia (i-Perth)", + "Australia\/Sydney": "Isikhathi sase-Eastern Australia (i-Sydney)", + "CST6CDT": "Isikhathi sase-North American Central", + "EST5EDT": "Isikhathi sase-North American East", + "Etc\/GMT": "Isikhathi sase-Greenwich Mean", + "Etc\/UTC": "isikhathi somhlaba esididiyelwe", + "Europe\/Amsterdam": "Isikhathi sase-Central Europe (i-Amsterdam)", + "Europe\/Andorra": "Isikhathi sase-Central Europe (i-Andorra)", + "Europe\/Astrakhan": "Isikhathi sase-Moscow (i-Astrakhan)", + "Europe\/Athens": "Isikhathi sase-Eastern Europe (i-Athens)", + "Europe\/Belgrade": "Isikhathi sase-Central Europe (i-Belgrade)", + "Europe\/Berlin": "Isikhathi sase-Central Europe (i-Berlin)", + "Europe\/Bratislava": "Isikhathi sase-Central Europe (i-Bratislava)", + "Europe\/Brussels": "Isikhathi sase-Central Europe (i-Brussels)", + "Europe\/Bucharest": "Isikhathi sase-Eastern Europe (i-Bucharest)", + "Europe\/Budapest": "Isikhathi sase-Central Europe (i-Budapest)", + "Europe\/Busingen": "Isikhathi sase-Central Europe (i-Busingen)", + "Europe\/Chisinau": "Isikhathi sase-Eastern Europe (i-Chisinau)", + "Europe\/Copenhagen": "Isikhathi sase-Central Europe (i-Copenhagen)", + "Europe\/Dublin": "Isikhathi sase-Greenwich Mean (i-Dublin)", + "Europe\/Gibraltar": "Isikhathi sase-Central Europe (i-Gibraltar)", + "Europe\/Guernsey": "Isikhathi sase-Greenwich Mean (i-Guernsey)", + "Europe\/Helsinki": "Isikhathi sase-Eastern Europe (i-Helsinki)", + "Europe\/Isle_of_Man": "Isikhathi sase-Greenwich Mean (i-Isle of Man)", + "Europe\/Jersey": "Isikhathi sase-Greenwich Mean (i-Jersey)", + "Europe\/Kaliningrad": "Isikhathi sase-Eastern Europe (i-Kaliningrad)", + "Europe\/Kiev": "Isikhathi sase-Eastern Europe (i-Kiev)", + "Europe\/Lisbon": "Isikhathi sase-Western Europe (i-Lisbon)", + "Europe\/Ljubljana": "Isikhathi sase-Central Europe (i-Ljubljana)", + "Europe\/London": "Isikhathi sase-Greenwich Mean (i-London)", + "Europe\/Luxembourg": "Isikhathi sase-Central Europe (i-Luxembourg)", + "Europe\/Madrid": "Isikhathi sase-Central Europe (i-Madrid)", + "Europe\/Malta": "Isikhathi sase-Central Europe (i-Malta)", + "Europe\/Mariehamn": "Isikhathi sase-Eastern Europe (i-Mariehamn)", + "Europe\/Minsk": "Isikhathi sase-Moscow (i-Minsk)", + "Europe\/Monaco": "Isikhathi sase-Central Europe (i-Monaco)", + "Europe\/Moscow": "Isikhathi sase-Moscow (i-Moscow)", + "Europe\/Oslo": "Isikhathi sase-Central Europe (i-Oslo)", + "Europe\/Paris": "Isikhathi sase-Central Europe (i-Paris)", + "Europe\/Podgorica": "Isikhathi sase-Central Europe (i-Podgorica)", + "Europe\/Prague": "Isikhathi sase-Central Europe (i-Prague)", + "Europe\/Riga": "Isikhathi sase-Eastern Europe (i-Riga)", + "Europe\/Rome": "Isikhathi sase-Central Europe (i-Rome)", + "Europe\/Samara": "esase-Samara Time (i-Samara)", + "Europe\/San_Marino": "Isikhathi sase-Central Europe (i-San Marino)", + "Europe\/Sarajevo": "Isikhathi sase-Central Europe (i-Sarajevo)", + "Europe\/Saratov": "Isikhathi sase-Moscow (i-Saratov)", + "Europe\/Simferopol": "Isikhathi sase-Moscow (i-Simferopol)", + "Europe\/Skopje": "Isikhathi sase-Central Europe (i-Skopje)", + "Europe\/Sofia": "Isikhathi sase-Eastern Europe (i-Sofia)", + "Europe\/Stockholm": "Isikhathi sase-Central Europe (i-Stockholm)", + "Europe\/Tallinn": "Isikhathi sase-Eastern Europe (i-Tallinn)", + "Europe\/Tirane": "Isikhathi sase-Central Europe (i-Tirane)", + "Europe\/Ulyanovsk": "Isikhathi sase-Moscow (i-Ulyanovsk)", + "Europe\/Uzhgorod": "Isikhathi sase-Eastern Europe (i-Uzhhorod)", + "Europe\/Vaduz": "Isikhathi sase-Central Europe (i-Vaduz)", + "Europe\/Vatican": "Isikhathi sase-Central Europe (i-Vatican)", + "Europe\/Vienna": "Isikhathi sase-Central Europe (i-Vienna)", + "Europe\/Vilnius": "Isikhathi sase-Eastern Europe (i-Vilnius)", + "Europe\/Volgograd": "Isikhathi sase-Volgograd (i-Volgograd)", + "Europe\/Warsaw": "Isikhathi sase-Central Europe (i-Warsaw)", + "Europe\/Zagreb": "Isikhathi sase-Central Europe (i-Zagreb)", + "Europe\/Zaporozhye": "Isikhathi sase-Eastern Europe (i-Zaporozhye)", + "Europe\/Zurich": "Isikhathi sase-Central Europe (i-Zurich)", + "Indian\/Antananarivo": "Isikhathi saseMpumalanga Afrika (i-Antananarivo)", + "Indian\/Chagos": "Isikhathi sase-Indian Ocean (i-Chagos)", + "Indian\/Christmas": "Isikhathi sase-Christmas Island (i-Christmas)", + "Indian\/Cocos": "Isikhathi sase-Cocos Islands (i-Cocos)", + "Indian\/Comoro": "Isikhathi saseMpumalanga Afrika (i-Comoro)", + "Indian\/Kerguelen": "Isikhathi sase-French Southern nase-Antarctic (i-Kerguelen)", + "Indian\/Mahe": "Isikhathi sase-Seychelles (iMahe)", + "Indian\/Maldives": "Isikhathi sase-Maldives (i-Maldives)", + "Indian\/Mauritius": "Isikhathi sase-Mauritius (i-Mauritius)", + "Indian\/Mayotte": "Isikhathi saseMpumalanga Afrika (i-Mayotte)", + "Indian\/Reunion": "Isikhathi sase-Reunion (i-Réunion)", + "MST7MDT": "Isikhathi sase-North American Mountain", + "PST8PDT": "Isikhathi sase-North American Pacific", + "Pacific\/Apia": "Isikhathi sase-Apia (i-Apia)", + "Pacific\/Auckland": "Isikhathi sase-New Zealand (i-Auckland)", + "Pacific\/Bougainville": "Isikhathi sase-Papua New Guinea (i-Bougainville)", + "Pacific\/Chatham": "Isikhathi sase-Chatham (i-Chatham)", + "Pacific\/Easter": "Isikhathi sase-Easter Island (i-Easter)", + "Pacific\/Efate": "Isikhathi sase-Vanuatu (i-Efate)", + "Pacific\/Enderbury": "Isikhathi sase-Phoenix Islands (i-Enderbury)", + "Pacific\/Fakaofo": "Isikhathi sase-Tokelau (i-Fakaofo)", + "Pacific\/Fiji": "Isikhathi sase-Fiji (i-Fiji)", + "Pacific\/Funafuti": "Isikhathi sase-Tuvalu (i-Funafuti)", + "Pacific\/Galapagos": "Isikhathi sase-Galapagos (i-Galapagos)", + "Pacific\/Gambier": "Isikhathi sase-Gambier (i-Gambier)", + "Pacific\/Guadalcanal": "Isikhathi sase-Solomon Islands (i-Guadalcanal)", + "Pacific\/Guam": "Isikhathi esijwayelekile sase-Chamorro (i-Guam)", + "Pacific\/Honolulu": "Isikhathi sase-Hawaii-Aleutia (i-Honolulu)", + "Pacific\/Johnston": "Isikhathi sase-Hawaii-Aleutia (i-Johnston)", + "Pacific\/Kiritimati": "Isikhathi sase-Line Islands (i-Kiritimati)", + "Pacific\/Kosrae": "Isikhathi sase-Kosrae (i-Kosrae)", + "Pacific\/Kwajalein": "Isikhathi sase-Marshall Islands (i-Kwajalein)", + "Pacific\/Majuro": "Isikhathi sase-Marshall Islands (i-Majuro)", + "Pacific\/Marquesas": "Isikhathi sase-Marquesas (i-Marquesas)", + "Pacific\/Midway": "Isikhathi sase-Samoa (i-Midway)", + "Pacific\/Nauru": "Isikhathi sase-Nauru (i-Nauru)", + "Pacific\/Niue": "Isikhathi sase-Niue (i-Niue)", + "Pacific\/Norfolk": "Isikhathi sase-Norfolk Islands (i-Norfolk)", + "Pacific\/Noumea": "Isikhathi sase-New Caledonia (i-Noumea)", + "Pacific\/Pago_Pago": "Isikhathi sase-Samoa (i-Pago Pago)", + "Pacific\/Palau": "Isikhathi sase-Palau (i-Palau)", + "Pacific\/Pitcairn": "Isikhathi sase-Pitcairn (i-Pitcairn)", + "Pacific\/Ponape": "Isikhathi sase-Ponape (i-Pohnpei)", + "Pacific\/Port_Moresby": "Isikhathi sase-Papua New Guinea (i-Port Moresby)", + "Pacific\/Rarotonga": "Isikhathi sase-Cook Islands (i-Rarotonga)", + "Pacific\/Saipan": "Isikhathi esijwayelekile sase-Chamorro (i-Saipan)", + "Pacific\/Tahiti": "Isikhathi sase-Tahiti (i-Tahiti)", + "Pacific\/Tarawa": "Isikhathi sase-Gilbert Islands (i-Tarawa)", + "Pacific\/Tongatapu": "Isikhathi sase-Tonga (i-Tongatapu)", + "Pacific\/Truk": "Isikhathi sase-Chuuk (i-Chuuk)", + "Pacific\/Wake": "Isikhathi sase-Wake Island (i-Wake)", + "Pacific\/Wallis": "Isikhathi sase-Wallis nase-Futuna (i-Wallis)" + } +} diff --git a/src/Symfony/Component/Intl/Tests/TimezonesTest.php b/src/Symfony/Component/Intl/Tests/TimezonesTest.php new file mode 100644 index 0000000000000..021364b777a81 --- /dev/null +++ b/src/Symfony/Component/Intl/Tests/TimezonesTest.php @@ -0,0 +1,518 @@ +<?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\Component\Intl\Tests; + +use Symfony\Component\Intl\Timezones; + +/** + * @group intl-data + */ +class TimezonesTest extends ResourceBundleTestCase +{ + // The below arrays document the state of the ICU data bundled with this package. + + private static $zones = [ + 'Africa/Abidjan', + 'Africa/Accra', + 'Africa/Addis_Ababa', + 'Africa/Algiers', + 'Africa/Asmera', + 'Africa/Bamako', + 'Africa/Bangui', + 'Africa/Banjul', + 'Africa/Bissau', + 'Africa/Blantyre', + 'Africa/Brazzaville', + 'Africa/Bujumbura', + 'Africa/Cairo', + 'Africa/Casablanca', + 'Africa/Ceuta', + 'Africa/Conakry', + 'Africa/Dakar', + 'Africa/Dar_es_Salaam', + 'Africa/Djibouti', + 'Africa/Douala', + 'Africa/El_Aaiun', + 'Africa/Freetown', + 'Africa/Gaborone', + 'Africa/Harare', + 'Africa/Johannesburg', + 'Africa/Juba', + 'Africa/Kampala', + 'Africa/Khartoum', + 'Africa/Kigali', + 'Africa/Kinshasa', + 'Africa/Lagos', + 'Africa/Libreville', + 'Africa/Lome', + 'Africa/Luanda', + 'Africa/Lubumbashi', + 'Africa/Lusaka', + 'Africa/Malabo', + 'Africa/Maputo', + 'Africa/Maseru', + 'Africa/Mbabane', + 'Africa/Mogadishu', + 'Africa/Monrovia', + 'Africa/Nairobi', + 'Africa/Ndjamena', + 'Africa/Niamey', + 'Africa/Nouakchott', + 'Africa/Ouagadougou', + 'Africa/Porto-Novo', + 'Africa/Sao_Tome', + 'Africa/Tripoli', + 'Africa/Tunis', + 'Africa/Windhoek', + 'America/Adak', + 'America/Anchorage', + 'America/Anguilla', + 'America/Antigua', + 'America/Araguaina', + 'America/Argentina/La_Rioja', + 'America/Argentina/Rio_Gallegos', + 'America/Argentina/Salta', + 'America/Argentina/San_Juan', + 'America/Argentina/San_Luis', + 'America/Argentina/Tucuman', + 'America/Argentina/Ushuaia', + 'America/Aruba', + 'America/Asuncion', + 'America/Bahia', + 'America/Bahia_Banderas', + 'America/Barbados', + 'America/Belem', + 'America/Belize', + 'America/Blanc-Sablon', + 'America/Boa_Vista', + 'America/Bogota', + 'America/Boise', + 'America/Buenos_Aires', + 'America/Cambridge_Bay', + 'America/Campo_Grande', + 'America/Cancun', + 'America/Caracas', + 'America/Catamarca', + 'America/Cayenne', + 'America/Cayman', + 'America/Chicago', + 'America/Chihuahua', + 'America/Coral_Harbour', + 'America/Cordoba', + 'America/Costa_Rica', + 'America/Creston', + 'America/Cuiaba', + 'America/Curacao', + 'America/Danmarkshavn', + 'America/Dawson', + 'America/Dawson_Creek', + 'America/Denver', + 'America/Detroit', + 'America/Dominica', + 'America/Edmonton', + 'America/Eirunepe', + 'America/El_Salvador', + 'America/Fort_Nelson', + 'America/Fortaleza', + 'America/Glace_Bay', + 'America/Godthab', + 'America/Goose_Bay', + 'America/Grand_Turk', + 'America/Grenada', + 'America/Guadeloupe', + 'America/Guatemala', + 'America/Guayaquil', + 'America/Guyana', + 'America/Halifax', + 'America/Havana', + 'America/Hermosillo', + 'America/Indiana/Knox', + 'America/Indiana/Marengo', + 'America/Indiana/Petersburg', + 'America/Indiana/Tell_City', + 'America/Indiana/Vevay', + 'America/Indiana/Vincennes', + 'America/Indiana/Winamac', + 'America/Indianapolis', + 'America/Inuvik', + 'America/Iqaluit', + 'America/Jamaica', + 'America/Jujuy', + 'America/Juneau', + 'America/Kentucky/Monticello', + 'America/Kralendijk', + 'America/La_Paz', + 'America/Lima', + 'America/Los_Angeles', + 'America/Louisville', + 'America/Lower_Princes', + 'America/Maceio', + 'America/Managua', + 'America/Manaus', + 'America/Marigot', + 'America/Martinique', + 'America/Matamoros', + 'America/Mazatlan', + 'America/Mendoza', + 'America/Menominee', + 'America/Merida', + 'America/Metlakatla', + 'America/Mexico_City', + 'America/Miquelon', + 'America/Moncton', + 'America/Monterrey', + 'America/Montevideo', + 'America/Montreal', + 'America/Montserrat', + 'America/Nassau', + 'America/New_York', + 'America/Nipigon', + 'America/Nome', + 'America/Noronha', + 'America/North_Dakota/Beulah', + 'America/North_Dakota/Center', + 'America/North_Dakota/New_Salem', + 'America/Ojinaga', + 'America/Panama', + 'America/Pangnirtung', + 'America/Paramaribo', + 'America/Phoenix', + 'America/Port-au-Prince', + 'America/Port_of_Spain', + 'America/Porto_Velho', + 'America/Puerto_Rico', + 'America/Punta_Arenas', + 'America/Rainy_River', + 'America/Rankin_Inlet', + 'America/Recife', + 'America/Regina', + 'America/Resolute', + 'America/Rio_Branco', + 'America/Santa_Isabel', + 'America/Santarem', + 'America/Santiago', + 'America/Santo_Domingo', + 'America/Sao_Paulo', + 'America/Scoresbysund', + 'America/Sitka', + 'America/St_Barthelemy', + 'America/St_Johns', + 'America/St_Kitts', + 'America/St_Lucia', + 'America/St_Thomas', + 'America/St_Vincent', + 'America/Swift_Current', + 'America/Tegucigalpa', + 'America/Thule', + 'America/Thunder_Bay', + 'America/Tijuana', + 'America/Toronto', + 'America/Tortola', + 'America/Vancouver', + 'America/Whitehorse', + 'America/Winnipeg', + 'America/Yakutat', + 'America/Yellowknife', + 'Antarctica/Casey', + 'Antarctica/Davis', + 'Antarctica/DumontDUrville', + 'Antarctica/Macquarie', + 'Antarctica/Mawson', + 'Antarctica/McMurdo', + 'Antarctica/Palmer', + 'Antarctica/Rothera', + 'Antarctica/Syowa', + 'Antarctica/Troll', + 'Antarctica/Vostok', + 'Arctic/Longyearbyen', + 'Asia/Aden', + 'Asia/Almaty', + 'Asia/Amman', + 'Asia/Anadyr', + 'Asia/Aqtau', + 'Asia/Aqtobe', + 'Asia/Ashgabat', + 'Asia/Atyrau', + 'Asia/Baghdad', + 'Asia/Bahrain', + 'Asia/Baku', + 'Asia/Bangkok', + 'Asia/Barnaul', + 'Asia/Beirut', + 'Asia/Bishkek', + 'Asia/Brunei', + 'Asia/Calcutta', + 'Asia/Chita', + 'Asia/Choibalsan', + 'Asia/Colombo', + 'Asia/Damascus', + 'Asia/Dhaka', + 'Asia/Dili', + 'Asia/Dubai', + 'Asia/Dushanbe', + 'Asia/Famagusta', + 'Asia/Gaza', + 'Asia/Hebron', + 'Asia/Hong_Kong', + 'Asia/Hovd', + 'Asia/Irkutsk', + 'Asia/Jakarta', + 'Asia/Jayapura', + 'Asia/Jerusalem', + 'Asia/Kabul', + 'Asia/Kamchatka', + 'Asia/Karachi', + 'Asia/Katmandu', + 'Asia/Khandyga', + 'Asia/Krasnoyarsk', + 'Asia/Kuala_Lumpur', + 'Asia/Kuching', + 'Asia/Kuwait', + 'Asia/Macau', + 'Asia/Magadan', + 'Asia/Makassar', + 'Asia/Manila', + 'Asia/Muscat', + 'Asia/Nicosia', + 'Asia/Novokuznetsk', + 'Asia/Novosibirsk', + 'Asia/Omsk', + 'Asia/Oral', + 'Asia/Phnom_Penh', + 'Asia/Pontianak', + 'Asia/Pyongyang', + 'Asia/Qatar', + 'Asia/Qostanay', + 'Asia/Qyzylorda', + 'Asia/Rangoon', + 'Asia/Riyadh', + 'Asia/Saigon', + 'Asia/Sakhalin', + 'Asia/Samarkand', + 'Asia/Seoul', + 'Asia/Shanghai', + 'Asia/Singapore', + 'Asia/Srednekolymsk', + 'Asia/Taipei', + 'Asia/Tashkent', + 'Asia/Tbilisi', + 'Asia/Tehran', + 'Asia/Thimphu', + 'Asia/Tokyo', + 'Asia/Tomsk', + 'Asia/Ulaanbaatar', + 'Asia/Urumqi', + 'Asia/Ust-Nera', + 'Asia/Vientiane', + 'Asia/Vladivostok', + 'Asia/Yakutsk', + 'Asia/Yekaterinburg', + 'Asia/Yerevan', + 'Atlantic/Azores', + 'Atlantic/Bermuda', + 'Atlantic/Canary', + 'Atlantic/Cape_Verde', + 'Atlantic/Faeroe', + 'Atlantic/Madeira', + 'Atlantic/Reykjavik', + 'Atlantic/South_Georgia', + 'Atlantic/St_Helena', + 'Atlantic/Stanley', + 'Australia/Adelaide', + 'Australia/Brisbane', + 'Australia/Broken_Hill', + 'Australia/Currie', + 'Australia/Darwin', + 'Australia/Eucla', + 'Australia/Hobart', + 'Australia/Lindeman', + 'Australia/Lord_Howe', + 'Australia/Melbourne', + 'Australia/Perth', + 'Australia/Sydney', + 'CST6CDT', + 'EST5EDT', + 'Etc/GMT', + 'Etc/UTC', + 'Europe/Amsterdam', + 'Europe/Andorra', + 'Europe/Astrakhan', + 'Europe/Athens', + 'Europe/Belgrade', + 'Europe/Berlin', + 'Europe/Bratislava', + 'Europe/Brussels', + 'Europe/Bucharest', + 'Europe/Budapest', + 'Europe/Busingen', + 'Europe/Chisinau', + 'Europe/Copenhagen', + 'Europe/Dublin', + 'Europe/Gibraltar', + 'Europe/Guernsey', + 'Europe/Helsinki', + 'Europe/Isle_of_Man', + 'Europe/Istanbul', + 'Europe/Jersey', + 'Europe/Kaliningrad', + 'Europe/Kiev', + 'Europe/Kirov', + 'Europe/Lisbon', + 'Europe/Ljubljana', + 'Europe/London', + 'Europe/Luxembourg', + 'Europe/Madrid', + 'Europe/Malta', + 'Europe/Mariehamn', + 'Europe/Minsk', + 'Europe/Monaco', + 'Europe/Moscow', + 'Europe/Oslo', + 'Europe/Paris', + 'Europe/Podgorica', + 'Europe/Prague', + 'Europe/Riga', + 'Europe/Rome', + 'Europe/Samara', + 'Europe/San_Marino', + 'Europe/Sarajevo', + 'Europe/Saratov', + 'Europe/Simferopol', + 'Europe/Skopje', + 'Europe/Sofia', + 'Europe/Stockholm', + 'Europe/Tallinn', + 'Europe/Tirane', + 'Europe/Ulyanovsk', + 'Europe/Uzhgorod', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Vilnius', + 'Europe/Volgograd', + 'Europe/Warsaw', + 'Europe/Zagreb', + 'Europe/Zaporozhye', + 'Europe/Zurich', + 'Indian/Antananarivo', + 'Indian/Chagos', + 'Indian/Christmas', + 'Indian/Cocos', + 'Indian/Comoro', + 'Indian/Kerguelen', + 'Indian/Mahe', + 'Indian/Maldives', + 'Indian/Mauritius', + 'Indian/Mayotte', + 'Indian/Reunion', + 'MST7MDT', + 'PST8PDT', + 'Pacific/Apia', + 'Pacific/Auckland', + 'Pacific/Bougainville', + 'Pacific/Chatham', + 'Pacific/Easter', + 'Pacific/Efate', + 'Pacific/Enderbury', + 'Pacific/Fakaofo', + 'Pacific/Fiji', + 'Pacific/Funafuti', + 'Pacific/Galapagos', + 'Pacific/Gambier', + 'Pacific/Guadalcanal', + 'Pacific/Guam', + 'Pacific/Honolulu', + 'Pacific/Johnston', + 'Pacific/Kiritimati', + 'Pacific/Kosrae', + 'Pacific/Kwajalein', + 'Pacific/Majuro', + 'Pacific/Marquesas', + 'Pacific/Midway', + 'Pacific/Nauru', + 'Pacific/Niue', + 'Pacific/Norfolk', + 'Pacific/Noumea', + 'Pacific/Pago_Pago', + 'Pacific/Palau', + 'Pacific/Pitcairn', + 'Pacific/Ponape', + 'Pacific/Port_Moresby', + 'Pacific/Rarotonga', + 'Pacific/Saipan', + 'Pacific/Tahiti', + 'Pacific/Tarawa', + 'Pacific/Tongatapu', + 'Pacific/Truk', + 'Pacific/Wake', + 'Pacific/Wallis', + ]; + + public function testGetTimezones() + { + $this->assertEquals(self::$zones, Timezones::getIds()); + } + + /** + * @dataProvider provideLocales + */ + public function testGetNames($displayLocale) + { + $zones = array_keys(Timezones::getNames($displayLocale)); + + sort($zones); + + $this->assertNotEmpty($zones); + $this->assertEmpty(array_diff($zones, self::$zones)); + } + + public function testGetNamesDefaultLocale() + { + \Locale::setDefault('de_AT'); + + $this->assertSame(Timezones::getNames('de_AT'), Timezones::getNames()); + } + + /** + * @dataProvider provideLocaleAliases + */ + public function testGetNamesSupportsAliases($alias, $ofLocale) + { + // Can't use assertSame(), because some aliases contain scripts with + // different collation (=order of output) than their aliased locale + // e.g. sr_Latn_ME => sr_ME + $this->assertEquals(Timezones::getNames($ofLocale), Timezones::getNames($alias)); + } + + /** + * @dataProvider provideLocales + */ + public function testGetName($displayLocale) + { + $names = Timezones::getNames($displayLocale); + + foreach ($names as $language => $name) { + $this->assertSame($name, Timezones::getName($language, $displayLocale)); + } + } + + public function testGetNameDefaultLocale() + { + \Locale::setDefault('de_AT'); + + $names = Timezones::getNames('de_AT'); + + foreach ($names as $language => $name) { + $this->assertSame($name, Timezones::getName($language)); + } + } +} diff --git a/src/Symfony/Component/Intl/Timezones.php b/src/Symfony/Component/Intl/Timezones.php new file mode 100644 index 0000000000000..89577ca7f85c6 --- /dev/null +++ b/src/Symfony/Component/Intl/Timezones.php @@ -0,0 +1,59 @@ +<?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\Component\Intl; + +use Symfony\Component\Intl\Exception\MissingResourceException; + +/** + * Gives access to timezone-related ICU data. + * + * @author Roland Franssen <franssen.roland@gmail.com> + */ +final class Timezones extends ResourceBundle +{ + /** + * @return string[] + */ + public static function getIds(): array + { + return self::readEntry(['Zones'], 'meta'); + } + + public static function exists(string $timezone): bool + { + try { + self::readEntry(['Names', $timezone]); + + return true; + } catch (MissingResourceException $e) { + return false; + } + } + + public static function getName(string $timezone, string $displayLocale = null): string + { + return self::readEntry(['Names', $timezone], $displayLocale); + } + + /** + * @return string[] + */ + public static function getNames(string $displayLocale = null): array + { + return self::asort(self::readEntry(['Names'], $displayLocale), $displayLocale); + } + + protected static function getPath(): string + { + return Intl::getDataDirectory().'/'.Intl::TIMEZONE_DIR; + } +} From fde4dc99229de893ad97742d0f8d92ca8eac09e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ksaveras=20=C5=A0akys?= <xawiers@gmail.com> Date: Fri, 12 Apr 2019 09:07:10 +0100 Subject: [PATCH 489/495] [DoctrineBridge] Unique mapping setting is optional --- .../Doctrine/Test/DoctrineTestHelper.php | 25 ++++++++++ .../Doctrine/Tests/Fixtures/BaseUser.php | 47 +++++++++++++++++++ .../Tests/Resources/orm/BaseUser.orm.xml | 11 +++++ .../Tests/Resources/validator/BaseUser.xml | 19 ++++++++ .../Tests/Validator/DoctrineLoaderTest.php | 25 ++++++++++ .../Doctrine/Validator/DoctrineLoader.php | 2 +- 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/BaseUser.php create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Resources/orm/BaseUser.orm.xml create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml diff --git a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php index 3f6ffeebb6e2d..24aa66a7dda46 100644 --- a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php +++ b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php @@ -13,9 +13,12 @@ use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Cache\ArrayCache; +use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain; +use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator; use Doctrine\ORM\Configuration; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; +use Doctrine\ORM\Mapping\Driver\XmlDriver; use PHPUnit\Framework\TestCase; /** @@ -67,6 +70,28 @@ public static function createTestConfiguration() return $config; } + /** + * @return Configuration + */ + public static function createTestConfigurationWithXmlLoader() + { + $config = static::createTestConfiguration(); + + $driverChain = new MappingDriverChain(); + $driverChain->addDriver( + new XmlDriver( + new SymfonyFileLocator( + [__DIR__.'/../Tests/Resources/orm' => 'Symfony\\Bridge\\Doctrine\\Tests\\Fixtures'], '.orm.xml' + ) + ), + 'Symfony\\Bridge\\Doctrine\\Tests\\Fixtures' + ); + + $config->setMetadataDriverImpl($driverChain); + + return $config; + } + /** * This class cannot be instantiated. */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/BaseUser.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/BaseUser.php new file mode 100644 index 0000000000000..cbd0ff44688eb --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/BaseUser.php @@ -0,0 +1,47 @@ +<?php + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +/** + * Class BaseUser. + */ +class BaseUser +{ + /** + * @var int + */ + private $id; + + /** + * @var string + */ + private $username; + + /** + * BaseUser constructor. + * + * @param int $id + * @param string $username + */ + public function __construct(int $id, string $username) + { + $this->id = $id; + $this->username = $username; + } + + /** + * @return int + */ + public function getId() + { + return $this->id; + } + + /** + * @return string + */ + public function getUsername() + { + return $this->username; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Resources/orm/BaseUser.orm.xml b/src/Symfony/Bridge/Doctrine/Tests/Resources/orm/BaseUser.orm.xml new file mode 100644 index 0000000000000..da4a536fd94e6 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Resources/orm/BaseUser.orm.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping + http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd"> + + <mapped-superclass name="Symfony\Bridge\Doctrine\Tests\Fixtures\BaseUser"> + <field name="username" column="username" type="string" length="120" /> + </mapped-superclass> + +</doctrine-mapping> diff --git a/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml b/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml new file mode 100644 index 0000000000000..bf64b92ca484d --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Resources/validator/BaseUser.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" ?> +<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/constraint-mapping + http://symfony.com/schema/dic/constraint-mapping/constraint-mapping-1.0.xsd"> + + <class name="Symfony\Bridge\Doctrine\Tests\Fixtures\BaseUser"> + <property name="username"> + <constraint name="NotBlank"> + <option name="groups">Registration</option> + </constraint> + <constraint name="Length"> + <option name="min">2</option> + <option name="max">120</option> + <option name="groups">Registration</option> + </constraint> + </property> + </class> +</constraint-mapping> diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php index 9599ac8995cda..cde956eed3493 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Tests\Fixtures\BaseUser; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoctrineLoaderEntity; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; use Symfony\Bridge\Doctrine\Validator\DoctrineLoader; @@ -72,6 +73,30 @@ public function testLoadClassMetadata() $this->assertSame(1, $alreadyMappedMaxLengthConstraints[0]->min); } + public function testFieldMappingsConfiguration() + { + if (!method_exists(ValidatorBuilder::class, 'addLoader')) { + $this->markTestSkipped('Auto-mapping requires symfony/validation 4.2+'); + } + + $validator = Validation::createValidatorBuilder() + ->enableAnnotationMapping() + ->addXmlMappings([__DIR__.'/../Resources/validator/BaseUser.xml']) + ->addLoader( + new DoctrineLoader( + DoctrineTestHelper::createTestEntityManager( + DoctrineTestHelper::createTestConfigurationWithXmlLoader() + ), '{}' + ) + ) + ->getValidator(); + + $classMetadata = $validator->getMetadataFor(new BaseUser(1, 'DemoUser')); + + $constraints = $classMetadata->getConstraints(); + $this->assertCount(0, $constraints); + } + /** * @dataProvider regexpProvider */ diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php index 3b6d065fe6e1f..9ae31671bd933 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php @@ -68,7 +68,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool // Type and nullable aren't handled here, use the PropertyInfo Loader instead. foreach ($doctrineMetadata->fieldMappings as $mapping) { - if (true === $mapping['unique'] && !isset($existingUniqueFields[$mapping['fieldName']])) { + if (true === ($mapping['unique'] ?? false) && !isset($existingUniqueFields[$mapping['fieldName']])) { $metadata->addConstraint(new UniqueEntity(['fields' => $mapping['fieldName']])); } From 3bdf4b0e0fa2d3379cb9f9e8ef446f8fccf5860e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas <nicolas.grekas@gmail.com> Date: Tue, 23 Apr 2019 13:15:09 +0200 Subject: [PATCH 490/495] [Messenger] ease testing and allow forking the middleware stack --- .../Messenger/Middleware/StackInterface.php | 2 + .../Messenger/Middleware/StackMiddleware.php | 65 +++++++++++++++---- .../Test/Middleware/MiddlewareTestCase.php | 31 ++++----- .../Tests/Middleware/StackMiddlewareTest.php | 51 +++++++++++++++ 4 files changed, 121 insertions(+), 28 deletions(-) create mode 100644 src/Symfony/Component/Messenger/Tests/Middleware/StackMiddlewareTest.php diff --git a/src/Symfony/Component/Messenger/Middleware/StackInterface.php b/src/Symfony/Component/Messenger/Middleware/StackInterface.php index 1ee38ea6ea6b9..17f0acf4aba51 100644 --- a/src/Symfony/Component/Messenger/Middleware/StackInterface.php +++ b/src/Symfony/Component/Messenger/Middleware/StackInterface.php @@ -14,6 +14,8 @@ /** * @author Nicolas Grekas <p@tchwork.com> * + * Implementations must be cloneable, and each clone must unstack the stack independently. + * * @experimental in 4.2 */ interface StackInterface diff --git a/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php b/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php index 24516cd88111d..4c1c597cf70aa 100644 --- a/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/StackMiddleware.php @@ -20,27 +20,42 @@ */ class StackMiddleware implements MiddlewareInterface, StackInterface { - private $middlewareIterator; + private $stack; + private $offset = 0; - public function __construct(\Iterator $middlewareIterator = null) + /** + * @param iterable|MiddlewareInterface[]|MiddlewareInterface|null $middlewareIterator + */ + public function __construct($middlewareIterator = null) { - $this->middlewareIterator = $middlewareIterator; + $this->stack = new MiddlewareStack(); + + if (null === $middlewareIterator) { + return; + } + + if ($middlewareIterator instanceof \Iterator) { + $this->stack->iterator = $middlewareIterator; + } elseif ($middlewareIterator instanceof MiddlewareInterface) { + $this->stack->stack[] = $middlewareIterator; + } elseif (!\is_iterable($middlewareIterator)) { + throw new \TypeError(sprintf('Argument 1 passed to %s() must be iterable of %s, %s given.', __METHOD__, MiddlewareInterface::class, \is_object($middlewareIterator) ? \get_class($middlewareIterator) : \gettype($middlewareIterator))); + } else { + $this->stack->iterator = (function () use ($middlewareIterator) { + yield from $middlewareIterator; + })(); + } } public function next(): MiddlewareInterface { - if (null === $iterator = $this->middlewareIterator) { + if (null === $next = $this->stack->next($this->offset)) { return $this; } - $iterator->next(); - if (!$iterator->valid()) { - $this->middlewareIterator = null; + ++$this->offset; - return $this; - } - - return $iterator->current(); + return $next; } public function handle(Envelope $envelope, StackInterface $stack): Envelope @@ -48,3 +63,31 @@ public function handle(Envelope $envelope, StackInterface $stack): Envelope return $envelope; } } + +/** + * @internal + */ +class MiddlewareStack +{ + public $iterator; + public $stack = []; + + public function next(int $offset): ?MiddlewareInterface + { + if (isset($this->stack[$offset])) { + return $this->stack[$offset]; + } + + if (null === $this->iterator) { + return null; + } + + $this->iterator->next(); + + if (!$this->iterator->valid()) { + return $this->iterator = null; + } + + return $this->stack[] = $this->iterator->current(); + } +} diff --git a/src/Symfony/Component/Messenger/Test/Middleware/MiddlewareTestCase.php b/src/Symfony/Component/Messenger/Test/Middleware/MiddlewareTestCase.php index 35bdc727551de..5970cf285fc44 100644 --- a/src/Symfony/Component/Messenger/Test/Middleware/MiddlewareTestCase.php +++ b/src/Symfony/Component/Messenger/Test/Middleware/MiddlewareTestCase.php @@ -15,6 +15,7 @@ use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; use Symfony\Component\Messenger\Middleware\StackInterface; +use Symfony\Component\Messenger\Middleware\StackMiddleware; /** * @author Nicolas Grekas <p@tchwork.com> @@ -25,23 +26,26 @@ abstract class MiddlewareTestCase extends TestCase { protected function getStackMock(bool $nextIsCalled = true) { + if (!$nextIsCalled) { + $stack = $this->createMock(StackInterface::class); + $stack + ->expects($this->never()) + ->method('next') + ; + + return $stack; + } + $nextMiddleware = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); $nextMiddleware - ->expects($nextIsCalled ? $this->once() : $this->never()) + ->expects($this->once()) ->method('handle') ->willReturnCallback(function (Envelope $envelope, StackInterface $stack): Envelope { return $envelope; }) ; - $stack = $this->createMock(StackInterface::class); - $stack - ->expects($nextIsCalled ? $this->once() : $this->never()) - ->method('next') - ->willReturn($nextMiddleware) - ; - - return $stack; + return new StackMiddleware($nextMiddleware); } protected function getThrowingStackMock(\Throwable $throwable = null) @@ -53,13 +57,6 @@ protected function getThrowingStackMock(\Throwable $throwable = null) ->willThrowException($throwable ?? new \RuntimeException('Thrown from next middleware.')) ; - $stack = $this->createMock(StackInterface::class); - $stack - ->expects($this->once()) - ->method('next') - ->willReturn($nextMiddleware) - ; - - return $stack; + return new StackMiddleware($nextMiddleware); } } diff --git a/src/Symfony/Component/Messenger/Tests/Middleware/StackMiddlewareTest.php b/src/Symfony/Component/Messenger/Tests/Middleware/StackMiddlewareTest.php new file mode 100644 index 0000000000000..de75271960472 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Middleware/StackMiddlewareTest.php @@ -0,0 +1,51 @@ +<?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\Component\Messenger\Tests\Middleware; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Messenger\Envelope; +use Symfony\Component\Messenger\MessageBus; +use Symfony\Component\Messenger\Middleware\MiddlewareInterface; +use Symfony\Component\Messenger\Middleware\StackInterface; + +class StackMiddlewareTest extends TestCase +{ + public function testClone() + { + $middleware1 = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); + $middleware1 + ->expects($this->once()) + ->method('handle') + ->willReturnCallback(function (Envelope $envelope, StackInterface $stack): Envelope { + $fork = clone $stack; + + $stack->next()->handle($envelope, $stack); + $fork->next()->handle($envelope, $fork); + + return $envelope; + }) + ; + + $middleware2 = $this->getMockBuilder(MiddlewareInterface::class)->getMock(); + $middleware2 + ->expects($this->exactly(2)) + ->method('handle') + ->willReturnCallback(function (Envelope $envelope, StackInterface $stack): Envelope { + return $envelope; + }) + ; + + $bus = new MessageBus([$middleware1, $middleware2]); + + $bus->dispatch(new \stdClass()); + } +} From 3278cb1c7e002374ba63e5edcb832a77ace69ed6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= <ar@ez.no> Date: Fri, 22 Feb 2019 20:19:14 +0100 Subject: [PATCH 491/495] [Cache] Add optimized FileSystem & Redis TagAware Adapters Reduces cache lookups by 50% by changing logic of how tag information is stored to avoid having to look it up on getItem(s) calls. For Filesystem symlinks are used, for Redis "Set" datatype is used. --- phpunit.xml.dist | 7 +- .../Cache/Adapter/AbstractAdapter.php | 112 +------ .../Cache/Adapter/AbstractTagAwareAdapter.php | 302 ++++++++++++++++++ .../Adapter/FilesystemTagAwareAdapter.php | 149 +++++++++ .../Cache/Adapter/RedisTagAwareAdapter.php | 209 ++++++++++++ .../DependencyInjection/CachePoolPass.php | 6 + src/Symfony/Component/Cache/LockRegistry.php | 3 + .../Adapter/FilesystemTagAwareAdapterTest.php | 28 ++ .../Adapter/PredisTagAwareAdapterTest.php | 34 ++ .../PredisTagAwareClusterAdapterTest.php | 34 ++ .../PredisTagAwareRedisClusterAdapterTest.php | 34 ++ .../Adapter/RedisTagAwareAdapterTest.php | 35 ++ .../Adapter/RedisTagAwareArrayAdapterTest.php | 34 ++ .../RedisTagAwareClusterAdapterTest.php | 35 ++ .../Tests/Adapter/TagAwareAdapterTest.php | 122 +------ .../DependencyInjection/CachePoolPassTest.php | 22 ++ .../Cache/Tests/Traits/TagAwareTestTrait.php | 160 ++++++++++ .../Cache/Traits/AbstractAdapterTrait.php | 139 ++++++++ .../Cache/Traits/FilesystemCommonTrait.php | 4 +- .../Component/Cache/Traits/RedisTrait.php | 53 +-- src/Symfony/Component/Cache/phpunit.xml.dist | 3 +- 21 files changed, 1269 insertions(+), 256 deletions(-) create mode 100644 src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php create mode 100644 src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php create mode 100644 src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php create mode 100644 src/Symfony/Component/Cache/Tests/Traits/TagAwareTestTrait.php create mode 100644 src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php diff --git a/phpunit.xml.dist b/phpunit.xml.dist index f7fe9d3464ac1..7313d16d25c70 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -71,9 +71,10 @@ <element key="1"><string>Doctrine\Common\Cache</string></element> <element key="2"><string>Symfony\Component\Cache</string></element> <element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element> - <element key="4"><string>Symfony\Component\Cache\Traits</string></element> - <element key="5"><string>Symfony\Component\Console</string></element> - <element key="6"><string>Symfony\Component\HttpFoundation</string></element> + <element key="4"><string>Symfony\Component\Cache\Tests\Traits</string></element> + <element key="5"><string>Symfony\Component\Cache\Traits</string></element> + <element key="6"><string>Symfony\Component\Console</string></element> + <element key="7"><string>Symfony\Component\HttpFoundation</string></element> </array> </element> </array> diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index 011a239bf6ac1..e8fc564ddd1ab 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -11,14 +11,13 @@ namespace Symfony\Component\Cache\Adapter; -use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; -use Symfony\Component\Cache\Traits\AbstractTrait; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Contracts\Cache\CacheInterface; @@ -27,15 +26,12 @@ */ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { - use AbstractTrait; + use AbstractAdapterTrait; use ContractsTrait; private static $apcuSupported; private static $phpFilesSupported; - private $createCacheItem; - private $mergeByLifetime; - protected function __construct(string $namespace = '', int $defaultLifetime = 0) { $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; @@ -142,81 +138,6 @@ public static function createConnection($dsn, array $options = []) throw new InvalidArgumentException(sprintf('Unsupported DSN: %s.', $dsn)); } - /** - * {@inheritdoc} - */ - public function getItem($key) - { - if ($this->deferred) { - $this->commit(); - } - $id = $this->getId($key); - - $f = $this->createCacheItem; - $isHit = false; - $value = null; - - try { - foreach ($this->doFetch([$id]) as $value) { - $isHit = true; - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); - } - - return $f($key, $value, $isHit); - } - - /** - * {@inheritdoc} - */ - public function getItems(array $keys = []) - { - if ($this->deferred) { - $this->commit(); - } - $ids = []; - - foreach ($keys as $key) { - $ids[] = $this->getId($key); - } - try { - $items = $this->doFetch($ids); - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]); - $items = []; - } - $ids = array_combine($ids, $keys); - - return $this->generateItems($items, $ids); - } - - /** - * {@inheritdoc} - */ - public function save(CacheItemInterface $item) - { - if (!$item instanceof CacheItem) { - return false; - } - $this->deferred[$item->getKey()] = $item; - - return $this->commit(); - } - - /** - * {@inheritdoc} - */ - public function saveDeferred(CacheItemInterface $item) - { - if (!$item instanceof CacheItem) { - return false; - } - $this->deferred[$item->getKey()] = $item; - - return true; - } - /** * {@inheritdoc} */ @@ -271,33 +192,4 @@ public function commit() return $ok; } - - public function __destruct() - { - if ($this->deferred) { - $this->commit(); - } - } - - private function generateItems($items, &$keys) - { - $f = $this->createCacheItem; - - try { - foreach ($items as $id => $value) { - if (!isset($keys[$id])) { - $id = key($keys); - } - $key = $keys[$id]; - unset($keys[$id]); - yield $key => $f($key, $value, true); - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]); - } - - foreach ($keys as $key) { - yield $key => $f($key, null, false); - } - } } diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php new file mode 100644 index 0000000000000..ddebdf19bbb07 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php @@ -0,0 +1,302 @@ +<?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\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * Abstract for native TagAware adapters. + * + * To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids + * to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate(). + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @internal + * @experimental in 4.3 + */ +abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface +{ + use AbstractAdapterTrait; + use ContractsTrait; + + private const TAGS_PREFIX = "\0tags\0"; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) + { + $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; + if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + } + $this->createCacheItem = \Closure::bind( + static function ($key, $value, $isHit) use ($defaultLifetime) { + $item = new CacheItem(); + $item->key = $key; + $item->defaultLifetime = $defaultLifetime; + $item->isTaggable = true; + // If structure does not match what we expect return item as is (no value and not a hit) + if (!\is_array($value) || !\array_key_exists('value', $value)) { + return $item; + } + $item->isHit = $isHit; + // Extract value, tags and meta data from the cache value + $item->value = $value['value']; + $item->metadata[CacheItem::METADATA_TAGS] = $value['tags'] ?? []; + if (isset($value['meta'])) { + // For compactness these values are packed, & expiry is offset to reduce size + $v = \unpack('Ve/Nc', $value['meta']); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } + + return $item; + }, + null, + CacheItem::class + ); + $getId = \Closure::fromCallable([$this, 'getId']); + $tagPrefix = self::TAGS_PREFIX; + $this->mergeByLifetime = \Closure::bind( + static function ($deferred, &$expiredIds) use ($getId, $tagPrefix) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0; + } elseif (0 >= $ttl = (int) ($item->expiry - $now)) { + $expiredIds[] = $getId($key); + continue; + } + // Store Value and Tags on the cache value + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + $value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]]; + unset($metadata[CacheItem::METADATA_TAGS]); + } else { + $value = ['value' => $item->value, 'tags' => []]; + } + + if ($metadata) { + // For compactness, expiry and creation duration are packed, using magic numbers as separators + $value['meta'] = \pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME]); + } + + // Extract tag changes, these should be removed from values in doSave() + $value['tag-operations'] = ['add' => [], 'remove' => []]; + $oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? []; + foreach (\array_diff($value['tags'], $oldTags) as $addedTag) { + $value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag); + } + foreach (\array_diff($oldTags, $value['tags']) as $removedTag) { + $value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag); + } + + $byLifetime[$ttl][$getId($key)] = $value; + } + + return $byLifetime; + }, + null, + CacheItem::class + ); + } + + /** + * Persists several cache items immediately. + * + * @param array $values The values to cache, indexed by their cache identifier + * @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning + * @param array[] $addTagData Hash where key is tag id, and array value is list of cache id's to add to tag + * @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag + * + * @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not + */ + abstract protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array; + + /** + * Removes multiple items from the pool and their corresponding tags. + * + * @param array $ids An array of identifiers that should be removed from the pool + * @param array $tagData Optional array of tag identifiers => key identifiers that should be removed from the pool + * + * @return bool True if the items were successfully removed, false otherwise + */ + abstract protected function doDelete(array $ids, array $tagData = []): bool; + + /** + * Invalidates cached items using tags. + * + * @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id + * + * @return bool True on success + */ + abstract protected function doInvalidate(array $tagIds): bool; + + /** + * {@inheritdoc} + */ + public function commit() + { + $ok = true; + $byLifetime = $this->mergeByLifetime; + $byLifetime = $byLifetime($this->deferred, $expiredIds); + $retry = $this->deferred = []; + + if ($expiredIds) { + // Tags are not cleaned up in this case, however that is done on invalidateTags(). + $this->doDelete($expiredIds); + } + foreach ($byLifetime as $lifetime => $values) { + try { + $values = $this->extractTagData($values, $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + if (\is_array($e) || 1 === \count($values)) { + foreach (\is_array($e) ? $e : array_keys($values) as $id) { + $ok = false; + $v = $values[$id]; + $type = \is_object($v) ? \get_class($v) : \gettype($v); + CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); + } + } else { + foreach ($values as $id => $v) { + $retry[$lifetime][] = $id; + } + } + } + + // When bulk-save failed, retry each item individually + foreach ($retry as $lifetime => $ids) { + foreach ($ids as $id) { + try { + $v = $byLifetime[$lifetime][$id]; + $values = $this->extractTagData([$id => $v], $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + $ok = false; + $type = \is_object($v) ? \get_class($v) : \gettype($v); + CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); + } + } + + return $ok; + } + + /** + * {@inheritdoc} + * + * Overloaded in order to deal with tags for adjusted doDelete() signature. + */ + public function deleteItems(array $keys) + { + if (!$keys) { + return true; + } + + $ids = []; + $tagData = []; + + foreach ($keys as $key) { + $ids[$key] = $this->getId($key); + unset($this->deferred[$key]); + } + + foreach ($this->doFetch($ids) as $id => $value) { + foreach ($value['tags'] ?? [] as $tag) { + $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id; + } + } + + try { + if ($this->doDelete(\array_values($ids), $tagData)) { + return true; + } + } catch (\Exception $e) { + } + + $ok = true; + + // When bulk-delete failed, retry each item individually + foreach ($ids as $key => $id) { + try { + $e = null; + if ($this->doDelete([$id])) { + continue; + } + } catch (\Exception $e) { + } + CacheItem::log($this->logger, 'Failed to delete key "{key}"', ['key' => $key, 'exception' => $e]); + $ok = false; + } + + return $ok; + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) + { + if (empty($tags)) { + return false; + } + + $tagIds = []; + foreach (\array_unique($tags) as $tag) { + $tagIds[] = $this->getId(self::TAGS_PREFIX.$tag); + } + + if ($this->doInvalidate($tagIds)) { + return true; + } + + return false; + } + + /** + * Extracts tags operation data from $values set in mergeByLifetime, and returns values without it. + */ + private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array + { + $addTagData = $removeTagData = []; + foreach ($values as $id => $value) { + foreach ($value['tag-operations']['add'] as $tag => $tagId) { + $addTagData[$tagId][] = $id; + } + + foreach ($value['tag-operations']['remove'] as $tag => $tagId) { + $removeTagData[$tagId][] = $id; + } + + unset($values[$id]['tag-operations']); + } + + return $values; + } +} diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php new file mode 100644 index 0000000000000..f96c670ae92e8 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php @@ -0,0 +1,149 @@ +<?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\Component\Cache\Adapter; + +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\FilesystemTrait; +use Symfony\Component\Filesystem\Filesystem; + +/** + * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @experimental in 4.3 + */ +class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface +{ + use FilesystemTrait { + doSave as doSaveCache; + doDelete as doDeleteCache; + } + + /** + * Folder used for tag symlinks. + */ + private const TAG_FOLDER = 'tags'; + + /** + * @var Filesystem|null + */ + private $fs; + + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) + { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array + { + $failed = $this->doSaveCache($values, $lifetime); + + $fs = $this->getFilesystem(); + // Add Tags as symlinks + foreach ($addTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $file = $this->getFile($id); + $fs->symlink($file, $this->getFile($id, true, $tagFolder)); + } + } + + // Unlink removed Tags + $files = []; + foreach ($removeTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $files[] = $this->getFile($id, false, $tagFolder); + } + } + $fs->remove($files); + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids, array $tagData = []): bool + { + $ok = $this->doDeleteCache($ids); + + // Remove tags + $files = []; + $fs = $this->getFilesystem(); + foreach ($tagData as $tagId => $idMap) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($idMap as $id) { + $files[] = $this->getFile($id, false, $tagFolder); + } + } + $fs->remove($files); + + return $ok; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + foreach ($tagIds as $tagId) { + $tagsFolder = $this->getTagFolder($tagId); + if (!file_exists($tagsFolder)) { + continue; + } + + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS)) as $itemLink) { + if (!$itemLink->isLink()) { + throw new LogicException('Expected a (sym)link when iterating over tag folder, non link found: '.$itemLink); + } + + $valueFile = $itemLink->getRealPath(); + if ($valueFile && \file_exists($valueFile)) { + @unlink($valueFile); + } + + @unlink((string) $itemLink); + } + } + + return true; + } + + private function getFilesystem(): Filesystem + { + return $this->fs ?? $this->fs = new Filesystem(); + } + + private function getTagFolder(string $tagId): string + { + return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR; + } +} diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php new file mode 100644 index 0000000000000..d4ee186789a31 --- /dev/null +++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php @@ -0,0 +1,209 @@ +<?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\Component\Cache\Adapter; + +use Predis; +use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Response\Status; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Traits\RedisTrait; + +/** + * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using sPOP. + * + * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even + * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache + * relationship survives eviction (cache cleanup when Redis runs out of memory). + * + * Requirements: + * - Server: Redis 3.2+ + * - Client: PHP Redis 3.1.3+ OR Predis + * - Redis Server(s) configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory + * + * Design limitations: + * - Max 2 billion cache keys per cache tag + * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 2 billion cache items as well + * + * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies. + * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype. + * @see https://redis.io/commands/spop Documentation for sPOP operation, capable of retriving AND emptying a Set at once. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @experimental in 4.3 + */ +class RedisTagAwareAdapter extends AbstractTagAwareAdapter +{ + use RedisTrait; + + /** + * Redis "Set" can hold more than 4 billion members, here we limit ourselves to PHP's > 2 billion max int (32Bit). + */ + private const POP_MAX_LIMIT = 2147483647 - 1; + + /** + * Limits for how many keys are deleted in batch. + */ + private const BULK_DELETE_LIMIT = 10000; + + /** + * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are + * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements. + */ + private const DEFAULT_CACHE_TTL = 8640000; + + /** + * @var bool|null + */ + private $redisServerSupportSPOP = null; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client + * @param string $namespace The default namespace + * @param int $defaultLifetime The default lifetime + * @param MarshallerInterface|null $marshaller + * + * @throws \Symfony\Component\Cache\Exception\LogicException If phpredis with version lower than 3.1.3. + */ + public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) + { + $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); + + // Make sure php-redis is 3.1.3 or higher configured for Redis classes + if (!$this->redis instanceof Predis\Client && \version_compare(\phpversion('redis'), '3.1.3', '<')) { + throw new LogicException('RedisTagAwareAdapter requires php-redis 3.1.3 or higher, alternatively use predis/predis'); + } + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $delTagData = []): array + { + // serialize values + if (!$serialized = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + // While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op + $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData) { + // Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one + foreach ($serialized as $id => $value) { + yield 'setEx' => [ + $id, + 0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime, + $value, + ]; + } + + // Add and Remove Tags + foreach ($addTagData as $tagId => $ids) { + yield 'sAdd' => array_merge([$tagId], $ids); + } + + foreach ($delTagData as $tagId => $ids) { + yield 'sRem' => array_merge([$tagId], $ids); + } + }); + + foreach ($results as $id => $result) { + // Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not + if (\is_numeric($result)) { + continue; + } + // setEx results + if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) { + $failed[] = $id; + } + } + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids, array $tagData = []): bool + { + if (!$ids) { + return true; + } + + $predisCluster = $this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface; + $this->pipeline(static function () use ($ids, $tagData, $predisCluster) { + if ($predisCluster) { + foreach ($ids as $id) { + yield 'del' => [$id]; + } + } else { + yield 'del' => $ids; + } + + foreach ($tagData as $tagId => $idList) { + yield 'sRem' => \array_merge([$tagId], $idList); + } + })->rewind(); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + if (!$this->redisServerSupportSPOP()) { + return false; + } + + // Pop all tag info at once to avoid race conditions + $tagIdSets = $this->pipeline(static function () use ($tagIds) { + foreach ($tagIds as $tagId) { + // Client: Predis or PHP Redis 3.1.3+ (https://github.com/phpredis/phpredis/commit/d2e203a6) + // Server: Redis 3.2 or higher (https://redis.io/commands/spop) + yield 'sPop' => [$tagId, self::POP_MAX_LIMIT]; + } + }); + + // Flatten generator result from pipeline, ignore keys (tag ids) + $ids = \array_unique(\array_merge(...\iterator_to_array($tagIdSets, false))); + + // Delete cache in chunks to avoid overloading the connection + foreach (\array_chunk($ids, self::BULK_DELETE_LIMIT) as $chunkIds) { + $this->doDelete($chunkIds); + } + + return true; + } + + private function redisServerSupportSPOP(): bool + { + if (null !== $this->redisServerSupportSPOP) { + return $this->redisServerSupportSPOP; + } + + foreach ($this->getHosts() as $host) { + $info = $host->info('Server'); + $info = isset($info['Server']) ? $info['Server'] : $info; + if (version_compare($info['redis_version'], '3.2', '<')) { + CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as {version}', ['version' => $info['redis_version']]); + + return $this->redisServerSupportSPOP = false; + } + } + + return $this->redisServerSupportSPOP = true; + } +} diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php index 1c69e10c942a2..5d7a2369c22e6 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php @@ -68,14 +68,20 @@ public function process(ContainerBuilder $container) if ($pool->isAbstract()) { continue; } + $class = $adapter->getClass(); while ($adapter instanceof ChildDefinition) { $adapter = $container->findDefinition($adapter->getParent()); + $class = $class ?: $adapter->getClass(); if ($t = $adapter->getTag($this->cachePoolTag)) { $tags[0] += $t[0]; } } $name = $tags[0]['name'] ?? $id; if (!isset($tags[0]['namespace'])) { + if (null !== $class) { + $seed .= '.'.$class; + } + $tags[0]['namespace'] = $this->getNamespace($seed, $name); } if (isset($tags[0]['clearer'])) { diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php index eee7948aab0b0..676fba5dca3f7 100644 --- a/src/Symfony/Component/Cache/LockRegistry.php +++ b/src/Symfony/Component/Cache/LockRegistry.php @@ -34,12 +34,14 @@ final class LockRegistry */ private static $files = [ __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php', @@ -48,6 +50,7 @@ final class LockRegistry __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'SimpleCacheAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php', __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php', diff --git a/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php new file mode 100644 index 0000000000000..83a7ea52ddad4 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php @@ -0,0 +1,28 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\FilesystemTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +/** + * @group time-sensitive + */ +class FilesystemTagAwareAdapterTest extends FilesystemAdapterTest +{ + use TagAwareTestTrait; + + public function createCachePool($defaultLifetime = 0) + { + return new FilesystemTagAwareAdapter('', $defaultLifetime); + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php new file mode 100644 index 0000000000000..e321a1c9b8c22 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php @@ -0,0 +1,34 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareAdapterTest extends PredisAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php new file mode 100644 index 0000000000000..a8a72e1de4ea2 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php @@ -0,0 +1,34 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareClusterAdapterTest extends PredisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php new file mode 100644 index 0000000000000..5b82a80ecb324 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php @@ -0,0 +1,34 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareRedisClusterAdapterTest extends PredisRedisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php new file mode 100644 index 0000000000000..95e5fe7e3a9ed --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php @@ -0,0 +1,35 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; +use Symfony\Component\Cache\Traits\RedisProxy; + +class RedisTagAwareAdapterTest extends RedisAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisProxy::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php new file mode 100644 index 0000000000000..5855cc3adfc6c --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php @@ -0,0 +1,34 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class RedisTagAwareArrayAdapterTest extends RedisArrayAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\RedisArray::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php new file mode 100644 index 0000000000000..ef17c1d69e814 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php @@ -0,0 +1,35 @@ +<?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\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; +use Symfony\Component\Cache\Traits\RedisClusterProxy; + +class RedisTagAwareClusterAdapterTest extends RedisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php index 7b8895b70019c..a339790862432 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php @@ -14,13 +14,15 @@ use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\TagAwareAdapter; -use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; /** * @group time-sensitive */ class TagAwareAdapterTest extends AdapterTestCase { + use TagAwareTestTrait; + public function createCachePool($defaultLifetime = 0) { return new TagAwareAdapter(new FilesystemAdapter('', $defaultLifetime)); @@ -32,53 +34,9 @@ public static function tearDownAfterClass() } /** - * @expectedException \Psr\Cache\InvalidArgumentException + * Test feature specific to TagAwareAdapter as it implicit needs to save deferred when also saving expiry info. */ - public function testInvalidTag() - { - $pool = $this->createCachePool(); - $item = $pool->getItem('foo'); - $item->tag(':'); - } - - public function testInvalidateTags() - { - $pool = $this->createCachePool(); - - $i0 = $pool->getItem('i0'); - $i1 = $pool->getItem('i1'); - $i2 = $pool->getItem('i2'); - $i3 = $pool->getItem('i3'); - $foo = $pool->getItem('foo'); - - $pool->save($i0->tag('bar')); - $pool->save($i1->tag('foo')); - $pool->save($i2->tag('foo')->tag('bar')); - $pool->save($i3->tag('foo')->tag('baz')); - $pool->save($foo); - - $pool->invalidateTags(['bar']); - - $this->assertFalse($pool->getItem('i0')->isHit()); - $this->assertTrue($pool->getItem('i1')->isHit()); - $this->assertFalse($pool->getItem('i2')->isHit()); - $this->assertTrue($pool->getItem('i3')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - $pool->invalidateTags(['foo']); - - $this->assertFalse($pool->getItem('i1')->isHit()); - $this->assertFalse($pool->getItem('i3')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - $anotherPoolInstance = $this->createCachePool(); - - $this->assertFalse($anotherPoolInstance->getItem('i1')->isHit()); - $this->assertFalse($anotherPoolInstance->getItem('i3')->isHit()); - $this->assertTrue($anotherPoolInstance->getItem('foo')->isHit()); - } - - public function testInvalidateCommits() + public function testInvalidateCommitsSeperatePools() { $pool1 = $this->createCachePool(); @@ -94,76 +52,6 @@ public function testInvalidateCommits() $this->assertTrue($foo->isHit()); } - public function testTagsAreCleanedOnSave() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $pool->save($i->tag('bar')); - - $pool->invalidateTags(['foo']); - $this->assertTrue($pool->getItem('k')->isHit()); - } - - public function testTagsAreCleanedOnDelete() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - $pool->deleteItem('k'); - - $pool->save($pool->getItem('k')); - $pool->invalidateTags(['foo']); - - $this->assertTrue($pool->getItem('k')->isHit()); - } - - public function testTagItemExpiry() - { - $pool = $this->createCachePool(10); - - $item = $pool->getItem('foo'); - $item->tag(['baz']); - $item->expiresAfter(100); - - $pool->save($item); - $pool->invalidateTags(['baz']); - $this->assertFalse($pool->getItem('foo')->isHit()); - - sleep(20); - - $this->assertFalse($pool->getItem('foo')->isHit()); - } - - /** - * @group legacy - */ - public function testGetPreviousTags() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $this->assertSame(['foo' => 'foo'], $i->getPreviousTags()); - } - - public function testGetMetadata() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $this->assertSame(['foo' => 'foo'], $i->getMetadata()[CacheItem::METADATA_TAGS]); - } - public function testPrune() { $cache = new TagAwareAdapter($this->getPruneableMock()); diff --git a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php index f307aa5386b0c..4681b3dc8197a 100644 --- a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php +++ b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DependencyInjection\CachePoolPass; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -48,6 +49,27 @@ public function testNamespaceArgumentIsReplaced() $this->assertSame('z3X945Jbf5', $cachePool->getArgument(0)); } + public function testNamespaceArgumentIsSeededWithAdapterClassName() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + $adapter = new Definition(); + $adapter->setAbstract(true); + $adapter->addTag('cache.pool'); + $adapter->setClass(RedisAdapter::class); + $container->setDefinition('app.cache_adapter', $adapter); + $container->setAlias('app.cache_adapter_alias', 'app.cache_adapter'); + $cachePool = new ChildDefinition('app.cache_adapter_alias'); + $cachePool->addArgument(null); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertSame('xmOJ8gqF-Y', $cachePool->getArgument(0)); + } + public function testNamespaceArgumentIsNotReplacedIfArrayAdapterIsUsed() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/Cache/Tests/Traits/TagAwareTestTrait.php b/src/Symfony/Component/Cache/Tests/Traits/TagAwareTestTrait.php new file mode 100644 index 0000000000000..38cc4dc9cc990 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Traits/TagAwareTestTrait.php @@ -0,0 +1,160 @@ +<?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\Component\Cache\Tests\Traits; + +use Symfony\Component\Cache\CacheItem; + +/** + * Common assertions for TagAware adapters. + * + * @method \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface createCachePool() Must be implemented by TestCase + */ +trait TagAwareTestTrait +{ + /** + * @expectedException \Psr\Cache\InvalidArgumentException + */ + public function testInvalidTag() + { + $pool = $this->createCachePool(); + $item = $pool->getItem('foo'); + $item->tag(':'); + } + + public function testInvalidateTags() + { + $pool = $this->createCachePool(); + + $i0 = $pool->getItem('i0'); + $i1 = $pool->getItem('i1'); + $i2 = $pool->getItem('i2'); + $i3 = $pool->getItem('i3'); + $foo = $pool->getItem('foo'); + + $pool->save($i0->tag('bar')); + $pool->save($i1->tag('foo')); + $pool->save($i2->tag('foo')->tag('bar')); + $pool->save($i3->tag('foo')->tag('baz')); + $pool->save($foo); + + $pool->invalidateTags(['bar']); + + $this->assertFalse($pool->getItem('i0')->isHit()); + $this->assertTrue($pool->getItem('i1')->isHit()); + $this->assertFalse($pool->getItem('i2')->isHit()); + $this->assertTrue($pool->getItem('i3')->isHit()); + $this->assertTrue($pool->getItem('foo')->isHit()); + + $pool->invalidateTags(['foo']); + + $this->assertFalse($pool->getItem('i1')->isHit()); + $this->assertFalse($pool->getItem('i3')->isHit()); + $this->assertTrue($pool->getItem('foo')->isHit()); + + $anotherPoolInstance = $this->createCachePool(); + + $this->assertFalse($anotherPoolInstance->getItem('i1')->isHit()); + $this->assertFalse($anotherPoolInstance->getItem('i3')->isHit()); + $this->assertTrue($anotherPoolInstance->getItem('foo')->isHit()); + } + + public function testInvalidateCommits() + { + $pool = $this->createCachePool(); + + $foo = $pool->getItem('foo'); + $foo->tag('tag'); + + $pool->saveDeferred($foo->set('foo')); + $pool->invalidateTags(['tag']); + + // ??: This seems to contradict a bit logic in deleteItems, where it does unset($this->deferred[$key]); on key matches + + $foo = $pool->getItem('foo'); + + $this->assertTrue($foo->isHit()); + } + + public function testTagsAreCleanedOnSave() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $pool->save($i->tag('bar')); + + $pool->invalidateTags(['foo']); + $this->assertTrue($pool->getItem('k')->isHit()); + } + + public function testTagsAreCleanedOnDelete() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + $pool->deleteItem('k'); + + $pool->save($pool->getItem('k')); + $pool->invalidateTags(['foo']); + + $this->assertTrue($pool->getItem('k')->isHit()); + } + + public function testTagItemExpiry() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $pool = $this->createCachePool(10); + + $item = $pool->getItem('foo'); + $item->tag(['baz']); + $item->expiresAfter(100); + + $pool->save($item); + $pool->invalidateTags(['baz']); + $this->assertFalse($pool->getItem('foo')->isHit()); + + sleep(20); + + $this->assertFalse($pool->getItem('foo')->isHit()); + } + + /** + * @group legacy + */ + public function testGetPreviousTags() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $this->assertSame(['foo' => 'foo'], $i->getPreviousTags()); + } + + public function testGetMetadata() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $this->assertSame(['foo' => 'foo'], $i->getMetadata()[CacheItem::METADATA_TAGS]); + } +} diff --git a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php new file mode 100644 index 0000000000000..f1d97abf2d2f8 --- /dev/null +++ b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php @@ -0,0 +1,139 @@ +<?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\Component\Cache\Traits; + +use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +trait AbstractAdapterTrait +{ + use AbstractTrait; + + /** + * @var \Closure needs to be set by class, signature is function(string <key>, mixed <value>, bool <isHit>) + */ + private $createCacheItem; + + /** + * @var \Closure needs to be set by class, signature is function(array <deferred>, string <namespace>, array <&expiredIds>) + */ + private $mergeByLifetime; + + /** + * {@inheritdoc} + */ + public function getItem($key) + { + if ($this->deferred) { + $this->commit(); + } + $id = $this->getId($key); + + $f = $this->createCacheItem; + $isHit = false; + $value = null; + + try { + foreach ($this->doFetch([$id]) as $value) { + $isHit = true; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); + } + + return $f($key, $value, $isHit); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []) + { + if ($this->deferred) { + $this->commit(); + } + $ids = []; + + foreach ($keys as $key) { + $ids[] = $this->getId($key); + } + try { + $items = $this->doFetch($ids); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]); + $items = []; + } + $ids = array_combine($ids, $keys); + + return $this->generateItems($items, $ids); + } + + /** + * {@inheritdoc} + */ + public function save(CacheItemInterface $item) + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return $this->commit(); + } + + /** + * {@inheritdoc} + */ + public function saveDeferred(CacheItemInterface $item) + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return true; + } + + public function __destruct() + { + if ($this->deferred) { + $this->commit(); + } + } + + private function generateItems($items, &$keys) + { + $f = $this->createCacheItem; + + try { + foreach ($items as $id => $value) { + if (!isset($keys[$id])) { + $id = key($keys); + } + $key = $keys[$id]; + unset($keys[$id]); + yield $key => $f($key, $value, true); + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]); + } + + foreach ($keys as $key) { + yield $key => $f($key, null, false); + } + } +} diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php index 3f684acd685d3..37e1fd1f06b3c 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php @@ -101,11 +101,11 @@ private function write($file, $data, $expiresAt = null) } } - private function getFile($id, $mkdir = false) + private function getFile($id, $mkdir = false, string $directory = null) { // Use MD5 to favor speed over security, which is not an issue here $hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true))); - $dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); + $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); if ($mkdir && !file_exists($dir)) { @mkdir($dir, 0777, true); diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 0b79a7d1adb30..b2faca651d0d6 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -321,33 +321,13 @@ protected function doHave($id) protected function doClear($namespace) { $cleared = true; - $hosts = [$this->redis]; - $evalArgs = [[$namespace], 0]; - if ($this->redis instanceof \Predis\Client) { $evalArgs = [0, $namespace]; - - $connection = $this->redis->getConnection(); - if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { - $hosts = []; - foreach ($connection as $c) { - $hosts[] = new \Predis\Client($c); - } - } - } elseif ($this->redis instanceof \RedisArray) { - $hosts = []; - foreach ($this->redis->_hosts() as $host) { - $hosts[] = $this->redis->_instance($host); - } - } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { - $hosts = []; - foreach ($this->redis->_masters() as $host) { - $hosts[] = $h = new \Redis(); - $h->connect($host[0], $host[1]); - } + } else { + $evalArgs = [[$namespace], 0]; } - foreach ($hosts as $host) { + foreach ($this->getHosts() as $host) { if (!isset($namespace[0])) { $cleared = $host->flushDb() && $cleared; continue; @@ -479,4 +459,31 @@ private function pipeline(\Closure $generator) yield $id => $results[$k]; } } + + private function getHosts(): array + { + $hosts = [$this->redis]; + if ($this->redis instanceof \Predis\Client) { + $connection = $this->redis->getConnection(); + if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { + $hosts = []; + foreach ($connection as $c) { + $hosts[] = new \Predis\Client($c); + } + } + } elseif ($this->redis instanceof \RedisArray) { + $hosts = []; + foreach ($this->redis->_hosts() as $host) { + $hosts[] = $this->redis->_instance($host); + } + } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { + $hosts = []; + foreach ($this->redis->_masters() as $host) { + $hosts[] = $h = new \Redis(); + $h->connect($host[0], $host[1]); + } + } + + return $hosts; + } } diff --git a/src/Symfony/Component/Cache/phpunit.xml.dist b/src/Symfony/Component/Cache/phpunit.xml.dist index c35458ca44716..591046cf1c41c 100644 --- a/src/Symfony/Component/Cache/phpunit.xml.dist +++ b/src/Symfony/Component/Cache/phpunit.xml.dist @@ -40,7 +40,8 @@ <element key="1"><string>Doctrine\Common\Cache</string></element> <element key="2"><string>Symfony\Component\Cache</string></element> <element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element> - <element key="4"><string>Symfony\Component\Cache\Traits</string></element> + <element key="4"><string>Symfony\Component\Cache\Tests\Traits</string></element> + <element key="5"><string>Symfony\Component\Cache\Traits</string></element> </array> </element> </array> From 1e9a9b2c064cca80d8da4abb7ed1319f2b44848b Mon Sep 17 00:00:00 2001 From: Robin Chalas <robin.chalas@elao.com> Date: Thu, 25 Apr 2019 15:37:39 +0200 Subject: [PATCH 492/495] [FrameworkBundle] Drop unused private method --- .../Command/ConsumeMessagesCommand.php | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index b5a617577969f..4ad5dfb278aef 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -249,21 +249,4 @@ private function convertToBytes(string $memoryLimit): int return $max; } - - private function findAlternatives($name, array $collection) - { - $alternatives = []; - foreach ($collection as $item) { - $lev = levenshtein($name, $item); - if ($lev <= \strlen($name) / 3 || false !== strpos($item, $name)) { - $alternatives[$item] = isset($alternatives[$item]) ? $alternatives[$item] - $lev : $lev; - } - } - - $threshold = 1e3; - $alternatives = array_filter($alternatives, function ($lev) use ($threshold) { return $lev < 2 * $threshold; }); - ksort($alternatives, SORT_NATURAL | SORT_FLAG_CASE); - - return array_keys($alternatives); - } } From 95f09fd80233110fe17ad51b8491a844819a1278 Mon Sep 17 00:00:00 2001 From: Roland Franssen <franssen.roland@gmail.com> Date: Sat, 27 Apr 2019 10:07:48 +0200 Subject: [PATCH 493/495] [Intl] Add tests --- .../Component/Intl/Tests/CurrenciesTest.php | 14 ++++++++++++++ src/Symfony/Component/Intl/Tests/LanguagesTest.php | 14 ++++++++++++++ src/Symfony/Component/Intl/Tests/LocalesTest.php | 14 ++++++++++++++ src/Symfony/Component/Intl/Tests/RegionsTest.php | 14 ++++++++++++++ src/Symfony/Component/Intl/Tests/ScriptsTest.php | 14 ++++++++++++++ src/Symfony/Component/Intl/Tests/TimezonesTest.php | 14 ++++++++++++++ 6 files changed, 84 insertions(+) diff --git a/src/Symfony/Component/Intl/Tests/CurrenciesTest.php b/src/Symfony/Component/Intl/Tests/CurrenciesTest.php index 1f1a4e567b7a8..dff4c157cda81 100644 --- a/src/Symfony/Component/Intl/Tests/CurrenciesTest.php +++ b/src/Symfony/Component/Intl/Tests/CurrenciesTest.php @@ -772,6 +772,20 @@ public function testForNumericCodeFailsIfInvalidNumericCode($currency) Currencies::forNumericCode($currency); } + /** + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNameWithInvalidCurrencyCode() + { + Currencies::getName('foo'); + } + + public function testExists() + { + $this->assertTrue(Currencies::exists('EUR')); + $this->assertFalse(Currencies::exists('XXX')); + } + private function getNumericToAlpha3Mapping() { $numericToAlpha3 = []; diff --git a/src/Symfony/Component/Intl/Tests/LanguagesTest.php b/src/Symfony/Component/Intl/Tests/LanguagesTest.php index 6fa059b29445a..74610076ceee9 100644 --- a/src/Symfony/Component/Intl/Tests/LanguagesTest.php +++ b/src/Symfony/Component/Intl/Tests/LanguagesTest.php @@ -915,4 +915,18 @@ public function testGetAlpha3CodeFailsIfNoAlpha3Equivalent($language) { Languages::getAlpha3Code($language); } + + /** + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNameWithInvalidLanguageCode() + { + Languages::getName('foo'); + } + + public function testExists() + { + $this->assertTrue(Languages::exists('nl')); + $this->assertFalse(Languages::exists('zxx')); + } } diff --git a/src/Symfony/Component/Intl/Tests/LocalesTest.php b/src/Symfony/Component/Intl/Tests/LocalesTest.php index e7ffbd2ca9a42..18bd2d9ccf8c6 100644 --- a/src/Symfony/Component/Intl/Tests/LocalesTest.php +++ b/src/Symfony/Component/Intl/Tests/LocalesTest.php @@ -84,4 +84,18 @@ public function testGetNameDefaultLocale() $this->assertSame($name, Locales::getName($locale)); } } + + /** + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNameWithInvalidLocale() + { + Locales::getName('foo'); + } + + public function testExists() + { + $this->assertTrue(Locales::exists('nl_NL')); + $this->assertFalse(Locales::exists('zxx_ZZ')); + } } diff --git a/src/Symfony/Component/Intl/Tests/RegionsTest.php b/src/Symfony/Component/Intl/Tests/RegionsTest.php index 80d4ca98bf638..a00245a5f5947 100644 --- a/src/Symfony/Component/Intl/Tests/RegionsTest.php +++ b/src/Symfony/Component/Intl/Tests/RegionsTest.php @@ -343,4 +343,18 @@ public function testLocaleAliasesAreLoaded() $this->assertSame($countryNameZhTw, $countryNameHantZhTw, 'zh_TW is an alias to zh_Hant_TW'); $this->assertNotSame($countryNameZh, $countryNameZhTw, 'zh_TW does not fall back to zh'); } + + /** + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNameWithInvalidRegionCode() + { + Regions::getName('foo'); + } + + public function testExists() + { + $this->assertTrue(Regions::exists('NL')); + $this->assertFalse(Regions::exists('ZZ')); + } } diff --git a/src/Symfony/Component/Intl/Tests/ScriptsTest.php b/src/Symfony/Component/Intl/Tests/ScriptsTest.php index 5b404fda85aaa..71ca1a0031374 100644 --- a/src/Symfony/Component/Intl/Tests/ScriptsTest.php +++ b/src/Symfony/Component/Intl/Tests/ScriptsTest.php @@ -274,4 +274,18 @@ public function testGetNameDefaultLocale() $this->assertSame($name, Scripts::getName($script)); } } + + /** + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNameWithInvalidScriptCode() + { + Scripts::getName('foo'); + } + + public function testExists() + { + $this->assertTrue(Scripts::exists('Hans')); + $this->assertTrue(Scripts::exists('Zzzz')); + } } diff --git a/src/Symfony/Component/Intl/Tests/TimezonesTest.php b/src/Symfony/Component/Intl/Tests/TimezonesTest.php index 021364b777a81..dd0c7e00f3466 100644 --- a/src/Symfony/Component/Intl/Tests/TimezonesTest.php +++ b/src/Symfony/Component/Intl/Tests/TimezonesTest.php @@ -515,4 +515,18 @@ public function testGetNameDefaultLocale() $this->assertSame($name, Timezones::getName($language)); } } + + /** + * @expectedException \Symfony\Component\Intl\Exception\MissingResourceException + */ + public function testGetNameWithInvalidTimezoneId() + { + Timezones::getName('foo'); + } + + public function testExists() + { + $this->assertTrue(Timezones::exists('Europe/Amsterdam')); + $this->assertFalse(Timezones::exists('Etc/Unknown')); + } } From c5b3b34b51a07e361d0eb3cf44fa8a2e01224329 Mon Sep 17 00:00:00 2001 From: Robin Chalas <robin.chalas@elao.com> Date: Thu, 25 Apr 2019 20:51:40 +0200 Subject: [PATCH 494/495] [EventDispatcher] Fix TraceableEventDispatcher FC/BC layer --- .../Debug/TraceableEventDispatcher.php | 5 +++-- .../EventDispatcher/Debug/WrappedListener.php | 6 +++--- .../Component/EventDispatcher/EventDispatcher.php | 6 ++++-- .../{WrappedEvent.php => LegacyEventProxy.php} | 9 +++++++-- .../Tests/Debug/TraceableEventDispatcherTest.php | 14 ++++++++++++++ 5 files changed, 31 insertions(+), 9 deletions(-) rename src/Symfony/Component/EventDispatcher/{WrappedEvent.php => LegacyEventProxy.php} (86%) diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php index e5b79276c62c9..7716d8663177e 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php @@ -18,6 +18,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\EventDispatcher\LegacyEventProxy; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; @@ -295,7 +296,7 @@ public function __call($method, $arguments) */ protected function beforeDispatch(string $eventName, $event) { - $this->preDispatch($eventName, $event); + $this->preDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event)); } /** @@ -305,7 +306,7 @@ protected function beforeDispatch(string $eventName, $event) */ protected function afterDispatch(string $eventName, $event) { - $this->postDispatch($eventName, $event); + $this->postDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event)); } /** diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index d5c137b94b2ad..34316b54c3429 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -14,7 +14,7 @@ use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\EventDispatcher\WrappedEvent; +use Symfony\Component\EventDispatcher\LegacyEventProxy; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Caster\ClassStub; use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; @@ -112,8 +112,8 @@ public function getInfo($eventName) public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) { - if ($event instanceof WrappedEvent) { - $event = $event->getWrappedEvent(); + if ($event instanceof LegacyEventProxy) { + $event = $event->getEvent(); } $dispatcher = $this->dispatcher ?: $dispatcher; diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index 60283882a8848..e68918c31c680 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -12,6 +12,7 @@ namespace Symfony\Component\EventDispatcher; use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Component\EventDispatcher\Debug\WrappedListener; use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** @@ -242,7 +243,8 @@ protected function callListeners(iterable $listeners, string $eventName, $event) if ($stoppable && $event->isPropagationStopped()) { break; } - $listener($event instanceof Event ? $event : new WrappedEvent($event), $eventName, $this); + // @deprecated: the ternary operator is part of a BC layer and should be removed in 5.0 + $listener($listener instanceof WrappedListener ? new LegacyEventProxy($event) : $event, $eventName, $this); } } @@ -296,7 +298,7 @@ private function optimizeListeners(string $eventName): array ($closure = \Closure::fromCallable($listener))(...$args); }; } else { - $closure = $listener instanceof \Closure ? $listener : \Closure::fromCallable($listener); + $closure = $listener instanceof \Closure || $listener instanceof WrappedListener ? $listener : \Closure::fromCallable($listener); } } } diff --git a/src/Symfony/Component/EventDispatcher/WrappedEvent.php b/src/Symfony/Component/EventDispatcher/LegacyEventProxy.php similarity index 86% rename from src/Symfony/Component/EventDispatcher/WrappedEvent.php rename to src/Symfony/Component/EventDispatcher/LegacyEventProxy.php index 705d1aeda1596..cad8cfaedb724 100644 --- a/src/Symfony/Component/EventDispatcher/WrappedEvent.php +++ b/src/Symfony/Component/EventDispatcher/LegacyEventProxy.php @@ -17,7 +17,7 @@ /** * @internal to be removed in 5.0. */ -final class WrappedEvent extends Event +final class LegacyEventProxy extends Event { private $event; @@ -32,7 +32,7 @@ public function __construct($event) /** * @return object $event */ - public function getWrappedEvent() + public function getEvent() { return $this->event; } @@ -54,4 +54,9 @@ public function stopPropagation() $this->event->stopPropagation(); } + + public function __call($name, $args) + { + return $this->event->{$name}(...$args); + } } diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php index 8fd0305b0e423..ea476eee04c8e 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -18,6 +18,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; class TraceableEventDispatcherTest extends TestCase { @@ -139,6 +140,19 @@ public function testClearCalledListeners() $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); } + public function testDispatchContractsEvent() + { + $expectedEvent = new ContractsEvent(); + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $tdispatcher->addListener('foo', function ($event) use ($expectedEvent) { + $this->assertSame($event, $expectedEvent); + }, 5); + $tdispatcher->dispatch($expectedEvent, 'foo'); + + $listeners = $tdispatcher->getCalledListeners(); + $this->assertArrayHasKey('stub', $listeners[0]); + } + public function testDispatchAfterReset() { $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); From 9c76b29d14181293cf27abb62fa1217fb8a67a87 Mon Sep 17 00:00:00 2001 From: Angel Fernando Quiroz Campos <angelfqc.18@gmail.com> Date: Tue, 23 Apr 2019 23:38:29 -0500 Subject: [PATCH 495/495] [TwigBridge] bootstrap4 file_widget: allow setting label attributes declared in label_attr --- .../Twig/Resources/views/Form/bootstrap_4_layout.html.twig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig index 03109bdf6cac2..1848d0dc9838c 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig @@ -122,7 +122,8 @@ <{{ element|default('div') }} class="custom-file"> {%- set type = type|default('file') -%} {{- block('form_widget_simple') -}} - <label for="{{ form.vars.id }}" class="custom-file-label"> + {%- set label_attr = label_attr|merge({ class: (label_attr.class|default('') ~ ' custom-file-label')|trim }) -%} + <label for="{{ form.vars.id }}" {% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}> {%- if attr.placeholder is defined -%} {{- translation_domain is same as(false) ? attr.placeholder : attr.placeholder|trans({}, translation_domain) -}} {%- endif -%}