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

Parabol Google Maps Picker Bundle Laravel Package

parabol/parabol-google-maps-picker-bundle

A Symfony bundle that adds an interactive Google Maps location picker form type, letting users search for an address or drop a pin and submit precise latitude/longitude coordinates. Configurable map options, simple asset setup, and easy integration into existing forms.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal steps to bring this into a Laravel project:

composer require parabol/parabol-google-maps-picker-bundle

Despite the -bundle suffix (a Symfony naming convention), this package exposes a form field type that renders a Google Maps picker widget and captures latitude / longitude into your model. It is not a Laravel package with an auto-discovered ServiceProvider in the usual sense — check the repository README for the current install path before assuming php artisan vendor:publish will do anything.

First things to look at, in order:

  1. The README.md on the GitHub repo — it is the only documentation. Look for the form type class name (typically something like Parabol\GoogleMapsPickerBundle\Form\Type\GoogleMapsPickerType) and the required options.
  2. Resources/config/ in the package — this is where the JS asset, default options, and any routing for the geocode endpoint live.
  3. Your Google Cloud Console — you need a Maps JavaScript API key with the Geocoding API enabled, plus billing attached. This is the step that trips up most first-time users.

First use case: a Venue or Location model with latitude and longitude decimal columns.

// app/Models/Venue.php
protected $fillable = ['name', 'address', 'latitude', 'longitude'];
protected $casts = ['latitude' => 'float', 'longitude' => 'float'];

Then wire the picker into a form (adapting the Symfony FormType to whatever Laravel form layer you use — Livewire, Filament, or plain Blade). In Blade the core contract is: a text input for the address, two hidden inputs for latitude/longitude, and the package JS that listens for a map click or autocomplete selection and writes those values.

Implementation Patterns

Two-coordinate entity pattern. The cleanest fit is a model with nullable latitude/longitude decimals. Render the picker, let the user pick a point, submit, and persist. On re-edit, hydrate the map from the stored coordinates.

<div
    x-data="mapsPicker({
        lat: {{ $venue->latitude ?? 'null' }},
        lng: {{ $venue->longitude ?? 'null' }},
        key: '{{ config('services.google_maps.key') }}'
    })"
>
    <input type="text" x-model="address" placeholder="Search a place">
    <div x-ref="map" style="height: 400px"></div>
    <input type="hidden" name="latitude"  x-model="lat">
    <input type="hidden" name="longitude" x-model="lng">
</div>

Validation gate. Never trust the widget. Require coordinates together and bound them:

$request->validate([
    'latitude'  => ['nullable', 'numeric', 'between:-90,90', 'required_with:longitude'],
    'longitude' => ['nullable', 'numeric', 'between:-180,180', 'required_with:latitude'],
]);

Persist, then optionally reverse-geocode to fill a human-readable address if the user didn't type one.

Livewire integration. Because the widget is JS-driven, the common trap is state desync. Bind the hidden inputs to Livewire properties and dispatch an event when the map marker moves:

protected $listeners = ['coordinatesChanged' => 'updateCoordinates'];

public function updateCoordinates($lat, $lng)
{
    $this->latitude  = round((float) $lat, 7);
    $this->longitude = round((float) $lng, 7);
}
map.addListener('click', e => {
    Livewire.dispatch('coordinatesChanged', {
        lat: e.latLng.lat(),
        lng: e.latLng.lng(),
    });
});

Filament field. Wrap the same contract in a custom Field, storing latitude/longitude as two sibling form fields via ->dehydrateStateUsing(). Do not try to cram both into one column — sorting and distance queries in MySQL/Postgres need them separate.

Distance queries. Once you have the columns, add a scope using ST_Distance_Sphere (MySQL) or earth_distance (Postgres). Coordinates stored as floats at 7 decimal places are fine for street-level accuracy.

Gotchas and Tips

  • It is a Symfony bundle. There is almost certainly no Laravel ServiceProvider. You will likely need to register the classes manually or use the package only for its JS asset and copy the widget logic into your own Blade component. Treat the package as a template more than a dependency.
  • Zero stars, zero dependents, no maintainer activity signal. Before you commit, read the code yourself. Prefer copying the relevant JS into your own resources/js and pinning it, rather than depending on a composer update bringing unreviewed changes.
  • API key exposure. Any Maps JavaScript key in the browser is public. Restrict it in Google Cloud Console by HTTP referrer, and use a separate server key for the Geocoding API — never reuse the browser key server-side.
  • Billing surprise. Google gives a monthly credit but charges above it. Autocomplete + map loads + reverse geocoding can pile up on a busy form. Cache reverse-geocoded addresses against coordinates; do not call the API on every keystroke.
  • Async script loading. maps.googleapis.com/maps/api/js must be loaded before the picker initializes. In a Livewire or SPA context, dynamically inserted DOM may run the init before the script resolves. Use the official callback= parameter or the loader utility rather than document.ready.
  • Initial map state. Without a center and zoom, the map renders grey. Default to a sensible city center when no coordinates are stored.
  • Hidden field validation. nullable plus required_with is the pattern; do not use bare required on both, or a user picking only a point with no reverse-geocode will fail validation.
  • Decimal precision. decimal(10,7) for latitude, decimal(11,7) for longitude covers the full globe. float is acceptable but avoid varchar.
  • Timezone of the map widget. The JS returns coordinates in WGS84. If you later integrate with a routing or geofencing service, confirm its expected datum — most expect WGS84, but some legacy APIs want GCJ-02 or others.
  • Extension point. If the bundled JS is awkward, the widget's contract is trivial: it just fills two hidden inputs. Replacing it with a 50-line Alpine + Maps JS snippet is often cleaner than fighting the bundle's assumptions.
  • Testing. Mock the Google API in feature tests — never hit the live endpoint in CI. Assert that latitude/longitude validation rejects out-of-range values and that null coordinates are handled gracefully on the edit form.
  • License check. With no stars or maintainers, verify the license in composer.json before using in production; unknown licensing is a real blocker for client work.
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