Photon   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 154
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
eloc 61
c 1
b 0
f 0
dl 0
loc 154
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A withKomootServer() 0 3 1
A executeQuery() 0 12 2
A __construct() 0 5 1
A reverseQuery() 0 27 4
A geocodeQuery() 0 29 5
A getName() 0 3 1
A featureToAddress() 0 28 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\Photon;
14
15
use Geocoder\Collection;
16
use Geocoder\Exception\InvalidServerResponse;
17
use Geocoder\Exception\UnsupportedOperation;
18
use Geocoder\Location;
19
use Geocoder\Model\AddressBuilder;
20
use Geocoder\Model\AddressCollection;
21
use Geocoder\Query\GeocodeQuery;
22
use Geocoder\Query\ReverseQuery;
23
use Geocoder\Http\Provider\AbstractHttpProvider;
24
use Geocoder\Provider\Provider;
25
use Geocoder\Provider\Photon\Model\PhotonAddress;
26
use Http\Client\HttpClient;
27
28
/**
29
 * @author Niklas Närhinen <[email protected]>
30
 * @author Jonathan Beliën <[email protected]>
31
 */
32
final class Photon extends AbstractHttpProvider implements Provider
33
{
34
    /**
35
     * @var string
36
     */
37
    private $rootUrl;
38
39
    /**
40
     * @param HttpClient $client an HTTP client
41
     *
42
     * @return Photon
43
     */
44
    public static function withKomootServer(HttpClient $client): self
45
    {
46
        return new self($client, 'https://photon.komoot.io');
47
    }
48
49
    /**
50
     * @param HttpClient $client  an HTTP client
51
     * @param string     $rootUrl Root URL of the photon server
52
     */
53
    public function __construct(HttpClient $client, $rootUrl)
54
    {
55
        parent::__construct($client);
56
57
        $this->rootUrl = rtrim($rootUrl, '/');
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 Photon provider does not support IP addresses.');
70
        }
71
72
        $url = $this->rootUrl
73
            .'/api?'
74
            .http_build_query([
75
                'q' => $address,
76
                'limit' => $query->getLimit(),
77
                'lang' => $query->getLocale(),
78
            ]);
79
80
        $json = $this->executeQuery($url, $query->getLocale());
0 ignored issues
show
Unused Code introduced by
The call to Geocoder\Provider\Photon\Photon::executeQuery() has too many arguments starting with $query->getLocale(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

80
        /** @scrutinizer ignore-call */ 
81
        $json = $this->executeQuery($url, $query->getLocale());

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
81
82
        if (!isset($json->features) || empty($json->features)) {
83
            return new AddressCollection([]);
84
        }
85
86
        $results = [];
87
        foreach ($json->features as $feature) {
88
            $results[] = $this->featureToAddress($feature);
89
        }
90
91
        return new AddressCollection($results);
92
    }
93
94
    /**
95
     * {@inheritdoc}
96
     */
97
    public function reverseQuery(ReverseQuery $query): Collection
98
    {
99
        $coordinates = $query->getCoordinates();
100
101
        $longitude = $coordinates->getLongitude();
102
        $latitude = $coordinates->getLatitude();
103
104
        $url = $this->rootUrl
105
            .'/reverse?'
106
            .http_build_query([
107
                'lat' => $latitude,
108
                'lon' => $longitude,
109
                'lang' => $query->getLocale(),
110
            ]);
111
112
        $json = $this->executeQuery($url);
113
114
        if (!isset($json->features) || empty($json->features)) {
115
            return new AddressCollection([]);
116
        }
117
118
        $results = [];
119
        foreach ($json->features as $feature) {
120
            $results[] = $this->featureToAddress($feature);
121
        }
122
123
        return new AddressCollection($results);
124
    }
125
126
    /**
127
     * @param \stdClass $feature
128
     *
129
     * @return Location
130
     */
131
    private function featureToAddress(\stdClass $feature): Location
132
    {
133
        $builder = new AddressBuilder($this->getName());
134
135
        $coordinates = $feature->geometry->coordinates;
136
        $properties = $feature->properties;
137
138
        $builder->setCoordinates(floatval($coordinates[1]), floatval($coordinates[0]));
139
140
        $builder->setStreetName($properties->street ?? null);
141
        $builder->setStreetNumber($properties->housenumber ?? null);
142
        $builder->setPostalCode($properties->postcode ?? null);
143
        $builder->setLocality($properties->city ?? null);
144
        $builder->setCountry($properties->country ?? null);
145
146
        if (isset($properties->extent)) {
147
            $builder->setBounds($properties->extent[0], $properties->extent[2], $properties->extent[1], $properties->extent[3]);
148
        }
149
150
        $address = $builder->build(PhotonAddress::class)
151
            ->withOSMId($properties->osm_id ?? null)
152
            ->withOSMType($properties->osm_type ?? null)
153
            ->withOSMTag(
154
                $properties->osm_key ?? null,
155
                $properties->osm_value ?? null
156
            );
157
158
        return $address;
159
    }
160
161
    /**
162
     * {@inheritdoc}
163
     */
164
    public function getName(): string
165
    {
166
        return 'photon';
167
    }
168
169
    /**
170
     * @param string $url
171
     *
172
     * @return \stdClass
173
     */
174
    private function executeQuery(string $url): \stdClass
175
    {
176
        $content = $this->getUrlContents($url);
177
178
        $json = json_decode($content);
179
180
        // API error
181
        if (is_null($json)) {
182
            throw InvalidServerResponse::create($url);
183
        }
184
185
        return $json;
186
    }
187
}
188