Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Wkt Parser Laravel Package

creof/wkt-parser

A PHP library for parsing Well-Known Text (WKT) geometry strings into usable geometry objects. Supports points, linestrings, polygons, and more, making it easy to work with spatial data in Laravel and other PHP apps without heavy GIS dependencies.

Deep Wiki
Context7

Getting Started

The parser is a standalone, framework-agnostic library — there is no Laravel service provider, facade, config file, or auto-discovery. Wire it up yourself.

Install it:

composer require creof/wkt-parser

Look first at CrEOF\Geo\WKT\Parser (v2.x). That's the entry point; ignore anything under CrEOF\WKT\Parser\ unless you're on an old 1.x install — v1 returned typed geometry objects, v2 returns plain arrays. The array shape is documented only by example, so read Parser::parse() for the return contract.

Minimal use case — accept a WKT string from a form/API and hand it to your DB:

use CrEOF\Geo\WKT\Parser;

$parsed = (new Parser('POINT(-122.68 45.52)'))->parse();
// [
//   'type'  => 'Point',
//   'value' => ['x' => -122.68, 'y' => 45.52],
//   'srid'  => null,
// ]

DB::statement(
    'INSERT INTO places (location) VALUES (ST_GeomFromText(?, ?))',
    ['POINT(-122.68 45.52)', 4326]
);

Your first meaningful use case is almost always "convert incoming WKT into something Laravel can validate, store, or serialize" — not "parse WKT in a controller." Build a small service around the parser immediately (see next section) so you don't scatter new Parser(...) calls.

Implementation Patterns

Wrap the parser in a bound service. This makes it mockable, gives you one place to normalize errors, and lets you swap libraries later without touching call sites.

namespace App\Services;

use CrEOF\Geo\WKT\Parser;
use CrEOF\Geo\WKT\Exception\UnexpectedTokenException;

class WktService
{
    public function parse(string $wkt): array
    {
        return (new Parser($wkt))->parse();
    }

    public function toGeoJson(string $wkt): array
    {
        $g = $this->parse($wkt);

        return match ($g['type']) {
            'Point'      => ['type' => 'Point', 'coordinates' => [$g['value']['x'], $g['value']['y']]],
            'LineString' => ['type' => 'LineString',
                'coordinates' => array_map(fn ($p) => [$p['x'], $p['y']], $g['value'])],
            'Polygon'    => ['type' => 'Polygon',
                'coordinates' => array_map(
                    fn ($ring) => array_map(fn ($p) => [$p['x'], $p['y']], $ring),
                    $g['value']
                )],
            default => throw new \InvalidArgumentException("Unsupported {$g['type']}"),
        };
    }
}

Bind it in a service provider: $this->app->singleton(WktService::class);

Validate with a custom rule. Never let the parser throw inside a controller — catch and convert to a validation message:

use Illuminate\Contracts\Validation\Rule;

class Wkt implements Rule
{
    public function passes($attribute, $value)
    {
        try { (new Parser($value))->parse(); return true; }
        catch (\Throwable) { return false; }
    }

    public function message() { return 'The :attribute must be a valid WKT/EWKT string.'; }
}

Eloquent cast for a geometry column. If your column is TEXT/GEOMETRY, a custom cast keeps models clean:

class WktCast implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return $value ? (new Parser($value))->parse() : null;
    }

    public function set($model, $key, $value, $attributes)
    {
        return is_string($value) ? $value : null; // accept WKT as-is
    }
}

API resource transformer. For a GeoJSON FeatureCollection endpoint, extend the service above and shape responses in JsonResource classes — do not return the raw parser array. {type, value, srid} is not what Leaflet, Mapbox GL, or Mapbox/Deck consumers expect.

Batch import pipeline. When ingesting a WKT file (CSV/GeoJSON-to-WKT dumps), parse in a queued job, chunk reads at ~500 rows, and push failures to a dead-letter table. The parser is fast per-string but is not a streaming parser; do not put it inside a loop over 100k rows on a web request.

Store SRID explicitly. If you receive EWKT (SRID=4326;POINT(...)), extract $parsed['srid'] and pass it as the second arg to ST_GeomFromText. Do not default silently — mixed SRIDs in one table will bite you later.

Gotchas and Tips

  • It's stale. Last release was May 2016. It won't run on PHP 8.x without patching (namespace/composer.json constraints bite first). Pin PHP or plan a migration to brick/geo, geo-io/wkt-parser, or phayes/geophp. If you're already on the modern stack, treat this package as a short-term bridge only.
  • Parse-only, no serialize. There is no toWkt(). You'll hand-build WKT strings or use a different library for the write path. Don't assume symmetry.
  • Array shapes vary by type. Point gives ['x'=>…, 'y'=>…], LineString gives a list of those, Polygon gives a list of rings (lists of points), GeometryCollection nests one more level. There is no unifying interface — build your normalizers defensively with match or switch on type, and reject unknown types rather than passing them through.
  • Coordinate order is lng lat (x y), not lat/lng. WKT follows Cartesian order; GeoJSON does too, so the pass-through is fine — but don't hand a Point's x/y to a LatLng constructor expecting lat, lng. This is the single most common production bug with WKT.
  • Case sensitivity. WKT keywords are canonical uppercase (POINT, LINESTRING, SRID=4326;). Some downstream systems emit lowercase; the parser is not reliably tolerant. strtoupper() the type token in your service before parsing if you accept user input.
  • Exceptions are narrow. You'll typically see CrEOF\Geo\WKT\Exception\UnexpectedTokenException (syntax) but also bare \Exception from the lexer on malformed input. Catch \Throwable at the boundary, then narrow. Never let one escape to a 500.
  • EMPTY geometries (POINT EMPTY, POLYGON EMPTY) are inconsistently handled. Reject them at the validation layer unless your DB/SRID pipeline explicitly supports empty geometries — PostGIS does, MySQL is pickier.
  • Z/M dimensions. POINT Z (1 2 3) support is partial at best in this version. If you need 3D, verify against your version with a test fixture before relying on it; assume 2D otherwise.
  • Whitespace and commas. The lexer is more tolerant of extra whitespace than of missing commas (LINESTRING(1 2,3 4) is fine; LINESTRING(1 2 3 4) is not). Trim and canonicalize on ingest.
  • Float precision. Coordinates come back as PHP floats. If you round-trip WKT through JSON or float arithmetic, expect sub-millimeter drift on projected coordinates. For anything precision-sensitive, store the original WKT string alongside the parsed value.
  • MySQL vs PostGIS integration. MySQL wants ST_GeomFromText(wkt, srid), PostGIS wants ST_GeomFromEWKT(wkt) for EWKT or ST_GeomFromText(wkt, srid) for WKT. Pick the function based on whether srid is null in the parsed result, or normalize to EWKT first.
  • Testing. Add fixtures for each geometry type plus three failure cases ("POINT()", "SRID=abc;POINT(1 2)", "POINT(1)"). The parser's error messages are not stable across versions, so assert on exception class or null, not message text.
  • Extension points worth building yourself: a WktService::toGeoJson() (as above), a Wkt validation rule, a WktCast, and a thin GeoJsonResource. Everything else in the package is closed — there are no pluggable visitors or handlers to hook into, so your wrapper is the extension point.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource