utafitilabs/postgis-bundle
Utafitilabs PostGIS Bundle adds PostGIS spatial support to PHP/Laravel applications, helping you define geometry and geography columns, run spatial migrations, and build location-aware queries for mapping and proximity features with less boilerplate.
v0.1.0 is the first public release, so treat this as an evaluation-grade package rather than something to drop into a production migration path on day one.
Install and confirm what you actually got.
composer require utafiti-labs/post-gis-bundle:^0.1.0
Read the installed composer.json before anything else. The namespace UtafitiLabs\PostGISBundle and the Bundle suffix suggest a Symfony/Doctrine bundle heritage, while the release notes describe Doctrine-level features (DBAL types, DQL functions, schema listener, repository base). Establish whether you are consuming it as (a) plain Doctrine DBAL types on top of Laravel's bundled doctrine/dbal, or (b) a full Doctrine ORM integration via something like laravel-doctrine/orm. The day-to-day workflow is very different between those two.
Verify PostGIS is actually enabled on the database before debugging the package:
SELECT postgis_version();
Also confirm the connection's search_path includes the schema where PostGIS lives (public by default). A missing extension is the most common cause of "the type doesn't exist" errors that look like package bugs.
Register the config. The release names the config key utafiti_labs_post_gis. In Laravel you will need to publish/merge it under config/utafiti_labs_post_gis.php and check whether the package ships a service provider — if it does not, you will be wiring the DBAL types and listeners manually in a service provider of your own.
First use case: add a geometry(Point, 4326) column to an existing table, insert a point, and query within a radius. That single loop exercises the column type, the schema listener, and the spatial functions all at once. Do it on a throwaway table first — v0.1.0 migrations are the highest-risk surface.
Column types in migrations. The value here is having geometry, geography, and likely point/linestring-style types recognized by the schema layer instead of a raw DB::statement. Register the types once at boot, then use them in migrations so Schema::table() round-trips don't try to rewrite the column as a generic string. Prefer declaring SRID and geometry subtype explicitly; PostGIS will happily accept untyped geometry and you will pay for it later in index and cast problems.
Schema listener. The schema listener is the piece that makes introspection work — it tells the platform how to read existing PostGIS columns back out of the database. This matters most when you run doctrine:schema:validate-style diffing or any migration tooling that introspects before altering. If you only ever write forward migrations and never diff, you can get by without it, but you lose most of the safety net.
Spatial DQL functions. These let you express PostGIS predicates in your ORM query language rather than raw SQL — things like distance comparisons and containment tests. Two patterns worth adopting:
nearbyRestaurants($lat, $lng, $radiusMeters)) rather than sprinkling spatial function calls through controllers. SRID and units are easy to get wrong and you want one place to fix them.ST_DWithin (index-usable) rather than ST_Distance(...) < x in a WHERE clause. The latter forces a sequential scan on any meaningful table.Spatial repository base. Extending the provided base class buys you conventional spatial query helpers, but it couples your repositories to the package. If the base class is thin in v0.1.0, consider copying its useful methods into your own abstract repository — you get the same behaviour with no upgrade risk.
Integration tip: wrap spatial reads in a small value object or cast (Point, BoundingBox) at the boundary. Geometry data arriving as WKT/WKB strings leaking into Blade templates and API resources is the usual source of "why is my JSON full of hex" tickets.
"0.1.0", not ^0.1) and assume method signatures on the repository base and config keys may move.Bundle naming in a Laravel context is a smell worth investigating. If the package expects Symfony's bundle registration, DI container config, or YAML configuration, you will be writing an adapter. Budget for that in your estimate; don't assume composer require is the whole install.CREATE INDEX ... USING GIST. Add the GIST index in a separate migration and verify with EXPLAIN that your nearby-query actually uses it.utafiti_labs_post_gis is verbose and snake-cased — unusual for Laravel (config('postgis.*') would be idiomatic). Verify the key matches the installed release; note it may be the Symfony parameter naming carried over.SELECT postgis_version(), (2) does the column exist with the right type/SRID via \d+ table, (3) are the DBAL types registered before the connection is first used, (4) is the schema listener attached. Roughly 90% of failures are step 1 or 3.How can I help you explore Laravel packages today?