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

Map Multi Linestring Laravel Package

wm/map-multi-linestring

A Laravel package for working with multi-linestring map geometries, offering helpers to handle, convert and render collections of line strings so multi-segment routes and paths are easier to display in map-based applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm compatibility first. This is a Nova field, so it will only work inside a Laravel app with Nova installed. Verify the Nova major version the package targets (composer show wm/map-multi-linestring for illuminate/* and laravel/nova constraints) before committing — adoption is very low, so you are the QA team.

Require at least ^1.0.4. The 1.0.4 patch fixes a crash where oldAttribute was null — i.e. the create path, not just edits. On older versions your first "new record" save can throw before you write a single line of integration code:

composer require wm/map-multi-linestring:^1.0.4
php artisan nova:publish   # if the README mentions publishing field assets
php artisan view:clear && php artisan config:clear

Database column. Linestring collections are stored as GeoJSON, so you want a json (MySQL/Postgres) or text column, nullable:

$table->json('route')->nullable();

Register the field. The minimal resource usage is the standard Nova shape:

use Wm\MapMultiLinestring\MapMultiLinestring;

MapMultiLinestring::make('Route')
    ->onlyOnForms(),   // index tables get ugly fast with a map per row

First use case to build: an admin editing a path-like geometry — delivery routes, pipeline/utility runs, fiber segments, hiking trails, catchment boundaries. You want an operator without GIS skills to click points on a map and have the model persist valid GeoJSON. Build that one screen end-to-end — including a genuine create (not just an edit of a seeded record) — before generalizing.

Where to look first: the package's src/ directory (field class, any withMeta defaults) and its compiled dist/js/field.js. There is no meaningful ecosystem around this package, so the source is the documentation. Read the field's resolve/fill methods before you decide how to cast the column — that interaction is where most of the friction lives. Note the 1.0.4 fix lives exactly there, in old-vs-new attribute comparison: the field does compare existing and incoming geometry, so it has opinions about what "unchanged" means.

Implementation Patterns

Treat the column as GeoJSON, not as an array. Keep the raw JSON string on the model and parse on the way out. This avoids double-encoding when Nova's field serializes its value:

protected $casts = [
    'route' => 'array', // only if the field's fill() tolerates it — verify first
];

Safer default: no cast at all, store the string, and add an accessor:

public function routeGeoJson(): ?array
{
    return $this->route ? json_decode($this->route, true) : null;
}

This is doubly true given 1.0.4: the field compares oldAttribute against the incoming value. An array cast changes what the model hands back on the old side, and you do not want to discover mismatch semantics through a changelog entry. Leave the attribute raw and decode at the edges.

Expected payload shape is a FeatureCollection of LineString / MultiLineString features. Check against a real save before writing downstream code:

[
  'type' => 'FeatureCollection',
  'features' => [
    ['type' => 'Feature', 'geometry' => ['type' => 'LineString', 'coordinates' => [[lng, lat], ...]], 'properties' => []],
  ],
]

Map configuration via withMeta. Most of these Nova map fields expose their knobs through meta rather than fluent setters. Confirm the exact keys in the field source, but expect something like:

MapMultiLinestring::make('Route')
    ->withMeta([
        'center' => [45.4383, 12.3266], // [lat, lng] for the map container
        'zoom'   => 13,
        'height' => '420px',
    ])
    ->help('Click to add vertices. Double-click to finish a line.');

If you need per-record centering (e.g. fit to existing geometry), compute it in resolve via ->withMeta(['center' => ...]) on the resolved value — cheap, and it makes editing existing records far nicer.

Separate fields per geometry role. If a model has both a planned and an actual route, use two distinct columns and two fields. Do not try to multiplex one column with a discriminator; the field has no concept of a feature's properties, so filtering by type downstream becomes guesswork.

Validation. The submitted value is a JSON string. A plain ->rules('json') catches syntax but not topology. Add a custom rule if the geometry matters:

->rules(['nullable', 'json', new ValidLineStringCollection])

Inside the rule, json_decode, assert type === 'FeatureCollection', and assert each feature is a LineString/MultiLineString with at least two coordinate pairs. That's enough to prevent the "empty geometry saved as {}" class of bug.

Downstream consumption. Because everything is GeoJSON, you get free interop: feed it straight into a frontend Mapbox/Leaflet layer, into PostGIS via ST_GeomFromGeoJSON, or into MySQL 8 spatial functions. Keep a single conversion point (a resource class or toGeoJson() method on the model) so you can swap rendering libraries without touching controllers.

Testing. Don't try to drive Leaflet draw in feature tests. Test the field configuration and the persistence/validation layer with Nova::actingAs($user) and a direct payload post. Cover create and update explicitly — 1.0.4 is a create-path bug, which is exactly the path people forget to test. Reserve a single Dusk/Playwright smoke test for "the map renders and the save button round-trips a fixture GeoJSON." That covers the realistic failure mode (asset not loaded) without a flaky suite.

Gotchas and Tips

  • Null oldAttribute (fixed in 1.0.4). Creating a record — or any state where the field previously had no value — used to blow up while comparing geometries. If you see an exception from the field on first save, you are on 1.0.3 or below. Pin ^1.0.4 and keep a test that creates a record with route => null.
  • Coordinate order. GeoJSON is [longitude, latitude]; most map APIs take [lat, lng]. This package's center/zoom meta almost certainly uses map-convention lat, lng while the stored geometry uses GeoJSON convention. Getting these crossed silently puts your routes off the coast of Somalia. Assert on one known fixture early.
  • Very low adoption — but not abandoned. A May 2025 patch means someone is maintaining it; still, pin the exact version (^1.0.4) and be prepared to fork. Don't put this field on a resource you can't afford to reimplement; the fallback is a Textarea with JSON validation plus a read-only map preview.
  • Nova major upgrades are the risk. Nova 5 moved field asset loading; a field that hasn't been updated will render an empty container with a JS console error. Check after every composer update laravel/nova.
  • Empty vs null. The field may emit an empty FeatureCollection rather than null when a user clears the drawing. Normalize in a mutator so your "has geometry" checks (whereNotNull, if ($model->route)) behave predictably. Normalizing also removes a whole class of old-vs-new comparison surprises.
  • Tabs, modals, and hidden containers. Leaflet initializes with a zero-size container inside a collapsed panel or Nova tab, rendering grey tiles until resize. If the map looks broken, toggle the tab before blaming the package. Fix by initializing on tab-show or calling invalidateSize() on the map instance.
  • Tiles need network access. If your admin runs in an airgapped or CSP-restricted environment, the base map will be blank while the drawing controls still work. Budget for self-hosted tiles or accept the field being unusable there.
  • Assets not compiling? These packages usually ship a prebuilt dist/, so no npm step — but that also means you cannot patch the JS without rebuilding. Confirm dist/ exists in vendor/; if not, you need the npm build, which is a much bigger commitment.
  • Debugging the save. When a save appears to do nothing, inspect the Nova request payload first: if the field key is present and holds a JSON string, the problem is server-side (fill()/cast/comparison); if it's absent, the JS never registered the draw event. And isolate create vs update immediately — they take different code paths through the field and failures rarely affect both.
  • Extension points. Views are typically publishable (vendor:publish --tag=...) if you only need CSS/labels. For real behavior changes — custom toolbar, snap-to-road, per-vertex tooltips — fork and point a VCS repository at your fork; there is no plugin architecture here worth building against. A fork also lets you drop the old-vs-new comparison entirely if it fights your data model.
  • Don't use it for display-heavy surfaces. Rendering a map per row in an index table will destroy performance. Use ->onlyOnForms() and show a human-readable summary (point count, bounding box) in the index instead.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin