Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Photon] Reverse Geocoding with query filters #1195

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/Provider/Photon/Photon.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ public function geocodeQuery(GeocodeQuery $query): Collection
'limit' => $query->getLimit(),
'lang' => $query->getLocale(),
]);
$osmTagFilters = $this->buildOsmTagFilterQuery($query->getData('osm_tag'));
if (!empty($osmTagFilters)) {
$url .= $osmTagFilters;
}

$json = $this->executeQuery($url);

Expand Down Expand Up @@ -98,8 +102,13 @@ public function reverseQuery(ReverseQuery $query): Collection
.http_build_query([
'lat' => $latitude,
'lon' => $longitude,
'limit' => $query->getLimit(),
'lang' => $query->getLocale(),
]);
$osmTagFilters = $this->buildOsmTagFilterQuery($query->getData('osm_tag'));
if (!empty($osmTagFilters)) {
$url .= $osmTagFilters;
}

$json = $this->executeQuery($url);

Expand Down Expand Up @@ -158,6 +167,25 @@ public function getName(): string
return 'photon';
}

/**
* @param string|array<int, string>|null $filters
*/
private function buildOsmTagFilterQuery($filters): string
{
$query = '';
if (null === $filters) {
return $query;
}
if (is_string($filters)) {
return '&osm_tag='.urlencode($filters);
}
foreach ($filters as $filter) {
$query .= '&osm_tag='.urlencode($filter);
}

return $query;
}

private function executeQuery(string $url): \stdClass
{
$content = $this->getUrlContents($url);
Expand Down
51 changes: 47 additions & 4 deletions src/Provider/Photon/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,56 @@
This is the photon provider from the PHP Geocoder. This is a **READ ONLY** repository. See the
[main repo](https://github.com/geocoder-php/Geocoder) for information and documentation.

### Install

## Install
```bash
composer require geocoder-php/photon-provider
```

### Contribute
## API Documentation
https://photon.komoot.io
https://github.com/komoot/photon

## Usage

### Basic usage
You can use your own photon instance :
```php
// New instance of the provider :
$provider = new Geocoder\Provider\Photon\Photon($httpClient, 'https://your-photon-root-url');
// Run geocode or reverse query
$query = $provider->geocodeQuery(\Geocoder\Query\GeocodeQuery::create('Paris'));
$reverseQuery = $provider->reverseQuery(\Geocoder\Query\ReverseQuery::fromCoordinates(48.86036 ,2.33852));
```

### OSM Tag Feature
You can search for location data based on osm tag filters.

For example, you can filter a geocode query to only include results of type 'place'. You can even restrict it to only have places of type 'city'.
In the reverse geocoding context you can search for the 3 pharmacies closest to a location.

To see what you can do with this feature, check [the official photon documentation](https://github.com/komoot/photon#filter-results-by-tags-and-values)

Below is an example to query the 3 pharmacies closest to a location :
```php
$provider = new Geocoder\Provider\Photon\Photon($httpClient, 'https://your-photon-root-url');
$reverseQuery = \Geocoder\Query\ReverseQuery::fromCoordinates(52.51644, 13.38890)
->withData('osm_tag', 'amenity:pharmacy')
->withLimit(3);

$results = $provider->reverseQuery($reverseQuery);
```

You can combine multiple osm tag filters :
```php
$provider = new Geocoder\Provider\Photon\Photon($httpClient, 'https://your-photon-root-url');
$reverseQuery = \Geocoder\Query\GeocodeQuery::create('Paris')
->withData('osm_tag', ['tourism', ':!museum'])
->withLimit(5);
// Here we get 5 tourism results in Paris which are not museums
$results = $provider->reverseQuery($reverseQuery);
```


Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
## Contribute
Contributions are very welcome! Send a pull request to the [main repository](https://github.com/geocoder-php/Geocoder) or
report any issues you find on the [issue tracker](https://github.com/geocoder-php/Geocoder/issues).

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s:1219:"{"features":[{"geometry":{"coordinates":[13.3879579,52.5185603],"type":"Point"},"type":"Feature","properties":{"osm_id":380498298,"country":"Deutschland","city":"Berlin","countrycode":"DE","postcode":"10117","locality":"Dorotheenstadt","type":"house","osm_type":"N","osm_key":"amenity","housenumber":"151","street":"Friedrichstraße","district":"Mitte","osm_value":"pharmacy","name":"Dorotheenstadt Apotheke"}},{"geometry":{"coordinates":[13.3874475,52.5196854],"type":"Point"},"type":"Feature","properties":{"osm_id":3331787468,"country":"Deutschland","city":"Berlin","countrycode":"DE","postcode":"10117","locality":"Dorotheenstadt","type":"house","osm_type":"N","osm_key":"amenity","housenumber":"25","street":"Georgenstraße","district":"Mitte","osm_value":"pharmacy","name":"Aschenbachs Apotheke"}},{"geometry":{"coordinates":[13.3903812,52.5122639],"type":"Point"},"type":"Feature","properties":{"osm_id":956306643,"country":"Deutschland","city":"Berlin","countrycode":"DE","postcode":"10117","locality":"Dorotheenstadt","type":"house","osm_type":"N","osm_key":"amenity","housenumber":"68","street":"Friedrichstraße","district":"Mitte","osm_value":"pharmacy","name":"Apotheke Q205"}}],"type":"FeatureCollection"}";

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s:2127:"{"features":[{"geometry":{"coordinates":[-77.0372192,38.9002248],"type":"Point"},"type":"Feature","properties":{"osm_type":"W","osm_id":1049842804,"extent":[-77.0372192,38.9002248,-77.0370581,38.9002243],"country":"United States","osm_key":"highway","city":"Washington","countrycode":"US","osm_value":"secondary","postcode":"20006","name":"H Street Northwest","state":"District of Columbia","type":"street"}},{"geometry":{"coordinates":[-77.0366811,38.9002231],"type":"Point"},"type":"Feature","properties":{"osm_type":"W","osm_id":589539534,"extent":[-77.0370581,38.9002243,-77.0365521,38.9002187],"country":"United States","osm_key":"highway","city":"Washington","countrycode":"US","osm_value":"secondary","postcode":"20006","name":"H Street Northwest","state":"District of Columbia","type":"street"}},{"geometry":{"coordinates":[-77.03689992471391,38.90050395],"type":"Point"},"type":"Feature","properties":{"osm_id":55326891,"extent":[-77.0371738,38.9006934,-77.0367231,38.9003173],"country":"United States","city":"Washington","countrycode":"US","postcode":"20006","locality":"Golden Triangle","type":"house","osm_type":"W","osm_key":"tourism","housenumber":"800","street":"Black Lives Matter Plaza Northwest","osm_value":"hotel","name":"Hay-Adams Hotel","state":"District of Columbia"}},{"geometry":{"coordinates":[-77.0374769,38.9003895],"type":"Point"},"type":"Feature","properties":{"osm_type":"N","osm_id":367142942,"country":"United States","osm_key":"building","city":"Washington","street":"H Street Northwest","countrycode":"US","osm_value":"public","postcode":"20006","name":"United States Chamber of Commerce Building","state":"District of Columbia","type":"house"}},{"geometry":{"coordinates":[-77.0364753,38.9003613],"type":"Point"},"type":"Feature","properties":{"osm_id":4957653991,"country":"United States","city":"Washington","countrycode":"US","postcode":"20062","locality":"Golden Triangle","type":"house","osm_type":"N","osm_key":"tourism","street":"Black Lives Matter Plaza Northwest","osm_value":"information","name":"16th Street Meridian","state":"District of Columbia"}}],"type":"FeatureCollection"}";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s:2187:"{"features":[{"geometry":{"coordinates":[2.2978602225671843,48.8643133],"type":"Point"},"type":"Feature","properties":{"osm_id":79219308,"extent":[2.2971088,48.8647083,2.2984772,48.8639024],"country":"France","city":"Paris","countrycode":"FR","postcode":"75116","locality":"Quartier de Chaillot","type":"house","osm_type":"W","osm_key":"tourism","street":"Rue Gaston de Saint-Paul","district":"Paris","osm_value":"museum","name":"Musée d'Art Moderne de Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.3518758,48.850724],"type":"Point"},"type":"Feature","properties":{"osm_id":237003117,"country":"France","city":"Paris","countrycode":"FR","postcode":"75005","locality":"Quartier Saint-Victor","type":"house","osm_type":"N","osm_key":"tourism","street":"Quai de la Tournelle","district":"Paris","osm_value":"museum","name":"Musée de l'Assistance Publique Hôpitaux de Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.3450724,48.8640506],"type":"Point"},"type":"Feature","properties":{"osm_id":3087374948,"country":"France","city":"Paris","countrycode":"FR","postcode":"75001","locality":"Les Halles","type":"house","osm_type":"N","osm_key":"tourism","street":"Rue du Jour","district":"Paris","osm_value":"museum","name":"Musée du Barreau de Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.3153496472839956,48.866042],"type":"Point"},"type":"Feature","properties":{"osm_id":2778854,"extent":[2.3143339,48.866628,2.3156049,48.8654594],"country":"France","city":"Paris","countrycode":"FR","postcode":"75008","locality":"Quartier des Champs-Élysées","type":"house","osm_type":"R","osm_key":"tourism","street":"Avenue Winston Churchill","district":"Paris","osm_value":"museum","name":"Petit Palais","state":"Île-de-France"}},{"geometry":{"coordinates":[2.3453019,48.8625016],"type":"Point"},"type":"Feature","properties":{"osm_id":1028569468,"country":"France","city":"Paris","countrycode":"FR","postcode":"75001","locality":"Les Halles","type":"house","osm_type":"N","osm_key":"tourism","street":"Rue du Cinéma","district":"Paris","osm_value":"museum","name":"Salle des collections","state":"Île-de-France"}}],"type":"FeatureCollection"}";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
s:2263:"{"features":[{"geometry":{"coordinates":[2.3328439,48.8587571],"type":"Point"},"type":"Feature","properties":{"osm_id":4839163372,"country":"France","city":"Paris","countrycode":"FR","postcode":"75006","locality":"Saint-Germain-des-Prés","type":"house","osm_type":"N","osm_key":"tourism","street":"Promenade Marceline Loridan-Ivens","district":"Paris","osm_value":"artwork","name":"La Ville de Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.418394477960865,48.8318844],"type":"Point"},"type":"Feature","properties":{"osm_id":26008116,"extent":[2.4141177,48.834668,2.4204695,48.8289812],"country":"France","city":"Paris","countrycode":"FR","postcode":"75012","locality":"Quartier du Bel-Air","type":"house","osm_type":"W","osm_key":"tourism","street":"Promenade Maurice-Boitel","district":"Paris","osm_value":"zoo","name":"Parc zoologique de Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.345051233260165,48.85565735],"type":"Point"},"type":"Feature","properties":{"osm_id":536982,"extent":[2.3429677,48.856811,2.3462472,48.8544964],"country":"France","city":"Paris","countrycode":"FR","postcode":"75001","locality":"Quartier Saint-Germain-l'Auxerrois","type":"house","osm_type":"R","osm_key":"tourism","street":"Cour du Premier Président","district":"Paris","osm_value":"attraction","name":"Palais de Justice de Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.2933072,48.870745],"type":"Point"},"type":"Feature","properties":{"osm_id":2990418382,"country":"France","city":"Paris","countrycode":"FR","postcode":"75116","locality":"Quartier de Chaillot","type":"house","osm_type":"N","osm_key":"tourism","street":"Avenue Kléber","district":"Paris","osm_value":"hotel","name":"The Peninsula Paris","state":"Île-de-France"}},{"geometry":{"coordinates":[2.288981354650506,48.82872115000001],"type":"Point"},"type":"Feature","properties":{"osm_id":129135460,"extent":[2.2847236,48.8321689,2.2921187,48.8253682],"country":"France","city":"Paris","countrycode":"FR","postcode":"75015","locality":"Paris Expo Porte de Versailles","type":"house","osm_type":"W","osm_key":"tourism","district":"Paris","osm_value":"attraction","name":"Parc des Expositions de Paris","state":"Île-de-France"}}],"type":"FeatureCollection"}";

This file was deleted.

52 changes: 51 additions & 1 deletion src/Provider/Photon/Tests/PhotonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
namespace Geocoder\Provider\Photon\Tests;

use Geocoder\IntegrationTest\BaseTestCase;
use Geocoder\Provider\Photon\Model\PhotonAddress;
use Geocoder\Provider\Photon\Photon;
use Geocoder\Query\GeocodeQuery;
use Geocoder\Query\ReverseQuery;
Expand Down Expand Up @@ -94,10 +95,43 @@ public function testGeocodeQueryWithNamedResult(): void
$this->assertEquals('The Sherlock Holmes Museum and shop', $result->getName());
}

public function testGeocodeQueryWithOsmTagFilter(): void
{
$provider = Photon::withKomootServer($this->getHttpClient());
$query = GeocodeQuery::create('Paris')
->withData('osm_tag', 'tourism:museum')
->withLimit(5);
$results = $provider->geocodeQuery($query);

$this->assertCount(5, $results);
foreach ($results as $result) {
$this->assertInstanceOf(PhotonAddress::class, $result);
$this->assertEquals('tourism', $result->getOSMTag()->key);
$this->assertEquals('museum', $result->getOSMTag()->value);
}
}

public function testGeocodeQueryWithMultipleOsmTagFilter(): void
{
$provider = Photon::withKomootServer($this->getHttpClient());
$query = GeocodeQuery::create('Paris')
->withData('osm_tag', ['tourism', ':!museum'])
->withLimit(5);
$results = $provider->geocodeQuery($query);

$this->assertCount(5, $results);
foreach ($results as $result) {
$this->assertInstanceOf(PhotonAddress::class, $result);
$this->assertEquals('tourism', $result->getOSMTag()->key);
$this->assertNotEquals('museum', $result->getOSMTag()->value);
}
}

public function testReverseQuery(): void
{
$provider = Photon::withKomootServer($this->getHttpClient());
$results = $provider->reverseQuery(ReverseQuery::fromCoordinates(52, 10));
$reverseQuery = ReverseQuery::fromCoordinates(52, 10)->withLimit(1);
$results = $provider->reverseQuery($reverseQuery);

$this->assertInstanceOf('Geocoder\Model\AddressCollection', $results);
$this->assertCount(1, $results);
Expand All @@ -120,4 +154,20 @@ public function testReverseQuery(): void
$this->assertEquals('Landkreis Hildesheim', $result->getCounty());
$this->assertEquals('Sehlem', $result->getDistrict());
}

public function testReverseQueryWithOsmTagFilter(): void
{
$provider = Photon::withKomootServer($this->getHttpClient());
$reverseQuery = ReverseQuery::fromCoordinates(52.51644, 13.38890)
->withData('osm_tag', 'amenity:pharmacy')
->withLimit(3);
$results = $provider->reverseQuery($reverseQuery);

$this->assertCount(3, $results);
foreach ($results as $result) {
$this->assertInstanceOf(PhotonAddress::class, $result);
$this->assertEquals('amenity', $result->getOSMTag()->key);
$this->assertEquals('pharmacy', $result->getOSMTag()->value);
}
}
}