1<?php 2 3namespace CommerceGuys\Intl\Currency; 4 5use CommerceGuys\Intl\LocaleResolverTrait; 6use CommerceGuys\Intl\Exception\UnknownCurrencyException; 7 8/** 9 * Manages currencies based on JSON definitions. 10 */ 11class CurrencyRepository implements CurrencyRepositoryInterface 12{ 13 use LocaleResolverTrait; 14 15 /** 16 * Base currency definitions. 17 * 18 * Contains data common to all locales, such as the currency numeric 19 * code, number of fraction digits. 20 * 21 * @var array 22 */ 23 protected $baseDefinitions = []; 24 25 /** 26 * Per-locale currency definitions. 27 * 28 * @var array 29 */ 30 protected $definitions = []; 31 32 /** 33 * Creates a CurrencyRepository instance. 34 * 35 * @param string $definitionPath The path to the currency definitions. 36 * Defaults to 'resources/currency'. 37 */ 38 public function __construct($definitionPath = null) 39 { 40 $this->definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/currency/'; 41 } 42 43 /** 44 * {@inheritdoc} 45 */ 46 public function get($currencyCode, $locale = null, $fallbackLocale = null) 47 { 48 $locale = $this->resolveLocale($locale, $fallbackLocale); 49 $definitions = $this->loadDefinitions($locale); 50 if (!isset($definitions[$currencyCode])) { 51 throw new UnknownCurrencyException($currencyCode); 52 } 53 54 return $this->createCurrencyFromDefinition($currencyCode, $definitions[$currencyCode], $locale); 55 } 56 57 /** 58 * {@inheritdoc} 59 */ 60 public function getAll($locale = null, $fallbackLocale = null) 61 { 62 $locale = $this->resolveLocale($locale, $fallbackLocale); 63 $definitions = $this->loadDefinitions($locale); 64 $currencies = []; 65 foreach ($definitions as $currencyCode => $definition) { 66 $currencies[$currencyCode] = $this->createCurrencyFromDefinition($currencyCode, $definition, $locale); 67 } 68 69 return $currencies; 70 } 71 72 /** 73 * {@inheritdoc} 74 */ 75 public function getList($locale = null, $fallbackLocale = null) 76 { 77 $locale = $this->resolveLocale($locale, $fallbackLocale); 78 $definitions = $this->loadDefinitions($locale); 79 $list = []; 80 foreach ($definitions as $currencyCode => $definition) { 81 $list[$currencyCode] = $definition['name']; 82 } 83 84 return $list; 85 } 86 87 /** 88 * Loads the currency definitions for the provided locale. 89 * 90 * @param string $locale The desired locale. 91 * 92 * @return array 93 */ 94 protected function loadDefinitions($locale) 95 { 96 if (!isset($this->definitions[$locale])) { 97 $filename = $this->definitionPath . $locale . '.json'; 98 $this->definitions[$locale] = json_decode(file_get_contents($filename), true); 99 100 // Make sure the base definitions have been loaded. 101 if (empty($this->baseDefinitions)) { 102 $this->baseDefinitions = json_decode(file_get_contents($this->definitionPath . 'base.json'), true); 103 } 104 // Merge-in base definitions. 105 foreach ($this->definitions[$locale] as $currencyCode => $definition) { 106 $this->definitions[$locale][$currencyCode] += $this->baseDefinitions[$currencyCode]; 107 } 108 } 109 110 return $this->definitions[$locale]; 111 } 112 113 /** 114 * Creates a currency object from the provided definition. 115 * 116 * @param string $currencyCode The currency code. 117 * @param array $definition The currency definition. 118 * @param string $locale The locale of the currency definition. 119 * 120 * @return Currency 121 */ 122 protected function createCurrencyFromDefinition($currencyCode, array $definition, $locale) 123 { 124 if (!isset($definition['symbol'])) { 125 $definition['symbol'] = $currencyCode; 126 } 127 if (!isset($definition['fraction_digits'])) { 128 $definition['fraction_digits'] = 2; 129 } 130 131 $currency = new Currency(); 132 $setValues = \Closure::bind(function ($currencyCode, $definition, $locale) { 133 $this->currencyCode = $currencyCode; 134 $this->name = $definition['name']; 135 $this->numericCode = $definition['numeric_code']; 136 $this->symbol = $definition['symbol']; 137 $this->fractionDigits = $definition['fraction_digits']; 138 $this->locale = $locale; 139 }, $currency, '\CommerceGuys\Intl\Currency\Currency'); 140 $setValues($currencyCode, $definition, $locale); 141 142 return $currency; 143 } 144} 145