geocoder-php/geonames-provider
GeoNames provider for the PHP Geocoder library. Adds forward/reverse geocoding and place lookup via the GeoNames API, with configurable options and integration alongside other Geocoder providers for consistent address and location results.
Installation
composer require geocoder-php/geonames-provider
Requires geocoder-php/geocoder (≥2.0) as a dependency.
Basic Usage
use Geocoder\Geocoder;
use Geocoder\Provider\GeoNamesProvider;
$geocoder = new Geocoder();
$geocoder->registerProvider(new GeoNamesProvider('YOUR_GEONAMES_USERNAME'));
// Reverse geocoding (lat/lng → address)
$results = $geocoder->reverseQuery('40.714224', '-73.961452');
foreach ($results as $result) {
echo $result->getStreet() . "\n";
}
// Forward geocoding (address → lat/lng)
$results = $geocoder->geocodeQuery('1600 Pennsylvania Ave NW, Washington, DC');
foreach ($results as $result) {
echo $result->getCoordinates()->getLatitude() . "\n";
}
First Use Case
geocodeQuery() to verify if an address exists and fetch coordinates.reverseQuery() to display nearby landmarks or services for a given lat/lng.Batch Processing
$addresses = ['123 Main St', '456 Oak Ave'];
foreach ($addresses as $address) {
$result = $geocoder->geocodeQuery($address)->first();
if ($result) {
// Process valid coordinates
}
}
Fallback Strategy Combine with other providers (e.g., Google, OpenStreetMap) for redundancy:
$geocoder->registerProvider(new GeoNamesProvider('USERNAME'));
$geocoder->registerProvider(new \Geocoder\Provider\OpenStreetMapProvider());
Caching Responses Use Laravel’s cache to avoid repeated API calls:
$cacheKey = 'geonames_' . md5($address);
$result = Cache::remember($cacheKey, now()->addHours(1), function() use ($geocoder, $address) {
return $geocoder->geocodeQuery($address)->first();
});
Custom Field Extraction Extract specific fields (e.g., country, postal code) from results:
$result = $geocoder->reverseQuery($lat, $lng)->first();
$country = $result->getCountry();
$postalCode = $result->getPostalCode();
Integration with Laravel Models Add a geocoding trait to Eloquent models:
use Geocoder\Geocoder;
trait HasGeocode {
public function getCoordinatesAttribute() {
$geocoder = new Geocoder();
$geocoder->registerProvider(new GeoNamesProvider(config('services.geonames.username')));
return $geocoder->geocodeQuery($this->address)->first()?->getCoordinates();
}
}
Rate Limits
429 Too Many Requests).Incomplete Results
null or partial data.Username Sensitivity
.env:
GEONAMES_USERNAME=your_username_here
Then load it in config/services.php:
'geonames' => [
'username' => env('GEONAMES_USERNAME'),
],
Deprecated Methods
geocoder-php/geocoder may use getFormattedAddress() instead of getStreet().Time Zone Handling
$time = $result->getTimezone()->getTimeZone()->getOffset($timestamp);
Error Handling Wrap queries in try-catch to handle API failures gracefully:
try {
$result = $geocoder->geocodeQuery($address)->first();
} catch (\Geocoder\Exception\UnsupportedOperationException $e) {
// Fallback logic
}
Testing Use mock providers for unit tests:
$geocoder->registerProvider(new \Geocoder\Provider\MockProvider());
Performance
geocodeQuery() in batches (e.g., 100 addresses at a time) to avoid rate limits.Custom Providers
Extend GeoNamesProvider to add custom parameters:
class CustomGeoNamesProvider extends GeoNamesProvider {
public function __construct($username, array $options = []) {
parent::__construct($username, array_merge([
'language' => 'en',
'featureClass' => 'P',
], $options));
}
}
Logging Log failed queries to identify patterns (e.g., specific regions or address formats that fail):
\Log::error('Geocoding failed for: ' . $address, ['exception' => $e]);
Fallback to Free Tier
If using a paid GeoNames account, ensure the free tier (freegeoip.net) is not accidentally triggered by misconfigured endpoints.
How can I help you explore Laravel packages today?