diff --git a/.gitignore b/.gitignore index 2c1fc0c..7cfd555 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /vendor composer.phar composer.lock -.DS_Store \ No newline at end of file +.DS_Store +.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml index a2e8692..a586f6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: php php: - - 7.1.3 - - 7.2 + - 7.3 + - 7.4 before_script: - travis_retry composer self-update diff --git a/CHANGELOG.md b/CHANGELOG.md index bc90a20..bf9a76b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +## [4.3.4] - 2020-06-21 +### Fixed +- non-caching declaration to only apply to current query. +- caching to take provider into account. + +### Changed +- `getProvider()` method to no longer be deprecated, and instead return the + currently set provider, or if none set, the first configured provider. + +## [4.3.3] - 2020-06-20 +### Added +- functionality to not cache requests by using `doNotCache()`. + +## [4.3.0] - 2020-02-29 +### Added +- Laravel 7 compatibility. + ## [4.1.2] - 23 May 2019 ### Fixed - initialization of geocoder adapter. diff --git a/README.md b/README.md index f4bed33..268684c 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ database: ], ``` -Finally, configure Geocoder for Laraver to use this store. Edit +Finally, configure Geocoder for Laravel to use this store. Edit `config/geocoder.php`: ```php "cache" => [ @@ -95,11 +95,20 @@ Finally, configure Geocoder for Laraver to use this store. Edit ], ``` +#### Disabling Caching on a Query-Basis +You can disable caching on a query-by-query basis as needed, like so: +```php + $results = app("geocoder") + ->doNotCache() + ->geocode('Los Angeles, CA') + ->get(); +``` + ### Providers If you are upgrading and have previously published the geocoder config file, you need to add the `cache-duration` variable, otherwise cache will be disabled (it will default to a `0` cache duration). The default cache duration provided - by the config file is `999999999` minutes, essentially forever. + by the config file is `999999999` seconds, essentially forever. By default, the configuration specifies a Chain provider, containing the GoogleMaps provider for addresses as well as reverse lookups with lat/long, @@ -152,7 +161,7 @@ return [ 'providers' => [ Chain::class => [ GoogleMaps::class => [ - env('GOOGLE_MAPS_LOCALE', 'en-US'), + env('GOOGLE_MAPS_LOCALE', 'us'), env('GOOGLE_MAPS_API_KEY'), ], GeoPlugin::class => [], @@ -182,7 +191,8 @@ return [ | | You can specify a reader for specific providers, like GeoIp2, which | connect to a local file-database. The reader should be set to an - | instance of the required reader class. + | instance of the required reader class or an array containing the reader + | class and arguments. | | Please consult the official Geocoder documentation for more info. | https://github.com/geocoder-php/geoip2-provider @@ -264,7 +274,7 @@ The one change to keep in mind here is that the results returned from instead of returning an instance of `AddressCollection`. This should provide greater versatility in manipulation of the results, and be inline with expectations for working with Laravel. The existing `AddressCollection` - methods should map strait over to Laravel's `Collection` methods. But be sure + methods should map straight over to Laravel's `Collection` methods. But be sure to double-check your results, if you have been using `count()`, `first()`, `isEmpty()`, `slice()`, `has()`, `get()`, or `all()` on your results. diff --git a/composer.json b/composer.json index 4b8ad1c..21cd476 100644 --- a/composer.json +++ b/composer.json @@ -23,31 +23,28 @@ } ], "require": { - "geocoder-php/chain-provider": "^4.0", - "geocoder-php/geo-plugin-provider": "^4.0", - "geocoder-php/google-maps-provider": "^4.0", + "geocoder-php/chain-provider": "^4.0|^5.0", + "geocoder-php/geo-plugin-provider": "^4.0|^5.0", + "geocoder-php/google-maps-provider": "^4.0|^5.0", "guzzlehttp/psr7": "*", "http-interop/http-factory-guzzle": "^1.0", - "illuminate/cache": "5.0 - 5.8", - "illuminate/support": "5.0 - 5.8", + "illuminate/cache": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^5.0|^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", "php-http/curl-client": "*", - "php": ">=7.1.3", - "willdurand/geocoder": "^4.0" + "php": "^8.0", + "willdurand/geocoder": "^4.0|^5.0" }, "require-dev": { "doctrine/dbal": "*", - "fzaninotto/faker": "*", "geocoder-php/bing-maps-provider": "^4.0", "geocoder-php/geoip2-provider": "^4.0", "geocoder-php/maxmind-binary-provider": "^4.0", - "mockery/mockery": "*", - "orchestra/testbench-browser-kit": "3.8.*", - "orchestra/database": "3.8.x-dev@dev", - "orchestra/testbench-dusk": "3.8.x-dev@dev", - "orchestra/testbench": "3.8.*", + "laravel/legacy-factories": "^1.0", + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "orchestra/testbench-browser-kit": "^7.0|^8.5|^10.0", + "orchestra/testbench-dusk": "^7.0|^8.22|^10.0", "php-coveralls/php-coveralls": "*", - "phpunit/phpunit": "^7.5", - "sebastian/phpcpd": "*" + "phpunit/phpunit": "8.5|^9.0|^10.5|^11.5.3" }, "autoload": { "psr-4": { @@ -67,9 +64,13 @@ ] } }, + "minimum-stability": "dev", "prefer-stable": true, "config": { "preferred-install": "dist", - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "php-http/discovery": true + } } } diff --git a/config/geocoder.php b/config/geocoder.php index d04b40d..c48c183 100644 --- a/config/geocoder.php +++ b/config/geocoder.php @@ -27,7 +27,7 @@ | Cache Duration |----------------------------------------------------------------------- | - | Specify the cache duration in minutes. The default approximates a + | Specify the cache duration in seconds. The default approximates a | "forever" cache, but there are certain issues with Laravel's forever | caching methods that prevent us from using them in this project. | @@ -58,7 +58,7 @@ 'providers' => [ Chain::class => [ GoogleMaps::class => [ - env('GOOGLE_MAPS_LOCALE', 'en-US'), + env('GOOGLE_MAPS_LOCALE', 'us'), env('GOOGLE_MAPS_API_KEY'), ], GeoPlugin::class => [], @@ -88,13 +88,22 @@ | | You can specify a reader for specific providers, like GeoIp2, which | connect to a local file-database. The reader should be set to an - | instance of the required reader class. + | instance of the required reader class or an array containing the reader + | class and arguments. | | Please consult the official Geocoder documentation for more info. | https://github.com/geocoder-php/geoip2-provider | | Default: null | + | Example: + | 'reader' => [ + | WebService::class => [ + | env('MAXMIND_USER_ID'), + | env('MAXMIND_LICENSE_KEY') + | ], + | ], + | */ 'reader' => null, diff --git a/phpmd.xml b/phpmd.xml new file mode 100644 index 0000000..e69de29 diff --git a/phpunit.xml b/phpunit.xml index fa0e22b..1524cdf 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,41 +1,34 @@ - - - ./tests/Browser - - + + + ./src + + + - ./tests/Feature - - - - ./tests/Unit + ./tests/Feature - - - - ./src - - - - - - - - - - - - + + + + + + + + + + diff --git a/src/ProviderAndDumperAggregator.php b/src/ProviderAndDumperAggregator.php index 1aa8c9d..a5c07c9 100644 --- a/src/ProviderAndDumperAggregator.php +++ b/src/ProviderAndDumperAggregator.php @@ -18,8 +18,10 @@ use Geocoder\ProviderAggregator; use Geocoder\Query\GeocodeQuery; use Geocoder\Query\ReverseQuery; +use Illuminate\Log\Logger; use Illuminate\Support\Collection; use Illuminate\Support\Str; +use Psr\Log\LoggerAwareTrait; use ReflectionClass; /** @@ -30,6 +32,7 @@ class ProviderAndDumperAggregator protected $aggregator; protected $limit; protected $results; + protected $isCaching = true; public function __construct() { @@ -57,6 +60,13 @@ public function toJson() : string ->first(); } + public function doNotCache() : self + { + $this->isCaching = false; + + return $this; + } + public function dump(string $dumper) : Collection { $dumperClasses = collect([ @@ -120,12 +130,14 @@ public function limit(int $limit) : self return $this; } - /** - * @deprecated Use `getProviders()` instead. - */ public function getProvider() { - return $this->getProviders()->first(); + $reflectedClass = new ReflectionClass(ProviderAggregator::class); + $reflectedProperty = $reflectedClass->getProperty('provider'); + $reflectedProperty->setAccessible(true); + + return $reflectedProperty->getValue($this->aggregator) + ?? $this->getProviders()->first(); } public function getProviders() : Collection @@ -179,7 +191,13 @@ public function using(string $name) : self protected function cacheRequest(string $cacheKey, array $queryElements, string $queryType) { - $hashedCacheKey = sha1($cacheKey); + if (! $this->isCaching) { + $this->isCaching = true; + + return collect($this->aggregator->{$queryType}(...$queryElements)); + } + + $hashedCacheKey = sha1($this->getProvider()->getName() . "-" . $cacheKey); $duration = config("geocoder.cache.duration", 0); $store = config('geocoder.cache.store'); @@ -219,6 +237,20 @@ protected function getAdapterClass(string $provider) : string return config('geocoder.adapter'); } + protected function getReader() + { + $reader = config('geocoder.reader'); + + if (is_array(config('geocoder.reader'))) { + $readerClass = array_key_first(config('geocoder.reader')); + $readerArguments = config('geocoder.reader')[$readerClass]; + $reflection = new ReflectionClass($readerClass); + $reader = $reflection->newInstanceArgs($readerArguments); + } + + return $reader; + } + protected function getArguments(array $arguments, string $provider) : array { if ($provider === 'Geocoder\Provider\Chain\Chain') { @@ -230,9 +262,11 @@ protected function getArguments(array $arguments, string $provider) : array $adapter = $this->getAdapterClass($provider); if ($adapter) { - $adapter = $this->requiresReader($provider) - ? new $adapter(config('geocoder.reader')) - : new $adapter; + if ($this->requiresReader($provider)) { + $adapter = new $adapter($this->getReader()); + } else { + $adapter = new $adapter; + } array_unshift($arguments, $adapter); } @@ -246,8 +280,17 @@ protected function getProvidersFromConfiguration(Collection $providers) : array $arguments = $this->getArguments($arguments, $provider); $reflection = new ReflectionClass($provider); - if ($provider === 'Geocoder\Provider\Chain\Chain') { - return $reflection->newInstance($arguments); + if ($provider === "Geocoder\Provider\Chain\Chain") { + $chainProvider = $reflection->newInstance($arguments); + + if (class_exists(Logger::class) + && in_array(LoggerAwareTrait::class, class_uses($chainProvider)) + && app(Logger::class) !== null + ) { + $chainProvider->setLogger(app(Logger::class)); + } + + return $chainProvider; } return $reflection->newInstanceArgs($arguments); @@ -277,7 +320,9 @@ protected function preventCacheKeyHashCollision( protected function removeEmptyCacheEntry(Collection $result, string $cacheKey) { if ($result && $result->isEmpty()) { - app('cache')->forget($cacheKey); + app('cache') + ->store(config('geocoder.cache.store')) + ->forget($cacheKey); } } diff --git a/tests/BrowserTestCase.php b/tests/BrowserTestCase.php deleted file mode 100644 index 8b191b6..0000000 --- a/tests/BrowserTestCase.php +++ /dev/null @@ -1,18 +0,0 @@ -reverse(38.897957, -77.036560) - ->get() - ->filter(function (GoogleAddress $address) { - return str_contains($address->getStreetName() ?? '', 'Northwest'); - }) - ->first(); - - $this->assertNotNull($result); - $this->assertEquals('1600', $result->getStreetNumber()); - $this->assertEquals('Pennsylvania Avenue Northwest', $result->getStreetName()); - $this->assertEquals('Washington', $result->getLocality()); - $this->assertEquals('20500', $result->getPostalCode()); - } + // public function testItReverseGeocodesCoordinates() + // { + // $result = app('geocoder') + // ->reverse(38.897957, -77.036560) + // ->get() + // ->filter(function (GoogleAddress $address) { + // return Str::contains($address->getStreetName() ?? '', 'Northwest'); + // }) + // ->first(); + + // $this->assertNotNull($result); + // $this->assertEquals('1600', $result->getStreetNumber()); + // $this->assertEquals('Pennsylvania Avenue Northwest', $result->getStreetName()); + // $this->assertEquals('Washington', $result->getLocality()); + // $this->assertEquals('20500', $result->getPostalCode()); + // } public function testItResolvesAGivenAddress() { @@ -159,7 +159,10 @@ public function testGeocoder() public function testCacheIsUsed() { - $cacheKey = sha1(str_slug(strtolower(urlencode('1600 Pennsylvania Ave NW, Washington, DC 20500, USA')))); + $cacheKey = sha1( + app('geocoder')->getProvider()->getName() + . "-" . Str::slug(strtolower(urlencode('1600 Pennsylvania Ave NW, Washington, DC 20500, USA'))) + ); $result = app('geocoder') ->geocode('1600 Pennsylvania Ave NW, Washington, DC 20500, USA') @@ -270,16 +273,14 @@ public function testGetProvider() public function testJapaneseCharacterGeocoding() { - $cacheKey = sha1(str_slug(strtolower(urlencode('108-0075 東京都港区港南2丁目16-3')))); + $cacheKey = sha1(app('geocoder')->getProvider()->getName() + . "-" . Str::slug(strtolower(urlencode('108-0075 東京都港区港南2丁目16-3'))) + ); app('geocoder') ->geocode('108-0075 東京都港区港南2丁目16-3') ->get(); - $this->assertEquals( - $cacheKey, - sha1('108-0075e69db1e4baace983bde6b8afe58cbae6b8afe58d97efbc92e4b881e79baeefbc91efbc96efbc8defbc93') - ); $this->assertTrue(app('cache')->has($cacheKey)); } @@ -310,10 +311,32 @@ public function testItHandlesOnlyCityAndState() public function testEmptyResultsAreNotCached() { - $cacheKey = md5(str_slug(strtolower(urlencode('_')))); + $cacheKey = md5(Str::slug(strtolower(urlencode('_')))); Geocoder::geocode('_')->get(); $this->assertFalse(app('cache')->has("geocoder-{$cacheKey}")); } + + public function testCachingCanBeDisabled() + { + $results = app("geocoder") + ->doNotCache() + ->geocode('Los Angeles, CA') + ->get(); + + $this->assertEquals( + "Los Angeles, CA, USA", + $results->first()->getFormattedAddress() + ); + } + + public function testGetProviderReturnsCurrentProvider() + { + $provider = app("geocoder") + ->using("google_maps") + ->getProvider(); + + $this->assertEquals("google_maps", $provider->getName()); + } } diff --git a/tests/UnitTestCase.php b/tests/UnitTestCase.php deleted file mode 100644 index 12c041f..0000000 --- a/tests/UnitTestCase.php +++ /dev/null @@ -1,8 +0,0 @@ - Client::class, - 'reader' => new Reader(__DIR__ . '/../resources/assets/GeoLite2-City.mmdb'), + // 'reader' => new Reader(__DIR__ . '/../resources/assets/GeoLite2-City.mmdb'), + "reader" => [ + Reader::class => [ + __DIR__ . '/../resources/assets/GeoLite2-City.mmdb', + ], + ], ];