5633969d98
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>
131 lines
5.0 KiB
PHP
131 lines
5.0 KiB
PHP
<?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);
|
||
}
|