Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a9aabf3
feat(#305): add support for PostGIS's `GEOGRAPHY` and `GEOMETRY`
martin-georgiev Aug 19, 2025
3801e55
excpetions skeleton
martin-georgiev Aug 19, 2025
9fa3471
add geometry vo
martin-georgiev Aug 19, 2025
1b9d623
add Geometry and Geography types
martin-georgiev Aug 19, 2025
d0fb182
add tests and minor names cleanup
martin-georgiev Aug 19, 2025
90f6509
test setup improvements
martin-georgiev Aug 19, 2025
2b6a808
Merge branch 'main' into postgis
martin-georgiev Aug 19, 2025
b1eeaf4
dimensional modifier preservation
martin-georgiev Aug 19, 2025
8787b19
devenv AI improvement
martin-georgiev Aug 19, 2025
94b9b46
Merge branch 'postgis' of https://github.com/martin-georgiev/postgres…
martin-georgiev Aug 19, 2025
1679b8b
add support for DBAL types of arrays of Geometry and Geography
martin-georgiev Aug 20, 2025
76d0b6d
extract dimensional modifier enum
martin-georgiev Aug 20, 2025
8f6d4a8
cleanup
martin-georgiev Aug 20, 2025
2f8b760
add multi item support
martin-georgiev Aug 21, 2025
3717176
tests -> cleanup -> tests :)
martin-georgiev Aug 21, 2025
caab1d8
fixes
martin-georgiev Aug 21, 2025
9ee1f11
complete set of test scenarios (but some cleanup expected):)
martin-georgiev Aug 21, 2025
63e1350
final touches
martin-georgiev Aug 21, 2025
e69e412
increase test coverage
martin-georgiev Aug 21, 2025
10fcc61
no message
martin-georgiev Aug 22, 2025
c1d7a3d
docs
martin-georgiev Aug 23, 2025
f8e91a9
docs
martin-georgiev Aug 23, 2025
ef344b1
Merge branch 'postgis' of https://github.com/martin-georgiev/postgres…
martin-georgiev Aug 23, 2025
3c87171
no message
martin-georgiev Aug 24, 2025
a442120
AI docs
martin-georgiev Aug 24, 2025
d1b5e36
no message
martin-georgiev Aug 24, 2025
d873c4b
Merge branch 'main' into postgis
martin-georgiev Aug 25, 2025
382c20a
no message
martin-georgiev Aug 25, 2025
687cb6a
Merge branch 'main' into postgis
martin-georgiev Aug 25, 2025
002cbd3
Update docs/GEOMETRY-ARRAYS.md
martin-georgiev Aug 25, 2025
20e8abe
no message
martin-georgiev Aug 25, 2025
94dc439
Merge branch 'main' into postgis
martin-georgiev Aug 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,18 @@ jobs:
needs: should-run
if: needs.should-run.outputs.run == 'true'
runs-on: ubuntu-latest
name: "PostgreSQL ${{ matrix.postgres }} + PHP ${{ matrix.php }}"
name: "PostgreSQL ${{ matrix.postgres }} + PostGIS ${{ matrix.postgis }} + PHP ${{ matrix.php }}"

strategy:
fail-fast: false
matrix:
php: ['8.1', '8.2', '8.3', '8.4']
postgres: ['16', '17']
postgis: ['3.4', '3.5']

services:
postgres:
image: postgres:${{ matrix.postgres }}
image: postgis/postgis:${{ matrix.postgres }}-${{ matrix.postgis }}
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
Expand Down Expand Up @@ -106,6 +107,9 @@ jobs:
echo "\nListing available PostgreSQL extensions:"
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT * FROM pg_available_extensions;"

echo "\nVerifying PostGIS installation:"
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"

Comment on lines +115 to +117
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Create the extension before querying PostGIS_Version()

On some images/databases, PostGIS is installed but not enabled in the target DB. Explicitly creating the extension avoids flakiness.

Apply this tweak to the verification step:

-echo "\nVerifying PostGIS installation:"
-PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"
+echo "Enabling PostGIS extension (idempotent):"
+PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "CREATE EXTENSION IF NOT EXISTS postgis;"
+
+echo "\nVerifying PostGIS installation:"
+PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"
+# Optionally check a canonical function/view to ensure the schema is present
+PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT COUNT(*) FROM pg_proc WHERE proname = 'st_astext';"

