Skip to content
35 changes: 35 additions & 0 deletions src/Geocoder/Provider/GoogleMaps.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ final class GoogleMaps extends AbstractHttpProvider implements LocaleAwareProvid
*/
private $region;

/**
* @var array
*/
private $componentFilters;

/**
* @var bool
*/
Expand Down Expand Up @@ -133,13 +138,33 @@ public function getName()
return 'google_maps';
}

/**
* @param $region
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doc block is not part of the PR. You can keep this but try to avoid "code cleanups" in the same PR as features.

*
* @return $this
*/
public function setRegion($region)
{
$this->region = $region;

return $this;
}

/**
* Add components for filtering.
* https://developers.google.com/maps/documentation/geocoding/#ComponentFiltering
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really good that you provide the link, but it should be updated.

*
* @param array $filters
*
* @return $this
*/
public function setComponentFilters(array $filters)
{
$this->componentFilters = $filters;

return $this;
}

/**
* @param string $query
*
Expand Down Expand Up @@ -167,11 +192,21 @@ private function buildQuery($query)
}
}

if (!empty($this->componentFilters)) {
$componentFilters = $this->componentFilters;

$query = sprintf('%s&key=%s&components=%s', $query, $this->apiKey, implode('|', array_map(function($key) use ($componentFilters) {
return $key.':'.urlencode($componentFilters[$key]);
}, array_keys($componentFilters))));
}

return $query;
}

/**
* @param string $query
* @return \Geocoder\Model\AddressCollection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this. It is not a part of the PR and it is no longer valid.

* @throws Exception
*/
private function executeQuery($query)
{
Expand Down
60 changes: 60 additions & 0 deletions tests/Geocoder/Tests/Provider/GoogleMapsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -427,4 +427,64 @@ public function testGeocodeWithInvalidClientIdAndKeyNoSsl()
$provider = GoogleMaps::business($this->getAdapter(), 'foo', 'bogus', null, null, false);
$provider->geocode('Columbia University');
}

/**
* @expectedException \Geocoder\Exception\NoResult
* @expectedExceptionMessage Could not execute query
*/
public function testGeocodeWithComponentFiltersInvalidCountry()
{
$provider = new GoogleMaps($this->getAdapter(), 'fr-FR', 'Île-de-France');
$arrFilters = ['country' => 'ru', 'postal_code' => '75020'];
$provider->setComponentFilters($arrFilters);

$provider->geocode('10 avenue Gambetta, Paris, France');
}

/**
* @expectedException \Geocoder\Exception\NoResult
* @expectedExceptionMessage Could not execute query
*/
public function testGeocodeWithComponentFiltersInvalidZipCode()
{
$provider = new GoogleMaps($this->getAdapter(), 'fr-FR', 'Île-de-France');
$arrFilters = ['country' => 'fr', 'postal_code' => '00000'];
$provider->setComponentFilters($arrFilters);

$provider->geocode('10 avenue Gambetta, Paris, France');
}

public function testGeocodeWithValidComponentFilters()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this test be different without setComponentFilters?

I suggest that you only write a unit test that make sure the correct parameters is added on the URL. We already have functional tests that make sure the response handing is proper.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ComponentFilters are 100% optional - so without it this test will not be different, but it will fail 100%

Not sure how i can redo this - any suggestions are welcome.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of doing this functional tests we could do unit tests that verifies that the query URL has changed when using setComponentFilters. We do not actually need to execute the query and verify the result.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are 100% right, but
Here is my concern: query is formed by private function buildQuery(and only there). I can test it, but it isn the perfect solution, kind of, i think

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you mock the HttpClient and verify that the sendRequest function has a request with the preferred query?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be done, sure. Will do if no one was willing to disagree or suggest something better.
I think, buildQuery must be refactored also - but i will not do that. It is way outside my small tiny PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think, buildQuery must be refactored also - but i will not do that. It is way outside my small tiny PR.

Yes it is outside the scope.

I do not think you have to refactor anything. Just update the test code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvcaaa i did something silimar for googles result_type & location_type and wrote a unittest that checks the url.
Check out here: https://github.com/arubacao/Geocoder/blob/8f322d551b486c8c3bf6fd7fe84caaec6364797e/tests/Geocoder/Tests/Provider/GoogleMapsTest.php#L304

{
$provider = new GoogleMaps($this->getAdapter(), 'fr-FR', 'Île-de-France');
$arrFilters = ['country' => 'fr', 'postal_code' => '75020'];
$provider->setComponentFilters($arrFilters);

$results = $provider->geocode('10 avenue Gambetta, Paris, France');

$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(48.8630462, $result->getLatitude(), '', 0.001);
$this->assertEquals(2.3882487, $result->getLongitude(), '', 0.001);
$this->assertTrue($result->getBounds()->isDefined());
$this->assertEquals(48.8630462, $result->getBounds()->getSouth(), '', 0.001);
$this->assertEquals(2.3882487, $result->getBounds()->getWest(), '', 0.001);
$this->assertEquals(48.8630462, $result->getBounds()->getNorth(), '', 0.001);
$this->assertEquals(2.3882487, $result->getBounds()->getEast(), '', 0.001);
$this->assertEquals(10, $result->getStreetNumber());
$this->assertEquals('Avenue Gambetta', $result->getStreetName());
$this->assertEquals(75020, $result->getPostalCode());
$this->assertEquals('Paris', $result->getLocality());
$this->assertEquals('Paris', $result->getAdminLevels()->get(2)->getName());
$this->assertEquals('Île-de-France', $result->getAdminLevels()->get(1)->getName());
$this->assertEquals('France', $result->getCountry()->getName());
$this->assertEquals('FR', $result->getCountry()->getCode());
// not provided
$this->assertNull($result->getTimezone());
}

}