Geometry and Geography Arrays

This document explains the usage of PostgreSQL geometry and geography array types in Doctrine DBAL.

📖 See also: PostGIS Spatial Functions and Operators for spatial functions that work with geometry and geography data

Overview

The GeometryArray and GeographyArray types provide support for PostgreSQL’s GEOMETRY[] and GEOGRAPHY[] array types, allowing you to store collections of spatial data in a single database column.

Registration and Type Mapping

use Doctrine\DBAL\Types\Type as DoctrineType;

DoctrineType::addType('geometry', \MartinGeorgiev\Doctrine\DBAL\Types\Geometry::class);
DoctrineType::addType('geometry[]', \MartinGeorgiev\Doctrine\DBAL\Types\GeometryArray::class);
DoctrineType::addType('geography', \MartinGeorgiev\Doctrine\DBAL\Types\Geography::class);
DoctrineType::addType('geography[]', \MartinGeorgiev\Doctrine\DBAL\Types\GeographyArray::class);

$platform = $connection->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('geometry', 'geometry');
$platform->registerDoctrineTypeMapping('_geometry', 'geometry[]');
$platform->registerDoctrineTypeMapping('geography', 'geography');
$platform->registerDoctrineTypeMapping('_geography', 'geography[]');

Basic Usage

Entity Definition

use MartinGeorgiev\Doctrine\DBAL\Types\ValueObject\WktSpatialData;
use Doctrine\ORM\Mapping as ORM;

class Location
{
    /**
     * @var WktSpatialData[]
     * @ORM\Column(type="geometry[]")
     */
    private array $geometries;

    /**
     * @var WktSpatialData[]
     * @ORM\Column(type="geography[]")
     */
    private array $geographies;

    public function setGeometries(WktSpatialData ...$geometries): void
    {
        $this->geometries = $geometries;
    }
}

Parameter Binding with DBAL

use MartinGeorgiev\Doctrine\DBAL\Types\ValueObject\WktSpatialData;

// Single-item geometry[] array
$qb = $connection->createQueryBuilder();
$qb->insert('locations')->values(['geometries' => ':wktSpatialData']);
$qb->setParameter('wktSpatialData', [WktSpatialData::fromString('POINT(0 0)')], 'geometry[]');
$qb->executeStatement();

// Single geography value
$qb = $connection->createQueryBuilder();
$qb->insert('places')->values(['locations' => ':wktSpatialData']);
$qb->setParameter('wktSpatialData', WktSpatialData::fromString('SRID=4326;POINT(-122.4194 37.7749)'), 'geography');
$qb->executeStatement();

Working Examples

// Single-item arrays
$singleGeometry = [WktSpatialData::fromString('POINT(0 0)')];
$singleGeography = [WktSpatialData::fromString('SRID=4326;POINT(-122.4194 37.7749)')];

// Complex single geometries
$complexGeometry = [WktSpatialData::fromString('POLYGON((0 0,0 1,1 1,1 0,0 0))')];
$geometryWithSrid = [WktSpatialData::fromString('SRID=4326;LINESTRING(-122 37,-121 38)')];

Multi-Item Arrays

Multi-item geometry[] and geography[] arrays bind through Doctrine DBAL like any other array type:

$entity->setGeometries([
    WktSpatialData::fromString('POINT(1 2)'),
    WktSpatialData::fromString('LINESTRING(0 0,1 1)'),
]);

A null element is written as a SQL NULL element and read back as null.

Normalization Rules (Dimensional Modifiers)

The library normalizes dimensional modifiers based on enums for geometry types and modifiers.

Examples:

POINTZ(1 2 3)               => POINT Z(1 2 3)
LINESTRINGM(0 0 1, 1 1 2)   => LINESTRING M(0 0 1, 1 1 2)
POLYGONZM((...))            => POLYGON ZM((...))
POINT Z (1 2 3)             => POINT Z(1 2 3)
SRID=4326;POINT Z (1 2 3)   => SRID=4326;POINT Z(1 2 3)

See also: Spatial foundations and parser behavior in the Spatial Types document.

Supported Features

Geometry Types

  • ✅ POINT, LINESTRING, POLYGON
  • ✅ MULTIPOINT, MULTILINESTRING, MULTIPOLYGON
  • ✅ GEOMETRYCOLLECTION
  • ✅ All other PostGIS geometry types as of v3.5

Coordinate Systems

  • ✅ SRID support: SRID=4326;POINT(-122 37)
  • ✅ Dimensional modifiers: Z (elevation), M (measure), ZM
  • ✅ Mixed coordinates: Arrays with different SRIDs/dimensions

Geography Features

  • ✅ Auto-SRID: Geography types automatically get SRID=4326 if none is provided
  • ✅ World coordinates: Null Island, poles, date line
  • ✅ Geographic calculations: Proper spherical geometry

Performance Considerations

  • Indexing: GiST/operator classes only support spatial types like geometry/geography and cannot directly index SQL array types like geometry[]. For proper spatial indexing, consider:
    • Normalizing arrays into separate geometry rows with individual GiST indexes
    • Materializing a single geometry (e.g., union or bounding geometry) into a geometry column for GiST indexing
    • See the PostGIS FAQ on spatial indexes for details
  • Query optimization: Use appropriate spatial operators and indexes on individual geometry columns, not arrays