Completed
Push — master ( a5f796...889627 )
by Tobias
02:21
created

GeoIP2::executeQuery()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 24
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 4.0039

Importance

Changes 0
Metric Value
dl 0
loc 24
ccs 15
cts 16
cp 0.9375
rs 8.6845
c 0
b 0
f 0
cc 4
eloc 17
nc 4
nop 1
crap 4.0039
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\GeoIP2;
14
15
use Geocoder\Collection;
16
use Geocoder\Model\Address;
17
use Geocoder\Model\AddressCollection;
18
use Geocoder\Query\GeocodeQuery;
19
use Geocoder\Query\ReverseQuery;
20
use Geocoder\Provider\AbstractProvider;
21
use Geocoder\Provider\IpAddressGeocoder;
22
use Geocoder\Provider\LocaleAwareGeocoder;
23
use Geocoder\Provider\Provider;
24
use Geocoder\Exception\UnsupportedOperation;
25
use Geocoder\Exception\InvalidCredentials;
26
use Geocoder\Exception\QuotaExceeded;
27
use GeoIp2\Exception\AddressNotFoundException;
28
use GeoIp2\Exception\AuthenticationException;
29
use GeoIp2\Exception\OutOfQueriesException;
30
31
/**
32
 * @author Jens Wiese <[email protected]>
33
 */
34
final class GeoIP2 extends AbstractProvider implements LocaleAwareGeocoder, IpAddressGeocoder, Provider
35
{
36
    /**
37
     * @var GeoIP2Adapter
38
     */
39
    private $adapter;
40
41 12
    public function __construct(GeoIP2Adapter $adapter)
42
    {
43 12
        $this->adapter = $adapter;
44 12
    }
45
46
    /**
47
     * {@inheritdoc}
48
     */
49 10
    public function geocodeQuery(GeocodeQuery $query): Collection
50
    {
51 10
        $address = $query->getText();
52 10
        $locale = $query->getLocale() ?: 'en'; // Default to English
53 10
        if (!filter_var($address, FILTER_VALIDATE_IP)) {
54 1
            throw new UnsupportedOperation('The GeoIP2 provider does not support street addresses, only IP addresses.');
55
        }
56
57 9
        if ('127.0.0.1' === $address) {
58 1
            return new AddressCollection([$this->getLocationForLocalhost()]);
59
        }
60
61 8
        $result = json_decode($this->executeQuery($address));
62
63 6
        if (null === $result) {
64 1
            return new AddressCollection([]);
65
        }
66
67 5
        $adminLevels = [];
68 5
        if (isset($result->subdivisions) && is_array($result->subdivisions)) {
69 3
            foreach ($result->subdivisions as $i => $subdivision) {
70 3
                $name = (isset($subdivision->names->{$locale}) ? $subdivision->names->{$locale} : null);
71 3
                $code = (isset($subdivision->iso_code) ? $subdivision->iso_code : null);
72
73 3
                if (null !== $name || null !== $code) {
74 3
                    $adminLevels[] = ['name' => $name, 'code' => $code, 'level' => $i + 1];
75
                }
76
            }
77
        }
78
79 5
        return new AddressCollection([
80 5
            Address::createFromArray([
81 5
                'providedBy' => $this->getName(),
82 4
                'countryCode' => (isset($result->country->iso_code) ? $result->country->iso_code : null),
83 4
                'country' => (isset($result->country->names->{$locale}) ? $result->country->names->{$locale} : null),
84 3
                'locality' => (isset($result->city->names->{$locale}) ? $result->city->names->{$locale} : null),
85 4
                'latitude' => (isset($result->location->latitude) ? $result->location->latitude : null),
86 4
                'longitude' => (isset($result->location->longitude) ? $result->location->longitude : null),
87 4
                'timezone' => (isset($result->location->time_zone) ? $result->location->time_zone : null),
88 2
                'postalCode' => (isset($result->postal->code) ? $result->postal->code : null),
89 5
                'adminLevels' => $adminLevels,
90
            ]),
91
        ]);
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97 1
    public function reverseQuery(ReverseQuery $query): Collection
98
    {
99 1
        throw new UnsupportedOperation('The GeoIP2 provider is not able to do reverse geocoding.');
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105 7
    public function getName(): string
106
    {
107 7
        return 'geoip2';
108
    }
109
110
    /**
111
     * @param string $address
112
     */
113 8
    private function executeQuery(string $address): string
114
    {
115 8
        $uri = sprintf('file://geoip?%s', $address);
116
117
        try {
118 8
            $result = $this->adapter->getContent($uri);
119 2
        } catch (AddressNotFoundException $e) {
120
            return '';
121 2
        } catch (AuthenticationException $e) {
122 1
            throw new InvalidCredentials(
123 1
                $e->getMessage(),
124 1
                $e->getCode(),
125 1
                $e
126
            );
127 1
        } catch (OutOfQueriesException $e) {
128 1
            throw new QuotaExceeded(
129 1
                $e->getMessage(),
130 1
                $e->getCode(),
131 1
                $e
132
            );
133
        }
134
135 6
        return $result;
136
    }
137
}
138