Completed
Push — master ( 9e0c22...810064 )
by Tobias
02:41
created

Ipstack::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 2
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(
87 1
                        'Invalid request (a required parameter is missing).'
88
                    );
89 3
                case 303:
90 1
                    throw new InvalidArgument(
91 1
                        'Bulk requests are not supported on your plan. Please upgrade your subscription.'
92
                    );
93 2
                case 104:
94 1
                    throw new QuotaExceeded(
95 1
                        'The maximum allowed amount of monthly API requests has been reached.'
96
                    );
97 1
                case 101:
98 1
                    throw new InvalidCredentials(
99 1
                        'No API Key was specified or an invalid API Key was specified.'
100
                    );
101
            }
102
        }
103
104 4
        if (null === $data['latitude']
105 4
            && null === $data['longitude']
106 4
            && null === $data['city']
107 4
            && null === $data['zip']
108 4
            && null === $data['country_name']
109 4
            && null === $data['country_code']) {
110 1
            return new AddressCollection([]);
111
        }
112
113 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...
114 3
            'providedBy' => $this->getName(),
115 3
            'latitude' => $data['latitude'] ?: null,
116 3
            'longitude' => $data['longitude'] ?: null,
117 3
            'locality' => $data['city'] ?: null,
118 3
            'postalCode' => $data['zip'] ?: null,
119 3
            'country' => $data['country_name'] ?: null,
120 3
            'countryCode' => $data['country_code'] ?: null,
121
        ]);
122
123 3
        return new AddressCollection($locations);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 1
    public function reverseQuery(ReverseQuery $query): Collection
130
    {
131 1
        throw new UnsupportedOperation('The Ipstack provider is not able to do reverse geocoding.');
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137 6
    public function getName(): string
138
    {
139 6
        return 'ipstack';
140
    }
141
}
142