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

Geo Laravel Package

lootils/geo

Lootils Geo provides convenient geographic data helpers for Laravel and PHP applications, making it easy to work with countries, regions, and related location data. Lightweight, simple to integrate, and useful for building location-aware features.

View on GitHub
Deep Wiki
Context7

Getting Started

lootils/geo is a small, framework-agnostic PHP value-object library for geodetic math — coordinates, distances, bearings, and related equations. It does not ship a Laravel service provider, config file, or database layer, so integration is entirely up to you. That is the point: it gives you correct math, you give it a home in your app.

Minimal setup:

composer require lootils/geo

First, open vendor/lootils/geo/src/ and the README before writing code. Confirm three things immediately:

  1. Coordinate order — does the constructor take (latitude, longitude) or (longitude, latitude)?
  2. Units — are distances returned in meters, kilometers, or a Distance object? Are angles in degrees or radians?
  3. Class names/namespaces — verify the actual FQCNs; the examples below use conventional names, not guaranteed ones.

A first smoke test in php artisan tinker:

use Lootils\Geo\Coordinate; // verify FQCN in src/

$london = new Coordinate(51.5074, -0.1278);
$paris  = new Coordinate(48.8566, 2.3522);

$distance = $london->distanceTo($paris);
dump($distance); // inspect type and units before using it anywhere

Your first real use case: store a venue's latitude/longitude, then compute the distance from a user's position to sort "nearest" results.

// app/Services/GeoService.php
public function distanceKm(float $lat1, float $lng1, float $lat2, float $lng2): float
{
    return (new Coordinate($lat1, $lng1))
        ->distanceTo(new Coordinate($lat2, $lng2)); // adjust for units
}

Wrap it immediately. Do not sprinkle Coordinate construction through controllers.

Implementation Patterns

1. Adapter/service layer (do this first). Keep the package behind one class so the rest of the app speaks your vocabulary (LatLng, kilometers, floats) and you can swap implementations without a grep-and-replace across the codebase.

final class GeoService
{
    public function distanceKm(LatLng $a, LatLng $b): float
    {
        $d = (new Coordinate($a->lat, $a->lng))
            ->distanceTo(new Coordinate($b->lat, $b->lng));

        return $this->toKilometers($d); // encapsulate unit conversion here
    }
}

2. Bounding-box prefilter in SQL, exact math in PHP. The package computes distances in PHP; it will not build SQL for you. For "within N km" queries, compute a lat/lng bounding box, filter with indexed WHERE clauses, then run exact geodetic distance in PHP on the survivors.

$latDelta = $radiusKm / 111.0;
$lngDelta = $radiusKm / (111.0 * cos(deg2rad($lat)));

$candidates = Venue::query()
    ->whereBetween('latitude',  [$lat - $latDelta, $lat + $latDelta])
    ->whereBetween('longitude', [$lng - $lngDelta, $lng + $lngDelta])
    ->get();

$nearby = $candidates
    ->map(fn ($v) => [$v, app(GeoService::class)->distanceKm($origin, $v->latLng())])
    ->filter(fn ($row) => $row[1] <= $radiusKm)
    ->sortBy(fn ($row) => $row[1]);

For high-volume or production geo search, prefer a spatial index (PostGIS/MySQL POINT with SRID 4326) and use lootils/geo for the math you still need in PHP — bearing, midpoint, destination points, validation of coordinates.

3. Eloquent cast / accessor for coordinates. Expose a single LatLng value object rather than two loose floats.

protected function latLng(): Attribute
{
    return Attribute::make(
        get: fn () => new LatLng((float) $this->latitude, (float) $this->longitude),
    );
}

4. Validation. Validate ranges at the boundary — latitude -90..90, longitude -180..180 — in a FormRequest. The package is not a validator; malformed coordinates should never reach it.

5. Workflow integration. Good fits: delivery/ETA estimation, store locators, matching a driver to a pickup, sorting search results by proximity, geo-fencing checks, and route waypoint calculations. Poor fit: heavy GIS pipelines, polygon containment at scale, and tile/rendering work. For those, add PostGIS or a dedicated geo service alongside it.

6. Testing. Pin known coordinate pairs (London↔Paris ≈ 343 km) as regression tests in your adapter. Assert with a tolerance (assertEqualsWithDelta), never exact float equality.

Gotchas and Tips

  • Latitude/longitude order is the #1 bug. Silently swapped values produce plausible-looking but wrong distances. Add a constructor check or a named factory (LatLng::fromLatLng()) in your wrapper.
  • Units are easy to misread. Mixing degrees (API input) with radians (math functions) or meters with kilometers will yield results off by orders of magnitude. Convert once, at the adapter boundary, and document it.
  • Different equations, different answers. Haversine treats Earth as a sphere; Vincenty/ellipsoidal methods are more accurate over long distances. Don't chase sub-meter precision unless the package explicitly promises an ellipsoidal model — and check which method distanceTo() uses.
  • Floating-point equality. Never == coordinates or distances. Use tolerances.
  • Antimeridian and poles. Longitude wrapping near ±180° and latitude near ±90° break naive bounding boxes. If your users are worldwide, clamp or special-case these.
  • Database SRID. If you introduce spatial columns, use SRID 4326 and be consistent about axis order — MySQL POINT(lng, lat) versus your (lat, lng) convention is another swap trap.
  • No config, no provider, no facades. Register your adapter as a singleton in a service provider if you want it injected. There is nothing to publish.
  • Small package, low bus factor. 16 stars means limited maintenance and few eyes on edge cases. Pin the version in composer.json, keep the wrapper thin, and write your own tests around the behaviors you depend on.
  • Debugging. When a distance looks wrong, compare against an independent calculator (geopy, movable-type, PostGIS) with the same inputs. The discrepancy almost always traces to axis order, units, or radius assumption — not the equation.
  • Extension points. Prefer decorating your own GeoService over subclassing package classes. If you need polygon operations, geohashing, or spatial indexes, add a second library rather than forking this one.
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.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections