Subversion Repositories eFlore/Applications.cel

Rev

Rev 768 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

<?php
// declare(encoding='UTF-8');
/**
 * Service de recherche et modification de l'arbre des mots clés associés à un id.
 * 1: Le service recoit un mot clé à ajouter à l'arbre
 * 2: Le service recherche l'arbre ou sous arbre correspondant au critères demandé
 * 3: Le service renvoie l'arbre au format json
 * 
 * Encodage en entrée : utf8
 * Encodage en sortie : utf8
 *
 * Cas d'utilisation :
 *
 * @author Aurélien PERONNET <aurelien@tela-botanica.org>
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
 * @version $Id$
 * @copyright © 2011, Tela-Botanica
 */
class InventoryKeyWordList extends DBAccessor {
        public $config ;
        protected $suffix = '';

        public function InventoryKeyWordList($config) {
                $this->config = $config;
        }

        public function getElement($uid) {
                // Controle detournement utilisateur
                session_start();
                $this->suffix = '_'.$uid[0];
                $id_utilisateur = $uid[1] ;
                $this->controleUtilisateur($uid[1]);
                
                $requete =      'SELECT cmc_mot_cle, cmc_id_mot_cle_utilisateur, cmc_id_parent '.
                                        'FROM cel_mots_cles'.$this->suffix.' '.
                                        'WHERE cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" '.
                                        'ORDER BY cmc_niveau ';
                
                $resultat = $this->recupererResultat($requete);
                if ($resultat) {
                        $mots_cles = array();
                        while($mot_cle = $resultat->fetchrow(DB_FETCHMODE_ASSOC)) {
                                $mots_cles[] = $mot_cle;
                        }
                        $infos = json_encode($mots_cles);

                        header('content-type: text/json');
                        print $infos;
                        exit();
                }
        }

        public function updateElement($uid, $pairs) {
                session_start();
                $this->suffix = '_'.$uid[0];
                $id_utilisateur = $uid[1];
                $this->controleUtilisateur($uid[1]);

                $id_mot_cle = $pairs['id'];
                $action = $pairs['action'];

                if ($action == 'modification') {
                        $nouveau_nom = $pairs['motcle'];
                        $nouvel_id_general = md5(strtolower($nouveau_nom));

                        $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                                'SET cmc_mot_cle = "'.$DB->escapeSimple($nouveau_nom).'" , '.
                                                '       cmc_id_mot_cle_general = "'.$DB->escapeSimple($nouvel_id_general).'" '.
                                                'WHERE cmc_id_mot_cle_utilisateur = "'.$DB->escapeSimple($id_mot_cle).'" '.
                                                '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'"' ;
                        $reussite = $this->executerRequete($requete);
                        if ($reussite) {
                                echo 'OK';
                        }
                } else if ($action == 'deplacement') {
                        $this->commencerTransaction();

                        $transaction_reussie_1 = true;
                        $id_pere = $pairs['parent'];
                        $bornes = $this->calculerBornesEtNiveau($id_mot_cle, $id_utilisateur);
                        $bg = $bornes['cmc_bg'];
                        $bd = $bornes['cmc_bd'];
                        $niveau = $bornes['cmc_niveau'];

                        // on inverse l'intervalle de l'élément déplacé et du sous arbre
                        $transaction_reussie_2 = $this->exclureIntervalle($bg, $bd, $id_utilisateur) ? true : false;

                        $bg_negative = $bg - $bd - 1;
                        $bd_negative = $bd - $bd - 1;

                        // on recalcule les intervalles de l'arbre privé de ce sous arbre
                        $transaction_reussie_3 = $this->decalerBornesMoinsIntervalle($bg, $bd, $id_utilisateur) ? true : false;

                        $bornes_pere = $this->calculerBornesEtNiveau($id_pere, $id_utilisateur);
                        $bg_pere = $bornes_pere['cmc_bg'];
                        $bd_pere = $bornes_pere['cmc_bd'];

                        $niveau_pere = $bornes_pere['cmc_niveau'];

                        $decalage = $bd - $bg + 1;

                        // on decale les bornes droite du pere pour préparer l'insertion
                        $transaction_reussie_4 = $this->decalerBornesPlusIntervalle($bd_pere, $decalage, $id_utilisateur) ? true : false;
                        
                        $nouvelle_bd = $bd_pere + $decalage;
                        $modif_niveau = $niveau_pere - $niveau + 1;

                        $transaction_reussie_5 = $this->inclureIntervalle($bg_negative, $bd_negative, $nouvelle_bd, $modif_niveau, $id_utilisateur) ? true : false;

                        $transaction_reussie_6 = $this->changerPere($id_mot_cle, $id_pere, $id_utilisateur) ? true : false;

                        if ($transaction_reussie_1 && $transaction_reussie_2 && $transaction_reussie_3 && $transaction_reussie_4 && $transaction_reussie_5 && $transaction_reussie_6) {
                                $this->completerTransaction();
                        } else {
                                $this->annulerTransaction();
                        }

                }
        }

