Subversion Repositories eFlore/Projets.eflore-projets

Rev

Rev 1029 | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
//declare(encoding='UTF-8');
/**
 * Exemple de lancement du script : :
 * /opt/lampp/bin/php cli.php apd -a chargerTous
 * 
 * Base de données des Trachéophytes (trachéo...quoi ?? C'est le truc avec le stylo Bic ?)
 * d'Afrique de l'Ouest (et Centrale mais faut pas le dire)
 *
 * @category    php 5.2
 * @package             eFlore/Scripts
 * @author              Mathias CHOUET <mathias@tela-botanica.org>
 * @copyright   Copyright (c) 2014, Tela Botanica (accueil@tela-botanica.org)
 * @license             http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
 * @license             http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
 */
class Apd extends EfloreScript {

        private $table = null;
        private $tableMeta = null;
        private $pasInsertion = 1000;
        private $departInsertion = 0;

        protected $parametres_autorises = array();

        // Entêtes du nouveau fichier Rtax à produire
        protected $entetesRtax = array("num_nom","num_nom_retenu","num_tax_sup","rang","nom_sci",
                "nom_supra_generique","genre","epithete_infra_generique","epithete_sp",
                "type_epithete","epithete_infra_sp","cultivar_groupe","cultivar","nom_commercial",
                "auteur","annee","biblio_origine","notes","nom_addendum","homonyme","num_type",
                "num_basionyme","synonyme_proparte","synonyme_douteux","synonyme_mal_applique",
                "synonyme_orthographique","orthographe_originelle","hybride_parent_01",
                "hybride_parent_01_notes","hybride_parent_02","hybride_parent_02_notes",
                "nom_francais","presence","statut_origine ","statut_introduction","statut_culture","exclure_taxref");

        public function initialiserProjet($projetNom) {
                parent::initialiserProjet($projetNom);
                $this->table = Config::get("apd");
                $this->tableMeta = Config::get("apdMeta");
        }

        public function executer() {
                try {
                        $this->initialiserProjet('apd');

                        // Lancement de l'action demandée
                        $cmd = $this->getParametre('a');
                        switch ($cmd) {
                                case 'tout' :
                                        $ok = $this->productionCsvPourReferentiels();
                                        if ($ok === true) {
                                                $this->integrationEFlore();
                                        }
                                        break;
                                case 'ref' : // partie 1 : "referentiels"
                                        $this->productionCsvPourReferentiels();
                                        break;
                                case 'eflore' : // partie 2 : "eFlore"
                                        $this->integrationEFlore();
                                        break;
                                case 'nettoyage' :
                                        $this->nettoyage();
                                        break;
                                case 'chargerStructureSql' :
                                        //$this->creerStructure();
                                        $this->chargerStructureSql();
                                        break;
                                case 'verifierEtGenererCsvRtax' :
                                        $this->verifierEtGenererCsvRtax();
                                        break;
                                case 'chargerCsvRtax' :
                                        $this->chargerCsvRtax();
                                        break;
                                case 'changerRangs' :
                                        $this->changerRangs();
                                        break;
                                case 'completerNumNomRetenu' :
                                        $this->completerNumNomRetenu();
                                        break;
                                case 'supprimerNumTaxSupPourSynonymes' :
                                        $this->supprimerNumTaxSupPourSynonymes();
                                        break;
                                case 'subspAutonymes' :
                                        $this->subspAutonymes();
                                        break;
                                case 'genererNomSupraGenerique' :
                                        $this->genererNomSupraGenerique();
                                        break;
                                case 'genererEpitheteInfraGenerique' :
                                        $this->genererEpitheteInfraGenerique();
                                        break;
                                case 'exporterCSVModifie' :
                                        $this->exporterCSVModifie();
                                        break;
                                case 'genererChpNumTax' :
                                        $this->genererChpNumTax();
                                        break;
                                case 'genererNomSciHtml' :
                                        $this->genererChpNomSciHtml();
                                        break;
                                case 'genererChpNomComplet' :
                                        $this->genererChpNomComplet();
                                        break;
                                case 'genererChpFamille' :
                                        $this->genererChpFamille();
                                        break;
                                case 'genererChpHierarchie' :
                                        $this->genererChpHierarchie();
                                        break;
                                default :
                                        throw new Exception("Erreur : la commande '$cmd' n'existe pas!");
                        }
                } catch (Exception $e) {
                        $this->traiterErreur($e->getMessage());
                }
        }

