Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

<?php
/**
 * Permet de mettre à jour les contours à partir d'un fichier de diff.
 *
 * Exemple de lancement du script :
 * /opt/lampp/bin/php -d memory_limit=3500M cli.php osm -a maj -f fichier_osm_change -e fichier_osm_nouveau
 */
class MiseAJour {
        private $conteneur;
        private $bdd;
        private $messages;
        private $mode;

        private $communes = array();
        private $relations_communes = array();
        private $relation_a_chemins = array();
        private $chemin_a_noeuds = array();
        private $noeuds = array();
        private $pas = 10000;
        private $pas_commune = 1000;
        private $elementType = '';

        public function __construct($conteneur) {
                $this->conteneur = $conteneur;
                $this->bdd = $this->conteneur->getBdd();
                $this->messages = $this->conteneur->getMessages();
                $this->mode = $this->conteneur->getParametre('m');
        }

        /**
         * Fonction qui parcourt tous les ways les noeuds de chaque relation en prenant en considération l'ordre et
         * le sens de chaque ways concaténés ensemble (séparés par des virgules). Update du champ polygone de chaque
         * relation dans la table `osm_relations`
         */
        public function executer() {
                // Lancement de l'action demandée
                $cmd = $this->conteneur->getParametre('a');
                switch ($cmd) {
                        case 'maj' :
                                $this->mettreAjour();
                                break;
                        default :
                                $msgTpl = "Erreur : la commande '%s' n'est pas prise en compte par la classe %s !";
                                $msg = sprintf($msgTpl, $cmd, get_class($this));
                                throw new Exception($msg);
                }
                print "\n";// Pour ramener à la ligne en fin de script
        }

        /**
         * Fonction permettant de traiter et d'analyser le fichier de différence et de mettre  à jour la base de données
         * en tenant compte des trois cas:Suppression, Création ,modification
        */
        private function mettreAjour() {
                $lecteur = $this->getLecteurXml();
                while ($lecteur->read()) {
                        if ($lecteur->nodeType == XMLREADER::ELEMENT) {
                                $this->elementType = $lecteur->localName;
                                $this->analyserElementXml($lecteur->localName, $lecteur->expand());
                        }

                        if ($this->mode == 'manuel') {
                                $this->messages->afficherAvancement("Analyse de la ligne du fichier de diff OSM : ", 1);
                        }
                }
        }

        private function getLecteurXml() {
                $fichierOsm = $this->conteneur->getParametre('f');
                $lecteur = new XMLReader();
                $ouvertureXmlOk = $lecteur->open($fichierOsm);
                if ($ouvertureXmlOk === false) {
                        $msgTpl = "Impossible d'ouvrir le fichier osm : %s";
                        $msg = sprintf($msgTpl, $this->conteneur->getParametre('f'));
                        new Exception($msg);
                }
                return $lecteur;
        }

        private function analyserElementXml($noeudDom) {
                $relations = $noeudDom->getElementsByTagName('relation');
                if ($relations->length > 0) {
                        foreach ($relations as $relation) {
                                $this->analyserRelation($relation);
                                $this->traiterRelations();
                        }
                }

                $ways = $creations->getElementsByTagName('way');
                if ($ways->length > 0) {
                        foreach ($ways as $way) {
                                $this->analyserWay($way);
                                $this->traiterCheminANoeuds();
                        }
                }

                $noeuds = $creations->getElementsByTagName('node');
                if ($noeuds->length > 0) {
                        foreach ($noeuds as $noeud) {
                                $this->analyserNode($noeud);
                                $this->traiterNoeuds();
                        }
                }

                $this->traiterElementsOrphelins();
        }

        private function traiterRelations() {
                if (count($this->relation_a_chemins) > $this->pas) {
                        switch ($this->elementType) {
                                case 'create' :
                                        $this->insererRelationAChemins();
                                        break;
                                case 'modify' :
                                        $this->modifierRelationAChemins();
                                        break;
                                case 'delete' :
                                        $this->supprimerRelationAChemins();
                                        break;
                        }
                }
                if (count($this->relations_communes) > $this->pas_commune) {
                        switch ($this->elementType) {
                                case 'create' :
                                        $this->insererRelationsCommunes();
                                        break;
                                case 'modify' :
                                        $this->modifierRelationsCommunes();
                                        break;
                                case 'delete' :
                                        $this->supprimerRelationsCommunes();
                                        break;
                        }
                }
        }

        private function traiterChemins() {
                if (count($this->chemin_a_noeuds) > $this->pas) {
                        switch ($this->elementType) {
                                case 'create' :
                                        $this->insererCheminANoeuds();
                                        break;
                                case 'modify' :
                                        $this->modifierCheminANoeuds();
                                        break;
                                case 'delete' :
                                        $this->supprimerCheminANoeuds();
                                        break;
                        }
                }
        }

