From 40a7b4aa288ef9179d506b3099f993a475458332 Mon Sep 17 00:00:00 2001 From: Jens Wiese Date: Wed, 9 Apr 2014 12:26:10 +0200 Subject: [PATCH 1/3] Implement MaxData GeoIP2 provider and database adapter Update README.md, add requirements/suggest to composer.json. --- README.md | 10 + composer.json | 7 +- .../HttpAdapter/GeoIP2DatabaseAdapter.php | 168 ++++++++++++++++ .../Provider/GeoIP2DatabaseProvider.php | 108 ++++++++++ .../HttpAdapter/GeoIP2DatabaseAdapterTest.php | 166 ++++++++++++++++ .../Provider/GeoIP2DatabaseProviderTest.php | 185 ++++++++++++++++++ 6 files changed, 642 insertions(+), 2 deletions(-) create mode 100644 src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php create mode 100644 src/Geocoder/Provider/GeoIP2DatabaseProvider.php create mode 100644 tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php create mode 100644 tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php diff --git a/README.md b/README.md index 3a168bde4..3a422c825 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Currently, there are the following adapters: * `GuzzleHttpAdapter` to use [Guzzle](https://github.com/guzzle/guzzle), PHP 5.3+ HTTP client and framework for building RESTful web service clients; * `SocketHttpAdapter` to use a [socket](http://www.php.net/manual/function.fsockopen.php); * `ZendHttpAdapter` to use [Zend Http Client](http://framework.zend.com/manual/2.0/en/modules/zend.http.client.html). +* `GeoIP2DatabaseAdapter` to use [GeoIP2 Database Reader by MaxMind](https://github.com/maxmind/GeoIP2-php#database-reader). ### Providers ### @@ -49,6 +50,7 @@ Currently, there are many providers for the following APIs: * [GeoIPs](http://www.geoips.com/developer/geoips-api) as IP-Based geocoding provider; * [MaxMind web service](http://dev.maxmind.com/geoip/legacy/web-services) as IP-Based geocoding provider (City/ISP/Org and Omni services); * [MaxMind binary file](http://dev.maxmind.com/geoip/legacy/downloadable) as IP-Based geocoding provider; +* [MaxMind GeoIP2 database file](http://www.maxmind.com/en/city) as IP-Based geocoding provider; * [Geonames](http://www.geonames.org/) as Place-Based geocoding and reverse geocoding provider; * [IpGeoBase](http://ipgeobase.ru/) as IP-Based geocoding provider (very accurate in Russia); * [Baidu](http://developer.baidu.com/map/geocoding-api.htm) as Address-Based geocoding and reverse geocoding provider (exclusively in China); @@ -259,6 +261,14 @@ package must be installed. It is worth mentioning that this provider has **serious performance issues**, and should **not** be used in production. For more information, please read [issue #301](https://github.com/geocoder-php/Geocoder/issues/301). +### GeoIP2DatabaseProvider ### + +The `GeoIP2DatabaseProvider` named `geoip2_database` is able to geocode **IPv4 and IPv6 addresses** +only - it makes use of the MaxMind GeoIP2 databases. + +It requires the [database file](http://dev.maxmind.com/geoip/geoip2/geolite2/), and the [geoip2/geoip2](https://packagist.org/packages/geoip2/geoip2) package must be installed. + +This provider will only work with the corresponding `GeoIP2DatabaseAdapter`. ### GeonamesProvider ### diff --git a/composer.json b/composer.json index 62ce76ece..794f33fbd 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,9 @@ "kriswallsmith/buzz": "@stable", "guzzle/guzzle": "@stable", "zendframework/zend-http": "~2.1", - "geoip/geoip": "~1.13" + "geoip/geoip": "~1.13", + "geoip2/geoip2": "~0.6", + "mikey179/vfsStream": "v1.2.0" }, "suggest": { "kriswallsmith/buzz": "Enabling Buzz allows you to use the BuzzHttpAdapter.", @@ -26,7 +28,8 @@ "ext-geoip": "Enabling the geoip extension allows you to use the MaxMindProvider.", "guzzle/guzzle": "Enabling Guzzle allows you to use the GuzzleHttpAdapter.", "zendframework/zend-http": "Enabling Zend Http allows you to use the ZendHttpAdapter.", - "geoip/geoip": "If you are going to use the MaxMindBinaryProvider (conflict with geoip extension)." + "geoip/geoip": "If you are going to use the MaxMindBinaryProvider (conflict with geoip extension).", + "geoip2/geoip2": "If you are going to use the GeoIP2DatabaseProvider." }, "autoload": { "psr-0": { "Geocoder": "src/" } diff --git a/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php b/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php new file mode 100644 index 000000000..8fd7db2c6 --- /dev/null +++ b/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php @@ -0,0 +1,168 @@ + + */ +class GeoIP2DatabaseAdapter implements HttpAdapterInterface +{ + /** + * Database file types + */ + const GEOIP2_CITY = 'geoip2_city'; + const GEOIP2_COUNTRY = 'geoip2_country'; + + /** + * @var string + */ + protected $dbFile; + + /** + * @var string + */ + protected $dbType; + + /** + * @var string + */ + protected $locale; + + /** + * @var Reader + */ + protected $dbReader; + + /** + * @param string $dbFile + * @param string $dbType (e.g. self::GEOIP2_CITY) + * @throws \Geocoder\Exception\RuntimeException + * @throws \Geocoder\Exception\InvalidArgumentException + */ + public function __construct($dbFile, $dbType = self::GEOIP2_CITY) + { + if (false === class_exists('\GeoIp2\Database\Reader')) { + throw new RuntimeException(sprintf("The %s requires maxmind's lib 'geoip2/geoip2'", __CLASS__)); + } + + if (false === is_file($dbFile)) { + throw new InvalidArgumentException(sprintf('Given MaxMind database file "%s" is not a file.', $dbFile)); + } + + if (false === is_readable($dbFile)) { + throw new InvalidArgumentException(sprintf('Given MaxMind database file "%s" is not readable.', $dbFile)); + } + + $this->dbFile = $dbFile; + $this->dbType = $dbType; + } + + /** + * @param Reader $dbReader + */ + public function setDbReader(Reader $dbReader) + { + $this->dbReader = $dbReader; + } + + /** + * @param string $locale + * @return $this + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + /** + * @return string + */ + public function getLocale() + { + return $this->locale; + } + + /** + * Destruct (e.g. database reader) + */ + public function __destruct() + { + $this->getDbReader()->close(); + } + + /** + * Returns the content fetched from a given resource. + * + * @param string $url (e.g. file://database?127.0.0.1) + * @throws \Geocoder\Exception\UnsupportedException + * @throws \Geocoder\Exception\InvalidArgumentException + * @return string + */ + public function getContent($url) + { + $url = trim($url); + + if (false === filter_var($url, FILTER_VALIDATE_URL)) { + throw new InvalidArgumentException( + sprintf('"%s" must be called with a valid url. Got "%s" instead.', __METHOD__, $url) + ); + } + + $ipAddress = parse_url($url, PHP_URL_QUERY); + + if (false === filter_var($ipAddress, FILTER_VALIDATE_IP)) { + throw new InvalidArgumentException('URL must contain a valid query-string (a IP address, 127.0.0.1 for instance)'); + } + + switch ($this->dbType) { + case self::GEOIP2_CITY: + $result = $this->getDbReader()->city($ipAddress); + break; + default: + throw new UnsupportedException( + sprintf('Database type "%s" not implemented yet.', $this->dbType) + ); + } + + return json_encode($result); + } + + /** + * Returns the name of the Adapter. + * + * @return string + */ + public function getName() + { + return 'maxmind_database'; + } + + /** + * Returns database reader + * + * @return Reader + */ + protected function getDbReader() + { + if (is_null($this->dbReader)) { + $this->dbReader = new Reader($this->dbFile, $this->getLocale()); + } + + return $this->dbReader; + } +} \ No newline at end of file diff --git a/src/Geocoder/Provider/GeoIP2DatabaseProvider.php b/src/Geocoder/Provider/GeoIP2DatabaseProvider.php new file mode 100644 index 000000000..6e3330579 --- /dev/null +++ b/src/Geocoder/Provider/GeoIP2DatabaseProvider.php @@ -0,0 +1,108 @@ + + */ +class GeoIP2DatabaseProvider extends AbstractProvider implements ProviderInterface +{ + /** + * @var string + */ + protected $dbFile; + + /** + * {@inheritdoc} + */ + public function __construct(HttpAdapterInterface $adapter, $locale = 'en') + { + if (false === $adapter instanceof GeoIP2DatabaseAdapter) { + throw new InvalidArgumentException( + 'GeoIP2DatabaseAdapter is needed in order to access the GeoIP2 databases.' + ); + } + + parent::__construct($adapter, $locale); + } + + /** + * {@inheritDoc} + */ + public function getGeocodedData($address) + { + if (false === filter_var($address, FILTER_VALIDATE_IP)) { + throw new UnsupportedException(sprintf('The %s does not support street addresses.', __CLASS__)); + } + + if ('127.0.0.1' === $address) { + return $this->getLocalhostDefaults(); + } + + $result = json_decode($this->executeQuery($address)); + + return array($this->fixEncoding(array_merge($this->getDefaults(), array( + 'countryCode' => (isset($result->country->iso_code) ? $result->country->iso_code : null), + 'country' => (isset($result->country->names->{$this->locale}) ? $result->country->names->{$this->locale} : null), + 'city' => (isset($result->city->names->{$this->locale}) ? $result->city->names->{$this->locale} : null), + 'latitude' => (isset($result->location->latitude) ? $result->location->latitude : null), + 'longitude' => (isset($result->location->longitude) ? $result->location->longitude : null), + 'timezone' => (isset($result->location->timezone) ? $result->location->timezone : null), + 'zipcode' => (isset($result->location->postalcode) ? $result->location->postalcode : null), + )))); + } + + /** + * {@inheritDoc} + */ + public function getReversedData(array $coordinates) + { + throw new UnsupportedException(sprintf('The %s is not able to do reverse geocoding.', __CLASS__)); + } + + /** + * {@inheritDoc} + */ + public function getName() + { + return 'geoip2_database'; + } + + /** + * @param string $address + * @throws \Geocoder\Exception\NoResultException + * @return City + */ + protected function executeQuery($address) + { + $uri = sprintf('file://database?%s', $address); + + try { + $result = $this->getAdapter()->setLocale($this->locale)->getContent($uri); + } catch (AddressNotFoundException $e) { + throw new NoResultException(sprintf('No results found for IP address %s', $address)); + } + + return $result; + } + +} diff --git a/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php b/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php new file mode 100644 index 000000000..9d1d3605c --- /dev/null +++ b/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php @@ -0,0 +1,166 @@ + + */ +class GeoIP2DatabaseAdapterTest extends TestCase +{ + /** + * @var GeoIP2DatabaseAdapter + */ + protected $adapter; + + /** + * {@inheritdoc} + * @throws RuntimeException + */ + public static function setUpBeforeClass() + { + if (false === class_exists('\GeoIp2\Database\Reader')) { + throw new RuntimeException("The maxmind's lib 'geoip2/geoip2' is required to run this test."); + } + } + + public function setUp() + { + $this->adapter = new GeoIP2DatabaseAdapter($this->getDbFile()->url()); + $this->adapter->setDbReader($this->getDbReaderMock()); + } + + /** + * @expectedException \Geocoder\Exception\InvalidArgumentException + * @expectedExceptionMessage Given MaxMind database file "/tmp" is not a file. + */ + public function testDatabaseFileMustBeFile() + { + $this->adapter = new GeoIP2DatabaseAdapter('/tmp'); + $this->adapter->setDbReader($this->getDbReaderMock()); + } + + /** + * @depends testDatabaseFileMustBeFile + * @expectedException \Geocoder\Exception\InvalidArgumentException + * @expectedExceptionMessage Given MaxMind database file "vfs://tmpdir/database.mmdb" is not readable. + */ + public function testDatabaseFileMustBeReadable() + { + $this->adapter = new GeoIP2DatabaseAdapter($this->getDbFile()->chmod(0)->url()); + $this->adapter->setDbReader($this->getDbReaderMock()); + } + + public function testGetName() + { + $expectedName = 'maxmind_database'; + $this->assertEquals($expectedName, $this->adapter->getName()); + } + + /** + * @expectedException \Geocoder\Exception\InvalidArgumentException + * @expectedExceptionMessage must be called with a valid url. Got "127.0.0.1" instead. + */ + public function testGetContentMustBeCalledWithUrl() + { + $url = '127.0.0.1'; + $this->adapter->getContent($url); + } + + /** + * @expectedException \Geocoder\Exception\InvalidArgumentException + * @expectedExceptionMessage URL must contain a valid query-string (a IP address, 127.0.0.1 for instance) + */ + public function testAddressPassedToReaderMustBeIpAddress() + { + $url = 'file://database?not-valid=1'; + $this->adapter->getContent($url); + } + + public function testIpAddressIsPassedCorrectToReader() + { + $url = 'file://database?127.0.0.1 '; + $dbReader = $this->getDbReaderMock(); + $dbReader->expects($this->once())->method('city')->with('127.0.0.1'); + $this->adapter->setDbReader($dbReader); + + $this->adapter->getContent($url); + } + + public function testSettingLocaleIsCorrect() + { + $this->assertNull($this->adapter->getLocale()); + + $expectedLocale = 'it'; + $this->adapter->setLocale($expectedLocale); + + $this->assertEquals($expectedLocale, $this->adapter->getLocale()); + } + + /** + * @expectedException \Geocoder\Exception\UnsupportedException + * @expectedExceptionMessage Database type "geoip2_does_not_exist" not implemented yet. + */ + public function testUsingNonExistantDatabaseTypesLeadsToException() + { + $this->adapter = new GeoIP2DatabaseAdapter($this->getDbFile()->url(), 'geoip2_does_not_exist'); + $this->adapter->setDbReader($this->getDbReaderMock()); + $this->adapter->getContent('file://database?127.0.0.1'); + } + + public function testReaderResponseIsJsonEncoded() + { + $city = new City(array('city' => 'Hamburg')); + + $dbReader = $this->getDbReaderMock(); + $dbReader->expects($this->once())->method('city')->will($this->returnValue($city)); + $this->adapter->setDbReader($dbReader); + + $result = $this->adapter->getContent('file://database?127.0.0.1'); + $this->assertJson($result); + + $decodedResult = json_decode($result); + $this->assertObjectHasAttribute('city', $decodedResult); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + protected function getDbReaderMock() + { + $mock = $this->getMockBuilder('\GeoIp2\Database\Reader')->disableOriginalConstructor()->getMock(); + + return $mock; + } + + /** + * Returns virtual db-file + * + * @return vfsStreamFile + */ + protected function getDbFile() + { + $filesystem = vfsStream::setup('tmpdir'); + $dbFile = new vfsStreamFile('database.mmdb', 0600); + $filesystem->addChild($dbFile); + + return $dbFile; + } + +} + \ No newline at end of file diff --git a/tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php b/tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php new file mode 100644 index 000000000..49daa57f1 --- /dev/null +++ b/tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php @@ -0,0 +1,185 @@ + + */ +class GeoIP2DatabaseProviderTest extends TestCase +{ + /** + * @var GeoIP2DatabaseProvider + */ + protected $provider; + + public function setUp() + { + $this->provider = new GeoIP2DatabaseProvider($this->getDatabaseAdapterMock()); + } + + /** + * @expectedException \Geocoder\Exception\InvalidArgumentException + * @expectedExceptionMessage GeoIP2DatabaseAdapter is needed in order to access the GeoIP2 databases. + */ + public function testWrongAdapterLeadsToException() + { + new GeoIP2DatabaseProvider(new CurlHttpAdapter()); + } + + public function testGetName() + { + $expectedName = 'geoip2_database'; + $this->assertEquals($expectedName, $this->provider->getName()); + } + + /** + * @expectedException \Geocoder\Exception\UnsupportedException + * @expectedExceptionMessage The Geocoder\Provider\GeoIP2DatabaseProvider is not able to do reverse geocoding. + */ + public function testQueryingReversedDataLeadToException() + { + $this->provider->getReversedData(array(50, 9)); + } + + public function testLocalhostDefaults() + { + $expectedResult = array( + 'city' => 'localhost', + 'region' => 'localhost', + 'county' => 'localhost', + 'country' => 'localhost', + ); + + $actualResult = $this->provider->getGeocodedData('127.0.0.1'); + + $this->assertSame($expectedResult, $actualResult); + } + + /** + * @expectedException \Geocoder\Exception\UnsupportedException + * @expectedExceptionMessage The Geocoder\Provider\GeoIP2DatabaseProvider does not support street addresses. + */ + public function testOnlyIpAddressesCouldBeResolved() + { + $this->provider->getGeocodedData('Street 123, Somewhere'); + } + + /** + * Provides data for getGeocodedData test + * + * @return array + */ + public static function provideDataForRetrievingGeodata() + { + $testdata = array( + 'Response with all possible data' => array( + '74.200.247.59', + '{"city":{"geoname_id":2911298,"names":{"de":"Hamburg","en":"Hamburg","es":"Hamburgo","fr":"Hambourg","ja":"\u30cf\u30f3\u30d6\u30eb\u30af","pt-BR":"Hamburgo","ru":"\u0413\u0430\u043c\u0431\u0443\u0440\u0433","zh-CN":"\u6c49\u5821\u5e02"}},"continent":{"code":"EU","geoname_id":6255148,"names":{"de":"Europa","en":"Europe","es":"Europa","fr":"Europe","ja":"\u30e8\u30fc\u30ed\u30c3\u30d1","pt-BR":"Europa","ru":"\u0415\u0432\u0440\u043e\u043f\u0430","zh-CN":"\u6b27\u6d32"}},"country":{"geoname_id":2921044,"iso_code":"DE","names":{"de":"Deutschland","en":"Germany","es":"Alemania","fr":"Allemagne","ja":"\u30c9\u30a4\u30c4\u9023\u90a6\u5171\u548c\u56fd","pt-BR":"Alemanha","ru":"\u0413\u0435\u0440\u043c\u0430\u043d\u0438\u044f","zh-CN":"\u5fb7\u56fd"}},"location":{"latitude":53.55,"longitude":10,"time_zone":"Europe\/Berlin"},"registered_country":{"geoname_id":2921044,"iso_code":"DE","names":{"de":"Deutschland","en":"Germany","es":"Alemania","fr":"Allemagne","ja":"\u30c9\u30a4\u30c4\u9023\u90a6\u5171\u548c\u56fd","pt-BR":"Alemanha","ru":"\u0413\u0435\u0440\u043c\u0430\u043d\u0438\u044f","zh-CN":"\u5fb7\u56fd"}},"subdivisions":[{"geoname_id":2911297,"iso_code":"HH","names":{"de":"Hamburg","en":"Hamburg","es":"Hamburgo","fr":"Hambourg"}}],"traits":{"ip_address":"74.200.247.59"}}', + array( + 'latitude' => 53.55, + 'longitude' => 10, + 'bounds' => null, + 'streetNumber' => null, + 'streetName' => null, + 'city' => 'Hamburg', + 'zipcode' => null, + 'cityDistrict' => null, + 'county' => null, + 'countyCode' => null, + 'region' => null, + 'regionCode' => null, + 'country' => 'Germany', + 'countryCode' => 'DE', + 'timezone' => null, + ) + ), + 'Response with all data null' => array( + '74.200.247.59', + '{}', + array( + 'latitude' => null, + 'longitude' => null, + 'bounds' => null, + 'streetNumber' => null, + 'streetName' => null, + 'city' => null, + 'zipcode' => null, + 'cityDistrict' => null, + 'county' => null, + 'countyCode' => null, + 'region' => null, + 'regionCode' => null, + 'country' => null, + 'countryCode' => null, + 'timezone' => null, + ) + ) + ); + + return $testdata; + } + + /** + * @dataProvider provideDataForRetrievingGeodata + * @param string $address + * @param $adapterResponse + * @param $expectedGeodata + */ + public function testRetrievingGeodata($address, $adapterResponse, $expectedGeodata) + { + $adapter = $this->getDatabaseAdapterMock($adapterResponse); + $provider = new GeoIP2DatabaseProvider($adapter); + + $actualGeodata = $provider->getGeocodedData($address); + + $this->assertSame($expectedGeodata, $actualGeodata[0]); + } + + /** + * @expectedException \Geocoder\Exception\NoResultException + * @expectedExceptionMessage No results found for IP address 74.200.247.59 + */ + public function testRetrievingGeodataNotExistingLocation() + { + $adapterReturn = new NoResultException('No results found for IP address 74.200.247.59'); + $adapter = $this->getDatabaseAdapterMock($adapterReturn); + + $provider = new GeoIP2DatabaseProvider($adapter); + + $provider->getGeocodedData('74.200.247.59'); + } + + /** + * @param mixed $returnValue + * @return \PHPUnit_Framework_MockObject_MockObject | GeoIP2DatabaseAdapter + */ + public function getDatabaseAdapterMock($returnValue = '') + { + $mock = $this->getMockBuilder('\Geocoder\HttpAdapter\GeoIP2DatabaseAdapter')->disableOriginalConstructor()->getMock(); + + if ($returnValue instanceof \Exception) { + $returnValue = $this->throwException($returnValue); + } else { + $returnValue = $this->returnValue($returnValue); + } + + $mock->expects($this->any())->method('setLocale')->will($this->returnSelf()); + $mock->expects($this->any())->method('getContent')->will($returnValue); + + return $mock; + } +} From d46ca18128a368180ea5d08748121fe35a9828c0 Mon Sep 17 00:00:00 2001 From: Jens Wiese Date: Thu, 10 Apr 2014 20:46:17 +0200 Subject: [PATCH 2/3] Change access of GeoIP2 database-reader, due to problems with JSON-encoded geodata. --- README.md | 8 ++++ .../HttpAdapter/GeoIP2DatabaseAdapter.php | 4 +- .../HttpAdapter/GeoIP2DatabaseAdapterTest.php | 48 ++++++++++++++++--- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3a422c825..30005fa91 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,14 @@ It requires the [database file](http://dev.maxmind.com/geoip/geoip2/geolite2/), This provider will only work with the corresponding `GeoIP2DatabaseAdapter`. +**Usage:** + + $adapter = new \Geocoder\HttpAdapter\GeoIP2DatabaseAdapter('/path/to/database'); + $provider = new \Geocoder\Provider\GeoIP2DatabaseProvider($adapter); + $geocoder = new \Geocoder\Geocoder($provider); + + $result = $geocoder->geocode('74.200.247.59'); + ### GeonamesProvider ### The `GeonamesProvider` named `geonames` is able to geocode and reverse geocode **places**. diff --git a/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php b/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php index 8fd7db2c6..381626049 100644 --- a/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php +++ b/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php @@ -131,7 +131,7 @@ public function getContent($url) switch ($this->dbType) { case self::GEOIP2_CITY: - $result = $this->getDbReader()->city($ipAddress); + $result = $this->getDbReader()->city($ipAddress)->jsonSerialize(); break; default: throw new UnsupportedException( @@ -165,4 +165,4 @@ protected function getDbReader() return $this->dbReader; } -} \ No newline at end of file +} diff --git a/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php b/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php index 9d1d3605c..bb11addac 100644 --- a/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php +++ b/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php @@ -14,7 +14,6 @@ use Geocoder\Tests\TestCase; use Geocoder\Exception\RuntimeException; use GeoIp2\Database\Reader; -use GeoIp2\Model\City; use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStreamFile; @@ -94,12 +93,15 @@ public function testAddressPassedToReaderMustBeIpAddress() public function testIpAddressIsPassedCorrectToReader() { - $url = 'file://database?127.0.0.1 '; $dbReader = $this->getDbReaderMock(); - $dbReader->expects($this->once())->method('city')->with('127.0.0.1'); + $dbReader + ->expects($this->once()) + ->method('city')->with('127.0.0.1') + ->will($this->returnValue($this->getCityModelMock())); + $this->adapter->setDbReader($dbReader); - $this->adapter->getContent($url); + $this->adapter->getContent('file://database?127.0.0.1'); } public function testSettingLocaleIsCorrect() @@ -125,10 +127,14 @@ public function testUsingNonExistantDatabaseTypesLeadsToException() public function testReaderResponseIsJsonEncoded() { - $city = new City(array('city' => 'Hamburg')); + $cityModel = $this->getCityModelMock(); $dbReader = $this->getDbReaderMock(); - $dbReader->expects($this->once())->method('city')->will($this->returnValue($city)); + $dbReader + ->expects($this->any()) + ->method('city') + ->will($this->returnValue($cityModel)); + $this->adapter->setDbReader($dbReader); $result = $this->adapter->getContent('file://database?127.0.0.1'); @@ -148,6 +154,36 @@ protected function getDbReaderMock() return $mock; } + /** + * @return \PHPUnit_Framework_MockObject_MockObject + */ + protected function getCityModelMock() + { + $mock = $this->getMockBuilder('\GeoIp2\Model\City')->disableOriginalConstructor()->getMock(); + $mock + ->expects($this->any()) + ->method('jsonSerialize') + ->will($this->returnValue( + array( + 'city' => array( + 'geoname_id' => 2911298, + 'names' => array( + 'de' => 'Hamburg', + 'en' => 'Hamburg', + 'es' => 'Hamburgo', + 'fr' => 'Hambourg', + 'ja' => 'ハンブルク', + 'pt-BR' => 'Hamburgo', + 'ru' => 'Гамбург', + 'zh-CN' => '汉堡市', + ) + ) + ) + )); + + return $mock; + } + /** * Returns virtual db-file * From 6b5bbd81320dbdd26375462af1a0a5def566ab98 Mon Sep 17 00:00:00 2001 From: Jens Wiese Date: Thu, 24 Apr 2014 10:12:30 +0200 Subject: [PATCH 3/3] Refactor GeoIP2Provider: Use injection of Maxmind provider. Instead of using only the database reader of Maxmind, inject the Maxmind provider. Thus both is available: database reader and webservice client. --- README.md | 19 +- composer.json | 3 +- src/Geocoder/HttpAdapter/GeoIP2Adapter.php | 137 ++++++++++++++ .../HttpAdapter/GeoIP2DatabaseAdapter.php | 168 ------------------ ...atabaseProvider.php => GeoIP2Provider.php} | 20 +-- ...eAdapterTest.php => GeoIP2AdapterTest.php} | 120 +++++-------- ...roviderTest.php => GeoIP2ProviderTest.php} | 31 ++-- 7 files changed, 218 insertions(+), 280 deletions(-) create mode 100644 src/Geocoder/HttpAdapter/GeoIP2Adapter.php delete mode 100644 src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php rename src/Geocoder/Provider/{GeoIP2DatabaseProvider.php => GeoIP2Provider.php} (83%) rename tests/Geocoder/Tests/HttpAdapter/{GeoIP2DatabaseAdapterTest.php => GeoIP2AdapterTest.php} (54%) rename tests/Geocoder/Tests/Provider/{GeoIP2DatabaseProviderTest.php => GeoIP2ProviderTest.php} (84%) diff --git a/README.md b/README.md index 30005fa91..66d97516d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Currently, there are the following adapters: * `GuzzleHttpAdapter` to use [Guzzle](https://github.com/guzzle/guzzle), PHP 5.3+ HTTP client and framework for building RESTful web service clients; * `SocketHttpAdapter` to use a [socket](http://www.php.net/manual/function.fsockopen.php); * `ZendHttpAdapter` to use [Zend Http Client](http://framework.zend.com/manual/2.0/en/modules/zend.http.client.html). -* `GeoIP2DatabaseAdapter` to use [GeoIP2 Database Reader by MaxMind](https://github.com/maxmind/GeoIP2-php#database-reader). +* `GeoIP2Adapter` to use [GeoIP2 Database Reader](https://github.com/maxmind/GeoIP2-php#database-reader) or the [Webservice Client](https://github.com/maxmind/GeoIP2-php#web-service-client) by MaxMind. ### Providers ### @@ -50,7 +50,7 @@ Currently, there are many providers for the following APIs: * [GeoIPs](http://www.geoips.com/developer/geoips-api) as IP-Based geocoding provider; * [MaxMind web service](http://dev.maxmind.com/geoip/legacy/web-services) as IP-Based geocoding provider (City/ISP/Org and Omni services); * [MaxMind binary file](http://dev.maxmind.com/geoip/legacy/downloadable) as IP-Based geocoding provider; -* [MaxMind GeoIP2 database file](http://www.maxmind.com/en/city) as IP-Based geocoding provider; +* [MaxMind GeoIP2](http://www.maxmind.com/en/city) as IP-Based geocoding provider; * [Geonames](http://www.geonames.org/) as Place-Based geocoding and reverse geocoding provider; * [IpGeoBase](http://ipgeobase.ru/) as IP-Based geocoding provider (very accurate in Russia); * [Baidu](http://developer.baidu.com/map/geocoding-api.htm) as Address-Based geocoding and reverse geocoding provider (exclusively in China); @@ -263,17 +263,20 @@ be used in production. For more information, please read [issue #301](https://gi ### GeoIP2DatabaseProvider ### -The `GeoIP2DatabaseProvider` named `geoip2_database` is able to geocode **IPv4 and IPv6 addresses** -only - it makes use of the MaxMind GeoIP2 databases. +The `GeoIP2Provider` named `maxmind_geoip2` is able to geocode **IPv4 and IPv6 addresses** +only - it makes use of the MaxMind GeoIP2 databases or the webservice. -It requires the [database file](http://dev.maxmind.com/geoip/geoip2/geolite2/), and the [geoip2/geoip2](https://packagist.org/packages/geoip2/geoip2) package must be installed. +It requires either the [database file](http://dev.maxmind.com/geoip/geoip2/geolite2/), or the [webservice](http://dev.maxmind.com/geoip/geoip2/web-services/) - represented by the GeoIP2 Provider, which is injected to the `GeoIP2Adapter`. The [geoip2/geoip2](https://packagist.org/packages/geoip2/geoip2) package must be installed. -This provider will only work with the corresponding `GeoIP2DatabaseAdapter`. +This provider will only work with the corresponding `GeoIP2Adapter`. **Usage:** - $adapter = new \Geocoder\HttpAdapter\GeoIP2DatabaseAdapter('/path/to/database'); - $provider = new \Geocoder\Provider\GeoIP2DatabaseProvider($adapter); + // Maxmind GeoIP2 Provider: e.g. the database reader + $reader = new \GeoIp2\Database\Reader('/path/to/database'); + + $adapter = new \Geocoder\HttpAdapter\GeoIP2Adapter($reader); + $provider = new \Geocoder\Provider\GeoIP2Provider($adapter); $geocoder = new \Geocoder\Geocoder($provider); $result = $geocoder->geocode('74.200.247.59'); diff --git a/composer.json b/composer.json index 794f33fbd..959f28a65 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,7 @@ "guzzle/guzzle": "@stable", "zendframework/zend-http": "~2.1", "geoip/geoip": "~1.13", - "geoip2/geoip2": "~0.6", - "mikey179/vfsStream": "v1.2.0" + "geoip2/geoip2": "~0.6" }, "suggest": { "kriswallsmith/buzz": "Enabling Buzz allows you to use the BuzzHttpAdapter.", diff --git a/src/Geocoder/HttpAdapter/GeoIP2Adapter.php b/src/Geocoder/HttpAdapter/GeoIP2Adapter.php new file mode 100644 index 000000000..dd511ddb7 --- /dev/null +++ b/src/Geocoder/HttpAdapter/GeoIP2Adapter.php @@ -0,0 +1,137 @@ + + */ +class GeoIP2Adapter implements HttpAdapterInterface +{ + /** + * GeoIP2 models (e.g. city or country) + */ + const GEOIP2_MODEL_CITY = 'city'; + const GEOIP2_MODEL_COUNTRY = 'country'; + const GEOIP2_MODEL_OMNI = 'omni'; + + /** + * @var ProviderInterface + */ + protected $geoIp2Provider; + + /** + * @var string + */ + protected $geoIP2Model; + + /** + * @var string + */ + protected $locale; + + /** + * @param \GeoIp2\ProviderInterface $geoIpProvider + * @param string $geoIP2Model (e.g. self::GEOIP2_MODEL_CITY) + * @throws \Geocoder\Exception\UnsupportedException + * @internal param string $dbFile + */ + public function __construct(ProviderInterface $geoIpProvider, $geoIP2Model = self::GEOIP2_MODEL_CITY) + { + $this->geoIp2Provider = $geoIpProvider; + + if (false === $this->isSupportedGeoIP2Model($geoIP2Model)) { + throw new UnsupportedException( + sprintf('Model "%s" is not available.', $geoIP2Model) + ); + } + + $this->geoIP2Model = $geoIP2Model; + } + + /** + * @param string $locale + * @return $this + */ + public function setLocale($locale) + { + $this->locale = $locale; + + return $this; + } + + /** + * @return string + */ + public function getLocale() + { + return $this->locale; + } + + /** + * Returns the content fetched from a given resource. + * + * @param string $url (e.g. file://database?127.0.0.1) + * @throws \Geocoder\Exception\UnsupportedException + * @throws \Geocoder\Exception\InvalidArgumentException + * @return string + */ + public function getContent($url) + { + if (false === filter_var($url, FILTER_VALIDATE_URL)) { + throw new InvalidArgumentException( + sprintf('"%s" must be called with a valid url. Got "%s" instead.', __METHOD__, $url) + ); + } + + $ipAddress = parse_url($url, PHP_URL_QUERY); + + if (false === filter_var($ipAddress, FILTER_VALIDATE_IP)) { + throw new InvalidArgumentException('URL must contain a valid query-string (an IP address, 127.0.0.1 for instance)'); + } + + $result = $this->geoIp2Provider + ->{$this->geoIP2Model}($ipAddress) + ->jsonSerialize(); + + return json_encode($result); + } + + /** + * Returns the name of the Adapter. + * + * @return string + */ + public function getName() + { + return 'maxmind_geoip2'; + } + + /** + * Returns whether method is supported by GeoIP2 + * + * @param string $method + * @return bool + */ + protected function isSupportedGeoIP2Model($method) + { + $availableMethods = array( + self::GEOIP2_MODEL_CITY, + self::GEOIP2_MODEL_COUNTRY, + self::GEOIP2_MODEL_OMNI + ); + + return in_array($method, $availableMethods); + } +} diff --git a/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php b/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php deleted file mode 100644 index 381626049..000000000 --- a/src/Geocoder/HttpAdapter/GeoIP2DatabaseAdapter.php +++ /dev/null @@ -1,168 +0,0 @@ - - */ -class GeoIP2DatabaseAdapter implements HttpAdapterInterface -{ - /** - * Database file types - */ - const GEOIP2_CITY = 'geoip2_city'; - const GEOIP2_COUNTRY = 'geoip2_country'; - - /** - * @var string - */ - protected $dbFile; - - /** - * @var string - */ - protected $dbType; - - /** - * @var string - */ - protected $locale; - - /** - * @var Reader - */ - protected $dbReader; - - /** - * @param string $dbFile - * @param string $dbType (e.g. self::GEOIP2_CITY) - * @throws \Geocoder\Exception\RuntimeException - * @throws \Geocoder\Exception\InvalidArgumentException - */ - public function __construct($dbFile, $dbType = self::GEOIP2_CITY) - { - if (false === class_exists('\GeoIp2\Database\Reader')) { - throw new RuntimeException(sprintf("The %s requires maxmind's lib 'geoip2/geoip2'", __CLASS__)); - } - - if (false === is_file($dbFile)) { - throw new InvalidArgumentException(sprintf('Given MaxMind database file "%s" is not a file.', $dbFile)); - } - - if (false === is_readable($dbFile)) { - throw new InvalidArgumentException(sprintf('Given MaxMind database file "%s" is not readable.', $dbFile)); - } - - $this->dbFile = $dbFile; - $this->dbType = $dbType; - } - - /** - * @param Reader $dbReader - */ - public function setDbReader(Reader $dbReader) - { - $this->dbReader = $dbReader; - } - - /** - * @param string $locale - * @return $this - */ - public function setLocale($locale) - { - $this->locale = $locale; - - return $this; - } - - /** - * @return string - */ - public function getLocale() - { - return $this->locale; - } - - /** - * Destruct (e.g. database reader) - */ - public function __destruct() - { - $this->getDbReader()->close(); - } - - /** - * Returns the content fetched from a given resource. - * - * @param string $url (e.g. file://database?127.0.0.1) - * @throws \Geocoder\Exception\UnsupportedException - * @throws \Geocoder\Exception\InvalidArgumentException - * @return string - */ - public function getContent($url) - { - $url = trim($url); - - if (false === filter_var($url, FILTER_VALIDATE_URL)) { - throw new InvalidArgumentException( - sprintf('"%s" must be called with a valid url. Got "%s" instead.', __METHOD__, $url) - ); - } - - $ipAddress = parse_url($url, PHP_URL_QUERY); - - if (false === filter_var($ipAddress, FILTER_VALIDATE_IP)) { - throw new InvalidArgumentException('URL must contain a valid query-string (a IP address, 127.0.0.1 for instance)'); - } - - switch ($this->dbType) { - case self::GEOIP2_CITY: - $result = $this->getDbReader()->city($ipAddress)->jsonSerialize(); - break; - default: - throw new UnsupportedException( - sprintf('Database type "%s" not implemented yet.', $this->dbType) - ); - } - - return json_encode($result); - } - - /** - * Returns the name of the Adapter. - * - * @return string - */ - public function getName() - { - return 'maxmind_database'; - } - - /** - * Returns database reader - * - * @return Reader - */ - protected function getDbReader() - { - if (is_null($this->dbReader)) { - $this->dbReader = new Reader($this->dbFile, $this->getLocale()); - } - - return $this->dbReader; - } -} diff --git a/src/Geocoder/Provider/GeoIP2DatabaseProvider.php b/src/Geocoder/Provider/GeoIP2Provider.php similarity index 83% rename from src/Geocoder/Provider/GeoIP2DatabaseProvider.php rename to src/Geocoder/Provider/GeoIP2Provider.php index 6e3330579..c57081e36 100644 --- a/src/Geocoder/Provider/GeoIP2DatabaseProvider.php +++ b/src/Geocoder/Provider/GeoIP2Provider.php @@ -12,33 +12,25 @@ use Geocoder\Exception\NoResultException; use Geocoder\Exception\InvalidArgumentException; -use Geocoder\Exception\RuntimeException; use Geocoder\Exception\UnsupportedException; -use Geocoder\HttpAdapter\AdapterInterface; -use Geocoder\HttpAdapter\GeoIP2DatabaseAdapter; +use Geocoder\HttpAdapter\GeoIP2Adapter; use Geocoder\HttpAdapter\HttpAdapterInterface; -use GeoIp2\Database\Reader; use GeoIp2\Exception\AddressNotFoundException; use GeoIp2\Model\City; /** * @author Jens Wiese */ -class GeoIP2DatabaseProvider extends AbstractProvider implements ProviderInterface +class GeoIP2Provider extends AbstractProvider implements ProviderInterface { - /** - * @var string - */ - protected $dbFile; - /** * {@inheritdoc} */ public function __construct(HttpAdapterInterface $adapter, $locale = 'en') { - if (false === $adapter instanceof GeoIP2DatabaseAdapter) { + if (false === $adapter instanceof GeoIP2Adapter) { throw new InvalidArgumentException( - 'GeoIP2DatabaseAdapter is needed in order to access the GeoIP2 databases.' + 'GeoIP2Adapter is needed in order to access the GeoIP2 service.' ); } @@ -84,7 +76,7 @@ public function getReversedData(array $coordinates) */ public function getName() { - return 'geoip2_database'; + return 'maxmind_geoip2'; } /** @@ -94,7 +86,7 @@ public function getName() */ protected function executeQuery($address) { - $uri = sprintf('file://database?%s', $address); + $uri = sprintf('file://geoip?%s', $address); try { $result = $this->getAdapter()->setLocale($this->locale)->getContent($uri); diff --git a/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php b/tests/Geocoder/Tests/HttpAdapter/GeoIP2AdapterTest.php similarity index 54% rename from tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php rename to tests/Geocoder/Tests/HttpAdapter/GeoIP2AdapterTest.php index bb11addac..9966fd0b2 100644 --- a/tests/Geocoder/Tests/HttpAdapter/GeoIP2DatabaseAdapterTest.php +++ b/tests/Geocoder/Tests/HttpAdapter/GeoIP2AdapterTest.php @@ -10,17 +10,16 @@ namespace Geocoder\Tests\HttpAdapter; -use Geocoder\HttpAdapter\GeoIP2DatabaseAdapter; +use Geocoder\HttpAdapter\GeoIP2Adapter; use Geocoder\Tests\TestCase; use Geocoder\Exception\RuntimeException; use GeoIp2\Database\Reader; -use org\bovigo\vfs\vfsStream; -use org\bovigo\vfs\vfsStreamFile; +use GeoIp2\WebService\Client; /** * @author Jens Wiese */ -class GeoIP2DatabaseAdapterTest extends TestCase +class GeoIP2AdapterTest extends TestCase { /** * @var GeoIP2DatabaseAdapter @@ -40,34 +39,12 @@ public static function setUpBeforeClass() public function setUp() { - $this->adapter = new GeoIP2DatabaseAdapter($this->getDbFile()->url()); - $this->adapter->setDbReader($this->getDbReaderMock()); - } - - /** - * @expectedException \Geocoder\Exception\InvalidArgumentException - * @expectedExceptionMessage Given MaxMind database file "/tmp" is not a file. - */ - public function testDatabaseFileMustBeFile() - { - $this->adapter = new GeoIP2DatabaseAdapter('/tmp'); - $this->adapter->setDbReader($this->getDbReaderMock()); - } - - /** - * @depends testDatabaseFileMustBeFile - * @expectedException \Geocoder\Exception\InvalidArgumentException - * @expectedExceptionMessage Given MaxMind database file "vfs://tmpdir/database.mmdb" is not readable. - */ - public function testDatabaseFileMustBeReadable() - { - $this->adapter = new GeoIP2DatabaseAdapter($this->getDbFile()->chmod(0)->url()); - $this->adapter->setDbReader($this->getDbReaderMock()); + $this->adapter = new GeoIP2Adapter($this->getGeoIP2ProviderMock()); } public function testGetName() { - $expectedName = 'maxmind_database'; + $expectedName = 'maxmind_geoip2'; $this->assertEquals($expectedName, $this->adapter->getName()); } @@ -83,7 +60,7 @@ public function testGetContentMustBeCalledWithUrl() /** * @expectedException \Geocoder\Exception\InvalidArgumentException - * @expectedExceptionMessage URL must contain a valid query-string (a IP address, 127.0.0.1 for instance) + * @expectedExceptionMessage URL must contain a valid query-string (an IP address, 127.0.0.1 for instance) */ public function testAddressPassedToReaderMustBeIpAddress() { @@ -91,17 +68,39 @@ public function testAddressPassedToReaderMustBeIpAddress() $this->adapter->getContent($url); } - public function testIpAddressIsPassedCorrectToReader() + public static function provideDataForSwitchingRequestMethods() { - $dbReader = $this->getDbReaderMock(); - $dbReader - ->expects($this->once()) - ->method('city')->with('127.0.0.1') - ->will($this->returnValue($this->getCityModelMock())); + return array( + array(GeoIP2Adapter::GEOIP2_MODEL_CITY), + array(GeoIP2Adapter::GEOIP2_MODEL_COUNTRY), + array(GeoIP2Adapter::GEOIP2_MODEL_OMNI), + ); + } - $this->adapter->setDbReader($dbReader); + /** + * @dataProvider provideDataForSwitchingRequestMethods + */ + public function testIpAddressIsPassedCorrectToReader($geoIp2Model) + { + $geoIp2Provider = $this->getGeoIP2ProviderMock(); + $geoIp2Provider + ->expects($this->any()) + ->method($geoIp2Model)->with('127.0.0.1') + ->will( + $this->returnValue($this->getGeoIP2ModelMock($geoIp2Model)) + ); - $this->adapter->getContent('file://database?127.0.0.1'); + $adapter = new GeoIP2Adapter($geoIp2Provider, $geoIp2Model); + $adapter->getContent('file://geoip?127.0.0.1'); + } + + /** + * @expectedException \Geocoder\Exception\UnsupportedException + * @expectedExceptionMessage Model "unsupported_model" is not available. + */ + public function testNotSupportedGeoIP2ModelLeadsToException() + { + new GeoIP2Adapter($this->getGeoIP2ProviderMock(), 'unsupported_model'); } public function testSettingLocaleIsCorrect() @@ -114,30 +113,19 @@ public function testSettingLocaleIsCorrect() $this->assertEquals($expectedLocale, $this->adapter->getLocale()); } - /** - * @expectedException \Geocoder\Exception\UnsupportedException - * @expectedExceptionMessage Database type "geoip2_does_not_exist" not implemented yet. - */ - public function testUsingNonExistantDatabaseTypesLeadsToException() - { - $this->adapter = new GeoIP2DatabaseAdapter($this->getDbFile()->url(), 'geoip2_does_not_exist'); - $this->adapter->setDbReader($this->getDbReaderMock()); - $this->adapter->getContent('file://database?127.0.0.1'); - } - public function testReaderResponseIsJsonEncoded() { - $cityModel = $this->getCityModelMock(); + $cityModel = $this->getGeoIP2ModelMock(GeoIP2Adapter::GEOIP2_MODEL_CITY); - $dbReader = $this->getDbReaderMock(); - $dbReader + $geoIp2Provider = $this->getGeoIP2ProviderMock(); + $geoIp2Provider ->expects($this->any()) ->method('city') ->will($this->returnValue($cityModel)); - $this->adapter->setDbReader($dbReader); + $adapter = new GeoIP2Adapter($geoIp2Provider); - $result = $this->adapter->getContent('file://database?127.0.0.1'); + $result = $adapter->getContent('file://database?127.0.0.1'); $this->assertJson($result); $decodedResult = json_decode($result); @@ -147,19 +135,22 @@ public function testReaderResponseIsJsonEncoded() /** * @return \PHPUnit_Framework_MockObject_MockObject */ - protected function getDbReaderMock() + protected function getGeoIP2ProviderMock() { - $mock = $this->getMockBuilder('\GeoIp2\Database\Reader')->disableOriginalConstructor()->getMock(); + $mock = $this->getMockBuilder('\GeoIp2\ProviderInterface')->getMock(); return $mock; } /** + * @param int $geoIP2Model (e.g. GeoIP2Adapter::GEOIP2_MODEL_ * @return \PHPUnit_Framework_MockObject_MockObject */ - protected function getCityModelMock() + protected function getGeoIP2ModelMock($geoIP2Model) { - $mock = $this->getMockBuilder('\GeoIp2\Model\City')->disableOriginalConstructor()->getMock(); + $mockClass = '\\GeoIp2\\Model\\' . ucfirst($geoIP2Model); + + $mock = $this->getMockBuilder($mockClass)->disableOriginalConstructor()->getMock(); $mock ->expects($this->any()) ->method('jsonSerialize') @@ -183,20 +174,5 @@ protected function getCityModelMock() return $mock; } - - /** - * Returns virtual db-file - * - * @return vfsStreamFile - */ - protected function getDbFile() - { - $filesystem = vfsStream::setup('tmpdir'); - $dbFile = new vfsStreamFile('database.mmdb', 0600); - $filesystem->addChild($dbFile); - - return $dbFile; - } - } \ No newline at end of file diff --git a/tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php b/tests/Geocoder/Tests/Provider/GeoIP2ProviderTest.php similarity index 84% rename from tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php rename to tests/Geocoder/Tests/Provider/GeoIP2ProviderTest.php index 49daa57f1..647da96b6 100644 --- a/tests/Geocoder/Tests/Provider/GeoIP2DatabaseProviderTest.php +++ b/tests/Geocoder/Tests/Provider/GeoIP2ProviderTest.php @@ -12,43 +12,42 @@ use Geocoder\Exception\NoResultException; use Geocoder\HttpAdapter\CurlHttpAdapter; -use Geocoder\HttpAdapter\GeoIP2DatabaseAdapter; -use Geocoder\Provider\GeoIP2DatabaseProvider; +use Geocoder\Provider\GeoIP2Provider; use Geocoder\Tests\TestCase; /** * @author Jens Wiese */ -class GeoIP2DatabaseProviderTest extends TestCase +class GeoIP2ProviderTest extends TestCase { /** - * @var GeoIP2DatabaseProvider + * @var GeoIP2Provider */ protected $provider; public function setUp() { - $this->provider = new GeoIP2DatabaseProvider($this->getDatabaseAdapterMock()); + $this->provider = new GeoIP2Provider($this->getGeoIP2AdapterMock()); } /** * @expectedException \Geocoder\Exception\InvalidArgumentException - * @expectedExceptionMessage GeoIP2DatabaseAdapter is needed in order to access the GeoIP2 databases. + * @expectedExceptionMessage GeoIP2Adapter is needed in order to access the GeoIP2 service. */ public function testWrongAdapterLeadsToException() { - new GeoIP2DatabaseProvider(new CurlHttpAdapter()); + new GeoIP2Provider(new CurlHttpAdapter()); } public function testGetName() { - $expectedName = 'geoip2_database'; + $expectedName = 'maxmind_geoip2'; $this->assertEquals($expectedName, $this->provider->getName()); } /** * @expectedException \Geocoder\Exception\UnsupportedException - * @expectedExceptionMessage The Geocoder\Provider\GeoIP2DatabaseProvider is not able to do reverse geocoding. + * @expectedExceptionMessage The Geocoder\Provider\GeoIP2Provider is not able to do reverse geocoding. */ public function testQueryingReversedDataLeadToException() { @@ -71,7 +70,7 @@ public function testLocalhostDefaults() /** * @expectedException \Geocoder\Exception\UnsupportedException - * @expectedExceptionMessage The Geocoder\Provider\GeoIP2DatabaseProvider does not support street addresses. + * @expectedExceptionMessage The Geocoder\Provider\GeoIP2Provider does not support street addresses. */ public function testOnlyIpAddressesCouldBeResolved() { @@ -141,8 +140,8 @@ public static function provideDataForRetrievingGeodata() */ public function testRetrievingGeodata($address, $adapterResponse, $expectedGeodata) { - $adapter = $this->getDatabaseAdapterMock($adapterResponse); - $provider = new GeoIP2DatabaseProvider($adapter); + $adapter = $this->getGeoIP2AdapterMock($adapterResponse); + $provider = new GeoIP2Provider($adapter); $actualGeodata = $provider->getGeocodedData($address); @@ -156,9 +155,9 @@ public function testRetrievingGeodata($address, $adapterResponse, $expectedGeoda public function testRetrievingGeodataNotExistingLocation() { $adapterReturn = new NoResultException('No results found for IP address 74.200.247.59'); - $adapter = $this->getDatabaseAdapterMock($adapterReturn); + $adapter = $this->getGeoIP2AdapterMock($adapterReturn); - $provider = new GeoIP2DatabaseProvider($adapter); + $provider = new GeoIP2Provider($adapter); $provider->getGeocodedData('74.200.247.59'); } @@ -167,9 +166,9 @@ public function testRetrievingGeodataNotExistingLocation() * @param mixed $returnValue * @return \PHPUnit_Framework_MockObject_MockObject | GeoIP2DatabaseAdapter */ - public function getDatabaseAdapterMock($returnValue = '') + public function getGeoIP2AdapterMock($returnValue = '') { - $mock = $this->getMockBuilder('\Geocoder\HttpAdapter\GeoIP2DatabaseAdapter')->disableOriginalConstructor()->getMock(); + $mock = $this->getMockBuilder('\Geocoder\HttpAdapter\GeoIP2Adapter')->disableOriginalConstructor()->getMock(); if ($returnValue instanceof \Exception) { $returnValue = $this->throwException($returnValue);