1<?php 2 3/* 4 * This file is part of the Symfony package. 5 * 6 * (c) Fabien Potencier <fabien@symfony.com> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Symfony\Component\Intl\Data\Generator; 13 14use Symfony\Component\Intl\Data\Bundle\Compiler\GenrbCompiler; 15use Symfony\Component\Intl\Data\Bundle\Reader\BundleReaderInterface; 16use Symfony\Component\Intl\Data\Util\ArrayAccessibleResourceBundle; 17use Symfony\Component\Intl\Data\Util\LocaleScanner; 18 19/** 20 * The rule for compiling the currency bundle. 21 * 22 * @author Bernhard Schussek <bschussek@gmail.com> 23 * 24 * @internal 25 */ 26class CurrencyDataGenerator extends AbstractDataGenerator 27{ 28 const UNKNOWN_CURRENCY_ID = 'XXX'; 29 const EUROPEAN_COMPOSITE_UNIT_ID = 'XBA'; 30 const EUROPEAN_MONETARY_UNIT_ID = 'XBB'; 31 const EUROPEAN_UNIT_OF_ACCOUNT_XBC_ID = 'XBC'; 32 const EUROPEAN_UNIT_OF_ACCOUNT_XBD_ID = 'XBD'; 33 const TESTING_CURRENCY_CODE_ID = 'XTS'; 34 const ADB_UNIT_OF_ACCOUNT_ID = 'XUA'; 35 const GOLD_ID = 'XAU'; 36 const SILVER_ID = 'XAG'; 37 const PLATINUM_ID = 'XPT'; 38 const PALLADIUM_ID = 'XPD'; 39 const SUCRE_ID = 'XSU'; 40 const SPECIAL_DRAWING_RIGHTS_ID = 'XDR'; 41 42 /** 43 * Monetary units excluded from generation. 44 */ 45 private static $blacklist = array( 46 self::UNKNOWN_CURRENCY_ID => true, 47 self::EUROPEAN_COMPOSITE_UNIT_ID => true, 48 self::EUROPEAN_MONETARY_UNIT_ID => true, 49 self::EUROPEAN_UNIT_OF_ACCOUNT_XBC_ID => true, 50 self::EUROPEAN_UNIT_OF_ACCOUNT_XBD_ID => true, 51 self::TESTING_CURRENCY_CODE_ID => true, 52 self::ADB_UNIT_OF_ACCOUNT_ID => true, 53 self::GOLD_ID => true, 54 self::SILVER_ID => true, 55 self::PLATINUM_ID => true, 56 self::PALLADIUM_ID => true, 57 self::SUCRE_ID => true, 58 self::SPECIAL_DRAWING_RIGHTS_ID => true, 59 ); 60 61 /** 62 * Collects all available currency codes. 63 * 64 * @var string[] 65 */ 66 private $currencyCodes = array(); 67 68 /** 69 * {@inheritdoc} 70 */ 71 protected function scanLocales(LocaleScanner $scanner, $sourceDir) 72 { 73 return $scanner->scanLocales($sourceDir.'/curr'); 74 } 75 76 /** 77 * {@inheritdoc} 78 */ 79 protected function compileTemporaryBundles(GenrbCompiler $compiler, $sourceDir, $tempDir) 80 { 81 $compiler->compile($sourceDir.'/curr', $tempDir); 82 $compiler->compile($sourceDir.'/misc/currencyNumericCodes.txt', $tempDir); 83 } 84 85 /** 86 * {@inheritdoc} 87 */ 88 protected function preGenerate() 89 { 90 $this->currencyCodes = array(); 91 } 92 93 /** 94 * {@inheritdoc} 95 */ 96 protected function generateDataForLocale(BundleReaderInterface $reader, $tempDir, $displayLocale) 97 { 98 $localeBundle = $reader->read($tempDir, $displayLocale); 99 100 if (isset($localeBundle['Currencies']) && null !== $localeBundle['Currencies']) { 101 $data = array( 102 'Version' => $localeBundle['Version'], 103 'Names' => $this->generateSymbolNamePairs($localeBundle), 104 ); 105 106 $this->currencyCodes = array_merge($this->currencyCodes, array_keys($data['Names'])); 107 108 return $data; 109 } 110 } 111 112 /** 113 * {@inheritdoc} 114 */ 115 protected function generateDataForRoot(BundleReaderInterface $reader, $tempDir) 116 { 117 $rootBundle = $reader->read($tempDir, 'root'); 118 119 return array( 120 'Version' => $rootBundle['Version'], 121 'Names' => $this->generateSymbolNamePairs($rootBundle), 122 ); 123 } 124 125 /** 126 * {@inheritdoc} 127 */ 128 protected function generateDataForMeta(BundleReaderInterface $reader, $tempDir) 129 { 130 $rootBundle = $reader->read($tempDir, 'root'); 131 $supplementalDataBundle = $reader->read($tempDir, 'supplementalData'); 132 $numericCodesBundle = $reader->read($tempDir, 'currencyNumericCodes'); 133 134 $this->currencyCodes = array_unique($this->currencyCodes); 135 136 sort($this->currencyCodes); 137 138 $data = array( 139 'Version' => $rootBundle['Version'], 140 'Currencies' => $this->currencyCodes, 141 'Meta' => $this->generateCurrencyMeta($supplementalDataBundle), 142 'Alpha3ToNumeric' => $this->generateAlpha3ToNumericMapping($numericCodesBundle, $this->currencyCodes), 143 ); 144 145 $data['NumericToAlpha3'] = $this->generateNumericToAlpha3Mapping($data['Alpha3ToNumeric']); 146 147 return $data; 148 } 149 150 /** 151 * @return array 152 */ 153 private function generateSymbolNamePairs(ArrayAccessibleResourceBundle $rootBundle) 154 { 155 $symbolNamePairs = iterator_to_array($rootBundle['Currencies']); 156 157 // Remove unwanted currencies 158 $symbolNamePairs = array_diff_key($symbolNamePairs, self::$blacklist); 159 160 return $symbolNamePairs; 161 } 162 163 private function generateCurrencyMeta(ArrayAccessibleResourceBundle $supplementalDataBundle) 164 { 165 // The metadata is already de-duplicated. It contains one key "DEFAULT" 166 // which is used for currencies that don't have dedicated entries. 167 return iterator_to_array($supplementalDataBundle['CurrencyMeta']); 168 } 169 170 private function generateAlpha3ToNumericMapping(ArrayAccessibleResourceBundle $numericCodesBundle, array $currencyCodes) 171 { 172 $alpha3ToNumericMapping = iterator_to_array($numericCodesBundle['codeMap']); 173 174 asort($alpha3ToNumericMapping); 175 176 // Filter unknown currencies (e.g. "AYM") 177 $alpha3ToNumericMapping = array_intersect_key($alpha3ToNumericMapping, array_flip($currencyCodes)); 178 179 return $alpha3ToNumericMapping; 180 } 181 182 private function generateNumericToAlpha3Mapping(array $alpha3ToNumericMapping) 183 { 184 $numericToAlpha3Mapping = array(); 185 186 foreach ($alpha3ToNumericMapping as $alpha3 => $numeric) { 187 // Make sure that the mapping is stored as table and not as array 188 $numeric = (string) $numeric; 189 190 if (!isset($numericToAlpha3Mapping[$numeric])) { 191 $numericToAlpha3Mapping[$numeric] = array(); 192 } 193 194 $numericToAlpha3Mapping[$numeric][] = $alpha3; 195 } 196 197 return $numericToAlpha3Mapping; 198 } 199} 200