Files
ecoles/api/population.php
T
Arnaud 5633969d98 Version initiale — carte des établissements scolaires
Carte Leaflet (annuaire Éducation nationale) + API PHP/MySQL :
fiche établissement (effectifs, IPS, population INSEE, DPE ADEME),
GED documents/photos, commentaires par groupe, gestion utilisateurs
et politique de mots de passe. Imports opendata (effectifs, IPS,
population, DPE, IRIS).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 21:35:41 +02:00

131 lines
5.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Historique de la population municipale (INSEE) de la zone d'un établissement.
* GET ?uai=UAI → { zone: [{annee,pop},…], zone_estimated: bool, ville: [...]|null, ville_nom }
*
* « zone » = commune, ou arrondissement pour Paris/Lyon/Marseille (code INSEE comc de
* l'établissement). Pour un arrondissement, « ville » donne en plus la courbe historique
* de la ville entière. Sinon « ville » est null.
*
* Lyon/Marseille n'ont pas d'historique INSEE par arrondissement : « zone » est alors
* ESTIMÉE (zone_estimated=true) = population de la ville × part de l'arrondissement dans
* les IRIS du recensement 2022 (iris_pop).
*
* Source : pop_commune (cf. import_pop_hist.php), prolongée à 2022 via iris_pop.
*/
declare(strict_types=1);
require __DIR__ . '/db.php';
/**
* Ville entière pour un arrondissement Paris/Lyon/Marseille :
* [ codes pop_commune (historique), codes iris_pop (point 2022), nom ] — ou null.
* Paris n'a pas de code commune unique dans pop_commune : on somme les arrondissements.
*/
function plm_ville(string $comc): ?array
{
$i = (int) $comc;
$codes = static fn(int $a, int $b) => array_map('strval', range($a, $b));
if ($i >= 13201 && $i <= 13216) return [['13055'], $codes(13201, 13216), 'Marseille'];
if ($i >= 69381 && $i <= 69389) return [['69123'], $codes(69381, 69389), 'Lyon'];
if ($i >= 75101 && $i <= 75120) return [$codes(75101, 75120), $codes(75101, 75120), 'Paris'];
return null;
}
/** Somme des populations IRIS (recensement 2022) pour une liste de codes commune/arrondissement. */
function iris_sum(array $codes): float
{
if (!$codes) {
return 0.0;
}
$ph = implode(',', array_fill(0, count($codes), '?'));
$st = db()->prepare("SELECT SUM(pop) FROM iris_pop WHERE com IN ($ph)");
$st->execute(array_map('strval', $codes));
return (float) $st->fetchColumn();
}
/**
* Construit une série [{annee,pop}] : somme de pop_commune sur $histCodes (par année),
* prolongée à 2022 par la somme d'iris_pop sur $irisCodes.
*/
function pop_series(bool $hasHist, bool $hasIris, array $histCodes, array $irisCodes): array
{
$out = [];
$hasYear = [];
if ($hasHist && $histCodes) {
$ph = implode(',', array_fill(0, count($histCodes), '?'));
$st = db()->prepare("SELECT annee, SUM(pop) AS pop FROM pop_commune WHERE comc IN ($ph) GROUP BY annee ORDER BY annee");
$st->execute($histCodes);
foreach ($st as $r) {
$y = (int) $r['annee'];
$out[] = ['annee' => $y, 'pop' => (int) $r['pop']];
$hasYear[$y] = true;
}
}
if ($hasIris && $irisCodes && empty($hasYear[2022])) {
$ph = implode(',', array_fill(0, count($irisCodes), '?'));
$p = db()->prepare("SELECT ROUND(SUM(pop)) FROM iris_pop WHERE com IN ($ph)");
$p->execute($irisCodes);
$v = $p->fetchColumn();
if ($v !== null && $v !== false && (float) $v > 0) {
$out[] = ['annee' => 2022, 'pop' => (int) $v];
}
}
usort($out, static fn($a, $b) => $a['annee'] - $b['annee']);
return $out;
}
try {
$uai = trim((string) ($_GET['uai'] ?? ''));
if ($uai === '') {
json_error('Paramètre uai requis.');
}
$hasHist = (bool) db()->query("SHOW TABLES LIKE 'pop_commune'")->fetchColumn();
$hasIris = (bool) db()->query("SHOW TABLES LIKE 'iris_pop'")->fetchColumn();
if (!$hasHist && !$hasIris) {
json_out(['zone' => [], 'ville' => null, 'ville_nom' => null]);
}
$e = db()->prepare('SELECT comc FROM etablissements WHERE id = ?');
$e->execute([$uai]);
$comc = $e->fetchColumn();
if (!$comc) {
json_out(['zone' => [], 'ville' => null, 'ville_nom' => null]);
}
$comc = (string) $comc;
// Zone = commune ou arrondissement (code de l'établissement directement).
$zone = pop_series($hasHist, $hasIris, [$comc], [$comc]);
// Ville entière (seulement pour un arrondissement PLM).
$ville = null;
$villeNom = null;
$estimated = false;
if ($plm = plm_ville($comc)) {
[$histCodes, $irisCodes, $villeNom] = $plm;
$ville = pop_series($hasHist, $hasIris, $histCodes, $irisCodes);
// Si l'arrondissement n'a pas d'historique propre (Lyon/Marseille), on l'ESTIME :
// population de la ville × part de l'arrondissement dans les IRIS (recensement 2022).
if (count($zone) < 2 && $ville && $hasIris) {
$arrIris = iris_sum([$comc]);
$cityIris = iris_sum($irisCodes);
if ($arrIris > 0 && $cityIris > 0) {
$share = $arrIris / $cityIris;
$zone = array_map(
static fn(array $p) => ['annee' => $p['annee'], 'pop' => (int) round($p['pop'] * $share)],
$ville
);
$estimated = true;
}
}
}
json_out([
'zone' => $zone,
'zone_estimated' => $estimated,
'ville' => $ville,
'ville_nom' => $villeNom,
]);
} catch (Throwable $e) {
json_error('Erreur : ' . $e->getMessage(), 500);
}