1 | <?php |
||
2 | |||
3 | namespace LeKoala\GeoTools; |
||
4 | |||
5 | use Exception; |
||
6 | use SilverStripe\i18n\Data\Intl\IntlLocales; |
||
7 | |||
8 | /** |
||
9 | * @author Koala |
||
10 | */ |
||
11 | class CountriesData |
||
12 | { |
||
13 | const SHORT_NAME = 'ShortName'; |
||
14 | const OFFICIAL_NAME = 'OfficialName'; |
||
15 | const ISO3 = 'ISO3'; |
||
16 | const ISO2 = 'ISO2'; |
||
17 | const UNI = 'UNI'; |
||
18 | const UNDP = 'UNDP'; |
||
19 | const FAOSTAT = 'FAOSTAT'; |
||
20 | const GAUL = 'GAUL'; |
||
21 | |||
22 | /** |
||
23 | * @var string |
||
24 | */ |
||
25 | private $file; |
||
26 | /** |
||
27 | * @var array<array<mixed>> |
||
28 | */ |
||
29 | private $data; |
||
30 | |||
31 | /** |
||
32 | * @param string $file |
||
33 | */ |
||
34 | public function __construct($file = null) |
||
35 | { |
||
36 | if ($file) { |
||
37 | $this->setFile($file); |
||
38 | } else { |
||
39 | $this->setFile(dirname(dirname(__DIR__)) . '/resources/Geo/countries.csv'); |
||
40 | } |
||
41 | } |
||
42 | |||
43 | /** |
||
44 | * @param string $file |
||
45 | * @return self |
||
46 | */ |
||
47 | public static function getInstance($file = null) |
||
48 | { |
||
49 | return new self($file); |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * @return string |
||
54 | */ |
||
55 | public function getFile() |
||
56 | { |
||
57 | return $this->file; |
||
58 | } |
||
59 | |||
60 | /** |
||
61 | * @param string $file |
||
62 | * @return self |
||
63 | */ |
||
64 | public function setFile($file) |
||
65 | { |
||
66 | $this->file = $file; |
||
67 | return $this; |
||
68 | } |
||
69 | |||
70 | private function loadData(): void |
||
71 | { |
||
72 | if ($this->data) { |
||
0 ignored issues
–
show
|
|||
73 | return; |
||
74 | } |
||
75 | if (!is_file($this->file)) { |
||
76 | throw new Exception("File {$this->file} is not valid"); |
||
77 | } |
||
78 | if (!is_readable($this->file)) { |
||
79 | throw new Exception("File {$this->file} is not readable"); |
||
80 | } |
||
81 | $file = fopen($this->file, "r"); |
||
82 | if ($file === false) { |
||
83 | throw new Exception("Unable to open stream"); |
||
84 | } |
||
85 | $arr = []; |
||
86 | $headers = fgetcsv($file); |
||
87 | while (!feof($file)) { |
||
88 | $line = fgetcsv($file); |
||
89 | if ($line) { |
||
0 ignored issues
–
show
The expression
$line of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
90 | //@phpstan-ignore-next-line |
||
91 | $arr[] = array_combine($headers, $line); |
||
92 | } |
||
93 | } |
||
94 | fclose($file); |
||
95 | $this->data = $arr; |
||
96 | } |
||
97 | /** |
||
98 | * Get the list of all countries |
||
99 | * |
||
100 | * @return array<array<mixed>> |
||
101 | */ |
||
102 | public function getCountries() |
||
103 | { |
||
104 | $this->loadData(); |
||
105 | return $this->data; |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Convert a code to another |
||
110 | * |
||
111 | * @param string $code |
||
112 | * @param string $from |
||
113 | * @param string $to |
||
114 | * @return string|bool |
||
115 | */ |
||
116 | public function convertCode($code, $from, $to) |
||
117 | { |
||
118 | if (!$code) { |
||
119 | return false; |
||
120 | } |
||
121 | $countries = $this->getCountries(); |
||
122 | foreach ($countries as $country) { |
||
123 | if ($country[$from] == $code) { |
||
124 | return $country[$to]; |
||
125 | } |
||
126 | } |
||
127 | return false; |
||
128 | } |
||
129 | |||
130 | /** |
||
131 | * Convert ISO2 to ISO3 |
||
132 | * |
||
133 | * @param string $code |
||
134 | * @return string|bool |
||
135 | */ |
||
136 | public function convertIso2ToIso3($code) |
||
137 | { |
||
138 | return $this->convertCode($code, self::ISO2, self::ISO3); |
||
139 | } |
||
140 | |||
141 | /** |
||
142 | * Convert ISO2 to ISO3 |
||
143 | * |
||
144 | * @param string $code |
||
145 | * @return string|bool |
||
146 | */ |
||
147 | public function convertIso3ToIso2($code) |
||
148 | { |
||
149 | return $this->convertCode($code, self::ISO3, self::ISO2); |
||
150 | } |
||
151 | |||
152 | /** |
||
153 | * Get a map of countries as key => value |
||
154 | * |
||
155 | * @param string $key |
||
156 | * @param string $value |
||
157 | * @return array<int|string,mixed> |
||
158 | */ |
||
159 | public function toMap($key = 'ISO2', $value = 'ShortName') |
||
160 | { |
||
161 | $arr = []; |
||
162 | foreach ($this->getCountries() as $country) { |
||
163 | $arr[$country[$key]] = $country[$value]; |
||
164 | } |
||
165 | return $arr; |
||
166 | } |
||
167 | |||
168 | /** |
||
169 | * Get the country list, using IntlLocales |
||
170 | * |
||
171 | * @return array<int|string,mixed> |
||
172 | */ |
||
173 | public static function getCountryList() |
||
174 | { |
||
175 | $intl = new IntlLocales; |
||
176 | return $intl->getCountries(); |
||
177 | } |
||
178 | } |
||
179 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.