Skip to content

Commit cc9e696

Browse files
author
Jonathan Beliën
committed
Update Pelias provider
1 parent af1105b commit cc9e696

File tree

2 files changed

+192
-52
lines changed

2 files changed

+192
-52
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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\Pelias\Model;
14+
15+
use Geocoder\Model\Address;
16+
17+
/**
18+
* @author Jonathan Beliën <[email protected]>
19+
*/
20+
final class PeliasAddress extends Address
21+
{
22+
/**
23+
* @var string|null
24+
*/
25+
private $id;
26+
27+
/**
28+
* @var string|null
29+
*/
30+
private $layer;
31+
32+
/**
33+
* @var string|null
34+
*/
35+
private $source;
36+
37+
/**
38+
* @var string|null
39+
*/
40+
private $name;
41+
42+
/**
43+
* @var float
44+
*/
45+
private $confidence;
46+
47+
/**
48+
* @var string|null
49+
*/
50+
private $accuracy;
51+
52+
public function getId(): ?string
53+
{
54+
return $this->id;
55+
}
56+
57+
public function withId(?string $id): self
58+
{
59+
$new = clone $this;
60+
$new->id = $id;
61+
62+
return $new;
63+
}
64+
65+
public function getSource(): ?string
66+
{
67+
return $this->source;
68+
}
69+
70+
public function withSource(?string $source): self
71+
{
72+
$new = clone $this;
73+
$new->source = $source;
74+
75+
return $new;
76+
}
77+
78+
public function getLayer(): string
79+
{
80+
return $this->layer;
81+
}
82+
83+
public function withLayer(?string $layer): self
84+
{
85+
$new = clone $this;
86+
$new->layer = $layer;
87+
88+
return $new;
89+
}
90+
91+
public function getName(): ?string
92+
{
93+
return $this->name;
94+
}
95+
96+
public function withName(?string $name): self
97+
{
98+
$new = clone $this;
99+
$new->name = $name;
100+
101+
return $new;
102+
}
103+
104+
public function getConfidence(): float
105+
{
106+
return $this->confidence;
107+
}
108+
109+
public function withConfidence(float $confidence): self
110+
{
111+
$new = clone $this;
112+
$new->confidence = $confidence;
113+
114+
return $new;
115+
}
116+
117+
public function getAccuracy(): ?string
118+
{
119+
return $this->accuracy;
120+
}
121+
122+
public function withAccuracy(?string $accuracy): self
123+
{
124+
$new = clone $this;
125+
$new->accuracy = $accuracy;
126+
127+
return $new;
128+
}
129+
}

