PHPackages                             juanparati/larageos - 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. juanparati/larageos

ActiveLibrary

juanparati/larageos
===================

A Laravel library that understands and speaks GeoSpatial data types.

0.7(today)02↑2900%MITPHPPHP ^8.2|^8.3|^8.4|^8.5CI passing

Since Aug 24Pushed todayCompare

[ Source](https://github.com/juanparati/larageos)[ Packagist](https://packagist.org/packages/juanparati/larageos)[ Docs](https://github.com/juanparati/larageos)[ RSS](/packages/juanparati-larageos/feed)WikiDiscussions master Synced today

READMEChangelog (1)Dependencies (3)Versions (2)Used By (0)

LaraGeos
========

[](#larageos)

[![Tests](https://github.com/juanparati/larageos/actions/workflows/tests.yml/badge.svg)](https://github.com/juanparati/larageos/actions/workflows/tests.yml/badge.svg)

A Laravel GeoSpatial library for your ORM. Store points and polygons in native spatial columns, query them with distance scopes, and exchange them as GeoJSON.

Based on [Laravel Spatial](https://github.com/tarfin-labs/laravel-spatial) by Tarfin Labs.

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

[](#requirements)

- PHP 8.2+
- Laravel 12+
- One of:
    - **MySQL 8.0+** (the library relies on the `axis-order` WKT option introduced in 8.0)
    - **MariaDB 11.4+** — you **must** use Laravel's `mariadb` driver, not `mysql`. Writes on the `mysql` driver generate MySQL-specific SQL (the three-argument `ST_GeomFromText` with `axis-order`) that MariaDB rejects.
    - **PostgreSQL with PostGIS**

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

[](#installation)

```
composer require juanparati/larageos
```

Optionally publish the config file:

```
php artisan vendor:publish --tag=larageos
```

```
// config/larageos.php
return [
    // SRID applied when a geometry is stored without an explicit SRID.
    'default_srid' => 4326,
];
```

Migrations
----------

[](#migrations)

Use Laravel's native `geography()` (or `geometry()`) column types:

```
Schema::create('addresses', function (Blueprint $table) {
    $table->id();
    $table->geography('location', subtype: 'point');          // SRID 4326 by default
    $table->geography('area', subtype: 'polygon')->nullable();
    $table->timestamps();
});
```

What that creates per database:

DriverColumn typeNotesMySQL`point SRID 4326`SRID-constrained geometryMariaDB`point ref_system_id=4326`Cartesian semanticsPostGIS`geography(point,4326)`True geography typeCasts
-----

[](#casts)

Cast columns to rich `Point` / `Polygon` value objects:

```
use Juanparati\LaraGeos\Casts\LocationCast;
use Juanparati\LaraGeos\Casts\RegionCast;
use Juanparati\LaraGeos\Traits\HasGeoSpatial;

class Address extends Model
{
    use HasGeoSpatial;  // Add HasGeoSpatial trait to the model

    protected $casts = [
        'location' => LocationCast::class,  // Point
        'area'     => RegionCast::class,    // Polygon
    ];
}
```

### Points

[](#points)

```
use Juanparati\LaraGeos\Types\Point;

$address = new Address();
$address->location = new Point(lat: 27.1234, lng: 39.1234); // SRID 4326 by default
$address->save();

$address->refresh();
$address->location->getLat();
$address->location->getLng();
$address->location->getSrid();
$address->location->toWkt();     // POINT(39.1234 27.1234)
```

Latitude must be within \[-90, 90\] and longitude within \[-180, 180\]; out-of-range values throw an `InvalidArgumentException`.

### Polygons

[](#polygons)

Polygons support interior rings (holes) and round-trip them faithfully:

```
use Juanparati\LaraGeos\Types\Polygon;

// A flat list of points is the exterior ring (auto-closed):
$area = new Polygon([
    new Point(lat: 0, lng: 0),
    new Point(lat: 0, lng: 4),
    new Point(lat: 4, lng: 4),
    new Point(lat: 4, lng: 0),
]);

// Or pass rings: [exterior, ...holes]
$area = new Polygon([
    [$p1, $p2, $p3, $p4],   // exterior ring
    [$h1, $h2, $h3],        // hole
]);

$area->getExteriorRing();   // Point[]
$area->getInteriorRings();  // Point[][]
$area->getRings();          // Point[][] (exterior first)
$area->toWkt();             // POLYGON((...),(...))
```

Every ring needs at least 3 unique points and is closed automatically.

Distance scopes
---------------

[](#distance-scopes)

Models using `HasGeoSpatial` get three query scopes:

```
$center = new Point(lat: 27.1234, lng: 39.1234);

// Add a `distance` column to the select:
Address::query()->selectDistanceTo('location', $center)->get();

// Only rows within the given distance (unit: see the table below!):
Address::query()->withinDistanceTo('location', $center, 10_000)->get();

// Order by proximity:
Address::query()->orderByDistanceTo('location', $center)->get();          // nearest first
Address::query()->orderByDistanceTo('location', $center, 'desc')->get();  // farthest first
```

### Distance units

[](#distance-units)

Distances — both the `distance` value returned by `selectDistanceTo` and the threshold passed to `withinDistanceTo` — are in **meters** on every driver:

DriverFunctionModelMySQL 8`ST_Distance` on geographic SRIDsgeodesic (ellipsoid)MariaDB`ST_Distance_Sphere`spherical (within ~0.5% of ellipsoid results)PostGIS`ST_Distance` on `geography` columnsgeodesic (ellipsoid)Caveats:

- **MariaDB**: `ST_Distance_Sphere` only accepts POINT geometries, so the distance scopes work on point columns only there (polygon columns throw a database error).
- **PostGIS `geometry` columns**: `ST_Distance` returns SRS units (degrees for 4326) instead of meters. Use `geography` columns for meters.

Unsupported drivers (e.g. SQLite) throw `Juanparati\LaraGeos\Exceptions\UnsupportedDriverException`.

Spatial predicate scopes
------------------------

[](#spatial-predicate-scopes)

Point-in-polygon and other topological filters:

```
$point = new Point(lat: 2, lng: 2);
$area  = Polygon::fromGeoJson([
    'type'        => 'Polygon',
    'coordinates' => [[[0, 0], [4, 0], [4, 4], [0, 4], [0, 0]]],
]);

// Rows whose polygon column contains the given point (or whole polygon):
Region::query()->whereContains('area', $point)->get();

// Rows whose column lies inside the given polygon:
Address::query()->whereWithin('location', $area)->get();

// Rows whose column intersects (shares any point with) the given geometry:
Region::query()->whereIntersects('area', $area)->get();
```

Functions used per driver:

ScopeMySQL / MariaDBPostGIS`whereContains``ST_Contains``ST_Covers``whereWithin``ST_Within``ST_CoveredBy``whereIntersects``ST_Intersects``ST_Intersects`Caveats:

- **Boundary points**: PostGIS `geography` columns do not support `ST_Contains`/`ST_Within`, so the scopes use `ST_Covers`/`ST_CoveredBy`there. The practical difference is only at the edges: a point exactly on a polygon's boundary counts as contained on PostGIS, but not on MySQL/MariaDB.
- **Edge semantics**: MySQL (geographic SRIDs) and PostGIS `geography` treat polygon edges as geodesics; MariaDB treats them as straight lines in coordinate space. Results near the edges of large polygons can differ between drivers.

GeoJSON
-------

[](#geojson)

Both types convert to and from RFC 7946 GeoJSON geometries (coordinates are `[lng, lat]`; GeoJSON is always WGS 84, so no SRID is emitted):

```
$point = Point::fromGeoJson('{"type":"Point","coordinates":[39.1234,27.1234]}');
$point->toGeoJson();   // ['type' => 'Point', 'coordinates' => [39.1234, 27.1234]]
json_encode($point);   // {"type":"Point","coordinates":[39.1234,27.1234]}

$polygon = Polygon::fromGeoJson([
    'type'        => 'Polygon',
    'coordinates' => [[[0, 0], [4, 0], [4, 4], [0, 0]]],
]);
json_encode($polygon); // {"type":"Polygon","coordinates":[[[0,0],[4,0],[4,4],[0,0]]]}
```

WKT factories are also available: `Point::fromWkt()` / `Polygon::fromWkt()`.

Model serialization
-------------------

[](#model-serialization)

`toArray()` / `toJson()` on a model serialize spatial attributes as:

```
// Point
['lat' => 27.1234, 'lng' => 39.1234, 'srid' => 4326]

// Polygon
['rings' => [[['lat' => ..., 'lng' => ...], ...], ...], 'srid' => 4326]
```

Testing
-------

[](#testing)

```
composer test
```

The CI matrix runs the suite on PHP 8.2–8.5 against MySQL 8.4, MariaDB 11.4, and PostGIS 16.

License
-------

[](#license)

MIT. See [LICENSE](LICENSE).

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance100

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

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

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/4caf72b4d969cfb8cdfbdc1d594c85b51c9316caf76b80aa0f9de7e3736cf59f?d=identicon)[juanparati](/maintainers/juanparati)

---

Tags

laravelspatialgeospatialjuanparatilarageos

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/juanparati-larageos/health.svg)

```
[![Health](https://phpackages.com/badges/juanparati-larageos/health.svg)](https://phpackages.com/packages/juanparati-larageos)
```

###  Alternatives

[laravel/ai

The official AI SDK for Laravel.

1.1k4.6M337](/packages/laravel-ai)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[ublabs/blade-simple-icons

A package to easily make use of Simple Icons in your Laravel Blade views.

1866.3k](/packages/ublabs-blade-simple-icons)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)

PHPackages © 2026

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