        // Lance la première moitié du boulot, et s'arrête lorsque le fichier CSV
        // au format Rtax est rempli avec les données amendées - il est prêt à rentrer dans Rtxß.
        // Retourne true si tout s'est bien passé, false sinon
        protected function productionCsvPourReferentiels() {
                $retour = false;
                $this->nettoyage();
                $this->chargerStructureSql();
                $verifOk = $this->verifierEtGenererCsvRtax();
                if ($verifOk === true) {
                        $chgtOk = $this->chargerCsvRtax();
                        if ($chgtOk) {
                                $this->changerRangs();
                                $this->completerNumNomRetenu();
                                $this->supprimerNumTaxSupPourSynonymes();
                                $this->subspAutonymes();
                                $this->genererNomSupraGenerique();
                                $this->genererEpitheteInfraGenerique();
                                $this->exporterCSVModifie();
                                $retour = true;
                        }
                }
                return $retour;
        }

        // Lance la seconde moitié du boulot, et s'arrête lorsque le référentiel
        // est inséré dans la base eFlore.
        // Retourne true si tout s'est bien passé, false sinon
        protected function integrationEFlore() {
                $retour = false;
                $this->genererChpNumTax();
                $this->genererChpNomSciHtml();
                $this->genererChpFamille();
                $this->genererChpNomComplet();
                $this->genererChpHierarchie();
                $retour = true;
                return $retour;
        }

        // -------------- partie Rtax -------------

        // Dézingue tout le bousin
        protected function nettoyage() {
                echo "---- suppression des tables\n";
                $req = "DROP TABLE IF EXISTS `" . $this->table . "`";
                $this->getBdd()->requeter($req);
                $req = "DROP TABLE IF EXISTS `" . $this->tableMeta . "`;";
                $this->getBdd()->requeter($req);
        }