src/Provider/Pelias/Pelias.php

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
use Geocoder\Exception\QuotaExceeded;
1818
use Geocoder\Exception\UnsupportedOperation;
1919
use Geocoder\Http\Provider\AbstractHttpProvider;
20-
use Geocoder\Model\Address;
20+
use Geocoder\Model\AddressBuilder;
2121
use Geocoder\Model\AddressCollection;
22+
use Geocoder\Provider\Pelias\Model\PeliasAddress;
2223
use Geocoder\Provider\Provider;
2324
use Geocoder\Query\GeocodeQuery;
2425
use Geocoder\Query\ReverseQuery;
@@ -60,14 +61,16 @@ protected function getGeocodeQueryUrl(GeocodeQuery $query, array $query_data = [
6061
$data = [
6162
'text' => $address,
6263
'size' => $query->getLimit(),
64+
'layers' => null !== $query->getData('layers') ? implode(',', $query->getData('layers')) : null,
65+
'boundary.country' => null !== $query->getData('boundary.country') ? implode(',', $query->getData('boundary.country')) : null,
6366
];
6467

6568
return sprintf('%s/search?%s', $this->root, http_build_query(array_merge($data, $query_data)));
6669
}
6770

6871
public function geocodeQuery(GeocodeQuery $query): Collection
6972
{
70-
return $this->executeQuery($this->getGeocodeQueryUrl($query));
73+
return $this->executeQuery($this->getGeocodeQueryUrl($query), $query->getLocale());
7174
}
7275

7376
/**
@@ -85,24 +88,32 @@ protected function getReverseQueryUrl(ReverseQuery $query, array $query_data = [
8588
'point.lat' => $latitude,
8689
'point.lon' => $longitude,
8790
'size' => $query->getLimit(),
91+
'layers' => null !== $query->getData('layers') ? implode(',', $query->getData('layers')) : null,
92+
'boundary.country' => null !== $query->getData('boundary.country') ? implode(',', $query->getData('boundary.country')) : null,
8893
];
8994

9095
return sprintf('%s/reverse?%s', $this->root, http_build_query(array_merge($data, $query_data)));
9196
}
9297

9398
public function reverseQuery(ReverseQuery $query): Collection
9499
{
95-
return $this->executeQuery($this->getReverseQueryUrl($query));
100+
return $this->executeQuery($this->getReverseQueryUrl($query), $query->getLocale());
96101
}
97102

98103
public function getName(): string
99104
{
100105
return 'pelias';
101106
}
102107

103-
protected function executeQuery(string $url): AddressCollection
108+
protected function executeQuery(string $url, ?string $locale): AddressCollection
104109
{
105-
$content = $this->getUrlContents($url);
110+
$headers = [];
111+
if (null !== $locale) {
112+
$headers['Accept-Language'] = $locale;
113+
}
114+
115+
$request = $this->createRequest('GET', $url, $headers);
116+
$content = $this->getParsedResponse($request);
106117
$json = json_decode($content, true);
107118

108119
if (isset($json['meta'])) {
@@ -124,53 +135,53 @@ protected function executeQuery(string $url): AddressCollection
124135
return new AddressCollection([]);
125136
}
126137

127-
$locations = $json['features'];
138+
$features = $json['features'];
128139

129-
if (empty($locations)) {
140+
if (empty($features)) {
130141
return new AddressCollection([]);
131142
}
132143

133144
$results = [];
134-
foreach ($locations as $location) {
135-
if (isset($location['bbox'])) {
136-
$bounds = [
137-
'south' => $location['bbox'][3],
138-
'west' => $location['bbox'][2],
139-
'north' => $location['bbox'][1],
140-
'east' => $location['bbox'][0],
141-
];
142-
} else {
143-
$bounds = [
144-
'south' => null,
145-
'west' => null,
146-
'north' => null,
147-
'east' => null,
148-
];
145+
foreach ($features as $feature) {
146+
$builder = new AddressBuilder($this->getName());
147+
$builder->setCoordinates($feature['geometry']['coordinates'][1], $feature['geometry']['coordinates'][0]);
148+
$builder->setStreetNumber($feature['properties']['housenumber'] ?? null);
149+
$builder->setStreetName($this->guessStreetName($feature['properties']));
150+
$builder->setSubLocality($this->guessSubLocality($feature['properties']));
151+
$builder->setLocality($this->guessLocality($feature['properties']));
152+
$builder->setPostalCode($feature['properties']['postalcode'] ?? null);
153+
$builder->setCountry($feature['properties']['country'] ?? null);
154+
$builder->setCountryCode(
155+
isset($feature['properties']['country_code']) ? strtoupper($feature['properties']['country_code']) :
156+
(isset($feature['properties']['country_a']) ? strtoupper($feature['properties']['country_a']) : null));
157+
$builder->setTimezone($feature['properties']['timezone'] ?? null);
158+
159+
if (isset($feature['bbox'])) {
160+
$builder->setBounds($feature['bbox'][3], $feature['bbox'][2], $feature['bbox'][1], $feature['bbox'][0]);
149161
}
150162

151-
$props = $location['properties'];
152-
153-
$adminLevels = [];
154-
foreach (['region', 'county', 'locality', 'macroregion', 'country'] as $i => $component) {
155-
if (isset($props[$component])) {
156-
$adminLevels[] = ['name' => $props[$component], 'level' => $i + 1];
163+
$level = 1;
164+
foreach (['macroregion', 'region', 'macrocounty', 'county', 'locality', 'localadmin', 'borough'] as $component) {
165+
if (isset($feature['properties'][$component])) {
166+
$builder->addAdminLevel($level++, $feature['properties'][$component], $feature['properties'][$component.'_a'] ?? null);
167+
}
168+
// Administrative level should be an integer in [1,5].
169+
if ($level > 5) {
170+
break;
157171
}
158172
}
159173

160-
$results[] = Address::createFromArray([
161-
'providedBy' => $this->getName(),
162-
'latitude' => $location['geometry']['coordinates'][1],
163-
'longitude' => $location['geometry']['coordinates'][0],
164-
'bounds' => $bounds,
165-
'streetNumber' => isset($props['housenumber']) ? $props['housenumber'] : null,
166-
'streetName' => isset($props['street']) ? $props['street'] : null,
167-
'subLocality' => isset($props['neighbourhood']) ? $props['neighbourhood'] : null,
168-
'locality' => isset($props['locality']) ? $props['locality'] : null,
169-
'postalCode' => isset($props['postalcode']) ? $props['postalcode'] : null,
170-
'adminLevels' => $adminLevels,
171-
'country' => isset($props['country']) ? $props['country'] : null,
172-
'countryCode' => isset($props['country_a']) ? strtoupper($props['country_a']) : null,
173-
]);
174+
/** @var PeliasAddress $location */
175+
$location = $builder->build(PeliasAddress::class);
176+
177+
$location = $location->withId($feature['properties']['id'] ?? null);
178+
$location = $location->withLayer($feature['properties']['layer'] ?? null);
179+
$location = $location->withSource($feature['properties']['source'] ?? null);
180+
$location = $location->withName($feature['properties']['name'] ?? null);
181+
$location = $location->withConfidence($feature['properties']['confidence'] ?? null);
182+
$location = $location->withAccuracy($feature['properties']['accuracy'] ?? null);
183+
184+
$results[] = $location;
174185
}
175186

