Skip to content

Commit 032e7b4

Browse files
sheubNyholm
authored andcommitted
Add Here Provider (#844)
* Add Here Provider * Rename here.php to Here.php * Update Here.php * Update HereAddress.php * Update Here.php * Update HereAddress.php * Update Here.php * Update Here.php * Review Corrections * + * @param string $appId An App ID. + * @param string $apoCode An App code. * Add Tests files * Add phpunit.xml.dist * Corrections after running tests * use{} * FIX IT! * Few Styles #844 * HereMaps->Here * .Some more tests * style * Build Test OK if $testIpv4 = false; * Update HereTest.php * Code review from Baachi * Update Here.php * Update Readme.md * updated Here_Test and cached_responses * Add <server name="HERE_APP_ID" value="YOUR_APP_ID" /> <server name="HERE_APP_CODE" value="YOUR_APP_CODE" /> * Update Readme.md * Reworking of the Tests with adjustments to fit the two Credentials keys (appID and AppCode) of the Here Provider * style-ci correction + override testGeocodeQueryWithNoResults, testReverseQuery and testReverseQueryWithNoResults * Styles * Update IntegrationTest.php * Correct the extends and the naming (to HereCachedResponseClient)
0 parents  commit 032e7b4

17 files changed

+916
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.lock
3+
phpunit.xml

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
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.

Here.php

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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\Here;
14+
15+
use Geocoder\Collection;
16+
use Geocoder\Exception\InvalidCredentials;
17+
use Geocoder\Exception\UnsupportedOperation;
18+
use Geocoder\Model\AddressBuilder;
19+
use Geocoder\Model\AddressCollection;
20+
use Geocoder\Query\GeocodeQuery;
21+
use Geocoder\Query\ReverseQuery;
22+
use Geocoder\Http\Provider\AbstractHttpProvider;
23+
use Geocoder\Provider\Provider;
24+
use Geocoder\Provider\Here\Model\HereAddress;
25+
use Http\Client\HttpClient;
26+
27+
/**
28+
* @author Sébastien Barré <[email protected]>
29+
*/
30+
final class Here extends AbstractHttpProvider implements Provider
31+
{
32+
/**
33+
* @var string
34+
*/
35+
const GEOCODE_ENDPOINT_URL = 'https://geocoder.api.here.com/6.2/geocode.json?app_id=%s&app_code=%s&searchtext=%s&gen=8';
36+
37+
/**
38+
* @var string
39+
*/
40+
const REVERSE_ENDPOINT_URL = 'https://reverse.geocoder.api.here.com/6.2/reversegeocode.json?prox=%F,%F&250&app_id=%s&app_code=%s&mode=retrieveAddresses&gen=8&maxresults=%d';
41+
42+
/**
43+
* @var string
44+
*/
45+
private $appId = null;
46+
47+
/**
48+
* @var string
49+
*/
50+
private $appCode = null;
51+
52+
/**
53+
* @param HttpClient $adapter An HTTP adapter.
54+
* @param string $appId An App ID.
55+
* @param string $apoCode An App code.
56+
*/
57+
public function __construct(HttpClient $client, string $appId, string $appCode)
58+
{
59+
if (empty($appId) || empty($appCode)) {
60+
throw new InvalidCredentials('Invalid or missing api key.');
61+
}
62+
$this->appId = $appId;
63+
$this->appCode = $appCode;
64+
65+
parent::__construct($client);
66+
}
67+
68+
/**
69+
* {@inheritdoc}
70+
*/
71+
public function geocodeQuery(GeocodeQuery $query): Collection
72+
{
73+
// This API doesn't handle IPs
74+
if (filter_var($query->getText(), FILTER_VALIDATE_IP)) {
75+
throw new UnsupportedOperation('The Here provider does not support IP addresses, only street addresses.');
76+
}
77+
78+
$url = sprintf(self::GEOCODE_ENDPOINT_URL, $this->appId, $this->appCode, rawurlencode($query->getText()));
79+
80+
if (null !== $query->getLocale()) {
81+
$url = sprintf('%s&language=%s', $url, $query->getLocale());
82+
}
83+
84+
return $this->executeQuery($url, $query->getLimit());
85+
}
86+
87+
/**
88+
* {@inheritdoc}
89+
*/
90+
public function reverseQuery(ReverseQuery $query): Collection
91+
{
92+
$coordinates = $query->getCoordinates();
93+
$url = sprintf(self::REVERSE_ENDPOINT_URL, $coordinates->getLatitude(), $coordinates->getLongitude(), $this->appId, $this->appCode, $query->getLimit());
94+
95+
return $this->executeQuery($url, $query->getLimit());
96+
}
97+
98+
/**
99+
* @param string $url
100+
* @param string $locale
101+
* @param int $limit
102+
*
103+
* @return \Geocoder\Collection
104+
*/
105+
private function executeQuery(string $url, int $limit): Collection
106+
{
107+
$content = $this->getUrlContents($url);
108+
$json = json_decode($content, true);
109+
110+
if (isset($json['type'])) {
111+
switch ($json['type']['subtype']) {
112+
case 'InvalidInputData':
113+
throw new InvalidArgument('Input parameter validation failed.');
114+
case 'QuotaExceeded':
115+
throw new QuotaExceeded('Valid request but quota exceeded.');
116+
case 'InvalidCredentials':
117+
throw new InvalidCredentials('Invalid or missing api key.');
118+
}
119+
}
120+
121+
if (!isset($json['Response']) || empty($json['Response'])) {
122+
return new AddressCollection([]);
123+
}
124+
125+
if (!isset($json['Response']['View'][0])) {
126+
return new AddressCollection([]);
127+
}
128+
129+
$locations = $json['Response']['View'][0]['Result'];
130+
131+
foreach ($locations as $loc) {
132+
$location = $loc['Location'];
133+
$builder = new AddressBuilder($this->getName());
134+
$coordinates = isset($location['NavigationPosition'][0]) ? $location['NavigationPosition'][0] : $location['DisplayPosition'];
135+
$builder->setCoordinates($coordinates['Latitude'], $coordinates['Longitude']);
136+
$bounds = $location['MapView'];
137+
138+
$builder->setBounds($bounds['BottomRight']['Latitude'], $bounds['TopLeft']['Longitude'], $bounds['TopLeft']['Latitude'], $bounds['BottomRight']['Longitude']);
139+
$builder->setStreetNumber($location['Address']['HouseNumber'] ?? null);
140+
$builder->setStreetName($location['Address']['Street'] ?? null);
141+
$builder->setPostalCode($location['Address']['PostalCode'] ?? null);
142+
$builder->setLocality($location['Address']['City'] ?? null);
143+
$builder->setSubLocality($location['Address']['District'] ?? null);
144+
$builder->setCountry($location['Address']['AdditionalData'][0]['value'] ?? null);
145+
$builder->setCountryCode($location['Address']['Country'] ?? null);
146+
147+
$address = $builder->build(HereAddress::class);
148+
$address = $address->withLocationId($location['LocationId']);
149+
$address = $address->withLocationType($location['LocationType']);
150+
$results[] = $address;
151+
152+
if (count($results) >= $limit) {
153+
break;
154+
}
155+
}
156+
157+
return new AddressCollection($results);
158+
}
159+
160+
/**
161+
* {@inheritdoc}
162+
*/
163+
public function getName(): string
164+
{
165+
return 'Here';
166+
}
167+
}

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018 — Sébastien Barré <[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.

Model/HereAddress.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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\Here\Model;
14+
15+
use Geocoder\Model\Address;
16+
17+
/**
18+
* @author sébastien Barré <[email protected]>
19+
*/
20+
final class HereAddress extends Address
21+
{
22+
/**
23+
* @var string|null
24+
*/
25+
private $locationId;
26+
27+
/**
28+
* @var string|null
29+
*/
30+
private $locationType;
31+
32+
/**
33+
* @var string|null
34+
*/
35+
private $locationName;
36+
37+
/**
38+
* @return null|string
39+
*/
40+
public function getLocationId()
41+
{
42+
return $this->locationId;
43+
}
44+
45+
/**
46+
* @param null|string $LocationId
47+
*
48+
* @return HereAddress
49+
*/
50+
public function withLocationId(string $locationId = null): self
51+
{
52+
$new = clone $this;
53+
$new->locationId = $locationId;
54+
55+
return $new;
56+
}
57+
58+
/**
59+
* @return null|string
60+
*/
61+
public function getLocationType()
62+
{
63+
return $this->locationType;
64+
}
65+
66+
/**
67+
* @param null|string $LocationType
68+
*
69+
* @return HereAddress
70+
*/
71+
public function withLocationType(string $locationType = null): self
72+
{
73+
$new = clone $this;
74+
$new->locationType = $locationType;
75+
76+
return $new;
77+
}
78+
79+
/**
80+
* @return null|string
81+
*/
82+
public function getLocationName()
83+
{
84+
return $this->locationName;
85+
}
86+
87+
/**
88+
* @param null|string $LocationName
89+
*
90+
* @return HereAddress
91+
*/
92+
public function withLocationName(string $locationName = null): self
93+
{
94+
$new = clone $this;
95+
$new->locationName = $locationName;
96+
97+
return $new;
98+
}
99+
}

Readme.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Here Geocoder provider
2+
[![Build Status](https://travis-ci.org/geocoder-php/here-provider.svg?branch=master)](http://travis-ci.org/geocoder-php/nominatim-provider)
3+
[![Latest Stable Version](https://poser.pugx.org/geocoder-php/here-provider/v/stable)](https://packagist.org/packages/geocoder-php/nominatim-provider)
4+
[![Total Downloads](https://poser.pugx.org/geocoder-php/here-provider/downloads)](https://packagist.org/packages/geocoder-php/nominatim-provider)
5+
[![Monthly Downloads](https://poser.pugx.org/geocoder-php/here-provider/d/monthly.png)](https://packagist.org/packages/geocoder-php/nominatim-provider)
6+
[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/geocoder-php/here-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/nominatim-provider)
7+
[![Quality Score](https://img.shields.io/scrutinizer/g/geocoder-php/here-provider.svg?style=flat-square)](https://scrutinizer-ci.com/g/geocoder-php/nominatim-provider)
8+
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
9+
10+
This is the Here provider from the PHP Geocoder. This is a **READ ONLY** repository. See the
11+
[main repo](https://github.com/geocoder-php/Geocoder) for information and documentation.
12+
13+
### Install
14+
15+
```bash
16+
composer require geocoder-php/here-provider
17+
```
18+
### Note
19+
## App Id and App Code
20+
Get your Here credentials at https://developer.here.com/
21+
22+
## Language parameter
23+
Define the preferred language of address elements in the result. Without a preferred language, the Here Geocoder will return results in an official country language or in a regional primary language so that local people will understand. Language code must be provided according to RFC 4647 standard.
24+
25+
### Contribute
26+
27+
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
28+
report any issues you find on the [issue tracker](https://github.com/geocoder-php/Geocoder/issues).
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
s:80:"{"Response":{"MetaInfo":{"Timestamp":"2018-06-22T09:46:26.209+0000"},"View":[]}}";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
s:991:"{"Response":{"MetaInfo":{"Timestamp":"2018-06-22T09:46:25.259+0000"},"View":[{"_type":"SearchResultsViewType","ViewId":0,"Result":[{"Relevance":1.0,"MatchLevel":"houseNumber","MatchQuality":{"Country":1.0,"City":1.0,"Street":[1.0],"HouseNumber":1.0},"MatchType":"pointAddress","Location":{"LocationId":"NT_0cb6yPlJYuup8k2I7emOLA_xAD","LocationType":"address","DisplayPosition":{"Latitude":48.8653,"Longitude":2.39844},"NavigationPosition":[{"Latitude":48.86518,"Longitude":2.39873}],"MapView":{"TopLeft":{"Latitude":48.8664242,"Longitude":2.3967311},"BottomRight":{"Latitude":48.8641758,"Longitude":2.4001489}},"Address":{"Label":"10 Avenue Gambetta, 75020 Paris, France","Country":"FRA","State":"Île-de-France","County":"Paris","City":"Paris","District":"20e Arrondissement","Street":"Avenue Gambetta","HouseNumber":"10","PostalCode":"75020","AdditionalData":[{"value":"France","key":"CountryName"},{"value":"Île-de-France","key":"StateName"},{"value":"Paris","key":"CountyName"}]}}}]}]}}";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
s:994:"{"Response":{"MetaInfo":{"Timestamp":"2018-06-20T18:12:16.673+0000"},"View":[{"_type":"SearchResultsViewType","ViewId":0,"Result":[{"Relevance":1.0,"MatchLevel":"houseNumber","MatchQuality":{"Country":1.0,"City":1.0,"Street":[1.0],"HouseNumber":1.0},"MatchType":"pointAddress","Location":{"LocationId":"NT_lWsc8knsFwVitNTFX88zmA_xAD","LocationType":"address","DisplayPosition":{"Latitude":51.50341,"Longitude":-0.12765},"NavigationPosition":[{"Latitude":51.50315,"Longitude":-0.12678}],"MapView":{"TopLeft":{"Latitude":51.5045342,"Longitude":-0.129456},"BottomRight":{"Latitude":51.5022858,"Longitude":-0.125844}},"Address":{"Label":"10 Downing Street, London, SW1A 2, United Kingdom","Country":"GBR","State":"England","County":"London","City":"London","District":"Westminster","Street":"Downing Street","HouseNumber":"10","PostalCode":"SW1A 2","AdditionalData":[{"value":"United Kingdom","key":"CountryName"},{"value":"England","key":"StateName"},{"value":"London","key":"CountyName"}]}}}]}]}}";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
s:80:"{"Response":{"MetaInfo":{"Timestamp":"2018-06-22T09:46:26.756+0000"},"View":[]}}";

0 commit comments

Comments
 (0)