diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000000..5274d5cf1fb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +CHANGELOG for 1.0.0-alpha3 +=================== + +This changelog references the relevant changes (new features, changes and bugs) done in 1.0.0-alpha3 versions. + +* 1.0.0-alpha3 (2013-06-27) + * Placeholders + * Developer toolbar works with AJAX navigation requests + * Configuring hidden columns in a Grid + * Auto-complete form type + * Added Address Book + * Localized countries and regions + * Enhanced data change log with ability to save changes for collections + * Removed dependency on lib ICU + diff --git a/UPGRADE.md b/UPGRADE.md new file mode 100644 index 00000000000..cdcd65fff46 --- /dev/null +++ b/UPGRADE.md @@ -0,0 +1,7 @@ +UPGRADE FROM 1.0.0-alpha2 to 1.0.0-alpha3 +======================= + +### General + + * Upgrade to 1.0.0-alpha3 is not supported and full reinstall is required + \ No newline at end of file diff --git a/composer.json b/composer.json index 2c3461e3867..b83fac5019f 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,8 @@ "jms/serializer": "0.12.*@dev", "jms/serializer-bundle": "0.12.*@dev", "kriswallsmith/assetic": "1.1.*@dev", - "knplabs/knp-menu": "dev-master", - "knplabs/knp-menu-bundle": "dev-master", + "knplabs/knp-menu": "v2.0.0-alpha1", + "knplabs/knp-menu-bundle": "v2.0.0-alpha1", "knplabs/knp-paginator-bundle": "dev-master", "friendsofsymfony/rest-bundle": "0.11.*", "friendsofsymfony/jsrouting-bundle": "1.1.*@dev", @@ -39,10 +39,9 @@ "sonata-project/doctrine-orm-admin-bundle": "2.1.x-dev", "liip/imagine-bundle": "dev-master", "leafo/lessphp": "dev-master", - "symfony/icu": "1.2.*@dev", - "symfony/intl": "2.3.*@dev", "willdurand/expose-translation-bundle": "0.2.*@dev", - "apy/jsfv-bundle": "dev-master#a27847b4e0e52212277c4759826328b3cfaa15dc" + "apy/jsfv-bundle": "dev-master#a27847b4e0e52212277c4759826328b3cfaa15dc", + "genemu/form-bundle": "2.1.*" }, "repositories": [ { diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1b7745c7854..2f9ce8dca63 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,26 +11,10 @@ processIsolation = "false" stopOnFailure = "false" syntaxCheck = "false" - bootstrap = "vendor/autoload.php"> - + bootstrap = "tests/bootstrap.php"> - src/Oro/Bundle/AddressBundle/Tests/Unit - src/Oro/Bundle/ConfigBundle/Tests/Unit - src/Oro/Bundle/DataAuditBundle/Tests/Unit - - src/Oro/Bundle/FilterBundle/Tests/Unit - - src/Oro/Bundle/GridBundle/Tests/Unit - src/Oro/Bundle/MeasureBundle/Tests/Unit - src/Oro/Bundle/NavigationBundle/Tests/Unit - src/Oro/Bundle/SearchBundle/Tests/Unit - src/Oro/Bundle/SegmentationTreeBundle/Tests/Unit - src/Oro/Bundle/SoapBundle/Tests/Unit - src/Oro/Bundle/TestFrameworkBundle/Tests/Unit - src/Oro/Bundle/UIBundle/Tests/Unit - src/Oro/Bundle/UserBundle/Tests/Unit - src/Oro/Bundle/WindowsBundle/Tests/Unit + src/*/Bundle/*Bundle/Tests/Unit diff --git a/src/Oro/Bundle/AddressBundle/Controller/Api/Rest/CountryRegionsController.php b/src/Oro/Bundle/AddressBundle/Controller/Api/Rest/CountryRegionsController.php index b22436c880b..4568b8d1667 100644 --- a/src/Oro/Bundle/AddressBundle/Controller/Api/Rest/CountryRegionsController.php +++ b/src/Oro/Bundle/AddressBundle/Controller/Api/Rest/CountryRegionsController.php @@ -2,12 +2,16 @@ namespace Oro\Bundle\AddressBundle\Controller\Api\Rest; +use Symfony\Component\HttpFoundation\Response; +use Doctrine\ORM\Query; use FOS\Rest\Util\Codes; use FOS\RestBundle\Controller\FOSRestController; use FOS\RestBundle\Controller\Annotations\NamePrefix; use FOS\RestBundle\Controller\Annotations\RouteResource; use Nelmio\ApiDocBundle\Annotation\ApiDoc; -use Symfony\Component\HttpFoundation\Response; + +use Oro\Bundle\AddressBundle\Entity\Country; +use Oro\Bundle\AddressBundle\Entity\Repository\RegionRepository; /** * @RouteResource("country/regions") @@ -18,7 +22,7 @@ class CountryRegionsController extends FOSRestController /** * REST GET regions by country * - * @param string $id + * @param Country $country * * @ApiDoc( * description="Get regions by country id", @@ -26,13 +30,20 @@ class CountryRegionsController extends FOSRestController * ) * @return Response */ - public function getAction($id) + public function getAction(Country $country = null) { - /** @var $item \Oro\Bundle\AddressBundle\Entity\Country */ - $item = $this->getDoctrine()->getRepository('OroAddressBundle:Country')->find($id); + if (!$country) { + return $this->handleView( + $this->view(null, Codes::HTTP_NOT_FOUND) + ); + } + + /** @var $regionRepository RegionRepository */ + $regionRepository = $this->getDoctrine()->getRepository('OroAddressBundle:Region'); + $regions = $regionRepository->getCountryRegions($country); return $this->handleView( - $this->view($item ? $item->getRegions() : null, $item ? Codes::HTTP_OK : Codes::HTTP_NOT_FOUND) + $this->view($regions, Codes::HTTP_OK) ); } } diff --git a/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadCountryData.php b/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadCountryData.php new file mode 100644 index 00000000000..0db0233b45a --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadCountryData.php @@ -0,0 +1,231 @@ +translator = $this->container->get('translator'); + + $fileName = $this->getFileName(); + $countries = $this->getDataFromFile($fileName); + $this->saveCountryData($manager, $countries); + } + + public function setContainer(ContainerInterface $container = null) + { + $this->container = $container; + } + + /** + * @return string + */ + protected function getFileName() + { + return __DIR__ . '/../data/countries.yml'; + } + + /** + * @param string $fileName + * @return bool + */ + protected function isFileAvailable($fileName) + { + return is_file($fileName) && is_readable($fileName); + } + + /** + * @param string $fileName + * @return array + * @throws \LogicException + */ + protected function getDataFromFile($fileName) + { + if (!$this->isFileAvailable($fileName)) { + throw new \LogicException('File ' . $fileName . 'is not available'); + } + + $fileName = realpath($fileName); + + return Yaml::parse($fileName); + } + + /** + * @return array + */ + protected function getAvailableCountryLocales() + { + $translationDirectory = str_replace('/', DIRECTORY_SEPARATOR, $this->translationDirectory); + $translationDirectories = array(); + + foreach ($this->container->getParameter('kernel.bundles') as $bundle) { + $reflection = new \ReflectionClass($bundle); + $bundleTranslationDirectory = dirname($reflection->getFilename()) . $translationDirectory; + if (is_dir($bundleTranslationDirectory) && is_readable($bundleTranslationDirectory)) { + $translationDirectories[] = realpath($bundleTranslationDirectory); + } + } + + $finder = new Finder(); + $finder->in($translationDirectories)->name(self::COUNTRY_FILE_REGEXP); + + $countryLocales = array(); + /** @var $file \SplFileInfo */ + foreach ($finder as $file) { + preg_match(self::COUNTRY_FILE_REGEXP, $file->getFilename(), $matches); + if ($matches) { + $countryLocales[] = $matches[1]; + } + } + + return $countryLocales; + } + + /** + * @param string $locale + * @param array $countryData + * @return null|Country + */ + protected function getCountry($locale, array $countryData) + { + if (empty($countryData['iso2Code']) || empty($countryData['iso3Code'])) { + return null; + } + + /** @var $country Country */ + $country = $this->countryRepository->findOneBy(array('iso2Code' => $countryData['iso2Code'])); + if (!$country) { + $country = new Country($countryData['iso2Code']); + $country->setIso3Code($countryData['iso3Code']); + } + + $countryName = $this->translator->trans( + $countryData['iso2Code'], + array(), + self::COUNTRY_DOMAIN, + $locale + ); + + $country->setLocale($locale) + ->setName($countryName); + + return $country; + } + + /** + * @param string $locale + * @param Country $country + * @param array $regionData + * @return null|Region + */ + protected function getRegion($locale, Country $country, array $regionData) + { + if (empty($regionData['combinedCode']) || empty($regionData['code'])) { + return null; + } + + /** @var $region Region */ + $region = $this->regionRepository->findOneBy(array('combinedCode' => $regionData['combinedCode'])); + if (!$region) { + $region = new Region($regionData['combinedCode']); + $region->setCode($regionData['code']) + ->setCountry($country); + } + + $regionName = $this->translator->trans( + $regionData['combinedCode'], + array(), + self::COUNTRY_DOMAIN, + $locale + ); + + $region->setLocale($locale) + ->setName($regionName); + + return $region; + } + + /** + * Save countries and regions to DB + * + * @param ObjectManager $manager + * @param array $countries + */ + protected function saveCountryData(ObjectManager $manager, array $countries) + { + $this->countryRepository = $manager->getRepository('OroAddressBundle:Country'); + $this->regionRepository = $manager->getRepository('OroAddressBundle:Region'); + + $countryLocales = $this->getAvailableCountryLocales(); + + foreach ($countryLocales as $locale) { + foreach ($countries as $countryData) { + $country = $this->getCountry($locale, $countryData); + if (!$country) { + continue; + } + + $manager->persist($country); + + if (!empty($countryData['regions'])) { + foreach ($countryData['regions'] as $regionData) { + $region = $this->getRegion($locale, $country, $regionData); + if (!$region) { + continue; + } + + $manager->persist($region); + } + } + } + + $manager->flush(); + $manager->clear(); + } + } +} diff --git a/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadCountryDictsData.php b/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadCountryDictsData.php deleted file mode 100644 index 9749855e9be..00000000000 --- a/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadCountryDictsData.php +++ /dev/null @@ -1,58 +0,0 @@ -container = $container; - } - - /** - * Load address types - * - * @param \Doctrine\Common\Persistence\ObjectManager $manager - */ - public function load(ObjectManager $manager) - { - /* sample for manual input - $importManager = $this->container->get('oro_address.dict.import.manager'); - $data = array( - new Country('Ukraine', 'UA', 'UKR'), - new Country('United States of America', 'US', 'USA'), - new Country('Russian Federation', 'RU', 'RUS'), - ); - $importManager->sync($data); - */ - - /** - * @var $importManager Manager - */ - $importManager = $this->container->get('oro_address.dict.import.intl.manager'); - $importManager->sync(); - } - - /** - * Get the order of this fixture - * - * @return integer - */ - public function getOrder() - { - return 10; - } -} diff --git a/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadRegionData.php b/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadRegionData.php deleted file mode 100644 index 4cad9eaaeb7..00000000000 --- a/src/Oro/Bundle/AddressBundle/DataFixtures/ORM/LoadRegionData.php +++ /dev/null @@ -1,40 +0,0 @@ -getRepository('OroAddressBundle:Country')->find('US'); - - $region = new Region(); - $region->setCode('AL') - ->setCountry($country) - ->setName('Alabama'); - $manager->persist($region); - $manager->flush(); - } - - /** - * Get the order of this fixture - * - * @return integer - */ - public function getOrder() - { - return 20; - } -} diff --git a/src/Oro/Bundle/AddressBundle/DataFixtures/countries.yml b/src/Oro/Bundle/AddressBundle/DataFixtures/countries.yml deleted file mode 100644 index 0bd74902fbb..00000000000 --- a/src/Oro/Bundle/AddressBundle/DataFixtures/countries.yml +++ /dev/null @@ -1,5975 +0,0 @@ - -- name: Afghanistan - iso2: AF - iso3: AFG - phone: 93 - units: - - "Badakhshan" - - "Badghis" - - "Baghlan" - - "Balkh" - - "Bamian" - - "Farah" - - "Faryab" - - "Ghazni" - - "Ghowr" - - "Helmand" - - "Herat" - - "Jowzjan" - - "Kabol" - - "Kandahar" - - "Kapisa" - - "Konar" - - "Kondoz" - - "Laghman" - - "Lowgar" - - "Nangarhar" - - "Nimruz" - - "Oruzgan" - - "Paktia" - - "Paktika" - - "Parvan" - - "Samangan" - - "Sar-e Pol" - - "Takhar" - - "Vardak" - - "Zabol" - -- name: Aland Islands - iso2: AX - iso3: ALA - phone: - units: - - "Aland Islands" - -- name: Albania - iso2: AL - iso3: ALB - phone: 355 - units: - - "Berat" - - "Bulqize" - - "Delvine" - - "Devoll [Bilisht]" - - "Diber [Peshkopi]" - - "Durres" - - "Elbasan" - - "Fier" - - "Gjirokaster" - - "Gramsh" - - "Has [Krume]" - - "Kavaje" - - "Kolonje [Erseke]" - - "Korce" - - "Kruje" - - "Kucove" - - "Kukes" - - "Kurbin" - - "Lezhe" - - "Librazhd" - - "Lushnje" - - "Malesi e Madhe [Koplik]" - - "Mallakaster [Ballsh]" - - "Mat [Burrel]" - - "Mirdite [Rreshen]" - - "Peqin" - - "Permet" - - "Pogradec" - - "Puke" - - "Sarande" - - "Shkoder" - - "Skrapar [Corovode]" - - "Tepelene" - - "Tirane [Tirana]" - - "Tirane [Tirana]" - - "Tropoje [Bajram Curri]" - - "Vlore" - -- name: Algeria - iso2: DZ - iso3: DZA - phone: 213 - units: - - "Adrar" - - "Ain Defla" - - "Ain Temouchent" - - "Alger" - - "Annaba" - - "Batna" - - "Bechar" - - "Bejaia" - - "Biskra" - - "Blida" - - "Bordj Bou Arreridj" - - "Bouira" - - "Boumerdes" - - "Chlef" - - "Constantine" - - "Djelfa" - - "El Bayadh" - - "El Oued" - - "El Tarf" - - "Ghardaia" - - "Guelma" - - "Illizi" - - "Jijel" - - "Khenchela" - - "Laghouat" - - "M'Sila" - - "Mascara" - - "Medea" - - "Mila" - - "Mostaganem" - - "Naama" - - "Oran" - - "Ouargla" - - "Oum el Bouaghi" - - "Relizane" - - "Saida" - - "Setif" - - "Sidi Bel Abbes" - - "Skikda" - - "Souk Ahras" - - "Tamanghasset" - - "Tebessa" - - "Tiaret" - - "Tindouf" - - "Tipaza" - - "Tissemsilt" - - "Tizi Ouzou" - - "Tlemcen" - -- name: American Samoa - iso2: AS - iso3: ASM - phone: 1 684 - units: - - "Eastern" - - "Manu'a" - - "Rose Island" - - "Swains Island" - - "Western" - -- name: Andorra - iso2: AD - iso3: AND - phone: 376 - units: - - "Andorra" - -- name: Angola - iso2: AO - iso3: AGO - phone: 244 - units: - - "Andorra la Vella" - - "Bengo" - - "Benguela" - - "Bie" - - "Cabinda" - - "Canillo" - - "Cuando Cubango" - - "Cuanza Norte" - - "Cuanza Sul" - - "Cunene" - - "Encamp" - - "Escaldes-Engordany" - - "Huambo" - - "Huila" - - "La Massana" - - "Luanda" - - "Lunda Norte" - - "Lunda Sul" - - "Malanje" - - "Moxico" - - "Namibe" - - "Ordino" - - "Sant Julia de Loria" - - "Uige" - - "Zaire" - -- name: Anguilla - iso2: AI - iso3: AIA - phone: 1 264 - units: - - "Anguilla" - -- name: Antarctica - iso2: AQ - iso3: ATA - phone: 672 - units: - - "Antarctica" - -- name: Antigua and Barbuda - iso2: AG - iso3: ATG - phone: 1 268 - units: - - "Barbuda" - - "Redonda" - - "Saint George" - - "Saint John" - - "Saint Mary" - - "Saint Paul" - - "Saint Peter" - - "Saint Philip" - -- name: Argentina - iso2: AR - iso3: ARG - phone: 54 - units: - - "Antartica e Islas del Atlantico Sur" - - "Buenos Aires" - - "Buenos Aires Capital Federal" - - "Catamarca" - - "Chaco" - - "Chubut" - - "Cordoba" - - "Corrientes" - - "Entre Rios" - - "Formosa" - - "Jujuy" - - "La Pampa" - - "La Rioja" - - "Mendoza" - - "Misiones" - - "Neuquen" - - "Rio Negro" - - "Salta" - - "San Juan" - - "San Luis" - - "Santa Cruz" - - "Santa Fe" - - "Santiago del Estero" - - "Tierra del Fuego" - - "Tucuman" - -- name: Armenia - iso2: AM - iso3: ARM - phone: 374 - units: - - "Aragatsotn" - - "Ararat" - - "Armavir" - - "Geghark'unik'" - - "Kotayk'" - - "Lorri" - - "Shirak" - - "Syunik'" - - "Tavush" - - "Vayots' Dzor" - - "Yerevan" - -- name: Aruba - iso2: AW - iso3: ABW - phone: 297 - units: - - "Aruba" - -- name: Australia - iso2: AU - iso3: AUS - phone: 61 - units: - - "Australian Capital Territory" - - "New South Wales" - - "Northern Territory" - - "Queensland" - - "South Australia" - - "Tasmania" - - "Victoria" - - "Western Australia" - -- name: Austria - iso2: AT - iso3: AUT - phone: 43 - units: - - "Burgenland" - - "Kaernten" - - "Niederoesterreich" - - "Oberoesterreich" - - "Salzburg" - - "Steiermark" - - "Tirol" - - "Vorarlberg" - - "Wien" - -- name: Azerbaijan - iso2: AZ - iso3: AZE - phone: 994 - units: - - "Abseron Rayonu" - - "Agcabadi Rayonu" - - "Agdam Rayonu" - - "Agdas Rayonu" - - "Agstafa Rayonu" - - "Agsu Rayonu" - - "Ali Bayramli Sahari" - - "Astara Rayonu" - - "Baki Sahari" - - "Balakan Rayonu" - - "Barda Rayonu" - - "Beylaqan Rayonu" - - "Bilasuvar Rayonu" - - "Cabrayil Rayonu" - - "Calilabad Rayonu" - - "Daskasan Rayonu" - - "Davaci Rayonu" - - "Fuzuli Rayonu" - - "Gadabay Rayonu" - - "Ganca Sahari" - - "Goranboy Rayonu" - - "Goycay Rayonu" - - "Haciqabul Rayonu" - - "Imisli Rayonu" - - "Ismayilli Rayonu" - - "Kalbacar Rayonu" - - "Kurdamir Rayonu" - - "Lacin Rayonu" - - "Lankaran Rayonu" - - "Lankaran Sahari" - - "Lerik Rayonu" - - "Masalli Rayonu" - - "Mingacevir Sahari" - - "Naftalan Sahari" - - "Naxcivan Muxtar Respublikasi" - - "Neftcala Rayonu" - - "Oguz Rayonu" - - "Qabala Rayonu" - - "Qax Rayonu" - - "Qazax Rayonu" - - "Qobustan Rayonu" - - "Quba Rayonu" - - "Qubadli Rayonu" - - "Qusar Rayonu" - - "Saatli Rayonu" - - "Sabirabad Rayonu" - - "Saki Rayonu" - - "Saki Sahari" - - "Salyan Rayonu" - - "Samaxi Rayonu" - - "Samkir Rayonu" - - "Samux Rayonu" - - "Siyazan Rayonu" - - "Sumqayit Sahari" - - "Susa Rayonu" - - "Susa Sahari" - - "Tartar Rayonu" - - "Tovuz Rayonu" - - "Ucar Rayonu" - - "Xacmaz Rayonu" - - "Xankandi Sahari" - - "Xanlar Rayonu" - - "Xizi Rayonu" - - "Xocali Rayonu" - - "Xocavand Rayonu" - - "Yardimli Rayonu" - - "Yevlax Rayonu" - - "Yevlax Sahari" - - "Zangilan Rayonu" - - "Zaqatala Rayonu" - - "Zardab Rayonu" - -- name: Bahamas - iso2: BS - iso3: BHS - phone: 1 242 - units: - - "Acklins and Crooked Islands" - - "Bimini" - - "Cat Island" - - "Exuma" - - "Freeport" - - "Fresh Creek" - - "Governor's Harbour" - - "Green Turtle Cay" - - "Harbour Island" - - "High Rock" - - "Inagua" - - "Kemps Bay" - - "Long Island" - - "Marsh Harbour" - - "Mayaguana" - - "New Providence" - - "Nicholls Town and Berry Islands" - - "Ragged Island" - - "Rock Sound" - - "San Salvador and Rum Cay" - - "Sandy Point" - -- name: Bahrain - iso2: BH - iso3: BHR - phone: 973 - units: - - "Al Hadd" - - "Al Manamah" - - "Al Mintaqah al Gharbiyah" - - "Al Mintaqah al Wusta" - - "Al Mintaqah ash Shamaliyah" - - "Al Muharraq" - - "Ar Rifa' wa al Mintaqah al Janubiyah" - - "Jidd Hafs" - - "Juzur Hawar" - - "Madinat 'Isa" - - "Madinat Hamad" - - "Sitrah" - -- name: Bangladesh - iso2: BD - iso3: BGD - phone: 880 - units: - - "Barguna" - - "Barisal" - - "Bhola" - - "Jhalokati" - - "Patuakhali" - - "Pirojpur" - - "Bandarban" - - "Brahmanbaria" - - "Chandpur" - - "Chittagong" - - "Comilla" - - "Cox's Bazar" - - "Feni" - - "Khagrachari" - - "Lakshmipur" - - "Noakhali" - - "Rangamati" - - "Dhaka" - - "Faridpur" - - "Gazipur" - - "Gopalganj" - - "Jamalpur" - - "Kishoreganj" - - "Madaripur" - - "Manikganj" - - "Munshiganj" - - "Mymensingh" - - "Narayanganj" - - "Narsingdi" - - "Netrokona" - - "Rajbari" - - "Shariatpur" - - "Sherpur" - - "Tangail" - - "Bagerhat" - - "Chuadanga" - - "Jessore" - - "Jhenaidah" - - "Khulna" - - "Kushtia" - - "Magura" - - "Meherpur" - - "Narail" - - "Satkhira" - - "Bogra" - - "Dinajpur" - - "Gaibandha" - - "Jaipurhat" - - "Kurigram" - - "Lalmonirhat" - - "Naogaon" - - "Natore" - - "Nawabganj" - - "Nilphamari" - - "Pabna" - - "Panchagarh" - - "Rajshahi" - - "Rangpur" - - "Sirajganj" - - "Thakurgaon" - - "Habiganj" - - "Maulvi bazar" - - "Sunamganj" - - "Sylhet" - -- name: Barbados - iso2: BB - iso3: BRB - phone: 1 246 - units: - - "Bridgetown" - - "Christ Church" - - "Saint Andrew" - - "Saint George" - - "Saint James" - - "Saint John" - - "Saint Joseph" - - "Saint Lucy" - - "Saint Michael" - - "Saint Peter" - - "Saint Philip" - - "Saint Thomas" - -- name: Belarus - iso2: BY - iso3: BLR - phone: 375 - units: - - "Brestskaya [Brest]" - - "Homyel'skaya [Homyel']" - - "Horad Minsk" - - "Hrodzyenskaya [Hrodna]" - - "Mahilyowskaya [Mahilyow]" - - "Minskaya" - - "Vitsyebskaya [Vitsyebsk]" - -- name: Belgium - iso2: BE - iso3: BEL - phone: 32 - units: - - "Antwerpen" - - "Brabant Wallon" - - "Brussels Capitol Region" - - "Hainaut" - - "Liege" - - "Limburg" - - "Luxembourg" - - "Namur" - - "Oost-Vlaanderen" - - "Vlaams Brabant" - - "West-Vlaanderen" - -- name: Belize - iso2: BZ - iso3: BLZ - phone: 501 - units: - - "Belize" - - "Cayo" - - "Corozal" - - "Orange Walk" - - "Stann Creek" - - "Toledo" - -- name: Benin - iso2: BJ - iso3: BEN - phone: 229 - units: - - "Alibori" - - "Atakora" - - "Atlantique" - - "Borgou" - - "Collines" - - "Couffo" - - "Donga" - - "Littoral" - - "Mono" - - "Oueme" - - "Plateau" - - "Zou" - -- name: Bermuda - iso2: BM - iso3: BMU - phone: 1 441 - units: - - "Devonshire" - - "Hamilton" - - "Hamilton" - - "Paget" - - "Pembroke" - - "Saint George" - - "Saint Georges" - - "Sandys" - - "Smiths" - - "Southampton" - - "Warwick" - -- name: Bhutan - iso2: BT - iso3: BTN - phone: 975 - units: - - "Bumthang" - - "Chhukha" - - "Chirang" - - "Daga" - - "Geylegphug" - - "Ha" - - "Lhuntshi" - - "Mongar" - - "Paro" - - "Pemagatsel" - - "Punakha" - - "Samchi" - - "Samdrup Jongkhar" - - "Shemgang" - - "Tashigang" - - "Thimphu" - - "Tongsa" - - "Wangdi Phodrang" - -- name: Bolivia Plurinational State of - iso2: BO - iso3: BOL - phone: 591 - units: - - "Beni" - - "Chuquisaca" - - "Cochabamba" - - "La Paz" - - "Oruro" - - "Pando" - - "Potosi" - - "Santa Cruz" - - "Tarija" - -- name: Bonaire Sint Eustatius and Saba - iso2: BQ - iso3: BES - phone: - units: - - "Bonaire" - -- name: Bosnia and Herzegovina - iso2: BA - iso3: BIH - phone: 387 - units: - - "Federation of Bosnia and Herzegovina" - - "Republika Srpska" - -- name: Botswana - iso2: BW - iso3: BWA - phone: 267 - units: - - "Central" - - "Chobe" - - "Francistown" - - "Gaborone" - - "Ghanzi" - - "Kgalagadi" - - "Kgatleng" - - "Kweneng" - - "Lobatse" - - "Ngamiland" - - "North-East" - - "Selebi-Pikwe" - - "South-East" - - "Southern" - -- name: Bouvet Island - iso2: BV - iso3: BVT - phone: - units: - - "Bouvet Island" - -- name: Brazil - iso2: BR - iso3: BRA - phone: 55 - units: - - "Acre" - - "Alagoas" - - "Amapa" - - "Amazonas" - - "Bahia" - - "Ceara" - - "Distrito Federal" - - "Espirito Santo" - - "Goias" - - "Maranhao" - - "Mato Grosso" - - "Mato Grosso do Sul" - - "Minas Gerais" - - "Para" - - "Paraiba" - - "Parana" - - "Pernambuco" - - "Piaui" - - "Rio de Janeiro" - - "Rio Grande do Norte" - - "Rio Grande do Sul" - - "Rondonia" - - "Roraima" - - "Santa Catarina" - - "Sao Paulo" - - "Sergipe" - - "Tocantins" - -- name: British Indian Ocean Territory - iso2: IO - iso3: IOT - phone: - units: - - "British Indian Ocean Territory" - -- name: Brunei Darussalam - iso2: BN - iso3: BRN - phone: 673 - units: - - "Belait" - - "Brunei and Muara" - - "Temburong" - - "Tutong" - -- name: Bulgaria - iso2: BG - iso3: BGR - phone: 359 - units: - - "Blagoevgrad" - - "Burgas" - - "Dobrich" - - "Gabrovo" - - "Khaskovo" - - "Kurdzhali" - - "Kyustendil" - - "Lovech" - - "Montana" - - "Pazardzhik" - - "Pernik" - - "Pleven" - - "Plovdiv" - - "Razgrad" - - "Ruse" - - "Shumen" - - "Silistra" - - "Sliven" - - "Smolyan" - - "Sofiya" - - "Sofiya-Grad" - - "Stara Zagora" - - "Turgovishte" - - "Varna" - - "Veliko Turnovo" - - "Vidin" - - "Vratsa" - - "Yambol" - -- name: Burkina Faso - iso2: BF - iso3: BFA - phone: 226 - units: - - "Bale" - - "Bam" - - "Banwa" - - "Bazega" - - "Bougouriba" - - "Boulgou" - - "Boulkiemde" - - "Comoe" - - "Ganzourgou" - - "Gnagna" - - "Gourma" - - "Houet" - - "Ioba" - - "Kadiogo" - - "Kenedougou" - - "Komandjari" - - "Kompienga" - - "Kossi" - - "Koupelogo" - - "Kouritenga" - - "Kourweogo" - - "Leraba" - - "Loroum" - - "Mouhoun" - - "Nahouri" - - "Namentenga" - - "Naumbiel" - - "Nayala" - - "Oubritenga" - - "Oudalan" - - "Passore" - - "Poni" - - "Samentenga" - - "Sanguie" - - "Seno" - - "Sissili" - - "Soum" - - "Sourou" - - "Tapoa" - - "Tuy" - - "Yagha" - - "Yatenga" - - "Ziro" - - "Zondomo" - - "Zoundweogo" - -- name: Burundi - iso2: BI - iso3: BDI - phone: 257 - units: - - "Bubanza" - - "Bujumbura" - - "Bururi" - - "Cankuzo" - - "Cibitoke" - - "Gitega" - - "Karuzi" - - "Kayanza" - - "Kirundo" - - "Makamba" - - "Muramvya" - - "Muyinga" - - "Mwaro" - - "Ngozi" - - "Rutana" - - "Ruyigi" - -- name: Cambodia - iso2: KH - iso3: KHM - phone: 855 - units: - - "Banteay Mean Cheay" - - "Batdambang" - - "Kampong Cham" - - "Kampong Chhnang" - - "Kampong Spoe" - - "Kampong Thum" - - "Kampot" - - "Kandal" - - "Kaoh Kong" - - "Keb" - - "Kracheh" - - "Mondol Kiri" - - "Otdar Mean Cheay" - - "Pailin" - - "Phnum Penh" - - "Pouthisat" - - "Preah Seihanu [Sihanoukville]" - - "Preah Vihear" - - "Prey Veng" - - "Rotanah Kiri" - - "Siem Reab" - - "Stoeng Treng" - - "Svay Rieng" - - "Takev" - -- name: Cameroon - iso2: CM - iso3: CMR - phone: 237 - units: - - "Adamaoua" - - "Centre" - - "Est" - - "Extreme-Nord" - - "Littoral" - - "Nord" - - "Nord-Ouest" - - "Ouest" - - "Sud" - - "Sud-Ouest" - -- name: Canada - iso2: CA - iso3: CAN - phone: 1 - units: - - "Alberta" - - "British Columbia" - - "Manitoba" - - "New Brunswick" - - "Newfoundland" - - "Northwest Territories" - - "Nova Scotia" - - "Nunavut" - - "Ontario" - - "Prince Edward Island" - - "Quebec" - - "Saskatchewan" - - "Yukon" - -- name: Cape Verde - iso2: CV - iso3: CPV - phone: 238 - units: - - "Boa Vista" - - "Brava" - - "Maio" - - "Mosteiros" - - "Paul" - - "Porto Novo" - - "Praia" - - "Ribeira Grande" - - "Sal" - - "Santa Catarina" - - "Santa Cruz" - - "Sao Domingos" - - "Sao Filipe" - - "Sao Nicolau" - - "Sao Vicente" - - "Tarrafal" - -- name: Cayman Islands - iso2: KY - iso3: CYM - phone: 1 345 - units: - - "Creek" - - "Eastern" - - "Midland" - - "South Town" - - "Spot Bay" - - "Stake Bay" - - "West End" - - "Western" - -- name: Central African Republic - iso2: CF - iso3: CAF - phone: 236 - units: - - "Bamingui-Bangoran" - - "Bangui" - - "Basse-Kotto" - - "Gribingui" - - "Haut-Mbomou" - - "Haute-Kotto" - - "Haute-Sangha" - - "Kemo-Gribingui" - - "Lobaye" - - "Mbomou" - - "Nana-Mambere" - - "Ombella-Mpoko" - - "Ouaka" - - "Ouham" - - "Ouham-Pende" - - "Sangha" - - "Vakaga" - -- name: Chad - iso2: TD - iso3: TCD - phone: 235 - units: - - "Batha" - - "Biltine" - - "Borkou-Ennedi-Tibesti" - - "Chari-Baguirmi" - - "Guera" - - "Kanem" - - "Lac" - - "Logone Occidental" - - "Logone Oriental" - - "Mayo-Kebbi" - - "Moyen-Chari" - - "Ouaddai" - - "Salamat" - - "Tandjile" - -- name: Chile - iso2: CL - iso3: CHL - phone: 56 - units: - - "Aisen del General Carlos Ibanez del Campo" - - "Antofagasta" - - "Araucania" - - "Atacama" - - "Bio-Bio" - - "Coquimbo" - - "Libertador General Bernardo O'Higgins" - - "Los Lagos" - - "Magallanes y de la Antartica Chilena" - - "Maule" - - "Region Metropolitana [Santiago]" - - "Tarapaca" - - "Valparaiso" - -- name: China - iso2: CN - iso3: CHN - phone: 86 - units: - - "Anhui" - - "Beijing" - - "Chongqing" - - "Fujian" - - "Gansu" - - "Guangdong" - - "Guangxi" - - "Guizhou" - - "Hainan" - - "Hebei" - - "Heilongjiang" - - "Henan" - - "Hubei" - - "Hunan" - - "Jiangsu" - - "Jiangxi" - - "Jilin" - - "Liaoning" - - "Nei Mongol" - - "Ningxia" - - "Qinghai" - - "Shaanxi" - - "Shandong" - - "Shanghai" - - "Shanxi" - - "Sichuan" - - "Tianjin" - - "Xinjiang" - - "Xizang [Tibet]" - - "Yunnan" - - "Zhejiang" - -- name: Christmas Island - iso2: CX - iso3: CXR - phone: 61 - units: - - "Christmas Island" - -- name: Cocos [Keeling, ] Islands - iso2: CC - iso3: CCK - phone: 61 - units: - - "Direction Island" - - "Home Island" - - "Horsburgh Island" - - "North Keeling Island" - - "South Island" - - "West Island" - -- name: Colombia - iso2: CO - iso3: COL - phone: 57 - units: - - "Amazonas" - - "Antioquia" - - "Arauca" - - "Atlantico" - - "Bolivar" - - "Boyaca" - - "Caldas" - - "Caqueta" - - "Casanare" - - "Cauca" - - "Cesar" - - "Choco" - - "Cordoba" - - "Cundinamarca" - - "Distrito Capital de Santa Fe de Bogota" - - "Guainia" - - "Guaviare" - - "Huila" - - "La Guajira" - - "Magdalena" - - "Meta" - - "Narino" - - "Norte de Santander" - - "Putumayo" - - "Quindio" - - "Risaralda" - - "San Andres y Providencia" - - "Santander" - - "Sucre" - - "Tolima" - - "Valle del Cauca" - - "Vaupes" - - "Vichada" - -- name: Comoros - iso2: KM - iso3: COM - phone: 269 - units: - - "Anjouan [Nzwani]" - - "Domoni" - - "Fomboni" - - "Grande Comore [Njazidja]" - - "Moheli [Mwali]" - - "Moroni" - - "Moutsamoudou" - -- name: Congo - iso2: CG - iso3: COG - phone: 242 - units: - - "Bouenza" - - "Brazzaville" - - "Cuvette" - - "Kouilou" - - "Lekoumou" - - "Likouala" - - "Niari" - - "Plateaux" - - "Pool" - - "Sangha" - -- name: Congo the Democratic Republic of the - iso2: CD - iso3: COD - phone: 243 - units: - - "Bandundu" - - "Bas-Congo" - - "Equateur" - - "Kasai-Occidental" - - "Kasai-Oriental" - - "Katanga" - - "Kinshasa" - - "Maniema" - - "Nord-Kivu" - - "Orientale" - - "Sud-Kivu" - -- name: Cook Islands - iso2: CK - iso3: COK - phone: 682 - units: - - "Aitutaki" - - "Atiu" - - "Avarua" - - "Mangaia" - - "Manihiki" - - "Manuae" - - "Mauke" - - "Mitiaro" - - "Nassau Island" - - "Palmerston" - - "Penrhyn" - - "Pukapuka" - - "Rakahanga" - - "Rarotonga" - - "Suwarrow" - - "Takutea" - -- name: Costa Rica - iso2: CR - iso3: CRI - phone: 506 - units: - - "Alajuela" - - "Cartago" - - "Guanacaste" - - "Heredia" - - "Limon" - - "Puntarenas" - - "San Jose" - -- name: Cote d'Ivoire - iso2: CI - iso3: CIV - phone: 225 - units: - - "Abengourou" - - "Abidjan" - - "Aboisso" - - "Adiake'" - - "Adzope" - - "Agboville" - - "Agnibilekrou" - - "Ale'pe'" - - "Bangolo" - - "Beoumi" - - "Biankouma" - - "Bocanda" - - "Bondoukou" - - "Bongouanou" - - "Bouafle" - - "Bouake" - - "Bouna" - - "Boundiali" - - "Dabakala" - - "Dabon" - - "Daloa" - - "Danane" - - "Daoukro" - - "Dimbokro" - - "Divo" - - "Duekoue" - - "Ferkessedougou" - - "Gagnoa" - - "Grand Bassam" - - "Grand-Lahou" - - "Guiglo" - - "Issia" - - "Jacqueville" - - "Katiola" - - "Korhogo" - - "Lakota" - - "Man" - - "Mankono" - - "Mbahiakro" - - "Odienne" - - "Oume" - - "Sakassou" - - "San-Pedro" - - "Sassandra" - - "Seguela" - - "Sinfra" - - "Soubre" - - "Tabou" - - "Tanda" - - "Tiassale" - - "Tiebissou" - - "Tingrela" - - "Touba" - - "Toulepleu" - - "Toumodi" - - "Vavoua" - - "Yamoussoukro" - - "Zuenoula" - -- name: Croatia - iso2: HR - iso3: HRV - phone: 385 - units: - - "Bjelovarsko-Bilogorska Zupanija" - - "Brodsko-Posavska Zupanija" - - "Dubrovacko-Neretvanska Zupanija" - - "Istarska Zupanija" - - "Karlovacka Zupanija" - - "Koprivnicko-Krizevacka Zupanija" - - "Krapinsko-Zagorska Zupanija" - - "Licko-Senjska Zupanija" - - "Medimurska Zupanija" - - "Osjecko-Baranjska Zupanija" - - "Pozesko-Slavonska Zupanija" - - "Primorsko-Goranska Zupanija" - - "Sibensko-Kninska Zupanija" - - "Sisacko-Moslavacka Zupanija" - - "Splitsko-Dalmatinska Zupanija" - - "Varazdinska Zupanija" - - "Viroviticko-Podravska Zupanija" - - "Vukovarsko-Srijemska Zupanija" - - "Zadarska Zupanija" - - "Zagreb" - - "Zagrebacka Zupanija" - -- name: Cuba - iso2: CU - iso3: CUB - phone: 53 - units: - - "Camaguey" - - "Ciego de Avila" - - "Cienfuegos" - - "Ciudad de La Habana" - - "Granma" - - "Guantanamo" - - "Holguin" - - "Isla de la Juventud" - - "La Habana" - - "Las Tunas" - - "Matanzas" - - "Pinar del Rio" - - "Sancti Spiritus" - - "Santiago de Cuba" - - "Villa Clara" - -- name: Curacao - iso2: CW - iso3: CUW - phone: - units: - - "Curacao" - -- name: Cyprus - iso2: CY - iso3: CYP - phone: 357 - units: - - "Famagusta" - - "Kyrenia" - - "Larnaca" - - "Limassol" - - "Nicosia" - - "Paphos" - -- name: Czech Republic - iso2: CZ - iso3: CZE - phone: 420 - units: - - "Brnensky" - - "Budejovicky" - - "Jihlavsky" - - "Karlovarsky" - - "Kralovehradecky" - - "Liberecky" - - "Olomoucky" - - "Ostravsky" - - "Pardubicky" - - "Plzensky" - - "Praha" - - "Stredocesky" - - "Ustecky" - - "Zlinsky" - -- name: Denmark - iso2: DK - iso3: DNK - phone: 45 - units: - - "Arhus" - - "Bornholm" - - "Fredericksberg" - - "Frederiksborg" - - "Fyn" - - "Kobenhavn" - - "Kobenhavns" - - "Nordjylland" - - "Ribe" - - "Ringkobing" - - "Roskilde" - - "Sonderjylland" - - "Storstrom" - - "Vejle" - - "Vestsjalland" - - "Viborg" - -- name: Djibouti - iso2: DJ - iso3: DJI - phone: 253 - units: - - "'Ali Sabih" - - "Dikhil" - - "Djibouti" - - "Obock" - - "Tadjoura" - -- name: Dominica - iso2: DM - iso3: DMA - phone: 1 767 - units: - - "Saint Andrew" - - "Saint David" - - "Saint George" - - "Saint John" - - "Saint Joseph" - - "Saint Luke" - - "Saint Mark" - - "Saint Patrick" - - "Saint Paul" - - "Saint Peter" - -- name: Dominican Republic - iso2: DO - iso3: DOM - phone: 1 809 - units: - - "Azua" - - "Baoruco" - - "Barahona" - - "Dajabon" - - "Distrito Nacional" - - "Duarte" - - "El Seibo" - - "Elias Pina" - - "Espaillat" - - "Hato Mayor" - - "Independencia" - - "La Altagracia" - - "La Romana" - - "La Vega" - - "Maria Trinidad Sanchez" - - "Monsenor Nouel" - - "Monte Cristi" - - "Monte Plata" - - "Pedernales" - - "Peravia" - - "Puerto Plata" - - "Salcedo" - - "Samana" - - "San Cristobal" - - "San Juan" - - "San Pedro de Macoris" - - "Sanchez Ramirez" - - "Santiago" - - "Santiago Rodriguez" - - "Valverde" - -- name: Ecuador - iso2: EC - iso3: ECU - phone: 593 - units: - - "Azuay" - - "Bolivar" - - "Canar" - - "Carchi" - - "Chimborazo" - - "Cotopaxi" - - "El Oro" - - "Esmeraldas" - - "Galapagos" - - "Guayas" - - "Imbabura" - - "Loja" - - "Los Rios" - - "Manabi" - - "Morona-Santiago" - - "Napo" - - "Orellana" - - "Pastaza" - - "Pichincha" - - "Sucumbios" - - "Tungurahua" - - "Zamora-Chinchipe" - -- name: Egypt - iso2: EG - iso3: EGY - phone: 20 - units: - - "Ad Daqahliyah" - - "Al Bahr al Ahmar" - - "Al Buhayrah" - - "Al Fayyum" - - "Al Gharbiyah" - - "Al Iskandariyah" - - "Al Isma'iliyah" - - "Al Jizah" - - "Al Minufiyah" - - "Al Minya" - - "Al Qahirah" - - "Al Qalyubiyah" - - "Al Wadi al Jadid" - - "As Suways" - - "Ash Sharqiyah" - - "Aswan" - - "Asyut" - - "Bani Suwayf" - - "Bur Sa'id" - - "Dumyat" - - "Janub Sina'" - - "Kafr ash Shaykh" - - "Matruh" - - "Qina" - - "Shamal Sina'" - - "Suhaj" - -- name: El Salvador - iso2: SV - iso3: SLV - phone: 503 - units: - - "Ahuachapan" - - "Cabanas" - - "Chalatenango" - - "Cuscatlan" - - "La Libertad" - - "La Paz" - - "La Union" - - "Morazan" - - "San Miguel" - - "San Salvador" - - "San Vicente" - - "Santa Ana" - - "Sonsonate" - - "Usulutan" - -- name: Equatorial Guinea - iso2: GQ - iso3: GNQ - phone: 240 - units: - - "Annobon" - - "Bioko Norte" - - "Bioko Sur" - - "Centro Sur" - - "Kie-Ntem" - - "Litoral" - - "Wele-Nzas" - -- name: Eritrea - iso2: ER - iso3: ERI - phone: 291 - units: - - "Akale Guzay" - - "Barka" - - "Denkel" - - "Hamasen" - - "Sahil" - - "Semhar" - - "Senhit" - - "Seraye" - -- name: Estonia - iso2: EE - iso3: EST - phone: 372 - units: - - "Harjumaa [Tallinn]" - - "Hiiumaa [Kardla]" - - "Ida-Virumaa [Johvi]" - - "Jarvamaa [Paide]" - - "Jogevamaa [Jogeva]" - - "Laane-Virumaa [Rakvere]" - - "Laanemaa [Haapsalu]" - - "Parnumaa [Parnu]" - - "Polvamaa [Polva]" - - "Raplamaa [Rapla]" - - "Saaremaa [Kuessaare]" - - "Tartumaa [Tartu]" - - "Valgamaa [Valga]" - - "Viljandimaa [Viljandi]" - - "Vorumaa [Voru]" - -- name: Ethiopia - iso2: ET - iso3: ETH - phone: 251 - units: - - "Adis Abeba [Addis Ababa]" - - "Afar" - - "Amara" - - "Dire Dawa" - - "Gambela Hizboch" - - "Hareri Hizb" - - "Oromiya" - - "Sumale" - - "Tigray" - - "YeDebub Biheroch Bihereseboch na Hizboch" - -- name: Falkland Islands [Malvinas, ] - iso2: FK - iso3: FLK - phone: 500 - units: - - "Falkland Islands [Islas Malvinas]" - -- name: Faroe Islands - iso2: FO - iso3: FRO - phone: 298 - units: - - "Bordoy" - - "Eysturoy" - - "Mykines" - - "Sandoy" - - "Skuvoy" - - "Streymoy" - - "Suduroy" - - "Tvoroyri" - - "Vagar" - -- name: Fiji - iso2: FJ - iso3: FJI - phone: 679 - units: - - "Central" - - "Eastern" - - "Northern" - - "Rotuma" - - "Western" - -- name: Finland - iso2: FI - iso3: FIN - phone: 358 - units: - - "Aland" - - "Etela-Suomen Laani" - - "Ita-Suomen Laani" - - "Lansi-Suomen Laani" - - "Lappi" - - "Oulun Laani" - -- name: France - iso2: FR - iso3: FRA - phone: 33 - units: - - "Alsace" - - "Aquitaine" - - "Auvergne" - - "Basse-Normandie" - - "Bourgogne" - - "Bretagne" - - "Centre" - - "Champagne-Ardenne" - - "Corse" - - "Franche-Comte" - - "Haute-Normandie" - - "Ile-de-France" - - "Languedoc-Roussillon" - - "Limousin" - - "Lorraine" - - "Midi-Pyrenees" - - "Nord-Pas-de-Calais" - - "Pays de la Loire" - - "Picardie" - - "Poitou-Charentes" - - "Provence-Alpes-Cote d'Azur" - - "Rhone-Alpes" - -- name: French Guiana - iso2: GF - iso3: GUF - phone: - units: - - "French Guiana" - -- name: French Polynesia - iso2: PF - iso3: PYF - phone: 689 - units: - - "Archipel des Marquises" - - "Archipel des Tuamotu" - - "Archipel des Tubuai" - - "Iles du Vent" - - "Iles Sous-le-Vent" - -- name: French Southern Territories - iso2: TF - iso3: ATF - phone: - units: - - "Adelie Land" - - "Ile Crozet" - - "Iles Kerguelen" - - "Iles Saint-Paul et Amsterdam" - -- name: Gabon - iso2: GA - iso3: GAB - phone: 241 - units: - - "Estuaire" - - "Haut-Ogooue" - - "Moyen-Ogooue" - - "Ngounie" - - "Nyanga" - - "Ogooue-Ivindo" - - "Ogooue-Lolo" - - "Ogooue-Maritime" - - "Woleu-Ntem" - -- name: Gambia - iso2: GM - iso3: GMB - phone: 220 - units: - - "Banjul" - - "Central River" - - "Lower River" - - "North Bank" - - "Upper River" - - "Western" - -- name: Georgia - iso2: GE - iso3: GEO - phone: 995 - units: - - "Abashis" - - "Abkhazia or Ap'khazet'is Avtonomiuri Respublika [Sokhumi]" - - "Adigenis" - - "Ajaria or Acharis Avtonomiuri Respublika [Bat'umi]" - - "Akhalgoris" - - "Akhalk'alak'is" - - "Akhalts'ikhis" - - "Akhmetis" - - "Ambrolauris" - - "Aspindzis" - - "Baghdat'is" - - "Bolnisis" - - "Borjomis" - - "Ch'khorotsqus" - - "Ch'okhatauris" - - "Chiat'ura" - - "Dedop'listsqaros" - - "Dmanisis" - - "Dushet'is" - - "Gardabanis" - - "Gori" - - "Goris" - - "Gurjaanis" - - "Javis" - - "K'arelis" - - "K'ut'aisi" - - "Kaspis" - - "Kharagaulis" - - "Khashuris" - - "Khobis" - - "Khonis" - - "Lagodekhis" - - "Lanch'khut'is" - - "Lentekhis" - - "Marneulis" - - "Martvilis" - - "Mestiis" - - "Mts'khet'is" - - "Ninotsmindis" - - "Onis" - - "Ozurget'is" - - "P'ot'i" - - "Qazbegis" - - "Qvarlis" - - "Rust'avi" - - "Sach'kheris" - - "Sagarejos" - - "Samtrediis" - - "Senakis" - - "Sighnaghis" - - "T'bilisi" - - "T'elavis" - - "T'erjolis" - - "T'et'ritsqaros" - - "T'ianet'is" - - "Tqibuli" - - "Ts'ageris" - - "Tsalenjikhis" - - "Tsalkis" - - "Tsqaltubo" - - "Vanis" - - "Zestap'onis" - - "Zugdidi" - - "Zugdidis" - -- name: Germany - iso2: DE - iso3: DEU - phone: 49 - units: - - "Brandenburg" - - "Berlin" - - "Baden-Württemberg" - - "Bayern [Bavaria]" - - "Bremen" - - "Hessen" - - "Hamburg" - - "Mecklenburg-Vorpommern" - - "Niedersachsen [Lower Saxony]" - - "Nordrhein-Westfalen" - - "Rheinland-Pfalz [Palatinate]" - - "Schleswig-Holstein" - - "Saarland" - - "Sachsen [Saxony]" - - "Sachsen-Anhalt [Saxony-Anhalt]" - - "Thüringen [Thuringia]" - -- name: Ghana - iso2: GH - iso3: GHA - phone: 233 - units: - - "Ashanti" - - "Brong-Ahafo" - - "Central" - - "Eastern" - - "Greater Accra" - - "Northern" - - "Upper East" - - "Upper West" - - "Volta" - - "Western" - -- name: Gibraltar - iso2: GI - iso3: GIB - phone: 350 - units: - - "Gibraltar" - -- name: Greece - iso2: GR - iso3: GRC - phone: 30 - units: - - "Achaea" - - "Aetolia-Acarnania" - - "Arcadia" - - "Argolis" - - "Arta" - - "Athens" - - "Boeotia" - - "Chalcidice" - - "Chania" - - "Chios" - - "Corfu" - - "Corinthia" - - "Cyclades" - - "Dodecanese" - - "Drama" - - "East Attica" - - "Elis" - - "Euboea" - - "Evros" - - "Evrytania" - - "Florina" - - "Grevena" - - "Heraklion" - - "Imathia" - - "Ioannina" - - "Karditsa" - - "Kastoria" - - "Kavala" - - "Kefalonia and Ithaka" - - "Kilkis" - - "Kozani" - - "Laconia" - - "Larissa" - - "Lasithi" - - "Lefkada" - - "Lesbos" - - "Magnesia" - - "Messenia" - - "Pella" - - "Phocis" - - "Phthiotis" - - "Pieria" - - "Piraeus" - - "Preveza" - - "Rethymno" - - "Rhodope" - - "Samos" - - "Serres" - - "Thesprotia" - - "Thessaloniki" - - "Trikala" - - "West Attica" - - "Xanthi" - - "Zakynthos" - -- name: Greenland - iso2: GL - iso3: GRL - phone: 299 - units: - - "Avannaa [Nordgronland]" - - "Kitaa [Vestgronland]" - - "Tunu [Ostgronland]" - -- name: Grenada - iso2: GD - iso3: GRD - phone: 1 473 - units: - - "Carriacou and Petit Martinique" - - "Saint Andrew" - - "Saint David" - - "Saint George" - - "Saint John" - - "Saint Mark" - - "Saint Patrick" - -- name: Guadeloupe - iso2: GP - iso3: GLP - phone: - units: - - "Basse-Terre" - - "Grande-Terre" - - "Iles de la Petite Terre" - - "Iles des Saintes" - - "Marie-Galante" - -- name: Guam - iso2: GU - iso3: GUM - phone: 1 671 - units: - - "Guam" - -- name: Guatemala - iso2: GT - iso3: GTM - phone: 502 - units: - - "Alta Verapaz" - - "Baja Verapaz" - - "Chimaltenango" - - "Chiquimula" - - "El Progreso" - - "Escuintla" - - "Guatemala" - - "Huehuetenango" - - "Izabal" - - "Jalapa" - - "Jutiapa" - - "Peten" - - "Quetzaltenango" - - "Quiche" - - "Retalhuleu" - - "Sacatepequez" - - "San Marcos" - - "Santa Rosa" - - "Solola" - - "Suchitepequez" - - "Totonicapan" - - "Zacapa" - -- name: Guernsey - iso2: GG - iso3: GGY - phone: - units: - - "Castel" - - "Forest" - - "St. Andrew" - - "St. Martin" - - "St. Peter Port" - - "St. Pierre du Bois" - - "St. Sampson" - - "St. Saviour" - - "Torteval" - - "Vale" - -- name: Guinea - iso2: GN - iso3: GIN - phone: 224 - units: - - "Beyla" - - "Boffa" - - "Boke" - - "Conakry" - - "Coyah" - - "Dabola" - - "Dalaba" - - "Dinguiraye" - - "Dubreka" - - "Faranah" - - "Forecariah" - - "Fria" - - "Gaoual" - - "Gueckedou" - - "Kankan" - - "Kerouane" - - "Kindia" - - "Kissidougou" - - "Koubia" - - "Koundara" - - "Kouroussa" - - "Labe" - - "Lelouma" - - "Lola" - - "Macenta" - - "Mali" - - "Mamou" - - "Mandiana" - - "Nzerekore" - - "Pita" - - "Siguiri" - - "Telimele" - - "Tougue" - - "Yomou" - -- name: Guinea-Bissau - iso2: GW - iso3: GNB - phone: 245 - units: - - "Bafata" - - "Biombo" - - "Bissau" - - "Bolama-Bijagos" - - "Cacheu" - - "Gabu" - - "Oio" - - "Quinara" - - "Tombali" - -- name: Guyana - iso2: GY - iso3: GUY - phone: 592 - units: - - "Barima-Waini" - - "Cuyuni-Mazaruni" - - "Demerara-Mahaica" - - "East Berbice-Corentyne" - - "Essequibo Islands-West Demerara" - - "Mahaica-Berbice" - - "Pomeroon-Supenaam" - - "Potaro-Siparuni" - - "Upper Demerara-Berbice" - - "Upper Takutu-Upper Essequibo" - -- name: Haiti - iso2: HT - iso3: HTI - phone: 509 - units: - - "Artibonite" - - "Centre" - - "Grand'Anse" - - "Nord" - - "Nord-Est" - - "Nord-Ouest" - - "Ouest" - - "Sud" - - "Sud-Est" - -- name: Heard Island and McDonald Islands - iso2: HM - iso3: HMD - phone: - units: - - "Heard Island and McDonald Islands" - -- name: Holy See, Vatican City State - iso2: VA - iso3: VAT - phone: 39 - units: - - "Holy See [Vatican City]" - -- name: Honduras - iso2: HN - iso3: HND - phone: 504 - units: - - "Atlantida" - - "Choluteca" - - "Colon" - - "Comayagua" - - "Copan" - - "Cortes" - - "El Paraiso" - - "Francisco Morazan" - - "Gracias a Dios" - - "Intibuca" - - "Islas de la Bahia" - - "La Paz" - - "Lempira" - - "Ocotepeque" - - "Olancho" - - "Santa Barbara" - - "Valle" - - "Yoro" - -- name: Hong Kong - iso2: HK - iso3: HKG - phone: 852 - units: - - "Hong Kong" - -- name: Hungary - iso2: HU - iso3: HUN - phone: 36 - units: - - "Bacs-Kiskun" - - "Baranya" - - "Bekes" - - "Bekescsaba" - - "Borsod-Abauj-Zemplen" - - "Budapest" - - "Csongrad" - - "Debrecen" - - "Dunaujvaros" - - "Eger" - - "Fejer" - - "Gyor" - - "Gyor-Moson-Sopron" - - "Hajdu-Bihar" - - "Heves" - - "Hodmezovasarhely" - - "Jasz-Nagykun-Szolnok" - - "Kaposvar" - - "Kecskemet" - - "Komarom-Esztergom" - - "Miskolc" - - "Nagykanizsa" - - "Nograd" - - "Nyiregyhaza" - - "Pecs" - - "Pest" - - "Somogy" - - "Sopron" - - "Szabolcs-Szatmar-Bereg" - - "Szeged" - - "Szekesfehervar" - - "Szolnok" - - "Szombathely" - - "Tatabanya" - - "Tolna" - - "Vas" - - "Veszprem" - - "Veszprem" - - "Zala" - - "Zalaegerszeg" - -- name: Iceland - iso2: IS - iso3: ISL - phone: 354 - units: - - "Akranes" - - "Akureyri" - - "Arnessysla" - - "Austur-Bardhastrandarsysla" - - "Austur-Hunavatnssysla" - - "Austur-Skaftafellssysla" - - "Borgarfjardharsysla" - - "Dalasysla" - - "Eyjafjardharsysla" - - "Gullbringusysla" - - "Hafnarfjordhur" - - "Husavik" - - "Isafjordhur" - - "Keflavik" - - "Kjosarsysla" - - "Kopavogur" - - "Myrasysla" - - "Neskaupstadhur" - - "Nordhur-Isafjardharsysla" - - "Nordhur-Mulasys-la" - - "Nordhur-Thingeyjarsysla" - - "Olafsfjordhur" - - "Rangarvallasysla" - - "Reykjavik" - - "Saudharkrokur" - - "Seydhisfjordhur" - - "Siglufjordhur" - - "Skagafjardharsysla" - - "Snaefellsnes-og Hnappadalssysla" - - "Strandasysla" - - "Sudhur-Mulasysla" - - "Sudhur-Thingeyjarsysla" - - "Vesttmannaeyjar" - - "Vestur-Bardhastrandarsysla" - - "Vestur-Hunavatnssysla" - - "Vestur-Isafjardharsysla" - - "Vestur-Skaftafellssysla" - -- name: India - iso2: IN - iso3: IND - phone: 91 - units: - - "Andaman and Nicobar Islands" - - "Andhra Pradesh" - - "Arunachal Pradesh" - - "Assam" - - "Bihar" - - "Chandigarh" - - "Chhattisgarh" - - "Dadra and Nagar Haveli" - - "Daman and Diu" - - "Delhi" - - "Goa" - - "Gujarat" - - "Haryana" - - "Himachal Pradesh" - - "Jammu and Kashmir" - - "Jharkhand" - - "Karnataka" - - "Kerala" - - "Lakshadweep" - - "Madhya Pradesh" - - "Maharashtra" - - "Manipur" - - "Meghalaya" - - "Mizoram" - - "Nagaland" - - "Orissa" - - "Pondicherry" - - "Punjab" - - "Rajasthan" - - "Sikkim" - - "Tamil Nadu" - - "Tripura" - - "Uttar Pradesh" - - "Uttaranchal" - - "West Bengal" - -- name: Indonesia - iso2: ID - iso3: IDN - phone: 62 - units: - - "Aceh" - - "Bali" - - "Banten" - - "Bengkulu" - - "East Timor" - - "Gorontalo" - - "Irian Jaya" - - "Jakarta Raya" - - "Jambi" - - "Jawa Barat" - - "Jawa Tengah" - - "Jawa Timur" - - "Kalimantan Barat" - - "Kalimantan Selatan" - - "Kalimantan Tengah" - - "Kalimantan Timur" - - "Kepulauan Bangka Belitung" - - "Lampung" - - "Maluku" - - "Maluku Utara" - - "Nusa Tenggara Barat" - - "Nusa Tenggara Timur" - - "Riau" - - "Sulawesi Selatan" - - "Sulawesi Tengah" - - "Sulawesi Tenggara" - - "Sulawesi Utara" - - "Sumatera Barat" - - "Sumatera Selatan" - - "Sumatera Utara" - - "Yogyakarta" - -- name: Iran Islamic Republic of - iso2: IR - iso3: IRN - phone: 98 - units: - - "Ardabil" - - "Azarbayjan-e Gharbi" - - "Azarbayjan-e Sharqi" - - "Bushehr" - - "Chahar Mahall va Bakhtiari" - - "Esfahan" - - "Fars" - - "Gilan" - - "Golestan" - - "Hamadan" - - "Hormozgan" - - "Ilam" - - "Kerman" - - "Kermanshah" - - "Khorasan" - - "Khuzestan" - - "Kohgiluyeh va Buyer Ahmad" - - "Kordestan" - - "Lorestan" - - "Markazi" - - "Mazandaran" - - "Qazvin" - - "Qom" - - "Semnan" - - "Sistan va Baluchestan" - - "Tehran" - - "Yazd" - - "Zanjan" - -- name: Iraq - iso2: IQ - iso3: IRQ - phone: 964 - units: - - "Al Anbar" - - "Al Basrah" - - "Al Muthanna" - - "Al Qadisiyah" - - "An Najaf" - - "Arbil" - - "As Sulaymaniyah" - - "At Ta'mim" - - "Babil" - - "Baghdad" - - "Dahuk" - - "Dhi Qar" - - "Diyala" - - "Karbala'" - - "Maysan" - - "Ninawa" - - "Salah ad Din" - - "Wasit" - -- name: Ireland - iso2: IE - iso3: IRL - phone: 353 - units: - - "Co. Carlow" - - "Co. Cavan" - - "Co. Clare" - - "Co. Cork" - - "Co. Donegal" - - "Co. Dublin" - - "Co. Galway" - - "Co. Kerry" - - "Co. Kildare" - - "Co. Kilkenny" - - "Co. Laois" - - "Co. Leitrim" - - "Co. Limerick" - - "Co. Longford" - - "Co. Louth" - - "Co. Mayo" - - "Co. Meath" - - "Co. Monaghan" - - "Co. Offaly" - - "Co. Roscommon" - - "Co. Sligo" - - "Co. Tipperary" - - "Co. Waterford" - - "Co. Westmeath" - - "Co. Wexford" - - "Co. Wicklow" - -- name: Isle of Man - iso2: IM - iso3: IMN - phone: 44 - units: - - "Isle of Man" - -- name: Israel - iso2: IL - iso3: ISR - phone: 972 - units: - - "Central" - - "Haifa" - - "Jerusalem" - - "Northern" - - "Southern" - - "Tel Aviv" - -- name: Italy - iso2: IT - iso3: ITA - phone: 39 - units: - - "Agrigento" - - "Alessandria" - - "Ancona" - - "Aosta" - - "Ascoli Piceno" - - "L'Aquila" - - "Arezzo" - - "Asti" - - "Avellino" - - "Bari" - - "Bergamo" - - "Biella" - - "Belluno" - - "Benevento" - - "Bologna" - - "Brindisi" - - "Brescia" - - "Barletta-Andria-Trani" - - "Bolzano-Bozen" - - "Cagliari" - - "Campobasso" - - "Caserta" - - "Chieti" - - "Carbonia-Inglesias" - - "Caltanissetta" - - "Cuneo" - - "Como" - - "Cremona" - - "Cosenza" - - "Catania" - - "Catanzaro" - - "Enna" - - "Forlì-Cesena" - - "Ferrara" - - "Foggia" - - "Firenze" - - "Fermo" - - "Frosinone" - - "Genova" - - "Gorizia" - - "Grosseto" - - "Imperia" - - "Isernia" - - "Crotone" - - "Lecco" - - "Lecce" - - "Livorno" - - "Lodi" - - "Latina" - - "Lucca" - - "Monza e Brianza" - - "Macerata" - - "Messina" - - "Milano" - - "Mantova" - - "Modena" - - "Massa-Carrara" - - "Matera" - - "Napoli" - - "Novara" - - "Nuoro" - - "Ogliastra" - - "Oristano" - - "Olbia-Tempio" - - "Palermo" - - "Piacenza" - - "Padova" - - "Pescara" - - "Perugia" - - "Pisa" - - "Pordenone" - - "Prato" - - "Parma" - - "Pistoia" - - "Pesaro e Urbino" - - "Pavia" - - "Potenza" - - "Ravenna" - - "Reggio Calabria" - - "Reggio Elilia" - - "Ragusa" - - "Rieti" - - "Roma" - - "Rimini" - - "Rovigo" - - "Salerno" - - "Siena" - - "Sondrio" - - "La Spezia" - - "Siracusa" - - "Sassari" - - "Savona" - - "Taranto" - - "Teramo" - - "Trento" - - "Torino" - - "Trapani" - - "Terni" - - "Trieste" - - "Treviso" - - "Udine" - - "Varese" - - "Verbano-Cusio-Ossola" - - "Vercelli" - - "Venezia" - - "Vicenza" - - "Verona" - - "Medio Campidano" - - "Viterbo" - - "Vibo Valentia" - -- name: Jamaica - iso2: JM - iso3: JAM - phone: 1 876 - units: - - "Clarendon" - - "Hanover" - - "Kingston" - - "Manchester" - - "Portland" - - "Saint Andrew" - - "Saint Ann" - - "Saint Catherine" - - "Saint Elizabeth" - - "Saint James" - - "Saint Mary" - - "Saint Thomas" - - "Trelawny" - - "Westmoreland" - -- name: Japan - iso2: JP - iso3: JPN - phone: 81 - units: - - "Aichi" - - "Akita" - - "Aomori" - - "Chiba" - - "Ehime" - - "Fukui" - - "Fukuoka" - - "Fukushima" - - "Gifu" - - "Gunma" - - "Hiroshima" - - "Hokkaido" - - "Hyogo" - - "Ibaragi" - - "Ishikawa" - - "Iwate" - - "Kagawa" - - "Kagoshima" - - "Kanagawa" - - "Kochi" - - "Kumamoto" - - "Kyoto" - - "Mie" - - "Miyagi" - - "Miyazaki" - - "Nagano" - - "Nagasaki" - - "Nara" - - "Niigata" - - "Oita" - - "Okayama" - - "Okinawa" - - "Osaka" - - "Saga" - - "Saitama" - - "Shiga" - - "Shimane" - - "Shizuoka" - - "Tochigi" - - "Tokushima" - - "Tokyo" - - "Tottori" - - "Toyama" - - "Wakayama" - - "Yamagata" - - "Yamaguchi" - - "Yamanashi" - -- name: Jersey - iso2: JE - iso3: JEY - phone: - units: - - "Jersey" - -- name: Jordan - iso2: JO - iso3: JOR - phone: 962 - units: - - "'Amman" - - "Ajlun" - - "Al 'Aqabah" - - "Al Balqa'" - - "Al Karak" - - "Al Mafraq" - - "At Tafilah" - - "Az Zarqa'" - - "Irbid" - - "Jarash" - - "Ma'an" - - "Madaba" - -- name: Kazakhstan - iso2: KZ - iso3: KAZ - phone: 7 - units: - - "Almaty" - - "Aqmola" - - "Aqtobe" - - "Astana" - - "Atyrau" - - "Batys Qazaqstan" - - "Bayqongyr" - - "Mangghystau" - - "Ongtustik Qazaqstan" - - "Pavlodar" - - "Qaraghandy" - - "Qostanay" - - "Qyzylorda" - - "Shyghys Qazaqstan" - - "Soltustik Qazaqstan" - - "Zhambyl" - -- name: Kenya - iso2: KE - iso3: KEN - phone: 254 - units: - - "Central" - - "Coast" - - "Eastern" - - "Nairobi Area" - - "North Eastern" - - "Nyanza" - - "Rift Valley" - - "Western" - -- name: Kiribati - iso2: KI - iso3: KIR - phone: 686 - units: - - "Abaiang" - - "Abemama" - - "Aranuka" - - "Arorae" - - "Banaba" - - "Banaba" - - "Beru" - - "Butaritari" - - "Central Gilberts" - - "Gilbert Islands" - - "Kanton" - - "Kiritimati" - - "Kuria" - - "Line Islands" - - "Line Islands" - - "Maiana" - - "Makin" - - "Marakei" - - "Nikunau" - - "Nonouti" - - "Northern Gilberts" - - "Onotoa" - - "Phoenix Islands" - - "Southern Gilberts" - - "Tabiteuea" - - "Tabuaeran" - - "Tamana" - - "Tarawa" - - "Tarawa" - - "Teraina" - -- name: Korea, Democratic People's Republic of - iso2: KP - iso3: PRK - phone: 850 - units: - - "Chagang-do [Chagang Province]" - - "Hamgyong-bukto [North Hamgyong Province]" - - "Hamgyong-namdo [South Hamgyong Province]" - - "Hwanghae-bukto [North Hwanghae Province]" - - "Hwanghae-namdo [South Hwanghae Province]" - - "Kaesong-si [Kaesong City]" - - "Kangwon-do [Kangwon Province]" - - "Namp'o-si [Namp'o City]" - - "P'yongan-bukto [North P'yongan Province]" - - "P'yongan-namdo [South P'yongan Province]" - - "P'yongyang-si [P'yongyang City]" - - "Yanggang-do [Yanggang Province]" - -- name: Korea, Republic of - iso2: KR - iso3: KOR - phone: 82 - units: - - "Ch'ungch'ong-bukto" - - "Ch'ungch'ong-namdo" - - "Cheju-do" - - "Cholla-bukto" - - "Cholla-namdo" - - "Inch'on-gwangyoksi" - - "Kangwon-do" - - "Kwangju-gwangyoksi" - - "Kyonggi-do" - - "Kyongsang-bukto" - - "Kyongsang-namdo" - - "Pusan-gwangyoksi" - - "Soul-t'ukpyolsi" - - "Taegu-gwangyoksi" - - "Taejon-gwangyoksi" - - "Ulsan-gwangyoksi" - -- name: Kuwait - iso2: KW - iso3: KWT - phone: 965 - units: - - "Al 'Asimah" - - "Al Ahmadi" - - "Al Farwaniyah" - - "Al Jahra'" - - "Hawalli" - -- name: Kyrgyzstan - iso2: KG - iso3: KGZ - phone: 996 - units: - - "Batken Oblasty" - - "Bishkek Shaary" - - "Chuy Oblasty [Bishkek]" - - "Jalal-Abad Oblasty" - - "Naryn Oblasty" - - "Osh Oblasty" - - "Talas Oblasty" - - "Ysyk-Kol Oblasty [Karakol]" - -- name: Lao People's Democratic Republic - iso2: LA - iso3: LAO - phone: 856 - units: - - "Attapu" - - "Bokeo" - - "Bolikhamxai" - - "Champasak" - - "Houaphan" - - "Khammouan" - - "Louangnamtha" - - "Louangphabang" - - "Oudomxai" - - "Phongsali" - - "Salavan" - - "Savannakhet" - - "Viangchan" - - "Viangchan" - - "Xaignabouli" - - "Xaisomboun" - - "Xekong" - - "Xiangkhoang" - -- name: Latvia - iso2: LV - iso3: LVA - phone: 371 - units: - - "Aizkraukles Rajons" - - "Aluksnes Rajons" - - "Balvu Rajons" - - "Bauskas Rajons" - - "Cesu Rajons" - - "Daugavpils" - - "Daugavpils Rajons" - - "Dobeles Rajons" - - "Gulbenes Rajons" - - "Jekabpils Rajons" - - "Jelgava" - - "Jelgavas Rajons" - - "Jurmala" - - "Kraslavas Rajons" - - "Kuldigas Rajons" - - "Leipaja" - - "Liepajas Rajons" - - "Limbazu Rajons" - - "Ludzas Rajons" - - "Madonas Rajons" - - "Ogres Rajons" - - "Preilu Rajons" - - "Rezekne" - - "Rezeknes Rajons" - - "Riga" - - "Rigas Rajons" - - "Saldus Rajons" - - "Talsu Rajons" - - "Tukuma Rajons" - - "Valkas Rajons" - - "Valmieras Rajons" - - "Ventspils" - - "Ventspils Rajons" - -- name: Lebanon - iso2: LB - iso3: LBN - phone: 961 - units: - - "Beyrouth" - - "Ech Chimal" - - "Ej Jnoub" - - "El Bekaa" - - "Jabal Loubnane" - -- name: Lesotho - iso2: LS - iso3: LSO - phone: 266 - units: - - "Berea" - - "Butha-Buthe" - - "Leribe" - - "Mafeteng" - - "Maseru" - - "Mohales Hoek" - - "Mokhotlong" - - "Qacha's Nek" - - "Quthing" - - "Thaba-Tseka" - -- name: Liberia - iso2: LR - iso3: LBR - phone: 231 - units: - - "Bomi" - - "Bong" - - "Grand Bassa" - - "Grand Cape Mount" - - "Grand Gedeh" - - "Grand Kru" - - "Lofa" - - "Margibi" - - "Maryland" - - "Montserrado" - - "Nimba" - - "River Cess" - - "Sinoe" - -- name: Libyan Arab Jamahiriya - iso2: LY - iso3: LBY - phone: 218 - units: - - "Ajdabiya" - - "Al 'Aziziyah" - - "Al Fatih" - - "Al Jabal al Akhdar" - - "Al Jufrah" - - "Al Khums" - - "Al Kufrah" - - "An Nuqat al Khams" - - "Ash Shati'" - - "Awbari" - - "Az Zawiyah" - - "Banghazi" - - "Darnah" - - "Ghadamis" - - "Gharyan" - - "Misratah" - - "Murzuq" - - "Sabha" - - "Sawfajjin" - - "Surt" - - "Tarabulus" - - "Tarhunah" - - "Tubruq" - - "Yafran" - - "Zlitan" - -- name: Liechtenstein - iso2: LI - iso3: LIE - phone: 423 - units: - - "Balzers" - - "Eschen" - - "Gamprin" - - "Mauren" - - "Planken" - - "Ruggell" - - "Schaan" - - "Schellenberg" - - "Triesen" - - "Triesenberg" - - "Vaduz" - -- name: Lithuania - iso2: LT - iso3: LTU - phone: 370 - units: - - "Akmenes Rajonas" - - "Alytaus Rajonas" - - "Alytus" - - "Anyksciu Rajonas" - - "Birstonas" - - "Birzu Rajonas" - - "Druskininkai" - - "Ignalinos Rajonas" - - "Jonavos Rajonas" - - "Joniskio Rajonas" - - "Jurbarko Rajonas" - - "Kaisiadoriu Rajonas" - - "Kaunas" - - "Kauno Rajonas" - - "Kedainiu Rajonas" - - "Kelmes Rajonas" - - "Klaipeda" - - "Klaipedos Rajonas" - - "Kretingos Rajonas" - - "Kupiskio Rajonas" - - "Lazdiju Rajonas" - - "Marijampole" - - "Marijampoles Rajonas" - - "Mazeikiu Rajonas" - - "Moletu Rajonas" - - "Neringa Pakruojo Rajonas" - - "Palanga" - - "Panevezio Rajonas" - - "Panevezys" - - "Pasvalio Rajonas" - - "Plunges Rajonas" - - "Prienu Rajonas" - - "Radviliskio Rajonas" - - "Raseiniu Rajonas" - - "Rokiskio Rajonas" - - "Sakiu Rajonas" - - "Salcininku Rajonas" - - "Siauliai" - - "Siauliu Rajonas" - - "Silales Rajonas" - - "Silutes Rajonas" - - "Sirvintu Rajonas" - - "Skuodo Rajonas" - - "Svencioniu Rajonas" - - "Taurages Rajonas" - - "Telsiu Rajonas" - - "Traku Rajonas" - - "Ukmerges Rajonas" - - "Utenos Rajonas" - - "Varenos Rajonas" - - "Vilkaviskio Rajonas" - - "Vilniaus Rajonas" - - "Vilnius" - - "Zarasu Rajonas" - -- name: Luxembourg - iso2: LU - iso3: LUX - phone: 352 - units: - - "Diekirch" - - "Grevenmacher" - - "Luxembourg" - -- name: Macao - iso2: MO - iso3: MAC - phone: 853 - units: - - "Macao" - -- name: Macedonia - iso2: MK - iso3: MKD - phone: 389 - units: - - "Aracinovo" - - "Bac" - - "Belcista" - - "Berovo" - - "Bistrica" - - "Bitola" - - "Blatec" - - "Bogdanci" - - "Bogomila" - - "Bogovinje" - - "Bosilovo" - - "Brvenica" - - "Cair [Skopje]" - - "Capari" - - "Caska" - - "Cegrane" - - "Centar [Skopje]" - - "Centar Zupa" - - "Cesinovo" - - "Cucer-Sandevo" - - "Debar" - - "Delcevo" - - "Delogozdi" - - "Demir Hisar" - - "Demir Kapija" - - "Dobrusevo" - - "Dolna Banjica" - - "Dolneni" - - "Dorce Petrov [Skopje]" - - "Drugovo" - - "Dzepciste" - - "Gazi Baba [Skopje]" - - "Gevgelija" - - "Gostivar" - - "Gradsko" - - "Ilinden" - - "Izvor" - - "Jegunovce" - - "Kamenjane" - - "Karbinci" - - "Karpos [Skopje]" - - "Kavadarci" - - "Kicevo" - - "Kisela Voda [Skopje]" - - "Klecevce" - - "Kocani" - - "Konce" - - "Kondovo" - - "Konopiste" - - "Kosel" - - "Kratovo" - - "Kriva Palanka" - - "Krivogastani" - - "Krusevo" - - "Kuklis" - - "Kukurecani" - - "Kumanovo" - - "Labunista" - - "Lipkovo" - - "Lozovo" - - "Lukovo" - - "Makedonska Kamenica" - - "Makedonski Brod" - - "Mavrovi Anovi" - - "Meseista" - - "Miravci" - - "Mogila" - - "Murtino" - - "Negotino" - - "Negotino-Poloska" - - "Novaci" - - "Novo Selo" - - "Oblesevo" - - "Ohrid" - - "Orasac" - - "Orizari" - - "Oslomej" - - "Pehcevo" - - "Petrovec" - - "Plasnia" - - "Podares" - - "Prilep" - - "Probistip" - - "Radovis" - - "Rankovce" - - "Resen" - - "Rosoman" - - "Rostusa" - - "Samokov" - - "Saraj" - - "Sipkovica" - - "Sopiste" - - "Sopotnika" - - "Srbinovo" - - "Star Dojran" - - "Staravina" - - "Staro Nagoricane" - - "Stip" - - "Struga" - - "Strumica" - - "Studenicani" - - "Suto Orizari [Skopje]" - - "Sveti Nikole" - - "Tearce" - - "Tetovo" - - "Topolcani" - - "Valandovo" - - "Vasilevo" - - "Veles" - - "Velesta" - - "Vevcani" - - "Vinica" - - "Vitoliste" - - "Vranestica" - - "Vrapciste" - - "Vratnica" - - "Vrutok" - - "Zajas" - - "Zelenikovo" - - "Zileno" - - "Zitose" - - "Zletovo" - - "Zrnovci" - -- name: Madagascar - iso2: MG - iso3: MDG - phone: 261 - units: - - "Antananarivo" - - "Antsiranana" - - "Fianarantsoa" - - "Mahajanga" - - "Toamasina" - - "Toliara" - -- name: Malawi - iso2: MW - iso3: MWI - phone: 265 - units: - - "Balaka" - - "Blantyre" - - "Chikwawa" - - "Chiradzulu" - - "Chitipa" - - "Dedza" - - "Dowa" - - "Karonga" - - "Kasungu" - - "Likoma" - - "Lilongwe" - - "Machinga [Kasupe]" - - "Mangochi" - - "Mchinji" - - "Mulanje" - - "Mwanza" - - "Mzimba" - - "Nkhata Bay" - - "Nkhotakota" - - "Nsanje" - - "Ntcheu" - - "Ntchisi" - - "Phalombe" - - "Rumphi" - - "Salima" - - "Thyolo" - - "Zomba" - -- name: Malaysia - iso2: MY - iso3: MYS - phone: 60 - units: - - "Johor" - - "Kedah" - - "Kelantan" - - "Labuan" - - "Melaka" - - "Negeri Sembilan" - - "Pahang" - - "Perak" - - "Perlis" - - "Pulau Pinang" - - "Sabah" - - "Sarawak" - - "Selangor" - - "Terengganu" - - "Wilayah Persekutuan" - -- name: Maldives - iso2: MV - iso3: MDV - phone: 960 - units: - - "Alifu" - - "Baa" - - "Dhaalu" - - "Faafu" - - "Gaafu Alifu" - - "Gaafu Dhaalu" - - "Gnaviyani" - - "Haa Alifu" - - "Haa Dhaalu" - - "Kaafu" - - "Laamu" - - "Lhaviyani" - - "Maale" - - "Meemu" - - "Noonu" - - "Raa" - - "Seenu" - - "Shaviyani" - - "Thaa" - - "Vaavu" - -- name: Mali - iso2: ML - iso3: MLI - phone: 223 - units: - - "Gao" - - "Kayes" - - "Kidal" - - "Koulikoro" - - "Mopti" - - "Segou" - - "Sikasso" - - "Tombouctou" - -- name: Malta - iso2: MT - iso3: MLT - phone: 356 - units: - - "Valletta" - -- name: Marshall Islands - iso2: MH - iso3: MHL - phone: 692 - units: - - "Ailinginae" - - "Ailinglaplap" - - "Ailuk" - - "Arno" - - "Aur" - - "Bikar" - - "Bikini" - - "Bokak" - - "Ebon" - - "Enewetak" - - "Erikub" - - "Jabat" - - "Jaluit" - - "Jemo" - - "Kili" - - "Kwajalein" - - "Lae" - - "Lib" - - "Likiep" - - "Majuro" - - "Maloelap" - - "Mejit" - - "Mili" - - "Namorik" - - "Namu" - - "Rongelap" - - "Rongrik" - - "Toke" - - "Ujae" - - "Ujelang" - - "Utirik" - - "Wotho" - - "Wotje" - -- name: Martinique - iso2: MQ - iso3: MTQ - phone: - units: - - "Martinique" - -- name: Mauritania - iso2: MR - iso3: MRT - phone: 222 - units: - - "Adrar" - - "Assaba" - - "Brakna" - - "Dakhlet Nouadhibou" - - "Gorgol" - - "Guidimaka" - - "Hodh Ech Chargui" - - "Hodh El Gharbi" - - "Inchiri" - - "Nouakchott" - - "Tagant" - - "Tiris Zemmour" - - "Trarza" - -- name: Mauritius - iso2: MU - iso3: MUS - phone: 230 - units: - - "Agalega Islands" - - "Black River" - - "Cargados Carajos Shoals" - - "Flacq" - - "Grand Port" - - "Moka" - - "Pamplemousses" - - "Plaines Wilhems" - - "Port Louis" - - "Riviere du Rempart" - - "Rodrigues" - - "Savanne" - -- name: Mayotte - iso2: YT - iso3: MYT - phone: 262 - units: - - "Mayotte" - -- name: Mexico - iso2: MX - iso3: MEX - phone: 52 - units: - - "Aguascalientes" - - "Baja California" - - "Baja California Sur" - - "Campeche" - - "Chiapas" - - "Chihuahua" - - "Coahuila de Zaragoza" - - "Colima" - - "Distrito Federal" - - "Durango" - - "Guanajuato" - - "Guerrero" - - "Hidalgo" - - "Jalisco" - - "Mexico" - - "Michoacan de Ocampo" - - "Morelos" - - "Nayarit" - - "Nuevo Leon" - - "Oaxaca" - - "Puebla" - - "Queretaro de Arteaga" - - "Quintana Roo" - - "San Luis Potosi" - - "Sinaloa" - - "Sonora" - - "Tabasco" - - "Tamaulipas" - - "Tlaxcala" - - "Veracruz-Llave" - - "Yucatan" - - "Zacatecas" - -- name: Micronesia Federated States of - iso2: FM - iso3: FSM - phone: 691 - units: - - "Chuuk [Truk]" - - "Kosrae" - - "Pohnpei" - - "Yap" - -- name: Moldova - iso2: MD - iso3: MDA - phone: 373 - units: - - "Balti" - - "Cahul" - - "Chisinau" - - "Chisinau" - - "Dubasari" - - "Edinet" - - "Gagauzia" - - "Lapusna" - - "Orhei" - - "Soroca" - - "Tighina" - - "Ungheni" - -- name: Monaco - iso2: MC - iso3: MCO - phone: 377 - units: - - "Fontvieille" - - "La Condamine" - - "Monaco-Ville" - - "Monte-Carlo" - -- name: Mongolia - iso2: MN - iso3: MNG - phone: 976 - units: - - "Arhangay" - - "Bayan-Olgiy" - - "Bayanhongor" - - "Bulgan" - - "Darhan" - - "Dornod" - - "Dornogovi" - - "Dundgovi" - - "Dzavhan" - - "Erdenet" - - "Govi-Altay" - - "Hentiy" - - "Hovd" - - "Hovsgol" - - "Omnogovi" - - "Ovorhangay" - - "Selenge" - - "Suhbaatar" - - "Tov" - - "Ulaanbaatar" - - "Uvs" - -- name: Montenegro - iso2: ME - iso3: MNE - phone: 382 - units: - - "Montenegro" - -- name: Montserrat - iso2: MS - iso3: MSR - phone: 1 664 - units: - - "Saint Anthony" - - "Saint Georges" - - "Saint Peter's" - -- name: Morocco - iso2: MA - iso3: MAR - phone: 212 - units: - - "Agadir" - - "Al Hoceima" - - "Azilal" - - "Ben Slimane" - - "Beni Mellal" - - "Boulemane" - - "Casablanca" - - "Chaouen" - - "El Jadida" - - "El Kelaa des Srarhna" - - "Er Rachidia" - - "Essaouira" - - "Fes" - - "Figuig" - - "Guelmim" - - "Ifrane" - - "Kenitra" - - "Khemisset" - - "Khenifra" - - "Khouribga" - - "Laayoune" - - "Larache" - - "Marrakech" - - "Meknes" - - "Nador" - - "Ouarzazate" - - "Oujda" - - "Rabat-Sale" - - "Safi" - - "Settat" - - "Sidi Kacem" - - "Tan-Tan" - - "Tanger" - - "Taounate" - - "Taroudannt" - - "Tata" - - "Taza" - - "Tetouan" - - "Tiznit" - -- name: Mozambique - iso2: MZ - iso3: MOZ - phone: 258 - units: - - "Cabo Delgado" - - "Gaza" - - "Inhambane" - - "Manica" - - "Maputo" - - "Nampula" - - "Niassa" - - "Sofala" - - "Tete" - - "Zambezia" - -- name: Myanmar - iso2: MM - iso3: MMR - phone: 95 - units: - - "Ayeyarwady" - - "Bago" - - "Chin State" - - "Kachin State" - - "Kayah State" - - "Kayin State" - - "Magway" - - "Mandalay" - - "Mon State" - - "Rakhine State" - - "Sagaing" - - "Shan State" - - "Tanintharyi" - - "Yangon" - -- name: Namibia - iso2: NA - iso3: NAM - phone: 264 - units: - - "Caprivi" - - "Erongo" - - "Hardap" - - "Karas" - - "Khomas" - - "Kunene" - - "Ohangwena" - - "Okavango" - - "Omaheke" - - "Omusati" - - "Oshana" - - "Oshikoto" - - "Otjozondjupa" - -- name: Nauru - iso2: NR - iso3: NRU - phone: 674 - units: - - "Aiwo" - - "Anabar" - - "Anetan" - - "Anibare" - - "Baiti" - - "Boe" - - "Buada" - - "Denigomodu" - - "Ewa" - - "Ijuw" - - "Meneng" - - "Nibok" - - "Uaboe" - - "Yaren" - -- name: Nepal - iso2: NP - iso3: NPL - phone: 977 - units: - - "Bagmati" - - "Bheri" - - "Dhawalagiri" - - "Gandaki" - - "Janakpur" - - "Karnali" - - "Kosi" - - "Lumbini" - - "Mahakali" - - "Mechi" - - "Narayani" - - "Rapti" - - "Sagarmatha" - - "Seti" - -- name: Netherlands - iso2: NL - iso3: NLD - phone: 31 - units: - - "Drenthe" - - "Flevoland" - - "Friesland" - - "Gelderland" - - "Groningen" - - "Limburg" - - "Noord-Brabant" - - "Noord-Holland" - - "Overijssel" - - "Utrecht" - - "Zeeland" - - "Zuid-Holland" - -- name: New Caledonia - iso2: NC - iso3: NCL - phone: 687 - units: - - "Iles Loyaute" - - "Nord" - - "Sud" - -- name: New Zealand - iso2: NZ - iso3: NZL - phone: 64 - units: - - "Akaroa" - - "Amuri" - - "Ashburton" - - "Bay of Islands" - - "Bruce" - - "Buller" - - "Chatham Islands" - - "Cheviot" - - "Clifton" - - "Clutha" - - "Cook" - - "Dannevirke" - - "Egmont" - - "Eketahuna" - - "Ellesmere" - - "Eltham" - - "Eyre" - - "Featherston" - - "Franklin" - - "Golden Bay" - - "Great Barrier Island" - - "Grey" - - "Hauraki Plains" - - "Hawera" - - "Hawke's Bay" - - "Heathcote" - - "Hikurangi" - - "Hobson" - - "Hokianga" - - "Horowhenua" - - "Hurunui" - - "Hutt" - - "Inangahua" - - "Inglewood" - - "Kaikoura" - - "Kairanga" - - "Kiwitea" - - "Lake" - - "Mackenzie" - - "Malvern" - - "Manaia" - - "Manawatu" - - "Mangonui" - - "Maniototo" - - "Marlborough" - - "Masterton" - - "Matamata" - - "Mount Herbert" - - "Ohinemuri" - - "Opotiki" - - "Oroua" - - "Otamatea" - - "Otorohanga" - - "Oxford" - - "Pahiatua" - - "Paparua" - - "Patea" - - "Piako" - - "Pohangina" - - "Raglan" - - "Rangiora" - - "Rangitikei" - - "Rodney" - - "Rotorua" - - "Runanga" - - "Saint Kilda" - - "Silverpeaks" - - "Southland" - - "Stewart Island" - - "Stratford" - - "Strathallan" - - "Taranaki" - - "Taumarunui" - - "Taupo" - - "Tauranga" - - "Thames-Coromandel" - - "Tuapeka" - - "Vincent" - - "Waiapu" - - "Waiheke" - - "Waihemo" - - "Waikato" - - "Waikohu" - - "Waimairi" - - "Waimarino" - - "Waimate" - - "Waimate West" - - "Waimea" - - "Waipa" - - "Waipawa" - - "Waipukurau" - - "Wairarapa South" - - "Wairewa" - - "Wairoa" - - "Waitaki" - - "Waitomo" - - "Waitotara" - - "Wallace" - - "Wanganui" - - "Waverley" - - "Westland" - - "Whakatane" - - "Whangarei" - - "Whangaroa" - - "Woodville" - -- name: Nicaragua - iso2: NI - iso3: NIC - phone: 505 - units: - - "Atlantico Norte" - - "Atlantico Sur" - - "Boaco" - - "Carazo" - - "Chinandega" - - "Chontales" - - "Esteli" - - "Granada" - - "Jinotega" - - "Leon" - - "Madriz" - - "Managua" - - "Masaya" - - "Matagalpa" - - "Nueva Segovia" - - "Rio San Juan" - - "Rivas" - -- name: Niger - iso2: NE - iso3: NER - phone: 227 - units: - - "Agadez" - - "Diffa" - - "Dosso" - - "Maradi" - - "Niamey" - - "Tahoua" - - "Tillaberi" - - "Zinder" - -- name: Nigeria - iso2: NG - iso3: NGA - phone: 234 - units: - - "Abia" - - "Abuja Federal Capital Territory" - - "Adamawa" - - "Akwa Ibom" - - "Anambra" - - "Bauchi" - - "Bayelsa" - - "Benue" - - "Borno" - - "Cross River" - - "Delta" - - "Ebonyi" - - "Edo" - - "Ekiti" - - "Enugu" - - "Gombe" - - "Imo" - - "Jigawa" - - "Kaduna" - - "Kano" - - "Katsina" - - "Kebbi" - - "Kogi" - - "Kwara" - - "Lagos" - - "Nassarawa" - - "Niger" - - "Ogun" - - "Ondo" - - "Osun" - - "Oyo" - - "Plateau" - - "Rivers" - - "Sokoto" - - "Taraba" - - "Yobe" - - "Zamfara" - -- name: Niue - iso2: NU - iso3: NIU - phone: 683 - units: - - "Niue" - -- name: Norfolk Island - iso2: NF - iso3: NFK - phone: - units: - - "Norfolk Island" - -- name: Northern Mariana Islands - iso2: MP - iso3: MNP - phone: 1 670 - units: - - "Northern Islands" - - "Rota" - - "Saipan" - - "Tinian" - -- name: Norway - iso2: NO - iso3: NOR - phone: 47 - units: - - "Akershus" - - "Aust-Agder" - - "Buskerud" - - "Finnmark" - - "Hedmark" - - "Hordaland" - - "More og Romsdal" - - "Nord-Trondelag" - - "Nordland" - - "Oppland" - - "Oslo" - - "Ostfold" - - "Rogaland" - - "Sogn og Fjordane" - - "Sor-Trondelag" - - "Telemark" - - "Troms" - - "Vest-Agder" - - "Vestfold" - -- name: Oman - iso2: OM - iso3: OMN - phone: 968 - units: - - "Ad Dakhiliyah" - - "Al Batinah" - - "Al Wusta" - - "Ash Sharqiyah" - - "Az Zahirah" - - "Masqat" - - "Musandam" - - "Zufar" - -- name: Pakistan - iso2: PK - iso3: PAK - phone: 92 - units: - - "Balochistan" - - "Federally Administered Tribal Areas" - - "Islamabad Capital Territory" - - "North-West Frontier Province" - - "Punjab" - - "Sindh" - -- name: Palau - iso2: PW - iso3: PLW - phone: 680 - units: - - "Aimeliik" - - "Airai" - - "Angaur" - - "Hatobohei" - - "Kayangel" - - "Koror" - - "Melekeok" - - "Ngaraard" - - "Ngarchelong" - - "Ngardmau" - - "Ngatpang" - - "Ngchesar" - - "Ngeremlengui" - - "Ngiwal" - - "Palau Island" - - "Peleliu" - - "Sonsoral" - - "Tobi" - -- name: Palestinian Territory Occupied - iso2: PS - iso3: PSE - phone: - units: - - "West Bank" - - "Gaza Strip" - -- name: Panama - iso2: PA - iso3: PAN - phone: 507 - units: - - "Bocas del Toro" - - "Chiriqui" - - "Cocle" - - "Colon" - - "Darien" - - "Herrera" - - "Los Santos" - - "Panama" - - "San Blas" - - "Veraguas" - -- name: Papua New Guinea - iso2: PG - iso3: PNG - phone: 675 - units: - - "Bougainville" - - "Central" - - "Chimbu" - - "East New Britain" - - "East Sepik" - - "Eastern Highlands" - - "Enga" - - "Gulf" - - "Madang" - - "Manus" - - "Milne Bay" - - "Morobe" - - "National Capital" - - "New Ireland" - - "Northern" - - "Sandaun" - - "Southern Highlands" - - "West New Britain" - - "Western" - - "Western Highlands" - -- name: Paraguay - iso2: PY - iso3: PRY - phone: 595 - units: - - "Alto Paraguay" - - "Alto Parana" - - "Amambay" - - "Asuncion [city]" - - "Boqueron" - - "Caaguazu" - - "Caazapa" - - "Canindeyu" - - "Central" - - "Concepcion" - - "Cordillera" - - "Guaira" - - "Itapua" - - "Misiones" - - "Neembucu" - - "Paraguari" - - "Presidente Hayes" - - "San Pedro" - -- name: Peru - iso2: PE - iso3: PER - phone: 51 - units: - - "Amazonas" - - "Ancash" - - "Apurimac" - - "Arequipa" - - "Ayacucho" - - "Cajamarca" - - "Callao" - - "Cusco" - - "Huancavelica" - - "Huanuco" - - "Ica" - - "Junin" - - "La Libertad" - - "Lambayeque" - - "Lima" - - "Loreto" - - "Madre de Dios" - - "Moquegua" - - "Pasco" - - "Piura" - - "Puno" - - "San Martin" - - "Tacna" - - "Tumbes" - - "Ucayali" - -- name: Philippines - iso2: PH - iso3: PHL - phone: 63 - units: - - "Abra" - - "Agusan del Norte" - - "Agusan del Sur" - - "Aklan" - - "Albay" - - "Angeles" - - "Antique" - - "Aurora" - - "Bacolod" - - "Bago" - - "Baguio" - - "Bais" - - "Basilan" - - "Basilan City" - - "Bataan" - - "Batanes" - - "Batangas" - - "Batangas City" - - "Benguet" - - "Bohol" - - "Bukidnon" - - "Bulacan" - - "Butuan" - - "Cabanatuan" - - "Cadiz" - - "Cagayan" - - "Cagayan de Oro" - - "Calbayog" - - "Caloocan" - - "Camarines Norte" - - "Camarines Sur" - - "Camiguin" - - "Canlaon" - - "Capiz" - - "Catanduanes" - - "Cavite" - - "Cavite City" - - "Cebu" - - "Cebu City" - - "Cotabato" - - "Dagupan" - - "Danao" - - "Dapitan" - - "Davao City Davao" - - "Davao del Sur" - - "Davao Oriental" - - "Dipolog" - - "Dumaguete" - - "Eastern Samar" - - "General Santos" - - "Gingoog" - - "Ifugao" - - "Iligan" - - "Ilocos Norte" - - "Ilocos Sur" - - "Iloilo" - - "Iloilo City" - - "Iriga" - - "Isabela" - - "Kalinga-Apayao" - - "La Carlota" - - "La Union" - - "Laguna" - - "Lanao del Norte" - - "Lanao del Sur" - - "Laoag" - - "Lapu-Lapu" - - "Legaspi" - - "Leyte" - - "Lipa" - - "Lucena" - - "Maguindanao" - - "Mandaue" - - "Manila" - - "Marawi" - - "Marinduque" - - "Masbate" - - "Mindoro Occidental" - - "Mindoro Oriental" - - "Misamis Occidental" - - "Misamis Oriental" - - "Mountain" - - "Naga" - - "Negros Occidental" - - "Negros Oriental" - - "North Cotabato" - - "Northern Samar" - - "Nueva Ecija" - - "Nueva Vizcaya" - - "Olongapo" - - "Ormoc" - - "Oroquieta" - - "Ozamis" - - "Pagadian" - - "Palawan" - - "Palayan" - - "Pampanga" - - "Pangasinan" - - "Pasay" - - "Puerto Princesa" - - "Quezon" - - "Quezon City" - - "Quirino" - - "Rizal" - - "Romblon" - - "Roxas" - - "Samar" - - "San Carlos [in Negros Occidental]" - - "San Carlos [in Pangasinan]" - - "San Jose" - - "San Pablo" - - "Silay" - - "Siquijor" - - "Sorsogon" - - "South Cotabato" - - "Southern Leyte" - - "Sultan Kudarat" - - "Sulu" - - "Surigao" - - "Surigao del Norte" - - "Surigao del Sur" - - "Tacloban" - - "Tagaytay" - - "Tagbilaran" - - "Tangub" - - "Tarlac" - - "Tawitawi" - - "Toledo" - - "Trece Martires" - - "Zambales" - - "Zamboanga" - - "Zamboanga del Norte" - - "Zamboanga del Sur" - -- name: Pitcairn - iso2: PN - iso3: PCN - phone: 870 - units: - - "Pitcarin Islands" - -- name: Poland - iso2: PL - iso3: POL - phone: 48 - units: - - "Dolnoslaskie" - - "Kujawsko-Pomorskie" - - "Lodzkie" - - "Lubelskie" - - "Lubuskie" - - "Malopolskie" - - "Mazowieckie" - - "Opolskie" - - "Podkarpackie" - - "Podlaskie" - - "Pomorskie" - - "Slaskie" - - "Swietokrzyskie" - - "Warminsko-Mazurskie" - - "Wielkopolskie" - - "Zachodniopomorskie" - -- name: Portugal - iso2: PT - iso3: PRT - phone: 351 - units: - - "Acores [Azores]" - - "Aveiro" - - "Beja" - - "Braga" - - "Braganca" - - "Castelo Branco" - - "Coimbra" - - "Evora" - - "Faro" - - "Guarda" - - "Leiria" - - "Lisboa" - - "Madeira" - - "Portalegre" - - "Porto" - - "Santarem" - - "Setubal" - - "Viana do Castelo" - - "Vila Real" - - "Viseu" - -- name: Puerto Rico - iso2: PR - iso3: PRI - phone: 1 - units: - - "Adjuntas" - - "Aguada" - - "Aguadilla" - - "Aguas Buenas" - - "Aibonito" - - "Anasco" - - "Arecibo" - - "Arroyo" - - "Barceloneta" - - "Barranquitas" - - "Bayamon" - - "Cabo Rojo" - - "Caguas" - - "Camuy" - - "Canovanas" - - "Carolina" - - "Catano" - - "Cayey" - - "Ceiba" - - "Ciales" - - "Cidra" - - "Coamo" - - "Comerio" - - "Corozal" - - "Culebra" - - "Dorado" - - "Fajardo" - - "Florida" - - "Guanica" - - "Guayama" - - "Guayanilla" - - "Guaynabo" - - "Gurabo" - - "Hatillo" - - "Hormigueros" - - "Humacao" - - "Isabela" - - "Jayuya" - - "Juana Diaz" - - "Juncos" - - "Lajas" - - "Lares" - - "Las Marias" - - "Las Piedras" - - "Loiza" - - "Luquillo" - - "Manati" - - "Maricao" - - "Maunabo" - - "Mayaguez" - - "Moca" - - "Morovis" - - "Naguabo" - - "Naranjito" - - "Orocovis" - - "Patillas" - - "Penuelas" - - "Ponce" - - "Quebradillas" - - "Rincon" - - "Rio Grande" - - "Sabana Grande" - - "Salinas" - - "San German" - - "San Juan" - - "San Lorenzo" - - "San Sebastian" - - "Santa Isabel" - - "Toa Alta" - - "Toa Baja" - - "Trujillo Alto" - - "Utuado" - - "Vega Alta" - - "Vega Baja" - - "Vieques" - - "Villalba" - - "Yabucoa" - - "Yauco" - -- name: Qatar - iso2: QA - iso3: QAT - phone: 974 - units: - - "Ad Dawhah" - - "Al Ghuwayriyah" - - "Al Jumayliyah" - - "Al Khawr" - - "Al Wakrah" - - "Ar Rayyan" - - "Jarayan al Batinah" - - "Madinat ash Shamal" - - "Umm Salal" - -- name: Reunion - iso2: RE - iso3: REU - phone: - units: - - "Reunion" - -- name: Romania - iso2: RO - iso3: ROU - phone: 40 - units: - - "Alba" - - "Arad" - - "Arges" - - "Bacau" - - "Bihor" - - "Bistrita-Nasaud" - - "Botosani" - - "Braila" - - "Brasov" - - "Bucuresti" - - "Buzau" - - "Calarasi" - - "Caras-Severin" - - "Cluj" - - "Constanta" - - "Covasna" - - "Dimbovita" - - "Dolj" - - "Galati" - - "Giurgiu" - - "Gorj" - - "Harghita" - - "Hunedoara" - - "Ialomita" - - "Iasi" - - "Maramures" - - "Mehedinti" - - "Mures" - - "Neamt" - - "Olt" - - "Prahova" - - "Salaj" - - "Satu Mare" - - "Sibiu" - - "Suceava" - - "Teleorman" - - "Timis" - - "Tulcea" - - "Vaslui" - - "Vilcea" - - "Vrancea" - -- name: Russian Federation - iso2: RU - iso3: RUS - phone: 7 - units: - - "Республика Адыгея" - - "Республика Алтай" - - "Амурская область" - - "Архангельская область" - - "Астраханская область" - - "Республика Башкортостан" - - "Белгородская область" - - "Брянская область" - - "Республика Бурятия" - - "Чеченская Республика" - - "Челябинская область" - - "Чукотский АО" - - "Чувашская Республика" - - "Республика Дагестан" - - "Республика Ингушетия" - - "Иркутская область" - - "Ивановская область" - - "Камчатский край" - - "Кабардино-Балкарская Республика" - - "Карачаево-Черкесская Республика" - - "Краснодарский край" - - "Кемеровская область" - - "Калининградская область" - - "Курганская область" - - "Хабаровский край" - - "Ханты-Мансийский АО" - - "Кировская область" - - "Республика Хакасия" - - "Республика Калмыкия" - - "Калужская область" - - "Республика Коми" - - "Костромская область" - - "Республика Карелия" - - "Курская область" - - "Красноярский край" - - "Ленинградская область" - - "Липецкая область" - - "Алтайский край" - - "Магаданская область" - - "Республика Марий Эл" - - "Республика Мордовия" - - "Московская область" - - "Москва" - - "Мурманская область" - - "Ненецкий АО" - - "Новгородская область" - - "Нижегородская область" - - "Новосибирская область" - - "Омская область" - - "Оренбургская область" - - "Орловская область" - - "Пермский край" - - "Пензенская область" - - "Приморский край" - - "Псковская область" - - "Ростовская область" - - "Рязанская область" - - "Республика Саха [Якутия]" - - "Сахалинская область" - - "Самарская область" - - "Саратовская область" - - "Республика Сев. Осетия-Алания" - - "Смоленская область" - - "Санкт-Петербург" - - "Ставропольский край" - - "Свердловская область" - - "Республика Татарстан" - - "Тамбовская область" - - "Томская область" - - "Тульская область" - - "Тверская область" - - "Республика Тыва" - - "Тюменская область" - - "Удмуртская Республика" - - "Ульяновская область" - - "Волгоградская область" - - "Владимирская область" - - "Вологодская область" - - "Воронежская область" - - "Ямало-Ненецкий АО" - - "Ярославская область" - - "Еврейская АО" - - "Забайкальский край" - -- name: Rwanda - iso2: RW - iso3: RWA - phone: 250 - units: - - "Butare" - - "Byumba" - - "Cyangugu" - - "Gikongoro" - - "Gisenyi" - - "Gitarama" - - "Kibungo" - - "Kibuye" - - "Kigali Rurale" - - "Kigali-ville" - - "Ruhengeri" - - "Umutara" - -- name: Saint Barthelemy - iso2: BL - iso3: BLM - phone: 590 - units: - - "Saint Barthelemy" - -- name: Saint Helena Ascension and Tristan da Cunha - iso2: SH - iso3: SHN - phone: 290 - units: - - "Ascension" - - "Saint Helena" - - "Tristan da Cunha" - -- name: Saint Kitts and Nevis - iso2: KN - iso3: KNA - phone: 1 869 - units: - - "Christ Church Nichola Town" - - "Saint Anne Sandy Point" - - "Saint George Basseterre" - - "Saint George Gingerland" - - "Saint James Windward" - - "Saint John Capisterre" - - "Saint John Figtree" - - "Saint Mary Cayon" - - "Saint Paul Capisterre" - - "Saint Paul Charlestown" - - "Saint Peter Basseterre" - - "Saint Thomas Lowland" - - "Saint Thomas Middle Island" - - "Trinity Palmetto Point" - -- name: Saint Lucia - iso2: LC - iso3: LCA - phone: 1 758 - units: - - "Anse-la-Raye" - - "Castries" - - "Choiseul" - - "Dauphin" - - "Dennery" - - "Gros Islet" - - "Laborie" - - "Micoud" - - "Praslin" - - "Soufriere" - - "Vieux Fort" - -- name: Saint Martin [French part] - iso2: MF - iso3: MAF - phone: 1 599 - units: - - "Saint Martin [French part]" - -- name: Saint Pierre and Miquelon - iso2: PM - iso3: SPM - phone: 508 - units: - - "Miquelon" - - "Saint Pierre" - -- name: Saint Vincent and the Grenadines - iso2: VC - iso3: VCT - phone: 1 784 - units: - - "Charlotte" - - "Grenadines" - - "Saint Andrew" - - "Saint David" - - "Saint George" - - "Saint Patrick" - -- name: Samoa - iso2: WS - iso3: WSM - phone: 685 - units: - - "A'ana" - - "Aiga-i-le-Tai" - - "Atua" - - "Fa'asaleleaga" - - "Gaga'emauga" - - "Gagaifomauga" - - "Palauli" - - "Satupa'itea" - - "Tuamasaga" - - "Va'a-o-Fonoti" - - "Vaisigano" - -- name: San Marino - iso2: SM - iso3: SMR - phone: 378 - units: - - "Acquaviva" - - "Borgo Maggiore" - - "Chiesanuova" - - "Domagnano" - - "Faetano" - - "Fiorentino" - - "Monte Giardino" - - "San Marino" - - "Serravalle" - -- name: Sao Tome and Principe - iso2: ST - iso3: STP - phone: 239 - units: - - "Principe" - - "Sao Tome" - -- name: Saudi Arabia - iso2: SA - iso3: SAU - phone: 966 - units: - - "'Asir" - - "Al Bahah" - - "Al Hudud ash Shamaliyah" - - "Al Jawf" - - "Al Madinah" - - "Al Qasim" - - "Ar Riyad" - - "Ash Sharqiyah [Eastern Province]" - - "Ha'il" - - "Jizan" - - "Makkah" - - "Najran" - - "Tabuk" - -- name: Senegal - iso2: SN - iso3: SEN - phone: 221 - units: - - "Dakar" - - "Diourbel" - - "Fatick" - - "Kaolack" - - "Kolda" - - "Louga" - - "Saint-Louis" - - "Tambacounda" - - "Thies" - - "Ziguinchor" - -- name: Serbia - iso2: RS - iso3: SRB - phone: 381 - units: - - "Serbia" - -- name: Seychelles - iso2: SC - iso3: SYC - phone: 248 - units: - - "Anse aux Pins" - - "Anse Boileau" - - "Anse Etoile" - - "Anse Louis" - - "Anse Royale" - - "Baie Lazare" - - "Baie Sainte Anne" - - "Beau Vallon" - - "Bel Air" - - "Bel Ombre" - - "Cascade" - - "Glacis" - - "Grand' Anse [on Mahe]" - - "Grand' Anse [on Praslin]" - - "La Digue" - - "La Riviere Anglaise" - - "Mont Buxton" - - "Mont Fleuri" - - "Plaisance" - - "Pointe La Rue" - - "Port Glaud" - - "Saint Louis" - - "Takamaka" - -- name: Sierra Leone - iso2: SL - iso3: SLE - phone: 232 - units: - - "Eastern" - - "Northern" - - "Southern" - - "Western" - -- name: Singapore - iso2: SG - iso3: SGP - phone: 65 - units: - - "Singapore" - -- name: Sint Maarten [Dutch part] - iso2: SX - iso3: SXM - phone: - units: - - "Sint Maarten [Dutch part]" - -- name: Slovakia - iso2: SK - iso3: SVK - phone: 421 - units: - - "Banskobystricky" - - "Bratislavsky" - - "Kosicky" - - "Nitriansky" - - "Presovsky" - - "Trenciansky" - - "Trnavsky" - - "Zilinsky" - -- name: Slovenia - iso2: SI - iso3: SVN - phone: 386 - units: - - "Ajdovscina" - - "Beltinci" - - "Bled" - - "Bohinj" - - "Borovnica" - - "Bovec" - - "Brda" - - "Brezice" - - "Brezovica" - - "Cankova-Tisina" - - "Celje" - - "Cerklje na Gorenjskem" - - "Cerknica" - - "Cerkno" - - "Crensovci" - - "Crna na Koroskem" - - "Crnomelj" - - "Destrnik-Trnovska Vas" - - "Divaca" - - "Dobrepolje" - - "Dobrova-Horjul-Polhov Gradec" - - "Dol pri Ljubljani" - - "Domzale" - - "Dornava" - - "Dravograd" - - "Duplek" - - "Gorenja Vas-Poljane" - - "Gorisnica" - - "Gornja Radgona" - - "Gornji Grad" - - "Gornji Petrovci" - - "Grosuplje" - - "Hodos Salovci" - - "Hrastnik" - - "Hrpelje-Kozina" - - "Idrija" - - "Ig" - - "Ilirska Bistrica" - - "Ivancna Gorica" - - "Izola" - - "Jesenice" - - "Jursinci" - - "Kamnik" - - "Kanal" - - "Kidricevo" - - "Kobarid" - - "Kobilje" - - "Kocevje" - - "Komen" - - "Koper" - - "Kozje" - - "Kranj" - - "Kranjska Gora" - - "Krsko" - - "Kungota" - - "Kuzma" - - "Lasko" - - "Lenart" - - "Lendava" - - "Litija" - - "Ljubljana" - - "Ljubno" - - "Ljutomer" - - "Logatec" - - "Loska Dolina" - - "Loski Potok" - - "Luce" - - "Lukovica" - - "Majsperk" - - "Maribor" - - "Medvode" - - "Menges" - - "Metlika" - - "Mezica" - - "Miren-Kostanjevica" - - "Mislinja" - - "Moravce" - - "Moravske Toplice" - - "Mozirje" - - "Murska Sobota" - - "Muta" - - "Naklo" - - "Nazarje" - - "Nova Gorica" - - "Novo Mesto" - - "Odranci" - - "Ormoz" - - "Osilnica" - - "Pesnica" - - "Piran" - - "Pivka" - - "Podcetrtek" - - "Podvelka-Ribnica" - - "Postojna" - - "Preddvor" - - "Ptuj" - - "Puconci" - - "Race-Fram" - - "Radece" - - "Radenci" - - "Radlje ob Dravi" - - "Radovljica" - - "Ravne-Prevalje" - - "Ribnica" - - "Rogasevci" - - "Rogaska Slatina" - - "Rogatec" - - "Ruse" - - "Semic" - - "Sencur" - - "Sentilj" - - "Sentjernej" - - "Sentjur pri Celju" - - "Sevnica" - - "Sezana" - - "Skocjan" - - "Skofja Loka" - - "Skofljica" - - "Slovenj Gradec" - - "Slovenska Bistrica" - - "Slovenske Konjice" - - "Smarje pri Jelsah" - - "Smartno ob Paki" - - "Sostanj" - - "Starse" - - "Store" - - "Sveti Jurij" - - "Tolmin" - - "Trbovlje" - - "Trebnje" - - "Trzic" - - "Turnisce" - - "Velenje" - - "Velike Lasce" - - "Videm" - - "Vipava" - - "Vitanje" - - "Vodice" - - "Vojnik" - - "Vrhnika" - - "Vuzenica" - - "Zagorje ob Savi" - - "Zalec" - - "Zavrc" - - "Zelezniki" - - "Ziri" - - "Zrece" - -- name: Solomon Islands - iso2: SB - iso3: SLB - phone: 677 - units: - - "Bellona" - - "Central" - - "Choiseul [Lauru]" - - "Guadalcanal" - - "Honiara" - - "Isabel" - - "Makira" - - "Malaita" - - "Rennell" - - "Temotu" - - "Western" - -- name: Somalia - iso2: SO - iso3: SOM - phone: 252 - units: - - "Awdal" - - "Bakool" - - "Banaadir" - - "Bari" - - "Bay" - - "Galguduud" - - "Gedo" - - "Hiiraan" - - "Jubbada Dhexe" - - "Jubbada Hoose" - - "Mudug" - - "Nugaal" - - "Sanaag" - - "Shabeellaha Dhexe" - - "Shabeellaha Hoose" - - "Sool" - - "Togdheer" - - "Woqooyi Galbeed" - -- name: South Africa - iso2: ZA - iso3: ZAF - phone: 27 - units: - - "Eastern Cape" - - "Free State" - - "Gauteng" - - "KwaZulu-Natal" - - "Limpopo" - - "Mpumalanga" - - "North West" - - "Northern Cape" - - "Western Cape" - -- name: South Georgia and the South Sandwich Islands - iso2: GS - iso3: SGS - phone: - units: - - "Bird Island" - - "Bristol Island" - - "Clerke Rocks" - - "Montagu Island" - - "Saunders Island" - - "South Georgia" - - "Southern Thule" - - "Traversay Islands" - -- name: South Sudan - iso2: SS - iso3: SSD - phone: - units: - - "South Sudan" - -- name: Spain - iso2: ES - iso3: ESP - phone: 34 - units: - - "Albacete" - - "Alicante" - - "Almería" - - "Asturias" - - "Badajoz" - - "Balearic Islands" - - "Barcelona" - - "Biscay" - - "Burgos" - - "Cantabria" - - "Castellón" - - "Ciudad Real" - - "Cuenca" - - "Cáceres" - - "Cádiz" - - "Córdoba" - - "Gerona" - - "Granada" - - "Guadalajara" - - "Guipúzcoa" - - "Huelva" - - "Huesca" - - "Jaén" - - "La Coruña" - - "La Rioja" - - "Las Palmas" - - "León" - - "Lugo" - - "Lérida" - - "Madrid" - - "Murcia" - - "Málaga" - - "Navarre" - - "Orense" - - "Palencia" - - "Pontevedra" - - "Salamanca" - - "Santa Cruz" - - "Segovia" - - "Sevilla" - - "Soria" - - "Tarragona" - - "Teruel" - - "Toledo" - - "Valencia" - - "Valladolid" - - "Zamora" - - "Zaragoza" - - "Álava" - - "Ávila" - -- name: Sri Lanka - iso2: LK - iso3: LKA - phone: 94 - units: - - "Central" - - "Eastern" - - "North Central" - - "North Eastern" - - "North Western" - - "Northern" - - "Sabaragamuwa" - - "Southern" - - "Uva" - - "Western" - -- name: Sudan - iso2: SD - iso3: SDN - phone: 249 - units: - - "A'ali an Nil" - - "Al Bahr al Ahmar" - - "Al Buhayrat" - - "Al Jazirah" - - "Al Khartum" - - "Al Qadarif" - - "Al Wahdah" - - "An Nil al Abyad" - - "An Nil al Azraq" - - "Ash Shamaliyah" - - "Bahr al Jabal" - - "Gharb al Istiwa'iyah" - - "Gharb Bahr al Ghazal" - - "Gharb Darfur" - - "Gharb Kurdufan" - - "Janub Darfur" - - "Janub Kurdufan" - - "Junqali" - - "Kassala" - - "Nahr an Nil" - - "Shamal Bahr al Ghazal" - - "Shamal Darfur" - - "Shamal Kurdufan" - - "Sharq al Istiwa'iyah" - - "Sinnar" - - "Warab" - -- name: Suriname - iso2: SR - iso3: SUR - phone: 597 - units: - - "Brokopondo" - - "Commewijne" - - "Coronie" - - "Marowijne" - - "Nickerie" - - "Para" - - "Paramaribo" - - "Saramacca" - - "Sipaliwini" - - "Wanica" - -- name: Svalbard and Jan Mayen - iso2: SJ - iso3: SJM - phone: - units: - - "Barentsoya" - - "Bjornoya" - - "Edgeoya" - - "Hopen" - - "Kvitoya" - - "Nordaustandet" - - "Prins Karls Forland" - - "Spitsbergen" - -- name: Swaziland - iso2: SZ - iso3: SWZ - phone: 268 - units: - - "Hhohho" - - "Lubombo" - - "Manzini" - - "Shiselweni" - -- name: Sweden - iso2: SE - iso3: SWE - phone: 46 - units: - - "Blekinge" - - "Dalarnas" - - "Gavleborgs" - - "Gotlands" - - "Hallands" - - "Jamtlands" - - "Jonkopings" - - "Kalmar" - - "Kronobergs" - - "Norrbottens" - - "Orebro" - - "Ostergotlands" - - "Skane" - - "Sodermanlands" - - "Stockholms" - - "Uppsala" - - "Varmlands" - - "Vasterbottens" - - "Vasternorrlands" - - "Vastmanlands" - - "Vastra Gotalands" - -- name: Switzerland - iso2: CH - iso3: CHE - phone: 41 - units: - - "Aargau" - - "Ausser-Rhoden" - - "Basel-Landschaft" - - "Basel-Stadt" - - "Bern" - - "Fribourg" - - "Geneve" - - "Glarus" - - "Graubunden" - - "Inner-Rhoden" - - "Jura" - - "Luzern" - - "Neuchatel" - - "Nidwalden" - - "Obwalden" - - "Sankt Gallen" - - "Schaffhausen" - - "Schwyz" - - "Solothurn" - - "Thurgau" - - "Ticino" - - "Uri" - - "Valais" - - "Vaud" - - "Zug" - - "Zurich" - -- name: Syrian Arab Republic - iso2: SY - iso3: SYR - phone: 963 - units: - - "Al Hasakah" - - "Al Ladhiqiyah" - - "Al Qunaytirah" - - "Ar Raqqah" - - "As Suwayda'" - - "Dar'a" - - "Dayr az Zawr" - - "Dimashq" - - "Halab" - - "Hamah" - - "Hims" - - "Idlib" - - "Rif Dimashq" - - "Tartus" - -- name: Taiwan - iso2: TW - iso3: TWN - phone: 886 - units: - - "Chang-hua" - - "Chi-lung" - - "Chia-i" - - "Chia-i" - - "Chung-hsing-hsin-ts'un" - - "Hsin-chu" - - "Hsin-chu" - - "Hua-lien" - - "I-lan" - - "Kao-hsiung" - - "Kao-hsiung" - - "Miao-li" - - "Nan-t'ou" - - "P'eng-hu" - - "P'ing-tung" - - "T'ai-chung" - - "T'ai-chung" - - "T'ai-nan" - - "T'ai-nan" - - "T'ai-pei" - - "T'ai-pei" - - "T'ai-tung" - - "T'ao-yuan" - - "Yun-lin" - -- name: Tajikistan - iso2: TJ - iso3: TJK - phone: 992 - units: - - "Viloyati Khatlon" - - "Viloyati Leninobod" - - "Viloyati Mukhtori Kuhistoni Badakhshon" - -- name: Tanzania United Republic of - iso2: TZ - iso3: TZA - phone: 255 - units: - - "Arusha" - - "Dar es Salaam" - - "Dodoma" - - "Iringa" - - "Kagera" - - "Kigoma" - - "Kilimanjaro" - - "Lindi" - - "Mara" - - "Mbeya" - - "Morogoro" - - "Mtwara" - - "Mwanza" - - "Pemba North" - - "Pemba South" - - "Pwani" - - "Rukwa" - - "Ruvuma" - - "Shinyanga" - - "Singida" - - "Tabora" - - "Tanga" - - "Zanzibar Central/South" - - "Zanzibar North" - - "Zanzibar Urban/West" - -- name: Thailand - iso2: TH - iso3: THA - phone: 66 - units: - - "Amnat Charoen" - - "Ang Thong" - - "Buriram" - - "Chachoengsao" - - "Chai Nat" - - "Chaiyaphum" - - "Chanthaburi" - - "Chiang Mai" - - "Chiang Rai" - - "Chon Buri" - - "Chumphon" - - "Kalasin" - - "Kamphaeng Phet" - - "Kanchanaburi" - - "Khon Kaen" - - "Krabi" - - "Krung Thep Mahanakhon [Bangkok]" - - "Lampang" - - "Lamphun" - - "Loei" - - "Lop Buri" - - "Mae Hong Son" - - "Maha Sarakham" - - "Mukdahan" - - "Nakhon Nayok" - - "Nakhon Pathom" - - "Nakhon Phanom" - - "Nakhon Ratchasima" - - "Nakhon Sawan" - - "Nakhon Si Thammarat" - - "Nan" - - "Narathiwat" - - "Nong Bua Lamphu" - - "Nong Khai" - - "Nonthaburi" - - "Pathum Thani" - - "Pattani" - - "Phangnga" - - "Phatthalung" - - "Phayao" - - "Phetchabun" - - "Phetchaburi" - - "Phichit" - - "Phitsanulok" - - "Phra Nakhon Si Ayutthaya" - - "Phrae" - - "Phuket" - - "Prachin Buri" - - "Prachuap Khiri Khan" - - "Ranong" - - "Ratchaburi" - - "Rayong" - - "Roi Et" - - "Sa Kaeo" - - "Sakon Nakhon" - - "Samut Prakan" - - "Samut Sakhon" - - "Samut Songkhram" - - "Sara Buri" - - "Satun" - - "Sing Buri" - - "Sisaket" - - "Songkhla" - - "Sukhothai" - - "Suphan Buri" - - "Surat Thani" - - "Surin" - - "Tak" - - "Trang" - - "Trat" - - "Ubon Ratchathani" - - "Udon Thani" - - "Uthai Thani" - - "Uttaradit" - - "Yala" - - "Yasothon" - -- name: Timor-Leste - iso2: TL - iso3: TLS - phone: 670 - units: - - "Timor-Leste" - -- name: Togo - iso2: TG - iso3: TGO - phone: 228 - units: - - "De La Kara" - - "Des Plateaux" - - "Des Savanes" - - "Du Centre" - - "Maritime" - -- name: Tokelau - iso2: TK - iso3: TKL - phone: 690 - units: - - "Atafu" - - "Fakaofo" - - "Nukunonu" - -- name: Tonga - iso2: TO - iso3: TON - phone: 676 - units: - - "Ha'apai" - - "Tongatapu" - - "Vava'u" - -- name: Trinidad and Tobago - iso2: TT - iso3: TTO - phone: 1 868 - units: - - "Arima" - - "Caroni" - - "Mayaro" - - "Nariva" - - "Port-of-Spain" - - "Saint Andrew" - - "Saint David" - - "Saint George" - - "Saint Patrick" - - "San Fernando" - - "Victoria" - - "Tobago" - -- name: Tunisia - iso2: TN - iso3: TUN - phone: 216 - units: - - "Ariana" - - "Beja" - - "Ben Arous" - - "Bizerte" - - "El Kef" - - "Gabes" - - "Gafsa" - - "Jendouba" - - "Kairouan" - - "Kasserine" - - "Kebili" - - "Mahdia" - - "Medenine" - - "Monastir" - - "Nabeul" - - "Sfax" - - "Sidi Bou Zid" - - "Siliana" - - "Sousse" - - "Tataouine" - - "Tozeur" - - "Tunis" - - "Zaghouan" - -- name: Turkey - iso2: TR - iso3: TUR - phone: 90 - units: - - "Adana" - - "Adiyaman" - - "Afyon" - - "Agri" - - "Aksaray" - - "Amasya" - - "Ankara" - - "Antalya" - - "Ardahan" - - "Artvin" - - "Aydin" - - "Balikesir" - - "Bartin" - - "Batman" - - "Bayburt" - - "Bilecik" - - "Bingol" - - "Bitlis" - - "Bolu" - - "Burdur" - - "Bursa" - - "Canakkale" - - "Cankiri" - - "Corum" - - "Denizli" - - "Diyarbakir" - - "Duzce" - - "Edirne" - - "Elazig" - - "Erzincan" - - "Erzurum" - - "Eskisehir" - - "Gaziantep" - - "Giresun" - - "Gumushane" - - "Hakkari" - - "Hatay" - - "Icel" - - "Igdir" - - "Isparta" - - "Istanbul" - - "Izmir" - - "Kahramanmaras" - - "Karabuk" - - "Karaman" - - "Kars" - - "Kastamonu" - - "Kayseri" - - "Kilis" - - "Kirikkale" - - "Kirklareli" - - "Kirsehir" - - "Kocaeli" - - "Konya" - - "Kutahya" - - "Malatya" - - "Manisa" - - "Mardin" - - "Mugla" - - "Mus" - - "Nevsehir" - - "Nigde" - - "Ordu" - - "Osmaniye" - - "Rize" - - "Sakarya" - - "Samsun" - - "Sanliurfa" - - "Siirt" - - "Sinop" - - "Sirnak" - - "Sivas" - - "Tekirdag" - - "Tokat" - - "Trabzon" - - "Tunceli" - - "Usak" - - "Van" - - "Yalova" - - "Yozgat" - - "Zonguldak" - -- name: Turkmenistan - iso2: TM - iso3: TKM - phone: 993 - units: - - "Ahal Welayaty" - - "Balkan Welayaty" - - "Dashhowuz Welayaty" - - "Lebap Welayaty" - - "Mary Welayaty" - -- name: Turks and Caicos Islands - iso2: TC - iso3: TCA - phone: 1 649 - units: - - "Turks and Caicos Islands" - -- name: Tuvalu - iso2: TV - iso3: TUV - phone: 688 - units: - - "Tuvalu" - -- name: Uganda - iso2: UG - iso3: UGA - phone: 256 - units: - - "Adjumani" - - "Apac" - - "Arua" - - "Bugiri" - - "Bundibugyo" - - "Bushenyi" - - "Busia" - - "Gulu" - - "Hoima" - - "Iganga" - - "Jinja" - - "Kabale" - - "Kabarole" - - "Kalangala" - - "Kampala" - - "Kamuli" - - "Kapchorwa" - - "Kasese" - - "Katakwi" - - "Kibale" - - "Kiboga" - - "Kisoro" - - "Kitgum" - - "Kotido" - - "Kumi" - - "Lira" - - "Luwero" - - "Masaka" - - "Masindi" - - "Mbale" - - "Mbarara" - - "Moroto" - - "Moyo" - - "Mpigi" - - "Mubende" - - "Mukono" - - "Nakasongola" - - "Nebbi" - - "Ntungamo" - - "Pallisa" - - "Rakai" - - "Rukungiri" - - "Sembabule" - - "Soroti" - - "Tororo" - -- name: Ukraine - iso2: UA - iso3: UKR - phone: 380 - units: - - "Avtonomna Respublika Krym [Simferopol']" - - "Cherkas'ka [Cherkasy]" - - "Chernihivs'ka [Chernihiv]" - - "Chernivets'ka [Chernivtsi]" - - "Dnipropetrovs'ka [Dnipropetrovs'k]" - - "Donets'ka [Donets'k]" - - "Ivano-Frankivs'ka [Ivano-Frankivs'k]" - - "Kharkivs'ka [Kharkiv]" - - "Khersons'ka [Kherson]" - - "Khmel'nyts'ka [Khmel'nyts'kyy]" - - "Kirovohrads'ka [Kirovohrad]" - - "Kyyiv" - - "Kyyivs'ka [Kiev]" - - "L'vivs'ka [L'viv]" - - "Luhans'ka [Luhans'k]" - - "Mykolayivs'ka [Mykolayiv]" - - "Odes'ka [Odesa]" - - "Poltavs'ka [Poltava]" - - "Rivnens'ka [Rivne]" - - "Sevastopol'" - - "Sums'ka [Sumy]" - - "Ternopil's'ka [Ternopil']" - - "Vinnyts'ka [Vinnytsya]" - - "Volyns'ka [Luts'k]" - - "Zakarpats'ka [Uzhhorod]" - - "Zaporiz'ka [Zaporizhzhya]" - - "Zhytomyrs'ka [Zhytomyr]" - -- name: United Arab Emirates - iso2: AE - iso3: ARE - phone: 971 - units: - - "'Ajman" - - "Abu Zaby [Abu Dhabi]" - - "Al Fujayrah" - - "Ash Shariqah [Sharjah]" - - "Dubayy [Dubai]" - - "Ra's al Khaymah" - - "Umm al Qaywayn" - -- name: United Kingdom - iso2: GB - iso3: GBR - phone: 44 - units: - - "Aberdeenshire" - - "Alderney" - - "Angus" - - "Antrim" - - "Argyll" - - "Armagh" - - "Avon" - - "Ayrshire" - - "Banffshire" - - "Bedfordshire" - - "Berkshire" - - "Berwickshire" - - "Blaenau Gwent" - - "Borders" - - "Bridgend" - - "Buckinghamshire" - - "Bute" - - "Caerphilly" - - "Caithness" - - "Cambridgeshire" - - "Cardiff" - - "Carmarthenshire" - - "Central" - - "Ceredigion" - - "Cheshire" - - "Clackmannanshire" - - "Cleveland" - - "Clwyd" - - "Co. Antrim" - - "Co. Armagh" - - "Co. Derry" - - "Co. Down" - - "Co. Fermanagh" - - "Co. Tyrone" - - "Conwy" - - "Cornwall" - - "Cumberland" - - "Cumbria" - - "Denbighshire" - - "Derbyshire" - - "Derry" - - "Devon" - - "Dorset" - - "Down" - - "Dumfries & Galloway" - - "Dumfriesshire" - - "Dunbartonshire" - - "Durham" - - "Dyfed" - - "East Lothian" - - "East Sussex" - - "Essex" - - "Fermanagh" - - "Fife" - - "Flintshire" - - "Gloucestershire" - - "Grampian" - - "Greater London" - - "Greater Manchester" - - "Guernsey" - - "Gwent" - - "Gwynedd" - - "Hampshire" - - "Hereford & Worcester" - - "Herefordshire" - - "Hertfordshire" - - "Highland" - - "Humberside" - - "Huntingdonshire" - - "Inverness" - - "Isle Of Man" - - "Isle of Anglesey" - - "Isle of Wight" - - "Jersey" - - "Kent" - - "Kincardineshire" - - "Kinross-shire" - - "Kirkcudbrightshire" - - "Lanarkshire" - - "Lancashire" - - "Leicestershire" - - "Lincolnshire" - - "Lothian" - - "Merseyside" - - "Merthyr Tydfil" - - "Mid Glamorgan" - - "Middlesex" - - "Midlothian" - - "Monmouthshire" - - "Moray" - - "Nairnshire" - - "Neath Port Talbot" - - "Newport" - - "Norfolk" - - "North Yorkshire" - - "Northamptonshire" - - "Northumberland" - - "Nottinghamshire" - - "Orkney" - - "Oxfordshire" - - "Peebleshire" - - "Pembrokeshire" - - "Perthshire" - - "Powys" - - "Renfrewshire" - - "Rhondda Cynon Taff" - - "Ross & Cromarty" - - "Roxburghshire" - - "Rutland" - - "Scotland" - - "Selkirkshire" - - "Shetland" - - "Shropshire" - - "Somerset" - - "South Glamorgan" - - "South Yorkshire" - - "Staffordshire" - - "Stirlingshire" - - "Strathclyde" - - "Suffolk" - - "Surrey" - - "Sussex" - - "Sutherland" - - "Swansea" - - "Tayside" - - "Torfaen" - - "Tyne & Wear" - - "Tyne and Wear" - - "Tyrone" - - "Vale of Glamorgan" - - "Wales" - - "Warwickshire" - - "West Glamorgan" - - "West Lothian" - - "West Midlands" - - "West Riding" - - "West Sussex" - - "West Yorkshire" - - "Western Isles" - - "Westmoorland" - - "Westmorland" - - "Wigtownshire" - - "Wiltshire" - - "Worcestershire" - - "Wrexham" - - "Yorkshire" - -- name: United States - iso2: US - iso3: USA - phone: 1 - units: - - "Alaska" - - "Alabama" - - "Arkansas" - - "Arizona" - - "California" - - "Colorado" - - "Connecticut" - - "Washington, D.C." - - "Delaware" - - "Florida" - - "Georgia" - - "Hawaii" - - "Iowa" - - "Idaho" - - "Illinois" - - "Indiana" - - "Kansas" - - "Kentucky" - - "Louisiana" - - "Massachusetts" - - "Maryland" - - "Maine" - - "Michigan" - - "Minnesota" - - "Missouri" - - "Mississippi" - - "Montana" - - "North Carolina" - - "North Dakota" - - "Nebraska" - - "New Hampshire" - - "New Jersey" - - "New Mexico" - - "Nevada" - - "New York" - - "Ohio" - - "Oklahoma" - - "Oregon" - - "Pennsylvania" - - "Rhode Island" - - "South Carolina" - - "South Dakota" - - "Tennessee" - - "Texas" - - "Utah" - - "Virginia" - - "Vermont" - - "Washington" - - "Wisconsin" - - "West Virginia" - - "Wyoming" - -- name: United States Minor Outlying Islands - iso2: UM - iso3: UMI - phone: - units: [] - -- name: Uruguay - iso2: UY - iso3: URY - phone: 598 - units: - - "Artigas" - - "Canelones" - - "Cerro Largo" - - "Colonia" - - "Durazno" - - "Flores" - - "Florida" - - "Lavalleja" - - "Maldonado" - - "Montevideo" - - "Paysandu" - - "Rio Negro" - - "Rivera" - - "Rocha" - - "Salto" - - "San Jose" - - "Soriano" - - "Tacuarembo" - - "Treinta y Tres" - -- name: Uzbekistan - iso2: UZ - iso3: UZB - phone: 998 - units: - - "Andijon Wiloyati" - - "Bukhoro Wiloyati" - - "Farghona Wiloyati" - - "Jizzakh Wiloyati" - - "Khorazm Wiloyati [Urganch]" - - "Namangan Wiloyati" - - "Nawoiy Wiloyati" - - "Qashqadaryo Wiloyati [Qarshi]" - - "Qoraqalpoghiston [Nukus]" - - "Samarqand Wiloyati" - - "Sirdaryo Wiloyati [Guliston]" - - "Surkhondaryo Wiloyati [Termiz]" - - "Toshkent Shahri" - - "Toshkent Wiloyati" - -- name: Vanuatu - iso2: VU - iso3: VUT - phone: 678 - units: - - "Malampa" - - "Penama" - - "Sanma" - - "Shefa" - - "Tafea" - - "Torba" - -- name: Venezuela, Bolivarian Republic of - iso2: VE - iso3: VEN - phone: 58 - units: - - "Amazonas" - - "Anzoategui" - - "Apure" - - "Aragua" - - "Barinas" - - "Bolivar" - - "Carabobo" - - "Cojedes" - - "Delta Amacuro" - - "Dependencias Federales" - - "Distrito Federal" - - "Falcon" - - "Guarico" - - "Lara" - - "Merida" - - "Miranda" - - "Monagas" - - "Nueva Esparta" - - "Portuguesa" - - "Sucre" - - "Tachira" - - "Trujillo" - - "Vargas" - - "Yaracuy" - - "Zulia" - -- name: Viet Nam - iso2: VN - iso3: VNM - phone: 84 - units: - - "An Giang" - - "Ba Ria-Vung Tau" - - "Bac Giang" - - "Bac Kan" - - "Bac Lieu" - - "Bac Ninh" - - "Ben Tre" - - "Binh Dinh" - - "Binh Duong" - - "Binh Phuoc" - - "Binh Thuan" - - "Ca Mau" - - "Can Tho" - - "Cao Bang" - - "Da Nang" - - "Dac Lak" - - "Dong Nai" - - "Dong Thap" - - "Gia Lai" - - "Ha Giang" - - "Ha Nam" - - "Ha Noi" - - "Ha Tay" - - "Ha Tinh" - - "Hai Duong" - - "Hai Phong" - - "Ho Chi Minh" - - "Hoa Binh" - - "Hung Yen" - - "Khanh Hoa" - - "Kien Giang" - - "Kon Tum" - - "Lai Chau" - - "Lam Dong" - - "Lang Son" - - "Lao Cai" - - "Long An" - - "Nam Dinh" - - "Nghe An" - - "Ninh Binh" - - "Ninh Thuan" - - "Phu Tho" - - "Phu Yen" - - "Quang Binh" - - "Quang Nam" - - "Quang Ngai" - - "Quang Ninh" - - "Quang Tri" - - "Soc Trang" - - "Son La" - - "Tay Ninh" - - "Thai Binh" - - "Thai Nguyen" - - "Thanh Hoa" - - "Thua Thien-Hue" - - "Tien Giang" - - "Tra Vinh" - - "Tuyen Quang" - - "Vinh Long" - - "Vinh Phuc" - - "Yen Bai" - -- name: Virgin Islands British - iso2: VG - iso3: VGB - phone: 1 284 - units: - - "Anegada" - - "Jost Van Dyke" - - "Tortola" - - "Virgin Gorda" - -- name: Virgin Islands U.S. - iso2: VI - iso3: VIR - phone: 1 340 - units: - - "Saint Croix" - - "Saint John" - - "Saint Thomas" - -- name: Wallis and Futuna - iso2: WF - iso3: WLF - phone: 681 - units: - - "Alo" - - "Sigave" - - "Wallis" - -- name: Western Sahara - iso2: EH - iso3: ESH - phone: - units: - - "Western Sahara" - -- name: Yemen - iso2: YE - iso3: YEM - phone: 967 - units: - - "'Adan" - - "'Ataq" - - "Abyan" - - "Al Bayda'" - - "Al Hudaydah" - - "Al Jawf" - - "Al Mahrah" - - "Al Mahwit" - - "Dhamar" - - "Hadhramawt" - - "Hajjah" - - "Ibb" - - "Lahij" - - "Ma'rib" - - "Sa'dah" - - "San'a'" - - "Ta'izz" - -- name: Zambia - iso2: ZM - iso3: ZMB - phone: 260 - units: - - "Central" - - "Copperbelt" - - "Eastern" - - "Luapula" - - "Lusaka" - - "North-Western" - - "Northern" - - "Southern" - - "Western" - -- name: Zimbabwe - iso2: ZW - iso3: ZWE - phone: 263 - units: - - "Bulawayo" - - "Harare" - - "Manicaland" - - "Mashonaland Central" - - "Mashonaland East" - - "Mashonaland West" - - "Masvingo" - - "Matabeleland North" - - "Matabeleland South" - - "Midlands" diff --git a/src/Oro/Bundle/AddressBundle/DataFixtures/data/countries.yml b/src/Oro/Bundle/AddressBundle/DataFixtures/data/countries.yml new file mode 100644 index 00000000000..5d5bff9b008 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/DataFixtures/data/countries.yml @@ -0,0 +1,12630 @@ +AD: + iso2Code: AD + iso3Code: AND + regions: + AD.06: + combinedCode: AD.06 + code: '06' + AD.05: + combinedCode: AD.05 + code: '05' + AD.04: + combinedCode: AD.04 + code: '04' + AD.03: + combinedCode: AD.03 + code: '03' + AD.02: + combinedCode: AD.02 + code: '02' + AD.07: + combinedCode: AD.07 + code: '07' + AD.08: + combinedCode: AD.08 + code: '08' +AE: + iso2Code: AE + iso3Code: ARE + regions: + AE.07: + combinedCode: AE.07 + code: '07' + AE.05: + combinedCode: AE.05 + code: '05' + AE.03: + combinedCode: AE.03 + code: '03' + AE.06: + combinedCode: AE.06 + code: '06' + AE.04: + combinedCode: AE.04 + code: '04' + AE.02: + combinedCode: AE.02 + code: '02' + AE.01: + combinedCode: AE.01 + code: '01' +AF: + iso2Code: AF + iso3Code: AFG + regions: + AF.28: + combinedCode: AF.28 + code: '28' + AF.27: + combinedCode: AF.27 + code: '27' + AF.26: + combinedCode: AF.26 + code: '26' + AF.33: + combinedCode: AF.33 + code: '33' + AF.32: + combinedCode: AF.32 + code: '32' + AF.40: + combinedCode: AF.40 + code: '40' + AF.29: + combinedCode: AF.29 + code: '29' + AF.36: + combinedCode: AF.36 + code: '36' + AF.39: + combinedCode: AF.39 + code: '39' + AF.19: + combinedCode: AF.19 + code: '19' + AF.18: + combinedCode: AF.18 + code: '18' + AF.17: + combinedCode: AF.17 + code: '17' + AF.35: + combinedCode: AF.35 + code: '35' + AF.24: + combinedCode: AF.24 + code: '24' + AF.34: + combinedCode: AF.34 + code: '34' + AF.14: + combinedCode: AF.14 + code: '14' + AF.23: + combinedCode: AF.23 + code: '23' + AF.13: + combinedCode: AF.13 + code: '13' + AF.31: + combinedCode: AF.31 + code: '31' + AF.11: + combinedCode: AF.11 + code: '11' + AF.10: + combinedCode: AF.10 + code: '10' + AF.09: + combinedCode: AF.09 + code: '09' + AF.08: + combinedCode: AF.08 + code: '08' + AF.07: + combinedCode: AF.07 + code: '07' + AF.06: + combinedCode: AF.06 + code: '06' + AF.05: + combinedCode: AF.05 + code: '05' + AF.30: + combinedCode: AF.30 + code: '30' + AF.03: + combinedCode: AF.03 + code: '03' + AF.02: + combinedCode: AF.02 + code: '02' + AF.01: + combinedCode: AF.01 + code: '01' + AF.37: + combinedCode: AF.37 + code: '37' + AF.38: + combinedCode: AF.38 + code: '38' + AF.41: + combinedCode: AF.41 + code: '41' + AF.42: + combinedCode: AF.42 + code: '42' +AG: + iso2Code: AG + iso3Code: ATG + regions: + AG.08: + combinedCode: AG.08 + code: '08' + AG.07: + combinedCode: AG.07 + code: '07' + AG.06: + combinedCode: AG.06 + code: '06' + AG.05: + combinedCode: AG.05 + code: '05' + AG.04: + combinedCode: AG.04 + code: '04' + AG.03: + combinedCode: AG.03 + code: '03' + AG.09: + combinedCode: AG.09 + code: '09' + AG.01: + combinedCode: AG.01 + code: '01' +AI: + iso2Code: AI + iso3Code: AIA + regions: { } +AL: + iso2Code: AL + iso3Code: ALB + regions: + AL.40: + combinedCode: AL.40 + code: '40' + AL.41: + combinedCode: AL.41 + code: '41' + AL.43: + combinedCode: AL.43 + code: '43' + AL.45: + combinedCode: AL.45 + code: '45' + AL.46: + combinedCode: AL.46 + code: '46' + AL.47: + combinedCode: AL.47 + code: '47' + AL.42: + combinedCode: AL.42 + code: '42' + AL.44: + combinedCode: AL.44 + code: '44' + AL.48: + combinedCode: AL.48 + code: '48' + AL.49: + combinedCode: AL.49 + code: '49' + AL.50: + combinedCode: AL.50 + code: '50' + AL.51: + combinedCode: AL.51 + code: '51' +AM: + iso2Code: AM + iso3Code: ARM + regions: + AM.02: + combinedCode: AM.02 + code: '02' + AM.08: + combinedCode: AM.08 + code: '08' + AM.10: + combinedCode: AM.10 + code: '10' + AM.11: + combinedCode: AM.11 + code: '11' + AM.01: + combinedCode: AM.01 + code: '01' + AM.03: + combinedCode: AM.03 + code: '03' + AM.04: + combinedCode: AM.04 + code: '04' + AM.05: + combinedCode: AM.05 + code: '05' + AM.06: + combinedCode: AM.06 + code: '06' + AM.07: + combinedCode: AM.07 + code: '07' + AM.09: + combinedCode: AM.09 + code: '09' +AO: + iso2Code: AO + iso3Code: AGO + regions: + AO.18: + combinedCode: AO.18 + code: '18' + AO.17: + combinedCode: AO.17 + code: '17' + AO.14: + combinedCode: AO.14 + code: '14' + AO.04: + combinedCode: AO.04 + code: '04' + AO.16: + combinedCode: AO.16 + code: '16' + AO.15: + combinedCode: AO.15 + code: '15' + AO.12: + combinedCode: AO.12 + code: '12' + AO.20: + combinedCode: AO.20 + code: '20' + AO.05: + combinedCode: AO.05 + code: '05' + AO.03: + combinedCode: AO.03 + code: '03' + AO.19: + combinedCode: AO.19 + code: '19' + AO.13: + combinedCode: AO.13 + code: '13' + AO.09: + combinedCode: AO.09 + code: '09' + AO.08: + combinedCode: AO.08 + code: '08' + AO.07: + combinedCode: AO.07 + code: '07' + AO.06: + combinedCode: AO.06 + code: '06' + AO.02: + combinedCode: AO.02 + code: '02' + AO.01: + combinedCode: AO.01 + code: '01' +AQ: + iso2Code: AQ + iso3Code: ATA + regions: { } +AR: + iso2Code: AR + iso3Code: ARG + regions: + AR.14: + combinedCode: AR.14 + code: '14' + AR.09: + combinedCode: AR.09 + code: '09' + AR.07: + combinedCode: AR.07 + code: '07' + AR.08: + combinedCode: AR.08 + code: '08' + AR.06: + combinedCode: AR.06 + code: '06' + AR.01: + combinedCode: AR.01 + code: '01' + AR.24: + combinedCode: AR.24 + code: '24' + AR.23: + combinedCode: AR.23 + code: '23' + AR.22: + combinedCode: AR.22 + code: '22' + AR.21: + combinedCode: AR.21 + code: '21' + AR.20: + combinedCode: AR.20 + code: '20' + AR.19: + combinedCode: AR.19 + code: '19' + AR.18: + combinedCode: AR.18 + code: '18' + AR.17: + combinedCode: AR.17 + code: '17' + AR.16: + combinedCode: AR.16 + code: '16' + AR.15: + combinedCode: AR.15 + code: '15' + AR.13: + combinedCode: AR.13 + code: '13' + AR.12: + combinedCode: AR.12 + code: '12' + AR.11: + combinedCode: AR.11 + code: '11' + AR.10: + combinedCode: AR.10 + code: '10' + AR.05: + combinedCode: AR.05 + code: '05' + AR.04: + combinedCode: AR.04 + code: '04' + AR.03: + combinedCode: AR.03 + code: '03' + AR.02: + combinedCode: AR.02 + code: '02' +AS: + iso2Code: AS + iso3Code: ASM + regions: + AS.050: + combinedCode: AS.050 + code: '050' + AS.040: + combinedCode: AS.040 + code: '040' + AS.010: + combinedCode: AS.010 + code: '010' + AS.020: + combinedCode: AS.020 + code: '020' + AS.030: + combinedCode: AS.030 + code: '030' +AT: + iso2Code: AT + iso3Code: AUT + regions: + AT.09: + combinedCode: AT.09 + code: '09' + AT.08: + combinedCode: AT.08 + code: '08' + AT.07: + combinedCode: AT.07 + code: '07' + AT.06: + combinedCode: AT.06 + code: '06' + AT.05: + combinedCode: AT.05 + code: '05' + AT.04: + combinedCode: AT.04 + code: '04' + AT.03: + combinedCode: AT.03 + code: '03' + AT.02: + combinedCode: AT.02 + code: '02' + AT.01: + combinedCode: AT.01 + code: '01' +AU: + iso2Code: AU + iso3Code: AUS + regions: + AU.08: + combinedCode: AU.08 + code: '08' + AU.05: + combinedCode: AU.05 + code: '05' + AU.03: + combinedCode: AU.03 + code: '03' + AU.07: + combinedCode: AU.07 + code: '07' + AU.06: + combinedCode: AU.06 + code: '06' + AU.04: + combinedCode: AU.04 + code: '04' + AU.02: + combinedCode: AU.02 + code: '02' + AU.01: + combinedCode: AU.01 + code: '01' +AW: + iso2Code: AW + iso3Code: ABW + regions: { } +AX: + iso2Code: AX + iso3Code: ALA + regions: + AX.941: + combinedCode: AX.941 + code: '941' + AX.771: + combinedCode: AX.771 + code: '771' + AX.766: + combinedCode: AX.766 + code: '766' + AX.736: + combinedCode: AX.736 + code: '736' + AX.438: + combinedCode: AX.438 + code: '438' + AX.417: + combinedCode: AX.417 + code: '417' + AX.295: + combinedCode: AX.295 + code: '295' + AX.318: + combinedCode: AX.318 + code: '318' + AX.062: + combinedCode: AX.062 + code: '062' + AX.035: + combinedCode: AX.035 + code: '035' + AX.478: + combinedCode: AX.478 + code: '478' + AX.170: + combinedCode: AX.170 + code: '170' + AX.076: + combinedCode: AX.076 + code: '076' + AX.065: + combinedCode: AX.065 + code: '065' + AX.060: + combinedCode: AX.060 + code: '060' + AX.043: + combinedCode: AX.043 + code: '043' +AZ: + iso2Code: AZ + iso3Code: AZE + regions: + AZ.12: + combinedCode: AZ.12 + code: '12' + AZ.69: + combinedCode: AZ.69 + code: '69' + AZ.66: + combinedCode: AZ.66 + code: '66' + AZ.55: + combinedCode: AZ.55 + code: '55' + AZ.49: + combinedCode: AZ.49 + code: '49' + AZ.46: + combinedCode: AZ.46 + code: '46' + AZ.45: + combinedCode: AZ.45 + code: '45' + AZ.13: + combinedCode: AZ.13 + code: '13' + AZ.36: + combinedCode: AZ.36 + code: '36' + AZ.35: + combinedCode: AZ.35 + code: '35' + AZ.32: + combinedCode: AZ.32 + code: '32' + AZ.31: + combinedCode: AZ.31 + code: '31' + AZ.29: + combinedCode: AZ.29 + code: '29' + AZ.28: + combinedCode: AZ.28 + code: '28' + AZ.43: + combinedCode: AZ.43 + code: '43' + AZ.24: + combinedCode: AZ.24 + code: '24' + AZ.18: + combinedCode: AZ.18 + code: '18' + AZ.14: + combinedCode: AZ.14 + code: '14' + AZ.15: + combinedCode: AZ.15 + code: '15' + AZ.08: + combinedCode: AZ.08 + code: '08' + AZ.64: + combinedCode: AZ.64 + code: '64' + AZ.02: + combinedCode: AZ.02 + code: '02' + AZ.03: + combinedCode: AZ.03 + code: '03' + AZ.07: + combinedCode: AZ.07 + code: '07' + AZ.30: + combinedCode: AZ.30 + code: '30' + AZ.56: + combinedCode: AZ.56 + code: '56' + AZ.57: + combinedCode: AZ.57 + code: '57' + AZ.61: + combinedCode: AZ.61 + code: '61' + AZ.65: + combinedCode: AZ.65 + code: '65' + AZ.71: + combinedCode: AZ.71 + code: '71' + AZ.70: + combinedCode: AZ.70 + code: '70' + AZ.67: + combinedCode: AZ.67 + code: '67' + AZ.37: + combinedCode: AZ.37 + code: '37' + AZ.59: + combinedCode: AZ.59 + code: '59' + AZ.58: + combinedCode: AZ.58 + code: '58' + AZ.50: + combinedCode: AZ.50 + code: '50' + AZ.47: + combinedCode: AZ.47 + code: '47' + AZ.51: + combinedCode: AZ.51 + code: '51' + AZ.27: + combinedCode: AZ.27 + code: '27' + AZ.38: + combinedCode: AZ.38 + code: '38' + AZ.44: + combinedCode: AZ.44 + code: '44' + AZ.42: + combinedCode: AZ.42 + code: '42' + AZ.62: + combinedCode: AZ.62 + code: '62' + AZ.60: + combinedCode: AZ.60 + code: '60' + AZ.26: + combinedCode: AZ.26 + code: '26' + AZ.40: + combinedCode: AZ.40 + code: '40' + AZ.21: + combinedCode: AZ.21 + code: '21' + AZ.39: + combinedCode: AZ.39 + code: '39' + AZ.25: + combinedCode: AZ.25 + code: '25' + AZ.22: + combinedCode: AZ.22 + code: '22' + AZ.17: + combinedCode: AZ.17 + code: '17' + AZ.16: + combinedCode: AZ.16 + code: '16' + AZ.10: + combinedCode: AZ.10 + code: '10' + AZ.11: + combinedCode: AZ.11 + code: '11' + AZ.09: + combinedCode: AZ.09 + code: '09' + AZ.01: + combinedCode: AZ.01 + code: '01' + AZ.06: + combinedCode: AZ.06 + code: '06' + AZ.04: + combinedCode: AZ.04 + code: '04' + AZ.19: + combinedCode: AZ.19 + code: '19' + AZ.05: + combinedCode: AZ.05 + code: '05' + AZ.20: + combinedCode: AZ.20 + code: '20' + AZ.33: + combinedCode: AZ.33 + code: '33' + AZ.34: + combinedCode: AZ.34 + code: '34' + AZ.41: + combinedCode: AZ.41 + code: '41' + AZ.52: + combinedCode: AZ.52 + code: '52' + AZ.48: + combinedCode: AZ.48 + code: '48' + AZ.53: + combinedCode: AZ.53 + code: '53' + AZ.54: + combinedCode: AZ.54 + code: '54' + AZ.63: + combinedCode: AZ.63 + code: '63' + AZ.68: + combinedCode: AZ.68 + code: '68' + AZ.23: + combinedCode: AZ.23 + code: '23' + AZ.75: + combinedCode: AZ.75 + code: '75' +BA: + iso2Code: BA + iso3Code: BIH + regions: + BA.01: + combinedCode: BA.01 + code: '01' + BA.02: + combinedCode: BA.02 + code: '02' + BA.BRC: + combinedCode: BA.BRC + code: BRC +BB: + iso2Code: BB + iso3Code: BRB + regions: + BB.11: + combinedCode: BB.11 + code: '11' + BB.10: + combinedCode: BB.10 + code: '10' + BB.09: + combinedCode: BB.09 + code: '09' + BB.08: + combinedCode: BB.08 + code: '08' + BB.07: + combinedCode: BB.07 + code: '07' + BB.06: + combinedCode: BB.06 + code: '06' + BB.05: + combinedCode: BB.05 + code: '05' + BB.04: + combinedCode: BB.04 + code: '04' + BB.03: + combinedCode: BB.03 + code: '03' + BB.02: + combinedCode: BB.02 + code: '02' + BB.01: + combinedCode: BB.01 + code: '01' +BD: + iso2Code: BD + iso3Code: BGD + regions: + BD.83: + combinedCode: BD.83 + code: '83' + BD.81: + combinedCode: BD.81 + code: '81' + BD.84: + combinedCode: BD.84 + code: '84' + BD.82: + combinedCode: BD.82 + code: '82' + BD.85: + combinedCode: BD.85 + code: '85' + BD.86: + combinedCode: BD.86 + code: '86' + BD.87: + combinedCode: BD.87 + code: '87' +BE: + iso2Code: BE + iso3Code: BEL + regions: + BE.BRU: + combinedCode: BE.BRU + code: BRU + BE.WAL: + combinedCode: BE.WAL + code: WAL + BE.VLG: + combinedCode: BE.VLG + code: VLG +BF: + iso2Code: BF + iso3Code: BFA + regions: + BF.01: + combinedCode: BF.01 + code: '01' + BF.02: + combinedCode: BF.02 + code: '02' + BF.03: + combinedCode: BF.03 + code: '03' + BF.04: + combinedCode: BF.04 + code: '04' + BF.05: + combinedCode: BF.05 + code: '05' + BF.06: + combinedCode: BF.06 + code: '06' + BF.07: + combinedCode: BF.07 + code: '07' + BF.08: + combinedCode: BF.08 + code: '08' + BF.09: + combinedCode: BF.09 + code: '09' + BF.10: + combinedCode: BF.10 + code: '10' + BF.11: + combinedCode: BF.11 + code: '11' + BF.12: + combinedCode: BF.12 + code: '12' + BF.13: + combinedCode: BF.13 + code: '13' +BG: + iso2Code: BG + iso3Code: BGR + regions: + BG.52: + combinedCode: BG.52 + code: '52' + BG.47: + combinedCode: BG.47 + code: '47' + BG.64: + combinedCode: BG.64 + code: '64' + BG.61: + combinedCode: BG.61 + code: '61' + BG.40: + combinedCode: BG.40 + code: '40' + BG.58: + combinedCode: BG.58 + code: '58' + BG.53: + combinedCode: BG.53 + code: '53' + BG.51: + combinedCode: BG.51 + code: '51' + BG.50: + combinedCode: BG.50 + code: '50' + BG.49: + combinedCode: BG.49 + code: '49' + BG.48: + combinedCode: BG.48 + code: '48' + BG.46: + combinedCode: BG.46 + code: '46' + BG.43: + combinedCode: BG.43 + code: '43' + BG.42: + combinedCode: BG.42 + code: '42' + BG.39: + combinedCode: BG.39 + code: '39' + BG.38: + combinedCode: BG.38 + code: '38' + BG.41: + combinedCode: BG.41 + code: '41' + BG.44: + combinedCode: BG.44 + code: '44' + BG.45: + combinedCode: BG.45 + code: '45' + BG.54: + combinedCode: BG.54 + code: '54' + BG.55: + combinedCode: BG.55 + code: '55' + BG.56: + combinedCode: BG.56 + code: '56' + BG.57: + combinedCode: BG.57 + code: '57' + BG.59: + combinedCode: BG.59 + code: '59' + BG.60: + combinedCode: BG.60 + code: '60' + BG.62: + combinedCode: BG.62 + code: '62' + BG.63: + combinedCode: BG.63 + code: '63' + BG.65: + combinedCode: BG.65 + code: '65' +BH: + iso2Code: BH + iso3Code: BHR + regions: + BH.15: + combinedCode: BH.15 + code: '15' + BH.16: + combinedCode: BH.16 + code: '16' + BH.17: + combinedCode: BH.17 + code: '17' + BH.18: + combinedCode: BH.18 + code: '18' + BH.19: + combinedCode: BH.19 + code: '19' +BI: + iso2Code: BI + iso3Code: BDI + regions: + BI.17: + combinedCode: BI.17 + code: '17' + BI.10: + combinedCode: BI.10 + code: '10' + BI.22: + combinedCode: BI.22 + code: '22' + BI.13: + combinedCode: BI.13 + code: '13' + BI.21: + combinedCode: BI.21 + code: '21' + BI.11: + combinedCode: BI.11 + code: '11' + BI.14: + combinedCode: BI.14 + code: '14' + BI.09: + combinedCode: BI.09 + code: '09' + BI.12: + combinedCode: BI.12 + code: '12' + BI.19: + combinedCode: BI.19 + code: '19' + BI.15: + combinedCode: BI.15 + code: '15' + BI.18: + combinedCode: BI.18 + code: '18' + BI.16: + combinedCode: BI.16 + code: '16' + BI.20: + combinedCode: BI.20 + code: '20' + BI.23: + combinedCode: BI.23 + code: '23' + BI.24: + combinedCode: BI.24 + code: '24' + BI.25: + combinedCode: BI.25 + code: '25' +BJ: + iso2Code: BJ + iso3Code: BEN + regions: + BJ.18: + combinedCode: BJ.18 + code: '18' + BJ.16: + combinedCode: BJ.16 + code: '16' + BJ.15: + combinedCode: BJ.15 + code: '15' + BJ.10: + combinedCode: BJ.10 + code: '10' + BJ.09: + combinedCode: BJ.09 + code: '09' + BJ.08: + combinedCode: BJ.08 + code: '08' + BJ.07: + combinedCode: BJ.07 + code: '07' + BJ.11: + combinedCode: BJ.11 + code: '11' + BJ.12: + combinedCode: BJ.12 + code: '12' + BJ.13: + combinedCode: BJ.13 + code: '13' + BJ.14: + combinedCode: BJ.14 + code: '14' + BJ.17: + combinedCode: BJ.17 + code: '17' +BL: + iso2Code: BL + iso3Code: BLM + regions: { } +BM: + iso2Code: BM + iso3Code: BMU + regions: + BM.11: + combinedCode: BM.11 + code: '11' + BM.10: + combinedCode: BM.10 + code: '10' + BM.09: + combinedCode: BM.09 + code: '09' + BM.08: + combinedCode: BM.08 + code: '08' + BM.07: + combinedCode: BM.07 + code: '07' + BM.06: + combinedCode: BM.06 + code: '06' + BM.05: + combinedCode: BM.05 + code: '05' + BM.04: + combinedCode: BM.04 + code: '04' + BM.02: + combinedCode: BM.02 + code: '02' + BM.03: + combinedCode: BM.03 + code: '03' + BM.01: + combinedCode: BM.01 + code: '01' +BN: + iso2Code: BN + iso3Code: BRN + regions: + BN.04: + combinedCode: BN.04 + code: '04' + BN.03: + combinedCode: BN.03 + code: '03' + BN.02: + combinedCode: BN.02 + code: '02' + BN.01: + combinedCode: BN.01 + code: '01' +BO: + iso2Code: BO + iso3Code: BOL + regions: + BO.09: + combinedCode: BO.09 + code: '09' + BO.08: + combinedCode: BO.08 + code: '08' + BO.07: + combinedCode: BO.07 + code: '07' + BO.06: + combinedCode: BO.06 + code: '06' + BO.05: + combinedCode: BO.05 + code: '05' + BO.04: + combinedCode: BO.04 + code: '04' + BO.02: + combinedCode: BO.02 + code: '02' + BO.01: + combinedCode: BO.01 + code: '01' + BO.03: + combinedCode: BO.03 + code: '03' +BQ: + iso2Code: BQ + iso3Code: BES + regions: + BQ.BO: + combinedCode: BQ.BO + code: BO + BQ.SB: + combinedCode: BQ.SB + code: SB + BQ.SE: + combinedCode: BQ.SE + code: SE +BR: + iso2Code: BR + iso3Code: BRA + regions: + BR.22: + combinedCode: BR.22 + code: '22' + BR.20: + combinedCode: BR.20 + code: '20' + BR.30: + combinedCode: BR.30 + code: '30' + BR.17: + combinedCode: BR.17 + code: '17' + BR.16: + combinedCode: BR.16 + code: '16' + BR.13: + combinedCode: BR.13 + code: '13' + BR.06: + combinedCode: BR.06 + code: '06' + BR.03: + combinedCode: BR.03 + code: '03' + BR.02: + combinedCode: BR.02 + code: '02' + BR.28: + combinedCode: BR.28 + code: '28' + BR.27: + combinedCode: BR.27 + code: '27' + BR.26: + combinedCode: BR.26 + code: '26' + BR.23: + combinedCode: BR.23 + code: '23' + BR.21: + combinedCode: BR.21 + code: '21' + BR.18: + combinedCode: BR.18 + code: '18' + BR.15: + combinedCode: BR.15 + code: '15' + BR.11: + combinedCode: BR.11 + code: '11' + BR.14: + combinedCode: BR.14 + code: '14' + BR.29: + combinedCode: BR.29 + code: '29' + BR.07: + combinedCode: BR.07 + code: '07' + BR.08: + combinedCode: BR.08 + code: '08' + BR.05: + combinedCode: BR.05 + code: '05' + BR.31: + combinedCode: BR.31 + code: '31' + BR.25: + combinedCode: BR.25 + code: '25' + BR.04: + combinedCode: BR.04 + code: '04' + BR.01: + combinedCode: BR.01 + code: '01' + BR.24: + combinedCode: BR.24 + code: '24' +BS: + iso2Code: BS + iso3Code: BHS + regions: + BS.35: + combinedCode: BS.35 + code: '35' + BS.34: + combinedCode: BS.34 + code: '34' + BS.33: + combinedCode: BS.33 + code: '33' + BS.18: + combinedCode: BS.18 + code: '18' + BS.32: + combinedCode: BS.32 + code: '32' + BS.23: + combinedCode: BS.23 + code: '23' + BS.16: + combinedCode: BS.16 + code: '16' + BS.31: + combinedCode: BS.31 + code: '31' + BS.15: + combinedCode: BS.15 + code: '15' + BS.30: + combinedCode: BS.30 + code: '30' + BS.13: + combinedCode: BS.13 + code: '13' + BS.29: + combinedCode: BS.29 + code: '29' + BS.22: + combinedCode: BS.22 + code: '22' + BS.28: + combinedCode: BS.28 + code: '28' + BS.27: + combinedCode: BS.27 + code: '27' + BS.26: + combinedCode: BS.26 + code: '26' + BS.25: + combinedCode: BS.25 + code: '25' + BS.10: + combinedCode: BS.10 + code: '10' + BS.06: + combinedCode: BS.06 + code: '06' + BS.05: + combinedCode: BS.05 + code: '05' + BS.24: + combinedCode: BS.24 + code: '24' + BS.36: + combinedCode: BS.36 + code: '36' + BS.37: + combinedCode: BS.37 + code: '37' + BS.38: + combinedCode: BS.38 + code: '38' + BS.39: + combinedCode: BS.39 + code: '39' + BS.40: + combinedCode: BS.40 + code: '40' + BS.41: + combinedCode: BS.41 + code: '41' + BS.42: + combinedCode: BS.42 + code: '42' + BS.43: + combinedCode: BS.43 + code: '43' + BS.44: + combinedCode: BS.44 + code: '44' + BS.45: + combinedCode: BS.45 + code: '45' + BS.46: + combinedCode: BS.46 + code: '46' + BS.47: + combinedCode: BS.47 + code: '47' + BS.48: + combinedCode: BS.48 + code: '48' + BS.49: + combinedCode: BS.49 + code: '49' + BS.50: + combinedCode: BS.50 + code: '50' + BS.51: + combinedCode: BS.51 + code: '51' + BS.52: + combinedCode: BS.52 + code: '52' + BS.53: + combinedCode: BS.53 + code: '53' + BS.54: + combinedCode: BS.54 + code: '54' +BT: + iso2Code: BT + iso3Code: BTN + regions: + BT.05: + combinedCode: BT.05 + code: '05' + BT.06: + combinedCode: BT.06 + code: '06' + BT.08: + combinedCode: BT.08 + code: '08' + BT.07: + combinedCode: BT.07 + code: '07' + BT.09: + combinedCode: BT.09 + code: '09' + BT.10: + combinedCode: BT.10 + code: '10' + BT.11: + combinedCode: BT.11 + code: '11' + BT.12: + combinedCode: BT.12 + code: '12' + BT.13: + combinedCode: BT.13 + code: '13' + BT.14: + combinedCode: BT.14 + code: '14' + BT.15: + combinedCode: BT.15 + code: '15' + BT.16: + combinedCode: BT.16 + code: '16' + BT.17: + combinedCode: BT.17 + code: '17' + BT.18: + combinedCode: BT.18 + code: '18' + BT.19: + combinedCode: BT.19 + code: '19' + BT.20: + combinedCode: BT.20 + code: '20' + BT.21: + combinedCode: BT.21 + code: '21' + BT.22: + combinedCode: BT.22 + code: '22' + BT.23: + combinedCode: BT.23 + code: '23' + BT.24: + combinedCode: BT.24 + code: '24' +BV: + iso2Code: BV + iso3Code: BVT + regions: { } +BW: + iso2Code: BW + iso3Code: BWA + regions: + BW.10: + combinedCode: BW.10 + code: '10' + BW.09: + combinedCode: BW.09 + code: '09' + BW.08: + combinedCode: BW.08 + code: '08' + BW.11: + combinedCode: BW.11 + code: '11' + BW.06: + combinedCode: BW.06 + code: '06' + BW.05: + combinedCode: BW.05 + code: '05' + BW.04: + combinedCode: BW.04 + code: '04' + BW.03: + combinedCode: BW.03 + code: '03' + BW.01: + combinedCode: BW.01 + code: '01' +BY: + iso2Code: BY + iso3Code: BLR + regions: + BY.07: + combinedCode: BY.07 + code: '07' + BY.06: + combinedCode: BY.06 + code: '06' + BY.05: + combinedCode: BY.05 + code: '05' + BY.04: + combinedCode: BY.04 + code: '04' + BY.03: + combinedCode: BY.03 + code: '03' + BY.02: + combinedCode: BY.02 + code: '02' + BY.01: + combinedCode: BY.01 + code: '01' +BZ: + iso2Code: BZ + iso3Code: BLZ + regions: + BZ.06: + combinedCode: BZ.06 + code: '06' + BZ.05: + combinedCode: BZ.05 + code: '05' + BZ.04: + combinedCode: BZ.04 + code: '04' + BZ.03: + combinedCode: BZ.03 + code: '03' + BZ.02: + combinedCode: BZ.02 + code: '02' + BZ.01: + combinedCode: BZ.01 + code: '01' +CA: + iso2Code: CA + iso3Code: CAN + regions: + CA.01: + combinedCode: CA.01 + code: '01' + CA.02: + combinedCode: CA.02 + code: '02' + CA.03: + combinedCode: CA.03 + code: '03' + CA.04: + combinedCode: CA.04 + code: '04' + CA.13: + combinedCode: CA.13 + code: '13' + CA.07: + combinedCode: CA.07 + code: '07' + CA.14: + combinedCode: CA.14 + code: '14' + CA.08: + combinedCode: CA.08 + code: '08' + CA.09: + combinedCode: CA.09 + code: '09' + CA.10: + combinedCode: CA.10 + code: '10' + CA.11: + combinedCode: CA.11 + code: '11' + CA.12: + combinedCode: CA.12 + code: '12' + CA.05: + combinedCode: CA.05 + code: '05' +CC: + iso2Code: CC + iso3Code: CCK + regions: { } +CD: + iso2Code: CD + iso3Code: COD + regions: + CD.12: + combinedCode: CD.12 + code: '12' + CD.05: + combinedCode: CD.05 + code: '05' + CD.11: + combinedCode: CD.11 + code: '11' + CD.10: + combinedCode: CD.10 + code: '10' + CD.04: + combinedCode: CD.04 + code: '04' + CD.03: + combinedCode: CD.03 + code: '03' + CD.09: + combinedCode: CD.09 + code: '09' + CD.02: + combinedCode: CD.02 + code: '02' + CD.06: + combinedCode: CD.06 + code: '06' + CD.08: + combinedCode: CD.08 + code: '08' + CD.01: + combinedCode: CD.01 + code: '01' +CF: + iso2Code: CF + iso3Code: CAF + regions: + CF.14: + combinedCode: CF.14 + code: '14' + CF.11: + combinedCode: CF.11 + code: '11' + CF.08: + combinedCode: CF.08 + code: '08' + CF.05: + combinedCode: CF.05 + code: '05' + CF.03: + combinedCode: CF.03 + code: '03' + CF.02: + combinedCode: CF.02 + code: '02' + CF.01: + combinedCode: CF.01 + code: '01' + CF.16: + combinedCode: CF.16 + code: '16' + CF.13: + combinedCode: CF.13 + code: '13' + CF.12: + combinedCode: CF.12 + code: '12' + CF.17: + combinedCode: CF.17 + code: '17' + CF.09: + combinedCode: CF.09 + code: '09' + CF.07: + combinedCode: CF.07 + code: '07' + CF.06: + combinedCode: CF.06 + code: '06' + CF.04: + combinedCode: CF.04 + code: '04' + CF.15: + combinedCode: CF.15 + code: '15' + CF.18: + combinedCode: CF.18 + code: '18' +CG: + iso2Code: CG + iso3Code: COG + regions: + CG.10: + combinedCode: CG.10 + code: '10' + CG.11: + combinedCode: CG.11 + code: '11' + CG.08: + combinedCode: CG.08 + code: '08' + CG.07: + combinedCode: CG.07 + code: '07' + CG.06: + combinedCode: CG.06 + code: '06' + CG.05: + combinedCode: CG.05 + code: '05' + CG.04: + combinedCode: CG.04 + code: '04' + CG.13: + combinedCode: CG.13 + code: '13' + CG.01: + combinedCode: CG.01 + code: '01' + CG.12: + combinedCode: CG.12 + code: '12' + CG.14: + combinedCode: CG.14 + code: '14' + CG.7280295: + combinedCode: CG.7280295 + code: '7280295' +CH: + iso2Code: CH + iso3Code: CHE + regions: + CH.ZH: + combinedCode: CH.ZH + code: ZH + CH.ZG: + combinedCode: CH.ZG + code: ZG + CH.VD: + combinedCode: CH.VD + code: VD + CH.VS: + combinedCode: CH.VS + code: VS + CH.UR: + combinedCode: CH.UR + code: UR + CH.TI: + combinedCode: CH.TI + code: TI + CH.TG: + combinedCode: CH.TG + code: TG + CH.SO: + combinedCode: CH.SO + code: SO + CH.SZ: + combinedCode: CH.SZ + code: SZ + CH.SH: + combinedCode: CH.SH + code: SH + CH.SG: + combinedCode: CH.SG + code: SG + CH.OW: + combinedCode: CH.OW + code: OW + CH.NW: + combinedCode: CH.NW + code: NW + CH.NE: + combinedCode: CH.NE + code: NE + CH.LU: + combinedCode: CH.LU + code: LU + CH.JU: + combinedCode: CH.JU + code: JU + CH.GR: + combinedCode: CH.GR + code: GR + CH.GL: + combinedCode: CH.GL + code: GL + CH.GE: + combinedCode: CH.GE + code: GE + CH.FR: + combinedCode: CH.FR + code: FR + CH.BE: + combinedCode: CH.BE + code: BE + CH.BS: + combinedCode: CH.BS + code: BS + CH.BL: + combinedCode: CH.BL + code: BL + CH.AR: + combinedCode: CH.AR + code: AR + CH.AI: + combinedCode: CH.AI + code: AI + CH.AG: + combinedCode: CH.AG + code: AG +CI: + iso2Code: CI + iso3Code: CIV + regions: + CI.82: + combinedCode: CI.82 + code: '82' + CI.89: + combinedCode: CI.89 + code: '89' + CI.74: + combinedCode: CI.74 + code: '74' + CI.80: + combinedCode: CI.80 + code: '80' + CI.87: + combinedCode: CI.87 + code: '87' + CI.90: + combinedCode: CI.90 + code: '90' + CI.85: + combinedCode: CI.85 + code: '85' + CI.78: + combinedCode: CI.78 + code: '78' + CI.81: + combinedCode: CI.81 + code: '81' + CI.92: + combinedCode: CI.92 + code: '92' + CI.76: + combinedCode: CI.76 + code: '76' + CI.91: + combinedCode: CI.91 + code: '91' + CI.77: + combinedCode: CI.77 + code: '77' + CI.88: + combinedCode: CI.88 + code: '88' + CI.79: + combinedCode: CI.79 + code: '79' + CI.86: + combinedCode: CI.86 + code: '86' + CI.83: + combinedCode: CI.83 + code: '83' + CI.84: + combinedCode: CI.84 + code: '84' + CI.75: + combinedCode: CI.75 + code: '75' +CK: + iso2Code: CK + iso3Code: COK + regions: { } +CL: + iso2Code: CL + iso3Code: CHL + regions: + CL.01: + combinedCode: CL.01 + code: '01' + CL.15: + combinedCode: CL.15 + code: '15' + CL.12: + combinedCode: CL.12 + code: '12' + CL.11: + combinedCode: CL.11 + code: '11' + CL.14: + combinedCode: CL.14 + code: '14' + CL.08: + combinedCode: CL.08 + code: '08' + CL.07: + combinedCode: CL.07 + code: '07' + CL.06: + combinedCode: CL.06 + code: '06' + CL.05: + combinedCode: CL.05 + code: '05' + CL.04: + combinedCode: CL.04 + code: '04' + CL.03: + combinedCode: CL.03 + code: '03' + CL.02: + combinedCode: CL.02 + code: '02' + CL.10: + combinedCode: CL.10 + code: '10' + CL.16: + combinedCode: CL.16 + code: '16' + CL.17: + combinedCode: CL.17 + code: '17' +CM: + iso2Code: CM + iso3Code: CMR + regions: + CM.09: + combinedCode: CM.09 + code: '09' + CM.14: + combinedCode: CM.14 + code: '14' + CM.08: + combinedCode: CM.08 + code: '08' + CM.07: + combinedCode: CM.07 + code: '07' + CM.13: + combinedCode: CM.13 + code: '13' + CM.05: + combinedCode: CM.05 + code: '05' + CM.12: + combinedCode: CM.12 + code: '12' + CM.04: + combinedCode: CM.04 + code: '04' + CM.11: + combinedCode: CM.11 + code: '11' + CM.10: + combinedCode: CM.10 + code: '10' +CN: + iso2Code: CN + iso3Code: CHN + regions: + CN.14: + combinedCode: CN.14 + code: '14' + CN.06: + combinedCode: CN.06 + code: '06' + CN.13: + combinedCode: CN.13 + code: '13' + CN.02: + combinedCode: CN.02 + code: '02' + CN.29: + combinedCode: CN.29 + code: '29' + CN.28: + combinedCode: CN.28 + code: '28' + CN.32: + combinedCode: CN.32 + code: '32' + CN.24: + combinedCode: CN.24 + code: '24' + CN.23: + combinedCode: CN.23 + code: '23' + CN.25: + combinedCode: CN.25 + code: '25' + CN.26: + combinedCode: CN.26 + code: '26' + CN.21: + combinedCode: CN.21 + code: '21' + CN.03: + combinedCode: CN.03 + code: '03' + CN.04: + combinedCode: CN.04 + code: '04' + CN.11: + combinedCode: CN.11 + code: '11' + CN.12: + combinedCode: CN.12 + code: '12' + CN.09: + combinedCode: CN.09 + code: '09' + CN.10: + combinedCode: CN.10 + code: '10' + CN.31: + combinedCode: CN.31 + code: '31' + CN.18: + combinedCode: CN.18 + code: '18' + CN.16: + combinedCode: CN.16 + code: '16' + CN.30: + combinedCode: CN.30 + code: '30' + CN.15: + combinedCode: CN.15 + code: '15' + CN.07: + combinedCode: CN.07 + code: '07' + CN.33: + combinedCode: CN.33 + code: '33' + CN.01: + combinedCode: CN.01 + code: '01' + CN.20: + combinedCode: CN.20 + code: '20' + CN.19: + combinedCode: CN.19 + code: '19' + CN.05: + combinedCode: CN.05 + code: '05' + CN.08: + combinedCode: CN.08 + code: '08' + CN.22: + combinedCode: CN.22 + code: '22' +CO: + iso2Code: CO + iso3Code: COL + regions: + CO.31: + combinedCode: CO.31 + code: '31' + CO.30: + combinedCode: CO.30 + code: '30' + CO.29: + combinedCode: CO.29 + code: '29' + CO.28: + combinedCode: CO.28 + code: '28' + CO.27: + combinedCode: CO.27 + code: '27' + CO.26: + combinedCode: CO.26 + code: '26' + CO.25: + combinedCode: CO.25 + code: '25' + CO.24: + combinedCode: CO.24 + code: '24' + CO.23: + combinedCode: CO.23 + code: '23' + CO.22: + combinedCode: CO.22 + code: '22' + CO.21: + combinedCode: CO.21 + code: '21' + CO.20: + combinedCode: CO.20 + code: '20' + CO.19: + combinedCode: CO.19 + code: '19' + CO.38: + combinedCode: CO.38 + code: '38' + CO.17: + combinedCode: CO.17 + code: '17' + CO.16: + combinedCode: CO.16 + code: '16' + CO.14: + combinedCode: CO.14 + code: '14' + CO.15: + combinedCode: CO.15 + code: '15' + CO.33: + combinedCode: CO.33 + code: '33' + CO.12: + combinedCode: CO.12 + code: '12' + CO.11: + combinedCode: CO.11 + code: '11' + CO.10: + combinedCode: CO.10 + code: '10' + CO.09: + combinedCode: CO.09 + code: '09' + CO.32: + combinedCode: CO.32 + code: '32' + CO.08: + combinedCode: CO.08 + code: '08' + CO.37: + combinedCode: CO.37 + code: '37' + CO.36: + combinedCode: CO.36 + code: '36' + CO.35: + combinedCode: CO.35 + code: '35' + CO.34: + combinedCode: CO.34 + code: '34' + CO.04: + combinedCode: CO.04 + code: '04' + CO.03: + combinedCode: CO.03 + code: '03' + CO.02: + combinedCode: CO.02 + code: '02' + CO.01: + combinedCode: CO.01 + code: '01' +CR: + iso2Code: CR + iso3Code: CRI + regions: + CR.08: + combinedCode: CR.08 + code: '08' + CR.07: + combinedCode: CR.07 + code: '07' + CR.06: + combinedCode: CR.06 + code: '06' + CR.04: + combinedCode: CR.04 + code: '04' + CR.03: + combinedCode: CR.03 + code: '03' + CR.02: + combinedCode: CR.02 + code: '02' + CR.01: + combinedCode: CR.01 + code: '01' +CU: + iso2Code: CU + iso3Code: CUB + regions: + CU.16: + combinedCode: CU.16 + code: '16' + CU.15: + combinedCode: CU.15 + code: '15' + CU.14: + combinedCode: CU.14 + code: '14' + CU.01: + combinedCode: CU.01 + code: '01' + CU.03: + combinedCode: CU.03 + code: '03' + CU.13: + combinedCode: CU.13 + code: '13' + CU.04: + combinedCode: CU.04 + code: '04' + CU.12: + combinedCode: CU.12 + code: '12' + CU.10: + combinedCode: CU.10 + code: '10' + CU.09: + combinedCode: CU.09 + code: '09' + CU.02: + combinedCode: CU.02 + code: '02' + CU.08: + combinedCode: CU.08 + code: '08' + CU.07: + combinedCode: CU.07 + code: '07' + CU.05: + combinedCode: CU.05 + code: '05' + CU.AR: + combinedCode: CU.AR + code: AR + CU.MA: + combinedCode: CU.MA + code: MA +CV: + iso2Code: CV + iso3Code: CPV + regions: + CV.20: + combinedCode: CV.20 + code: '20' + CV.11: + combinedCode: CV.11 + code: '11' + CV.15: + combinedCode: CV.15 + code: '15' + CV.08: + combinedCode: CV.08 + code: '08' + CV.07: + combinedCode: CV.07 + code: '07' + CV.14: + combinedCode: CV.14 + code: '14' + CV.05: + combinedCode: CV.05 + code: '05' + CV.04: + combinedCode: CV.04 + code: '04' + CV.02: + combinedCode: CV.02 + code: '02' + CV.01: + combinedCode: CV.01 + code: '01' + CV.13: + combinedCode: CV.13 + code: '13' + CV.16: + combinedCode: CV.16 + code: '16' + CV.17: + combinedCode: CV.17 + code: '17' + CV.18: + combinedCode: CV.18 + code: '18' + CV.19: + combinedCode: CV.19 + code: '19' + CV.21: + combinedCode: CV.21 + code: '21' + CV.22: + combinedCode: CV.22 + code: '22' + CV.24: + combinedCode: CV.24 + code: '24' + CV.26: + combinedCode: CV.26 + code: '26' + CV.27: + combinedCode: CV.27 + code: '27' + CV.25: + combinedCode: CV.25 + code: '25' + CV.23: + combinedCode: CV.23 + code: '23' +CW: + iso2Code: CW + iso3Code: CUW + regions: { } +CX: + iso2Code: CX + iso3Code: CXR + regions: { } +CY: + iso2Code: CY + iso3Code: CYP + regions: + CY.06: + combinedCode: CY.06 + code: '06' + CY.04: + combinedCode: CY.04 + code: '04' + CY.05: + combinedCode: CY.05 + code: '05' + CY.03: + combinedCode: CY.03 + code: '03' + CY.02: + combinedCode: CY.02 + code: '02' + CY.01: + combinedCode: CY.01 + code: '01' +CZ: + iso2Code: CZ + iso3Code: CZE + regions: + CZ.52: + combinedCode: CZ.52 + code: '52' + CZ.78: + combinedCode: CZ.78 + code: '78' + CZ.79: + combinedCode: CZ.79 + code: '79' + CZ.80: + combinedCode: CZ.80 + code: '80' + CZ.81: + combinedCode: CZ.81 + code: '81' + CZ.82: + combinedCode: CZ.82 + code: '82' + CZ.83: + combinedCode: CZ.83 + code: '83' + CZ.84: + combinedCode: CZ.84 + code: '84' + CZ.85: + combinedCode: CZ.85 + code: '85' + CZ.86: + combinedCode: CZ.86 + code: '86' + CZ.87: + combinedCode: CZ.87 + code: '87' + CZ.88: + combinedCode: CZ.88 + code: '88' + CZ.89: + combinedCode: CZ.89 + code: '89' + CZ.90: + combinedCode: CZ.90 + code: '90' +DE: + iso2Code: DE + iso3Code: DEU + regions: + DE.15: + combinedCode: DE.15 + code: '15' + DE.10: + combinedCode: DE.10 + code: '10' + DE.14: + combinedCode: DE.14 + code: '14' + DE.13: + combinedCode: DE.13 + code: '13' + DE.09: + combinedCode: DE.09 + code: '09' + DE.08: + combinedCode: DE.08 + code: '08' + DE.07: + combinedCode: DE.07 + code: '07' + DE.06: + combinedCode: DE.06 + code: '06' + DE.12: + combinedCode: DE.12 + code: '12' + DE.05: + combinedCode: DE.05 + code: '05' + DE.04: + combinedCode: DE.04 + code: '04' + DE.03: + combinedCode: DE.03 + code: '03' + DE.11: + combinedCode: DE.11 + code: '11' + DE.16: + combinedCode: DE.16 + code: '16' + DE.02: + combinedCode: DE.02 + code: '02' + DE.01: + combinedCode: DE.01 + code: '01' +DJ: + iso2Code: DJ + iso3Code: DJI + regions: + DJ.05: + combinedCode: DJ.05 + code: '05' + DJ.04: + combinedCode: DJ.04 + code: '04' + DJ.07: + combinedCode: DJ.07 + code: '07' + DJ.06: + combinedCode: DJ.06 + code: '06' + DJ.01: + combinedCode: DJ.01 + code: '01' + DJ.08: + combinedCode: DJ.08 + code: '08' +DK: + iso2Code: DK + iso3Code: DNK + regions: + DK.17: + combinedCode: DK.17 + code: '17' + DK.18: + combinedCode: DK.18 + code: '18' + DK.19: + combinedCode: DK.19 + code: '19' + DK.20: + combinedCode: DK.20 + code: '20' + DK.21: + combinedCode: DK.21 + code: '21' +DM: + iso2Code: DM + iso3Code: DMA + regions: + DM.11: + combinedCode: DM.11 + code: '11' + DM.10: + combinedCode: DM.10 + code: '10' + DM.09: + combinedCode: DM.09 + code: '09' + DM.08: + combinedCode: DM.08 + code: '08' + DM.07: + combinedCode: DM.07 + code: '07' + DM.06: + combinedCode: DM.06 + code: '06' + DM.05: + combinedCode: DM.05 + code: '05' + DM.04: + combinedCode: DM.04 + code: '04' + DM.03: + combinedCode: DM.03 + code: '03' + DM.02: + combinedCode: DM.02 + code: '02' +DO: + iso2Code: DO + iso3Code: DOM + regions: + DO.27: + combinedCode: DO.27 + code: '27' + DO.26: + combinedCode: DO.26 + code: '26' + DO.25: + combinedCode: DO.25 + code: '25' + DO.24: + combinedCode: DO.24 + code: '24' + DO.23: + combinedCode: DO.23 + code: '23' + DO.33: + combinedCode: DO.33 + code: '33' + DO.21: + combinedCode: DO.21 + code: '21' + DO.20: + combinedCode: DO.20 + code: '20' + DO.19: + combinedCode: DO.19 + code: '19' + DO.18: + combinedCode: DO.18 + code: '18' + DO.35: + combinedCode: DO.35 + code: '35' + DO.16: + combinedCode: DO.16 + code: '16' + DO.34: + combinedCode: DO.34 + code: '34' + DO.32: + combinedCode: DO.32 + code: '32' + DO.15: + combinedCode: DO.15 + code: '15' + DO.31: + combinedCode: DO.31 + code: '31' + DO.14: + combinedCode: DO.14 + code: '14' + DO.30: + combinedCode: DO.30 + code: '30' + DO.12: + combinedCode: DO.12 + code: '12' + DO.10: + combinedCode: DO.10 + code: '10' + DO.09: + combinedCode: DO.09 + code: '09' + DO.29: + combinedCode: DO.29 + code: '29' + DO.08: + combinedCode: DO.08 + code: '08' + DO.28: + combinedCode: DO.28 + code: '28' + DO.11: + combinedCode: DO.11 + code: '11' + DO.06: + combinedCode: DO.06 + code: '06' + DO.04: + combinedCode: DO.04 + code: '04' + DO.03: + combinedCode: DO.03 + code: '03' + DO.02: + combinedCode: DO.02 + code: '02' + DO.01: + combinedCode: DO.01 + code: '01' + DO.36: + combinedCode: DO.36 + code: '36' + DO.37: + combinedCode: DO.37 + code: '37' +DZ: + iso2Code: DZ + iso3Code: DZA + regions: + DZ.15: + combinedCode: DZ.15 + code: '15' + DZ.14: + combinedCode: DZ.14 + code: '14' + DZ.56: + combinedCode: DZ.56 + code: '56' + DZ.55: + combinedCode: DZ.55 + code: '55' + DZ.54: + combinedCode: DZ.54 + code: '54' + DZ.13: + combinedCode: DZ.13 + code: '13' + DZ.33: + combinedCode: DZ.33 + code: '33' + DZ.53: + combinedCode: DZ.53 + code: '53' + DZ.52: + combinedCode: DZ.52 + code: '52' + DZ.31: + combinedCode: DZ.31 + code: '31' + DZ.30: + combinedCode: DZ.30 + code: '30' + DZ.12: + combinedCode: DZ.12 + code: '12' + DZ.10: + combinedCode: DZ.10 + code: '10' + DZ.51: + combinedCode: DZ.51 + code: '51' + DZ.29: + combinedCode: DZ.29 + code: '29' + DZ.50: + combinedCode: DZ.50 + code: '50' + DZ.09: + combinedCode: DZ.09 + code: '09' + DZ.49: + combinedCode: DZ.49 + code: '49' + DZ.27: + combinedCode: DZ.27 + code: '27' + DZ.07: + combinedCode: DZ.07 + code: '07' + DZ.48: + combinedCode: DZ.48 + code: '48' + DZ.06: + combinedCode: DZ.06 + code: '06' + DZ.26: + combinedCode: DZ.26 + code: '26' + DZ.25: + combinedCode: DZ.25 + code: '25' + DZ.47: + combinedCode: DZ.47 + code: '47' + DZ.24: + combinedCode: DZ.24 + code: '24' + DZ.46: + combinedCode: DZ.46 + code: '46' + DZ.23: + combinedCode: DZ.23 + code: '23' + DZ.45: + combinedCode: DZ.45 + code: '45' + DZ.44: + combinedCode: DZ.44 + code: '44' + DZ.43: + combinedCode: DZ.43 + code: '43' + DZ.42: + combinedCode: DZ.42 + code: '42' + DZ.22: + combinedCode: DZ.22 + code: '22' + DZ.04: + combinedCode: DZ.04 + code: '04' + DZ.41: + combinedCode: DZ.41 + code: '41' + DZ.40: + combinedCode: DZ.40 + code: '40' + DZ.21: + combinedCode: DZ.21 + code: '21' + DZ.39: + combinedCode: DZ.39 + code: '39' + DZ.20: + combinedCode: DZ.20 + code: '20' + DZ.19: + combinedCode: DZ.19 + code: '19' + DZ.18: + combinedCode: DZ.18 + code: '18' + DZ.38: + combinedCode: DZ.38 + code: '38' + DZ.03: + combinedCode: DZ.03 + code: '03' + DZ.37: + combinedCode: DZ.37 + code: '37' + DZ.01: + combinedCode: DZ.01 + code: '01' + DZ.36: + combinedCode: DZ.36 + code: '36' + DZ.35: + combinedCode: DZ.35 + code: '35' + DZ.34: + combinedCode: DZ.34 + code: '34' +EC: + iso2Code: EC + iso3Code: ECU + regions: + EC.20: + combinedCode: EC.20 + code: '20' + EC.19: + combinedCode: EC.19 + code: '19' + EC.18: + combinedCode: EC.18 + code: '18' + EC.17: + combinedCode: EC.17 + code: '17' + EC.23: + combinedCode: EC.23 + code: '23' + EC.15: + combinedCode: EC.15 + code: '15' + EC.14: + combinedCode: EC.14 + code: '14' + EC.13: + combinedCode: EC.13 + code: '13' + EC.12: + combinedCode: EC.12 + code: '12' + EC.11: + combinedCode: EC.11 + code: '11' + EC.10: + combinedCode: EC.10 + code: '10' + EC.01: + combinedCode: EC.01 + code: '01' + EC.09: + combinedCode: EC.09 + code: '09' + EC.08: + combinedCode: EC.08 + code: '08' + EC.07: + combinedCode: EC.07 + code: '07' + EC.06: + combinedCode: EC.06 + code: '06' + EC.05: + combinedCode: EC.05 + code: '05' + EC.04: + combinedCode: EC.04 + code: '04' + EC.03: + combinedCode: EC.03 + code: '03' + EC.02: + combinedCode: EC.02 + code: '02' + EC.22: + combinedCode: EC.22 + code: '22' + EC.24: + combinedCode: EC.24 + code: '24' + EC.26: + combinedCode: EC.26 + code: '26' + EC.25: + combinedCode: EC.25 + code: '25' +EE: + iso2Code: EE + iso3Code: EST + regions: + EE.21: + combinedCode: EE.21 + code: '21' + EE.20: + combinedCode: EE.20 + code: '20' + EE.19: + combinedCode: EE.19 + code: '19' + EE.18: + combinedCode: EE.18 + code: '18' + EE.14: + combinedCode: EE.14 + code: '14' + EE.13: + combinedCode: EE.13 + code: '13' + EE.12: + combinedCode: EE.12 + code: '12' + EE.11: + combinedCode: EE.11 + code: '11' + EE.08: + combinedCode: EE.08 + code: '08' + EE.07: + combinedCode: EE.07 + code: '07' + EE.05: + combinedCode: EE.05 + code: '05' + EE.04: + combinedCode: EE.04 + code: '04' + EE.03: + combinedCode: EE.03 + code: '03' + EE.02: + combinedCode: EE.02 + code: '02' + EE.01: + combinedCode: EE.01 + code: '01' +EG: + iso2Code: EG + iso3Code: EGY + regions: + EG.24: + combinedCode: EG.24 + code: '24' + EG.27: + combinedCode: EG.27 + code: '27' + EG.23: + combinedCode: EG.23 + code: '23' + EG.22: + combinedCode: EG.22 + code: '22' + EG.21: + combinedCode: EG.21 + code: '21' + EG.26: + combinedCode: EG.26 + code: '26' + EG.20: + combinedCode: EG.20 + code: '20' + EG.19: + combinedCode: EG.19 + code: '19' + EG.18: + combinedCode: EG.18 + code: '18' + EG.17: + combinedCode: EG.17 + code: '17' + EG.16: + combinedCode: EG.16 + code: '16' + EG.15: + combinedCode: EG.15 + code: '15' + EG.14: + combinedCode: EG.14 + code: '14' + EG.13: + combinedCode: EG.13 + code: '13' + EG.12: + combinedCode: EG.12 + code: '12' + EG.11: + combinedCode: EG.11 + code: '11' + EG.10: + combinedCode: EG.10 + code: '10' + EG.09: + combinedCode: EG.09 + code: '09' + EG.08: + combinedCode: EG.08 + code: '08' + EG.07: + combinedCode: EG.07 + code: '07' + EG.06: + combinedCode: EG.06 + code: '06' + EG.05: + combinedCode: EG.05 + code: '05' + EG.04: + combinedCode: EG.04 + code: '04' + EG.03: + combinedCode: EG.03 + code: '03' + EG.02: + combinedCode: EG.02 + code: '02' + EG.01: + combinedCode: EG.01 + code: '01' + EG.28: + combinedCode: EG.28 + code: '28' +EH: + iso2Code: EH + iso3Code: ESH + regions: + EH.CE: + combinedCode: EH.CE + code: CE +ER: + iso2Code: ER + iso3Code: ERI + regions: + ER.01: + combinedCode: ER.01 + code: '01' + ER.02: + combinedCode: ER.02 + code: '02' + ER.03: + combinedCode: ER.03 + code: '03' + ER.04: + combinedCode: ER.04 + code: '04' + ER.05: + combinedCode: ER.05 + code: '05' + ER.06: + combinedCode: ER.06 + code: '06' +ES: + iso2Code: ES + iso3Code: ESP + regions: + ES.31: + combinedCode: ES.31 + code: '31' + ES.CE: + combinedCode: ES.CE + code: CE + ES.07: + combinedCode: ES.07 + code: '07' + ES.51: + combinedCode: ES.51 + code: '51' + ES.53: + combinedCode: ES.53 + code: '53' + ES.54: + combinedCode: ES.54 + code: '54' + ES.57: + combinedCode: ES.57 + code: '57' + ES.60: + combinedCode: ES.60 + code: '60' + ES.34: + combinedCode: ES.34 + code: '34' + ES.32: + combinedCode: ES.32 + code: '32' + ES.29: + combinedCode: ES.29 + code: '29' + ES.27: + combinedCode: ES.27 + code: '27' + ES.39: + combinedCode: ES.39 + code: '39' + ES.52: + combinedCode: ES.52 + code: '52' + ES.55: + combinedCode: ES.55 + code: '55' + ES.56: + combinedCode: ES.56 + code: '56' + ES.58: + combinedCode: ES.58 + code: '58' + ES.59: + combinedCode: ES.59 + code: '59' + ES.ML: + combinedCode: ES.ML + code: ML +ET: + iso2Code: ET + iso3Code: ETH + regions: + ET.44: + combinedCode: ET.44 + code: '44' + ET.45: + combinedCode: ET.45 + code: '45' + ET.46: + combinedCode: ET.46 + code: '46' + ET.47: + combinedCode: ET.47 + code: '47' + ET.48: + combinedCode: ET.48 + code: '48' + ET.49: + combinedCode: ET.49 + code: '49' + ET.50: + combinedCode: ET.50 + code: '50' + ET.51: + combinedCode: ET.51 + code: '51' + ET.52: + combinedCode: ET.52 + code: '52' + ET.53: + combinedCode: ET.53 + code: '53' + ET.54: + combinedCode: ET.54 + code: '54' +FI: + iso2Code: FI + iso3Code: FIN + regions: + FI.08: + combinedCode: FI.08 + code: '08' + FI.06: + combinedCode: FI.06 + code: '06' + FI.13: + combinedCode: FI.13 + code: '13' + FI.14: + combinedCode: FI.14 + code: '14' + FI.15: + combinedCode: FI.15 + code: '15' +FJ: + iso2Code: FJ + iso3Code: FJI + regions: + FJ.05: + combinedCode: FJ.05 + code: '05' + FJ.03: + combinedCode: FJ.03 + code: '03' + FJ.01: + combinedCode: FJ.01 + code: '01' + FJ.02: + combinedCode: FJ.02 + code: '02' + FJ.04: + combinedCode: FJ.04 + code: '04' +FK: + iso2Code: FK + iso3Code: FLK + regions: { } +FM: + iso2Code: FM + iso3Code: FSM + regions: + FM.04: + combinedCode: FM.04 + code: '04' + FM.02: + combinedCode: FM.02 + code: '02' + FM.01: + combinedCode: FM.01 + code: '01' + FM.03: + combinedCode: FM.03 + code: '03' +FO: + iso2Code: FO + iso3Code: FRO + regions: + FO.VG: + combinedCode: FO.VG + code: VG + FO.SU: + combinedCode: FO.SU + code: SU + FO.ST: + combinedCode: FO.ST + code: ST + FO.SA: + combinedCode: FO.SA + code: SA + FO.NO: + combinedCode: FO.NO + code: NO + FO.OS: + combinedCode: FO.OS + code: OS +FR: + iso2Code: FR + iso3Code: FRA + regions: + FR.B9: + combinedCode: FR.B9 + code: B9 + FR.B8: + combinedCode: FR.B8 + code: B8 + FR.B7: + combinedCode: FR.B7 + code: B7 + FR.B6: + combinedCode: FR.B6 + code: B6 + FR.B5: + combinedCode: FR.B5 + code: B5 + FR.B4: + combinedCode: FR.B4 + code: B4 + FR.B3: + combinedCode: FR.B3 + code: B3 + FR.B2: + combinedCode: FR.B2 + code: B2 + FR.B1: + combinedCode: FR.B1 + code: B1 + FR.A9: + combinedCode: FR.A9 + code: A9 + FR.A8: + combinedCode: FR.A8 + code: A8 + FR.A7: + combinedCode: FR.A7 + code: A7 + FR.A6: + combinedCode: FR.A6 + code: A6 + FR.A5: + combinedCode: FR.A5 + code: A5 + FR.A4: + combinedCode: FR.A4 + code: A4 + FR.A3: + combinedCode: FR.A3 + code: A3 + FR.A2: + combinedCode: FR.A2 + code: A2 + FR.A1: + combinedCode: FR.A1 + code: A1 + FR.99: + combinedCode: FR.99 + code: '99' + FR.98: + combinedCode: FR.98 + code: '98' + FR.97: + combinedCode: FR.97 + code: '97' + FR.C1: + combinedCode: FR.C1 + code: C1 +GA: + iso2Code: GA + iso3Code: GAB + regions: + GA.09: + combinedCode: GA.09 + code: '09' + GA.08: + combinedCode: GA.08 + code: '08' + GA.07: + combinedCode: GA.07 + code: '07' + GA.06: + combinedCode: GA.06 + code: '06' + GA.05: + combinedCode: GA.05 + code: '05' + GA.04: + combinedCode: GA.04 + code: '04' + GA.03: + combinedCode: GA.03 + code: '03' + GA.02: + combinedCode: GA.02 + code: '02' + GA.01: + combinedCode: GA.01 + code: '01' +GB: + iso2Code: GB + iso3Code: GBR + regions: + GB.WLS: + combinedCode: GB.WLS + code: WLS + GB.SCT: + combinedCode: GB.SCT + code: SCT + GB.NIR: + combinedCode: GB.NIR + code: NIR + GB.ENG: + combinedCode: GB.ENG + code: ENG +GD: + iso2Code: GD + iso3Code: GRD + regions: + GD.06: + combinedCode: GD.06 + code: '06' + GD.05: + combinedCode: GD.05 + code: '05' + GD.04: + combinedCode: GD.04 + code: '04' + GD.03: + combinedCode: GD.03 + code: '03' + GD.02: + combinedCode: GD.02 + code: '02' + GD.01: + combinedCode: GD.01 + code: '01' + GD.10: + combinedCode: GD.10 + code: '10' +GE: + iso2Code: GE + iso3Code: GEO + regions: + GE.51: + combinedCode: GE.51 + code: '51' + GE.04: + combinedCode: GE.04 + code: '04' + GE.68: + combinedCode: GE.68 + code: '68' + GE.67: + combinedCode: GE.67 + code: '67' + GE.65: + combinedCode: GE.65 + code: '65' + GE.66: + combinedCode: GE.66 + code: '66' + GE.73: + combinedCode: GE.73 + code: '73' + GE.69: + combinedCode: GE.69 + code: '69' + GE.70: + combinedCode: GE.70 + code: '70' + GE.71: + combinedCode: GE.71 + code: '71' + GE.72: + combinedCode: GE.72 + code: '72' + GE.02: + combinedCode: GE.02 + code: '02' +GF: + iso2Code: GF + iso3Code: GUF + regions: + GF.GF: + combinedCode: GF.GF + code: GF +GG: + iso2Code: GG + iso3Code: GGY + regions: { } +GH: + iso2Code: GH + iso3Code: GHA + regions: + GH.09: + combinedCode: GH.09 + code: '09' + GH.08: + combinedCode: GH.08 + code: '08' + GH.11: + combinedCode: GH.11 + code: '11' + GH.10: + combinedCode: GH.10 + code: '10' + GH.06: + combinedCode: GH.06 + code: '06' + GH.01: + combinedCode: GH.01 + code: '01' + GH.05: + combinedCode: GH.05 + code: '05' + GH.04: + combinedCode: GH.04 + code: '04' + GH.03: + combinedCode: GH.03 + code: '03' + GH.02: + combinedCode: GH.02 + code: '02' +GI: + iso2Code: GI + iso3Code: GIB + regions: { } +GL: + iso2Code: GL + iso3Code: GRL + regions: + GL.05: + combinedCode: GL.05 + code: '05' + GL.04: + combinedCode: GL.04 + code: '04' + GL.06: + combinedCode: GL.06 + code: '06' + GL.07: + combinedCode: GL.07 + code: '07' +GM: + iso2Code: GM + iso3Code: GMB + regions: + GM.05: + combinedCode: GM.05 + code: '05' + GM.04: + combinedCode: GM.04 + code: '04' + GM.07: + combinedCode: GM.07 + code: '07' + GM.03: + combinedCode: GM.03 + code: '03' + GM.02: + combinedCode: GM.02 + code: '02' + GM.01: + combinedCode: GM.01 + code: '01' +GN: + iso2Code: GN + iso3Code: GIN + regions: + GN.04: + combinedCode: GN.04 + code: '04' + GN.B: + combinedCode: GN.B + code: B + GN.F: + combinedCode: GN.F + code: F + GN.K: + combinedCode: GN.K + code: K + GN.D: + combinedCode: GN.D + code: D + GN.L: + combinedCode: GN.L + code: L + GN.M: + combinedCode: GN.M + code: M + GN.N: + combinedCode: GN.N + code: N +GP: + iso2Code: GP + iso3Code: GLP + regions: + GP.GP: + combinedCode: GP.GP + code: GP +GQ: + iso2Code: GQ + iso3Code: GNQ + regions: + GQ.03: + combinedCode: GQ.03 + code: '03' + GQ.04: + combinedCode: GQ.04 + code: '04' + GQ.05: + combinedCode: GQ.05 + code: '05' + GQ.06: + combinedCode: GQ.06 + code: '06' + GQ.07: + combinedCode: GQ.07 + code: '07' + GQ.08: + combinedCode: GQ.08 + code: '08' + GQ.09: + combinedCode: GQ.09 + code: '09' +GR: + iso2Code: GR + iso3Code: GRC + regions: + GR.736572: + combinedCode: GR.736572 + code: '736572' + GR.ESYE31: + combinedCode: GR.ESYE31 + code: ESYE31 + GR.ESYE24: + combinedCode: GR.ESYE24 + code: ESYE24 + GR.ESYE12: + combinedCode: GR.ESYE12 + code: ESYE12 + GR.ESYE43: + combinedCode: GR.ESYE43 + code: ESYE43 + GR.ESYE11: + combinedCode: GR.ESYE11 + code: ESYE11 + GR.ESYE21: + combinedCode: GR.ESYE21 + code: ESYE21 + GR.ESYE22: + combinedCode: GR.ESYE22 + code: ESYE22 + GR.ESYE41: + combinedCode: GR.ESYE41 + code: ESYE41 + GR.ESYE25: + combinedCode: GR.ESYE25 + code: ESYE25 + GR.ESYE42: + combinedCode: GR.ESYE42 + code: ESYE42 + GR.ESYE14: + combinedCode: GR.ESYE14 + code: ESYE14 + GR.ESYE23: + combinedCode: GR.ESYE23 + code: ESYE23 + GR.ESYE13: + combinedCode: GR.ESYE13 + code: ESYE13 +GS: + iso2Code: GS + iso3Code: SGS + regions: { } +GT: + iso2Code: GT + iso3Code: GTM + regions: + GT.22: + combinedCode: GT.22 + code: '22' + GT.21: + combinedCode: GT.21 + code: '21' + GT.20: + combinedCode: GT.20 + code: '20' + GT.19: + combinedCode: GT.19 + code: '19' + GT.18: + combinedCode: GT.18 + code: '18' + GT.17: + combinedCode: GT.17 + code: '17' + GT.16: + combinedCode: GT.16 + code: '16' + GT.15: + combinedCode: GT.15 + code: '15' + GT.14: + combinedCode: GT.14 + code: '14' + GT.13: + combinedCode: GT.13 + code: '13' + GT.12: + combinedCode: GT.12 + code: '12' + GT.11: + combinedCode: GT.11 + code: '11' + GT.10: + combinedCode: GT.10 + code: '10' + GT.09: + combinedCode: GT.09 + code: '09' + GT.08: + combinedCode: GT.08 + code: '08' + GT.07: + combinedCode: GT.07 + code: '07' + GT.06: + combinedCode: GT.06 + code: '06' + GT.05: + combinedCode: GT.05 + code: '05' + GT.04: + combinedCode: GT.04 + code: '04' + GT.03: + combinedCode: GT.03 + code: '03' + GT.02: + combinedCode: GT.02 + code: '02' + GT.01: + combinedCode: GT.01 + code: '01' +GU: + iso2Code: GU + iso3Code: GUM + regions: + GU.PI: + combinedCode: GU.PI + code: PI + GU.SR: + combinedCode: GU.SR + code: SR + GU.SJ: + combinedCode: GU.SJ + code: SJ + GU.TF: + combinedCode: GU.TF + code: TF + GU.TM: + combinedCode: GU.TM + code: TM + GU.UM: + combinedCode: GU.UM + code: UM + GU.YG: + combinedCode: GU.YG + code: YG + GU.YN: + combinedCode: GU.YN + code: YN + GU.ME: + combinedCode: GU.ME + code: ME + GU.MA: + combinedCode: GU.MA + code: MA + GU.AH: + combinedCode: GU.AH + code: AH + GU.CP: + combinedCode: GU.CP + code: CP + GU.AS: + combinedCode: GU.AS + code: AS + GU.AT: + combinedCode: GU.AT + code: AT + GU.DD: + combinedCode: GU.DD + code: DD + GU.BA: + combinedCode: GU.BA + code: BA + GU.AN: + combinedCode: GU.AN + code: AN + GU.IN: + combinedCode: GU.IN + code: IN + GU.MT: + combinedCode: GU.MT + code: MT +GW: + iso2Code: GW + iso3Code: GNB + regions: + GW.07: + combinedCode: GW.07 + code: '07' + GW.02: + combinedCode: GW.02 + code: '02' + GW.04: + combinedCode: GW.04 + code: '04' + GW.10: + combinedCode: GW.10 + code: '10' + GW.06: + combinedCode: GW.06 + code: '06' + GW.05: + combinedCode: GW.05 + code: '05' + GW.11: + combinedCode: GW.11 + code: '11' + GW.12: + combinedCode: GW.12 + code: '12' + GW.01: + combinedCode: GW.01 + code: '01' +GY: + iso2Code: GY + iso3Code: GUY + regions: + GY.19: + combinedCode: GY.19 + code: '19' + GY.18: + combinedCode: GY.18 + code: '18' + GY.17: + combinedCode: GY.17 + code: '17' + GY.16: + combinedCode: GY.16 + code: '16' + GY.15: + combinedCode: GY.15 + code: '15' + GY.14: + combinedCode: GY.14 + code: '14' + GY.13: + combinedCode: GY.13 + code: '13' + GY.12: + combinedCode: GY.12 + code: '12' + GY.11: + combinedCode: GY.11 + code: '11' + GY.10: + combinedCode: GY.10 + code: '10' +HK: + iso2Code: HK + iso3Code: HKG + regions: + HK.NYL: + combinedCode: HK.NYL + code: NYL + HK.NTW: + combinedCode: HK.NTW + code: NTW + HK.NTP: + combinedCode: HK.NTP + code: NTP + HK.NSK: + combinedCode: HK.NSK + code: NSK + HK.NIS: + combinedCode: HK.NIS + code: NIS + HK.HCW: + combinedCode: HK.HCW + code: HCW + HK.HWC: + combinedCode: HK.HWC + code: HWC + HK.HEA: + combinedCode: HK.HEA + code: HEA + HK.HSO: + combinedCode: HK.HSO + code: HSO + HK.KYT: + combinedCode: HK.KYT + code: KYT + HK.KSS: + combinedCode: HK.KSS + code: KSS + HK.KKC: + combinedCode: HK.KKC + code: KKC + HK.KWT: + combinedCode: HK.KWT + code: KWT + HK.KKT: + combinedCode: HK.KKT + code: KKT + HK.NKT: + combinedCode: HK.NKT + code: NKT + HK.NTM: + combinedCode: HK.NTM + code: NTM + HK.NNO: + combinedCode: HK.NNO + code: NNO + HK.NST: + combinedCode: HK.NST + code: NST +HM: + iso2Code: HM + iso3Code: HMD + regions: { } +HN: + iso2Code: HN + iso3Code: HND + regions: + HN.18: + combinedCode: HN.18 + code: '18' + HN.17: + combinedCode: HN.17 + code: '17' + HN.16: + combinedCode: HN.16 + code: '16' + HN.15: + combinedCode: HN.15 + code: '15' + HN.14: + combinedCode: HN.14 + code: '14' + HN.13: + combinedCode: HN.13 + code: '13' + HN.12: + combinedCode: HN.12 + code: '12' + HN.11: + combinedCode: HN.11 + code: '11' + HN.10: + combinedCode: HN.10 + code: '10' + HN.09: + combinedCode: HN.09 + code: '09' + HN.08: + combinedCode: HN.08 + code: '08' + HN.07: + combinedCode: HN.07 + code: '07' + HN.06: + combinedCode: HN.06 + code: '06' + HN.05: + combinedCode: HN.05 + code: '05' + HN.04: + combinedCode: HN.04 + code: '04' + HN.03: + combinedCode: HN.03 + code: '03' + HN.02: + combinedCode: HN.02 + code: '02' + HN.01: + combinedCode: HN.01 + code: '01' +HR: + iso2Code: HR + iso3Code: HRV + regions: + HR.01: + combinedCode: HR.01 + code: '01' + HR.02: + combinedCode: HR.02 + code: '02' + HR.03: + combinedCode: HR.03 + code: '03' + HR.04: + combinedCode: HR.04 + code: '04' + HR.05: + combinedCode: HR.05 + code: '05' + HR.06: + combinedCode: HR.06 + code: '06' + HR.07: + combinedCode: HR.07 + code: '07' + HR.08: + combinedCode: HR.08 + code: '08' + HR.09: + combinedCode: HR.09 + code: '09' + HR.10: + combinedCode: HR.10 + code: '10' + HR.11: + combinedCode: HR.11 + code: '11' + HR.12: + combinedCode: HR.12 + code: '12' + HR.13: + combinedCode: HR.13 + code: '13' + HR.14: + combinedCode: HR.14 + code: '14' + HR.15: + combinedCode: HR.15 + code: '15' + HR.16: + combinedCode: HR.16 + code: '16' + HR.18: + combinedCode: HR.18 + code: '18' + HR.19: + combinedCode: HR.19 + code: '19' + HR.20: + combinedCode: HR.20 + code: '20' + HR.21: + combinedCode: HR.21 + code: '21' + HR.17: + combinedCode: HR.17 + code: '17' +HT: + iso2Code: HT + iso3Code: HTI + regions: + HT.13: + combinedCode: HT.13 + code: '13' + HT.12: + combinedCode: HT.12 + code: '12' + HT.11: + combinedCode: HT.11 + code: '11' + HT.03: + combinedCode: HT.03 + code: '03' + HT.10: + combinedCode: HT.10 + code: '10' + HT.09: + combinedCode: HT.09 + code: '09' + HT.14: + combinedCode: HT.14 + code: '14' + HT.07: + combinedCode: HT.07 + code: '07' + HT.06: + combinedCode: HT.06 + code: '06' + HT.15: + combinedCode: HT.15 + code: '15' +HU: + iso2Code: HU + iso3Code: HUN + regions: + HU.18: + combinedCode: HU.18 + code: '18' + HU.20: + combinedCode: HU.20 + code: '20' + HU.11: + combinedCode: HU.11 + code: '11' + HU.10: + combinedCode: HU.10 + code: '10' + HU.06: + combinedCode: HU.06 + code: '06' + HU.04: + combinedCode: HU.04 + code: '04' + HU.03: + combinedCode: HU.03 + code: '03' + HU.24: + combinedCode: HU.24 + code: '24' + HU.23: + combinedCode: HU.23 + code: '23' + HU.22: + combinedCode: HU.22 + code: '22' + HU.21: + combinedCode: HU.21 + code: '21' + HU.17: + combinedCode: HU.17 + code: '17' + HU.16: + combinedCode: HU.16 + code: '16' + HU.14: + combinedCode: HU.14 + code: '14' + HU.12: + combinedCode: HU.12 + code: '12' + HU.09: + combinedCode: HU.09 + code: '09' + HU.08: + combinedCode: HU.08 + code: '08' + HU.05: + combinedCode: HU.05 + code: '05' + HU.02: + combinedCode: HU.02 + code: '02' + HU.01: + combinedCode: HU.01 + code: '01' +ID: + iso2Code: ID + iso3Code: IDN + regions: + ID.26: + combinedCode: ID.26 + code: '26' + ID.01: + combinedCode: ID.01 + code: '01' + ID.10: + combinedCode: ID.10 + code: '10' + ID.32: + combinedCode: ID.32 + code: '32' + ID.24: + combinedCode: ID.24 + code: '24' + ID.31: + combinedCode: ID.31 + code: '31' + ID.22: + combinedCode: ID.22 + code: '22' + ID.21: + combinedCode: ID.21 + code: '21' + ID.38: + combinedCode: ID.38 + code: '38' + ID.37: + combinedCode: ID.37 + code: '37' + ID.18: + combinedCode: ID.18 + code: '18' + ID.17: + combinedCode: ID.17 + code: '17' + ID.28: + combinedCode: ID.28 + code: '28' + ID.15: + combinedCode: ID.15 + code: '15' + ID.14: + combinedCode: ID.14 + code: '14' + ID.13: + combinedCode: ID.13 + code: '13' + ID.12: + combinedCode: ID.12 + code: '12' + ID.11: + combinedCode: ID.11 + code: '11' + ID.08: + combinedCode: ID.08 + code: '08' + ID.07: + combinedCode: ID.07 + code: '07' + ID.30: + combinedCode: ID.30 + code: '30' + ID.05: + combinedCode: ID.05 + code: '05' + ID.04: + combinedCode: ID.04 + code: '04' + ID.36: + combinedCode: ID.36 + code: '36' + ID.03: + combinedCode: ID.03 + code: '03' + ID.02: + combinedCode: ID.02 + code: '02' + ID.33: + combinedCode: ID.33 + code: '33' + ID.34: + combinedCode: ID.34 + code: '34' + ID.35: + combinedCode: ID.35 + code: '35' + ID.29: + combinedCode: ID.29 + code: '29' + ID.39: + combinedCode: ID.39 + code: '39' + ID.41: + combinedCode: ID.41 + code: '41' + ID.40: + combinedCode: ID.40 + code: '40' +IE: + iso2Code: IE + iso3Code: IRL + regions: + IE.C: + combinedCode: IE.C + code: C + IE.L: + combinedCode: IE.L + code: L + IE.M: + combinedCode: IE.M + code: M + IE.U: + combinedCode: IE.U + code: U +IL: + iso2Code: IL + iso3Code: ISR + regions: + IL.06: + combinedCode: IL.06 + code: '06' + IL.05: + combinedCode: IL.05 + code: '05' + IL.04: + combinedCode: IL.04 + code: '04' + IL.03: + combinedCode: IL.03 + code: '03' + IL.02: + combinedCode: IL.02 + code: '02' + IL.01: + combinedCode: IL.01 + code: '01' +IM: + iso2Code: IM + iso3Code: IMN + regions: { } +IN: + iso2Code: IN + iso3Code: IND + regions: + IN.28: + combinedCode: IN.28 + code: '28' + IN.36: + combinedCode: IN.36 + code: '36' + IN.26: + combinedCode: IN.26 + code: '26' + IN.25: + combinedCode: IN.25 + code: '25' + IN.29: + combinedCode: IN.29 + code: '29' + IN.24: + combinedCode: IN.24 + code: '24' + IN.23: + combinedCode: IN.23 + code: '23' + IN.22: + combinedCode: IN.22 + code: '22' + IN.21: + combinedCode: IN.21 + code: '21' + IN.20: + combinedCode: IN.20 + code: '20' + IN.31: + combinedCode: IN.31 + code: '31' + IN.18: + combinedCode: IN.18 + code: '18' + IN.17: + combinedCode: IN.17 + code: '17' + IN.16: + combinedCode: IN.16 + code: '16' + IN.35: + combinedCode: IN.35 + code: '35' + IN.14: + combinedCode: IN.14 + code: '14' + IN.13: + combinedCode: IN.13 + code: '13' + IN.19: + combinedCode: IN.19 + code: '19' + IN.12: + combinedCode: IN.12 + code: '12' + IN.11: + combinedCode: IN.11 + code: '11' + IN.10: + combinedCode: IN.10 + code: '10' + IN.09: + combinedCode: IN.09 + code: '09' + IN.32: + combinedCode: IN.32 + code: '32' + IN.33: + combinedCode: IN.33 + code: '33' + IN.07: + combinedCode: IN.07 + code: '07' + IN.06: + combinedCode: IN.06 + code: '06' + IN.05: + combinedCode: IN.05 + code: '05' + IN.34: + combinedCode: IN.34 + code: '34' + IN.03: + combinedCode: IN.03 + code: '03' + IN.30: + combinedCode: IN.30 + code: '30' + IN.02: + combinedCode: IN.02 + code: '02' + IN.01: + combinedCode: IN.01 + code: '01' + IN.37: + combinedCode: IN.37 + code: '37' + IN.38: + combinedCode: IN.38 + code: '38' + IN.39: + combinedCode: IN.39 + code: '39' +IO: + iso2Code: IO + iso3Code: IOT + regions: { } +IQ: + iso2Code: IQ + iso3Code: IRQ + regions: + IQ.02: + combinedCode: IQ.02 + code: '02' + IQ.16: + combinedCode: IQ.16 + code: '16' + IQ.18: + combinedCode: IQ.18 + code: '18' + IQ.15: + combinedCode: IQ.15 + code: '15' + IQ.14: + combinedCode: IQ.14 + code: '14' + IQ.12: + combinedCode: IQ.12 + code: '12' + IQ.11: + combinedCode: IQ.11 + code: '11' + IQ.10: + combinedCode: IQ.10 + code: '10' + IQ.09: + combinedCode: IQ.09 + code: '09' + IQ.08: + combinedCode: IQ.08 + code: '08' + IQ.07: + combinedCode: IQ.07 + code: '07' + IQ.06: + combinedCode: IQ.06 + code: '06' + IQ.13: + combinedCode: IQ.13 + code: '13' + IQ.05: + combinedCode: IQ.05 + code: '05' + IQ.17: + combinedCode: IQ.17 + code: '17' + IQ.04: + combinedCode: IQ.04 + code: '04' + IQ.03: + combinedCode: IQ.03 + code: '03' + IQ.01: + combinedCode: IQ.01 + code: '01' +IR: + iso2Code: IR + iso3Code: IRN + regions: + IR.26: + combinedCode: IR.26 + code: '26' + IR.36: + combinedCode: IR.36 + code: '36' + IR.40: + combinedCode: IR.40 + code: '40' + IR.25: + combinedCode: IR.25 + code: '25' + IR.35: + combinedCode: IR.35 + code: '35' + IR.34: + combinedCode: IR.34 + code: '34' + IR.23: + combinedCode: IR.23 + code: '23' + IR.16: + combinedCode: IR.16 + code: '16' + IR.05: + combinedCode: IR.05 + code: '05' + IR.15: + combinedCode: IR.15 + code: '15' + IR.13: + combinedCode: IR.13 + code: '13' + IR.29: + combinedCode: IR.29 + code: '29' + IR.10: + combinedCode: IR.10 + code: '10' + IR.11: + combinedCode: IR.11 + code: '11' + IR.09: + combinedCode: IR.09 + code: '09' + IR.08: + combinedCode: IR.08 + code: '08' + IR.07: + combinedCode: IR.07 + code: '07' + IR.03: + combinedCode: IR.03 + code: '03' + IR.22: + combinedCode: IR.22 + code: '22' + IR.33: + combinedCode: IR.33 + code: '33' + IR.01: + combinedCode: IR.01 + code: '01' + IR.32: + combinedCode: IR.32 + code: '32' + IR.28: + combinedCode: IR.28 + code: '28' + IR.37: + combinedCode: IR.37 + code: '37' + IR.38: + combinedCode: IR.38 + code: '38' + IR.39: + combinedCode: IR.39 + code: '39' + IR.04: + combinedCode: IR.04 + code: '04' + IR.41: + combinedCode: IR.41 + code: '41' + IR.42: + combinedCode: IR.42 + code: '42' + IR.43: + combinedCode: IR.43 + code: '43' + IR.44: + combinedCode: IR.44 + code: '44' +IS: + iso2Code: IS + iso3Code: ISL + regions: + IS.41: + combinedCode: IS.41 + code: '41' + IS.40: + combinedCode: IS.40 + code: '40' + IS.38: + combinedCode: IS.38 + code: '38' + IS.42: + combinedCode: IS.42 + code: '42' + IS.39: + combinedCode: IS.39 + code: '39' + IS.43: + combinedCode: IS.43 + code: '43' + IS.45: + combinedCode: IS.45 + code: '45' + IS.44: + combinedCode: IS.44 + code: '44' +IT: + iso2Code: IT + iso3Code: ITA + regions: + IT.15: + combinedCode: IT.15 + code: '15' + IT.14: + combinedCode: IT.14 + code: '14' + IT.03: + combinedCode: IT.03 + code: '03' + IT.20: + combinedCode: IT.20 + code: '20' + IT.19: + combinedCode: IT.19 + code: '19' + IT.18: + combinedCode: IT.18 + code: '18' + IT.17: + combinedCode: IT.17 + code: '17' + IT.16: + combinedCode: IT.16 + code: '16' + IT.13: + combinedCode: IT.13 + code: '13' + IT.12: + combinedCode: IT.12 + code: '12' + IT.11: + combinedCode: IT.11 + code: '11' + IT.10: + combinedCode: IT.10 + code: '10' + IT.09: + combinedCode: IT.09 + code: '09' + IT.08: + combinedCode: IT.08 + code: '08' + IT.07: + combinedCode: IT.07 + code: '07' + IT.06: + combinedCode: IT.06 + code: '06' + IT.05: + combinedCode: IT.05 + code: '05' + IT.04: + combinedCode: IT.04 + code: '04' + IT.02: + combinedCode: IT.02 + code: '02' + IT.01: + combinedCode: IT.01 + code: '01' +JE: + iso2Code: JE + iso3Code: JEY + regions: { } +JM: + iso2Code: JM + iso3Code: JAM + regions: + JM.16: + combinedCode: JM.16 + code: '16' + JM.15: + combinedCode: JM.15 + code: '15' + JM.14: + combinedCode: JM.14 + code: '14' + JM.13: + combinedCode: JM.13 + code: '13' + JM.12: + combinedCode: JM.12 + code: '12' + JM.11: + combinedCode: JM.11 + code: '11' + JM.10: + combinedCode: JM.10 + code: '10' + JM.09: + combinedCode: JM.09 + code: '09' + JM.08: + combinedCode: JM.08 + code: '08' + JM.07: + combinedCode: JM.07 + code: '07' + JM.04: + combinedCode: JM.04 + code: '04' + JM.17: + combinedCode: JM.17 + code: '17' + JM.02: + combinedCode: JM.02 + code: '02' + JM.01: + combinedCode: JM.01 + code: '01' +JO: + iso2Code: JO + iso3Code: JOR + regions: + JO.19: + combinedCode: JO.19 + code: '19' + JO.18: + combinedCode: JO.18 + code: '18' + JO.17: + combinedCode: JO.17 + code: '17' + JO.12: + combinedCode: JO.12 + code: '12' + JO.16: + combinedCode: JO.16 + code: '16' + JO.15: + combinedCode: JO.15 + code: '15' + JO.09: + combinedCode: JO.09 + code: '09' + JO.02: + combinedCode: JO.02 + code: '02' + JO.20: + combinedCode: JO.20 + code: '20' + JO.22: + combinedCode: JO.22 + code: '22' + JO.21: + combinedCode: JO.21 + code: '21' + JO.23: + combinedCode: JO.23 + code: '23' +JP: + iso2Code: JP + iso3Code: JPN + regions: + JP.46: + combinedCode: JP.46 + code: '46' + JP.45: + combinedCode: JP.45 + code: '45' + JP.43: + combinedCode: JP.43 + code: '43' + JP.42: + combinedCode: JP.42 + code: '42' + JP.41: + combinedCode: JP.41 + code: '41' + JP.40: + combinedCode: JP.40 + code: '40' + JP.39: + combinedCode: JP.39 + code: '39' + JP.38: + combinedCode: JP.38 + code: '38' + JP.37: + combinedCode: JP.37 + code: '37' + JP.36: + combinedCode: JP.36 + code: '36' + JP.35: + combinedCode: JP.35 + code: '35' + JP.34: + combinedCode: JP.34 + code: '34' + JP.33: + combinedCode: JP.33 + code: '33' + JP.32: + combinedCode: JP.32 + code: '32' + JP.47: + combinedCode: JP.47 + code: '47' + JP.31: + combinedCode: JP.31 + code: '31' + JP.30: + combinedCode: JP.30 + code: '30' + JP.29: + combinedCode: JP.29 + code: '29' + JP.28: + combinedCode: JP.28 + code: '28' + JP.27: + combinedCode: JP.27 + code: '27' + JP.26: + combinedCode: JP.26 + code: '26' + JP.25: + combinedCode: JP.25 + code: '25' + JP.23: + combinedCode: JP.23 + code: '23' + JP.22: + combinedCode: JP.22 + code: '22' + JP.21: + combinedCode: JP.21 + code: '21' + JP.20: + combinedCode: JP.20 + code: '20' + JP.19: + combinedCode: JP.19 + code: '19' + JP.18: + combinedCode: JP.18 + code: '18' + JP.17: + combinedCode: JP.17 + code: '17' + JP.15: + combinedCode: JP.15 + code: '15' + JP.13: + combinedCode: JP.13 + code: '13' + JP.11: + combinedCode: JP.11 + code: '11' + JP.10: + combinedCode: JP.10 + code: '10' + JP.09: + combinedCode: JP.09 + code: '09' + JP.07: + combinedCode: JP.07 + code: '07' + JP.06: + combinedCode: JP.06 + code: '06' + JP.05: + combinedCode: JP.05 + code: '05' + JP.01: + combinedCode: JP.01 + code: '01' + JP.44: + combinedCode: JP.44 + code: '44' + JP.24: + combinedCode: JP.24 + code: '24' + JP.16: + combinedCode: JP.16 + code: '16' + JP.14: + combinedCode: JP.14 + code: '14' + JP.08: + combinedCode: JP.08 + code: '08' + JP.04: + combinedCode: JP.04 + code: '04' + JP.02: + combinedCode: JP.02 + code: '02' + JP.12: + combinedCode: JP.12 + code: '12' + JP.03: + combinedCode: JP.03 + code: '03' +KE: + iso2Code: KE + iso3Code: KEN + regions: + KE.55: + combinedCode: KE.55 + code: '55' + KE.54: + combinedCode: KE.54 + code: '54' + KE.52: + combinedCode: KE.52 + code: '52' + KE.51: + combinedCode: KE.51 + code: '51' + KE.50: + combinedCode: KE.50 + code: '50' + KE.49: + combinedCode: KE.49 + code: '49' + KE.48: + combinedCode: KE.48 + code: '48' + KE.46: + combinedCode: KE.46 + code: '46' + KE.45: + combinedCode: KE.45 + code: '45' + KE.05: + combinedCode: KE.05 + code: '05' + KE.38: + combinedCode: KE.38 + code: '38' + KE.37: + combinedCode: KE.37 + code: '37' + KE.35: + combinedCode: KE.35 + code: '35' + KE.34: + combinedCode: KE.34 + code: '34' + KE.33: + combinedCode: KE.33 + code: '33' + KE.29: + combinedCode: KE.29 + code: '29' + KE.28: + combinedCode: KE.28 + code: '28' + KE.27: + combinedCode: KE.27 + code: '27' + KE.26: + combinedCode: KE.26 + code: '26' + KE.25: + combinedCode: KE.25 + code: '25' + KE.24: + combinedCode: KE.24 + code: '24' + KE.23: + combinedCode: KE.23 + code: '23' + KE.22: + combinedCode: KE.22 + code: '22' + KE.21: + combinedCode: KE.21 + code: '21' + KE.20: + combinedCode: KE.20 + code: '20' + KE.18: + combinedCode: KE.18 + code: '18' + KE.16: + combinedCode: KE.16 + code: '16' + KE.15: + combinedCode: KE.15 + code: '15' + KE.13: + combinedCode: KE.13 + code: '13' + KE.12: + combinedCode: KE.12 + code: '12' + KE.10: + combinedCode: KE.10 + code: '10' + KE.43: + combinedCode: KE.43 + code: '43' + KE.53: + combinedCode: KE.53 + code: '53' + KE.30: + combinedCode: KE.30 + code: '30' + KE.31: + combinedCode: KE.31 + code: '31' + KE.32: + combinedCode: KE.32 + code: '32' + KE.14: + combinedCode: KE.14 + code: '14' + KE.47: + combinedCode: KE.47 + code: '47' + KE.19: + combinedCode: KE.19 + code: '19' + KE.44: + combinedCode: KE.44 + code: '44' + KE.17: + combinedCode: KE.17 + code: '17' + KE.11: + combinedCode: KE.11 + code: '11' + KE.36: + combinedCode: KE.36 + code: '36' + KE.39: + combinedCode: KE.39 + code: '39' + KE.41: + combinedCode: KE.41 + code: '41' + KE.42: + combinedCode: KE.42 + code: '42' + KE.40: + combinedCode: KE.40 + code: '40' +KG: + iso2Code: KG + iso3Code: KGZ + regions: + KG.08: + combinedCode: KG.08 + code: '08' + KG.09: + combinedCode: KG.09 + code: '09' + KG.06: + combinedCode: KG.06 + code: '06' + KG.04: + combinedCode: KG.04 + code: '04' + KG.07: + combinedCode: KG.07 + code: '07' + KG.01: + combinedCode: KG.01 + code: '01' + KG.03: + combinedCode: KG.03 + code: '03' + KG.02: + combinedCode: KG.02 + code: '02' +KH: + iso2Code: KH + iso3Code: KHM + regions: + KH.12: + combinedCode: KH.12 + code: '12' + KH.29: + combinedCode: KH.29 + code: '29' + KH.19: + combinedCode: KH.19 + code: '19' + KH.18: + combinedCode: KH.18 + code: '18' + KH.17: + combinedCode: KH.17 + code: '17' + KH.27: + combinedCode: KH.27 + code: '27' + KH.24: + combinedCode: KH.24 + code: '24' + KH.23: + combinedCode: KH.23 + code: '23' + KH.14: + combinedCode: KH.14 + code: '14' + KH.13: + combinedCode: KH.13 + code: '13' + KH.22: + combinedCode: KH.22 + code: '22' + KH.30: + combinedCode: KH.30 + code: '30' + KH.10: + combinedCode: KH.10 + code: '10' + KH.09: + combinedCode: KH.09 + code: '09' + KH.26: + combinedCode: KH.26 + code: '26' + KH.08: + combinedCode: KH.08 + code: '08' + KH.07: + combinedCode: KH.07 + code: '07' + KH.21: + combinedCode: KH.21 + code: '21' + KH.05: + combinedCode: KH.05 + code: '05' + KH.04: + combinedCode: KH.04 + code: '04' + KH.03: + combinedCode: KH.03 + code: '03' + KH.02: + combinedCode: KH.02 + code: '02' + KH.28: + combinedCode: KH.28 + code: '28' + KH.25: + combinedCode: KH.25 + code: '25' +KI: + iso2Code: KI + iso3Code: KIR + regions: + KI.01: + combinedCode: KI.01 + code: '01' + KI.02: + combinedCode: KI.02 + code: '02' + KI.03: + combinedCode: KI.03 + code: '03' +KM: + iso2Code: KM + iso3Code: COM + regions: + KM.03: + combinedCode: KM.03 + code: '03' + KM.02: + combinedCode: KM.02 + code: '02' + KM.01: + combinedCode: KM.01 + code: '01' +KN: + iso2Code: KN + iso3Code: KNA + regions: + KN.15: + combinedCode: KN.15 + code: '15' + KN.13: + combinedCode: KN.13 + code: '13' + KN.12: + combinedCode: KN.12 + code: '12' + KN.11: + combinedCode: KN.11 + code: '11' + KN.10: + combinedCode: KN.10 + code: '10' + KN.09: + combinedCode: KN.09 + code: '09' + KN.08: + combinedCode: KN.08 + code: '08' + KN.07: + combinedCode: KN.07 + code: '07' + KN.06: + combinedCode: KN.06 + code: '06' + KN.05: + combinedCode: KN.05 + code: '05' + KN.04: + combinedCode: KN.04 + code: '04' + KN.03: + combinedCode: KN.03 + code: '03' + KN.02: + combinedCode: KN.02 + code: '02' + KN.01: + combinedCode: KN.01 + code: '01' +KP: + iso2Code: KP + iso3Code: PRK + regions: + KP.12: + combinedCode: KP.12 + code: '12' + KP.15: + combinedCode: KP.15 + code: '15' + KP.11: + combinedCode: KP.11 + code: '11' + KP.09: + combinedCode: KP.09 + code: '09' + KP.06: + combinedCode: KP.06 + code: '06' + KP.07: + combinedCode: KP.07 + code: '07' + KP.03: + combinedCode: KP.03 + code: '03' + KP.13: + combinedCode: KP.13 + code: '13' + KP.17: + combinedCode: KP.17 + code: '17' + KP.01: + combinedCode: KP.01 + code: '01' + KP.18: + combinedCode: KP.18 + code: '18' +KR: + iso2Code: KR + iso3Code: KOR + regions: + KR.21: + combinedCode: KR.21 + code: '21' + KR.19: + combinedCode: KR.19 + code: '19' + KR.15: + combinedCode: KR.15 + code: '15' + KR.11: + combinedCode: KR.11 + code: '11' + KR.10: + combinedCode: KR.10 + code: '10' + KR.14: + combinedCode: KR.14 + code: '14' + KR.13: + combinedCode: KR.13 + code: '13' + KR.18: + combinedCode: KR.18 + code: '18' + KR.06: + combinedCode: KR.06 + code: '06' + KR.12: + combinedCode: KR.12 + code: '12' + KR.17: + combinedCode: KR.17 + code: '17' + KR.05: + combinedCode: KR.05 + code: '05' + KR.16: + combinedCode: KR.16 + code: '16' + KR.03: + combinedCode: KR.03 + code: '03' + KR.01: + combinedCode: KR.01 + code: '01' + KR.20: + combinedCode: KR.20 + code: '20' + KR.22: + combinedCode: KR.22 + code: '22' +XK: + iso2Code: XK + iso3Code: XKX + regions: + XK.28: + combinedCode: XK.28 + code: '28' + XK.27: + combinedCode: XK.27 + code: '27' + XK.03: + combinedCode: XK.03 + code: '03' + XK.15: + combinedCode: XK.15 + code: '15' + XK.26: + combinedCode: XK.26 + code: '26' + XK.25: + combinedCode: XK.25 + code: '25' + XK.21: + combinedCode: XK.21 + code: '21' + XK.20: + combinedCode: XK.20 + code: '20' + XK.19: + combinedCode: XK.19 + code: '19' + XK.18: + combinedCode: XK.18 + code: '18' + XK.22: + combinedCode: XK.22 + code: '22' + XK.13: + combinedCode: XK.13 + code: '13' + XK.12: + combinedCode: XK.12 + code: '12' + XK.10: + combinedCode: XK.10 + code: '10' + XK.11: + combinedCode: XK.11 + code: '11' + XK.09: + combinedCode: XK.09 + code: '09' + XK.08: + combinedCode: XK.08 + code: '08' + XK.06: + combinedCode: XK.06 + code: '06' + XK.07: + combinedCode: XK.07 + code: '07' + XK.02: + combinedCode: XK.02 + code: '02' + XK.01: + combinedCode: XK.01 + code: '01' + XK.05: + combinedCode: XK.05 + code: '05' + XK.04: + combinedCode: XK.04 + code: '04' + XK.23: + combinedCode: XK.23 + code: '23' + XK.24: + combinedCode: XK.24 + code: '24' + XK.16: + combinedCode: XK.16 + code: '16' + XK.17: + combinedCode: XK.17 + code: '17' + XK.14: + combinedCode: XK.14 + code: '14' + XK.29: + combinedCode: XK.29 + code: '29' + XK.30: + combinedCode: XK.30 + code: '30' + XK.31: + combinedCode: XK.31 + code: '31' + XK.32: + combinedCode: XK.32 + code: '32' + XK.33: + combinedCode: XK.33 + code: '33' + XK.34: + combinedCode: XK.34 + code: '34' + XK.35: + combinedCode: XK.35 + code: '35' + XK.36: + combinedCode: XK.36 + code: '36' + XK.37: + combinedCode: XK.37 + code: '37' +KW: + iso2Code: KW + iso3Code: KWT + regions: + KW.08: + combinedCode: KW.08 + code: '08' + KW.02: + combinedCode: KW.02 + code: '02' + KW.05: + combinedCode: KW.05 + code: '05' + KW.07: + combinedCode: KW.07 + code: '07' + KW.04: + combinedCode: KW.04 + code: '04' + KW.09: + combinedCode: KW.09 + code: '09' +KY: + iso2Code: KY + iso3Code: CYM + regions: { } +KZ: + iso2Code: KZ + iso3Code: KAZ + regions: + KZ.07: + combinedCode: KZ.07 + code: '07' + KZ.09: + combinedCode: KZ.09 + code: '09' + KZ.06: + combinedCode: KZ.06 + code: '06' + KZ.04: + combinedCode: KZ.04 + code: '04' + KZ.15: + combinedCode: KZ.15 + code: '15' + KZ.03: + combinedCode: KZ.03 + code: '03' + KZ.16: + combinedCode: KZ.16 + code: '16' + KZ.11: + combinedCode: KZ.11 + code: '11' + KZ.14: + combinedCode: KZ.14 + code: '14' + KZ.13: + combinedCode: KZ.13 + code: '13' + KZ.12: + combinedCode: KZ.12 + code: '12' + KZ.17: + combinedCode: KZ.17 + code: '17' + KZ.10: + combinedCode: KZ.10 + code: '10' + KZ.02: + combinedCode: KZ.02 + code: '02' + KZ.01: + combinedCode: KZ.01 + code: '01' + KZ.08: + combinedCode: KZ.08 + code: '08' + KZ.05: + combinedCode: KZ.05 + code: '05' +LA: + iso2Code: LA + iso3Code: LAO + regions: + LA.14: + combinedCode: LA.14 + code: '14' + LA.13: + combinedCode: LA.13 + code: '13' + LA.27: + combinedCode: LA.27 + code: '27' + LA.20: + combinedCode: LA.20 + code: '20' + LA.19: + combinedCode: LA.19 + code: '19' + LA.18: + combinedCode: LA.18 + code: '18' + LA.07: + combinedCode: LA.07 + code: '07' + LA.17: + combinedCode: LA.17 + code: '17' + LA.16: + combinedCode: LA.16 + code: '16' + LA.15: + combinedCode: LA.15 + code: '15' + LA.03: + combinedCode: LA.03 + code: '03' + LA.02: + combinedCode: LA.02 + code: '02' + LA.01: + combinedCode: LA.01 + code: '01' + LA.26: + combinedCode: LA.26 + code: '26' + LA.22: + combinedCode: LA.22 + code: '22' + LA.23: + combinedCode: LA.23 + code: '23' + LA.24: + combinedCode: LA.24 + code: '24' +LB: + iso2Code: LB + iso3Code: LBN + regions: + LB.05: + combinedCode: LB.05 + code: '05' + LB.04: + combinedCode: LB.04 + code: '04' + LB.09: + combinedCode: LB.09 + code: '09' + LB.06: + combinedCode: LB.06 + code: '06' + LB.08: + combinedCode: LB.08 + code: '08' + LB.07: + combinedCode: LB.07 + code: '07' + LB.10: + combinedCode: LB.10 + code: '10' + LB.11: + combinedCode: LB.11 + code: '11' +LC: + iso2Code: LC + iso3Code: LCA + regions: + LC.10: + combinedCode: LC.10 + code: '10' + LC.09: + combinedCode: LC.09 + code: '09' + LC.11: + combinedCode: LC.11 + code: '11' + LC.08: + combinedCode: LC.08 + code: '08' + LC.07: + combinedCode: LC.07 + code: '07' + LC.06: + combinedCode: LC.06 + code: '06' + LC.05: + combinedCode: LC.05 + code: '05' + LC.02: + combinedCode: LC.02 + code: '02' + LC.04: + combinedCode: LC.04 + code: '04' + LC.03: + combinedCode: LC.03 + code: '03' + LC.01: + combinedCode: LC.01 + code: '01' +LI: + iso2Code: LI + iso3Code: LIE + regions: + LI.11: + combinedCode: LI.11 + code: '11' + LI.10: + combinedCode: LI.10 + code: '10' + LI.09: + combinedCode: LI.09 + code: '09' + LI.08: + combinedCode: LI.08 + code: '08' + LI.07: + combinedCode: LI.07 + code: '07' + LI.06: + combinedCode: LI.06 + code: '06' + LI.05: + combinedCode: LI.05 + code: '05' + LI.04: + combinedCode: LI.04 + code: '04' + LI.03: + combinedCode: LI.03 + code: '03' + LI.02: + combinedCode: LI.02 + code: '02' + LI.01: + combinedCode: LI.01 + code: '01' +LK: + iso2Code: LK + iso3Code: LKA + regions: + LK.36: + combinedCode: LK.36 + code: '36' + LK.35: + combinedCode: LK.35 + code: '35' + LK.34: + combinedCode: LK.34 + code: '34' + LK.33: + combinedCode: LK.33 + code: '33' + LK.32: + combinedCode: LK.32 + code: '32' + LK.30: + combinedCode: LK.30 + code: '30' + LK.29: + combinedCode: LK.29 + code: '29' + LK.38: + combinedCode: LK.38 + code: '38' + LK.37: + combinedCode: LK.37 + code: '37' +LR: + iso2Code: LR + iso3Code: LBR + regions: + LR.10: + combinedCode: LR.10 + code: '10' + LR.09: + combinedCode: LR.09 + code: '09' + LR.14: + combinedCode: LR.14 + code: '14' + LR.13: + combinedCode: LR.13 + code: '13' + LR.20: + combinedCode: LR.20 + code: '20' + LR.19: + combinedCode: LR.19 + code: '19' + LR.12: + combinedCode: LR.12 + code: '12' + LR.11: + combinedCode: LR.11 + code: '11' + LR.01: + combinedCode: LR.01 + code: '01' + LR.15: + combinedCode: LR.15 + code: '15' + LR.16: + combinedCode: LR.16 + code: '16' + LR.17: + combinedCode: LR.17 + code: '17' + LR.18: + combinedCode: LR.18 + code: '18' + LR.21: + combinedCode: LR.21 + code: '21' + LR.22: + combinedCode: LR.22 + code: '22' +LS: + iso2Code: LS + iso3Code: LSO + regions: + LS.19: + combinedCode: LS.19 + code: '19' + LS.18: + combinedCode: LS.18 + code: '18' + LS.17: + combinedCode: LS.17 + code: '17' + LS.16: + combinedCode: LS.16 + code: '16' + LS.15: + combinedCode: LS.15 + code: '15' + LS.14: + combinedCode: LS.14 + code: '14' + LS.13: + combinedCode: LS.13 + code: '13' + LS.12: + combinedCode: LS.12 + code: '12' + LS.11: + combinedCode: LS.11 + code: '11' + LS.10: + combinedCode: LS.10 + code: '10' +LT: + iso2Code: LT + iso3Code: LTU + regions: + LT.56: + combinedCode: LT.56 + code: '56' + LT.57: + combinedCode: LT.57 + code: '57' + LT.58: + combinedCode: LT.58 + code: '58' + LT.59: + combinedCode: LT.59 + code: '59' + LT.60: + combinedCode: LT.60 + code: '60' + LT.61: + combinedCode: LT.61 + code: '61' + LT.62: + combinedCode: LT.62 + code: '62' + LT.63: + combinedCode: LT.63 + code: '63' + LT.64: + combinedCode: LT.64 + code: '64' + LT.65: + combinedCode: LT.65 + code: '65' +LU: + iso2Code: LU + iso3Code: LUX + regions: + LU.03: + combinedCode: LU.03 + code: '03' + LU.02: + combinedCode: LU.02 + code: '02' + LU.01: + combinedCode: LU.01 + code: '01' +LV: + iso2Code: LV + iso3Code: LVA + regions: + LV.33: + combinedCode: LV.33 + code: '33' + LV.32: + combinedCode: LV.32 + code: '32' + LV.31: + combinedCode: LV.31 + code: '31' + LV.30: + combinedCode: LV.30 + code: '30' + LV.29: + combinedCode: LV.29 + code: '29' + LV.28: + combinedCode: LV.28 + code: '28' + LV.27: + combinedCode: LV.27 + code: '27' + LV.25: + combinedCode: LV.25 + code: '25' + LV.24: + combinedCode: LV.24 + code: '24' + LV.23: + combinedCode: LV.23 + code: '23' + LV.22: + combinedCode: LV.22 + code: '22' + LV.21: + combinedCode: LV.21 + code: '21' + LV.20: + combinedCode: LV.20 + code: '20' + LV.19: + combinedCode: LV.19 + code: '19' + LV.18: + combinedCode: LV.18 + code: '18' + LV.16: + combinedCode: LV.16 + code: '16' + LV.15: + combinedCode: LV.15 + code: '15' + LV.14: + combinedCode: LV.14 + code: '14' + LV.13: + combinedCode: LV.13 + code: '13' + LV.12: + combinedCode: LV.12 + code: '12' + LV.11: + combinedCode: LV.11 + code: '11' + LV.10: + combinedCode: LV.10 + code: '10' + LV.09: + combinedCode: LV.09 + code: '09' + LV.08: + combinedCode: LV.08 + code: '08' + LV.07: + combinedCode: LV.07 + code: '07' + LV.06: + combinedCode: LV.06 + code: '06' + LV.05: + combinedCode: LV.05 + code: '05' + LV.04: + combinedCode: LV.04 + code: '04' + LV.03: + combinedCode: LV.03 + code: '03' + LV.02: + combinedCode: LV.02 + code: '02' + LV.01: + combinedCode: LV.01 + code: '01' + LV.60: + combinedCode: LV.60 + code: '60' + LV.40: + combinedCode: LV.40 + code: '40' + LV.A5: + combinedCode: LV.A5 + code: A5 + LV.99: + combinedCode: LV.99 + code: '99' + LV.B6: + combinedCode: LV.B6 + code: B6 + LV.65: + combinedCode: LV.65 + code: '65' + LV.61: + combinedCode: LV.61 + code: '61' + LV.37: + combinedCode: LV.37 + code: '37' + LV.A8: + combinedCode: LV.A8 + code: A8 + LV.D7: + combinedCode: LV.D7 + code: D7 + LV.C9: + combinedCode: LV.C9 + code: C9 + LV.51: + combinedCode: LV.51 + code: '51' + LV.B4: + combinedCode: LV.B4 + code: B4 + LV.77: + combinedCode: LV.77 + code: '77' + LV.44: + combinedCode: LV.44 + code: '44' + LV.73: + combinedCode: LV.73 + code: '73' + LV.62: + combinedCode: LV.62 + code: '62' + LV.D5: + combinedCode: LV.D5 + code: D5 + LV.A3: + combinedCode: LV.A3 + code: A3 + LV.B9: + combinedCode: LV.B9 + code: B9 + LV.45: + combinedCode: LV.45 + code: '45' + LV.95: + combinedCode: LV.95 + code: '95' + LV.A2: + combinedCode: LV.A2 + code: A2 + LV.67: + combinedCode: LV.67 + code: '67' + LV.80: + combinedCode: LV.80 + code: '80' + LV.C3: + combinedCode: LV.C3 + code: C3 + LV.46: + combinedCode: LV.46 + code: '46' + LV.D2: + combinedCode: LV.D2 + code: D2 + LV.53: + combinedCode: LV.53 + code: '53' + LV.34: + combinedCode: LV.34 + code: '34' + LV.64: + combinedCode: LV.64 + code: '64' + LV.E4: + combinedCode: LV.E4 + code: E4 + LV.79: + combinedCode: LV.79 + code: '79' + LV.87: + combinedCode: LV.87 + code: '87' + LV.C8: + combinedCode: LV.C8 + code: C8 + LV.71: + combinedCode: LV.71 + code: '71' + LV.98: + combinedCode: LV.98 + code: '98' + LV.E6: + combinedCode: LV.E6 + code: E6 + LV.C2: + combinedCode: LV.C2 + code: C2 + LV.74: + combinedCode: LV.74 + code: '74' + LV.38: + combinedCode: LV.38 + code: '38' + LV.69: + combinedCode: LV.69 + code: '69' + LV.E2: + combinedCode: LV.E2 + code: E2 + LV.90: + combinedCode: LV.90 + code: '90' + LV.E1: + combinedCode: LV.E1 + code: E1 + LV.E8: + combinedCode: LV.E8 + code: E8 + LV.B3: + combinedCode: LV.B3 + code: B3 + LV.35: + combinedCode: LV.35 + code: '35' + LV.56: + combinedCode: LV.56 + code: '56' + LV.E9: + combinedCode: LV.E9 + code: E9 + LV.E7: + combinedCode: LV.E7 + code: E7 + LV.47: + combinedCode: LV.47 + code: '47' + LV.57: + combinedCode: LV.57 + code: '57' + LV.78: + combinedCode: LV.78 + code: '78' + LV.B7: + combinedCode: LV.B7 + code: B7 + LV.55: + combinedCode: LV.55 + code: '55' + LV.91: + combinedCode: LV.91 + code: '91' + LV.85: + combinedCode: LV.85 + code: '85' + LV.A6: + combinedCode: LV.A6 + code: A6 + LV.82: + combinedCode: LV.82 + code: '82' + LV.68: + combinedCode: LV.68 + code: '68' + LV.B5: + combinedCode: LV.B5 + code: B5 + LV.70: + combinedCode: LV.70 + code: '70' + LV.84: + combinedCode: LV.84 + code: '84' + LV.C7: + combinedCode: LV.C7 + code: C7 + LV.88: + combinedCode: LV.88 + code: '88' + LV.94: + combinedCode: LV.94 + code: '94' + LV.C6: + combinedCode: LV.C6 + code: C6 + LV.C5: + combinedCode: LV.C5 + code: C5 + LV.C1: + combinedCode: LV.C1 + code: C1 + LV.39: + combinedCode: LV.39 + code: '39' + LV.97: + combinedCode: LV.97 + code: '97' + LV.B8: + combinedCode: LV.B8 + code: B8 + LV.96: + combinedCode: LV.96 + code: '96' + LV.52: + combinedCode: LV.52 + code: '52' + LV.A4: + combinedCode: LV.A4 + code: A4 + LV.81: + combinedCode: LV.81 + code: '81' + LV.42: + combinedCode: LV.42 + code: '42' + LV.A9: + combinedCode: LV.A9 + code: A9 + LV.B1: + combinedCode: LV.B1 + code: B1 + LV.D3: + combinedCode: LV.D3 + code: D3 + LV.50: + combinedCode: LV.50 + code: '50' + LV.D1: + combinedCode: LV.D1 + code: D1 + LV.72: + combinedCode: LV.72 + code: '72' + LV.63: + combinedCode: LV.63 + code: '63' + LV.E3: + combinedCode: LV.E3 + code: E3 + LV.43: + combinedCode: LV.43 + code: '43' + LV.F1: + combinedCode: LV.F1 + code: F1 +LY: + iso2Code: LY + iso3Code: LBY + regions: + LY.70: + combinedCode: LY.70 + code: '70' + LY.69: + combinedCode: LY.69 + code: '69' + LY.66: + combinedCode: LY.66 + code: '66' + LY.65: + combinedCode: LY.65 + code: '65' + LY.63: + combinedCode: LY.63 + code: '63' + LY.77: + combinedCode: LY.77 + code: '77' + LY.76: + combinedCode: LY.76 + code: '76' + LY.75: + combinedCode: LY.75 + code: '75' + LY.74: + combinedCode: LY.74 + code: '74' + LY.73: + combinedCode: LY.73 + code: '73' + LY.72: + combinedCode: LY.72 + code: '72' + LY.71: + combinedCode: LY.71 + code: '71' + LY.68: + combinedCode: LY.68 + code: '68' + LY.78: + combinedCode: LY.78 + code: '78' + LY.64: + combinedCode: LY.64 + code: '64' + LY.67: + combinedCode: LY.67 + code: '67' + LY.79: + combinedCode: LY.79 + code: '79' + LY.80: + combinedCode: LY.80 + code: '80' + LY.81: + combinedCode: LY.81 + code: '81' + LY.82: + combinedCode: LY.82 + code: '82' + LY.83: + combinedCode: LY.83 + code: '83' + LY.84: + combinedCode: LY.84 + code: '84' +MA: + iso2Code: MA + iso3Code: MAR + regions: + MA.49: + combinedCode: MA.49 + code: '49' + MA.48: + combinedCode: MA.48 + code: '48' + MA.47: + combinedCode: MA.47 + code: '47' + MA.46: + combinedCode: MA.46 + code: '46' + MA.45: + combinedCode: MA.45 + code: '45' + MA.50: + combinedCode: MA.50 + code: '50' + MA.51: + combinedCode: MA.51 + code: '51' + MA.52: + combinedCode: MA.52 + code: '52' + MA.53: + combinedCode: MA.53 + code: '53' + MA.54: + combinedCode: MA.54 + code: '54' + MA.55: + combinedCode: MA.55 + code: '55' + MA.56: + combinedCode: MA.56 + code: '56' + MA.57: + combinedCode: MA.57 + code: '57' + MA.58: + combinedCode: MA.58 + code: '58' + MA.59: + combinedCode: MA.59 + code: '59' + MA.EH: + combinedCode: MA.EH + code: EH +MC: + iso2Code: MC + iso3Code: MCO + regions: + MC.00: + combinedCode: MC.00 + code: '00' +MD: + iso2Code: MD + iso3Code: MDA + regions: + MD.73: + combinedCode: MD.73 + code: '73' + MD.92: + combinedCode: MD.92 + code: '92' + MD.91: + combinedCode: MD.91 + code: '91' + MD.90: + combinedCode: MD.90 + code: '90' + MD.88: + combinedCode: MD.88 + code: '88' + MD.89: + combinedCode: MD.89 + code: '89' + MD.87: + combinedCode: MD.87 + code: '87' + MD.84: + combinedCode: MD.84 + code: '84' + MD.83: + combinedCode: MD.83 + code: '83' + MD.82: + combinedCode: MD.82 + code: '82' + MD.81: + combinedCode: MD.81 + code: '81' + MD.59: + combinedCode: MD.59 + code: '59' + MD.80: + combinedCode: MD.80 + code: '80' + MD.79: + combinedCode: MD.79 + code: '79' + MD.85: + combinedCode: MD.85 + code: '85' + MD.69: + combinedCode: MD.69 + code: '69' + MD.78: + combinedCode: MD.78 + code: '78' + MD.57: + combinedCode: MD.57 + code: '57' + MD.67: + combinedCode: MD.67 + code: '67' + MD.65: + combinedCode: MD.65 + code: '65' + MD.66: + combinedCode: MD.66 + code: '66' + MD.64: + combinedCode: MD.64 + code: '64' + MD.76: + combinedCode: MD.76 + code: '76' + MD.75: + combinedCode: MD.75 + code: '75' + MD.74: + combinedCode: MD.74 + code: '74' + MD.72: + combinedCode: MD.72 + code: '72' + MD.71: + combinedCode: MD.71 + code: '71' + MD.70: + combinedCode: MD.70 + code: '70' + MD.68: + combinedCode: MD.68 + code: '68' + MD.63: + combinedCode: MD.63 + code: '63' + MD.61: + combinedCode: MD.61 + code: '61' + MD.77: + combinedCode: MD.77 + code: '77' + MD.86: + combinedCode: MD.86 + code: '86' + MD.58: + combinedCode: MD.58 + code: '58' + MD.51: + combinedCode: MD.51 + code: '51' + MD.62: + combinedCode: MD.62 + code: '62' + MD.60: + combinedCode: MD.60 + code: '60' +ME: + iso2Code: ME + iso3Code: MNE + regions: + ME.17: + combinedCode: ME.17 + code: '17' + ME.21: + combinedCode: ME.21 + code: '21' + ME.20: + combinedCode: ME.20 + code: '20' + ME.19: + combinedCode: ME.19 + code: '19' + ME.16: + combinedCode: ME.16 + code: '16' + ME.18: + combinedCode: ME.18 + code: '18' + ME.15: + combinedCode: ME.15 + code: '15' + ME.14: + combinedCode: ME.14 + code: '14' + ME.13: + combinedCode: ME.13 + code: '13' + ME.12: + combinedCode: ME.12 + code: '12' + ME.11: + combinedCode: ME.11 + code: '11' + ME.10: + combinedCode: ME.10 + code: '10' + ME.09: + combinedCode: ME.09 + code: '09' + ME.03: + combinedCode: ME.03 + code: '03' + ME.08: + combinedCode: ME.08 + code: '08' + ME.07: + combinedCode: ME.07 + code: '07' + ME.06: + combinedCode: ME.06 + code: '06' + ME.05: + combinedCode: ME.05 + code: '05' + ME.04: + combinedCode: ME.04 + code: '04' + ME.02: + combinedCode: ME.02 + code: '02' + ME.01: + combinedCode: ME.01 + code: '01' +MF: + iso2Code: MF + iso3Code: MAF + regions: { } +MG: + iso2Code: MG + iso3Code: MDG + regions: + MG.7670842: + combinedCode: MG.7670842 + code: '7670842' + MG.7670846: + combinedCode: MG.7670846 + code: '7670846' + MG.7670847: + combinedCode: MG.7670847 + code: '7670847' + MG.7670848: + combinedCode: MG.7670848 + code: '7670848' + MG.7670849: + combinedCode: MG.7670849 + code: '7670849' + MG.7670850: + combinedCode: MG.7670850 + code: '7670850' + MG.7670851: + combinedCode: MG.7670851 + code: '7670851' + MG.7670852: + combinedCode: MG.7670852 + code: '7670852' + MG.7670853: + combinedCode: MG.7670853 + code: '7670853' + MG.7670854: + combinedCode: MG.7670854 + code: '7670854' + MG.7670855: + combinedCode: MG.7670855 + code: '7670855' + MG.7670856: + combinedCode: MG.7670856 + code: '7670856' + MG.7670857: + combinedCode: MG.7670857 + code: '7670857' + MG.7670902: + combinedCode: MG.7670902 + code: '7670902' + MG.7670904: + combinedCode: MG.7670904 + code: '7670904' + MG.7670905: + combinedCode: MG.7670905 + code: '7670905' + MG.7670906: + combinedCode: MG.7670906 + code: '7670906' + MG.7670907: + combinedCode: MG.7670907 + code: '7670907' + MG.7670908: + combinedCode: MG.7670908 + code: '7670908' + MG.7670910: + combinedCode: MG.7670910 + code: '7670910' + MG.7670911: + combinedCode: MG.7670911 + code: '7670911' + MG.7670913: + combinedCode: MG.7670913 + code: '7670913' +MH: + iso2Code: MH + iso3Code: MHL + regions: + MH.007: + combinedCode: MH.007 + code: '007' + MH.010: + combinedCode: MH.010 + code: '010' + MH.030: + combinedCode: MH.030 + code: '030' + MH.040: + combinedCode: MH.040 + code: '040' + MH.050: + combinedCode: MH.050 + code: '050' + MH.060: + combinedCode: MH.060 + code: '060' + MH.070: + combinedCode: MH.070 + code: '070' + MH.080: + combinedCode: MH.080 + code: '080' + MH.090: + combinedCode: MH.090 + code: '090' + MH.100: + combinedCode: MH.100 + code: '100' + MH.120: + combinedCode: MH.120 + code: '120' + MH.150: + combinedCode: MH.150 + code: '150' + MH.160: + combinedCode: MH.160 + code: '160' + MH.180: + combinedCode: MH.180 + code: '180' + MH.190: + combinedCode: MH.190 + code: '190' + MH.300: + combinedCode: MH.300 + code: '300' + MH.320: + combinedCode: MH.320 + code: '320' + MH.330: + combinedCode: MH.330 + code: '330' + MH.340: + combinedCode: MH.340 + code: '340' + MH.350: + combinedCode: MH.350 + code: '350' + MH.360: + combinedCode: MH.360 + code: '360' + MH.385: + combinedCode: MH.385 + code: '385' + MH.073: + combinedCode: MH.073 + code: '073' + MH.390: + combinedCode: MH.390 + code: '390' + MH.400: + combinedCode: MH.400 + code: '400' + MH.410: + combinedCode: MH.410 + code: '410' + MH.420: + combinedCode: MH.420 + code: '420' + MH.430: + combinedCode: MH.430 + code: '430' + MH.110: + combinedCode: MH.110 + code: '110' + MH.130: + combinedCode: MH.130 + code: '130' + MH.140: + combinedCode: MH.140 + code: '140' + MH.170: + combinedCode: MH.170 + code: '170' + MH.310: + combinedCode: MH.310 + code: '310' +MK: + iso2Code: MK + iso3Code: MKD + regions: + MK.E9: + combinedCode: MK.E9 + code: E9 + MK.86: + combinedCode: MK.86 + code: '86' + MK.51: + combinedCode: MK.51 + code: '51' + MK.78: + combinedCode: MK.78 + code: '78' + MK.72: + combinedCode: MK.72 + code: '72' + MK.11: + combinedCode: MK.11 + code: '11' + MK.A9: + combinedCode: MK.A9 + code: A9 + MK.E5: + combinedCode: MK.E5 + code: E5 + MK.08: + combinedCode: MK.08 + code: '08' + MK.47: + combinedCode: MK.47 + code: '47' + MK.62: + combinedCode: MK.62 + code: '62' + MK.C6: + combinedCode: MK.C6 + code: C6 + MK.40: + combinedCode: MK.40 + code: '40' + MK.25: + combinedCode: MK.25 + code: '25' + MK.87: + combinedCode: MK.87 + code: '87' + MK.35: + combinedCode: MK.35 + code: '35' + MK.60: + combinedCode: MK.60 + code: '60' + MK.19: + combinedCode: MK.19 + code: '19' + MK.E1: + combinedCode: MK.E1 + code: E1 + MK.04: + combinedCode: MK.04 + code: '04' + MK.06: + combinedCode: MK.06 + code: '06' + MK.D9: + combinedCode: MK.D9 + code: D9 + MK.01: + combinedCode: MK.01 + code: '01' + MK.C7: + combinedCode: MK.C7 + code: C7 + MK.12: + combinedCode: MK.12 + code: '12' + MK.C8: + combinedCode: MK.C8 + code: C8 + MK.C9: + combinedCode: MK.C9 + code: C9 + MK.D1: + combinedCode: MK.D1 + code: D1 + MK.18: + combinedCode: MK.18 + code: '18' + MK.20: + combinedCode: MK.20 + code: '20' + MK.D2: + combinedCode: MK.D2 + code: D2 + MK.22: + combinedCode: MK.22 + code: '22' + MK.D3: + combinedCode: MK.D3 + code: D3 + MK.28: + combinedCode: MK.28 + code: '28' + MK.29: + combinedCode: MK.29 + code: '29' + MK.30: + combinedCode: MK.30 + code: '30' + MK.32: + combinedCode: MK.32 + code: '32' + MK.33: + combinedCode: MK.33 + code: '33' + MK.D4: + combinedCode: MK.D4 + code: D4 + MK.36: + combinedCode: MK.36 + code: '36' + MK.D5: + combinedCode: MK.D5 + code: D5 + MK.41: + combinedCode: MK.41 + code: '41' + MK.D6: + combinedCode: MK.D6 + code: D6 + MK.43: + combinedCode: MK.43 + code: '43' + MK.44: + combinedCode: MK.44 + code: '44' + MK.46: + combinedCode: MK.46 + code: '46' + MK.52: + combinedCode: MK.52 + code: '52' + MK.53: + combinedCode: MK.53 + code: '53' + MK.54: + combinedCode: MK.54 + code: '54' + MK.D7: + combinedCode: MK.D7 + code: D7 + MK.59: + combinedCode: MK.59 + code: '59' + MK.D8: + combinedCode: MK.D8 + code: D8 + MK.69: + combinedCode: MK.69 + code: '69' + MK.E2: + combinedCode: MK.E2 + code: E2 + MK.77: + combinedCode: MK.77 + code: '77' + MK.79: + combinedCode: MK.79 + code: '79' + MK.80: + combinedCode: MK.80 + code: '80' + MK.E3: + combinedCode: MK.E3 + code: E3 + MK.83: + combinedCode: MK.83 + code: '83' + MK.84: + combinedCode: MK.84 + code: '84' + MK.85: + combinedCode: MK.85 + code: '85' + MK.E4: + combinedCode: MK.E4 + code: E4 + MK.90: + combinedCode: MK.90 + code: '90' + MK.92: + combinedCode: MK.92 + code: '92' + MK.97: + combinedCode: MK.97 + code: '97' + MK.98: + combinedCode: MK.98 + code: '98' + MK.E6: + combinedCode: MK.E6 + code: E6 + MK.E7: + combinedCode: MK.E7 + code: E7 + MK.A2: + combinedCode: MK.A2 + code: A2 + MK.A3: + combinedCode: MK.A3 + code: A3 + MK.A4: + combinedCode: MK.A4 + code: A4 + MK.A5: + combinedCode: MK.A5 + code: A5 + MK.E8: + combinedCode: MK.E8 + code: E8 + MK.F1: + combinedCode: MK.F1 + code: F1 + MK.B3: + combinedCode: MK.B3 + code: B3 + MK.B4: + combinedCode: MK.B4 + code: B4 + MK.B6: + combinedCode: MK.B6 + code: B6 + MK.B7: + combinedCode: MK.B7 + code: B7 + MK.C1: + combinedCode: MK.C1 + code: C1 + MK.C2: + combinedCode: MK.C2 + code: C2 + MK.C3: + combinedCode: MK.C3 + code: C3 + MK.F3: + combinedCode: MK.F3 + code: F3 + MK.F4: + combinedCode: MK.F4 + code: F4 + MK.F5: + combinedCode: MK.F5 + code: F5 +ML: + iso2Code: ML + iso3Code: MLI + regions: + ML.08: + combinedCode: ML.08 + code: '08' + ML.06: + combinedCode: ML.06 + code: '06' + ML.05: + combinedCode: ML.05 + code: '05' + ML.04: + combinedCode: ML.04 + code: '04' + ML.07: + combinedCode: ML.07 + code: '07' + ML.03: + combinedCode: ML.03 + code: '03' + ML.09: + combinedCode: ML.09 + code: '09' + ML.01: + combinedCode: ML.01 + code: '01' + ML.10: + combinedCode: ML.10 + code: '10' +MM: + iso2Code: MM + iso3Code: MMR + regions: + MM.12: + combinedCode: MM.12 + code: '12' + MM.11: + combinedCode: MM.11 + code: '11' + MM.10: + combinedCode: MM.10 + code: '10' + MM.17: + combinedCode: MM.17 + code: '17' + MM.01: + combinedCode: MM.01 + code: '01' + MM.16: + combinedCode: MM.16 + code: '16' + MM.13: + combinedCode: MM.13 + code: '13' + MM.08: + combinedCode: MM.08 + code: '08' + MM.15: + combinedCode: MM.15 + code: '15' + MM.06: + combinedCode: MM.06 + code: '06' + MM.05: + combinedCode: MM.05 + code: '05' + MM.04: + combinedCode: MM.04 + code: '04' + MM.03: + combinedCode: MM.03 + code: '03' + MM.02: + combinedCode: MM.02 + code: '02' +MN: + iso2Code: MN + iso3Code: MNG + regions: + MN.19: + combinedCode: MN.19 + code: '19' + MN.12: + combinedCode: MN.12 + code: '12' + MN.10: + combinedCode: MN.10 + code: '10' + MN.09: + combinedCode: MN.09 + code: '09' + MN.03: + combinedCode: MN.03 + code: '03' + MN.02: + combinedCode: MN.02 + code: '02' + MN.20: + combinedCode: MN.20 + code: '20' + MN.18: + combinedCode: MN.18 + code: '18' + MN.17: + combinedCode: MN.17 + code: '17' + MN.16: + combinedCode: MN.16 + code: '16' + MN.15: + combinedCode: MN.15 + code: '15' + MN.14: + combinedCode: MN.14 + code: '14' + MN.13: + combinedCode: MN.13 + code: '13' + MN.11: + combinedCode: MN.11 + code: '11' + MN.08: + combinedCode: MN.08 + code: '08' + MN.07: + combinedCode: MN.07 + code: '07' + MN.06: + combinedCode: MN.06 + code: '06' + MN.21: + combinedCode: MN.21 + code: '21' + MN.01: + combinedCode: MN.01 + code: '01' + MN.23: + combinedCode: MN.23 + code: '23' + MN.24: + combinedCode: MN.24 + code: '24' + MN.25: + combinedCode: MN.25 + code: '25' +MO: + iso2Code: MO + iso3Code: MAC + regions: + MO.02: + combinedCode: MO.02 + code: '02' + MO.01: + combinedCode: MO.01 + code: '01' +MP: + iso2Code: MP + iso3Code: MNP + regions: + MP.100: + combinedCode: MP.100 + code: '100' + MP.110: + combinedCode: MP.110 + code: '110' + MP.120: + combinedCode: MP.120 + code: '120' + MP.085: + combinedCode: MP.085 + code: '085' +MQ: + iso2Code: MQ + iso3Code: MTQ + regions: + MQ.MQ: + combinedCode: MQ.MQ + code: MQ +MR: + iso2Code: MR + iso3Code: MRT + regions: + MR.06: + combinedCode: MR.06 + code: '06' + MR.11: + combinedCode: MR.11 + code: '11' + MR.09: + combinedCode: MR.09 + code: '09' + MR.NKC: + combinedCode: MR.NKC + code: NKC + MR.12: + combinedCode: MR.12 + code: '12' + MR.02: + combinedCode: MR.02 + code: '02' + MR.01: + combinedCode: MR.01 + code: '01' + MR.10: + combinedCode: MR.10 + code: '10' + MR.04: + combinedCode: MR.04 + code: '04' + MR.08: + combinedCode: MR.08 + code: '08' + MR.05: + combinedCode: MR.05 + code: '05' + MR.03: + combinedCode: MR.03 + code: '03' + MR.07: + combinedCode: MR.07 + code: '07' +MS: + iso2Code: MS + iso3Code: MSR + regions: + MS.03: + combinedCode: MS.03 + code: '03' + MS.02: + combinedCode: MS.02 + code: '02' + MS.01: + combinedCode: MS.01 + code: '01' +MT: + iso2Code: MT + iso3Code: MLT + regions: + MT.01: + combinedCode: MT.01 + code: '01' + MT.02: + combinedCode: MT.02 + code: '02' + MT.03: + combinedCode: MT.03 + code: '03' + MT.04: + combinedCode: MT.04 + code: '04' + MT.05: + combinedCode: MT.05 + code: '05' + MT.06: + combinedCode: MT.06 + code: '06' + MT.07: + combinedCode: MT.07 + code: '07' + MT.08: + combinedCode: MT.08 + code: '08' + MT.09: + combinedCode: MT.09 + code: '09' + MT.10: + combinedCode: MT.10 + code: '10' + MT.11: + combinedCode: MT.11 + code: '11' + MT.12: + combinedCode: MT.12 + code: '12' + MT.13: + combinedCode: MT.13 + code: '13' + MT.14: + combinedCode: MT.14 + code: '14' + MT.15: + combinedCode: MT.15 + code: '15' + MT.16: + combinedCode: MT.16 + code: '16' + MT.17: + combinedCode: MT.17 + code: '17' + MT.18: + combinedCode: MT.18 + code: '18' + MT.19: + combinedCode: MT.19 + code: '19' + MT.20: + combinedCode: MT.20 + code: '20' + MT.21: + combinedCode: MT.21 + code: '21' + MT.22: + combinedCode: MT.22 + code: '22' + MT.23: + combinedCode: MT.23 + code: '23' + MT.24: + combinedCode: MT.24 + code: '24' + MT.25: + combinedCode: MT.25 + code: '25' + MT.26: + combinedCode: MT.26 + code: '26' + MT.27: + combinedCode: MT.27 + code: '27' + MT.28: + combinedCode: MT.28 + code: '28' + MT.29: + combinedCode: MT.29 + code: '29' + MT.30: + combinedCode: MT.30 + code: '30' + MT.31: + combinedCode: MT.31 + code: '31' + MT.32: + combinedCode: MT.32 + code: '32' + MT.33: + combinedCode: MT.33 + code: '33' + MT.34: + combinedCode: MT.34 + code: '34' + MT.35: + combinedCode: MT.35 + code: '35' + MT.36: + combinedCode: MT.36 + code: '36' + MT.37: + combinedCode: MT.37 + code: '37' + MT.38: + combinedCode: MT.38 + code: '38' + MT.39: + combinedCode: MT.39 + code: '39' + MT.40: + combinedCode: MT.40 + code: '40' + MT.41: + combinedCode: MT.41 + code: '41' + MT.42: + combinedCode: MT.42 + code: '42' + MT.43: + combinedCode: MT.43 + code: '43' + MT.44: + combinedCode: MT.44 + code: '44' + MT.46: + combinedCode: MT.46 + code: '46' + MT.47: + combinedCode: MT.47 + code: '47' + MT.48: + combinedCode: MT.48 + code: '48' + MT.49: + combinedCode: MT.49 + code: '49' + MT.50: + combinedCode: MT.50 + code: '50' + MT.51: + combinedCode: MT.51 + code: '51' + MT.52: + combinedCode: MT.52 + code: '52' + MT.53: + combinedCode: MT.53 + code: '53' + MT.54: + combinedCode: MT.54 + code: '54' + MT.55: + combinedCode: MT.55 + code: '55' + MT.56: + combinedCode: MT.56 + code: '56' + MT.57: + combinedCode: MT.57 + code: '57' + MT.58: + combinedCode: MT.58 + code: '58' + MT.59: + combinedCode: MT.59 + code: '59' + MT.61: + combinedCode: MT.61 + code: '61' + MT.62: + combinedCode: MT.62 + code: '62' + MT.63: + combinedCode: MT.63 + code: '63' + MT.64: + combinedCode: MT.64 + code: '64' + MT.65: + combinedCode: MT.65 + code: '65' + MT.66: + combinedCode: MT.66 + code: '66' + MT.67: + combinedCode: MT.67 + code: '67' + MT.68: + combinedCode: MT.68 + code: '68' + MT.60: + combinedCode: MT.60 + code: '60' +MU: + iso2Code: MU + iso3Code: MUS + regions: + MU.21: + combinedCode: MU.21 + code: '21' + MU.20: + combinedCode: MU.20 + code: '20' + MU.19: + combinedCode: MU.19 + code: '19' + MU.18: + combinedCode: MU.18 + code: '18' + MU.17: + combinedCode: MU.17 + code: '17' + MU.16: + combinedCode: MU.16 + code: '16' + MU.15: + combinedCode: MU.15 + code: '15' + MU.14: + combinedCode: MU.14 + code: '14' + MU.13: + combinedCode: MU.13 + code: '13' + MU.12: + combinedCode: MU.12 + code: '12' + MU.22: + combinedCode: MU.22 + code: '22' + MU.23: + combinedCode: MU.23 + code: '23' +MV: + iso2Code: MV + iso3Code: MDV + regions: + MV.47: + combinedCode: MV.47 + code: '47' + MV.46: + combinedCode: MV.46 + code: '46' + MV.45: + combinedCode: MV.45 + code: '45' + MV.01: + combinedCode: MV.01 + code: '01' + MV.44: + combinedCode: MV.44 + code: '44' + MV.43: + combinedCode: MV.43 + code: '43' + MV.42: + combinedCode: MV.42 + code: '42' + MV.41: + combinedCode: MV.41 + code: '41' + MV.39: + combinedCode: MV.39 + code: '39' + MV.05: + combinedCode: MV.05 + code: '05' + MV.38: + combinedCode: MV.38 + code: '38' + MV.37: + combinedCode: MV.37 + code: '37' + MV.36: + combinedCode: MV.36 + code: '36' + MV.35: + combinedCode: MV.35 + code: '35' + MV.34: + combinedCode: MV.34 + code: '34' + MV.33: + combinedCode: MV.33 + code: '33' + MV.32: + combinedCode: MV.32 + code: '32' + MV.31: + combinedCode: MV.31 + code: '31' + MV.30: + combinedCode: MV.30 + code: '30' + MV.40: + combinedCode: MV.40 + code: '40' + MV.48: + combinedCode: MV.48 + code: '48' + MV.49: + combinedCode: MV.49 + code: '49' + MV.50: + combinedCode: MV.50 + code: '50' + MV.51: + combinedCode: MV.51 + code: '51' + MV.52: + combinedCode: MV.52 + code: '52' + MV.53: + combinedCode: MV.53 + code: '53' + MV.54: + combinedCode: MV.54 + code: '54' +MW: + iso2Code: MW + iso3Code: MWI + regions: + MW.S: + combinedCode: MW.S + code: S + MW.N: + combinedCode: MW.N + code: N + MW.C: + combinedCode: MW.C + code: C +MX: + iso2Code: MX + iso3Code: MEX + regions: + MX.31: + combinedCode: MX.31 + code: '31' + MX.30: + combinedCode: MX.30 + code: '30' + MX.29: + combinedCode: MX.29 + code: '29' + MX.28: + combinedCode: MX.28 + code: '28' + MX.27: + combinedCode: MX.27 + code: '27' + MX.23: + combinedCode: MX.23 + code: '23' + MX.22: + combinedCode: MX.22 + code: '22' + MX.21: + combinedCode: MX.21 + code: '21' + MX.20: + combinedCode: MX.20 + code: '20' + MX.19: + combinedCode: MX.19 + code: '19' + MX.17: + combinedCode: MX.17 + code: '17' + MX.15: + combinedCode: MX.15 + code: '15' + MX.13: + combinedCode: MX.13 + code: '13' + MX.12: + combinedCode: MX.12 + code: '12' + MX.09: + combinedCode: MX.09 + code: '09' + MX.05: + combinedCode: MX.05 + code: '05' + MX.04: + combinedCode: MX.04 + code: '04' + MX.32: + combinedCode: MX.32 + code: '32' + MX.26: + combinedCode: MX.26 + code: '26' + MX.25: + combinedCode: MX.25 + code: '25' + MX.24: + combinedCode: MX.24 + code: '24' + MX.18: + combinedCode: MX.18 + code: '18' + MX.16: + combinedCode: MX.16 + code: '16' + MX.14: + combinedCode: MX.14 + code: '14' + MX.11: + combinedCode: MX.11 + code: '11' + MX.10: + combinedCode: MX.10 + code: '10' + MX.08: + combinedCode: MX.08 + code: '08' + MX.07: + combinedCode: MX.07 + code: '07' + MX.06: + combinedCode: MX.06 + code: '06' + MX.03: + combinedCode: MX.03 + code: '03' + MX.02: + combinedCode: MX.02 + code: '02' + MX.01: + combinedCode: MX.01 + code: '01' +MY: + iso2Code: MY + iso3Code: MYS + regions: + MY.04: + combinedCode: MY.04 + code: '04' + MY.13: + combinedCode: MY.13 + code: '13' + MY.12: + combinedCode: MY.12 + code: '12' + MY.11: + combinedCode: MY.11 + code: '11' + MY.16: + combinedCode: MY.16 + code: '16' + MY.08: + combinedCode: MY.08 + code: '08' + MY.07: + combinedCode: MY.07 + code: '07' + MY.06: + combinedCode: MY.06 + code: '06' + MY.05: + combinedCode: MY.05 + code: '05' + MY.03: + combinedCode: MY.03 + code: '03' + MY.14: + combinedCode: MY.14 + code: '14' + MY.09: + combinedCode: MY.09 + code: '09' + MY.02: + combinedCode: MY.02 + code: '02' + MY.01: + combinedCode: MY.01 + code: '01' + MY.15: + combinedCode: MY.15 + code: '15' + MY.17: + combinedCode: MY.17 + code: '17' +MZ: + iso2Code: MZ + iso3Code: MOZ + regions: + MZ.09: + combinedCode: MZ.09 + code: '09' + MZ.08: + combinedCode: MZ.08 + code: '08' + MZ.05: + combinedCode: MZ.05 + code: '05' + MZ.07: + combinedCode: MZ.07 + code: '07' + MZ.06: + combinedCode: MZ.06 + code: '06' + MZ.04: + combinedCode: MZ.04 + code: '04' + MZ.10: + combinedCode: MZ.10 + code: '10' + MZ.03: + combinedCode: MZ.03 + code: '03' + MZ.02: + combinedCode: MZ.02 + code: '02' + MZ.01: + combinedCode: MZ.01 + code: '01' + MZ.11: + combinedCode: MZ.11 + code: '11' +NA: + iso2Code: NA + iso3Code: NAM + regions: + NA.28: + combinedCode: NA.28 + code: '28' + NA.21: + combinedCode: NA.21 + code: '21' + NA.29: + combinedCode: NA.29 + code: '29' + NA.30: + combinedCode: NA.30 + code: '30' + NA.31: + combinedCode: NA.31 + code: '31' + NA.32: + combinedCode: NA.32 + code: '32' + NA.33: + combinedCode: NA.33 + code: '33' + NA.34: + combinedCode: NA.34 + code: '34' + NA.35: + combinedCode: NA.35 + code: '35' + NA.36: + combinedCode: NA.36 + code: '36' + NA.37: + combinedCode: NA.37 + code: '37' + NA.38: + combinedCode: NA.38 + code: '38' + NA.39: + combinedCode: NA.39 + code: '39' +NC: + iso2Code: NC + iso3Code: NCL + regions: + NC.02: + combinedCode: NC.02 + code: '02' + NC.01: + combinedCode: NC.01 + code: '01' + NC.03: + combinedCode: NC.03 + code: '03' +NE: + iso2Code: NE + iso3Code: NER + regions: + NE.07: + combinedCode: NE.07 + code: '07' + NE.06: + combinedCode: NE.06 + code: '06' + NE.04: + combinedCode: NE.04 + code: '04' + NE.03: + combinedCode: NE.03 + code: '03' + NE.02: + combinedCode: NE.02 + code: '02' + NE.01: + combinedCode: NE.01 + code: '01' + NE.09: + combinedCode: NE.09 + code: '09' + NE.08: + combinedCode: NE.08 + code: '08' +NF: + iso2Code: NF + iso3Code: NFK + regions: { } +NG: + iso2Code: NG + iso3Code: NGA + regions: + NG.51: + combinedCode: NG.51 + code: '51' + NG.50: + combinedCode: NG.50 + code: '50' + NG.49: + combinedCode: NG.49 + code: '49' + NG.32: + combinedCode: NG.32 + code: '32' + NG.48: + combinedCode: NG.48 + code: '48' + NG.16: + combinedCode: NG.16 + code: '16' + NG.31: + combinedCode: NG.31 + code: '31' + NG.05: + combinedCode: NG.05 + code: '05' + NG.30: + combinedCode: NG.30 + code: '30' + NG.24: + combinedCode: NG.24 + code: '24' + NG.29: + combinedCode: NG.29 + code: '29' + NG.23: + combinedCode: NG.23 + code: '23' + NG.28: + combinedCode: NG.28 + code: '28' + NG.22: + combinedCode: NG.22 + code: '22' + NG.27: + combinedCode: NG.27 + code: '27' + NG.26: + combinedCode: NG.26 + code: '26' + NG.46: + combinedCode: NG.46 + code: '46' + NG.25: + combinedCode: NG.25 + code: '25' + NG.21: + combinedCode: NG.21 + code: '21' + NG.11: + combinedCode: NG.11 + code: '11' + NG.45: + combinedCode: NG.45 + code: '45' + NG.36: + combinedCode: NG.36 + code: '36' + NG.35: + combinedCode: NG.35 + code: '35' + NG.37: + combinedCode: NG.37 + code: '37' + NG.47: + combinedCode: NG.47 + code: '47' + NG.39: + combinedCode: NG.39 + code: '39' + NG.52: + combinedCode: NG.52 + code: '52' + NG.53: + combinedCode: NG.53 + code: '53' + NG.54: + combinedCode: NG.54 + code: '54' + NG.55: + combinedCode: NG.55 + code: '55' + NG.56: + combinedCode: NG.56 + code: '56' + NG.57: + combinedCode: NG.57 + code: '57' + NG.40: + combinedCode: NG.40 + code: '40' + NG.41: + combinedCode: NG.41 + code: '41' + NG.42: + combinedCode: NG.42 + code: '42' + NG.43: + combinedCode: NG.43 + code: '43' + NG.44: + combinedCode: NG.44 + code: '44' +NI: + iso2Code: NI + iso3Code: NIC + regions: + NI.15: + combinedCode: NI.15 + code: '15' + NI.14: + combinedCode: NI.14 + code: '14' + NI.13: + combinedCode: NI.13 + code: '13' + NI.12: + combinedCode: NI.12 + code: '12' + NI.11: + combinedCode: NI.11 + code: '11' + NI.10: + combinedCode: NI.10 + code: '10' + NI.09: + combinedCode: NI.09 + code: '09' + NI.08: + combinedCode: NI.08 + code: '08' + NI.07: + combinedCode: NI.07 + code: '07' + NI.06: + combinedCode: NI.06 + code: '06' + NI.05: + combinedCode: NI.05 + code: '05' + NI.04: + combinedCode: NI.04 + code: '04' + NI.03: + combinedCode: NI.03 + code: '03' + NI.02: + combinedCode: NI.02 + code: '02' + NI.01: + combinedCode: NI.01 + code: '01' + NI.17: + combinedCode: NI.17 + code: '17' + NI.18: + combinedCode: NI.18 + code: '18' +NL: + iso2Code: NL + iso3Code: NLD + regions: + NL.11: + combinedCode: NL.11 + code: '11' + NL.10: + combinedCode: NL.10 + code: '10' + NL.09: + combinedCode: NL.09 + code: '09' + NL.15: + combinedCode: NL.15 + code: '15' + NL.07: + combinedCode: NL.07 + code: '07' + NL.06: + combinedCode: NL.06 + code: '06' + NL.05: + combinedCode: NL.05 + code: '05' + NL.04: + combinedCode: NL.04 + code: '04' + NL.03: + combinedCode: NL.03 + code: '03' + NL.02: + combinedCode: NL.02 + code: '02' + NL.01: + combinedCode: NL.01 + code: '01' + NL.16: + combinedCode: NL.16 + code: '16' +NO: + iso2Code: NO + iso3Code: NOR + regions: + NO.05: + combinedCode: NO.05 + code: '05' + NO.20: + combinedCode: NO.20 + code: '20' + NO.19: + combinedCode: NO.19 + code: '19' + NO.18: + combinedCode: NO.18 + code: '18' + NO.17: + combinedCode: NO.17 + code: '17' + NO.16: + combinedCode: NO.16 + code: '16' + NO.15: + combinedCode: NO.15 + code: '15' + NO.14: + combinedCode: NO.14 + code: '14' + NO.13: + combinedCode: NO.13 + code: '13' + NO.12: + combinedCode: NO.12 + code: '12' + NO.11: + combinedCode: NO.11 + code: '11' + NO.10: + combinedCode: NO.10 + code: '10' + NO.09: + combinedCode: NO.09 + code: '09' + NO.08: + combinedCode: NO.08 + code: '08' + NO.07: + combinedCode: NO.07 + code: '07' + NO.06: + combinedCode: NO.06 + code: '06' + NO.04: + combinedCode: NO.04 + code: '04' + NO.02: + combinedCode: NO.02 + code: '02' + NO.01: + combinedCode: NO.01 + code: '01' +NP: + iso2Code: NP + iso3Code: NPL + regions: + NP.FR: + combinedCode: NP.FR + code: FR + NP.MR: + combinedCode: NP.MR + code: MR + NP.CR: + combinedCode: NP.CR + code: CR + NP.ER: + combinedCode: NP.ER + code: ER + NP.WR: + combinedCode: NP.WR + code: WR +NR: + iso2Code: NR + iso3Code: NRU + regions: + NR.14: + combinedCode: NR.14 + code: '14' + NR.13: + combinedCode: NR.13 + code: '13' + NR.12: + combinedCode: NR.12 + code: '12' + NR.11: + combinedCode: NR.11 + code: '11' + NR.10: + combinedCode: NR.10 + code: '10' + NR.09: + combinedCode: NR.09 + code: '09' + NR.08: + combinedCode: NR.08 + code: '08' + NR.07: + combinedCode: NR.07 + code: '07' + NR.06: + combinedCode: NR.06 + code: '06' + NR.05: + combinedCode: NR.05 + code: '05' + NR.04: + combinedCode: NR.04 + code: '04' + NR.03: + combinedCode: NR.03 + code: '03' + NR.02: + combinedCode: NR.02 + code: '02' + NR.01: + combinedCode: NR.01 + code: '01' +NU: + iso2Code: NU + iso3Code: NIU + regions: { } +NZ: + iso2Code: NZ + iso3Code: NZL + regions: + NZ.G2: + combinedCode: NZ.G2 + code: G2 + NZ.F3: + combinedCode: NZ.F3 + code: F3 + NZ.G1: + combinedCode: NZ.G1 + code: G1 + NZ.TAS: + combinedCode: NZ.TAS + code: TAS + NZ.F9: + combinedCode: NZ.F9 + code: F9 + NZ.F8: + combinedCode: NZ.F8 + code: F8 + NZ.E8: + combinedCode: NZ.E8 + code: E8 + NZ.F6: + combinedCode: NZ.F6 + code: F6 + NZ.F4: + combinedCode: NZ.F4 + code: F4 + NZ.F2: + combinedCode: NZ.F2 + code: F2 + NZ.F1: + combinedCode: NZ.F1 + code: F1 + NZ.E9: + combinedCode: NZ.E9 + code: E9 + NZ.E7: + combinedCode: NZ.E7 + code: E7 + NZ.10: + combinedCode: NZ.10 + code: '10' + NZ.F5: + combinedCode: NZ.F5 + code: F5 + NZ.F7: + combinedCode: NZ.F7 + code: F7 + NZ.G3: + combinedCode: NZ.G3 + code: G3 +OM: + iso2Code: OM + iso3Code: OMN + regions: + OM.01: + combinedCode: OM.01 + code: '01' + OM.02: + combinedCode: OM.02 + code: '02' + OM.03: + combinedCode: OM.03 + code: '03' + OM.04: + combinedCode: OM.04 + code: '04' + OM.09: + combinedCode: OM.09 + code: '09' + OM.06: + combinedCode: OM.06 + code: '06' + OM.07: + combinedCode: OM.07 + code: '07' + OM.08: + combinedCode: OM.08 + code: '08' + OM.10: + combinedCode: OM.10 + code: '10' + OM.12: + combinedCode: OM.12 + code: '12' + OM.11: + combinedCode: OM.11 + code: '11' +PA: + iso2Code: PA + iso3Code: PAN + regions: + PA.10: + combinedCode: PA.10 + code: '10' + PA.09: + combinedCode: PA.09 + code: '09' + PA.08: + combinedCode: PA.08 + code: '08' + PA.07: + combinedCode: PA.07 + code: '07' + PA.06: + combinedCode: PA.06 + code: '06' + PA.05: + combinedCode: PA.05 + code: '05' + PA.04: + combinedCode: PA.04 + code: '04' + PA.03: + combinedCode: PA.03 + code: '03' + PA.02: + combinedCode: PA.02 + code: '02' + PA.01: + combinedCode: PA.01 + code: '01' + PA.11: + combinedCode: PA.11 + code: '11' + PA.12: + combinedCode: PA.12 + code: '12' +PE: + iso2Code: PE + iso3Code: PER + regions: + PE.25: + combinedCode: PE.25 + code: '25' + PE.24: + combinedCode: PE.24 + code: '24' + PE.22: + combinedCode: PE.22 + code: '22' + PE.20: + combinedCode: PE.20 + code: '20' + PE.16: + combinedCode: PE.16 + code: '16' + PE.14: + combinedCode: PE.14 + code: '14' + PE.13: + combinedCode: PE.13 + code: '13' + PE.10: + combinedCode: PE.10 + code: '10' + PE.06: + combinedCode: PE.06 + code: '06' + PE.02: + combinedCode: PE.02 + code: '02' + PE.01: + combinedCode: PE.01 + code: '01' + PE.23: + combinedCode: PE.23 + code: '23' + PE.21: + combinedCode: PE.21 + code: '21' + PE.19: + combinedCode: PE.19 + code: '19' + PE.18: + combinedCode: PE.18 + code: '18' + PE.17: + combinedCode: PE.17 + code: '17' + PE.LMA: + combinedCode: PE.LMA + code: LMA + PE.15: + combinedCode: PE.15 + code: '15' + PE.12: + combinedCode: PE.12 + code: '12' + PE.11: + combinedCode: PE.11 + code: '11' + PE.09: + combinedCode: PE.09 + code: '09' + PE.08: + combinedCode: PE.08 + code: '08' + PE.07: + combinedCode: PE.07 + code: '07' + PE.05: + combinedCode: PE.05 + code: '05' + PE.04: + combinedCode: PE.04 + code: '04' + PE.03: + combinedCode: PE.03 + code: '03' +PF: + iso2Code: PF + iso3Code: PYF + regions: + PF.04: + combinedCode: PF.04 + code: '04' + PF.03: + combinedCode: PF.03 + code: '03' + PF.02: + combinedCode: PF.02 + code: '02' + PF.01: + combinedCode: PF.01 + code: '01' + PF.05: + combinedCode: PF.05 + code: '05' +PG: + iso2Code: PG + iso3Code: PNG + regions: + PG.17: + combinedCode: PG.17 + code: '17' + PG.06: + combinedCode: PG.06 + code: '06' + PG.16: + combinedCode: PG.16 + code: '16' + PG.05: + combinedCode: PG.05 + code: '05' + PG.18: + combinedCode: PG.18 + code: '18' + PG.07: + combinedCode: PG.07 + code: '07' + PG.04: + combinedCode: PG.04 + code: '04' + PG.15: + combinedCode: PG.15 + code: '15' + PG.20: + combinedCode: PG.20 + code: '20' + PG.14: + combinedCode: PG.14 + code: '14' + PG.13: + combinedCode: PG.13 + code: '13' + PG.12: + combinedCode: PG.12 + code: '12' + PG.02: + combinedCode: PG.02 + code: '02' + PG.19: + combinedCode: PG.19 + code: '19' + PG.11: + combinedCode: PG.11 + code: '11' + PG.10: + combinedCode: PG.10 + code: '10' + PG.09: + combinedCode: PG.09 + code: '09' + PG.08: + combinedCode: PG.08 + code: '08' + PG.03: + combinedCode: PG.03 + code: '03' + PG.01: + combinedCode: PG.01 + code: '01' + PG.21: + combinedCode: PG.21 + code: '21' + PG.22: + combinedCode: PG.22 + code: '22' +PH: + iso2Code: PH + iso3Code: PHL + regions: + PH.14: + combinedCode: PH.14 + code: '14' + PH.10: + combinedCode: PH.10 + code: '10' + PH.41: + combinedCode: PH.41 + code: '41' + PH.02: + combinedCode: PH.02 + code: '02' + PH.12: + combinedCode: PH.12 + code: '12' + PH.13: + combinedCode: PH.13 + code: '13' + PH.15: + combinedCode: PH.15 + code: '15' + PH.01: + combinedCode: PH.01 + code: '01' + PH.40: + combinedCode: PH.40 + code: '40' + PH.06: + combinedCode: PH.06 + code: '06' + PH.03: + combinedCode: PH.03 + code: '03' + PH.07: + combinedCode: PH.07 + code: '07' + PH.08: + combinedCode: PH.08 + code: '08' + PH.09: + combinedCode: PH.09 + code: '09' + PH.11: + combinedCode: PH.11 + code: '11' + PH.05: + combinedCode: PH.05 + code: '05' + PH.NCR: + combinedCode: PH.NCR + code: NCR +PK: + iso2Code: PK + iso3Code: PAK + regions: + PK.08: + combinedCode: PK.08 + code: '08' + PK.05: + combinedCode: PK.05 + code: '05' + PK.04: + combinedCode: PK.04 + code: '04' + PK.03: + combinedCode: PK.03 + code: '03' + PK.07: + combinedCode: PK.07 + code: '07' + PK.01: + combinedCode: PK.01 + code: '01' + PK.02: + combinedCode: PK.02 + code: '02' + PK.06: + combinedCode: PK.06 + code: '06' +PL: + iso2Code: PL + iso3Code: POL + regions: + PL.75: + combinedCode: PL.75 + code: '75' + PL.77: + combinedCode: PL.77 + code: '77' + PL.78: + combinedCode: PL.78 + code: '78' + PL.80: + combinedCode: PL.80 + code: '80' + PL.81: + combinedCode: PL.81 + code: '81' + PL.84: + combinedCode: PL.84 + code: '84' + PL.85: + combinedCode: PL.85 + code: '85' + PL.72: + combinedCode: PL.72 + code: '72' + PL.74: + combinedCode: PL.74 + code: '74' + PL.76: + combinedCode: PL.76 + code: '76' + PL.79: + combinedCode: PL.79 + code: '79' + PL.82: + combinedCode: PL.82 + code: '82' + PL.83: + combinedCode: PL.83 + code: '83' + PL.86: + combinedCode: PL.86 + code: '86' + PL.87: + combinedCode: PL.87 + code: '87' + PL.73: + combinedCode: PL.73 + code: '73' +PM: + iso2Code: PM + iso3Code: SPM + regions: + PM.97502: + combinedCode: PM.97502 + code: '97502' + PM.97501: + combinedCode: PM.97501 + code: '97501' +PN: + iso2Code: PN + iso3Code: PCN + regions: { } +PR: + iso2Code: PR + iso3Code: PRI + regions: + PR.001: + combinedCode: PR.001 + code: '001' + PR.003: + combinedCode: PR.003 + code: '003' + PR.005: + combinedCode: PR.005 + code: '005' + PR.007: + combinedCode: PR.007 + code: '007' + PR.009: + combinedCode: PR.009 + code: '009' + PR.011: + combinedCode: PR.011 + code: '011' + PR.013: + combinedCode: PR.013 + code: '013' + PR.015: + combinedCode: PR.015 + code: '015' + PR.017: + combinedCode: PR.017 + code: '017' + PR.019: + combinedCode: PR.019 + code: '019' + PR.021: + combinedCode: PR.021 + code: '021' + PR.023: + combinedCode: PR.023 + code: '023' + PR.025: + combinedCode: PR.025 + code: '025' + PR.027: + combinedCode: PR.027 + code: '027' + PR.029: + combinedCode: PR.029 + code: '029' + PR.031: + combinedCode: PR.031 + code: '031' + PR.033: + combinedCode: PR.033 + code: '033' + PR.035: + combinedCode: PR.035 + code: '035' + PR.037: + combinedCode: PR.037 + code: '037' + PR.039: + combinedCode: PR.039 + code: '039' + PR.041: + combinedCode: PR.041 + code: '041' + PR.043: + combinedCode: PR.043 + code: '043' + PR.045: + combinedCode: PR.045 + code: '045' + PR.047: + combinedCode: PR.047 + code: '047' + PR.049: + combinedCode: PR.049 + code: '049' + PR.051: + combinedCode: PR.051 + code: '051' + PR.053: + combinedCode: PR.053 + code: '053' + PR.054: + combinedCode: PR.054 + code: '054' + PR.055: + combinedCode: PR.055 + code: '055' + PR.057: + combinedCode: PR.057 + code: '057' + PR.059: + combinedCode: PR.059 + code: '059' + PR.061: + combinedCode: PR.061 + code: '061' + PR.063: + combinedCode: PR.063 + code: '063' + PR.065: + combinedCode: PR.065 + code: '065' + PR.067: + combinedCode: PR.067 + code: '067' + PR.069: + combinedCode: PR.069 + code: '069' + PR.071: + combinedCode: PR.071 + code: '071' + PR.073: + combinedCode: PR.073 + code: '073' + PR.075: + combinedCode: PR.075 + code: '075' + PR.077: + combinedCode: PR.077 + code: '077' + PR.079: + combinedCode: PR.079 + code: '079' + PR.081: + combinedCode: PR.081 + code: '081' + PR.083: + combinedCode: PR.083 + code: '083' + PR.085: + combinedCode: PR.085 + code: '085' + PR.087: + combinedCode: PR.087 + code: '087' + PR.089: + combinedCode: PR.089 + code: '089' + PR.091: + combinedCode: PR.091 + code: '091' + PR.093: + combinedCode: PR.093 + code: '093' + PR.095: + combinedCode: PR.095 + code: '095' + PR.097: + combinedCode: PR.097 + code: '097' + PR.099: + combinedCode: PR.099 + code: '099' + PR.101: + combinedCode: PR.101 + code: '101' + PR.103: + combinedCode: PR.103 + code: '103' + PR.105: + combinedCode: PR.105 + code: '105' + PR.107: + combinedCode: PR.107 + code: '107' + PR.109: + combinedCode: PR.109 + code: '109' + PR.111: + combinedCode: PR.111 + code: '111' + PR.113: + combinedCode: PR.113 + code: '113' + PR.117: + combinedCode: PR.117 + code: '117' + PR.115: + combinedCode: PR.115 + code: '115' + PR.119: + combinedCode: PR.119 + code: '119' + PR.121: + combinedCode: PR.121 + code: '121' + PR.123: + combinedCode: PR.123 + code: '123' + PR.125: + combinedCode: PR.125 + code: '125' + PR.127: + combinedCode: PR.127 + code: '127' + PR.129: + combinedCode: PR.129 + code: '129' + PR.131: + combinedCode: PR.131 + code: '131' + PR.133: + combinedCode: PR.133 + code: '133' + PR.135: + combinedCode: PR.135 + code: '135' + PR.137: + combinedCode: PR.137 + code: '137' + PR.139: + combinedCode: PR.139 + code: '139' + PR.141: + combinedCode: PR.141 + code: '141' + PR.143: + combinedCode: PR.143 + code: '143' + PR.145: + combinedCode: PR.145 + code: '145' + PR.149: + combinedCode: PR.149 + code: '149' + PR.151: + combinedCode: PR.151 + code: '151' + PR.153: + combinedCode: PR.153 + code: '153' + PR.147: + combinedCode: PR.147 + code: '147' +PS: + iso2Code: PS + iso3Code: PSE + regions: + PS.GZ: + combinedCode: PS.GZ + code: GZ + PS.WE: + combinedCode: PS.WE + code: WE +PT: + iso2Code: PT + iso3Code: PRT + regions: + PT.19: + combinedCode: PT.19 + code: '19' + PT.18: + combinedCode: PT.18 + code: '18' + PT.16: + combinedCode: PT.16 + code: '16' + PT.14: + combinedCode: PT.14 + code: '14' + PT.13: + combinedCode: PT.13 + code: '13' + PT.09: + combinedCode: PT.09 + code: '09' + PT.08: + combinedCode: PT.08 + code: '08' + PT.06: + combinedCode: PT.06 + code: '06' + PT.03: + combinedCode: PT.03 + code: '03' + PT.10: + combinedCode: PT.10 + code: '10' + PT.22: + combinedCode: PT.22 + code: '22' + PT.21: + combinedCode: PT.21 + code: '21' + PT.20: + combinedCode: PT.20 + code: '20' + PT.17: + combinedCode: PT.17 + code: '17' + PT.11: + combinedCode: PT.11 + code: '11' + PT.07: + combinedCode: PT.07 + code: '07' + PT.05: + combinedCode: PT.05 + code: '05' + PT.04: + combinedCode: PT.04 + code: '04' + PT.02: + combinedCode: PT.02 + code: '02' + PT.23: + combinedCode: PT.23 + code: '23' +PW: + iso2Code: PW + iso3Code: PLW + regions: + PW.11: + combinedCode: PW.11 + code: '11' + PW.16: + combinedCode: PW.16 + code: '16' + PW.05: + combinedCode: PW.05 + code: '05' + PW.04: + combinedCode: PW.04 + code: '04' + PW.01: + combinedCode: PW.01 + code: '01' + PW.02: + combinedCode: PW.02 + code: '02' + PW.03: + combinedCode: PW.03 + code: '03' + PW.06: + combinedCode: PW.06 + code: '06' + PW.07: + combinedCode: PW.07 + code: '07' + PW.08: + combinedCode: PW.08 + code: '08' + PW.12: + combinedCode: PW.12 + code: '12' + PW.09: + combinedCode: PW.09 + code: '09' + PW.10: + combinedCode: PW.10 + code: '10' + PW.13: + combinedCode: PW.13 + code: '13' + PW.14: + combinedCode: PW.14 + code: '14' + PW.15: + combinedCode: PW.15 + code: '15' +PY: + iso2Code: PY + iso3Code: PRY + regions: + PY.17: + combinedCode: PY.17 + code: '17' + PY.16: + combinedCode: PY.16 + code: '16' + PY.15: + combinedCode: PY.15 + code: '15' + PY.13: + combinedCode: PY.13 + code: '13' + PY.12: + combinedCode: PY.12 + code: '12' + PY.11: + combinedCode: PY.11 + code: '11' + PY.10: + combinedCode: PY.10 + code: '10' + PY.08: + combinedCode: PY.08 + code: '08' + PY.07: + combinedCode: PY.07 + code: '07' + PY.06: + combinedCode: PY.06 + code: '06' + PY.19: + combinedCode: PY.19 + code: '19' + PY.05: + combinedCode: PY.05 + code: '05' + PY.04: + combinedCode: PY.04 + code: '04' + PY.02: + combinedCode: PY.02 + code: '02' + PY.01: + combinedCode: PY.01 + code: '01' + PY.23: + combinedCode: PY.23 + code: '23' + PY.22: + combinedCode: PY.22 + code: '22' + PY.24: + combinedCode: PY.24 + code: '24' +QA: + iso2Code: QA + iso3Code: QAT + regions: + QA.08: + combinedCode: QA.08 + code: '08' + QA.02: + combinedCode: QA.02 + code: '02' + QA.04: + combinedCode: QA.04 + code: '04' + QA.09: + combinedCode: QA.09 + code: '09' + QA.03: + combinedCode: QA.03 + code: '03' + QA.06: + combinedCode: QA.06 + code: '06' + QA.01: + combinedCode: QA.01 + code: '01' + QA.10: + combinedCode: QA.10 + code: '10' + QA.11: + combinedCode: QA.11 + code: '11' + QA.12: + combinedCode: QA.12 + code: '12' + QA.13: + combinedCode: QA.13 + code: '13' +RE: + iso2Code: RE + iso3Code: REU + regions: + RE.RE: + combinedCode: RE.RE + code: RE +RO: + iso2Code: RO + iso3Code: ROU + regions: + RO.40: + combinedCode: RO.40 + code: '40' + RO.39: + combinedCode: RO.39 + code: '39' + RO.38: + combinedCode: RO.38 + code: '38' + RO.37: + combinedCode: RO.37 + code: '37' + RO.36: + combinedCode: RO.36 + code: '36' + RO.35: + combinedCode: RO.35 + code: '35' + RO.34: + combinedCode: RO.34 + code: '34' + RO.33: + combinedCode: RO.33 + code: '33' + RO.32: + combinedCode: RO.32 + code: '32' + RO.31: + combinedCode: RO.31 + code: '31' + RO.30: + combinedCode: RO.30 + code: '30' + RO.29: + combinedCode: RO.29 + code: '29' + RO.28: + combinedCode: RO.28 + code: '28' + RO.27: + combinedCode: RO.27 + code: '27' + RO.26: + combinedCode: RO.26 + code: '26' + RO.25: + combinedCode: RO.25 + code: '25' + RO.23: + combinedCode: RO.23 + code: '23' + RO.22: + combinedCode: RO.22 + code: '22' + RO.21: + combinedCode: RO.21 + code: '21' + RO.20: + combinedCode: RO.20 + code: '20' + RO.19: + combinedCode: RO.19 + code: '19' + RO.42: + combinedCode: RO.42 + code: '42' + RO.18: + combinedCode: RO.18 + code: '18' + RO.17: + combinedCode: RO.17 + code: '17' + RO.16: + combinedCode: RO.16 + code: '16' + RO.15: + combinedCode: RO.15 + code: '15' + RO.14: + combinedCode: RO.14 + code: '14' + RO.13: + combinedCode: RO.13 + code: '13' + RO.12: + combinedCode: RO.12 + code: '12' + RO.41: + combinedCode: RO.41 + code: '41' + RO.11: + combinedCode: RO.11 + code: '11' + RO.10: + combinedCode: RO.10 + code: '10' + RO.09: + combinedCode: RO.09 + code: '09' + RO.08: + combinedCode: RO.08 + code: '08' + RO.07: + combinedCode: RO.07 + code: '07' + RO.06: + combinedCode: RO.06 + code: '06' + RO.05: + combinedCode: RO.05 + code: '05' + RO.04: + combinedCode: RO.04 + code: '04' + RO.03: + combinedCode: RO.03 + code: '03' + RO.02: + combinedCode: RO.02 + code: '02' + RO.01: + combinedCode: RO.01 + code: '01' + RO.43: + combinedCode: RO.43 + code: '43' +RS: + iso2Code: RS + iso3Code: SRB + regions: + RS.VO: + combinedCode: RS.VO + code: VO + RS.SE: + combinedCode: RS.SE + code: SE +RU: + iso2Code: RU + iso3Code: RUS + regions: + RU.88: + combinedCode: RU.88 + code: '88' + RU.86: + combinedCode: RU.86 + code: '86' + RU.85: + combinedCode: RU.85 + code: '85' + RU.84: + combinedCode: RU.84 + code: '84' + RU.81: + combinedCode: RU.81 + code: '81' + RU.80: + combinedCode: RU.80 + code: '80' + RU.77: + combinedCode: RU.77 + code: '77' + RU.76: + combinedCode: RU.76 + code: '76' + RU.73: + combinedCode: RU.73 + code: '73' + RU.72: + combinedCode: RU.72 + code: '72' + RU.70: + combinedCode: RU.70 + code: '70' + RU.69: + combinedCode: RU.69 + code: '69' + RU.67: + combinedCode: RU.67 + code: '67' + RU.65: + combinedCode: RU.65 + code: '65' + RU.62: + combinedCode: RU.62 + code: '62' + RU.61: + combinedCode: RU.61 + code: '61' + RU.60: + combinedCode: RU.60 + code: '60' + RU.90: + combinedCode: RU.90 + code: '90' + RU.57: + combinedCode: RU.57 + code: '57' + RU.56: + combinedCode: RU.56 + code: '56' + RU.55: + combinedCode: RU.55 + code: '55' + RU.52: + combinedCode: RU.52 + code: '52' + RU.68: + combinedCode: RU.68 + code: '68' + RU.50: + combinedCode: RU.50 + code: '50' + RU.49: + combinedCode: RU.49 + code: '49' + RU.48: + combinedCode: RU.48 + code: '48' + RU.47: + combinedCode: RU.47 + code: '47' + RU.46: + combinedCode: RU.46 + code: '46' + RU.45: + combinedCode: RU.45 + code: '45' + RU.43: + combinedCode: RU.43 + code: '43' + RU.42: + combinedCode: RU.42 + code: '42' + RU.66: + combinedCode: RU.66 + code: '66' + RU.41: + combinedCode: RU.41 + code: '41' + RU.38: + combinedCode: RU.38 + code: '38' + RU.37: + combinedCode: RU.37 + code: '37' + RU.34: + combinedCode: RU.34 + code: '34' + RU.33: + combinedCode: RU.33 + code: '33' + RU.28: + combinedCode: RU.28 + code: '28' + RU.27: + combinedCode: RU.27 + code: '27' + RU.25: + combinedCode: RU.25 + code: '25' + RU.24: + combinedCode: RU.24 + code: '24' + RU.23: + combinedCode: RU.23 + code: '23' + RU.22: + combinedCode: RU.22 + code: '22' + RU.21: + combinedCode: RU.21 + code: '21' + RU.19: + combinedCode: RU.19 + code: '19' + RU.51: + combinedCode: RU.51 + code: '51' + RU.17: + combinedCode: RU.17 + code: '17' + RU.16: + combinedCode: RU.16 + code: '16' + RU.12: + combinedCode: RU.12 + code: '12' + RU.10: + combinedCode: RU.10 + code: '10' + RU.09: + combinedCode: RU.09 + code: '09' + RU.08: + combinedCode: RU.08 + code: '08' + RU.07: + combinedCode: RU.07 + code: '07' + RU.06: + combinedCode: RU.06 + code: '06' + RU.01: + combinedCode: RU.01 + code: '01' + RU.83: + combinedCode: RU.83 + code: '83' + RU.87: + combinedCode: RU.87 + code: '87' + RU.78: + combinedCode: RU.78 + code: '78' + RU.79: + combinedCode: RU.79 + code: '79' + RU.75: + combinedCode: RU.75 + code: '75' + RU.71: + combinedCode: RU.71 + code: '71' + RU.54: + combinedCode: RU.54 + code: '54' + RU.53: + combinedCode: RU.53 + code: '53' + RU.40: + combinedCode: RU.40 + code: '40' + RU.91: + combinedCode: RU.91 + code: '91' + RU.32: + combinedCode: RU.32 + code: '32' + RU.31: + combinedCode: RU.31 + code: '31' + RU.29: + combinedCode: RU.29 + code: '29' + RU.03: + combinedCode: RU.03 + code: '03' + RU.13: + combinedCode: RU.13 + code: '13' + RU.04: + combinedCode: RU.04 + code: '04' + RU.63: + combinedCode: RU.63 + code: '63' + RU.59: + combinedCode: RU.59 + code: '59' + RU.30: + combinedCode: RU.30 + code: '30' + RU.20: + combinedCode: RU.20 + code: '20' + RU.89: + combinedCode: RU.89 + code: '89' + RU.05: + combinedCode: RU.05 + code: '05' + RU.11: + combinedCode: RU.11 + code: '11' + RU.64: + combinedCode: RU.64 + code: '64' + RU.44: + combinedCode: RU.44 + code: '44' + RU.92: + combinedCode: RU.92 + code: '92' + RU.15: + combinedCode: RU.15 + code: '15' + RU.93: + combinedCode: RU.93 + code: '93' +RW: + iso2Code: RW + iso3Code: RWA + regions: + RW.11: + combinedCode: RW.11 + code: '11' + RW.12: + combinedCode: RW.12 + code: '12' + RW.13: + combinedCode: RW.13 + code: '13' + RW.14: + combinedCode: RW.14 + code: '14' + RW.15: + combinedCode: RW.15 + code: '15' +SA: + iso2Code: SA + iso3Code: SAU + regions: + SA.19: + combinedCode: SA.19 + code: '19' + SA.16: + combinedCode: SA.16 + code: '16' + SA.14: + combinedCode: SA.14 + code: '14' + SA.17: + combinedCode: SA.17 + code: '17' + SA.13: + combinedCode: SA.13 + code: '13' + SA.11: + combinedCode: SA.11 + code: '11' + SA.06: + combinedCode: SA.06 + code: '06' + SA.10: + combinedCode: SA.10 + code: '10' + SA.08: + combinedCode: SA.08 + code: '08' + SA.05: + combinedCode: SA.05 + code: '05' + SA.20: + combinedCode: SA.20 + code: '20' + SA.15: + combinedCode: SA.15 + code: '15' + SA.02: + combinedCode: SA.02 + code: '02' +SB: + iso2Code: SB + iso3Code: SLB + regions: + SB.11: + combinedCode: SB.11 + code: '11' + SB.03: + combinedCode: SB.03 + code: '03' + SB.07: + combinedCode: SB.07 + code: '07' + SB.06: + combinedCode: SB.06 + code: '06' + SB.10: + combinedCode: SB.10 + code: '10' + SB.09: + combinedCode: SB.09 + code: '09' + SB.08: + combinedCode: SB.08 + code: '08' + SB.12: + combinedCode: SB.12 + code: '12' + SB.13: + combinedCode: SB.13 + code: '13' +SC: + iso2Code: SC + iso3Code: SYC + regions: + SC.23: + combinedCode: SC.23 + code: '23' + SC.22: + combinedCode: SC.22 + code: '22' + SC.27: + combinedCode: SC.27 + code: '27' + SC.20: + combinedCode: SC.20 + code: '20' + SC.19: + combinedCode: SC.19 + code: '19' + SC.18: + combinedCode: SC.18 + code: '18' + SC.17: + combinedCode: SC.17 + code: '17' + SC.26: + combinedCode: SC.26 + code: '26' + SC.25: + combinedCode: SC.25 + code: '25' + SC.24: + combinedCode: SC.24 + code: '24' + SC.14: + combinedCode: SC.14 + code: '14' + SC.12: + combinedCode: SC.12 + code: '12' + SC.11: + combinedCode: SC.11 + code: '11' + SC.10: + combinedCode: SC.10 + code: '10' + SC.09: + combinedCode: SC.09 + code: '09' + SC.08: + combinedCode: SC.08 + code: '08' + SC.07: + combinedCode: SC.07 + code: '07' + SC.06: + combinedCode: SC.06 + code: '06' + SC.05: + combinedCode: SC.05 + code: '05' + SC.03: + combinedCode: SC.03 + code: '03' + SC.02: + combinedCode: SC.02 + code: '02' + SC.01: + combinedCode: SC.01 + code: '01' + SC.29: + combinedCode: SC.29 + code: '29' + SC.30: + combinedCode: SC.30 + code: '30' + SC.28: + combinedCode: SC.28 + code: '28' +SD: + iso2Code: SD + iso3Code: SDN + regions: + SD.43: + combinedCode: SD.43 + code: '43' + SD.29: + combinedCode: SD.29 + code: '29' + SD.36: + combinedCode: SD.36 + code: '36' + SD.38: + combinedCode: SD.38 + code: '38' + SD.39: + combinedCode: SD.39 + code: '39' + SD.41: + combinedCode: SD.41 + code: '41' + SD.42: + combinedCode: SD.42 + code: '42' + SD.47: + combinedCode: SD.47 + code: '47' + SD.49: + combinedCode: SD.49 + code: '49' + SD.50: + combinedCode: SD.50 + code: '50' + SD.52: + combinedCode: SD.52 + code: '52' + SD.53: + combinedCode: SD.53 + code: '53' + SD.55: + combinedCode: SD.55 + code: '55' + SD.56: + combinedCode: SD.56 + code: '56' + SD.58: + combinedCode: SD.58 + code: '58' + SD.60: + combinedCode: SD.60 + code: '60' + SD.61: + combinedCode: SD.61 + code: '61' +SS: + iso2Code: SS + iso3Code: SSD + regions: + SS.07: + combinedCode: SS.07 + code: '07' + SS.04: + combinedCode: SS.04 + code: '04' + SS.06: + combinedCode: SS.06 + code: '06' + SS.01: + combinedCode: SS.01 + code: '01' + SS.10: + combinedCode: SS.10 + code: '10' + SS.09: + combinedCode: SS.09 + code: '09' + SS.03: + combinedCode: SS.03 + code: '03' + SS.05: + combinedCode: SS.05 + code: '05' + SS.02: + combinedCode: SS.02 + code: '02' + SS.08: + combinedCode: SS.08 + code: '08' +SE: + iso2Code: SE + iso3Code: SWE + regions: + SE.14: + combinedCode: SE.14 + code: '14' + SE.25: + combinedCode: SE.25 + code: '25' + SE.24: + combinedCode: SE.24 + code: '24' + SE.23: + combinedCode: SE.23 + code: '23' + SE.22: + combinedCode: SE.22 + code: '22' + SE.21: + combinedCode: SE.21 + code: '21' + SE.26: + combinedCode: SE.26 + code: '26' + SE.18: + combinedCode: SE.18 + code: '18' + SE.16: + combinedCode: SE.16 + code: '16' + SE.15: + combinedCode: SE.15 + code: '15' + SE.12: + combinedCode: SE.12 + code: '12' + SE.10: + combinedCode: SE.10 + code: '10' + SE.09: + combinedCode: SE.09 + code: '09' + SE.08: + combinedCode: SE.08 + code: '08' + SE.07: + combinedCode: SE.07 + code: '07' + SE.06: + combinedCode: SE.06 + code: '06' + SE.05: + combinedCode: SE.05 + code: '05' + SE.03: + combinedCode: SE.03 + code: '03' + SE.02: + combinedCode: SE.02 + code: '02' + SE.27: + combinedCode: SE.27 + code: '27' + SE.28: + combinedCode: SE.28 + code: '28' +SG: + iso2Code: SG + iso3Code: SGP + regions: + SG.01: + combinedCode: SG.01 + code: '01' + SG.02: + combinedCode: SG.02 + code: '02' + SG.04: + combinedCode: SG.04 + code: '04' + SG.05: + combinedCode: SG.05 + code: '05' + SG.03: + combinedCode: SG.03 + code: '03' +SH: + iso2Code: SH + iso3Code: SHN + regions: + SH.01: + combinedCode: SH.01 + code: '01' + SH.03: + combinedCode: SH.03 + code: '03' + SH.02: + combinedCode: SH.02 + code: '02' +SI: + iso2Code: SI + iso3Code: SVN + regions: + SI.N5: + combinedCode: SI.N5 + code: N5 + SI.E7: + combinedCode: SI.E7 + code: E7 + SI.E5: + combinedCode: SI.E5 + code: E5 + SI.D5: + combinedCode: SI.D5 + code: D5 + SI.D4: + combinedCode: SI.D4 + code: D4 + SI.D3: + combinedCode: SI.D3 + code: D3 + SI.D2: + combinedCode: SI.D2 + code: D2 + SI.D7: + combinedCode: SI.D7 + code: D7 + SI.C5: + combinedCode: SI.C5 + code: C5 + SI.C4: + combinedCode: SI.C4 + code: C4 + SI.L8: + combinedCode: SI.L8 + code: L8 + SI.C2: + combinedCode: SI.C2 + code: C2 + SI.B9: + combinedCode: SI.B9 + code: B9 + SI.B7: + combinedCode: SI.B7 + code: B7 + SI.B6: + combinedCode: SI.B6 + code: B6 + SI.L7: + combinedCode: SI.L7 + code: L7 + SI.L1: + combinedCode: SI.L1 + code: L1 + SI.A3: + combinedCode: SI.A3 + code: A3 + SI.A2: + combinedCode: SI.A2 + code: A2 + SI.K7: + combinedCode: SI.K7 + code: K7 + SI.94: + combinedCode: SI.94 + code: '94' + SI.J9: + combinedCode: SI.J9 + code: J9 + SI.87: + combinedCode: SI.87 + code: '87' + SI.J7: + combinedCode: SI.J7 + code: J7 + SI.84: + combinedCode: SI.84 + code: '84' + SI.80: + combinedCode: SI.80 + code: '80' + SI.79: + combinedCode: SI.79 + code: '79' + SI.73: + combinedCode: SI.73 + code: '73' + SI.J2: + combinedCode: SI.J2 + code: J2 + SI.64: + combinedCode: SI.64 + code: '64' + SI.I6: + combinedCode: SI.I6 + code: I6 + SI.I5: + combinedCode: SI.I5 + code: I5 + SI.I3: + combinedCode: SI.I3 + code: I3 + SI.57: + combinedCode: SI.57 + code: '57' + SI.54: + combinedCode: SI.54 + code: '54' + SI.52: + combinedCode: SI.52 + code: '52' + SI.50: + combinedCode: SI.50 + code: '50' + SI.H7: + combinedCode: SI.H7 + code: H7 + SI.H6: + combinedCode: SI.H6 + code: H6 + SI.H4: + combinedCode: SI.H4 + code: H4 + SI.40: + combinedCode: SI.40 + code: '40' + SI.38: + combinedCode: SI.38 + code: '38' + SI.36: + combinedCode: SI.36 + code: '36' + SI.34: + combinedCode: SI.34 + code: '34' + SI.32: + combinedCode: SI.32 + code: '32' + SI.29: + combinedCode: SI.29 + code: '29' + SI.25: + combinedCode: SI.25 + code: '25' + SI.G7: + combinedCode: SI.G7 + code: G7 + SI.17: + combinedCode: SI.17 + code: '17' + SI.13: + combinedCode: SI.13 + code: '13' + SI.11: + combinedCode: SI.11 + code: '11' + SI.08: + combinedCode: SI.08 + code: '08' + SI.01: + combinedCode: SI.01 + code: '01' + SI.35: + combinedCode: SI.35 + code: '35' + SI.19: + combinedCode: SI.19 + code: '19' + SI.91: + combinedCode: SI.91 + code: '91' + SI.I7: + combinedCode: SI.I7 + code: I7 + SI.66: + combinedCode: SI.66 + code: '66' + SI.88: + combinedCode: SI.88 + code: '88' + SI.D8: + combinedCode: SI.D8 + code: D8 + SI.C1: + combinedCode: SI.C1 + code: C1 + SI.37: + combinedCode: SI.37 + code: '37' + SI.09: + combinedCode: SI.09 + code: '09' + SI.05: + combinedCode: SI.05 + code: '05' + SI.E1: + combinedCode: SI.E1 + code: E1 + SI.49: + combinedCode: SI.49 + code: '49' + SI.J5: + combinedCode: SI.J5 + code: J5 + SI.07: + combinedCode: SI.07 + code: '07' + SI.44: + combinedCode: SI.44 + code: '44' + SI.F2: + combinedCode: SI.F2 + code: F2 + SI.14: + combinedCode: SI.14 + code: '14' + SI.F1: + combinedCode: SI.F1 + code: F1 + SI.27: + combinedCode: SI.27 + code: '27' + SI.G4: + combinedCode: SI.G4 + code: G4 + SI.46: + combinedCode: SI.46 + code: '46' + SI.06: + combinedCode: SI.06 + code: '06' + SI.04: + combinedCode: SI.04 + code: '04' + SI.03: + combinedCode: SI.03 + code: '03' + SI.82: + combinedCode: SI.82 + code: '82' + SI.53: + combinedCode: SI.53 + code: '53' + SI.K5: + combinedCode: SI.K5 + code: K5 + SI.12: + combinedCode: SI.12 + code: '12' + SI.B2: + combinedCode: SI.B2 + code: B2 + SI.E3: + combinedCode: SI.E3 + code: E3 + SI.71: + combinedCode: SI.71 + code: '71' + SI.72: + combinedCode: SI.72 + code: '72' + SI.22: + combinedCode: SI.22 + code: '22' + SI.77: + combinedCode: SI.77 + code: '77' + SI.30: + combinedCode: SI.30 + code: '30' + SI.I9: + combinedCode: SI.I9 + code: I9 + SI.K8: + combinedCode: SI.K8 + code: K8 + SI.74: + combinedCode: SI.74 + code: '74' + SI.81: + combinedCode: SI.81 + code: '81' + SI.E6: + combinedCode: SI.E6 + code: E6 + SI.16: + combinedCode: SI.16 + code: '16' + SI.62: + combinedCode: SI.62 + code: '62' + SI.C7: + combinedCode: SI.C7 + code: C7 + SI.C6: + combinedCode: SI.C6 + code: C6 + SI.68: + combinedCode: SI.68 + code: '68' + SI.99: + combinedCode: SI.99 + code: '99' + SI.39: + combinedCode: SI.39 + code: '39' + SI.20: + combinedCode: SI.20 + code: '20' + SI.B1: + combinedCode: SI.B1 + code: B1 + SI.B4: + combinedCode: SI.B4 + code: B4 + SI.B8: + combinedCode: SI.B8 + code: B8 + SI.C9: + combinedCode: SI.C9 + code: C9 + SI.N3: + combinedCode: SI.N3 + code: N3 + SI.E2: + combinedCode: SI.E2 + code: E2 + SI.F3: + combinedCode: SI.F3 + code: F3 + SI.76: + combinedCode: SI.76 + code: '76' + SI.L3: + combinedCode: SI.L3 + code: L3 + SI.55: + combinedCode: SI.55 + code: '55' + SI.B3: + combinedCode: SI.B3 + code: B3 + SI.89: + combinedCode: SI.89 + code: '89' + SI.26: + combinedCode: SI.26 + code: '26' + SI.98: + combinedCode: SI.98 + code: '98' + SI.C8: + combinedCode: SI.C8 + code: C8 + SI.45: + combinedCode: SI.45 + code: '45' + SI.J1: + combinedCode: SI.J1 + code: J1 + SI.N2: + combinedCode: SI.N2 + code: N2 + SI.A7: + combinedCode: SI.A7 + code: A7 + SI.A8: + combinedCode: SI.A8 + code: A8 + SI.92: + combinedCode: SI.92 + code: '92' + SI.51: + combinedCode: SI.51 + code: '51' + SI.28: + combinedCode: SI.28 + code: '28' + SI.E9: + combinedCode: SI.E9 + code: E9 + SI.24: + combinedCode: SI.24 + code: '24' + SI.42: + combinedCode: SI.42 + code: '42' + SI.D1: + combinedCode: SI.D1 + code: D1 + SI.A1: + combinedCode: SI.A1 + code: A1 + SI.97: + combinedCode: SI.97 + code: '97' + SI.A6: + combinedCode: SI.A6 + code: A6 + SI.I2: + combinedCode: SI.I2 + code: I2 + SI.31: + combinedCode: SI.31 + code: '31' + SI.78: + combinedCode: SI.78 + code: '78' + SI.47: + combinedCode: SI.47 + code: '47' + SI.02: + combinedCode: SI.02 + code: '02' + SI.D6: + combinedCode: SI.D6 + code: D6 + SI.86: + combinedCode: SI.86 + code: '86' + SI.15: + combinedCode: SI.15 + code: '15' + SI.83: + combinedCode: SI.83 + code: '83' + SI.61: + combinedCode: SI.61 + code: '61' + SI.N7: + combinedCode: SI.N7 + code: N7 + SI.H5: + combinedCode: SI.H5 + code: H5 + SI.M2: + combinedCode: SI.M2 + code: M2 + SI.H8: + combinedCode: SI.H8 + code: H8 + SI.H3: + combinedCode: SI.H3 + code: H3 + SI.L6: + combinedCode: SI.L6 + code: L6 + SI.F6: + combinedCode: SI.F6 + code: F6 + SI.M1: + combinedCode: SI.M1 + code: M1 + SI.M8: + combinedCode: SI.M8 + code: M8 + SI.K6: + combinedCode: SI.K6 + code: K6 + SI.N4: + combinedCode: SI.N4 + code: N4 + SI.M5: + combinedCode: SI.M5 + code: M5 + SI.F7: + combinedCode: SI.F7 + code: F7 + SI.K3: + combinedCode: SI.K3 + code: K3 + SI.K4: + combinedCode: SI.K4 + code: K4 + SI.H9: + combinedCode: SI.H9 + code: H9 + SI.N8: + combinedCode: SI.N8 + code: N8 + SI.G6: + combinedCode: SI.G6 + code: G6 + SI.J6: + combinedCode: SI.J6 + code: J6 + SI.F5: + combinedCode: SI.F5 + code: F5 + SI.G2: + combinedCode: SI.G2 + code: G2 + SI.G3: + combinedCode: SI.G3 + code: G3 + SI.J8: + combinedCode: SI.J8 + code: J8 + SI.K2: + combinedCode: SI.K2 + code: K2 + SI.L2: + combinedCode: SI.L2 + code: L2 + SI.I8: + combinedCode: SI.I8 + code: I8 + SI.L5: + combinedCode: SI.L5 + code: L5 + SI.H1: + combinedCode: SI.H1 + code: H1 + SI.J4: + combinedCode: SI.J4 + code: J4 + SI.G9: + combinedCode: SI.G9 + code: G9 + SI.N6: + combinedCode: SI.N6 + code: N6 + SI.K1: + combinedCode: SI.K1 + code: K1 + SI.J3: + combinedCode: SI.J3 + code: J3 + SI.G1: + combinedCode: SI.G1 + code: G1 + SI.M7: + combinedCode: SI.M7 + code: M7 + SI.M4: + combinedCode: SI.M4 + code: M4 + SI.F9: + combinedCode: SI.F9 + code: F9 + SI.F4: + combinedCode: SI.F4 + code: F4 + SI.M3: + combinedCode: SI.M3 + code: M3 + SI.I1: + combinedCode: SI.I1 + code: I1 + SI.N1: + combinedCode: SI.N1 + code: N1 + SI.M9: + combinedCode: SI.M9 + code: M9 + SI.I4: + combinedCode: SI.I4 + code: I4 + SI.G5: + combinedCode: SI.G5 + code: G5 + SI.M6: + combinedCode: SI.M6 + code: M6 + SI.F8: + combinedCode: SI.F8 + code: F8 + SI.G8: + combinedCode: SI.G8 + code: G8 + SI.H2: + combinedCode: SI.H2 + code: H2 + SI.K9: + combinedCode: SI.K9 + code: K9 + SI.L9: + combinedCode: SI.L9 + code: L9 + SI.L4: + combinedCode: SI.L4 + code: L4 + SI.N9: + combinedCode: SI.N9 + code: N9 + SI.O1: + combinedCode: SI.O1 + code: O1 + SI.O3: + combinedCode: SI.O3 + code: O3 + SI.O4: + combinedCode: SI.O4 + code: O4 + SI.O5: + combinedCode: SI.O5 + code: O5 + SI.O7: + combinedCode: SI.O7 + code: O7 + SI.O8: + combinedCode: SI.O8 + code: O8 + SI.O9: + combinedCode: SI.O9 + code: O9 + SI.P1: + combinedCode: SI.P1 + code: P1 + SI.P4: + combinedCode: SI.P4 + code: P4 + SI.P5: + combinedCode: SI.P5 + code: P5 + SI.P6: + combinedCode: SI.P6 + code: P6 + SI.P8: + combinedCode: SI.P8 + code: P8 + SI.P2: + combinedCode: SI.P2 + code: P2 + SI.P3: + combinedCode: SI.P3 + code: P3 + SI.P7: + combinedCode: SI.P7 + code: P7 +SJ: + iso2Code: SJ + iso3Code: SJM + regions: + SJ.22: + combinedCode: SJ.22 + code: '22' + SJ.21: + combinedCode: SJ.21 + code: '21' +SK: + iso2Code: SK + iso3Code: SVK + regions: + SK.03: + combinedCode: SK.03 + code: '03' + SK.05: + combinedCode: SK.05 + code: '05' + SK.08: + combinedCode: SK.08 + code: '08' + SK.01: + combinedCode: SK.01 + code: '01' + SK.02: + combinedCode: SK.02 + code: '02' + SK.04: + combinedCode: SK.04 + code: '04' + SK.06: + combinedCode: SK.06 + code: '06' + SK.07: + combinedCode: SK.07 + code: '07' +SL: + iso2Code: SL + iso3Code: SLE + regions: + SL.04: + combinedCode: SL.04 + code: '04' + SL.03: + combinedCode: SL.03 + code: '03' + SL.02: + combinedCode: SL.02 + code: '02' + SL.01: + combinedCode: SL.01 + code: '01' +SM: + iso2Code: SM + iso3Code: SMR + regions: + SM.09: + combinedCode: SM.09 + code: '09' + SM.02: + combinedCode: SM.02 + code: '02' + SM.07: + combinedCode: SM.07 + code: '07' + SM.01: + combinedCode: SM.01 + code: '01' + SM.06: + combinedCode: SM.06 + code: '06' + SM.03: + combinedCode: SM.03 + code: '03' + SM.04: + combinedCode: SM.04 + code: '04' + SM.05: + combinedCode: SM.05 + code: '05' + SM.08: + combinedCode: SM.08 + code: '08' +SN: + iso2Code: SN + iso3Code: SEN + regions: + SN.12: + combinedCode: SN.12 + code: '12' + SN.07: + combinedCode: SN.07 + code: '07' + SN.05: + combinedCode: SN.05 + code: '05' + SN.14: + combinedCode: SN.14 + code: '14' + SN.15: + combinedCode: SN.15 + code: '15' + SN.13: + combinedCode: SN.13 + code: '13' + SN.11: + combinedCode: SN.11 + code: '11' + SN.10: + combinedCode: SN.10 + code: '10' + SN.09: + combinedCode: SN.09 + code: '09' + SN.03: + combinedCode: SN.03 + code: '03' + SN.01: + combinedCode: SN.01 + code: '01' + SN.16: + combinedCode: SN.16 + code: '16' + SN.17: + combinedCode: SN.17 + code: '17' + SN.18: + combinedCode: SN.18 + code: '18' +SO: + iso2Code: SO + iso3Code: SOM + regions: + SO.20: + combinedCode: SO.20 + code: '20' + SO.19: + combinedCode: SO.19 + code: '19' + SO.14: + combinedCode: SO.14 + code: '14' + SO.13: + combinedCode: SO.13 + code: '13' + SO.12: + combinedCode: SO.12 + code: '12' + SO.18: + combinedCode: SO.18 + code: '18' + SO.10: + combinedCode: SO.10 + code: '10' + SO.09: + combinedCode: SO.09 + code: '09' + SO.08: + combinedCode: SO.08 + code: '08' + SO.07: + combinedCode: SO.07 + code: '07' + SO.06: + combinedCode: SO.06 + code: '06' + SO.05: + combinedCode: SO.05 + code: '05' + SO.04: + combinedCode: SO.04 + code: '04' + SO.03: + combinedCode: SO.03 + code: '03' + SO.02: + combinedCode: SO.02 + code: '02' + SO.01: + combinedCode: SO.01 + code: '01' + SO.21: + combinedCode: SO.21 + code: '21' + SO.22: + combinedCode: SO.22 + code: '22' +SR: + iso2Code: SR + iso3Code: SUR + regions: + SR.19: + combinedCode: SR.19 + code: '19' + SR.18: + combinedCode: SR.18 + code: '18' + SR.17: + combinedCode: SR.17 + code: '17' + SR.16: + combinedCode: SR.16 + code: '16' + SR.15: + combinedCode: SR.15 + code: '15' + SR.14: + combinedCode: SR.14 + code: '14' + SR.13: + combinedCode: SR.13 + code: '13' + SR.12: + combinedCode: SR.12 + code: '12' + SR.11: + combinedCode: SR.11 + code: '11' + SR.10: + combinedCode: SR.10 + code: '10' +ST: + iso2Code: ST + iso3Code: STP + regions: + ST.02: + combinedCode: ST.02 + code: '02' + ST.01: + combinedCode: ST.01 + code: '01' +SV: + iso2Code: SV + iso3Code: SLV + regions: + SV.14: + combinedCode: SV.14 + code: '14' + SV.13: + combinedCode: SV.13 + code: '13' + SV.12: + combinedCode: SV.12 + code: '12' + SV.11: + combinedCode: SV.11 + code: '11' + SV.10: + combinedCode: SV.10 + code: '10' + SV.09: + combinedCode: SV.09 + code: '09' + SV.08: + combinedCode: SV.08 + code: '08' + SV.07: + combinedCode: SV.07 + code: '07' + SV.06: + combinedCode: SV.06 + code: '06' + SV.05: + combinedCode: SV.05 + code: '05' + SV.04: + combinedCode: SV.04 + code: '04' + SV.03: + combinedCode: SV.03 + code: '03' + SV.02: + combinedCode: SV.02 + code: '02' + SV.01: + combinedCode: SV.01 + code: '01' +SX: + iso2Code: SX + iso3Code: SXM + regions: { } +SY: + iso2Code: SY + iso3Code: SYR + regions: + SY.14: + combinedCode: SY.14 + code: '14' + SY.13: + combinedCode: SY.13 + code: '13' + SY.12: + combinedCode: SY.12 + code: '12' + SY.11: + combinedCode: SY.11 + code: '11' + SY.10: + combinedCode: SY.10 + code: '10' + SY.09: + combinedCode: SY.09 + code: '09' + SY.08: + combinedCode: SY.08 + code: '08' + SY.07: + combinedCode: SY.07 + code: '07' + SY.06: + combinedCode: SY.06 + code: '06' + SY.05: + combinedCode: SY.05 + code: '05' + SY.04: + combinedCode: SY.04 + code: '04' + SY.03: + combinedCode: SY.03 + code: '03' + SY.02: + combinedCode: SY.02 + code: '02' + SY.01: + combinedCode: SY.01 + code: '01' +SZ: + iso2Code: SZ + iso3Code: SWZ + regions: + SZ.04: + combinedCode: SZ.04 + code: '04' + SZ.03: + combinedCode: SZ.03 + code: '03' + SZ.02: + combinedCode: SZ.02 + code: '02' + SZ.01: + combinedCode: SZ.01 + code: '01' +TC: + iso2Code: TC + iso3Code: TCA + regions: { } +TD: + iso2Code: TD + iso3Code: TCD + regions: + TD.13: + combinedCode: TD.13 + code: '13' + TD.12: + combinedCode: TD.12 + code: '12' + TD.02: + combinedCode: TD.02 + code: '02' + TD.14: + combinedCode: TD.14 + code: '14' + TD.17: + combinedCode: TD.17 + code: '17' + TD.16: + combinedCode: TD.16 + code: '16' + TD.09: + combinedCode: TD.09 + code: '09' + TD.08: + combinedCode: TD.08 + code: '08' + TD.07: + combinedCode: TD.07 + code: '07' + TD.06: + combinedCode: TD.06 + code: '06' + TD.05: + combinedCode: TD.05 + code: '05' + TD.15: + combinedCode: TD.15 + code: '15' + TD.01: + combinedCode: TD.01 + code: '01' + TD.23: + combinedCode: TD.23 + code: '23' + TD.18: + combinedCode: TD.18 + code: '18' + TD.19: + combinedCode: TD.19 + code: '19' + TD.20: + combinedCode: TD.20 + code: '20' + TD.21: + combinedCode: TD.21 + code: '21' + TD.22: + combinedCode: TD.22 + code: '22' + TD.24: + combinedCode: TD.24 + code: '24' + TD.25: + combinedCode: TD.25 + code: '25' + TD.26: + combinedCode: TD.26 + code: '26' +TF: + iso2Code: TF + iso3Code: ATF + regions: + TF.02: + combinedCode: TF.02 + code: '02' + TF.03: + combinedCode: TF.03 + code: '03' + TF.01: + combinedCode: TF.01 + code: '01' + TF.05: + combinedCode: TF.05 + code: '05' + TF.04: + combinedCode: TF.04 + code: '04' +TG: + iso2Code: TG + iso3Code: TGO + regions: + TG.26: + combinedCode: TG.26 + code: '26' + TG.25: + combinedCode: TG.25 + code: '25' + TG.24: + combinedCode: TG.24 + code: '24' + TG.22: + combinedCode: TG.22 + code: '22' + TG.23: + combinedCode: TG.23 + code: '23' +TH: + iso2Code: TH + iso3Code: THA + regions: + TH.15: + combinedCode: TH.15 + code: '15' + TH.65: + combinedCode: TH.65 + code: '65' + TH.08: + combinedCode: TH.08 + code: '08' + TH.60: + combinedCode: TH.60 + code: '60' + TH.09: + combinedCode: TH.09 + code: '09' + TH.52: + combinedCode: TH.52 + code: '52' + TH.59: + combinedCode: TH.59 + code: '59' + TH.57: + combinedCode: TH.57 + code: '57' + TH.62: + combinedCode: TH.62 + code: '62' + TH.56: + combinedCode: TH.56 + code: '56' + TH.61: + combinedCode: TH.61 + code: '61' + TH.01: + combinedCode: TH.01 + code: '01' + TH.05: + combinedCode: TH.05 + code: '05' + TH.06: + combinedCode: TH.06 + code: '06' + TH.63: + combinedCode: TH.63 + code: '63' + TH.50: + combinedCode: TH.50 + code: '50' + TH.11: + combinedCode: TH.11 + code: '11' + TH.58: + combinedCode: TH.58 + code: '58' + TH.03: + combinedCode: TH.03 + code: '03' + TH.02: + combinedCode: TH.02 + code: '02' + TH.72: + combinedCode: TH.72 + code: '72' + TH.70: + combinedCode: TH.70 + code: '70' + TH.10: + combinedCode: TH.10 + code: '10' + TH.49: + combinedCode: TH.49 + code: '49' + TH.29: + combinedCode: TH.29 + code: '29' + TH.51: + combinedCode: TH.51 + code: '51' + TH.68: + combinedCode: TH.68 + code: '68' + TH.30: + combinedCode: TH.30 + code: '30' + TH.33: + combinedCode: TH.33 + code: '33' + TH.67: + combinedCode: TH.67 + code: '67' + TH.37: + combinedCode: TH.37 + code: '37' + TH.54: + combinedCode: TH.54 + code: '54' + TH.55: + combinedCode: TH.55 + code: '55' + TH.42: + combinedCode: TH.42 + code: '42' + TH.20: + combinedCode: TH.20 + code: '20' + TH.25: + combinedCode: TH.25 + code: '25' + TH.47: + combinedCode: TH.47 + code: '47' + TH.36: + combinedCode: TH.36 + code: '36' + TH.07: + combinedCode: TH.07 + code: '07' + TH.12: + combinedCode: TH.12 + code: '12' + TH.13: + combinedCode: TH.13 + code: '13' + TH.14: + combinedCode: TH.14 + code: '14' + TH.41: + combinedCode: TH.41 + code: '41' + TH.66: + combinedCode: TH.66 + code: '66' + TH.69: + combinedCode: TH.69 + code: '69' + TH.39: + combinedCode: TH.39 + code: '39' + TH.38: + combinedCode: TH.38 + code: '38' + TH.17: + combinedCode: TH.17 + code: '17' + TH.31: + combinedCode: TH.31 + code: '31' + TH.04: + combinedCode: TH.04 + code: '04' + TH.64: + combinedCode: TH.64 + code: '64' + TH.16: + combinedCode: TH.16 + code: '16' + TH.27: + combinedCode: TH.27 + code: '27' + TH.73: + combinedCode: TH.73 + code: '73' + TH.53: + combinedCode: TH.53 + code: '53' + TH.43: + combinedCode: TH.43 + code: '43' + TH.78: + combinedCode: TH.78 + code: '78' + TH.24: + combinedCode: TH.24 + code: '24' + TH.34: + combinedCode: TH.34 + code: '34' + TH.18: + combinedCode: TH.18 + code: '18' + TH.40: + combinedCode: TH.40 + code: '40' + TH.22: + combinedCode: TH.22 + code: '22' + TH.23: + combinedCode: TH.23 + code: '23' + TH.46: + combinedCode: TH.46 + code: '46' + TH.48: + combinedCode: TH.48 + code: '48' + TH.26: + combinedCode: TH.26 + code: '26' + TH.32: + combinedCode: TH.32 + code: '32' + TH.44: + combinedCode: TH.44 + code: '44' + TH.28: + combinedCode: TH.28 + code: '28' + TH.35: + combinedCode: TH.35 + code: '35' + TH.76: + combinedCode: TH.76 + code: '76' + TH.74: + combinedCode: TH.74 + code: '74' + TH.75: + combinedCode: TH.75 + code: '75' + TH.77: + combinedCode: TH.77 + code: '77' + TH.79: + combinedCode: TH.79 + code: '79' + TH.80: + combinedCode: TH.80 + code: '80' + TH.81: + combinedCode: TH.81 + code: '81' +TJ: + iso2Code: TJ + iso3Code: TJK + regions: + TJ.03: + combinedCode: TJ.03 + code: '03' + TJ.01: + combinedCode: TJ.01 + code: '01' + TJ.02: + combinedCode: TJ.02 + code: '02' + TJ.RR: + combinedCode: TJ.RR + code: RR + TJ.7280679: + combinedCode: TJ.7280679 + code: '7280679' +TK: + iso2Code: TK + iso3Code: TKL + regions: + TK.N: + combinedCode: TK.N + code: N + TK.F: + combinedCode: TK.F + code: F + TK.A: + combinedCode: TK.A + code: A +TL: + iso2Code: TL + iso3Code: TLS + regions: + TL.VI: + combinedCode: TL.VI + code: VI + TL.MF: + combinedCode: TL.MF + code: MF + TL.MT: + combinedCode: TL.MT + code: MT + TL.LI: + combinedCode: TL.LI + code: LI + TL.LA: + combinedCode: TL.LA + code: LA + TL.CO: + combinedCode: TL.CO + code: CO + TL.ER: + combinedCode: TL.ER + code: ER + TL.DI: + combinedCode: TL.DI + code: DI + TL.BO: + combinedCode: TL.BO + code: BO + TL.BA: + combinedCode: TL.BA + code: BA + TL.OE: + combinedCode: TL.OE + code: OE + TL.AN: + combinedCode: TL.AN + code: AN + TL.AL: + combinedCode: TL.AL + code: AL +TM: + iso2Code: TM + iso3Code: TKM + regions: + TM.02: + combinedCode: TM.02 + code: '02' + TM.01: + combinedCode: TM.01 + code: '01' + TM.03: + combinedCode: TM.03 + code: '03' + TM.05: + combinedCode: TM.05 + code: '05' + TM.04: + combinedCode: TM.04 + code: '04' +TN: + iso2Code: TN + iso3Code: TUN + regions: + TN.37: + combinedCode: TN.37 + code: '37' + TN.36: + combinedCode: TN.36 + code: '36' + TN.35: + combinedCode: TN.35 + code: '35' + TN.34: + combinedCode: TN.34 + code: '34' + TN.23: + combinedCode: TN.23 + code: '23' + TN.22: + combinedCode: TN.22 + code: '22' + TN.33: + combinedCode: TN.33 + code: '33' + TN.32: + combinedCode: TN.32 + code: '32' + TN.31: + combinedCode: TN.31 + code: '31' + TN.30: + combinedCode: TN.30 + code: '30' + TN.29: + combinedCode: TN.29 + code: '29' + TN.19: + combinedCode: TN.19 + code: '19' + TN.28: + combinedCode: TN.28 + code: '28' + TN.06: + combinedCode: TN.06 + code: '06' + TN.27: + combinedCode: TN.27 + code: '27' + TN.18: + combinedCode: TN.18 + code: '18' + TN.17: + combinedCode: TN.17 + code: '17' + TN.38: + combinedCode: TN.38 + code: '38' + TN.03: + combinedCode: TN.03 + code: '03' + TN.02: + combinedCode: TN.02 + code: '02' + TN.16: + combinedCode: TN.16 + code: '16' + TN.15: + combinedCode: TN.15 + code: '15' + TN.14: + combinedCode: TN.14 + code: '14' + TN.39: + combinedCode: TN.39 + code: '39' +TO: + iso2Code: TO + iso3Code: TON + regions: + TO.03: + combinedCode: TO.03 + code: '03' + TO.02: + combinedCode: TO.02 + code: '02' + TO.01: + combinedCode: TO.01 + code: '01' + TO.EU: + combinedCode: TO.EU + code: EU + TO.NI: + combinedCode: TO.NI + code: NI +TR: + iso2Code: TR + iso3Code: TUR + regions: + TR.66: + combinedCode: TR.66 + code: '66' + TR.65: + combinedCode: TR.65 + code: '65' + TR.64: + combinedCode: TR.64 + code: '64' + TR.63: + combinedCode: TR.63 + code: '63' + TR.62: + combinedCode: TR.62 + code: '62' + TR.58: + combinedCode: TR.58 + code: '58' + TR.74: + combinedCode: TR.74 + code: '74' + TR.73: + combinedCode: TR.73 + code: '73' + TR.50: + combinedCode: TR.50 + code: '50' + TR.49: + combinedCode: TR.49 + code: '49' + TR.48: + combinedCode: TR.48 + code: '48' + TR.72: + combinedCode: TR.72 + code: '72' + TR.45: + combinedCode: TR.45 + code: '45' + TR.44: + combinedCode: TR.44 + code: '44' + TR.43: + combinedCode: TR.43 + code: '43' + TR.71: + combinedCode: TR.71 + code: '71' + TR.40: + combinedCode: TR.40 + code: '40' + TR.38: + combinedCode: TR.38 + code: '38' + TR.46: + combinedCode: TR.46 + code: '46' + TR.35: + combinedCode: TR.35 + code: '35' + TR.33: + combinedCode: TR.33 + code: '33' + TR.32: + combinedCode: TR.32 + code: '32' + TR.31: + combinedCode: TR.31 + code: '31' + TR.70: + combinedCode: TR.70 + code: '70' + TR.83: + combinedCode: TR.83 + code: '83' + TR.26: + combinedCode: TR.26 + code: '26' + TR.25: + combinedCode: TR.25 + code: '25' + TR.24: + combinedCode: TR.24 + code: '24' + TR.23: + combinedCode: TR.23 + code: '23' + TR.21: + combinedCode: TR.21 + code: '21' + TR.20: + combinedCode: TR.20 + code: '20' + TR.15: + combinedCode: TR.15 + code: '15' + TR.13: + combinedCode: TR.13 + code: '13' + TR.12: + combinedCode: TR.12 + code: '12' + TR.11: + combinedCode: TR.11 + code: '11' + TR.10: + combinedCode: TR.10 + code: '10' + TR.09: + combinedCode: TR.09 + code: '09' + TR.07: + combinedCode: TR.07 + code: '07' + TR.68: + combinedCode: TR.68 + code: '68' + TR.04: + combinedCode: TR.04 + code: '04' + TR.03: + combinedCode: TR.03 + code: '03' + TR.02: + combinedCode: TR.02 + code: '02' + TR.81: + combinedCode: TR.81 + code: '81' + TR.91: + combinedCode: TR.91 + code: '91' + TR.88: + combinedCode: TR.88 + code: '88' + TR.75: + combinedCode: TR.75 + code: '75' + TR.76: + combinedCode: TR.76 + code: '76' + TR.78: + combinedCode: TR.78 + code: '78' + TR.79: + combinedCode: TR.79 + code: '79' + TR.80: + combinedCode: TR.80 + code: '80' + TR.90: + combinedCode: TR.90 + code: '90' + TR.85: + combinedCode: TR.85 + code: '85' + TR.61: + combinedCode: TR.61 + code: '61' + TR.60: + combinedCode: TR.60 + code: '60' + TR.59: + combinedCode: TR.59 + code: '59' + TR.57: + combinedCode: TR.57 + code: '57' + TR.55: + combinedCode: TR.55 + code: '55' + TR.54: + combinedCode: TR.54 + code: '54' + TR.53: + combinedCode: TR.53 + code: '53' + TR.52: + combinedCode: TR.52 + code: '52' + TR.41: + combinedCode: TR.41 + code: '41' + TR.39: + combinedCode: TR.39 + code: '39' + TR.37: + combinedCode: TR.37 + code: '37' + TR.84: + combinedCode: TR.84 + code: '84' + TR.34: + combinedCode: TR.34 + code: '34' + TR.69: + combinedCode: TR.69 + code: '69' + TR.28: + combinedCode: TR.28 + code: '28' + TR.22: + combinedCode: TR.22 + code: '22' + TR.19: + combinedCode: TR.19 + code: '19' + TR.82: + combinedCode: TR.82 + code: '82' + TR.17: + combinedCode: TR.17 + code: '17' + TR.16: + combinedCode: TR.16 + code: '16' + TR.14: + combinedCode: TR.14 + code: '14' + TR.08: + combinedCode: TR.08 + code: '08' + TR.05: + combinedCode: TR.05 + code: '05' + TR.87: + combinedCode: TR.87 + code: '87' + TR.89: + combinedCode: TR.89 + code: '89' + TR.92: + combinedCode: TR.92 + code: '92' + TR.86: + combinedCode: TR.86 + code: '86' + TR.77: + combinedCode: TR.77 + code: '77' + TR.93: + combinedCode: TR.93 + code: '93' +TT: + iso2Code: TT + iso3Code: TTO + regions: + TT.11: + combinedCode: TT.11 + code: '11' + TT.10: + combinedCode: TT.10 + code: '10' + TT.05: + combinedCode: TT.05 + code: '05' + TT.03: + combinedCode: TT.03 + code: '03' + TT.01: + combinedCode: TT.01 + code: '01' + TT.CHA: + combinedCode: TT.CHA + code: CHA + TT.CTT: + combinedCode: TT.CTT + code: CTT + TT.DMN: + combinedCode: TT.DMN + code: DMN + TT.ETO: + combinedCode: TT.ETO + code: ETO + TT.PED: + combinedCode: TT.PED + code: PED + TT.PRT: + combinedCode: TT.PRT + code: PRT + TT.PTF: + combinedCode: TT.PTF + code: PTF + TT.SGE: + combinedCode: TT.SGE + code: SGE + TT.SIP: + combinedCode: TT.SIP + code: SIP + TT.SJL: + combinedCode: TT.SJL + code: SJL + TT.TUP: + combinedCode: TT.TUP + code: TUP +TV: + iso2Code: TV + iso3Code: TUV + regions: + TV.NUI: + combinedCode: TV.NUI + code: NUI + TV.NMA: + combinedCode: TV.NMA + code: NMA + TV.FUN: + combinedCode: TV.FUN + code: FUN + TV.NIT: + combinedCode: TV.NIT + code: NIT + TV.NMG: + combinedCode: TV.NMG + code: NMG + TV.VAI: + combinedCode: TV.VAI + code: VAI + TV.NKF: + combinedCode: TV.NKF + code: NKF + TV.NKL: + combinedCode: TV.NKL + code: NKL +TW: + iso2Code: TW + iso3Code: TWN + regions: + TW.01: + combinedCode: TW.01 + code: '01' + TW.02: + combinedCode: TW.02 + code: '02' + TW.03: + combinedCode: TW.03 + code: '03' + TW.04: + combinedCode: TW.04 + code: '04' +TZ: + iso2Code: TZ + iso3Code: TZA + regions: + TZ.19: + combinedCode: TZ.19 + code: '19' + TZ.25: + combinedCode: TZ.25 + code: '25' + TZ.22: + combinedCode: TZ.22 + code: '22' + TZ.21: + combinedCode: TZ.21 + code: '21' + TZ.18: + combinedCode: TZ.18 + code: '18' + TZ.17: + combinedCode: TZ.17 + code: '17' + TZ.16: + combinedCode: TZ.16 + code: '16' + TZ.15: + combinedCode: TZ.15 + code: '15' + TZ.24: + combinedCode: TZ.24 + code: '24' + TZ.02: + combinedCode: TZ.02 + code: '02' + TZ.20: + combinedCode: TZ.20 + code: '20' + TZ.13: + combinedCode: TZ.13 + code: '13' + TZ.12: + combinedCode: TZ.12 + code: '12' + TZ.10: + combinedCode: TZ.10 + code: '10' + TZ.09: + combinedCode: TZ.09 + code: '09' + TZ.08: + combinedCode: TZ.08 + code: '08' + TZ.07: + combinedCode: TZ.07 + code: '07' + TZ.06: + combinedCode: TZ.06 + code: '06' + TZ.05: + combinedCode: TZ.05 + code: '05' + TZ.04: + combinedCode: TZ.04 + code: '04' + TZ.03: + combinedCode: TZ.03 + code: '03' + TZ.23: + combinedCode: TZ.23 + code: '23' + TZ.26: + combinedCode: TZ.26 + code: '26' + TZ.27: + combinedCode: TZ.27 + code: '27' + TZ.14: + combinedCode: TZ.14 + code: '14' + TZ.11: + combinedCode: TZ.11 + code: '11' + TZ.31: + combinedCode: TZ.31 + code: '31' + TZ.28: + combinedCode: TZ.28 + code: '28' + TZ.29: + combinedCode: TZ.29 + code: '29' + TZ.30: + combinedCode: TZ.30 + code: '30' +UA: + iso2Code: UA + iso3Code: UKR + regions: + UA.27: + combinedCode: UA.27 + code: '27' + UA.26: + combinedCode: UA.26 + code: '26' + UA.25: + combinedCode: UA.25 + code: '25' + UA.24: + combinedCode: UA.24 + code: '24' + UA.23: + combinedCode: UA.23 + code: '23' + UA.22: + combinedCode: UA.22 + code: '22' + UA.21: + combinedCode: UA.21 + code: '21' + UA.20: + combinedCode: UA.20 + code: '20' + UA.19: + combinedCode: UA.19 + code: '19' + UA.18: + combinedCode: UA.18 + code: '18' + UA.17: + combinedCode: UA.17 + code: '17' + UA.16: + combinedCode: UA.16 + code: '16' + UA.15: + combinedCode: UA.15 + code: '15' + UA.14: + combinedCode: UA.14 + code: '14' + UA.13: + combinedCode: UA.13 + code: '13' + UA.12: + combinedCode: UA.12 + code: '12' + UA.11: + combinedCode: UA.11 + code: '11' + UA.10: + combinedCode: UA.10 + code: '10' + UA.09: + combinedCode: UA.09 + code: '09' + UA.08: + combinedCode: UA.08 + code: '08' + UA.07: + combinedCode: UA.07 + code: '07' + UA.06: + combinedCode: UA.06 + code: '06' + UA.05: + combinedCode: UA.05 + code: '05' + UA.04: + combinedCode: UA.04 + code: '04' + UA.03: + combinedCode: UA.03 + code: '03' + UA.02: + combinedCode: UA.02 + code: '02' + UA.01: + combinedCode: UA.01 + code: '01' +UG: + iso2Code: UG + iso3Code: UGA + regions: + UG.C: + combinedCode: UG.C + code: C + UG.E: + combinedCode: UG.E + code: E + UG.N: + combinedCode: UG.N + code: N + UG.W: + combinedCode: UG.W + code: W +UM: + iso2Code: UM + iso3Code: UMI + regions: + UM.450: + combinedCode: UM.450 + code: '450' + UM.350: + combinedCode: UM.350 + code: '350' + UM.050: + combinedCode: UM.050 + code: '050' + UM.100: + combinedCode: UM.100 + code: '100' + UM.150: + combinedCode: UM.150 + code: '150' + UM.200: + combinedCode: UM.200 + code: '200' + UM.250: + combinedCode: UM.250 + code: '250' + UM.300: + combinedCode: UM.300 + code: '300' + UM.400: + combinedCode: UM.400 + code: '400' +US: + iso2Code: US + iso3Code: USA + regions: + US.AR: + combinedCode: US.AR + code: AR + US.DC: + combinedCode: US.DC + code: DC + US.DE: + combinedCode: US.DE + code: DE + US.FL: + combinedCode: US.FL + code: FL + US.GA: + combinedCode: US.GA + code: GA + US.KS: + combinedCode: US.KS + code: KS + US.LA: + combinedCode: US.LA + code: LA + US.MD: + combinedCode: US.MD + code: MD + US.MO: + combinedCode: US.MO + code: MO + US.MS: + combinedCode: US.MS + code: MS + US.NC: + combinedCode: US.NC + code: NC + US.OK: + combinedCode: US.OK + code: OK + US.SC: + combinedCode: US.SC + code: SC + US.TN: + combinedCode: US.TN + code: TN + US.TX: + combinedCode: US.TX + code: TX + US.WV: + combinedCode: US.WV + code: WV + US.AL: + combinedCode: US.AL + code: AL + US.CT: + combinedCode: US.CT + code: CT + US.IA: + combinedCode: US.IA + code: IA + US.IL: + combinedCode: US.IL + code: IL + US.IN: + combinedCode: US.IN + code: IN + US.ME: + combinedCode: US.ME + code: ME + US.MI: + combinedCode: US.MI + code: MI + US.MN: + combinedCode: US.MN + code: MN + US.NE: + combinedCode: US.NE + code: NE + US.NH: + combinedCode: US.NH + code: NH + US.NJ: + combinedCode: US.NJ + code: NJ + US.NY: + combinedCode: US.NY + code: NY + US.OH: + combinedCode: US.OH + code: OH + US.RI: + combinedCode: US.RI + code: RI + US.VT: + combinedCode: US.VT + code: VT + US.WI: + combinedCode: US.WI + code: WI + US.CA: + combinedCode: US.CA + code: CA + US.CO: + combinedCode: US.CO + code: CO + US.NM: + combinedCode: US.NM + code: NM + US.NV: + combinedCode: US.NV + code: NV + US.UT: + combinedCode: US.UT + code: UT + US.AZ: + combinedCode: US.AZ + code: AZ + US.ID: + combinedCode: US.ID + code: ID + US.MT: + combinedCode: US.MT + code: MT + US.ND: + combinedCode: US.ND + code: ND + US.OR: + combinedCode: US.OR + code: OR + US.SD: + combinedCode: US.SD + code: SD + US.WA: + combinedCode: US.WA + code: WA + US.WY: + combinedCode: US.WY + code: WY + US.HI: + combinedCode: US.HI + code: HI + US.AK: + combinedCode: US.AK + code: AK + US.KY: + combinedCode: US.KY + code: KY + US.MA: + combinedCode: US.MA + code: MA + US.PA: + combinedCode: US.PA + code: PA + US.VA: + combinedCode: US.VA + code: VA +UY: + iso2Code: UY + iso3Code: URY + regions: + UY.19: + combinedCode: UY.19 + code: '19' + UY.18: + combinedCode: UY.18 + code: '18' + UY.17: + combinedCode: UY.17 + code: '17' + UY.16: + combinedCode: UY.16 + code: '16' + UY.15: + combinedCode: UY.15 + code: '15' + UY.14: + combinedCode: UY.14 + code: '14' + UY.13: + combinedCode: UY.13 + code: '13' + UY.12: + combinedCode: UY.12 + code: '12' + UY.11: + combinedCode: UY.11 + code: '11' + UY.10: + combinedCode: UY.10 + code: '10' + UY.09: + combinedCode: UY.09 + code: '09' + UY.08: + combinedCode: UY.08 + code: '08' + UY.07: + combinedCode: UY.07 + code: '07' + UY.06: + combinedCode: UY.06 + code: '06' + UY.05: + combinedCode: UY.05 + code: '05' + UY.04: + combinedCode: UY.04 + code: '04' + UY.03: + combinedCode: UY.03 + code: '03' + UY.02: + combinedCode: UY.02 + code: '02' + UY.01: + combinedCode: UY.01 + code: '01' +UZ: + iso2Code: UZ + iso3Code: UZB + regions: + UZ.09: + combinedCode: UZ.09 + code: '09' + UZ.12: + combinedCode: UZ.12 + code: '12' + UZ.10: + combinedCode: UZ.10 + code: '10' + UZ.08: + combinedCode: UZ.08 + code: '08' + UZ.02: + combinedCode: UZ.02 + code: '02' + UZ.14: + combinedCode: UZ.14 + code: '14' + UZ.13: + combinedCode: UZ.13 + code: '13' + UZ.16: + combinedCode: UZ.16 + code: '16' + UZ.07: + combinedCode: UZ.07 + code: '07' + UZ.06: + combinedCode: UZ.06 + code: '06' + UZ.05: + combinedCode: UZ.05 + code: '05' + UZ.15: + combinedCode: UZ.15 + code: '15' + UZ.03: + combinedCode: UZ.03 + code: '03' + UZ.01: + combinedCode: UZ.01 + code: '01' +VA: + iso2Code: VA + iso3Code: VAT + regions: { } +VC: + iso2Code: VC + iso3Code: VCT + regions: + VC.05: + combinedCode: VC.05 + code: '05' + VC.04: + combinedCode: VC.04 + code: '04' + VC.03: + combinedCode: VC.03 + code: '03' + VC.02: + combinedCode: VC.02 + code: '02' + VC.06: + combinedCode: VC.06 + code: '06' + VC.01: + combinedCode: VC.01 + code: '01' +VE: + iso2Code: VE + iso3Code: VEN + regions: + VE.23: + combinedCode: VE.23 + code: '23' + VE.22: + combinedCode: VE.22 + code: '22' + VE.21: + combinedCode: VE.21 + code: '21' + VE.20: + combinedCode: VE.20 + code: '20' + VE.19: + combinedCode: VE.19 + code: '19' + VE.18: + combinedCode: VE.18 + code: '18' + VE.17: + combinedCode: VE.17 + code: '17' + VE.16: + combinedCode: VE.16 + code: '16' + VE.15: + combinedCode: VE.15 + code: '15' + VE.14: + combinedCode: VE.14 + code: '14' + VE.13: + combinedCode: VE.13 + code: '13' + VE.12: + combinedCode: VE.12 + code: '12' + VE.24: + combinedCode: VE.24 + code: '24' + VE.25: + combinedCode: VE.25 + code: '25' + VE.11: + combinedCode: VE.11 + code: '11' + VE.09: + combinedCode: VE.09 + code: '09' + VE.08: + combinedCode: VE.08 + code: '08' + VE.07: + combinedCode: VE.07 + code: '07' + VE.06: + combinedCode: VE.06 + code: '06' + VE.05: + combinedCode: VE.05 + code: '05' + VE.04: + combinedCode: VE.04 + code: '04' + VE.03: + combinedCode: VE.03 + code: '03' + VE.02: + combinedCode: VE.02 + code: '02' + VE.01: + combinedCode: VE.01 + code: '01' + VE.26: + combinedCode: VE.26 + code: '26' +VG: + iso2Code: VG + iso3Code: VGB + regions: { } +VI: + iso2Code: VI + iso3Code: VIR + regions: + VI.010: + combinedCode: VI.010 + code: '010' + VI.020: + combinedCode: VI.020 + code: '020' + VI.030: + combinedCode: VI.030 + code: '030' +VN: + iso2Code: VN + iso3Code: VNM + regions: + VN.58: + combinedCode: VN.58 + code: '58' + VN.59: + combinedCode: VN.59 + code: '59' + VN.60: + combinedCode: VN.60 + code: '60' + VN.65: + combinedCode: VN.65 + code: '65' + VN.67: + combinedCode: VN.67 + code: '67' + VN.68: + combinedCode: VN.68 + code: '68' + VN.69: + combinedCode: VN.69 + code: '69' + VN.70: + combinedCode: VN.70 + code: '70' + VN.90: + combinedCode: VN.90 + code: '90' + VN.37: + combinedCode: VN.37 + code: '37' + VN.66: + combinedCode: VN.66 + code: '66' + VN.55: + combinedCode: VN.55 + code: '55' + VN.34: + combinedCode: VN.34 + code: '34' + VN.35: + combinedCode: VN.35 + code: '35' + VN.33: + combinedCode: VN.33 + code: '33' + VN.32: + combinedCode: VN.32 + code: '32' + VN.64: + combinedCode: VN.64 + code: '64' + VN.30: + combinedCode: VN.30 + code: '30' + VN.63: + combinedCode: VN.63 + code: '63' + VN.62: + combinedCode: VN.62 + code: '62' + VN.61: + combinedCode: VN.61 + code: '61' + VN.53: + combinedCode: VN.53 + code: '53' + VN.24: + combinedCode: VN.24 + code: '24' + VN.39: + combinedCode: VN.39 + code: '39' + VN.23: + combinedCode: VN.23 + code: '23' + VN.89: + combinedCode: VN.89 + code: '89' + VN.21: + combinedCode: VN.21 + code: '21' + VN.54: + combinedCode: VN.54 + code: '54' + VN.20: + combinedCode: VN.20 + code: '20' + VN.52: + combinedCode: VN.52 + code: '52' + VN.51: + combinedCode: VN.51 + code: '51' + VN.50: + combinedCode: VN.50 + code: '50' + VN.49: + combinedCode: VN.49 + code: '49' + VN.44: + combinedCode: VN.44 + code: '44' + VN.87: + combinedCode: VN.87 + code: '87' + VN.13: + combinedCode: VN.13 + code: '13' + VN.47: + combinedCode: VN.47 + code: '47' + VN.09: + combinedCode: VN.09 + code: '09' + VN.43: + combinedCode: VN.43 + code: '43' + VN.88: + combinedCode: VN.88 + code: '88' + VN.45: + combinedCode: VN.45 + code: '45' + VN.05: + combinedCode: VN.05 + code: '05' + VN.46: + combinedCode: VN.46 + code: '46' + VN.03: + combinedCode: VN.03 + code: '03' + VN.01: + combinedCode: VN.01 + code: '01' + VN.91: + combinedCode: VN.91 + code: '91' + VN.92: + combinedCode: VN.92 + code: '92' + VN.74: + combinedCode: VN.74 + code: '74' + VN.71: + combinedCode: VN.71 + code: '71' + VN.78: + combinedCode: VN.78 + code: '78' + VN.75: + combinedCode: VN.75 + code: '75' + VN.76: + combinedCode: VN.76 + code: '76' + VN.85: + combinedCode: VN.85 + code: '85' + VN.84: + combinedCode: VN.84 + code: '84' + VN.83: + combinedCode: VN.83 + code: '83' + VN.82: + combinedCode: VN.82 + code: '82' + VN.80: + combinedCode: VN.80 + code: '80' + VN.72: + combinedCode: VN.72 + code: '72' + VN.73: + combinedCode: VN.73 + code: '73' + VN.77: + combinedCode: VN.77 + code: '77' + VN.79: + combinedCode: VN.79 + code: '79' + VN.81: + combinedCode: VN.81 + code: '81' + VN.86: + combinedCode: VN.86 + code: '86' + VN.93: + combinedCode: VN.93 + code: '93' +VU: + iso2Code: VU + iso3Code: VUT + regions: + VU.15: + combinedCode: VU.15 + code: '15' + VU.13: + combinedCode: VU.13 + code: '13' + VU.07: + combinedCode: VU.07 + code: '07' + VU.16: + combinedCode: VU.16 + code: '16' + VU.17: + combinedCode: VU.17 + code: '17' + VU.18: + combinedCode: VU.18 + code: '18' +WF: + iso2Code: WF + iso3Code: WLF + regions: + WF.98613: + combinedCode: WF.98613 + code: '98613' + WF.98612: + combinedCode: WF.98612 + code: '98612' + WF.98611: + combinedCode: WF.98611 + code: '98611' +WS: + iso2Code: WS + iso3Code: WSM + regions: + WS.11: + combinedCode: WS.11 + code: '11' + WS.06: + combinedCode: WS.06 + code: '06' + WS.10: + combinedCode: WS.10 + code: '10' + WS.09: + combinedCode: WS.09 + code: '09' + WS.08: + combinedCode: WS.08 + code: '08' + WS.07: + combinedCode: WS.07 + code: '07' + WS.05: + combinedCode: WS.05 + code: '05' + WS.04: + combinedCode: WS.04 + code: '04' + WS.03: + combinedCode: WS.03 + code: '03' + WS.02: + combinedCode: WS.02 + code: '02' + WS.01: + combinedCode: WS.01 + code: '01' +YE: + iso2Code: YE + iso3Code: YEM + regions: + YE.25: + combinedCode: YE.25 + code: '25' + YE.05: + combinedCode: YE.05 + code: '05' + YE.16: + combinedCode: YE.16 + code: '16' + YE.15: + combinedCode: YE.15 + code: '15' + YE.27: + combinedCode: YE.27 + code: '27' + YE.14: + combinedCode: YE.14 + code: '14' + YE.10: + combinedCode: YE.10 + code: '10' + YE.21: + combinedCode: YE.21 + code: '21' + YE.04: + combinedCode: YE.04 + code: '04' + YE.11: + combinedCode: YE.11 + code: '11' + YE.03: + combinedCode: YE.03 + code: '03' + YE.08: + combinedCode: YE.08 + code: '08' + YE.20: + combinedCode: YE.20 + code: '20' + YE.02: + combinedCode: YE.02 + code: '02' + YE.01: + combinedCode: YE.01 + code: '01' + YE.18: + combinedCode: YE.18 + code: '18' + YE.19: + combinedCode: YE.19 + code: '19' + YE.22: + combinedCode: YE.22 + code: '22' + YE.23: + combinedCode: YE.23 + code: '23' + YE.24: + combinedCode: YE.24 + code: '24' + YE.26: + combinedCode: YE.26 + code: '26' +YT: + iso2Code: YT + iso3Code: MYT + regions: + YT.97601: + combinedCode: YT.97601 + code: '97601' + YT.97602: + combinedCode: YT.97602 + code: '97602' + YT.97603: + combinedCode: YT.97603 + code: '97603' + YT.97604: + combinedCode: YT.97604 + code: '97604' + YT.97605: + combinedCode: YT.97605 + code: '97605' + YT.97606: + combinedCode: YT.97606 + code: '97606' + YT.97607: + combinedCode: YT.97607 + code: '97607' + YT.97608: + combinedCode: YT.97608 + code: '97608' + YT.97609: + combinedCode: YT.97609 + code: '97609' + YT.97610: + combinedCode: YT.97610 + code: '97610' + YT.97611: + combinedCode: YT.97611 + code: '97611' + YT.97612: + combinedCode: YT.97612 + code: '97612' + YT.97613: + combinedCode: YT.97613 + code: '97613' + YT.97614: + combinedCode: YT.97614 + code: '97614' + YT.97615: + combinedCode: YT.97615 + code: '97615' + YT.97616: + combinedCode: YT.97616 + code: '97616' + YT.97617: + combinedCode: YT.97617 + code: '97617' +ZA: + iso2Code: ZA + iso3Code: ZAF + regions: + ZA.03: + combinedCode: ZA.03 + code: '03' + ZA.02: + combinedCode: ZA.02 + code: '02' + ZA.05: + combinedCode: ZA.05 + code: '05' + ZA.06: + combinedCode: ZA.06 + code: '06' + ZA.07: + combinedCode: ZA.07 + code: '07' + ZA.08: + combinedCode: ZA.08 + code: '08' + ZA.09: + combinedCode: ZA.09 + code: '09' + ZA.10: + combinedCode: ZA.10 + code: '10' + ZA.11: + combinedCode: ZA.11 + code: '11' +ZM: + iso2Code: ZM + iso3Code: ZMB + regions: + ZM.01: + combinedCode: ZM.01 + code: '01' + ZM.07: + combinedCode: ZM.07 + code: '07' + ZM.06: + combinedCode: ZM.06 + code: '06' + ZM.05: + combinedCode: ZM.05 + code: '05' + ZM.09: + combinedCode: ZM.09 + code: '09' + ZM.04: + combinedCode: ZM.04 + code: '04' + ZM.03: + combinedCode: ZM.03 + code: '03' + ZM.08: + combinedCode: ZM.08 + code: '08' + ZM.02: + combinedCode: ZM.02 + code: '02' +ZW: + iso2Code: ZW + iso3Code: ZWE + regions: + ZW.02: + combinedCode: ZW.02 + code: '02' + ZW.07: + combinedCode: ZW.07 + code: '07' + ZW.06: + combinedCode: ZW.06 + code: '06' + ZW.08: + combinedCode: ZW.08 + code: '08' + ZW.05: + combinedCode: ZW.05 + code: '05' + ZW.04: + combinedCode: ZW.04 + code: '04' + ZW.03: + combinedCode: ZW.03 + code: '03' + ZW.01: + combinedCode: ZW.01 + code: '01' + ZW.09: + combinedCode: ZW.09 + code: '09' + ZW.10: + combinedCode: ZW.10 + code: '10' +CS: + iso2Code: CS + iso3Code: SCG + regions: { } +AN: + iso2Code: AN + iso3Code: ANT + regions: { } diff --git a/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php b/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php index d4ea7250643..8a5b7b6afe0 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php +++ b/src/Oro/Bundle/AddressBundle/Entity/AddressBase.php @@ -7,6 +7,7 @@ use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap; use Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible; +use Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface; use Symfony\Component\Validator\ExecutionContext; /** @@ -50,15 +51,6 @@ class AddressBase extends AbstractEntityFlexible */ protected $city; - /** - * @var string - * - * @ORM\ManyToOne(targetEntity="Oro\Bundle\AddressBundle\Entity\Region", cascade={"persist"}) - * @ORM\JoinColumn(name="region_id", referencedColumnName="id") - * @Soap\ComplexType("string", nillable=true) - */ - protected $state; - /** * @var string * @@ -79,11 +71,20 @@ class AddressBase extends AbstractEntityFlexible * @var string * * @ORM\ManyToOne(targetEntity="Oro\Bundle\AddressBundle\Entity\Country", cascade={"persist"}) - * @ORM\JoinColumn(name="country_id", referencedColumnName="iso2_code") + * @ORM\JoinColumn(name="country_code", referencedColumnName="iso2_code") * @Soap\ComplexType("string", nillable=false) */ protected $country; + /** + * @var Region + * + * @ORM\ManyToOne(targetEntity="Oro\Bundle\AddressBundle\Entity\Region", cascade={"persist"}) + * @ORM\JoinColumn(name="region_code", referencedColumnName="combined_code") + * @Soap\ComplexType("string", nillable=true) + */ + protected $state; + /** * @var string * @@ -103,7 +104,7 @@ class AddressBase extends AbstractEntityFlexible /** * Get id * - * @return integer + * @return integer */ public function getId() { @@ -113,20 +114,20 @@ public function getId() /** * Set street * - * @param string $street + * @param string $street * @return AddressBase */ public function setStreet($street) { $this->street = $street; - + return $this; } /** * Get street * - * @return string + * @return string */ public function getStreet() { @@ -136,20 +137,20 @@ public function getStreet() /** * Set street2 * - * @param string $street2 + * @param string $street2 * @return AddressBase */ public function setStreet2($street2) { $this->street2 = $street2; - + return $this; } /** * Get street2 * - * @return string + * @return string */ public function getStreet2() { @@ -159,20 +160,20 @@ public function getStreet2() /** * Set city * - * @param string $city + * @param string $city * @return AddressBase */ public function setCity($city) { $this->city = $city; - + return $this; } /** * Get city * - * @return string + * @return string */ public function getCity() { @@ -188,7 +189,7 @@ public function getCity() public function setState($state) { $this->state = $state; - + return $this; } @@ -199,17 +200,13 @@ public function setState($state) */ public function getState() { - if (!empty($this->stateText)) { - return $this->stateText; - } else { - return $this->state; - } + return $this->state; } /** * Set state text * - * @param Region $stateText + * @param string $stateText * @return AddressBase */ public function setStateText($stateText) @@ -222,30 +219,44 @@ public function setStateText($stateText) /** * Get state test * - * @return Region + * @return string */ public function getStateText() { return $this->stateText; } + /** + * Get state + * + * @return Region|string + */ + public function getUniversalState() + { + if (!empty($this->stateText)) { + return $this->stateText; + } else { + return $this->state; + } + } + /** * Set postal_code * - * @param string $postalCode + * @param string $postalCode * @return AddressBase */ public function setPostalCode($postalCode) { $this->postalCode = $postalCode; - + return $this; } /** * Get postal_code * - * @return string + * @return string */ public function getPostalCode() { @@ -255,13 +266,13 @@ public function getPostalCode() /** * Set country * - * @param Country $country + * @param Country $country * @return AddressBase */ public function setCountry($country) { $this->country = $country; - + return $this; } @@ -380,11 +391,38 @@ public function __toString() $this->getStreet(), $this->getStreet2(), $this->getCity(), - $this->getState(), + $this->getUniversalState(), ',', $this->getCountry(), $this->getPostalCode(), ); - return implode(' ', $data); + + $str = implode(' ', $data); + $check = trim(str_replace(',', '', $str)); + return empty($check) ? '' : $str; + } + + /** + * Check if entity is empty. + * + * @return bool + */ + public function isEmpty() + { + $isEmpty = empty($this->firstName) + && empty($this->lastName) + && empty($this->street) + && empty($this->street2) + && empty($this->city) + && empty($this->state) + && empty($this->stateText) + && empty($this->country) + && empty($this->postalCode); + /** @var FlexibleValueInterface $value */ + foreach ($this->values as $value) { + $flexibleValue = $value->getData(); + $isEmpty = $isEmpty && empty($flexibleValue); + } + return $isEmpty; } } diff --git a/src/Oro/Bundle/AddressBundle/Entity/AddressType.php b/src/Oro/Bundle/AddressBundle/Entity/AddressType.php index c69b60616bb..11e368ec609 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/AddressType.php +++ b/src/Oro/Bundle/AddressBundle/Entity/AddressType.php @@ -24,7 +24,7 @@ class AddressType /** * @var string * - * @ORM\Column(name="type", type="string", length=255) + * @ORM\Column(name="type", type="string", length=255, unique=true) */ private $type; @@ -41,7 +41,7 @@ public function getId() /** * Set route * - * @param string $type + * @param string $type * @return AddressType */ public function setType($type) @@ -60,4 +60,12 @@ public function getType() { return $this->type; } + + /** + * @return string + */ + public function __toString() + { + return $this->type; + } } diff --git a/src/Oro/Bundle/AddressBundle/Entity/Country.php b/src/Oro/Bundle/AddressBundle/Entity/Country.php index d8792afcd76..d9ac5e6ce33 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Country.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Country.php @@ -3,8 +3,12 @@ namespace Oro\Bundle\AddressBundle\Entity; use JMS\Serializer\Annotation\Exclude; + use Doctrine\ORM\Mapping as ORM; use Doctrine\Common\Collections\ArrayCollection; +use Gedmo\Mapping\Annotation as Gedmo; +use Gedmo\Translatable\Translatable; + use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap; /** @@ -12,8 +16,9 @@ * * @ORM\Table("oro_dictionary_country") * @ORM\Entity + * @Gedmo\TranslationEntity(class="Oro\Bundle\AddressBundle\Entity\CountryTranslation") */ -class Country +class Country implements Translatable { /** * @var string @@ -35,29 +40,47 @@ class Country /** * @var string * - * @ORM\Column(name="name", type="string", length=100) + * @ORM\Column(name="name", type="string", length=255) * @Soap\ComplexType("string", nillable=true) + * @Gedmo\Translatable */ private $name; /** * @var ArrayCollection * - * @ORM\OneToMany(targetEntity="Region", mappedBy="country", cascade={"ALL"}, fetch="EXTRA_LAZY") + * @ORM\OneToMany( + * targetEntity="Oro\Bundle\AddressBundle\Entity\Region", + * mappedBy="country", + * cascade={"ALL"}, + * fetch="EXTRA_LAZY" + * ) * @Exclude */ private $regions; /** - * @param null|string $name - * @param null|string $iso2Code - * @param null|string $iso3Code + * @Gedmo\Locale */ - public function __construct($name = null, $iso2Code = null, $iso3Code = null) + private $locale; + + /** + * @param string $iso2Code ISO2 country code + */ + public function __construct($iso2Code) { - $this->setName($name); - $this->setIso2Code($iso2Code); - $this->setIso3Code($iso3Code); + $this->iso2Code = $iso2Code; + $this->regions = new ArrayCollection(); + } + + /** + * Get iso2_code + * + * @return string + */ + public function getIso2Code() + { + return $this->iso2Code; } /** @@ -81,55 +104,60 @@ public function getRegions() } /** - * Check if country contains regions - * - * @return bool + * @param Region $region + * @return Country */ - public function hasRegions() + public function addRegion(Region $region) { - return count($this->regions) > 0; + if (!$this->regions->contains($region)) { + $this->regions->add($region); + $region->setCountry($this); + } + + return $this; } /** - * Set iso2_code - * - * @param string $iso2Code + * @param Region $region * @return Country */ - public function setIso2Code($iso2Code) + public function removeRegion(Region $region) { - $this->iso2Code = $iso2Code; - + if ($this->regions->contains($region)) { + $this->regions->removeElement($region); + $region->setCountry(null); + } + return $this; } /** - * Get iso2_code + * Check if country contains regions * - * @return string + * @return bool */ - public function getIso2Code() + public function hasRegions() { - return $this->iso2Code; + return count($this->regions) > 0; } /** * Set iso3_code * - * @param string $iso3Code + * @param string $iso3Code * @return Country */ public function setIso3Code($iso3Code) { $this->iso3Code = $iso3Code; - + return $this; } /** * Get iso3_code * - * @return string + * @return string */ public function getIso3Code() { @@ -139,26 +167,49 @@ public function getIso3Code() /** * Set country name * - * @param string $name + * @param string $name * @return Country */ public function setName($name) { $this->name = $name; - + return $this; } /** * Get country name * - * @return string + * @return string */ public function getName() { return $this->name; } + /** + * Set locale + * + * @param string $locale + * @return Country + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + /** + * Returns locale code + * + * @return mixed + */ + public function getLocale() + { + return $this->locale; + } + /** * @return string */ diff --git a/src/Oro/Bundle/AddressBundle/Entity/CountryTranslation.php b/src/Oro/Bundle/AddressBundle/Entity/CountryTranslation.php new file mode 100644 index 00000000000..2f7ec0427fd --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Entity/CountryTranslation.php @@ -0,0 +1,24 @@ +fm->getFlexibleRepository(); + return $repository->findByWithAttributesQB(array(), null, array('id' => 'ASC'), $limit, $offset); } /** * Provide proxy method calls to flexible manager * - * @param string $name - * @param array $args + * @param string $name + * @param array $args * @return mixed * @throws \RuntimeException */ diff --git a/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php b/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php index 33098eaaa5d..8b38822f95d 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Manager/AddressTypeManager.php @@ -25,8 +25,8 @@ class AddressTypeManager /** * Constructor * - * @param string $class Entity name - * @param ObjectManager $om Object manager + * @param string $class Entity name + * @param ObjectManager $om Object manager */ public function __construct($class, ObjectManager $om) { @@ -76,7 +76,7 @@ public function deleteAddressType(AddressType $addressType) /** * Finds one address type by the given criteria * - * @param array $criteria + * @param array $criteria * @return AddressType */ public function findAddressTypeBy(array $criteria) diff --git a/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php b/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php index 2b99a5f0efd..c0b8759ee3b 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Manager/StorageInterface.php @@ -16,8 +16,8 @@ public function createAddress(); /** * Updates an address * - * @param AddressBase $address - * @param bool $flush Whether to flush the changes (default true) + * @param AddressBase $address + * @param bool $flush Whether to flush the changes (default true) * @throws \RuntimeException */ public function updateAddress(AddressBase $address, $flush = true); @@ -32,7 +32,7 @@ public function deleteAddress(AddressBase $address); /** * Finds one address by the given criteria * - * @param array $criteria + * @param array $criteria * @return AddressBase */ public function findAddressBy(array $criteria); diff --git a/src/Oro/Bundle/AddressBundle/Entity/Region.php b/src/Oro/Bundle/AddressBundle/Entity/Region.php index 8252dee18ff..343ef60fb95 100644 --- a/src/Oro/Bundle/AddressBundle/Entity/Region.php +++ b/src/Oro/Bundle/AddressBundle/Entity/Region.php @@ -3,9 +3,11 @@ namespace Oro\Bundle\AddressBundle\Entity; use Doctrine\ORM\Mapping as ORM; +use Doctrine\Common\Collections\ArrayCollection; use JMS\Serializer\Annotation\Type; use BeSimple\SoapBundle\ServiceDefinition\Annotation as Soap; use Gedmo\Mapping\Annotation as Gedmo; +use Gedmo\Translatable\Translatable; use Oro\Bundle\AddressBundle\Entity\Country; @@ -13,25 +15,25 @@ * Region * * @ORM\Table("oro_dictionary_region") - * @ORM\Entity - * @Gedmo\TranslationEntity(class="Oro\Bundle\AddressBundle\Entity\RegionLocalized") + * @ORM\Entity(repositoryClass="Oro\Bundle\AddressBundle\Entity\Repository\RegionRepository") + * @Gedmo\TranslationEntity(class="Oro\Bundle\AddressBundle\Entity\RegionTranslation") */ -class Region +class Region implements Translatable { /** - * @var integer + * @var string * - * @ORM\Column(name="id", type="integer") * @ORM\Id - * @ORM\GeneratedValue(strategy="AUTO") + * @ORM\Column(name="combined_code", type="string", length=16) + * @Soap\ComplexType("string", nillable=true) */ - private $id; + private $combinedCode; /** * @var string * * @ORM\ManyToOne(targetEntity="Country", inversedBy="regions",cascade={"persist"}) - * @ORM\JoinColumn(name="country_id", referencedColumnName="iso2_code") + * @ORM\JoinColumn(name="country_code", referencedColumnName="iso2_code") * @Type("string") * @Soap\ComplexType("string", nillable=true) */ @@ -59,26 +61,34 @@ class Region */ private $locale; + /** + * @param string $combinedCode + */ + public function __construct($combinedCode) + { + $this->combinedCode = $combinedCode; + } + /** * Get id * - * @return integer + * @return integer */ - public function getId() + public function getCombinedCode() { - return $this->id; + return $this->combinedCode; } /** * Set country * - * @param Country $country + * @param Country $country * @return Region */ public function setCountry($country) { $this->country = $country; - + return $this; } @@ -95,20 +105,20 @@ public function getCountry() /** * Set code * - * @param string $code + * @param string $code * @return Region */ public function setCode($code) { $this->code = $code; - + return $this; } /** * Get code * - * @return string + * @return string */ public function getCode() { @@ -118,20 +128,20 @@ public function getCode() /** * Set name * - * @param string $name + * @param string $name * @return Region */ public function setName($name) { $this->name = $name; - + return $this; } /** * Get name * - * @return string + * @return string */ public function getName() { @@ -142,9 +152,9 @@ public function getName() * Set locale * * @param string $locale - * @return $this + * @return Region */ - public function setLocale($locale = 'en_US') + public function setLocale($locale) { $this->locale = $locale; diff --git a/src/Oro/Bundle/AddressBundle/Entity/RegionLocalized.php b/src/Oro/Bundle/AddressBundle/Entity/RegionLocalized.php deleted file mode 100644 index 483cfb84f86..00000000000 --- a/src/Oro/Bundle/AddressBundle/Entity/RegionLocalized.php +++ /dev/null @@ -1,19 +0,0 @@ -createQueryBuilder('r') + ->where('r.country = :country') + ->orderBy('r.name', 'ASC') + ->setParameter('country', $country); + } + + /** + * @param Country $country + * @return Region[] + */ + public function getCountryRegions(Country $country) + { + $query = $this->getCountryRegionsQueryBuilder($country)->getQuery(); + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + return $query->execute(); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Entity/TypedAddress.php b/src/Oro/Bundle/AddressBundle/Entity/TypedAddress.php new file mode 100644 index 00000000000..41f16c85b83 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Entity/TypedAddress.php @@ -0,0 +1,76 @@ +type = $type; + + return $this; + } + + /** + * @return AddressType + */ + public function getType() + { + return $this->type; + } + + /** + * @param bool $primary + */ + public function setPrimary($primary) + { + $this->primary = $primary; + } + + /** + * @return bool + */ + public function isPrimary() + { + return $this->primary; + } + + /** + * {@inheritdoc} + */ + public function isEmpty() + { + return parent::isEmpty() + && empty($this->type) + && empty($this->primary); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Form/DataTransformer/AddressTypeToTypeTransformer.php b/src/Oro/Bundle/AddressBundle/Form/DataTransformer/AddressTypeToTypeTransformer.php new file mode 100644 index 00000000000..642f5f2efa8 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Form/DataTransformer/AddressTypeToTypeTransformer.php @@ -0,0 +1,68 @@ +om = $om; + } + + /** + * Transforms an object to a string. + * + * @param AddressType|null $addressType + * @return string + */ + public function transform($addressType) + { + if (null === $addressType) { + return ""; + } + + return $addressType->getType(); + } + + /** + * Transforms a string to an object. + * + * @param string $type + * @return int|null + * @throws TransformationFailedException + */ + public function reverseTransform($type) + { + if (!$type) { + return null; + } + + $addressType = $this->om + ->getRepository('OroAddressBundle:AddressType') + ->findOneBy(array('type' => $type)); + + if (null === $addressType) { + throw new TransformationFailedException( + sprintf( + 'An address type with type "%s" does not exist!', + $type + ) + ); + } + + return $addressType; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Form/EventListener/AddressCollectionTypeSubscriber.php b/src/Oro/Bundle/AddressBundle/Form/EventListener/AddressCollectionTypeSubscriber.php new file mode 100644 index 00000000000..d9b5b0e26f9 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Form/EventListener/AddressCollectionTypeSubscriber.php @@ -0,0 +1,150 @@ +property = $property; + $this->entityClass = $entityClass; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + FormEvents::POST_BIND => 'postBind', + FormEvents::PRE_SET_DATA => 'preSet', + FormEvents::PRE_BIND => 'preBind' + ); + } + + /** + * Pre set empty collection elements. + * + * @param FormEvent $event + */ + public function preSet(FormEvent $event) + { + $data = $event->getData(); + + $method = $this->getMethodName(); + if ($data && method_exists($data, $method)) { + /** @var Collection $addresses */ + $addresses = $data->$method(); + if ($addresses->isEmpty()) { + $addresses->add(new $this->entityClass()); + } + } + } + + /** + * Removes empty collection elements. + * + * @param FormEvent $event + */ + public function postBind(FormEvent $event) + { + $data = $event->getData(); + + $method = $this->getMethodName(); + if ($data && method_exists($data, $method)) { + /** @var Collection $addresses */ + $addresses = $data->$method(); + /** @var TypedAddress $item */ + foreach ($addresses as $item) { + if ($item->isEmpty()) { + $addresses->removeElement($item); + } + } + } + } + + /** + * Remove empty addresses to prevent validation. + * + * @param FormEvent $event + */ + public function preBind(FormEvent $event) + { + $data = $event->getData(); + if (!$data) { + return; + } + + $addresses = array(); + $hasPrimary = false; + if ($data && array_key_exists($this->property, $data)) { + foreach ($data[$this->property] as $addressRow) { + if (!$this->isArrayEmpty($addressRow)) { + $hasPrimary = $hasPrimary || (array_key_exists('primary', $addressRow) && $addressRow['primary']); + $addresses[] = $addressRow; + } + } + } + + // Set first non empty address for new item as primary + if ($addresses) { + if ((!array_key_exists('id', $data) || !$data['id']) && !$hasPrimary) { + $first = array_shift($addresses); + $first['primary'] = true; + array_unshift($addresses, $first); + } + $data[$this->property] = $addresses; + $event->setData($data); + } + } + + /** + * Check if array is empty + * + * @param array $array + * @return bool + */ + protected function isArrayEmpty($array) + { + foreach ($array as $val) { + if (is_array($val)) { + if (!$this->isArrayEmpty($val)) { + return false; + } + } elseif (!empty($val)) { + return false; + } + } + return true; + } + + /** + * Get getter method name. + * + * @return string + */ + protected function getMethodName() + { + return 'get' . ucfirst($this->property); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Form/EventListener/BuildAddressFormListener.php b/src/Oro/Bundle/AddressBundle/Form/EventListener/BuildAddressFormListener.php index d9704c5e6ef..05f2398e1b1 100644 --- a/src/Oro/Bundle/AddressBundle/Form/EventListener/BuildAddressFormListener.php +++ b/src/Oro/Bundle/AddressBundle/Form/EventListener/BuildAddressFormListener.php @@ -1,13 +1,15 @@ has('state')) { $config = $form->get('state')->getConfig()->getOptions(); unset($config['choice_list']); + unset($config['choices']); } else { $config = array(); } + $config['country'] = $country; + $config['query_builder'] = $this->getRegionClosure($country); $form->add( $this->factory->createNamed( @@ -95,12 +100,16 @@ public function preBind(FormEvent $event) $form = $event->getForm(); /** @var $country \Oro\Bundle\AddressBundle\Entity\Country */ - $country = $this->om->getRepository('OroAddressBundle:Country')->find(isset($data['country']) ? $data['country'] : false); + $country = $this->om->getRepository('OroAddressBundle:Country') + ->find(isset($data['country']) ? $data['country'] : false); if ($country && $country->hasRegions()) { $config = $form->get('state')->getConfig()->getOptions(); unset($config['choice_list']); + unset($config['choices']); + $config['country'] = $country; + $config['query_builder'] = $this->getRegionClosure($country); $form->add( $this->factory->createNamed( @@ -112,4 +121,15 @@ public function preBind(FormEvent $event) ); } } + + /** + * @param Country $country + * @return callable + */ + protected function getRegionClosure(Country $country) + { + return function (RegionRepository $regionRepository) use ($country) { + return $regionRepository->getCountryRegionsQueryBuilder($country); + }; + } } diff --git a/src/Oro/Bundle/AddressBundle/Form/Type/AddressCollectionType.php b/src/Oro/Bundle/AddressBundle/Form/Type/AddressCollectionType.php new file mode 100644 index 00000000000..c1a9236ad44 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Form/Type/AddressCollectionType.php @@ -0,0 +1,61 @@ +setDefaults( + array( + 'type' => 'oro_address_typed', + 'allow_add' => true, + 'allow_delete' => true, + 'by_reference' => false, + 'prototype' => true, + 'prototype_name' => '__name__', + 'label' => ' ', + 'validation_groups' => function (FormInterface $form) { + /** @var AddressBase[] $data */ + $data = $form->getData(); + $hasAddress = false; + foreach ($data as $item) { + if (!$item->isEmpty()) { + $hasAddress = true; + break; + } + } + if ($hasAddress) { + return array('Default'); + } else { + return array(); + } + }, + ) + ); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'collection'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_address_collection'; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Form/Type/AddressTypedType.php b/src/Oro/Bundle/AddressBundle/Form/Type/AddressTypedType.php new file mode 100644 index 00000000000..289e994942c --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Form/Type/AddressTypedType.php @@ -0,0 +1,42 @@ +add( + 'type', + 'entity', + array( + 'class' => 'OroAddressBundle:AddressType', + 'property' => 'type', + 'required' => false, + 'empty_value' => 'Choose type...' + ) + ); + $builder->add( + 'primary', + 'checkbox', + array( + 'label' => 'Primary', + 'required' => false + ) + ); + parent::addEntityFields($builder); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_address_typed'; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php b/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php index 58cebad248b..8c39b5e0e47 100644 --- a/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php +++ b/src/Oro/Bundle/AddressBundle/Form/Type/CountryType.php @@ -16,7 +16,10 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) return $er->createQueryBuilder('c') ->orderBy('c.name', 'ASC'); }, - 'empty_value' => 'Choose a country...', + 'configs' => array( + 'placeholder' => 'oro.address.form.choose_country' + ), + 'empty_value' => '', 'empty_data' => null ) ); @@ -24,7 +27,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) public function getParent() { - return 'entity'; + return 'genemu_jqueryselect2_translatable_entity'; } public function getName() diff --git a/src/Oro/Bundle/AddressBundle/Form/Type/RegionType.php b/src/Oro/Bundle/AddressBundle/Form/Type/RegionType.php index 27d0f29ea41..fb9e68111f1 100644 --- a/src/Oro/Bundle/AddressBundle/Form/Type/RegionType.php +++ b/src/Oro/Bundle/AddressBundle/Form/Type/RegionType.php @@ -3,12 +3,11 @@ namespace Oro\Bundle\AddressBundle\Form\Type; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; -use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\OptionsResolver\Options; class RegionType extends AbstractType { @@ -28,22 +27,29 @@ public function buildForm(FormBuilderInterface $builder, array $options) */ public function setDefaultOptions(OptionsResolverInterface $resolver) { - $list = function (Options $options) { - if (null === $options['country']) { - return new ObjectChoiceList(array()); + $choices = function (Options $options) { + // show empty list if country is not selected + if (empty($options['country'])) { + return array(); } - return new ObjectChoiceList($options['country']->getRegions(), null, array(), null, 'code'); + return null; }; $resolver ->setDefaults( array( - 'choice_list' => $list, - 'country' => null, + 'class' => 'OroAddressBundle:Region', + 'property' => 'name', + 'query_builder' => null, + 'choices' => $choices, + 'country' => null, 'country_field' => null, - 'empty_value' => 'Choose a state...', - 'empty_data' => null, + 'configs' => array( + 'placeholder' => 'oro.address.form.choose_state', + ), + 'empty_value' => '', + 'empty_data' => null ) ); } @@ -53,7 +59,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver) */ public function finishView(FormView $view, FormInterface $form, array $options) { - $view->vars['country_field'] = $form->getAttribute(self::COUNTRY_OPTION_KEY); + $view->vars['country_field'] = $form->getConfig()->getAttribute(self::COUNTRY_OPTION_KEY); } /** @@ -61,7 +67,7 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function getParent() { - return 'choice'; + return 'genemu_jqueryselect2_translatable_entity'; } /** diff --git a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/DbReader.php b/src/Oro/Bundle/AddressBundle/Provider/ImportExport/DbReader.php deleted file mode 100644 index a591e5b6eb8..00000000000 --- a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/DbReader.php +++ /dev/null @@ -1,45 +0,0 @@ -getClassMetadata($class); - $this->class = $metadata->getName(); - $this->om = $om; - - if (!is_null($batchSize)) { - $this->batchSize = $batchSize; - } - } - - /** - * @inheritdoc - */ - public function readBatch() - { - $offset = $this->offset * $this->batchSize; - $this->offset++; - - return $this->om->getRepository($this->class)->findBy(array(), array(), $this->batchSize, $offset); - } -} diff --git a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/DbWriter.php b/src/Oro/Bundle/AddressBundle/Provider/ImportExport/DbWriter.php deleted file mode 100644 index 42659d0102c..00000000000 --- a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/DbWriter.php +++ /dev/null @@ -1,40 +0,0 @@ -om = $om; - } - - /** - * @inheritdoc - */ - public function writeBatch($data) - { - if (empty($data) || !is_array($data)) { - return false; - } - - foreach ($data as $entry) { - if (is_object($entry)) { - $this->om->persist($entry); - } else { - throw new \Exception("Entry passed to writer is not an object"); - } - } - - $this->om->flush(); - - return true; - } -} diff --git a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/IntlReader.php b/src/Oro/Bundle/AddressBundle/Provider/ImportExport/IntlReader.php deleted file mode 100644 index ff83acb0dd8..00000000000 --- a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/IntlReader.php +++ /dev/null @@ -1,74 +0,0 @@ -class = $class; - - if (!is_null($batchSize)) { - $this->batchSize = $batchSize; - } - } - - /** - * @inheritdoc - */ - public function readBatch() - { - if (!extension_loaded('intl')) { - return false; - } - - $countries = Intl::getRegionBundle()->getCountryNames(); - $class = $this->class; - - $offset = $this->offset * $this->batchSize; - $this->offset++; - - $isoCodes = $this->readFallbackData(); - - $countries = array_slice($countries, $offset, $this->batchSize); - - if (!empty($countries)) { - $result = array(); - foreach ($countries as $iso2code => $countryName) { - $result[] = new $class($countryName, $iso2code, isset($isoCodes[$iso2code]) ? $isoCodes[$iso2code] : $iso2code); - } - return $result; - } - - return false; - } - - /** - * Move it or delete when valid datasource will be found - */ - public function readFallbackData() - { - $data = Yaml::parse(realpath(__DIR__ . '/../../' . self::FALLBACK_DATA)); - $isoCodes = array(); - - foreach ($data as $country) { - $isoCodes[ $country['iso2'] ] = $country['iso3']; - } - - return $isoCodes; - } -} diff --git a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/Manager.php b/src/Oro/Bundle/AddressBundle/Provider/ImportExport/Manager.php deleted file mode 100644 index 3c9d15c9914..00000000000 --- a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/Manager.php +++ /dev/null @@ -1,45 +0,0 @@ -reader = $reader; - $this->writer = $writer; - } - - /** - * Reading/Writing data in a batch and write/read it to destination - * data can be passed through argument or read from reader - * - * @param $data - * @throws \Exception - * @return boolean true on success - */ - public function sync($data = null) - { - if ($this->reader instanceof ReaderInterface) { - while ($batchData = $this->reader->readBatch()) { - $this->writer->writeBatch($batchData); - } - } elseif (!is_null($data)) { - $this->writer->writeBatch($data); - } else { - throw new \Exception("Source is not defined"); - } - - return true; - } -} diff --git a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/Reader.php b/src/Oro/Bundle/AddressBundle/Provider/ImportExport/Reader.php deleted file mode 100644 index 293a6710a9d..00000000000 --- a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/Reader.php +++ /dev/null @@ -1,35 +0,0 @@ -offset = 0; - } - - /** - * Return batch size - * - * @return int - */ - public function getBatchSize() - { - return $this->batchSize; - } -} diff --git a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/ReaderInterface.php b/src/Oro/Bundle/AddressBundle/Provider/ImportExport/ReaderInterface.php deleted file mode 100644 index 732c9807c07..00000000000 --- a/src/Oro/Bundle/AddressBundle/Provider/ImportExport/ReaderInterface.php +++ /dev/null @@ -1,13 +0,0 @@ - + +### Address collection +Address collection may be added to form with next three steps +1) Add field with type oro_address_collection to form + +```php +$builder->add( + 'multiAddress', + 'oro_address_collection', + array( + 'required' => false, + 'label' => ' ' + ) +); +``` +2) Add AddressCollectionTypeSubscriber. AddressCollectionTypeSubscriber must be initialized with address collection field name. + +```php +$builder->addEventSubscriber(new AddressCollectionTypeSubscriber('multiAddress')); +``` + +3) In template add OroAddressBundle:Include:fields.html.twig to support address form field typed + +```php +{% form_theme form with ['OroAddressBundle:Include:fields.html.twig']} +``` diff --git a/src/Oro/Bundle/AddressBundle/Resources/config/flexibleentity.yml b/src/Oro/Bundle/AddressBundle/Resources/config/flexibleentity.yml index ce1cb487c69..59f2dd35ddf 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/config/flexibleentity.yml +++ b/src/Oro/Bundle/AddressBundle/Resources/config/flexibleentity.yml @@ -4,3 +4,9 @@ entities_config: flexible_class: %oro_address.address.entity.class% flexible_value_class: %oro_address.address.entity.value.class% flexible_init_mode: all_attributes + + Oro\Bundle\AddressBundle\Entity\TypedAddress: + flexible_manager: oro_address.typed_address.manager.flexible + flexible_class: %oro_address.typed_address.entity.class% + flexible_value_class: %oro_address.address.entity.value.class% + flexible_init_mode: all_attributes \ No newline at end of file diff --git a/src/Oro/Bundle/AddressBundle/Resources/config/services.yml b/src/Oro/Bundle/AddressBundle/Resources/config/services.yml index 80f45580b43..66e43a63290 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/AddressBundle/Resources/config/services.yml @@ -1,17 +1,21 @@ parameters: oro_address.address.base.class: Oro\Bundle\AddressBundle\Entity\AddressBase oro_address.address.entity.class: Oro\Bundle\AddressBundle\Entity\Address + oro_address.typed_address.entity.class: Oro\Bundle\AddressBundle\Entity\TypedAddress oro_address.address.type.entity.class: Oro\Bundle\AddressBundle\Entity\AddressType oro_address.address.manager.class: Oro\Bundle\AddressBundle\Entity\Manager\AddressManager oro_address.address.manager.api.class: Oro\Bundle\SoapBundle\Entity\Manager\ApiFlexibleEntityManager oro_address.address.manager.flexible.class: Oro\Bundle\FlexibleEntityBundle\Manager\FlexibleManager + oro_address.typed_address.manager.flexible.class: Oro\Bundle\FlexibleEntityBundle\Manager\FlexibleManager oro_address.address.type.manager.class: Oro\Bundle\AddressBundle\Entity\Manager\AddressTypeManager oro_address.address.entity.value.class: Oro\Bundle\AddressBundle\Entity\Value\AddressValue oro_address.type.address.class: Oro\Bundle\AddressBundle\Form\Type\AddressType oro_address.type.address_value.class: Oro\Bundle\AddressBundle\Form\Type\AddressValueType + oro_address.type.address_typed.class: Oro\Bundle\AddressBundle\Form\Type\AddressTypedType + oro_address.type.address_collection.class: Oro\Bundle\AddressBundle\Form\Type\AddressCollectionType oro_address.type.address_api.class: Oro\Bundle\AddressBundle\Form\Type\AddressApiType oro_address.type.address_api_value.class: Oro\Bundle\AddressBundle\Form\Type\AddressApiValueType oro_address.handler.address.class: Oro\Bundle\AddressBundle\Form\Handler\AddressHandler @@ -19,11 +23,6 @@ parameters: oro_address.provider.address.class: Oro\Bundle\AddressBundle\Provider\AddressProvider oro_address.entity.value.class: Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexibleValue - oro_address.dict.import.writer.class: Oro\Bundle\AddressBundle\Provider\ImportExport\DbWriter - oro_address.dict.import.intlreader.class: Oro\Bundle\AddressBundle\Provider\ImportExport\IntlReader - oro_address.dict.manager.class: Oro\Bundle\AddressBundle\Provider\ImportExport\Manager - oro_address.dict.import.entity.class: Oro\Bundle\AddressBundle\Entity\Country - oro_address.type.country.class: Oro\Bundle\AddressBundle\Form\Type\CountryType oro_address.type.region.class: Oro\Bundle\AddressBundle\Form\Type\RegionType @@ -31,6 +30,10 @@ parameters: oro_address.attribute.address.class: Oro\Bundle\AddressBundle\AttributeType\AddressType + oro_address.twig.hasAddress.extension.class: Oro\Bundle\AddressBundle\Twig\HasAddressExtension + + oro_address.typed.transformer.class: Oro\Bundle\AddressBundle\Form\DataTransformer\AddressTypeToTypeTransformer + services: oro_address.address.provider: class: %oro_address.provider.address.class% @@ -49,6 +52,19 @@ services: calls: - [ addAttributeType, ['oro_flexibleentity_text'] ] + oro_address.typed_address.manager.flexible: + class: %oro_address.typed_address.manager.flexible.class% + arguments: + - %oro_address.typed_address.entity.class% + - %oro_flexibleentity.flexible_config% + - @doctrine.orm.entity_manager + - @event_dispatcher + - @oro_flexibleentity.attributetype.factory + tags: + - { name: oro_flexibleentity_manager, entity: %oro_address.typed_address.entity.class%} + calls: + - [ addAttributeType, ['oro_flexibleentity_text'] ] + oro_address.address.manager: class: %oro_address.address.manager.class% arguments: @@ -103,6 +119,20 @@ services: tags: - { name: form.type, alias: oro_address_value } + oro_address.type.address_typed: + class: %oro_address.type.address_typed.class% + arguments: + - @oro_address.typed_address.manager.flexible + - "oro_address_value" + - @oro_address.form.listener.address + tags: + - { name: form.type, alias: oro_address_typed } + + oro_address.type.address_collection: + class: %oro_address.type.address_collection.class% + tags: + - { name: form.type, alias: oro_address_collection } + oro_address.form.type.address.api: class: %oro_address.type.address_api.class% arguments: @@ -147,23 +177,6 @@ services: tags: - { name: form.type, alias: oro_region } - # dictionary services - oro_address.dict.import.dbwriter: - class: %oro_address.dict.import.writer.class% - arguments: ["@doctrine.orm.entity_manager"] - - oro_address.dict.import.intlreader: - class: %oro_address.dict.import.intlreader.class% - arguments: ["%oro_address.dict.import.entity.class%"] - - oro_address.dict.import.manager: - class: %oro_address.dict.manager.class% - arguments: ["@oro_address.dict.import.dbwriter", null] - - oro_address.dict.import.intl.manager: - class: %oro_address.dict.manager.class% - arguments: ["@oro_address.dict.import.dbwriter", "@oro_address.dict.import.intlreader"] - oro_address.form.type.region: class: %oro_address.type.region.class% tags: @@ -181,5 +194,16 @@ services: arguments: - "address" - "oro_address" + - @oro_flexibleentity.validator.attribute_constraint_guesser + tags: + - { name: oro_flexibleentity.attributetype, alias: oro_address } + + oro_address.twig.hasAddress.extension: + class: %oro_address.twig.hasAddress.extension.class% tags: - - { name: oro_flexibleentity.attributetype, alias: oro_address } \ No newline at end of file + - { name: twig.extension } + + oro_address.typed.transformer: + class: %oro_address.typed.transformer.class% + arguments: + - @doctrine.orm.entity_manager diff --git a/src/Oro/Bundle/AddressBundle/Resources/config/validation.yml b/src/Oro/Bundle/AddressBundle/Resources/config/validation.yml index ca2b0fc5ae7..7045f024b2b 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/config/validation.yml +++ b/src/Oro/Bundle/AddressBundle/Resources/config/validation.yml @@ -1,4 +1,4 @@ -Oro\Bundle\AddressBundle\Entity\Address: +Oro\Bundle\AddressBundle\Entity\AddressBase: properties: street: - NotBlank: ~ diff --git a/src/Oro/Bundle/AddressBundle/Resources/public/js/collections/region.updater.js b/src/Oro/Bundle/AddressBundle/Resources/public/js/collections/region.updater.js index 38063c8417d..de37601d23d 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/public/js/collections/region.updater.js +++ b/src/Oro/Bundle/AddressBundle/Resources/public/js/collections/region.updater.js @@ -19,6 +19,6 @@ Oro.RegionUpdater.Collection = Backbone.Collection.extend({ * @param id {String} */ setCountryId: function (id) { - this.url = Routing.generate(this.route, {id: id}); + this.url = Routing.generate(this.route, {country: id}); } }); diff --git a/src/Oro/Bundle/AddressBundle/Resources/public/js/views/region.updater.js b/src/Oro/Bundle/AddressBundle/Resources/public/js/views/region.updater.js index 049c3246d03..621cbbdbffd 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/public/js/views/region.updater.js +++ b/src/Oro/Bundle/AddressBundle/Resources/public/js/views/region.updater.js @@ -18,11 +18,30 @@ Oro.RegionUpdater.View = Backbone.View.extend({ this.target.closest('.controls').append(this.$simpleEl); this.$simpleEl.attr('type', 'text'); + this.showSelect = options.showSelect; + this.template = $('#region-chooser-template').html(); + this.target.on('select2-init', _.bind(function() { + this.displaySelect2(this.showSelect); + }, this)); + this.listenTo(this.collection, 'reset', this.render); }, + /** + * Show/hide select 2 element + * + * @param {Boolean} display + */ + displaySelect2: function(display) { + if (display) { + this.target.select2('container').show(); + } else { + this.target.select2('container').hide(); + } + }, + /** * Trigger change event */ @@ -46,6 +65,7 @@ Oro.RegionUpdater.View = Backbone.View.extend({ render: function() { if (this.collection.models.length > 0) { this.target.show(); + this.displaySelect2(true); $('#uniform-' + this.target[0].id).show(); this.target.val('').trigger('change'); @@ -56,6 +76,8 @@ Oro.RegionUpdater.View = Backbone.View.extend({ this.$simpleEl.val(''); } else { this.target.hide(); + this.target.val(''); + this.displaySelect2(false); $('#uniform-' + this.target[0].id).hide(); this.$simpleEl.show(); } diff --git a/src/Oro/Bundle/AddressBundle/Resources/translations/countries.en.yml b/src/Oro/Bundle/AddressBundle/Resources/translations/countries.en.yml new file mode 100644 index 00000000000..26bf2d17db7 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Resources/translations/countries.en.yml @@ -0,0 +1,4126 @@ +AD: Andorra +AE: 'United Arab Emirates' +AF: Afghanistan +AG: 'Antigua and Barbuda' +AI: Anguilla +AL: Albania +AM: Armenia +AO: Angola +AQ: Antarctica +AR: Argentina +AS: 'American Samoa' +AT: Austria +AU: Australia +AW: Aruba +AX: 'Aland Islands' +AZ: Azerbaijan +BA: 'Bosnia and Herzegovina' +BB: Barbados +BD: Bangladesh +BE: Belgium +BF: 'Burkina Faso' +BG: Bulgaria +BH: Bahrain +BI: Burundi +BJ: Benin +BL: 'Saint Barthelemy' +BM: Bermuda +BN: Brunei +BO: Bolivia +BQ: 'Bonaire, Saint Eustatius and Saba ' +BR: Brazil +BS: Bahamas +BT: Bhutan +BV: 'Bouvet Island' +BW: Botswana +BY: Belarus +BZ: Belize +CA: Canada +CC: 'Cocos Islands' +CD: 'Democratic Republic of the Congo' +CF: 'Central African Republic' +CG: 'Republic of the Congo' +CH: Switzerland +CI: 'Ivory Coast' +CK: 'Cook Islands' +CL: Chile +CM: Cameroon +CN: China +CO: Colombia +CR: 'Costa Rica' +CU: Cuba +CV: 'Cape Verde' +CW: Curacao +CX: 'Christmas Island' +CY: Cyprus +CZ: 'Czech Republic' +DE: Germany +DJ: Djibouti +DK: Denmark +DM: Dominica +DO: 'Dominican Republic' +DZ: Algeria +EC: Ecuador +EE: Estonia +EG: Egypt +EH: 'Western Sahara' +ER: Eritrea +ES: Spain +ET: Ethiopia +FI: Finland +FJ: Fiji +FK: 'Falkland Islands' +FM: Micronesia +FO: 'Faroe Islands' +FR: France +GA: Gabon +GB: 'United Kingdom' +GD: Grenada +GE: Georgia +GF: 'French Guiana' +GG: Guernsey +GH: Ghana +GI: Gibraltar +GL: Greenland +GM: Gambia +GN: Guinea +GP: Guadeloupe +GQ: 'Equatorial Guinea' +GR: Greece +GS: 'South Georgia and the South Sandwich Islands' +GT: Guatemala +GU: Guam +GW: Guinea-Bissau +GY: Guyana +HK: 'Hong Kong' +HM: 'Heard Island and McDonald Islands' +HN: Honduras +HR: Croatia +HT: Haiti +HU: Hungary +ID: Indonesia +IE: Ireland +IL: Israel +IM: 'Isle of Man' +IN: India +IO: 'British Indian Ocean Territory' +IQ: Iraq +IR: Iran +IS: Iceland +IT: Italy +JE: Jersey +JM: Jamaica +JO: Jordan +JP: Japan +KE: Kenya +KG: Kyrgyzstan +KH: Cambodia +KI: Kiribati +KM: Comoros +KN: 'Saint Kitts and Nevis' +KP: 'North Korea' +KR: 'South Korea' +XK: Kosovo +KW: Kuwait +KY: 'Cayman Islands' +KZ: Kazakhstan +LA: Laos +LB: Lebanon +LC: 'Saint Lucia' +LI: Liechtenstein +LK: 'Sri Lanka' +LR: Liberia +LS: Lesotho +LT: Lithuania +LU: Luxembourg +LV: Latvia +LY: Libya +MA: Morocco +MC: Monaco +MD: Moldova +ME: Montenegro +MF: 'Saint Martin' +MG: Madagascar +MH: 'Marshall Islands' +MK: Macedonia +ML: Mali +MM: Myanmar +MN: Mongolia +MO: Macao +MP: 'Northern Mariana Islands' +MQ: Martinique +MR: Mauritania +MS: Montserrat +MT: Malta +MU: Mauritius +MV: Maldives +MW: Malawi +MX: Mexico +MY: Malaysia +MZ: Mozambique +NA: Namibia +NC: 'New Caledonia' +NE: Niger +NF: 'Norfolk Island' +NG: Nigeria +NI: Nicaragua +NL: Netherlands +NO: Norway +NP: Nepal +NR: Nauru +NU: Niue +NZ: 'New Zealand' +OM: Oman +PA: Panama +PE: Peru +PF: 'French Polynesia' +PG: 'Papua New Guinea' +PH: Philippines +PK: Pakistan +PL: Poland +PM: 'Saint Pierre and Miquelon' +PN: Pitcairn +PR: 'Puerto Rico' +PS: 'Palestinian Territory' +PT: Portugal +PW: Palau +PY: Paraguay +QA: Qatar +RE: Reunion +RO: Romania +RS: Serbia +RU: Russia +RW: Rwanda +SA: 'Saudi Arabia' +SB: 'Solomon Islands' +SC: Seychelles +SD: Sudan +SS: 'South Sudan' +SE: Sweden +SG: Singapore +SH: 'Saint Helena' +SI: Slovenia +SJ: 'Svalbard and Jan Mayen' +SK: Slovakia +SL: 'Sierra Leone' +SM: 'San Marino' +SN: Senegal +SO: Somalia +SR: Suriname +ST: 'Sao Tome and Principe' +SV: 'El Salvador' +SX: 'Sint Maarten' +SY: Syria +SZ: Swaziland +TC: 'Turks and Caicos Islands' +TD: Chad +TF: 'French Southern Territories' +TG: Togo +TH: Thailand +TJ: Tajikistan +TK: Tokelau +TL: 'East Timor' +TM: Turkmenistan +TN: Tunisia +TO: Tonga +TR: Turkey +TT: 'Trinidad and Tobago' +TV: Tuvalu +TW: Taiwan +TZ: Tanzania +UA: Ukraine +UG: Uganda +UM: 'United States Minor Outlying Islands' +US: 'United States' +UY: Uruguay +UZ: Uzbekistan +VA: Vatican +VC: 'Saint Vincent and the Grenadines' +VE: Venezuela +VG: 'British Virgin Islands' +VI: 'U.S. Virgin Islands' +VN: Vietnam +VU: Vanuatu +WF: 'Wallis and Futuna' +WS: Samoa +YE: Yemen +YT: Mayotte +ZA: 'South Africa' +ZM: Zambia +ZW: Zimbabwe +CS: 'Serbia and Montenegro' +AN: 'Netherlands Antilles' +AD.06: 'Parròquia de Sant Julià de Lòria' +AD.05: 'Parròquia d''Ordino' +AD.04: 'Parròquia de la Massana' +AD.03: 'Parròquia d''Encamp' +AD.02: Canillo +AD.07: 'Parròquia d''Andorra la Vella' +AD.08: 'Parròquia d''Escaldes-Engordany' +AE.07: 'Umm al Qaywayn' +AE.05: 'Raʼs al Khaymah' +AE.03: Dubai +AE.06: 'Ash Shāriqah' +AE.04: 'Al Fujayrah' +AE.02: Ajman +AE.01: 'Abu Dhabi' +AF.28: Zabul +AF.27: Vardak +AF.26: Takhār +AF.33: 'Sar-e Pol' +AF.32: Samangān +AF.40: Parvān +AF.29: Paktīkā +AF.36: Paktia +AF.39: Orūzgān +AF.19: Nīmrūz +AF.18: Nangarhār +AF.17: Lowgar +AF.35: Laghmān +AF.24: Kunduz +AF.34: Konar +AF.14: Kāpīsā +AF.23: Kandahār +AF.13: Kabul +AF.31: Jowzjān +AF.11: Herat +AF.10: Helmand +AF.09: Ghowr +AF.08: Ghaznī +AF.07: Faryab +AF.06: Farah +AF.05: Bāmīān +AF.30: 'Balkh Province' +AF.03: 'Wilāyat-e Baghlān' +AF.02: Badghis +AF.01: Badakhshan +AF.37: Khowst +AF.38: Nūrestān +AF.41: 'Wilāyat-e Dāykundī' +AF.42: Panjshir +AG.08: 'Saint Philip' +AG.07: 'Saint Peter' +AG.06: 'Saint Paul' +AG.05: 'Saint Mary' +AG.04: 'Saint John' +AG.03: 'Saint George' +AG.09: Redonda +AG.01: Barbuda +AL.40: Berat +AL.41: Dibër +AL.43: Elbasan +AL.45: Gjirokastër +AL.46: Korçë +AL.47: Kukës +AL.42: Durrës +AL.44: Fier +AL.48: Lezhë +AL.49: Shkodër +AL.50: Tiranë +AL.51: Vlorë +AM.02: Ararat +AM.08: Syunikʼ +AM.10: 'Vayotsʼ Dzor' +AM.11: Yerevan +AM.01: Aragatsotn +AM.03: Armavir +AM.04: Gegharkʼunikʼ +AM.05: Kotaykʼ +AM.06: Lorri +AM.07: Shirak +AM.09: Tavush +AO.18: 'Lunda Sul' +AO.17: 'Lunda Norte' +AO.14: Moxico +AO.04: 'Cuando Cubango' +AO.16: Zaire +AO.15: Uíge +AO.12: Malanje +AO.20: Luanda +AO.05: 'Cuanza Norte' +AO.03: Cabinda +AO.19: Bengo +AO.13: Namibe +AO.09: Huíla +AO.08: Huambo +AO.07: Cunene +AO.06: 'Cuanza Sul' +AO.02: Bié +AO.01: Benguela +AR.14: Misiones +AR.09: Formosa +AR.07: 'Buenos Aires F.D.' +AR.08: 'Entre Ríos' +AR.06: Corrientes +AR.01: 'Buenos Aires' +AR.24: Tucumán +AR.23: 'Tierra del Fuego' +AR.22: 'Santiago del Estero' +AR.21: 'Santa Fe' +AR.20: 'Santa Cruz' +AR.19: 'San Luis' +AR.18: 'San Juan' +AR.17: Salta +AR.16: 'Río Negro' +AR.15: Neuquén +AR.13: Mendoza +AR.12: 'La Rioja' +AR.11: 'La Pampa' +AR.10: Jujuy +AR.05: Córdoba +AR.04: Chubut +AR.03: Chaco +AR.02: Catamarca +AS.050: 'Western District' +AS.040: 'Swains Island' +AS.010: 'Eastern District' +AS.020: 'Manu''a' +AS.030: 'Rose Atoll' +AT.09: Vienna +AT.08: Vorarlberg +AT.07: Tyrol +AT.06: Styria +AT.05: Salzburg +AT.04: 'Upper Austria' +AT.03: 'Lower Austria' +AT.02: Carinthia +AT.01: Burgenland +AU.08: 'Western Australia' +AU.05: 'South Australia' +AU.03: 'Northern Territory' +AU.07: Victoria +AU.06: Tasmania +AU.04: Queensland +AU.02: 'New South Wales' +AU.01: 'Australian Capital Territory' +AX.941: Vårdö +AX.771: Sund +AX.766: Sottunga +AX.736: Saltvik +AX.438: Lumparland +AX.417: Lemland +AX.295: Kumlinge +AX.318: Kökar +AX.062: Föglö +AX.035: Brändö +AX.478: Mariehamn +AX.170: Jomala +AX.076: Hammarland +AX.065: Geta +AX.060: Finström +AX.043: Eckerö +AZ.12: Beyləqan +AZ.69: Zǝngilan +AZ.66: Yardımlı +AZ.55: Şuşa +AZ.49: Salyan +AZ.46: Sabirabad +AZ.45: Saatlı +AZ.13: Bilǝsuvar +AZ.36: Neftçala +AZ.35: Nakhichevan +AZ.32: Masallı +AZ.31: Lerik +AZ.29: Lənkəran +AZ.28: Laçın +AZ.43: Qubadlı +AZ.24: İmişli +AZ.18: Füzuli +AZ.14: Cǝbrayıl +AZ.15: Cəlilabad +AZ.08: Astara +AZ.64: Xocalı +AZ.02: Ağcabǝdi +AZ.03: Ağdam +AZ.07: 'Əli Bayramli' +AZ.30: 'Lənkəran Şəhəri' +AZ.56: 'Şuşa Şəhəri' +AZ.57: Tǝrtǝr +AZ.61: Xankǝndi +AZ.65: Xocavǝnd +AZ.71: Zərdab +AZ.70: Zaqatala +AZ.67: Yevlax +AZ.37: Oğuz +AZ.59: Ucar +AZ.58: Tovuz +AZ.50: Şamaxı +AZ.47: Şǝki +AZ.51: Şǝmkir +AZ.27: Kürdǝmir +AZ.38: Qǝbǝlǝ +AZ.44: Qusar +AZ.42: Quba +AZ.62: 'Goygol Rayon' +AZ.60: Xaçmaz +AZ.26: Kǝlbǝcǝr +AZ.40: Qazax +AZ.21: Goranboy +AZ.39: Qǝx +AZ.25: İsmayıllı +AZ.22: Göyçay +AZ.17: Dǝvǝçi +AZ.16: Daşkǝsǝn +AZ.10: Balakǝn +AZ.11: Bǝrdǝ +AZ.09: Baki +AZ.01: Abşeron +AZ.06: Ağsu +AZ.04: Ağdaş +AZ.19: Gǝdǝbǝy +AZ.05: Ağstafa +AZ.20: Gǝncǝ +AZ.33: Mingǝcevir +AZ.34: Naftalan +AZ.41: Qobustan +AZ.52: Samux +AZ.48: 'Shaki City' +AZ.53: Siyǝzǝn +AZ.54: Sumqayit +AZ.63: Xızı +AZ.68: 'Yevlax City' +AZ.23: Hacıqabul +AZ.75: 'Naxçıvan Şəhəri' +BA.01: 'Federation of Bosnia and Herzegovina' +BA.02: 'Republika Srpska' +BA.BRC: Brčko +BB.11: 'Saint Thomas' +BB.10: 'Saint Philip' +BB.09: 'Saint Peter' +BB.08: 'Saint Michael' +BB.07: 'Saint Lucy' +BB.06: 'Saint Joseph' +BB.05: 'Saint John' +BB.04: 'Saint James' +BB.03: 'Saint George' +BB.02: 'Saint Andrew' +BB.01: 'Christ Church' +BD.83: Rājshāhi +BD.81: Dhaka +BD.84: Chittagong +BD.82: Khulna +BD.85: Barisāl +BD.86: Sylhet +BD.87: 'Rangpur Division' +BE.BRU: 'Brussels Capital Region' +BE.WAL: 'Walloon Region' +BE.VLG: Flanders +BF.01: 'Boucle du Mouhoun Region' +BF.02: 'Cascades Region' +BF.03: Centre +BF.04: Centre-Est +BF.05: Centre-Nord +BF.06: Centre-Ouest +BF.07: Centre-Sud +BF.08: Est +BF.09: 'High-Basins Region' +BF.10: Nord +BF.11: Plateau-Central +BF.12: Sahel +BF.13: 'Southwest Region' +BG.52: Razgrad +BG.47: Montana +BG.64: Vratsa +BG.61: Varna +BG.40: Dobrich +BG.58: Sofiya +BG.53: Ruse +BG.51: Plovdiv +BG.50: Pleven +BG.49: Pernik +BG.48: Pazardzhit +BG.46: Lovech +BG.43: Khaskovo +BG.42: Sofia-Capital +BG.39: Burgas +BG.38: Blagoevgrad +BG.41: 'Gabrovo Province' +BG.44: Kŭrdzhali +BG.45: Kyustendil +BG.54: Shumen +BG.55: Silistra +BG.56: Sliven +BG.57: Smolyan +BG.59: 'Stara Zagora' +BG.60: Tŭrgovishte +BG.62: 'Veliko Tŭrnovo' +BG.63: Vidin +BG.65: Yambol +BH.15: Muharraq +BH.16: Capital +BH.17: 'Southern Governorate' +BH.18: 'Central Governorate' +BH.19: Northern +BI.17: Makamba +BI.10: Bururi +BI.22: Muramvya +BI.13: Gitega +BI.21: Ruyigi +BI.11: Cankuzo +BI.14: Karuzi +BI.09: Bubanza +BI.12: Cibitoke +BI.19: Ngozi +BI.15: Kayanza +BI.18: Muyinga +BI.16: Kirundo +BI.20: Rutana +BI.23: Mwaro +BI.24: 'Bujumbura Mairie Province' +BI.25: 'Bujumbura Rural Province' +BJ.18: Zou +BJ.16: Quémé +BJ.15: Mono +BJ.10: Borgou +BJ.09: Atlantique +BJ.08: Atakora +BJ.07: Alibori +BJ.11: Collines +BJ.12: Kouffo +BJ.13: Donga +BJ.14: Littoral +BJ.17: Plateau +BM.11: Warwick +BM.10: Southampton +BM.09: Smithʼs +BM.08: Sandys +BM.07: 'Saint Georgeʼs' +BM.06: 'Saint George' +BM.05: Pembroke +BM.04: Paget +BM.02: 'Hamilton Parish' +BM.03: 'Hamilton city' +BM.01: Devonshire +BN.04: Tutong +BN.03: Temburong +BN.02: 'Brunei and Muara' +BN.01: Belait +BO.09: Tarija +BO.08: 'Santa Cruz' +BO.07: Potosí +BO.06: Pando +BO.05: Oruro +BO.04: 'La Paz' +BO.02: Cochabamba +BO.01: Chuquisaca +BO.03: 'El Beni' +BQ.BO: Bonaire +BQ.SB: Saba +BQ.SE: 'Sint Eustatius' +BR.22: 'Rio Grande do Norte' +BR.20: Piauí +BR.30: Pernambuco +BR.17: Paraíba +BR.16: Pará +BR.13: Maranhão +BR.06: Ceará +BR.03: Amapá +BR.02: Alagoas +BR.28: Sergipe +BR.27: 'São Paulo' +BR.26: 'Santa Catarina' +BR.23: 'Rio Grande do Sul' +BR.21: 'Rio de Janeiro' +BR.18: Paraná +BR.15: 'Minas Gerais' +BR.11: 'Estado de Mato Grosso do Sul' +BR.14: 'Mato Grosso' +BR.29: Goiás +BR.07: 'Federal District' +BR.08: 'Espírito Santo' +BR.05: 'Estado de Bahía' +BR.31: Tocantins +BR.25: Roraima +BR.04: Amazonas +BR.01: Acre +BR.24: Rondônia +BS.35: 'San Salvador' +BS.34: 'Sandy Point' +BS.33: 'Rock Sound' +BS.18: 'Ragged Island' +BS.32: 'Berry Islands District' +BS.23: 'New Providence' +BS.16: Mayaguana +BS.31: 'Marsh Harbour' +BS.15: 'Long Island' +BS.30: 'Kemps Bay' +BS.13: Inagua +BS.29: 'High Rock' +BS.22: 'Harbour Island' +BS.28: 'Green Turtle Cay' +BS.27: 'Governorʼs Harbour' +BS.26: 'Fresh Creek' +BS.25: Freeport +BS.10: Exuma +BS.06: 'Cat Island' +BS.05: Bimini +BS.24: 'Acklins and Crooked Islands' +BS.36: 'Black Point' +BS.37: 'Central Abaco' +BS.38: 'Central Andros' +BS.39: 'Central Eleuthera' +BS.40: 'Crooked Island and Long Cay' +BS.41: 'East Grand Bahama' +BS.42: 'Grand Cay' +BS.43: 'Hope Town' +BS.44: 'Mangrove Cay' +BS.45: 'Moore’s Island' +BS.46: 'North Abaco' +BS.47: 'North Andros' +BS.48: 'North Eleuthera' +BS.49: 'Rum Cay' +BS.50: 'South Abaco' +BS.51: 'South Andros' +BS.52: 'South Eleuthera' +BS.53: 'Spanish Wells' +BS.54: 'West Grand Bahama' +BT.05: Bumthang +BT.06: Chhukha +BT.08: Daga +BT.07: Chirang +BT.09: Geylegphug +BT.10: Ha +BT.11: Lhuntshi +BT.12: Mongar +BT.13: Paro +BT.14: Pemagatsel +BT.15: Punakha +BT.16: Samchi +BT.17: 'Samdrup Jongkhar' +BT.18: Shemgang +BT.19: Tashigang +BT.20: Thimphu +BT.21: Tongsa +BT.22: 'Wangdi Phodrang' +BT.23: Gasa +BT.24: 'Trashi Yangste' +BW.10: Southern +BW.09: 'South East' +BW.08: 'North East' +BW.11: 'North West' +BW.06: Kweneng +BW.05: Kgatleng +BW.04: Kgalagadi +BW.03: Ghanzi +BW.01: Central +BY.07: 'Vitsyebskaya Voblastsʼ' +BY.06: 'Mahilyowskaya Voblastsʼ' +BY.05: 'Minskaya Voblastsʼ' +BY.04: Minsk +BY.03: 'Hrodzyenskaya Voblastsʼ' +BY.02: 'Homyelʼskaya Voblastsʼ' +BY.01: 'Brestskaya Voblastsʼ' +BZ.06: Toledo +BZ.05: 'Stann Creek' +BZ.04: 'Orange Walk' +BZ.03: Corozal +BZ.02: Cayo +BZ.01: Belize +CA.01: Alberta +CA.02: 'British Columbia' +CA.03: Manitoba +CA.04: 'New Brunswick' +CA.13: 'Northwest Territories' +CA.07: 'Nova Scotia' +CA.14: Nunavut +CA.08: Ontario +CA.09: 'Prince Edward Island' +CA.10: Quebec +CA.11: Saskatchewan +CA.12: Yukon +CA.05: 'Newfoundland and Labrador' +CD.12: 'South Kivu' +CD.05: Katanga +CD.11: 'Nord Kivu' +CD.10: Maniema +CD.04: Kasaï-Oriental +CD.03: Kasaï-Occidental +CD.09: 'Eastern Province' +CD.02: Équateur +CD.06: Kinshasa +CD.08: Bas-Congo +CD.01: Bandundu +CF.14: Vakaga +CF.11: Ouaka +CF.08: Mbomou +CF.05: Haut-Mbomou +CF.03: Haute-Kotto +CF.02: Basse-Kotto +CF.01: Bamingui-Bangoran +CF.16: Sangha-Mbaéré +CF.13: Ouham-Pendé +CF.12: Ouham +CF.17: Ombella-Mpoko +CF.09: Nana-Mambéré +CF.07: Lobaye +CF.06: Kémo +CF.04: Mambéré-Kadéï +CF.15: Nana-Grébizi +CF.18: Bangui +CG.10: Sangha +CG.11: Pool +CG.08: Plateaux +CG.07: Niari +CG.06: Likouala +CG.05: Lékoumou +CG.04: Kouilou +CG.13: Cuvette +CG.01: Bouenza +CG.12: Brazzaville +CG.14: Cuvette-Ouest +CG.7280295: Pointe-Noire +CH.ZH: Zurich +CH.ZG: Zug +CH.VD: Vaud +CH.VS: Valais +CH.UR: Uri +CH.TI: Ticino +CH.TG: Thurgau +CH.SO: Solothurn +CH.SZ: Schwyz +CH.SH: Schaffhausen +CH.SG: 'Saint Gallen' +CH.OW: Obwalden +CH.NW: Nidwalden +CH.NE: Neuchâtel +CH.LU: Lucerne +CH.JU: Jura +CH.GR: Grisons +CH.GL: Glarus +CH.GE: Geneva +CH.FR: Fribourg +CH.BE: Bern +CH.BS: Basel-City +CH.BL: Basel-Landschaft +CH.AR: 'Appenzell Ausserrhoden' +CH.AI: 'Canton d''Appenzell Rhoden-Intérieur' +CH.AG: Aargau +CI.82: Lagunes +CI.89: Sud-Comoé +CI.74: Agnéby +CI.80: Haut-Sassandra +CI.87: Savanes +CI.90: 'Vallée du Bandama' +CI.85: Moyen-Comoé +CI.78: 'Dix-Huit Montagnes' +CI.81: Lacs +CI.92: Zanzan +CI.76: Bas-Sassandra +CI.91: Worodougou +CI.77: Denguélé +CI.88: Sud-Bandama +CI.79: Fromager +CI.86: Nʼzi-Comoé +CI.83: Marahoué +CI.84: Moyen-Cavally +CI.75: Bafing +CL.01: Valparaíso +CL.15: 'Tarapacá Region' +CL.12: Santiago +CL.11: Maule +CL.14: 'Los Lagos' +CL.08: 'O''Higgins' +CL.07: Coquimbo +CL.06: Biobío +CL.05: Atacama +CL.04: Araucanía +CL.03: Antofagasta +CL.02: Aisén +CL.10: Magallanes +CL.16: 'Arica y Parinacota' +CL.17: 'Los Ríos' +CM.09: 'South-West Province' +CM.14: 'South Province' +CM.08: 'West Region' +CM.07: 'North-West Province' +CM.13: 'North Province' +CM.05: 'Littoral Province' +CM.12: 'Far North Region' +CM.04: 'East Province' +CM.11: 'Centre Region' +CM.10: 'Adamaoua Province' +CN.14: 'Tibet Autonomous Region' +CN.06: 'Qinghai Sheng' +CN.13: 'Xinjiang Uygur Zizhiqu' +CN.02: 'Zhejiang Sheng' +CN.29: Yunnan +CN.28: 'Tianjin Shi' +CN.32: Sichuan +CN.24: 'Shanxi Sheng' +CN.23: 'Shanghai Shi' +CN.25: 'Shandong Sheng' +CN.26: Shaanxi +CN.21: 'Ningxia Huizu Zizhiqu' +CN.03: 'Jiangxi Sheng' +CN.04: 'Jiangsu Sheng' +CN.11: Hunan +CN.12: Hubei +CN.09: 'Henan Sheng' +CN.10: Hebei +CN.31: Hainan +CN.18: 'Guizhou Sheng' +CN.16: 'Guangxi Zhuangzu Zizhiqu' +CN.30: 'Guangdong Province' +CN.15: 'Gansu Sheng' +CN.07: Fujian +CN.33: 'Chongqing Shi' +CN.01: 'Anhui Sheng' +CN.20: 'Inner Mongolia' +CN.19: Liaoning +CN.05: 'Jilin Sheng' +CN.08: 'Heilongjiang Sheng' +CN.22: Beijing +CO.31: Vichada +CO.30: Vaupés +CO.29: 'Valle del Cauca' +CO.28: Tolima +CO.27: Sucre +CO.26: Santander +CO.25: 'Archipiélago de San Andrés, Providencia y Santa Catalina' +CO.24: Risaralda +CO.23: Quindío +CO.22: Putumayo +CO.21: 'Norte de Santander' +CO.20: Nariño +CO.19: Meta +CO.38: Magdalena +CO.17: 'La Guajira' +CO.16: Huila +CO.14: Guaviare +CO.15: Guainía +CO.33: Cundinamarca +CO.12: Córdoba +CO.11: Chocó +CO.10: Cesar +CO.09: Cauca +CO.32: Casanare +CO.08: Caquetá +CO.37: Caldas +CO.36: Boyacá +CO.35: Bolívar +CO.34: 'Bogota D.C.' +CO.04: Atlántico +CO.03: Arauca +CO.02: 'Departamento de Antioquia' +CO.01: Amazonas +CR.08: 'San José' +CR.07: Puntarenas +CR.06: Limón +CR.04: Heredia +CR.03: Guanacaste +CR.02: Cartago +CR.01: Alajuela +CU.16: 'Villa Clara' +CU.15: 'Santiago de Cuba' +CU.14: 'Sancti Spíritus' +CU.01: 'Pinar del Río' +CU.03: Matanzas +CU.13: 'Las Tunas' +CU.04: 'Isla de la Juventud' +CU.12: Holguín +CU.10: Guantánamo +CU.09: Granma +CU.02: 'Ciudad de La Habana' +CU.08: Cienfuegos +CU.07: 'Ciego de Ávila' +CU.05: Camagüey +CU.AR: 'Provincia Artemisa' +CU.MA: 'Provincia Mayabeque' +CV.20: Tarrafal +CV.11: 'São Vicente' +CV.15: 'Santa Catarina' +CV.08: 'Sal Municipality' +CV.07: 'Ribeira Grande' +CV.14: Praia +CV.05: Paul +CV.04: Maio +CV.02: Brava +CV.01: 'Boa Vista' +CV.13: Mosteiros +CV.16: 'Santa Cruz' +CV.17: 'São Domingos' +CV.18: 'São Filipe' +CV.19: 'São Miguel' +CV.21: 'Porto Novo' +CV.22: 'Ribeira Brava' +CV.24: 'Santa Catarina do Fogo' +CV.26: 'São Salvador do Mundo' +CV.27: 'Tarrafal de São Nicolau' +CV.25: 'Concelho de São Lourenço dos Órgãos' +CV.23: 'Ribeira Grande de Santiago' +CY.06: Pafos +CY.04: Lefkosia +CY.05: Lemesos +CY.03: Larnaka +CY.02: Keryneia +CY.01: Ammochostos +CZ.52: Praha +CZ.78: 'South Moravian Region' +CZ.79: Jihočeský +CZ.80: Vysočina +CZ.81: Karlovarský +CZ.82: Královéhradecký +CZ.83: Liberecký +CZ.84: Olomoucký +CZ.85: Moravskoslezský +CZ.86: Pardubický +CZ.87: Plzeňský +CZ.88: Středočeský +CZ.89: Ústecký +CZ.90: Zlínský +DE.15: Thuringia +DE.10: Schleswig-Holstein +DE.14: Saxony-Anhalt +DE.13: Saxony +DE.09: Saarland +DE.08: Rheinland-Pfalz +DE.07: 'North Rhine-Westphalia' +DE.06: 'Lower Saxony' +DE.12: Mecklenburg-Vorpommern +DE.05: Hesse +DE.04: 'Free and Hanseatic City of Hamburg' +DE.03: Bremen +DE.11: Brandenburg +DE.16: Berlin +DE.02: Bavaria +DE.01: 'Baden-Württemberg Region' +DJ.05: Tadjourah +DJ.04: Obock +DJ.07: Djibouti +DJ.06: Dikhil +DJ.01: 'Ali Sabieh' +DJ.08: Arta +DK.17: 'Capital Region' +DK.18: 'Central Jutland' +DK.19: 'North Denmark Region' +DK.20: Zealand +DK.21: 'South Denmark' +DM.11: 'Saint Peter' +DM.10: 'Saint Paul' +DM.09: 'Saint Patrick' +DM.08: 'Saint Mark' +DM.07: 'Saint Luke' +DM.06: 'Saint Joseph' +DM.05: 'Saint John' +DM.04: 'Saint George' +DM.03: 'Saint David' +DM.02: 'Saint Andrew' +DO.27: Valverde +DO.26: 'Santiago Rodríguez' +DO.25: Santiago +DO.24: 'San Pedro de Macorís' +DO.23: 'San Juan' +DO.33: 'San Cristóbal' +DO.21: 'Sánchez Ramírez' +DO.20: Samaná +DO.19: 'Hermanas Mirabal' +DO.18: 'Puerto Plata' +DO.35: Peravia +DO.16: Pedernales +DO.34: 'Distrito Nacional' +DO.32: 'Monte Plata' +DO.15: 'Monte Cristi' +DO.31: 'Monseñor Nouel' +DO.14: 'María Trinidad Sánchez' +DO.30: 'La Vega' +DO.12: 'La Romana' +DO.10: 'La Altagracia' +DO.09: Independencia +DO.29: 'Hato Mayor' +DO.08: Espaillat +DO.28: 'El Seíbo' +DO.11: 'Elías Piña' +DO.06: Duarte +DO.04: Dajabón +DO.03: Barahona +DO.02: Baoruco +DO.01: Azua +DO.36: 'San José de Ocoa' +DO.37: 'Santo Domingo' +DZ.15: Tlemcen +DZ.14: 'Tizi Ouzou' +DZ.56: Tissemsilt +DZ.55: Tipaza +DZ.54: Tindouf +DZ.13: Tiaret +DZ.33: Tébessa +DZ.53: Tamanghasset +DZ.52: 'Souk Ahras' +DZ.31: Skikda +DZ.30: 'Sidi Bel Abbès' +DZ.12: Sétif +DZ.10: Saïda +DZ.51: Relizane +DZ.29: 'Oum el Bouaghi' +DZ.50: Ouargla +DZ.09: Oran +DZ.49: 'Naama النعامة' +DZ.27: Mʼsila +DZ.07: Mostaganem +DZ.48: Mila +DZ.06: Médéa +DZ.26: Mascara +DZ.25: Laghouat +DZ.47: Khenchela +DZ.24: Jijel +DZ.46: Illizi +DZ.23: Guelma +DZ.45: Ghardaïa +DZ.44: 'El Tarf' +DZ.43: 'El Oued' +DZ.42: 'El Bayadh' +DZ.22: Djelfa +DZ.04: Constantine +DZ.41: Chlef +DZ.40: Boumerdes +DZ.21: Bouira +DZ.39: 'Bordj Bou Arréridj' +DZ.20: Blida +DZ.19: Biskra +DZ.18: Bejaïa +DZ.38: Béchar +DZ.03: Batna +DZ.37: Annaba +DZ.01: Alger +DZ.36: 'Aïn Temouchent' +DZ.35: 'Aïn Defla' +DZ.34: Adrar +EC.20: Zamora-Chinchipe +EC.19: Tungurahua +EC.18: Pichincha +EC.17: Pastaza +EC.23: Napo +EC.15: Morona-Santiago +EC.14: Manabí +EC.13: 'Los Ríos' +EC.12: Loja +EC.11: Imbabura +EC.10: Guayas +EC.01: Galápagos +EC.09: Esmeraldas +EC.08: 'El Oro' +EC.07: Cotopaxi +EC.06: Chimborazo +EC.05: Carchi +EC.04: Cañar +EC.03: Bolívar +EC.02: Azuay +EC.22: Sucumbios +EC.24: Orellana +EC.26: 'Santo Domingo de los Tsáchilas' +EC.25: 'Santa Elena' +EE.21: Võrumaa +EE.20: Viljandimaa +EE.19: Valgamaa +EE.18: 'Tartu County' +EE.14: 'Saare County' +EE.13: Raplamaa +EE.12: Põlvamaa +EE.11: Pärnumaa +EE.08: Lääne-Virumaa +EE.07: 'Lääne County' +EE.05: Jõgevamaa +EE.04: Järvamaa +EE.03: Ida-Virumaa +EE.02: Hiiumaa +EE.01: 'Harju County' +EG.24: Sūhāj +EG.27: 'Shamāl Sīnāʼ' +EG.23: Qinā +EG.22: Maţrūḩ +EG.21: 'Kafr ash Shaykh' +EG.26: 'Janūb Sīnāʼ' +EG.20: Dumyāţ +EG.19: 'Būr Sa‘īd' +EG.18: 'Banī Suwayf' +EG.17: Asyūţ +EG.16: Aswān +EG.15: 'As Suways' +EG.14: 'Eastern Province' +EG.13: 'Al Wādī al Jadīd' +EG.12: 'Al Qalyūbīyah' +EG.11: 'Al Qāhirah' +EG.10: 'Al Minyā' +EG.09: 'Al Minūfīyah' +EG.08: 'Al Jīzah' +EG.07: 'Al Ismā‘īlīyah' +EG.06: Alexandria +EG.05: 'Al Gharbīyah' +EG.04: 'Al Fayyūm' +EG.03: 'Al Buḩayrah' +EG.02: 'Al Baḩr al Aḩmar' +EG.01: 'Ad Daqahlīyah' +EG.28: 'Muḩāfaz̧at al Uqşur' +EH.CE: 'Oued Ed-Dahab-Lagouira' +ER.01: Ānseba +ER.02: Debub +ER.03: 'Debubawī Kʼeyih Bahrī' +ER.04: 'Gash Barka' +ER.05: Maʼākel +ER.06: 'Semēnawī Kʼeyih Bahrī' +ES.31: Murcia +ES.CE: Ceuta +ES.07: 'Balearic Islands' +ES.51: Andalusia +ES.53: 'Canary Islands' +ES.54: 'Castille-La Mancha' +ES.57: Extremadura +ES.60: Valencia +ES.34: Asturias +ES.32: Navarre +ES.29: Madrid +ES.27: 'La Rioja' +ES.39: Cantabria +ES.52: Aragon +ES.55: 'Castille and León' +ES.56: Catalonia +ES.58: Galicia +ES.59: 'Basque Country' +ES.ML: Melilla +ET.44: 'Ādīs Ābeba' +ET.45: 'Afar Region' +ET.46: 'Amhara Region' +ET.47: 'Benishangul-Gumuz Region' +ET.48: 'Dire Dawa Region' +ET.49: Gambela +ET.50: 'Harari Region' +ET.51: 'Oromiya Region' +ET.52: 'Somali Region' +ET.53: 'Tigray Region' +ET.54: 'Southern Nations, Nationalities, and People''s Region' +FI.08: Oulu +FI.06: Lapponia +FI.13: 'Southern Finland Province' +FI.14: 'Eastern Finland Province' +FI.15: 'Province of Western Finland' +FJ.05: Western +FJ.03: Northern +FJ.01: Central +FJ.02: Eastern +FJ.04: Rotuma +FM.04: Yap +FM.02: Pohnpei +FM.01: Kosrae +FM.03: Chuuk +FO.VG: Vágar +FO.SU: Suðuroy +FO.ST: Streymoy +FO.SA: Sandoy +FO.NO: Norðoyar +FO.OS: Eysturoy +FR.B9: Rhône-Alpes +FR.B8: 'Provence-Alpes-Côte d''Azur' +FR.B7: Poitou-Charentes +FR.B6: Picardie +FR.B5: 'Pays de la Loire' +FR.B4: Nord-Pas-de-Calais +FR.B3: Midi-Pyrénées +FR.B2: Lorraine +FR.B1: Limousin +FR.A9: Languedoc-Roussillon +FR.A8: Île-de-France +FR.A7: 'Upper Normandy' +FR.A6: Franche-Comté +FR.A5: Corsica +FR.A4: Champagne-Ardenne +FR.A3: Centre +FR.A2: Brittany +FR.A1: Bourgogne +FR.99: 'Lower Normandy' +FR.98: Auvergne +FR.97: Aquitaine +FR.C1: Alsace +GA.09: Woleu-Ntem +GA.08: Ogooué-Maritime +GA.07: Ogooué-Lolo +GA.06: Ogooué-Ivindo +GA.05: Nyanga +GA.04: Ngounié +GA.03: Moyen-Ogooué +GA.02: Haut-Ogooué +GA.01: Estuaire +GB.WLS: Wales +GB.SCT: Scotland +GB.NIR: 'N Ireland' +GB.ENG: England +GD.06: 'Saint Patrick' +GD.05: 'Saint Mark' +GD.04: 'Saint John' +GD.03: 'Saint George' +GD.02: 'Saint David' +GD.01: 'Saint Andrew' +GD.10: 'Carriacou and Petite Martinique' +GE.51: 'T''bilisi' +GE.04: Ajaria +GE.68: 'Kvemo Kartli' +GE.67: Kakheti +GE.65: Guria +GE.66: Imereti +GE.73: 'Shida Kartli' +GE.69: Mtskheta-Mtianeti +GE.70: 'Racha-Lechkhumi and Kvemo Svaneti' +GE.71: 'Samegrelo and Zemo Svaneti' +GE.72: Samtskhe-Javakheti +GE.02: Abkhazia +GF.GF: Guyane +GH.09: Western +GH.08: Volta +GH.11: 'Upper West' +GH.10: 'Upper East' +GH.06: Northern +GH.01: 'Greater Accra' +GH.05: Eastern +GH.04: Central +GH.03: Brong-Ahafo +GH.02: Ashanti +GL.05: Qaasuitsup +GL.04: Kujalleq +GL.06: Qeqqata +GL.07: Sermersooq +GM.05: Western +GM.04: 'Upper River' +GM.07: 'North Bank' +GM.03: 'Central River' +GM.02: 'Lower River' +GM.01: Banjul +GN.04: Conakry +GN.B: 'Boke Region' +GN.F: 'Faranah Region' +GN.K: 'Kankan Region' +GN.D: 'Kindia Region' +GN.L: 'Labé Region' +GN.M: 'Mamou Region' +GN.N: 'Nzerekore Region' +GP.GP: Guadeloupe +GQ.03: Annobón +GQ.04: 'Bioko Norte' +GQ.05: 'Bioko Sur' +GQ.06: 'Centro Sur' +GQ.07: Kié-Ntem +GQ.08: Litoral +GQ.09: Wele-Nzas +GR.736572: 'Mount Athos' +GR.ESYE31: Attica +GR.ESYE24: 'Central Greece' +GR.ESYE12: 'Central Macedonia' +GR.ESYE43: Crete +GR.ESYE11: 'East Macedonia and Thrace' +GR.ESYE21: Epirus +GR.ESYE22: 'Ionian Islands' +GR.ESYE41: 'North Aegean' +GR.ESYE25: Peloponnese +GR.ESYE42: 'South Aegean' +GR.ESYE14: Thessaly +GR.ESYE23: 'West Greece' +GR.ESYE13: 'West Macedonia' +GT.22: Zacapa +GT.21: Totonicapán +GT.20: Suchitepéquez +GT.19: Sololá +GT.18: 'Santa Rosa' +GT.17: 'San Marcos' +GT.16: Sacatepéquez +GT.15: Retalhuleu +GT.14: Quiché +GT.13: Quetzaltenango +GT.12: Petén +GT.11: Jutiapa +GT.10: Jalapa +GT.09: Izabal +GT.08: Huehuetenango +GT.07: Guatemala +GT.06: Escuintla +GT.05: 'El Progreso' +GT.04: Chiquimula +GT.03: Chimaltenango +GT.02: 'Baja Verapaz' +GT.01: 'Alta Verapaz' +GU.PI: 'Piti Municipality' +GU.SR: 'Santa Rita Municipality' +GU.SJ: 'Sinajana Municipality' +GU.TF: 'Talofofo Municipality' +GU.TM: 'Tamuning-Tumon-Harmon Municipality' +GU.UM: 'Umatac Municipality' +GU.YG: 'Yigo Municipality' +GU.YN: 'Yona Municipality' +GU.ME: 'Merizo Municipality' +GU.MA: 'Mangilao Municipality' +GU.AH: 'Agana Heights Municipality' +GU.CP: 'Chalan Pago-Ordot Municipality' +GU.AS: 'Asan-Maina Municipality' +GU.AT: 'Agat Municipality' +GU.DD: 'Dededo Municipality' +GU.BA: 'Barrigada Municipality' +GU.AN: 'Hagåtña Municipality' +GU.IN: 'Inarajan Municipality' +GU.MT: 'Mongmong-Toto-Maite Municipality' +GW.07: Tombali +GW.02: Quinara +GW.04: Oio +GW.10: Gabú +GW.06: Cacheu +GW.05: 'Bolama and Bijagos' +GW.11: 'Bissau Autonomous Region' +GW.12: Biombo +GW.01: Bafatá +GY.19: 'Upper Takutu-Upper Essequibo' +GY.18: 'Upper Demerara-Berbice' +GY.17: Potaro-Siparuni +GY.16: Pomeroon-Supenaam +GY.15: Mahaica-Berbice +GY.14: 'Essequibo Islands-West Demerara' +GY.13: 'East Berbice-Corentyne' +GY.12: Demerara-Mahaica +GY.11: Cuyuni-Mazaruni +GY.10: Barima-Waini +HK.NYL: 'Yuen Long' +HK.NTW: 'Tsuen Wan' +HK.NTP: 'Tai Po' +HK.NSK: 'Sai Kung' +HK.NIS: Islands +HK.HCW: 'Central and Western' +HK.HWC: Wanchai +HK.HEA: Eastern +HK.HSO: Southern +HK.KYT: 'Yau Tsim Mong' +HK.KSS: 'Sham Shui Po' +HK.KKC: 'Kowloon City' +HK.KWT: 'Wong Tai Sin' +HK.KKT: 'Kwon Tong' +HK.NKT: 'Kwai Tsing' +HK.NTM: 'Tuen Mun' +HK.NNO: North +HK.NST: 'Sha Tin' +HN.18: Yoro +HN.17: Valle +HN.16: 'Santa Bárbara' +HN.15: Olancho +HN.14: Ocotepeque +HN.13: Lempira +HN.12: 'La Paz' +HN.11: 'Bay Islands' +HN.10: Intibucá +HN.09: 'Gracias a Dios' +HN.08: 'Francisco Morazán' +HN.07: 'El Paraíso' +HN.06: Cortés +HN.05: Copán +HN.04: Comayagua +HN.03: Colón +HN.02: Choluteca +HN.01: Atlántida +HR.01: Bjelovarsko-Bilogorska +HR.02: Brodsko-Posavska +HR.03: Dubrovačko-Neretvanska +HR.04: Istarska +HR.05: Karlovačka +HR.06: Koprivničko-Križevačka +HR.07: Krapinsko-Zagorska +HR.08: Ličko-Senjska +HR.09: Međimurska +HR.10: Osječko-Baranjska +HR.11: Požeško-Slavonska +HR.12: Primorsko-Goranska +HR.13: Šibensko-Kniniska +HR.14: Sisačko-Moslavačka +HR.15: Splitsko-Dalmatinska +HR.16: Varaždinska +HR.18: Vukovarsko-Srijemska +HR.19: Zadarska +HR.20: Zagrebačka +HR.21: 'Grad Zagreb' +HR.17: Virovitičk-Podravska +HT.13: Sud-Est +HT.12: Sud +HT.11: Ouest +HT.03: Nord-Ouest +HT.10: Nord-Est +HT.09: Nord +HT.14: GrandʼAnse +HT.07: Centre +HT.06: Artibonite +HT.15: Nippes +HU.18: Szabolcs-Szatmár-Bereg +HU.20: Jász-Nagykun-Szolnok +HU.11: Heves +HU.10: Hajdú-Bihar +HU.06: Csongrád +HU.04: Borsod-Abaúj-Zemplén +HU.03: 'Bekes County' +HU.24: Zala +HU.23: Veszprém +HU.22: Vas +HU.21: Tolna +HU.17: Somogy +HU.16: Pest +HU.14: Nógrád +HU.12: Komárom-Esztergom +HU.09: Győr-Moson-Sopron +HU.08: Fejér +HU.05: Budapest +HU.02: 'Baranya county' +HU.01: Bács-Kiskun +ID.26: 'North Sumatra' +ID.01: Aceh +ID.10: 'Daerah Istimewa Yogyakarta' +ID.32: 'South Sumatra' +ID.24: 'West Sumatra' +ID.31: 'North Sulawesi' +ID.22: 'Sulawesi Tenggara' +ID.21: 'Central Sulawesi' +ID.38: 'South Sulawesi' +ID.37: Riau +ID.18: 'East Nusa Tenggara' +ID.17: 'Nusa Tenggara Barat' +ID.28: Maluku +ID.15: Lampung +ID.14: 'East Kalimantan' +ID.13: 'Kalimantan Tengah' +ID.12: 'South Kalimantan' +ID.11: 'West Kalimantan' +ID.08: 'East Java' +ID.07: 'Central Java' +ID.30: 'West Java' +ID.05: Jambi +ID.04: 'Jakarta Raya' +ID.36: Papua +ID.03: Bengkulu +ID.02: Bali +ID.33: Banten +ID.34: Gorontalo +ID.35: Bangka-Belitung +ID.29: 'Maluku Utara' +ID.39: 'West Papua' +ID.41: 'Sulawesi Barat' +ID.40: 'Riau Islands' +IE.C: Connaught +IE.L: Leinster +IE.M: Munster +IE.U: Ulster +IL.06: 'Jerusalem District' +IL.05: 'Tel Aviv' +IL.04: 'Haifa District' +IL.03: 'Northern District' +IL.02: 'Central District' +IL.01: 'Southern District' +IN.28: Bengal +IN.36: 'Uttar Pradesh' +IN.26: Tripura +IN.25: 'Tamil Nādu' +IN.29: Sikkim +IN.24: Rajasthan +IN.23: Punjab +IN.22: Pondicherry +IN.21: Orissa +IN.20: Nāgāland +IN.31: Mizoram +IN.18: Meghālaya +IN.17: Manipur +IN.16: Mahārāshtra +IN.35: 'Madhya Pradesh' +IN.14: Laccadives +IN.13: Kerala +IN.19: Karnātaka +IN.12: Kashmir +IN.11: 'Himachal Pradesh' +IN.10: Haryana +IN.09: Gujarāt +IN.32: 'Daman and Diu' +IN.33: Goa +IN.07: NCT +IN.06: 'Dādra and Nagar Haveli' +IN.05: Chandīgarh +IN.34: Bihār +IN.03: Assam +IN.30: 'Arunāchal Pradesh' +IN.02: 'Andhra Pradesh' +IN.01: 'Andaman and Nicobar Islands' +IN.37: Chhattisgarh +IN.38: Jharkhand +IN.39: Uttarakhand +IQ.02: 'Al Başrah' +IQ.16: Wāsiţ +IQ.18: 'Şalāḩ ad Dīn' +IQ.15: Nīnawá +IQ.14: Maysan +IQ.12: Karbalāʼ +IQ.11: Arbīl +IQ.10: 'Diyala Province' +IQ.09: 'Dhi Qar' +IQ.08: Dahūk +IQ.07: 'Mayorality of Baghdad' +IQ.06: Bābil +IQ.13: 'At Taʼmīm' +IQ.05: 'As Sulaymānīyah' +IQ.17: 'An Najaf' +IQ.04: 'Al Qādisīyah' +IQ.03: 'Al Muthanná' +IQ.01: Anbar +IR.26: Tehrān +IR.36: Zanjan +IR.40: Yazd +IR.25: Semnān +IR.35: Māzandarān +IR.34: Markazi +IR.23: Lorestān +IR.16: Kordestān +IR.05: 'Kohgīlūyeh va Būyer Aḩmad' +IR.15: Khūzestān +IR.13: Kermānshāh +IR.29: Kermān +IR.10: Īlām +IR.11: Hormozgān +IR.09: Hamadān +IR.08: Gīlān +IR.07: Fārs +IR.03: 'Chahār Maḩāll va Bakhtīārī' +IR.22: Bushehr +IR.33: 'East Azarbaijan' +IR.01: 'Āz̄ārbāyjān-e Gharbī' +IR.32: Ardabīl +IR.28: 'Ostān-e Eşfahān' +IR.37: Golestān +IR.38: Qazvīn +IR.39: Qom +IR.04: 'Sīstān va Balūchestān' +IR.41: 'Khorāsān-e Jonūbī' +IR.42: 'Razavi Khorasan' +IR.43: 'Khorāsān-e Shomālī' +IR.44: Alborz +IS.41: Northwest +IS.40: Northeast +IS.38: East +IS.42: South +IS.39: 'Capital Region' +IS.43: 'Southern Peninsula' +IS.45: West +IS.44: Westfjords +IT.15: Sicily +IT.14: Sardinia +IT.03: Calabria +IT.20: Veneto +IT.19: 'Aosta Valley' +IT.18: Umbria +IT.17: 'Trentino-Alto Adige' +IT.16: Tuscany +IT.13: Apulia +IT.12: Piedmont +IT.11: Molise +IT.10: 'The Marches' +IT.09: Lombardy +IT.08: Liguria +IT.07: Latium +IT.06: 'Friuli Venezia Giulia' +IT.05: Emilia-Romagna +IT.04: Campania +IT.02: Basilicate +IT.01: Abruzzo +JM.16: Westmoreland +JM.15: Trelawny +JM.14: 'Saint Thomas' +JM.13: 'Saint Mary' +JM.12: 'Saint James' +JM.11: 'St. Elizabeth' +JM.10: 'Saint Catherine' +JM.09: 'Saint Ann' +JM.08: 'Saint Andrew' +JM.07: Portland +JM.04: Manchester +JM.17: Kingston +JM.02: 'Hanover Parish' +JM.01: Clarendon +JO.19: Ma’an +JO.18: Irbid +JO.17: Zarqa +JO.12: Tafielah +JO.16: Amman +JO.15: Mafraq +JO.09: Karak +JO.02: Balqa +JO.20: Ajlun +JO.22: Jerash +JO.21: Aqaba +JO.23: Madaba +JP.46: Yamanashi +JP.45: Yamaguchi +JP.43: Wakayama +JP.42: Toyama +JP.41: Tottori +JP.40: Tōkyō +JP.39: Tokushima +JP.38: Tochigi +JP.37: Shizuoka +JP.36: 'Shimane Prefecture' +JP.35: Shiga +JP.34: Saitama +JP.33: Saga +JP.32: Ōsaka +JP.47: Okinawa +JP.31: Okayama +JP.30: Ōita +JP.29: Niigata +JP.28: Nara +JP.27: Nagasaki +JP.26: Nagano +JP.25: Miyazaki +JP.23: Mie +JP.22: Kyōto +JP.21: 'Kumamoto Prefecture' +JP.20: Kōchi +JP.19: Kanagawa +JP.18: Kagoshima +JP.17: Kagawa +JP.15: Ishikawa +JP.13: Hyōgo +JP.11: Hiroshima +JP.10: 'Gunma Prefecture' +JP.09: Gifu +JP.07: Fukuoka +JP.06: Fukui +JP.05: Ehime +JP.01: Aichi +JP.44: Yamagata +JP.24: Miyagi +JP.16: Iwate +JP.14: Ibaraki +JP.08: Fukushima +JP.04: Chiba +JP.02: Akita +JP.12: Hokkaidō +JP.03: 'Aomori Prefecture' +KE.55: 'West Pokot' +KE.54: Wajir +KE.52: 'Uasin Gishu' +KE.51: Turkana +KE.50: 'Trans Nzoia' +KE.49: 'Tharaka - Nithi' +KE.48: 'Tana River' +KE.46: Siaya +KE.45: Samburu +KE.05: 'Nairobi Area' +KE.38: 'Murang''A' +KE.37: Mombasa +KE.35: Meru +KE.34: Marsabit +KE.33: Mandera +KE.29: 'Laikipia District' +KE.28: Kwale +KE.27: Kitui +KE.26: Kisumu +KE.25: Kisii +KE.24: Kirinyaga +KE.23: Kilifi +KE.22: Kiambu +KE.21: Kericho +KE.20: Kakamega +KE.18: Isiolo +KE.16: Garissa +KE.15: Embu +KE.13: Busia +KE.12: Bungoma +KE.10: Baringo +KE.43: Nyandarua +KE.53: Vihiga +KE.30: Lamu +KE.31: Machakos +KE.32: Makueni +KE.14: Elegeyo-Marakwet +KE.47: 'Taita Taveta' +KE.19: Kajiado +KE.44: Nyeri +KE.17: 'Homa Bay' +KE.11: Bomet +KE.36: Migori +KE.39: Nakuru +KE.41: Narok +KE.42: Nyamira +KE.40: Nandi +KG.08: Osh +KG.09: 'Batken Oblasty' +KG.06: Talas +KG.04: Naryn +KG.07: Ysyk-Köl +KG.01: Bishkek +KG.03: Jalal-Abad +KG.02: Chüy +KH.12: Poŭthĭsăt +KH.29: 'Battambang Province' +KH.19: Takeo +KH.18: 'Svay Rieng' +KH.17: 'Stung Treng' +KH.27: 'Ŏtâr Méanchey' +KH.24: 'Siem Reap' +KH.23: Ratanakiri +KH.14: 'Prey Veng' +KH.13: 'Preah Vihear' +KH.22: 'Phnom Penh' +KH.30: Pailin +KH.10: Mondolkiri +KH.09: Kratie +KH.26: Kep +KH.08: 'Kaôh Kŏng' +KH.07: Kandal +KH.21: Kampot +KH.05: 'Kampong Thom' +KH.04: 'Kampong Speu' +KH.03: 'Kampong Chhnang' +KH.02: 'Kampong Cham' +KH.28: 'Preah Sihanouk' +KH.25: 'Banteay Meanchey Province' +KI.01: 'Gilbert Islands' +KI.02: 'Line Islands' +KI.03: 'Phoenix Islands' +KM.03: Mohéli +KM.02: 'Grande Comore' +KM.01: Anjouan +KN.15: 'Trinity Palmetto Point' +KN.13: 'Saint Thomas Middle Island' +KN.12: 'Saint Thomas Lowland' +KN.11: 'Saint Peter Basseterre' +KN.10: 'Saint Paul Charlestown' +KN.09: 'Saint Paul Capesterre' +KN.08: 'Saint Mary Cayon' +KN.07: 'Saint John Figtree' +KN.06: 'Saint John Capesterre' +KN.05: 'Saint James Windwa' +KN.04: 'Saint George Gingerland' +KN.03: 'Saint George Basseterre' +KN.02: 'Saint Anne Sandy Point' +KN.01: 'Christ Church Nichola Town' +KP.12: 'P''yŏngyang-si' +KP.15: 'P''yŏngan-namdo' +KP.11: 'P''yŏngan-bukto' +KP.09: Gangwon +KP.06: Hwanghae-namdo +KP.07: Hwanghae-bukto +KP.03: Hamgyŏng-namdo +KP.13: Yanggang-do +KP.17: Hamgyŏng-bukto +KP.01: Chagang-do +KP.18: 'Najin Sŏnbong-si' +KR.21: Ulsan +KR.19: Daejeon +KR.15: Daegu +KR.11: Seoul +KR.10: Busan +KR.14: 'North Gyeongsang' +KR.13: 'Gyeonggi Province' +KR.18: Gwangju +KR.06: Gangwon +KR.12: Incheon +KR.17: 'South Chungcheong' +KR.05: 'North Chungcheong' +KR.16: 'South Jeolla' +KR.03: 'North Jeolla' +KR.01: Jeju +KR.20: 'South Gyeongsang' +KR.22: Sejong +KW.08: Ḩawallī +KW.02: 'Al Asimah Governorate' +KW.05: 'Al Jahrāʼ' +KW.07: 'Al Farwaniyah' +KW.04: 'Al Aḩmadī' +KW.09: 'Muḩāfaz̧at Mubārak al Kabīr' +KZ.07: 'Batys Qazaqstan' +KZ.09: Mangghystaū +KZ.06: Atyraū +KZ.04: Aqtöbe +KZ.15: 'East Kazakhstan' +KZ.03: Aqmola +KZ.16: 'Soltüstik Qazaqstan' +KZ.11: Pavlodar +KZ.14: Qyzylorda +KZ.13: Qostanay +KZ.12: Qaraghandy +KZ.17: Zhambyl +KZ.10: 'Ongtüstik Qazaqstan' +KZ.02: 'Almaty Qalasy' +KZ.01: Almaty +KZ.08: 'Bayqongyr Qalasy' +KZ.05: 'Astana Qalasy' +LA.14: Xiangkhoang +LA.13: Xiagnabouli +LA.27: 'Vientiane Province' +LA.20: Savannahkhét +LA.19: Salavan +LA.18: Phôngsali +LA.07: Oudômxai +LA.17: Louangphabang +LA.16: Loungnamtha +LA.15: Khammouan +LA.03: Houaphan +LA.02: Champasak +LA.01: Attapu +LA.26: Xékong +LA.22: Bokèo +LA.23: Bolikhamxai +LA.24: 'Vientiane Prefecture' +LB.05: Mont-Liban +LB.04: Beyrouth +LB.09: Liban-Nord +LB.06: Liban-Sud +LB.08: Béqaa +LB.07: Nabatîyé +LB.10: Aakkâr +LB.11: Baalbek-Hermel +LC.10: Vieux-Fort +LC.09: Soufrière +LC.11: Praslin +LC.08: Micoud +LC.07: Laborie +LC.06: Gros-Islet +LC.05: Dennery +LC.02: Dauphin +LC.04: Choiseul +LC.03: Castries +LC.01: Anse-la-Raye +LI.11: Vaduz +LI.10: Triesenberg +LI.09: Triesen +LI.08: Schellenberg +LI.07: Schaan +LI.06: Ruggell +LI.05: Planken +LI.04: Mauren +LI.03: Gamprin +LI.02: Eschen +LI.01: Balzers +LK.36: Western +LK.35: Uva +LK.34: Southern +LK.33: Sabaragamuwa +LK.32: 'North Western' +LK.30: 'North Central' +LK.29: Central +LK.38: 'Northern Province' +LK.37: 'Eastern Province' +LR.10: Sinoe +LR.09: Nimba +LR.14: Montserrado +LR.13: Maryland +LR.20: Lofa +LR.19: 'Grand Gedeh' +LR.12: 'Grand Cape Mount' +LR.11: 'Grand Bassa' +LR.01: Bong +LR.15: Bomi +LR.16: 'Grand Kru' +LR.17: Margibi +LR.18: 'River Cess' +LR.21: Gbarpolu +LR.22: 'River Gee' +LS.19: Thaba-Tseka +LS.18: Quthing +LS.17: 'Qachaʼs Nek' +LS.16: Mokhotlong +LS.15: 'Mohaleʼs Hoek' +LS.14: Maseru +LS.13: Mafeteng +LS.12: Leribe +LS.11: Butha-Buthe +LS.10: Berea +LT.56: 'Alytaus Apskritis' +LT.57: 'Kauno Apskritis' +LT.58: 'Klaipėdos Apskritis' +LT.59: 'Marijampolės Apskritis' +LT.60: 'Panevėžio Apskritis' +LT.61: 'Šiaulių Apskritis' +LT.62: 'Tauragės Apskritis' +LT.63: 'Telšių Apskritis' +LT.64: 'Utenos Apskritis' +LT.65: 'Vilniaus Apskritis' +LU.03: Luxembourg +LU.02: Grevenmacher +LU.01: Diekirch +LV.33: 'Ventspils Rajons' +LV.32: Ventspils +LV.31: 'Valmieras Rajons' +LV.30: 'Valkas Rajons' +LV.29: 'Tukuma Rajons' +LV.28: 'Talsu Rajons' +LV.27: 'Saldus Rajons' +LV.25: Rīga +LV.24: 'Rēzeknes Rajons' +LV.23: Rēzekne +LV.22: 'Preiļu Rajons' +LV.21: 'Ogres Rajons' +LV.20: 'Madonas Rajons' +LV.19: 'Ludzas Rajons' +LV.18: 'Limbažu Rajons' +LV.16: Liepāja +LV.15: 'Kuldīgas Rajons' +LV.14: 'Krāslavas Rajons' +LV.13: Jūrmala +LV.12: 'Jelgavas Rajons' +LV.11: Jelgava +LV.10: 'Jēkabpils Rajons' +LV.09: 'Gulbenes Rajons' +LV.08: 'Dobeles Rajons' +LV.07: 'Daugavpils municipality' +LV.06: Daugavpils +LV.05: 'Cēsu Rajons' +LV.04: 'Bauskas Rajons' +LV.03: 'Balvu Rajons' +LV.02: 'Alūksnes Rajons' +LV.01: 'Aizkraukles Rajons' +LV.60: 'Dundagas Novads' +LV.40: 'Alsungas Novads' +LV.A5: 'Pāvilostas Novads' +LV.99: 'Nīcas Novads' +LV.B6: 'Rucavas Novads' +LV.65: 'Grobiņas Novads' +LV.61: 'Durbes Novads' +LV.37: 'Aizputes Novads' +LV.A8: 'Priekules Novads' +LV.D7: 'Vaiņodes Novads' +LV.C9: 'Skrundas Novads' +LV.51: 'Brocēnu Novads' +LV.B4: 'Rojas Novads' +LV.77: 'Kandavas Novads' +LV.44: 'Auces Novads' +LV.73: 'Jaunpils Novads' +LV.62: 'Engures Novads' +LV.D5: 'Tērvetes Novads' +LV.A3: 'Ozolnieku Novads' +LV.B9: 'Rundāles Novads' +LV.45: 'Babītes Novads' +LV.95: 'Mārupes Novads' +LV.A2: 'Olaines Novads' +LV.67: 'Iecavas Novads' +LV.80: 'Ķekavas Novads' +LV.C3: 'Salaspils Novads' +LV.46: 'Baldones Novads' +LV.D2: 'Stopiņu Novads' +LV.53: 'Carnikavas Novads' +LV.34: 'Ādažu Novads' +LV.64: 'Garkalnes Novads' +LV.E4: 'Vecumnieku Novads' +LV.79: 'Ķeguma Novads' +LV.87: 'Lielvārdes Novads' +LV.C8: 'Skrīveru Novads' +LV.71: 'Jaunjelgavas Novads' +LV.98: 'Neretas Novads' +LV.E6: 'Viesītes Novads' +LV.C2: 'Salas Novads' +LV.74: Jēkabpils +LV.38: 'Aknīstes Novads' +LV.69: 'Ilūkstes Novads' +LV.E2: 'Vārkavas Novads' +LV.90: 'Līvānu Novads' +LV.E1: 'Varakļānu Novads' +LV.E8: 'Viļānu Novads' +LV.B3: 'Riebiņu Novads' +LV.35: 'Aglonas Novads' +LV.56: 'Ciblas Novads' +LV.E9: 'Zilupes Novads' +LV.E7: 'Viļakas Novads' +LV.47: 'Baltinavas Novads' +LV.57: 'Dagdas Novads' +LV.78: 'Kārsavas Novads' +LV.B7: 'Rugāju Novads' +LV.55: 'Cesvaines Novads' +LV.91: 'Lubānas Novads' +LV.85: 'Krustpils Novads' +LV.A6: 'Pļaviņu Novads' +LV.82: 'Kokneses Novads' +LV.68: 'Ikšķiles Novads' +LV.B5: 'Ropažu Novads' +LV.70: 'Inčukalna Novads' +LV.84: 'Krimuldas Novads' +LV.C7: 'Siguldas Novads' +LV.88: 'Līgatnes Novads' +LV.94: 'Mālpils Novads' +LV.C6: 'Sējas Novads' +LV.C5: 'Saulkrastu Novads' +LV.C1: 'Salacgrīvas Novads' +LV.39: 'Alojas Novads' +LV.97: 'Naukšēnu Novads' +LV.B8: 'Rūjienas Novads' +LV.96: 'Mazsalacas Novads' +LV.52: 'Burtnieku Novads' +LV.A4: 'Pārgaujas Novads' +LV.81: 'Kocēnu Novads' +LV.42: 'Amatas Novads' +LV.A9: 'Priekuļu Novads' +LV.B1: 'Raunas Novads' +LV.D3: 'Strenču Novads' +LV.50: 'Beverīnas Novads' +LV.D1: 'Smiltenes Novads' +LV.72: 'Jaunpiebalgas Novads' +LV.63: 'Ērgļu Novads' +LV.E3: 'Vecpiebalgas Novads' +LV.43: 'Apes Novads' +LV.F1: 'Mērsraga Novads' +LY.70: Darnah +LY.69: Banghāzī +LY.66: 'Al Marj' +LY.65: 'Al Kufrah' +LY.63: 'Al Jabal al Akhḑar' +LY.77: Ţarābulus +LY.76: Surt +LY.75: Sabhā +LY.74: 'Sha‘bīyat Nālūt' +LY.73: Murzuq +LY.72: Mişrātah +LY.71: 'Sha‘bīyat Ghāt' +LY.68: 'Az Zāwiyah' +LY.78: 'Ash Shāţiʼ' +LY.64: 'Al Jufrah' +LY.67: 'An Nuqāţ al Khams' +LY.79: 'Sha‘bīyat al Buţnān' +LY.80: 'Sha‘bīyat al Jabal al Gharbī' +LY.81: 'Sha‘bīyat al Jafārah' +LY.82: 'Al Marqab' +LY.83: 'Sha‘bīyat al Wāḩāt' +LY.84: 'Sha‘bīyat Wādī al Ḩayāt' +MA.49: Rabat-Salé-Zemmour-Zaër +MA.48: Meknès-Tafilalet +MA.47: 'Marrakech-Tensift-Al Haouz' +MA.46: Fès-Boulemane +MA.45: 'Grand Casablanca' +MA.50: Chaouia-Ouardigha +MA.51: Doukkala-Abda +MA.52: 'Gharb-Chrarda-Beni Hssen' +MA.53: 'Guelmim-Es Smara' +MA.54: 'Oriental Region' +MA.55: Souss-Massa-Drâa +MA.56: Tadla-Azilal +MA.57: Tanger-Tétouan +MA.58: 'Taza-Al Hoceima-Taounate' +MA.59: 'Laâyoune-Boujdour-Sakia El Hamra' +MA.EH: 'Oued ed Dahab-Lagouira' +MC.00: '' +MD.73: 'Raionul Edineţ' +MD.92: 'Ungheni District' +MD.91: 'Raionul Teleneşti' +MD.90: 'Raionul Taraclia' +MD.88: Ştefan-Vodă +MD.89: 'Strășeni District' +MD.87: 'Raionul Soroca' +MD.84: 'Raionul Rîşcani' +MD.83: 'Raionul Rezina' +MD.82: 'Raionul Orhei' +MD.81: 'Raionul Ocniţa' +MD.59: 'Raionul Anenii Noi' +MD.80: 'Raionul Nisporeni' +MD.79: 'Raionul Leova' +MD.85: 'Raionul Sîngerei' +MD.69: 'Raionul Criuleni' +MD.78: 'Raionul Ialoveni' +MD.57: Chişinău +MD.67: Căuşeni +MD.65: 'Raionul Cantemir' +MD.66: Călăraşi +MD.64: 'Cahul District' +MD.76: 'Raionul Glodeni' +MD.75: 'Raionul Floreşti' +MD.74: 'Raionul Făleşti' +MD.72: Dubăsari +MD.71: 'Drochia District' +MD.70: 'Raionul Donduşeni' +MD.68: 'Raionul Cimişlia' +MD.63: 'Raionul Briceni' +MD.61: 'Raionul Basarabeasca' +MD.77: 'Raionul Hînceşti' +MD.86: 'Raionul Şoldăneşti' +MD.58: 'Stînga Nistrului' +MD.51: Găgăuzia +MD.62: Bender +MD.60: Bălţi +ME.17: 'Opština Rožaje' +ME.21: 'Opština Žabljak' +ME.20: Ulcinj +ME.19: Tivat +ME.16: Podgorica +ME.18: 'Opština Šavnik' +ME.15: 'Opština Plužine' +ME.14: Pljevlja +ME.13: 'Opština Plav' +ME.12: 'Opština Nikšić' +ME.11: Mojkovac +ME.10: Kotor +ME.09: 'Opština Kolašin' +ME.03: Berane +ME.08: 'Herceg Novi' +ME.07: Danilovgrad +ME.06: Cetinje +ME.05: Budva +ME.04: 'Bijelo Polje' +ME.02: Bar +ME.01: Andrijevica +MG.7670842: Diana +MG.7670846: Sava +MG.7670847: Sofia +MG.7670848: Analanjirofo +MG.7670849: Boeny +MG.7670850: Betsiboka +MG.7670851: 'Alaotra Mangoro' +MG.7670852: Melaky +MG.7670853: Bongolava +MG.7670854: Vakinankaratra +MG.7670855: Itasy +MG.7670856: Analamanga +MG.7670857: Atsinanana +MG.7670902: Menabe +MG.7670904: 'Amoron''i Mania' +MG.7670905: 'Upper Matsiatra' +MG.7670906: 'Vatovavy Fitovinany' +MG.7670907: Ihorombe +MG.7670908: 'Atsimo-Atsinanana Region' +MG.7670910: Anosy +MG.7670911: Androy +MG.7670913: Atsimo-Andrefana +MH.007: 'Ailinginae Atoll' +MH.010: 'Ailinglaplap Atoll' +MH.030: 'Ailuk Atoll' +MH.040: 'Arno Atoll' +MH.050: 'Aur Atoll' +MH.060: 'Bikar Atoll' +MH.070: 'Bikini Atoll' +MH.080: 'Ebon Atoll' +MH.090: 'Enewetak Atoll' +MH.100: 'Erikub Atoll' +MH.120: 'Jaluit Atoll' +MH.150: 'Kwajalein Atoll' +MH.160: 'Lae Atoll' +MH.180: 'Likiep Atoll' +MH.190: 'Majuro Atoll' +MH.300: 'Maloelap Atoll' +MH.320: 'Mili Atoll' +MH.330: 'Namdrik Atoll' +MH.340: 'Namu Atoll' +MH.350: 'Rongelap Atoll' +MH.360: 'Rongrik Atoll' +MH.385: 'Taka Atoll' +MH.073: 'Bokak Atoll' +MH.390: 'Ujae Atoll' +MH.400: Ujelang +MH.410: 'Utrik Atoll' +MH.420: 'Wotho Atoll' +MH.430: 'Wotje Atoll' +MH.110: 'Jabat Island' +MH.130: 'Jemo Island' +MH.140: 'Kili Island' +MH.170: 'Lib Island' +MH.310: 'Mejit Island' +MK.E9: Valandovo +MK.86: Resen +MK.51: Kratovo +MK.78: Pehčevo +MK.72: 'Novo Selo' +MK.11: Bosilovo +MK.A9: Vasilevo +MK.E5: Dojran +MK.08: Bogdanci +MK.47: Konče +MK.62: 'Makedonska Kamenica' +MK.C6: Zrnovci +MK.40: Karbinci +MK.25: 'Demir Kapija' +MK.87: Rosoman +MK.35: Gradsko +MK.60: Lozovo +MK.19: Češinovo +MK.E1: Novaci +MK.04: Berovo +MK.06: Bitola +MK.D9: Mogila +MK.01: Aračinovo +MK.C7: Bogovinje +MK.12: Brvenica +MK.C8: Čair +MK.C9: Čaška +MK.D1: Centar +MK.18: 'Centar Župa' +MK.20: Čučer-Sandevo +MK.D2: Debar +MK.22: Delčevo +MK.D3: 'Demir Hisar' +MK.28: Dolneni +MK.29: 'Opstina Gjorce Petrov' +MK.30: Drugovo +MK.32: 'Gazi Baba' +MK.33: Gevgelija +MK.D4: Gostivar +MK.36: Ilinden +MK.D5: Jegunovce +MK.41: Karpoš +MK.D6: Kavadarci +MK.43: Kičevo +MK.44: 'Kisela Voda' +MK.46: Kočani +MK.52: 'Kriva Palanka' +MK.53: Krivogaštani +MK.54: Kruševo +MK.D7: Kumanovo +MK.59: 'Opstina Lipkovo' +MK.D8: 'Makedonski Brod' +MK.69: Negotino +MK.E2: Ohrid +MK.77: Oslomej +MK.79: Petrovec +MK.80: Plasnica +MK.E3: Prilep +MK.83: Probištip +MK.84: Radoviš +MK.85: 'Opstina Rankovce' +MK.E4: 'Opština Rostuša' +MK.90: Saraj +MK.92: Sopište +MK.97: 'Staro Nagoričane' +MK.98: Štip +MK.E6: Struga +MK.E7: Strumica +MK.A2: Studeničani +MK.A3: 'Šuto Orizari' +MK.A4: 'Sveti Nikole' +MK.A5: Tearce +MK.E8: Tetovo +MK.F1: Veles +MK.B3: Vevčani +MK.B4: Vinica +MK.B6: Vraneštica +MK.B7: Vrapčište +MK.C1: Zajas +MK.C2: Zelenikovo +MK.C3: Želino +MK.F3: Aerodrom +MK.F4: Butel +MK.F5: Debarca +ML.08: 'Tombouctou Region' +ML.06: 'Sikasso Region' +ML.05: 'Ségou Region' +ML.04: 'Mopti Region' +ML.07: 'Koulikoro Region' +ML.03: 'Kayes Region' +ML.09: 'Gao Region' +ML.01: Bamako +ML.10: 'Kidal Region' +MM.12: Tanintharyi +MM.11: Shan +MM.10: Sagain +MM.17: Yangon +MM.01: Rakhine +MM.16: Bago +MM.13: Mon +MM.08: Mandalay +MM.15: Magway +MM.06: Kayah +MM.05: Kayin +MM.04: Kachin +MM.03: Ayeyarwady +MM.02: Chin +MN.19: Uvs +MN.12: Hovd +MN.10: Govĭ-Altay +MN.09: Dzabkhan +MN.03: Bayan-Ölgiy +MN.02: Bayanhongor +MN.20: Ulaanbaatar +MN.18: 'Central Aimak' +MN.17: Sühbaatar +MN.16: Selenge +MN.15: Övörhangay +MN.14: 'Ömnögovi Province' +MN.13: Hövsgöl +MN.11: Hentiy +MN.08: 'Middle Govĭ' +MN.07: 'East Gobi Aymag' +MN.06: 'East Aimak' +MN.21: Bulgan +MN.01: Arhangay +MN.23: 'Darhan Uul' +MN.24: Govĭ-Sumber +MN.25: Orhon +MO.02: Macau +MO.01: Ilhas +MP.100: 'Rota Municipality' +MP.110: 'Saipan Municipality' +MP.120: 'Tinian Municipality' +MP.085: 'Northern Islands Municipality' +MQ.MQ: Martinique +MR.06: Trarza +MR.11: 'Tiris Zemmour' +MR.09: Tagant +MR.NKC: Nouakchott +MR.12: Inchiri +MR.02: 'Hodh el Gharbi' +MR.01: 'Hodh ech Chargui' +MR.10: Guidimaka +MR.04: Gorgol +MR.08: 'Dakhlet Nouadhibou' +MR.05: Brakna +MR.03: Assaba +MR.07: Adrar +MS.03: 'Saint Peter' +MS.02: 'Saint Georges' +MS.01: 'Saint Anthony' +MT.01: Attard +MT.02: Balzan +MT.03: Il-Birgu +MT.04: Birkirkara +MT.05: Birżebbuġa +MT.06: Bormla +MT.07: Dingli +MT.08: Il-Fgura +MT.09: Il-Furjana +MT.10: Il-Fontana +MT.11: Għajnsielem +MT.12: L-Għarb +MT.13: 'Ħal Għargħur' +MT.14: L-Għasri +MT.15: 'Ħal Għaxaq' +MT.16: Il-Gudja +MT.17: Il-Gżira +MT.18: Il-Ħamrun +MT.19: L-Iklin +MT.20: L-Imdina +MT.21: L-Imġarr +MT.22: L-Imqabba +MT.23: L-Imsida +MT.24: L-Imtarfa +MT.25: L-Isla +MT.26: Il-Kalkara +MT.27: 'Ta’ Kerċem' +MT.28: Kirkop +MT.29: Lija +MT.30: Luqa +MT.31: Il-Marsa +MT.32: Marsaskala +MT.33: Marsaxlokk +MT.34: Il-Mellieħa +MT.35: Il-Mosta +MT.36: Il-Munxar +MT.37: In-Nadur +MT.38: In-Naxxar +MT.39: Paola +MT.40: Pembroke +MT.41: Tal-Pietà +MT.42: Il-Qala +MT.43: Qormi +MT.44: Il-Qrendi +MT.46: Ir-Rabat +MT.47: Safi +MT.48: 'Saint John' +MT.49: 'Saint Julian' +MT.50: 'Saint Lawrence' +MT.51: 'Saint Lucia' +MT.52: 'Saint Paul’s Bay' +MT.53: 'Saint Venera' +MT.54: Sannat +MT.55: Is-Siġġiewi +MT.56: Tas-Sliema +MT.57: Is-Swieqi +MT.58: Tarxien +MT.59: 'Ta’ Xbiex' +MT.61: Ix-Xagħra +MT.62: Ix-Xewkija +MT.63: Ix-Xgħajra +MT.64: Ħaż-Żabbar +MT.65: Ħaż-Żebbuġ +MT.66: Iż-Żebbuġ +MT.67: Iż-Żejtun +MT.68: Iż-Żurrieq +MT.60: 'Il-Belt Valletta' +MU.21: 'Agalega Islands' +MU.20: Savanne +MU.19: 'Rivière du Rempart' +MU.18: 'Port Louis' +MU.17: 'Plaines Wilhems' +MU.16: Pamplemousses +MU.15: Moka +MU.14: 'Grand Port' +MU.13: Flacq +MU.12: 'Black River' +MU.22: 'Cargados Carajos' +MU.23: Rodrigues +MV.47: 'Vaavu Atholhu' +MV.46: 'Thaa Atholhu' +MV.45: 'Shaviyani Atholhu' +MV.01: Seenu +MV.44: 'Raa Atholhu' +MV.43: 'Noonu Atoll' +MV.42: 'Gnyaviyani Atoll' +MV.41: 'Meemu Atholhu' +MV.39: 'Lhaviyani Atholhu' +MV.05: Laamu +MV.38: 'Kaafu Atoll' +MV.37: 'Haa Dhaalu Atholhu' +MV.36: 'Haa Alifu Atholhu' +MV.35: 'Gaafu Dhaalu Atholhu' +MV.34: 'Gaafu Alifu Atholhu' +MV.33: 'Faafu Atholhu' +MV.32: 'Dhaalu Atholhu' +MV.31: 'Baa Atholhu' +MV.30: 'Northern Ari Atoll' +MV.40: Maale +MV.48: 'South Province' +MV.49: 'Upper South Province' +MV.50: 'Upper North Province' +MV.51: 'Central Province' +MV.52: 'South Central Province' +MV.53: 'North Central Province' +MV.54: 'North Province' +MW.S: 'Southern Region' +MW.N: 'Northern Region' +MW.C: 'Central Region' +MX.31: Yucatán +MX.30: Veracruz-Llave +MX.29: Tlaxcala +MX.28: Tamaulipas +MX.27: Tabasco +MX.23: 'Quintana Roo' +MX.22: Querétaro +MX.21: Puebla +MX.20: Oaxaca +MX.19: 'Nuevo León' +MX.17: Morelos +MX.15: México +MX.13: Hidalgo +MX.12: Guerrero +MX.09: 'The Federal District' +MX.05: Chiapas +MX.04: Campeche +MX.32: Zacatecas +MX.26: Sonora +MX.25: Sinaloa +MX.24: 'San Luis Potosí' +MX.18: Nayarit +MX.16: Michoacán +MX.14: Jalisco +MX.11: Guanajuato +MX.10: Durango +MX.08: Colima +MX.07: Coahuila +MX.06: Chihuahua +MX.03: 'Baja California Sur' +MX.02: 'Baja California' +MX.01: Aguascalientes +MY.04: Melaka +MY.13: Terengganu +MY.12: Selangor +MY.11: Sarawak +MY.16: Sabah +MY.08: Perlis +MY.07: Perak +MY.06: Pahang +MY.05: 'Negeri Sembilan' +MY.03: Kelantan +MY.14: 'Kuala Lumpur' +MY.09: 'Pulau Pinang' +MY.02: Kedah +MY.01: Johor +MY.15: Labuan +MY.17: Putrajaya +MZ.09: Zambézia +MZ.08: 'Province of Tete' +MZ.05: Sofala +MZ.07: Niassa +MZ.06: Nampula +MZ.04: Maputo +MZ.10: Manica +MZ.03: Inhambane +MZ.02: Gaza +MZ.01: 'Cabo Delgado' +MZ.11: 'Maputo City' +NA.28: Caprivi +NA.21: Khomas +NA.29: Erongo +NA.30: Hardap +NA.31: Karas +NA.32: Kunene +NA.33: Ohangwena +NA.34: Okavango +NA.35: Omaheke +NA.36: Omusati +NA.37: Oshana +NA.38: Oshikoto +NA.39: Otjozondjupa +NC.02: 'Province Sud' +NC.01: 'Province Nord' +NC.03: 'Province des îles Loyauté' +NE.07: Zinder +NE.06: Tahoua +NE.04: Maradi +NE.03: Dosso +NE.02: Diffa +NE.01: 'Agadez Region' +NE.09: Tillabéri +NE.08: Niamey +NG.51: Sokoto +NG.50: Rivers +NG.49: Plateau +NG.32: Oyo +NG.48: Ondo +NG.16: Ogun +NG.31: Niger +NG.05: Lagos +NG.30: Kwara +NG.24: Katsina +NG.29: Kano +NG.23: Kaduna +NG.28: 'Imo State' +NG.22: 'Cross River' +NG.27: Borno +NG.26: 'Benue State' +NG.46: 'Bauchi State' +NG.25: 'Anambra State' +NG.21: 'Akwa Ibom' +NG.11: 'Abuja Federal Capital Territory' +NG.45: Abia +NG.36: 'Delta State' +NG.35: 'Adamawa State' +NG.37: Edo +NG.47: 'Enugu State' +NG.39: 'Jigawa State' +NG.52: Bayelsa +NG.53: Ebonyi +NG.54: Ekiti +NG.55: Gombe +NG.56: Nassarawa +NG.57: Zamfara +NG.40: Kebbi +NG.41: Kogi +NG.42: Osun +NG.43: 'Taraba State' +NG.44: Yobe +NI.15: Rivas +NI.14: 'Río San Juan' +NI.13: 'Nueva Segovia' +NI.12: Matagalpa +NI.11: Masaya +NI.10: Managua +NI.09: Madriz +NI.08: León +NI.07: Jinotega +NI.06: Granada +NI.05: Estelí +NI.04: Chontales +NI.03: Chinandega +NI.02: Carazo +NI.01: Boaco +NI.17: 'Atlántico Norte' +NI.18: 'Atlántico Sur' +NL.11: 'South Holland' +NL.10: Zeeland +NL.09: Utrecht +NL.15: Overijssel +NL.07: 'North Holland' +NL.06: 'North Brabant' +NL.05: Limburg +NL.04: Groningen +NL.03: Gelderland +NL.02: Friesland +NL.01: Drenthe +NL.16: Flevoland +NO.05: Finnmark +NO.20: 'Vestfold county' +NO.19: Vest-Agder +NO.18: Troms +NO.17: 'Telemark county' +NO.16: Sør-Trøndelag +NO.15: 'Sogn og Fjordane' +NO.14: Rogaland +NO.13: Østfold +NO.12: 'Oslo County' +NO.11: 'Oppland county' +NO.10: Nord-Trøndelag +NO.09: Nordland +NO.08: 'Møre og Romsdal' +NO.07: Hordaland +NO.06: 'Hedmark county' +NO.04: 'Buskerud county' +NO.02: 'Aust-Agder county' +NO.01: 'Akershus county' +NP.FR: 'Far Western Region' +NP.MR: 'Mid Western Region' +NP.CR: 'Central Region' +NP.ER: 'Eastern Region' +NP.WR: 'Western Region' +NR.14: Yaren +NR.13: Uaboe +NR.12: Nibok +NR.11: Meneng +NR.10: Ijuw +NR.09: Ewa +NR.08: Denigomodu +NR.07: Buada +NR.06: Boe +NR.05: Baiti +NR.04: Anibare +NR.03: Anetan +NR.02: Anabar +NR.01: Aiwo +NZ.G2: Wellington +NZ.F3: Manawatu-Wanganui +NZ.G1: Waikato +NZ.TAS: Tasman +NZ.F9: Taranaki +NZ.F8: 'Southland Region' +NZ.E8: 'Bay of Plenty' +NZ.F6: Northland +NZ.F4: Marlborough +NZ.F2: 'Hawke''s Bay' +NZ.F1: 'Gisborne Region' +NZ.E9: 'Canterbury Region' +NZ.E7: Auckland +NZ.10: 'Chatham Islands' +NZ.F5: Nelson +NZ.F7: 'Otago Region' +NZ.G3: 'West Coast' +OM.01: 'Ad Dākhilīyah' +OM.02: 'Al Bāţinah' +OM.03: 'Al Wusţá' +OM.04: 'Ash Sharqīyah' +OM.09: 'Az̧ Z̧āhirah' +OM.06: Masqaţ +OM.07: Musandam +OM.08: Z̧ufār +OM.10: 'Muḩāfaz̧at al Buraymī' +OM.12: 'Muḩāfaz̧at Shamāl ash Sharqīyah' +OM.11: 'Muḩāfaz̧at Shamāl al Bāţinah' +PA.10: Veraguas +PA.09: 'Kuna Yala' +PA.08: Panamá +PA.07: 'Los Santos' +PA.06: Herrera +PA.05: Darién +PA.04: Colón +PA.03: Coclé +PA.02: Chiriquí +PA.01: 'Bocas del Toro' +PA.11: Emberá +PA.12: Ngöbe-Buglé +PE.25: 'Ucayali Region' +PE.24: Tumbes +PE.22: 'San Martín' +PE.20: 'Piura Region' +PE.16: 'Loreto Region' +PE.14: 'Lambayeque Region' +PE.13: 'La Libertad Region' +PE.10: Huanuco +PE.06: Cajamarca +PE.02: 'Ancash Region' +PE.01: 'Amazonas Region' +PE.23: 'Tacna Region' +PE.21: 'Puno Region' +PE.19: Pasco +PE.18: Moquegua +PE.17: 'Madre de Dios' +PE.LMA: 'Provincia de Lima' +PE.15: 'Lima Region' +PE.12: Junín +PE.11: 'Ica Region' +PE.09: 'Huancavelica Region' +PE.08: Cusco +PE.07: Callao +PE.05: 'Ayacucho Region' +PE.04: 'Arequipa Region' +PE.03: Apurímac +PF.04: 'Îles Marquises' +PF.03: 'Îles Tuamotu-Gambier' +PF.02: 'Îles Sous-le-Vent' +PF.01: 'Îles du Vent' +PF.05: 'Îles Australes' +PG.17: 'West New Britain' +PG.06: 'Western Province' +PG.16: 'Western Highlands' +PG.05: 'Southern Highlands' +PG.18: Sandaun +PG.07: Bougainville +PG.04: 'Northern Province' +PG.15: 'New Ireland' +PG.20: 'National Capital District' +PG.14: Morobe +PG.13: Manus +PG.12: Madang +PG.02: Gulf +PG.19: Enga +PG.11: 'East Sepik' +PG.10: 'East New Britain' +PG.09: 'Eastern Highlands' +PG.08: Chimbu +PG.03: 'Milne Bay' +PG.01: 'Central Province' +PG.21: Hela +PG.22: Jiwaka +PH.14: 'Autonomous Region in Muslim Mindanao' +PH.10: 'Northern Mindanao' +PH.41: Mimaropa +PH.02: 'Cagayan Valley' +PH.12: Soccsksargen +PH.13: Caraga +PH.15: 'Cordillera Administrative Region' +PH.01: 'Ilocos Region' +PH.40: Calabarzon +PH.06: 'Western Visayas' +PH.03: 'Central Luzon' +PH.07: 'Central Visayas' +PH.08: 'Eastern Visayas' +PH.09: 'Zamboanga Peninsula' +PH.11: Davao +PH.05: Bicol +PH.NCR: 'National Capital Region' +PK.08: Islāmābād +PK.05: Sindh +PK.04: Punjab +PK.03: 'North-West Frontier Province' +PK.07: Gilgit-Baltistan +PK.01: 'Federally Administered Tribal Areas' +PK.02: Balochistān +PK.06: 'Azad Kashmir' +PL.75: 'Lublin Voivodeship' +PL.77: 'Lesser Poland Voivodeship' +PL.78: 'Masovian Voivodeship' +PL.80: 'Subcarpathian Voivodeship' +PL.81: Podlasie +PL.84: Świętokrzyskie +PL.85: 'Warmian-Masurian Voivodeship' +PL.72: 'Lower Silesian Voivodeship' +PL.74: 'Łódź Voivodeship' +PL.76: Lubusz +PL.79: 'Opole Voivodeship' +PL.82: 'Pomeranian Voivodeship' +PL.83: 'Silesian Voivodeship' +PL.86: 'Greater Poland Voivodeship' +PL.87: 'West Pomeranian Voivodeship' +PL.73: Kujawsko-Pomorskie +PM.97502: Saint-Pierre +PM.97501: Miquelon-Langlade +PR.001: Adjuntas +PR.003: Aguada +PR.005: Aguadilla +PR.007: 'Aguas Buenas' +PR.009: Aibonito +PR.011: Añasco +PR.013: Arecibo +PR.015: Arroyo +PR.017: Barceloneta +PR.019: Barranquitas +PR.021: Bayamón +PR.023: 'Cabo Rojo' +PR.025: Caguas +PR.027: Camuy +PR.029: Canovanas +PR.031: Carolina +PR.033: Catano +PR.035: Cayey +PR.037: Ceiba +PR.039: Ciales +PR.041: Cidra +PR.043: Coamo +PR.045: Comerio +PR.047: Corozal +PR.049: Culebra +PR.051: Dorado +PR.053: Fajardo +PR.054: Florida +PR.055: Guanica +PR.057: Guayama +PR.059: Guayanilla +PR.061: Guaynabo +PR.063: Gurabo +PR.065: Hatillo +PR.067: Hormigueros +PR.069: Humacao +PR.071: Isabela +PR.073: 'Municipio de Jayuya' +PR.075: 'Juana Diaz' +PR.077: 'Municipio de Juncos' +PR.079: Lajas +PR.081: Lares +PR.083: 'Las Marias' +PR.085: 'Las Piedras' +PR.087: Loiza +PR.089: Luquillo +PR.091: Manati +PR.093: Maricao +PR.095: Maunabo +PR.097: Mayaguez +PR.099: Moca +PR.101: Morovis +PR.103: Naguabo +PR.105: Naranjito +PR.107: Orocovis +PR.109: Patillas +PR.111: Penuelas +PR.113: Ponce +PR.117: Rincon +PR.115: Quebradillas +PR.119: 'Rio Grande' +PR.121: 'Sabana Grande' +PR.123: Salinas +PR.125: 'San German' +PR.127: 'San Juan' +PR.129: 'San Lorenzo' +PR.131: 'San Sebastian' +PR.133: 'Santa Isabel Municipio' +PR.135: 'Toa Alta' +PR.137: 'Toa Baja' +PR.139: 'Trujillo Alto' +PR.141: Utuado +PR.143: 'Vega Alta' +PR.145: 'Vega Baja' +PR.149: Villalba +PR.151: Yabucoa +PR.153: Yauco +PR.147: Vieques +PS.GZ: 'Gaza Strip' +PS.WE: 'West Bank' +PT.19: Setúbal +PT.18: Santarém +PT.16: Portalegre +PT.14: Lisbon +PT.13: Leiria +PT.09: Faro +PT.08: Évora +PT.06: 'Castelo Branco' +PT.03: Beja +PT.10: Madeira +PT.22: Viseu +PT.21: 'Vila Real' +PT.20: 'Viana do Castelo' +PT.17: Porto +PT.11: Guarda +PT.07: Coimbra +PT.05: Bragança +PT.04: Braga +PT.02: Aveiro +PT.23: Azores +PW.11: Ngatpang +PW.16: Sonsorol +PW.05: Kayangel +PW.04: 'State of Hatohobei' +PW.01: Aimeliik +PW.02: Airai +PW.03: Angaur +PW.06: Koror +PW.07: Melekeok +PW.08: Ngaraard +PW.12: Ngchesar +PW.09: Ngarchelong +PW.10: Ngardmau +PW.13: 'State of Ngeremlengui' +PW.14: Ngiwal +PW.15: Peleliu +PY.17: 'San Pedro' +PY.16: 'Presidente Hayes' +PY.15: Paraguarí +PY.13: Ñeembucú +PY.12: Misiones +PY.11: Itapúa +PY.10: Guairá +PY.08: Cordillera +PY.07: Concepción +PY.06: Central +PY.19: Canindeyú +PY.05: Caazapá +PY.04: Caaguazú +PY.02: Amambay +PY.01: 'Alto Paraná' +PY.23: 'Alto Paraguay' +PY.22: Asunción +PY.24: Boquerón +QA.08: 'Madīnat ash Shamāl' +QA.02: 'Al Ghuwayrīyah' +QA.04: 'Al Khawr' +QA.09: 'Umm Şalāl' +QA.03: 'Al Jumaylīyah' +QA.06: 'Ar Rayyān' +QA.01: 'Ad Dawḩah' +QA.10: 'Al Wakrah' +QA.11: 'Jarayān al Bāţinah' +QA.12: 'Baladīyat Umm Sa‘īd' +QA.13: 'Baladīyat az̧ Z̧a‘āyin' +RE.RE: Réunion +RO.40: Vrancea +RO.39: Vâlcea +RO.38: Vaslui +RO.37: Tulcea +RO.36: Timiş +RO.35: Teleorman +RO.34: Suceava +RO.33: Sibiu +RO.32: 'Satu Mare' +RO.31: Sălaj +RO.30: 'Prahova County' +RO.29: Olt +RO.28: Neamţ +RO.27: Mureş +RO.26: Mehedinţi +RO.25: Maramureş +RO.23: Iaşi +RO.22: Ialomiţa +RO.21: Hunedoara +RO.20: Harghita +RO.19: Gorj +RO.42: Giurgiu +RO.18: Galaţi +RO.17: Dolj +RO.16: Dâmboviţa +RO.15: Covasna +RO.14: Constanţa +RO.13: Cluj +RO.12: Caraş-Severin +RO.41: Călăraşi +RO.11: Buzău +RO.10: Bucureşti +RO.09: Braşov +RO.08: Brăila +RO.07: Botoşani +RO.06: Bistriţa-Năsăud +RO.05: Bihor +RO.04: Bacău +RO.03: Argeş +RO.02: Arad +RO.01: Alba +RO.43: 'Ilfov County' +RS.VO: 'Autonomna Pokrajina Vojvodina' +RS.SE: 'Central Serbia' +RU.88: Jaroslavl +RU.86: Voronezj +RU.85: Vologda +RU.84: Volgograd +RU.81: Uljanovsk +RU.80: Udmurtiya +RU.77: Tverskaya +RU.76: Tula +RU.73: Tatarstan +RU.72: Tambov +RU.70: 'Stavropol''skiy' +RU.69: Smolensk +RU.67: Saratov +RU.65: Samara +RU.62: Rjazan +RU.61: Rostov +RU.60: Pskov +RU.90: Perm +RU.57: Penza +RU.56: Orjol +RU.55: Orenburg +RU.52: Novgorod +RU.68: 'North Ossetia' +RU.50: 'Nenetskiy Avtonomnyy Okrug' +RU.49: Murmansk +RU.48: Moscow +RU.47: Moskovskaya +RU.46: Mordoviya +RU.45: Mariy-El +RU.43: Lipetsk +RU.42: Leningrad +RU.66: St.-Petersburg +RU.41: Kursk +RU.38: Krasnodarskiy +RU.37: Kostroma +RU.34: 'Komi Republic' +RU.33: Kirov +RU.28: Kareliya +RU.27: Karachayevo-Cherkesiya +RU.25: Kaluga +RU.24: Kalmykiya +RU.23: Kaliningrad +RU.22: Kabardino-Balkariya +RU.21: Ivanovo +RU.19: Ingushetiya +RU.51: 'Nizjnij Novgorod' +RU.17: Dagestan +RU.16: Chuvashia +RU.12: Chechnya +RU.10: Brjansk +RU.09: Belgorod +RU.08: Bashkortostan +RU.07: Astrakhan +RU.06: Arkhangelskaya +RU.01: Adygeya +RU.83: Vladimir +RU.87: 'Yamalo-Nenetskiy Avtonomnyy Okrug' +RU.78: Tjumen +RU.79: Tyva +RU.75: Tomsk +RU.71: Sverdlovsk +RU.54: Omsk +RU.53: Novosibirsk +RU.40: Kurgan +RU.91: Krasnoyarskiy +RU.32: 'Khanty-Mansiyskiy Avtonomnyy Okrug' +RU.31: Khakasiya +RU.29: Kemerovo +RU.03: Altay +RU.13: 'Chelyabinsk Oblast' +RU.04: Altayskiy +RU.63: Sakha +RU.59: Primorskiy +RU.30: 'Khabarovsk Krai' +RU.20: Irkutsk +RU.89: 'Jewish Autonomous Oblast' +RU.05: Amur +RU.11: Buryatiya +RU.64: Sakhalin +RU.44: Magadan +RU.92: Kamtsjatka +RU.15: 'Chukotskiy Avtonomnyy Okrug' +RU.93: 'Zabaykal’skiy Kray' +RW.11: 'Eastern Province' +RW.12: 'Kigali Province' +RW.13: 'Northern Province' +RW.14: 'Western Province' +RW.15: 'Southern Province' +SA.19: Tabūk +SA.16: Najrān +SA.14: Makkah +SA.17: Jīzān +SA.13: Ḩāʼil +SA.11: 'Minţaqat ‘Asīr' +SA.06: 'Eastern Province' +SA.10: 'Ar Riyāḑ' +SA.08: 'Al-Qassim Province' +SA.05: 'Al Madīnah' +SA.20: 'Al Jawf' +SA.15: 'Northern Borders Region' +SA.02: 'Al Bāḩah' +SB.11: 'Western Province' +SB.03: Malaita +SB.07: Isabel +SB.06: Guadalcanal +SB.10: 'Central Province' +SB.09: Temotu +SB.08: Makira +SB.12: Choiseul +SB.13: 'Rennell and Bellona' +SC.23: Takamaka +SC.22: 'Saint Louis' +SC.27: 'Port Glaud' +SC.20: 'Pointe Larue' +SC.19: Plaisance +SC.18: 'Mont Fleuri' +SC.17: 'Mont Buxton' +SC.26: 'English River' +SC.25: 'Inner Islands' +SC.24: 'Grand Anse Mahe' +SC.14: 'Grand Anse Praslin' +SC.12: Glacis +SC.11: Cascade +SC.10: 'Bel Ombre' +SC.09: 'Bel Air' +SC.08: 'Beau Vallon' +SC.07: 'Baie Sainte Anne' +SC.06: 'Baie Lazare' +SC.05: 'Anse Royale' +SC.03: 'Anse Etoile' +SC.02: 'Anse Boileau' +SC.01: 'Anse aux Pins' +SC.29: 'Les Mamelles' +SC.30: 'Roche Caiman' +SC.28: 'Au Cap' +SD.43: 'Northern State' +SD.29: 'Khartoum State' +SD.36: 'Red Sea' +SD.38: 'Al Jazirah State' +SD.39: 'Al Qadarif State' +SD.41: 'White Nile State' +SD.42: 'Blue Nile' +SD.47: 'Western Darfur State' +SD.49: 'Southern Darfur State' +SD.50: 'Southern Kordofan State' +SD.52: 'Kassala State' +SD.53: 'River Nile' +SD.55: 'Northern Darfur State' +SD.56: 'Northern Kordofan State' +SD.58: 'Sinnar State' +SD.60: 'Eastern Darfur State' +SD.61: 'Central Darfur State' +SE.14: Norrbotten +SE.25: Västmanland +SE.24: Västernorrland +SE.23: Västerbotten +SE.22: Värmland +SE.21: Uppsala +SE.26: Stockholm +SE.18: Södermanland +SE.16: Östergötland +SE.15: Örebro +SE.12: Kronoberg +SE.10: Dalarna +SE.09: Kalmar +SE.08: Jönköping +SE.07: Jämtland +SE.06: Halland +SE.05: Gotland +SE.03: Gävleborg +SE.02: Blekinge +SE.27: Skåne +SE.28: 'Västra Götaland' +SG.01: 'Central Singapore' +SG.02: 'North East' +SG.04: 'South East' +SG.05: 'South West' +SG.03: 'North West' +SH.01: Ascension +SH.03: 'Tristan da Cunha' +SH.02: 'Saint Helena' +SI.N5: Žalec +SI.E7: 'Zagorje ob Savi' +SI.E5: Vrhnika +SI.D5: Tržič +SI.D4: Trebnje +SI.D3: Trbovlje +SI.D2: Tolmin +SI.D7: Velenje +SI.C5: 'Šmarje pri Jelšah' +SI.C4: 'Slovenska Konjice' +SI.L8: 'Slovenska Bistrica' +SI.C2: 'Slovenj Gradec' +SI.B9: 'Škofja Loka' +SI.B7: Sežana +SI.B6: Sevnica +SI.L7: 'Šentjur pri Celju' +SI.L1: Ribnica +SI.A3: Radovljica +SI.A2: 'Radlje ob Dravi' +SI.K7: Ptuj +SI.94: Postojna +SI.J9: Piran-Pirano +SI.87: Ormož +SI.J7: 'Novo Mesto' +SI.84: 'Nova Gorica' +SI.80: 'Murska Sobota' +SI.79: Mozirje +SI.73: Metlika +SI.J2: Maribor +SI.64: Logatec +SI.I6: Ljutomer +SI.I5: Litija +SI.I3: Lenart +SI.57: Laško +SI.54: Krško +SI.52: Kranj +SI.50: Koper-Capodistria +SI.H7: Kočevje +SI.H6: Kamnik +SI.H4: Jesenice +SI.40: Izola-Isola +SI.38: 'Ilirska Bistrica' +SI.36: Idrija +SI.34: Hrastnik +SI.32: Grosuplje +SI.29: 'Gornja Radgona' +SI.25: Dravograd +SI.G7: Domžale +SI.17: Črnomelj +SI.13: Cerknica +SI.11: Celje +SI.08: Brežice +SI.01: Ajdovščina +SI.35: Hrpelje-Kozina +SI.19: Divača +SI.91: Pivka +SI.I7: 'Loška Dolina' +SI.66: 'Loški Potok' +SI.88: Osilnica +SI.D8: 'Velike Lašče' +SI.C1: Škofljica +SI.37: Ig +SI.09: Brezovica +SI.05: Borovnica +SI.E1: Vipava +SI.49: Komen +SI.J5: Miren-Kostanjevica +SI.07: Brda +SI.44: Kanal +SI.F2: Žiri +SI.14: Cerkno +SI.F1: Železniki +SI.27: 'Gorenja Vas-Poljane' +SI.G4: 'Dobrova-Horjul-Polhov Gradec' +SI.46: Kobarid +SI.06: Bovec +SI.04: Bohinj +SI.03: Bled +SI.82: Naklo +SI.53: 'Kranjska Gora' +SI.K5: Preddvor +SI.12: 'Cerklje na Gorenjskem' +SI.B2: Šenčur +SI.E3: Vodice +SI.71: Medvode +SI.72: Mengeš +SI.22: 'Dol pri Ljubljani' +SI.77: Moravče +SI.30: 'Gornji Grad' +SI.I9: Luče +SI.K8: 'Ravne na Koroškem' +SI.74: Mežica +SI.81: Muta +SI.E6: Vuzenica +SI.16: 'Črna na Koroškem' +SI.62: Ljubno +SI.C7: Šoštanj +SI.C6: 'Šmartno ob Paki' +SI.68: Lukovica +SI.99: Radeče +SI.39: 'Ivančna Gorica' +SI.20: Dobrepolje +SI.B1: Semič +SI.B4: Šentjernej +SI.B8: Škocjan +SI.C9: Štore +SI.N3: Vojnik +SI.E2: Vitanje +SI.F3: Zreče +SI.76: Mislinja +SI.L3: Ruše +SI.55: Kungota +SI.B3: Šentilj +SI.89: Pesnica +SI.26: Duplek +SI.98: Rače-Fram +SI.C8: Starše +SI.45: Kidričevo +SI.J1: Majšperk +SI.N2: Videm +SI.A7: 'Rogaška Slatina' +SI.A8: Rogatec +SI.92: Podčetrtek +SI.51: Kozje +SI.28: Gorišnica +SI.E9: Zavrč +SI.24: Dornava +SI.42: Juršinci +SI.D1: 'Sveti Jurij' +SI.A1: Radenci +SI.97: Puconci +SI.A6: Rogašovci +SI.I2: Kuzma +SI.31: 'Gornji Petrovci' +SI.78: 'Moravske Toplice' +SI.47: Kobilje +SI.02: Beltinci +SI.D6: Turnišče +SI.86: Odranci +SI.15: Črenšovci +SI.83: Nazarje +SI.61: Ljubljana +SI.N7: Žirovnica +SI.H5: Jezersko +SI.M2: Solčava +SI.H8: Komenda +SI.H3: Horjul +SI.L6: Šempeter-Vrtojba +SI.F6: Bloke +SI.M1: Sodražica +SI.M8: Trzin +SI.K6: Prevalje +SI.N4: Vransko +SI.M5: Tabor +SI.F7: Braslovče +SI.K3: Polzela +SI.K4: Prebold +SI.H9: Kostel +SI.N8: Žužemberk +SI.G6: 'Dolenjske Toplice' +SI.J6: 'Mirna Peč' +SI.F5: 'Bistrica ob Sotli' +SI.G2: Dobje +SI.G3: Dobrna +SI.J8: Oplotnica +SI.K2: Podvelka +SI.L2: 'Ribnica na Pohorju' +SI.I8: 'Lovrenc na Pohorju' +SI.L5: 'Selnica ob Dravi' +SI.H1: Hoče-Slivnica +SI.J4: 'Miklavž na Dravskem Polju' +SI.G9: Hajdina +SI.N6: Žetale +SI.K1: Podlehnik +SI.J3: Markovci +SI.G1: Destrnik +SI.M7: 'Trnovska Vas' +SI.M4: 'Sveti Andraž v Slovenskih Goricah' +SI.F9: Cerkvenjak +SI.F4: Benedikt +SI.M3: 'Sveta Ana' +SI.I1: Križevci +SI.N1: Veržej +SI.M9: 'Velika Polana' +SI.I4: Lendava-Lendva +SI.G5: Dobrovnik-Dobronak +SI.M6: Tišina +SI.F8: Cankova +SI.G8: Grad +SI.H2: Hodoš-Hodos +SI.K9: Razkrižje +SI.L9: 'Šmartno pri Litiji' +SI.L4: Šalovci +SI.N9: 'Občina Apače' +SI.O1: Cirkulane +SI.O3: 'Kostanjevica na Krki' +SI.O4: Log-Dragomer +SI.O5: Makole +SI.O7: Mokronog-Trebelno +SI.O8: 'Občina Poljčane' +SI.O9: 'Občina Rečica ob Savinji' +SI.P1: 'Občina Renče-Vogrsko' +SI.P4: 'Občina Središče ob Dravi' +SI.P5: 'Občina Straža' +SI.P6: 'Sveta Trojica v Slovenskih Goricah' +SI.P8: 'Občina Sveti Tomaž' +SI.P2: 'Občina Šentrupert' +SI.P3: 'Občina Šmarješke Toplice' +SI.P7: 'Sveti Jurij v Slovenskih Goricah' +SJ.22: 'Jan Mayen' +SJ.21: Svalbard +SK.03: Košický +SK.05: Prešovský +SK.08: Žilinský +SK.01: Banskobystrický +SK.02: Bratislavský +SK.04: Nitriansky +SK.06: Trenčiansky +SK.07: Trnavský +SL.04: 'Western Area' +SL.03: 'Southern Province' +SL.02: 'Northern Province' +SL.01: 'Eastern Province' +SM.09: Serravalle +SM.02: Chiesanuova +SM.07: 'San Marino' +SM.01: Acquaviva +SM.06: 'Borgo Maggiore' +SM.03: Domagnano +SM.04: Faetano +SM.05: Fiorentino +SM.08: Montegiardino +SN.12: Ziguinchor +SN.07: Thiès +SN.05: Tambacounda +SN.14: Saint-Louis +SN.15: Matam +SN.13: Louga +SN.11: Kolda +SN.10: Kaolack +SN.09: Fatick +SN.03: Diourbel +SN.01: Dakar +SN.16: Kaffrine +SN.17: Kédougou +SN.18: Sédhiou +SO.20: 'Waqooyi Galbeed Region' +SO.19: 'Togdheer Region' +SO.14: 'Shabeele Hoose Region' +SO.13: 'Middle Shabele' +SO.12: 'Sanaag Region' +SO.18: 'Nugaal Region' +SO.10: 'Mudug Region' +SO.09: 'Lower Juba' +SO.08: 'Middle Juba' +SO.07: 'Hiiran Region' +SO.06: 'Gedo Region' +SO.05: 'Galgadud Region' +SO.04: 'Bay Region' +SO.03: 'Bari Region' +SO.02: 'Banadir Region' +SO.01: 'Bakool Region' +SO.21: 'Awadal Region' +SO.22: 'Sool Region' +SR.19: Wanica +SR.18: Sipaliwini +SR.17: Saramacca +SR.16: Paramaribo +SR.15: Para +SR.14: Nickerie +SR.13: Marowijne +SR.12: Coronie +SR.11: Commewijne +SR.10: Brokopondo +SS.07: 'Upper Nile' +SS.04: Lakes +SS.06: Unity +SS.01: 'Central Equatoria State' +SS.10: 'Western Equatoria State' +SS.09: 'Western Bahr al Ghazal' +SS.03: 'Jonglei State' +SS.05: 'Northern Bahr el Ghazal State' +SS.02: 'Eastern Equatoria' +SS.08: 'Warab State' +ST.02: 'São Tomé Island' +ST.01: Príncipe +SV.14: Usulután +SV.13: Sonsonate +SV.12: 'San Vicente' +SV.11: 'Santa Ana' +SV.10: 'San Salvador' +SV.09: 'San Miguel' +SV.08: Morazán +SV.07: 'La Unión' +SV.06: 'La Paz' +SV.05: 'La Libertad' +SV.04: Cuscatlán +SV.03: Chalatenango +SV.02: Cabañas +SV.01: Ahuachapán +SY.14: Tartus +SY.13: 'Damascus City' +SY.12: Idlib +SY.11: Homs +SY.10: Hama +SY.09: Aleppo +SY.08: Rif-dimashq +SY.07: 'Deir ez-Zor' +SY.06: Daraa +SY.05: As-Suwayda +SY.04: Ar-Raqqah +SY.03: Quneitra +SY.02: Latakia +SY.01: Al-Hasakah +SZ.04: Shiselweni +SZ.03: Manzini +SZ.02: Lubombo +SZ.01: Hhohho +TD.13: Salamat +TD.12: Ouaddaï +TD.02: Biltine +TD.14: Tandjilé +TD.17: Moyen-Chari +TD.16: 'Mayo-Kebbi East Region' +TD.09: 'Logone Oriental' +TD.08: 'Logone Occidental' +TD.07: Lac +TD.06: Kanem +TD.05: Guéra +TD.15: Chari-Baguirmi +TD.01: Batha +TD.23: 'Borkou Region' +TD.18: Hadjer-Lamis +TD.19: Mandoul +TD.20: 'Mayo-Kebbi West Region' +TD.21: 'Ville de N''Djaména' +TD.22: 'Barh el Gazel' +TD.24: 'Ennedi Region' +TD.25: Sila +TD.26: 'Tibesti Region' +TF.02: Crozet +TF.03: Kerguelen +TF.01: Saint-Paul-et-Amsterdam +TF.05: 'Îles Éparses' +TF.04: Terre-Adélie +TG.26: Savanes +TG.25: Plateaux +TG.24: Maritime +TG.22: Centrale +TG.23: Kara +TH.15: 'Uthai Thani' +TH.65: Trang +TH.08: Tak +TH.60: 'Surat Thani' +TH.09: Sukhothai +TH.52: Ratchaburi +TH.59: Ranong +TH.57: 'Prachuap Khiri Khan' +TH.62: 'Phuket Province' +TH.56: Phetchaburi +TH.61: Phangnga +TH.01: 'Mae Hong Son' +TH.05: Lamphun +TH.06: Lampang +TH.63: Krabi +TH.50: Kanchanaburi +TH.11: 'Kamphaeng Phet' +TH.58: Chumphon +TH.03: 'Chiang Rai' +TH.02: 'Chiang Mai' +TH.72: Yasothon +TH.70: Yala +TH.10: Uttaradit +TH.49: Trat +TH.29: Surin +TH.51: 'Suphan Buri' +TH.68: Songkhla +TH.30: Sisaket +TH.33: 'Sing Buri' +TH.67: Satun +TH.37: 'Sara Buri' +TH.54: 'Samut Songkhram' +TH.55: 'Samut Sakhon' +TH.42: 'Samut Prakan' +TH.20: 'Sakon Nakhon' +TH.25: 'Roi Et' +TH.47: Rayong +TH.36: 'Phra Nakhon Si Ayutthaya' +TH.07: Phrae +TH.12: Phitsanulok +TH.13: Phichit +TH.14: Phetchabun +TH.41: Phayao +TH.66: Phatthalung +TH.69: Pattani +TH.39: 'Pathum Thani' +TH.38: Nonthaburi +TH.17: 'Nong Khai' +TH.31: Narathiwat +TH.04: Nan +TH.64: 'Nakhon Si Thammarat' +TH.16: 'Nakhon Sawan' +TH.27: 'Nakhon Ratchasima' +TH.73: 'Nakhon Phanom' +TH.53: 'Nakhon Pathom' +TH.43: 'Nakhon Nayok' +TH.78: Mukdahan +TH.24: 'Maha Sarakham' +TH.34: 'Lop Buri' +TH.18: Loei +TH.40: Bangkok +TH.22: 'Khon Kaen' +TH.23: Kalasin +TH.46: 'Chon Buri' +TH.48: Chanthaburi +TH.26: Chaiyaphum +TH.32: 'Chai Nat' +TH.44: Chachoengsao +TH.28: Buriram +TH.35: 'Ang Thong' +TH.76: 'Changwat Udon Thani' +TH.74: 'Prachin Buri' +TH.75: 'Changwat Ubon Ratchathani' +TH.77: 'Amnat Charoen' +TH.79: 'Changwat Nong Bua Lamphu' +TH.80: 'Sa Kaeo' +TH.81: 'Changwat Bueng Kan' +TJ.03: 'Viloyati Sughd' +TJ.01: Gorno-Badakhshan +TJ.02: Khatlon +TJ.RR: 'Region of Republican Subordination' +TJ.7280679: Dushanbe +TK.N: Nukunonu +TK.F: Fakaofo +TK.A: Atafu +TL.VI: 'Distrito Viqueque' +TL.MF: Manufahi +TL.MT: 'Distrito Manatuto' +TL.LI: 'Distrito Liquiçá' +TL.LA: 'Distrito Lautém' +TL.CO: 'Distrito Cova Lima' +TL.ER: Ermera +TL.DI: 'Distrito Díli' +TL.BO: Bobonaro +TL.BA: 'Distrito Bacau' +TL.OE: 'Distrito Oecussi-Ambeno' +TL.AN: 'Distrito Ainaro' +TL.AL: 'Distrito Aileu' +TM.02: Balkan +TM.01: Ahal +TM.03: Daşoguz +TM.05: Mary +TM.04: Lebap +TN.37: Zaghwān +TN.36: Tūnis +TN.35: Tawzar +TN.34: Taţāwīn +TN.23: Sūsah +TN.22: Silyānah +TN.33: 'Sīdī Bū Zayd' +TN.32: Şafāqis +TN.31: Qibilī +TN.30: Qafşah +TN.29: Qābis +TN.19: Nābul +TN.28: Madanīn +TN.06: Jundūbah +TN.27: 'Bin ‘Arūs' +TN.18: Banzart +TN.17: Bājah +TN.38: Ariana +TN.03: 'Al Qayrawān' +TN.02: 'Al Qaşrayn' +TN.16: 'Al Munastīr' +TN.15: 'Al Mahdīyah' +TN.14: Kef +TN.39: Manouba +TO.03: Vava`u +TO.02: Tongatapu +TO.01: Ha`apai +TO.EU: Eua +TO.NI: Niuas +TR.66: Yozgat +TR.65: Van +TR.64: Uşak +TR.63: Şanlıurfa +TR.62: Tunceli +TR.58: Sivas +TR.74: Siirt +TR.73: Niğde +TR.50: Nevşehir +TR.49: Muş +TR.48: Muğla +TR.72: Mardin +TR.45: Manisa +TR.44: Malatya +TR.43: Kütahya +TR.71: Konya +TR.40: Kırşehir +TR.38: Kayseri +TR.46: Kahramanmaraş +TR.35: İzmir +TR.33: Isparta +TR.32: Mersin +TR.31: Hatay +TR.70: Hakkâri +TR.83: Gaziantep +TR.26: Eskişehir +TR.25: Erzurum +TR.24: Erzincan +TR.23: Elazığ +TR.21: Diyarbakır +TR.20: Denizli +TR.15: Burdur +TR.13: Bitlis +TR.12: Bingöl +TR.11: Bilecik +TR.10: Balıkesir +TR.09: Aydın +TR.07: Antalya +TR.68: Ankara +TR.04: Ağrı +TR.03: Afyonkarahisar +TR.02: Adıyaman +TR.81: Adana +TR.91: Osmaniye +TR.88: Iğdır +TR.75: Aksaray +TR.76: Batman +TR.78: Karaman +TR.79: Kırıkkale +TR.80: Şırnak +TR.90: Kilis +TR.85: Zonguldak +TR.61: Trabzon +TR.60: Tokat +TR.59: Tekirdağ +TR.57: Sinop +TR.55: Samsun +TR.54: Sakarya +TR.53: Rize +TR.52: Ordu +TR.41: Kocaeli +TR.39: Kırklareli +TR.37: Kastamonu +TR.84: Kars +TR.34: Istanbul +TR.69: Gümüşhane +TR.28: Giresun +TR.22: Edirne +TR.19: Çorum +TR.82: Çankırı +TR.17: Çanakkale +TR.16: Bursa +TR.14: Bolu +TR.08: Artvin +TR.05: Amasya +TR.87: Bartın +TR.89: Karabük +TR.92: Yalova +TR.86: Ardahan +TR.77: Bayburt +TR.93: Düzce +TT.11: Tobago +TT.10: 'City of San Fernando' +TT.05: 'City of Port of Spain' +TT.03: Mayaro +TT.01: 'Borough of Arima' +TT.CHA: Chaguanas +TT.CTT: Couva-Tabaquite-Talparo +TT.DMN: 'Diego Martin' +TT.ETO: 'Eastern Tobago' +TT.PED: Penal/Debe +TT.PRT: 'Princes Town' +TT.PTF: 'Point Fortin' +TT.SGE: 'Sangre Grande' +TT.SIP: Siparia +TT.SJL: 'San Juan/Laventille' +TT.TUP: Tunapuna/Piarco +TV.NUI: Nui +TV.NMA: Nanumea +TV.FUN: Funafuti +TV.NIT: Niutao +TV.NMG: Nanumanga +TV.VAI: Vaitupu +TV.NKF: Nukufetau +TV.NKL: Nukulaelae +TW.01: Fukien +TW.02: Kaohsiung +TW.03: Taipei +TW.04: Taiwan +TZ.19: Kagera +TZ.25: 'Zanzibar Urban/West' +TZ.22: 'Zanzibar North' +TZ.21: 'Zanzibar Central/South' +TZ.18: Tanga +TZ.17: Tabora +TZ.16: Singida +TZ.15: Shinyanga +TZ.24: 'Rukwa Region' +TZ.02: Pwani +TZ.20: 'Pemba South' +TZ.13: 'Pemba North' +TZ.12: Mwanza +TZ.10: 'Morogoro Region' +TZ.09: Mbeya +TZ.08: Mara +TZ.07: Lindi +TZ.06: Kilimanjaro +TZ.05: Kigoma +TZ.04: Iringa +TZ.03: Dodoma +TZ.23: 'Dar es Salaam' +TZ.26: Arusha +TZ.27: Manyara +TZ.14: Ruvuma +TZ.11: Mtwara +TZ.31: 'Simiyu Region' +TZ.28: 'Geita Region' +TZ.29: 'Katavi Region' +TZ.30: 'Njombe Region' +UA.27: 'Zhytomyrs’ka Oblast’' +UA.26: 'Zaporiz’ka Oblast’' +UA.25: 'Zakarpattia Oblast' +UA.24: 'Volyns’ka Oblast’' +UA.23: 'Vinnyts''ka' +UA.22: 'Ternopil’s’ka Oblast’' +UA.21: 'Sums’ka Oblast’' +UA.20: 'Misto Sevastopol’' +UA.19: 'Rivnens’ka Oblast’' +UA.18: 'Poltavs’ka Oblast’' +UA.17: 'Odes’ka Oblast’' +UA.16: 'Mykolayivs’ka Oblast’' +UA.15: 'L’vivs’ka Oblast’' +UA.14: 'Luhans’ka Oblast’' +UA.13: 'Kyyivs’ka Oblast’' +UA.12: 'Kyiv City' +UA.11: 'Avtonomna Respublika Krym' +UA.10: 'Kirovohrads’ka Oblast’' +UA.09: 'Khmel’nyts’ka Oblast’' +UA.08: 'Khersons’ka Oblast’' +UA.07: 'Kharkivs’ka Oblast’' +UA.06: 'Ivano-Frankivs’ka Oblast’' +UA.05: 'Donets’ka Oblast’' +UA.04: 'Dnipropetrovs''ka Oblast''' +UA.03: 'Chernivets''ka Oblast''' +UA.02: 'Chernihivs’ka Oblast’' +UA.01: 'Cherkas''ka Oblast''' +UG.C: 'Central Region' +UG.E: 'Eastern Region' +UG.N: 'Northern Region' +UG.W: 'Western Region' +UM.450: 'Wake Island' +UM.350: 'Navassa Island' +UM.050: 'Baker Island' +UM.100: 'Howland Island' +UM.150: 'Jarvis Island' +UM.200: 'Johnston Atoll' +UM.250: 'Kingman Reef' +UM.300: 'Midway Islands' +UM.400: 'Palmyra Atoll' +US.AR: Arkansas +US.DC: 'Washington, D.C.' +US.DE: Delaware +US.FL: Florida +US.GA: Georgia +US.KS: Kansas +US.LA: Louisiana +US.MD: Maryland +US.MO: Missouri +US.MS: Mississippi +US.NC: 'North Carolina' +US.OK: Oklahoma +US.SC: 'South Carolina' +US.TN: Tennessee +US.TX: Texas +US.WV: 'West Virginia' +US.AL: Alabama +US.CT: Connecticut +US.IA: Iowa +US.IL: Illinois +US.IN: Indiana +US.ME: Maine +US.MI: Michigan +US.MN: Minnesota +US.NE: Nebraska +US.NH: 'New Hampshire' +US.NJ: 'New Jersey' +US.NY: 'New York' +US.OH: Ohio +US.RI: 'Rhode Island' +US.VT: Vermont +US.WI: Wisconsin +US.CA: California +US.CO: Colorado +US.NM: 'New Mexico' +US.NV: Nevada +US.UT: Utah +US.AZ: Arizona +US.ID: Idaho +US.MT: Montana +US.ND: 'North Dakota' +US.OR: Oregon +US.SD: 'South Dakota' +US.WA: Washington +US.WY: Wyoming +US.HI: Hawaii +US.AK: Alaska +US.KY: Kentucky +US.MA: Massachusetts +US.PA: Pennsylvania +US.VA: Virginia +UY.19: 'Treinta y Tres' +UY.18: Tacuarembó +UY.17: Soriano +UY.16: 'San José' +UY.15: Salto +UY.14: Rocha +UY.13: Rivera +UY.12: 'Río Negro' +UY.11: Paysandú +UY.10: Montevideo +UY.09: Maldonado +UY.08: Lavalleja +UY.07: Florida +UY.06: Flores +UY.05: Durazno +UY.04: Colonia +UY.03: 'Cerro Largo' +UY.02: Canelones +UY.01: Artigas +UZ.09: Karakalpakstan +UZ.12: Surxondaryo +UZ.10: Samarqand +UZ.08: 'Kashkadarya Province' +UZ.02: Bukhara +UZ.14: Toshkent +UZ.13: 'Toshkent Shahri' +UZ.16: Sirdaryo +UZ.07: Navoiy +UZ.06: 'Namangan Province' +UZ.05: Xorazm +UZ.15: Jizzax +UZ.03: Fergana +UZ.01: Andijon +VC.05: 'Saint Patrick' +VC.04: 'Saint George' +VC.03: 'Saint David' +VC.02: 'Saint Andrew' +VC.06: Grenadines +VC.01: Charlotte +VE.23: 'Estado Zulia' +VE.22: 'Estado Yaracuy' +VE.21: Trujillo +VE.20: 'Estado Táchira' +VE.19: Sucre +VE.18: 'Estado Portuguesa' +VE.17: 'Estado Nueva Esparta' +VE.16: 'Estado Monagas' +VE.15: 'Estado Miranda' +VE.14: 'Estado Mérida' +VE.13: 'Estado Lara' +VE.12: 'Estado Guárico' +VE.24: 'Dependencias Federales' +VE.25: 'Distrito Federal' +VE.11: 'Estado Falcón' +VE.09: 'Delta Amacuro' +VE.08: 'Estado Cojedes' +VE.07: 'Estado Carabobo' +VE.06: 'Estado Bolívar' +VE.05: 'Estado Barinas' +VE.04: 'Estado Aragua' +VE.03: 'Estado Apure' +VE.02: 'Estado Anzoátegui' +VE.01: 'Estado Amazonas' +VE.26: Vargas +VI.010: 'Saint Croix Island' +VI.020: 'Saint John Island' +VI.030: 'Saint Thomas Island' +VN.58: 'Nghệ An' +VN.59: 'Ninh Bình' +VN.60: 'Ninh Thuận' +VN.65: 'Sóc Trăng' +VN.67: 'Trà Vinh' +VN.68: 'Tuyên Quang' +VN.69: 'Vĩnh Long' +VN.70: 'Yên Bái' +VN.90: 'Lào Cai' +VN.37: 'Tiền Giang' +VN.66: 'Thừa Thiên-Huế' +VN.55: 'Kon Tum' +VN.34: 'Thanh Hóa' +VN.35: 'Thái Bình' +VN.33: 'Tây Ninh' +VN.32: 'Sơn La' +VN.64: 'Quảng Trị' +VN.30: 'Quảng Ninh' +VN.63: 'Quảng Ngãi' +VN.62: 'Quảng Bình' +VN.61: 'Phú Yên' +VN.53: 'Hòa Bình' +VN.24: 'Long An' +VN.39: 'Lạng Sơn' +VN.23: 'Lâm Đồng' +VN.89: 'Lai Châu' +VN.21: 'Kiến Giang' +VN.54: 'Khánh Hòa' +VN.20: 'Hồ Chí Minh' +VN.52: 'Hà Tĩnh' +VN.51: 'Hà Tây' +VN.50: 'Hà Giang' +VN.49: 'Gia Lai' +VN.44: 'Ha Nội' +VN.87: 'Cần Thơ' +VN.13: 'Hải Phòng' +VN.47: 'Bình Thuận' +VN.09: 'Đồng Tháp' +VN.43: 'Đồng Nai' +VN.88: 'Ðắc Lắk' +VN.45: 'Bà Rịa-Vũng Tàu' +VN.05: 'Cao Bằng' +VN.46: 'Bình Định' +VN.03: 'Bến Tre' +VN.01: 'An Giang' +VN.91: 'Ðắk Nông' +VN.92: 'Huyện Ðiện Biên' +VN.74: 'Bắc Ninh' +VN.71: 'Bắc Giang' +VN.78: 'Đà Nẵng' +VN.75: 'Bình Dương' +VN.76: 'Bình Phước' +VN.85: 'Thái Nguyên' +VN.84: 'Quảng Nam' +VN.83: 'Phú Thọ' +VN.82: 'Nam Ðịnh' +VN.80: 'Hà Nam' +VN.72: 'Bắc Kạn' +VN.73: 'Bạc Liêu' +VN.77: 'Cà Mau' +VN.79: 'Hải Dương' +VN.81: 'Hưng Yên' +VN.86: 'Vĩnh Phúc' +VN.93: 'Hau Giang' +VU.15: Tafea +VU.13: Sanma +VU.07: Torba +VU.16: Malampa +VU.17: Penama +VU.18: Shefa +WF.98613: 'Circonscription d''Uvéa' +WF.98612: 'Circonscription de Sigavé' +WF.98611: 'Circonscription d''Alo' +WS.11: Vaisigano +WS.06: Va‘a-o-Fonoti +WS.10: Tuamasaga +WS.09: Satupa‘itea +WS.08: Palauli +WS.07: Gagaifomauga +WS.05: Gaga‘emauga +WS.04: Fa‘asaleleaga +WS.03: Atua +WS.02: Aiga-i-le-Tai +WS.01: 'A''ana' +XK.28: Vushtrri +XK.27: 'Komuna e Vitisë' +XK.03: 'Komuna e Ferizajt' +XK.15: 'Komuna e Mitrovicës' +XK.26: 'Komuna e Thërandës' +XK.25: 'Komuna e Skenderajt' +XK.21: Prizren +XK.20: 'Komuna e Prishtinës' +XK.19: Podujevo +XK.18: 'Komuna e Pejës' +XK.22: Orahovac +XK.13: Lipjan +XK.12: 'Komuna e Leposaviqit' +XK.10: Kamenica +XK.11: 'Komuna e Klines' +XK.09: 'Komuna e Kaçanikut' +XK.08: 'Komuna e Istogut' +XK.06: 'Komuna e Gjilanit' +XK.07: 'Komuna e Drenasit' +XK.02: 'Komuna e Dragashit' +XK.01: 'Komuna e Deçanit' +XK.05: 'Komuna e Gjakovës' +XK.04: 'Kosovo Polje' +XK.23: 'Opština Štrpce' +XK.24: 'Komuna e Shtimes' +XK.16: 'Novo Brdo' +XK.17: 'Komuna e Obiliqit' +XK.14: 'Komuna e Malisheves' +XK.29: 'Komuna e Zubin Potokut' +XK.30: 'Opština Zvečan' +XK.31: 'Komuna e Graçanicës' +XK.32: 'Hani i Elezit' +XK.33: 'Komuna e Junikut' +XK.34: 'Komuna e Kllokotit' +XK.35: 'Komuna e Mamushës' +XK.36: 'Komuna e Parteshit' +XK.37: 'Komuna e Ranillugut' +YE.25: 'Muḩāfaz̧at Ta‘izz' +YE.05: Shabwah +YE.16: Sanaa +YE.15: 'Muḩāfaz̧at Şa‘dah' +YE.27: 'Muḩāfaz̧at Raymah' +YE.14: 'Muḩāfaz̧at Ma’rib' +YE.10: 'Al Maḩwīt' +YE.21: 'Muḩāfaz̧at al Jawf' +YE.04: Ḩaḑramawt +YE.11: 'Muḩāfaz̧at Dhamār' +YE.03: 'Al Mahrah' +YE.08: 'Al Ḩudaydah' +YE.20: 'Al Bayḑāʼ' +YE.02: Aden +YE.01: Abyan +YE.18: 'Muḩāfaz̧at aḑ Ḑāli‘' +YE.19: Omran +YE.22: 'Muḩāfaz̧at Ḩajjah' +YE.23: Ibb +YE.24: 'Muḩāfaz̧at Laḩij' +YE.26: 'Amanat Al Asimah' +YT.97601: Acoua +YT.97602: Bandraboua +YT.97603: Bandrele +YT.97604: Bouéni +YT.97605: Chiconi +YT.97606: Chirongui +YT.97607: Dembeni +YT.97608: Dzaoudzi +YT.97609: Kani-Kéli +YT.97610: Koungou +YT.97611: Mamoudzou +YT.97612: Mtsamboro +YT.97613: 'M''Tsangamouji' +YT.97614: Ouangani +YT.97615: Pamandzi +YT.97616: Sada +YT.97617: Tsingoni +ZA.03: 'Free State' +ZA.02: KwaZulu-Natal +ZA.05: 'Eastern Cape' +ZA.06: Gauteng +ZA.07: Mpumalanga +ZA.08: 'Northern Cape' +ZA.09: Limpopo +ZA.10: North-West +ZA.11: 'Western Cape' +ZM.01: Western +ZM.07: Southern +ZM.06: North-Western +ZM.05: Northern +ZM.09: Lusaka +ZM.04: Luapula +ZM.03: Eastern +ZM.08: Copperbelt +ZM.02: Central +ZW.02: Midlands +ZW.07: 'Matabeleland South' +ZW.06: 'Matabeleland North' +ZW.08: Masvingo +ZW.05: 'Mashonaland West Province' +ZW.04: 'Mashonaland East' +ZW.03: 'Mashonaland Central Province' +ZW.01: Manicaland +ZW.09: Bulawayo +ZW.10: 'Harare Province' diff --git a/src/Oro/Bundle/AddressBundle/Resources/translations/messages.en.yml b/src/Oro/Bundle/AddressBundle/Resources/translations/messages.en.yml index d1f27f6412b..c255b431049 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/translations/messages.en.yml +++ b/src/Oro/Bundle/AddressBundle/Resources/translations/messages.en.yml @@ -3,4 +3,6 @@ "View address": "View address" "Edit address": "Edit address" "Create address": "Create address" -"Remove address": "Remove address" \ No newline at end of file +"Remove address": "Remove address" +oro.address.form.choose_country: "Choose a country..." +oro.address.form.choose_state: "Choose a state..." diff --git a/src/Oro/Bundle/AddressBundle/Resources/views/Include/fields.html.twig b/src/Oro/Bundle/AddressBundle/Resources/views/Include/fields.html.twig index 69a96c1af2b..96886bca127 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/views/Include/fields.html.twig +++ b/src/Oro/Bundle/AddressBundle/Resources/views/Include/fields.html.twig @@ -22,11 +22,12 @@ $(function() { var regions = new Oro.RegionUpdater.Collection(); - var regionView = new Oro.RegionUpdater.View ({ + var regionView = new Oro.RegionUpdater.View({ el: $('{{ country_field }}'), target: $('#{{ id }}'), simpleEl: $('{{ state_text_field }}'), - collection: regions + collection: regions, + showSelect: {{ (choices is not empty)|json_encode }} }); }); @@ -63,3 +64,51 @@ {{ form_row(form.country) }} {{ form_row(form.postalCode) }} {% endblock oro_address_widget %} + +{% macro address_collection_prototype(widget) %} + {% if widget.get('prototype') %} + {% set form = widget.get('prototype') %} + {% set name = widget.get('prototype').get('name') %} + {% else %} + {% set form = widget %} + {% set name = widget.get('full_name') %} + {% endif %} +
+
+ {{ form_errors(form) }} + {{ form_row(form.id) }} + {{ form_row(form.type) }} + {{ form_row(form.primary) }} + {{ block('oro_address_widget') }} + +
+
+{% endmacro %} + +{% block oro_address_collection_widget %} + {% spaceless %} +
+
+ {% for field in form.children %} + {{ _self.address_collection_prototype(field) }} + {% endfor %} +
+ {{ 'Add'|trans }} +
+ + {% endspaceless %} +{% endblock oro_address_collection_widget %} diff --git a/src/Oro/Bundle/AddressBundle/Resources/views/Include/javascript.html.twig b/src/Oro/Bundle/AddressBundle/Resources/views/Include/javascript.html.twig index 1ec3b218323..16bad123d3e 100644 --- a/src/Oro/Bundle/AddressBundle/Resources/views/Include/javascript.html.twig +++ b/src/Oro/Bundle/AddressBundle/Resources/views/Include/javascript.html.twig @@ -1,7 +1,7 @@ {% block oro_region_updater_js %} {% endblock oro_region_updater_js %} diff --git a/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig new file mode 100644 index 00000000000..14c5133de49 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Resources/views/Include/viewMacro.html.twig @@ -0,0 +1,45 @@ +{% macro renderAddress(address) %} + {% import _self as __ %} + + {% set fields = [ + {label: "First name", data: "firstName"}, + {label: "Last name", data: "lastName"}, + {label: "Street", data: "street"}, + {label: "Street 2", data: "street2"}, + {label: "City", data: "city"}, + {label: "State", data: "universalState"}, + {label: "Country", data: "country"}, + {label: "Zip/postal code", data: "postalCode"} + ] %} + + {{ __.renderAddressView(address, fields) }} +{% endmacro %} + +{% macro renderAddressView(address, fields, renderFlexibleAttributes) %} + {# Render flexible attributes by default #} + {% set renderFlexibleAttributes = renderFlexibleAttributes|default(true) %} + + {# Render static attributes #} + {% for field in fields %} + {{ block('addressStaticAttribute') }} + {% endfor %} + + {# Render flexible attributes #} + {% import 'OroUIBundle::macros.html.twig' as UI %} + {% for value in address|getAttributes() %} + {{ UI.flexibleAttributeRow(value) }} + {% endfor %} +{% endmacro %} + +{% block addressStaticAttribute %} + {% set defaultValue = field.defaultValue|default('N/A') %} + {% set value = field.value is defined ? field.value : attribute(address, field.data) %} +
+ +
+
+

{{ value|default(defaultValue) }}

+
+
+
+{% endblock addressStaticAttribute %} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Functional/API/RestApiTest.php b/src/Oro/Bundle/AddressBundle/Tests/Functional/API/RestApiTest.php index f8f3c7548b2..104b36cbaf2 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Functional/API/RestApiTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Functional/API/RestApiTest.php @@ -25,7 +25,7 @@ public function testPost() array( 'street' => 'Some kind st.', 'city' => 'Old York', - 'state' => 'AL', + 'state' => 'US.AL', 'country' => 'US', 'postalCode' => '32422', ) diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressBaseTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressBaseTest.php new file mode 100644 index 00000000000..dd3e0422e7a --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressBaseTest.php @@ -0,0 +1,225 @@ +assertEquals($value, call_user_func_array(array($obj, 'get' . ucfirst($property)), array())); + } + + /** + * Data provider with entity properties + * + * @return array + */ + public function propertiesDataProvider() + { + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country') + ->disableOriginalConstructor() + ->getMock(); + $regionMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Region', array(), array('combinedCode')); + return array( + 'id' => array('id', 1), + 'lastName' => array('lastName', 'last name'), + 'firstName' => array('firstName', 'first_name'), + 'street' => array('street', 'street'), + 'street2' => array('street2', 'street2'), + 'city' => array('city', 'city'), + 'state' => array('state', $regionMock), + 'stateText' => array('stateText', 'test state'), + 'postalCode' => array('postalCode', '12345'), + 'country' => array('country', $countryMock), + 'created' => array('created', new \DateTime()), + 'updated' => array('updated', new \DateTime()), + ); + } + + public function testBeforeSave() + { + $obj = new AddressBase(); + $obj->beforeSave(); + + $this->assertNotNull($obj->getCreatedAt()); + $this->assertNotNull($obj->getUpdatedAt()); + + $this->assertEquals($obj->getCreatedAt(), $obj->getUpdatedAt()); + } + + public function testToString() + { + $obj = new AddressBase(); + $country = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country') + ->disableOriginalConstructor() + ->getMock(); + $country->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('Ukraine')); + + $regionMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Region', array(), array('combinedCode')); + $regionMock->expects($this->once()) + ->method('__toString') + ->will($this->returnValue('Kharkivs\'ka oblast\'')); + + $obj->setFirstName('FirstName') + ->setLastName('LastName') + ->setStreet('Street') + ->setState($regionMock) + ->setPostalCode('12345') + ->setCountry($country); + + $this->assertTrue(method_exists($obj, '__toString')); + $this->assertEquals('FirstName LastName , Street Kharkivs\'ka oblast\' , Ukraine 12345', $obj->__toString()); + } + + public function testStateText() + { + $obj = new AddressBase(); + $region = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Region') + ->disableOriginalConstructor() + ->getMock(); + $obj->setState($region); + $this->assertEquals($region, $obj->getState()); + $obj->setStateText('text state'); + $this->assertEquals('text state', $obj->getUniversalState()); + } + + public function testIsStateValidNoCountry() + { + $context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext') + ->disableOriginalConstructor() + ->getMock(); + $context->expects($this->never()) + ->method('addViolationAtPath'); + + $obj = new AddressBase(); + $obj->isStateValid($context); + } + + public function testIsStateValidNoRegion() + { + $country = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country') + ->disableOriginalConstructor() + ->getMock(); + $country->expects($this->once()) + ->method('hasRegions') + ->will($this->returnValue(false)); + + $context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext') + ->disableOriginalConstructor() + ->getMock(); + $context->expects($this->never()) + ->method('addViolationAtPath'); + + $obj = new AddressBase(); + $obj->setCountry($country); + $obj->isStateValid($context); + } + + public function testIsStateValid() + { + $country = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country') + ->disableOriginalConstructor() + ->getMock(); + $country->expects($this->once()) + ->method('hasRegions') + ->will($this->returnValue(true)); + $country->expects($this->once()) + ->method('getName') + ->will($this->returnValue('Country')); + + $context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext') + ->disableOriginalConstructor() + ->getMock(); + $context->expects($this->once()) + ->method('getPropertyPath') + ->will($this->returnValue('test')); + $context->expects($this->once()) + ->method('addViolationAtPath') + ->with( + 'test.state', + 'State is required for country %country%', + array('%country%' => 'Country') + ); + + $obj = new AddressBase(); + $obj->setCountry($country); + $obj->isStateValid($context); + } + + public function testIsEmpty() + { + $obj = new AddressBase(); + $this->assertTrue($obj->isEmpty()); + } + + /** + * @dataProvider emptyCheckPropertiesDataProvider + * @param string $property + * @param mixed $value + */ + public function testIsNotEmpty($property, $value) + { + $obj = new AddressBase(); + call_user_func_array(array($obj, 'set' . ucfirst($property)), array($value)); + $this->assertFalse($obj->isEmpty()); + } + + /** + * Data provider with entity properties + * + * @return array + */ + public function emptyCheckPropertiesDataProvider() + { + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country') + ->disableOriginalConstructor() + ->getMock(); + $regionMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Region', array(), array('combinedCode')); + return array( + 'lastName' => array('lastName', 'last name'), + 'firstName' => array('firstName', 'first_name'), + 'street' => array('street', 'street'), + 'street2' => array('street2', 'street2'), + 'city' => array('city', 'city'), + 'state' => array('state', $regionMock), + 'stateText' => array('stateText', 'test state'), + 'postalCode' => array('postalCode', '12345'), + 'country' => array('country', $countryMock), + ); + } + + public function testIsNotEmptyFlexible() + { + $value = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexibleValue'); + $value->expects($this->once()) + ->method('getData') + ->will($this->returnValue('not empty')); + + $obj = new AddressBase(); + $obj->addValue($value); + $this->assertFalse($obj->isEmpty()); + } + + public function testIsEmptyFlexible() + { + $value = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexibleValue'); + $value->expects($this->once()) + ->method('getData'); + + $obj = new AddressBase(); + $obj->addValue($value); + $this->assertTrue($obj->isEmpty()); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php deleted file mode 100644 index 6b6547b5e2a..00000000000 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/AddressTest.php +++ /dev/null @@ -1,80 +0,0 @@ -assertEquals($value, call_user_func_array(array($obj, 'get' . ucfirst($property)), array())); - } - - public function testBeforeSave() - { - $obj = new Address(); - $obj->beforeSave(); - - $this->assertNotNull($obj->getCreatedAt()); - $this->assertNotNull($obj->getUpdatedAt()); - - $this->assertEquals($obj->getCreatedAt(), $obj->getUpdatedAt()); - } - - public function testToString() - { - $obj = new Address(); - $country = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); - $country->expects($this->once()) - ->method('__toString') - ->will($this->returnValue('Ukraine')); - - $regionMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Region'); - $regionMock->expects($this->once()) - ->method('__toString') - ->will($this->returnValue('Kharkivs\'ka oblast\'')); - - $obj->setFirstName('FirstName') - ->setLastName('LastName') - ->setStreet('Street') - ->setState($regionMock) - ->setPostalCode('12345') - ->setCountry($country); - - $this->assertTrue(method_exists($obj, '__toString')); - $this->assertEquals('FirstName LastName , Street Kharkivs\'ka oblast\' , Ukraine 12345', $obj->__toString()); - } - - /** - * Data provider - * - * @return array - */ - public function provider() - { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); - $regionMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Region'); - return array( - array('id', 1), - array('lastName', 'last name'), - array('firstName', 'first_name'), - array('street', 'street'), - array('street2', 'street2'), - array('city', 'city'), - array('state', $regionMock), - array('postalCode', '12345'), - array('country', $countryMock), - array('created', new \DateTime()), - array('updated', new \DateTime()), - ); - } -} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/CountryTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/CountryTest.php index 59d53ad9a93..768b4051177 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/CountryTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/CountryTest.php @@ -3,6 +3,7 @@ namespace Oro\Bundle\AddressBundle\Tests\Entity; use Oro\Bundle\AddressBundle\Entity\Country; +use Oro\Bundle\AddressBundle\Entity\Region; class CountryTest extends \PHPUnit_Framework_TestCase { @@ -12,7 +13,7 @@ class CountryTest extends \PHPUnit_Framework_TestCase */ public function testSettersAndGetters($property) { - $obj = new Country(); + $obj = new Country('iso2code'); $value = 'testValue'; call_user_func_array(array($obj, 'set' . ucfirst($property)), array($value)); @@ -21,11 +22,9 @@ public function testSettersAndGetters($property) public function testConstructorData() { - $obj = new Country('name', 'iso2Code', 'iso3Code'); + $obj = new Country('iso2Code'); - $this->assertEquals('name', $obj->getName()); $this->assertEquals('iso2Code', $obj->getIso2Code()); - $this->assertEquals('iso3Code', $obj->getIso3Code()); } /** @@ -37,15 +36,55 @@ public function provider() { return array( array('name'), - array('iso2code'), array('iso3code'), array('regions'), + array('locale'), ); } public function testToString() { - $obj = new Country('name', 'iso2Code', 'iso3Code'); + $obj = new Country('iso2Code'); + $obj->setName('name'); $this->assertEquals('name', $obj->__toString()); } + + public function testAddRegion() + { + $country = new Country('iso2Code'); + $region = new Region('combinedCode'); + + $this->assertEmpty($country->getRegions()->getValues()); + + $country->addRegion($region); + + $this->assertEquals(array($region), $country->getRegions()->getValues()); + $this->assertEquals($country, $region->getCountry()); + } + + public function testRemoveRegion() + { + $country = new Country('iso2Code'); + $region = new Region('combinedCode'); + $country->addRegion($region); + + $this->assertNotEmpty($country->getRegions()->getValues()); + + $country->removeRegion($region); + + $this->assertEmpty($country->getRegions()->getValues()); + $this->assertNull($region->getCountry()); + } + + public function testHasRegions() + { + $country = new Country('iso2Code'); + $region = new Region('combinedCode'); + + $this->assertFalse($country->hasRegions()); + + $country->addRegion($region); + + $this->assertTrue($country->hasRegions()); + } } diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php index 0d973dceb12..0da538d24ec 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/RegionTest.php @@ -8,10 +8,10 @@ class RegionTest extends \PHPUnit_Framework_TestCase { public function testConstructorData() { - $obj = new Region(); + $combinedCode = 'combinedCode'; - $this->assertNull($obj->getId()); - $obj->setLocale(); + $obj = new Region($combinedCode); + $this->assertEquals($combinedCode, $obj->getCombinedCode()); } /** @@ -19,13 +19,14 @@ public function testConstructorData() */ public function testCountrySetter() { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country') + ->disableOriginalConstructor() + ->getMock(); - $obj = new Region(); + $obj = new Region('combinedCode'); $obj->setCountry($countryMock); $this->assertEquals($countryMock, $obj->getCountry()); - $this->assertNull($obj->getId()); } /** @@ -34,7 +35,7 @@ public function testCountrySetter() */ public function testSettersAndGetters($property) { - $obj = new Region(); + $obj = new Region('combinedCode'); $value = 'testValue'; call_user_func_array(array($obj, 'set' . ucfirst($property)), array($value)); @@ -54,4 +55,11 @@ public function provider() array('locale'), ); } + + public function testToString() + { + $obj = new Region('combinedCode'); + $obj->setName('name'); + $this->assertEquals('name', $obj->__toString()); + } } diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/Repository/RegionRepositoryTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/Repository/RegionRepositoryTest.php new file mode 100644 index 00000000000..a71025082d4 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/Repository/RegionRepositoryTest.php @@ -0,0 +1,89 @@ +entityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->setMethods(array('createQueryBuilder')) + ->getMock(); + + $this->repository = new RegionRepository($this->entityManager, new ClassMetadata(self::ENTITY_NAME)); + } + + protected function tearDown() + { + unset($this->repository); + } + + /** + * Tests both getCountryRegionsQueryBuilder and getCountryRegions + */ + public function testGetCountryRegions() + { + $entityAlias = 'r'; + $country = new Country('iso2Code'); + + $query = $this->getMockBuilder('Doctrine\ORM\AbstractQuery') + ->disableOriginalConstructor() + ->setMethods(array('setHint', 'execute')) + ->getMockForAbstractClass(); + $query->expects($this->once())->method('setHint')->with( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + $query->expects($this->once())->method('execute') + ->will($this->returnValue($this->testRegions)); + + $queryBuilder = $this->getMockBuilder('Doctrine\ORM\QueryBuilder') + ->disableOriginalConstructor() + ->setMethods(array('select', 'from', 'where', 'orderBy', 'setParameter', 'getQuery')) + ->getMock(); + $queryBuilder->expects($this->once())->method('select')->with($entityAlias) + ->will($this->returnSelf()); + $queryBuilder->expects($this->once())->method('from')->with(self::ENTITY_NAME, $entityAlias) + ->will($this->returnSelf()); + $queryBuilder->expects($this->once())->method('where')->with('r.country = :country') + ->will($this->returnSelf()); + $queryBuilder->expects($this->once())->method('orderBy')->with('r.name', 'ASC') + ->will($this->returnSelf()); + $queryBuilder->expects($this->once())->method('setParameter')->with('country', $country) + ->will($this->returnSelf()); + $queryBuilder->expects($this->once())->method('getQuery') + ->will($this->returnValue($query)); + + $this->entityManager->expects($this->once()) + ->method('createQueryBuilder') + ->will($this->returnValue($queryBuilder)); + + $actualRegions = $this->repository->getCountryRegions($country); + $this->assertEquals($this->testRegions, $actualRegions); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/TypedAddressTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/TypedAddressTest.php new file mode 100644 index 00000000000..f7961f32e77 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Entity/TypedAddressTest.php @@ -0,0 +1,15 @@ +setType('TEST'); + $this->assertEquals('TEST', $obj->getType()); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/DataTransformer/AddressTypeToTypeTransformerTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/DataTransformer/AddressTypeToTypeTransformerTest.php new file mode 100644 index 00000000000..cb7ac8c7b58 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/DataTransformer/AddressTypeToTypeTransformerTest.php @@ -0,0 +1,102 @@ +om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager') + ->disableOriginalConstructor() + ->getMock(); + $this->transformer = new AddressTypeToTypeTransformer($this->om); + } + + /** + * @dataProvider typesDataProvider + * @param null|AddressType $type + * @param string $expected + */ + public function testTransform($type, $expected) + { + $this->assertEquals($expected, $this->transformer->transform($type)); + } + + /** + * @return array + */ + public function typesDataProvider() + { + return array( + array(null, ''), + array($this->getAddressTypeMock('test'), 'test') + ); + } + + public function testReverseTransformEmpty() + { + $this->assertNull($this->transformer->reverseTransform(false)); + } + + /** + * @expectedException Symfony\Component\Form\Exception\TransformationFailedException + * @expectedExceptionMessage An address type with type "unknown" does not exist! + */ + public function testReverseTransformException() + { + $type = 'unknown'; + $this->assertRepositoryCall($type, null); + $this->transformer->reverseTransform($type); + } + + public function testReverseTransform() + { + $type = 'test'; + $addressType = $addressType = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\AddressType') + ->disableOriginalConstructor() + ->getMock(); + $this->assertRepositoryCall($type, $addressType); + $this->assertSame($addressType, $this->transformer->reverseTransform($type)); + } + + protected function assertRepositoryCall($type, $addressType) + { + $repository = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectRepository') + ->disableOriginalConstructor() + ->getMock(); + $repository->expects($this->once()) + ->method('findOneBy') + ->with(array('type' => $type)) + ->will($this->returnValue($addressType)); + + $this->om->expects($this->once()) + ->method('getRepository') + ->with('OroAddressBundle:AddressType') + ->will($this->returnValue($repository)); + } + + protected function getAddressTypeMock($type) + { + $addressType = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\AddressType') + ->disableOriginalConstructor() + ->getMock(); + $addressType->expects($this->once()) + ->method('getType') + ->will($this->returnValue($type)); + return $addressType; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/AddressCollectionTypeSubscriberTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/AddressCollectionTypeSubscriberTest.php new file mode 100644 index 00000000000..60b32f34d42 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/AddressCollectionTypeSubscriberTest.php @@ -0,0 +1,206 @@ +subscriber = new AddressCollectionTypeSubscriber('test', '\Oro\Bundle\AddressBundle\Entity\TypedAddress'); + } + + public function testGetSubscribedEvents() + { + $result = $this->subscriber->getSubscribedEvents(); + + $this->assertInternalType('array', $result); + $this->assertArrayHasKey(FormEvents::PRE_SET_DATA, $result); + $this->assertArrayHasKey(FormEvents::PRE_BIND, $result); + $this->assertArrayHasKey(FormEvents::POST_BIND, $result); + } + + public function testPreSetNotEmpty() + { + $addresses = $this->getMockBuilder('Doctrine\Common\Collections\Collection') + ->disableOriginalConstructor() + ->getMock(); + $addresses->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(false)); + $addresses->expects($this->never()) + ->method('add'); + $this->subscriber->preSet($this->getEvent($addresses)); + } + + public function testPreSetEmpty() + { + $addresses = $this->getMockBuilder('Doctrine\Common\Collections\Collection') + ->disableOriginalConstructor() + ->getMock(); + $addresses->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(true)); + $addresses->expects($this->once()) + ->method('add') + ->with($this->isInstanceOf('Oro\Bundle\AddressBundle\Entity\TypedAddress')); + $this->subscriber->preSet($this->getEvent($addresses)); + } + + public function testPostBind() + { + $addressEmpty = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\TypedAddress') + ->disableOriginalConstructor() + ->getMock(); + $addressEmpty->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(true)); + $addressNotEmpty = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\TypedAddress') + ->disableOriginalConstructor() + ->getMock(); + $addressNotEmpty->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(false)); + + $iterator = new \ArrayIterator(array($addressEmpty, $addressNotEmpty)); + $addresses = $this->getMockBuilder('Doctrine\Common\Collections\Collection') + ->disableOriginalConstructor() + ->getMock(); + $addresses->expects($this->once()) + ->method('getIterator') + ->will($this->returnValue($iterator)); + $addresses->expects($this->once()) + ->method('removeElement') + ->with($addressEmpty); + $this->subscriber->postBind($this->getEvent($addresses)); + } + + protected function getEvent($collection) + { + $data = $this->getMockBuilder('\stdClass') + ->setMethods(array('getTest')) + ->getMock(); + $data->expects($this->once()) + ->method('getTest') + ->will($this->returnValue($collection)); + + $event = $this->getMockBuilder('Symfony\Component\Form\FormEvent') + ->disableOriginalConstructor() + ->getMock(); + $event->expects($this->once()) + ->method('getData') + ->will($this->returnValue($data)); + return $event; + } + + /** + * @dataProvider noDataPreBindDataProvider + * @param array|null $data + */ + public function testPreBindNoData($data) + { + $event = $this->getMockBuilder('Symfony\Component\Form\FormEvent') + ->disableOriginalConstructor() + ->getMock(); + $event->expects($this->once()) + ->method('getData') + ->will($this->returnValue($data)); + $event->expects($this->never()) + ->method('setData'); + $this->subscriber->preBind($event); + } + + /** + * @return array + */ + public function noDataPreBindDataProvider() + { + return array( + array( + null, array() + ), + array( + array(), array() + ) + ); + } + + /** + * @dataProvider preBindDataProvider + * @param array|null $data + * @param array $expected + */ + public function testPreBind($data, $expected) + { + $event = $this->getMockBuilder('Symfony\Component\Form\FormEvent') + ->disableOriginalConstructor() + ->getMock(); + $event->expects($this->once()) + ->method('getData') + ->will($this->returnValue($data)); + $event->expects($this->once()) + ->method('setData') + ->with($expected); + $this->subscriber->preBind($event); + } + + public function preBindDataProvider() + { + return array( + array( + array('key' => 'value', 'test' => array(array(), array('k' => 'v'))), + array('key' => 'value', 'test' => array(array('k' => 'v', 'primary' => true))) + ), + array( + array('key' => 'value', 'test' => array(array(array()), array('k' => 'v'))), + array('key' => 'value', 'test' => array(array('k' => 'v', 'primary' => true))) + ), + array( + array('key' => 'value', 'test' => array(array(array('k2' => 'v')), array('k' => 'v'))), + array('key' => 'value', 'test' => array(array(array('k2' => 'v'), 'primary' => true), array('k' => 'v'))) + ), + ); + } + + /** + * @dataProvider preBindNoResetDataProvider + * @param array $data + */ + public function testPreBindNoReset($data) + { + $event = $this->getMockBuilder('Symfony\Component\Form\FormEvent') + ->disableOriginalConstructor() + ->getMock(); + $event->expects($this->once()) + ->method('getData') + ->will($this->returnValue($data)); + $event->expects($this->never()) + ->method('setData'); + $this->subscriber->preBind($event); + } + + /** + * @return array + */ + public function preBindNoResetDataProvider() + { + return array( + array( + array('key' => 'value') + ), + array( + array('key' => 'value', 'test' => array()) + ) + ); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php index 6604a6f00b7..56183697c96 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/EventListener/BuildAddressFormListenerTest.php @@ -79,7 +79,7 @@ public function testPreSetDataHasState() ->disableOriginalConstructor() ->getMock(); - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $countryMock->expects($this->once()) ->method('hasRegions') ->will($this->returnValue(true)); @@ -142,7 +142,7 @@ public function testPreSetDataNoState() ->disableOriginalConstructor() ->getMock(); - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $countryMock->expects($this->once()) ->method('hasRegions') ->will($this->returnValue(true)); @@ -190,7 +190,7 @@ public function testPreBindData() ->disableOriginalConstructor() ->getMock(); - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); + $countryMock = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\Country')->disableOriginalConstructor()->getMock(); $countryMock->expects($this->once()) ->method('hasRegions') ->will($this->returnValue(true)); diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/AddressCollectionTypeTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/AddressCollectionTypeTest.php new file mode 100644 index 00000000000..776428744c1 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/AddressCollectionTypeTest.php @@ -0,0 +1,42 @@ +type = new AddressCollectionType(); + } + + public function testSetDefaultOptions() + { + /** @var OptionsResolverInterface $resolver */ + $resolver = $this->getMock('Symfony\Component\OptionsResolver\OptionsResolverInterface'); + $resolver->expects($this->once()) + ->method('setDefaults') + ->with($this->isType('array')); + $this->type->setDefaultOptions($resolver); + } + + public function testGetParent() + { + $this->assertEquals('collection', $this->type->getParent()); + } + + public function testGetName() + { + $this->assertEquals('oro_address_collection', $this->type->getName()); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/AddressTypedTypeTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/AddressTypedTypeTest.php new file mode 100644 index 00000000000..996aaad85fa --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/AddressTypedTypeTest.php @@ -0,0 +1,55 @@ +getMockBuilder('Oro\Bundle\AddressBundle\Form\EventListener\BuildAddressFormListener') + ->disableOriginalConstructor() + ->getMock(); + $flexibleManager = $this->getMockBuilder('Oro\Bundle\FlexibleEntityBundle\Manager\FlexibleManager') + ->disableOriginalConstructor() + ->getMock(); + + $this->type = new AddressTypedType( + $flexibleManager, + 'oro_address_value', + $buildAddressFormListener + ); + } + + public function testAddEntityFields() + { + $builder = $this->getMockBuilder('Symfony\Component\Form\FormBuilder') + ->disableOriginalConstructor() + ->getMock(); + $builder->expects($this->any()) + ->method('add') + ->will($this->returnSelf()); + $builder->expects($this->at(0)) + ->method('add') + ->with( + 'type', + 'entity', + $this->isType('array') + ); + $this->type->addEntityFields($builder); + } + + public function testGetName() + { + $this->assertEquals('oro_address_typed', $this->type->getName()); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/CountryTypeTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/CountryTypeTest.php index 75581c05c39..8c5c6b2a409 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/CountryTypeTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/CountryTypeTest.php @@ -35,7 +35,7 @@ public function testSetDefaultOptions() public function testGetParent() { - $this->assertEquals('entity', $this->type->getParent()); + $this->assertEquals('genemu_jqueryselect2_translatable_entity', $this->type->getParent()); } public function testGetName() diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/RegionTypeTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/RegionTypeTest.php index f53a853c2a4..ee8c608f41a 100644 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/RegionTypeTest.php +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Form/Type/RegionTypeTest.php @@ -1,7 +1,8 @@ getMock('Symfony\Component\OptionsResolver\OptionsResolverInterface'); $resolver->expects($this->once()) ->method('setDefaults') @@ -35,7 +35,7 @@ public function testSetDefaultOptions() public function testGetParent() { - $this->assertEquals('choice', $this->type->getParent()); + $this->assertEquals('genemu_jqueryselect2_translatable_entity', $this->type->getParent()); } public function testGetName() @@ -58,15 +58,28 @@ public function testBuildForm() public function testFinishView() { - $formViewMock = $this->getMock('Symfony\Component\Form\FormView'); + $optionKey = 'countryFieldName'; + + $formConfigMock = $this->getMockBuilder('Symfony\Component\Form\FormConfigInterface') + ->disableOriginalConstructor() + ->setMethods(array('getAttribute')) + ->getMockForAbstractClass(); + $formConfigMock->expects($this->once()) + ->method('getAttribute') + ->with($this->equalTo(RegionType::COUNTRY_OPTION_KEY)) + ->will($this->returnValue($optionKey)); + $formMock = $this->getMockBuilder('Symfony\Component\Form\Form') ->disableOriginalConstructor() + ->setMethods(array('getConfig')) ->getMock(); $formMock->expects($this->once()) - ->method('getAttribute') - ->with($this->equalTo(RegionType::COUNTRY_OPTION_KEY)) - ->will($this->returnValue('')); + ->method('getConfig') + ->will($this->returnValue($formConfigMock)); - $this->type->finishView($formViewMock, $formMock, array()); + $formView = new FormView(); + $this->type->finishView($formView, $formMock, array()); + $this->assertArrayHasKey('country_field', $formView->vars); + $this->assertEquals($optionKey, $formView->vars['country_field']); } } diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/DbReaderTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/DbReaderTest.php deleted file mode 100644 index 31197357576..00000000000 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/DbReaderTest.php +++ /dev/null @@ -1,102 +0,0 @@ -class = 'Oro\Bundle\AddressBundle\Entity\Country'; - $this->om = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); - - $classMetaData = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata') - ->disableOriginalConstructor() - ->getMock(); - - $classMetaData - ->expects($this->once()) - ->method('getName') - ->with() - ->will($this->returnValue($this->class)); - - $this->om - ->expects($this->once()) - ->method('getClassMetadata') - ->with($this->equalTo($this->class)) - ->will($this->returnValue($classMetaData)); - - - $this->reader = new ImportExport\DbReader($this->class, $this->om, $this->batchSize); - } - - /** - * Test setting limits - */ - public function testSettingBatchLimit() - { - $this->assertEquals($this->batchSize, $this->reader->getBatchSize()); - } - - /** - * Test read batch - */ - public function testDbReader() - { - $repository = $this->getMock('Doctrine\Common\Persistence\ObjectRepository'); - $repository - ->expects($this->exactly(3)) - ->method('findBy') - ->with( - $this->equalTo(array()), - $this->equalTo(array()), - $this->batchSize, - $this->logicalOr(0, $this->batchSize) - ) - ->will( - $this->returnValue( - array( - new Country(), - ) - ) - ); - - $this->om - ->expects($this->any()) - ->method('getRepository') - ->with($this->equalTo($this->class)) - ->will($this->returnValue($repository)); - - $this->reader->readBatch(); - $this->reader->readBatch(); - - $this->reader->reset(); - $this->reader->readBatch(); - } -} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/DbWriterTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/DbWriterTest.php deleted file mode 100644 index 8246875c8b0..00000000000 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/DbWriterTest.php +++ /dev/null @@ -1,64 +0,0 @@ -om = $this->getMock('Doctrine\Common\Persistence\ObjectManager'); - $this->writer = new ImportExport\DbWriter($this->om); - } - - /** - * Test write batch - */ - public function testWriter() - { - $data = array( - new Country('Ukraine', 'UA', 'UKR'), - new Country('United States of America', 'US', 'USA'), - new Country('Russian Federation', 'RU', 'RUS'), - ); - - $this->om - ->expects($this->exactly(count($data))) - ->method('persist') - ->with($this->containsOnlyInstancesOf('Country')); - - $this->om - ->expects($this->once()) - ->method('flush'); - - $this->writer->writeBatch($data); - } - - /** - * Test exception on not valid write - * - * @expectedException \Exception - */ - public function testEmptyWrite() - { - $this->assertFalse($this->writer->writeBatch(array())); - - $this->writer->writeBatch(array(1)); - } -} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/IntlReaderTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/IntlReaderTest.php deleted file mode 100644 index fee5ea0a037..00000000000 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/IntlReaderTest.php +++ /dev/null @@ -1,61 +0,0 @@ -class = 'Oro\Bundle\AddressBundle\Entity\Country'; - - $this->reader = new ImportExport\IntlReader($this->class, $this->batchSize); - } - - /** - * Test setting limits - */ - public function testSettingBatchLimit() - { - $this->assertEquals($this->batchSize, $this->reader->getBatchSize()); - } - - /** - * Test read batch - */ - public function testReader() - { - $data = $this->reader->readBatch(); - $this->assertInternalType('array', $data); - $this->assertCount($this->batchSize, $data); - - $this->reader->reset(); - $data2 = $this->reader->readBatch(); - - $this->assertEquals($data, $data2); - - $this->reader->readBatch(); - $this->assertFalse($this->reader->readBatch()); - } -} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php deleted file mode 100644 index 030c9dd8694..00000000000 --- a/src/Oro/Bundle/AddressBundle/Tests/Unit/Provider/ImportExport/ManagerTest.php +++ /dev/null @@ -1,92 +0,0 @@ -writer = $this->getMock('Oro\Bundle\AddressBundle\Provider\ImportExport\WriterInterface'); - $this->reader = $this->getMock('Oro\Bundle\AddressBundle\Provider\ImportExport\ReaderInterface'); - } - - /** - * Test sync with reader and writer - */ - public function testSync() - { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); - - $this->reader - ->expects($this->exactly(2)) - ->method('readBatch') - ->will( - $this->onConsecutiveCalls( - $countryMock, // first batch return - false // second batch return - ) - ); - - $this->writer - ->expects($this->once()) - ->method('writeBatch') - ->with($this->equalTo($countryMock)) - ->will($this->returnValue(true)); - - /** - * @var ImportExport\Manager - */ - $manager = new ImportExport\Manager($this->writer, $this->reader); - $manager->sync(); - } - - /** - * Test sync for array data without reader - */ - public function testArraySync() - { - $countryMock = $this->getMock('Oro\Bundle\AddressBundle\Entity\Country'); - $data = array($countryMock); - - $this->writer - ->expects($this->once()) - ->method('writeBatch') - ->with($this->equalTo($data)) - ->will($this->returnValue(true)); - - /** - * @var ImportExport\Manager - */ - $manager = new ImportExport\Manager($this->writer); - $manager->sync($data); - } - - /** - * Test exception - * - * @expectedException \Exception - */ - public function testExceptionSync() - { - /** - * @var ImportExport\Manager - */ - $manager = new ImportExport\Manager($this->writer); - $manager->sync(); - } -} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php new file mode 100644 index 00000000000..b30a6db8d04 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Twig/HasAddressExtensionTest.php @@ -0,0 +1,112 @@ +extension = new HasAddressExtension(); + $this->entityMock = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible'); + $this->valuesMock = $this->getMock('Doctrine\Common\Collections\ArrayCollection'); + $this->valueMock = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface'); + } + + public function testGetName() + { + $this->assertEquals('oro_address_hasAddress', $this->extension->getName()); + } + + public function testGetFilters() + { + $filters = $this->extension->getFilters(); + + $this->assertArrayHasKey('hasAddress', $filters); + $this->assertInstanceOf('\Twig_Filter_Method', $filters['hasAddress']); + } + + public function testHasAddressPositiveScenario() + { + $this->valueMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue(true)); + + $this->entityMock->expects($this->once()) + ->method('getValue') + ->with($this->equalTo('address')) + ->will($this->returnValue($this->valueMock)); + + $this->assertTrue($this->extension->hasAddress($this->entityMock, 'address')); + } + + public function testHasAddressNegativeScenario() + { + $this->valueMock->expects($this->once()) + ->method('getData') + ->will($this->returnValue(null)); + + $this->entityMock->expects($this->once()) + ->method('getValue') + ->with($this->equalTo('address')) + ->will($this->returnValue($this->valueMock)); + + $this->assertFalse($this->extension->hasAddress($this->entityMock, 'address')); + } + + public function testHasAddressPositiveScenarioWithoutCode() + { + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('filter') + ->will($this->returnValue($this->valuesMock)); + $this->valuesMock->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(false)); + + $this->assertTrue($this->extension->hasAddress($this->entityMock)); + } + + public function testHasAddressNegativeScenarioWithoutCode() + { + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('filter') + ->will($this->returnValue($this->valuesMock)); + $this->valuesMock->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(true)); + + $this->assertFalse($this->extension->hasAddress($this->entityMock)); + } +} diff --git a/src/Oro/Bundle/AddressBundle/Tests/Unit/Validator/Constraints/ContainsPrimaryValidatorTest.php b/src/Oro/Bundle/AddressBundle/Tests/Unit/Validator/Constraints/ContainsPrimaryValidatorTest.php new file mode 100644 index 00000000000..44214fb898f --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Tests/Unit/Validator/Constraints/ContainsPrimaryValidatorTest.php @@ -0,0 +1,121 @@ +getMock('Symfony\Component\Validator\Constraint'); + $validator = new ContainsPrimaryValidator(); + $validator->validate(false, $constraint); + } + + /** + * @dataProvider validAddressesDataProvider + * @param array $addresses + */ + public function testValidateValid($addresses) + { + $context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext') + ->disableOriginalConstructor() + ->getMock(); + $context->expects($this->never()) + ->method('addViolation'); + + $constraint = $this->getMock('Oro\Bundle\AddressBundle\Validator\Constraints\ContainsPrimary'); + $validator = new ContainsPrimaryValidator(); + $validator->initialize($context); + + $validator->validate($addresses, $constraint); + } + + /** + * @return array + */ + public function validAddressesDataProvider() + { + return array( + 'no addresses' => array( + array() + ), + 'one address primary' => array( + array($this->getTypedAddressMock(true)) + ), + 'more than one address with primary' => array( + array($this->getTypedAddressMock(false), $this->getTypedAddressMock(true)) + ), + 'empty address' => array( + array($this->getTypedAddressMock(false, true), $this->getTypedAddressMock(false, true)) + ), + 'empty address and primary' => array( + array($this->getTypedAddressMock(false, true), $this->getTypedAddressMock(true), $this->getTypedAddressMock(false, true)) + ) + ); + } + + /** + * @dataProvider invalidAddressesDataProvider + * @param array $addresses + */ + public function testValidateInvalid($addresses) + { + $context = $this->getMockBuilder('Symfony\Component\Validator\ExecutionContext') + ->disableOriginalConstructor() + ->getMock(); + $context->expects($this->once()) + ->method('addViolation') + ->with('One of addresses must be set as primary.'); + + $constraint = $this->getMock('Oro\Bundle\AddressBundle\Validator\Constraints\ContainsPrimary'); + $validator = new ContainsPrimaryValidator(); + $validator->initialize($context); + + $validator->validate($addresses, $constraint); + } + + /** + * @return array + */ + public function invalidAddressesDataProvider() + { + return array( + 'one address' => array( + array($this->getTypedAddressMock(false)) + ), + 'more than one address no primary' => array( + array($this->getTypedAddressMock(false), $this->getTypedAddressMock(false)) + ), + 'more than one address more than one primary' => array( + array($this->getTypedAddressMock(true), $this->getTypedAddressMock(true)) + ), + ); + } + + /** + * Get address mock. + * + * @param bool $isPrimary + * @param bool $isEmpty + * @return \PHPUnit_Framework_MockObject_MockObject + */ + protected function getTypedAddressMock($isPrimary, $isEmpty = false) + { + $address = $this->getMockBuilder('Oro\Bundle\AddressBundle\Entity\TypedAddress') + ->disableOriginalConstructor() + ->getMock(); + $address->expects($this->any()) + ->method('isPrimary') + ->will($this->returnValue($isPrimary)); + $address->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue($isEmpty)); + return $address; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php b/src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php new file mode 100644 index 00000000000..bdb44400038 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Twig/HasAddressExtension.php @@ -0,0 +1,55 @@ + new \Twig_Filter_Method($this, 'hasAddress') + ); + } + + /** + * Check whenever flexible entity contains not empty address attribute + * + * @param \Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible $entity + * @param null $addressCode + * @return bool + */ + public function hasAddress(AbstractEntityFlexible $entity, $addressCode = null) + { + if ($addressCode !== null) { + $address = $entity->getValue($addressCode); + + return $address->getData() != null; + } + + /** @var \Doctrine\Common\Collections\ArrayCollection $values **/ + $values = $entity->getValues(); + $values = $values->filter( + function ($value) { + if (strpos($value->getAttribute()->getCode(), 'address') !== false) { + return $value->getData() != null; + } + + return false; + } + ); + return !$values->isEmpty(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_address_hasAddress'; + } +} diff --git a/src/Oro/Bundle/AddressBundle/Validator/Constraints/ContainsPrimary.php b/src/Oro/Bundle/AddressBundle/Validator/Constraints/ContainsPrimary.php new file mode 100644 index 00000000000..b69b3e8e904 --- /dev/null +++ b/src/Oro/Bundle/AddressBundle/Validator/Constraints/ContainsPrimary.php @@ -0,0 +1,13 @@ +isEmpty()) { + if ($item instanceof TypedAddress && $item->isPrimary()) { + $primaryItemsNumber++; + } + $totalItemsNumber++; + } + } + + if ($totalItemsNumber > 0 && $primaryItemsNumber != 1) { + $this->context->addViolation($constraint->message); + } + } +} diff --git a/src/Oro/Bundle/AddressBundle/composer.json b/src/Oro/Bundle/AddressBundle/composer.json index 1de58a3bc06..ea61775cf34 100644 --- a/src/Oro/Bundle/AddressBundle/composer.json +++ b/src/Oro/Bundle/AddressBundle/composer.json @@ -8,12 +8,11 @@ "require": { "php": ">=5.3.3", "symfony/symfony": "2.1.*", - "symfony/icu": "1.2.*@dev", - "symfony/intl": "2.3.*@dev", "friendsofsymfony/rest-bundle": "0.11.*", "friendsofsymfony/jsrouting-bundle": "1.1.*@dev", "nelmio/api-doc-bundle": "dev-master", "oro/flexible-entity-bundle": "dev-master", + "oro/form-bundle": "dev-master", "besimple/soap-bundle": "dev-master" }, "autoload": { diff --git a/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php index 4612d396be3..0f01cdf50a8 100644 --- a/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php +++ b/src/Oro/Bundle/ConfigBundle/DependencyInjection/Configuration.php @@ -13,7 +13,18 @@ class Configuration implements ConfigurationInterface public function getConfigTreeBuilder() { $builder = new TreeBuilder(); - $root = $builder->root('oro_config'); + $root = $builder + ->root('oro_config') + ->children() + ->arrayNode('entity_output') + ->prototype('array') + ->children() + ->scalarNode('icon_class')->end() + ->scalarNode('name')->end() + ->scalarNode('description')->end() + ->end() + ->end() + ->end(); return $builder; } diff --git a/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php b/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php index 236f2f6aed7..525c720a09e 100644 --- a/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php +++ b/src/Oro/Bundle/ConfigBundle/DependencyInjection/OroConfigExtension.php @@ -3,9 +3,10 @@ namespace Oro\Bundle\ConfigBundle\DependencyInjection; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader; use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\Yaml\Yaml; /** * This is the class that loads and manages your bundle configuration @@ -19,10 +20,25 @@ class OroConfigExtension extends Extension */ public function load(array $configs, ContainerBuilder $container) { + $data = array(); + + foreach ($container->getParameter('kernel.bundles') as $bundle) { + $reflection = new \ReflectionClass($bundle); + + if (file_exists($file = dirname($reflection->getFilename()) . '/Resources/config/entity_output.yml')) { + $data = array_merge($data, Yaml::parse(realpath($file))); + } + } + + $configs[] = array('entity_output' => $data); $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); - $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('services.yml'); + + $container->setParameter('oro_config.entities', $data); } } diff --git a/src/Oro/Bundle/ConfigBundle/DependencyInjection/SettingsBuilder.php b/src/Oro/Bundle/ConfigBundle/DependencyInjection/SettingsBuilder.php index 81ffbd0d360..f4f402df898 100644 --- a/src/Oro/Bundle/ConfigBundle/DependencyInjection/SettingsBuilder.php +++ b/src/Oro/Bundle/ConfigBundle/DependencyInjection/SettingsBuilder.php @@ -35,12 +35,10 @@ public static function append(ArrayNodeDefinition $root, $settings) $child->scalarNode('value')->defaultValue($setting['value']); break; - case 'boolean': $child->booleanNode('value')->defaultValue((bool) $setting['value']); break; - case 'array': $child->arrayNode('value'); diff --git a/src/Oro/Bundle/ConfigBundle/README.md b/src/Oro/Bundle/ConfigBundle/README.md index 05fd162cb10..c63b659bed9 100644 --- a/src/Oro/Bundle/ConfigBundle/README.md +++ b/src/Oro/Bundle/ConfigBundle/README.md @@ -40,7 +40,8 @@ $ phpunit --coverage-html=cov/ ``` ## Usage ## -In your controllers you can access different Oro settings using different scopes. +### Controller ### +You can access different Oro settings using different scopes. **Note:** Currently, only `oro_config.user` scope implemented. @@ -85,4 +86,35 @@ public function getConfigTreeBuilder() } ``` -`type` above could be `scalar` (which is default) or `boolean`. \ No newline at end of file +`type` above could be `scalar` (which is default) or `boolean`. + +### View ### + +``` +{% set format = oro_config_value('oro_anybundle.anysetting') %} +``` + +### Entity ### +It is possible to configure entity output through the yaml config file named `entity_output.yml`. Sample syntax: + +``` yaml +Acme\Bundle\MyBundle\Entity\MyEntity: + icon_class: icon-entity + name: entity.myentity.name + description: entity.myentity.description +``` + +To make name and description translatable, add `translations/config.{locale}.yml` file: + +``` yaml +entity: + myentity: + name: My entity + description: My entity description +``` + +Then, you can use customized entity parameters in views: + +``` +{{ oro_config_entity('Acme\\Bundle\\MyBundle\\Entity\\MyEntity').name|trans({}, 'config') }} +``` diff --git a/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml b/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml index 7ceef9efdb9..ea40dd3b1d3 100644 --- a/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/ConfigBundle/Resources/config/services.yml @@ -13,6 +13,6 @@ services: oro_config.twig.config_extension: class: %oro_config.twig_extension.class% - arguments: ["@oro_config.user"] + arguments: ["@oro_config.user", %oro_config.entities%] tags: - { name: twig.extension } diff --git a/src/Oro/Bundle/ConfigBundle/Tests/Unit/Config/UserConfigManagerTest.php b/src/Oro/Bundle/ConfigBundle/Tests/Unit/Config/UserConfigManagerTest.php index 97546fb18e3..da21724617e 100644 --- a/src/Oro/Bundle/ConfigBundle/Tests/Unit/Config/UserConfigManagerTest.php +++ b/src/Oro/Bundle/ConfigBundle/Tests/Unit/Config/UserConfigManagerTest.php @@ -112,10 +112,8 @@ function ($param) use ($configUser, $configGroup) { switch ($param['recordId']) { case 1: return $configUser; - case 2: return $configGroup; - case 3: return null; } diff --git a/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/OroConfigExtensionTest.php b/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/OroConfigExtensionTest.php index 7d737af75b1..46b692deb95 100644 --- a/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/OroConfigExtensionTest.php +++ b/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/OroConfigExtensionTest.php @@ -28,6 +28,8 @@ protected function createEmptyConfiguration() { $this->configuration = new ContainerBuilder(); + $this->configuration->setParameter('kernel.bundles', array()); + $loader = new OroConfigExtension(); $config = $this->getEmptyConfig(); @@ -59,10 +61,10 @@ protected function assertParameter($value, $key) protected function getContainer(array $config = array()) { $container = new ContainerBuilder(); - $container->addCompilerPass(new Compiler\ConfigPass()); - - $loader = new OroConfigExtension(); + $loader = new OroConfigExtension(); + $container->addCompilerPass(new Compiler\ConfigPass()); + $container->setParameter('kernel.bundles', array()); $loader->load($config, $container); $container->register('doctrine.orm.entity_manager', $this->getMockClass('Doctrine\Common\Persistence\ObjectManager')); diff --git a/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/SettingsBuilderTest.php b/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/SettingsBuilderTest.php index 4a6be1160b7..634dee05939 100644 --- a/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/SettingsBuilderTest.php +++ b/src/Oro/Bundle/ConfigBundle/Tests/Unit/DependencyInjection/SettingsBuilderTest.php @@ -3,7 +3,6 @@ namespace Oro\Bundle\ConfigBundle\DependencyInjection; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; -use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition; class SettingsBuilderTest extends \PHPUnit_Framework_TestCase { diff --git a/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php b/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php index c506955ae61..dffbb8ec8de 100644 --- a/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php +++ b/src/Oro/Bundle/ConfigBundle/Twig/ConfigExtension.php @@ -11,9 +11,15 @@ class ConfigExtension extends \Twig_Extension */ protected $userConfigManager; - public function __construct(UserConfigManager $userConfigManager) + /** + * @var array + */ + protected $entityOutput; + + public function __construct(UserConfigManager $userConfigManager, $entityOutput = array()) { $this->userConfigManager = $userConfigManager; + $this->entityOutput = $entityOutput; } /** @@ -24,7 +30,8 @@ public function __construct(UserConfigManager $userConfigManager) public function getFunctions() { return array( - 'get_user_value' => new \Twig_Function_Method($this, 'getUserValue'), + 'oro_config_value' => new \Twig_Function_Method($this, 'getUserValue'), + 'oro_config_entity' => new \Twig_Function_Method($this, 'getEntityOutput'), ); } @@ -37,6 +44,28 @@ public function getUserValue($name) return $this->userConfigManager->get($name); } + /** + * Get entity output config (if any provided). + * Provided parameters: + * "icon_class" - CSS class name for icon element + * "name" - custom entity name + * "description" - entity description + * + * @param string $class FQCN of the entity + * @return array + */ + public function getEntityOutput($class) + { + $default = explode('\\', $class); + + return isset($this->entityOutput[$class]) + ? $this->entityOutput[$class] + : array( + 'icon_class' => '', + 'name' => end($default), + 'description' => 'No description' + ); + } /** * Returns the name of the extension. diff --git a/src/Oro/Bundle/DataAuditBundle/Datagrid/AuditDatagridManager.php b/src/Oro/Bundle/DataAuditBundle/Datagrid/AuditDatagridManager.php index fe7a3816fdc..da4f50788b4 100644 --- a/src/Oro/Bundle/DataAuditBundle/Datagrid/AuditDatagridManager.php +++ b/src/Oro/Bundle/DataAuditBundle/Datagrid/AuditDatagridManager.php @@ -4,7 +4,7 @@ use Doctrine\ORM\Query; -use Gedmo\Loggable\LoggableListener; +use Oro\Bundle\DataAuditBundle\Loggable\LoggableManager; use Oro\Bundle\GridBundle\Datagrid\DatagridManager; use Oro\Bundle\GridBundle\Field\FieldDescription; @@ -35,6 +35,7 @@ class AuditDatagridManager extends DatagridManager /** * {@inheritDoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function configureFields(FieldDescriptionCollection $fieldsCollection) { @@ -51,9 +52,9 @@ protected function configureFields(FieldDescriptionCollection $fieldsCollection) 'filterable' => true, 'show_filter' => true, 'choices' => array( - LoggableListener::ACTION_UPDATE => 'Updated', - LoggableListener::ACTION_CREATE => 'Created', - LoggableListener::ACTION_REMOVE => 'Deleted', + LoggableManager::ACTION_UPDATE => 'Updated', + LoggableManager::ACTION_CREATE => 'Created', + LoggableManager::ACTION_REMOVE => 'Deleted', ), 'multiple' => true, ) diff --git a/src/Oro/Bundle/DataAuditBundle/DependencyInjection/OroDataAuditExtension.php b/src/Oro/Bundle/DataAuditBundle/DependencyInjection/OroDataAuditExtension.php index b60f3d24bbf..a5857c84ae7 100644 --- a/src/Oro/Bundle/DataAuditBundle/DependencyInjection/OroDataAuditExtension.php +++ b/src/Oro/Bundle/DataAuditBundle/DependencyInjection/OroDataAuditExtension.php @@ -16,5 +16,6 @@ public function load(array $configs, ContainerBuilder $container) { $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('datagrid.yml'); + $loader->load('services.yml'); } } diff --git a/src/Oro/Bundle/DataAuditBundle/Entity/Audit.php b/src/Oro/Bundle/DataAuditBundle/Entity/Audit.php index d3bd395080b..e5900cad804 100644 --- a/src/Oro/Bundle/DataAuditBundle/Entity/Audit.php +++ b/src/Oro/Bundle/DataAuditBundle/Entity/Audit.php @@ -12,7 +12,7 @@ use Oro\Bundle\UserBundle\Entity\User; /** - * @ORM\Entity + * @ORM\Entity(repositoryClass="Gedmo\Loggable\Entity\Repository\LogEntryRepository") * @ORM\Table(name="oro_audit") */ class Audit extends AbstractLogEntry @@ -92,7 +92,7 @@ class Audit extends AbstractLogEntry /** * @var User $user * - * @ORM\ManyToOne(targetEntity="Oro\Bundle\UserBundle\Entity\User") + * @ORM\ManyToOne(targetEntity="Oro\Bundle\UserBundle\Entity\User", cascade={"persist"}) * @ORM\JoinColumn(name="user_id", referencedColumnName="id", nullable=false, onDelete="CASCADE") * @Type("string") * @Soap\ComplexType("string", nillable=true) diff --git a/src/Oro/Bundle/DataAuditBundle/Entity/AuditableInterface.php b/src/Oro/Bundle/DataAuditBundle/Entity/AuditableInterface.php deleted file mode 100644 index 2467ae7fd7c..00000000000 --- a/src/Oro/Bundle/DataAuditBundle/Entity/AuditableInterface.php +++ /dev/null @@ -1,18 +0,0 @@ - "stringifiedValue" - * ... - * ) - */ - public function setAuditData(); -} \ No newline at end of file diff --git a/src/Oro/Bundle/DataAuditBundle/EventListener/EntitySubscriber.php b/src/Oro/Bundle/DataAuditBundle/EventListener/EntitySubscriber.php new file mode 100644 index 00000000000..7ed761dfb3b --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/EventListener/EntitySubscriber.php @@ -0,0 +1,73 @@ +metadataFactory = $metadataFactory; + $this->loggableManager = $loggableManager; + } + + /** + * @return array + */ + public function getSubscribedEvents() + { + return array( + 'onFlush', + 'loadClassMetadata', + 'postPersist', + ); + } + + /** + * @param OnFlushEventArgs $event + */ + public function onFlush(OnFlushEventArgs $event) + { + $this->loggableManager->handleLoggable($event->getEntityManager()); + } + + /** + * @param LoadClassMetadataEventArgs $event + */ + public function loadClassMetadata(LoadClassMetadataEventArgs $event) + { + if ($metadata = $this->metadataFactory->extendLoadMetadataForClass($event->getClassMetadata())) { + $this->loggableManager->addConfig($metadata); + } + } + + /** + * @param LifecycleEventArgs $event + */ + public function postPersist(LifecycleEventArgs $event) + { + $this->loggableManager->handlePostPersist($event->getEntity(), $event->getEntityManager()); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/EventListener/KernelListener.php b/src/Oro/Bundle/DataAuditBundle/EventListener/KernelListener.php new file mode 100644 index 00000000000..4d834ab280c --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/EventListener/KernelListener.php @@ -0,0 +1,58 @@ +loggableManager = $loggableManager; + $this->securityContext = $securityContext; + } + + /** + * @param GetResponseEvent $event + */ + public function onKernelRequest(GetResponseEvent $event) + { + if (null === $this->securityContext) { + return; + } + + $token = $this->securityContext->getToken(); + if (null !== $token && $this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) { + $this->loggableManager->setUsername($token); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => 'onKernelRequest', + ); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php b/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php deleted file mode 100644 index 17397b2c6bf..00000000000 --- a/src/Oro/Bundle/DataAuditBundle/EventListener/LoggableListener.php +++ /dev/null @@ -1,242 +0,0 @@ -getEventAdapter($eventArgs)->getObjectManager(); - - foreach ($this->loggedObjects as &$lo) { - if ($lo['log']->getAction() == self::ACTION_UPDATE && !$lo['log']->getData()) { - $om->remove($lo['log']); - } - } - } - - /** - * Create a new Audit instance - * - * @param string $action - * @param object $object - * @param LoggableAdapter $ea - */ - protected function createLogEntry($action, $object, LoggableAdapter $ea) - { - $om = $ea->getObjectManager(); - $uow = $om->getUnitOfWork(); - $user = $om->getRepository('OroUserBundle:User')->findOneBy(array('username' => $this->username)); - - if (!$user) { - return; - } - - $wrapped = AbstractWrapper::wrap($object, $om); - $meta = $wrapped->getMetadata(); - - if ($config = $this->getConfiguration($om, $meta->name)) { - $logEntryClass = $this->getLogEntryClass($ea, $meta->name); - $logEntryMeta = $om->getClassMetadata($logEntryClass); - $logEntry = $logEntryMeta->newInstance(); - - // do not store log entries for flexible attributes - add them to a parent entity instead - if ($object instanceof AbstractEntityFlexibleValue) { - if ($action !== self::ACTION_REMOVE && !$this->logFlexible($object, $ea)) { - $objectMeta = $om->getClassMetadata(get_class($object)); - - // if no "parent" object has been saved previously - get it from attribute and save it's log - if ($objectMeta->reflFields['entity']->getValue($object) instanceof AbstractEntityFlexible) { - $this->createLogEntry($action, $objectMeta->reflFields['entity']->getValue($object), $ea); - } - - $this->logFlexible($object, $ea); - } - - return; - } - - $logEntry->setAction($action); - $logEntry->setObjectClass($meta->name); - $logEntry->setLoggedAt(); - $logEntry->setUser($user); - $logEntry->setObjectName(method_exists($object, '__toString') ? $object->__toString() : $meta->name); - - // check for the availability of the primary key - $objectId = $wrapped->getIdentifier(); - - if (!$objectId && $action === self::ACTION_CREATE) { - $this->pendingLogEntryInserts[spl_object_hash($object)] = $logEntry; - } - - $logEntry->setObjectId($objectId); - - $newValues = array(); - - if ($action !== self::ACTION_REMOVE && isset($config['versioned'])) { - foreach ($ea->getObjectChangeSet($uow, $object) as $field => $changes) { - if (!in_array($field, $config['versioned'])) { - continue; - } - - // fix issues with DateTime - if ($changes[0] == $changes[1]) { - continue; - } - - $value = $changes[1]; - - if ($meta->isSingleValuedAssociation($field) && $value) { - $oid = spl_object_hash($value); - $wrappedAssoc = AbstractWrapper::wrap($value, $om); - $value = $wrappedAssoc->getIdentifier(false); - - if (!is_array($value) && !$value) { - $this->pendingRelatedObjects[$oid][] = array( - 'log' => $logEntry, - 'field' => $field - ); - } - } - - $newValues[$field] = array( - 'old' => $changes[0], - 'new' => $value, - ); - } - - $logEntry->setData($newValues); - } - - if ($action === self::ACTION_UPDATE && 0 === count($newValues) && !($object instanceof AbstractEntityFlexible)) { - return; - } - - $version = 1; - - if ($action !== self::ACTION_CREATE) { - $version = $ea->getNewVersion($logEntryMeta, $object); - - if (empty($version)) { - // was versioned later - $version = 1; - } - } - - $logEntry->setVersion($version); - - $this->prePersistLogEntry($logEntry, $object); - - $om->persist($logEntry); - $uow->computeChangeSet($logEntryMeta, $logEntry); - - // save logged data for possible future handling of flexible attributes - if ($object instanceof AbstractEntityFlexible) { - $this->loggedObjects[] = array( - 'object' => $object, - 'log' => $logEntry, - 'meta' => $logEntryMeta, - ); - } - } - } - - /** - * Add flexible attribute log to a parent entity's log entry - * - * @param AbstractEntityFlexibleValue $object - * @param LoggableAdapter $ea - * @return boolean True if value has been saved, false otherwise - */ - protected function logFlexible(AbstractEntityFlexibleValue $object, LoggableAdapter $ea) - { - $om = $ea->getObjectManager(); - $uow = $om->getUnitOfWork(); - - foreach ($this->loggedObjects as &$lo) { - if ($lo['object']->getValues()->contains($object)) { - $logEntry = $lo['log']; - $changes = current($ea->getObjectChangeSet($uow, $object)); - $oldData = $changes[0]; - $newData = $object->getData(); - - if ($oldData instanceof AbstractEntityAttributeOption) { - $oldData = $oldData->getOptionValue()->getValue(); - } - - if ($newData instanceof AbstractEntityAttributeOption) { - $newData = $newData->getOptionValue()->getValue(); - } elseif ($newData instanceof Collection) { - $oldData = implode( - ', ', - array_map( - function ($item) { - return $item->getOptionValue()->getValue(); - }, - $newData->getSnapshot() - ) - ); - - $newData = implode( - ', ', - $newData->map(function ($item) { - return $item->getOptionValue()->getValue(); - })->toArray() - ); - } - - // special case for, as an example, decimal values - // do not store changeset d:123 and s:3:"123" - if ($oldData == $newData) { - return true; - } - - $data = array_merge( - (array) $logEntry->getData(), - array( - $object->getAttribute()->getCode() => array( - 'old' => $oldData, - 'new' => $newData, - ) - ) - ); - - $logEntry->setData($data); - - $om->persist($logEntry); - $uow->recomputeSingleEntityChangeSet($lo['meta'], $logEntry); - - return true; - } - } - - return false; - } -} diff --git a/src/Oro/Bundle/DataAuditBundle/Form/EventListener/AuditableSubscriber.php b/src/Oro/Bundle/DataAuditBundle/Form/EventListener/AuditableSubscriber.php deleted file mode 100644 index 494048328bc..00000000000 --- a/src/Oro/Bundle/DataAuditBundle/Form/EventListener/AuditableSubscriber.php +++ /dev/null @@ -1,34 +0,0 @@ - 'postBind', - ); - } - - public function postBind(FormEvent $event) - { - /* @var $entity AuditableInterface */ - $entity = $event->getData(); - - if (is_null($entity) || !$entity instanceof AuditableInterface) { - return; - } - - $entity->setAuditData(); - } -} diff --git a/src/Oro/Bundle/DataAuditBundle/Loggable/LoggableManager.php b/src/Oro/Bundle/DataAuditBundle/Loggable/LoggableManager.php new file mode 100644 index 00000000000..9c6cccdda05 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Loggable/LoggableManager.php @@ -0,0 +1,482 @@ +logEntityClass = $logEntityClass; + } + + /** + * @param ClassMetadata $metadata + */ + public function addConfig(ClassMetadata $metadata) + { + $this->configs[$metadata->name] = $metadata; + } + + /** + * @param $name + * @return ClassMetadata + * @throws InvalidParameterException + */ + public function getConfig($name) + { + if (!isset($this->configs[$name])) { + throw new InvalidParameterException(sprintf('invalid config name %s', $name)); + } + + return $this->configs[$name]; + } + + /** + * @param $name + * @return bool + */ + public function hasConfig($name) + { + return isset($this->configs[$name]); + } + + /** + * @param $username + * @throws \InvalidArgumentException + */ + public function setUsername($username) + { + if (is_string($username)) { + $this->username = $username; + } elseif (is_object($username) && method_exists($username, 'getUsername')) { + $this->username = (string) $username->getUsername(); + } else { + throw new \InvalidArgumentException("Username must be a string, or object should have method: getUsername"); + } + } + + /** + * @param EntityManager $em + */ + public function handleLoggable(EntityManager $em) + { + $this->em = $em; + $uow = $em->getUnitOfWork(); + + $collections = array_merge($uow->getScheduledCollectionUpdates(), $uow->getScheduledCollectionDeletions()); + foreach ($collections as $collection) { + $this->calculateCollectionData($collection); + } + + foreach ($uow->getScheduledEntityInsertions() as $entity) { + $this->createLogEntity(self::ACTION_CREATE, $entity); + } + foreach ($uow->getScheduledEntityUpdates() as $entity) { + $this->createLogEntity(self::ACTION_UPDATE, $entity); + } + foreach ($uow->getScheduledEntityDeletions() as $entity) { + $this->createLogEntity(self::ACTION_REMOVE, $entity); + } + } + + /** + * @param $entity + * @param EntityManager $em + */ + public function handlePostPersist($entity, EntityManager $em) + { + $this->em = $em; + $uow = $em->getUnitOfWork(); + + $oid = spl_object_hash($entity); + + if ($this->pendingLogEntityInserts && array_key_exists($oid, $this->pendingLogEntityInserts)) { + $logEntry = $this->pendingLogEntityInserts[$oid]; + $logEntryMeta = $em->getClassMetadata(get_class($logEntry)); + + $id = $this->getIdentifier($entity); + $logEntryMeta->getReflectionProperty('objectId')->setValue($logEntry, $id); + $uow->scheduleExtraUpdate($logEntry, array( + 'objectId' => array(null, $id) + )); + + $uow->setOriginalEntityProperty(spl_object_hash($logEntry), 'objectId', $id); + + unset($this->pendingLogEntityInserts[$oid]); + } + + if ($this->pendingRelatedEntities && array_key_exists($oid, $this->pendingRelatedEntities)) { + $identifiers = $uow->getEntityIdentifier($entity); + + foreach ($this->pendingRelatedEntities[$oid] as $props) { + $logEntry = $props['log']; + $oldData = $data = $logEntry->getData(); + $data[$props['field']] = $identifiers; + $logEntry->setData($data); + + $uow->scheduleExtraUpdate($logEntry, array( + 'data' => array($oldData, $data) + )); + $uow->setOriginalEntityProperty(spl_object_hash($logEntry), 'objectId', $data); + } + unset($this->pendingRelatedEntities[$oid]); + } + } + + /** + * @param PersistentCollection $collection + */ + protected function calculateCollectionData(PersistentCollection $collection) + { + $ownerEntity = $collection->getOwner(); + + if ($this->hasConfig(get_class($ownerEntity))) { + $meta = $this->getConfig(get_class($ownerEntity)); + $collectionMapping = $collection->getMapping(); + + if (isset($meta->propertyMetadata[$collectionMapping['fieldName']])) { + $method = $meta->propertyMetadata[$collectionMapping['fieldName']]->method; + + $oldData = array_reduce( + $collection->getSnapshot(), + function ($result, $item) use ($method) { + return $result . ($result ? ', ' : '') . $item->{$method}(); + } + ); + + $newData = array_reduce( + $collection->toArray(), + function ($result, $item) use ($method) { + return $result . ($result ? ', ' : '') . $item->{$method}(); + } + ); + + $this->collectionLogData[$collectionMapping['fieldName']] = array( + 'old' => $oldData, + 'new' => $newData, + ); + } + } + } + + /** + * @param $action + * @param $entity + */ + protected function createLogEntity($action, $entity) + { + if (!$this->username) { + return; + } + + /** @var User $user */ + $user = $this->em->getRepository('OroUserBundle:User')->findOneBy(array('username' => $this->username)); + + if (!$user) { + return; + } + + $uow = $this->em->getUnitOfWork(); + + if ($this->hasConfig(get_class($entity))) { + $meta = $this->getConfig(get_class($entity)); + $entityMeta = $this->em->getClassMetadata(get_class($entity)); + + $logEntryMeta = $this->em->getClassMetadata($this->getLogEntityClass()); + /** @var Audit $logEntry */ + $logEntry = $logEntryMeta->newInstance(); + + // do not store log entries for flexible attributes - add them to a parent entity instead + if ($entity instanceof AbstractEntityFlexibleValue) { + if ($action !== self::ACTION_REMOVE && !$this->logFlexible($entity)) { + $flexibleEntityMeta = $this->em->getClassMetadata(get_class($entity)); + + // if no "parent" object has been saved previously - get it from attribute and save it's log + if ($flexibleEntityMeta->reflFields['entity']->getValue($entity) instanceof AbstractEntityFlexible) { + $this->createLogEntity($action, $flexibleEntityMeta->reflFields['entity']->getValue($entity)); + } + + $this->logFlexible($entity); + } + + return; + } + + $logEntry->setAction($action); + $logEntry->setObjectClass($meta->name); + $logEntry->setLoggedAt(); + $logEntry->setUser($user); + $logEntry->setObjectName(method_exists($entity, '__toString') ? $entity->__toString() : $meta->name); + + $entityId = $this->getIdentifier($entity); + + if (!$entityId && $action === self::ACTION_CREATE) { + $this->pendingLogEntityInserts[spl_object_hash($entity)] = $logEntry; + } + + $logEntry->setObjectId($entityId); + + $newValues = array(); + + if ($action !== self::ACTION_REMOVE && count($meta->propertyMetadata)) { + foreach ($uow->getEntityChangeSet($entity) as $field => $changes) { + if (!isset($meta->propertyMetadata[$field])) { + continue; + } + + // fix issues with DateTime + if ($changes[0] == $changes[1]) { + continue; + } + + $value = $changes[1]; + + if ($entityMeta->isSingleValuedAssociation($field) && $value) { + $oid = spl_object_hash($value); + $value = $this->getIdentifier($value); + + if (!is_array($value) && !$value) { + $this->pendingRelatedEntities[$oid][] = array( + 'log' => $logEntry, + 'field' => $field + ); + } + } + + $newValues[$field] = array( + 'old' => $changes[0], + 'new' => $value, + ); + } + + $logEntry->setData(array_merge($newValues, $this->collectionLogData)); + } + + + if ($action === self::ACTION_UPDATE && 0 === count($newValues) && !($entity instanceof AbstractEntityFlexible)) { + return; + } + + $version = 1; + + if ($action !== self::ACTION_CREATE) { + $version = $this->getNewVersion($logEntryMeta, $entity); + + if (empty($version)) { + // was versioned later + $version = 1; + } + } + + $logEntry->setVersion($version); + + $this->em->persist($logEntry); + $uow->computeChangeSet($logEntryMeta, $logEntry); + + // save logged data for possible future handling of flexible attributes + if ($entity instanceof AbstractEntityFlexible) { + $this->loggedObjects[] = array( + 'object' => $entity, + 'log' => $logEntry, + 'meta' => $logEntryMeta, + ); + } + } + } + + /** + * Get the LogEntry class + * + * @return string + */ + protected function getLogEntityClass() + { + return $this->logEntityClass; + } + + /** + * Add flexible attribute log to a parent entity's log entry + * + * @param AbstractEntityFlexibleValue $entity + * @return boolean True if value has been saved, false otherwise + */ + protected function logFlexible(AbstractEntityFlexibleValue $entity) + { + $uow = $this->em->getUnitOfWork(); + + foreach ($this->loggedObjects as &$lo) { + if ($lo['object']->getValues()->contains($entity)) { + $logEntry = $lo['log']; + $changes = current($uow->getEntityChangeSet($entity)); + $oldData = $changes[0]; + $newData = $entity->getData(); + + if ($oldData instanceof AbstractEntityAttributeOption) { + $oldData = $oldData->getOptionValue()->getValue(); + } + + if ($newData instanceof AbstractEntityAttributeOption) { + $newData = $newData->getOptionValue()->getValue(); + } elseif ($newData instanceof Collection) { + $oldData = implode( + ', ', + array_map( + function (AbstractEntityAttributeOption $item) { + return $item->getOptionValue()->getValue(); + }, + $newData->getSnapshot() + ) + ); + + $newData = implode( + ', ', + $newData->map(function (AbstractEntityAttributeOption $item) { + return $item->getOptionValue()->getValue(); + })->toArray() + ); + } + + // special case for, as an example, decimal values + // do not store changeset d:123 and s:3:"123" + if ($oldData == $newData) { + return true; + } + + $data = array_merge( + (array) $logEntry->getData(), + array( + $entity->getAttribute()->getCode() => array( + 'old' => $oldData, + 'new' => $newData, + ) + ) + ); + + $logEntry->setData($data); + + $this->em->persist($logEntry); + $uow->recomputeSingleEntityChangeSet($lo['meta'], $logEntry); + + return true; + } + } + + return false; + } + + /** + * @param $logEntityMeta + * @param $entity + * @return mixed + */ + protected function getNewVersion($logEntityMeta, $entity) + { + $entityMeta = $this->em->getClassMetadata(get_class($entity)); + $entityId = $this->getIdentifier($entity); + + $dql = "SELECT MAX(log.version) FROM {$logEntityMeta->name} log"; + $dql .= " WHERE log.objectId = :objectId"; + $dql .= " AND log.objectClass = :objectClass"; + + $q = $this->em->createQuery($dql); + $q->setParameters(array( + 'objectId' => $entityId, + 'objectClass' => $entityMeta->name + )); + + return $q->getSingleScalarResult() + 1; + } + + /** + * @param $entity + * @param null $entityMeta + * @return mixed + */ + protected function getIdentifier($entity, $entityMeta = null) + { + $entityMeta = $entityMeta ? $entityMeta : $this->em->getClassMetadata(get_class($entity)); + $identifierField = $entityMeta->getSingleIdentifierFieldName($entityMeta); + + return $entityMeta->getReflectionProperty($identifierField)->getValue($entity); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Metadata/Annotation/Loggable.php b/src/Oro/Bundle/DataAuditBundle/Metadata/Annotation/Loggable.php new file mode 100644 index 00000000000..67ec6a6a761 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Metadata/Annotation/Loggable.php @@ -0,0 +1,13 @@ +method = $data['method']; + } elseif (isset($data['value'])) { + $this->method = $data['value']; + } + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Metadata/ClassMetadata.php b/src/Oro/Bundle/DataAuditBundle/Metadata/ClassMetadata.php new file mode 100644 index 00000000000..0b044fa890f --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Metadata/ClassMetadata.php @@ -0,0 +1,9 @@ +reader = $reader; + } + + /** + * Merge DoctrineClassMetadata and DataAuditClassMetadata + * @param DoctrineClassMetadata $doctrineClassMetadata + * @return null|ClassMetadata + * @throws \InvalidArgumentException + */ + public function extendLoadMetadataForClass(DoctrineClassMetadata $doctrineClassMetadata) + { + if ($doctrineClassMetadata->isMappedSuperclass + || !$classMetadata = $this->loadMetadataForClass($doctrineClassMetadata->getReflectionClass()) + ) { + return null; + } + + /** @var $property PropertyMetadata */ + foreach ($classMetadata->propertyMetadata as $name => $property) { + if ($doctrineClassMetadata->isInheritedField($name) || + isset($doctrineClassMetadata->associationMappings[$property->name]['inherited']) + ) { + unset($classMetadata->propertyMetadata[$name]); + continue; + } + + if ($doctrineClassMetadata->isCollectionValuedAssociation($name)) { + $property->isCollection = true; + + $targetMapping = $doctrineClassMetadata->getAssociationMapping($name); + + if (!method_exists($targetMapping['targetEntity'], $property->method)) { + throw new \InvalidArgumentException(sprintf( + "Method %s in Class %s is not defined. Class must implement a method '__toString' or configure getMethod with Versioned annotation", + $property->method, + $targetMapping['targetEntity']) + ); + } + } + } + + return $classMetadata; + } + + /** + * {@inheritdoc} + */ + public function loadMetadataForClass(\ReflectionClass $class) + { + $classMetadata = new ClassMetadata($class->getName()); + + /** @var Loggable $loggable */ + $loggable = $this->reader->getClassAnnotation($class, self::LOGGABLE); + + foreach ($class->getProperties() as $reflectionProperty) { + /** @var Versioned $versioned */ + if ($versioned = $this->reader->getPropertyAnnotation($reflectionProperty, self::VERSIONED)) { + $propertyMetadata = new PropertyMetadata($class->getName(), $reflectionProperty->getName()); + $propertyMetadata->method = $versioned->method ? $versioned->method : '__toString'; + + $classMetadata->addPropertyMetadata($propertyMetadata); + } + } + + if (count($classMetadata->propertyMetadata) && !$loggable) { + throw new \InvalidArgumentException(sprintf( + "Class must be annoted with Loggable annotation in order to track versioned fields in class - %s", + $classMetadata->name) + ); + } + + if (count($classMetadata->propertyMetadata)) { + return $classMetadata; + } else { + return null; + } + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Metadata/ExtendMetadataFactory.php b/src/Oro/Bundle/DataAuditBundle/Metadata/ExtendMetadataFactory.php new file mode 100644 index 00000000000..6ea2dd33585 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Metadata/ExtendMetadataFactory.php @@ -0,0 +1,32 @@ +driver = $driver; + } + + /** + * @param DoctrineClassMetadata $metadata + * @return null|ClassMetadata + */ + public function extendLoadMetadataForClass(DoctrineClassMetadata $metadata) + { + return $this->driver->extendLoadMetadataForClass($metadata); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Metadata/PropertyMetadata.php b/src/Oro/Bundle/DataAuditBundle/Metadata/PropertyMetadata.php new file mode 100644 index 00000000000..5a881e85de0 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Metadata/PropertyMetadata.php @@ -0,0 +1,44 @@ +isCollection, + $this->method, + parent::serialize(), + )); + } + + /** + * {@inheritdoc} + */ + public function unserialize($str) + { + list( + $this->isCollection, + $this->method, + $parentStr + ) = unserialize($str); + + parent::unserialize($parentStr); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/README.md b/src/Oro/Bundle/DataAuditBundle/README.md index fe36215b33b..371f782db7b 100644 --- a/src/Oro/Bundle/DataAuditBundle/README.md +++ b/src/Oro/Bundle/DataAuditBundle/README.md @@ -35,18 +35,6 @@ public function registerBundles() } ``` -Enable Loggable behavior in your `app/config/config.yml` file and customize `LoggableListener`: - -``` yaml -stof_doctrine_extensions: - orm: - default: - [...] - loggable: true - class: - [...] - loggable: Oro\Bundle\DataAuditBundle\EventListener\LoggableListener -``` To enable log view and API calls, import routing rules in `app/config/routing.yml` @@ -67,12 +55,12 @@ In your entity add special annotations to mark particular fields versioned. ``` php {% block content %} -
+
{% endblock %} {% endblock %} diff --git a/src/Oro/Bundle/DataAuditBundle/Resources/views/Audit/index.html.twig b/src/Oro/Bundle/DataAuditBundle/Resources/views/Audit/index.html.twig index f44750d00f6..ee16d3ebf95 100644 --- a/src/Oro/Bundle/DataAuditBundle/Resources/views/Audit/index.html.twig +++ b/src/Oro/Bundle/DataAuditBundle/Resources/views/Audit/index.html.twig @@ -1,17 +1,7 @@ -{% extends bap.layout %} - -{% block head_script %} +{% extends 'OroUIBundle:actions:index.html.twig' %} +{% import 'OroUIBundle::macros.html.twig' as UI %} +{% set gridId = 'audit-grid' %} +{% block content %} + {% set pageTitle = 'Data Audit' %} {{ parent() }} - - {% include 'OroGridBundle:Include:javascript.html.twig' with {'datagridView': datagrid, 'selector': '#audit-grid'} %} - {% include 'OroGridBundle:Include:stylesheet.html.twig' %} -{% endblock %} - -{% block page_container %} -
- {% block content %} -

{{ 'Data Audit'|trans }}

-
- {% endblock %} -
{% endblock %} diff --git a/src/Oro/Bundle/DataAuditBundle/Resources/views/change_history_link.html.twig b/src/Oro/Bundle/DataAuditBundle/Resources/views/change_history_link.html.twig new file mode 100644 index 00000000000..bfb3cf326f5 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Resources/views/change_history_link.html.twig @@ -0,0 +1,6 @@ +
+ +
diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Functional/RestDataAuditApiTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Functional/RestDataAuditApiTest.php new file mode 100644 index 00000000000..3f915b83e79 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Functional/RestDataAuditApiTest.php @@ -0,0 +1,91 @@ +client = static::createClient(array(), ToolsAPI::generateWsseHeader()); + } + + /** + * @return array + */ + public function testPreconditions() + { + //create users + $request = array( + "user" => array ( + "username" => 'user_' . mt_rand(), + "email" => 'test_' . mt_rand() . '@test.com', + "enabled" => '1', + "plainPassword" => '1231231q', + "firstName" => "firstName", + "lastName" => "lastName", + "rolesCollection" => array("1") + ) + ); + + $this->client->request('POST', 'http://localhost/api/rest/latest/user', $request); + $result = $this->client->getResponse(); + ToolsAPI::assertJsonResponse($result, 201); + + return $request; + } + + /** + * @param $response + * @return array + * @depends testPreconditions + */ + public function testGetAudits($response) + { + $this->client->request('GET', 'http://localhost/api/rest/latest/audits'); + $result = $this->client->getResponse(); + ToolsAPI::assertJsonResponse($result, 200); + $result = ToolsAPI::jsonToArray($result->getContent()); + + return $result; + } + + /** + * @param array $response + * @return array + * @depends testGetAudits + */ + public function testGetAudit($response) + { + $this->client->request('GET', 'http://localhost/api/rest/latest/audits/' . $response[0]['id']); + $result = $this->client->getResponse(); + ToolsAPI::assertJsonResponse($result, 200); + $result = ToolsAPI::jsonToArray($result->getContent()); + + return $result; + } + + /** + * @param array $response + * @depends testGetAudit + */ + public function testDeleteAudit($response) + { + $this->client->request('DELETE', 'http://localhost/api/rest/latest/audits/' . $response['id']); + $result = $this->client->getResponse(); + ToolsAPI::assertJsonResponse($result, 204); + $this->client->request('GET', 'http://localhost/api/rest/latest/audits/' . $response['id']); + $result = $this->client->getResponse(); + ToolsAPI::assertJsonResponse($result, 404); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Functional/SoapDataAuditApiTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Functional/SoapDataAuditApiTest.php new file mode 100644 index 00000000000..f0929940220 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Functional/SoapDataAuditApiTest.php @@ -0,0 +1,85 @@ +client = static::createClient(array(), ToolsAPI::generateWsseHeader()); + + $this->client->soap( + "http://localhost/api/soap", + array( + 'location' => 'http://localhost/api/soap', + 'soap_version' => SOAP_1_2 + ) + ); + } + + /** + * @return array + */ + public function testPreconditions() + { + //create users + $request = array( + "username" => 'user_' . mt_rand(), + "email" => 'test_' . mt_rand() . '@test.com', + "enabled" => '1', + "plainPassword" => '1231231q', + "firstName" => "firstName", + "lastName" => "lastName", + "rolesCollection" => array("1") + ); + $result = $this->client->soapClient->createUser($request); + $this->assertTrue($result, $this->client->soapClient->__getLastResponse()); + + return $request; + } + + /** + * @param $response + * @return array + * @depends testPreconditions + */ + public function testGetAudits($response) + { + $this->markTestSkipped('BAP-949'); + $result = $this->client->soapClient->getAudits(); + + return $result; + } + + /** + * @param array $response + * @return array + * @depends testGetAudits + */ + public function testGetAudit($response) + { + $result = $this->client->soapClient->getAudit($response[0]['id']); + + return $result; + } + + /** + * @param array $response + * @depends testGetAudit + */ + public function testDeleteAudit($response) + { + $this->client->soapClient->deleteAudit($response[0]['id']); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/DependencyInjection/OroDataAuditExtensionTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/DependencyInjection/OroDataAuditExtensionTest.php index 0979ee419db..e9240e7cc25 100644 --- a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/DependencyInjection/OroDataAuditExtensionTest.php +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/DependencyInjection/OroDataAuditExtensionTest.php @@ -1,6 +1,6 @@ assertTrue($configuration instanceof ContainerBuilder); $this->assertTrue($configuration->has('oro_dataaudit.datagrid.manager')); + $this->assertTrue($configuration->has('oro_dataaudit.loggable.loggable_manager')); + $this->assertTrue($configuration->has('oro_dataaudit.listener.kernel_listener')); } /** diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditDataTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditDataTest.php new file mode 100644 index 00000000000..29cb5fc6857 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditDataTest.php @@ -0,0 +1,18 @@ +assertInstanceOf('Oro\Bundle\DataAuditBundle\Entity\AuditData', $auditData); + + $this->assertEquals('key', $auditData->getKey()); + $this->assertEquals('value', $auditData->getValue()); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditTest.php index d755a2636cf..a463e35c726 100644 --- a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditTest.php +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Entity/AuditTest.php @@ -1,6 +1,6 @@ id; + } + + /** + * @param mixed $name + * @return $this + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @param mixed $collection + * @return $this + */ + public function setCollection($collection) + { + $this->collection = $collection; + + return $this; + } + + /** + * @return mixed + */ + public function getCollection() + { + return $this->collection; + } + + /** + * @param LoggableCollectionClass[] $collectionWithMethodName + * @return $this + */ + public function setCollectionWithMethodName($collectionWithMethodName) + { + $this->collectionWithMethodName = $collectionWithMethodName; + + return $this; + } + + /** + * @return LoggableCollectionClass[] + */ + public function getCollectionWithMethodName() + { + return $this->collectionWithMethodName; + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Fixture/LoggableCollectionClass.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Fixture/LoggableCollectionClass.php new file mode 100644 index 00000000000..82e553fd543 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Fixture/LoggableCollectionClass.php @@ -0,0 +1,62 @@ +id; + } + + /** + * @param mixed $name + * @return $this + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->name; + } + + /** + * @return string + */ + public function __toString() + { + return $this->name; + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Fixture/Repository/UserRepository.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Fixture/Repository/UserRepository.php new file mode 100644 index 00000000000..ac6ad3d8f6f --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Fixture/Repository/UserRepository.php @@ -0,0 +1,17 @@ +setUsername('testUser'); + + return $user; + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Loggable/LoggableManagerTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Loggable/LoggableManagerTest.php new file mode 100644 index 00000000000..f3d510b7749 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Loggable/LoggableManagerTest.php @@ -0,0 +1,99 @@ +em->getClassMetadata('Oro\Bundle\UserBundle\Entity\User'); + $meta->setCustomRepositoryClass('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\Repository\UserRepository'); + + $this->config = $this->loggableAnnotationDriver->extendLoadMetadataForClass( + $this->em->getClassMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass') + ); + + $this->loggableManager = new LoggableManager('Oro\Bundle\DataAuditBundle\Entity\Audit'); + $this->loggableManager->addConfig($this->config); + + $this->loggableClass = new LoggableClass(); + $this->loggableClass->setName('testName'); + } + + public function testHandleLoggable() + { + $loggableCollectionClass = new LoggableCollectionClass(); + $loggableCollectionClass->setName('testCollectionName'); + + $collection = new PersistentCollection($this->em, get_class($loggableCollectionClass), array($loggableCollectionClass)); + $collection->setDirty(true); + $this->loggableClass->setCollection($collection); + + $this->em->persist($this->loggableClass); + + //log with out user + $this->loggableManager->handleLoggable($this->em); + + //log with user + $this->loggableManager->setUsername('testUser'); + $this->loggableManager->handleLoggable($this->em); + + //log delete + $this->em->remove($this->loggableClass); + $this->loggableManager->handleLoggable($this->em); + } + + public function testHandlePostPersist() + { + $this->loggableManager->handlePostPersist($this->loggableClass, $this->em); + } + + public function testSetUsername() + { + $user = new User(); + $user->setUsername('testuser'); + + $this->loggableManager->setUsername($user); + + $this->setExpectedException('InvalidArgumentException', 'Username must be a string, or object should have method: getUsername'); + $wrongUser = new \stdClass(); + $this->loggableManager->setUsername($wrongUser); + } + + public function testGetConfig() + { + $this->setExpectedException('InvalidArgumentException', 'Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClassWrong'); + $this->loggableManager->getConfig('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClassWrong'); + + $resultConfig = $this->loggableManager->getConfig('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass'); + + $this->assertEquals($this->config, $resultConfig); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/AbstractMetadataTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/AbstractMetadataTest.php new file mode 100644 index 00000000000..7bedf57bf1c --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/AbstractMetadataTest.php @@ -0,0 +1,41 @@ +em = $this->_getTestEntityManager(); + $this->em->getConfiguration()->setEntityNamespaces(array( + 'OroUserBundle' => 'Oro\\Bundle\\UserBundle\\Entity', + 'OroDataAuditBundle' => 'Oro\\Bundle\\DataAuditBundle\\Entity' + )); + $this->em->getConfiguration()->setMetadataDriverImpl($metadataDriver); + + $this->loggableAnnotationDriver = new \Oro\Bundle\DataAuditBundle\Metadata\Driver\AnnotationDriver(new AnnotationReader()); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/Annotation/VersionedTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/Annotation/VersionedTest.php new file mode 100644 index 00000000000..96e83e653bd --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/Annotation/VersionedTest.php @@ -0,0 +1,17 @@ + '__toString')); + $versioned2 = new Versioned(array('method' => '__toString')); + + $this->assertAttributeEquals('__toString', 'method', $versioned); + $this->assertAttributeEquals('__toString', 'method', $versioned2); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/Driver/AnnotationDriverTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/Driver/AnnotationDriverTest.php new file mode 100644 index 00000000000..884d7693250 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/Driver/AnnotationDriverTest.php @@ -0,0 +1,48 @@ +em->getClassMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass'); + + $nameProperty = new PropertyMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass', 'name'); + $nameProperty->method = '__toString'; + + $collectionProperty = new PropertyMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass', 'collection'); + $collectionProperty->method = '__toString'; + $collectionProperty->isCollection = true; + + $collectionWithMethodNameProperty = new PropertyMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass', 'collectionWithMethodName'); + $collectionWithMethodNameProperty->isCollection = true; + $collectionWithMethodNameProperty->method = 'getName'; + + $metadata = new BaseClassMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass'); + $metadata->addPropertyMetadata($nameProperty); + $metadata->addPropertyMetadata($collectionProperty); + $metadata->addPropertyMetadata($collectionWithMethodNameProperty); + + $annotationDriver = new AnnotationDriver(new AnnotationReader()); + + $resultMetadata = $annotationDriver->extendLoadMetadataForClass($doctrineClassMetadata); + + $metadata->createdAt = $resultMetadata->createdAt; + + $this->assertEquals($metadata, $resultMetadata); + } + + public function testLoadMetadataForClass() + { + $this->assertEquals(true, true); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/ExtendMetadataFactoryTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/ExtendMetadataFactoryTest.php new file mode 100644 index 00000000000..71d3ec5b777 --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/ExtendMetadataFactoryTest.php @@ -0,0 +1,22 @@ +em->getClassMetadata('Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass'); + + $metadata = $this->loggableAnnotationDriver->extendLoadMetadataForClass($doctrineClassMetadata); + + $metadataFactory = new ExtendMetadataFactory($this->loggableAnnotationDriver); + $resultMetadata = $metadataFactory->extendLoadMetadataForClass($doctrineClassMetadata); + + $metadata->createdAt = $resultMetadata->createdAt; + + $this->assertEquals($metadata, $resultMetadata); + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/PropertyMetadataTest.php b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/PropertyMetadataTest.php new file mode 100644 index 00000000000..7b3eafbc48f --- /dev/null +++ b/src/Oro/Bundle/DataAuditBundle/Tests/Unit/Metadata/PropertyMetadataTest.php @@ -0,0 +1,34 @@ +propertyMetadata = new PropertyMetadata( + 'Oro\Bundle\DataAuditBundle\Tests\Unit\Fixture\LoggableClass', + 'name' + ); + } + + public function testSerializeUnserialize() + { + $this->propertyMetadata->isCollection = true; + $this->propertyMetadata->method = 'getName'; + + $this->assertEquals($this->propertyMetadata, unserialize(serialize($this->propertyMetadata))); + } + + public function tearDown() + { + $this->propertyMetadata = null; + } +} diff --git a/src/Oro/Bundle/DataAuditBundle/phpunit.xml.dist b/src/Oro/Bundle/DataAuditBundle/phpunit.xml.dist index 03e301e89c0..829e44d12d0 100644 --- a/src/Oro/Bundle/DataAuditBundle/phpunit.xml.dist +++ b/src/Oro/Bundle/DataAuditBundle/phpunit.xml.dist @@ -10,7 +10,7 @@ stopOnFailure="false" syntaxCheck="false" bootstrap="Tests/bootstrap.php" -> + > diff --git a/src/Oro/Bundle/FilterBundle/Form/Type/Filter/EntityFilterType.php b/src/Oro/Bundle/FilterBundle/Form/Type/Filter/EntityFilterType.php new file mode 100644 index 00000000000..606313d9fd0 --- /dev/null +++ b/src/Oro/Bundle/FilterBundle/Form/Type/Filter/EntityFilterType.php @@ -0,0 +1,54 @@ +setDefaults( + array( + 'field_type' => 'entity', + 'field_options' => array(), + 'translatable' => false, + ) + ); + + $resolver->setNormalizers( + array( + 'field_type' => function (Options $options, $value) { + if (!empty($options['translatable'])) { + $value = 'translatable_entity'; + } + return $value; + } + ) + ); + } +} diff --git a/src/Oro/Bundle/FilterBundle/Resources/config/form_types.yml b/src/Oro/Bundle/FilterBundle/Resources/config/form_types.yml index 3148398587f..2089c4ea321 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/config/form_types.yml +++ b/src/Oro/Bundle/FilterBundle/Resources/config/form_types.yml @@ -50,3 +50,9 @@ services: arguments: ["@translator"] tags: - { name: form.type, alias: oro_type_boolean_filter } + + oro_filter.form.type.filter.entity: + class: Oro\Bundle\FilterBundle\Form\Type\Filter\EntityFilterType + arguments: ["@translator"] + tags: + - { name: form.type, alias: oro_type_entity_filter } diff --git a/src/Oro/Bundle/FilterBundle/Resources/doc/reference/filter_form_types.md b/src/Oro/Bundle/FilterBundle/Resources/doc/reference/filter_form_types.md index 692d9200bca..40ea67488af 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/doc/reference/filter_form_types.md +++ b/src/Oro/Bundle/FilterBundle/Resources/doc/reference/filter_form_types.md @@ -43,6 +43,11 @@ There are next filters form types: oro_type_choice_filter Represents choice filter form + + EntityFilterType + oro_type_entity_filter + Represents entity filter form + BooleanFilterType oro_type_boolean_filter @@ -222,6 +227,34 @@ _Oro\Bundle\FilterBundle\Form\Type\Filter\ChoiceFilterType_ _Oro.Filter.MultiSelectFilter_ _Oro.Filter.SelectFilter_ +### oro\_type\_entity\_filter Form Type + +**Inherit Options** + +* field\_type +* field\_options +* operator\_choices +* operator\_type +* operator\_options +* show\_filter + +**Default Options** + +* field\_type = entity + +**Parent Type** + +oro\_type\_choice\_filter + +**Class** + +_Oro\Bundle\FilterBundle\Form\Type\Filter\EntityFilterType_ + +**JS Classes** + +_Oro.Filter.MultiSelectFilter_ +_Oro.Filter.SelectFilter_ + ### oro\_type\_boolean\_filter Form Type **Inherit Options** diff --git a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/abstractfilter.js b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/abstractfilter.js index d3e7af97fba..60872de9daa 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/abstractfilter.js +++ b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/abstractfilter.js @@ -355,5 +355,18 @@ Oro.Filter.AbstractFilter = Backbone.View.extend({ } else { element.parent().removeClass(this.buttonActiveClass); } + }, + + /** + * Prevent submit of parent form if any. + * + * @param {Event} e + * @private + */ + _preventEnterProcessing: function(e) { + if (e.keyCode == 13) { + e.preventDefault() + e.stopPropagation(); + } } }); diff --git a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/choicefilter.js b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/choicefilter.js index f9d688a4001..12bd8108491 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/choicefilter.js +++ b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/choicefilter.js @@ -120,6 +120,7 @@ Oro.Filter.ChoiceFilter = Oro.Filter.TextFilter.extend({ */ events: { 'keyup input': '_onReadCriteriaInputKey', + 'keydown [type="text"]': '_preventEnterProcessing', 'click .filter-update': '_onClickUpdateCriteria', 'click .filter-criteria-selector': '_onClickCriteriaSelector', 'click .filter-criteria .filter-criteria-hide': '_onClickCloseCriteria', diff --git a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/selectfilter.js b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/selectfilter.js index d5bead4a13c..09bd742b047 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/selectfilter.js +++ b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/selectfilter.js @@ -117,6 +117,7 @@ Oro.Filter.SelectFilter = Oro.Filter.AbstractFilter.extend({ * @property */ events: { + 'keydown select': '_preventEnterProcessing', 'click .filter-select': '_onClickFilterArea', 'click .disable-filter': '_onClickDisableFilter', 'change select': '_onSelectChange' @@ -209,7 +210,7 @@ Oro.Filter.SelectFilter = Oro.Filter.AbstractFilter.extend({ */ _setDropdownWidth: function() { if (!this.minimumWidth) { - this.minimumWidth = this.selectWidget.getMinimumDropdownWidth() + 12; + this.minimumWidth = this.selectWidget.getMinimumDropdownWidth() + 22; } var widget = this.selectWidget.getWidget(); var filterWidth = this.$(this.containerSelector).width(); diff --git a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/textfilter.js b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/textfilter.js index c8dd47e439a..65b70965a6c 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/textfilter.js +++ b/src/Oro/Bundle/FilterBundle/Resources/public/js/app/filter/textfilter.js @@ -94,6 +94,7 @@ Oro.Filter.TextFilter = Oro.Filter.AbstractFilter.extend({ */ events: { 'keyup input': '_onReadCriteriaInputKey', + 'keydown [type="text"]': '_preventEnterProcessing', 'click .filter-update': '_onClickUpdateCriteria', 'click .filter-criteria-selector': '_onClickCriteriaSelector', 'click .filter-criteria .filter-criteria-hide': '_onClickCloseCriteria', diff --git a/src/Oro/Bundle/FilterBundle/Resources/views/Filter/layout.js.twig b/src/Oro/Bundle/FilterBundle/Resources/views/Filter/layout.js.twig index d7cdcbc45d3..6a49996517a 100644 --- a/src/Oro/Bundle/FilterBundle/Resources/views/Filter/layout.js.twig +++ b/src/Oro/Bundle/FilterBundle/Resources/views/Filter/layout.js.twig @@ -43,32 +43,36 @@ })) {% endblock %} -{% block oro_type_choice_filter_js %} - {% if formView.children.value.vars.multiple %} - {{ block('oro_type_multiselect_filter_js') }} - {% else %} - {{ block('oro_type_select_filter_js') }} - {% endif %} -{% endblock %} - {% block oro_type_select_filter_js %} Oro.createInstanceFromConstructor(Oro.Filter.SelectFilter.extend({ - 'name': {{ formView.vars.name|json_encode|raw }}, - 'label': {{ formView.vars.label|json_encode|raw }}, - 'enabled': {{ formView.vars.show_filter|json_encode|raw }}, - 'options': {{ formView.children.value.vars.choices|oro_filter_choices|json_encode|raw }} + 'name': {{ formView.vars.name|json_encode|raw }}, + 'label': {{ formView.vars.label|json_encode|raw }}, + 'enabled': {{ formView.vars.show_filter|json_encode|raw }}, + 'options': {{ formView.children.value.vars.choices|oro_filter_choices|json_encode|raw }} })) {% endblock %} {% block oro_type_multiselect_filter_js %} Oro.createInstanceFromConstructor(Oro.Filter.MultiSelectFilter.extend({ - 'name': {{ formView.vars.name|json_encode|raw }}, - 'label': {{ formView.vars.label|json_encode|raw }}, - 'enabled': {{ formView.vars.show_filter|json_encode|raw }}, - 'options': {{ formView.children.value.vars.choices|oro_filter_choices|json_encode|raw }} + 'name': {{ formView.vars.name|json_encode|raw }}, + 'label': {{ formView.vars.label|json_encode|raw }}, + 'enabled': {{ formView.vars.show_filter|json_encode|raw }}, + 'options': {{ formView.children.value.vars.choices|oro_filter_choices|json_encode|raw }} })) {% endblock %} +{% block oro_type_choice_filter_js %} + {% if formView.children.value.vars.multiple %} + {{ block('oro_type_multiselect_filter_js') }} + {% else %} + {{ block('oro_type_select_filter_js') }} + {% endif %} +{% endblock %} + +{% block oro_type_entity_filter_js %} + {{ block('oro_type_choice_filter_js') }} +{% endblock %} + {% block oro_type_boolean_filter_js %} Oro.createInstanceFromConstructor(Oro.Filter.SelectFilter.extend({ 'name': {{ formView.vars.name|json_encode|raw }}, diff --git a/src/Oro/Bundle/FilterBundle/Tests/Unit/DependencyInjection/OroFilterExtensionTest.php b/src/Oro/Bundle/FilterBundle/Tests/Unit/DependencyInjection/OroFilterExtensionTest.php index 7d6ec4282a4..d58733d3279 100644 --- a/src/Oro/Bundle/FilterBundle/Tests/Unit/DependencyInjection/OroFilterExtensionTest.php +++ b/src/Oro/Bundle/FilterBundle/Tests/Unit/DependencyInjection/OroFilterExtensionTest.php @@ -6,7 +6,7 @@ use Symfony\Component\DependencyInjection\Definition; use Oro\Bundle\FilterBundle\DependencyInjection\OroFilterExtension; -class OroGridExtensionTest extends \PHPUnit_Framework_TestCase +class OroFilterExtensionTest extends \PHPUnit_Framework_TestCase { /** * @var array diff --git a/src/Oro/Bundle/FilterBundle/Tests/Unit/Form/Type/Filter/EntityFilterTypeTest.php b/src/Oro/Bundle/FilterBundle/Tests/Unit/Form/Type/Filter/EntityFilterTypeTest.php new file mode 100644 index 00000000000..85c5f3c6444 --- /dev/null +++ b/src/Oro/Bundle/FilterBundle/Tests/Unit/Form/Type/Filter/EntityFilterTypeTest.php @@ -0,0 +1,95 @@ +createMockTranslator(); + $this->type = new EntityFilterType($translator); + $this->factory->addType(new FilterType($translator)); + $this->factory->addType(new ChoiceFilterType($translator)); + + $registry = $this->getMockForAbstractClass('Doctrine\Common\Persistence\ManagerRegistry', array(), '', false); + $this->factory->addType(new EntityType($registry)); + } + + /** + * @return EntityFilterType + */ + protected function getTestFormType() + { + return $this->type; + } + + public function testGetName() + { + $this->assertEquals(EntityFilterType::NAME, $this->type->getName()); + } + + public function testGetParent() + { + $this->assertEquals(ChoiceFilterType::NAME, $this->type->getParent()); + } + + /** + * {@inheritDoc} + */ + public function setDefaultOptionsDataProvider() + { + return array( + array( + 'defaultOptions' => array( + 'field_type' => 'entity', + 'field_options' => array(), + 'translatable' => false, + ) + ) + ); + } + + /** + * @dataProvider bindDataProvider + * @param array $bindData + * @param array $formData + * @param array $viewData + * @param array $customOptions + */ + public function testBindData( + array $bindData, + array $formData, + array $viewData, + array $customOptions = array() + ) { + // bind method should be tested in functional test + } + + /** + * {@inheritDoc} + */ + public function bindDataProvider() + { + return array( + 'empty' => array( + 'bindData' => array(), + 'formData' => array(), + 'viewData' => array(), + ), + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AbstractAttributeType.php b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AbstractAttributeType.php index bd0724efc06..d6b1eabfed0 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AbstractAttributeType.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AbstractAttributeType.php @@ -6,6 +6,7 @@ use Oro\Bundle\FlexibleEntityBundle\AttributeType\AttributeTypeInterface; use Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface; use Oro\Bundle\FlexibleEntityBundle\Model\AbstractAttribute; +use Oro\Bundle\FlexibleEntityBundle\Form\Validator\ConstraintGuesserInterface; /** * Abstract attribute type @@ -32,6 +33,7 @@ abstract class AbstractAttributeType implements AttributeTypeInterface const BACKEND_TYPE_DATE = 'date'; const BACKEND_TYPE_DATETIME = 'datetime'; const BACKEND_TYPE_DECIMAL = 'decimal'; + const BACKEND_TYPE_BOOLEAN = 'boolean'; const BACKEND_TYPE_INTEGER = 'integer'; const BACKEND_TYPE_OPTIONS = 'options'; const BACKEND_TYPE_OPTION = 'option'; @@ -59,13 +61,14 @@ abstract class AbstractAttributeType implements AttributeTypeInterface /** * Constructor * - * @param string $backendType the backend type - * @param string $formType the form type + * @param string $backendType the backend type + * @param string $formType the form type */ - public function __construct($backendType, $formType) + public function __construct($backendType, $formType, ConstraintGuesserInterface $constraintGuesser) { - $this->backendType = $backendType; - $this->formType = $formType; + $this->backendType = $backendType; + $this->formType = $formType; + $this->constraintGuesser = $constraintGuesser; } /** @@ -95,11 +98,13 @@ public function buildValueFormType(FormFactoryInterface $factory, FlexibleValueI { $name = $this->prepareValueFormName($value); $type = $this->prepareValueFormAlias($value); - $options = $this->prepareValueFormOptions($value); $data = $this->prepareValueFormData($value); - $form = $factory->createNamed($name, $type, $data, $options); + $options = array_merge( + $this->prepareValueFormConstraints($value), + $this->prepareValueFormOptions($value) + ); - return $form; + return $factory->createNamed($name, $type, $data, $options); } /** @@ -135,29 +140,24 @@ protected function prepareValueFormAlias(FlexibleValueInterface $value) */ protected function prepareValueFormOptions(FlexibleValueInterface $value) { - $options = array( - 'label' => $value->getAttribute()->getLabel(), - 'required' => $value->getAttribute()->getRequired(), - 'constraints' => array() + return array( + 'label' => $value->getAttribute()->getLabel(), + 'required' => $value->getAttribute()->getRequired(), ); + } - if ($options['required']) { - $options['constraints'][] = new Constraints\NotBlank(); - } - - switch ($value->getAttribute()->getBackendType()) { - case self::BACKEND_TYPE_DATE: - $options['constraints'][] = new Constraints\Date(); - break; - case self::BACKEND_TYPE_DATE: - $options['constraints'][] = new Constraints\Date(); - break; - case self::BACKEND_TYPE_DATETIME: - $options['constraints'][] = new Constraints\DateTime(); - break; + /** + * Guess the constraints to apply on the form + */ + protected function prepareValueFormConstraints(FlexibleValueInterface $value) + { + if ($this->constraintGuesser->supportAttribute($attribute = $value->getAttribute())) { + return array( + 'constraints' => $this->constraintGuesser->guessConstraints($attribute), + ); } - return $options; + return array(); } /** @@ -175,10 +175,47 @@ protected function prepareValueFormData(FlexibleValueInterface $value) /** * {@inheritdoc} */ - public function buildAttributeFormType(FormFactoryInterface $factory, AbstractAttribute $attribute) + public function buildAttributeFormTypes(FormFactoryInterface $factory, AbstractAttribute $attribute) { - // TODO will be used to build attribute create / edit form for attribute management, cf BAP-650 + $properties = $this->defineCustomAttributeProperties($attribute); + + $types = array(); + + foreach ($properties as $property) { + $fieldType = 'text'; + if (isset($property['fieldType'])) { + $fieldType = $property['fieldType']; + } + $data = null; + if (isset($property['data'])) { + $data = $property['data']; + } + $options = array(); + if (isset($property['options'])) { + $options = $property['options']; + } + if (!isset($options['required'])) { + $options['required'] = false; + } + + $types[] = $factory->createNamed($property['name'], $fieldType, $data, $options); + } - return null; + return $types; + } + + /** + * Define custom properties used in attribute form + * + * Each property must be an array with a 'name' key that matches the name of the property + * Optional 'fieldType', 'data' and 'options' keys can be provided for field customization + * + * @param AbstractAttribute $attribute Attribute entity + * + * @return array:array:multitype $properties an array of custom properties + */ + protected function defineCustomAttributeProperties(AbstractAttribute $attribute) + { + return array(); } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AttributeTypeInterface.php b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AttributeTypeInterface.php index e83124005c5..a18bdb5197b 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AttributeTypeInterface.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/AttributeTypeInterface.php @@ -32,12 +32,12 @@ public function getName(); public function buildValueFormType(FormFactoryInterface $factory, FlexibleValueInterface $value); /** - * Build form type for attribute + * Build form types for custom properties of an attribute * * @param FormFactoryInterface $factory the form factory * @param AbstractAttribute $attribute the attribute * * @return FormInterface the form */ - public function buildAttributeFormType(FormFactoryInterface $factory, AbstractAttribute $attribute); + public function buildAttributeFormTypes(FormFactoryInterface $factory, AbstractAttribute $attribute); } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/MetricType.php b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/MetricType.php index f0716a4fa60..8ce9fa69106 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/MetricType.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/MetricType.php @@ -4,6 +4,7 @@ use Oro\Bundle\FlexibleEntityBundle\AttributeType\AbstractAttributeType; use Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface; use Oro\Bundle\MeasureBundle\Manager\MeasureManager; +use Oro\Bundle\FlexibleEntityBundle\Form\Validator\ConstraintGuesserInterface; /** * Metric attribute type @@ -23,9 +24,9 @@ class MetricType extends AbstractAttributeType * @param string $formType the form type * @param MeasureManager $manager The measure manager */ - public function __construct($backendType, $formType, MeasureManager $manager) + public function __construct($backendType, $formType, ConstraintGuesserInterface $constraintGuesser, MeasureManager $manager) { - parent::__construct($backendType, $formType); + parent::__construct($backendType, $formType, $constraintGuesser); $this->manager = $manager; } @@ -43,13 +44,14 @@ public function getName() */ protected function prepareValueFormOptions(FlexibleValueInterface $value) { - return array( - 'label' => $value->getAttribute()->getLabel(), - 'required' => $value->getAttribute()->getRequired(), - 'units' => $this->manager->getUnitSymbolsForFamily( - $value->getAttribute()->getMetricFamily() - ), - 'default_unit' => $value->getAttribute()->getDefaultMetricUnit(), + return array_merge( + parent::prepareValueFormOptions($value), + array( + 'units' => $this->manager->getUnitSymbolsForFamily( + $value->getAttribute()->getMetricFamily() + ), + 'default_unit' => $value->getAttribute()->getDefaultMetricUnit(), + ) ); } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/OptionMultiCheckboxType.php b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/OptionMultiCheckboxType.php index 5a0c9f8d4d8..e43e65a83d2 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/OptionMultiCheckboxType.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/AttributeType/OptionMultiCheckboxType.php @@ -1,7 +1,7 @@ array('=', '<', '<=', '>', '>='), AbstractAttributeType::BACKEND_TYPE_DECIMAL => array('=', '<', '<=', '>', '>='), AbstractAttributeType::BACKEND_TYPE_INTEGER => array('=', '<', '<=', '>', '>='), + AbstractAttributeType::BACKEND_TYPE_BOOLEAN => array('='), AbstractAttributeType::BACKEND_TYPE_OPTION => array('IN', 'NOT IN'), AbstractAttributeType::BACKEND_TYPE_OPTIONS => array('IN', 'NOT IN'), AbstractAttributeType::BACKEND_TYPE_TEXT => array('=', 'NOT LIKE', 'LIKE'), @@ -153,6 +154,9 @@ public function getAllowedOperators($backendType) * * @return string * @throws FlexibleQueryException + * + * @SuppressWarnings(PHPMD) + * TODO: This method should be refactored (BAP-974). */ public function prepareCriteriaCondition($field, $operator, $value) { diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Entity/Mapping/AbstractEntityFlexibleValue.php b/src/Oro/Bundle/FlexibleEntityBundle/Entity/Mapping/AbstractEntityFlexibleValue.php index 1f2e4b5eeb5..25108c8f84f 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Entity/Mapping/AbstractEntityFlexibleValue.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Entity/Mapping/AbstractEntityFlexibleValue.php @@ -84,6 +84,14 @@ abstract class AbstractEntityFlexibleValue extends AbstractFlexibleValue */ protected $decimal; + /** + * Store boolean value + * @var boolean $boolean + * + * @ORM\Column(name="value_boolean", type="boolean", nullable=true) + */ + protected $boolean; + /** * Store text value * @var string $text @@ -149,6 +157,16 @@ public function __construct() $this->collection = new ArrayCollection(); } + /** + * Get entity + * + * @return AbstractFlexible $entity + */ + public function getEntity() + { + return $this->entity; + } + /** * Set entity * @@ -261,6 +279,30 @@ public function setDecimal($decimal) return $this; } + /** + * Get boolean data + * + * @return boolean + */ + public function getBoolean() + { + return $this->boolean; + } + + /** + * Set boolean data + * + * @param boolean $boolean + * + * @return EntityAttributeValue + */ + public function setBoolean($boolean) + { + $this->boolean = $boolean; + + return $this; + } + /** * Get text data * @@ -340,7 +382,7 @@ public function setDatetime($datetime) * * @return AbstractEntityFlexibleValue */ - public function setOption(AbstractEntityAttributeOption $option) + public function setOption(AbstractEntityAttributeOption $option = null) { $this->option = $option; @@ -421,7 +463,7 @@ public function getCollection() * @param AbstractEntityFlexibleValue $value * @return $this */ - public function setCollections(AbstractEntityFlexibleValue $value) + public function setCollections(AbstractEntityFlexibleValue $value = null) { $this->collection = $value->getCollections(); @@ -460,7 +502,7 @@ public function __toString() return implode(', ', $items); - } else if (is_object($data)) { + } elseif (is_object($data)) { return $data->__toString(); } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Entity/Repository/FlexibleEntityRepository.php b/src/Oro/Bundle/FlexibleEntityBundle/Entity/Repository/FlexibleEntityRepository.php index 75a53d9e80f..8c22dc395a0 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Entity/Repository/FlexibleEntityRepository.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Entity/Repository/FlexibleEntityRepository.php @@ -214,11 +214,8 @@ public function createFlexibleQueryBuilder($alias, $attributeCodes = null) $this->entityAlias = $alias; $qb = new FlexibleQueryBuilder($this->_em); - // TODO : grid integration, find a smart way to inject locale and scope in repo then qb - $locale = ($this->getLocale() !== null) ? $this->getLocale() : 'en_US'; - $scope = ($this->getScope() !== null) ? $this->getScope() : 'ecommerce'; - $qb->setLocale($locale); - $qb->setScope($scope); + $qb->setLocale($this->getLocale()); + $qb->setScope($this->getScope()); $qb->select($alias, 'Value', 'Attribute', 'ValueOption', 'AttributeOptionValue') ->from($this->_entityName, $this->entityAlias); @@ -374,24 +371,18 @@ public function findWithAttributes($id) } /** - * Load a flexible entity with only localized values + * Load a flexible entity with its attributes sorted by sortOrder * * @param integer $id * - * @return AbstractFlexible + * @return AbstractFlexible|null + * @throws NonUniqueResultException */ - public function findWithLocalizedValuesAndSortedAttributes($id) + public function findWithSortedAttribute($id) { - $qb = $this->findByWithAttributesQB(array(), array('id' => $id)); - - return $qb - ->andWhere( - $qb->expr()->orX( - $qb->expr()->isNull('Value.locale'), - $qb->expr()->eq('Value.locale', $qb->expr()->literal($this->getLocale())) - ) - ) - ->orderBy('Attribute.sortOrder') + return $this + ->findByWithAttributesQB(array(), array('id' => $id)) + ->addOrderBy('Attribute.sortOrder') ->getQuery() ->getOneOrNullResult(); } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/EventListener/TimestampableListener.php b/src/Oro/Bundle/FlexibleEntityBundle/EventListener/TimestampableListener.php index a08e9081b73..5b45509f04c 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/EventListener/TimestampableListener.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/EventListener/TimestampableListener.php @@ -2,8 +2,10 @@ namespace Oro\Bundle\FlexibleEntityBundle\EventListener; use Doctrine\Common\EventSubscriber; +use Doctrine\Common\Persistence\ObjectManager; use Doctrine\ORM\Event\LifecycleEventArgs; use Oro\Bundle\FlexibleEntityBundle\Model\Behavior\TimestampableInterface; +use Oro\Bundle\FlexibleEntityBundle\Model\AbstractFlexible; /** * Aims to add timestambable behavior @@ -47,8 +49,35 @@ public function prePersist(LifecycleEventArgs $args) public function preUpdate(LifecycleEventArgs $args) { $entity = $args->getEntity(); + + if ($entity instanceof \Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexibleValue) { + $flexible = $entity->getEntity(); + if ($flexible !== null) { + $this->updateFlexibleFields($args->getEntityManager(), $flexible, array('updated')); + } + } + if ($entity instanceof \Oro\Bundle\FlexibleEntityBundle\Model\Behavior\TimestampableInterface) { $entity->setUpdated(new \DateTime('now', new \DateTimeZone('UTC'))); } } + + /** + * Update flexible fields when a value is updated + * + * @param ObjectManager $om + * @param Flexible $flexible + * @param array $fields + */ + protected function updateFlexibleFields(ObjectManager $om, AbstractFlexible $flexible, $fields) + { + $meta = $om->getClassMetadata(get_class($flexible)); + $uow = $om->getUnitOfWork(); + $now = new \DateTime('now', new \DateTimeZone('UTC')); + $changes = array(); + foreach ($fields as $field) { + $changes[$field]= array(null, $now); + } + $uow->scheduleExtraUpdate($flexible, $changes); + } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/FlexibleType.php b/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/FlexibleType.php index 03c3cef1f01..dc6d0434be1 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/FlexibleType.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/FlexibleType.php @@ -52,7 +52,7 @@ public function __construct(FlexibleManager $flexibleManager, $valueFormAlias) public function buildForm(FormBuilderInterface $builder, array $options) { $this->addEntityFields($builder); - $this->addDynamicAttributesFields($builder); + $this->addDynamicAttributesFields($builder, $options); } /** @@ -70,7 +70,7 @@ public function addEntityFields(FormBuilderInterface $builder) * * @param FormBuilderInterface $builder */ - public function addDynamicAttributesFields(FormBuilderInterface $builder) + public function addDynamicAttributesFields(FormBuilderInterface $builder, array $options) { $builder->add( 'values', diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/MetricType.php b/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/MetricType.php index ec4612b5439..2b21a6a0813 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/MetricType.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Form/Type/MetricType.php @@ -28,8 +28,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder ->add('id', 'hidden') ->add('data', 'number') - ->add('unit', 'choice', $unitOptions) - ; + ->add('unit', 'choice', $unitOptions); } /** diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Form/Validator/AttributeConstraintGuesser.php b/src/Oro/Bundle/FlexibleEntityBundle/Form/Validator/AttributeConstraintGuesser.php new file mode 100644 index 00000000000..c993ea69e20 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Form/Validator/AttributeConstraintGuesser.php @@ -0,0 +1,46 @@ + + * @copyright 2013 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class AttributeConstraintGuesser implements ConstraintGuesserInterface +{ + public function supportAttribute(AbstractAttribute $attribute) + { + return true; + } + + public function guessConstraints(AbstractAttribute $attribute) + { + $constraints = array(); + + if ($attribute->getRequired()) { + $constraints[] = new Constraints\NotBlank(); + } + + switch ($attribute->getBackendType()) { + case AbstractAttributeType::BACKEND_TYPE_DATE: + $constraints[] = new Constraints\Date(); + break; + case AbstractAttributeType::BACKEND_TYPE_DATETIME: + $constraints[] = new Constraints\DateTime(); + break; + } + + switch ($attribute->getAttributeType()) { + case 'oro_flexibleentity_email': + $constraints[] = new Constraints\Email(); + break; + } + + return $constraints; + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Form/Validator/ConstraintGuesserInterface.php b/src/Oro/Bundle/FlexibleEntityBundle/Form/Validator/ConstraintGuesserInterface.php new file mode 100644 index 00000000000..269b48e7a07 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Form/Validator/ConstraintGuesserInterface.php @@ -0,0 +1,31 @@ + + * @copyright 2013 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +interface ConstraintGuesserInterface +{ + /** + * Tells wether or not the constraint guesser supports the given attribute type + * + * @param AbstractAttribute $attribute + * + * @return bool + */ + public function supportAttribute(AbstractAttribute $attribute); + + /** + * Guess the constraints for the given attribute + * + * @param AbstractAttribute $attribute + * + * @return Symfony\Component\Validator\Constraint[] + */ + public function guessConstraints(AbstractAttribute $attribute); +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManager.php b/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManager.php index 0957c790f4a..0e73e361499 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManager.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManager.php @@ -83,8 +83,13 @@ class FlexibleManager implements TranslatableInterface, ScopableInterface * @param EventDispatcherInterface $eventDispatcher Event dispatcher * @param AttributeTypeFactory $attributeTypeFactory Attribute type factory */ - public function __construct($flexibleName, $flexibleConfig, ObjectManager $storageManager, EventDispatcherInterface $eventDispatcher, AttributeTypeFactory $attributeTypeFactory) - { + public function __construct( + $flexibleName, + $flexibleConfig, + ObjectManager $storageManager, + EventDispatcherInterface $eventDispatcher, + AttributeTypeFactory $attributeTypeFactory + ) { $this->flexibleName = $flexibleName; $this->flexibleConfig = $flexibleConfig['entities_config'][$flexibleName]; $this->storageManager = $storageManager; @@ -368,21 +373,6 @@ public function createFlexibleValue() return $value; } - /** - * Return only localized values of flexible entity - * - * @param integer $id - * - * @return AbstractFlexible - */ - public function localizedFind($id) - { - $fr = $this->getFlexibleRepository(); - $fr->setLocale($this->getLocale()); - - return $fr->findWithLocalizedValuesAndSortedAttributes($id); - } - /** * Get attribute type factory * diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManagerRegistry.php b/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManagerRegistry.php index 2be18e41880..0c79b84dce4 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManagerRegistry.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Manager/FlexibleManagerRegistry.php @@ -1,7 +1,7 @@ entityToManager[$entityFQCN]; + $realClassName = ClassUtils::getRealClass($entityFQCN); + return $this->entityToManager[$realClassName]; } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/attribute_types.yml b/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/attribute_types.yml index 83103b84eb9..aede0e3c5fd 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/attribute_types.yml +++ b/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/attribute_types.yml @@ -1,112 +1,199 @@ services: oro_flexibleentity.attributetype.boolean: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\BooleanType - arguments: ["integer", "option"] + arguments: + - "boolean" + - "checkbox" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_boolean } + oro_flexibleentity.attributetype.text: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\TextType - arguments: ["varchar", "text"] + arguments: + - "varchar" + - "text" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_text } + oro_flexibleentity.attributetype.textarea: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\TextAreaType - arguments: ["text", "textarea"] + arguments: + - "text" + - "textarea" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_textarea } + oro_flexibleentity.attributetype.date: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\DateType - arguments: ["date", "oro_date"] + arguments: + - "date" + - "oro_date" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_date } + oro_flexibleentity.attributetype.datetime: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\DateTimeType - arguments: ["datetime", "oro_datetime"] + arguments: + - "datetime" + - "oro_datetime" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_datetime } + oro_flexibleentity.attributetype.integer: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\IntegerType - arguments: ["integer", "integer"] + arguments: + - "integer" + - "integer" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_integer } + oro_flexibleentity.attributetype.money: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\MoneyType - arguments: ["decimal", "money"] + arguments: + - "decimal" + - "money" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_money } + oro_flexibleentity.attributetype.number: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\NumberType - arguments: ["decimal", "number"] + arguments: + - "decimal" + - "number" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_number } + oro_flexibleentity.attributetype.multiselect: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\OptionMultiSelectType - arguments: ["options", "entity"] + arguments: + - "options" + - "entity" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_multiselect } + oro_flexibleentity.attributetype.simpleselect: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\OptionSimpleSelectType - arguments: ["option", "entity"] + arguments: + - "option" + - "entity" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_simpleselect } + oro_flexibleentity.attributetype.metric: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\MetricType - arguments: ["metric", "oro_flexibleentity_metric", @oro_measure.manager] + arguments: + - "metric" + - "oro_flexibleentity_metric" + - @oro_flexibleentity.validator.attribute_constraint_guesser + - @oro_measure.manager tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_metric } + oro_flexibleentity.attributetype.file: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\FileType - arguments: ["media", "oro_media"] + arguments: + - "media" + - "oro_media" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_file } + oro_flexibleentity.attributetype.image: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\ImageType - arguments: ["media", "oro_media"] + arguments: + - "media" + - "oro_media" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_image } + oro_flexibleentity.attributetype.fileurl: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\FileUrlType - arguments: ["media", "oro_media"] + arguments: + - "media" + - "oro_media" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_fileurl } + oro_flexibleentity.attributetype.imageurl: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\ImageUrlType - arguments: ["media", "oro_media"] + arguments: + - "media" + - "oro_media" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_imageurl } + oro_flexibleentity.attributetype.email: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\EmailType - arguments: ["varchar", "email"] + arguments: + - "varchar" + - "email" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_email } + oro_flexibleentity.attributetype.url: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\UrlType - arguments: ["varchar", "url"] + arguments: + - "varchar" + - "url" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_url } + oro_flexibleentity.attributetype.multicheckbox: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\OptionMultiCheckboxType - arguments: ["options", "entity"] + arguments: + - "options" + - "entity" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_multicheckbox } + oro_flexibleentity.attributetype.simpleradio: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\OptionSimpleRadioType - arguments: ["option", "entity"] + arguments: + - "option" + - "entity" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_simpleradio } + oro_flexibleentity.attributetype.price: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\PriceType - arguments: ["price", "oro_flexibleentity_price"] + arguments: + - "price" + - "oro_flexibleentity_price" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_price } + oro_flexibleentity.attributetype.email_collection: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\EmailCollectionType - arguments: ["collections", "oro_flexibleentity_email_collection"] + arguments: + - "collections" + - "oro_flexibleentity_email_collection" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_email_collection } + oro_flexibleentity.attributetype.phone_collection: class: Oro\Bundle\FlexibleEntityBundle\AttributeType\PhoneCollectionType - arguments: ["collections", "oro_flexibleentity_phone_collection"] + arguments: + - "collections" + - "oro_flexibleentity_phone_collection" + - @oro_flexibleentity.validator.attribute_constraint_guesser tags: - { name: oro_flexibleentity.attributetype, alias: oro_flexibleentity_phone_collection } - diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml b/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml index 18b8a58ac24..9bbcba2a71f 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/FlexibleEntityBundle/Resources/config/services.yml @@ -1,8 +1,10 @@ parameters: - oro_flexibleentity.flexible_config: ~ - oro_flexibleentity.registry.class: Oro\Bundle\FlexibleEntityBundle\Manager\FlexibleManagerRegistry - oro_flexibleentity.attributetype.factory.class: Oro\Bundle\FlexibleEntityBundle\AttributeType\AttributeTypeFactory - oro_flexibleentity.value_form.value_subscriber.class: Oro\Bundle\FlexibleEntityBundle\Form\EventListener\FlexibleValueSubscriber + oro_flexibleentity.flexible_config: ~ + oro_flexibleentity.registry.class: Oro\Bundle\FlexibleEntityBundle\Manager\FlexibleManagerRegistry + oro_flexibleentity.attributetype.factory.class: Oro\Bundle\FlexibleEntityBundle\AttributeType\AttributeTypeFactory + oro_flexibleentity.value_form.value_subscriber.class: Oro\Bundle\FlexibleEntityBundle\Form\EventListener\FlexibleValueSubscriber + oro_flexibleentity.filterAttributes.twig.extension.class: Oro\Bundle\FlexibleEntityBundle\Twig\FilterAttributesExtension + oro_flexibleentity.validator.attribute_constraint_guesser.class: Oro\Bundle\FlexibleEntityBundle\Form\Validator\AttributeConstraintGuesser services: oro_flexibleentity.value_form.value_subscriber: @@ -89,3 +91,12 @@ services: class: Oro\Bundle\FlexibleEntityBundle\Form\Type\EmailCollectionType tags: - { name: form.type, alias: oro_flexibleentity_email_collection } + + oro_flexibleentity.filterAttributes.twig.extension: + class: %oro_flexibleentity.filterAttributes.twig.extension.class% + tags: + - { name: twig.extension } + + oro_flexibleentity.validator.attribute_constraint_guesser: + class: %oro_flexibleentity.validator.attribute_constraint_guesser.class% + public: false diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AbstractFlexibleEntityManagerTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AbstractFlexibleEntityManagerTest.php index 744ae3e969b..9bb478bc505 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AbstractFlexibleEntityManagerTest.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AbstractFlexibleEntityManagerTest.php @@ -107,7 +107,7 @@ public function setUp() $this->container->setParameter('oro_flexibleentity.flexible_config', $this->flexibleConfig); // prepare attribute type factory - $attType = new TextType('varchar', 'text'); + $attType = new TextType('varchar', 'text', $this->getMock('Oro\Bundle\FlexibleEntityBundle\Form\Validator\AttributeConstraintGuesser')); $this->container->set('oro_flexibleentity.attributetype.text', $attType); $attTypes = array('oro_flexibleentity_text' => 'oro_flexibleentity.attributetype.text'); $this->attributeTypeFactory = new AttributeTypeFactory($this->container, $attTypes); diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/AttributeTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/AttributeTypeTest.php index 47082ba08db..1f82b888f58 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/AttributeTypeTest.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/AttributeTypeTest.php @@ -1,46 +1,104 @@ - * @copyright 2012 Akeneo SAS (http://www.akeneo.com) - * @license http://opensource.org/licenses/MIT MIT - */ -class AttributeTypeTest extends \PHPUnit_Framework_TestCase + * @author Gildas Quemener + * @copyright 2013 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +abstract class AttributeTypeTest extends \PHPUnit_Framework_TestCase { - /** - * Data provider - * - * @return array - * - * @static - */ - public static function typesProvider() + protected $target; + protected $name; + + public function setUp() + { + $this->guesser = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Form\Validator\AttributeConstraintGuesser'); + $this->guesser->expects($this->any()) + ->method('supportAttribute') + ->will($this->returnValue(true)); + $this->guesser->expects($this->any()) + ->method('guessConstraints') + ->will($this->returnValue(array('constraints'))); + } + + public function testGetName() + { + if (!$this->target) { + throw new \Exception(sprintf('You must override the setUp() method and provide a $target instance.')); + } + + if (!$this->name) { + throw new \Exception(sprintf('You must override the $name property.')); + } + $this->assertEquals($this->name, $this->target->getName()); + } + + public function testAssertInstanceOfAbstractAttributeType() + { + if (!$this->target) { + throw new \Exception(sprintf('You must override the setUp() method and provide a $target instance.')); + } + $this->assertInstanceOf('Oro\Bundle\FlexibleEntityBundle\AttributeType\AbstractAttributeType', $this->target); + } + + protected function getFormFactoryMock() { - return array( - array('Oro\Bundle\FlexibleEntityBundle\AttributeType\BooleanType', 'integer', 'option', 'oro_flexibleentity_boolean'), - array('Oro\Bundle\FlexibleEntityBundle\AttributeType\TextType', 'varchar', 'text', 'oro_flexibleentity_text'), - array('Oro\Bundle\FlexibleEntityBundle\AttributeType\TextAreaType', 'text', 'textarea', 'oro_flexibleentity_textarea') + return $this + ->getMockBuilder('Symfony\Component\Form\FormFactory') + ->disableOriginalConstructor() + ->getMock(); + } + + protected function getFlexibleValueMock(array $options) + { + $options = array_merge( + array( + 'data' => null, + 'defaultValue' => null, + 'backendType' => null, + ), + $options ); + + $value = $this->getMock( + 'Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface', + array( + 'getAttribute', 'getData' + ) + ); + + $value->expects($this->any()) + ->method('getAttribute') + ->will( + $this->returnValue( + $this->getAttributeMock( + $options['backendType'], + $options['defaultValue'] + ) + ) + ); + + $value->expects($this->any()) + ->method('getData') + ->will($this->returnValue($options['data'])); + + return $value; } - /** - * Test related methods - * - * @param string $class - * @param string $backend - * @param string $form - * @param string $name - * - * @dataProvider typesProvider - */ - public function testConstructorAnGetters($class, $backend, $form, $name) + protected function getAttributeMock($backendType, $defaultValue) { - $attType = new $class($backend, $form); - $this->assertEquals($attType->getName(), $name); - $this->assertEquals($attType->getBackendType(), $backend); - $this->assertEquals($attType->getFormType(), $form); + $attribute = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\AbstractAttribute'); + + $attribute->expects($this->any()) + ->method('getBackendType') + ->will($this->returnValue($backendType)); + + $attribute->expects($this->any()) + ->method('getDefaultValue') + ->will($this->returnValue($defaultValue)); + + return $attribute; } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/BooleanTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/BooleanTypeTest.php new file mode 100644 index 00000000000..3ff7d3083c3 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/BooleanTypeTest.php @@ -0,0 +1,64 @@ +target = new BooleanType('text', 'email', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'email', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('text', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('email', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/DateTimeTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/DateTimeTypeTest.php new file mode 100644 index 00000000000..92a20583102 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/DateTimeTypeTest.php @@ -0,0 +1,71 @@ + + * @copyright 2013 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class DateTimeTypeTest extends AttributeTypeTest +{ + protected $name = 'oro_flexibleentity_datetime'; + + public function setUp() + { + parent::setUp(); + + $this->target = new DateTimeType('integer', 'date', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'date', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + 'widget' => 'single_text', + 'input' => 'datetime', + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('integer', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('date', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/DateTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/DateTypeTest.php new file mode 100644 index 00000000000..342a2cb01cf --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/DateTypeTest.php @@ -0,0 +1,71 @@ + + * @copyright 2013 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class DateTypeTest extends AttributeTypeTest +{ + protected $name = 'oro_flexibleentity_date'; + + public function setUp() + { + parent::setUp(); + + $this->target = new DateType('integer', 'date', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'date', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + 'widget' => 'single_text', + 'input' => 'datetime', + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('integer', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('date', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailCollectionTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailCollectionTypeTest.php index fd63a1129f3..016b384bac7 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailCollectionTypeTest.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailCollectionTypeTest.php @@ -3,37 +3,62 @@ use Oro\Bundle\FlexibleEntityBundle\AttributeType\EmailCollectionType; -class EmailCollectionTypeTest extends \PHPUnit_Framework_TestCase +class EmailCollectionTypeTest extends AttributeTypeTest { - /** - * Data provider - * - * @return array - * - * @static - */ - public static function typesProvider() + protected $name = 'oro_flexibleentity_email_collection'; + + public function setUp() { - return array( - array('Oro\Bundle\FlexibleEntityBundle\AttributeType\EmailCollectionType', 'integer', 'option', 'oro_flexibleentity_email_collection'), + parent::setUp(); + + $this->target = new EmailCollectionType('collections', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $email = $this->getFlexibleValueMock(array()); + $value = $this->getFlexibleValueMock( + array( + 'data' => $email, + 'backendType' => 'foo', + ) ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + $email, + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); } - /** - * Test related methods - * - * @param string $class - * @param string $backend - * @param string $form - * @param string $name - * - * @dataProvider typesProvider - */ - public function testConstructorAnGetters($class, $backend, $form, $name) + public function testGetBackendType() { - $attType = new $class($backend, $form); - $this->assertEquals($attType->getName(), $name); - $this->assertEquals($attType->getBackendType(), $backend); - $this->assertEquals($attType->getFormType(), $form); + $this->assertEquals('collections', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailTypeTest.php index 9b3235be8e6..425af8877e8 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailTypeTest.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/EmailTypeTest.php @@ -1,20 +1,64 @@ target = new EmailType('text', 'email', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'email', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('text', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('email', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() { - $backend = 'varchar'; - $attType = new EmailType($backend, 'test'); - $this->assertEquals($attType->getName(), 'oro_flexibleentity_email'); - $this->assertEquals($attType->getBackendType(), $backend); - $this->assertEquals($attType->getFormType(), 'test'); + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/FileTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/FileTypeTest.php new file mode 100644 index 00000000000..5c2b78c164e --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/FileTypeTest.php @@ -0,0 +1,64 @@ +target = new FileType('varchar', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('varchar', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/FileUrlTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/FileUrlTypeTest.php new file mode 100644 index 00000000000..a4dbd543f80 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/FileUrlTypeTest.php @@ -0,0 +1,64 @@ +target = new FileUrlType('varchar', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('varchar', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/ImageTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/ImageTypeTest.php new file mode 100644 index 00000000000..70cf2cbd1e3 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/ImageTypeTest.php @@ -0,0 +1,64 @@ +target = new ImageType('varchar', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('varchar', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/ImageUrlTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/ImageUrlTypeTest.php new file mode 100644 index 00000000000..d8ee8604217 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/ImageUrlTypeTest.php @@ -0,0 +1,64 @@ +target = new ImageUrlType('varchar', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('varchar', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/IntegerTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/IntegerTypeTest.php new file mode 100644 index 00000000000..b661cf94f06 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/IntegerTypeTest.php @@ -0,0 +1,64 @@ +target = new IntegerType('integer', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('integer', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/MoneyTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/MoneyTypeTest.php new file mode 100644 index 00000000000..8133093d470 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/MoneyTypeTest.php @@ -0,0 +1,64 @@ +target = new MoneyType('varchar', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('varchar', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/NumberTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/NumberTypeTest.php new file mode 100644 index 00000000000..e2b712e981a --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/NumberTypeTest.php @@ -0,0 +1,64 @@ +target = new NumberType('number', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('number', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionMultiCheckboxTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionMultiCheckboxTypeTest.php new file mode 100644 index 00000000000..134e2991061 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionMultiCheckboxTypeTest.php @@ -0,0 +1,70 @@ +target = new OptionMultiCheckboxType('text', 'email', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'email', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + 'empty_value' => false, + 'class' => 'OroFlexibleEntityBundle:AttributeOption', + 'expanded' => true, + 'multiple' => true, + 'query_builder' => function () { + }, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('text', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('email', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionMultiSelectTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionMultiSelectTypeTest.php new file mode 100644 index 00000000000..1338c876788 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionMultiSelectTypeTest.php @@ -0,0 +1,70 @@ +target = new OptionMultiSelectType('text', 'email', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'email', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + 'empty_value' => false, + 'class' => 'OroFlexibleEntityBundle:AttributeOption', + 'expanded' => false, + 'multiple' => true, + 'query_builder' => function () { + }, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('text', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('email', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionSimpleRadioTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionSimpleRadioTypeTest.php new file mode 100644 index 00000000000..7b3f2119720 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionSimpleRadioTypeTest.php @@ -0,0 +1,70 @@ +target = new OptionSimpleRadioType('text', 'email', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'email', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + 'empty_value' => false, + 'class' => 'OroFlexibleEntityBundle:AttributeOption', + 'expanded' => true, + 'multiple' => false, + 'query_builder' => function () { + }, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('text', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('email', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionSimpleSelectTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionSimpleSelectTypeTest.php new file mode 100644 index 00000000000..485dd9f044e --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/OptionSimpleSelectTypeTest.php @@ -0,0 +1,70 @@ +target = new OptionSimpleSelectType('text', 'email', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'email', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + 'empty_value' => false, + 'class' => 'OroFlexibleEntityBundle:AttributeOption', + 'expanded' => false, + 'multiple' => false, + 'query_builder' => function () { + } + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('text', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('email', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PhoneCollectionTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PhoneCollectionTypeTest.php index e722555c2d8..bbb4fdc3a0a 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PhoneCollectionTypeTest.php +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PhoneCollectionTypeTest.php @@ -3,37 +3,62 @@ use Oro\Bundle\FlexibleEntityBundle\AttributeType\PhoneCollectionType; -class PhoneCollectionTypeTest extends \PHPUnit_Framework_TestCase +class PhoneCollectionTypeTest extends AttributeTypeTest { - /** - * Data provider - * - * @return array - * - * @static - */ - public static function typesProvider() + protected $name = 'oro_flexibleentity_phone_collection'; + + public function setUp() { - return array( - array('Oro\Bundle\FlexibleEntityBundle\AttributeType\PhoneCollectionType', 'integer', 'option', 'oro_flexibleentity_phone_collection'), + parent::setUp(); + + $this->target = new PhoneCollectionType('collections', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $phone = $this->getFlexibleValueMock(array()); + $value = $this->getFlexibleValueMock( + array( + 'data' => $phone, + 'backendType' => 'foo', + ) ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + $phone, + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null + ) + ); + + $this->target->buildValueFormType($factory, $value); } - /** - * Test related methods - * - * @param string $class - * @param string $backend - * @param string $form - * @param string $name - * - * @dataProvider typesProvider - */ - public function testConstructorAnGetters($class, $backend, $form, $name) + public function testGetBackendType() { - $attType = new $class($backend, $form); - $this->assertEquals($attType->getName(), $name); - $this->assertEquals($attType->getBackendType(), $backend); - $this->assertEquals($attType->getFormType(), $form); + $this->assertEquals('collections', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); } } diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PriceTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PriceTypeTest.php new file mode 100644 index 00000000000..93559486b49 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/PriceTypeTest.php @@ -0,0 +1,64 @@ +target = new TextAreaType('longtext', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('longtext', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/TextTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/TextTypeTest.php new file mode 100644 index 00000000000..2c1da5b6bc4 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/TextTypeTest.php @@ -0,0 +1,64 @@ +target = new TextType('longtext', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('longtext', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/UrlTypeTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/UrlTypeTest.php new file mode 100644 index 00000000000..5a462ea240b --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/AttributeType/UrlTypeTest.php @@ -0,0 +1,64 @@ +target = new UrlType('longtext', 'text', $this->guesser); + } + + public function testBuildValueFormType() + { + $factory = $this->getFormFactoryMock(); + $value = $this->getFlexibleValueMock( + array( + 'data' => 'bar', + 'backendType' => 'foo', + ) + ); + + $factory->expects($this->once()) + ->method('createNamed') + ->with( + 'foo', + 'text', + 'bar', + array( + 'constraints' => array('constraints'), + 'label' => null, + 'required' => null, + ) + ); + + $this->target->buildValueFormType($factory, $value); + } + + public function testGetBackendType() + { + $this->assertEquals('longtext', $this->target->getBackendType()); + } + + public function testGetFormType() + { + $this->assertEquals('text', $this->target->getFormType()); + } + + public function testBuildAttributeFormTypes() + { + $this->assertEquals( + array(), + $this->target->buildAttributeFormTypes( + $this->getFormFactoryMock(), + $this->getAttributeMock(null, null) + ) + ); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Form/Validator/AttributeConstraintGuesserTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Form/Validator/AttributeConstraintGuesserTest.php new file mode 100644 index 00000000000..40e06b3ffcc --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Form/Validator/AttributeConstraintGuesserTest.php @@ -0,0 +1,92 @@ + + * @copyright 2013 Akeneo SAS (http://www.akeneo.com) + * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) + */ +class ChainedConstraintGuesserTest extends \PHPUnit_Framework_TestCase +{ + public function setUp() + { + $this->target = new AttributeConstraintGuesser; + } + + public function testInstanceOfContraintGuesserInterface() + { + $this->assertInstanceOf( + 'Oro\Bundle\FlexibleEntityBundle\Form\Validator\ConstraintGuesserInterface', + $this->target + ); + } + + public function testGuessNotBlankConstraints() + { + $this->assertContainsInstanceOf( + 'Symfony\Component\Validator\Constraints\NotBlank', + $this->target->guessConstraints( + $this->getAttributeMock(array('required' => true)) + ) + ); + } + + public function testGuessDateConstraints() + { + $this->assertContainsInstanceOf( + 'Symfony\Component\Validator\Constraints\Date', + $this->target->guessConstraints( + $this->getAttributeMock(array('backendType' => AbstractAttributeType::BACKEND_TYPE_DATE)) + ) + ); + } + + public function testGuessDateTimeConstraints() + { + $this->assertContainsInstanceOf( + 'Symfony\Component\Validator\Constraints\DateTime', + $this->target->guessConstraints( + $this->getAttributeMock(array('backendType' => AbstractAttributeType::BACKEND_TYPE_DATETIME)) + ) + ); + } + + private function getAttributeMock(array $options) + { + $options = array_merge( + array( + 'required' => false, + 'backendType' => null, + ), + $options + ); + + $attribute = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\AbstractAttribute'); + + $attribute->expects($this->any()) + ->method('getBackendType') + ->will($this->returnValue($options['backendType'])); + + $attribute->expects($this->any()) + ->method('getRequired') + ->will($this->returnValue($options['required'])); + + return $attribute; + } + + private function assertContainsInstanceOf($class, $constraints) + { + foreach ($constraints as $constraint) { + if ($constraint instanceof $class) { + return true; + } + } + + throw new \Exception(sprintf('Expecting constraints to contain instance of "%s"', $class)); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php new file mode 100644 index 00000000000..09995427a19 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Tests/Unit/Twig/FilterAttributesExtensionTest.php @@ -0,0 +1,176 @@ +extension = new FilterAttributesExtension(); + $this->entityMock = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Entity\Mapping\AbstractEntityFlexible'); + $this->valuesMock = $this->getMock('Doctrine\Common\Collections\ArrayCollection'); + } + + public function testGetName() + { + $this->assertEquals('oro_flexibleentity_getAttributes', $this->extension->getName()); + } + + public function testGetFilters() + { + $filters = $this->extension->getFilters(); + + $this->assertArrayHasKey('getAttributes', $filters); + $this->assertInstanceOf('\Twig_Filter_Method', $filters['getAttributes']); + } + + public function testGetAttributesEmptyValuesScenario() + { + $this->entityMock->expects($this->exactly(2)) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->exactly(2)) + ->method('isEmpty') + ->will($this->returnValue(true)); + + $result = $this->extension->getAttributes($this->entityMock, 'test attribute'); + $this->assertEquals($this->valuesMock, $result); + + $result = $this->extension->getAttributes($this->entityMock, array('test'), true); + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $result); + } + + public function testGetAttributesValuesScenario() + { + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('filter') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->once()) + ->method('isEmpty') + ->will($this->returnValue(false)); + + $result = $this->extension->getAttributes($this->entityMock, 'test attribute', true); + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $result); + $this->assertEquals($this->valuesMock, $result); + } + + public function testGetAttributesEmptyAttributesScenario() + { + $this->entityMock->expects($this->exactly(2)) + ->method('getValues') + ->will($this->returnValue($this->valuesMock)); + + $this->valuesMock->expects($this->exactly(2)) + ->method('isEmpty') + ->will($this->returnValue(true)); + + $result = $this->extension->getAttributes($this->entityMock); + $this->assertInstanceOf('\PHPUnit_Framework_MockObject_MockObject', $result); + + $result = $this->extension->getAttributes($this->entityMock, array(), true); + $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $result); + } + + public function testFilterScenario() + { + $valueMock1 = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface'); + $attributeMock1 = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\AbstractAttribute'); + $valueMock2 = clone $valueMock1; + $attributeMock2 = clone $attributeMock1; + + $valueMock1->expects($this->once()) + ->method('getAttribute') + ->will($this->returnValue($attributeMock1)); + + $valueMock2->expects($this->once()) + ->method('getAttribute') + ->will($this->returnValue($attributeMock2)); + + $attributeMock1->expects($this->once()) + ->method('getCode') + ->will($this->returnValue('codeNeeded')); + + $attributeMock2->expects($this->once()) + ->method('getCode') + ->will($this->returnValue('codeNotNeeded')); + + $collection = new ArrayCollection( + array( + $valueMock1, $valueMock2 + ) + ); + + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($collection)); + + $result = $this->extension->getAttributes($this->entityMock, array('codeNeeded')); + $this->assertCount(1, $result); + $this->assertEquals($valueMock1, $result->first()); + } + + public function testFilterSkipScenario() + { + $valueMock1 = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface'); + $attributeMock1 = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\AbstractAttribute'); + $valueMock2 = clone $valueMock1; + $attributeMock2 = clone $attributeMock1; + + $valueMock1->expects($this->once()) + ->method('getAttribute') + ->will($this->returnValue($attributeMock1)); + + $valueMock2->expects($this->once()) + ->method('getAttribute') + ->will($this->returnValue($attributeMock2)); + + $attributeMock1->expects($this->once()) + ->method('getCode') + ->will($this->returnValue('codeNeeded')); + + $attributeMock2->expects($this->once()) + ->method('getCode') + ->will($this->returnValue('codeNotNeeded')); + + $collection = new ArrayCollection( + array( + $valueMock1, $valueMock2 + ) + ); + + $this->entityMock->expects($this->once()) + ->method('getValues') + ->will($this->returnValue($collection)); + + $result = $this->extension->getAttributes($this->entityMock, array('codeNotNeeded'), true); + $this->assertCount(1, $result); + $this->assertEquals($valueMock1, $result->first()); + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php b/src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php new file mode 100644 index 00000000000..7975c44f486 --- /dev/null +++ b/src/Oro/Bundle/FlexibleEntityBundle/Twig/FilterAttributesExtension.php @@ -0,0 +1,68 @@ + new \Twig_Filter_Method($this, 'getAttributes') + ); + } + + /** + * Returns attribute values array and filter if attributes array filled + * |getAttributes() - will return all attributes + * |getAttributes('address') - will return attribute with code "address" + * |getAttributes(['firstName', 'lastName']) - will filter by few attribute codes + * + * If third parameter equals true method will return attributes that not in given array(or string) + * + * @param AbstractEntityFlexible $entity + * @param string|array $attributes attribute names + * @param bool $skip + * @return ArrayCollection + */ + public function getAttributes(AbstractEntityFlexible $entity, $attributes = array(), $skip = false) + { + if (!empty($attributes) && !is_array($attributes)) { + $attributes = array($attributes); + } + + /** @var ArrayCollection $values */ + $values = $entity->getValues(); + + if ($values->isEmpty() || empty($attributes)) { + $values = $skip ? new ArrayCollection() : $values; + return $values; + } + + $values = $values->filter( + function ($value) use ($attributes, $skip) { + if (in_array($value->getAttribute()->getCode(), $attributes)) { + return !$skip; + } + + return $skip; + } + ); + + return $values; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_flexibleentity_getAttributes'; + } +} diff --git a/src/Oro/Bundle/FlexibleEntityBundle/composer.lock b/src/Oro/Bundle/FlexibleEntityBundle/composer.lock index 6048a3b5538..16d2e72af9a 100644 --- a/src/Oro/Bundle/FlexibleEntityBundle/composer.lock +++ b/src/Oro/Bundle/FlexibleEntityBundle/composer.lock @@ -1,32 +1,248 @@ { - "hash": "9929fae7cd616b247e68db5443bbe0be", + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "ad390ff8c7df168e5cf338dd719569ae", "packages": [ + { + "name": "doctrine/annotations", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "v1.1.1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/v1.1.1", + "reference": "v1.1.1", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/cache": "1.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Annotations\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2013-04-20 08:30:17" + }, + { + "name": "doctrine/cache", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "89493d2c6e1362f581f9de1c1871cc52eb29c030" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/89493d2c6e1362f581f9de1c1871cc52eb29c030", + "reference": "89493d2c6e1362f581f9de1c1871cc52eb29c030", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Cache\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "http://jmsyst.com", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2013-06-07 14:54:47" + }, + { + "name": "doctrine/collections", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "3db3ab843ff76774bee4679d4cb3a10cffb0a935" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/3db3ab843ff76774bee4679d4cb3a10cffb0a935", + "reference": "3db3ab843ff76774bee4679d4cb3a10cffb0a935", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2013-05-26 05:21:22" + }, { "name": "doctrine/common", - "version": "2.3.x-dev", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "bb0aebbf234db52df476a2b473d434745b34221c" + "reference": "c4255b9fbd63ee1fe52697839318af5937fced9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/bb0aebbf234db52df476a2b473d434745b34221c", - "reference": "bb0aebbf234db52df476a2b473d434745b34221c", + "url": "https://api.github.com/repos/doctrine/common/zipball/c4255b9fbd63ee1fe52697839318af5937fced9b", + "reference": "c4255b9fbd63ee1fe52697839318af5937fced9b", "shasum": "" }, "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", "php": ">=5.3.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-master": "2.4.x-dev" } }, "autoload": { "psr-0": { - "Doctrine\\Common": "lib/" + "Doctrine\\Common\\": "lib/" } }, "notification-url": "https://packagist.org/downloads/", @@ -55,7 +271,7 @@ { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com", - "homepage": "http://jmsyst.com", + "homepage": "https://github.com/schmittjoh", "role": "Developer of wrapped JMSSerializerBundle" } ], @@ -68,24 +284,291 @@ "persistence", "spl" ], - "time": "2012-09-20 05:55:18" + "time": "2013-06-21 12:11:28" + }, + { + "name": "doctrine/inflector", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "8b4b3ccec7aafc596e2fc1e593c9f2e78f939c8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/8b4b3ccec7aafc596e2fc1e593c9f2e78f939c8c", + "reference": "8b4b3ccec7aafc596e2fc1e593c9f2e78f939c8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Inflector\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com", + "homepage": "http://www.jwage.com/" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2013-04-10 16:14:30" + }, + { + "name": "doctrine/lexer", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "bc0e1f0cc285127a38c6c8ea88bc5dba2fd53e94" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/bc0e1f0cc285127a38c6c8ea88bc5dba2fd53e94", + "reference": "bc0e1f0cc285127a38c6c8ea88bc5dba2fd53e94", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com", + "homepage": "http://www.instaclick.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh", + "role": "Developer of wrapped JMSSerializerBundle" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2013-03-07 12:15:25" + }, + { + "name": "gedmo/doctrine-extensions", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/l3pp4rd/DoctrineExtensions.git", + "reference": "10f5f83a3e20fb94566e9a103b45a40a817e6134" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/l3pp4rd/DoctrineExtensions/zipball/10f5f83a3e20fb94566e9a103b45a40a817e6134", + "reference": "10f5f83a3e20fb94566e9a103b45a40a817e6134", + "shasum": "" + }, + "require": { + "doctrine/common": ">=2.2,<2.5-dev", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/common": ">=2.4.0-RC3", + "doctrine/dbal": ">=2.4.0-RC1", + "doctrine/mongodb": ">=1.0.3", + "doctrine/mongodb-odm": ">=1.0.0-BETA9", + "doctrine/orm": ">=2.4.0-RC1", + "symfony/yaml": "2.3.1" + }, + "suggest": { + "doctrine/dbal": ">=2.3.2", + "doctrine/mongodb": ">=1.0.1", + "doctrine/mongodb-odm": ">=1.0.0-BETA7", + "doctrine/orm": ">=2.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Gedmo\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David Buchmann", + "email": "david@liip.ch" + }, + { + "name": "Gediminas Morkevicius", + "email": "gediminas.morkevicius@gmail.com" + }, + { + "name": "Gustavo Falco", + "email": "comfortablynumb84@gmail.com" + } + ], + "description": "Doctrine2 behavioral extensions", + "homepage": "http://gediminasm.org/", + "keywords": [ + "Blameable", + "behaviors", + "doctrine2", + "extensions", + "gedmo", + "loggable", + "nestedset", + "sluggable", + "sortable", + "timestampable", + "translatable", + "tree", + "uploadable" + ], + "time": "2013-06-24 12:42:19" + }, + { + "name": "stof/doctrine-extensions-bundle", + "version": "dev-master", + "target-dir": "Stof/DoctrineExtensionsBundle", + "source": { + "type": "git", + "url": "https://github.com/stof/StofDoctrineExtensionsBundle.git", + "reference": "6577f2388abeac4896aa0aef37fc1b6f2c6923e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/6577f2388abeac4896aa0aef37fc1b6f2c6923e9", + "reference": "6577f2388abeac4896aa0aef37fc1b6f2c6923e9", + "shasum": "" + }, + "require": { + "gedmo/doctrine-extensions": "2.3.*", + "php": ">=5.3.2", + "symfony/framework-bundle": ">=2.1,<3.0" + }, + "suggest": { + "doctrine/doctrine-bundle": "to use the ORM extensions", + "doctrine/mongodb-odm-bundle": "to use the MongoDB ODM extensions" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-0": { + "Stof\\DoctrineExtensionsBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integration of the gedmo/doctrine-extensions with Symfony2", + "homepage": "https://github.com/stof/StofDoctrineExtensionsBundle", + "keywords": [ + "behaviors", + "doctrine2", + "extensions", + "gedmo", + "loggable", + "nestedset", + "sluggable", + "sortable", + "timestampable", + "translatable", + "tree" + ], + "time": "2013-06-25 08:05:01" }, { "name": "symfony/symfony", - "version": "v2.1.7", + "version": "2.1.x-dev", "source": { "type": "git", - "url": "git://github.com/symfony/symfony.git", - "reference": "v2.1.7" + "url": "https://github.com/symfony/symfony.git", + "reference": "0c0a3e90e79b63215707ae7e92193f511cc0ec77" }, "dist": { "type": "zip", - "url": "https://github.com/symfony/symfony/archive/v2.1.7.zip", - "reference": "v2.1.7", + "url": "https://api.github.com/repos/symfony/symfony/zipball/0c0a3e90e79b63215707ae7e92193f511cc0ec77", + "reference": "0c0a3e90e79b63215707ae7e92193f511cc0ec77", "shasum": "" }, "require": { - "doctrine/common": ">2.2,<2.4-dev", + "doctrine/common": ">=2.2,<3.0", "php": ">=5.3.3", "twig/twig": ">=1.9.1,<2.0-dev" }, @@ -156,7 +639,7 @@ "keywords": [ "framework" ], - "time": "2013-01-17 21:21:51" + "time": "2013-06-11 07:34:22" }, { "name": "twig/twig", @@ -164,12 +647,12 @@ "source": { "type": "git", "url": "https://github.com/fabpot/Twig.git", - "reference": "399916916533589c95dc04e1afd4aeefa34928ad" + "reference": "6f753205834b511269a97fe35108bbd5c8d245f5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fabpot/Twig/zipball/399916916533589c95dc04e1afd4aeefa34928ad", - "reference": "399916916533589c95dc04e1afd4aeefa34928ad", + "url": "https://api.github.com/repos/fabpot/Twig/zipball/6f753205834b511269a97fe35108bbd5c8d245f5", + "reference": "6f753205834b511269a97fe35108bbd5c8d245f5", "shasum": "" }, "require": { @@ -178,7 +661,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.12-dev" + "dev-master": "1.13-dev" } }, "autoload": { @@ -205,7 +688,7 @@ "keywords": [ "templating" ], - "time": "2013-04-01 08:27:18" + "time": "2013-06-09 06:03:21" } ], "packages-dev": [ @@ -215,12 +698,12 @@ "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "dd69835e0dcc44f7f0726b105e83ae5013622f5c" + "reference": "6a62fefefde6b2c0d8b3df70151d6a81fc028d28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/dd69835e0dcc44f7f0726b105e83ae5013622f5c", - "reference": "dd69835e0dcc44f7f0726b105e83ae5013622f5c", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/6a62fefefde6b2c0d8b3df70151d6a81fc028d28", + "reference": "6a62fefefde6b2c0d8b3df70151d6a81fc028d28", "shasum": "" }, "require": { @@ -270,7 +753,7 @@ "persistence", "queryobject" ], - "time": "2013-03-24 19:16:29" + "time": "2013-05-21 05:53:02" }, { "name": "doctrine/orm", @@ -278,12 +761,12 @@ "source": { "type": "git", "url": "https://github.com/doctrine/doctrine2.git", - "reference": "868bb68cc8f96485a5407d2b16f88037a69e96b8" + "reference": "9787b27518bf4e4da1523ced6bfca74e98397907" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/868bb68cc8f96485a5407d2b16f88037a69e96b8", - "reference": "868bb68cc8f96485a5407d2b16f88037a69e96b8", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/9787b27518bf4e4da1523ced6bfca74e98397907", + "reference": "9787b27518bf4e4da1523ced6bfca74e98397907", "shasum": "" }, "require": { @@ -340,16 +823,16 @@ "database", "orm" ], - "time": "2013-03-24 20:43:58" + "time": "2013-05-26 07:27:03" } ], "aliases": [ ], "minimum-stability": "dev", - "stability-flags": [ - - ], + "stability-flags": { + "stof/doctrine-extensions-bundle": 20 + }, "platform": { "php": ">=5.3.3" }, diff --git a/src/Oro/Bundle/FormBundle/.gitignore b/src/Oro/Bundle/FormBundle/.gitignore new file mode 100644 index 00000000000..dad62749d16 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/.gitignore @@ -0,0 +1,4 @@ +/.settings +/.buildpath +/.project +/.idea diff --git a/src/Oro/Bundle/FormBundle/Autocomplete/ConverterInterface.php b/src/Oro/Bundle/FormBundle/Autocomplete/ConverterInterface.php new file mode 100644 index 00000000000..e454e0dcc8a --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Autocomplete/ConverterInterface.php @@ -0,0 +1,14 @@ +entityName = $entityName; + $this->properties = $properties; + } + + /** + * {@inheritdoc} + */ + public function getProperties() + { + return $this->properties; + } + + /** + * @param Indexer $indexer + * @param array $config + * @throws \RuntimeException + */ + public function initSearchIndexer(Indexer $indexer, array $config) + { + $this->indexer = $indexer; + if (empty($config[$this->entityName]['alias'])) { + throw new \RuntimeException("Cannot init entity search alias."); + } + $this->entitySearchAlias = $config[$this->entityName]['alias']; + } + + /** + * @param ManagerRegistry $managerRegistry + * @throws \RuntimeException + */ + public function initDoctrinePropertiesByManagerRegistry(ManagerRegistry $managerRegistry) + { + $objectManager = $managerRegistry->getManagerForClass($this->entityName); + if (!$objectManager instanceof EntityManager) { + throw new \RuntimeException( + 'Object manager for "%s" expected to be an instance of "%s".', + $this->entityName, + 'Doctrine\ORM\EntityManager' + ); + } + $this->initDoctrinePropertiesByEntityManager($objectManager); + } + + /** + * @param EntityManager $entityManager + */ + public function initDoctrinePropertiesByEntityManager(EntityManager $entityManager) + { + $this->entityRepository = $entityManager->getRepository($this->entityName); + $this->idFieldName = $this->getEntityIdentifierFieldName($entityManager); + } + + /** + * @param EntityManager $entityManager + * @return string + */ + protected function getEntityIdentifierFieldName(EntityManager $entityManager) + { + /** @var $metadata \Doctrine\ORM\Mapping\ClassMetadata */ + $metadata = $entityManager->getMetadataFactory()->getMetadataFor($this->entityName); + return $metadata->getSingleIdentifierFieldName(); + } + + /** + * {@inheritdoc} + */ + public function search($query, $page, $perPage) + { + $this->checkAllDependenciesInjected(); + + $page = (int)$page > 0 ? (int)$page : 1; + $perPage = (int)$perPage > 0 ? (int)$perPage : 10; + $perPage += 1; + + $items = $this->searchEntities($query, ($page - 1) * $perPage, $perPage); + + $this->hasMore = count($items) == $perPage; + if ($this->hasMore) { + $items = array_slice($items, 0, $perPage - 1); + } + + return $this->formatResult($items); + } + + /** + * @throws \RuntimeException + */ + private function checkAllDependenciesInjected() + { + if (!$this->indexer || !$this->entitySearchAlias || !$this->entityRepository || !$this->idFieldName) { + throw new \RuntimeException('Search handler is not fully configured'); + } + } + + /** + * @param array $items + * @return array + */ + protected function formatResult(array $items) + { + return array( + 'results' => $this->convertItems($items), + 'more' => $this->hasMore + ); + } + + /** + * Search and return entities + * + * @param string $search + * @param int $firstResult + * @param int $maxResults + * @return array + */ + protected function searchEntities($search, $firstResult, $maxResults) + { + $entityIds = $this->searchIds($search, $firstResult, $maxResults); + + $resultEntities = array(); + + if ($entityIds) { + /** @var QueryBuilder $queryBuilder */ + $queryBuilder = $this->entityRepository->createQueryBuilder('e'); + $queryBuilder->where($queryBuilder->expr()->in('e.' . $this->idFieldName, $entityIds)); + $currentEntities = $queryBuilder->getQuery()->getResult(); + + foreach ($currentEntities as $entity) { + $resultEntities[] = $entity; + } + } + + return $resultEntities; + } + + /** + * @param string $search + * @param int $firstResult + * @param int $maxResults + * @return array + */ + protected function searchIds($search, $firstResult, $maxResults) + { + $result = $this->indexer->simpleSearch($search, $firstResult, $maxResults, $this->entitySearchAlias); + $elements = $result->getElements(); + + $ids = array(); + foreach ($elements as $element) { + $ids[] = $element->getRecordId(); + } + + return $ids; + } + + /** + * @param array $items + * @return array + */ + protected function convertItems(array $items) + { + $result = array(); + foreach ($items as $item) { + $result[] = $this->convertItem($item); + } + return $result; + } + + /** + * {@inheritdoc} + */ + public function convertItem($item) + { + $result = array(); + + $result[$this->idFieldName] = $this->getPropertyValue($this->idFieldName, $item); + + foreach ($this->properties as $property) { + $result[$property] = $this->getPropertyValue($property, $item); + } + + return $result; + } + + /** + * @param string $name + * @param object|array $item + * @return mixed + */ + protected function getPropertyValue($name, $item) + { + $result = null; + + if (is_object($item)) { + $method = 'get' . str_replace(' ', '', str_replace('_', ' ', ucwords($name))); + if (method_exists($item, $method)) { + $result = $item->$method(); + } elseif (isset($item->$name)) { + $result = $item->$name; + } + } elseif (is_array($item) && array_key_exists($name, $item)) { + $result = $item[$name]; + } + + if ($result instanceof FlexibleValueInterface) { + $result = $result->getData(); + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function getEntityName() + { + return $this->entityName; + } +} diff --git a/src/Oro/Bundle/FormBundle/Autocomplete/SearchHandlerInterface.php b/src/Oro/Bundle/FormBundle/Autocomplete/SearchHandlerInterface.php new file mode 100644 index 00000000000..71e882ae2af --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Autocomplete/SearchHandlerInterface.php @@ -0,0 +1,30 @@ +searchHandlers[$name] = $searchHandler; + } + + /** + * @param string $name + * @return SearchHandlerInterface + * @throws \RuntimeException + */ + public function getSearchHandler($name) + { + if (!isset($this->searchHandlers[$name])) { + throw new \RuntimeException(sprintf('Search handler "%s" is not registered', $name)); + } + + return $this->searchHandlers[$name]; + } + + /** + * @param string $name + * @return boolean + */ + public function hasSearchHandler($name) + { + return isset($this->searchHandlers[$name]); + } +} diff --git a/src/Oro/Bundle/FormBundle/Autocomplete/Security.php b/src/Oro/Bundle/FormBundle/Autocomplete/Security.php new file mode 100644 index 00000000000..69c3019353a --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Autocomplete/Security.php @@ -0,0 +1,52 @@ +manager = $manager; + $this->autocompleteAclResources = array(); + } + + /** + * @param string $name + * @param string $aclResource + */ + public function setAutocompleteAclResource($name, $aclResource) + { + $this->autocompleteAclResources[$name] = $aclResource; + } + + /** + * @param string $name + * @return string|null + */ + public function getAutocompleteAclResource($name) + { + return isset($this->autocompleteAclResources[$name]) ? $this->autocompleteAclResources[$name] : null; + } + + /** + * @param $name + * @return boolean + */ + public function isAutocompleteGranted($name) + { + $aclResource = $this->getAutocompleteAclResource($name); + return $aclResource && $this->manager->isResourceGranted($aclResource); + } +} diff --git a/src/Oro/Bundle/FormBundle/Controller/AutocompleteController.php b/src/Oro/Bundle/FormBundle/Controller/AutocompleteController.php new file mode 100644 index 00000000000..43a91c161ea --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Controller/AutocompleteController.php @@ -0,0 +1,68 @@ +get('name'); + $query = $request->get('query'); + $page = intval($request->get('page', 1)); + $perPage = intval($request->get('per_page', 50)); + + if (!$name) { + throw new HttpException(400, 'Parameter "name" is required'); + } + + if ($page <= 0) { + throw new HttpException(400, 'Parameter "page" must be greater than 0'); + } + + if ($perPage <= 0) { + throw new HttpException(400, 'Parameter "per_page" must be greater than 0'); + } + + if (!$this->get('oro_form.autocomplete.security')->isAutocompleteGranted($name)) { + throw new AccessDeniedHttpException('Access denied.'); + } + + /** @var SearchHandlerInterface $searchHandler */ + $searchHandler = $this->get('oro_form.autocomplete.search_registry')->getSearchHandler($name); + + return new JsonResponse($searchHandler->search($query, $page, $perPage)); + } +} diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/Compiler/AutocompleteCompilerPass.php b/src/Oro/Bundle/FormBundle/DependencyInjection/Compiler/AutocompleteCompilerPass.php new file mode 100644 index 00000000000..57e1e84934c --- /dev/null +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/Compiler/AutocompleteCompilerPass.php @@ -0,0 +1,33 @@ +getDefinition('oro_form.autocomplete.search_registry'); + $securityDefinition = $container->getDefinition('oro_form.autocomplete.security'); + + foreach ($container->findTaggedServiceIds('oro_form.autocomplete.search_handler') as $id => $attributes) { + foreach ($attributes as $eachTag) { + $name = !empty($eachTag['alias']) ? $eachTag['alias'] : $id; + $searchRegistryDefinition->addMethodCall('addSearchHandler', array($name, new Reference($id))); + if (!empty($eachTag['acl_resource'])) { + $securityDefinition->addMethodCall( + 'setAutocompleteAclResource', + array($name, $eachTag['acl_resource']) + ); + } + } + } + } +} diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php new file mode 100644 index 00000000000..50d983926f2 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/Configuration.php @@ -0,0 +1,20 @@ +root('oro_form'); + + return $treeBuilder; + } +} diff --git a/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php b/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php new file mode 100644 index 00000000000..b0c7e7c78a2 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/DependencyInjection/OroFormExtension.php @@ -0,0 +1,26 @@ +processConfiguration($configuration, $configs); + + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config')); + $loader->load('autocomplete.yml'); + $loader->load('form_type.yml'); + } +} diff --git a/src/Oro/Bundle/UIBundle/Form/DataTransformer/ArrayToStringTransformer.php b/src/Oro/Bundle/FormBundle/Form/DataTransformer/ArrayToStringTransformer.php similarity index 97% rename from src/Oro/Bundle/UIBundle/Form/DataTransformer/ArrayToStringTransformer.php rename to src/Oro/Bundle/FormBundle/Form/DataTransformer/ArrayToStringTransformer.php index 7b438bc29d0..c81589f966c 100644 --- a/src/Oro/Bundle/UIBundle/Form/DataTransformer/ArrayToStringTransformer.php +++ b/src/Oro/Bundle/FormBundle/Form/DataTransformer/ArrayToStringTransformer.php @@ -1,6 +1,6 @@ propertyPath->getValue($entity); + $result[] = $id; + } + + return $result; + } + + /** + * {@inheritdoc} + */ + public function reverseTransform($value) + { + if (!is_array($value)) { + throw new UnexpectedTypeException($value, 'array'); + } + + if (!$value) { + return array(); + } + + $entities = $this->loadEntitiesByIds($value); + + if (count($entities) !== count($value)) { + throw new TransformationFailedException('Could not find all entities for the given IDs'); + } + + return $entities; + } + + /** + * Load entities by array of ids + * + * @param array $ids + * @return array + * @throws UnexpectedTypeException if query builder callback returns invalid type + */ + protected function loadEntitiesByIds(array $ids) + { + $repository = $this->em->getRepository($this->className); + if ($this->queryBuilderCallback) { + /** @var $qb QueryBuilder */ + $qb = call_user_func($this->queryBuilderCallback, $repository, $ids); + if (!$qb instanceof QueryBuilder) { + throw new UnexpectedTypeException($qb, 'Doctrine\ORM\QueryBuilder'); + } + } else { + $qb = $repository->createQueryBuilder('e'); + $qb->where(sprintf('e.%s IN (:ids)', $this->propertyPath)) + ->setParameter('ids', $ids); + } + + return $qb->getQuery()->execute(); + } +} diff --git a/src/Oro/Bundle/UIBundle/Form/DataTransformer/EntitiesToIdsTransformer.php b/src/Oro/Bundle/FormBundle/Form/DataTransformer/EntityToIdTransformer.php similarity index 65% rename from src/Oro/Bundle/UIBundle/Form/DataTransformer/EntitiesToIdsTransformer.php rename to src/Oro/Bundle/FormBundle/Form/DataTransformer/EntityToIdTransformer.php index 2877ce7315d..4a70b213aa2 100644 --- a/src/Oro/Bundle/UIBundle/Form/DataTransformer/EntitiesToIdsTransformer.php +++ b/src/Oro/Bundle/FormBundle/Form/DataTransformer/EntityToIdTransformer.php @@ -1,21 +1,20 @@ getSingleIdentifierFieldName(); } catch (MappingException $e) { throw new FormException( - "Cannot get id property path of entity. \"$this->className\" has composite primary key." + "Cannot get id property path of entity. \"$className\" has composite primary key." ); } } @@ -84,21 +88,15 @@ protected function getIdPropertyPathFromEntityManager(EntityManager $em, $classN */ public function transform($value) { - if (null === $value || array() === $value) { - return array(); - } - - if (!is_array($value)) { - throw new UnexpectedTypeException($value, 'array'); + if (null === $value) { + return null; } - $result = array(); - foreach ($value as $entity) { - $id = $this->propertyPath->getValue($entity); - $result[] = $id; + if (!is_object($value)) { + throw new UnexpectedTypeException($value, 'object'); } - return $result; + return $this->propertyPath->getValue($value); } /** @@ -106,45 +104,32 @@ public function transform($value) */ public function reverseTransform($value) { - if (!is_array($value)) { - throw new UnexpectedTypeException($value, 'array'); - } - if (!$value) { - return array(); + return null; } - $entities = $this->loadEntitiesByIds($value); - - if (count($entities) !== count($value)) { - throw new TransformationFailedException('Could not find all entities for the given IDs'); - } - - return $entities; + return $this->loadEntityById($value); } /** - * Load entities by array of ids + * Load entity by id * - * @param array $ids - * @return array + * @param mixed $id + * @return object * @throws UnexpectedTypeException if query builder callback returns invalid type */ - protected function loadEntitiesByIds(array $ids) + protected function loadEntityById($id) { $repository = $this->em->getRepository($this->className); if ($this->queryBuilderCallback) { /** @var $qb QueryBuilder */ - $qb = call_user_func($this->queryBuilderCallback, $repository, $ids); + $qb = call_user_func($this->queryBuilderCallback, $repository, $id); if (!$qb instanceof QueryBuilder) { throw new UnexpectedTypeException($qb, 'Doctrine\ORM\QueryBuilder'); } + return $qb->getQuery()->execute(); } else { - $qb = $repository->createQueryBuilder('e'); - $qb->where(sprintf('e.%s IN (:ids)', $this->propertyPath)) - ->setParameter('ids', $ids); + return $repository->find($id); } - - return $qb->getQuery()->execute(); } } diff --git a/src/Oro/Bundle/UIBundle/Form/EventListener/FixArrayToStringListener.php b/src/Oro/Bundle/FormBundle/Form/EventListener/FixArrayToStringListener.php similarity index 93% rename from src/Oro/Bundle/UIBundle/Form/EventListener/FixArrayToStringListener.php rename to src/Oro/Bundle/FormBundle/Form/EventListener/FixArrayToStringListener.php index cb364220120..3e27a9d3e28 100644 --- a/src/Oro/Bundle/UIBundle/Form/EventListener/FixArrayToStringListener.php +++ b/src/Oro/Bundle/FormBundle/Form/EventListener/FixArrayToStringListener.php @@ -1,6 +1,6 @@ entityManager = $entityManager; + $this->searchRegistry = $registry; + } + + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $defaultConfig = array( + 'placeholder' => 'oro.form.choose_value', + 'allowClear' => true, + 'minimumInputLength' => 1, + ); + + $searchRegistry = $this->searchRegistry; + $formType = $this; + + $resolver + ->setDefaults( + array( + 'empty_value' => '', + 'empty_data' => null, + 'data_class' => null, + 'entity_class' => null, + 'configs' => $defaultConfig, + 'converter' => null, + 'autocomplete_alias' => null + ) + ); + + $this->setConverterNormalizer($resolver); + $this->setConfigsNormalizer($resolver, $defaultConfig); + + $resolver + ->setNormalizers( + array( + 'entity_class' => function (Options $options, $value) use ($searchRegistry) { + if (!$value && !empty($options['autocomplete_alias'])) { + $searchHandler = $searchRegistry->getSearchHandler($options['autocomplete_alias']); + $value = $searchHandler->getEntityName(); + } + + if (!$value) { + throw new FormException('The option "entity_class" must be set.'); + } + return $value; + }, + 'transformer' => function (Options $options, $value) use ($formType) { + if (!$value) { + $value = $formType->createDefaultTransformer($options['entity_class']); + } elseif (!$value instanceof DataTransformerInterface) { + throw new FormException( + sprintf( + 'The option "transformer" must be an instance of "%s".', + 'Symfony\Component\Form\DataTransformerInterface' + ) + ); + } + return $value; + } + ) + ); + } + + /** + * @param OptionsResolverInterface $resolver + */ + protected function setConverterNormalizer(OptionsResolverInterface $resolver) + { + $searchRegistry = $this->searchRegistry; + $resolver->setNormalizers( + array( + 'converter' => function (Options $options, $value) use ($searchRegistry) { + if (!$value && !empty($options['autocomplete_alias'])) { + $value = $searchRegistry->getSearchHandler($options['autocomplete_alias']); + } elseif (!$value) { + throw new FormException('The option "converter" must be set.'); + } + + if (!$value instanceof ConverterInterface) { + throw new FormException( + sprintf( + 'The option "converter" must be an instance of "%s".', + 'Oro\Bundle\FormBundle\Autocomplete\ConverterInterface' + ) + ); + } + return $value; + } + ) + ); + } + + /** + * @param OptionsResolverInterface $resolver + * @param array $defaultConfig + */ + protected function setConfigsNormalizer(OptionsResolverInterface $resolver, array $defaultConfig) + { + $searchRegistry = $this->searchRegistry; + $resolver->setNormalizers( + array( + 'configs' => function (Options $options, $configs) use ($searchRegistry, $defaultConfig) { + $result = array_replace_recursive($defaultConfig, $configs); + + if (!empty($options['autocomplete_alias'])) { + $result['autocomplete_alias'] = $options['autocomplete_alias']; + if (empty($result['properties'])) { + $searchHandler = $searchRegistry->getSearchHandler($options['autocomplete_alias']); + $result['properties'] = $searchHandler->getProperties(); + } + if (empty($result['route_name'])) { + $result['route_name'] = 'oro_form_autocomplete_search'; + } + if (empty($result['extra_config'])) { + $result['extra_config'] = 'autocomplete'; + } + } + + if (empty($result['route_name']) && empty($result['ajax']['url'])) { + throw new FormException( + 'Either option "configs.route_name" or "configs.ajax.url" must be set.' + ); + } + + return $result; + } + ) + ); + } + + /** + * @param string $entityClass + * @return EntityToIdTransformer + */ + public function createDefaultTransformer($entityClass) + { + return $value = new EntityToIdTransformer($this->entityManager, $entityClass); + } + + /** + * Set data-title attribute to element to show selected value + * + * @param FormView $view + * @param FormInterface $form + * @param array $options + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + parent::buildView($view, $form, $options); + + $vars = array('configs' => $options['configs']); + if ($form->getData()) { + $vars['attr'] = array( + 'data-entity' => json_encode($options['converter']->convertItem($form->getData())) + ); + } + + $view->vars = array_replace_recursive($view->vars, $vars); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'genemu_jqueryselect2_hidden'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_jqueryselect2_hidden'; + } +} diff --git a/src/Oro/Bundle/FormBundle/Form/Type/TranslatableEntityType.php b/src/Oro/Bundle/FormBundle/Form/Type/TranslatableEntityType.php new file mode 100644 index 00000000000..b912c741c81 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Form/Type/TranslatableEntityType.php @@ -0,0 +1,123 @@ +registry = $registry; + } + + /** + * @return string + */ + public function getName() + { + return self::NAME; + } + + /** + * @return string + */ + public function getParent() + { + return 'choice'; + } + + /** + * @param FormBuilderInterface $builder + * @param array $options + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + // transformer must be only one in chain + $builder->resetViewTransformers(); + + /** @var $entityManager EntityManager */ + $entityManager = $this->registry->getManager(); + if (!empty($options['multiple'])) { + $builder->addViewTransformer(new EntitiesToIdsTransformer($entityManager, $options['class'])); + } else { + $builder->addViewTransformer(new EntityToIdTransformer($entityManager, $options['class'])); + } + } + + /** + * @param OptionsResolverInterface $resolver + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $registry = $this->registry; + + $choiceList = function (Options $options) use ($registry) { + $className = $options['class']; + + /** @var $entityManager EntityManager */ + $entityManager = $registry->getManager(); + $idField = $entityManager->getClassMetadata($className)->getSingleIdentifierFieldName(); + + if (null !== $options['choices']) { + return new ObjectChoiceList($options['choices'], $options['property'], array(), null, $idField); + } + + // get query builder + if (!empty($options['query_builder'])) { + $queryBuilder = $options['query_builder']; + if ($queryBuilder instanceof \Closure) { + $queryBuilder = $queryBuilder($registry->getRepository($className)); + } + } else { + /** @var $repository EntityRepository */ + $repository = $registry->getRepository($className); + $queryBuilder = $repository->createQueryBuilder('e'); + } + + // make entity translatable + /** @var $queryBuilder QueryBuilder */ + $query = $queryBuilder->getQuery(); + $query->setHint( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + + return new ObjectChoiceList($query->execute(), $options['property'], array(), null, $idField); + }; + + $resolver->setDefaults( + array( + 'property' => null, + 'query_builder' => null, + 'choices' => null, + 'choice_list' => $choiceList + ) + ); + + $resolver->setRequired(array('class')); + } +} diff --git a/src/Oro/Bundle/FormBundle/OroFormBundle.php b/src/Oro/Bundle/FormBundle/OroFormBundle.php new file mode 100644 index 00000000000..978ea324277 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/OroFormBundle.php @@ -0,0 +1,19 @@ +addCompilerPass(new AutocompleteCompilerPass()); + } +} diff --git a/src/Oro/Bundle/FormBundle/README.md b/src/Oro/Bundle/FormBundle/README.md new file mode 100644 index 00000000000..d594728b9c0 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/README.md @@ -0,0 +1,6 @@ +OroFormBundle +============= + +Provide additional form types and form components. + +Please see [documentation](./Resources/doc/index.md) for more details. diff --git a/src/Oro/Bundle/FormBundle/Resources/config/assets.yml b/src/Oro/Bundle/FormBundle/Resources/config/assets.yml new file mode 100644 index 00000000000..8310dca3f2c --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/config/assets.yml @@ -0,0 +1,2 @@ +js: + - '@OroFormBundle/Resources/public/js/oro.select2.config.js' \ No newline at end of file diff --git a/src/Oro/Bundle/FormBundle/Resources/config/autocomplete.yml b/src/Oro/Bundle/FormBundle/Resources/config/autocomplete.yml new file mode 100644 index 00000000000..01f4672ce5f --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/config/autocomplete.yml @@ -0,0 +1,19 @@ +parameters: + oro_form.autocomplete.security.class: Oro\Bundle\FormBundle\Autocomplete\Security + oro_form.autocomplete.search_registry.class: Oro\Bundle\FormBundle\Autocomplete\SearchRegistry + oro_form.autocomplete.search_handler.class: Oro\Bundle\FormBundle\Autocomplete\SearchHandler + +services: + oro_form.autocomplete.security: + class: %oro_form.autocomplete.security.class% + arguments: [@oro_user.acl_manager] + + oro_form.autocomplete.search_registry: + class: %oro_form.autocomplete.search_registry.class% + + oro_form.autocomplete.search_handler: + class: %oro_form.autocomplete.search_handler.class% + abstract: true + calls: + - [initSearchIndexer, ["@oro_search.index", %oro_search.entities_config%]] + - [initDoctrinePropertiesByManagerRegistry, ["@doctrine"]] diff --git a/src/Oro/Bundle/FormBundle/Resources/config/form_type.yml b/src/Oro/Bundle/FormBundle/Resources/config/form_type.yml new file mode 100644 index 00000000000..678e5de4383 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/config/form_type.yml @@ -0,0 +1,45 @@ +parameters: + oro_form.type.date.class: Oro\Bundle\FormBundle\Form\Type\OroDateType + oro_form.type.datetime.class: Oro\Bundle\FormBundle\Form\Type\OroDateTimeType + oro_form.type.combobox_local.class: Oro\Bundle\FormBundle\Form\Type\OroComboboxLocalType + oro_form.type.entity_identifier.class: Oro\Bundle\FormBundle\Form\Type\EntityIdentifierType + oro_form.type.jqueryselect2_hidden.class: Oro\Bundle\FormBundle\Form\Type\OroJquerySelect2HiddenType + oro_form.type.translatable_entity.class: Oro\Bundle\FormBundle\Form\Type\TranslatableEntityType + +services: + # Form types + oro_form.type.date: + class: %oro_form.type.date.class% + tags: + - { name: form.type, alias: oro_date } + + oro_form.type.datetime: + class: %oro_form.type.datetime.class% + tags: + - { name: form.type, alias: oro_datetime } + + oro_form.type.entity_identifier: + class: %oro_form.type.entity_identifier.class% + arguments: ["@doctrine"] + tags: + - { name: form.type, alias: oro_entity_identifier } + + oro_form.type.jqueryselect2_hidden: + class: %oro_form.type.jqueryselect2_hidden.class% + arguments: + - @doctrine.orm.entity_manager + - @oro_form.autocomplete.search_registry + tags: + - { name: form.type, alias: oro_jqueryselect2_hidden } + + oro_form.type.translatable_entity: + class: %oro_form.type.translatable_entity.class% + arguments: ["@doctrine"] + tags: + - { name: form.type, alias: translatable_entity } + + oro_form.type.jqueryselect2_translatable_entity: + parent: genemu.form.jquery.type.select2 + arguments: ["translatable_entity"] + tags: + - { name: form.type, alias: genemu_jqueryselect2_translatable_entity } diff --git a/src/Oro/Bundle/FormBundle/Resources/config/routing.yml b/src/Oro/Bundle/FormBundle/Resources/config/routing.yml new file mode 100644 index 00000000000..ff2eaa3411c --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/config/routing.yml @@ -0,0 +1,3 @@ +oro_form_bundle: + resource: "@OroFormBundle/Controller" + type: annotation diff --git a/src/Oro/Bundle/FormBundle/Resources/doc/index.md b/src/Oro/Bundle/FormBundle/Resources/doc/index.md new file mode 100644 index 00000000000..65145cf3382 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/doc/index.md @@ -0,0 +1,5 @@ +OroFormBundle Documentation +=========================== + +- [Form Components Overview](./reference/form_components.md) +- [Autocomplete Form Type](./reference/autocomplete_form_type.md) diff --git a/src/Oro/Bundle/FormBundle/Resources/doc/reference/autocomplete_form_type.md b/src/Oro/Bundle/FormBundle/Resources/doc/reference/autocomplete_form_type.md new file mode 100644 index 00000000000..c21a3392724 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/doc/reference/autocomplete_form_type.md @@ -0,0 +1,242 @@ +Autocomplete Form Type +---------------------- + +#### Overview + +Autocomplete element is based on [GenemuFormBundle](https://github.com/genemu/GenemuFormBundle) [Select2](http://ivaynberg.github.io/select2/) +form type. In case when autocomplete functionality is required for static selects +or for entity based selects generic genemu_jqueryselect2_* form types may be used. For example: + +- genemu_jqueryselect2_choice +- genemu_jqueryselect2_country +- genemu_jqueryselect2_entity + +oro_jqueryselect2_hidden was created to add more complex support of AJAX based data sources. +Main differences from genemu_jqueryselect2_hidden are: + +- support of configuration based autocompletition +- selected value text is shown on entity edit form +- pre-configured ability to work with doctrine entities, flexible entities and grids + +#### Form Type Configuration + +Consider there is a form type that should have a field with support of autocomplete powered by Select2 jQuery plugin: + +```php +class ProductType extends AbstractType +{ +/** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add( + 'user', + 'oro_jqueryselect2_hidden', + array( + 'autocomplete_alias' => 'users', + + // Default values + 'configs' => array( + 'extra_config' => 'autocomplete', + 'placeholder' => 'Choose a value...', + 'allowClear' => true, + 'minimumInputLength' => 1, + 'route_name' => 'oro_form_autocomplete_search' + ) + ) + ); + } + + // ... +} +``` + +Minimum required configuration with use of "autocomplete_alias": + +```php +class ProductType extends AbstractType +{ +/** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add( + 'user', + 'oro_jqueryselect2_hidden', + array( + 'autocomplete_alias' => 'users' + ) + ); + } + + // ... +} +``` + + +Configuration without "autocomplete_alias": + +```php +class ProductType extends AbstractType +{ +/** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add( + 'user', + 'oro_jqueryselect2_hidden', + array( + 'converter' => $this->converter, + 'configs' => array( + 'properties' => array(), + 'route' => 'some_route', + 'entity_class' => 'UserFullyQualifiedClassName' + ) + ) + ); + } + + // ... +} +``` + +**autocomplete_alias** + +This option refers to a service configured with tag "oro_form.autocomplete.search_handler". Details of service configuration +described [here](#search-handler-configuration). If this option is set next options will be inited if they are empty: +*entity_class*, *configs.properties*, *converter*, *configs.extra_config* ("autocomplete") + +**entity_class** + +Entity class (optional if "autocomplete_alias" option is provided). + +**converter** + +Object that implements Oro\Bundle\FormBundle\Autocomplete\ConverterInterface that will be used to convert bind entity into array to use in select2 plugin. +This option can be ommited if option "autocomplete_alias" provided. + +**configs.properties** + +List of properties that will be used in view to convert json object to string that will be displayed in select options +(optional if "autocomplete_alias" option is provided). + +**configs.extra_config** + +This option changes the block name in twig template that will be used to add extra configuration to select2 jQuery plugin. +Make sure that block with name "oro_combobox_dataconfig_%extra_config%" exists. There are two predefined values that can be used: +"autocomplete" (block name "oro_combobox_dataconfig_autocomplete") and "grid" (block name "oro_combobox_dataconfig_grid"). + +If you need to extend select2 logic you can add a block in twig template with name of your "extra_config" and do all customization there. + +**configs.selection_template_twig** + +A name of Twig template that contain [underscore.js](http://underscorejs.org/) template. +This template will be used in dropdown list to render each result row. +Example of template: +``` +<%= highlight(firstName) %> <%= highlight(lastName) %> (<%= highlight(email) %>) %>) +``` + +**configs.result_template_twig** + +Difference from "selection_template_twig" is that it will be used to render value when it is selected. + +**configs.placeholder** + +A string that will be displayed when field doesn't have a value. + +**configs.allowClear** + +Controls possibility to make selected value empty. + +**configs.minimumInputLength** + +Count of characters that should be typed before request to remote server will be send. + +**configs.ajax** + +Custom options that are used by select2 jQuery plugin. + +**configs.ajax.url** + +Custom URL that will be used instead of route_name to send search requests. + +**configs.route_name** + +Url of this route will be used by select2 plugin to iteract with search handler. +By default Oro\Bundle\FormBundle\Controller\AutocompleteController::searchAction is used +but you can implement your own action and use it by referencing it via *route_name*. + + +#### Search Handler Service + +This service has several responsibilities: +* searching results that matches queries when user types characters in field on the web page +* converting each found entities to associated array that will be used on side of view and particularly in js code that + renders search results +* providing information about entity class name that is handled, this information is used in form type to transform + id to entity object using transformer + +Generic way to declare a search handler service and make possible to reference it using option "autocomplete_alias" is +to add declaration like below: + +```yml +services: + users_search_handler: + parent: oro_form.autocomplete.search_handler + arguments: + - %user_class% # pass class name of entity + - ["firstName", "lastName"] # pass properties that should be transported to the client + tags: + - { name: oro_form.autocomplete.search_handler, alias: users, acl_resource: user_acl_resource } + +``` + + +After this "oro_jqueryselect2_hidden" form type can receive option "autocomplete_alias" with value "users". + +This services receives a class name of entity that will be used by form type and during search requests. Also it +receives properties names that control what data will be transported to select2 javascript widget. + +This services can be parent of abstract service "oro_form.autocomplete.search_handler" but if you need your +own implementation of search handler you should implement Oro\Bundle\FormBundle\Autocomplete\SearchHandlerInterface. + +#### Security + +Each tag "oro_form.autocomplete.search_handler" can contain attribute "acl_resource" that references to an ACL resource +that should be granted to user that performs autocomplete request. This feature works only if you use default implementation +of autocomplete search action: Oro\Bundle\FormBundle\Controller\AutocompleteController::searchAction. + +If you use custom "configs.route_name" option it's on your own to check user permissions. + +#### Iteraction of Server and Javascript + +Server action receives next parameters from client: +* **name** - alias of search handler that is specified using tag "oro_form.autocomplete.search_handler" +* **query** - search string +* **page** - number of page to return +* **per_page** - how many records service should return + +Select2 plugin on client side expects response in next format: +``` +{ + "results": [{"id": 1, "firstName": "John", "lastName": "Doe"}, {...}, ...] + "more": true|false +} +``` + +Properties "firstName" and "lastName" are configured in search handler service. + + +#### Dependency on OroSearchBundle + +Default implementation of search handler is based on functionality of OroSearchBundle. If you use this implementation +your entity should be properly configured in the way that OroSearchBundle allows. + +#### Dependency on OroUserBundle + +As each autocomplete could be protected using ACL-resource, there is a dependency on OroUserBundle, particularly on "oro_user.acl_manager" service. diff --git a/src/Oro/Bundle/FormBundle/Resources/doc/reference/form_components.md b/src/Oro/Bundle/FormBundle/Resources/doc/reference/form_components.md new file mode 100644 index 00000000000..b47f3a80ac4 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/doc/reference/form_components.md @@ -0,0 +1,61 @@ +Form Components Overview +------------------------ + +This article describes all form components that are stored in OroUIBundle. +Form components are form types, data transformers and event listeners. + +### Form Types + +* **Form / Type / OroDateType** (name = oro_date) - encapsulates date element logic; +* **Form / Type / OroDateTimeType** (name = oro_datetime) - encapsulates datetime element logic; +* **Form / Type / EntityIdentifierType** (name = oro_entity_identifier) - converts string or array of entity IDs to existing entities of specified type. +* **Form / Type / OroJquerySelect2HiddenType** (name = oro_jqueryselect2_hidden) - supports autocompletition ([more details](./autocomplete_form_type.md)) + +### Data Transformers + +* **Form / DataTransformer / ArrayToStringTransformer** - converts array to string and back; +* **Form / DataTransformer / EntitiesToIdsTransformer** - converts entity IDs to entities and back. +* **Form / DataTransformer / EntityToIdTransformer** - converts entity ID to entity and back. + + +### Event Subscribers + +* **Form / EventListener / FixArrayToStringListener** - converts array to string on form PRE_BIND event. + + +### Configuration + +#### Form Types + +``` +parameters: + oro_form.type.date.class: Oro\Bundle\FormBundle\Form\Type\OroDateType + oro_form.type.datetime.class: Oro\Bundle\FormBundle\Form\Type\OroDateTimeType + oro_form.type.entity_identifier.class: Oro\Bundle\FormBundle\Form\Type\EntityIdentifierType + oro_form.type.jqueryselect2_hidden.class: Oro\Bundle\FormBundle\Form\Type\OroJquerySelect2HiddenType + +services: + oro_form.type.date: + class: %oro_form.type.date.class% + tags: + - { name: form.type, alias: oro_date } + + oro_form.type.datetime: + class: %oro_form.type.datetime.class% + tags: + - { name: form.type, alias: oro_datetime } + + oro_form.type.entity_identifier: + class: %oro_form.type.entity_identifier.class% + tags: + - { name: form.type, alias: oro_entity_identifier } + arguments: ["@doctrine"] + + oro_form.type.jqueryselect2_hidden: + class: %oro_form.type.jqueryselect2_hidden.class% + arguments: + - @doctrine.orm.entity_manager + - @oro_form.autocomplete.configuration + tags: + - { name: form.type, alias: oro_jqueryselect2_hidden } +``` diff --git a/src/Oro/Bundle/FormBundle/Resources/public/js/oro.select2.config.js b/src/Oro/Bundle/FormBundle/Resources/public/js/oro.select2.config.js new file mode 100644 index 00000000000..94258d63bba --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/public/js/oro.select2.config.js @@ -0,0 +1,83 @@ +var OroSelect2Config = function (config, url, perPage) { + this.config = config; + this.url = url; + this.perPage = perPage; +}; + +OroSelect2Config.prototype.getConfig = function () { + var self = this; + if (this.config.formatResult === undefined) { + this.config.formatResult = this.format(this.config.result_template !== undefined ? this.config.result_template : false); + } + if (this.config.formatSelection === undefined) { + this.config.formatSelection = this.format(this.config.selection_template !== undefined ? this.config.selection_template : false); + } + if (this.config.initSelection === undefined) { + this.config.initSelection = this.initSelection; + } + if (this.config.ajax === undefined) { + this.config.ajax = { + 'url': this.url, + 'data': function (query, page) { + return { + 'page': page, + 'per_page': self.perPage, + 'query': query + }; + }, + 'results': function (data, page) { + return data; + } + }; + } + if (this.config.ajax.quietMillis === undefined) { + this.config.ajax.quietMillis = 700; + } + if (this.config.escapeMarkup === undefined) { + this.config.escapeMarkup = function (m) { return m; }; + } + return this.config; +}; + +OroSelect2Config.prototype.format = function (jsTemplate) { + var self = this; + return function (object, container, query) { + if ($.isEmptyObject(object)) { + return undefined; + } + var result = ''; + var highlight = function (str) { + return self.highlightSelection(str, query); + }; + if (object._html !== undefined) { + result = object._html; + } else if (jsTemplate) { + object.highlight = highlight; + var tpl = _.template(jsTemplate); + result = tpl(object); + } else { + result = highlight(self.getTitle(object, self.config.properties)); + } + return result; + }; +}; + +OroSelect2Config.prototype.initSelection = function (element, callback) { + callback(element.data('entity')); +}; + +OroSelect2Config.prototype.highlightSelection = function (str, selection) { + return str && selection && selection.term ? str.replace(new RegExp(selection.term, 'ig'), '$&') : str; +}; + +OroSelect2Config.prototype.getTitle = function (data, properties) { + var title = ''; + if (data) { + var result = []; + for (var i = 0; i < properties.length; i++) { + result.push(data[properties[i]]); + } + title = result.join(' '); + } + return title; +}; diff --git a/src/Oro/Bundle/FormBundle/Resources/translations/messages.en.yml b/src/Oro/Bundle/FormBundle/Resources/translations/messages.en.yml new file mode 100644 index 00000000000..8f83e39dbfd --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/translations/messages.en.yml @@ -0,0 +1 @@ +oro.form.choose_value: Choose a value... diff --git a/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig b/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig new file mode 100644 index 00000000000..8c80e4ac9e7 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Resources/views/Form/fields.html.twig @@ -0,0 +1,155 @@ +{% block oro_ticker_symbol_widget %} + + + {{ form_widget(form) }} +{% endblock %} + +{% block genemu_jqueryselect2_country_row %} + {{ block('genemu_jqueryselect2_row') }} +{% endblock %} + +{% block genemu_jqueryselect2_choice_row %} + {{ block('genemu_jqueryselect2_row') }} +{% endblock %} + +{% block genemu_jqueryselect2_entity_row %} + {{ block('genemu_jqueryselect2_row') }} +{% endblock %} + +{% block oro_jqueryselect2_hidden_row %} + {{ block('genemu_jqueryselect2_row') }} +{% endblock %} + +{% block genemu_jqueryselect2_row %} + {{ form_row(form) }} + {{ form_javascript(form) }} +{% endblock %} + +{% block genemu_jqueryselect2_javascript %} + +{% endblock %} + +{% block oro_combobox_dataconfig_autocomplete %} + {% set url = '' %} + {% if configs.ajax.url is defined and configs.ajax.url%} + {% set url = configs.ajax.url %} + {% elseif configs.route_name is defined and configs.route_name %} + {% set url = path(configs.route_name) %} + {% endif %} + select2Config.ajax = { + 'url': {{ url|json_encode|raw }}, + 'data': function (query, page) { + return { + 'page': page, + 'per_page': {{ configs.per_page|default(10) }}, + 'name': "{{ configs.autocomplete_alias }}", + 'query': query + }; + }, + 'results': function (data, page) { + return data; + } + }; +{% endblock %} + +{% block oro_combobox_dataconfig_grid %} + {% set url = configs.ajax.url is defined ? configs.ajax.url : path(configs.route, {'_format': 'json'}) %} + select2Config.ajax = { + 'url': {{ url|json_encode|raw }}, + 'data': function (query, page) { + return { + '{{ configs.grid.name }}[_pager][_page]': page, + '{{ configs.grid.name }}[_pager][_per_page]': {{ configs.per_page|default(10) }}, + '{{ configs.grid.name }}[_sort_by][{{ configs.grid.sort_by|default(configs.properties[0]) }}]': "{{ configs.grid.sort_order|default('ASC') }}", + '{{ configs.grid.name }}[_filter][{{ configs.properties[0] }}][type]': 1, + '{{ configs.grid.name }}[_filter][{{ configs.properties[0] }}][value]': query + }; + }, + 'results': function (data, page) { + return { + results: $.map(data.data, function(item) { + return {'id': item.id, 'text': item.{{- configs.properties[0] -}} }; + }), + more: page*10 < data.options.totalRecords + }; + } + }; +{% endblock %} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SearchHandlerTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SearchHandlerTest.php new file mode 100644 index 00000000000..3b5e01591af --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SearchHandlerTest.php @@ -0,0 +1,426 @@ + array('alias' => self::TEST_ENTITY_SEARCH_ALIAS)); + + /** + * @var Indexer|\PHPUnit_Framework_MockObject_MockObject + */ + protected $indexer; + + /** + * @var ManagerRegistry|\PHPUnit_Framework_MockObject_MockObject + */ + protected $managerRegistry; + + /** + * @var EntityManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entityManager; + + /** + * @var EntityRepository|\PHPUnit_Framework_MockObject_MockObject + */ + protected $entityRepository; + + /** + * @var QueryBuilder|\PHPUnit_Framework_MockObject_MockObject + */ + protected $queryBuilder; + + /** + * @var AbstractQuery|\PHPUnit_Framework_MockObject_MockObject + */ + protected $query; + + /** + * @var Expr|\PHPUnit_Framework_MockObject_MockObject + */ + protected $expr; + + /** + * @var Result|\PHPUnit_Framework_MockObject_MockObject + */ + protected $searchResult; + + /** + * @var SearchHandler + */ + protected $searchHandler; + + protected function setUp() + { + $this->indexer = $this->getMockBuilder('Oro\Bundle\SearchBundle\Engine\Indexer') + ->setMethods(array('simpleSearch')) + ->disableOriginalConstructor() + ->getMock(); + + $this->entityRepository = $this->getMockBuilder('Doctrine\ORM\EntityRepository') + ->disableOriginalConstructor() + ->setMethods(array('createQueryBuilder')) + ->getMock(); + + $metadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadata') + ->setMethods(array('getSingleIdentifierFieldName')) + ->disableOriginalConstructor() + ->getMock(); + $metadata->expects($this->once()) + ->method('getSingleIdentifierFieldName') + ->will($this->returnValue(self::TEST_ID_FIELD)); + + $metadataFactory = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataFactory') + ->setMethods(array('getMetadataFor')) + ->disableOriginalConstructor() + ->getMock(); + $metadataFactory->expects($this->once()) + ->method('getMetadataFor') + ->with(self::TEST_ENTITY_CLASS) + ->will($this->returnValue($metadata)); + + $this->entityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->setMethods(array('getRepository', 'getMetadataFactory')) + ->getMock(); + $this->entityManager->expects($this->once()) + ->method('getRepository') + ->will($this->returnValue($this->entityRepository)); + $this->entityManager->expects($this->once()) + ->method('getMetadataFactory') + ->will($this->returnValue($metadataFactory)); + + $this->managerRegistry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry'); + $this->managerRegistry->expects($this->once()) + ->method('getManagerForClass') + ->with(self::TEST_ENTITY_CLASS) + ->will($this->returnValue($this->entityManager)); + + $this->queryBuilder = $this->getMockBuilder('Doctrine\ORM\QueryBuilder') + ->disableOriginalConstructor() + ->setMethods(array('expr', 'getQuery', 'where')) + ->getMock(); + + $this->query = $this->getMockBuilder('Doctrine\ORM\AbstractQuery') + ->disableOriginalConstructor() + ->setMethods(array('getResult')) + ->getMockForAbstractClass(); + + $this->expr = $this->getMockBuilder('Doctrine\ORM\Query\Expr') + ->disableOriginalConstructor() + ->setMethods(array('in')) + ->getMock(); + + $this->searchResult = $this->getMockBuilder('Oro\Bundle\SearchBundle\Query\Result') + ->setMethods(array('getElements')) + ->disableOriginalConstructor() + ->getMock(); + + $this->searchHandler = new SearchHandler( + self::TEST_ENTITY_CLASS, + $this->testProperties + ); + + $this->searchHandler->initDoctrinePropertiesByManagerRegistry($this->managerRegistry); + $this->searchHandler->initSearchIndexer($this->indexer, $this->testSearchConfig); + } + + public function testConstructorAndInitialize() + { + $this->assertAttributeSame( + $this->indexer, + 'indexer', + $this->searchHandler + ); + $this->assertAttributeSame( + $this->entityRepository, + 'entityRepository', + $this->searchHandler + ); + $this->assertAttributeEquals( + self::TEST_ENTITY_CLASS, + 'entityName', + $this->searchHandler + ); + $this->assertAttributeEquals( + self::TEST_ID_FIELD, + 'idFieldName', + $this->searchHandler + ); + $this->assertAttributeEquals( + $this->testProperties, + 'properties', + $this->searchHandler + ); + } + + public function testGetProperties() + { + $this->assertEquals($this->testProperties, $this->searchHandler->getProperties()); + } + + public function testGetEntitName() + { + $this->assertEquals(self::TEST_ENTITY_CLASS, $this->searchHandler->getEntityName()); + } + + /** + * @dataProvider searchDataProvider + * @param string $query + * @param array $expectedResult + * @param array $expectedIndexerCalls + * @param array $expectSearchResultCalls + * @param array $expectEntityRepositoryCalls + * @param array $expectQueryBuilderCalls + * @param array $expectExprCalls + * @param array $expectQueryCalls + */ + public function testSearch( + $query, + $expectedResult, + $expectedIndexerCalls, + $expectSearchResultCalls, + $expectEntityRepositoryCalls, + $expectQueryBuilderCalls, + $expectExprCalls, + $expectQueryCalls + ) { + MockHelper::addMockExpectedCalls($this->indexer, $expectedIndexerCalls, $this); + MockHelper::addMockExpectedCalls($this->searchResult, $expectSearchResultCalls, $this); + MockHelper::addMockExpectedCalls($this->entityRepository, $expectEntityRepositoryCalls, $this); + MockHelper::addMockExpectedCalls($this->queryBuilder, $expectQueryBuilderCalls, $this); + MockHelper::addMockExpectedCalls($this->expr, $expectExprCalls, $this); + MockHelper::addMockExpectedCalls($this->query, $expectQueryCalls, $this); + + $actualResult = $this->searchHandler->search($query['query'], $query['page'], $query['perPage']); + $this->assertEquals($expectedResult, $actualResult); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function searchDataProvider() + { + return array( + 'default' => array( + 'query' => array('query' => 'search', 'page' => 1, 'perPage' => 100), + 'expectedResult' => array( + 'results' => array( + array(self::TEST_ID_FIELD => 1, 'name' => 'John', 'email' => 'john@example.com'), + array(self::TEST_ID_FIELD => 2, 'name' => 'Jane', 'email' => 'jane@example.com'), + array(self::TEST_ID_FIELD => 3, 'name' => 'Jack', 'email' => null), + array(self::TEST_ID_FIELD => 4, 'name' => 'Bill', 'email' => 'bill@example.com') + ), + 'more' => false + ), + 'expectIndexerCalls' => array( + array( + 'simpleSearch', + array('search', 0, 101, self::TEST_ENTITY_SEARCH_ALIAS), 'getMockSearchResult' + ) + ), + 'expectSearchResultCalls' => array( + array('getElements', array(), $this->createMockSearchItems(array(1, 2, 3, 4))) + ), + 'expectEntityRepositoryCalls' => array( + array('createQueryBuilder', array('e'), 'getMockQueryBuilder') + ), + 'expectQueryBuilderCalls' => array( + array('expr', array(), 'getMockExpr'), + array('where', array('e.id IN (1, 2, 3, 4)'), 'getMockQueryBuilder'), + array('getQuery', array(), 'getMockQuery'), + ), + 'expectExprCalls' => array( + array('in', array('e.' . self::TEST_ID_FIELD, array(1, 2, 3, 4)), 'e.id IN (1, 2, 3, 4)') + ), + 'expectQueryCalls' => array( + array( + 'getResult', + array(), + array( + $this->createMockEntity( + array(self::TEST_ID_FIELD => 1, 'name' => 'John', 'email' => 'john@example.com') + ), + $this->createMockEntity( + array(self::TEST_ID_FIELD => 2, 'name' => 'Jane', 'email' => 'jane@example.com') + ), + array(self::TEST_ID_FIELD => 3,'name' => 'Jack'), + $this->createStubEntityWithProperties( + array( + self::TEST_ID_FIELD => 4, + 'name' => 'Bill', + 'email' => $this->createMockFlexibleValue('bill@example.com') + ) + ) + ) + ) + ), + ), + 'hasMore' => array( + 'query' => array('query' => 'search', 'page' => 1, 'perPage' => 1), + 'expectedResult' => array( + 'results' => array( + array( + self::TEST_ID_FIELD => 1, 'name' => 'John', 'email' => 'john@example.com' + ) + ), + 'more' => true + ), + 'expectIndexerCalls' => array( + array( + 'simpleSearch', array('search', 0, 2, self::TEST_ENTITY_SEARCH_ALIAS), 'getMockSearchResult' + ) + ), + 'expectSearchResultCalls' => array( + array('getElements', array(), $this->createMockSearchItems(array(1, 2))) + ), + 'expectEntityRepositoryCalls' => array( + array('createQueryBuilder', array('e'), 'getMockQueryBuilder') + ), + 'expectQueryBuilderCalls' => array( + array('expr', array(), 'getMockExpr'), + array('where', array('e.id IN (1, 2)'), 'getMockQueryBuilder'), + array('getQuery', array(), 'getMockQuery'), + ), + 'expectExprCalls' => array( + array('in', array('e.' . self::TEST_ID_FIELD, array(1, 2)), 'e.id IN (1, 2)') + ), + 'expectQueryCalls' => array( + array( + 'getResult', + array(), + array( + $this->createMockEntity( + array(self::TEST_ID_FIELD => 1, 'name' => 'John', 'email' => 'john@example.com') + ), + $this->createMockEntity( + array(self::TEST_ID_FIELD => 2, 'name' => 'Jane', 'email' => 'jane@example.com') + ) + ) + ) + ), + ), + ); + } + + /** + * @return Result|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockSearchResult() + { + return $this->searchResult; + } + + /** + * @return QueryBuilder|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockQueryBuilder() + { + return $this->queryBuilder; + } + + /** + * @return Expr|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockExpr() + { + return $this->expr; + } + + /** + * @return AbstractQuery|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockQuery() + { + return $this->query; + } + + /** + * @param array $ids + * @return Item[] + */ + public function createMockSearchItems(array $ids) + { + $result = array(); + foreach ($ids as $id) { + $item = $this->getMockBuilder('Oro\Bundle\SearchBundle\Query\Result\Item') + ->disableOriginalConstructor() + ->setMethods(array('getRecordId')) + ->getMock(); + $item->expects($this->once()) + ->method('getRecordId') + ->will($this->returnValue($id)); + $result[] = $item; + } + return $result; + } + + public function createStubEntityWithProperties(array $data) + { + $result = new \stdClass(); + foreach ($data as $name => $property) { + $result->$name = $property; + } + return $result; + } + + public function createMockEntity(array $data) + { + $methods = array(); + foreach (array_keys($data) as $name) { + $methods[$name] = 'get' .ucfirst($name); + } + $result = $this->getMock('stdClass', array_values($methods)); + foreach ($data as $name => $property) { + $result->expects($this->any()) + ->method($methods[$name]) + ->will($this->returnValue($property)); + } + return $result; + } + + public function createMockFlexibleValue($data) + { + $result = $this->getMock('Oro\Bundle\FlexibleEntityBundle\Model\FlexibleValueInterface'); + $result->expects($this->any()) + ->method('getData') + ->will($this->returnValue($data)); + return $result; + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SearchRegistryTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SearchRegistryTest.php new file mode 100644 index 00000000000..c9f2dd0a8ca --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SearchRegistryTest.php @@ -0,0 +1,50 @@ +searchHandler = $this->getMock('Oro\Bundle\FormBundle\Autocomplete\SearchHandlerInterface'); + $this->searchRegistry = new SearchRegistry(); + } + + public function testAddSearchHandler() + { + $this->searchRegistry->addSearchHandler('test', $this->searchHandler); + $this->assertAttributeSame( + array('test' => $this->searchHandler), + 'searchHandlers', + $this->searchRegistry + ); + } + + public function testGetSearchHandler() + { + $this->searchRegistry->addSearchHandler('test', $this->searchHandler); + $this->assertSame($this->searchHandler, $this->searchRegistry->getSearchHandler('test')); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Search handler "test" is not registered + */ + public function testGetSearchHandlerFails() + { + $this->searchRegistry->getSearchHandler('test'); + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SecurityTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SecurityTest.php new file mode 100644 index 00000000000..4858bb5c613 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Autocomplete/SecurityTest.php @@ -0,0 +1,57 @@ +manager = $this->getMock('Oro\Bundle\UserBundle\Acl\ManagerInterface'); + $this->security = new Security($this->manager); + } + + public function testSetAutocompleteAclResource() + { + $this->security->setAutocompleteAclResource('test_search', 'test_acl_resource'); + $this->assertAttributeEquals( + array('test_search' => 'test_acl_resource'), + 'autocompleteAclResources', + $this->security + ); + } + + public function testGetAutocompleteAclResource() + { + $this->assertNull($this->security->getAutocompleteAclResource('test')); + + $this->security->setAutocompleteAclResource('test_search', 'test_acl_resource'); + $this->assertEquals('test_acl_resource', $this->security->getAutocompleteAclResource('test_search')); + } + + public function testIsAutocompleteGranted() + { + $this->assertFalse($this->security->isAutocompleteGranted('test_acl_resource')); + + $this->security->setAutocompleteAclResource('test_search', 'test_acl_resource'); + + $this->manager->expects($this->once()) + ->method('isResourceGranted') + ->with('test_acl_resource') + ->will($this->returnValue(true)); + + $this->assertTrue($this->security->isAutocompleteGranted('test_search')); + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/DependencyInjection/Compiler/AutocompleteCompilerPassTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/DependencyInjection/Compiler/AutocompleteCompilerPassTest.php new file mode 100644 index 00000000000..b5a9f0e0e23 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/DependencyInjection/Compiler/AutocompleteCompilerPassTest.php @@ -0,0 +1,73 @@ + array( + array('alias' => 'tag1'), array('alias' => 'tag2') + ), + 'testId2' => array( + array('alias' => 'tag1', 'acl_resource' => 'test_acl_resource') + ), + 'testId3' => array( + array('name' => 'not_matched') + ) + ); + + $searchRegistryDefinition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition') + ->disableOriginalConstructor() + ->getMock(); + $searchRegistryDefinition->expects($this->exactly(4)) + ->method('addMethodCall'); + $searchRegistryDefinition->expects($this->at(0)) + ->method('addMethodCall') + ->with('addSearchHandler', array('tag1', new Reference('testId1'))); + $searchRegistryDefinition->expects($this->at(1)) + ->method('addMethodCall') + ->with('addSearchHandler', array('tag2', new Reference('testId1'))); + $searchRegistryDefinition->expects($this->at(2)) + ->method('addMethodCall') + ->with('addSearchHandler', array('tag1', new Reference('testId2'))); + $searchRegistryDefinition->expects($this->at(3)) + ->method('addMethodCall') + ->with('addSearchHandler', array('testId3', new Reference('testId3'))); + + $securityDefinition = $this->getMockBuilder('Symfony\Component\DependencyInjection\Definition') + ->disableOriginalConstructor() + ->getMock(); + $securityDefinition->expects($this->exactly(1)) + ->method('addMethodCall'); + $securityDefinition->expects($this->at(0)) + ->method('addMethodCall') + ->with('setAutocompleteAclResource', array('tag1', 'test_acl_resource')); + + $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerBuilder') + ->disableOriginalConstructor() + ->getMock(); + + $container->expects($this->at(0)) + ->method('getDefinition') + ->with('oro_form.autocomplete.search_registry') + ->will($this->returnValue($searchRegistryDefinition)); + + $container->expects($this->at(1)) + ->method('getDefinition') + ->with('oro_form.autocomplete.security') + ->will($this->returnValue($securityDefinition)); + + $container->expects($this->at(2)) + ->method('findTaggedServiceIds') + ->with('oro_form.autocomplete.search_handler') + ->will($this->returnValue($attributes)); + + $pass = new AutocompleteCompilerPass(); + $pass->process($container); + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/DependencyInjection/ConfigurationTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/DependencyInjection/ConfigurationTest.php new file mode 100644 index 00000000000..51de5520e4f --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -0,0 +1,23 @@ +getConfigTreeBuilder(); + $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\TreeBuilder', $builder); + + /** @var $root ArrayNode */ + $root = $builder->buildTree(); + $this->assertInstanceOf('Symfony\Component\Config\Definition\ArrayNode', $root); + $this->assertEquals('oro_form', $root->getName()); + } +} diff --git a/src/Oro/Bundle/UIBundle/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php similarity index 97% rename from src/Oro/Bundle/UIBundle/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php rename to src/Oro/Bundle/FormBundle/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php index 4e18674cc80..f20f2f832ee 100644 --- a/src/Oro/Bundle/UIBundle/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/DataTransformer/ArrayToStringTransformerTest.php @@ -1,8 +1,8 @@ getMockEntityManager(), 'TestClass', $property, null); + $this->assertEquals($expectedValue, $transformer->transform($value)); + } + + /** + * @return array + */ + public function transformDataProvider() + { + return array( + 'default' => array( + 'id', + $this->createMockEntity('id', 1), + 1 + ), + 'empty' => array( + 'id', + null, + null + ), + ); + } + + /** + * @expectedException \Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedExceptionMessage Expected argument of type "object", "string" given + */ + public function testTransformFailsWhenValueInNotAnArray() + { + $transformer = new EntityToIdTransformer($this->getMockEntityManager(), 'TestClass', 'id', null); + $transformer->transform('invalid value'); + } + + public function testReverseTransformEmpty() + { + $transformer = new EntityToIdTransformer($this->getMockEntityManager(), 'TestClass', 'id', null); + $this->assertNull($transformer->reverseTransform('')); + } + + public function testReverseTransform() + { + $entity = $this->createMockEntity('id', 1); + + $repository = $this->getMockBuilder('Doctrine\ORM\EntityRepository') + ->disableOriginalConstructor() + ->getMock(); + $repository->expects($this->once()) + ->method('find') + ->with(1) + ->will($this->returnValue($entity)); + + $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + $em->expects($this->once()) + ->method('getRepository') + ->with('TestClass') + ->will($this->returnValue($repository)); + + $transformer = new EntityToIdTransformer($em, 'TestClass', 'id', null); + $this->assertEquals($entity, $transformer->reverseTransform(1)); + } + + public function testReverseTransformQueryBuilder() + { + $entity = $this->createMockEntity('id', 1); + + $repository = $this->getMockBuilder('Doctrine\ORM\EntityRepository') + ->disableOriginalConstructor() + ->getMock(); + + $self= $this; + $callback = function ($pRepository, $pId) use ($self, $repository, $entity) { + $self->assertEquals($repository, $pRepository); + $self->assertEquals(1, $pId); + + $query = $self->getMockBuilder('Doctrine\ORM\AbstractQuery') + ->disableOriginalConstructor() + ->setMethods(array('execute')) + ->getMockForAbstractClass(); + $query->expects($self->once()) + ->method('execute') + ->will($self->returnValue($entity)); + + $qb = $self->getMockBuilder('Doctrine\ORM\QueryBuilder') + ->disableOriginalConstructor() + ->getMock(); + $qb->expects($self->once()) + ->method('getQuery') + ->will($self->returnValue($query)); + return $qb; + }; + + $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + $em->expects($this->once()) + ->method('getRepository') + ->with('TestClass') + ->will($this->returnValue($repository)); + + $transformer = new EntityToIdTransformer($em, 'TestClass', 'id', $callback); + $this->assertEquals($entity, $transformer->reverseTransform(1)); + } + + /** + * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedExceptionMessage Expected argument of type "Doctrine\ORM\QueryBuilder", "NULL" given + */ + public function testReverseTransformQueryBuilderException() + { + $entity = $this->createMockEntity('id', 1); + + $repository = $this->getMockBuilder('Doctrine\ORM\EntityRepository') + ->disableOriginalConstructor() + ->getMock(); + + $callback = function () { + return null; + }; + + $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + $em->expects($this->once()) + ->method('getRepository') + ->with('TestClass') + ->will($this->returnValue($repository)); + + $transformer = new EntityToIdTransformer($em, 'TestClass', 'id', $callback); + $this->assertEquals($entity, $transformer->reverseTransform(1)); + } + + public function testPropertyConstruction() + { + $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + + $metadata = $this->getMockBuilder('\Doctrine\ORM\Mapping\ClassMetadata') + ->disableOriginalConstructor() + ->getMock(); + $metadata->expects($this->once()) + ->method('getSingleIdentifierFieldName') + ->will($this->returnValue('id')); + $em->expects($this->once()) + ->method('getClassMetadata') + ->will($this->returnValue($metadata)); + + new EntityToIdTransformer($em, 'TestClass', null, null); + } + + /** + * @expectedException Symfony\Component\Form\Exception\FormException + * @expectedExceptionMessage Cannot get id property path of entity. "TestClass" has composite primary key. + */ + public function testPropertyConstructionException() + { + $em = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->getMock(); + + $metadata = $this->getMockBuilder('\Doctrine\ORM\Mapping\ClassMetadata') + ->disableOriginalConstructor() + ->getMock(); + $metadata->expects($this->once()) + ->method('getSingleIdentifierFieldName') + ->will( + $this->returnCallback( + function () { + throw new MappingException('Exception'); + } + ) + ); + $em->expects($this->once()) + ->method('getClassMetadata') + ->will($this->returnValue($metadata)); + + new EntityToIdTransformer($em, 'TestClass', null, null); + } + + /** + * @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException + * @expectedExceptionMessage Expected argument of type "callable", "string" given + */ + public function testCallbackException() + { + new EntityToIdTransformer($this->getMockEntityManager(), 'TestClass', 'id', 'uncallable'); + } + + /** + * @return EntityManager|\PHPUnit_Framework_MockObject_MockObject + */ + protected function getMockEntityManager() + { + if (!$this->entityManager) { + $this->entityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->setMethods(array('getClassMetadata', 'getRepository')) + ->getMockForAbstractClass(); + } + + return $this->entityManager; + } + + /** + * Create mock entity by id property name and value + * + * @param string $property + * @param mixed $value + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createMockEntity($property, $value) + { + $getter = 'get' . ucfirst($property); + $result = $this->getMock('MockEntity', array($getter)); + $result->expects($this->any())->method($getter)->will($this->returnValue($value)); + return $result; + } +} diff --git a/src/Oro/Bundle/UIBundle/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php similarity index 91% rename from src/Oro/Bundle/UIBundle/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php rename to src/Oro/Bundle/FormBundle/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php index a9a231ad0be..f2448d1cf0e 100644 --- a/src/Oro/Bundle/UIBundle/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/EventListener/FixArrayToStringListenerTest.php @@ -1,12 +1,12 @@ type = $this->getMockBuilder('Oro\Bundle\UIBundle\Form\Type\EntityIdentifierType') + $this->type = $this->getMockBuilder('Oro\Bundle\FormBundle\Form\Type\EntityIdentifierType') ->setMethods(array('createEntitiesToIdsTransformer')) ->setConstructorArgs(array($this->getMockManagerRegistry())) ->getMock(); @@ -282,7 +283,7 @@ public function testCreateEntitiesToIdsTransformer() $this->callback( function ($transformer) use ($options) { \PHPUnit_Framework_TestCase::assertInstanceOf( - 'Oro\Bundle\UIBundle\Form\DataTransformer\EntitiesToIdsTransformer', + 'Oro\Bundle\FormBundle\Form\DataTransformer\EntitiesToIdsTransformer', $transformer ); \PHPUnit_Framework_TestCase::assertAttributeEquals( @@ -412,7 +413,7 @@ protected function getMockEntitiesToIdsTransformer() { if (!$this->entitiesToIdsTransformer) { $this->entitiesToIdsTransformer = - $this->getMockBuilder('Oro\Bundle\UIBundle\Form\DataTransformer\EntitiesToIdsTransformer') + $this->getMockBuilder('Oro\Bundle\FormBundle\Form\DataTransformer\EntitiesToIdsTransformer') ->disableOriginalConstructor() ->setMethods(array('transform', 'reverseTransform')) ->getMockForAbstractClass(); diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/OroJquerySelect2HiddenTypeTest.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/OroJquerySelect2HiddenTypeTest.php new file mode 100644 index 00000000000..61fd28773d6 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/OroJquerySelect2HiddenTypeTest.php @@ -0,0 +1,404 @@ +type = $this->getMockBuilder('Oro\Bundle\FormBundle\Form\Type\OroJquerySelect2HiddenType') + ->setMethods(array('createDefaultTransformer')) + ->setConstructorArgs(array($this->getMockEntityManager(), $this->getMockSearchRegistry())) + ->getMock(); + /*$this->type->expects($this->any())->method('createDefaultTransformer') + ->will($this->returnValue($this->getMockEntityToIdTransformer()));*/ + } + + protected function getExtensions() + { + return array_merge(parent::getExtensions(), array(new TestFormExtension())); + } + + /** + * @dataProvider bindDataProvider + * @param mixed $bindData + * @param mixed $formData + * @param mixed $viewData + * @param array $options + * @param array $expectedCalls + * @param array $expectedVars + */ + public function testBindData( + $bindData, + $formData, + $viewData, + array $options, + array $expectedCalls, + array $expectedVars + ) { + if (isset($options['converter']) + && is_string($options['converter']) + && method_exists($this, $options['converter']) + ) { + $options['converter'] = $this->$options['converter'](); + } + + foreach ($expectedCalls as $key => $calls) { + $mock = $this->{'getMock' . ucfirst($key)}(); + MockHelper::addMockExpectedCalls($mock, $calls, $this); + } + + $form = $this->factory->create($this->type, null, $options); + + $form->bind($bindData); + + $this->assertTrue($form->isSynchronized()); + $this->assertEquals($formData, $form->getData()); + + $view = $form->createView(); + $this->assertEquals($viewData, $view->vars['value']); + + foreach ($expectedVars as $name => $expectedValue) { + $this->assertEquals($expectedValue, $view->vars[$name]); + } + } + + + /** + * Data provider for testBindData + * + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function bindDataProvider() + { + $entityId1 = $this->createMockEntity('id', 1); + return array( + 'use autocomplete_alias' => array( + '1', + $entityId1, + '1', + array('autocomplete_alias' => 'foo'), + 'expectedCalls' => array( + 'searchRegistry' => array( + array('getSearchHandler', array('foo'), 'getMockSearchHandler'), + array('getSearchHandler', array('foo'), 'getMockSearchHandler'), + array('getSearchHandler', array('foo'), 'getMockSearchHandler') + ), + 'searchHandler' => array( + array('getProperties', array(), array('bar', 'baz')), + array('getEntityName', array(), 'TestEntityClass'), + array( + 'convertItem', + array($entityId1), + array('id' => 1, 'bar' => 'Bar value', 'baz' => 'Baz value') + ), + ), + 'formType' => array( + array('createDefaultTransformer', array('TestEntityClass'), 'getMockEntityToIdTransformer') + ), + 'entityToIdTransformer' => array( + array('transform', array(null), null), + array('reverseTransform', array('1'), $entityId1) + ) + ), + 'expectedVars' => array( + 'configs' => array( + 'placeholder' => 'oro.form.choose_value', + 'allowClear' => 1, + 'minimumInputLength' => 1, + 'autocomplete_alias' => 'foo', + 'properties' => array('bar', 'baz'), + 'route_name' => 'oro_form_autocomplete_search', + 'extra_config' => 'autocomplete' + ), + 'attr' => array( + 'data-entity' => json_encode(array('id' => 1, 'bar' => 'Bar value', 'baz' => 'Baz value')) + ) + ) + ), + 'without autocomplete_alias' => array( + '1', + $entityId1, + '1', + array( + 'configs' => array( + 'route_name' => 'custom_route' + ), + 'converter' => 'getMockConverter', + 'entity_class' => 'TestEntityClass' + ), + 'expectedCalls' => array( + 'converter' => array( + array( + 'convertItem', + array($entityId1), + array('id' => 1, 'bar' => 'Bar value', 'baz' => 'Baz value') + ), + ), + 'formType' => array( + array('createDefaultTransformer', array('TestEntityClass'), 'getMockEntityToIdTransformer') + ), + 'entityToIdTransformer' => array( + array('transform', array(null), null), + array('reverseTransform', array('1'), $entityId1) + ) + ), + 'expectedVars' => array( + 'configs' => array( + 'placeholder' => 'oro.form.choose_value', + 'allowClear' => 1, + 'minimumInputLength' => 1, + 'route_name' => 'custom_route' + ), + 'attr' => array( + 'data-entity' => json_encode(array('id' => 1, 'bar' => 'Bar value', 'baz' => 'Baz value')) + ) + ) + ) + ); + } + + /** + * @dataProvider createErrorsDataProvider + * @param array $options + * @param array $expectedCalls + * @param string $expectedException + * @param string $expectedExceptionMessage + */ + public function testCreateErrors( + array $options, + array $expectedCalls, + $expectedException, + $expectedExceptionMessage + ) { + if (isset($options['converter']) + && is_string($options['converter']) + && method_exists($this, $options['converter']) + ) { + $options['converter'] = $this->$options['converter'](); + } + + foreach ($expectedCalls as $key => $calls) { + $mock = $this->{'getMock' . ucfirst($key)}(); + MockHelper::addMockExpectedCalls($mock, $calls, $this); + } + + $this->setExpectedException($expectedException, $expectedExceptionMessage); + $this->factory->create($this->type, null, $options); + } + + /** + * Data provider for testBindData + * + * @return array + */ + public function createErrorsDataProvider() + { + return array( + 'configs.route_name or configs.ajax.url must be set' => array( + array(), + 'expectedCalls' => array(), + 'expectedException' => 'Symfony\Component\Form\Exception\FormException', + 'expectedExceptionMessage' => 'Either option "configs.route_name" or "configs.ajax.url" must be set.' + ), + 'converter must be set' => array( + array( + 'configs' => array( + 'route_name' => 'foo' + ) + ), + 'expectedCalls' => array(), + 'expectedException' => 'Symfony\Component\Form\Exception\FormException', + 'expectedExceptionMessage' => 'The option "converter" must be set.' + ), + 'converter invalid' => array( + array( + 'converter' => 'bar', + 'configs' => array( + 'route_name' => 'foo' + ) + ), + 'expectedCalls' => array(), + 'expectedException' => 'Symfony\Component\Form\Exception\FormException', + 'expectedExceptionMessage' => + sprintf( + 'The option "converter" must be an instance of "%s".', + 'Oro\Bundle\FormBundle\Autocomplete\ConverterInterface' + ) + ), + 'entity_class must be set' => array( + array( + 'converter' => 'getMockConverter', + 'configs' => array( + 'route_name' => 'foo' + ) + ), + 'expectedCalls' => array(), + 'expectedException' => 'Symfony\Component\Form\Exception\FormException', + 'expectedExceptionMessage' => 'The option "entity_class" must be set.' + ), + 'entity_class must be set2' => array( + array( + 'converter' => 'getMockConverter', + 'entity_class' => 'bar', + 'configs' => array( + 'route_name' => 'foo' + ), + 'transformer' => 'invalid' + ), + 'expectedCalls' => array(), + 'expectedException' => 'Symfony\Component\Form\Exception\FormException', + 'expectedExceptionMessage' => + sprintf( + 'The option "transformer" must be an instance of "%s".', + 'Symfony\Component\Form\DataTransformerInterface' + ) + ) + ); + } + + /** + * Create mock entity by id property name and value + * + * @param string $property + * @param mixed $value + * @return \PHPUnit_Framework_MockObject_MockObject + */ + private function createMockEntity($property, $value) + { + $getter = 'get' . ucfirst($property); + $result = $this->getMock('MockEntity', array($getter)); + $result->expects($this->any())->method($getter)->will($this->returnValue($value)); + return $result; + } + + /** + * @return EntityManager|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockEntityManager() + { + if (!$this->entityManager) { + $this->entityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->setMethods(array('getClassMetadata', 'getRepository')) + ->getMockForAbstractClass(); + } + + return $this->entityManager; + } + + /** + * @return SearchRegistry|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockSearchRegistry() + { + if (!$this->searchRegistry) { + $this->searchRegistry = $this->getMockBuilder('Oro\Bundle\FormBundle\Autocomplete\SearchRegistry') + ->disableOriginalConstructor() + ->setMethods(array('hasSearchHandler', 'getSearchHandler')) + ->getMock(); + } + + return $this->searchRegistry; + } + + /** + * @return ConverterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockConverter() + { + if (!$this->converter) { + $this->converter = $this->getMock('Oro\Bundle\FormBundle\Autocomplete\ConverterInterface'); + } + + return $this->converter; + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + public function getMockFormType() + { + return $this->type; + } + + /** + * @return SearchHandlerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockSearchHandler() + { + if (!$this->searchHandler) { + $this->searchHandler = $this->getMock('Oro\Bundle\FormBundle\Autocomplete\SearchHandlerInterface'); + } + + return $this->searchHandler; + } + + /** + * @return EntityToIdTransformer|\PHPUnit_Framework_MockObject_MockObject + */ + public function getMockEntityToIdTransformer() + { + if (!$this->entityToIdTransformer) { + $this->entityToIdTransformer = + $this->getMockBuilder('Oro\Bundle\FormBundle\Form\DataTransformer\EntityToIdTransformer') + ->disableOriginalConstructor() + ->setMethods(array('transform', 'reverseTransform')) + ->getMockForAbstractClass(); + } + return $this->entityToIdTransformer; + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/Stub/TestEntity.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/Stub/TestEntity.php new file mode 100644 index 00000000000..3d47c582164 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/Stub/TestEntity.php @@ -0,0 +1,26 @@ +testId = $id; + $this->testProperty = $property; + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/TestFormExtension.php b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/TestFormExtension.php new file mode 100644 index 00000000000..860ac541093 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/Form/Type/TestFormExtension.php @@ -0,0 +1,17 @@ +classMetadata = $this->getMockBuilder('Doctrine\ORM\Mapping\ClassMetadataInfo') + ->disableOriginalConstructor() + ->setMethods(array('getSingleIdentifierFieldName')) + ->getMock(); + $this->classMetadata->expects($this->any()) + ->method('getSingleIdentifierFieldName') + ->will($this->returnValue(self::TEST_IDENTIFIER)); + + $this->entityManager = $this->getMockBuilder('Doctrine\ORM\EntityManager') + ->disableOriginalConstructor() + ->setMethods(array('getClassMetadata')) + ->getMock(); + $this->entityManager->expects($this->any()) + ->method('getClassMetadata') + ->with(self::TEST_CLASS) + ->will($this->returnValue($this->classMetadata)); + + $this->registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry') + ->disableOriginalConstructor() + ->setMethods('getManager', 'getRepository') + ->getMockForAbstractClass(); + $this->registry->expects($this->any()) + ->method('getManager') + ->will($this->returnValue($this->entityManager)); + $this->registry->expects($this->any()) + ->method('getRepository') + ->with(self::TEST_CLASS) + ->will($this->returnValue($this->getEntityRepository())); + + $this->type = new TranslatableEntityType($this->registry); + } + + protected function tearDown() + { + unset($this->classMetadata); + unset($this->entityManager); + unset($this->registry); + unset($this->entityRepository); + unset($this->queryBuilder); + unset($this->type); + } + + public function testGetName() + { + $this->assertEquals(TranslatableEntityType::NAME, $this->type->getName()); + } + + public function testGetParent() + { + $this->assertEquals('choice', $this->type->getParent()); + } + + /** + * @return QueryBuilder + */ + public function getQueryBuilder() + { + $testChoiceEntities = $this->getTestChoiceEntities($this->testChoices); + + if (!$this->queryBuilder) { + $query = $this->getMockBuilder('Doctrine\ORM\AbstractQuery') + ->disableOriginalConstructor() + ->setMethods(array('execute', 'setHint')) + ->getMockForAbstractClass(); + $query->expects($this->any()) + ->method('execute') + ->will($this->returnValue($testChoiceEntities)); + + $this->queryBuilder = $this->getMockBuilder('Doctrine\ORM\QueryBuilder') + ->disableOriginalConstructor() + ->setMethods(array('getQuery')) + ->getMock(); + $this->queryBuilder->expects($this->any()) + ->method('getQuery') + ->will($this->returnValue($query)); + } + + return $this->queryBuilder; + } + + /** + * @return EntityRepository + */ + public function getEntityRepository() + { + if (!$this->entityRepository) { + $this->entityRepository = $this->getMockBuilder('Doctrine\ORM\EntityRepository') + ->disableOriginalConstructor() + ->getMock(); + $this->entityRepository->expects($this->any()) + ->method('createQueryBuilder') + ->with('e') + ->will($this->returnValue($this->getQueryBuilder())); + } + + return $this->entityRepository; + } + + /** + * @param array $choices + * @return array + */ + protected function getTestChoiceEntities($choices) + { + foreach ($choices as $key => $value) { + $entity = new TestEntity($key, $value); + $choices[$key] = $entity; + } + + return $choices; + } + + /** + * @param array $options + * @param string $transformerClass + * + * @dataProvider buildFormDataProvider + */ + public function testBuildForm($options, $transformerClass) + { + // mock + $formBuilder = $this->getMockBuilder('Symfony\Component\Form\FormBuilder') + ->disableOriginalConstructor() + ->setMethods(array('resetViewTransformers')) + ->getMock(); + $formBuilder->expects($this->at(0)) + ->method('resetViewTransformers'); + + // test + $this->type->buildForm($formBuilder, $options); + + // assertions + /** @var $formBuilder FormBuilderInterface */ + $transformers = $formBuilder->getViewTransformers(); + $this->assertCount(1, $transformers); + + $transformer = current($transformers); + $this->assertInstanceOf($transformerClass, $transformer); + + $this->assertAttributeEquals($this->entityManager, 'em', $transformer); + $this->assertAttributeEquals(self::TEST_CLASS, 'className', $transformer); + $this->assertAttributeEquals(self::TEST_IDENTIFIER, 'property', $transformer); + } + + /** + * @return array + */ + public function buildFormDataProvider() + { + return array( + 'single' => array( + 'options' => array('class' => self::TEST_CLASS), + 'transformerClass' => 'Oro\Bundle\FormBundle\Form\DataTransformer\EntityToIdTransformer' + ), + 'multiple' => array( + 'options' => array('class' => self::TEST_CLASS, 'multiple' => true), + 'transformerClass' => 'Oro\Bundle\FormBundle\Form\DataTransformer\EntitiesToIdsTransformer' + ), + ); + } + + /** + * @param array $choiceListOptions + * @param array $expectedChoices + * @param boolean $expectSetHint + * + * @dataProvider setDefaultOptionsDataProvider + */ + public function testSetDefaultOptions(array $choiceListOptions, array $expectedChoices, $expectSetHint = false) + { + $test = $this; + + // prepare query builder option + if (isset($choiceListOptions['query_builder'])) { + $choiceListOptions['query_builder'] = $this->getQueryBuilderOption($choiceListOptions); + } + + // expectations for option resolver + $expectedRequiredOptions = array('class'); + + $optionsResolver = $this->getMockBuilder('Symfony\Component\OptionsResolver\OptionsResolverInterface') + ->disableOriginalConstructor() + ->setMethods(array('setRequired', 'setDefaults')) + ->getMockForAbstractClass(); + $optionsResolver->expects($this->once()) + ->method('setRequired') + ->with($expectedRequiredOptions); + $optionsResolver->expects($this->once()) + ->method('setDefaults') + ->will( + $this->returnCallback( + function ($options) use ($test, $choiceListOptions, $expectedChoices) { + $test->assertNull($options['property']); + $test->assertNull($options['query_builder']); + $test->assertNull($options['choices']); + $test->assertInstanceOf('\Closure', $options['choice_list']); + + $test->assertChoiceList($options['choice_list'], $choiceListOptions, $expectedChoices); + } + ) + ); + + // expectation for translation walker hint + if ($expectSetHint) { + /** @var $query \PHPUnit_Framework_MockObject_MockObject */ + $query = $this->getQueryBuilder()->getQuery(); + $query->expects($this->once()) + ->method('setHint') + ->with( + Query::HINT_CUSTOM_OUTPUT_WALKER, + 'Gedmo\\Translatable\\Query\\TreeWalker\\TranslationWalker' + ); + } + + // test + $this->type->setDefaultOptions($optionsResolver); + } + + /** + * @param array $options + * @return callable|QueryBuilder + */ + protected function getQueryBuilderOption(array $options) + { + if (empty($options['query_builder'])) { + return null; + } + + $test = $this; + + switch ($options['query_builder']) { + case 'closure': + return function (EntityRepository $entityRepository) use ($test) { + $test->assertEquals($test->getEntityRepository(), $entityRepository); + return $test->getQueryBuilder(); + }; + case 'object': + default: + return $this->getQueryBuilder(); + } + } + + /** + * @return array + */ + public function setDefaultOptionsDataProvider() + { + $testChoiceEntities = $this->getTestChoiceEntities($this->testChoices); + + return array( + 'predefined_choices' => array( + 'choiceListOptions' => array( + 'class' => self::TEST_CLASS, + 'property' => self::TEST_PROPERTY, + 'choices' => $testChoiceEntities + ), + 'expectedChoices' => $testChoiceEntities + ), + 'all_choices' => array( + 'choiceListOptions' => array( + 'class' => self::TEST_CLASS, + 'property' => self::TEST_PROPERTY, + 'choices' => null + ), + 'expectedChoices' => $testChoiceEntities, + 'expectSetHint' => true, + ), + 'query_builder' => array( + 'choiceListOptions' => array( + 'class' => self::TEST_CLASS, + 'property' => self::TEST_PROPERTY, + 'choices' => null, + 'query_builder' => 'object' + ), + 'expectedChoices' => $testChoiceEntities, + 'expectSetHint' => true, + ), + 'query_builder_callback' => array( + 'choiceListOptions' => array( + 'class' => self::TEST_CLASS, + 'property' => self::TEST_PROPERTY, + 'choices' => null, + 'query_builder' => 'closure' + ), + 'expectedChoices' => $testChoiceEntities, + 'expectSetHint' => true, + ), + ); + } + + /** + * @param callback $choiceList + * @param array $options + * @param array $expectedChoices + */ + public function assertChoiceList($choiceList, $options, $expectedChoices) + { + /** @var $objectChoiceList ObjectChoiceList */ + $objectChoiceList = $choiceList($this->getResolverOptions($options)); + + $this->assertInstanceOf('Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList', $objectChoiceList); + $this->assertEquals($expectedChoices, $objectChoiceList->getChoices()); + } + + /** + * @param array $options + * @return Options + */ + protected function getResolverOptions($options) + { + $resolverOptions = new Options(); + foreach ($options as $key => $value) { + $resolverOptions->set($key, $value); + } + + return $resolverOptions; + } +} diff --git a/src/Oro/Bundle/FormBundle/Tests/Unit/MockHelper.php b/src/Oro/Bundle/FormBundle/Tests/Unit/MockHelper.php new file mode 100644 index 00000000000..10d84153780 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/Tests/Unit/MockHelper.php @@ -0,0 +1,33 @@ +expects(\PHPUnit_Framework_TestCase::at($index++))->method($method); + $methodExpectation = call_user_func_array(array($methodExpectation, 'with'), $arguments); + if (is_string($result) && $callbacksContext && method_exists($callbacksContext, $result)) { + $result = $callbacksContext->$result(); + } + $methodExpectation->will(\PHPUnit_Framework_TestCase::returnValue($result)); + } + } else { + $mock->expects(\PHPUnit_Framework_TestCase::never())->method(\PHPUnit_Framework_TestCase::anything()); + } + } +} diff --git a/src/Oro/Bundle/FormBundle/bootstrap.php b/src/Oro/Bundle/FormBundle/bootstrap.php new file mode 100644 index 00000000000..fd52fe63a9a --- /dev/null +++ b/src/Oro/Bundle/FormBundle/bootstrap.php @@ -0,0 +1,14 @@ +=5.3.3", + "symfony/symfony": ">=2.1", + "genemu/form-bundle": "2.1.*", + "oro/search-bundle": "dev-master", + "oro/user-bundle": "dev-master" + }, + "autoload": { + "psr-0": { "Oro\\Bundle\\FormBundle": "" } + }, + "target-dir": "Oro/Bundle/FormBundle", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + } +} diff --git a/src/Oro/Bundle/FormBundle/phpunit.xml.dist b/src/Oro/Bundle/FormBundle/phpunit.xml.dist new file mode 100644 index 00000000000..ed8987c8a21 --- /dev/null +++ b/src/Oro/Bundle/FormBundle/phpunit.xml.dist @@ -0,0 +1,33 @@ + + + + + + + + ./Tests + + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + diff --git a/src/Oro/Bundle/GridBundle/Datagrid/Datagrid.php b/src/Oro/Bundle/GridBundle/Datagrid/Datagrid.php index 4eb43e01489..587edac3870 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/Datagrid.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/Datagrid.php @@ -52,6 +52,13 @@ class Datagrid implements DatagridInterface */ protected $parametersApplied = false; + /** + * Pager applied flag + * + * @var bool + */ + protected $pagerApplied = false; + /** * @var RouteGeneratorInterface */ @@ -320,10 +327,16 @@ protected function applySorters() */ protected function applyPager() { + if ($this->pagerApplied) { + return; + } + $pagerParameters = $this->parameters->get(ParametersInterface::PAGER_PARAMETERS); $this->pager->setPage(isset($pagerParameters['_page']) ? $pagerParameters['_page'] : 1); $this->pager->setMaxPerPage(!empty($pagerParameters['_per_page']) ? $pagerParameters['_per_page'] : 10); $this->pager->init(); + + $this->pagerApplied = true; } /** diff --git a/src/Oro/Bundle/GridBundle/Datagrid/DatagridManager.php b/src/Oro/Bundle/GridBundle/Datagrid/DatagridManager.php index 010d4371142..60c80471d13 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/DatagridManager.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/DatagridManager.php @@ -37,6 +37,11 @@ abstract class DatagridManager implements DatagridManagerInterface */ protected $translator; + /** + * @var string + */ + protected $translationDomain; + /** * @var ValidatorInterface */ @@ -104,6 +109,14 @@ public function setTranslator(TranslatorInterface $translator) $this->translator = $translator; } + /** + * {@inheritDoc} + */ + public function setTranslationDomain($translationDomain) + { + $this->translationDomain = $translationDomain; + } + /** * {@inheritDoc} */ @@ -217,7 +230,16 @@ public function getDatagrid() */ protected function createQuery() { - return $this->queryFactory->createQuery(); + $query = $this->queryFactory->createQuery(); + $this->prepareQuery($query); + return $query; + } + + /** + * @param ProxyQueryInterface $query + */ + protected function prepareQuery(ProxyQueryInterface $query) + { } /** @@ -259,7 +281,6 @@ protected function getFieldDescriptionCollection() */ protected function configureFields(FieldDescriptionCollection $fieldCollection) { - } /** @@ -385,4 +406,19 @@ protected function getDefaultPager() { return array(); } + + /** + * @param string $id + * @param array $parameters + * @param string $domain + * @return string + */ + protected function translate($id, array $parameters = array(), $domain = null) + { + if (!$domain) { + $domain = $this->translationDomain; + } + + return $this->translator->trans($id, $parameters, $domain); + } } diff --git a/src/Oro/Bundle/GridBundle/Datagrid/DatagridManagerInterface.php b/src/Oro/Bundle/GridBundle/Datagrid/DatagridManagerInterface.php index 194eadede72..98a2e17efde 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/DatagridManagerInterface.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/DatagridManagerInterface.php @@ -59,6 +59,12 @@ public function setQueryFactory(QueryFactoryInterface $queryManager); */ public function setTranslator(TranslatorInterface $translator); + /** + * @param string $translationDomain + * @return void + */ + public function setTranslationDomain($translationDomain); + /** * @param ValidatorInterface $validator * @return void diff --git a/src/Oro/Bundle/GridBundle/Datagrid/FlexibleDatagridManager.php b/src/Oro/Bundle/GridBundle/Datagrid/FlexibleDatagridManager.php index 06db3e24295..374f6a4881d 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/FlexibleDatagridManager.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/FlexibleDatagridManager.php @@ -39,6 +39,10 @@ abstract class FlexibleDatagridManager extends DatagridManager 'field' => FieldDescriptionInterface::TYPE_DECIMAL, 'filter' => FilterInterface::TYPE_FLEXIBLE_NUMBER, ), + AbstractAttributeType::BACKEND_TYPE_BOOLEAN => array( + 'field' => FieldDescriptionInterface::TYPE_BOOLEAN, + 'filter' => FilterInterface::TYPE_FLEXIBLE_BOOLEAN, + ), AbstractAttributeType::BACKEND_TYPE_INTEGER => array( 'field' => FieldDescriptionInterface::TYPE_INTEGER, 'filter' => FilterInterface::TYPE_FLEXIBLE_NUMBER, @@ -76,9 +80,8 @@ public function setFlexibleManager(FlexibleManager $flexibleManager) { $this->flexibleManager = $flexibleManager; - // TODO: somehow get locale and scope from parameters interface - $this->flexibleManager->setLocale('en_US'); - $this->flexibleManager->setScope('ecommerce'); + $this->flexibleManager->setLocale($this->parameters->getLocale()); + $this->flexibleManager->setScope($this->parameters->getScope()); } /** @@ -112,12 +115,14 @@ protected function configureFlexibleField( $attributeCode, array $options = array() ) { - $fieldsCollection->add( - $this->createFlexibleField( - $this->getFlexibleAttribute($attributeCode), - $options - ) - ); + if ($this->hasFlexibleAttribute($attributeCode)) { + $fieldsCollection->add( + $this->createFlexibleField( + $this->getFlexibleAttribute($attributeCode), + $options + ) + ); + } } /** @@ -192,7 +197,7 @@ protected function getFlexibleAttributes() } /** - * @param $code + * @param string $code * @return AbstractAttribute * @throws \LogicException */ @@ -206,6 +211,17 @@ protected function getFlexibleAttribute($code) return $attributes[$code]; } + /** + * @param string $code + * @return boolean + */ + protected function hasFlexibleAttribute($code) + { + $attributes = $this->getFlexibleAttributes(); + + return isset($attributes[$code]); + } + /** * @param $flexibleFieldType * @return string diff --git a/src/Oro/Bundle/GridBundle/Datagrid/ORM/ProxyQuery.php b/src/Oro/Bundle/GridBundle/Datagrid/ORM/ProxyQuery.php index ad2d46bbfd2..b79be51cbef 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/ORM/ProxyQuery.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/ORM/ProxyQuery.php @@ -4,11 +4,16 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\Query; +use Doctrine\ORM\AbstractQuery; use Sonata\DoctrineORMAdminBundle\Datagrid\ProxyQuery as BaseProxyQuery; use Oro\Bundle\GridBundle\Datagrid\ProxyQueryInterface; +/** + * @SuppressWarnings(PHPMD) + * TODO: This class should be refactored (BAP-969). + */ class ProxyQuery extends BaseProxyQuery implements ProxyQueryInterface { /** @@ -36,6 +41,11 @@ class ProxyQuery extends BaseProxyQuery implements ProxyQueryInterface */ protected $selectWhitelist = array(); + /** + * @var array + */ + protected $queryHints = array(); + /** * Get query builder * @@ -58,7 +68,9 @@ public function getTotalCount() $qb->setMaxResults(null); $qb->resetDQLPart('orderBy'); - $ids = $qb->getQuery()->execute(); + $query = $qb->getQuery(); + $this->applyQueryHints($query); + $ids = $query->execute(); return count($ids); } @@ -69,6 +81,7 @@ public function getTotalCount() public function execute(array $params = array(), $hydrationMode = null) { $query = $this->getResultQueryBuilder()->getQuery(); + $this->applyQueryHints($query); return $query->execute($params, $hydrationMode); } @@ -202,6 +215,7 @@ protected function getResultIds() $idx = array(); $query = $this->getResultIdsQueryBuilder()->getQuery(); + $this->applyQueryHints($query); $results = $query->execute(array(), Query::HYDRATE_ARRAY); $connection = $this->getQueryBuilder()->getEntityManager()->getConnection(); @@ -306,7 +320,7 @@ public function entityJoin(array $associationMappings) * * @return string */ - protected function getRootAlias() + public function getRootAlias() { if (!$this->rootAlias) { $this->rootAlias = current($this->getQueryBuilder()->getRootAliases()); @@ -408,9 +422,36 @@ public function addSelect($select = null, $addToWhitelist = false) * * @param string $name * @param mixed $value + * @return ProxyQuery */ public function setParameter($name, $value) { $this->getQueryBuilder()->setParameter($name, $value); + + return $this; + } + + /** + * Sets a query hint + * + * @param string $name + * @param mixed $value + * @return ProxyQuery + */ + public function setQueryHint($name, $value) + { + $this->queryHints[$name] = $value; + + return $this; + } + + /** + * @param AbstractQuery $query + */ + protected function applyQueryHints(AbstractQuery $query) + { + foreach ($this->queryHints as $name => $value) { + $query->setHint($name, $value); + } } } diff --git a/src/Oro/Bundle/GridBundle/Datagrid/ORM/QueryFactory/AbstractQueryFactory.php b/src/Oro/Bundle/GridBundle/Datagrid/ORM/QueryFactory/AbstractQueryFactory.php index 493f957fad9..9d1b8d5cd9c 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/ORM/QueryFactory/AbstractQueryFactory.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/ORM/QueryFactory/AbstractQueryFactory.php @@ -14,9 +14,9 @@ abstract class AbstractQueryFactory implements QueryFactoryInterface */ protected $queryBuilder; - /** * @return ProxyQueryInterface + * @throws \LogicException */ public function createQuery() { diff --git a/src/Oro/Bundle/GridBundle/Datagrid/ParametersInterface.php b/src/Oro/Bundle/GridBundle/Datagrid/ParametersInterface.php index 0f25cb2f61c..9c7028fb9db 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/ParametersInterface.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/ParametersInterface.php @@ -8,6 +8,7 @@ interface ParametersInterface const SORT_PARAMETERS = '_sort_by'; const PAGER_PARAMETERS = '_pager'; const ADDITIONAL_PARAMETERS = '_parameters'; + const SCOPE_PARAMETER = '_scope'; /** * Get parameter value from parameters container @@ -29,4 +30,14 @@ public function set($type, $value); * @return array */ public function toArray(); + + /** + * @return string + */ + public function getLocale(); + + /** + * @return string + */ + public function getScope(); } diff --git a/src/Oro/Bundle/GridBundle/Datagrid/ProxyQueryInterface.php b/src/Oro/Bundle/GridBundle/Datagrid/ProxyQueryInterface.php index c9506137e00..41dd3f0f5d9 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/ProxyQueryInterface.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/ProxyQueryInterface.php @@ -39,6 +39,23 @@ public function addSelect($select = null, $addToWhitelist = false); * * @param string $name * @param mixed $value + * @return ProxyQueryInterface */ public function setParameter($name, $value); + + /** + * Gets the root alias of the query + * + * @return string + */ + public function getRootAlias(); + + /** + * Sets a query hint + * + * @param string $name + * @param mixed $value + * @return ProxyQueryInterface + */ + public function setQueryHint($name, $value); } diff --git a/src/Oro/Bundle/GridBundle/Datagrid/RequestParameters.php b/src/Oro/Bundle/GridBundle/Datagrid/RequestParameters.php index 3ce83805b0e..048779e5ce1 100644 --- a/src/Oro/Bundle/GridBundle/Datagrid/RequestParameters.php +++ b/src/Oro/Bundle/GridBundle/Datagrid/RequestParameters.php @@ -109,4 +109,21 @@ public function toArray() return $result; } + + /** + * @return string + */ + public function getLocale() + { + return $this->getRequest()->getLocale(); + } + + /** + * @return string + */ + public function getScope() + { + $rootValue = $this->getRootParameterValue(); + return isset($rootValue[self::SCOPE_PARAMETER]) ? $rootValue[self::SCOPE_PARAMETER] : null; + } } diff --git a/src/Oro/Bundle/GridBundle/DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php b/src/Oro/Bundle/GridBundle/DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php index c223969a8a1..bee9166b5b6 100644 --- a/src/Oro/Bundle/GridBundle/DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php +++ b/src/Oro/Bundle/GridBundle/DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php @@ -5,20 +5,25 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException; +use Oro\Bundle\GridBundle\DependencyInjection\OroGridExtension; + class AddDependencyCallsCompilerPass extends AbstractDatagridManagerCompilerPass { - const QUERY_FACTORY_ATTRIBUTE = 'query_factory'; - const ROUTE_GENERATOR_ATTRIBUTE = 'route_generator'; - const DATAGRID_BUILDER_ATTRIBUTE = 'datagrid_builder'; - const LIST_BUILDER_ATTRIBUTE = 'list_builder'; - const PARAMETERS_ATTRIBUTE = 'parameters'; - const TRANSLATOR_ATTRIBUTE = 'translator'; - const VALIDATOR_ATTRIBUTE = 'validator'; - const ROUTER_ATTRIBUTE = 'router'; + const QUERY_FACTORY_ATTRIBUTE = 'query_factory'; + const ROUTE_GENERATOR_ATTRIBUTE = 'route_generator'; + const DATAGRID_BUILDER_ATTRIBUTE = 'datagrid_builder'; + const LIST_BUILDER_ATTRIBUTE = 'list_builder'; + const PARAMETERS_ATTRIBUTE = 'parameters'; + const TRANSLATOR_ATTRIBUTE = 'translator'; + const TRANSLATION_DOMAIN_ATTRIBUTE = 'translation_domain'; + const VALIDATOR_ATTRIBUTE = 'validator'; + const ROUTER_ATTRIBUTE = 'router'; + const ENTITY_HINT_ATTRIBUTE = 'entity_hint'; /** * {@inheritDoc} @@ -34,7 +39,10 @@ public function processDatagrid() */ protected function applyConfigurationFromAttributes() { - $keys = array( + $this->definition->addMethodCall('setName', array($this->getMandatoryAttribute('datagrid_name'))); + + // add services + $serviceKeys = array( self::QUERY_FACTORY_ATTRIBUTE, self::ROUTE_GENERATOR_ATTRIBUTE, self::DATAGRID_BUILDER_ATTRIBUTE, @@ -45,7 +53,7 @@ protected function applyConfigurationFromAttributes() self::ROUTER_ATTRIBUTE, ); - foreach ($keys as $key) { + foreach ($serviceKeys as $key) { $method = 'set' . $this->camelize($key); if (!$this->hasAttribute($key) || $this->definition->hasMethodCall($method)) { continue; @@ -54,10 +62,19 @@ protected function applyConfigurationFromAttributes() $this->definition->addMethodCall($method, array(new Reference($this->getAttribute($key)))); } - $this->definition->addMethodCall('setName', array($this->getMandatoryAttribute('datagrid_name'))); + // add other attributes + $attributeKeys = array( + self::ENTITY_HINT_ATTRIBUTE, + self::TRANSLATION_DOMAIN_ATTRIBUTE + ); + + foreach ($attributeKeys as $key) { + $method = 'set' . $this->camelize($key); + if (!$this->hasAttribute($key) || $this->definition->hasMethodCall($method)) { + continue; + } - if ($this->hasAttribute('entity_hint')) { - $this->definition->addMethodCall('setEntityHint', array($this->getAttribute('entity_hint'))); + $this->definition->addMethodCall($method, array($this->getAttribute($key))); } } @@ -68,6 +85,7 @@ protected function applyDefaults() { $this->definition->setScope(ContainerInterface::SCOPE_PROTOTYPE); + // add default services $defaultAddServices = array( self::QUERY_FACTORY_ATTRIBUTE => array($this, 'getDefaultQueryFactoryServiceId'), self::ROUTE_GENERATOR_ATTRIBUTE => array($this, 'getDefaultRouteGeneratorServiceId'), @@ -89,6 +107,19 @@ protected function applyDefaults() $this->definition->addMethodCall($method, array(new Reference($serviceId))); } } + + // add default parameters + $defaultAddParameters = array( + self::TRANSLATION_DOMAIN_ATTRIBUTE => OroGridExtension::PARAMETER_TRANSLATION_DOMAIN + ); + + foreach ($defaultAddParameters as $attribute => $parameterId) { + $method = 'set' . $this->camelize($attribute); + + if (!$this->definition->hasMethodCall($method)) { + $this->definition->addMethodCall($method, array(new Parameter($parameterId))); + } + } } /** diff --git a/src/Oro/Bundle/GridBundle/DependencyInjection/Configuration.php b/src/Oro/Bundle/GridBundle/DependencyInjection/Configuration.php index 848cc1c6d68..e0b0e417db4 100644 --- a/src/Oro/Bundle/GridBundle/DependencyInjection/Configuration.php +++ b/src/Oro/Bundle/GridBundle/DependencyInjection/Configuration.php @@ -7,13 +7,23 @@ class Configuration implements ConfigurationInterface { + const TRANSLATION_DOMAIN_NODE = 'translation_domain'; + const DEFAULT_TRANSLATION_DOMAIN = 'datagrid'; + /** * {@inheritDoc} */ public function getConfigTreeBuilder() { $treeBuilder = new TreeBuilder(); - $treeBuilder->root('oro_grid'); + $rootNode = $treeBuilder->root('oro_grid'); + + $rootNode + ->children() + ->scalarNode(self::TRANSLATION_DOMAIN_NODE) + ->cannotBeEmpty() + ->defaultValue(self::DEFAULT_TRANSLATION_DOMAIN) + ->end(); return $treeBuilder; } diff --git a/src/Oro/Bundle/GridBundle/DependencyInjection/OroGridExtension.php b/src/Oro/Bundle/GridBundle/DependencyInjection/OroGridExtension.php index 81291eb232c..6be455fe818 100644 --- a/src/Oro/Bundle/GridBundle/DependencyInjection/OroGridExtension.php +++ b/src/Oro/Bundle/GridBundle/DependencyInjection/OroGridExtension.php @@ -10,6 +10,8 @@ class OroGridExtension extends Extension { + const PARAMETER_TRANSLATION_DOMAIN = 'oro_grid.translation.translation_domain'; + /** * {@inheritdoc} */ @@ -18,6 +20,8 @@ public function load(array $configs, ContainerBuilder $container) $configuration = new Configuration(); $config = $this->processConfiguration($configuration, $configs); + $container->setParameter(self::PARAMETER_TRANSLATION_DOMAIN, $config[Configuration::TRANSLATION_DOMAIN_NODE]); + $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.yml'); $loader->load('orm_filter_types.yml'); diff --git a/src/Oro/Bundle/GridBundle/Field/FieldDescription.php b/src/Oro/Bundle/GridBundle/Field/FieldDescription.php index f125d9628da..5ac826dd3bb 100644 --- a/src/Oro/Bundle/GridBundle/Field/FieldDescription.php +++ b/src/Oro/Bundle/GridBundle/Field/FieldDescription.php @@ -138,8 +138,6 @@ public function setOptions(array $options) // set the field_name if provided if (isset($options['field_name'])) { $this->setFieldName($options['field_name']); - // TODO Cannot unset option because it is used by filter! - //unset($options['field_name']); } // remove property value @@ -153,7 +151,7 @@ public function setOptions(array $options) $this->setFieldMapping($options['field_mapping']); } else { $fieldMapping = array( - 'fieldName' => $this->getFieldName() + 'fieldName' => $this->getFieldName(), ); if (isset($options['entity_alias'])) { $fieldMapping['entityAlias'] = $options['entity_alias']; @@ -161,6 +159,12 @@ public function setOptions(array $options) if (isset($options['expression'])) { $fieldMapping['fieldExpression'] = $options['expression']; } + if (isset($options['filter_by_where'])) { + $fieldMapping['filterByWhere'] = $options['filter_by_where']; + } + if (isset($options['filter_by_having'])) { + $fieldMapping['filterByHaving'] = $options['filter_by_having']; + } $this->setFieldMapping($fieldMapping); $options['field_mapping'] = $fieldMapping; } diff --git a/src/Oro/Bundle/GridBundle/Filter/FilterInterface.php b/src/Oro/Bundle/GridBundle/Filter/FilterInterface.php index 5d38ff3615d..c2cc47f9d28 100644 --- a/src/Oro/Bundle/GridBundle/Filter/FilterInterface.php +++ b/src/Oro/Bundle/GridBundle/Filter/FilterInterface.php @@ -15,9 +15,11 @@ interface FilterInterface extends BaseFilterInterface const TYPE_STRING = 'oro_grid_orm_string'; const TYPE_CHOICE = 'oro_grid_orm_choice'; const TYPE_BOOLEAN = 'oro_grid_orm_boolean'; + const TYPE_ENTITY = 'oro_grid_orm_entity'; const TYPE_FLEXIBLE_DATE = 'oro_grid_orm_flexible_date_range'; const TYPE_FLEXIBLE_DATETIME = 'oro_grid_orm_flexible_datetime_range'; const TYPE_FLEXIBLE_NUMBER = 'oro_grid_orm_flexible_number'; + const TYPE_FLEXIBLE_BOOLEAN = 'oro_grid_orm_flexible_boolean'; const TYPE_FLEXIBLE_STRING = 'oro_grid_orm_flexible_string'; const TYPE_FLEXIBLE_OPTIONS = 'oro_grid_orm_flexible_options'; diff --git a/src/Oro/Bundle/GridBundle/Filter/ORM/AbstractFilter.php b/src/Oro/Bundle/GridBundle/Filter/ORM/AbstractFilter.php index 04d52f29956..8ee35c43abf 100644 --- a/src/Oro/Bundle/GridBundle/Filter/ORM/AbstractFilter.php +++ b/src/Oro/Bundle/GridBundle/Filter/ORM/AbstractFilter.php @@ -76,7 +76,13 @@ protected function applyFilterToClause(ProxyQueryInterface $queryBuilder, $expre protected function isApplyFilterToHavingClause() { $fieldMapping = $this->getFieldMapping(); - return !empty($fieldMapping['fieldExpression']); + if (!empty($fieldMapping['filterByHaving'])) { + return true; + } elseif (!empty($fieldMapping['filterByWhere'])) { + return false; + } else { + return !empty($fieldMapping['fieldExpression']); + } } /** diff --git a/src/Oro/Bundle/GridBundle/Filter/ORM/ChoiceFilter.php b/src/Oro/Bundle/GridBundle/Filter/ORM/ChoiceFilter.php index 75776a6b84f..5d992f75a8f 100644 --- a/src/Oro/Bundle/GridBundle/Filter/ORM/ChoiceFilter.php +++ b/src/Oro/Bundle/GridBundle/Filter/ORM/ChoiceFilter.php @@ -3,6 +3,8 @@ namespace Oro\Bundle\GridBundle\Filter\ORM; use Doctrine\DBAL\Query\QueryBuilder; +use Doctrine\Common\Collections\Collection; + use Sonata\AdminBundle\Datagrid\ProxyQueryInterface; use Oro\Bundle\FilterBundle\Form\Type\Filter\ChoiceFilterType; @@ -18,20 +20,24 @@ public function filter(ProxyQueryInterface $queryBuilder, $alias, $field, $data) return; } - $operator = $this->getOperator($data['type']); + $operator = $this->getOperator($data['type']); + $parameter = $this->getName() . '_choices'; if ('IN' == $operator) { $expression = $this->getExpressionFactory()->in( $this->createFieldExpression($field, $alias), - $data['value'] + ':' . $parameter ); } else { $expression = $this->getExpressionFactory()->notIn( $this->createFieldExpression($field, $alias), - $data['value'] + ':' . $parameter ); } + $this->applyFilterToClause($queryBuilder, $expression); + /** @var $queryBuilder QueryBuilder */ + $queryBuilder->setParameter($parameter, $data['value']); } /** @@ -44,16 +50,22 @@ public function parseData($data) || !array_key_exists('value', $data) || $data['value'] === '' || is_null($data['value']) - || (is_array($data['value']) && !count($data['value'])) + || ((is_array($data['value']) || $data['value'] instanceof Collection) && !count($data['value'])) ) { return false; } - if (!is_array($data['value'])) { - $data['value'] = array($data['value']); + $value = $data['value']; + + if ($value instanceof Collection) { + $value = $value->getValues(); + } + if (!is_array($value)) { + $value = array($value); } - $data['type'] = isset($data['type']) ? $data['type'] : null; + $data['type'] = isset($data['type']) ? $data['type'] : null; + $data['value'] = $value; return $data; } diff --git a/src/Oro/Bundle/GridBundle/Filter/ORM/EntityFilter.php b/src/Oro/Bundle/GridBundle/Filter/ORM/EntityFilter.php new file mode 100644 index 00000000000..3ee95c08f7f --- /dev/null +++ b/src/Oro/Bundle/GridBundle/Filter/ORM/EntityFilter.php @@ -0,0 +1,41 @@ + EntityFilterType::NAME + ); + } + + /** + * {@inheritdoc} + */ + public function getRenderSettings() + { + list($formType, $formOptions) = parent::getRenderSettings(); + + // proxy for entity form type options + foreach (array('class', 'property', 'query_builder') as $option) { + $optionValue = $this->getOption($option); + if ($optionValue) { + $formOptions['field_options'][$option] = $optionValue; + } + } + + $translatable = $this->getOption('translatable'); + if ($translatable) { + $formOptions['translatable'] = $translatable; + } + + return array($formType, $formOptions); + } +} diff --git a/src/Oro/Bundle/GridBundle/Filter/ORM/Flexible/FlexibleBooleanFilter.php b/src/Oro/Bundle/GridBundle/Filter/ORM/Flexible/FlexibleBooleanFilter.php new file mode 100644 index 00000000000..761b0fa1461 --- /dev/null +++ b/src/Oro/Bundle/GridBundle/Filter/ORM/Flexible/FlexibleBooleanFilter.php @@ -0,0 +1,33 @@ +parentFilter->parseData($data); + if (!$data) { + return; + } + + $value = ($data['value'] == BooleanFilterType::TYPE_YES) ? 1 : 0; + + $this->applyFlexibleFilter($proxyQuery, $field, $value, '='); + } +} diff --git a/src/Oro/Bundle/GridBundle/Property/UrlProperty.php b/src/Oro/Bundle/GridBundle/Property/UrlProperty.php index d342bc03c4c..b4f98cfd10c 100644 --- a/src/Oro/Bundle/GridBundle/Property/UrlProperty.php +++ b/src/Oro/Bundle/GridBundle/Property/UrlProperty.php @@ -32,6 +32,11 @@ class UrlProperty extends AbstractProperty */ protected $isAbsolute; + /** + * @var string + */ + protected $anchor; + /** * @param string $name * @param Router $router @@ -39,13 +44,14 @@ class UrlProperty extends AbstractProperty * @param array $placeholders * @param bool $isAbsolute */ - public function __construct($name, Router $router, $routeName, array $placeholders = array(), $isAbsolute = false) + public function __construct($name, Router $router, $routeName, array $placeholders = array(), $isAbsolute = false, $anchor = null) { $this->name = $name; $this->router = $router; $this->routeName = $routeName; $this->placeholders = $placeholders; $this->isAbsolute = $isAbsolute; + $this->anchor = $anchor; } /** @@ -53,7 +59,8 @@ public function __construct($name, Router $router, $routeName, array $placeholde */ public function getValue(ResultRecordInterface $record) { - return $this->router->generate($this->routeName, $this->getParameters($record), $this->isAbsolute); + $route = $this->router->generate($this->routeName, $this->getParameters($record), $this->isAbsolute); + return $route . $this->anchor; } /** diff --git a/src/Oro/Bundle/GridBundle/Resources/config/orm_filter_types.yml b/src/Oro/Bundle/GridBundle/Resources/config/orm_filter_types.yml index ba9120d8b89..d3d514f2030 100644 --- a/src/Oro/Bundle/GridBundle/Resources/config/orm_filter_types.yml +++ b/src/Oro/Bundle/GridBundle/Resources/config/orm_filter_types.yml @@ -35,12 +35,24 @@ services: tags: - { name: oro_grid.filter.type, alias: oro_grid_orm_boolean } + oro_grid.orm.filter.type.entity: + class: Oro\Bundle\GridBundle\Filter\ORM\EntityFilter + arguments: ["@translator"] + tags: + - { name: oro_grid.filter.type, alias: oro_grid_orm_entity } + oro_grid.orm.filter.type.flexible_number: class: Oro\Bundle\GridBundle\Filter\ORM\Flexible\FlexibleNumberFilter arguments: ["@oro_flexibleentity.registry", "@oro_grid.orm.filter.type.number"] tags: - { name: oro_grid.filter.type, alias: oro_grid_orm_flexible_number } + oro_grid.orm.filter.type.flexible_boolean: + class: Oro\Bundle\GridBundle\Filter\ORM\Flexible\FlexibleBooleanFilter + arguments: ["@oro_flexibleentity.registry", "@oro_grid.orm.filter.type.boolean"] + tags: + - { name: oro_grid.filter.type, alias: oro_grid_orm_flexible_boolean } + oro_grid.orm.filter.type.flexible_string: class: Oro\Bundle\GridBundle\Filter\ORM\Flexible\FlexibleStringFilter arguments: ["@oro_flexibleentity.registry", "@oro_grid.orm.filter.type.string"] diff --git a/src/Oro/Bundle/GridBundle/Resources/config/placeholders.yml b/src/Oro/Bundle/GridBundle/Resources/config/placeholders.yml new file mode 100644 index 00000000000..4a96a1d01e1 --- /dev/null +++ b/src/Oro/Bundle/GridBundle/Resources/config/placeholders.yml @@ -0,0 +1,9 @@ +placeholders: + prepare_grid: + label: Prepare grid tempaltes + items: + datagrid: + order: 100 +items: + datagrid: + template: OroGridBundle:Include:datagrid.html.twig diff --git a/src/Oro/Bundle/GridBundle/Resources/doc/index.md b/src/Oro/Bundle/GridBundle/Resources/doc/index.md index 96462ab2add..c11e32a1df0 100644 --- a/src/Oro/Bundle/GridBundle/Resources/doc/index.md +++ b/src/Oro/Bundle/GridBundle/Resources/doc/index.md @@ -22,6 +22,7 @@ OroGridBundle Documentation - [Route Generator](./reference/backend/route-generator.md) - [Grid Rendering](./reference/backend/grid-rendering.md) - [Events](./reference/backend/events.md) + - [Translations](./reference/backend/translations.md) - **Frontend Architecture** - [Overview](./reference/frontend/overview.md) - [Backbone Developer Introduction](./reference/frontend/backbone-developer-introduction.md) diff --git a/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/filters.md b/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/filters.md index 56ede129388..c8223605fd1 100644 --- a/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/filters.md +++ b/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/filters.md @@ -17,6 +17,8 @@ Flexible filters are used to apply filters to flexible attributes in flexible en * **Filter \ ORM \ NumberFilter** - ORM filter for number values; * **Filter \ ORM \ StringFilter** - ORM filter for string values; * **Filter \ ORM \ ChoiceFilter** - ORM filter which allows to use choices (single or multiple); +* **Filter \ ORM \ EntityFilter** - ORM choices filter based on Symfony entity field type and allows to use +entity repository or query builder as choices data source; * **Filter \ ORM \ BooleanFilter** - ORM filter which allows to filter data as boolean value; * **Filter \ ORM \ AbstractDateFilter** - abstract filter implementation to work with date/datetime values; * **Filter \ ORM \ DateRangeFilter** - ORM filter for date and date range values; @@ -86,6 +88,12 @@ services: tags: - { name: oro_grid.filter.type, alias: oro_grid_orm_boolean } + oro_grid.orm.filter.type.entity: + class: Oro\Bundle\GridBundle\Filter\ORM\EntityFilter + arguments: ["@translator"] + tags: + - { name: oro_grid.filter.type, alias: oro_grid_orm_entity } + oro_grid.orm.filter.type.flexible_number: class: Oro\Bundle\GridBundle\Filter\ORM\Flexible\FlexibleNumberFilter arguments: ["@oro_flexibleentity.registry", "@oro_grid.orm.filter.type.number"] diff --git a/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/translations.md b/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/translations.md new file mode 100644 index 00000000000..0697616c5db --- /dev/null +++ b/src/Oro/Bundle/GridBundle/Resources/doc/reference/backend/translations.md @@ -0,0 +1,40 @@ +Translations +------------ + +OroGridBundle provides translation mechanism which can translate localized information (column and row action labels). + +DatagridManager contains translator object and translation domain and provides method _translate_ +which use translator object to perform translation. Default translation domain is "datagrid". + +#### Configuration + +**Translator and translation domain configuration** + +Datagrid manager can customize translator service and translation domain. + +``` +services: + orocrm_contact.contact.datagrid_manager: + class: %orocrm_contact.contact.datagrid_manager.class% + tags: + - name: oro_grid.datagrid.manager + ... + translator: acme_demobundle.custom_translator + translation_domain: acme_datagrid +``` + +**Default translation domain configuration** + +Default translation domain can be customized in main configuration. + +``` +oro_grid: + translation_domain: acme_datagrid +``` + +Another way to customize default translation domain is to set it as parameter in some specific bundle configuration. + +``` +parameters: + oro_grid.translation.translation_domain: acme_datagrid +``` diff --git a/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/deleteaction.js b/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/deleteaction.js index 9ef550eda95..765ee77cfc7 100644 --- a/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/deleteaction.js +++ b/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/deleteaction.js @@ -35,9 +35,9 @@ Oro.Datagrid.Action.DeleteAction = Oro.Datagrid.Action.ModelAction.extend({ self.getErrorDialog().open(); }, success: function() { - var messageText = 'Item was deleted'; - if (!_.isUndefined(Oro.Messages)) { - Oro.Messages.showMessage('success', messageText); + var messageText = Translator.get('Item was deleted'); + if (!_.isUndefined(Oro.NotificationFlashMessage)) { + Oro.NotificationFlashMessage('success', messageText); } else { alert(messageText); } @@ -53,8 +53,8 @@ Oro.Datagrid.Action.DeleteAction = Oro.Datagrid.Action.ModelAction.extend({ getConfirmDialog: function() { if (!this.confirmModal) { this.confirmModal = new Oro.BootstrapModal({ - title: 'Delete Confirmation', - content: 'Are you sure you want to delete this item?', + title: Translator.get('Delete Confirmation'), + content: Translator.get('Are you sure you want to delete this item?'), okText: 'Yes, Delete', allowCancel: 'false' }); diff --git a/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/launcher.js b/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/launcher.js index e096a478f7c..a6d69ddc1db 100644 --- a/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/launcher.js +++ b/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/launcher.js @@ -166,6 +166,9 @@ Oro.Datagrid.Action.Launcher = Backbone.View.extend({ this.trigger('click', this); if (this.runAction) { this.action.run(); + + // skip launcher functionality, if action was executed + return false; } return this.onClickReturnValue; }, diff --git a/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/navigateaction.js b/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/navigateaction.js index ade409877f1..c73a2456cf4 100644 --- a/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/navigateaction.js +++ b/src/Oro/Bundle/GridBundle/Resources/public/js/app/datagrid/action/navigateaction.js @@ -31,6 +31,8 @@ Oro.Datagrid.Action.NavigateAction = Oro.Datagrid.Action.ModelAction.extend({ this.useDirectLauncherLink = options.useDirectLauncherLink; } + this.on('preExecute', _.bind(this._preExecuteSubscriber, this)); + if (this.useDirectLauncherLink) { this.launcherOptions = _.extend({ link: this.getLink(), @@ -43,10 +45,15 @@ Oro.Datagrid.Action.NavigateAction = Oro.Datagrid.Action.ModelAction.extend({ * Execute redirect */ execute: function() { - if (Oro.hashNavigationEnabled()) { - Oro.Navigation.prototype.setLocation(this.getLink()); - } else { - window.location.href = this.getLink(); - } + window.location.href = this.getLink(); + }, + + /** + * Trigger global event + * + * @private + */ + _preExecuteSubscriber: function(action, options) { + Oro.Events.trigger('grid_action:navigateAction:preExecute', action, options); } }); diff --git a/src/Oro/Bundle/GridBundle/Resources/translations/OroGridBundle.en.xliff b/src/Oro/Bundle/GridBundle/Resources/translations/OroGridBundle.en.xliff index 113d2a1fe77..5024b1ee64c 100644 --- a/src/Oro/Bundle/GridBundle/Resources/translations/OroGridBundle.en.xliff +++ b/src/Oro/Bundle/GridBundle/Resources/translations/OroGridBundle.en.xliff @@ -2,42 +2,6 @@ - - oro_grid.button.filter - Filter - - - oro_grid.button.reset - Reset - - - oro_grid.link.sort_desc - Sort descending - - - oro_grid.link.sort_asc - Sort ascending - - - oro_grid.list_results_count - 1 result|%count% results - - - oro_grid.label_per_page - Per page - - - oro_grid.all_elements - All elements - - - oro_grid.label_export_download - Download - - - oro_grid.btn_batch - OK - oro_grid.no_data_hint %entityHint% No %entityHint% were found to match your search. diff --git a/src/Oro/Bundle/GridBundle/Resources/views/Include/datagrid.html.twig b/src/Oro/Bundle/GridBundle/Resources/views/Include/datagrid.html.twig new file mode 100644 index 00000000000..b68d1c41623 --- /dev/null +++ b/src/Oro/Bundle/GridBundle/Resources/views/Include/datagrid.html.twig @@ -0,0 +1,5 @@ +{% include 'OroGridBundle:Include:javascript.html.twig' with {'datagridView': datagrid, 'selector': selector} %} +{% include 'OroGridBundle:Include:stylesheet.html.twig' %} +{% if parameters is defined and parameters|length %} + {% include 'OroGridBundle:Include:Listener/column_form.html.twig' with {'datagridView': datagrid, 'parameters': parameters} %} +{% endif %} diff --git a/src/Oro/Bundle/GridBundle/Resources/views/Include/javascript.html.twig b/src/Oro/Bundle/GridBundle/Resources/views/Include/javascript.html.twig index ef2fae5e912..89c8f90dbca 100644 --- a/src/Oro/Bundle/GridBundle/Resources/views/Include/javascript.html.twig +++ b/src/Oro/Bundle/GridBundle/Resources/views/Include/javascript.html.twig @@ -4,7 +4,7 @@ {% set form = datagridView.formView %} +{% endoro_js %} diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig index c66574ccedb..da25244e89f 100644 --- a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/hashNavAjax.html.twig @@ -1,23 +1,14 @@ - - -
- {{ messages|raw }} -
-
- {{ oro_menu_render('history') }} -
-
- {{ oro_menu_render('mostviewed') }} -
-
- {{ content|raw }} -
-
- {% if app.request.attributes.get('_route') == bap.start_route %}false{% else %}true{% endif %} -
+{% spaceless %} +{% set data = { + 'title': oro_title_render(), + 'titleSerialized': oro_title_render_serialized(), + 'scripts': script, + 'mainMenu': menu, + 'flashMessages': app.session.flashbag.all, + 'history': oro_menu_render('history'), + 'mostviewed': oro_menu_render('mostviewed'), + 'content': content, + 'showPinButton': (app.request.attributes.get('_route') != bap.start_route) +} %} +{{ data|json_encode|raw }} +{% endspaceless %} \ No newline at end of file diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/redirect.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/redirect.html.twig index 967c49204f6..a8c000750f6 100644 --- a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/redirect.html.twig +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/redirect.html.twig @@ -1 +1,6 @@ -
{{ location }}
\ No newline at end of file +{% set data = { + 'redirect': true, + 'fullRedirect': full_redirect, + 'location': location +} %} +{{ data|json_encode|raw }} \ No newline at end of file diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/script.js.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/script.js.twig new file mode 100644 index 00000000000..04bfe833335 --- /dev/null +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/HashNav/script.js.twig @@ -0,0 +1,10 @@ + diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/Js/navigationItem.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/Js/navigationItem.html.twig new file mode 100644 index 00000000000..e2cb57efa2e --- /dev/null +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/Js/navigationItem.html.twig @@ -0,0 +1,3 @@ + diff --git a/src/Oro/Bundle/UIBundle/Resources/views/Menu/application_menu.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/application_menu.html.twig similarity index 100% rename from src/Oro/Bundle/UIBundle/Resources/views/Menu/application_menu.html.twig rename to src/Oro/Bundle/NavigationBundle/Resources/views/Menu/application_menu.html.twig diff --git a/src/Oro/Bundle/UIBundle/Resources/views/Menu/dots_menu.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/dots_menu.html.twig similarity index 100% rename from src/Oro/Bundle/UIBundle/Resources/views/Menu/dots_menu.html.twig rename to src/Oro/Bundle/NavigationBundle/Resources/views/Menu/dots_menu.html.twig diff --git a/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/menuProfile.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/menuProfile.html.twig new file mode 100644 index 00000000000..a2060171c88 --- /dev/null +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/menuProfile.html.twig @@ -0,0 +1,8 @@ +{% if app.user %} + +{% else %} +
  • Login
  • +{% endif %} diff --git a/src/Oro/Bundle/UIBundle/Resources/views/Menu/shortcuts.html.twig b/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/shortcuts.html.twig similarity index 75% rename from src/Oro/Bundle/UIBundle/Resources/views/Menu/shortcuts.html.twig rename to src/Oro/Bundle/NavigationBundle/Resources/views/Menu/shortcuts.html.twig index af15e6a1cad..d8cf132c458 100644 --- a/src/Oro/Bundle/UIBundle/Resources/views/Menu/shortcuts.html.twig +++ b/src/Oro/Bundle/NavigationBundle/Resources/views/Menu/shortcuts.html.twig @@ -14,23 +14,23 @@