        private function traiterNoeuds() {
                if (count($this->noeuds) > $this->pas) {
                        switch ($this->elementType) {
                                case 'create' :
                                        $this->insererNoeuds();
                                        break;
                                case 'modify' :
                                        $this->modifierNoeuds();
                                        break;
                                case 'delete' :
                                        $this->supprimerNoeuds();
                                        break;
                        }
                }
        }

        private function traiterElementsOrphelins() {
                switch ($this->elementType) {
                        case 'create' :
                                $this->insererRelationsCommunes();
                                $this->insererRelationAChemins();
                                $this->insererCheminANoeuds();
                                $this->insererNoeuds();
                                break;
                        case 'modify' :
                                $this->modifierRelationsCommunes();
                                $this->modifierRelationAChemins();
                                $this->modifierCheminANoeuds();
                                $this->modifierNoeuds();
                                break;
                        case 'delete' :
                                $this->supprimerRelationsCommunes();
                                $this->supprimerRelationAChemins();
                                $this->supprimerCheminANoeuds();
                                $this->supprimerNoeuds();
                                break;
                }
        }

        /**
         * Récupère l'id commune, nom commune et le code INSEE et remplie la table `osm_relations`
         */
        private function analyserRelation($relation) {
                $relation_id = $relation->getAttribute('id');
                $chemins = $relation->getElementsByTagName('member');
                foreach ($chemins as $chemin) {
                        if ($chemin->getAttribute('type') == 'way') { //écarter le noeud centrale
                                $chemin_id = $chemin->getAttribute('ref');
                                $role = $chemin->getAttribute('role');//role: null, inner, outer, exclave et enclave.
                                $this->relation_a_chemins[] = array($relation_id, $chemin_id, $role);
                        }
                }

                $tags = $relation->getElementsByTagName('tag');
                if ($tags->length > 0) {
                        $this->analyserTags($relation_id, $tags);
                }
        }

        private function analyserTags($relation_id, $tags) {
                $commune_nom = null;
                $commune_insee = null;
                foreach ($tags as $tag) {
                        $tag_cle = $tag->getAttribute('k');
                        $tag_val = $tag->getAttribute('v');
                        switch ($tag_cle) {
                                case 'name' :
                                        $commune_nom = $tag_val;
                                        break;
                                case 'ref:INSEE' :
                                        $commune_insee = $tag_val;
                                        break;
                        }
                        if (!is_null($commune_nom) && !is_null($commune_insee)) {
                                $this->relations_communes[] = array($relation_id, $commune_nom, $commune_insee);
                                if (!isset($this->communes[$commune_insee])) {
                                        $this->communes[$commune_insee] = $relation_id;
                                } else {
                                        $e = "La relation #%s contient déjà le tag ref:INSEE avec la valeur %s.".
                                                "Veuillez corriger la carte OSM.";
                                        $this->traiterErreur($e, array($this->communes[$commune_insee], $commune_insee, $relation_id));
                                }
                                break;
                        }
                }
        }

        /**
         * Récupère l'id_way et tous les id_node de chaque way et remplie la table `osm_chemin_a_noeuds`
         */
        private function analyserWay($way) {
                $chemin_id = $way->getAttribute('id');
                $noeuds = $way->getElementsByTagName('nd');
                $ordre = 0;
                foreach ($noeuds as $noeud) {
                        $noeud_id = $noeud->getAttribute('ref');
                        $this->chemin_a_noeuds[] = array($chemin_id, $noeud_id, ++$ordre);
                }
        }

        /**
         * Fonction qui récupère tous les l'id_node et les valeurs(Lat/Lon) correspondantes et remplie la table `osm_noeuds`
         */
        private function analyserNode($node) {
                $this->noeuds[] = array(
                        $node->getAttribute('id'),
                        $node->getAttribute('lat'),
                        $node->getAttribute('lon')
                );
        }

        //Insertion des relations
        private function insererRelationsCommunes() {
                $requete = 'INSERT INTO osm_relations (id_relation, nom, code_insee) '.
                        'VALUES '.$this->creerValuesMultiple($this->relations_communes).
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
                $this->relations_communes = array();
        }

        //Insertion des relations à chemins
        private function insererRelationAChemins() {
                $requete = 'INSERT INTO osm_relation_a_chemins (id_relation, id_chemin, role) '.
                        'VALUES '.$this->creerValuesMultiple($this->relation_a_chemins).
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
                $this->relation_a_chemins = array();
        }

        //Insertion des chemins à noeuds
        private function insererCheminANoeuds() {
                $requete = 'INSERT INTO osm_chemin_a_noeuds (id_chemin, id_noeud, ordre) '.
                        'VALUES '.$this->creerValuesMultiple($this->chemin_a_noeuds).
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
                $this->chemin_a_noeuds = array();
        }

