* TODO: GET /ExportXLS/ [ sans "range" ? ] * * Les données POST acceptées sont: * range (obligatoire): un range d'id_observation sous la forme d'entier ou d'intervalles d'entiers * séparés par des virgules ou bien '*' (pour toutes) * TODO: limit * TODO: départ * TODO: sets (ou colonnes, ou extended) * TODO: + les critères supportés par fabriquerSousRequeteRecherche() * * Si est fourni, celui-ci doit être authentifié * TODO: export des données public et non-sensible d'un utilisateur * * Si est fourni, le observations seront le résultat de l'intersection des 2 contraintes * * @internal Mininum PHP version : 5.2 * @category CEL * @package Services * @subpackage Observations * @version 0.1 * @author Mathias CHOUET * @author Raphaël Droz * @author Jean-Pascal MILCENT * @author Aurelien PERONNET * @license GPL v3 * @license CECILL v2 * @copyright 1999-2014 Tela Botanica */ set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib'); ini_set('html_errors', 0); ini_set('xdebug.cli_color', 2); require_once 'lib/PHPExcel/Classes/PHPExcel.php'; require_once 'lib/FormateurGroupeColonne.php'; class ExportXLS extends Cel { private $id_utilisateur = NULL; private $parametres_defaut = array('range' => '*', 'format' => 'CSV'); private $filtres_autorises = array( 'id_utilisateur' => 'id_utilisateur', 'utilisateur' => 'courriel_utilisateur', 'commune' => 'zone_geo', 'dept' => 'departement', 'projet' => 'mots_cles', 'num_taxon' => 'nt', 'date_debut' => 'date_debut', 'date_fin' => 'date_fin', 'taxon' => 'taxon' ); public function __construct($config) { parent::__construct($config); } public function getRessource() { return $this->getElement(array()); } public function getElement($uid) { $parametres_format = $this->traiterParametresFormat($uid, $_GET); $filtres = $this->traiterFiltres($_GET); $this->export($parametres_format, $filtres); exit(); } private function traiterParametresFormat($uid, $params) { $parametres = $this->parametres_defaut; if (isset($params['format'])) { if($params['format'] == 'csv') $parametres['format'] = 'CSV'; if($params['format'] == 'xls') $parametres['format'] = 'Excel5'; if($params['format'] == 'xlsx') $parametres['format'] = 'Excel2007'; if($params['format'] == 'pdf') $parametres['format'] = 'pdf'; } // TODO: $params['part'] pour le multi-part $parametres['widget'] = isset($params['widget']) ? $params['widget'] : 'CEL'; $parametres['debut'] = isset($params['debut']) ? intval($params['debut']) : 0; $parametres['limite'] = isset($params['limite']) ? intval($params['limite']) : 0; $parametres['id_utilisateur'] = $this->traiterIdUtilisateur($uid); $parametres['groupe_champs'] = isset($params['colonnes']) ? $params['colonnes'] : 'standard,avance'; return $parametres; } private function traiterIdUtilisateur($uid) { $id_utilisateur = null; // TODO: controleUtilisateur() if (isset($uid[0])) { $id_utilisateur = intval($uid[0]); } return $id_utilisateur; } private function traiterFiltres($params) { $obs_ids = $this->traiterObsIds($params); $filtres = array(); if (!$obs_ids || count($obs_ids) == 1 && $obs_ids[0] == '*') { unset($filtres['sql_brut']); } else { $filtres = Array('sql_brut' => sprintf('id_observation IN (%s)', implode(',', $obs_ids))); } foreach ($params as $cle => $valeur) { if (trim($valeur) != '' && isset($this->filtres_autorises[$cle])) { $filtres[$this->filtres_autorises[$cle]] = $valeur; } } return $filtres; } private function traiterObsIds($params) { $obs_ids = Array('*'); if (isset($params['range']) && trim($params['range']) != '*') { // trim() car: `POST http://url<<<"range=*"` $obs_ids = self::rangeToList(trim($params['range'])); } return $obs_ids; } /* * $param: Tableau associatif, indexes supportés: * - widget: le nom du widget d'origine (utilisé pour les méta-données du tableur) * */ private function export(Array $parametres_format = Array(),Array $filtres = array()) { $chercheur_observations = new RechercheObservation($this->config); $observations = $chercheur_observations ->rechercherObservations($parametres_format['id_utilisateur'], $filtres, $parametres_format['debut'], $parametres_format['limite'], TRUE) ->get(); // debug //echo ($chercheur_observations->requete_selection_observations); // XXX: malheureusement l'instance de JRest n'est pas accessible ici if (!$observations) { header('HTTP/1.0 204 No Content'); exit(); } if ($parametres_format['format'] == 'pdf') { if (count($observations) > 300) { die('too much'); } require_once('GenerateurPDF.php'); $pdf = new GenerateurPDF(); $pdf->export($observations); //$pdf->export1($observations); //$pdf->export2($observations); $pdf->pdf->Output('etiquettes.pdf', 'I'); die(); } $colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($parametres_format['groupe_champs']); // $colonne_abbrev = array_keys($colonnes); $objPHPExcel = $this->gerenerFeuilleImportFormatee($parametres_format); $feuille = $objPHPExcel->setActiveSheetIndex(0); // attention formaterColonnesFeuille prend ses 2 premiers paramètres par référence $this->formaterColonnesFeuille($feuille, $colonnes, $parametres_format); $objPHPExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(12); $no_ligne = 2; foreach ($observations as $obs) { // attention traiterLigneObservation prend ses 3 premiers paramètres par référence $this->traiterLigneObservation($obs, $colonnes, $feuille, $no_ligne); $no_ligne++; } $this->envoyerFeuille($objPHPExcel, $parametres_format); } private function envoyerFeuille($objPHPExcel, $parametres_format) { header('Content-Type: application/vnd.ms-excel'); header('Content-Disposition: attachment; filename="liste.xls"; charset=utf-8'); header('Cache-Control: max-age=0'); // csv|xls|xlsx => CSV|Excel5|Excel2007 // Note: le format Excel2007 utilise un fichier temporaire $generateur = PHPExcel_IOFactory::createWriter($objPHPExcel, $parametres_format['format']); $generateur->save('php://output'); exit; } private function traiterLigneObservation(&$obs, &$colonnes, &$feuille, $no_ligne) { $no_colonne = 0; foreach ($colonnes as $abbrev => $colonne) { $valeur = null; if ($colonne['extra'] == 2 || ! is_null($colonne['dyna'])) { continue; } // valeur direct depuis cel_obs ? if (isset($obs[$abbrev])) { $valeur = $obs[$abbrev]; } // pré-processeur de la champs if (function_exists($colonne['fonction'])) { $valeur = $colonne['fonction']($valeur); } else if (method_exists('FormateurGroupeColonne', $colonne['fonction'])) { $valeur = call_user_func(array('FormateurGroupeColonne', $colonne['fonction']), $valeur); } else if (method_exists(__CLASS__, $colonne['fonction'])) { $valeur = call_user_func(array(__CLASS__, $colonne['fonction']), $valeur); } else if ($colonne['fonction']) { die("méthode {$colonne['fonction']} introuvable"); } else if (function_exists($colonne['fonction_data'])) { // fonction pour obtenir des champs (étendus) $valeur = $colonne['fonction_data']($obs); } else if (method_exists(__CLASS__, $colonne['fonction_data'])) { $valeur = call_user_func(array(__CLASS__, $colonne['fonction_data']), $obs); } // // cette section devrait être vide: // // cas particuliers ingérable avec l'architecture actuelle: if (false && $abbrev == 'date_observation' && $valeur == "0000-00-00") { /* blah */ } if ($abbrev == 'images') { $valeur = FormateurGroupeColonne::getImages($obs, $this->id_utilisateur, $this); } if ($abbrev == 'nom-commun') { $valeur = FormateurGroupeColonne::getNomCommun_v4($obs, $this); } // // fin de section "cas particuliers" $feuille->setCellValueByColumnAndRow($no_colonne, $no_ligne, $valeur); $no_colonne++; } } private function gerenerFeuilleImportFormatee($parametres_format) { $objPHPExcel = new PHPExcel(); $objPHPExcel->getProperties()->setCreator($parametres_format['widget']) // ou $uid ? ->setLastModifiedBy("XX") // TODO: $uid ->setTitle("Export des observation du carnet en ligne") // TODO ->setSubject("Export") // TODO ->setDescription("Export"); $objPHPExcel->getActiveSheet()->setTitle("Observations"); return $objPHPExcel; } private function formaterColonnesFeuille(&$feuille, &$colonnes, $parametres_format) { $colid = 0; foreach ($colonnes as $colonne) { if ($colonne['extra'] == 2) { continue; } $feuille->setCellValueByColumnAndRow($colid, 1, $colonne['nom']); if ($colonne['extra'] == 1) { $feuille->getStyleByColumnAndRow($colid, 1)->getBorders()->applyFromArray( array( 'allborders' => array( 'style' => PHPExcel_Style_Border::BORDER_DASHDOT, 'color' => array('rgb' => PHPExcel_Style_Color::COLOR_BLUE) ) ) ); } if (! $colonne['importable']) { $feuille->getStyleByColumnAndRow($colid, 1)->getFill()->applyFromArray( array( 'type' => PHPExcel_Style_Fill::FILL_SOLID, 'color' => array('rgb' => PHPExcel_Style_Color::COLOR_YELLOW) ) ); } $colid++; } } /* * @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(',', $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; } }