176187
return new AddressCollection($results);
@@ -181,35 +192,35 @@ protected function executeQuery(string $url): AddressCollection
181192
*
182193
* @return string|null
183194
*/
184-
protected function guessLocality(array $components)
195+
protected static function guessLocality(array $components)
185196
{
186-
$localityKeys = ['city', 'town', 'village', 'hamlet'];
197+
$localityKeys = ['locality', 'localadmin', 'city', 'town', 'village', 'hamlet'];
187198

188-
return $this->guessBestComponent($components, $localityKeys);
199+
return self::guessBestComponent($components, $localityKeys);
189200
}
190201

191202
/**
192203
* @param array<string, mixed> $components
193204
*
194205
* @return string|null
195206
*/
196-
protected function guessStreetName(array $components)
207+
protected static function guessSubLocality(array $components)
197208
{
198-
$streetNameKeys = ['road', 'street', 'street_name', 'residential'];
209+
$subLocalityKeys = ['neighbourhood', 'city_district'];
199210

200-
return $this->guessBestComponent($components, $streetNameKeys);
211+
return self::guessBestComponent($components, $subLocalityKeys);
201212
}
202213

203214
/**
204215
* @param array<string, mixed> $components
205216
*
206217
* @return string|null
207218
*/
208-
protected function guessSubLocality(array $components)
219+
protected static function guessStreetName(array $components)
209220
{
210-
$subLocalityKeys = ['neighbourhood', 'city_district'];
221+
$streetNameKeys = ['road', 'street', 'street_name', 'residential'];
211222

212-
return $this->guessBestComponent($components, $subLocalityKeys);
223+
return self::guessBestComponent($components, $streetNameKeys);
213224
}
214225

215226
/**
@@ -218,7 +229,7 @@ protected function guessSubLocality(array $components)
218229
*
219230
* @return string|null
220231
*/
221-
protected function guessBestComponent(array $components, array $keys)
232+
protected static function guessBestComponent(array $components, array $keys)
222233
{
223234
foreach ($keys as $key) {
224235
if (isset($components[$key]) && !empty($components[$key])) {

0 commit comments

Comments
 (0)