Completed
Push — master ( 328274...701739 )
by Tobias
05:21
created

Ipstack.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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\Ipstack;
14
15
use Geocoder\Collection;
16
use Geocoder\Exception\InvalidArgument;
17
use Geocoder\Exception\InvalidCredentials;
18
use Geocoder\Exception\QuotaExceeded;
19
use Geocoder\Exception\UnsupportedOperation;
20
use Geocoder\Model\Address;
21
use Geocoder\Model\AddressCollection;
22
use Geocoder\Query\GeocodeQuery;
23
use Geocoder\Query\ReverseQuery;
24
use Geocoder\Http\Provider\AbstractHttpProvider;
25
use Geocoder\Provider\Provider;
26
use Http\Client\HttpClient;
27
28
/**
29
 * @author Jonas Gielen <[email protected]>
30
 */
31
final class Ipstack extends AbstractHttpProvider implements Provider
32
{
33
    /**
34
     * @var string
35
     */
36
    const GEOCODE_ENDPOINT_URL = 'http://api.ipstack.com/%s?access_key=%s';
37
38
    /**
39
     * @var string
40
     */
41
    private $apiKey;
42
43
    /**
44
     * @param HttpClient $client an HTTP adapter
45
     * @param string     $apiKey an API key
46
     */
47 24
    public function __construct(HttpClient $client, string $apiKey)
48
    {
49 24
        if (empty($apiKey)) {
50 1
            throw new InvalidCredentials('No API key provided.');
51
        }
52
53 23
        $this->apiKey = $apiKey;
54 23
        parent::__construct($client);
55 23
    }
56
57
    /**
58
     * {@inheritdoc}
59
     */
60 21
    public function geocodeQuery(GeocodeQuery $query): Collection
61
    {
62 21
        $address = $query->getText();
63
64
        // This API doesn't handle IPs
65 21
        if (!filter_var($address, FILTER_VALIDATE_IP)) {
66 1
            throw new UnsupportedOperation('The Ipstack provider does not support street addresses.');
67
        }
68
69 20
        if (in_array($address, ['127.0.0.1', '::1'])) {
70 2
            return new AddressCollection([$this->getLocationForLocalhost()]);
71
        }
72
73 18
        $url = sprintf(sprintf(self::GEOCODE_ENDPOINT_URL, $address, $this->apiKey));
74
75 18
        if (null !== $query->getLocale()) {
76 3
            $url = sprintf('%s&language=%s', $url, $query->getLocale());
77
        }
78
79 18
        $body = $this->getUrlContents($url);
80 8
        $data = json_decode($body, true);
81
82
        // https://ipstack.com/documentation#errors
83 8
        if (isset($data['error'])) {
84 4
            switch ($data['error']['code']) {
85 4
                case 301:
86 1
                    throw new InvalidArgument('Invalid request (a required parameter is missing).');
87 3
                case 303:
88 1
                    throw new InvalidArgument('Bulk requests are not supported on your plan. Please upgrade your subscription.');
89 2
                case 104:
90 1
                    throw new QuotaExceeded('The maximum allowed amount of monthly API requests has been reached.');
91 1
                case 101:
92 1
                    throw new InvalidCredentials('No API Key was specified or an invalid API Key was specified.');
93
            }
94
        }
95
96 4
        if (null === $data['latitude']
97 4
            && null === $data['longitude']
98 4
            && null === $data['city']
99 4
            && null === $data['zip']
100 4
            && null === $data['country_name']
101 4
            && null === $data['country_code']) {
102 1
            return new AddressCollection([]);
103
        }
104
105 3
        $locations[] = Address::createFromArray([
0 ignored issues
show
Coding Style Comprehensibility introduced by
$locations was never initialized. Although not strictly required by PHP, it is generally a good practice to add $locations = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
106 3
            'providedBy' => $this->getName(),
107 3
            'latitude' => $data['latitude'] ?: null,
108 3
            'longitude' => $data['longitude'] ?: null,
109 3
            'locality' => $data['city'] ?: null,
110 3
            'postalCode' => $data['zip'] ?: null,
111 3
            'country' => $data['country_name'] ?: null,
112 3
            'countryCode' => $data['country_code'] ?: null,
113
        ]);
114
115 3
        return new AddressCollection($locations);
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121 1
    public function reverseQuery(ReverseQuery $query): Collection
122
    {
123 1
        throw new UnsupportedOperation('The Ipstack provider is not able to do reverse geocoding.');
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 6
    public function getName(): string
130
    {
131 6
        return 'ipstack';
132
    }
133
}
134