Subversion Repositories eFlore/Applications.cel

Rev

Rev 1696 | Rev 1703 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

<?php
/**
* Service fournissant des informations concernant le CEL au format RSS1, RSS2 ou ATOM.
* Encodage en entrée : utf8
* Encodage en sortie : utf8
* Format du service :
* /CelWidgetExport/format
* /CelWidgetExport/csv
*
* Les paramêtres :
*  - "start" indique le numéro du premier item à afficher
*  - "limit" nombre d'items à afficher
*
* @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 2012
*/

set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
// la sortie est binaire (xls), mais OLE n'est pas compatible E_ALL en PHP-5.4
error_reporting(error_reporting() & ~E_STRICT);
require_once("lib/OLE.php");
require_once("lib/Spreadsheet/Excel/Writer.php");

class CelWidgetExport extends Cel {
        
        private $nom_fichier_export = 'cel_export';
        // certains paramètres apparaissent plusieurs fois car ils ont des alias
        // dans certains widgets
        private $parametres_autorises = array(
                'id_utilisateur' => 'ce_utilisateur',
                'utilisateur' => 'courriel_utilisateur',
                'commune' => 'zone_geo',
                'zone_geo' => 'zone_geo',
                'dept' => 'departement',
                'departement' => 'departement',
                'lieudit' => 'lieudit',
                'station' => 'station',
                'projet' => 'mots_cles',
                'num_taxon' => 'nt',
                'date_debut' => 'date_debut',
                'date_fin' => 'date_fin',
                'taxon' => 'taxon',
                'annee' => 'annee',
                'mois' => 'mois',
                'jour' => 'jour',
                'recherche' => 'recherche',
                'id_mots_cles' => 'id_mots_cles',
                'mots_cles' => 'mots_cles',
                'debut' => 'debut',
                'limite' => 'limite',
                'format' => 'format',
                'colonnes' => 'colonnes',
                'transmission' => 'transmission',
                'obsids' => 'obsids',
        );
        
        private $limite_decoupage_defaut = 9000; 
        
        private $format = 'csv';
        
        public $id_utilisateur = null;
        
        public function getRessource() {
                return $this->getElement(array());
        }
                
        /**
         * Méthode appelée avec une requête de type GET.
         */
        public function getElement($params = array()) {         
                if(count($params) > 0) {
                        switch(strtolower($params[0])) {
                                case 'calcul':
                                        $this->getCalcul();
                                break;
                                
                                case 'export':
                                        $this->getExport();
                                break;
                                
                                default:
                                        $this->getExport();
                        }
                } else {
                        $this->getExport();
                }
        }
        
        private function getCalcul() {
                $criteres = $this->traiterParametresAutorises($_GET);

                $criteres['transmission'] = 1;
                if($this->doitEtPeutExporterObsPrivees($criteres)) {
                        unset($criteres['transmission']);
                        $this->id_utilisateur = $criteres['id_utilisateur'];
                }
                $chercheur_observations = new RechercheObservation($this->config);
                
                $numero_page = isset($criteres['debut']) ? $criteres['debut'] : 0;
                $limite = isset($criteres['limite']) ? $criteres['limite'] : 0;
                $colonnes = isset($criteres['colonnes']) ? $criteres['colonnes'] : 'standard,avance';
                
                unset($criteres['limite']);
                unset($criteres['debut']);
                unset($criteres['format']);
                unset($criteres['colonnes']);
                
                $nb_observations = $chercheur_observations->compterObservations(null, $criteres);
                $limite_decoupage = $this->calculerNbLignesMaxParFichier();
                
                $url_telechargements = array();
                $intervalle = 0;
                
                $params_url = $criteres;
                unset($params_url['transmission']);
                do {
                        $base_url = $this->config['settings']['baseURLAbsolu'].'CelWidgetExport/export';
                        $params_url['debut'] = $intervalle;
                        $params_url['limite'] = $limite_decoupage;
                        $url_telechargement_fichier = $base_url;
                        $url_telechargements[] = $base_url.'?'.http_build_query($params_url).'&format='.$this->format.'&colonnes='.$colonnes;
                        $intervalle += $limite_decoupage;
                        $nb_observations -= $limite_decoupage;
                } while($nb_observations >= $limite_decoupage);
                
                $this->envoyerJson($url_telechargements);
        }
        
        private function calculerNbLignesMaxParFichier() {
                $limite = $this->limite_decoupage_defaut;
                switch($this->format) {
                        case 'csv':
                                $limite = 20000;
                                break;
                        case 'xls':
                                $limite = 8000;
                                break;
                        case 'pdf':
                                $limite = 300;
                                break;
                }
                return $limite;
        }
        
