creof/geo-parser
Creof GeoParser is a PHP library that parses geographic coordinate strings and formats like WKT, GeoJSON, KML, and GPX into geometry objects via geoPHP, making it easy to import, convert, and work with spatial data in Laravel and PHP applications.
creof/geo-parser is a small, standalone PHP library that turns free-form coordinate strings (40.7128, -74.0060, 40°42'46"N 74°0'22"W) and WKT literals (POINT(-74.0060 40.7128)) into value objects from creof/geo. It is not Laravel-aware — there is no service provider, facade, config file, or validation rule shipped with it. Plan to wire it up yourself.
composer require creof/geo-parser
Look at these first:
Creof\GeoParser\GeoParser — the single entry point. parse($string) auto-detects the format and returns the parsed value object(s).Creof\GeoParser\Parse\ParseCoord and Parse\ParseWKT — the concrete strategies that do the work; look here when a string fails to parse and you need to know the accepted grammar.Creof\Geo\Value\Coordinate — the lat/lon value object you will almost always end up holding.First use case — parse a user-supplied "lat, lng" input in a controller:
use Creof\GeoParser\GeoParser;
$parser = new GeoParser();
$coordinate = $parser->parse($request->input('location')); // e.g. "40.7128, -74.0060"
$coordinate->getLatitude(); // 40.7128
$coordinate->getLongitude(); // -74.0060
Bind it as a singleton in AppServiceProvider so you are not instantiating it per call:
$this->app->singleton(\Creof\GeoParser\GeoParser::class, fn () => new \Creof\GeoParser\GeoParser());
Then app(GeoParser::class) or constructor injection works everywhere.
Validation rule for form input. The parser throws on garbage, which makes it a natural validation rule:
use Creof\GeoParser\GeoParser;
use Illuminate\Contracts\Validation\Rule;
class CoordinateString implements Rule
{
public function passes($attribute, $value): bool
{
try {
app(GeoParser::class)->parse((string) $value);
return true;
} catch (\Throwable $e) {
return false;
}
}
public function message(): string
{
return 'The :attribute must be a valid coordinate pair or WKT literal.';
}
}
Normalize on the way in via a form request. Parse once in prepareForValidation()/passedValidation() and store canonical numeric columns rather than the raw string, so downstream queries are simple:
protected function passedValidation(): void
{
$coord = app(GeoParser::class)->parse($this->input('location'));
$this->merge([
'latitude' => $coord->getLatitude(),
'longitude' => $coord->getLongitude(),
]);
}
Bulk imports (CSV/seeders). Reuse one GeoParser instance across the loop — the object is stateless and cheap to call. Collect failures instead of aborting the whole import:
$parser = app(GeoParser::class);
$errors = [];
foreach ($rows as $i => $row) {
try {
$coord = $parser->parse($row['coords']);
} catch (\Throwable $e) {
$errors[$i] = $e->getMessage();
continue;
}
// persist...
}
WKT for spatial columns. MySQL POINT/GEOMETRY columns and PostGIS accept WKT. Since the parser reads WKT but does not write it, treat it as input-side only: parse user WKT, pull the coordinate out, and let your own ST_GeomFromText/ST_MakePoint or creof/geo geometry objects do the output. Keep coordinate ordering explicit at the boundary (see Gotchas).
API resources. Serialize to a stable shape rather than exposing creof/geo objects directly — they are not JsonSerializable in a way tailored to your clients:
return [
'latitude' => (float) $coordinate->getLatitude(),
'longitude' => (float) $coordinate->getLongitude(),
];
Multi-format endpoint. Because parse() auto-detects, you can accept decimals, DMS, and WKT through one field and branch only when you need to know which format arrived — parse the WKT path separately if you need the geometry type (point vs. linestring).
lat, lng; WKT POINT(x y) is lng lat. Parse WKT into a Coordinate and always read via getLatitude()/getLongitude() rather than positional access, or you will silently swap axes on one code path.--ignore-platform-reqs, which hides genuine incompatibilities.\Throwable at the boundaries rather than memorizing specific exception classes — input that is almost a coordinate (extra text, a trailing comma, a range unit suffix) fails in slightly different ways depending on which parser strategy is tried first.parse("91, 0") may succeed syntactically. Add your own range check (-90..90, -180..180) if lat/lon correctness matters; the parser is not a geographic validator and definitely not a geocoder.toWKT() serializer here. For output, either build WKT yourself or use creof/geo geometry objects — check what the installed version exposes before assuming symmetry with the parser.ParseInterface/the Parse\* classes are the seam to watch: if you need a custom grammar (e.g. "lat/lng" with a slash separator or a plus-code prefix), implement the parse interface and compose it rather than regex-splitting in your controller.+/-, and DMS with seconds all behave subtly differently. Put a handful of these strings in a Pest/PHPUnit data provider early — it doubles as documentation for your team about what the field accepts.How can I help you explore Laravel packages today?