utafitilabs / postgis-bundle
PostGIS spatial types, automatic GiST indexing, and ST_* DQL functions for Doctrine ORM 3 / DBAL 4 on Symfony.
Package info
github.com/utafitilabs/postgis-bundle
Type:symfony-bundle
pkg:composer/utafitilabs/postgis-bundle
Requires
- php: >=8.4
- doctrine/dbal: ^4.0
- doctrine/doctrine-bundle: ^3.0
- doctrine/orm: ^3.5
- symfony/framework-bundle: ^7.3 || ^8.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.2
- phpunit/phpunit: ^13.2
- symfony/dependency-injection: ^7.3
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-19 19:18:08 UTC
README
This bundle gives Doctrine ORM 3 / DBAL 4 first-class PostGIS support: spatial column
types exchanged as GeoJSON, ST_* DQL functions, automatic GiST indexing, and
typed geometry columns with churn-free migrations — no hand-written spatial SQL,
no configuration. Enable the bundle and go.
Part of the utafiti tools.
Why
Doctrine ships no spatial types, and PostGIS stores every shape as the base geometry
type — so the usual approaches either hand-write DDL or fight migrations:diff churn.
This bundle handles all of it: declare a column, get a GiST-indexed, GeoJSON-friendly,
optionally shape-constrained column with clean diffs.
Install
Applications using Symfony Flex:
composer require utafitilabs/postgis-bundle
Applications without Symfony Flex — after requiring the package, enable the bundle:
// config/bundles.php return [ // ... UtafitiLabs\PostGISBundle\UtafitiLabsPostGISBundle::class => ['all' => true], ];
That one line registers the spatial types, the DB-type mappings, the ST_* DQL functions,
the USING gist platform middleware, the typmod-aware schema manager, and the auto-GiST
schema listener. Nothing else to configure.
The bundle's configuration root key is utafiti_labs_post_gis. It takes no options — it
is simply the key reserved in config/packages/, and the prefix of the bundle's internal
service ids.
A taste
use Doctrine\ORM\Mapping as ORM; class Area { // Generic geometry — accepts any shape, SRID 4326, diff-clean. #[ORM\Column(type: 'geometry')] public ?string $footprint = null; // GeoJSON string in, GeoJSON string out // Typed — PostGIS enforces the shape via the typmod, still diff-clean. #[ORM\Column(type: 'multipolygon')] public ?string $boundary = null; // geometry(MultiPolygon,4326) }
$em->createQuery( 'SELECT COUNT(a.id) FROM App\Entity\Area a WHERE ST_Intersects(a.boundary, ST_GeomFromGeoJSON(:poly)) = true' )->setParameter('poly', $geoJsonPolygon)->getSingleScalarResult();
Column types: geometry, geography, point, linestring, polygon, multipolygon.
DQL functions: ST_AsGeoJSON, ST_GeomFromGeoJSON, ST_Intersects, ST_DWithin, ST_Union,
ST_SimplifyPreserveTopology, ST_MakeValid, ST_CollectionExtract, ST_Multi,
ST_Area, and Geography(g) (the ::geography cast, for geodesic measurement:
ST_Area(Geography(t.geom)) = m²) — enough to express dissolve-style aggregation
entirely in DQL.
Prefer no DQL at all? Extend the repository base and the St methods just exist:
use UtafitiLabs\PostGISBundle\Repository\SpatialEntityRepository; final class AreaRepository extends SpatialEntityRepository {} // that's all $areas->findStIntersecting($geoJson); // GiST-backed ST_Intersects $areas->stAreaKm2(['source' => 'wdpa']); // geodesic km², findBy-style criteria
Every method carries the St marker — the bundle's signature, never confusable
with a Doctrine core method. The geometry column is discovered from the entity's
own metadata; an entity without one is rejected at construction with a teaching
message.
Every geometry/geography column gets a USING gist index in generated migrations, automatically.
Documentation
Read the documentation at docs/index.md — including
generic vs. typed geometry columns and how typed columns
stay migrations:diff-clean.
Requirements
- PHP 8.4+ · Symfony 7.3+ / 8
doctrine/dbal^4,doctrine/orm^3.5,doctrine/doctrine-bundle^3- PostgreSQL with the PostGIS extension
Contributing
See CONTRIBUTING.md. CI enforces the standard (php-cs-fixer, PHPStan max, PHPUnit against real PostGIS, lowest→newest dependency matrix) on every pull request.
Credits
License
MIT License (MIT): see the LICENSE file for more details.