Subversion Repositories eFlore/Applications.cel

Rev

Rev 1872 | Blame | Last modification | View Log | RSS feed

<?php
// declare(encoding='UTF-8');
// ATTENTION ! Classe compatible uniquement avec nouveau format de bdd du cel //
/**
 * 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 Cel {

        protected $suffixe = '';
        protected $suffixe_table = null;
        protected $suffixe_champ = null;
        
        private function setChampsEtTablePourSuffixe($suffixe) {
                $this->suffixe = $suffixe;
                switch($suffixe) {
                        case 'obs':
                                $this->suffixe_table = '_obs';
                                $this->suffixe_champ = '_obs';
                        break;
                        case 'images':
                                $this->suffixe_table = '_images';
                                $this->suffixe_champ = '_image';
                        break;
                }
        }

        public function getElement($uid) {
                // Controle detournement utilisateur
                $id_utilisateur = $uid[1] ;
                $this->controleUtilisateur($uid[1]);
                $this->setChampsEtTablePourSuffixe($uid[0]);
                
                $this->envoyerJson(self::getMotsClefs($uid[1], $uid[0]));
                return TRUE; // compat: pourquoi renvoyer true si vide ?
        }


        static function getMotsClefs($uid, $type) {
                if($type == 'obs') {
                        return Cel::db()->requeter(sprintf(
                                'SELECT mot_cle, id_mot_cle_obs, ce_mot_cle_obs_parent'.
                                ' FROM cel_mots_cles_obs'.
                                ' WHERE id_utilisateur = %s'.
                                ' ORDER BY niveau',
                                Cel::db()->proteger($uid)));
                }

                if($type == 'images') {
                        return Cel::db()->requeter(sprintf(
                                'SELECT mot_cle, id_mot_cle_image, ce_mot_cle_image_parent'.
                                ' FROM cel_mots_cles_images'.
                                ' WHERE id_utilisateur = %s'.
                                ' ORDER BY niveau',
                                Cel::db()->proteger($uid)));
                }
                /* pour extraire un mot-clef en particulier (bien que getMotsClefId() soit plus adapté:
                array_walk($ret,
                                   create_function('&$val, $k, $keyword',
                                                                   'if($val["mot_cle"] != $keyword) $val = NULL;' .
                                                                   'else $val = $val["id_mot_cle_obs"];'),
                                   'XXX');
                $obsKeywordIdToDetach = array_filter($ret);
                $obsKeywordIdToDetach = array_pop($obsKeywordIdToDetach); */

                return array();
        }


        static function getMotsClefId($uid, $type, $keyword) {
                if($type == 'obs') {
                        $ret = Cel::db()->requeter(sprintf(
                                'SELECT mot_cle, id_mot_cle_obs, ce_mot_cle_obs_parent'.
                                ' FROM cel_mots_cles_obs'.
                                ' WHERE id_utilisateur = %s'.
                                ' AND mot_cle = %s'.
                                ' ORDER BY niveau',
                                Cel::db()->proteger($uid),
                                Cel::db()->proteger($keyword) ));
                }

                if($type == 'images') {
                        $ret = Cel::db()->requeter(sprintf(
                                'SELECT mot_cle, id_mot_cle_image, ce_mot_cle_image_parent'.
                                ' FROM cel_mots_cles_images'.
                                ' WHERE id_utilisateur = %s'.
                                ' AND mot_cle = %s'.
                                ' ORDER BY niveau',
                                Cel::db()->proteger($uid),
                                Cel::db()->proteger($keyword) ));
                }
                return @$ret[0]['id_mot_cle_obs'];
        }

        public function updateElement($uid, $pairs) {
                $id_utilisateur = $uid[1];
                $this->controleUtilisateur($uid[1]);
                
                $this->setChampsEtTablePourSuffixe($uid[0]);

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

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

                        $requete =      'UPDATE cel_mots_cles'.$this->suffixe_table.' '.
                                                'SET mot_cle = '.Cel::db()->proteger($nouveau_nom).' , '.
                                                '       md5 = '.Cel::db()->proteger($nouvel_id_general).' '.
                                                'WHERE id_mot_cle'.$this->suffixe_champ.' = '.Cel::db()->proteger($id_mot_cle).' '.
                                                '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur) ;
                        $reussite = Cel::db()->executer($requete);
                        if ($reussite !== false) {
                                echo 'OK';
                                return true;
                        } else {
                                return false;
                        }
                } else if ($action == 'deplacement') {
                        
                        self::commencerTransaction();
                        
                        $transaction_reussie_1 = true;
                        $id_pere = $pairs['parent'];
                        $bornes = $this->calculerBornesEtNiveau($id_mot_cle, $id_utilisateur);
                        $bg = $bornes['bg'];
                        $bd = $bornes['bd'];
                        $niveau = $bornes['niveau'];

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

                        $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);

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

                        $niveau_pere = $bornes_pere['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);
                        
                        $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);
                                                
                        $transaction_reussie_6 = $this->changerPere($id_mot_cle, $id_pere, $id_utilisateur);

                        if ($transaction_reussie_1 !== false && $transaction_reussie_2 !== false && 
                                $transaction_reussie_3 !== false && $transaction_reussie_4 !== false && 
                                $transaction_reussie_5 !== false && $transaction_reussie_6 !== false) {
                                self::completerTransaction();
                                return true;
                        } else {
                                self::annulerTransaction();
                                return false;
                        }
                }
                return true;
        }

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

                $this->setChampsEtTablePourSuffixe($pairs['mode']);
                $id_utilisateur = $pairs['identifiant'];
                $mot_cle = $pairs['motcle'];

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

                $this->ajouterMotCleRacine($id_utilisateur);

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

        if(!$borne_pere) return false;

                self::commencerTransaction();
                $transaction_reussie_1 = $this->decalerBornesPlusDeux($borne_pere,$id_utilisateur) ? true : false;
                
                $requete =      'INSERT INTO  cel_mots_cles'.$this->suffixe_table.' '.
                                        'VALUES ( '.
                                        Cel::db()->proteger($id_mot_cle).', '.
                                        Cel::db()->proteger($id_utilisateur).', '.
                                        Cel::db()->proteger($mot_cle).', '.
                                        Cel::db()->proteger($id_mot_cle_general).', '.
                                        Cel::db()->proteger($bg).', '.
                                        Cel::db()->proteger($bd).', '.
                                        Cel::db()->proteger($niveau).', '.
                                        Cel::db()->proteger($id_parent).') ' ;
                                                        
                $transaction_reussie_2 = Cel::db()->executer($requete);

                if ($transaction_reussie_1 && $transaction_reussie_2) {
            // on sort de self::createElement ==> JRest::(get|post) ==> JRest->created() qui fait header().
            // or si nous dépassons ini_get(output_buffering) nous ne pouvons plus réécrire le code de retour
            // HTTP, de plus, si ini_get(output_buffering) == off, nous enverrions un warning.
            // d'où ce clone de JRest::created();
            header('HTTP/1.0 201 Created');
                        self::completerTransaction();
            exit;
                } else {
            // cf ci-dessus: JRest::badRequest
            header('HTTP/1.0 400 Bad Request');
                        self::annulerTransaction();
            exit;
                }
                return true;
        }

        public function deleteElement($uid) {
                
                $this->setChampsEtTablePourSuffixe($uid[0]);
                $id_utilisateur = $uid[1];
                $id_mot_cle = $uid[2];
                
                $tableau_ids_mots_cles = array();
                $tableau_ids_mots_cles[] = $id_mot_cle;

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

                $bornes  = $this->calculerBornesEtNiveau($id_mot_cle, $id_utilisateur);
                if($bornes) {
                        $bg = $bornes['bg'];
                        $bd = $bornes['bd'];
                        
                        $requete_mots_cles_fils = 'SELECT id_mot_cle'.$this->suffixe_champ.' as id FROM cel_mots_cles'.$this->suffixe_table.' '.
                                                'WHERE bg >= '.Cel::db()->proteger($bg).' '.
                                                '       AND bd <= '.Cel::db()->proteger($bd).' '.
                                                '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';

                        $mots_cles_fils = Cel::db()->requeter($requete_mots_cles_fils);
                        foreach ($mots_cles_fils as $fils) {
                                $tableau_ids_mots_cles[] = $fils['id'];
                        }
        
                        $requete =      'DELETE FROM cel_mots_cles'.$this->suffixe_table.' '.
                                                'WHERE bg >= '.Cel::db()->proteger($bg).' '.
                                                '       AND bd <= '.Cel::db()->proteger($bd).' '.
                                                '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                                                
                        $transaction_reussie_1 = Cel::db()->executer($requete);
                        $transaction_reussie_2 = $this->decalerBornesMoinsIntervalle($bg, $bd, $id_utilisateur) ? true : false;
        
                        if ($transaction_reussie_1 !== false && $transaction_reussie_2 !== false) {
                                self::completerTransaction();
                        } else {
                                self::annulerTransaction();
                        }
                }
                // Suppression des liaisons associées à ce mot clé
                $gestion_liaisons = new LiaisonMotsCles($this->config, $this->suffixe);
                $gestion_liaisons->supprimerToutesLiaisonsPourIdMotCle($id_utilisateur, $tableau_ids_mots_cles);
                
                return true;
        }
        
        private function ajouterMotCleRacine($id) {
                $requete =      'SELECT COUNT(*) as nb_mc '.
                                        'FROM cel_mots_cles'.$this->suffixe_table.' '.
                                        'WHERE id_utilisateur = '.Cel::db()->proteger($id).' ';
                $resultat = Cel::db()->requeter($requete);

                if (is_array($resultat) && count($resultat) > 0) {
                        $valeurs = $resultat[0]['nb_mc'];

                        switch ($this->suffixe) {
                                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->suffixe;
                                        $id_racine = $this->suffixe;
                        }
                        
                        $md5_racine = Cel::db()->proteger(md5($nom_racine));
                        $id_racine = Cel::db()->proteger($id_racine);
                        $nom_racine = Cel::db()->proteger($nom_racine);
                        $id_utilisateur = Cel::db()->proteger($id);

                        if ($valeurs == 0) {                            
                                $requete = "INSERT INTO cel_mots_cles{$this->suffixe_table} ".
                                                   "VALUES ($id_racine, $id_utilisateur, $nom_racine, $md5_racine, ".
                                                   "1, 2, 0, '') ";
                                
                                Cel::db()->executer($requete);
                        }
                }
        }

        /**
         * Désactive l'auto-commit puis débute la transaction
         */
        static function commencerTransaction() {
                // Désactive l'autocommit le temps de la manipulation de l'arbre
                $reussite_autocommit = Cel::db()->executer("SET AUTOCOMMIT = 0");
                // Débute une nouvelle transaction
                $reussite_begin = Cel::db()->executer("BEGIN");
        }

        /**
         * Termine la transaction puis réactive l'auto-commit
         */
        static function completerTransaction() {
                // Complète la transaction
                $reussite_commit = Cel::db()->executer("COMMIT");
                // Réactive l'autocommit le temps de la manipulation de l'arbre
                $reussite_autocommit = Cel::db()->executer("SET AUTOCOMMIT = 1");

                echo 'OK';
        }
        
        /**
         * Annule la transaction et réactive l'auto-commit
         */
        static function annulerTransaction() {
                // Annule la transaction
                $reussite_rollback = Cel::db()->executer("ROLLBACK");
                // Réactive l'autocommit le temps de la manipulation de l'arbre
                $reussite_autocommit = Cel::db()->executer("SET AUTOCOMMIT = 1");

                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 bd, bg, niveau '.
                                        'FROM cel_mots_cles'.$this->suffixe_table.' '.
                                        'WHERE id_mot_cle'.$this->suffixe_champ.' = '.Cel::db()->proteger($id_mot_cle).' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                
                $resultat = Cel::db()->requeter($requete);
                
                $valeurs = null;
                if(is_array($resultat) && count($resultat) > 0) {
                        $valeurs = $resultat[0];
                }
                
                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->suffixe_table.' '.
                                        'SET bd = bd + 2 WHERE bd >= '.$valeur.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                $reussi_1 = Cel::db()->executer($requete);
                
                // Décalage borne gauche
                $requete =      'UPDATE cel_mots_cles'.$this->suffixe_table.' '.
                                        'SET bg = bg + 2 '.
                                        'WHERE bg >= '.$valeur.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                $reussi_2 = Cel::db()->executer($requete);
                
                return $reussi_1 !== false && $reussi_2 !== false;
        }

        /**
         * 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->suffixe_table.' '.
                                        'SET bd = bd - '.$decalage.' '.
                                        'WHERE bd >=  '.$bg.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                $reussi_1 = Cel::db()->executer($requete);

                // Décalage borne gauche
                $requete =      'UPDATE cel_mots_cles'.$this->suffixe_table.' '.
                                        'SET bg = bg - '.$decalage.' '.
                                        'WHERE bg >  '.$bg.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                $reussi_2 = Cel::db()->executer($requete);
                
                return $reussi_1 !== false && $reussi_2 !== false;
        }

        /**
         * 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->suffixe_table.' '.
                                        'SET bd = bd + '.$decalage.' '.
                                        'WHERE bd >=  '.$valeur_bornes.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                $reussi_1 = Cel::db()->executer($requete);

                // decalage borne gauche
                $requete =      'UPDATE cel_mots_cles'.$this->suffixe_table.' '.
                                        'SET bg = bg + '.$decalage.' '.
                                        'WHERE bg >=  '.$valeur_bornes.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';
                $reussi_2 = Cel::db()->executer($requete);

                return $reussi_1 !== false && $reussi_2 !== false;
        }

        /**
         * 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->suffixe_table.' '.
                                        'SET bd = bd - '.$bd.' - 1 , '.
                                        '       bg =  bg -  '.$bd.' - 1 '.
                                        'WHERE bd <=  '.$bd.' '.
                                        '       AND bg >=  '.$bg.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';

                return Cel::db()->executer($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->suffixe_table.' '.
                                        'SET bg =  bg + '.$decalage.' , '.
                                        '       bd = bd + '.$decalage.', '.
                                        '       niveau = niveau + '.$modif_niveau.' '.
                                        ' WHERE bg >=  '.$bg.' '.
                                        '       AND bd <=  '.$bd.' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';

                return Cel::db()->executer($requete);
        }

        private function changerPere($id_mot_cle, $id_pere, $id_utilisateur) {
                $requete =      'UPDATE cel_mots_cles'.$this->suffixe_table.' '.
                                        'SET ce_mot_cle'.$this->suffixe_champ.'_parent = '.Cel::db()->proteger($id_pere).' '.
                                        'WHERE id_mot_cle'.$this->suffixe_champ.' = '.Cel::db()->proteger($id_mot_cle).' '.
                                        '       AND id_utilisateur = '.Cel::db()->proteger($id_utilisateur).' ';

                return Cel::db()->executer($requete);
        }
 }
?>