diff --git a/.github/workflows/provider.yml b/.github/workflows/provider.yml new file mode 100644 index 0000000..590442d --- /dev/null +++ b/.github/workflows/provider.yml @@ -0,0 +1,33 @@ +name: Provider + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + name: PHP ${{ matrix.php-version }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-version: ['8.0', '8.1', '8.2', '8.3', '8.4'] + steps: + - uses: actions/checkout@v4 + - name: Use PHP ${{ matrix.php-version }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: curl + - name: Validate composer.json and composer.lock + run: composer validate --strict + - name: Install dependencies + run: composer update --prefer-stable --prefer-dist --no-progress + - name: Run test suite + run: composer run-script test-ci + - name: Upload Coverage report + run: | + wget https://scrutinizer-ci.com/ocular.phar + php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d2b93dc..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: php -sudo: false - -php: 7.0 - -install: - - composer update --prefer-stable --prefer-dist - -script: - - composer test-ci - -after_success: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover build/coverage.xml - diff --git a/CHANGELOG.md b/CHANGELOG.md index 77016a4..c145a90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,61 @@ The change log describes what is "Added", "Removed", "Changed" or "Fixed" between each release. +## 4.4.0 + +### Added + +- Add support for PHP Geocoder 5 + +## 4.3.1 + +### Changed + +- Fix `utf8_encode()` deprecation[^1] + +## 4.3.0 + +### Added + +- Add support for PHP 8.1 +- Add GitHub Actions workflow + +### Removed + +- Drop support for PHP 7.3 + +### Changed + +- Migrate from PHP-HTTP to PSR-18 client + +## 4.2.0 + +### Added + +- Add support for PHP 8.0 + +### Removed + +- Drop support for PHP 7.2 + +### Changed + +- Upgrade PHPUnit to version 9 + +## 4.1.0 + +### Removed + +- Drop support for PHP < 7.2 + +## 4.0.1 + +### Fixed + +- Fix issue with `utf8_encode()` + ## 4.0.0 -First release of this library. +First release of this library. + +[^1]: See https://www.php.net/manual/en/function.utf8-encode.php diff --git a/MaxMindBinary.php b/MaxMindBinary.php index 55a42aa..3e1f8a8 100644 --- a/MaxMindBinary.php +++ b/MaxMindBinary.php @@ -18,10 +18,10 @@ use Geocoder\Exception\UnsupportedOperation; use Geocoder\Model\Address; use Geocoder\Model\AddressCollection; -use Geocoder\Query\GeocodeQuery; -use Geocoder\Query\ReverseQuery; use Geocoder\Provider\AbstractProvider; use Geocoder\Provider\Provider; +use Geocoder\Query\GeocodeQuery; +use Geocoder\Query\ReverseQuery; final class MaxMindBinary extends AbstractProvider implements Provider { @@ -36,26 +36,17 @@ final class MaxMindBinary extends AbstractProvider implements Provider private $openFlag; /** - * @param string $datFile - * @param int|null $openFlag - * * @throws FunctionNotFound if maxmind's lib not installed * @throws InvalidArgument if dat file is not correct (optional) */ - public function __construct(string $datFile, int $openFlag = null) + public function __construct(string $datFile, ?int $openFlag = null) { if (false === function_exists('geoip_open')) { - throw new FunctionNotFound( - 'geoip_open', - 'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoip.inc file?' - ); + throw new FunctionNotFound('geoip_open', 'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoip.inc file?'); } if (false === function_exists('GeoIP_record_by_addr')) { - throw new FunctionNotFound( - 'GeoIP_record_by_addr', - 'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoipcity.inc file?' - ); + throw new FunctionNotFound('GeoIP_record_by_addr', 'The MaxMindBinary requires maxmind\'s lib to be installed and loaded. Have you included geoipcity.inc file?'); } if (false === is_file($datFile)) { @@ -70,9 +61,6 @@ public function __construct(string $datFile, int $openFlag = null) $this->openFlag = null === $openFlag ? GEOIP_STANDARD : $openFlag; } - /** - * {@inheritdoc} - */ public function geocodeQuery(GeocodeQuery $query): Collection { $address = $query->getText(); @@ -104,9 +92,9 @@ public function geocodeQuery(GeocodeQuery $query): Collection Address::createFromArray([ 'providedBy' => $this->getName(), 'countryCode' => $geoIpRecord->country_code, - 'country' => utf8_encode($geoIpRecord->country_name), + 'country' => null === $geoIpRecord->country_name ? null : mb_convert_encoding($geoIpRecord->country_name, 'UTF-8', 'ISO-8859-1'), 'adminLevels' => $adminLevels, - 'locality' => utf8_encode($geoIpRecord->city), + 'locality' => null === $geoIpRecord->city ? null : mb_convert_encoding($geoIpRecord->city, 'UTF-8', 'ISO-8859-1'), 'latitude' => $geoIpRecord->latitude, 'longitude' => $geoIpRecord->longitude, 'postalCode' => $geoIpRecord->postal_code, @@ -114,17 +102,11 @@ public function geocodeQuery(GeocodeQuery $query): Collection ]); } - /** - * {@inheritdoc} - */ public function reverseQuery(ReverseQuery $query): Collection { throw new UnsupportedOperation('The MaxMindBinary is not able to do reverse geocoding.'); } - /** - * {@inheritdoc} - */ public function getName(): string { return 'maxmind_binary'; diff --git a/Tests/IntegrationTest.php b/Tests/IntegrationTest.php index f26a3af..e92bd72 100644 --- a/Tests/IntegrationTest.php +++ b/Tests/IntegrationTest.php @@ -14,22 +14,24 @@ use Geocoder\IntegrationTest\ProviderIntegrationTest; use Geocoder\Provider\MaxMindBinary\MaxMindBinary; -use Http\Client\HttpClient; +use Psr\Http\Client\ClientInterface; /** * @author Tobias Nyholm */ class IntegrationTest extends ProviderIntegrationTest { - protected $skippedTests = [ - ]; + protected array $skippedTests = []; - protected $testAddress = false; - protected $testReverse = false; - protected $testIpv6 = false; - protected $testHttpProvider = false; + protected bool $testAddress = false; - public static function setUpBeforeClass() + protected bool $testReverse = false; + + protected bool $testIpv6 = false; + + protected bool $testHttpProvider = false; + + public static function setUpBeforeClass(): void { if (false == function_exists('geoip_open')) { self::markTestSkipped('The maxmind\'s official lib required to run these tests.'); @@ -42,18 +44,18 @@ public static function setUpBeforeClass() parent::setUpBeforeClass(); } - protected function createProvider(HttpClient $httpClient) + protected function createProvider(ClientInterface $httpClient) { return new MaxMindBinary(__DIR__.'/fixtures/GeoLiteCity.dat'); } - protected function getCacheDir() + protected function getCacheDir(): string { return __DIR__.'/.cached_responses'; } - protected function getApiKey() + protected function getApiKey(): string { - return null; + return ''; } } diff --git a/Tests/MaxMindBinaryTest.php b/Tests/MaxMindBinaryTest.php index d54e6e9..dca752e 100644 --- a/Tests/MaxMindBinaryTest.php +++ b/Tests/MaxMindBinaryTest.php @@ -15,25 +15,25 @@ use Geocoder\Collection; use Geocoder\IntegrationTest\BaseTestCase; use Geocoder\Location; +use Geocoder\Provider\MaxMindBinary\MaxMindBinary; use Geocoder\Query\GeocodeQuery; use Geocoder\Query\ReverseQuery; -use Geocoder\Provider\MaxMindBinary\MaxMindBinary; class MaxMindBinaryTest extends BaseTestCase { - private $binaryFile; + private string $binaryFile; - public function setUp() + public function setUp(): void { $this->binaryFile = __DIR__.'/fixtures/GeoLiteCity.dat'; } - protected function getCacheDir() + protected function getCacheDir(): string { return __DIR__.'/.cached_responses'; } - public static function setUpBeforeClass() + public static function setUpBeforeClass(): void { if (false == function_exists('geoip_open')) { self::markTestSkipped('The maxmind\'s official lib required to run these tests.'); @@ -44,7 +44,10 @@ public static function setUpBeforeClass() } } - public static function provideIps() + /** + * @return array + */ + public static function provideIps(): array { return [ '24.24.24.24' => ['24.24.24.24', 'East Syracuse', 'United States'], @@ -52,29 +55,28 @@ public static function provideIps() ]; } - /** - * @expectedException \Geocoder\Exception\InvalidArgument - * @expectedExceptionMessage Given MaxMind dat file "not_exist.dat" does not exist. - */ - public function testThrowIfNotExistBinaryFileGiven() + public function testThrowIfNotExistBinaryFileGiven(): void { + $this->expectException(\Geocoder\Exception\InvalidArgument::class); + $this->expectExceptionMessage('Given MaxMind dat file "not_exist.dat" does not exist.'); + new MaxMindBinary('not_exist.dat'); } - public function testLocationResultContainsExpectedFieldsForAnAmericanIp() + public function testLocationResultContainsExpectedFieldsForAnAmericanIp(): void { $provider = new MaxMindBinary($this->binaryFile); $results = $provider->geocodeQuery(GeocodeQuery::create('24.24.24.24')); - $this->assertInstanceOf('Geocoder\Model\AddressCollection', $results); + $this->assertInstanceOf(\Geocoder\Model\AddressCollection::class, $results); $this->assertCount(1, $results); /** @var Location $result */ $result = $results->first(); - $this->assertInstanceOf('\Geocoder\Model\Address', $result); + $this->assertInstanceOf(\Geocoder\Model\Address::class, $result); - $this->assertEquals('43.089200000000005', $result->getCoordinates()->getLatitude(), '', 0.001); - $this->assertEquals('-76.025000000000006', $result->getCoordinates()->getLongitude(), '', 0.001); + $this->assertEqualsWithDelta(43.089200000000005, $result->getCoordinates()->getLatitude(), 0.001); + $this->assertEqualsWithDelta(-76.025000000000006, $result->getCoordinates()->getLongitude(), 0.001); $this->assertNull($result->getBounds()); $this->assertNull($result->getStreetNumber()); $this->assertNull($result->getStreetName()); @@ -89,20 +91,20 @@ public function testLocationResultContainsExpectedFieldsForAnAmericanIp() $this->assertNull($result->getTimezone()); } - public function testLocationResultContainsExpectedFieldsForASpanishIp() + public function testLocationResultContainsExpectedFieldsForASpanishIp(): void { $provider = new MaxMindBinary($this->binaryFile); $results = $provider->geocodeQuery(GeocodeQuery::create('80.24.24.24')); - $this->assertInstanceOf('Geocoder\Model\AddressCollection', $results); + $this->assertInstanceOf(\Geocoder\Model\AddressCollection::class, $results); $this->assertCount(1, $results); /** @var Location $result */ $result = $results->first(); - $this->assertInstanceOf('\Geocoder\Model\Address', $result); + $this->assertInstanceOf(\Geocoder\Model\Address::class, $result); - $this->assertEquals('41.543299999999988', $result->getCoordinates()->getLatitude(), '', 0.001); - $this->assertEquals('2.1093999999999937', $result->getCoordinates()->getLongitude(), '', 0.001); + $this->assertEqualsWithDelta(41.543299999999988, $result->getCoordinates()->getLatitude(), 0.001); + $this->assertEqualsWithDelta(2.1093999999999937, $result->getCoordinates()->getLongitude(), 0.001); $this->assertNull($result->getBounds()); $this->assertNull($result->getStreetNumber()); $this->assertNull($result->getStreetName()); @@ -120,40 +122,40 @@ public function testLocationResultContainsExpectedFieldsForASpanishIp() /** * @dataProvider provideIps */ - public function testFindLocationByIp($ip, $expectedCity, $expectedCountry) + public function testFindLocationByIp(string $ip, ?string $expectedCity, ?string $expectedCountry): void { $provider = new MaxMindBinary($this->binaryFile); $results = $provider->geocodeQuery(GeocodeQuery::create($ip)); - $this->assertInstanceOf('Geocoder\Model\AddressCollection', $results); + $this->assertInstanceOf(\Geocoder\Model\AddressCollection::class, $results); $this->assertCount(1, $results); /** @var Location $result */ $result = $results->first(); - $this->assertInstanceOf('\Geocoder\Model\Address', $result); + $this->assertInstanceOf(\Geocoder\Model\Address::class, $result); $this->assertEquals($expectedCity, $result->getLocality()); $this->assertEquals($expectedCountry, $result->getCountry()->getName()); } - public function testShouldReturnResultsAsUtf8Encoded() + public function testShouldReturnResultsAsUtf8Encoded(): void { $provider = new MaxMindBinary($this->binaryFile); $results = $provider->geocodeQuery(GeocodeQuery::create('212.51.181.237')); /** @var Location $result */ $result = $results->first(); - $this->assertInstanceOf('\Geocoder\Model\Address', $result); + $this->assertInstanceOf(\Geocoder\Model\Address::class, $result); $this->assertSame('Châlette-sur-loing', $result->getLocality()); } - public function testGetName() + public function testGetName(): void { $provider = new MaxMindBinary($this->binaryFile); $this->assertEquals('maxmind_binary', $provider->getName()); } - public function testThrowIfIpAddressCouldNotBeLocated() + public function testThrowIfIpAddressCouldNotBeLocated(): void { $provider = new MaxMindBinary($this->binaryFile); $result = $provider->geocodeQuery(GeocodeQuery::create('127.0.0.1')); @@ -162,34 +164,31 @@ public function testThrowIfIpAddressCouldNotBeLocated() $this->assertEquals(0, $result->count()); } - /** - * @expectedException \Geocoder\Exception\UnsupportedOperation - * @expectedExceptionMessage The MaxMindBinary provider does not support IPv6 addresses. - */ - public function testThrowIfIpAddressIsNotIpV4() + public function testThrowIfIpAddressIsNotIpV4(): void { + $this->expectException(\Geocoder\Exception\UnsupportedOperation::class); + $this->expectExceptionMessage('The MaxMindBinary provider does not support IPv6 addresses.'); + $provider = new MaxMindBinary($this->binaryFile); $provider->geocodeQuery(GeocodeQuery::create('2002:5018:1818:0:0:0:0:0')); } - /** - * @expectedException \Geocoder\Exception\UnsupportedOperation - * @expectedExceptionMessage The MaxMindBinary provider does not support street addresses. - */ - public function testThrowIfInvalidIpAddressGiven() + public function testThrowIfInvalidIpAddressGiven(): void { + $this->expectException(\Geocoder\Exception\UnsupportedOperation::class); + $this->expectExceptionMessage('The MaxMindBinary provider does not support street addresses.'); + $provider = new MaxMindBinary($this->binaryFile); $provider->geocodeQuery(GeocodeQuery::create('invalidIp')); } - /** - * @expectedException \Geocoder\Exception\UnsupportedOperation - * @expectedExceptionMessage The MaxMindBinary is not able to do reverse geocoding. - */ - public function testThrowOnReverseMethodUsage() + public function testThrowOnReverseMethodUsage(): void { + $this->expectException(\Geocoder\Exception\UnsupportedOperation::class); + $this->expectExceptionMessage('The MaxMindBinary is not able to do reverse geocoding.'); + $provider = new MaxMindBinary($this->binaryFile); $provider->reverseQuery(ReverseQuery::fromCoordinates(0, 0)); diff --git a/composer.json b/composer.json index 34b38a9..6b9adb2 100644 --- a/composer.json +++ b/composer.json @@ -12,32 +12,35 @@ } ], "require": { - "php": "^7.0", + "php": "^8.0", "geoip/geoip": "^1.17", - "willdurand/geocoder": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.1", - "geocoder-php/provider-integration-tests": "^1.0.1" + "symfony/polyfill-mbstring": "^1.0", + "willdurand/geocoder": "^4.0|^5.0" }, "provide": { "geocoder-php/provider-implementation": "1.0" }, + "require-dev": { + "geocoder-php/provider-integration-tests": "^1.6.3", + "phpunit/phpunit": "^9.5" + }, + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, "autoload": { - "psr-4": { "Geocoder\\Provider\\MaxMindBinary\\": "" }, + "psr-4": { + "Geocoder\\Provider\\MaxMindBinary\\": "" + }, "exclude-from-classmap": [ "/Tests/" ] }, + "minimum-stability": "dev", + "prefer-stable": true, "scripts": { "test": "vendor/bin/phpunit", "test-ci": "vendor/bin/phpunit --coverage-text --coverage-clover=build/coverage.xml" - }, - "minimum-stability": "dev", - "prefer-stable": true, - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 21fa595..548cbd0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,29 +1,21 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Tests - ./vendor - - - + + + + ./ + + + ./Tests + ./vendor + + + + + + + + + ./Tests/ + +