Skip to content

Commit 83d8417

Browse files
authored
Add MapTiler provider (#1113)
* [MapTiler] Initial commit * Apply StyleCI fixes * Update cached responses * Add bbox parameter * Fix result location * Add missing Bounds class * Extract country and locality from context * Update tests * Apply StyleCI fixes * Add MAPTILER_KEY to main phpunit.xml.dist
1 parent 2f0f516 commit 83d8417

19 files changed

+515
-0
lines changed

phpunit.xml.dist

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<server name="GEOCODE_EARTH_API_KEY" value="YOUR_GEOCODE_EARTH_API_KEY"/>
5454
<server name="OPEN_ROUTE_SERVICE_API_KEY" value="YOUR_OPEN_ROUTE_SERVICE_API_KEY"/>
5555
<server name="AZURE_MAPS_SUBSCRIPTION_KEY" value="YOUR_AZURE_MAPS_SUBSCRIPTION_KEY"/>
56+
<server name="MAPTILER_KEY" value="YOUR_MAPTILER_KEY"/>
5657
<!--<server name="MAXMIND_API_KEY" value="YOUR_API_KEY" />-->
5758
</php>
5859
<testsuites>

src/Provider/MapTiler/.gitattributes

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.gitattributes export-ignore
2+
.travis.yml export-ignore
3+
phpunit.xml.dist export-ignore
4+
Tests/ export-ignore

src/Provider/MapTiler/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml

src/Provider/MapTiler/.travis.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: php
2+
3+
matrix:
4+
fast_finish: true
5+
include:
6+
- php: 7.3
7+
- php: 7.4
8+
- php: 8.0
9+
10+
install:
11+
- composer update --prefer-stable --prefer-dist
12+
13+
script:
14+
- composer test-ci
15+
16+
after_success:
17+
- wget https://scrutinizer-ci.com/ocular.phar
18+
- php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml

src/Provider/MapTiler/CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Change Log
2+
3+
The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release.
4+
5+
## 1.0.0
6+
7+
First release of this library.

src/Provider/MapTiler/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2011 — William Durand <[email protected]>
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

src/Provider/MapTiler/MapTiler.php

+183
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
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\MapTiler;
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\Model\Bounds;
25+
use Geocoder\Provider\Provider;
26+
use Http\Client\HttpClient;
27+
28+
/**
29+
* @author Jonathan Beliën
30+
*/
31+
final class MapTiler extends AbstractHttpProvider implements Provider
32+
{
33+
/**
34+
* @var string
35+
*/
36+
const ENDPOINT_URL = 'https://api.maptiler.com/geocoding/%s.json?key=%s';
37+
38+
/**
39+
* @var string
40+
*/
41+
private $apiKey;
42+
43+
/**
44+
* @param HttpClient $client an HTTP client
45+
* @param string $key API key
46+
*/
47+
public function __construct(HttpClient $client, string $apiKey)
48+
{
49+
parent::__construct($client);
50+
51+
$this->apiKey = $apiKey;
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function geocodeQuery(GeocodeQuery $query): Collection
58+
{
59+
$address = $query->getText();
60+
61+
// This API doesn't handle IPs
62+
if (filter_var($address, FILTER_VALIDATE_IP)) {
63+
throw new UnsupportedOperation('The MapTiler provider does not support IP addresses.');
64+
}
65+
66+
$url = sprintf(self::ENDPOINT_URL, $address, $this->apiKey);
67+
68+
$json = $this->executeQuery($url, $query->getLocale(), $query->getBounds());
69+
70+
if (!isset($json->features) || empty($json->features)) {
71+
return new AddressCollection([]);
72+
}
73+
74+
$results = [];
75+
foreach ($json->features as $feature) {
76+
$results[] = $this->featureToAddress($feature);
77+
}
78+
79+
return new AddressCollection($results);
80+
}
81+
82+
/**
83+
* {@inheritdoc}
84+
*/
85+
public function reverseQuery(ReverseQuery $query): Collection
86+
{
87+
$coordinates = $query->getCoordinates();
88+
89+
$url = sprintf(self::ENDPOINT_URL, implode(',', $coordinates->toArray()), $this->apiKey);
90+
91+
$json = $this->executeQuery($url, $query->getLocale());
92+
93+
if (!isset($json->features) || empty($json->features)) {
94+
return new AddressCollection([]);
95+
}
96+
97+
$results = [];
98+
foreach ($json->features as $feature) {
99+
$results[] = $this->featureToAddress($feature);
100+
}
101+
102+
return new AddressCollection($results);
103+
}
104+
105+
/**
106+
* @param \stdClass $feature
107+
*
108+
* @return Location
109+
*/
110+
private function featureToAddress(\stdClass $feature): Location
111+
{
112+
$builder = new AddressBuilder($this->getName());
113+
114+
$coordinates = 'Point' === $feature->geometry->type ? $feature->geometry->coordinates : $feature->center;
115+
116+
$builder->setCoordinates(floatval($coordinates[1]), floatval($coordinates[0]));
117+
118+
if (in_array('street', $feature->place_type, true)) {
119+
$builder->setStreetName($feature->text);
120+
} elseif (in_array('subcity', $feature->place_type, true)) {
121+
$builder->setSubLocality($feature->text);
122+
} elseif (in_array('city', $feature->place_type, true)) {
123+
$builder->setLocality($feature->text);
124+
}
125+
126+
if (isset($feature->bbox)) {
127+
$builder->setBounds($feature->bbox[0], $feature->bbox[2], $feature->bbox[1], $feature->bbox[3]);
128+
}
129+
130+
$this->extractFromContext($builder, $feature->context ?? []);
131+
132+
return $builder->build();
133+
}
134+
135+
private function extractFromContext(AddressBuilder &$builder, array $context): AddressBuilder
136+
{
137+
$cityContext = array_filter($context, function ($c) { return 1 === preg_match('/^city\.\d+$/', $c->id); });
138+
if (count($cityContext) > 0) {
139+
$city = current($cityContext);
140+
$builder->setLocality($city->text);
141+
}
142+
143+
$countryContext = array_filter($context, function ($c) { return 1 === preg_match('/^country\.\d+$/', $c->id); });
144+
if (count($countryContext) > 0) {
145+
$country = current($countryContext);
146+
$builder->setCountry($country->text);
147+
}
148+
149+
return $builder;
150+
}
151+
152+
/**
153+
* {@inheritdoc}
154+
*/
155+
public function getName(): string
156+
{
157+
return 'maptiler';
158+
}
159+
160+
/**
161+
* @param string $url
162+
*
163+
* @return \stdClass
164+
*/
165+
private function executeQuery(string $url, string $locale = null, Bounds $bounds = null): \stdClass
166+
{
167+
$url .= '&'.http_build_query([
168+
'language' => $locale,
169+
'bbox' => !is_null($bounds) ? implode(',', $bounds->toArray()) : null,
170+
]);
171+
172+
$content = $this->getUrlContents($url);
173+
174+
$json = json_decode($content);
175+
176+
// API error
177+
if (is_null($json)) {
178+
throw InvalidServerResponse::create($url);
179+
}
180+
181+
return $json;
182+
}
183+
}

src/Provider/MapTiler/README.md

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# MapTiler Geocoder provider
2+
3+
[![Build Status](https://travis-ci.org/geocoder-php/maptiler-provider.svg?branch=master)](http://travis-ci.org/geocoder-php/maptiler-provider)
4+
[![Latest Stable Version](https://poser.pugx.org/geocoder-php/maptiler-provider/v/stable)](https://packagist.org/packages/geocoder-php/maptiler-provider)
5+
[![Total Downloads](https://poser.pugx.org/geocoder-php/maptiler-provider/downloads)](https://packagist.org/packages/geocoder-php/maptiler-provider)
6+
[![Monthly Downloads](https://poser.pugx.org/geocoder-php/maptiler-provider/d/monthly.png)](https://packagist.org/packages/geocoder-php/maptiler-provider)
7+
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/geocoder-php/maptiler-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/maptiler-provider)
8+
[![Quality Score](https://img.shields.io/scrutinizer/g/geocoder-php/maptiler-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/maptiler-provider)
9+
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
10+
11+
This is the maptiler provider from the PHP Geocoder. This is a **READ ONLY** repository. See the
12+
[main repo](https://github.com/geocoder-php/Geocoder) for information and documentation.
13+
14+
### Install
15+
16+
```bash
17+
composer require geocoder-php/maptiler-provider
18+
```
19+
20+
### Contribute
21+
22+
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
23+
report any issues you find on the [issue tracker](https://github.com/geocoder-php/Geocoder/issues).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
s:298:"{"type":"FeatureCollection","query":["jsajhgsdkfjhsfkjhaldkadjaslgldasd"],"features":[],"attribution":"<a href=\"https://www.maptiler.com/copyright/\" target=\"_blank\">&copy; MapTiler</a> <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">&copy; OpenStreetMap contributors</a>"}";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
s:6124:"{"type":"FeatureCollection","query":["avenue","gambetta","paris","france"],"features":[{"id":"street.51568494","type":"Feature","place_type":["street"],"relevance":1,"properties":{"osm_id":"way51568494"},"text":"Avenue Gambetta","place_name":"Avenue Gambetta, Campagne à Paris, Paris, Paris, Ile-de-France","center":[2.3993232,48.8658863],"geometry":{"type":"GeometryCollection","geometries":[{"type":"MultiLineString","coordinates":[[[2.39791024,48.86491949],[2.39796422,48.86491748]],[[2.39791024,48.86491949],[2.39796422,48.86491748]],[[2.39791024,48.86491949],[2.39796422,48.86491748]],[[2.39791024,48.86491949],[2.39796422,48.86491748]],[[2.39796422,48.86491748],[2.39818567,48.86490919]],[[2.39796422,48.86491748],[2.39818567,48.86490919]],[[2.39796422,48.86491748],[2.39818567,48.86490919]],[[2.39796422,48.86491748],[2.39818567,48.86490919]],[[2.3976722,48.86492855],[2.39791024,48.86491949]],[[2.3976722,48.86492855],[2.39791024,48.86491949]],[[2.3976722,48.86492855],[2.39791024,48.86491949]],[[2.3976722,48.86492855],[2.39791024,48.86491949]],[[2.39554839,48.86499518],[2.3976722,48.86492855]],[[2.39554839,48.86499518],[2.3976722,48.86492855]],[[2.39554839,48.86499518],[2.3976722,48.86492855]],[[2.39554839,48.86499518],[2.3976722,48.86492855]],[[2.40638057,48.87674812],[2.40597246,48.87567054]],[[2.40647244,48.876986],[2.40663974,48.87700519]],[[2.39932318,48.86588635],[2.39988384,48.86654005]],[[2.39932318,48.86588635],[2.39988384,48.86654005]],[[2.39932318,48.86588635],[2.39988384,48.86654005]],[[2.39932318,48.86588635],[2.39988384,48.86654005]]]},{"type":"MultiPoint","coordinates":[[2.3968889,48.8655145],[2.3977123,48.8666327],[2.3961174,48.8661272],[2.3879599,48.8628656],[2.3980319,48.8651632],[2.3984435,48.8652957],[2.397445,48.8648546],[2.3989861,48.8650884],[2.3976202,48.8650269],[2.3978113,48.8650197],[2.3985883,48.8652932],[2.3979294,48.8650579],[2.3973119,48.8650741],[2.3978624,48.8653227],[2.3976656,48.8653382],[2.3977909,48.8654313],[2.3975409,48.8650829],[2.3982557,48.8653828],[2.3981876,48.8654696],[2.3979859,48.8653372],[2.3973788,48.8651243],[2.3975959,48.8651241],[2.3974486,48.8651763],[2.397701,48.8652024],[2.3974828,48.8652019],[2.3977661,48.8652507],[2.3986834,48.8653241],[2.3975636,48.8652621],[2.39853,48.8656988],[2.3977603,48.8660169],[2.397578,48.86625],[2.397417,48.8664559],[2.3965452,48.8664493],[2.3960454,48.8659781],[2.3959914,48.8659514],[2.396211,48.8658558],[2.3961068,48.8658323],[2.3962065,48.8657655],[2.3975264,48.8659257],[2.3975889,48.8648492],[2.3977727,48.864842],[2.3994979,48.8669679],[2.3999885,48.8668276],[2.3981956,48.8655718],[2.3992319,48.8670278],[2.3983199,48.8656631],[2.3993247,48.8669423],[2.3981229,48.8656786],[2.3983842,48.8657106],[2.3982262,48.8657561],[2.3987002,48.8658913],[2.3983184,48.8658502],[2.3976121,48.8657615],[2.3989757,48.8660153],[2.3985475,48.8659537],[2.3978212,48.865939],[2.39799,48.8657233],[2.3976717,48.8661303],[2.397513,48.866333],[2.3972824,48.8666281],[2.3973523,48.8665385],[2.3986695,48.8660094],[2.3977646,48.8656216],[2.397585,48.865851],[2.3987816,48.8660604],[2.3976947,48.8657107],[2.3973652,48.8661313],[2.3972298,48.8663044],[2.39744,48.8660355],[2.3988845,48.8661069],[2.3990006,48.8661593],[2.399608,48.8666806],[2.3990681,48.8661934],[2.3991933,48.8662489],[2.3993136,48.8662986],[2.3993965,48.8663348],[2.397384,48.8656937],[2.3995057,48.8663821],[2.3996112,48.8664278],[2.3976916,48.8669887],[2.3972858,48.8655976],[2.3995134,48.866769],[2.4002001,48.8667062],[2.3979806,48.8671394],[2.3973283,48.8667095],[2.3973109,48.8656212],[2.3997309,48.8667523],[2.3975692,48.8668209],[2.3976574,48.8668623],[2.3977927,48.8668838],[2.3978818,48.8669263],[2.3979744,48.8670114],[2.3994332,48.8668439],[2.3980875,48.8670641],[2.3981612,48.8670986],[2.3995901,48.866882],[2.3992006,48.8659208],[2.3993193,48.8660583],[2.3996743,48.8664648],[2.3997201,48.8665182],[2.3981685,48.8662114],[2.3982049,48.8660092],[2.3979808,48.8662216],[2.3978904,48.8663075],[2.3977683,48.8664231],[2.3975479,48.8666321],[2.398411,48.8659707],[2.3983224,48.8658977],[2.3981175,48.866092],[2.3983128,48.866064],[2.3982758,48.8659421],[2.3979017,48.8664531],[2.3980056,48.8663546],[2.3971757,48.8648022],[2.3971109,48.8648353],[2.4061134,48.8763955],[2.4059371,48.8759539],[2.4061663,48.8765281],[2.4062376,48.8767061],[2.4062714,48.8767911],[2.4047705,48.8765464],[2.4050355,48.8766341],[2.4052051,48.8766903],[2.4053472,48.8767371],[2.4055643,48.8768089],[2.4057177,48.8768543],[2.4054461,48.8767697],[2.4058728,48.8768914],[2.4060009,48.876922],[2.4051634,48.8740552],[2.4055141,48.8741732],[2.4052011,48.8741363],[2.3963819,48.8648955],[2.3965612,48.8648886],[2.396755,48.8648809],[2.3968971,48.8648753],[2.3970648,48.8648587],[2.3957786,48.8650974],[2.3956395,48.8651026],[2.3958957,48.8650929],[2.3960729,48.8650859],[2.396193,48.8650813],[2.3963192,48.865077],[2.3964395,48.8650725],[2.3965955,48.8650668],[2.3969641,48.865053],[2.3967556,48.865061],[2.3971217,48.8650466],[2.3970924,48.8664795],[2.3960749,48.8661011],[2.3964054,48.8663832],[2.3966131,48.8665142],[2.3961748,48.8661643],[2.3967047,48.8665565],[2.3962526,48.8662002],[2.3967617,48.8665825],[2.3963955,48.8662676],[2.3964732,48.8663044],[2.3965212,48.866327],[2.3966953,48.8664091],[2.3967664,48.8664428],[2.3968188,48.8664676],[2.3968654,48.8664896],[2.3969463,48.8665277],[2.3998742,48.8669118],[2.4024535,48.8702781],[2.3962146,48.8650889],[2.3975371,48.8647332],[2.3973193,48.8647294],[2.3975075,48.8646339],[2.3976781,48.8646616]]}]},"context":[{"id":"subcity.3234185968","osm_id":"node3234185968","text":"Campagne à Paris"},{"id":"city.7444","osm_id":"relation7444","text":"Paris"},{"id":"county.71525","osm_id":"relation71525","text":"Paris"},{"id":"country.2202162","osm_id":"relation2202162","text":"France"},{"id":"state.8649","osm_id":"relation8649","text":"Ile-de-France"}],"bbox":[2.3879599,48.8628656,2.40663974,48.87700519]}],"attribution":"<a href=\"https://www.maptiler.com/copyright/\" target=\"_blank\">&copy; MapTiler</a> <a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">&copy; OpenStreetMap contributors</a>"}";

0 commit comments

Comments
 (0)