        public function createElement($pairs) {
                // Controle detournement utilisateur
                session_start();
                $this->controleUtilisateur($pairs['identifiant']);

                $this->suffix = '_'.$pairs['mode'];
                $id_utilisateur = $pairs['identifiant'];
                $mot_cle = $pairs['motcle'];

                // TODO supprimer accents et majuscules
                $id_mot_cle_general = md5(mb_strtolower($mot_cle));
                $id_mot_cle = $pairs['id'];
                $id_parent = $pairs['parent'];

                $this->ajouterMotCleRacine($id_utilisateur);

                $this->commencerTransaction();

                $bornes = $this->calculerBornesEtNiveau($id_parent, $id_utilisateur);
                $borne_pere = $bornes['cmc_bd'];
                $niveau = $bornes['cmc_niveau'] + 1;
                $bg = $bornes['cmc_bd'];
                $bd = $bg + 1;

                $transaction_reussie_1 = $this->decalerBornesPlusDeux($borne_pere,$id_utilisateur) ? true : false;
                
                $requete =      'INSERT INTO  cel_mots_cles'.$this->suffix.' '.
                                        'VALUES ( '.
                                        '"'.$DB->escapeSimple($mot_cle).'", '.
                                        '"'.$DB->escapeSimple($bg).'", '.
                                        '"'.$DB->escapeSimple($bd).'", '.
                                        '"'.$DB->escapeSimple($id_mot_cle_general).'", '.
                                        '"'.$DB->escapeSimple($id_mot_cle).'", '.
                                        '"'.$DB->escapeSimple($id_utilisateur).'", '.
                                        '"'.$DB->escapeSimple($id_parent).'", '.
                                        '"'.$DB->escapeSimple($niveau).'" )' ;
                $transaction_reussie_2 = $this->executerRequete($requete);

                if ($transaction_reussie_1 && $transaction_reussie_2) {
                        $this->completerTransaction();
                        echo 'OK';
                } else {
                        $this->annulerTransaction();
                }
        }

        public function deleteElement($uid) {
                session_start();
                
                $this->suffix = '_'.$uid[0];
                $id_utilisateur = $uid[1];
                $id_mot_cle = $uid[2];

                $this->controleUtilisateur($id_utilisateur);            
                $this->commencerTransaction();

                $bornes  = $this->calculerBornesEtNiveau($id_mot_cle, $id_utilisateur);
                $bg = $bornes['cmc_bg'];
                $bd = $bornes['cmc_bd'];

                $requete =      'DELETE FROM cel_mots_cles'.$this->suffix.' '.
                                        'WHERE cmc_bg >= "'.$DB->escapeSimple($bg).'" '.
                                        '       AND cmc_bd <= "'.$DB->escapeSimple($bd).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $transaction_reussie_1 = $this->verifierLignesAffectees($requete);

                $transaction_reussie_2 = $this->decalerBornesMoinsIntervalle($bg, $bd, $id_utilisateur) ? true : false;

                if ($transaction_reussie_1 && $transaction_reussie_2) {
                        $this->completerTransaction();
                } else {
                        $this->annulerTransaction();
                }
        }
        