        // Analyse le fichier CSV fourni par le CJBG, le vérifie et écrit un CSV minimal au format Rtax
        function verifierEtGenererCsvRtax() {
                $cheminCsvRtax = Config::get('chemins.csvRtax');
                $cheminCsvCjbg = Config::get('chemins.csvCjbg');
                $retour = false;
                echo "---- vérification CSV CJBG [$cheminCsvCjbg] et génération CSV Rtax\n";

                // Correspondances de colonnes pour le remplissage à minima du fichier CSV Rtax
                // Clefs: CJBG
                // Valeurs: Rtax
                $entetesCjbgVersRtax = array(
                    "id_name" => "num_nom",
                    "presence" => "presence",
                    "statut_introduction" => "statut_introduction",
                    "statut_origine" => "statut_origine",
                    "nom_addendum" => "nom_addendum",
                    "BASIONYME" => "num_basyonyme",
                    "NO_RANG" => "rang",
                    "auteur" => "auteur",
                    "ANNEE" => "annee",
                    "type_epithete" => "type_epithete",
                    "SYN_mal_applique" => "synonyme_mal_applique",
                    "nom_sci" => "nom_sci",
                    "num_tax_sup" => "num_tax_sup",
                    "num_nom_retenu" => "num_nom_retenu",
                    "genre" => "genre",
                    "NOTES" => "notes",
                    "epithete_sp" => "epithete_sp",
                    "epithete_infra_sp" => "epithete_infra_sp",
                        // champs additionnels
                    "NOM_STANDARD2" => false,
                    "STATUT_SYN" => false, // @TODO convertir
                    "hybride_parents" => false, // toujours "x" => ??
                    "FAM APG3" => false,
                    "auth_genre" => false,
                    "auth_esp" => false
                );

                $analyseOK = true;
                $numLigne = 1;
                $idNames = array();
                // lecture CSV d'origine
                $csv = fopen($cheminCsvCjbg, "r");
                $donneesTransformees = array();
                if ($csv) {
                        $entetes = fgetcsv($csv);
                        //echo "Entetes: " . print_r($entetes, true) . "\n";
                        while(($ligne = fgetcsv($csv)) !== false) {
                                $numLigne++;
                                $nouvelleLigne = array();
                                if (isset($idNames[$ligne[0]])) {
                                        echo "Entrée dupliquée pour id_name [" . $ligne[0] . "]\n";
                                        $analyseOK = false;
                                } else if (! is_numeric($ligne[0])) {
                                        echo "Ligne $numLigne : la clef [" . $ligne[0] . "] n'est pas un entier\n";
                                        $analyseOK = false;
                                } else if ($ligne[0] == 0) {
                                        echo "Ligne $numLigne : la clef [" . $ligne[0] . "] vaut zéro\n";
                                        $analyseOK = false;
                                } else {
                                        $idNames[$ligne[0]] = $ligne[13]; // stockage du nom retenu
                                        foreach ($ligne as $idx => $col) {
                                                $entete = $entetes[$idx];
                                                $ert = $entetesCjbgVersRtax[$entete];
                                                if (strpos($col, "\n") > -1) {
                                                        echo "Info: la colonne $ert de la ligne $numLigne contient des retours chariot. Conversion en espaces.\n";
                                                        $col = str_replace("\n", " ", $col);
                                                }
                                                $nouvelleLigne[$ert] = $col;
                                        }
                                        $donneesTransformees[] = $nouvelleLigne;
                                }
                        }
                } else {
                        echo "Erreur lors de l'ouverture du fichier\n";
                }

                // Vérifications:
                // - existence des num_nom_retenu et num_tax_sup mentionnés
                // - réduction des chaînes de synonymie
                $nnrManquants = array();
                $ntsManquants = array();
                $chaineSyn = array();
                foreach ($donneesTransformees as $ligne) {
                        $taxSup = $ligne['num_tax_sup'];
                        $nomRet = $ligne['num_nom_retenu'];
                        $numNom = $ligne['num_nom'];
                        // Si un nom est retenu, son taxon supérieur doit être mentionné et exister
                        if (($numNom == $nomRet) && $taxSup && (! isset($idNames[$taxSup])) && (! isset($ntsManquants[$taxSup]))) {
                                $ntsManquants[$taxSup] = true;
                        }
                        // Si un nom retenu est mentionné, il doit exister et être un nom retenu
                        if ($nomRet) {
                                if (isset($idNames[$nomRet])) {
                                        /*$nrnr = $idNames[$nomRet];
                                        echo "Test pour nn $numNom, nr $nomRet, " . $nrnr . "\n";
                                        if ($nomRet && $nrnr != $nomRet) {
                                                if (! isset($chaineSyn[$nomRet])) {
                                                        $chaineSyn[$nomRet] = true;
                                                }
                                        }*/
                                } else {
                                        if (! isset($nnrManquants[$nomRet])) {
                                                $nnrManquants[$nomRet] = true;
                                        }
                                }
                        }
                }
                if (count($nnrManquants) > 0) {
                        echo count($nnrManquants) . " Nom(s) retenu(s) absent(s):\n";
                        echo "(" . implode(",", array_keys($nnrManquants)) . ")\n";
                }
                if (count($ntsManquants) > 0) {
                        echo count($ntsManquants) . " Taxon(s) supérieur(s) absent(s):\n";
                        echo "(" . implode(",", array_keys($ntsManquants)) . ")\n";
                }
                /*if (count($chaineSyn) > 0) {
                        echo count($chaineSyn) . " Synonymes ne sont pas des noms retenus:\n";
                        //echo "(" . implode(",", array_keys($chaineSyn)) . ")\n";
                }*/

                if ($analyseOK === true) {
                        // Production CSV de destination
                        $csvDestination = '';
                        $csvDestination .= implode($this->entetesRtax, ',') . "\n";
                        $tailleLigne = count($this->entetesRtax);
                        foreach ($donneesTransformees as $dt) {
                                //$ligne = array();
                                $ligneCsv = '';
                                $i = 0;
                                foreach ($this->entetesRtax as $e) {
                                        /*if (isset($dt[$e])) {
                                                $ligne[] = $dt[$e];
                                        } else {
                                                $ligne[] = '';
                                        }*/
                                        if (isset($dt[$e]) && ($dt[$e] !== '')) {
                                                $ligneCsv .= '"' . $dt[$e] . '"';
                                        }
                                        if ($i < $tailleLigne) {
                                                $ligneCsv .= ',';
                                        }
                                        $i++;
                                }
                                $ligneCsv .= "\n";
                                //$ligneCsv = '"' . implode($ligne, '","') . '"' . "\n"; // met des double guillemets sur les champs vides et /i
                                $csvDestination .= $ligneCsv;
                        }
                        // @TODO créer le répertoire dans /tmp et donner les droits 777
                        file_put_contents($cheminCsvRtax, $csvDestination);
                        $retour = true;
                } else {
                        echo "L'analyse a mis en évidence des erreurs. Interruption.\n";
                }

                return $retour;
        }