        //Insertion des noeuds
        private function insererNoeuds() {
                $requete = 'INSERT INTO osm_noeuds (id_noeud, lat, `long`) '.
                        'VALUES '.$this->creerValuesMultiple($this->noeuds).
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
                $this->noeuds = array();
        }

        //Update des relations
        private function modifierRelationsCommunes() {
                foreach ($this->relations_communes as $donnee) {
                        $infosP = $this->bdd->proteger($donnee);
                        $requete = 'UPDATE osm_relations '.
                                "SET id_relation = $infosP[0], nom = $infosP[1], code_insee = $infosP[2] ".
                                "WHERE id_relation = $infosP[0] ".
                                ' -- '.__FILE__.' : '.__LINE__;
                        $this->bdd->requeter($requete);
                }
                $this->relations_communes = array();
        }

        /*
        *Update des relations à chemins en supprimant l'ancienne relation et tous ses chemins
        *de la table osm_relation_a_chemins et insérer la nouvelle
        */
        private function modifierRelationAChemins() {
                $this->supprimerRelationAChemins();
                foreach ($this->relation_a_chemins as $donnee) {
                        $infosP = $this->bdd->proteger($donnee);
                        $requete = 'INSERT INTO osm_relation_a_chemins (id_relation, id_chemin, role) '.
                                "VALUES ($infosP[0], $infosP[1], $infosP[2]) ".
                                ' -- '.__FILE__.' : '.__LINE__;
                        $this->bdd->requeter($requete);
                }
                $this->relation_a_chemins = array();
        }

        /*
        *Update des chemins à noeuds en supprimant l'ancien chemin et tous ses noeuds
        *de la table osm_chemins_a_noeuds et insérer le nouveau
        */
        private function modifierCheminANoeuds() {
                $this->supprimerCheminANoeuds();
                foreach ($this->chemin_a_noeuds as $donnee) {
                        $infosP = $this->bdd->proteger($donnee);
                        $requete = 'INSERT INTO osm_chemin_a_noeuds (id_chemin, id_noeud, ordre) '.
                                "VALUES ($infosP[0], $infosP[1], $infosP[2]) ".
                                ' -- '.__FILE__.' : '.__LINE__;
                        $this->bdd->requeter($requete);
                }
                $this->chemin_a_noeuds = array();
        }

        //Update des noeuds
        private function modifierNoeuds() {
                foreach ($this->noeuds as $donnee) {
                        $infosP = $this->bdd->proteger($donnee);
                        $requete = 'UPDATE osm_noeuds '.
                                "SET id_noeud = $infosP[0], lat = $infosP[1], `long` = $infosP[2] ".
                                "WHERE id_noeud = $infosP[0] ".
                                ' -- '.__FILE__.' : '.__LINE__;
                        $this->bdd->requeter($requete);
                }
                $this->noeuds = array();
        }

        //Suppressions des relations
        private function supprimerRelationsCommunes() {
                $idsIn = $this->getIds($this->relations_communes);
                $this->relations_communes = array();
                $requete = 'DELETE FROM osm_relations '.
                        "WHERE id_relation IN ($idsIn) ".
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
        }

        //Suppressions des relations à chemins
        private function supprimerRelationAChemins() {
                $idsIn = $this->getIds($this->relation_a_chemins);
                $this->relation_a_chemins = array();
                $requete = 'DELETE FROM osm_relation_a_chemins '.
                        "WHERE id_relation IN ($idsIn) ".
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
        }

        //Suppressions des chemins à noeuds
        private function supprimerCheminANoeuds() {
                $idsIn = $this->getIds($this->chemin_a_noeuds);
                $this->chemin_a_noeuds = array();
                $requete = 'DELETE FROM osm_chemin_a_noeuds '.
                        "WHERE id_chemin IN ($idsIn) ".
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
        }

        //Suppressions des chemins à noeuds
        private function supprimerNoeuds() {
                $idsIn = $this->getIds($this->noeuds);
                $this->noeuds = array();
                $requete = 'DELETE FROM osm_noeuds '.
                        "WHERE id_noeud IN ($idsIn) ".
                        ' -- '.__FILE__.' : '.__LINE__;
                $this->bdd->requeter($requete);
        }

        private function getIds(&$tableau) {
                $ids = array();
                foreach ($tableau as $info) {
                        $ids[] = $this->bdd->proteger($info[0]);
                }
                $idsSansDoublon = array_unique($ids);
                $idsIn = implode(',', $idsSansDoublon);
                return $idsIn;
        }

        private function creerValuesMultiple($donnees) {
                $values = array();
                foreach ($donnees as $infos) {
                        $infosP = $this->bdd->proteger($infos);
                        $values[] = implode(',', $infosP);
                }
                $valuesClause = '('.implode('),(', $values).')';
                return $valuesClause;
        }
}