PHPackages                             multek/laravel-geoaddress - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. multek/laravel-geoaddress

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

multek/laravel-geoaddress
=========================

Production-ready polymorphic address system with automatic geocoding for Laravel

v1.1.0(1mo ago)11MITPHPPHP ^8.2CI failing

Since Dec 4Pushed 1mo agoCompare

[ Source](https://github.com/rodrigocoliveira/laravel-geoaddress)[ Packagist](https://packagist.org/packages/multek/laravel-geoaddress)[ RSS](/packages/multek-laravel-geoaddress/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (12)Versions (8)Used By (0)

Laravel Geoaddress
==================

[](#laravel-geoaddress)

Production-ready polymorphic address system with automatic geocoding, PostGIS geographic queries, and multi-provider support.

Features
--------

[](#features)

- **Polymorphic Relationships** - Any model can have multiple addresses
- **Automatic Geocoding** - Background job processing with Google Maps API (or other providers)
- **PostGIS Integration** - Geographic queries and spatial indexing
- **Brazilian Address Format** - Street, number, complement, neighbourhood, city, state, postal code
- **Smart Geocoding Control** - `geocoding_enabled` flag for address types that don't need coordinates
- **Trust-Based Coordinate Input** - Pass lat/lng to skip geocoding API calls
- **Multiple Address Types** - Home, work, billing, shipping, delivery with custom nicknames
- **Customer Contact Information** - Store recipient/contact details with each address
- **Flexible Metadata** - JSON storage for edge cases and custom data
- **Multi-Provider Geocoding** - Support for Google Maps, Nominatim (free), Mapbox
- **Smart Re-geocoding** - Automatically re-geocodes when address fields change (unless coordinates provided)

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 11.0+
- **PostgreSQL with PostGIS extension** (required)

> **Note:** This package is designed exclusively for PostgreSQL with PostGIS. It uses PostGIS geography types for storing coordinates and spatial indexing, enabling powerful geographic queries like radius searches. MySQL and SQLite are not supported.

Installation
------------

[](#installation)

```
composer require multek/laravel-geoaddress
```

### Quick Install

[](#quick-install)

The easiest way to install is using the install command:

```
php artisan geoaddress:install
```

This will:

1. Check and enable PostGIS extension if needed
2. Publish the configuration file
3. Publish and run migrations

### Manual Installation

[](#manual-installation)

If you prefer to install manually:

```
# Enable PostGIS (if not already enabled)
psql -d your_database -c "CREATE EXTENSION IF NOT EXISTS postgis;"

# Publish config and migrations
php artisan vendor:publish --tag=geoaddress-config
php artisan vendor:publish --tag=geoaddress-migrations
php artisan migrate
```

### Environment Variables

[](#environment-variables)

```
# Geocoding Provider: google, nominatim, mapbox
GEOADDRESS_PROVIDER=google

# Fallback Provider (optional) - used if primary fails
GEOADDRESS_FALLBACK_PROVIDER=nominatim

# Google Maps (if using google provider)
GOOGLE_MAPS_API_KEY=your-api-key-here

# Nominatim (if using nominatim provider - optional custom URL)
NOMINATIM_URL=https://nominatim.openstreetmap.org
NOMINATIM_USER_AGENT=YourAppName

# Mapbox (if using mapbox provider)
MAPBOX_ACCESS_TOKEN=your-access-token

# Queue settings (optional)
GEOADDRESS_QUEUE_CONNECTION=redis
GEOADDRESS_QUEUE_NAME=geocoding
```

> **Tip:** For production, we recommend using Google Maps as primary provider and Nominatim as fallback. Google is more accurate, especially for Brazilian addresses, while Nominatim provides free fallback if Google is unavailable.

Usage
-----

[](#usage)

### Make a Model Addressable

[](#make-a-model-addressable)

```
use Multek\LaravelGeoaddress\Traits\Addressable;

class Customer extends Model
{
    use Addressable;
}
```

### Creating Addresses

[](#creating-addresses)

```
// Delivery address - Will be geocoded automatically
$customer->addAddress([
    'type' => 'delivery',
    'is_primary' => true,
    'street' => 'Avenida Paulista',
    'number' => '1578',
    'neighbourhood' => 'Bela Vista',
    'city' => 'Sao Paulo',
    'state' => 'SP',
    'postal_code' => '01310-200',
    'country_code' => 'BR',
]);

// Billing address - No geocoding
$customer->addAddress([
    'type' => 'billing',
    'geocoding_enabled' => false,
    'street' => 'Rua Fiscal',
    'number' => '100',
    'city' => 'Sao Paulo',
    'state' => 'SP',
    'country_code' => 'BR',
]);

// Delivery from map picker - Skip geocoding API ("trust me")
$customer->addAddress([
    'type' => 'delivery',
    'street' => 'Avenida Paulista',
    'number' => '1578',
    'city' => 'Sao Paulo',
    'state' => 'SP',
    'country_code' => 'BR',
    'latitude' => -23.561414,
    'longitude' => -46.656689,
]);
```

### Working with Addresses

[](#working-with-addresses)

```
// Get all addresses
$addresses = $customer->addresses;

// Get primary address
$primary = $customer->primaryAddress();

// Get formatted address string
$formatted = $customer->full_address;

// Set primary address
$customer->setPrimaryAddress($addressId);

// Get only geocoding-enabled addresses
$physical = $customer->geocodableAddresses;
```

### Query Scopes

[](#query-scopes)

```
use Multek\LaravelGeoaddress\Models\Address;

$geocoded = Address::geocoded()->get();
$failed = Address::failed()->get();
$primary = Address::primary()->get();
$needsGeocoding = Address::needsGeocoding()->get();
$geocodingEnabled = Address::geocodingEnabled()->get();
```

### Geographic Queries (PostGIS)

[](#geographic-queries-postgis)

```
use MatanYadaev\EloquentSpatial\Objects\Point;

// Find addresses within 5km radius
$nearby = Address::geocodingEnabled()
    ->whereRaw(
        'ST_DWithin(coordinates::geography, ST_MakePoint(?, ?)::geography, ?)',
        [$longitude, $latitude, 5000]
    )
    ->get();
```

### Listening to Events

[](#listening-to-events)

```
use Multek\LaravelGeoaddress\Events\AddressGeocoded;

// In a listener or EventServiceProvider
Event::listen(AddressGeocoded::class, function ($event) {
    // $event->address contains the geocoded address
});
```

Geocoding Design Philosophy
---------------------------

[](#geocoding-design-philosophy)

The geocoding system uses a two-layer approach to decide when and how coordinates are set.

### Layer 1: `geocoding_enabled` (Persistent — stored in DB)

[](#layer-1-geocoding_enabled-persistent--stored-in-db)

Controls whether an address **should ever have coordinates**.

ValueMeaningExample`true` (default)Physical address — should have coordinatesdelivery, home, work`false`Non-physical address — coordinates are **always null**billing, PO Box, virtualWhen `geocoding_enabled` is `false`, the system **actively clears** coordinates, `geocoded_at`, and any geocoding error data on every save. This is enforced both in the model's `saving` callback and in the observer's `updating` event.

### Layer 2: `trustProvidedCoordinates` (Transient — per request only)

[](#layer-2-trustprovidedcoordinates-transient--per-request-only)

Controls whether the system **should call a geocoding API** or trust what was provided. This flag is set automatically when you pass `latitude` and `longitude` in the address data — you never set it manually.

ScenarioFlagWhat happens`addAddress()` without lat/lng`false`Geocoding job is dispatched`addAddress()` with lat/lng`true`Coordinates are used directly, **no API call**`update()` changes address fields, no lat/lng`false`Old coordinates are cleared, new geocoding job dispatched`update()` changes address fields, with lat/lng`true`New coordinates are used directly, **no API call**`update()` changes non-address fields (notes, metadata)`false`Nothing happens — existing coordinates are preserved### Lifecycle: Converting Address Types

[](#lifecycle-converting-address-types)

When you change `geocoding_enabled` on an existing address:

**Billing to Delivery** (`false` → `true`):

```
$address->update(['geocoding_enabled' => true, 'type' => 'delivery']);
// → Geocoding job is dispatched (address now needs coordinates)

// Or, if you already have coordinates:
$address->update([
    'geocoding_enabled' => true,
    'type' => 'delivery',
    'latitude' => -23.561414,
    'longitude' => -46.656689,
]);
// → Coordinates are stored directly, no API call
```

**Delivery to Billing** (`true` → `false`):

```
$address->update(['geocoding_enabled' => false, 'type' => 'billing']);
// → Coordinates, geocoded_at, and geocoding errors are all cleared
```

### Internal Flow Summary

[](#internal-flow-summary)

```
User calls addAddress() or update()
  │
  ├─ geocoding_enabled = false?
  │    └─ Clear all coordinate data → DONE
  │
  ├─ latitude + longitude provided?
  │    ├─ Set trustProvidedCoordinates = true
  │    ├─ Store Point coordinates (PostgreSQL)
  │    ├─ Set geocoded_at timestamp
  │    └─ Fire AddressGeocoded event → DONE (no API call)
  │
  └─ No coordinates provided?
       ├─ Address fields changed? → Clear old coords, dispatch GeocodeAddress job
       ├─ geocoding_enabled just turned on? → Dispatch GeocodeAddress job
       └─ Nothing relevant changed? → DONE (keep existing coords)

```

Geocoding Providers
-------------------

[](#geocoding-providers)

### Available Providers

[](#available-providers)

ProviderProsCons**Google Maps**Most accurate, great for BrazilRequires API key, costs money**Nominatim**Free, no API key neededLess accurate, rate limited (1 req/sec)**Mapbox**Good accuracy, generous free tierRequires access token### Fallback Provider

[](#fallback-provider)

If the primary provider fails (API down, rate limited, etc.), the system can automatically try a fallback provider:

```
GEOADDRESS_PROVIDER=google
GEOADDRESS_FALLBACK_PROVIDER=nominatim
```

### Custom Providers

[](#custom-providers)

```
use Multek\LaravelGeoaddress\Services\GeocoderFactory;

$factory = app(GeocoderFactory::class);

// Use a specific provider
$nominatim = $factory->make('nominatim');
$google = $factory->make('google');
$mapbox = $factory->make('mapbox');

// Extend with custom provider
$factory->extend('custom', CustomGeocoder::class);
```

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT License

###  Health Score

40

—

FairBetter than 88% of packages

Maintenance92

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~29 days

Total

5

Last Release

41d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/532197fb4915f98f7958d544b920ef85339270b9010632f3704ecee763310724?d=identicon)[rodrigocoliveira](/maintainers/rodrigocoliveira)

---

Top Contributors

[![rodrigocoliveira](https://avatars.githubusercontent.com/u/8976719?v=4)](https://github.com/rodrigocoliveira "rodrigocoliveira (17 commits)")

---

Tags

laravelgeocodingaddresspostgispolymorphic

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/multek-laravel-geoaddress/health.svg)

```
[![Health](https://phpackages.com/badges/multek-laravel-geoaddress/health.svg)](https://phpackages.com/packages/multek-laravel-geoaddress)
```

###  Alternatives

[spatie/laravel-livewire-wizard

Build wizards using Livewire

4061.0M4](/packages/spatie-laravel-livewire-wizard)[tonysm/importmap-laravel

Use ESM with importmap to manage modern JavaScript in Laravel without transpiling or bundling.

148399.8k1](/packages/tonysm-importmap-laravel)[bensampo/laravel-embed

Painless responsive embeds for videos, slideshows and more.

142146.8k](/packages/bensampo-laravel-embed)[dragon-code/pretty-routes

Pretty Routes for Laravel

10058.7k4](/packages/dragon-code-pretty-routes)[laracraft-tech/laravel-useful-additions

A collection of useful Laravel additions!

58109.4k](/packages/laracraft-tech-laravel-useful-additions)[tapp/filament-google-autocomplete-field

Filament plugin that provides a Google Autocomplete field

3098.1k](/packages/tapp-filament-google-autocomplete-field)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