        // Charge le CSV minimal au format TexRaf
        protected function chargerCsvRtax() {
                $cheminCsvRtax = Config::get('chemins.csvRtax');
                echo "---- chargement du fichier CSV Rtax [$cheminCsvRtax]\n";
                $req = "LOAD DATA INFILE '" . $cheminCsvRtax . "' INTO TABLE " . $this->table
                        . " FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n' IGNORE 1 LINES";
                $retour = $this->getBdd()->requeter($req);
                return $retour;
        }

        // Convertit les rangs du format chaispasquoi au format RexTaf
        protected function changerRangs() {
                echo "---- conversion des rangs\n";
                $rangs = array(
                        "0" => "10",
                        "1" => "20",
                        "2" => "50",
                        "3" => "53",
                        "4" => "80",
                        "5" => "140",
                        "6" => "180",
                        "7" => "190",
                        "8" => "200",
                        "9" => "220",
                        "10" => "230",
                        "11" => "240",
                        "12" => "250",
                        "13" => "260",
                        "14" => "280",
                        "15" => "290",
                        "16" => "320",
                        "17" => "340",
                        "18" => "350",
                        "19" => "360",
                        "20" => "370",
                        "26" => "440"
                );
                foreach ($rangs as $src => $dest) {
                        echo "rang $src => rang $dest\n";
                        $req = "UPDATE " . $this->table . " SET rang=$dest WHERE rang=$src;";
                        $this->getBdd()->requeter($req);
                }
        }

        // Copie num_nom dans num_nom_retenu lorsque ce dernier est vide
        protected function completerNumNomRetenu() {
                echo "---- complétion des num_nom_retenu\n";
                $req = "UPDATE " . $this->table . " SET num_nom_retenu = num_nom WHERE num_nom_retenu='';";
                $this->getBdd()->requeter($req);
        }

        // Supprime le num_tax_sup pour les synonymes
        // et le met à 1 s'il est égal au num_nom
        protected function supprimerNumTaxSupPourSynonymes() {
                echo "---- suppression de num_tax_sup pour les synonymes et mise à 1 si égal à num_nom\n";
                $req = "UPDATE " . $this->table . " SET num_tax_sup = '' WHERE num_nom != num_nom_retenu;";
                $this->getBdd()->requeter($req);
                $req = "UPDATE " . $this->table . " SET num_tax_sup = 1 WHERE num_nom = num_tax_sup;";
                $this->getBdd()->requeter($req);
        }

        // Pour chaque subsp. autonyme, inscrit l'epithete_infra_sp
        protected function subspAutonymes() {
                echo "---- inscription de l'épithète infraspécifique des subsp. autonymes\n";
                $req = "SELECT num_nom, nom_sci, epithete_infra_sp FROM " . $this->table . " WHERE nom_sci LIKE '%subsp.%'";
                $res = $this->getBdd()->recupererTous($req);

                $nbres = count($res);
                $cpt = 0;
                $ok = 0;
                $ids = array();
                foreach ($res as $subsp) {
                        $ns = $subsp['nom_sci'];
                        $pos = strpos($ns, 'subsp.');
                        $gsp = substr($ns, 0, $pos - 1);
                        $sp = substr($gsp, strrpos($gsp, ' ') + 1);
                        $sub = substr($ns, $pos + 8);
                        if ($sub == $sp) {
                                $cpt++;
                                // @TODO
                                // 1) récupérer l'auteur
                                // 2) intégrer l'auteur avant "subsp." dans le nom_sci
                                //echo "[$sp] || [$sub] || [" . $subsp['epithete_infra_sp'] . "]\n";
                                if ($sub == $subsp['epithete_infra_sp']) {
                                        $ok++;
                                } else {
                                        $reqMod = "UPDATE " . $this->table . " SET epithete_infra_sp='"
                                                . $sub . "' WHERE num_nom=" . $subsp['num_nom'];
                                        $this->getBdd()->requeter($reqMod);
                                }
                        }
                }
                echo "subsp.: $nbres\n";
                echo "Autonymes: $cpt dont $ok déjà inscrites\n";
        }

