| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- <?php
- require_once "libs/fnMain.php";
- /**************************
- * VALIDATION DES DONNEES
- **************************/
- $isClassementValid = isset($_GET["classement"]) && (int) $_GET["classement"] !== 0;
- $isTriVilleValid = isset($_GET["v"]) && is_array($_GET["v"]) && $_GET["v"] !== [];
- $isTriSpeValid = isset($_GET["s"]) && is_array($_GET["s"]) && $_GET["s"] !== [];
- $specialitySourceDatasetAbrev = getCsvToArrayKeyValue($_SETTINGS["datasetFolder"]."/liste_specialites_abrev.csv");
- $specialitySourceDataset = getCsvToArrayKeyValue($_SETTINGS["datasetFolder"]."/liste_specialites.csv");
- $citySourceDataset = getCsvToArrayKeyValue($_SETTINGS["datasetFolder"]."/liste_villes.csv");
- /**************************
- * Affichage du formulaire
- **************************/
- ?>
- <!doctype html>
- <html lang="fr">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport"
- content="width=device-width, initial-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>RangLimier</title>
- <link rel="icon" type="image/png" href="assets/favicon.png">
- <link rel="stylesheet" href="assets/fonts/material-icons.min.css">
- <link rel="stylesheet" href="assets/bootstrap.min.css">
- <link rel="stylesheet" href="assets/divers.css">
- <!-- Font Awesome icons (free version)-->
- <script src="https://use.fontawesome.com/releases/v5.15.1/js/all.js" crossorigin="anonymous"></script>
- <!-- Google fonts-->
- <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet" type="text/css" />
- <link href="https://fonts.googleapis.com/css?family=Lato:400,700,400italic,700italic" rel="stylesheet" type="text/css" />
-
- </head>
- <body>
- <div id="navbar">
- <nav id="mainNav" class="navbar navbar-expand-lg text-uppercase sticky-top">
- <div class="container">
- <a href="https://asclepia.io/" class="navbar-brand">
- <!-- <div class="text-lowercase" style="font-family: no-name;">asclepia</div> -->
- <img alt="Logo Asclepia" src="assets/logo-desktop.svg" decoding="async" style="width: 150%;">
- </a>
- <button type="button" data-toggle="collapse" data-target="#navbarResponsive"
- aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"
- class="navbar-toggler navbar-toggler-right text-uppercase font-weight-bold bg-primary text-white rounded collapsed">
- Menu
- <svg class="svg-inline--fa fa-bars fa-w-14" aria-hidden="true" focusable="false"
- data-prefix="fas" data-icon="bars" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"
- data-fa-i2svg="">
- <path fill="currentColor"
- d="M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"></path>
- </svg>
- </button>
- <div id="navbarResponsive" class="navbar-collapse collapse" style="">
- <ul class="navbar-nav ml-auto">
- <li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href="https://ranglimier.asclepia.io/">Rang Limier</a></li>
- <?php // <!-- <li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href="https://dispo.asclepia.io/">Easy Dispo</a></li> -->
- ?>
- <li class="nav-item mx-0 mx-lg-1">
- <a href="https://app.asclepia.io/login" class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger">Se connecter</a>
- </li>
- <li class="nav-item mx-0 mx-lg-1">
- <a href="https://app.asclepia.io/sign-up" class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger">Découvrir</a>
- </li>
- </ul>
- </div>
- </div>
- </nav>
- </div>
- <div id="rangLimier"><div class="container">
- <br>
- <h1 style="text-align: left;">RangLimier</h1>
- <p>Cet outil permet d'apprécier les choix de postes accessibles pour un rang de classement donné sur les années post-R3C (à partir des ECNi 2017).
- Il ne réalise pas d'ajustements pour le nombre total d'étudiants au niveau national, dont les tendances sont à l'augmentation.<br>
- Sur un seul tableau, qu'il est possible de restreindre à certains DES et/ou certaines subdivisions, est affiché, dans chaque case, le nombre d'années où le poste aurait été accessible.
- </p>
- <ul>
- <li>En rouge, les postes n'ayant jamais été accessible.</li>
- <li>En jaune, les postes ayant été accessible sur au moins une fois, mais pas tous les ans.</li>
- <li>En vert, les postes ayant été accessible tous les ans.</li>
- <li>En remplissage bleu marine, les postes n'ayant jamais été proposés.</li>
- </ul>
- <p>
- Un survol d’une cellule fait apparaître une info-bulle avec le classement auquel l’étudiant aurait pu prétendre pour chaque année. Lorsqu’il n’y a pas d’information dans l’info-bulle pour une année, c’est qu’il n’y avait aucun poste proposé la même année.
- </p>
- <p>
- ⚠ <i> Ces informations sont données à titre indicatif et ne peuvent constituer une quelconque garantie pour les procédures de choix à venir.</i>
- <br>
- <i>Toutes les données utilisées par cet outil proviennent du site <a href="https://www.cng.sante.fr/">cng.sante.fr</a> et de son application
- <a href="https://www.cngsante.fr/chiron/celine/">CELINE</a>. Pour toute information officielle, veuillez vous référer à ces derniers.</i>
- </p>
- <form action="index.php" method="get" class="d-flex flex-column align-items-left">
- <div class="form-group row align-items-center">
- <label for="classement" class="col-sm-3">Saisissez un rang de classement : </label>
- <div class="col-sm-1">
- <input type="text" required name="classement" class="form-control rounded-pill" <?= ($isClassementValid === TRUE) ? 'value='.(int) $_GET["classement"] : "" ?>>
- </div>
- </div>
- <div class="d-flex flex-column flex-sm-row">
- <div class="form-group align-item-center" style="margin-right: 10px;">
- <label for="triSpe">Restreindre aux DES suivants : </label> <br>
- <select name="s[]" id="triSpe" multiple size="7" class="form-control rounded">
- <?php
- if ($isTriSpeValid) { $selectedSpeId = array_flip($_GET['s']); }
- foreach ($specialitySourceDataset as $speId => $speName) : ?>
- <option
- <?= (isset($selectedSpeId[$speId])) ? "selected " : "" ?>
- value="<?= $speId ?>">
- <?= $specialitySourceDatasetAbrev[$speId]." - ".$speName ?>
- </option>
- <?php endforeach; ?>
- </select>
- </div>
- <div class="form-group align-item-center">
- <label for="triVille">Restreindre aux subdivisions suivantes : </label> <br>
- <select name="v[]" id="triVille" multiple size="7" class="form-control rounded">
- <?php
- if ($isTriVilleValid) { $selectedVilleId = array_flip($_GET['v']); }
- foreach ($citySourceDataset as $cityId => $cityName) :
- if ($cityName !== "XX") : ?>
- <option
- <?= (isset($selectedVilleId[$cityId])) ? "selected " : "" ?>
- value="<?= $cityId ?>">
- <?= $cityName ?>
- </option>
- <?php endif; endforeach; ?>
- </select>
- </div>
- </div>
- <i>Utiliser Ctrl/Command + Clic pour (dé)sélectionner plusieurs options sur PC/Mac</i> <br>
- <button type="submit" class="btn btn-info rounded-pill col-sm-2" >Envoyer !</button>
- </form>
- </div>
- <?php if ($isClassementValid) : ?>
- <!--
- <hr><h1>Tableau de classement</h1>
- <h2>Légende</h2>
- <table>
- <thead>
- <th colspan="5" style="text-align: center;">Légende (sur toutes les années)</th>
- </thead>
- <tbody>
- <tr>
- <td class="never-available">Jamais proposé</td>
- <td class="no-choice">Aucun choix</td>
- <td class="half-choices">Plusieurs choix</td>
- <td class="all-choices">Tous les choix</td>
- </tr>
- </tbody>
- </table>
- <p>
- Chaque nombre dans chaque case correspond au nombre d'années où ce choix était dispo au classement rentré <br>
- </p> -->
-
- <?php
- $html = '<div class="container"><i>Glissez ce lien dans vos favoris pour retrouver cette recherche rapidement : <a href="'.$_SERVER['REQUEST_URI'].'">Recherche RangLimier</i></a></div>';
- $html .= "<br><div class='row justify-content-center'><div class='col-auto'>";
-
- // On va récupérer tous les rangs limited dispo triés par idChoix
- //Mysql
- $reqRL = $db->query('SELECT idChoix, annee, rangLimite FROM dataset');
- //pgsql
- // $reqRL = $db->query('SELECT dataset."idChoix", annee, dataset."rangLimite" FROM dataset');
-
- $rangLimites = $reqRL->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_ASSOC);
- $inputClassement = (int) $_GET["classement"];
-
- //////////////////////////////////
- // Calcul et affichage des données
- //////////////////////////////////
- // v2.A Conversion du filtre spé/ville de l'utilisateur
- // On croise l'array source de données avec les id sélectionnés via le GET (ce qui sécurise les données en plus)
- // array_intersect_key(array_source, clés_à_garder)
- // Si pas de filtre sélectionné, bah on prend toutes les spé/villes disponibles
- $cityDataset = ($isTriVilleValid === TRUE) ? array_intersect_key($citySourceDataset, array_flip($_GET["v"])) : $citySourceDataset;
- $specialityDatasetAbrev = ($isTriSpeValid === TRUE) ? array_intersect_key($specialitySourceDatasetAbrev, array_flip($_GET["s"])) : $specialitySourceDatasetAbrev;
- $specialityDataset = ($isTriSpeValid === TRUE) ? array_intersect_key($specialitySourceDataset, array_flip($_GET['s'])) : $specialitySourceDataset;
-
- // v2. Calcul des rangs potentiels pour chaque année simulée
- // Requete sélectionnant le nombre de personnes ayant choisi avant le classement X
- $sql = "SELECT idChoix, COUNT(*) as nb_perso_avant
- FROM anciens_choix
- WHERE classement < :classement AND annee = :annee
- GROUP BY idChoix";
- // pgSQL
- /* $sql = 'SELECT anciens_choix."idChoix", COUNT(*) as nb_perso_avant
- FROM anciens_choix
- WHERE classement < :classement AND annee = :annee
- GROUP BY anciens_choix."idChoix"'; */
- $reqAnciensChoixPourClassementX = $db->prepare($sql);
-
- // Requete sélectionnant le nombre total de personnes à chaque choix
- $sql = "SELECT idChoix, COUNT(*) as nb_perso_total
- FROM anciens_choix
- WHERE annee = :annee
- GROUP BY idChoix";
- // pgSQL
- /* $sql = 'SELECT anciens_choix."idChoix", COUNT(*) as nb_perso_total
- FROM anciens_choix
- WHERE annee = :annee
- GROUP BY anciens_choix."idChoix"'; */
- $reqAnciensChoixNbPostes = $db->prepare($sql);
-
- $nbAncienChoixParAn = [];
- $nbPersChoixAvant = [];
- // On détermine les années simulées : 2017 à année actuelle - 1, et on récupère les données pour les gens avant ce classement
- for ($annee = 2017; $annee <= (int) date("Y") - 1 ; $annee++) {
- // On formate les données pour le nombre de postes avant le classement (pour l'intégrer à tous les postes après)
- $reqAnciensChoixPourClassementX->execute([
- "annee" => $annee,
- "classement" => $inputClassement
- ]);
- $nbChoixAnneeI = $reqAnciensChoixPourClassementX->fetchAll();
- foreach ($nbChoixAnneeI as $nbPostesItem) {
- $nbPersChoixAvant[$annee][$nbPostesItem['idChoix']] = $nbPostesItem['nb_perso_avant'];
- }
-
- // On formate les données pour position dans promo et nombres de postes
- $reqAnciensChoixNbPostes->execute(["annee" => $annee]);
- $nbPostesRaw = $reqAnciensChoixNbPostes->fetchAll();
- foreach ($nbPostesRaw as $choix) {
- $nbAncienChoixParAn[$choix["idChoix"]][$annee] = [
- "position" => (isset ($nbPersChoixAvant[$annee][$choix['idChoix']])) ? $nbPersChoixAvant[$annee][$choix['idChoix']] + 1 : 1,
- "nbPostesTotal" => $choix["nb_perso_total"]
- ];
- }
- }
- unset($reqAnciensChoixNbPostes, $reqAnciensChoixPourClassementX, $nbPersChoixAvant);
-
- // Affichage de la 1ère ligne = Titre des colonnes + infobulles (via BootstrapJS)
- $html .= "<table><thead><tr><th></th>";
- foreach ($specialityDatasetAbrev as $speId => $specialityName) {
- // $html .= "<th scope='col'>".$specialityName."</th>";
- $html .= "<th scope='col' data-toggle='tooltip' data-placement='bottom' title='".$specialitySourceDataset[$speId]."'>".$specialityName."</th>";
- }
- $html .= "</tr></thead><tbody>";
-
- // Affichage de la suite du tableau avec le calcul
- foreach ($cityDataset as $cityId => $cityName) {
- // On gère la séparation des différentes régions entre elles (représentées dans le csv villes par les lignes XX_:XX)
- // La notation des lignes de séparation est sous forme XX_x car si on laissait XX, la fonction getCsvToArrayKeyValue
- // ne retourne la position que pour la 1ère occurence de XX;XX
- // La manière de fix ça de manière la plus opti et sale, c'est de faire un substr et de tester les 2 premiers charactères
- // si ils sont égaux à XX, on fait une séparation
- if (strpos($cityId, "XX") !== FALSE) {
- $html .= "<tr><th></th>";
- foreach ($specialityDatasetAbrev as $speId => $specialityName) {
- $html .= "<th scope='col' data-toggle='tooltip' data-placement='bottom' title='".$specialitySourceDataset[$speId]."'>".$specialityName."</th>";
- }
- $html .= "</th>";
- continue;
- }
-
- $html .= "<tr><th scope='row'>".$cityName."</th>";
- foreach ($specialityDatasetAbrev AS $specialityId => $specialityName) {
- $idChoice = "0".$cityId.$specialityId;
- $tooltip = FALSE;
- $tooltipContent = "";
-
- if (!isset($rangLimites[$idChoice])) {
- $nbAnneePropose = 0;
- $nbPossibleAnneePropose = 0;
- } else {
- $nbAnneePropose = count($rangLimites[$idChoice]);
- $nbPossibleAnneePropose = 0;
- $tooltip = TRUE; // Autorise l'insertion des données de la tooltip
- foreach ($rangLimites[$idChoice] as $rangLimite) {
- if ((int) $rangLimite["rangLimite"] >= $inputClassement) {
- $nbPossibleAnneePropose++;
-
- // Gestion du contenu de la tooltip
- if(isset($nbAncienChoixParAn[$idChoice][$rangLimite["annee"]])) { // Cas où il reste de la place
- $temp = $nbAncienChoixParAn[$idChoice][$rangLimite["annee"]];
- $tooltipContent .= $rangLimite["annee"]." : ".$temp["position"]."/".$temp["nbPostesTotal"] ."<br>";
- } else { // Cas où le choix n'a pas été pourvu (donc y'a personne dans les anciens choix)
- $tooltipContent .= $rangLimite["annee"]." : Disponible<br>";
- }
- } else { // Cas où le choix était impossible cette année
- $tooltipContent .= $rangLimite["annee"]." : Non disponible<br>";
- }
- }
- }
-
- // Affichage de la cellule
- $html .= "<td ";
- $html .= ($tooltip === TRUE) ? "data-toggle='tooltip' data-placement='bottom' data-html='true' " : "";
- $html .= " class=\"";
- switch (TRUE) {
- case ($nbPossibleAnneePropose === 0 && $nbAnneePropose === 0):
- $html .= "never-available";
- break;
-
- case ($nbPossibleAnneePropose === 0):
- $html .= "no-choice";
- break;
-
- case ($nbAnneePropose > $nbPossibleAnneePropose && $nbPossibleAnneePropose === 1):
- $html .= "last-choice";
- break;
-
- case ($nbAnneePropose > $nbPossibleAnneePropose && $nbPossibleAnneePropose !== 1):
- $html .= "half-choices";
- break;
-
- case ($nbAnneePropose === $nbPossibleAnneePropose):
- $html .= "all-choices";
- break;
- }
- $html .= "\" ";
- $html .= ($tooltip === TRUE) ? "title='".$tooltipContent."'" : "";
- $html .= ">";
- if ($nbPossibleAnneePropose > 0) {
- $html .= $nbPossibleAnneePropose;
- } else if ($nbPossibleAnneePropose === 0 && $nbAnneePropose !== 0) {
- $html .= "0";
- }
- $html .= "</td>";
- }
- $html .= "</tr>";
- }
-
- $html .= "</tbody></table></div></div><br>";
- echo $html;
- ?>
- <table>
- </table>
- <?php endif;?>
- </div>
- <div style="text-align: center; font-weight: 700;">
- Copyright © 2021 MH2V SAS. Tous droits réservés.
- </div>
- <!-- Bootstrap core JS-->
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"></script>
- <script>
- $(function () {
- $('[data-toggle="tooltip"]').tooltip()
- })
- </script>
- </body>
- </html>
|