        private function getExport() {
                $criteres = $this->traiterParametresAutorises($_GET);
                $criteres['transmission'] = 1;
                if($this->doitEtPeutExporterObsPrivees($criteres)) {
                        unset($criteres['transmission']);
                }
                $chercheur_observations = new RechercheObservation($this->config);
                
                $debut = isset($criteres['debut']) ? intval($criteres['debut']) : 0;
                $limite = isset($criteres['limite']) ? intval($criteres['limite']) : 0;
                $colonnes = isset($criteres['colonnes']) ? $criteres['colonnes'] : 'standard,avance';

                if($criteres['obsids']) $criteres['sql_brut'] = sprintf('id_observation IN (%s)',
                                                                                                                                implode(',', $criteres['obsids']));
                
                unset($criteres['limite']);
                unset($criteres['debut']);
                unset($criteres['format']);
                unset($criteres['colonnes']);
                unset($criteres['obsids']);

                $observations = $chercheur_observations->rechercherObservations(null, $criteres, $debut, $limite, TRUE)->get();
                $ids = array();
                foreach($observations as &$obs) {
                        $ids[] = $obs['id_observation'];
                }

                if($this->format != 'pdf') {
                        $gestion_champs_etendus = new GestionChampsEtendus($this->config, 'obs');
                $champs_supp_par_obs = $gestion_champs_etendus->consulterParLots($ids);
                $colonnes_champs_supp_par_obs = $gestion_champs_etendus->consulterClesParLots($ids);
                        // $cache pourrait être utilisé par les fonctions de colonnes
                        // * Pour "nom commun", "preload" retourne NULL, car c'est le cache statique de FormateurGroupeColonne
                        // qu'il initialise et utilise en interne sans qu'un passage par paramètre ne soit nécessaire
                        $cache = FormateurGroupeColonne::preload(FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes),
                                                                                                         $this,
                                                                                                         $ids);
                }

