lendable/google-map-bundle
A Symfony bundle that integrates Google Maps into your application, providing services and Twig helpers to render maps, configure markers, and manage API settings from a central configuration.
Read this first: it is not a Laravel package. lendable/google-map-bundle is a Symfony2 bundle (a fork of egeloen/ivory-google-map-bundle), it is archived since 2016, has zero dependents, and ships no service provider, facade, or package discovery. composer require lendable/google-map-bundle in a Laravel app gets you a bundle class that Laravel will never boot, plus a hard dependency on Symfony DI/Twig wiring you don't have.
That said, the value of the package is the underlying framework-agnostic library in the Ivory lineage (Ivory\GoogleMap\Map, Coordinate, Marker, InfoWindow, Ivory\GoogleMap\Helper\MapHelper). That part is plain PHP and can be driven from a Laravel controller. Treat the "bundle" as a documentation reference, not an install target.
Minimal path if you insist on using the library:
composer.json in the repo and look at the php constraint. This code is PHP 5.5/7.x-era; expect friction (or hard failures) on PHP 8.1+. If the Lendable fork doesn't declare ^8.0, stop here.composer require lendable/google-map-bundle (or pull the underlying map library directly if the fork's autoload map is bundle-shaped).config/services.php:
'google_maps' => ['key' => env('GOOGLE_MAPS_KEY')],
AppServiceProvider::register():
$this->app->singleton(MapHelper::class, fn () => MapHelperBuilder::create()->build());
{!! $mapHtml !!} (unescaped is mandatory — the helper returns markup + <script>).First use case: a single-location "find us" page — one Map, one Coordinate, one Marker, one InfoWindow. That exercises 90% of the API surface you'll ever need and tells you within an hour whether the library runs on your PHP version.
If the answer to step 1 is "no," skip to Gotchas — you're better off with a Blade component wrapping the Maps JS API.
Render in the controller, not the view. The helper produces a container <div>, a map_js config object, and initialization code. Build it once and cache the string; it's deterministic for a given set of coordinates, so Cache::remember("map:{$id}", 3600, fn () => $helper->render($map)) works well for static store-locator pages.
Separate HTML from JS when you need control over script placement. Rather than render(), use the helper's HTML and JavaScript renderers individually so the JS can go in a @push('scripts') stack below the Google loader:
// Controller
return view('contact', [
'mapHtml' => $helper->renderHtml($map),
'mapJs' => $helper->renderJavascript($map),
]);
{{-- contact.blade.php --}}
{!! $mapHtml !!}
@push('scripts')
<script src="https://maps.googleapis.com/maps/api/js?key={{ config('services.google_maps.key') }}"></script>
{!! $mapJs !!}
@endpush
This ordering matters: the generated JS calls new google.maps.Map(...) and will throw google is not defined if the API script hasn't loaded.
Wrap it in a Blade component for reuse. A <x-google-map :markers="$locations" /> component (class-based, taking an array of ['lat','lng','title','html']) keeps Ivory\GoogleMap\* imports out of your views and out of every controller. Inside the component, loop the array and add a Marker per entry, attaching an InfoWindow to each.
Overlay building is imperative and order-sensitive. The pattern is always: create Coordinate → create Marker with that coordinate → $map->getOverlayManager()->addMarker($marker) → create InfoWindow with content and coordinate → $marker->setInfoWindow($infoWindow) → $map->getOverlayManager()->addInfoWindow($infoWindow). Attach the InfoWindow to both the marker and the map, or clicking does nothing. Same shape for Polyline, Polygon, and Circle via the overlay manager.
Custom JS goes through the library, not around it. Instead of hand-writing event handlers and hoping the map variable is in scope, push Ivory\GoogleMap\Utility\.../Javascript objects onto the map so they're emitted inside the same initialization callback and can reference the generated map variable. This is the one place the library genuinely saves you work versus raw JS.
Multiple maps per page: give each Map a distinct htmlVariable/container id before rendering. The default id is shared and two render() calls in one response will collide on the DOM id and on the JS variable name.
Config: the bundle's Symfony config tree (ivory_google_map.api_key) does not exist in Laravel. Every "set the API key in config.yml" instruction in the README is dead weight — the library doesn't read it; the generated JS just points at the API script. You're responsible for injecting ?key= yourself.
ivory_google_map() function, no bundle config, no app/config/config.yml. Any tutorial you find for Ivory Google Map Bundle will show Twig and YAML you cannot use. Translate to PHP + Blade, or ignore it.AdvancedMarkerElement / Map ID are the modern marker path, and several legacy behaviors are deprecated. This library emits the 2016-era google.maps.Marker API. It still works today, but you're building on a deprecation clock you didn't set.<script>. If you run a script-src policy without 'unsafe-inline', the map will not initialize. Either allow inline scripts for that route or extract the rendered JS into an external file — the latter is brittle because the generated code references generated variables.{{ $mapHtml }} renders literal <div> text. Use {!! !!} and be aware you're now trusting the library's output (fine, it HTML-escapes InfoWindow content — verify that it does for your version).dd($mapJs) and read the emitted map_js config object — the failure is almost always a malformed coordinate, an InfoWindow added to a marker but not the map, or a duplicate container id.Coordinate takes lat/lng as floats. If you're feeding it from Eloquent with string-cast columns, cast explicitly — a "51.5" string reaching the serializer produces odd output in older versions.MapHelperBuilder, styles, MarkerClusterer support). Those are usable standalone. The bundle's compiler passes and Twig extensions are not; don't try to port them.GoogleMaps service holding the key and a markers() payload, render with the Maps JS API directly, and keep the markup under your control. Alternatives in the Laravel ecosystem (cornford/googlmapper, farhanwazir/laravelgooglemaps) are largely in the same abandoned state — the JS-API-direct route is the one with no maintenance cliff. Consider this package only if you have an existing Ivory-based codebase to port and need API parity for a migration window.How can I help you explore Laravel packages today?