        // Copie le nom scientifique dans le nom supra générique pour les taxons de rang
        // supérieur au genre
        protected function genererNomSupraGenerique() {
                echo "---- complétion des noms supragénériques\n";
                $req = "UPDATE " . $this->table . " SET nom_supra_generique = nom_sci WHERE rang < 220";
                $res = $this->getBdd()->requeter($req);
        }

        // Copie le nom scientifique dans l'épithète infra générique pour les taxons de rang
        // entre genre et espèce
        protected function genererEpitheteInfraGenerique() {
                echo "---- complétion des épithètes infragénériques\n";
                $req = "UPDATE " . $this->table . " SET epithete_infra_generique = nom_sci WHERE rang > 220 AND rang < 290";
                $res = $this->getBdd()->requeter($req);
        }

        protected function exporterCSVModifie() {
                $cheminFichierCsvRtaxModifie = Config::get('chemins.csvRtaxModifie');
                echo "---- export du CSV Rtax modifié [$cheminFichierCsvRtaxModifie]\n";
                if (file_exists($cheminFichierCsvRtaxModifie)) {
                        unlink($cheminFichierCsvRtaxModifie);
                }
                $req = "SELECT '" . implode("','", $this->entetesRtax) . "'"
                        . " UNION ALL "
                        . " SELECT * FROM " . $this->table . " INTO OUTFILE '" . $cheminFichierCsvRtaxModifie . "'"
                        . " FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'";
                $res = $this->getBdd()->requeter($req);
                // Remplacement des cases vides par '' aulieu de '""' (peut faire foirer l'import par la suite)
                exec("sed -i 's/\"\"//g' " . $cheminFichierCsvRtaxModifie);
        }

        // -------------- partie eFlore ------------- copiée depuis le script Bdtfx

        private function genererChpNomSciHtml() {
                echo "---- génération des noms scientifiques en HTML \n";
                $this->preparerTablePrChpNomSciHtml();
                $generateur = new GenerateurNomSciHtml();
                $nbreTotal = $this->recupererNbTotalTuples();
                $erreurs = array();
                $this->departInsertion = 0;
                while ($this->departInsertion < $nbreTotal) {
                        $resultat = $this->recupererTuplesPrChpNomSciHtml();
        
                        try {
                                $nomsSciEnHtml = $generateur->generer($resultat);
                        } catch (Exception $e) {
                                $erreurs[] = $e->getMessage();
                        }
        
                        $this->remplirChpNomSciHtm($nomsSciEnHtml);
                        $this->departInsertion += $this->pasInsertion;
                        $this->afficherAvancement("Insertion des noms scientifique au format HTML dans la base par paquet de {$this->pasInsertion} en cours");
                }
                echo "\n";

                if (count($erreurs) > 0) {
                        echo 'Erreurs lors de la génération HTML des noms scientifiques:\n' . print_r($erreurs, true) . "\n";
                }
        }

        private function preparerTablePrChpNomSciHtml() {
                echo "---- ajout de la colonne nom_sci_html \n";
                $requete = "SHOW COLUMNS FROM {$this->table} LIKE 'nom_sci_html' ";
                $resultat = $this->getBdd()->recuperer($requete);
                if ($resultat === false) {
                        $requete =      "ALTER TABLE {$this->table} ".
                                'ADD nom_sci_html VARCHAR( 500 ) '.
                                'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ';
                        $this->getBdd()->requeter($requete);
                }
        }

        private function recupererNbTotalTuples(){
                $requete = "SELECT count(*) AS nb FROM {$this->table} ";
                $resultat = $this->getBdd()->recuperer($requete);
                return $resultat['nb'];
        }

        private function recupererTuplesPrChpNomSciHtml() {
                $requete = 'SELECT      num_nom, rang, nom_sci, nom_supra_generique, genre, epithete_infra_generique, '.
                        '       epithete_sp, type_epithete, epithete_infra_sp,cultivar_groupe, '.
                        '       nom_commercial, cultivar '.
                        "FROM {$this->table} ".
                        "LIMIT {$this->departInsertion},{$this->pasInsertion} ";
                $resultat = $this->getBdd()->recupererTous($requete);
                return $resultat;
        }

