MapBox::getLanguage()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 4
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 7
rs 10
1
<?php
2
3
namespace LeKoala\GeoTools\Services;
4
5
use Exception;
6
use LeKoala\GeoTools\Models\Address;
7
use LeKoala\GeoTools\Models\Country;
8
use LeKoala\GeoTools\Models\Coordinates;
9
use SilverStripe\i18n\i18n;
10
use SilverStripe\Core\Environment;
11
12
/**
13
 * In mapbox, coordinates are reversed! (longitude, latitude)
14
 *
15
 * @link https://www.mapbox.com/api-playground
16
 * @link https://github.com/mapbox/geocoding-example/tree/master/php
17
 */
18
class MapBox implements Geocoder
19
{
20
    const API_URL = 'https://api.mapbox.com/geocoding/v5/{mode}/{query}.json';
21
    const MODE_PLACES = 'mapbox.places';
22
    const MODE_PLACES_PERMANENT = 'mapbox.places-permanent';
23
24
    /**
25
     * @link https://www.mapbox.com/api-documentation/#geocoding
26
     * @param string $query
27
     * @param array<int|string,mixed> $params country, proximity, types, autocomplete, bbox, limit, language
28
     * @return Address
29
     * @throws Exception when there is a problem with the api, otherwise may return an empty address
30
     */
31
    protected function query($query, $params = [])
32
    {
33
        $url = self::API_URL;
34
        $url = str_replace('{mode}', self::MODE_PLACES, $url);
35
        $url = str_replace('{query}', urlencode($query), $url);
36
37
        $defaultParams = [
38
            // 'language' => $this->getLanguage(i18n::get_locale()),
39
            'types' => 'address',
40
            'limit' => 1,
41
            'access_token' => Environment::getEnv('MAPBOX_API_KEY')
42
        ];
43
        $params = array_merge($defaultParams, $params);
44
45
        $url .= '?' . http_build_query($params);
46
47
        $result = file_get_contents($url);
48
        if (!$result) {
49
            throw new Exception("The api returned no result");
50
        }
51
52
        $data = json_decode($result, true);
53
54
        if (!$data) {
55
            throw new Exception("Failed to decode api results");
56
        }
57
58
        $location = null;
59
        $countryCode = $countryName = null;
60
        $lat = $lon = null;
61
62
        if (!empty($data['features'])) {
63
            $feature = $data['features'][0];
64
65
            $location = [
66
                // A string of the house number for the returned address feature
67
                'streetNumber' => $feature['address'] ?? null,
68
                'streetName' => $feature['text'],
69
            ];
70
71
            $lat = $feature['geometry']['coordinates'][1];
72
            $lon = $feature['geometry']['coordinates'][0];
73
            foreach ($feature['context'] as $context) {
74
                $parts = explode('.', $context['id']);
75
                $contextType = $parts[0];
76
                $contextId = $parts[1];
0 ignored issues
show
Unused Code introduced by
The assignment to $contextId is dead and can be removed.
Loading history...
77
                if ($contextType == 'postcode') {
78
                    $location['postalCode'] = $context['text'];
79
                }
80
                if ($contextType == 'place') {
81
                    $location['locality'] = $context['text'];
82
                }
83
                if ($contextType == 'country') {
84
                    $countryCode = $context['short_code'];
85
                    $countryName = $context['text'];
86
                }
87
            }
88
        }
89
90
        $country = new Country($countryCode, $countryName);
91
        $coordinates = new Coordinates($lat, $lon);
92
93
        return new Address($location, $country, $coordinates);
94
    }
95
96
    /**
97
     * @param string $locale
98
     * @return string
99
     */
100
    protected function getLanguage($locale)
101
    {
102
        $lang = substr($locale, 0, 2);
103
        if (in_array($lang, self::listLanguages())) {
104
            return $lang;
105
        }
106
        return 'en';
107
    }
108
109
    /**
110
     * @return array<string>
111
     */
112
    public static function listLanguages()
113
    {
114
        return [
115
            'en',
116
            'de',
117
            'fr',
118
            'it',
119
            'nl',
120
        ];
121
    }
122
123
    /**
124
     * @inheritDoc
125
     */
126
    public function reverseGeocode($lat, $lon, $params = [])
127
    {
128
        return $this->query("$lon,$lat", $params);
129
    }
130
131
    /**
132
     * @inheritDoc
133
     */
134
    public function geocode($address, $params = [])
135
    {
136
        return $this->query($address, $params);
137
    }
138
}
139