$npx -y skills add smnandre/symfony-ux-skills --skill ux-mapSymfony UX Map for interactive maps with Leaflet or Google Maps in Symfony. Covers markers, polygons, polylines, circles, info windows, and LiveComponent integration. Use when displaying maps, placing markers, drawing shapes or routes, handling map events, building store locators
| 1 | # UX Map |
| 2 | |
| 3 | Interactive maps in Symfony with Leaflet or Google Maps. Build maps in PHP, render them in Twig, and extend them with Stimulus controllers. Supports markers, polygons, polylines, circles, info windows, and LiveComponent integration. |
| 4 | |
| 5 | ## Installation |
| 6 | |
| 7 | ```bash |
| 8 | # Install the base package |
| 9 | composer require symfony/ux-map |
| 10 | |
| 11 | # Then install ONE renderer: |
| 12 | composer require symfony/ux-leaflet-map # Leaflet (free, open source) |
| 13 | # OR |
| 14 | composer require symfony/ux-google-map # Google Maps (requires API key) |
| 15 | ``` |
| 16 | |
| 17 | ## Quick Reference |
| 18 | |
| 19 | ``` |
| 20 | Map PHP object, holds markers/shapes/options |
| 21 | Point latitude + longitude |
| 22 | Marker pin on the map, optional InfoWindow |
| 23 | Polygon closed shape (array of Points) |
| 24 | Polyline open line (array of Points) |
| 25 | Circle center Point + radius in meters |
| 26 | InfoWindow popup attached to a Marker, Polygon, or Circle |
| 27 | ux_map(map, attrs) Twig function to render a Map |
| 28 | <twig:ux:map /> Twig component (requires ux-twig-component) |
| 29 | ``` |
| 30 | |
| 31 | ## Building a Map in PHP |
| 32 | |
| 33 | ```php |
| 34 | use Symfony\UX\Map\Map; |
| 35 | use Symfony\UX\Map\Point; |
| 36 | use Symfony\UX\Map\Marker; |
| 37 | use Symfony\UX\Map\InfoWindow; |
| 38 | use Symfony\UX\Map\Polygon; |
| 39 | use Symfony\UX\Map\Polyline; |
| 40 | use Symfony\UX\Map\Circle; |
| 41 | |
| 42 | $map = (new Map()) |
| 43 | ->center(new Point(48.8566, 2.3522)) |
| 44 | ->zoom(12) |
| 45 | ->minZoom(3) |
| 46 | ->maxZoom(18); |
| 47 | |
| 48 | // Marker with info window |
| 49 | $map->addMarker(new Marker( |
| 50 | position: new Point(48.8566, 2.3522), |
| 51 | title: 'Paris', |
| 52 | infoWindow: new InfoWindow( |
| 53 | headerContent: '<b>Paris</b>', |
| 54 | content: 'The capital of France', |
| 55 | ), |
| 56 | )); |
| 57 | |
| 58 | // Marker with custom icon (UX Icons integration) |
| 59 | $map->addMarker(new Marker( |
| 60 | position: new Point(48.8738, 2.2950), |
| 61 | title: 'Eiffel Tower', |
| 62 | icon: Icon::ux('mdi:tower-eiffel')->width(32)->height(32), |
| 63 | extra: ['category' => 'landmark'], |
| 64 | )); |
| 65 | |
| 66 | // Polygon (closed area) |
| 67 | $map->addPolygon(new Polygon( |
| 68 | points: [ |
| 69 | new Point(48.8566, 2.3522), |
| 70 | new Point(48.8606, 2.3376), |
| 71 | new Point(48.8530, 2.3499), |
| 72 | ], |
| 73 | infoWindow: new InfoWindow(content: 'Central Paris area'), |
| 74 | )); |
| 75 | |
| 76 | // Polyline (open line) |
| 77 | $map->addPolyline(new Polyline( |
| 78 | points: [ |
| 79 | new Point(48.8566, 2.3522), |
| 80 | new Point(48.8738, 2.2950), |
| 81 | ], |
| 82 | )); |
| 83 | |
| 84 | // Circle (center + radius in meters) |
| 85 | $map->addCircle(new Circle( |
| 86 | center: new Point(48.8566, 2.3522), |
| 87 | radius: 500, |
| 88 | infoWindow: new InfoWindow(content: '500m radius'), |
| 89 | )); |
| 90 | |
| 91 | // Auto-fit bounds to show all markers |
| 92 | $map->fitBoundsToMarkers(); |
| 93 | ``` |
| 94 | |
| 95 | ## Rendering in Twig |
| 96 | |
| 97 | ### Twig Function |
| 98 | |
| 99 | ```twig |
| 100 | {# Basic rendering #} |
| 101 | {{ ux_map(map, {style: 'height: 400px; width: 100%;'}) }} |
| 102 | |
| 103 | {# With custom attributes and Stimulus controller #} |
| 104 | {{ ux_map(map, { |
| 105 | 'data-controller': 'custom-map', |
| 106 | style: 'height: 400px;', |
| 107 | class: 'rounded shadow' |
| 108 | }) }} |
| 109 | ``` |
| 110 | |
| 111 | ### Twig Component (HTML Syntax) |
| 112 | |
| 113 | Requires `symfony/ux-twig-component`. Allows inline map definition without PHP: |
| 114 | |
| 115 | ```html |
| 116 | <twig:ux:map |
| 117 | :center="[48.8566, 2.3522]" |
| 118 | zoom="12" |
| 119 | :markers='[ |
| 120 | {"position": [48.8566, 2.3522], "title": "Paris"}, |
| 121 | {"position": [48.8738, 2.2950], "title": "Eiffel Tower", |
| 122 | "infoWindow": {"content": "324m tall"}} |
| 123 | ]' |
| 124 | :fitBoundsToMarkers="true" |
| 125 | style="height: 400px; width: 100%;" |
| 126 | class="rounded shadow" |
| 127 | /> |
| 128 | ``` |
| 129 | |
| 130 | ## Configuration |
| 131 | |
| 132 | ```yaml |
| 133 | # config/packages/ux_map.yaml |
| 134 | ux_map: |
| 135 | renderer: '%env(resolve:default::UX_MAP_DSN)%' |
| 136 | |
| 137 | # Google Maps specific |
| 138 | google_maps: |
| 139 | default_map_id: null # Optional: default Map ID for all maps |
| 140 | ``` |
| 141 | |
| 142 | ### Renderer DSN |
| 143 | |
| 144 | Set in `.env`: |
| 145 | |
| 146 | ```bash |
| 147 | # Leaflet (free) |
| 148 | UX_MAP_DSN=leaflet://default |
| 149 | |
| 150 | # Google Maps (requires API key) |
| 151 | UX_MAP_DSN=google://GOOGLE_MAPS_API_KEY@default |
| 152 | ``` |
| 153 | |
| 154 | ## Renderer Options |
| 155 | |
| 156 | ### Leaflet Options |
| 157 | |
| 158 | ```php |
| 159 | use Symfony\UX\Map\Bridge\Leaflet\LeafletOptions; |
| 160 | use Symfony\UX\ |