Subversion Repositories eFlore/Applications.cel

Rev

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