1<?php 2 3namespace CommerceGuys\Intl\Country; 4 5use CommerceGuys\Intl\LocaleResolverTrait; 6use CommerceGuys\Intl\Exception\UnknownCountryException; 7 8/** 9 * Manages countries based on JSON definitions. 10 */ 11class CountryRepository implements CountryRepositoryInterface 12{ 13 use LocaleResolverTrait; 14 15 /** 16 * Base country definitions. 17 * 18 * Contains data common to all locales, such as the country numeric, 19 * three-letter, currency codes. 20 * 21 * @var array 22 */ 23 protected $baseDefinitions = []; 24 25 /** 26 * Per-locale country definitions. 27 * 28 * @var array 29 */ 30 protected $definitions = []; 31 32 /** 33 * Creates a CountryRepository instance. 34 * 35 * @param string $definitionPath The path to the country definitions. 36 * Defaults to 'resources/country'. 37 */ 38 public function __construct($definitionPath = null) 39 { 40 $this->definitionPath = $definitionPath ? $definitionPath : __DIR__ . '/../../resources/country/'; 41 } 42 43 /** 44 * {@inheritdoc} 45 */ 46 public function get($countryCode, $locale = null, $fallbackLocale = null) 47 { 48 $locale = $this->resolveLocale($locale, $fallbackLocale); 49 $definitions = $this->loadDefinitions($locale); 50 if (!isset($definitions[$countryCode])) { 51 throw new UnknownCountryException($countryCode); 52 } 53 54 return $this->createCountryFromDefinition($countryCode, $definitions[$countryCode], $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 $countries = []; 65 foreach ($definitions as $countryCode => $definition) { 66 $countries[$countryCode] = $this->createCountryFromDefinition($countryCode, $definition, $locale); 67 } 68 69 return $countries; 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 $countryCode => $definition) { 81 $list[$countryCode] = $definition['name']; 82 } 83 84 return $list; 85 } 86 87 /** 88 * Loads the country 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 $countryCode => $definition) { 106 $this->definitions[$locale][$countryCode] += $this->baseDefinitions[$countryCode]; 107 } 108 } 109 110 return $this->definitions[$locale]; 111 } 112 113 /** 114 * Creates a country object from the provided definition. 115 * 116 * @param string $countryCode The country code. 117 * @param array $definition The country definition. 118 * @param string $locale The locale of the country definition. 119 * 120 * @return Country 121 */ 122 protected function createCountryFromDefinition($countryCode, array $definition, $locale) 123 { 124 $country = new Country(); 125 $setValues = \Closure::bind(function ($countryCode, $definition, $locale) { 126 $this->countryCode = $countryCode; 127 $this->name = $definition['name']; 128 $this->locale = $locale; 129 if (isset($definition['three_letter_code'])) { 130 $this->threeLetterCode = $definition['three_letter_code']; 131 } 132 if (isset($definition['numeric_code'])) { 133 $this->numericCode = $definition['numeric_code']; 134 } 135 if (isset($definition['currency_code'])) { 136 $this->currencyCode = $definition['currency_code']; 137 } 138 }, $country, '\CommerceGuys\Intl\Country\Country'); 139 $setValues($countryCode, $definition, $locale); 140 141 return $country; 142 } 143} 144