Google Maps package for Filament PHP
This package provides a comprehensive set of tools for using Google Maps within the Filament PHP ecosystem (an application builder for Laravel), either as part of an admin panel, or in standalone front end forms, tables and dashboards.
This is the v3 branch, compatible with the recent Filament v3 release. At some point soon we will replace the main branch (currently the Filament v2 compatible branch) with this v3 branch, and move Filament v2 support to a v2 branch.
Please report any you find either on the GitHub Issues page, or find me (@cheesegrits) on the Filament Discord server.
IMPORTANT NOTE - some features of this package could potentially drive up your API bill. If you have large tables that you display static maps on, and you clear your cache frequently. Or if you allow public access to forms that use geocoding, and get hit by bots.
We strongly suggest you set usage quotas in your Google Console. We are not liable if you get a surprise bill!
If you just can't handle reading documentation and want to dive right in ...
composer require cheesegrits/filament-google-maps "^3.0"
... then follow these instructions to add a computed attribute to any model(s) that will use these components (which should already have separate lat and lng fields, even if they are empty, see the Batch Commands section) ...
php artisan filament-google-maps:model-code
... then start using the components, like ...
use Cheesegrits\FilamentGoogleMaps\Fields\Map
...
->schema[
...
// must use the computed attribute name you used on your model
// which must NOT exist on the table itself
Map::make('location'),
...
]
The Map field displays (unsurprisingly) a Google map, with a comprehensive set of configuration options. It supports coordinate updating both ways between map and form, forward and revese geocompletion, reverse geocoding and KML layers.
The Geocomplete field turns a text field on your form into a Google geocomplete field, with optional reverse geocoding of address components.
The MapEntry Infolist field displays a (read only) map showing a single pin. This is currently WIP, features and functionality (like KML layers, GeoJSON drawings, etc) to be added soon.
The MapWidget displays a filterable set of locations from a model, with optional clustering, templatable labels, customizable icons, etc.
The MapTableWidget displays a map widget, along with a Filament Table, and reacts to all filtering and searching on the table.
The MapColumn displays a customizable static map image, with the images cached locally to reduce API overhead.
The StaticMapAction is a bulk action that lets you select any number of table rows, and generate a downloadable static map showing those locations.
The RadiusFilter provides radius filtering against a geocomplete address, in kilometers or miles.
The Artisan commands allow you to do batch processing on your location tables, either geocoding a combination of address fields into lat lng, or reverse geocoding lat and lng to address fields.
(back to top)
This package is built on Filament V2, and Laravel 9. It may run on earlier versions of Laravel, but has not been tested.
You can install this project via composer:
composer install cheesegrits/filament-google-maps
This package handles asynchronous loading of JS and CSS assets, in both the Filament Admin Panel and standalone pages, with no need to publish anything or modify your project.
To simplify working with coordinate data, we require a computed property on any model being used for map data, which converts between separate lat and lng fields on your table, and a Google Point style array of 'lat' and 'lng' keys.
To prepare your model, use the Artisan command:
php artisan filament-google-maps:model-code
... which will prompt you for:
The 'location' computed attribute is what you will use when you make() your map fields and columns. If you have no religious preference and it doesn't already exist on your table, just use 'location'.
It will then spit out the code for you to copy and paste to your model class.
NOTE - this script also gives you modified $fillable and $appends arrays if required, which will merge any existing content of these arrays, make sure you replace the existing ones if you already have them.
All use of the Google Maps API requires an API key. If you don't have one, refer to Google's documentation.
Once you have a key, either add it to your .env file as:
GOOGLE_MAPS_API_KEY=your_map_key_here
... or publish and edit the filament-google-maps.php config file. We recommend using an environment variable. Note that we deliberately use the same key name used by most Google related Laravel packages, just to make life easier. However, if need to use a different key for this package, you may do so - refer to the config file in the next section.
You may optionally publish the package configuration. The configuration comes with a set of sane defaults, so we suggest not publishing unless you actually need to change something ... and even then, best to do it with .env variables.
php artisan vendor:publish --tag="filament-google-maps-config"
... which can then be found in ./config/filament-google-maps.php
Of particular note are the config settings for your API Keys and the cache store. By default, we will cache all API responses for 30 days, using your default cache driver. For most normal usage this is sufficient, but if you expect heavy usage, we suggest setting up a dedicated Redis store in your cache.php config, and specify this with the FILAMENT_GOOGLE_MAPS_CACHE_STORE environment variable.
(click to expand)
…
(back to top)
The form field can be used with no options, by simply adding this to your Filament Form schema:
use Cheesegrits\FilamentGoogleMaps\Fields\Map
...
->schema[
...
Map::make('location'),
...
]
The name used for make() must be the one you set up as your model's computed location property. Note that you can have multiple maps on a form, by adding a second computed property referencing a second pair of lat/lng fields.
The full set of options is as follows. All option methods support closures, as well as direct values.
…
The mapControls without comments are standard Google Maps controls, refer to the API documentation.
The autocomplete('field_name') option turns the field name you give it into a Google Places geocomplete field, which suggests locations as you type. Selecting a suggestion will move the marker on the map.
If you specify autocompleteReverse(), moving the map marker will update the field specified in autocomplete() with the reverse geocoded address (using the formatted_address component from Google).
There are three additional options you can specify (typically as named params) for the autocomplete() method, see the Geocomplete field section for details.
Map::make('location')
->autocomplete(
fieldName: 'airport_name',
types: ['airport'],
placeField: 'name',
countries: ['US', 'CA', 'MX'],
)
The reverseGeocode() option lets you specify a list of field names from your form, with corresponding format strings for decoding the address component response from Google. We use the printf() style formatting defined by Geocoder PHP as follows:
Note that %p is not listed in the Geocoder PHP docs, and represents the "premise" of an address if present, typically a place name like "The Old Farmhouse".
To help you figure out the format strings you need, you can set debug() on the map field, which will console.log() the response from each reverse geocode event (e.g. whenever you move the marker).
There are two ways to add layers to the map. The layers() method accepts an array of KML or GeoRSS file URLs, which will be added to the map using the Maps API KmlLayer() method. Note that these URLs must be publicly accessible, as the KmlLayer() method requires Google servers to read and process the files, see the KML & GeoRSS Layers documentation for details and limitations.
The second method allows for a single GeoJSON file to be specified using the geoJson() method, which accepts a closure or string that can be a local file path, raw GeoJSON, or a URL to a GeoJSON file. If specifying a local path, the optional second argument can be the name of the Storage disk to use. The GeoJSON is rendered on the map using the Maps API Data Layer.
Map::make('location')
//
->geoJson('jsons/MyGeoJson.geojson', 'json-disk')
// ... or ...
->geoJson('https://my.site/jsons/MyGeoJson.geojson')
// ... or ...
->geoJson(function () {
// code that builds and returns raw GeoJSON
return $json;
})
When using GeoJSON, we provide a convenience method for storing a reference to any polygon features which contain the map marker coordinates, using the geoJsonContainsField() method. The first argument to this method is the field name on your form (which can be a Hidden field type) in which to store the data. The second is an optional argument specifying a property name from your GeoJSON features to store. If not specified, the entire GeoJSON feature will be stored.
Map::make('location')
->geoJson(function () {
return geoJsonContainsField('geojson_contains', 'prop0')
->geoJsonVisible(false)
With the above example, if the user dropped the map pin inside the rectangle, the 'geojson_contains' field would be updated as ["value0"]. If the second argument was omitted, the field would be updated with a GeoJSON FeatureCollection containing the JSON for the rectangle. If you have overlapping features, and multiple polygons contain the marker, all features containing the marker will be included in the array / FeatureCollection.
Also note the optional use of the geoJsonVisible(false) method, which hides the layer (creates a separate Data layer and does not attach it to the map), so you can track which polygons contain the marker without showing the polygons.
If you want the map marker to react to changes to lat or lng fie
No open issues yet, or sync has not completed.