Completed
Push — master ( 729cb6...871ddf )
by Tobias
04:42
created

GeoIP2::reverseQuery()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

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