GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

GeoIPs::executeQuery()   D
last analyzed

Complexity

Conditions 22
Paths 14

Size

Total Lines 89
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 89
rs 4.6625
c 0
b 0
f 0
cc 22
eloc 61
nc 14
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Geocoder package.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT License
11
 */
12
13
namespace Geocoder\Provider\GeoIPs;
14
15
use Geocoder\Collection;
16
use Geocoder\Exception\InvalidArgument;
17
use Geocoder\Exception\InvalidCredentials;
18
use Geocoder\Exception\InvalidServerResponse;
19
use Geocoder\Exception\QuotaExceeded;
20
use Geocoder\Exception\UnsupportedOperation;
21
use Geocoder\Model\Address;
22
use Geocoder\Model\AddressCollection;
23
use Geocoder\Query\GeocodeQuery;
24
use Geocoder\Query\ReverseQuery;
25
use Geocoder\Http\Provider\AbstractHttpProvider;
26
use Geocoder\Provider\Provider;
27
use Http\Client\HttpClient;
28
29
/**
30
 * @author Andrea Cristaudo <[email protected]>
31
 * @author Arthur Bodera <[email protected]>
32
 *
33
 * @see http://www.geoips.com/en/developer/api-guide
34
 */
35
final class GeoIPs extends AbstractHttpProvider implements Provider
36
{
37
    /**
38
     * @var string
39
     */
40
    const GEOCODE_ENDPOINT_URL = 'https://api.geoips.com/ip/%s/key/%s/output/json/timezone/true/';
41
42
    const CODE_SUCCESS = '200_1'; // The following results has been returned.
43
44
    const CODE_NOT_FOUND = '200_2'; // No result set has been returned.
45
46
    const CODE_BAD_KEY = '400_1'; // Error in the URI - The API call should include a API key parameter.
47
48
    const CODE_BAD_IP = '400_2'; // Error in the URI - The API call should include a valid IP address.
49
50
    const CODE_NOT_AUTHORIZED = '403_1'; // The API key associated with your request was not recognized.
51
52
    const CODE_ACCOUNT_INACTIVE = '403_2'; // The API key has not been approved or has been disabled.
53
54
    const CODE_LIMIT_EXCEEDED = '403_3'; // The service you have requested is over capacity.
55
56
    /**
57
     * @var string
58
     */
59
    private $apiKey;
60
61
    /**
62
     * @param HttpClient $client An HTTP adapter
63
     * @param string     $apiKey An API key
64
     */
65
    public function __construct(HttpClient $client, string $apiKey)
66
    {
67
        if (empty($apiKey)) {
68
            throw new InvalidCredentials('No API key provided.');
69
        }
70
71
        $this->apiKey = $apiKey;
72
        parent::__construct($client);
73
    }
74
75
    /**
76
     * {@inheritdoc}
77
     */
78
    public function geocodeQuery(GeocodeQuery $query): Collection
79
    {
80
        $address = $query->getText();
81
        if (!filter_var($address, FILTER_VALIDATE_IP)) {
82
            throw new UnsupportedOperation('The GeoIPs provider does not support street addresses, only IPv4 addresses.');
83
        }
84
85
        if (filter_var($address, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
86
            throw new UnsupportedOperation('The GeoIPs provider does not support IPv6 addresses, only IPv4 addresses.');
87
        }
88
89
        if ('127.0.0.1' === $address) {
90
            return new AddressCollection([$this->getLocationForLocalhost()]);
91
        }
92
93
        $query = sprintf(self::GEOCODE_ENDPOINT_URL, $address, $this->apiKey);
94
95
        return $this->executeQuery($query);
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101
    public function reverseQuery(ReverseQuery $query): Collection
102
    {
103
        throw new UnsupportedOperation('The GeoIPs provider is not able to do reverse geocoding.');
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109
    public function getName(): string
110
    {
111
        return 'geo_ips';
112
    }
113
114
    /**
115
     * @param string $url
116
     *
117
     * @return AddressCollection
118
     */
119
    private function executeQuery(string $url): AddressCollection
120
    {
121
        $content = $this->getUrlContents($url);
122
        $json = json_decode($content, true);
123
124
        if (isset($json['error'])) {
125
            switch ($json['error']['code']) {
126
                case static::CODE_BAD_IP:
127
                    throw new InvalidArgument('The API call should include a valid IP address.');
128
                case static::CODE_BAD_KEY:
129
                    throw new InvalidCredentials('The API call should include a API key parameter.');
130
                case static::CODE_NOT_AUTHORIZED:
131
                    throw new InvalidCredentials('The API key associated with your request was not recognized.');
132
                case static::CODE_ACCOUNT_INACTIVE:
133
                    throw new InvalidCredentials('The API key has not been approved or has been disabled.');
134
                case static::CODE_LIMIT_EXCEEDED:
135
                    throw new QuotaExceeded('The service you have requested is over capacity.');
136
                default:
137
                    throw new InvalidServerResponse(sprintf(
138
                        'GeoIPs error %s%s%s%s - query: %s',
139
                        $json['error']['code'],
140
                        isset($json['error']['status']) ? ', '.$json['error']['status'] : '',
141
                        isset($json['error']['message']) ? ', '.$json['error']['message'] : '',
142
                        isset($json['error']['notes']) ? ', '.$json['error']['notes'] : '',
143
                        $url
144
                    ));
145
            }
146
        }
147
148
        if (!is_array($json) || empty($json) || empty($json['response']) || empty($json['response']['code'])) {
149
            throw InvalidServerResponse::create($url);
150
        }
151
152
        $response = $json['response'];
153
154
        // Check response code
155
        switch ($response['code']) {
156
            case static::CODE_SUCCESS:
157
                // everything is ok
158
                break;
159
            case static::CODE_NOT_FOUND:
160
                return new AddressCollection([]);
161
            default:
162
                throw new InvalidServerResponse(sprintf(
163
                    'The GeoIPs API returned unknown result code "%s" for query: "%s".',
164
                    $response['code'],
165
                    $url
166
                ));
167
        }
168
169
        // Make sure that we do have proper result array
170
        if (empty($response['location']) || !is_array($response['location'])) {
171
            return new AddressCollection([]);
172
        }
173
174
        $location = array_map(function ($value) {
175
            return '' === $value ? null : $value;
176
        }, $response['location']);
177
178
        $adminLevels = [];
179
180
        if (null !== $location['region_name'] || null !== $location['region_code']) {
181
            $adminLevels[] = [
182
                'name' => $location['region_name'],
183
                'code' => $location['region_code'],
184
                'level' => 1,
185
            ];
186
        }
187
188
        if (null !== $location['county_name']) {
189
            $adminLevels[] = [
190
                'name' => $location['county_name'],
191
                'level' => 2,
192
            ];
193
        }
194
195
        $results = Address::createFromArray([
196
            'providedBy' => $this->getName(),
197
            'country' => $location['country_name'],
198
            'countryCode' => $location['country_code'],
199
            'adminLevels' => $adminLevels,
200
            'locality' => $location['city_name'],
201
            'latitude' => $location['latitude'],
202
            'longitude' => $location['longitude'],
203
            'timezone' => $location['timezone'],
204
        ]);
205
206
        return new AddressCollection([$results]);
207
    }
208
}
209