Installation Add the bundle via Composer:
composer require daa/addressable-bundle
Register it in config/bundles.php (Symfony 5/6):
Addressable\Bundle\AddressableBundle::class => ['all' => true],
For Symfony 2/3, add it to AppKernel.php.
Configure Twig
Include the form theme in config/packages/twig.yml (Symfony 5/6):
twig:
form_themes:
- '@Addressable/Form/fields.html.twig'
For Symfony 2/3, add it to config.yml under twig.form_themes.
First Use Case: Making an Entity Addressable
Annotate your entity with Addressable\Bundle\AddressableBundle\Annotation\Addressable:
use Addressable\Bundle\AddressableBundle\Annotation\Addressable;
/**
* @Addressable
*/
class Restaurant
{
// ...
}
Add latitude and longitude fields to your entity:
/**
* @ORM\Column(type="decimal", scale=10, precision=13)
*/
private $latitude;
/**
* @ORM\Column(type="decimal", scale=10, precision=13)
*/
private $longitude;
Generate Addressable Fields Run the bundle’s command to scaffold the address fields:
php bin/console addressable:generate
This creates a Address entity (or uses an existing one) and updates your entity with address-related fields.
Use the Google Maps form type to let users search for addresses interactively:
{{ form_row(form.address) }}
This renders a searchable Google Maps input. The bundle handles conversion between addresses and lat/lng.
Leverage the GeoSpatialService to filter/sort entities by distance or location:
use Addressable\Bundle\AddressableBundle\Service\GeoSpatialService;
class RestaurantController
{
public function __construct(private GeoSpatialService $geoSpatial)
{
}
public function nearbyRestaurants(Request $request)
{
$latitude = $request->query->get('lat');
$longitude = $request->query->get('lng');
$radius = $request->query->get('radius', 10); // km
$restaurants = $this->geoSpatial->findNearby(
Restaurant::class,
$latitude,
$longitude,
$radius
);
return $this->render('restaurants/index.html.twig', [
'restaurants' => $restaurants,
]);
}
}
Calculate distances between two addressable entities:
$distance = $this->geoSpatial->distance(
$entity1,
$entity2
); // Returns distance in kilometers
Sort a collection of entities by their distance to a given point:
$sortedRestaurants = $this->geoSpatial->sortByDistance(
$restaurants,
$latitude,
$longitude
);
Address entity, configure a custom one in config/packages/addressable.yml:
addressable:
address_entity: App\Entity\CustomAddress
lat/lng) in your entity annotations:
/**
* @Addressable(latitudeField="custom_lat", longitudeField="custom_lng")
*/
class Event {}
@Addressable/Form/fields.html.twig) to add custom behavior (e.g., default markers, API keys).$form = $this->createFormBuilder($entity)
->add('address', AddressType::class, [
'google_maps_api_key' => 'YOUR_API_KEY',
'default_lat' => 40.7128,
'default_lng' => -74.0060,
])
->getForm();
latitude/longitude fields are indexed for performance:
/**
* @ORM\Column(type="decimal", scale=10, precision=13)
* @ORM\Index(columns={"latitude", "longitude"})
*/
private $latitude;
Outdated Dependencies
symfony/form, doctrine/orm) if needed.Google Maps API Key
config/packages/addressable.yml:
addressable:
google_maps_api_key: 'YOUR_KEY'
Precision Issues
decimal(13,10). Ensure your database supports this precision (e.g., MySQL’s DECIMAL type).scale=10 and precision=13 to avoid rounding errors during calculations.Doctrine DQL Limitations
GeoSpatialService uses raw SQL for distance calculations (e.g., Haversine formula). Complex queries may hit performance limits.Entity Generation Overwrite
addressable:generate again may overwrite your entity’s address fields. Backup or use --dry-run to preview changes.Form Not Rendering
form_themes is correctly configured in Twig. Clear the cache if needed:
php bin/console cache:clear
Distance Calculations Returning null
latitude/longitude fields are populated and valid (e.g., -90 <= lat <= 90, -180 <= lng <= 180).GeoSpatialService:
$query = $this->geoSpatial->createNearbyQuery(...);
dump($query->getSQL());
Performance Issues
latitude/longitude fields if queries are slow.GIS functions).Extend the Address Entity
Add custom fields to the Address entity (e.g., formattedAddress, country) to store additional data from the Google Maps API:
/**
* @ORM\Column(type="text", nullable=true)
*/
private $formattedAddress;
Custom Distance Units
Modify the GeoSpatialService to return distances in miles instead of kilometers by overriding the distance method or creating a decorator.
Validation
Add validation constraints to latitude/longitude:
use Symfony\Component\Validator\Constraints as Assert;
/**
* @Assert\Type("numeric")
* @Assert\GreaterThanOrEqual(-90)
* @Assert\LessThanOrEqual(90)
*/
private $latitude;
Testing
Mock the GeoSpatialService in tests to avoid external dependencies:
$geoSpatial = $this->createMock(GeoSpatialService::class);
$geoSpatial->method('distance')->willReturn(1.5);
$this->entityManager->getRepository(Restaurant::class)->setGeoSpatial($geoSpatial);
Fallback for Offline Use Provide a fallback mechanism (e.g., static lat/lng) when the Google Maps API is unavailable:
{% if form.address.vars.data.google_maps_error %}
<p>Google Maps unavailable. Using default location.</p>
{% endif %}
How can I help you explore Laravel packages today?