Minor: the earlier echo lines use "\n", which many shells won’t interpret without -e. Consider printf for consistent newlines.


🏁 Script executed:

#!/usr/bin/env bash
set -e

# Show context around the PostGIS version check
grep -R -n -C3 "PostGIS_Version" .github/workflows/integration-tests.yml || echo "No PostGIS_Version found"

# Check whether the workflow already creates the PostGIS extension
grep -R -n -C3 "CREATE EXTENSION" .github/workflows/integration-tests.yml || echo "No CREATE EXTENSION found"

Length of output: 631


Enable PostGIS extension before querying its version

The workflow currently lists available extensions but never creates/enables PostGIS in the test database, which can lead to flakiness on images where PostGIS isn’t auto-enabled.

• File: .github/workflows/integration-tests.yml
• Around lines 108–112

Apply this diff:

   - name: Verify available PostGIS extensions
     run: |
       echo "Available extensions:"
       PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT * FROM pg_available_extensions;"
+      echo "Enabling PostGIS extension (idempotent):"
+      PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "CREATE EXTENSION IF NOT EXISTS postgis;"
  
   - name: Verify PostGIS installation
     run: |
-      echo "\nVerifying PostGIS installation:"
-      PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"
+      # Use printf or echo -e for consistent newlines
+      printf "\nVerifying PostGIS installation:\n"
+      PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"
+      # Optional sanity check for a PostGIS function
+      PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT COUNT(*) FROM pg_proc WHERE proname='st_astext';"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo "\nVerifying PostGIS installation:"
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"
- name: Verify available PostGIS extensions
run: |
echo "Available extensions:"
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT * FROM pg_available_extensions;"
echo "Enabling PostGIS extension (idempotent):"
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "CREATE EXTENSION IF NOT EXISTS postgis;"
- name: Verify PostGIS installation
run: |
# Use printf or echo -e for consistent newlines
printf "\nVerifying PostGIS installation:\n"
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT PostGIS_Version();"
# Optional sanity check for a PostGIS function
PGPASSWORD=postgres psql -h localhost -U postgres -d postgres_doctrine_test -c "SELECT COUNT(*) FROM pg_proc WHERE proname='st_astext';"
🤖 Prompt for AI Agents
In .github/workflows/integration-tests.yml around lines 110 to 112, the job
queries PostGIS version but never ensures the extension is enabled; before
running the version check, run a psql command to create/enable the postgis
extension in the test database (e.g., execute "CREATE EXTENSION IF NOT EXISTS
postgis;" against postgres_doctrine_test using the same PGPASSWORD/psql
invocation) so the version query won't fail on images where PostGIS isn't
auto-enabled.

- name: Run integration test suite
run: composer run-integration-tests
env:
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ This package provides comprehensive Doctrine support for PostgreSQL features:
- MAC addresses (`macaddr`, `macaddr[]`)
- **Geometric Types**
- Point (`point`, `point[]`)
- PostGIS Geometry (`geometry`)
- PostGIS Geography (`geography`)
- **Range Types**
- Date and time ranges (`daterange`, `tsrange`, `tstzrange`)
- Numeric ranges (`numrange`, `int4range`, `int8range`)
Expand Down Expand Up @@ -122,10 +124,10 @@ composer run-unit-tests
```

### PostgreSQL Integration Tests
We also provide integration tests that run against a real PostgreSQL database to ensure compatibility:
We also provide integration tests that run against a real PostgreSQL database with PostGIS to ensure compatibility:

```bash
# Start PostgreSQL using Docker Compose
# Start PostgreSQL with PostGIS using Docker Compose
docker-compose up -d

