GraphHopper::executeQuery()   B
last analyzed

Complexity

Conditions 10
Paths 5

Size

Total Lines 47
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 31
c 1
b 0
f 0
nc 5
nop 1
dl 0
loc 47
rs 7.6666

How to fix   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\GraphHopper;
14
15
use Geocoder\Collection;
16
use Geocoder\Exception\InvalidCredentials;
17
use Geocoder\Exception\UnsupportedOperation;
18
use Geocoder\Model\Address;
19
use Geocoder\Model\AddressCollection;
20
use Geocoder\Query\GeocodeQuery;
21
use Geocoder\Query\ReverseQuery;
22
use Geocoder\Http\Provider\AbstractHttpProvider;
23
use Geocoder\Provider\Provider;
24
use Http\Client\HttpClient;
25
26
/**
27
 * @author Gary Gale <[email protected]>
28
 */
29
final class GraphHopper extends AbstractHttpProvider implements Provider
30
{
31
    /**
32
     * @var string
33
     */
34
    const GEOCODE_ENDPOINT_URL = 'https://graphhopper.com/api/1/geocode?q=%s&key=%s&locale=%s&limit=%d';
35
36
    /**
37
     * @var string
38
     */
39
    const REVERSE_ENDPOINT_URL = 'https://graphhopper.com/api/1/geocode?reverse=true&point=%f,%f&key=%s&locale=%s&limit=%d';
40
41
    /**
42
     * @var string
43
     */
44
    private $apiKey;
45
46
    /**
47
     * @param HttpClient $client an HTTP adapter
48
     * @param string     $apiKey an API key
49
     */
50
    public function __construct(HttpClient $client, string $apiKey)
51
    {
52
        if (empty($apiKey)) {
53
            throw new InvalidCredentials('No API key provided.');
54
        }
55
56
        $this->apiKey = $apiKey;
57
        parent::__construct($client);
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function geocodeQuery(GeocodeQuery $query): Collection
64
    {
65
        $address = $query->getText();
66
67
        // This API doesn't handle IPs
68
        if (filter_var($address, FILTER_VALIDATE_IP)) {
69
            throw new UnsupportedOperation('The GraphHopper provider does not support IP addresses, only street addresses.');
70
        }
71
72
        $url = sprintf(self::GEOCODE_ENDPOINT_URL, urlencode($address), $this->apiKey, $query->getLocale(), $query->getLimit());
73
74
        return $this->executeQuery($url);
75
    }
76
77
    /**
78
     * {@inheritdoc}
79
     */
80
    public function reverseQuery(ReverseQuery $query): Collection
81
    {
82
        $coordinates = $query->getCoordinates();
83
        $longitude = $coordinates->getLongitude();
84
        $latitude = $coordinates->getLatitude();
85
86
        $url = sprintf(self::REVERSE_ENDPOINT_URL, $latitude, $longitude, $this->apiKey, $query->getLocale(), $query->getLimit());
87
88
        return $this->executeQuery($url);
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function getName(): string
95
    {
96
        return 'graphhopper';
97
    }
98
99
    /**
100
     * @param $url
101
     *
102
     * @return Collection
103
     */
104
    private function executeQuery(string $url): AddressCollection
105
    {
106
        $content = $this->getUrlContents($url);
107
108
        $json = json_decode($content, true);
109
110
        if (!isset($json['hits'])) {
111
            return new AddressCollection([]);
112
        }
113
114
        $locations = $json['hits'];
115
116
        if (empty($locations)) {
117
            return new AddressCollection([]);
118
        }
119
120
        $results = [];
121
        foreach ($locations as $location) {
122
            $bounds = [
123
                'east' => null,
124
                'north' => null,
125
                'west' => null,
126
                'south' => null,
127
            ];
128
            if (isset($location['extent'])) {
129
                $bounds = [
130
                    'east' => $location['extent'][0],
131
                    'north' => $location['extent'][1],
132
                    'west' => $location['extent'][2],
133
                    'south' => $location['extent'][3],
134
                ];
135
            }
136
137
            $results[] = Address::createFromArray([
138
                'providedBy' => $this->getName(),
139
                'latitude' => $location['point']['lat'],
140
                'longitude' => $location['point']['lng'],
141
                'bounds' => $bounds,
142
                'streetNumber' => isset($location['housenumber']) ? $location['housenumber'] : null,
143
                'streetName' => isset($location['street']) ? $location['street'] : null,
144
                'locality' => isset($location['city']) ? $location['city'] : null,
145
                'postalCode' => isset($location['postcode']) ? $location['postcode'] : null,
146
                'country' => isset($location['country']) ? $location['country'] : null,
147
            ]);
148
        }
149
150
        return new AddressCollection($results);
151
    }
152
}
153