## Getting Started
### Minimal Setup
1. **Install the package**:
```bash
composer require anotterweb/ux-location
config/bundles.php:
Anotterweb\UxLocation\AnotterWebUxLocationBundle::class => ['all' => true],
config/packages/anotterweb_ux_location.yaml:
anotterweb_ux_location:
mapbox_access_token: '%env(MAPBOX_ACCESS_TOKEN)%'
php bin/console importmap:require mapbox-gl mapbox-gl/dist/mapbox-gl.css
Add the LocationType to a form:
use Anotterweb\UxLocation\Form\Type\LocationType;
$builder->add('location', LocationType::class, [
'label' => 'Store Location',
]);
Render in Twig:
{{ form_row(form.location) }}
Form Integration:
LocationType as a replacement for TextType where geographic coordinates are needed.Customization:
$builder->add('location', LocationType::class, [
'default_lat' => 40.7128, // New York
'default_lng' => -74.0060,
'map_height' => '400px',
]);
Data Handling:
lat,lng format (e.g., 48.8566,2.3522).$data = $form->getData();
$coordinates = explode(',', $data['location']);
if (count($coordinates) !== 2) {
// Handle invalid format
}
Symfony UX Integration:
data-controller="location" in Twig to attach custom logic.Dynamic Map Styling:
map_style option to switch between Mapbox styles (e.g., mapbox://styles/mapbox/streets-v11).Custom Markers:
// assets/controllers/location_controller.js
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
connect() {
this.map.addSource('custom-marker', {
type: 'geojson',
data: { type: 'FeatureCollection', features: [...] }
});
}
}
Geocoding:
TextType for address input, then trigger the map via JavaScript.Validation:
use Symfony\Component\Validator\Constraints as Assert;
$builder->add('location', LocationType::class, [
'constraints' => [
new Assert\Regex('/^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$/'),
],
]);
Missing Mapbox Token:
MAPBOX_ACCESS_TOKEN is not set, the map will fail to load. Always validate the env variable:
# config/packages/dev/anotterweb_ux_location.yaml
anotterweb_ux_location:
mapbox_access_token: '%env(MAPBOX_ACCESS_TOKEN)%'
401 Unauthorized errors.AssetMapper Issues:
mapbox-gl and its CSS are imported. Run:
php bin/console debug:asset-mapper
importmap:require is used instead of encore.Coordinate Format:
lat,lng format. Reject malformed input early:
if (!preg_match('/^[-+]?\d+(\.\d+)?,\s*[-+]?\d+(\.\d+)?$/', $data['location'])) {
$form->addError(new FormError('Invalid coordinates format.'));
}
Form Theme Conflicts:
php bin/console cache:clear
templates/form/fields.html.twig isn’t overriding the bundle’s templates.Symfony 8+ Compatibility:
symfony/asset-mapper and symfony/ux are installed:
composer require symfony/asset-mapper symfony/ux
Browser DevTools:
data-controller or data-action attributes).Log Configuration:
# config/packages/dev/monolog.yaml
handlers:
main:
type: stream
path: "%kernel.logs_dir%/%kernel.environment%.log"
level: debug
Stimulus Debugging:
data-controller="location" to the map container in Twig:
{{ form_widget(form.location, { 'attr': {'data-controller': 'location'} }) }}
console.log in custom Stimulus controllers to trace execution.Custom Stimulus Controllers:
assets/controllers/location_controller.js:
import { LocationController } from '@anotterweb/ux-location';
export default class extends LocationController {
connect() {
super.connect();
// Add custom logic (e.g., disable map interaction)
this.map.boxZoom.disable();
}
}
{{ form_widget(form.location, { 'attr': {'data-controller': 'location--custom'} }) }}
Form Events:
$form->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
if ($data['location']) {
$event->getForm()->add('location', LocationType::class, [
'default_lat' => explode(',', $data['location'])[0],
'default_lng' => explode(',', $data['location'])[1],
]);
}
});
Twig Extensions:
// src/Twig/MapExtension.php
class MapExtension extends \Twig\Extension\AbstractExtension {
public function getFunctions() {
return [
new \Twig\TwigFunction('map_url', [$this, 'getMapUrl']),
];
}
public function getMapUrl(array $coordinates) {
return "https://api.mapbox.com/styles/v1/mapbox/streets-v11/static/pin-s+ff0000($coordinates[1],$coordinates[0])/$coordinates[1],$coordinates[0],14/600x400?access_token=%env(MAPBOX_ACCESS_TOKEN)%";
}
}
<img src="{{ map_url([48.8566, 2.3522]) }}" alt="Preview">
Database Storage:
Point type column (PostgreSQL) or as separate latitude/longitude fields:
// Doctrine Entity
/**
* @ORM\Column(type="string", length=50)
*/
private $location; // "lat,lng"
// OR
/**
* @ORM\Column(type="decimal", precision=10, scale=8)
*/
private $latitude;
/**
* @ORM\Column(type="decimal", precision=11, scale=8)
*/
How can I help you explore Laravel packages today?