1630 |
raphael |
1 |
<?php
|
|
|
2 |
|
|
|
3 |
/**
|
|
|
4 |
* @category PHP
|
|
|
5 |
* @package jrest
|
|
|
6 |
* @author Raphaël Droz <raphael@tela-botania.org>
|
|
|
7 |
* @copyright 2013 Tela-Botanica
|
|
|
8 |
* @license http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
|
|
|
9 |
* @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
|
|
|
10 |
*/
|
|
|
11 |
|
|
|
12 |
/**
|
|
|
13 |
* Service d'export de données d'observation du CEL au format XLS
|
|
|
14 |
*
|
|
|
15 |
* Format du service :
|
|
|
16 |
* POST /ExportXLS
|
|
|
17 |
* POST /ExportXLS/<Utilisateur>
|
|
|
18 |
* TODO: GET /ExportXLS/<Utilisateur> [ sans "range" ? ]
|
|
|
19 |
*
|
|
|
20 |
* Les données POST acceptées sont:
|
|
|
21 |
* range (obligatoire): un range d'id_observation sous la forme d'entier ou d'intervalles d'entiers
|
|
|
22 |
* séparés par des virgules ou bien '*' (pour toutes)
|
|
|
23 |
* TODO: limit
|
|
|
24 |
* TODO: départ
|
|
|
25 |
* TODO: sets (ou colonnes, ou extended)
|
|
|
26 |
* TODO: + les critères supportés par fabriquerSousRequeteRecherche()
|
|
|
27 |
*
|
|
|
28 |
* Si <Utilisateur> est fourni, celui-ci doit être authentifié
|
|
|
29 |
* TODO: export des données public et non-sensible d'un utilisateur
|
|
|
30 |
*
|
|
|
31 |
* Si <Utilisateur> est fourni, le observations seront le résultat de l'intersection des 2 contraintes
|
|
|
32 |
*
|
|
|
33 |
*/
|
|
|
34 |
set_include_path(get_include_path() . PATH_SEPARATOR . dirname(dirname(realpath(__FILE__))) . '/lib');
|
1634 |
raphael |
35 |
// TERM
|
|
|
36 |
ini_set('html_errors', 0);
|
|
|
37 |
ini_set('xdebug.cli_color', 2);
|
|
|
38 |
require_once('lib/PHPExcel/Classes/PHPExcel.php');
|
1656 |
raphael |
39 |
require_once('lib/FormateurGroupeColonne.php');
|
1630 |
raphael |
40 |
|
|
|
41 |
class ExportXLS extends Cel {
|
|
|
42 |
|
1639 |
raphael |
43 |
private $id_utilisateur = NULL;
|
1644 |
aurelien |
44 |
private $parametres_defaut = array("range" => "*",
|
1656 |
raphael |
45 |
"format" => "CSV");
|
1645 |
aurelien |
46 |
|
|
|
47 |
private $filtres_autorises = array(
|
|
|
48 |
'id_utilisateur' => 'id_utilisateur',
|
|
|
49 |
'utilisateur' => 'courriel_utilisateur',
|
|
|
50 |
'commune' => 'zone_geo',
|
|
|
51 |
'dept' => 'departement',
|
|
|
52 |
'projet' => 'mots_cles',
|
|
|
53 |
'num_taxon' => 'nt',
|
|
|
54 |
'date_debut' => 'date_debut',
|
|
|
55 |
'date_fin' => 'date_fin',
|
|
|
56 |
'taxon' => 'taxon'
|
|
|
57 |
);
|
1633 |
raphael |
58 |
|
1630 |
raphael |
59 |
function ExportXLS($config) {
|
|
|
60 |
parent::__construct($config);
|
|
|
61 |
}
|
1644 |
aurelien |
62 |
|
|
|
63 |
function getRessource() {
|
|
|
64 |
return $this->getElement(array());
|
|
|
65 |
}
|
|
|
66 |
|
|
|
67 |
function getElement($uid) {
|
|
|
68 |
$parametres_format = $this->traiterParametresFormat($uid, $_GET);
|
|
|
69 |
$filtres = $this->traiterFiltres($_GET);
|
|
|
70 |
$this->export($parametres_format, $filtres);
|
|
|
71 |
exit;
|
|
|
72 |
}
|
|
|
73 |
|
|
|
74 |
function traiterParametresFormat($uid, $params) {
|
|
|
75 |
$parametres = $this->parametres_defaut;
|
|
|
76 |
if(isset($params['format'])) {
|
|
|
77 |
if($params['format'] == 'csv') $parametres['format'] = 'CSV';
|
|
|
78 |
if($params['format'] == 'xls') $parametres['format'] = 'Excel5';
|
|
|
79 |
if($params['format'] == 'xlsx') $parametres['format'] = 'Excel2007';
|
1630 |
raphael |
80 |
}
|
1644 |
aurelien |
81 |
// TODO: $params['part'] pour le multi-part
|
|
|
82 |
$parametres['widget'] = isset($params['widget']) ? $params['widget'] : 'CEL';
|
|
|
83 |
$parametres['debut'] = isset($params['debut']) ? intval($params['debut']) : 0;
|
|
|
84 |
$parametres['limite'] = isset($params['limite']) ? intval($params['limite']) : 0;
|
|
|
85 |
$parametres['id_utilisateur'] = $this->traiterIdUtilisateur($uid);
|
|
|
86 |
$parametres['groupe_champs'] = null;
|
|
|
87 |
|
|
|
88 |
return $parametres;
|
|
|
89 |
}
|
|
|
90 |
|
|
|
91 |
function traiterIdUtilisateur($uid) {
|
|
|
92 |
$id_utilisateur = null;
|
|
|
93 |
// TODO: controleUtilisateur()
|
|
|
94 |
if(isset($uid[0])) {
|
|
|
95 |
$id_utilisateur = intval($uid[0]);
|
1630 |
raphael |
96 |
}
|
1644 |
aurelien |
97 |
return $id_utilisateur;
|
|
|
98 |
}
|
|
|
99 |
|
|
|
100 |
function traiterFiltres($params) {
|
|
|
101 |
$obs_ids = $this->traiterObsIds($params);
|
|
|
102 |
$filtres = array();
|
|
|
103 |
if(!$obs_ids || count($obs_ids) == 1 && $obs_ids[0] == '*') {
|
|
|
104 |
unset($filtres['sql_brut']);
|
|
|
105 |
}
|
1630 |
raphael |
106 |
else {
|
1644 |
aurelien |
107 |
$filtres = Array('sql_brut' =>
|
|
|
108 |
sprintf('id_observation IN (%s)', implode(',', $obs_ids)));
|
1630 |
raphael |
109 |
}
|
1645 |
aurelien |
110 |
foreach($params as $cle => $valeur) {
|
|
|
111 |
if(trim($valeur) != '' && isset($this->filtres_autorises[$cle])) {
|
|
|
112 |
$filtres[$this->filtres_autorises[$cle]] = $valeur;
|
|
|
113 |
}
|
|
|
114 |
}
|
1644 |
aurelien |
115 |
return $filtres;
|
1630 |
raphael |
116 |
}
|
1644 |
aurelien |
117 |
|
|
|
118 |
|
|
|
119 |
function traiterObsIds($params) {
|
|
|
120 |
$obs_ids = Array('*');
|
|
|
121 |
if (isset($params['range']) && trim($params['range']) != '*') {
|
|
|
122 |
// trim() car: `POST http://url<<<"range=*"`
|
|
|
123 |
$obs_ids = self::rangeToList(trim($params['range']));
|
|
|
124 |
}
|
|
|
125 |
return $obs_ids;
|
|
|
126 |
}
|
1630 |
raphael |
127 |
|
|
|
128 |
/*
|
|
|
129 |
* $param: Tableau associatif, indexes supportés:
|
|
|
130 |
* - widget: le nom du widget d'origine (utilisé pour les méta-données du tableur)
|
|
|
131 |
*
|
|
|
132 |
*/
|
1644 |
aurelien |
133 |
function export(Array $parametres_format = Array(),Array $filtres = array()) {
|
1630 |
raphael |
134 |
$chercheur_observations = new RechercheObservation($this->config);
|
|
|
135 |
|
1632 |
raphael |
136 |
$observations = $chercheur_observations
|
1644 |
aurelien |
137 |
->rechercherObservations($parametres_format['id_utilisateur'], $filtres, $parametres_format['debut'], $parametres_format['limite'], TRUE)
|
1632 |
raphael |
138 |
->get();
|
|
|
139 |
// debug //echo ($chercheur_observations->requete_selection_observations);
|
1630 |
raphael |
140 |
// XXX: malheureusement l'instance de JRest n'est pas accessible ici
|
|
|
141 |
if(!$observations) {
|
|
|
142 |
header('HTTP/1.0 204 No Content');
|
|
|
143 |
exit;
|
|
|
144 |
}
|
1656 |
raphael |
145 |
|
|
|
146 |
$colonnes = FormateurGroupeColonne::nomEnsembleVersListeColonnes($parametres_format['groupe_champs']);
|
1644 |
aurelien |
147 |
// $colonne_abbrev = array_keys($colonnes);
|
|
|
148 |
$objPHPExcel = $this->gerenerFeuilleImportFormatee($parametres_format);
|
|
|
149 |
$feuille = $objPHPExcel->setActiveSheetIndex(0);
|
|
|
150 |
// attention formaterColonnesFeuille prend ses 2 premiers paramètres par référence
|
|
|
151 |
$this->formaterColonnesFeuille($feuille, $colonnes, $parametres_format);
|
|
|
152 |
$objPHPExcel->getActiveSheet()->getDefaultColumnDimension()->setWidth(12);
|
1630 |
raphael |
153 |
|
1644 |
aurelien |
154 |
$no_ligne = 2;
|
|
|
155 |
foreach ($observations as $obs) {
|
|
|
156 |
// attention traiterLigneObservation prend ses 3 premiers paramètres par référence
|
|
|
157 |
$this->traiterLigneObservation($obs, $colonnes, $feuille, $no_ligne);
|
|
|
158 |
$no_ligne++;
|
|
|
159 |
}
|
1630 |
raphael |
160 |
|
1644 |
aurelien |
161 |
$this->envoyerFeuille($objPHPExcel, $parametres_format);
|
|
|
162 |
}
|
|
|
163 |
|
|
|
164 |
private function envoyerFeuille($objPHPExcel, $parametres_format) {
|
|
|
165 |
header("Content-Type: application/vnd.ms-excel");
|
|
|
166 |
header("Content-Disposition: attachment; filename=\"liste.xls\"; charset=utf-8");
|
|
|
167 |
header("Cache-Control: max-age=0");
|
|
|
168 |
|
|
|
169 |
// csv|xls|xlsx => CSV|Excel5|Excel2007
|
|
|
170 |
// Note: le format Excel2007 utilise un fichier temporaire
|
|
|
171 |
$generateur = PHPExcel_IOFactory::createWriter($objPHPExcel, $parametres_format['format']);
|
|
|
172 |
$generateur->save('php://output');
|
|
|
173 |
exit;
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
private function traiterLigneObservation(&$obs, &$colonnes, &$feuille, $no_ligne) {
|
|
|
177 |
$no_colonne = 0;
|
|
|
178 |
foreach($colonnes as $abbrev => $colonne) {
|
|
|
179 |
$valeur = null;
|
|
|
180 |
if($colonne['extra'] == 2) continue;
|
|
|
181 |
|
|
|
182 |
// valeur direct depuis cel_obs ?
|
|
|
183 |
if(isset($obs[$abbrev])) $valeur = $obs[$abbrev];
|
|
|
184 |
|
|
|
185 |
// pré-processeur de la champs
|
|
|
186 |
if(function_exists($colonne['fonction'])) {
|
|
|
187 |
$valeur = $colonne['fonction']($valeur);
|
1656 |
raphael |
188 |
} elseif(method_exists('FormateurGroupeColonne', $colonne['fonction'])) {
|
|
|
189 |
$valeur = call_user_func(array('FormateurGroupeColonne', $colonne['fonction']), $valeur);
|
1644 |
aurelien |
190 |
} elseif(method_exists(__CLASS__, $colonne['fonction'])) {
|
|
|
191 |
$valeur = call_user_func(array(__CLASS__, $colonne['fonction']), $valeur);
|
|
|
192 |
} elseif($colonne['fonction']) {
|
|
|
193 |
die("méthode {$colonne['fonction']} introuvable");
|
|
|
194 |
}
|
|
|
195 |
// fonction pour obtenir des champs (étendus)
|
|
|
196 |
elseif(function_exists($colonne['fonction_data'])) {
|
|
|
197 |
$valeur = $colonne['fonction_data']($obs);
|
|
|
198 |
}
|
|
|
199 |
elseif(method_exists(__CLASS__, $colonne['fonction_data'])) {
|
|
|
200 |
$valeur = call_user_func(array(__CLASS__, $colonne['fonction_data']), $obs);
|
|
|
201 |
}
|
|
|
202 |
|
|
|
203 |
// // cette section devrait être vide:
|
|
|
204 |
// // cas particuliers ingérable avec l'architecture actuelle:
|
|
|
205 |
if(false && $abbrev == 'date_observation' && $valeur == "0000-00-00") {
|
|
|
206 |
/* blah */
|
|
|
207 |
}
|
1656 |
raphael |
208 |
if($abbrev == 'images') {
|
|
|
209 |
$valeur = FormateurGroupeColonne::getImages($obs, $this->id_utilisateur, $this);
|
|
|
210 |
}
|
|
|
211 |
|
1644 |
aurelien |
212 |
// // fin de section "cas particuliers"
|
|
|
213 |
$feuille->setCellValueByColumnAndRow($no_colonne, $no_ligne, $valeur);
|
|
|
214 |
$no_colonne++;
|
|
|
215 |
}
|
|
|
216 |
}
|
|
|
217 |
|
|
|
218 |
private function gerenerFeuilleImportFormatee($parametres_format) {
|
|
|
219 |
$objPHPExcel = new PHPExcel();
|
|
|
220 |
|
|
|
221 |
$objPHPExcel->getProperties()->setCreator($parametres_format['widget']) // ou $uid ?
|
|
|
222 |
->setLastModifiedBy("XX") // TODO: $uid
|
|
|
223 |
->setTitle("Export des observation du carnet en ligne") // TODO
|
|
|
224 |
->setSubject("Export") // TODO
|
|
|
225 |
->setDescription("Export");
|
|
|
226 |
//->setKeywords("office PHPExcel php")
|
|
|
227 |
//->setCategory("Test result file")
|
|
|
228 |
|
1630 |
raphael |
229 |
$objPHPExcel->getActiveSheet()->setTitle("Observations");
|
1644 |
aurelien |
230 |
return $objPHPExcel;
|
|
|
231 |
}
|
|
|
232 |
|
|
|
233 |
private function formaterColonnesFeuille(&$feuille, &$colonnes, $parametres_format) {
|
1630 |
raphael |
234 |
$colid = 0;
|
|
|
235 |
foreach($colonnes as $colonne) {
|
1639 |
raphael |
236 |
if($colonne['extra'] == 2) continue;
|
1644 |
aurelien |
237 |
|
1638 |
raphael |
238 |
$feuille->setCellValueByColumnAndRow($colid, 1, $colonne['nom']);
|
1639 |
raphael |
239 |
if($colonne['extra'] == 1) {
|
1638 |
raphael |
240 |
$feuille->getStyleByColumnAndRow($colid, 1)->getBorders()->applyFromArray(
|
1630 |
raphael |
241 |
array(
|
|
|
242 |
'allborders' => array(
|
|
|
243 |
'style' => PHPExcel_Style_Border::BORDER_DASHDOT,
|
|
|
244 |
'color' => array('rgb' => PHPExcel_Style_Color::COLOR_BLUE)
|
|
|
245 |
)
|
|
|
246 |
)
|
|
|
247 |
);
|
|
|
248 |
}
|
1642 |
raphael |
249 |
if(! $colonne['importable']) {
|
|
|
250 |
$feuille->getStyleByColumnAndRow($colid, 1)->getFill()->applyFromArray(
|
|
|
251 |
array(
|
|
|
252 |
'type' => PHPExcel_Style_Fill::FILL_SOLID,
|
|
|
253 |
'color' => array('rgb' => PHPExcel_Style_Color::COLOR_YELLOW)
|
|
|
254 |
)
|
|
|
255 |
);
|
|
|
256 |
}
|
1644 |
aurelien |
257 |
|
1630 |
raphael |
258 |
$colid++;
|
|
|
259 |
}
|
|
|
260 |
}
|
|
|
261 |
|
|
|
262 |
/*
|
|
|
263 |
* @param $fieldSets: un range, eg: 1-5,8,32,58-101
|
|
|
264 |
* @return un tableau trié, eg: 1,2,3,4,5,8,32,58,...,101
|
1638 |
raphael |
265 |
* http://stackoverflow.com/questions/7698664/converting-a-range-or-partial-array-in-the-form-3-6-or-3-6-12-into-an-arra
|
1630 |
raphael |
266 |
*/
|
|
|
267 |
static function rangeToList($in = '') {
|
|
|
268 |
$inSets = explode(',', $in);
|
|
|
269 |
$outSets = array();
|
1632 |
raphael |
270 |
|
1630 |
raphael |
271 |
foreach($inSets as $inSet) {
|
|
|
272 |
list($start,$end) = explode('-', $inSet . '-' . $inSet);
|
1634 |
raphael |
273 |
// ignore les ranges trop importants
|
|
|
274 |
if($start > 10000000 || $end > 10000000 || abs($start-$end) > 10000) continue;
|
1630 |
raphael |
275 |
$outSets = array_merge($outSets,range($start,$end));
|
|
|
276 |
}
|
|
|
277 |
$outSets = array_unique($outSets);
|
|
|
278 |
$outSets = array_filter($outSets, 'is_numeric');
|
|
|
279 |
sort($outSets);
|
|
|
280 |
return $outSets;
|
|
|
281 |
}
|
1656 |
raphael |
282 |
}
|