diff --git a/src/Geocoder/Provider/OpenCage.php b/src/Geocoder/Provider/OpenCage.php index c8e7c3b1c..600820af7 100644 --- a/src/Geocoder/Provider/OpenCage.php +++ b/src/Geocoder/Provider/OpenCage.php @@ -7,7 +7,6 @@ * * @license MIT License */ - namespace Geocoder\Provider; use Geocoder\Exception\InvalidCredentials; @@ -53,7 +52,7 @@ public function __construct(HttpAdapterInterface $adapter, $apiKey, $useSsl = fa } /** - * {@inheritDoc} + * {@inheritdoc} */ public function geocode($address) { @@ -66,23 +65,23 @@ public function geocode($address) throw new UnsupportedOperation('The OpenCage provider does not support IP addresses, only street addresses.'); } - $query = sprintf(self::GEOCODE_ENDPOINT_URL, $this->scheme, $this->apiKey, urlencode($address), $this->getLimit() ); + $query = sprintf(self::GEOCODE_ENDPOINT_URL, $this->scheme, $this->apiKey, urlencode($address), $this->getLimit()); return $this->executeQuery($query); } /** - * {@inheritDoc} + * {@inheritdoc} */ public function reverse($latitude, $longitude) { - $address = sprintf("%f, %f", $latitude, $longitude); + $address = sprintf('%f, %f', $latitude, $longitude); return $this->geocode($address); } /** - * {@inheritDoc} + * {@inheritdoc} */ public function getName() { @@ -90,7 +89,8 @@ public function getName() } /** - * @param string $query + * @param $query + * @return \Geocoder\Model\AddressCollection */ private function executeQuery($query) { @@ -106,7 +106,7 @@ private function executeQuery($query) $json = json_decode($content, true); - if (!isset($json['total_results']) || $json['total_results'] == 0 ) { + if (!isset($json['total_results']) || $json['total_results'] == 0) { throw new NoResult(sprintf('Could not find results for query "%s".', $query)); } @@ -122,9 +122,9 @@ private function executeQuery($query) if (isset($location['bounds'])) { $bounds = [ 'south' => $location['bounds']['southwest']['lat'], - 'west' => $location['bounds']['southwest']['lng'], + 'west' => $location['bounds']['southwest']['lng'], 'north' => $location['bounds']['northeast']['lat'], - 'east' => $location['bounds']['northeast']['lng'], + 'east' => $location['bounds']['northeast']['lng'], ]; } @@ -138,21 +138,74 @@ private function executeQuery($query) } $results[] = array_merge($this->getDefaults(), array( - 'latitude' => $location['geometry']['lat'], - 'longitude' => $location['geometry']['lng'], - 'bounds' => $bounds ?: [], + 'latitude' => $location['geometry']['lat'], + 'longitude' => $location['geometry']['lng'], + 'bounds' => $bounds ?: [], 'streetNumber' => isset($comp['house_number']) ? $comp['house_number'] : null, - 'streetName' => isset($comp['road'] ) ? $comp['road'] : null, - 'subLocality' => isset($comp['suburb'] ) ? $comp['suburb'] : null, - 'locality' => isset($comp['city'] ) ? $comp['city'] : null, - 'postalCode' => isset($comp['postcode'] ) ? $comp['postcode'] : null, - 'adminLevels' => $adminLevels, - 'country' => isset($comp['country'] ) ? $comp['country'] : null, - 'countryCode' => isset($comp['country_code']) ? strtoupper($comp['country_code']) : null, - 'timezone' => isset($location['annotations']['timezone']['name']) ? $location['annotations']['timezone']['name'] : null, + 'streetName' => $this->guessStreetName($comp), + 'subLocality' => $this->guessSubLocality($comp), + 'locality' => $this->guessLocality($comp), + 'postalCode' => isset($comp['postcode']) ? $comp['postcode'] : null, + 'adminLevels' => $adminLevels, + 'country' => isset($comp['country']) ? $comp['country'] : null, + 'countryCode' => isset($comp['country_code']) ? strtoupper($comp['country_code']) : null, + 'timezone' => isset($location['annotations']['timezone']['name']) ? $location['annotations']['timezone']['name'] : null, )); } return $this->returnResults($results); } + + /** + * @param array $components + * + * @return null|string + */ + protected function guessLocality(array $components) + { + $localityKeys = array('city', 'town' , 'village', 'hamlet'); + + return $this->guessBestComponent($components, $localityKeys); + } + + /** + * @param array $components + * + * @return null|string + */ + protected function guessStreetName(array $components) + { + $streetNameKeys = array('road', 'street', 'street_name', 'residential'); + + return $this->guessBestComponent($components, $streetNameKeys); + } + + /** + * @param array $components + * + * @return null|string + */ + protected function guessSubLocality(array $components) + { + $subLocalityKeys = array('suburb', 'neighbourhood', 'city_district'); + + return $this->guessBestComponent($components, $subLocalityKeys); + } + + /** + * @param array $components + * @param array $keys + * + * @return null|string + */ + protected function guessBestComponent(array $components, array $keys) + { + foreach ($keys as $key) { + if (isset($components[$key]) && !empty($components[$key])) { + return $components[$key]; + } + } + + return null; + } } diff --git a/tests/.cached_responses/8d579eb3ca22f821281bd4f15c3eb1c3fd73fb11 b/tests/.cached_responses/8d579eb3ca22f821281bd4f15c3eb1c3fd73fb11 new file mode 100644 index 000000000..a3101fa07 --- /dev/null +++ b/tests/.cached_responses/8d579eb3ca22f821281bd4f15c3eb1c3fd73fb11 @@ -0,0 +1,100 @@ +s:2884:"{ + "licenses" : [ + { + "name" : "CC-BY-SA", + "url" : "http://creativecommons.org/licenses/by-sa/3.0/" + }, + { + "name" : "ODbL", + "url" : "http://opendatacommons.org/licenses/odbl/summary/" + } + ], + "rate" : { + "limit" : 2500, + "remaining" : 2496, + "reset" : 1439856000 + }, + "results" : [ + { + "annotations" : { + "DMS" : { + "lat" : "49\u00b0 8' 20.73264'' N", + "lng" : "1\u00b0 39' 26.08632'' E" + }, + "MGRS" : "31UDQ0206243786", + "Maidenhead" : "JN09td83uj", + "Mercator" : { + "x" : 184483.803, + "y" : 6266161.941 + }, + "OSM" : { + "url" : "http://www.openstreetmap.org/?mlat=49.13909&mlon=1.65725#map=17/49.13909/1.65725" + }, + "callingcode" : 33, + "geohash" : "u09pt9qzbwsrft58uhm6", + "sun" : { + "rise" : { + "astronomical" : 1439779140, + "civil" : 1439784780, + "nautical" : 1439782200 + }, + "set" : { + "astronomical" : 1439845980, + "civil" : 1439840400, + "nautical" : 1439843040 + } + }, + "timezone" : { + "name" : "Europe/Paris", + "now_in_dst" : 1, + "offset_sec" : 7200, + "offset_string" : 200, + "short_name" : "CEST" + }, + "what3words" : { + "words" : "cocotier.maniable.arabesque" + } + }, + "bounds" : { + "northeast" : { + "lat" : 49.1391424, + "lng" : 1.6572962 + }, + "southwest" : { + "lat" : 49.1390424, + "lng" : 1.6571962 + } + }, + "components" : { + "country" : "France", + "country_code" : "fr", + "county" : "Pontoise", + "hotel" : "Les Jardins d'\u00c9picure", + "postcode" : "95710", + "road" : "Grande Rue", + "state" : "\u00cele-de-France", + "village" : "Bray-et-L\u00fb" + }, + "confidence" : 10, + "formatted" : "Les Jardins d'\u00c9picure, Grande Rue, 95710 Bray-et-L\u00fb, France", + "geometry" : { + "lat" : 49.1390924, + "lng" : 1.6572462 + } + } + ], + "status" : { + "code" : 200, + "message" : "OK" + }, + "stay_informed" : { + "blog" : "http://blog.opencagedata.com", + "twitter" : "https://twitter.com/opencagedata" + }, + "thanks" : "For using an OpenCage Data API", + "timestamp" : { + "created_http" : "Mon, 17 Aug 2015 14:29:15 GMT", + "created_unix" : 1439821755 + }, + "total_results" : 1 +}"; \ No newline at end of file diff --git a/tests/Geocoder/Tests/Provider/OpenCageTest.php b/tests/Geocoder/Tests/Provider/OpenCageTest.php index 113ef9e2f..9fae66096 100644 --- a/tests/Geocoder/Tests/Provider/OpenCageTest.php +++ b/tests/Geocoder/Tests/Provider/OpenCageTest.php @@ -127,6 +127,24 @@ public function testReverseWithRealCoordinates() $this->assertEquals('Europe/London' , $result->getTimezone()); } + public function testReverseWithVillage() + { + if (!isset($_SERVER['OPENCAGE_API_KEY'])) { + $this->markTestSkipped('You need to configure the OPENCAGE_API_KEY value in phpunit.xml'); + } + + $provider = new OpenCage($this->getAdapter($_SERVER['OPENCAGE_API_KEY']), $_SERVER['OPENCAGE_API_KEY']); + $results = $provider->reverse(49.1390924, 1.6572462); + + $this->assertInstanceOf('Geocoder\Model\AddressCollection', $results); + $this->assertCount(1, $results); + + /** @var \Geocoder\Model\Address $result */ + $result = $results->first(); + $this->assertInstanceOf('\Geocoder\Model\Address', $result); + $this->assertEquals('Bray-et-Lû', $result->getLocality()); + } + public function testGeocodeWithCity() { if (!isset($_SERVER['OPENCAGE_API_KEY'])) {