osm-commerces/src/Command/CreateMissingCommunesStatsCommand.php
Tykayn 8cfea30fdf commande pour créer des stats de toutes les villes insee
# Conflicts:
#	src/Command/ProcessLabourageQueueCommand.php
#	src/Controller/PublicController.php
2025-08-08 18:13:46 +02:00

194 lines
No EOL
7.2 KiB
PHP

<?php
namespace App\Command;
use App\Entity\CityFollowUp;
use App\Entity\Stats;
use App\Repository\StatsRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
#[AsCommand(
name: 'app:create-missing-communes-stats',
description: 'Create Stats objects for missing communes using data from cities_insee.csv',
)]
class CreateMissingCommunesStatsCommand extends Command
{
private const CSV_PATH = '/home/poule/encrypted/stockage-syncable/www/development/html/osm-commerce-sf/counting_osm_objects/cities_insee.csv';
// List of themes to create CityFollowUp measurements for
private const THEMES = [
'charging_station',
'defibrillator',
'shop',
'amenity',
// Add more themes as needed
];
private EntityManagerInterface $entityManager;
private StatsRepository $statsRepository;
public function __construct(
EntityManagerInterface $entityManager,
StatsRepository $statsRepository
) {
parent::__construct();
$this->entityManager = $entityManager;
$this->statsRepository = $statsRepository;
}
protected function configure(): void
{
$this
->addOption('limit', 'l', InputOption::VALUE_REQUIRED, 'Limit the number of communes to process', 0)
->addOption('dry-run', null, InputOption::VALUE_NONE, 'Simulate without modifying the database');
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output);
$io->title('Creating Stats objects for missing communes');
$limit = (int) $input->getOption('limit');
$dryRun = $input->getOption('dry-run');
// Check if CSV file exists
if (!file_exists(self::CSV_PATH)) {
$io->error('CSV file not found: ' . self::CSV_PATH);
return Command::FAILURE;
}
// Read CSV file
$io->info('Reading CSV file: ' . self::CSV_PATH);
$communes = $this->readCsvFile(self::CSV_PATH);
$io->info(sprintf('Found %d communes in CSV file', count($communes)));
// Get existing Stats objects
$existingStats = $this->statsRepository->findAll();
$existingZones = [];
foreach ($existingStats as $stats) {
$existingZones[$stats->getZone()] = true;
}
$io->info(sprintf('Found %d existing Stats objects', count($existingZones)));
// Find missing communes
$missingCommunes = [];
foreach ($communes as $commune) {
if (!isset($existingZones[$commune['code_insee']])) {
$missingCommunes[] = $commune;
}
}
$io->info(sprintf('Found %d missing communes', count($missingCommunes)));
// Apply limit if specified
if ($limit > 0 && count($missingCommunes) > $limit) {
$io->info(sprintf('Limiting to %d communes', $limit));
$missingCommunes = array_slice($missingCommunes, 0, $limit);
}
// Create Stats objects for missing communes
$created = 0;
$now = new \DateTime();
foreach ($missingCommunes as $commune) {
$io->text(sprintf('Processing commune: %s (%s)', $commune['nom_standard'], $commune['code_insee']));
if (!$dryRun) {
// Create new Stats object
$stats = new Stats();
$stats->setZone($commune['code_insee']);
$stats->setName($commune['nom_standard']);
// Handle population - convert empty string to null or cast to int
$population = $commune['population'] !== '' ? (int) $commune['population'] : null;
$stats->setPopulation($population);
$stats->setDateCreated($now);
$stats->setKind('command'); // Set the kind to 'command'
// Set coordinates if available and not empty
if (isset($commune['latitude_centre']) && isset($commune['longitude_centre'])) {
// Convert empty strings to null for numeric fields
$lat = $commune['latitude_centre'] !== '' ? $commune['latitude_centre'] : null;
$lon = $commune['longitude_centre'] !== '' ? $commune['longitude_centre'] : null;
$stats->setLat($lat);
$stats->setLon($lon);
}
// Create CityFollowUp measurements for each theme
foreach (self::THEMES as $theme) {
// Create a basic measurement with a default value
// In a real scenario, you would fetch actual data for each theme
$followUp = new CityFollowUp();
$followUp->setName($theme . '_count');
$followUp->setMeasure(0); // Default value, should be replaced with actual data
$followUp->setDate($now);
$followUp->setStats($stats);
$this->entityManager->persist($followUp);
}
$this->entityManager->persist($stats);
$created++;
// Flush every 20 entities to avoid memory issues
if ($created % 20 === 0) {
$this->entityManager->flush();
$this->entityManager->clear(Stats::class);
$this->entityManager->clear(CityFollowUp::class);
$io->text(sprintf('Flushed after creating %d Stats objects', $created));
}
} else {
$created++;
}
}
// Final flush
if (!$dryRun && $created > 0) {
$this->entityManager->flush();
}
if ($dryRun) {
$io->success(sprintf('Dry run completed. Would have created %d Stats objects for missing communes.', $created));
} else {
$io->success(sprintf('Created %d Stats objects for missing communes.', $created));
}
return Command::SUCCESS;
}
/**
* Read CSV file and return an array of communes
*/
private function readCsvFile(string $path): array
{
$communes = [];
if (($handle = fopen($path, 'r')) !== false) {
// Read header
$header = fgetcsv($handle, 0, ',');
if ($header === false) {
return [];
}
// Read data
while (($row = fgetcsv($handle, 0, ',')) !== false) {
$commune = [];
foreach ($header as $i => $key) {
$commune[$key] = $row[$i] ?? '';
}
$communes[] = $commune;
}
fclose($handle);
}
return $communes;
}
}