# Run integration tests
Expand All @@ -135,7 +137,7 @@ composer run-integration-tests
docker-compose down -v
```

See [tests-integration/README.md](tests-integration/README.md) for more details.
See [tests/Integration/README.md](tests/Integration/README.md) for more details.

## ⭐ Support the Project

Expand Down
27 changes: 25 additions & 2 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,37 @@ in
services.postgres = {
enable = true;

# Use PostgreSQL 17 to match Docker Compose and CI
package = pkgs.postgresql_17;

listen_addresses = "127.0.0.1";
port = config.env.POSTGRES_PORT;

initialDatabases = [ { name = config.env.POSTGRES_DB; } ];

# Enable PostGIS extension
extensions = extensions: [
extensions.postgis
];

initialScript = ''
CREATE ROLE "${config.env.POSTGRES_USER}"
WITH SUPERUSER LOGIN PASSWORD '${config.env.POSTGRES_PASSWORD}';
-- Create role if it doesn't exist, or update password if it does
DO $$
BEGIN
IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '${config.env.POSTGRES_USER}') THEN
CREATE ROLE "${config.env.POSTGRES_USER}" WITH SUPERUSER LOGIN PASSWORD '${config.env.POSTGRES_PASSWORD}';
ELSE
ALTER ROLE "${config.env.POSTGRES_USER}" WITH SUPERUSER LOGIN PASSWORD '${config.env.POSTGRES_PASSWORD}';
END IF;
END
$$;

-- Set database owner
ALTER DATABASE "${config.env.POSTGRES_DB}" OWNER TO "${config.env.POSTGRES_USER}";

-- Enable PostGIS extension in the database
\c ${config.env.POSTGRES_DB}
CREATE EXTENSION IF NOT EXISTS postgis;
'';
};

Expand Down
3 changes: 2 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
services:
postgres:
image: postgres:${POSTGRES_VERSION:-17}
image: postgis/postgis:${POSTGRES_VERSION:-17}-3.4
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
POSTGRES_DB: ${POSTGRES_DB:-postgres_doctrine_test}
TZ: UTC
ports:
- "${POSTGRES_PORT:-5432}:5432"
volumes:
Expand Down
20 changes: 14 additions & 6 deletions docs/AVAILABLE-TYPES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,28 @@
| bigint[] | _int8 | `MartinGeorgiev\Doctrine\DBAL\Types\BigIntArray` |
| real[] | _float4 | `MartinGeorgiev\Doctrine\DBAL\Types\RealArray` |
| double precision[] | _float8 | `MartinGeorgiev\Doctrine\DBAL\Types\DoublePrecisionArray` |
| text[] | _text | `MartinGeorgiev\Doctrine\DBAL\Types\TextArray` |
| jsonb[] | _jsonb | `MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray` |
|---|---|---|
| jsonb | jsonb | `MartinGeorgiev\Doctrine\DBAL\Types\Jsonb` |
| inet | inet | `MartinGeorgiev\Doctrine\DBAL\Types\Inet` |
| inet[] | _inet | `MartinGeorgiev\Doctrine\DBAL\Types\InetArray` |
| jsonb[] | _jsonb | `MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray` |
| text[] | _text | `MartinGeorgiev\Doctrine\DBAL\Types\TextArray` |
|---|---|---|
| cidr | cidr | `MartinGeorgiev\Doctrine\DBAL\Types\Cidr` |
| cidr[] | _cidr | `MartinGeorgiev\Doctrine\DBAL\Types\CidrArray` |
| inet | inet | `MartinGeorgiev\Doctrine\DBAL\Types\Inet` |
| inet[] | _inet | `MartinGeorgiev\Doctrine\DBAL\Types\InetArray` |
| macaddr | macaddr | `MartinGeorgiev\Doctrine\DBAL\Types\Macaddr` |
| macaddr[] | _macaddr | `MartinGeorgiev\Doctrine\DBAL\Types\MacaddrArray` |
| point | point | `MartinGeorgiev\Doctrine\DBAL\Types\Point` |
| point[] | _point | `MartinGeorgiev\Doctrine\DBAL\Types\PointArray` |
|---|---|---|
| daterange | daterange | `MartinGeorgiev\Doctrine\DBAL\Types\DateRange` |
| int4range | int4range | `MartinGeorgiev\Doctrine\DBAL\Types\Int4Range` |
| int8range | int8range | `MartinGeorgiev\Doctrine\DBAL\Types\Int8Range` |
| numrange | numrange | `MartinGeorgiev\Doctrine\DBAL\Types\NumRange` |
| tsrange | tsrange | `MartinGeorgiev\Doctrine\DBAL\Types\TsRange` |
| tstzrange | tstzrange | `MartinGeorgiev\Doctrine\DBAL\Types\TstzRange` |
|---|---|---|
| geography | geography | `MartinGeorgiev\Doctrine\DBAL\Types\Geography` |
| geography[] | _geography | `MartinGeorgiev\Doctrine\DBAL\Types\GeographyArray` |
| geometry | geometry | `MartinGeorgiev\Doctrine\DBAL\Types\Geometry` |
| geometry[] | _geometry | `MartinGeorgiev\Doctrine\DBAL\Types\GeometryArray` |
| point | point | `MartinGeorgiev\Doctrine\DBAL\Types\Point` |
| point[] | _point | `MartinGeorgiev\Doctrine\DBAL\Types\PointArray` |
2 changes: 1 addition & 1 deletion docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ The provided environment includes:

- PHP 8.1, which is the oldest PHP version supported by this project.
- Composer
- PostgreSQL 17, started by `devenv up`.
- PostgreSQL 17 with PostGIS 3.4, started by `devenv up`.
- Pre-commit hooks (PHP-CS-Fixer, PHPStan, Rector, deptrac, ...).

### Local development
Expand Down
29 changes: 29 additions & 0 deletions docs/USE-CASES-AND-EXAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,32 @@ SELECT p FROM Product p WHERE CONTAINS(p.availabilityPeriod, DATERANGE('2024-06-
-- Find products with prices in a specific range
SELECT p FROM Product p WHERE p.priceRange @> 25.0
```


