Skip to content

Commit de0ef84

Browse files
committed
new OpenCageProvider - http://geocoder.opencagedata.com/
1 parent 0271825 commit de0ef84

9 files changed

+1210
-3
lines changed

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Currently, there are many providers for the following APIs:
4040
* ChainProvider is a special provider that takes a list of providers and iterates
4141
over this list to get information;
4242
* [MapQuest](http://open.mapquestapi.com/) as Address-Based geocoding and reverse geocoding provider;
43+
* [OpenCage](http://geocoder.opencagedata.com/) as Address-Based geocoding and reverse geocoding provider;
4344
* [OIORest](http://geo.oiorest.dk/) as very accurate Address-Based geocoding and reverse geocoding provider (exclusively in Denmark);
4445
* [GeoCoder.ca](http://geocoder.ca/) as Address-Based geocoding and reverse geocoding provider (exclusively in USA & Canada);
4546
* [GeoCoder.us](http://geocoder.us/) as Address-Based geocoding provider (exclusively in USA);
@@ -197,7 +198,13 @@ The `ChainProvider` named `chain` is a special provider that takes a list of pro
197198

198199
The `MapQuestProvider` named `map_quest` is able to geocode and reverse geocode **street addresses**.
199200
A valid api key is required. Access to [MapQuest's licensed endpoints](http://developer.mapquest.com/web/tools/getting-started/platform/licensed-vs-open)
200-
is provided via constructor agrument.
201+
is provided via constructor argument.
202+
203+
204+
### OpenCageProvider ###
205+
206+
The `OpenCageProvider` named `opencage` is able to geocode and reverse geocode **street addresses**.
207+
A valid api key is required.
201208

202209

203210
### OIORestProvider ###
@@ -357,11 +364,11 @@ $geocoder->registerProviders(array(
357364

358365
Parameters:
359366

360-
* `$locale` is available for `YandexProvider`, `BingMapsProvider` and `TomTomProvider`.
367+
* `$locale` is available for `YandexProvider`, `BingMapsProvider`, `OpenCageProvider` and `TomTomProvider`.
361368
* `$region` is available for `GoogleMapsProvider` and `GoogleMapsBusinessProvider`.
362369
* `$toponym` is available for `YandexProvider`.
363370
* `$service` is available for `MaxMindProvider`.
364-
* `$useSsl` is available for `GoogleMapsProvider`, `GoogleMapsBusinessProvider`, `MaxMindProvider` and `ArcGISOnlineProvider`.
371+
* `$useSsl` is available for `GoogleMapsProvider`, `GoogleMapsBusinessProvider`, `OpenCageProvider`, `MaxMindProvider` and `ArcGISOnlineProvider`.
365372
* `$sourceCountry` is available for `ArcGISOnlineProvider`.
366373
* `$rootUrl` is available for `NominatimProvider`.
367374

@@ -664,6 +671,7 @@ Rename the `phpunit.xml.dist` file to `phpunit.xml`, then uncomment the followin
664671
<!-- <server name="TOMTOM_GEOCODING_KEY" value="YOUR_GEOCODING_KEY" /> -->
665672
<!-- <server name="TOMTOM_MAP_KEY" value="YOUR_MAP_KEY" /> -->
666673
<!-- <server name="GOOGLE_GEOCODING_KEY" value="YOUR_GEOCODING_KEY" /> -->
674+
<!-- <server name="OPENCAGE_API_KEY" value="YOUR_API_KEY" /> -->
667675
</php>
668676
```
669677

phpunit.xml.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
<!-- <server name="TOMTOM_GEOCODING_KEY" value="YOUR_GEOCODING_KEY" /> -->
3131
<!-- <server name="TOMTOM_MAP_KEY" value="YOUR_MAP_KEY" /> -->
3232
<!-- <server name="GOOGLE_GEOCODING_KEY" value="YOUR_GEOCODING_KEY" /> -->
33+
<!-- <server name="OPENCAGE_API_KEY" value="YOUR_GEOCODING_KEY" /> -->
34+
3335
</php>
3436
<testsuites>
3537
<testsuite name="Geocoder Test Suite">
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
<?php
2+
3+
/**
4+
* This file is part of the Geocoder package.
5+
* For the full copyright and license information, please view the LICENSE
6+
* file that was distributed with this source code.
7+
*
8+
* @license MIT License
9+
*/
10+
11+
namespace Geocoder\Provider;
12+
13+
use Geocoder\Exception\InvalidCredentialsException;
14+
use Geocoder\HttpAdapter\HttpAdapterInterface;
15+
use Geocoder\Exception\NoResultException;
16+
use Geocoder\Exception\UnsupportedException;
17+
18+
/**
19+
* @author mtm <[email protected]>
20+
*/
21+
class OpenCageProvider extends AbstractProvider implements ProviderInterface
22+
{
23+
/**
24+
* @var string
25+
*/
26+
const GEOCODE_ENDPOINT_URL = '%s://api.opencagedata.com/geocode/v1/json?key=%s&query=%s&limit=%d&pretty=1';
27+
28+
/**
29+
* @var string
30+
*/
31+
private $scheme = 'http';
32+
33+
/**
34+
* @var string
35+
*/
36+
private $apiKey = null;
37+
38+
/**
39+
* @param HttpAdapterInterface $adapter An HTTP adapter.
40+
* @param string $apiKey An API key.
41+
* @param bool $useSsl Whether to use an SSL connection (optional).
42+
* @param string|null $locale A locale (optional).
43+
*/
44+
public function __construct(HttpAdapterInterface $adapter, $apiKey, $useSsl = false, $locale = null)
45+
{
46+
parent::__construct($adapter, $locale);
47+
48+
$this->apiKey = $apiKey;
49+
$this->scheme = $useSsl ? 'https' : $this->scheme;
50+
}
51+
52+
/**
53+
* {@inheritDoc}
54+
*/
55+
public function getGeocodedData($address)
56+
{
57+
// This API doesn't handle IPs
58+
if (filter_var($address, FILTER_VALIDATE_IP)) {
59+
throw new UnsupportedException('The OpenCageProvider does not support IP addresses.');
60+
}
61+
62+
if (null === $this->apiKey) {
63+
throw new InvalidCredentialsException('No API Key provided.');
64+
}
65+
66+
$query = sprintf(self::GEOCODE_ENDPOINT_URL, $this->scheme, $this->apiKey, urlencode($address), $this->getMaxResults() );
67+
68+
return $this->executeQuery($query);
69+
}
70+
71+
/**
72+
* {@inheritDoc}
73+
*/
74+
public function getReversedData(array $coordinates)
75+
{
76+
// latitude, longitude
77+
$address = sprintf("%f, %f", $coordinates[0], $coordinates[1]);
78+
79+
return $this->getGeocodedData($address);
80+
}
81+
82+
/**
83+
* {@inheritDoc}
84+
*/
85+
public function getName()
86+
{
87+
return 'opencage';
88+
}
89+
90+
/**
91+
* @param string $query
92+
*
93+
* @return array
94+
*/
95+
protected function executeQuery($query)
96+
{
97+
98+
if (null !== $this->getLocale()) {
99+
$query = sprintf('%s&language=%s', $query, $this->getLocale());
100+
}
101+
102+
$content = $this->getAdapter()->getContent($query);
103+
104+
if (null === $content) {
105+
throw new NoResultException(sprintf('Could not execute query: %s', $query));
106+
}
107+
108+
$json = json_decode($content, true);
109+
110+
if (!isset($json['total_results']) || $json['total_results'] == 0 ) {
111+
throw new NoResultException(sprintf('Could not find results for given query: %s', $query));
112+
}
113+
114+
$locations = $json['results'];
115+
116+
if (empty($locations)) {
117+
throw new NoResultException(sprintf('Could not find results for given query: %s', $query));
118+
}
119+
120+
$results = array();
121+
122+
123+
124+
foreach ($locations as $location) {
125+
126+
$bounds = null;
127+
if (isset($location['bounds'])) {
128+
$bounds = array(
129+
'south' => $location['bounds']['southwest']['lat'],
130+
'west' => $location['bounds']['southwest']['lng'],
131+
'north' => $location['bounds']['northeast']['lat'],
132+
'east' => $location['bounds']['northeast']['lng'],
133+
);
134+
}
135+
136+
$comp = $location['components'];
137+
138+
$results[] = array_merge($this->getDefaults(), array(
139+
'latitude' => $location['geometry']['lat'],
140+
'longitude' => $location['geometry']['lng'],
141+
'bounds' => $bounds ?: null,
142+
'streetNumber' => isset($comp['house_number']) ? $comp['house_number'] : null,
143+
'streetName' => isset($comp['road'] ) ? $comp['road'] : null,
144+
'cityDistrict' => isset($comp['suburb'] ) ? $comp['suburb'] : null,
145+
'city' => isset($comp['city'] ) ? $comp['city'] : null,
146+
'zipcode' => isset($comp['postcode'] ) ? $comp['postcode'] : null,
147+
'county' => isset($comp['county'] ) ? $comp['county'] : null,
148+
'region' => isset($comp['state'] ) ? $comp['state'] : null,
149+
'country' => isset($comp['country'] ) ? $comp['country'] : null,
150+
'countryCode' => isset($comp['country_code']) ? strtoupper($comp['country_code']) : null,
151+
'timezone' => isset($location['annotations']['timezone']['name']) ? $location['annotations']['timezone']['name'] : null,
152+
));
153+
}
154+
155+
return $results;
156+
}
157+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
s:2133:"{
2+
"licenses" : [
3+
{
4+
"name" : "CC-BY-SA",
5+
"url" : "http://creativecommons.org/licenses/by-sa/3.0/"
6+
},
7+
{
8+
"name" : "ODbL",
9+
"url" : "http://opendatacommons.org/licenses/odbl/summary/"
10+
}
11+
],
12+
"rate" : {
13+
"limit" : 2500,
14+
"remaining" : 2448,
15+
"reset" : 1410393600
16+
},
17+
"results" : [
18+
{
19+
"annotations" : {
20+
"OSGB" : {
21+
"easting" : 347696.195,
22+
"gridref" : "SD 476 617",
23+
"northing" : 461750.824
24+
},
25+
"OSM" : {
26+
"url" : "http://www.openstreetmap.org/?mlat=54.04888&mlon=-2.79895#map=17/54.04888/-2.79895"
27+
},
28+
"geohash" : "gcw52r3cec2m35vkre86",
29+
"timezone" : {
30+
"name" : "Europe/London",
31+
"now_in_dst" : 1,
32+
"offset_sec" : 3600,
33+
"offset_string" : 100,
34+
"short_name" : "BST"
35+
}
36+
},
37+
"bounds" : {
38+
"northeast" : {
39+
"lat" : 54.0494992,
40+
"lng" : -2.79813
41+
},
42+
"southwest" : {
43+
"lat" : 54.0482731,
44+
"lng" : -2.7998815
45+
}
46+
},
47+
"components" : {
48+
"building" : "St Nicholas Arcades",
49+
"city" : "Lancaster",
50+
"country" : "United Kingdom",
51+
"country_code" : "gb",
52+
"county" : "Lancashire",
53+
"pedestrian" : "Lancaster Gate",
54+
"state" : "England",
55+
"state_district" : "North West England",
56+
"suburb" : "Vale"
57+
},
58+
"confidence" : 10,
59+
"formatted" : "Lancaster, United Kingdom",
60+
"geometry" : {
61+
"lat" : 54.0488796,
62+
"lng" : -2.79894909568771
63+
}
64+
}
65+
],
66+
"status" : {
67+
"code" : 200,
68+
"message" : "OK"
69+
},
70+
"thanks" : "For using an OpenCage Data API",
71+
"timestamp" : {
72+
"created_http" : "Wed, 10 Sep 2014 21:12:51 GMT",
73+
"created_unix" : 1410383571
74+
},
75+
"total_results" : 1,
76+
"we_are_hiring" : "http://lokku.com/#jobs"
77+
}
78+
";

0 commit comments

Comments
 (0)