chill-bundles/src/Bundle/ChillMainBundle/Service/Import/PostalCodeFRFromOpenData.php

93 lines
2.7 KiB
PHP

<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\MainBundle\Service\Import;
use League\Csv\Reader;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
* Load French's postal codes from opendata.
*
* Currently, the source is datanova / la poste:
* https://datanova.legroupe.laposte.fr/explore/dataset/laposte_hexasmal/information/
*/
class PostalCodeFRFromOpenData
{
private const CSV = 'https://datanova.laposte.fr/data-fair/api/v1/datasets/laposte-hexasmal/data-files/019HexaSmal.csv';
public function __construct(private readonly PostalCodeBaseImporter $baseImporter, private readonly HttpClientInterface $client, private readonly LoggerInterface $logger)
{
}
public function import(): void
{
$response = $this->client->request('GET', self::CSV);
if (200 !== $response->getStatusCode()) {
throw new \RuntimeException('could not download CSV');
}
$tmpfile = tmpfile();
if (false === $tmpfile) {
throw new \RuntimeException('could not create temporary file');
}
foreach ($this->client->stream($response) as $chunk) {
fwrite($tmpfile, $chunk->getContent());
}
fseek($tmpfile, 0);
$csv = Reader::createFromStream($tmpfile);
$csv->setDelimiter(';');
$csv->setHeaderOffset(0);
foreach ($csv as $offset => $record) {
$this->handleRecord($record);
}
$this->baseImporter->finalize();
fclose($tmpfile);
$this->logger->info(self::class.' postal code fetched', ['offset' => $offset ?? 0]);
}
private function handleRecord(array $record): void
{
if ('' !== trim($record['coordonnees_geographiques'] ?? $record['coordonnees_gps'])) {
[$lat, $lon] = array_map(static fn ($el) => (float) trim($el), explode(',', $record['coordonnees_geographiques'] ?? $record['coordonnees_gps']));
} else {
$lat = $lon = 0.0;
}
$ref = trim((string) $record['Code_commune_INSEE']);
if (str_starts_with($ref, '987')) {
// some differences in French Polynesia
$ref .= '.'.trim((string) $record['Libellé_d_acheminement']);
}
$this->baseImporter->importCode(
'FR',
trim((string) $record['Libellé_d_acheminement']),
trim((string) $record['Code_postal']),
$ref,
'INSEE',
$lat,
$lon,
4326
);
}
}