Skip to content

Commit 174081d

Browse files
committed
feat(mapbox): parse Geocoding API v6 responses
1 parent 769d0b5 commit 174081d

1 file changed

Lines changed: 77 additions & 54 deletions

File tree

‎src/Provider/Mapbox/Mapbox.php‎

Lines changed: 77 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -329,103 +329,126 @@ private function fetchUrl(string $url, int $limit, ?string $locale, ?string $cou
329329

330330
$results = [];
331331
foreach ($json['features'] as $result) {
332-
if (!array_key_exists('context', $result)) {
332+
$results[] = $this->parseFeature($result);
333+
334+
if (count($results) >= $limit) {
333335
break;
334336
}
337+
}
335338

336-
$builder = new AddressBuilder($this->getName());
337-
$this->parseCoordinates($builder, $result);
339+
return new AddressCollection($results);
340+
}
338341

339-
// set official Mapbox place id
340-
if (isset($result['id'])) {
341-
$builder->setValue('id', $result['id']);
342-
}
342+
/**
343+
* @param array<string, mixed> $result
344+
*/
345+
private function parseFeature(array $result): MapboxAddress
346+
{
347+
$properties = $result['properties'] ?? [];
348+
$context = $properties['context'] ?? [];
343349

344-
// set official Mapbox place id
345-
if (isset($result['text'])) {
346-
$builder->setValue('street_name', $result['text']);
347-
}
350+
$builder = new AddressBuilder($this->getName());
351+
$this->parseCoordinates($builder, $result);
348352

349-
// update address components
350-
foreach ($result['context'] as $component) {
351-
$this->updateAddressComponent($builder, $component['id'], $component);
353+
// update address components (context is an object keyed by feature type in v6)
354+
foreach ($context as $type => $component) {
355+
if (is_array($component)) {
356+
$this->updateAddressComponent($builder, (string) $type, $component);
352357
}
358+
}
353359

354-
/** @var MapboxAddress $address */
355-
$address = $builder->build(MapboxAddress::class);
356-
$address = $address->withId($builder->getValue('id'));
357-
if (isset($result['address'])) {
358-
$address = $address->withStreetNumber($result['address']);
359-
}
360-
if (isset($result['place_type'])) {
361-
$address = $address->withResultType($result['place_type']);
362-
}
363-
if (isset($result['place_name'])) {
364-
$address = $address->withFormattedAddress($result['place_name']);
365-
}
366-
$address = $address->withStreetName($builder->getValue('street_name'));
367-
$address = $address->withNeighborhood($builder->getValue('neighborhood'));
368-
$results[] = $address;
360+
/** @var MapboxAddress $address */
361+
$address = $builder->build(MapboxAddress::class);
369362

370-
if (count($results) >= $limit) {
371-
break;
363+
if (isset($properties['mapbox_id'])) {
364+
$address = $address->withId((string) $properties['mapbox_id']);
365+
} elseif (isset($result['id'])) {
366+
$address = $address->withId((string) $result['id']);
367+
}
368+
369+
// street name without the house number (v5 semantics)
370+
$streetName = $context['address']['street_name'] ?? $context['street']['name'] ?? $properties['name'] ?? null;
371+
if (null !== $streetName) {
372+
$address = $address->withStreetName((string) $streetName);
373+
}
374+
375+
$streetNumber = $context['address']['address_number'] ?? null;
376+
if (null !== $streetNumber) {
377+
$address = $address->withStreetNumber((string) $streetNumber);
378+
}
379+
380+
if (isset($properties['feature_type'])) {
381+
$address = $address->withResultType([(string) $properties['feature_type']]);
382+
}
383+
384+
if (isset($properties['full_address'])) {
385+
$address = $address->withFormattedAddress((string) $properties['full_address']);
386+
}
387+
388+
$neighborhood = $context['neighborhood']['name'] ?? null;
389+
if (null !== $neighborhood && '' !== $neighborhood) {
390+
$address = $address->withNeighborhood((string) $neighborhood);
391+
}
392+
393+
if (isset($properties['match_code']) && is_array($properties['match_code'])) {
394+
$address = $address->withMatchCode($properties['match_code']);
395+
$confidence = $properties['match_code']['confidence'] ?? null;
396+
if (null !== $confidence) {
397+
$address = $address->withMatchConfidence((string) $confidence);
372398
}
373399
}
374400

375-
return new AddressCollection($results);
401+
if (isset($properties['coordinates']['accuracy'])) {
402+
$address = $address->withAccuracy((string) $properties['coordinates']['accuracy']);
403+
}
404+
405+
return $address;
376406
}
377407

378408
/**
379409
* Update current resultSet with given key/value.
380410
*
381-
* @param string $type Component type
382-
* @param array<string, mixed> $value Component value
411+
* @param array<string, mixed> $component
383412
*/
384-
private function updateAddressComponent(AddressBuilder $builder, string $type, array $value): void
413+
private function updateAddressComponent(AddressBuilder $builder, string $type, array $component): void
385414
{
386-
$typeParts = explode('.', $type);
387-
$type = reset($typeParts);
415+
if (!isset($component['name']) || '' === $component['name']) {
416+
return;
417+
}
388418

389419
switch ($type) {
390420
case 'postcode':
391-
$builder->setPostalCode($value['text']);
421+
$builder->setPostalCode($component['name']);
392422

393423
break;
394424

395425
case 'locality':
396-
$builder->setLocality($value['text']);
426+
$builder->setLocality($component['name']);
397427

398428
break;
399429

400430
case 'country':
401-
$builder->setCountry($value['text']);
402-
if (isset($value['short_code'])) {
403-
$builder->setCountryCode(strtoupper($value['short_code']));
431+
$builder->setCountry($component['name']);
432+
if (isset($component['country_code'])) {
433+
$builder->setCountryCode(strtoupper((string) $component['country_code']));
404434
}
405435

406436
break;
407437

408-
case 'neighborhood':
409-
$builder->setValue($type, $value['text']);
410-
411-
break;
412-
413438
case 'place':
414-
$builder->addAdminLevel(1, $value['text']);
415-
$builder->setLocality($value['text']);
439+
$builder->addAdminLevel(1, $component['name']);
440+
$builder->setLocality($component['name']);
416441

417442
break;
418443

419444
case 'region':
420-
$code = null;
421-
if (!empty($value['short_code']) && preg_match('/[A-z]{2}-/', $value['short_code'])) {
422-
$code = preg_replace('/[A-z]{2}-/', '', $value['short_code']);
423-
}
424-
$builder->addAdminLevel(2, $value['text'], $code);
445+
$code = isset($component['region_code']) ? (string) $component['region_code'] : null;
446+
$builder->addAdminLevel(2, $component['name'], $code);
425447

426448
break;
427449

428450
default:
451+
// address, street, district, neighborhood: handled (or intentionally ignored) elsewhere
429452
}
430453
}
431454

0 commit comments

Comments
 (0)