CountriesData::getCountries()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 4
rs 10
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
Bug Best Practice introduced by
The expression $this->data of type array<mixed,array<mixed,mixed>> 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 empty(..) or ! empty(...) instead.

Loading history...
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
Bug Best Practice introduced by
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 empty(..) or ! empty(...) instead.

Loading history...
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