        private function remplirChpNomSciHtm($nomsSciHtm) {
                foreach ($nomsSciHtm as $id => $html) {
                        $html = $this->getBdd()->proteger($html);
                        $requete = "UPDATE {$this->table} SET nom_sci_html = $html WHERE num_nom = $id ";
                        $resultat = $this->getBdd()->requeter($requete);
                        if ($resultat === false) {
                                throw new Exception("Erreur d'insertion pour le tuple $id");
                        }
                }
        }

        // Attention c'est over-lent !
        private function genererChpNumTax() {
                $this->preparerTablePrChpNumTax();
                $erreurs = array();
                $this->departInsertion = 0;
                $dernier_num_tax = 0;
                
                $requete = 'SELECT num_nom '.
                                        'FROM '.$this->table.' '.
                                        'WHERE num_nom = num_nom_retenu AND num_nom_retenu != 0 '.
                                        'ORDER by num_nom_retenu ASC ';

                $resultat = $this->getBdd()->recupererTous($requete);
                foreach ($resultat as $taxon) {
                        $dernier_num_tax++;
                        $requete_maj = 'UPDATE '.$this->table.' '.
                                                        'SET num_taxonomique = '.$dernier_num_tax.' '.
                                                        'WHERE num_nom_retenu = '.$taxon['num_nom'];
                        $this->getBdd()->requeter($requete_maj);
                        $this->pasInsertion++;
                        $this->afficherAvancement("Insertion des num tax, ".count($resultat)." num tax a traiter");
                }
                echo "\n";
                if (count($erreurs) > 0) {
                        echo 'Erreurs lors de la génération des numéros taxonomiques' . print_r($erreurs, true) . "\n";
                }
        }
        
        private function preparerTablePrChpNumTax() {
                $requete = "SHOW COLUMNS FROM {$this->table} LIKE 'num_taxonomique' ";
                $resultat = $this->getBdd()->recuperer($requete);
                if ($resultat === false) {
                        $requete =      "ALTER TABLE {$this->table} ".
                                                'ADD num_taxonomique INT( 9 ) ';
                        $this->getBdd()->requeter($requete);
                }
        }

        private function genererChpNomComplet() {
                $this->preparerTablePrChpNomComplet();
                $this->remplirChpNomComplet();
        }
        
        private function preparerTablePrChpNomComplet() {
                $requete = "SHOW COLUMNS FROM {$this->table} LIKE 'nom_complet' ";
                $resultat = $this->getBdd()->recuperer($requete);
                if ($resultat === false) {
                        $requete =      "ALTER TABLE {$this->table} ".
                                        'ADD nom_complet VARCHAR( 500 ) '.
                                        'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ';
                        $this->getBdd()->requeter($requete);
                }
        }
        
        private function remplirChpNomComplet() {
                echo "---- Attribution du champ nom complet au taxons :\n";
                $requete = "UPDATE {$this->table} SET nom_complet = CONCAT(nom_sci,' ',auteur)";
                $resultat = $this->getBdd()->requeter($requete);
                if ($resultat === false) {
                        echo "Erreur de génération du champ nom complet\n";
                } else {
                        echo "OK\n";
                }
        }

        private function genererChpFamille() {
                $this->preparerTablePrChpFamille();
                $resultats = $this->recupererTuplesPrChpFamille();
                $noms = array();
                $introuvables = array();
                $introuvablesSyno = array();
                foreach ($resultats as $id => $nom) {
                        $nn = $nom['num_nom'];
                        $nnr = $nom['num_nom_retenu'];
                        $nts = $nom['num_tax_sup'];
                        $rg = $nom['rang'];
                        if ($nnr != '') {
                                if ($rg == '180') {
                                        $noms[$nn] = $nom['nom_sci'];
                                } else {
                                        if ($nn == $nnr) {// nom retenu
                                                if (isset($noms[$nts])) {
                                                        $noms[$nn] = $noms[$nts];
                                                } else {
                                                        $introuvables[] = $nn;
                                                }
                                        } else {// nom synonyme
                                                if (isset($noms[$nnr])) {
                                                        $noms[$nn] = $noms[$nnr];
                                                } else {
                                                        $introuvablesSyno[] = $nom;
                                                }
                                        }
                                }
                        }
                        unset($resultats[$id]);
                        $this->afficherAvancement("Attribution de leur famille aux noms en cours");
                }
                echo "\n";

                foreach ($introuvablesSyno as $id => $nom) {
                        $nn = $nom['num_nom'];
                        $nnr = $nom['num_nom_retenu'];
                        if (isset($noms[$nnr])) {
                                $noms[$nn] = $noms[$nnr];
                        } else {
                                $introuvables[] = $nn;
                        }
                        unset($introuvablesSyno[$id]);
                        $this->afficherAvancement("Attribution de leur famille aux synonymes en cours");
                }
                echo "\n";

                if (count($introuvables) > 0) {
                        echo count($introuvables) . ' familles sont introuvables : ' . implode(',', $introuvables) . "\n";
                }
                $this->remplirChpFamille($noms);
        }

