aldaflux/photon-osm-connector-bundle
Install the Bundle
composer require aldaflux/photon-osm-connector-bundle
Enable the bundle in config/bundles.php:
return [
// ...
Aldaflux\PhotonOsmConnectorBundle\AldafluxPhotonOsmConnectorBundle::class => ['all' => true],
];
Configure API Key
Add your Photon API key to .env:
PHOTON_API_KEY=your_api_key_here
Publish the default config (if needed):
php bin/console config:dump-reference AldafluxPhotonOsmConnectorBundle
First Use Case: Fetch Coordinates
Inject the PhotonClient service and call the simplest endpoint:
use Aldaflux\PhotonOsmConnectorBundle\Service\PhotonClient;
class MyController extends AbstractController {
public function __construct(private PhotonClient $photon) {}
public function searchCoordinates(): Response {
$response = $this->photon->search('Berlin, Germany');
return $this->json($response);
}
}
Searching Locations
Use the search() method for geocoding:
$results = $photon->search('Paris, France', [
'limit' => 5,
'bounded' => true,
]);
Reverse Geocoding Convert coordinates to addresses:
$address = $photon->reverse([
'lat' => 52.5200,
'lon' => 13.4050,
]);
Route Planning Fetch routes between coordinates:
$route = $photon->route([
'start' => ['lat' => 52.5200, 'lon' => 13.4050],
'end' => ['lat' => 48.8566, 'lon' => 2.3522],
]);
Integration with Doctrine
Use the PhotonResult DTOs in entities:
use Aldaflux\PhotonOsmConnectorBundle\Model\PhotonResult;
#[ORM\Entity]
class Location {
#[ORM\Column(type: 'json')]
private PhotonResult $photonData;
}
Caching Responses
Decorate PhotonClient to cache responses (e.g., with Symfony Cache):
$client = new CachedPhotonClient($photon, $cachePool);
Batch Processing Loop through results for large datasets:
$results = $photon->search('Germany', ['limit' => 100]);
foreach ($results as $result) {
// Process each result
}
Error Handling Use exceptions for API failures:
try {
$data = $photon->search('Invalid Query');
} catch (PhotonApiException $e) {
$this->addFlash('error', $e->getMessage());
}
API Key Validation
$this->photon->ping(); // Throws exception if key is invalid
Rate Limits
use Symfony\Component\Stopwatch\Stopwatch;
$stopwatch = new Stopwatch();
$event = $stopwatch->start('photon_request');
try {
$response = $photon->search('...');
} catch (RateLimitExceededException $e) {
$event->stop();
$wait = min(10, $event->getDuration() * 1.5); // Exponential backoff
sleep($wait);
retry();
}
Pagination Quirks
limit parameter is not always respected. Use offset for large datasets:
$results = $photon->search('Berlin', ['limit' => 50, 'offset' => 0]);
Data Structure Changes
PhotonResult DTOs to avoid breaking changes:
$result = $photon->search('...');
$lat = $result->getGeometry()->getCoordinates()[0]; // Safe access
Enable API Logging
Configure Monolog in config/packages/monolog.yaml:
handlers:
photon:
type: stream
path: "%kernel.logs_dir%/photon.log"
level: debug
channels: ["photon"]
Then enable the channel in PhotonClient:
$photon = new PhotonClient($client, ['logger' => $logger->channel('photon')]);
Test with Mocks
Use PhotonClientInterface to mock responses in tests:
$mock = $this->createMock(PhotonClientInterface::class);
$mock->method('search')->willReturn([new PhotonResult()]);
$this->container->set(PhotonClientInterface::class, $mock);
Custom Endpoints
Extend PhotonClient to add unsupported endpoints:
class CustomPhotonClient extends PhotonClient {
public function isochrone(array $params): array {
return $this->request('isochrone', $params);
}
}
Response Transformers
Override PhotonResult to customize data mapping:
class CustomPhotonResult extends PhotonResult {
public function getFormattedAddress(): string {
return $this->getProperties()['display_name'] ?? '';
}
}
Event Listeners
Subscribe to photon.response events to modify responses:
$dispatcher->addListener('photon.response', function (PhotonResponseEvent $event) {
$event->setData(array_merge($event->getData(), ['custom_field' => true]));
});
How can I help you explore Laravel packages today?