        private function ajouterMotCleRacine($id) {
                $requete =      'SELECT COUNT(*) '.
                                        'FROM cel_mots_cles'.$this->suffix.' '.
                                        'WHERE cmc_id_proprietaire = "'.$DB->escapeSimple($id).'" ';
                $resultat = $this->recupererResultat($requete);

                if ($resultat) {
                        $valeurs = $resultat->fetchrow(DB_FETCHMODE_ORDERED);

                        switch ($this->suffix) {
                                case '_obs' :
                                        $nom_racine = 'Projets';
                                        $id_racine = 'racine_obs';
                                        break;
                                case '_images' :
                                        $nom_racine = 'Mots clés';
                                        $id_racine = 'racine';
                                        break;
                                default:
                                        $nom_racine = $this->suffix;
                                        $id_racine = $this->suffix;
                        }

                        if ($valeurs[0] == 0) {
                                $requete =      'INSERT INTO cel_mots_cles'.$this->suffix.' '.
                                                        'VALUES ("'.$nom_racine.'", 1, 2, "'.$id_racine.'", "'.$id_racine.'", "'.$DB->escapeSimple($id).'", "", 0) ';
                                $this->executerRequete($requete);
                        }
                }
        }

        /**
         * Désactive l'auto-commit puis débute la transaction
         */
        private function commencerTransaction() {
                // Désactive l'autocommit le temps de la manipulation de l'arbre
                $requete = 'SET AUTOCOMMIT = 0 ';
                $reussite_autocommit = $this->executerRequete($requete);

                // Débute une nouvelle transaction
                $requete = 'BEGIN ';
                $reussite_begin = $this->executerRequete($requete);
        }

        /**
         * Termine la transaction puis réactive l'auto-commit
         */
        private function completerTransaction() {
                // Complète la transaction
                $requete = 'COMMIT ';
                $reussite_commit = $this->executerRequete($requete);

                // Réactive l'autocommit le temps de la manipulation de l'arbre
                $requete = 'SET AUTOCOMMIT = 1 ';
                $reussite_autocommit = $this->executerRequete($requete);

                echo 'OK';
        }
        
        /**
         * Annule la transaction et réactive l'auto-commit
         */
        private function annulerTransaction() {
                // Annule la transaction
                $requete = 'ROLLBACK ';
                $reussite_rollback = $this->executerRequete($requete);

                // Réactive l'autocommit le temps de la manipulation de l'arbre
                $requete = 'SET AUTOCOMMIT = 1 ';
                $reussite_autocommit = $this->executerRequete($requete);

                echo 'ERROR';
        }

        /** 
         * Renvoie les bornes d'un noeud de l'arbre des mots clés
         */
        private function calculerBornesEtNiveau($id_mot_cle,$id_utilisateur) {
                $requete =      'SELECT cmc_bd, cmc_bg, cmc_niveau '.
                                        'FROM cel_mots_cles'.$this->suffix.' '.
                                        'WHERE cmc_id_mot_cle_utilisateur = "'.$DB->escapeSimple($id_mot_cle).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $resultat = $this->recupererResultat($requete);
                $valeurs = $resultat->fetchrow(DB_FETCHMODE_ASSOC);
                return $valeurs;
        }

        /**
         * Décale les bornes de deux pour insérer un nouvel élément
         */ 
        private function decalerBornesPlusDeux($valeur, $id_utilisateur) {
                // Décalage borne droite
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bd = cmc_bd + 2 WHERE cmc_bd >= "'.$DB->escapeSimple($valeur).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $reussi_1 = $this->executerRequete($requete);
                
                // Décalage borne gauche
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bg = cmc_bg + 2 '.
                                        'WHERE cmc_bg >=  "'.$DB->escapeSimple($valeur).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $reussi_2 = $this->executerRequete($requete);
                
                return $reussi_1 && $reussi_2;
        }

        /**
         * Décale les bornes d'un intervalle negatif donne (pour la suppression d'un sous arbre).
         */
        private function decalerBornesMoinsIntervalle($bg, $bd, $id_utilisateur) {
                $decalage = $bd - $bg + 1;

                // Décalage borne droite
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bd = cmc_bd - "'.$DB->escapeSimple($decalage).'" '.
                                        'WHERE cmc_bd >=  "'.$DB->escapeSimple($bg).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $reussi_1 = $this->executerRequete($requete);

                // Décalage borne gauche
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bg = cmc_bg - "'.$DB->escapeSimple($decalage).'" '.
                                        'WHERE cmc_bg >  "'.$DB->escapeSimple($bg).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $reussi_2 = $this->executerRequete($requete);
                
                return $reussi_1 && $reussi_2;
        }