        private function preparerTablePrChpFamille() {
                $requete = "SHOW COLUMNS FROM {$this->table} LIKE 'famille' ";
                $resultat = $this->getBdd()->recuperer($requete);
                if ($resultat === false) {
                        $requete =      "ALTER TABLE {$this->table} ".
                                'ADD famille VARCHAR(255) '.
                                'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ';
                        $this->getBdd()->requeter($requete);
                }
        }

        private function recupererTuplesPrChpFamille() {
                $requete = 'SELECT num_nom, num_nom_retenu, num_tax_sup, rang, nom_sci '.
                        "FROM {$this->table} ".
                        "WHERE rang >= 180 ".
                        "ORDER BY rang ASC, num_tax_sup ASC, num_nom_retenu DESC ";
                $resultat = $this->getBdd()->recupererTous($requete);
                return $resultat;
        }

        private function remplirChpFamille($noms) {
                foreach ($noms as $id => $famille) {
                        $famille = $this->getBdd()->proteger($famille);
                        $requete = "UPDATE {$this->table} SET famille = $famille WHERE num_nom = $id ";
                        $resultat = $this->getBdd()->requeter($requete);
                        if ($resultat === false) {
                                throw new Exception("Erreur d'insertion pour le tuple $id");
                        }
                        $this->afficherAvancement("Insertion des noms de famille dans la base en cours");
                }
                echo "\n";
        }
        
        private function genererChpHierarchie() {
                $this->preparerTablePrChpHierarchie();
                $table = Config::get('tables.isfan');
        
                $requete = "UPDATE {$this->table} SET hierarchie = NULL ";
                $mise_a_jour = $this->getBdd()->requeter($requete);
        
                $requete_hierarchie = "SELECT num_nom, num_nom_retenu, num_tax_sup FROM " . $this->table . " ORDER BY rang DESC";
        
                $resultat = $this->getBdd()->recupererTous($requete_hierarchie);
                $num_nom_a_num_sup = array();
                foreach($resultat as &$taxon) {
                        $num_nom_a_num_sup[$taxon['num_nom']] = $taxon['num_tax_sup'];
                }
                $chemin_taxo = "";
                foreach($resultat as &$taxon) {
                        $chemin_taxo = $this->traiterHierarchieNumTaxSup($taxon['num_nom_retenu'], $num_nom_a_num_sup).'-';
                        $requete = "UPDATE {$this->table} SET hierarchie = ".$this->getBdd()->proteger($chemin_taxo)." WHERE num_nom = ".$taxon['num_nom']." ";
                        $mise_a_jour = $this->getBdd()->requeter($requete);
                        $this->afficherAvancement("Insertion de la hierarchie taxonomique en cours");
                }
                echo "\n";
        }
        
        private function traiterHierarchieNumTaxSup($num_nom_retenu, &$num_nom_a_num_sup) {
                $chaine_hierarchie = "";
                if(isset($num_nom_a_num_sup[$num_nom_retenu])) {
                        $num_tax_sup = $num_nom_a_num_sup[$num_nom_retenu];
                        $chaine_hierarchie = '-'.$num_tax_sup;
                        if($num_tax_sup != 0 && $num_tax_sup != '') {
                                $chaine_hierarchie = $this->traiterHierarchieNumTaxSup($num_tax_sup, $num_nom_a_num_sup).$chaine_hierarchie;
                        }
                }
                return $chaine_hierarchie;
        }
        
        private function preparerTablePrChpHierarchie() {
                $requete = "SHOW COLUMNS FROM {$this->table} LIKE 'hierarchie' ";
                $resultat = $this->getBdd()->recuperer($requete);
                if ($resultat === false) {
                        $requete =      "ALTER TABLE {$this->table} ".
                                                'ADD hierarchie VARCHAR(1000) '.
                                                'CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ';
                        $this->getBdd()->requeter($requete);
                }
        }
}
?>