wm/map-point
A lightweight Laravel/PHP package for managing map points and geographic coordinates. Store latitude and longitude, attach points to models, and build simple location-aware features without a heavy GIS dependency. Useful for markers, listings, and proximity-based queries.
Install: composer require wm/map-point. Nova 4 custom fields need their frontend assets registered; check the package README for any php artisan vendor:publish or build step (npm run dev if dist/ isn’t shipped).
Database prerequisite: PostGIS must be enabled on the connection the model uses:
CREATE EXTENSION IF NOT EXISTS postgis;
Look here first: src/MapPoint.php (the Laravel\Nova\Fields\Field subclass) and resources/js/components/Field.vue (or IndexField/DetailField variants). Those two files define the entire contract — what the field accepts in PHP and what it renders in the UI. Grep the source for resolve, fill, hydrate, and persist before trusting any README example.
First use case — add a location picker to a resource:
use Wm\MapPoint\MapPoint;
public function fields(Request $request): array
{
return [
MapPoint::make('Location', 'location')
->rules('required'),
];
}
With a matching PostGIS column:
// database/migrations/xxxx_add_location_to_places_table.php
public function up(): void
{
DB::statement('ALTER TABLE places ADD COLUMN location geometry(Point, 4326)');
}
geometry(Point, 4326) (WGS84) unless you already work in a projected SRID like 3857. A nullable column is the safe default; the field must already know how to fill null (verify by inspecting MapPoint::fill).ST_GeomFromText, ST_AsText, ST_AsGeoJSON). If your model toArray() includes the attribute, wrap it in an accessor that returns GeoJSON or WKT — don’t leak the raw binary geometry to JSON, which will fail to encode.
protected $appends = ['location_geojson'];
public function getLocationGeojsonAttribute(): ?array
{
if (! $this->location) return null;
return json_decode(
DB::selectOne(
'SELECT ST_AsGeoJSON(?) AS g',
[$this->location]
)->g,
true
);
}
DB::statement('CREATE INDEX places_location_gist ON places USING GIST (location)');
ST_DWithin:
$query->whereRaw(
'ST_DWithin(location::geography, ST_MakePoint(?, ?)::geography, ?)',
[$lng, $lat, $meters]
);
MapPoint fields with distinct column names; keep SRIDs identical across both or ST_Distance results are meaningless.->rules('required', 'array', 'size:2') (or whatever shape the field emits) plus a custom rule that checks lat/lng ranges before it hits the DB.IndexField or PreviewField, use it; a raw WKT string in an index table is unreadable to operators.POINT(lng lat); the JS picker’s [lat, lng] is the opposite. Check MapPoint::fill() explicitly — a silent swap produces map markers off the coast of Somalia.4326 columns with 3857 inputs throws Operation on mixed SRID geometries. Always pass an SRID when creating geometry: ST_SetSRID(ST_MakePoint(?, ?), 4326).resolve in isolation.CREATE EXTENSION postgis must run before the ALTER TABLE. In CI, seed this as a separate migration or via psql in the pipeline.POINT EMPTY value behaves differently from NULL in ST_DWithin and ST_AsGeoJSON. Normalize in the model or in the field’s fill() override: an empty picker should persist null, not an empty geometry literal.dist/js/field.js is stale — recompile or re-copy from vendor/ after composer update. Symptom is a blank panel where the map should be, with no PHP error.src/MapPoint.php end-to-end (it’s small), pin the version in composer.json, and vendor any customizations into your own field subclass rather than patching vendor/. Extension points to lean on: ->resolveUsing(), ->fillUsing(), and ->withMeta() for default zoom/center.MapPoint::fill() and run SELECT ST_AsText(location), ST_SRID(location) FROM places WHERE id = ? in tinker. Nine times out of ten the answer is “wrong SRID” or “lat/lng swapped.”How can I help you explore Laravel packages today?