Using PostGIS Types
---

The library provides DBAL type support for PostGIS `geometry` and `geography` columns. Example usage:

```sql
CREATE TABLE places (
id SERIAL PRIMARY KEY,
location GEOMETRY,
boundary GEOGRAPHY
);
```

```php
use Doctrine\DBAL\Types\Type;
use MartinGeorgiev\Doctrine\DBAL\Types\ValueObject\Geometry as GeometryValueObject;

Type::addType('geography', MartinGeorgiev\Doctrine\DBAL\Types\Geography::class);
Type::addType('geometry', MartinGeorgiev\Doctrine\DBAL\Types\Geometry::class);

$location = GeometryValueObject::fromWKT('SRID=4326;POINT(-122.4194 37.7749)');
$entity->setLocation($location);
```

Notes:
- Values round-trip as EWKT/WKT strings at the database boundary.
- Integration tests automatically enable the `postgis` extension; ensure PostGIS is available in your environment.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;

use Doctrine\DBAL\Types\ConversionException;

/**
* @since 3.5
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*/
final class InvalidGeographyForDatabaseException extends ConversionException
{
private static function create(string $message, mixed $value): self
{
return new self(\sprintf($message, \var_export($value, true)));
}

public static function forInvalidType(mixed $value): self
{
return self::create('Database value must be a string, %s given', $value);
}

public static function forInvalidFormat(mixed $value): self
{
return self::create('Invalid geography format in database: %s', $value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;

use Doctrine\DBAL\Types\ConversionException;

/**
* @since 3.5
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*/
final class InvalidGeographyForPHPException extends ConversionException
{
private static function create(string $message, mixed $value): self
{
return new self(\sprintf($message, \var_export($value, true)));
}

public static function forInvalidType(mixed $value): self
{
return self::create('Value must be a Geography value object, %s given', $value);
}

public static function forInvalidFormat(mixed $value): self
{
return self::create('Invalid Geography value object format: %s', $value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;

use Doctrine\DBAL\Types\ConversionException;

/**
* @since 3.5
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*/
final class InvalidGeometryForDatabaseException extends ConversionException
{
private static function create(string $message, mixed $value): self
{
return new self(\sprintf($message, \var_export($value, true)));
}

public static function forInvalidType(mixed $value): self
{
return self::create('Database value must be a string, %s given', $value);
}

public static function forInvalidFormat(mixed $value): self
{
return self::create('Invalid geometry format in database: %s', $value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace MartinGeorgiev\Doctrine\DBAL\Types\Exceptions;

use Doctrine\DBAL\Types\ConversionException;

/**
* @since 3.5
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*/
final class InvalidGeometryForPHPException extends ConversionException
{
private static function create(string $message, mixed $value): self
{
return new self(\sprintf($message, \var_export($value, true)));
}

public static function forInvalidType(mixed $value): self
{
return self::create('Value must be a Geometry value object, %s given', $value);
}

public static function forInvalidFormat(mixed $value): self
{
return self::create('Invalid Geometry value object format: %s', $value);
}
}
Comment on lines +14 to +30
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Sanity-check usage paths for this exception in Geometry DBAL type

To avoid dead code, verify that convertToDatabaseValue/convertToPHPValue in Geometry type actually throw these factories on invalid PHP input or malformed value-object state.

Run this to confirm call sites exist:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Searching for InvalidGeometryForPHPException usage…"
rg -nP '\bInvalidGeometryForPHPException::forInvalid(?:Type|Format)\(' -C2

echo
echo "Looking for Geometry DBAL type and potential throw sites…"
rg -nP '(?s)class\s+Geometry\b.*?(convertTo(Database|PHP)Value)\s*\(' -C3 --type=php || true

Length of output: 846


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Inspecting the start of Geometry.php for class declaration..."
sed -n '1,200p' src/MartinGeorgiev/Doctrine/DBAL/Types/Geometry.php || true

echo
echo "Searching for convertToDatabaseValue definitions and usage…"
rg -nP 'function\s+convertToDatabaseValue' -C5 src/MartinGeorgiev/Doctrine/DBAL/Types/Geometry.php || true

echo
echo "Searching for convertToPHPValue definitions and usage…"
rg -nP 'function\s+convertToPHPValue' -C5 src/MartinGeorgiev/Doctrine/DBAL/Types/Geometry.php || true

echo
echo "Searching for forInvalidFormat calls in Geometry.php…"
rg -nP 'InvalidGeometryForPHPException::forInvalidFormat' -C3 src/MartinGeorgiev/Doctrine/DBAL/Types/Geometry.php || true

Length of output: 3035


Remove unused forInvalidFormat() factory in InvalidGeometryForPHPException

The forInvalidFormat() method is never thrown by Geometry::convertToDatabaseValue() (and convertToPHPValue() uses the database exception), making it dead code. Please choose one of the following:

  • Remove the unused public static function forInvalidFormat(string $message, mixed $value): self from
    src/MartinGeorgiev/Doctrine/DBAL/Types/Exceptions/InvalidGeometryForPHPException.php
  • Or, if you need to guard against malformed WktSpatialData state, add a check in
    convertToDatabaseValue() to throw this factory before casting to string.
🤖 Prompt for AI Agents
In
src/MartinGeorgiev/Doctrine/DBAL/Types/Exceptions/InvalidGeometryForPHPException.php
around lines 14-30, the public static function forInvalidFormat(...) is dead
code (never thrown); remove the entire forInvalidFormat method declaration from
this file to eliminate the unused factory method (or alternatively, if you
prefer to keep it, add a validation in Geometry::convertToDatabaseValue() to
detect malformed WktSpatialData and throw
InvalidGeometryForPHPException::forInvalidFormat() before casting to string).

54 changes: 54 additions & 0 deletions src/MartinGeorgiev/Doctrine/DBAL/Types/Geography.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace MartinGeorgiev\Doctrine\DBAL\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidGeographyForDatabaseException;
use MartinGeorgiev\Doctrine\DBAL\Types\Exceptions\InvalidGeographyForPHPException;
use MartinGeorgiev\Doctrine\DBAL\Types\ValueObject\Exceptions\InvalidWktSpatialDataException;
use MartinGeorgiev\Doctrine\DBAL\Types\ValueObject\WktSpatialData;

/**
* Implementation of PostGIS GEOGRAPHY data type.
*
* @see https://postgis.net/docs/using_postgis_dbmanagement.html
* @since 3.5
*
* @author Martin Georgiev <martin.georgiev@gmail.com>
*/
final class Geography extends BaseType
{
protected const TYPE_NAME = 'geography';

public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value === null) {
return null;
}

if (!$value instanceof WktSpatialData) {
throw InvalidGeographyForPHPException::forInvalidType($value);
}

return (string) $value;
}

public function convertToPHPValue($value, AbstractPlatform $platform): ?WktSpatialData
{
if ($value === null) {
return null;
}

if (!\is_string($value)) {
throw InvalidGeographyForDatabaseException::forInvalidType($value);
}

try {
return WktSpatialData::fromWkt($value);
} catch (InvalidWktSpatialDataException) {
throw InvalidGeographyForDatabaseException::forInvalidFormat($value);
}
}
}
Loading
Loading