        /**
         * Décale à droite des bornes donées d'un intervalle positif donne (pour l'ajout d'un sous arbre).
         */ 
        private function decalerBornesPlusIntervalle($valeur_bornes, $largeur, $id_utilisateur) {
                $decalage = $largeur;

                // decalage borne droite
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bd = cmc_bd + "'.$DB->escapeSimple($decalage).'" '.
                                        'WHERE cmc_bd >=  "'.$DB->escapeSimple($valeur_bornes).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $reussi_1 = $this->executerRequete($requete);

                // decalage borne gauche
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bg = cmc_bg + "'.$DB->escapeSimple($decalage).'" '.
                                        'WHERE cmc_bg >=  "'.$DB->escapeSimple($valeur_bornes).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                $reussi_2 = $this->executerRequete($requete);

                return $reussi_1 && $reussi_2;
        }

        /**
         * Inverse les bornes d'un intervalle pour l'exclure des modifications sur l'arbre sans changer la hiérarchie.
         */
        private function exclureIntervalle($bg, $bd, $id_utilisateur) {
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bd = cmc_bd - "'.$DB->escapeSimple($bd).'" - 1 , '.
                                        '       cmc_bg =  cmc_bg -  "'.$DB->escapeSimple($bd).'" - 1 '.
                                        'WHERE cmc_bd <=  "'.$DB->escapeSimple($bd).'" '.
                                        '       AND cmc_bg >=  "'.$DB->escapeSimple($bg).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';

                return $this->executerRequete($requete);
        }

        /** 
         * Recale les bornes dun intervalle pour l'inclure dans l'arbre à la bonne place.
         * Décalage borne droite
         */
        private function inclureIntervalle($bg, $bd, $decalage,$modif_niveau, $id_utilisateur) {

                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_bg =  cmc_bg + "'.$DB->escapeSimple($decalage).'" , '.
                                        '       cmc_bd = cmc_bd + "'.$DB->escapeSimple($decalage).'", '.
                                        '       cmc_niveau = cmc_niveau + "'.$modif_niveau.'" '.
                                        'WHERE cmc_bg >=  "'.$DB->escapeSimple($bg).'" '.
                                        '       AND cmc_bd <=  "'.$DB->escapeSimple($bd).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';

                return $this->executerRequete($requete);
        }

        private function changerPere($id_mot_cle, $id_pere, $id_utilisateur) {
                $requete =      'UPDATE cel_mots_cles'.$this->suffix.' '.
                                        'SET cmc_id_parent = "'.$DB->escapeSimple($id_pere).'" '.
                                        'WHERE cmc_id_mot_cle_utilisateur = "'.$DB->escapeSimple($id_mot_cle).'" '.
                                        '       AND cmc_id_proprietaire = "'.$DB->escapeSimple($id_utilisateur).'" ';
                
                return $this->executerRequete($requete);
        }
        
        private function executerRequete($requete) {
                $DB = $this->connectDB($this->config, 'cel_db');
                $resultat =& $DB->query($requete);
                $execution = true;
                if (PEAR::isError($resultat)) {
                        die($res->getMessage());
                        $execution = false;
                }
                return $execution;
        }
        
        private function recupererResultat($requete) {
                $DB = $this->connectDB($this->config, 'cel_db');
                $resultat =& $DB->query($requete);
                if (PEAR::isError($resultat)) {
                        die($res->getMessage());
                        $resultat = false;
                }
                return $resultat;
        }
        
        private function verifierLignesAffectees($requete) {
                $DB = $this->connectDB($this->config, 'cel_db');
                $resultat =& $DB->query($requete);
                $execution = true;
                if (PEAR::isError($resultat)) {
                        die($res->getMessage());
                        $execution = false;
                } else {
                        if ($DB->affectedRows() <= 0) {
                                $execution = false;
                        }
                } 
                return $execution;
        }
 }
?>