        // TODO: tous les champs étendus et les paramètres supplémentaires devraient être passés en un seul
        // tableau (et chaque formateur csv, xls etc... pourrait également être dans une classe à part)
                switch($this->format) {
                case 'csv':
                        $csv = $this->convertirEnCsv($observations, $colonnes, $colonnes_champs_supp_par_obs, $champs_supp_par_obs);
                        $this->envoyerCsv($csv);
                        break;
                case 'xls':
                        $xls = $this->convertirEnXls($observations, $colonnes, $colonnes_champs_supp_par_obs, $champs_supp_par_obs);
                        $this->envoyerXls($xls);
                        break;
                case 'pdf':
                        $pdf = $this->convertirEnPdf($observations);
                        $this->envoyerPdf($pdf);
                        break;
                default:
                }
        }
        
        protected function traiterParametresAutorises(Array $parametres) {
                $parametres_traites = array();
                $this->format = (isset($parametres['format']) && $parametres['format'] != '') ? $parametres['format'] : $this->format;
                foreach($parametres as $cle => $valeur) {
                        if(trim($valeur) != '' && isset($this->parametres_autorises[$cle])) {
                                $parametres_traites[$this->parametres_autorises[$cle]] = $valeur;
                        }
                }
                $parametres_traites['obsids'] = @self::traiterObsIds($parametres['obsids']);
                return $parametres_traites;
        }
        
        private function envoyerCsv($csv) {
                header('Content-Type: text/csv; charset=UTF-8');
                header('Content-Disposition: attachment;filename='.$this->nom_fichier_export.'.csv');
                echo $csv;
                exit;
        }
        
        private function envoyerXls($workbook) {
                $workbook->close();
                exit;
        }
        
        private function convertirEnCsv(&$data, &$colonnes, &$colonnes_supplementaires, &$champs_supplementaires = array()) {
                $chemin_temp = "php://temp";
                $outstream = fopen($chemin_temp, 'r+');

                $groupe_colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes);

                $intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($groupe_colonnes),
                                                                           array_values($colonnes_supplementaires));

                // header
                fputcsv($outstream, $intitule_champs, ',', '"');                        
                // lignes
                foreach($data as &$ligne) {
                        $id_obs = $ligne['id_observation'];
                        $ligne = self::filtrerDonneesSensibles($ligne);
                        $ligne = FormateurGroupeColonne::getLigneObservation($ligne, $groupe_colonnes, $this);
                        $ligne_etendue_aplatie = self::aplatirChampsEtendus($champs_supplementaires[$id_obs]);
                        self::traiterLigneEtendue($ligne, $colonnes_supplementaires, $ligne_etendue_aplatie);
                        fputcsv($outstream, $ligne, ',', '"');
                }
                rewind($outstream);
                $csv = stream_get_contents($outstream);
                fclose($outstream);
                return $csv;
        }
        
        private function convertirEnXls(&$data, &$colonnes,  &$colonnes_supplementaires, &$champs_supplementaires = array()) {          
                $this->extendSpreadsheetProductor = new SpreadsheetProductor();
                $this->extendSpreadsheetProductor->initSpreadsheet();
                
                $workbook = new Spreadsheet_Excel_Writer();
                $worksheet = $workbook->addWorksheet('Liste');
                $workbook->setTempDir($this->config['cel']['chemin_stockage_temp']);
                $workbook->setVersion(8);

                $worksheet->setInputEncoding('utf-8');
                $workbook->send($this->nom_fichier_export.'.xls');
                
                $nb_lignes = 1;
                $groupe_colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($colonnes);
                $intitule_champs = array_merge(FormateurGroupeColonne::getIntitulesColonnes($groupe_colonnes),
                                                                           array_values($colonnes_supplementaires));

                // header
                $indice = 0;
                foreach ($intitule_champs as &$intitule) {      
                        $worksheet->write(0,$indice++,$intitule);
                }

                foreach($data as &$ligne) {
                        $id_obs = $ligne['id_observation'];
                        $ligne = self::filtrerDonneesSensibles($ligne);
                        $ligne = FormateurGroupeColonne::getLigneObservation($ligne, $groupe_colonnes, $this);

                        $ligne_etendue_aplatie = self::aplatirChampsEtendus($champs_supplementaires[$id_obs]);
                        $ligne_supp = self::traiterLigneEtendue($ligne, $colonnes_supplementaires, $ligne_etendue_aplatie);
                        $indice = 0;
                        foreach($ligne as &$champ) {
                                $worksheet->write($nb_lignes,$indice++,$champ);
                        }
                        $nb_lignes++;
                }
                return $workbook;
        }
        
        private function convertirEnPdf(&$observations) {
                if(count($observations) > 300) die('trop de données');
                //require_once('GenerateurPDF.php');
                $pdf = new GenerateurPDF();
                $pdf->export($observations);
                return $pdf;
        }
        
        private function envoyerPdf(&$pdf) {
                $pdf->pdf->Output('etiquettes.pdf', 'I');
                exit;;
        }
        
        static function traiterLigneEtendue(&$ligne, &$colonnes_etendues, $ligne_etendue_aplatie) {
                if(! $colonnes_etendues) return;
                if(! $ligne_etendue_aplatie) return;
                $nb_colonnes_supp = count($colonnes_etendues);

                $ligne_supp = array_fill(0, $nb_colonnes_supp, '');
                $ligne_etendue_fmt = array();

                foreach($colonnes_etendues as $colonne) {
                        if(!isset($ligne_etendue_aplatie[$colonne])) {
                                $ligne_etendue_fmt[$colonne] = ''; 
                        } else {
                                $ligne_etendue_fmt[$colonne] = $ligne_etendue_aplatie[$colonne];
                        }
                }

                $ligne += $ligne_etendue_fmt;
        }
        
        static function aplatirChampsEtendus(&$ligne_champs_etendus) {
                $champs_etendus_fmt = array();
                if(!$ligne_champs_etendus) return $champs_etendus_fmt;
                foreach($ligne_champs_etendus as $champ) {
                        $champs_etendus_fmt[$champ->cle] = $champ->valeur;
                }
                return $champs_etendus_fmt;
        }
        
        static function filtrerDonneesSensibles($ligne) {
                if(stripos($ligne['mots_cles_texte'], 'sensible') !== false) {
                        $ligne['latitude'] = '';
                        $ligne['longitude'] = '';
                }
                return $ligne;
        }
        
        private function doitEtPeutExporterObsPrivees($criteres) {
                return isset($criteres['ce_utilisateur']) && 
                                        $this->peutExporterObsPrivees($criteres['ce_utilisateur']);
        }
        
        private function peutExporterObsPrivees($id_utilisateur) {
                $gestion_utilisateur = new User($this->config);
                $utilisateur = $gestion_utilisateur->obtenirIdentiteConnectee();
                return $utilisateur['connecte'] && 
                                $utilisateur['id_utilisateur'] != '' &&
                                $id_utilisateur == $utilisateur['id_utilisateur'];
        }

        static function traiterObsIds($range_param) {
                if (!isset($range_param)) return NULL;
                // trim() car: `POST http://url<<<"range=*"`
                if (trim($range_param) == '*') return NULL;
                return self::rangeToList(trim($range_param));
        }

        /*
         * @param $fieldSets: un range, eg: 1-5,8,32,58-101
         * @return un tableau trié, eg: 1,2,3,4,5,8,32,58,...,101
         * http://stackoverflow.com/questions/7698664/converting-a-range-or-partial-array-in-the-form-3-6-or-3-6-12-into-an-arra
         */
        static function rangeToList($in = '') {
                $inSets = explode(',', trim($in, ','));
                $outSets = array();

                foreach($inSets as $inSet) {
                        list($start,$end) = explode('-', $inSet . '-' . $inSet);
                        // ignore les ranges trop importants
                        if($start > 10000000 || $end > 10000000 || abs($start-$end) > 10000) continue;
                        $outSets = array_merge($outSets,range($start,$end));
                }
                $outSets = array_unique($outSets);
                $outSets = array_filter($outSets, 'is_numeric');
                sort($outSets);
                return $outSets;
        }
}
?>