Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Geolocation Bundle Laravel Package

phil/geolocation-bundle

A Symfony bundle for adding geolocation support to PHP applications. It provides configurable services for resolving and working with location data, making it easier to integrate geolocation features without building the underlying plumbing yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: do not composer require this into a Laravel app. ph-il/geolocation-bundle is a Symfony2 bundle (PHP 5.4/5.5 era, Doctrine 2.x), last released January 2015, archived, and has zero dependents. It won't autoload into Laravel, brings no service provider, and pulls Symfony2 FrameworkBundle/DependencyInjection expectations you'd have to shim. Treat it as a reference implementation to read, not a dependency to install.

What it actually gives you (worth mining):

  • A location trait/entity — lat/lng fields on your entities, with the interface + trait pair the bundle uses to let any entity be "geolocatable."
  • Address entities — a normalized address record (street, city, postal code, country) intended to be geocoded once and reused.
  • User geo location — a pattern for storing a user's last-known coordinates separately from their profile address.
  • Doctrine DQL distance functions — custom DQL functions (Haversine-style) registered with the ORM so you can write SELECT ... ORDER BY DISTANCE(...) inside DQL instead of raw SQL.

Where to look in the repo, in order:

  1. README.md — install snippet, bundle registration, mapping config. Short but shows the intended workflow.
  2. The Doctrine function directory (Doctrine/ or DQL/) — this is the only part with real value. The generated SQL is the Haversine formula written as a SQL snippet; copy it.
  3. Entity/ and any Resources/config/doctrine/*.orm.xml — shows the field types (decimal vs float) and indexes they chose.
  4. Any Trait/Interface files — the "geolocatable entity" contract.

First use case to port: "find the 20 nearest stores to this postcode." That's a bounding-box prefilter plus a Haversine ORDER BY, and it's what 90% of these bundles exist for. In Laravel that's a query scope plus ST_Distance_Sphere (MySQL 5.7+) or PostGIS ST_DWithin — roughly 30 lines. Read the bundle's DQL function to confirm the formula, then write it natively.

Implementation Patterns

Entity trait + interface. The bundle's core idea: an interface (GeolocatableInterface-style) plus a trait supplying latitude/longitude getters/setters. Port it as a PHP trait and an Eloquent interface:

trait HasCoordinates {
    public function scopeWithinBox($q, float $lat, float $lng, float $km) { /* ... */ }
    public function scopeOrderByDistance($q, float $lat, float $lng) { /* ... */ }
}

Use decimal(10,7) for latitude and decimal(10,7) for longitude — not float. Floats bite you on equality and on index-only scans.

Address as a separate aggregate. The bundle separates Address from the geolocatable entity on purpose: one address can be geocoded once and shared, and the geocode result (lat/lng + provider + accuracy) is metadata about the address, not about the user. Keep that separation. Geocode on write, cache the result keyed by a normalized address hash, never geocode in a request loop.

Custom DQL functions. Registration pattern in Symfony2 was:

doctrine:
  orm:
    dql:
      numeric_functions:
        DISTANCE: Phil\GeolocationBundle\Doctrine\...\Distance

The Laravel equivalent is Doctrine\ORM\Configuration::addCustomNumericFunction() if you're using Doctrine via laravel-doctrine, or just an Eloquent scope. Don't register the bundle's function as-is — the emitted SQL is dialect-specific (written against MySQL of that era) and will not run on Postgres or on MySQL 8 with ONLY_FULL_GROUP_BY.

Bounding-box prefilter before Haversine. The pattern that matters: compute a lat/lng box (lat ± km/111, lng ± km/(111*cos(lat))), index (latitude, longitude), filter with a cheap BETWEEN, then sort by the expensive trig expression on the small result set. Pure Haversine over a full table is a sequential scan; this bundle's docs gloss over that and it's the #1 reason people think geo queries are "slow."

Integration tips for a Laravel migration:

  • Keep the DB doing distance math; don't pull 50k rows into PHP to sort by sqrt(...).
  • Wrap distance queries in a repository/scope so you can swap MySQL → PostGIS later.
  • Store a geocoded_at and geocoder column. You will re-geocode, and you'll want to know which records used a bad provider.
  • Round display distances (round($km, 1)) in the presenter, never in SQL.

Gotchas and Tips

Archived means archived. No security patches, no PHP 8 compatibility, no Doctrine 3 support. Even in a legacy Symfony 2.8 app, budget for patching the DQL function yourself. Do not add it to a new project under any circumstances.

Symfony2 vs Laravel is a hard wall. There's no bridge, no GeoServiceProvider, and the bundle assumes AppKernel::registerBundles() plus YAML/XML Doctrine mapping. You'd spend longer shimming than rewriting. The realistic play is a half-day port of the two useful pieces (trait + distance SQL).

The DQL function is dialect-locked. Check which SQL it emits before trusting it. The classic bug: it uses RADIANS()/ACOS() with a LEAST(1, ...) guard — and without that guard, floating-point drift makes ACOS of 1.0000001 return NULL, silently dropping rows from your results. Always clamp: ACOS(LEAST(1, GREATEST(-1, ...))).

Degrees vs radians. The most common porting error. RADIANS() on the stored columns and on the bound parameters — and be explicit about which the API accepts.

Index reality. A composite B-tree on (latitude, longitude) only helps the bounding-box filter if latitude is the leading column and your box is narrow. For real spatial querying, add a POINT column with a SPATIAL INDEX (MySQL) and use ST_Distance_Sphere. The bundle predates usable MySQL spatial support and doesn't do this.

Geocoding side effects. The bundle's address flow assumes you bring your own geocoder (Google/MapQuest-era). Rate limits and ToS are on you. Cache aggressively; geocode failures should leave latitude/longitude null, not 0,0 — Null Island coordinates are the single most common bug in geo data and will silently appear in "nearest" results.

Extension points (for reading, not extending): the entity mappings are overridable via bundle config (Symfony's resolve_target_entities-style pattern), and the geocoder is injectable. Both are worth understanding as design patterns, but with 12 stars and no maintainers there's no ecosystem to extend into.

Verification checklist after porting: test the formula against a known pair (e.g. two coordinates with a published distance), confirm results are symmetric, confirm a point at distance d is included at d - ε and excluded at d + ε, and check the query plan (EXPLAIN) to prove the bounding box is actually being used.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource