pugx/geo-form-bundle
PugxGeoFormBundle adds a map-based coordinate picker form type to Symfony apps, letting users select latitude and longitude visually on an interactive map instead of typing raw numbers. Easy to embed in existing forms, with configurable map options and simple GeoPoint handling.
composer require pugx/geo-form-bundle
Register PUGX\GeoFormBundle\PUGXGeoFormBundle in config/bundles.php (or AppKernel on older Symfony). Check composer.json first — the bundle predates Symfony 4/5 and may need a fork or constraint patch to install on current Symfony.
# config/packages/pugx_geo_form.yaml
pugx_geo_form:
api_key: '%env(GOOGLE_MAPS_API_KEY)%'
include_assets: true # renders the Maps <script> for you
Publish the bundle's JS (bin/console assets:install --symlink on Symfony 3, or copy it into your Encore/importmap setup on modern versions — it is not auto-included).
First use case — add latitude/longitude to a form:
$builder->add('geo', GeoFormType::class, [
'label' => 'Pick a location',
]);
Where to look first:
src/Form/Type/GeoFormType.php and GeoFormTypeCollection.php — the child field names (latitude, longitude, optional address) you'll be mapping.src/DependencyInjection/Configuration.php — the real list of available options (api_key, include_assets, map defaults).Resources/views/Form/geo_form_widget.html.twig — the markup and data-* attributes the JS binds to. If anything breaks, this template is the contract.Entity + Doctrine. Store coordinates as nullable DECIMAL(10,7), never FLOAT — Google returns 48.8583701 and binary float will drift on round-trips. Nullable is important: a user may not pick a point yet.
Mapping into your entity. GeoFormType renders its own latitude/longitude children, so submitted data arrives under geo[latitude]. Either:
data_class pointing at a small value object, orPRE_SUBMIT / SUBMIT listener that copies $data['geo']['latitude'] onto your entity fields.Don't rely on mapped => true for nested field names unless you've verified the property path in a profiler.
Collections for multiple points. Use GeoFormTypeCollection (a CollectionType subclass) for one-to-many locations — each row gets its own map. The JS initializes per-instance from data-* attributes, so prototype rendering works, but you must call the bundle's init after collection:add (or dispatch whatever event the shipped JS listens for).
Server-side geocoding. If you enable the address-search option, the JS fills coordinates via Google's geocoder; for non-JS clients or API imports, add a Geocoder call in a form event. Keep the two paths consistent — round to 6–7 decimals before persisting so the same place stores identically.
Progressive enhancement / no-JS fallback. The coordinate inputs are hidden, so non-JS clients submit nothing. Render visible NumberType inputs in a <noscript> block, or flip the widget to text inputs when JS is unavailable.
Validation. The bundle does not validate coordinates. Add Assert\NotBlank plus a Range (-90..90, -180..180) on the entity, and a JS guard preventing submit when the map was never touched.
Testing. With KernelTestCase, resolve form.factory, instantiate the form, and submit(['geo' => ['latitude' => '48.85', 'longitude' => '2.35']]). You can't test the map widget in PHP — treat the JS as untested and keep the coordinate contract (field names + rounding) under test.
getBlockPrefix, configureOptions, and Twig form-theme registration for Symfony 5/6. Budget half a day for that or reimplement the widget yourself (a form type + ~60-line Stimulus controller is often less work than patching).maps.googleapis.com/maps/api/js, include_assets: true will trigger the "included multiple times" warning and can break the map. Set include_assets: false and load the API once globally.localhost unless whitelisted. A blank grey map is almost always the key, referrer, or a missing Geocoding API enablement — check the browser console before touching PHP.assets:install doesn't exist; copy the bundle's JS into assets/vendor/ and import it via Encore/importmap. No error is thrown if you forget — the widget just renders an inert <div>.<div> in the HTML with its data-* attributes? (2) did the JS file actually load (network tab)? (3) is the Maps API key valid for the referrer? (4) only then look at PHP.$options array (map center/zoom/height/CSS class), the geo_form_widget Twig block to override markup globally, and getParent() if you want a project-specific base type. There are no events or service tags — configuration is the only tuning surface.DECIMAL(10,7); otherwise the same user re-saving the form produces != values and breaks any "has location changed" logic.How can I help you explore Laravel packages today?