Subversion Repositories eFlore/Applications.cel

Rev

Rev 2732 | Rev 3135 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1654 aurelien 1
<?php
2461 jpm 2
// declare(encoding='UTF-8');
1656 raphael 3
/**
2461 jpm 4
 * Classe métier de mise en forme des groupes de colonnes pour les exports.
5
 *
6
 * @internal   Mininum PHP version : 5.2
7
 * @category   CEL
8
 * @package    Services
9
 * @subpackage Bibliothèques
10
 * @version    0.1
11
 * @author     Mathias CHOUET <mathias@tela-botanica.org>
12
 * @author     Raphaël Droz <raphael@tela-botania.org>
13
 * @author     Jean-Pascal MILCENT <jpm@tela-botanica.org>
14
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
15
 * @license    GPL v3 <http://www.gnu.org/licenses/gpl.txt>
16
 * @license    CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
17
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
18
 */
19
define('SEPARATEUR_IMAGES', ' / ');
20
define('PREFIX_CHAMPS_ETENDUS', 'ext:');
1835 raphael 21
// utilisé par formaterUrlUser() [ nécessaire pour le widget d'export)
22
define('USER_BASEURL', 'http://www.tela-botanica.org/profil:%d');
1656 raphael 23
 
2461 jpm 24
class FormateurGroupeColonne {
1656 raphael 25
 
1702 raphael 26
	// cache pour les données des fonctions
1656 raphael 27
	static $cache = Array();
28
 
1702 raphael 29
	// test sur la table cel_references, mis à TRUE si la table existe
30
	static $is_table = false;
31
 
1714 raphael 32
	// les groupes de champs utilisables
33
	static $fieldGroups = array(
34
		'standard',
3134 delphine 35
		'standardexport',
1714 raphael 36
		'avance',
37
		'etendu',
1835 raphael 38
		'baseflor',
39
		'auteur'
1714 raphael 40
	);
41
 
1702 raphael 42
	// les données baseflor à récupérer: colonnes présentes dans cel_references
43
	// et intitulés associés
44
	static $baseflor_col = array(
2461 jpm 45
		've_lumiere' => 'Lumière',
46
		've_temperature' => 'Température',
47
		've_continentalite' => 'Continentalité',
48
		've_humidite_atmos' => 'Humidité Atmosphérique',
49
		've_humidite_edaph' => 'Humidité',
50
		've_reaction_sol' => 'Réaction (pH)',
51
		've_nutriments_sol' => 'Nutriments',
52
		've_salinite' => 'Salinité',
53
		've_texture_sol' => 'Texture' ,
54
		've_mat_org_sol' => 'Matière Organique',
55
		'catminat_code' => 'Code Catminat',
56
		'syntaxon' => 'Syntaxon',
1702 raphael 57
	);
58
 
1741 raphael 59
	// TODO: dirty, ordre des champs étendus... souhaité pour florilèges:
60
	static $ordre_champ_etendus_Florileges = array(
2461 jpm 61
		'personneStructure',
62
		'personneService',
63
		'personneFonction',
64
		'adresse',
65
		'latitudeDebutRue',
66
		'longitudeDebutRue',
67
		'latitudeFinRue',
68
		'longitudeFinRue',
69
		'typoUrbaine',
70
		'revetementSol',
71
		'presenceZoneVegetalise',
72
		'hauteurBatimentAvoisinant',
73
		'intensiteGestion',
74
		'periodiciteTraitementPhyto',
75
		'dateArretTraitementPhyto',
76
		'itineraireGestion',
77
		'dateDerniereIntervention',
78
		'hauteurPlante',
79
		'resistanceTraitementPhyto',
80
		'vitesseCroissance',
81
		'perceptionTechnicien',
82
		'perceptionRiverainMauvaise',
1741 raphael 83
	);
84
 
3134 delphine 85
	static function colGroupsValidation($groupe_de_champs = 'standard,avance', $programme = "") {
2461 jpm 86
		if (! $groupe_de_champs) return FALSE;
87
		if (is_string($groupe_de_champs)) {
1714 raphael 88
			$groupe_de_champs = array_flip(explode(',', $groupe_de_champs));
2461 jpm 89
		} elseif(is_array($groupe_de_champs)) {
1714 raphael 90
			$groupe_de_champs = array_flip($groupe_de_champs);
2461 jpm 91
		} else {
92
			return null;
1714 raphael 93
		}
2461 jpm 94
		$groupe_de_champs = array_intersect_key(array_flip(self::$fieldGroups), $groupe_de_champs);
95
		if (!$groupe_de_champs) {
96
			return false;
1714 raphael 97
		}
3134 delphine 98
		if ($programme != "") {
99
			$groupe_de_champs['avance'] = true;
100
			$groupe_de_champs['etendu'] = true;
101
		}
1714 raphael 102
		// toujours ajouter standard
2461 jpm 103
		$groupe_de_champs['standard'] = true;
1714 raphael 104
		return implode(',', array_keys($groupe_de_champs));
105
	}
106
 
1654 aurelien 107
	/*
108
	* @param $fieldSets: un liste de noms de colonnes ou de sets de colonnes
109
	*		séparés par des virgules
110
	* 		eg: "espece" ou "champs-etendus", ...
111
	*
112
	* @return: un tableau associatif déjà ordonné
113
	* 		clé: abbrev [machine-name] de la colonne (eg: "espece" ou "mot-clef")
114
	* 		valeur: des données relative à cette colonne, cf GenColInfo
115
	*
1757 raphael 116
	* Si la colonne n'utilise pas de fonction de récupération particulière
117
	* (ie: si le champ exportés [ou importé] correspond exactement au champ dans la base de donnée)
118
	* Alors 'abbrev' doit avoir la même valeur que le nom de la colonne dans la table mysql `cel_obs`.
1654 aurelien 119
	*/
120
	static function nomEnsembleVersListeColonnes($groupe_de_champs = 'standard') {
2461 jpm 121
		if (! $groupe_de_champs) {
122
			$groupe_de_champs = 'standard';
123
		}
124
		if (is_string($groupe_de_champs)) {
1711 raphael 125
			$groupe_de_champs = array_flip(explode(',', $groupe_de_champs));
2461 jpm 126
		} elseif(is_array($groupe_de_champs)) {
1711 raphael 127
			$groupe_de_champs = array_flip($groupe_de_champs);
2461 jpm 128
		} else {
129
			return null;
1711 raphael 130
		}
2461 jpm 131
		$groupe_de_champs = array_intersect_key(array_flip(self::$fieldGroups), $groupe_de_champs);
132
		if (!$groupe_de_champs) {
133
			return null;
1711 raphael 134
		}
135
 
2461 jpm 136
		$colonnes = array();
3134 delphine 137
		if (isset($groupe_de_champs['standardexport'])) {
1654 aurelien 138
			$colonnes += Array(
3134 delphine 139
				'guid'			=> self::GenColInfo(Array('abbrev' => 'guid',
140
																'nom' => 'Identifiant unique')),
1757 raphael 141
				'nom_sel'			=> self::GenColInfo(Array('abbrev' => 'nom_sel',
142
															  'nom' => 'Espèce')),
143
				'nom_sel_nn'		=> self::GenColInfo(Array('abbrev' => 'nom_sel_nn',
144
															  'nom' => 'Numéro nomenclatural',
145
															  'importable' => FALSE)),
146
				'nom_ret'			=> self::GenColInfo(Array('abbrev' => 'nom_ret',
147
															  'nom' => 'Nom retenu',
148
															  'importable' => FALSE)),
149
				'nom_ret_nn'		=> self::GenColInfo(Array('abbrev' => 'nom_ret_nn',
150
															  'nom' => 'Numéro nomenclatural nom retenu',
151
															  'importable' => FALSE)),
152
				'nt'				=> self::GenColInfo(Array('abbrev' => 'nt',
153
															  'nom' => 'Numéro taxonomique',
154
															  'importable' => FALSE)),
155
				'famille'			=> self::GenColInfo(Array('abbrev' => 'famille',
156
															  'nom' => 'Famille',
157
															  'importable' => FALSE)),
158
				'nom_referentiel'	=> self::GenColInfo(Array('abbrev' => 'nom_referentiel',
159
															  'nom' => 'Referentiel taxonomique')),
2730 mathias 160
				'pays'				=> self::GenColInfo(Array('abbrev' => 'pays',
2538 aurelien 161
															  'nom' => 'Pays')),
1757 raphael 162
				'zone_geo'			=> self::GenColInfo(Array('abbrev' => 'zone_geo',
163
															  'nom' => 'Commune')),
164
				'ce_zone_geo'		=> self::GenColInfo(Array('abbrev' => 'ce_zone_geo',
165
															  'nom' => 'Identifiant Commune',
166
															  'fonction' => 'convertirCodeZoneGeoVersDepartement')),
167
				'date_observation'	=> self::GenColInfo(Array('abbrev' => 'date_observation',
168
															  'nom' => 'Date',
169
															  'fonction' => 'formaterDate')),
170
				'lieudit'			=> self::GenColInfo(Array('abbrev' => 'lieudit',
171
															  'nom' => 'Lieu-dit')),
172
				'station'			=> self::GenColInfo(Array('abbrev' => 'station',
173
															  'nom' => 'Station')),
174
				'milieu'			=> self::GenColInfo(Array('abbrev' => 'milieu',
175
															  'nom' => 'Milieu')),
176
				'commentaire'		=> self::GenColInfo(Array('abbrev' => 'commentaire',
177
															  'nom' => 'Notes')),
178
				'latitude'			=> self::GenColInfo(Array('abbrev' => 'latitude',
179
															  'nom' => 'Latitude',
180
															  'extra' => 1,
181
															  'fonction' => 'trim0')),
182
				'longitude'			=> self::GenColInfo(Array('abbrev' => 'longitude',
183
															  'nom' => 'Longitude',
184
															  'extra' => 1,
185
															  'fonction' => 'trim0')),
186
				'altitude'			=> self::GenColInfo(Array('abbrev' => 'altitude',
187
															  'nom' => 'Altitude',
1816 raphael 188
															  'extra' => 1)), // pas de trim0 car INT(5) en DB
1757 raphael 189
				'geodatum'			=> self::GenColInfo(Array('abbrev' => 'geodatum',
190
															  'nom' => 'Référentiel Géographique',
191
															  'extra' => 1,
192
															  'importable' => FALSE)),
3134 delphine 193
				'programme'			=> self::GenColInfo(Array('abbrev' => 'programme',
194
															'nom' => 'Programme de sciences participatives ou observatoire citoyen',
195
															'importable' => FALSE)),
196
				'validation_identiplante'			=> self::GenColInfo(Array('abbrev' => 'validation_identiplante',
197
															'nom' => 'Espéce validée sur IdentiPlante',
198
															'importable' => FALSE)),
1654 aurelien 199
			);
3134 delphine 200
		} elseif (isset($groupe_de_champs['standard'])) {
201
			$colonnes += Array(
202
					'nom_sel'			=> self::GenColInfo(Array('abbrev' => 'nom_sel',
203
							'nom' => 'Espèce')),
204
					'nom_sel_nn'		=> self::GenColInfo(Array('abbrev' => 'nom_sel_nn',
205
							'nom' => 'Numéro nomenclatural',
206
							'importable' => FALSE)),
207
					'nom_ret'			=> self::GenColInfo(Array('abbrev' => 'nom_ret',
208
							'nom' => 'Nom retenu',
209
							'importable' => FALSE)),
210
					'nom_ret_nn'		=> self::GenColInfo(Array('abbrev' => 'nom_ret_nn',
211
							'nom' => 'Numéro nomenclatural nom retenu',
212
							'importable' => FALSE)),
213
					'nt'				=> self::GenColInfo(Array('abbrev' => 'nt',
214
							'nom' => 'Numéro taxonomique',
215
							'importable' => FALSE)),
216
					'famille'			=> self::GenColInfo(Array('abbrev' => 'famille',
217
							'nom' => 'Famille',
218
							'importable' => FALSE)),
219
					'nom_referentiel'	=> self::GenColInfo(Array('abbrev' => 'nom_referentiel',
220
							'nom' => 'Referentiel taxonomique')),
221
					'pays'				=> self::GenColInfo(Array('abbrev' => 'pays',
222
							'nom' => 'Pays')),
223
					'zone_geo'			=> self::GenColInfo(Array('abbrev' => 'zone_geo',
224
							'nom' => 'Commune')),
225
					'ce_zone_geo'		=> self::GenColInfo(Array('abbrev' => 'ce_zone_geo',
226
							'nom' => 'Identifiant Commune',
227
							'fonction' => 'convertirCodeZoneGeoVersDepartement')),
228
					'date_observation'	=> self::GenColInfo(Array('abbrev' => 'date_observation',
229
							'nom' => 'Date',
230
							'fonction' => 'formaterDate')),
231
					'lieudit'			=> self::GenColInfo(Array('abbrev' => 'lieudit',
232
							'nom' => 'Lieu-dit')),
233
					'station'			=> self::GenColInfo(Array('abbrev' => 'station',
234
							'nom' => 'Station')),
235
					'milieu'			=> self::GenColInfo(Array('abbrev' => 'milieu',
236
							'nom' => 'Milieu')),
237
					'commentaire'		=> self::GenColInfo(Array('abbrev' => 'commentaire',
238
							'nom' => 'Notes')),
239
					'latitude'			=> self::GenColInfo(Array('abbrev' => 'latitude',
240
							'nom' => 'Latitude',
241
							'extra' => 1,
242
							'fonction' => 'trim0')),
243
					'longitude'			=> self::GenColInfo(Array('abbrev' => 'longitude',
244
							'nom' => 'Longitude',
245
							'extra' => 1,
246
							'fonction' => 'trim0')),
247
					'altitude'			=> self::GenColInfo(Array('abbrev' => 'altitude',
248
							'nom' => 'Altitude',
249
							'extra' => 1)), // pas de trim0 car INT(5) en DB
250
					'geodatum'			=> self::GenColInfo(Array('abbrev' => 'geodatum',
251
							'nom' => 'Référentiel Géographique',
252
							'extra' => 1,
253
							'importable' => FALSE)),
254
					);
1654 aurelien 255
		}
2143 jpm 256
 
1654 aurelien 257
		if(isset($groupe_de_champs['avance'])) {
1656 raphael 258
			$colonnes += array(
1757 raphael 259
				// TODO: importable = FALSE car pas de merge de données importées
260
				'ordre'				=> self::GenColInfo(Array('abbrev' => 'ordre',
261
															  'nom' => 'Ordre',
262
															  'extra' => 1,
263
															  'importable' => FALSE)),
264
				'id_observation'	=> self::GenColInfo(Array('abbrev' => 'id_observation',
265
															  'nom' => 'Identifiant',
266
															  'extra' => 1,
267
															  'importable' => FALSE)),
1656 raphael 268
 
1757 raphael 269
				'mots_cles_texte'	=> self::GenColInfo(Array('abbrev' => 'mots_cles_texte',
270
															  'nom' => 'Mots Clés',
271
															  'extra' => 1)),
272
				'date_creation'		=> self::GenColInfo(Array('abbrev' => 'date_creation',
273
															  'nom' => 'Date Création',
274
															  'extra' => 1,
275
															  'importable' => FALSE)),
276
				'date_modification'	=> self::GenColInfo(Array('abbrev' => 'date_modification',
277
															  'nom' => 'Date Modification',
278
															  'extra' => 1,
279
															  'importable' => FALSE)),
1656 raphael 280
 
1757 raphael 281
				// rappel transmission = 1, signifie simplement "public"
282
				// des données importées peuvent être d'emblée "publiques"
283
				// "importable" = TRUE
284
				'transmission'		=> self::GenColInfo(Array('abbrev' => 'transmission',
285
															  'nom' => 'Transmis',
286
															  'extra' => 1,
287
															  'fonction' => 'boolOuiNon')),
288
				'date_transmission'	=> self::GenColInfo(Array('abbrev' => 'date_transmission',
289
															  'nom' => 'Date Transmission',
290
															  'extra' => 1,
291
															  'importable' => FALSE)),
292
				'abondance'			=> self::GenColInfo(Array('abbrev' => 'abondance',
293
															  'nom' => 'Abondance',
294
															  'extra' => 1)),
295
				'certitude'			=> self::GenColInfo(Array('abbrev' => 'certitude',
296
															  'nom' => 'Certitude',
297
															  'extra' => 1)),
298
				'phenologie'		=> self::GenColInfo(Array('abbrev' => 'phenologie',
299
															  'nom' => 'Phénologie',
300
															  'extra' => 1)),
2143 jpm 301
 
1757 raphael 302
				// XXX: getImages() dépend du contexte de Cel, et doit être appelée comme cas particulier
303
				// cf ExportXLS::traiterLigneObservation()
304
				'images'			=> self::GenColInfo(Array('abbrev' => 'images',
305
															  'nom' => 'Image(s)',
306
															  'extra' => 1,
307
															  'fonction_data' => NULL /* cas particulier 'getImages' */,
308
															  'importable' => TRUE,
309
															  //'preload' => array(__CLASS__, 'getImages_preload')//TODO
310
				)),
1656 raphael 311
 
1757 raphael 312
				/* 'nom_commun'			=> self::GenColInfo(Array('abbrev' => 'nom_commun',
313
				   'nom' => 'Nom Commun',
314
				   'extra' => 1,
315
				   'fonction_data' => 'getNomCommun',
316
				   'importable' => FALSE),
1685 raphael 317
 
1757 raphael 318
				   'nom-commun'			=> self::GenColInfo(Array('abbrev' => 'nom-commun',
319
				   'nom' => 'Nom Commun',
320
				   'extra' => 1,
321
				   'fonction_data' => 'getNomCommun_v2'),
322
 
323
				   'nom-commun'			=> self::GenColInfo(Array('abbrev' => 'nom-commun',
324
				   'nom' => 'Nom Commun',
325
				   'extra' => 1,
326
				   'fonction_data' => 'getNomCommun_v3'),
327
				   'importable' => FALSE), */
2461 jpm 328
				'nom-commun' => self::GenColInfo(array(
329
					'abbrev' => 'nom-commun',
330
					'nom' => 'Nom Commun',
331
					'extra' => 1,
332
					'fonction_data' => null /* cas particu 'getNomCommun_v4' */,
333
					'preload' => array(__CLASS__, 'getNomCommun_preload')))
1702 raphael 334
			);
335
		}
1685 raphael 336
 
1702 raphael 337
		if(isset($groupe_de_champs['baseflor'])) {
338
			$colonnes += array(
339
				// champ dynamique
2461 jpm 340
				'baseflor' => self::GenColInfo(array(
341
					'abbrev' => 'baseflor',
342
					'nom' => '',
343
					'extra' => 1,
344
					'importable' => false,
345
					'preload' => array(__CLASS__, 'baseflor_preload'),
346
					'dyna' => array(__CLASS__, 'baseflor_ligne'))),
1654 aurelien 347
			);
1702 raphael 348
		}
1656 raphael 349
 
2461 jpm 350
		if (isset($groupe_de_champs['etendu'])) {
1714 raphael 351
			$colonnes += array(
352
				// champ dynamique
2461 jpm 353
				'etendu' => self::GenColInfo(array(
354
					'abbrev' => 'etendu',
355
					'nom' => '',
356
					'extra' => 1,
357
					'importable' => false,
358
					'preload' => array(__CLASS__, 'champsEtendus_preload'),
359
					'dyna' => array(__CLASS__, 'champsEtendus_ligne'))),
1714 raphael 360
			);
361
		}
1835 raphael 362
 
2461 jpm 363
		if (isset($groupe_de_champs['auteur'])) {
1835 raphael 364
			$colonnes += array(
2461 jpm 365
				'observateur' => self::GenColInfo(array(
366
					'abbrev' => 'observateur',
367
					'nom' => 'Observateur',
368
					'extra' => 1,
369
					'fonction_data' => 'formaterUrlUser',
370
					'importable' => false)),
1835 raphael 371
			);
372
		}
1654 aurelien 373
		return $colonnes;
374
	}
1694 raphael 375
 
376
	static function preload($colonnes, $cel, $ids) {
377
		$result = array();
2461 jpm 378
		foreach ($colonnes as $abbrev => $colonne) {
379
			if (!$colonne['preload']) {
380
				continue;
381
			}
1702 raphael 382
			$result[$abbrev] = call_user_func($colonne['preload'], $cel, $ids);
1694 raphael 383
		}
384
		return $result;
385
	}
2143 jpm 386
 
1656 raphael 387
	public static function getIntitulesColonnes($colonnes) {
1702 raphael 388
		// array_filter pour supprimer les colonnes "dynamique" n'ayant pas défini $nom (cf GenColInfo())
389
		return array_filter(array_map(array('FormateurGroupeColonne', 'retournerNomItem'), $colonnes));
1654 aurelien 390
	}
2143 jpm 391
 
1671 aurelien 392
	public static function retournerNomItem(&$item) {
393
		return $item['nom'];
394
	}
1694 raphael 395
 
1656 raphael 396
	public static function getLigneObservation(&$obs, &$colonnes, $cel = false) {
1654 aurelien 397
		$ligne_formatee = array();
398
		foreach($colonnes as $abbrev => $colonne) {
399
			$valeur = null;
2461 jpm 400
			if ($colonne['extra'] == 2 || ! is_null($colonne['dyna'])) {
401
				continue;
402
			}
2143 jpm 403
 
1835 raphael 404
			// valeur directe depuis cel_obs ?
2461 jpm 405
			if (isset($obs[$abbrev])) {
406
				$valeur = $obs[$abbrev];
407
			}
2143 jpm 408
 
1835 raphael 409
			// pré-processeur des champs
2461 jpm 410
			if (function_exists($colonne['fonction'])) {
1654 aurelien 411
				$valeur = $colonne['fonction']($valeur);
2461 jpm 412
			} else if(method_exists(__CLASS__, $colonne['fonction'])) {
1654 aurelien 413
				$valeur = call_user_func(array(__CLASS__, $colonne['fonction']), $valeur);
2461 jpm 414
			} else if($colonne['fonction']) {
1654 aurelien 415
				die("méthode {$colonne['fonction']} introuvable");
2461 jpm 416
			} else if(function_exists($colonne['fonction_data'])) {// fonction pour obtenir des champs (étendus)
1654 aurelien 417
				$valeur = $colonne['fonction_data']($obs);
2461 jpm 418
			} else if(method_exists(__CLASS__, $colonne['fonction_data'])) {
1654 aurelien 419
				$valeur = call_user_func(array(__CLASS__, $colonne['fonction_data']), $obs);
420
			}
2143 jpm 421
 
1654 aurelien 422
			// // cette section devrait être vide:
423
			// // cas particuliers ingérable avec l'architecture actuelle:
2461 jpm 424
			if (false && $abbrev == 'date_observation' && $valeur == '0000-00-00') {
1654 aurelien 425
				/* blah */
426
			}
1765 raphael 427
			// ici à cause du passage de $cel ($this->utilisateur)
2461 jpm 428
			if ($abbrev == 'images') {
1765 raphael 429
				$valeur = FormateurGroupeColonne::getImages($obs, $cel->id_utilisateur);
1656 raphael 430
			}
2461 jpm 431
			if ($abbrev == 'nom-commun') {
1765 raphael 432
				$valeur = FormateurGroupeColonne::getNomCommun_v4($obs);
1685 raphael 433
			}
2143 jpm 434
 
2461 jpm 435
			if ($valeur == null) {
436
				$valeur = '';
1654 aurelien 437
			}
2143 jpm 438
 
2461 jpm 439
			// fin de section "cas particuliers"
1654 aurelien 440
			$ligne_formatee[] = $valeur;
441
		}
1694 raphael 442
 
1835 raphael 443
		// uniquement les champs dynamiques
1702 raphael 444
		foreach($colonnes as $abbrev => $colonne) {
445
			$valeur = null;
2461 jpm 446
			if (is_null($colonne['dyna'])) {
447
				continue;
448
			}
449
			call_user_func_array($colonne['dyna'], array($obs, &$ligne_formatee));
1702 raphael 450
		}
1654 aurelien 451
		return $ligne_formatee;
452
	}
2143 jpm 453
 
1654 aurelien 454
	/*
455
	* Wrapper générant un tableau associatif:
1694 raphael 456
	* Ne pas changer les valeurs par défaut du prototype sans réflexion sur l'implication pour nomEnsembleVersListeColonnes()
2143 jpm 457
 
1654 aurelien 458
	* @param $abbrev (obligatoire): nom court de colonne, largement utilisé lors de l'import.
459
	*		  En effet chaque ligne importée est accessible à l'aide du `define` de $abbrev en majuscule, préfixé de "C_"
460
	*		  Exemple: $ligne[C_LONGITUDE] pour "longitude".
461
	*		  cf: ImportXLS::detectionEntete()
2143 jpm 462
 
1654 aurelien 463
	* @param $nom (obligatoire): nom complet de colonne (utilisé pour la ligne d'en-tête)
1702 raphael 464
	*		  Les définition de champs dynamique (correspondant à de multiples colonnes) doivent laisser cette valeur
465
	*		  vide afin de ne pas créer une colonne supplémentaire erronée.
2143 jpm 466
 
1654 aurelien 467
	* @param $is_extra:
468
	* Si 0, la colonne est une colonne standard
469
	* Si 1, la colonne est extra [le plus souvent générée automatiquement]
470
	*		 (auquel cas une bordure bleue entoure son nom dans la ligne d'entête)
471
	* Si 2, la colonne n'est pas traité à l'export, mais une définition peut lui être donnée
472
	*		 qui pourra être utilisée à l'import, exemple: "image"
2143 jpm 473
 
1654 aurelien 474
	* @param $fonction (optionnel): un nom d'un fonction de préprocessing
475
	* 		  $fonction doit prendre comme seul argument la valeur d'origine et retourner la valeur transformée
2143 jpm 476
 
1654 aurelien 477
	* @param $fonction_data (optionnel): une *méthode* d'obtention de donnée
478
	* 		  $fonction_data doit prendre comme premier argument le tableau des champs de l'enregistrement existant
479
	*		  $fonction_data doit retourner une valeur
2143 jpm 480
 
1654 aurelien 481
	* @param $importable (optionnel): défini si la colonne est traitée (ou absolument ignorée par PHPExcel) lors de
482
	*		  l'import.
1694 raphael 483
 
484
	* @param $preload (optionnel): défini une fonction de préchargement massif de donnée potentiellement utilisable par $fonction_data.
485
	*		  Utile, notamment, dans le cadre de l'export
1702 raphael 486
 
487
	* @param $fonction_dynamique (optionnel): défini une fonction ajoutant un nombre arbitraire de colonnes à une ligne donnée
488
	*		  Utile, notamment, dans le cadre de l'export des champs étendus ou des données baseflor
489
	*		  La fonction doit TOUJOURS alterer la ligne en lui ajoutant une nombre CONSTANT d'éléments (NULL ou non)
1765 raphael 490
	*		  La fonction doit prendre comme arguments ($obs, &$ligne_formatee)
1654 aurelien 491
	*/
1757 raphael 492
	static function GenColInfo($args) {
2461 jpm 493
		$default = array(
494
			'abbrev' => null,
495
			'nom' => null,
496
			'extra' => 0,
497
			'fonction' => null,
498
			'fonction_data' => null,
499
			'importable' => true,
500
			'preload' => null,
501
			'dyna' => null);
1757 raphael 502
		$ret = array_intersect_key($args, $default);
503
		return array_merge($default, $ret);
1654 aurelien 504
	}
2143 jpm 505
 
1656 raphael 506
	static function formaterDate($date_heure_mysql) {
1671 aurelien 507
		//return "";
2461 jpm 508
		if (!$date_heure_mysql || $date_heure_mysql == "0000-00-00 00:00:00") {
509
			return null;
510
		}
1671 aurelien 511
		// malheureusement pas disponible en php < 5.3
512
		//$date_format = DateTime::createFromFormat("Y-m-d H:i:s", $date_heure_mysql);
513
		$val = explode(' ', $date_heure_mysql);
514
		$date = explode('-', $val[0]);
515
		$heure = explode(':', $val[1]);
516
		$timestamp = mktime((int) $heure[0], (int) $heure[1], (int) $heure[2], (int) $date[1], (int) $date[2], (int) $date[0]);
2461 jpm 517
		if (!$timestamp) {
518
			return null;
519
		}
1656 raphael 520
		// TODO: les widgets ne font malheureusement pas usage de l'heure dans le CEL
521
		// TODO: si modification, ne pas oublier de modifier le format d'import correspondant
1698 raphael 522
		//	dans ImportXLS, traiterDateObs() (actuellement: "Y/m/d" car utilisation de strtotime() qui ne lit pas tout)
523
		// $date_formatee = strftime('%d/%m/%Y', $timestamp);
524
		$date_formatee = strftime('%Y/%m/%d', $timestamp);
2461 jpm 525
		if (!$date_formatee) {
526
			return '00/00/0000';
527
		}
1654 aurelien 528
		return $date_formatee;
529
	}
1757 raphael 530
 
1835 raphael 531
	static function formaterUrlUser($obs) {
532
		$is_id = is_numeric($obs['ce_utilisateur']);
533
		return sprintf("%s %s <%s>%s",
2461 jpm 534
			$obs['prenom_utilisateur'],
535
			$obs['nom_utilisateur'],
536
			preg_replace(';@.*;', '@...', $obs['courriel_utilisateur']),
537
			$is_id ? sprintf(' (' . USER_BASEURL . ')', $obs['ce_utilisateur']) : '');
1835 raphael 538
	}
539
 
1759 raphael 540
	static function getImages_preload($cel, $obsids) {
2461 jpm 541
		if (!$obsids) return;
1766 raphael 542
		$rec = Cel::db()->requeter(
1759 raphael 543
			sprintf("SELECT o.id_observation, GROUP_CONCAT(nom_original ORDER BY nom_original ASC SEPARATOR '%s') AS i " .
2446 jpm 544
					"FROM cel_images i LEFT JOIN cel_obs o ON (i.ce_observation = o.id_observation) " .
1759 raphael 545
					"WHERE o.ce_utilisateur = %d AND o.id_observation IN (%s) " .
546
					"GROUP BY id_observation",
547
					SEPARATEUR_IMAGES,
548
					$cel->id_utilisateur,
549
					implode(',', $obsids)));
2461 jpm 550
		foreach ($rec as $v) {
1759 raphael 551
			self::$cache['getImages'][$v['id_observation']] = $v['i'];
552
		}
2461 jpm 553
		return null;
1759 raphael 554
	}
555
 
1765 raphael 556
	static function getImages($obs, $id_utilisateur) {
1656 raphael 557
		if(! $id_utilisateur) return NULL;
1759 raphael 558
		if(isset(self::$cache['getImages'][$obs['id_observation']]))
559
			return self::$cache['getImages'][$obs['id_observation']];
560
 
1765 raphael 561
		$rec = Cel::db()->requeter(
2446 jpm 562
			sprintf("SELECT GROUP_CONCAT(nom_original ORDER BY nom_original ASC SEPARATOR '%s') AS i ".
563
					"FROM cel_images i ".
564
					"	LEFT JOIN cel_obs o ON (i.ce_observation = o.id_observation) ".
565
					"WHERE o.ce_utilisateur = %d ".
566
					"	AND o.id_observation = %d ".
567
					'LIMIT 1',
1656 raphael 568
					SEPARATEUR_IMAGES,
1757 raphael 569
					$id_utilisateur,
570
					$obs['id_observation']));
571
		return $rec ? $rec[0]['i'] : NULL;
1654 aurelien 572
	}
2143 jpm 573
 
574
	public static function convertirCodeZoneGeoVersDepartement($code_zone_geo) {
1654 aurelien 575
		$code_departement = '';
576
		if(self::estUnCodeInseeDepartement($code_zone_geo)) {
577
			$code_departement = substr(ltrim($code_zone_geo,'INSEE-C:'),0,2);
578
		}
2143 jpm 579
 
1654 aurelien 580
		return $code_departement;
581
	}
1757 raphael 582
 
2730 mathias 583
	/**
584
	 * Enlève les zéros excédentaires (devenus nomades) au début et à la fin d'une
585
	 * latitude ou longitude, en prenant garde à ne pas foirer les nombres 0.xyz
586
	 */
1757 raphael 587
	public static function trim0($lonlat) {
2730 mathias 588
		$retour = trim($lonlat, "0");
589
		// si on a trop enlevé de zéros à gauche, on en remet un (mode synthobois)
590
		if (substr($retour, 0, 1) == ".") {
591
			$retour = "0" . $retour;
592
		}
593
		return $retour;
1757 raphael 594
	}
595
 
596
	public static function boolOuiNon($transmission) {
597
		return $transmission ? 'oui' : '';
598
	}
2143 jpm 599
 
1654 aurelien 600
	public static function estUnCodeInseeDepartement($code_a_tester) {
601
		return preg_match('/^INSEE-C:[0-9]{5}/',$code_a_tester);
602
	}
2143 jpm 603
 
1654 aurelien 604
	// TODO: référentiel ne devrait pas être généré au moment d'un Config::get,
605
	// comme dans Config::get('nomsVernaRechercheLimiteeTpl')
606
	// Par exemple, la variable pour "nva" ?
607
	function getNomCommun($obs) {
608
		$langue = 'fra';
609
		list($referentiel) = explode(':', strtolower($obs['nom_referentiel']));
610
		if($referentiel == 'bdtfx') $referentiel = 'nvjfl';
611
		else return '';
2143 jpm 612
 
1654 aurelien 613
		$cache_id = $referentiel . '-' . $obs['nt'] . '-' . $langue;
1657 raphael 614
		if(isset(self::$cache['getNomCommun'][$cache_id])) {
1656 raphael 615
			//debug: error_log("require url_service_nom_attribution: OK ! (pour \"{$obs['nom_ret']}\")");
1657 raphael 616
			return self::$cache['getNomCommun'][$cache_id];
1654 aurelien 617
		}
618
		// pas de cache:
619
		//debug: error_log("require url_service_nom_attribution pour \"{$obs['nom_ret']}\"");
2143 jpm 620
 
1654 aurelien 621
		// pour bdtfx:
622
		// /service:eflore:0.1/nvjfl/noms-vernaculaires/attributions?masque.nt=X&masque.lg=fra&retour.champs=num_statut
623
		// /projet/services/modules/0.1/nvjfl/NomsVernaculaires.php
624
		$url = str_replace(Array('{referentiel}', '{valeur}', '{langue}'),
1656 raphael 625
						   Array($referentiel, $obs['nt'], $langue),
1657 raphael 626
						   self::$config['eflore']['url_service_nom_attribution']) . // TODO !
1656 raphael 627
			"&retour.champs=num_statut";
1654 aurelien 628
		$noms = @json_decode(file_get_contents($url));
629
		if(! $noms) return '';
1673 raphael 630
		$noms = array_filter((array)($noms->resultat), array($this, retournerNumStatutUn)); // XXX: php 5.3
1654 aurelien 631
		$nom = array_pop($noms)->nom_vernaculaire;
2143 jpm 632
 
1654 aurelien 633
		// cache
1657 raphael 634
		self::$cache['getNomCommun'][$cache_id] = $nom;
1654 aurelien 635
		return $nom;
636
	}
2143 jpm 637
 
1671 aurelien 638
	private function retournerNumStatutUn(&$item) {
639
		return ($item->num_statut == 1);
640
	}
1673 raphael 641
 
642
	private function retournerNumStatutUnArr(&$item) {
643
		return ($item['num_statut'] == 1);
644
	}
2143 jpm 645
 
1656 raphael 646
	// si getNomCommun_v2 ou getNomCommun_v3 sont utilisés
647
	/* require_once('/home/raphael/eflore/framework/framework/Framework.php');
648
	Framework::setCheminAppli("/home/raphael/eflore/projets/services/index.php");
649
	Framework::setInfoAppli(Config::get('info'));
650
	require_once('/home/raphael/eflore/projets/services/modules/0.1/Projets.php');*/
2143 jpm 651
 
1654 aurelien 652
	/* Tente de bootstraper le framework au plus court et d'initialiser une instance de
1656 raphael 653
	   NomsVernaculaires pour obtenir le nom commun */
1654 aurelien 654
	function getNomCommun_v2($obs) {
655
		static $service;
1656 raphael 656
		$service = new Projets();
2143 jpm 657
 
1654 aurelien 658
		$langue = 'fra';
659
		list($referentiel) = explode(':', strtolower($obs['nom_referentiel']));
660
		if($referentiel == 'bdtfx') $referentiel = 'nvjfl';
661
		else return '';
2143 jpm 662
 
1654 aurelien 663
		$cache_id = $referentiel . '-' . $obs['nt'] . '-' . $langue;
1657 raphael 664
		if(isset(self::$cache['getNomCommun'][$cache_id])) {
1656 raphael 665
			error_log("require NomsVernaculaires.php: OK ! (pour \"{$obs['nom_ret']}\")");
1657 raphael 666
			return self::$cache['getNomCommun'][$cache_id];
1654 aurelien 667
		}
668
		// pas de cache:
669
		error_log("require NomsVernaculaires.php pour \"{$obs['nom_ret']}\"");
2143 jpm 670
 
1656 raphael 671
		$donnees = Array('masque.nt' => $obs['nt'],
672
						 'masque.lg' => $langue,
673
						 'retour.champs' => 'num_statut');
1654 aurelien 674
		$noms = $service->consulter(Array('nvjfl', 'noms-vernaculaires'), $donnees);
2143 jpm 675
 
1654 aurelien 676
		if(! $noms) return '';
1673 raphael 677
		$noms = array_filter((array)($noms->resultat), array($this, retournerNumStatutUn)); // XXX: php 5.3
1654 aurelien 678
		$nom = array_pop($noms)->nom_vernaculaire;
2143 jpm 679
 
1656 raphael 680
		// cache
1657 raphael 681
		self::$cache['getNomCommun'][$cache_id] = $nom;
1654 aurelien 682
		return $nom;
683
	}
2143 jpm 684
 
685
 
1654 aurelien 686
	/* Effectue un bootstraping plus sage que ci-dessus, mais le gain d'efficacité
1656 raphael 687
	   n'est pas aussi retentissant qu'espéré */
1654 aurelien 688
	static $service;
689
	function getNomCommun_v3($obs) {
690
		if(! $this->service) $this->service = new Projets();
2143 jpm 691
 
1654 aurelien 692
		$langue = 'fra';
693
		list($referentiel) = explode(':', strtolower($obs['nom_referentiel']));
694
		if($referentiel == 'bdtfx') $referentiel = 'nvjfl';
695
		else return '';
2143 jpm 696
 
1654 aurelien 697
		$cache_id = $referentiel . '-' . $obs['nt'] . '-' . $langue;
1657 raphael 698
		if(isset(self::$cache['getNomCommun'][$cache_id])) {
1656 raphael 699
			error_log("require NomsVernaculaires.php: OK ! (pour \"{$obs['nom_ret']}\")");
1657 raphael 700
			return self::$cache['getNomCommun'][$cache_id];
1654 aurelien 701
		}
702
		// pas de cache:
1656 raphael 703
		error_log("require NomsVernaculaires.php pour \"{$obs['nom_ret']}\"");
2143 jpm 704
 
1654 aurelien 705
		$donnees = Array('masque.nt' => $obs['nt'],
1656 raphael 706
						 'masque.lg' => $langue,
707
						 'retour.champs' => 'conseil_emploi');
708
		$this->service->initialiserRessourcesEtParametres(Array('nvjfl', 'noms-vernaculaires', 'attributions'), $donnees);
1654 aurelien 709
		try {
1656 raphael 710
			$noms = $this->service->traiterRessources();
2143 jpm 711
		} catch(Exception $e) {
1656 raphael 712
			return '';
1654 aurelien 713
		}
1656 raphael 714
		if(! $noms) return '';
1673 raphael 715
		$noms = array_filter($noms['resultat'], array($this, retournerNumStatutUnArr)); // XXX: php 5.3
1656 raphael 716
		$premier_nom = array_pop($noms);
1654 aurelien 717
		$nom = $premier_nom['nom_vernaculaire'];
2143 jpm 718
 
1654 aurelien 719
		// cache
1657 raphael 720
		self::$cache['getNomCommun'][$cache_id] = $nom;
1654 aurelien 721
		return $nom;
722
	}
1685 raphael 723
 
1694 raphael 724
	/* Cette fonction initialise le cache des noms communs en 1 fois, sur la liste des observations à exporter.
1702 raphael 725
	   Ainsi, les appels successifs à getNomCommun_v4() ne sont pas couteux (pas de requête SQL) */
1694 raphael 726
	static function getNomCommun_preload($cel, $obsids) {
727
		if(!$obsids) return;
1765 raphael 728
		if(!self::referenceTableExiste()) return NULL;
1694 raphael 729
 
730
		// CREATE INDEX i_nom_referentiel ON cel_obs (nom_referentiel(5));
731
		$req = sprintf("SELECT r.referentiel, r.num_taxon, r.nom_commun FROM cel_references r" .
732
					   " INNER JOIN cel_obs c ON (r.referentiel = substring_index(c.nom_referentiel, ':', 1) and r.num_taxon = c.nt)" .
733
					   " WHERE c.id_observation IN (%s)",
734
					   implode(',', $obsids));
1765 raphael 735
		$res = Cel::db()->requeter($req);
1694 raphael 736
		foreach($res as $v) {
737
			self::$cache['getNomCommun'][$v['referentiel'] . '-' . $v['num_taxon'] . '-' . 'fra'] = $v['nom_commun'];
738
		}
739
		return NULL;
740
	}
1702 raphael 741
 
1765 raphael 742
	static function referenceTableExiste() {
2143 jpm 743
		if (!self::$is_table) {
1702 raphael 744
			// une seule fois
2143 jpm 745
			if (! Cel::db()->requeterLigne("SHOW TABLES LIKE 'cel_references'")) return FALSE;
1702 raphael 746
			self::$is_table = TRUE;
747
		}
748
		return TRUE;
749
	}
2143 jpm 750
 
1765 raphael 751
	static function getNomCommun_v4($obs) {
2446 jpm 752
		// Attention la fonction suppose que l'on ait fait appel à getNomCommun_preload avant
2281 aurelien 753
		// d'être appelée
1685 raphael 754
		if(! $obs['nt']) return NULL;
1765 raphael 755
		if(! self::referenceTableExiste()) return NULL;
1689 raphael 756
 
1685 raphael 757
		$langue = 'fra';
758
		list($referentiel) = explode(':', strtolower($obs['nom_referentiel']));
759
		$cache_id = $referentiel . '-' . $obs['nt'] . '-' . $langue;
760
 
2281 aurelien 761
		$nom = null;
1757 raphael 762
		// cache:
2281 aurelien 763
		if(isset(self::$cache['getNomCommun'])) {
1757 raphael 764
			if(isset(self::$cache['getNomCommun'][$cache_id])) return self::$cache['getNomCommun'][$cache_id];
765
			// XXX: problème de valeurs NULL ?
2281 aurelien 766
			if(array_key_exists($cache_id, self::$cache['getNomCommun'])) {
767
				$nom = self::$cache['getNomCommun'][$cache_id];
768
			}
1757 raphael 769
		}
1685 raphael 770
 
771
		return $nom;
772
	}
1702 raphael 773
 
774
 
775
	/* Cette fonction initialise le cache des données baseflor en 1 fois, sur la liste des observations à exporter.
776
	   Ainsi, les appels successifs à baseflor_ligne() ne sont pas couteux (pas de requête SQL) */
777
	static function baseflor_preload($cel, $obsids) {
778
		if(!$obsids) return;
1765 raphael 779
		if(!self::referenceTableExiste()) return NULL;
1702 raphael 780
 
2254 aurelien 781
		// Attention (en attendant de faire une meilleure table et une meilleure requete) le distinct est très important
782
		$req = sprintf("SELECT DISTINCT referentiel, num_nom_retenu, %s FROM cel_references r" .
2297 mathias 783
						" INNER JOIN cel_obs c ON (r.num_nom_retenu = c.nom_ret_nn)" .
784
						" AND r.referentiel = IF(LOCATE(':', c.nom_referentiel) = 0, c.nom_referentiel, SUBSTR(c.nom_referentiel FROM 1 FOR LOCATE(':', c.nom_referentiel) - 1))" .
785
						" WHERE c.id_observation IN (%s)",
786
						//" AND catminat_code IS NOT NULL", // TODO: suppression des NULL ici signifie que le cache sera partiel...
787
						implode(',', array_keys(self::$baseflor_col)),
788
						implode(',', $obsids));
1765 raphael 789
		$res = Cel::db()->requeter($req);
1706 raphael 790
		if(!$res) return NULL;
1702 raphael 791
 
792
		foreach($res as $v) {
793
			$data = $v;
794
			unset($data['referentiel']); // non nécessaire
795
			unset($data['num_nom_retenu']); // non nécessaire
2446 jpm 796
 
2244 aurelien 797
			// Des fois les synonymes ont des valeurs pour baseflor et pas le nom retenu et vice versa
2446 jpm 798
			// on les fusionne pour avoir le maximum d'infos, en attendant de repenser la table référence
2244 aurelien 799
			if(isset(self::$cache['getBaseflor'][$v['referentiel'] . '-' . $v['num_nom_retenu']])) {
2446 jpm 800
				$orig  = array_filter(self::$cache['getBaseflor'][$v['referentiel'] . '-' . $v['num_nom_retenu']], 'strlen');
801
				$data  = array_filter($data , 'strlen');
2244 aurelien 802
				$data = array_merge($orig, $data);
803
			}
2446 jpm 804
 
1702 raphael 805
			self::$cache['getBaseflor'][$v['referentiel'] . '-' . $v['num_nom_retenu']] = $data;
806
		}
807
 
808
		return NULL;
809
	}
1685 raphael 810
 
2446 jpm 811
	/**
2312 mathias 812
	 * Attention la fonction suppose que l'on ait fait appel à baseflor_preload avant
813
	 * d'être appelée
814
	 * @CASSECOUILLES elle pourrait le détecter et le faire elle-même
815
	 */
1765 raphael 816
	static function baseflor_ligne($obs, &$ligne) {
2312 mathias 817
		$clefsBF = array_keys(self::$baseflor_col);
818
		// par défaut des colonnes vides pour ne pas décaler le bousin
819
		$donneesBF = array_fill_keys($clefsBF, "");
1702 raphael 820
 
2312 mathias 821
		// s'il y a des données baseflor
822
		if ($obs['nom_ret_nn'] && self::referenceTableExiste() && count(self::$cache['getBaseflor']) > 0) {
823
			// l'astuce à un franc vingt
824
			list($referentiel) = explode(':', strtolower($obs['nom_referentiel']));
825
			$cache_id = $referentiel . '-' . $obs['nom_ret_nn'];
1702 raphael 826
 
2312 mathias 827
			// si les données baseflor existent dans le cache pour ce nom_ret_nn
828
			if (array_key_exists($cache_id, self::$cache['getBaseflor'])) {
829
				$donneesBFATrous = self::$cache['getBaseflor'][$cache_id];
830
				foreach($clefsBF as $colbf) { // remplit les trous tout en préservant l'ordre
831
					if(array_key_exists($colbf, $donneesBFATrous)) {
832
						$donneesBF[$colbf] = $donneesBFATrous[$colbf];
833
					} else {
834
						$donneesBF[$colbf] = "";
835
					}
836
				}
837
			}
1702 raphael 838
		}
2312 mathias 839
 
840
		// Quand les données sont prêtes, on les fusionne
841
		$ligne = array_merge($ligne, $donneesBF);
1702 raphael 842
	}
2446 jpm 843
 
1715 raphael 844
	static function champsEtendus_preload($cel, $obsids) {
2446 jpm 845
		$gestion_champs_etendus = new GestionChampsEtendus($cel->config, 'obs');
1718 raphael 846
		$colonnes_champs_supp_par_obs = $gestion_champs_etendus->consulterClesParLots($obsids);
2446 jpm 847
 
848
		// Supprime les champs étendus considérés comme privés dans le cas de l'export public en chargeant
2403 aurelien 849
		// le catalogue et en excluant ceux qui sont explicitement privés
850
		if(!$cel->export_prive) {
851
			$indices_a_supprimer = array();
852
			$catalogue_champs_etendus = $gestion_champs_etendus->consulterCatalogueChampsEtendusPredefinis();
853
			foreach($catalogue_champs_etendus as $champ_catalogue) {
854
				if($champ_catalogue['options']['prive'] == 1) {
2446 jpm 855
					// Les champs étendus peuvent avoir des variantes lorsqu'ils apparaissent de multiples fois.
2407 aurelien 856
					// Vont donc matcher monChamp mais aussi monChamp:1, monChamp:2 ou bien monChamp1, monChamp: etc...
857
					// pour plus de sécurité (ce filtra n'est affectué qu'une fois au début de l'export donc on ne s'en prive pas)
858
					$entrees = preg_grep("/".$champ_catalogue['cle']."(?::?\d*)?$/", $colonnes_champs_supp_par_obs);
2403 aurelien 859
					$indices_a_supprimer = array_merge($indices_a_supprimer, array_keys($entrees));
860
				}
861
			}
862
			// les champs étendus sont renvoyés dans l'export suivant les colonnes présentes dans ce tableau
863
			// les éliminer de la liste des colonnes suffit à les faire ignorer par l'export
2446 jpm 864
			foreach($indices_a_supprimer as $indice_supp) {
865
				unset($colonnes_champs_supp_par_obs[$indice_supp]);
2403 aurelien 866
			}
867
		}
2446 jpm 868
 
1741 raphael 869
		// ces deux lignes réordonnent l'ordre des colonnes des champs étendus en fonction de l'ordre (très spécifique)
870
		// de self::$ordre_champ_etendus_Florileges, les champs non-mentionnés sont ajoutés à la fin.
871
		$colonnes_champs_supp_par_obs = self::sortArrayByArray(array_flip($colonnes_champs_supp_par_obs),
872
															   self::$ordre_champ_etendus_Florileges);
873
		$colonnes_champs_supp_par_obs = array_keys($colonnes_champs_supp_par_obs);
874
 
1718 raphael 875
		// si le SELECT des clefs ne retourne rien, une autre requêtes est inutile
876
		// TODO: optimize, 1 seule requête
877
		if(!$colonnes_champs_supp_par_obs) return Array('header' => array(), 'data' => array());
878
 
1715 raphael 879
		$champs_supp_par_obs = $gestion_champs_etendus->consulterParLots($obsids);
1741 raphael 880
 
1791 raphael 881
		self::$cache['champsEtendus']['header'] = self::champsEtendus_prefixHeader($colonnes_champs_supp_par_obs);
882
 
1715 raphael 883
		foreach($champs_supp_par_obs as &$v) {
884
			$v = self::champsEtendus_aplatir($v);
885
		}
886
		self::$cache['champsEtendus']['data'] = $champs_supp_par_obs;
887
		// ce return est temporaire,
888
		// le temps que toutes les fonctions bougent ici et utilise plutôt le cache statique
1716 raphael 889
		// encore utilisé pour les entêtes (self::$cache['champsEtendus']['header'])
1715 raphael 890
		return self::$cache['champsEtendus'];
891
	}
892
 
893
	// XXX: PHP-5.3, fonction anonyme + array_map
1791 raphael 894
	static function champsEtendus_prefixHeader($array) {
895
		return array_map(create_function('$v', 'return "' . PREFIX_CHAMPS_ETENDUS . '".$v;'), $array);
896
	}
897
 
898
	// XXX: PHP-5.3, fonction anonyme + array_map
1715 raphael 899
	static function champsEtendus_aplatir($ligne_champs_etendus) {
900
		$champs_etendus_fmt = array();
901
		if(!$ligne_champs_etendus) return $champs_etendus_fmt;
902
		foreach($ligne_champs_etendus as $champ) {
1791 raphael 903
			$champs_etendus_fmt[PREFIX_CHAMPS_ETENDUS . $champ->cle] = $champ->valeur;
1715 raphael 904
		}
905
		return $champs_etendus_fmt;
906
	}
1716 raphael 907
 
1765 raphael 908
	static function champsEtendus_ligne($obs, &$ligne) {
1716 raphael 909
		// si header n'est pas défini, aucune observation ne possède de champ étendu
910
		// et nous n'ajoutons ni colonnes, ni valeurs.
911
		if(! isset(self::$cache['champsEtendus']['header'])) return;
1736 raphael 912
		$ligne_etendue_aplatie = @self::$cache['champsEtendus']['data'][$obs['id_observation']];
1716 raphael 913
 
914
		$ligne_supp = array_fill(0, count(self::$cache['champsEtendus']['header']), '');
915
		$ligne_etendue_fmt = array();
916
 
917
		// si, cependant cette seule observation n'a pas de champs étendus,
918
		// nous devons rajouter des blancs (notamment dans le cas ou d'autres
919
		// champs viennent à être ajoutés en aval à l'avenir
920
		// cf: $fonction_dynamique dans FormateurGroupeColonne::GenColInfo()
921
		if(! $ligne_etendue_aplatie) {
922
			$ligne = array_merge($ligne, $ligne_supp);
923
			return;
924
		}
925
 
926
		foreach(self::$cache['champsEtendus']['header'] as $colonne) {
927
			if(!isset($ligne_etendue_aplatie[$colonne])) {
2143 jpm 928
				$ligne_etendue_fmt[$colonne] = '';
1716 raphael 929
			} else {
930
				$ligne_etendue_fmt[$colonne] = $ligne_etendue_aplatie[$colonne];
931
			}
932
		}
933
 
934
		// XXX/ array_merge() ?
935
		$ligne += $ligne_etendue_fmt;
936
	}
1741 raphael 937
 
938
	/* HELPERS */
939
 
940
	// http://stackoverflow.com/questions/348410/sort-an-array-based-on-another-array
941
	// XXX; redéfinition, utilisé aussi par ExportXLS
942
	static function sortArrayByArray($array, $orderArray) {
943
		$ordered = array();
944
		foreach($orderArray as $key) {
945
			if(array_key_exists($key, $array)) {
946
				$ordered[$key] = $array[$key];
947
				unset($array[$key]);
948
			}
949
		}
950
		return $ordered + $array;
951
	}
2461 jpm 952
}