Subversion Repositories eFlore/Applications.coel

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1497 jpm 1
<?php
2
/**
3
 * Service fournissant la liste des structures et leurs informations.
4
 *
1706 raphael 5
 * @author Raphaël Droz <raphael@tela-botanica.org>
1497 jpm 6
 * @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
1706 raphael 7
 * @Copyright (c) 2009, 2013 Tela Botanica (accueil@tela-botanica.org)
1497 jpm 8
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
9
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
10
 */
11
class CoelStructure extends Coel {
1693 raphael 12
 
1706 raphael 13
	static $optional_bool_fields = array(
14
		'cs_nbre_personne',
15
		'csc_mark_formation', 'csc_mark_formation_interet',
1713 raphael 16
		'csc_mark_collection_commune', 'csc_mark_acces_controle', 'csc_mark_restauration', 'csc_mark_traitement',
1706 raphael 17
		'csc_mark_acquisition_collection', 'csc_mark_acquisition_echantillon',
18
		'cs_latitude', 'cs_longitude',
19
	);
1693 raphael 20
 
1497 jpm 21
	// ATTENTION : tjrs garder la table principale en premier, puis mettre les tables spécialisées.
1711 raphael 22
	protected $tables = array(	120 => array(
23
		'nom' => 'coel_structure',
24
		'prefixe' => 'cs',
25
		'id' => array('cs_id_structure')),
26
	122 => array(
27
		'nom' => 'coel_structure_conservation',
28
		'prefixe' => 'csc',
29
		'id' => array('csc_id_structure')),
30
	123 => array(
31
		'nom' => 'coel_structure_valorisation',
32
		'prefixe' => 'csv',
33
		'id' => array('csv_id_structure')));
1497 jpm 34
 
35
	/**
36
	 * Méthode principale appelée avec une requête de type GET.
37
	 */
38
	public function getElement($param = array()) {
39
		// Initialisation des variables
40
		$info = array();
41
 
42
		// Nour recherchons le type de requête demandé
43
		$type = $param[0];
44
 
45
		if ($type == '*' || is_numeric($type)) {
1673 raphael 46
			// Pré traitement des paramêtres
47
			$p = $this->traiterParametresUrl(array('id_projet', 'id_structure', 'recherche'), $param);
48
			$info = $this->getElementParDefaut($p);
1497 jpm 49
		} else {
50
			$methode = 'getElement'.$type;
51
			if (method_exists($this, $methode)) {
52
				array_shift($param);
53
				$info = $this->$methode($param);
54
			} else {
55
				$this->messages[] = "Le type d'information demandé '$type' n'est pas disponible.";
56
			}
57
		}
58
 
59
		// Envoie sur la sortie standard
60
		$this->envoyer($info);
61
	}
62
 
63
	/**
64
	 * Méthode par défaut pour garder la compatibilité avec Coel.
65
	 * Appelée avec les paramêtres d'url suivant :
66
	 * /CoelStructure/_/_/_
67
	 * ou les _ représentent dans l'ordre : id_projet, id_structure et nom
68
	 * Si un des paramêtres est abscent, il prendre la valeur *
69
	 */
1673 raphael 70
	public function getElementParDefaut($p) {
1497 jpm 71
		// Initialisation des variables
72
		$info = array();
1673 raphael 73
 
1706 raphael 74
		$whereClause = array();
75
		if(isset($p['id_projet'])) $whereClause[] = "cs_ce_projet = {$p['id_projet']}";
76
		if(isset($p['id_structure'])) $whereClause[] = "cs_id_structure = {$p['id_structure']}";
1688 raphael 77
 
1706 raphael 78
		if(isset($p['recherche'])) {
1711 raphael 79
			if(@$this->searchCity && trim($this->searchCity) == 'true') {
1706 raphael 80
				$whereClause[] = "(" . implode(" OR ", array("cs_nom LIKE {$p['recherche']}", "cs_ville LIKE {$p['recherche']}")) . ")";
81
			} else {
82
				$whereClause[] = "cs_nom LIKE {$p['recherche']}";
83
			}
84
		}
1688 raphael 85
 
1497 jpm 86
		// Construction de la requête
1688 raphael 87
		$requete = sprintf(
1706 raphael 88
			'SELECT SQL_CALC_FOUND_ROWS %s cs.*, csc.*, csv.*, cmhl_date_modification, cmhl_notes, cmhl_source, cmhl_ce_modifier_par, cmhl_ce_etat, cmhl_ip '
89
			. ' FROM coel_structure AS cs '
90
			. ' LEFT JOIN coel_meta_historique_ligne ON (cs_ce_meta = cmhl_id_historique_ligne) '
91
			. ' LEFT JOIN coel_structure_conservation AS csc ON (cs_id_structure = csc_id_structure) '
92
			. ' LEFT JOIN coel_structure_valorisation AS csv ON (cs_id_structure = csv_id_structure) '
93
			. ' WHERE %s ORDER BY %s LIMIT %d, %d -- %s:%d',
1497 jpm 94
 
1706 raphael 95
			$this->distinct ? 'DISTINCT' : '',
96
			$whereClause ? implode(" AND ", $whereClause) : TRUE,
97
			is_null($this->orderby) ? 'cs.cs_nom ASC' : $this->orderby,
98
			$this->start, $this->limit,
99
			__FILE__, __LINE__);
1688 raphael 100
 
1706 raphael 101
		// Récupération des résultats
1497 jpm 102
		try {
103
			// SPÉCIAL :
104
			// Lorsqu'on cherche une seule structure avec un id passé en paramêtre, nous devons renvoyer un objet
1595 aurelien 105
			$donnees = ($this->formatRetour == 'objet' && isset($p['id_structure'])) ? $this->bdd->query($requete)->fetch(PDO::FETCH_OBJ) : $this->bdd->query($requete)->fetchAll(PDO::FETCH_ASSOC);
1497 jpm 106
			if ($donnees === false) {
107
				$this->messages[] = "La requête a retourné aucun résultat.";
108
			}
1689 raphael 109
 
1706 raphael 110
			// l'UI java n'aime pas les NULL
111
			if(!is_array($donnees)) {
112
				// $donnees est un objet PHP
113
				array_walk($donnees, create_function('&$val', '$val = is_null($val) ? "" : $val;'));
114
			}
115
			else {
116
				// $donnees est un tableau d'objets PHP
117
				foreach($donnees as &$structure) {
118
					array_walk($structure, create_function('&$val', '$val = is_null($val) ? "" : $val;'));
119
				}
120
			}
1689 raphael 121
 
1688 raphael 122
			$elements_nbre = $this->bdd->query("SELECT FOUND_ROWS() AS c")->fetch(PDO::FETCH_ASSOC);
1689 raphael 123
			$info['nbElements'] = intval($elements_nbre['c']);
1497 jpm 124
			$info['structures'] = $donnees;
125
		} catch (PDOException $e) {
126
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
127
		}
128
 
129
		return $info;
130
	}
131
 
132
	/* Méthode pour récupérer le nombre de structure par zone géographique.
133
	 * Appelée avec les paramêtres d'url suivant :
134
	 * /CoelStructure/ParZoneGeo/_
135
	 * ou les _ représentent dans l'ordre : type.
136
	 * ou type peut valoir: FRD (= département français)
137
	 * Si un des paramêtres est abscent, il prendre la valeur *
138
	 */
139
	public function getElementParZoneGeo($param) {
140
		// Pré traitement des paramêtres
1581 jpm 141
		$p = $this->traiterParametresUrl(array('type', 'projets'), $param);
1497 jpm 142
		if (!isset($p['type'])) {
143
			$this->messages[] = "Il est obligatoire d'indiquer type de recherche pour utiliser ce service.";
1711 raphael 144
			return array();
1497 jpm 145
		}
1693 raphael 146
 
1711 raphael 147
		// Construction de la requête
148
		$requete =	(($this->distinct) ? 'SELECT DISTINCT' : 'SELECT').' '.
149
			'	IF ( SUBSTRING( cs_code_postal FROM 1 FOR 2 ) >= 96, '.
150
			'		SUBSTRING( cs_code_postal FROM 1 FOR 3 ), '.
151
			'		SUBSTRING( cs_code_postal FROM 1 FOR 2 ) ) AS id, '.
152
			'	COUNT( cs_id_structure ) AS nbre '.
153
			'FROM coel_structure '.
154
			'WHERE cs_ce_truk_pays = 2654 '.
155
			(isset($p['projets']) ? "	AND cs_ce_projet IN ({$p['projets']}) " : '').
156
			'GROUP BY IF ( SUBSTRING( cs_code_postal FROM 1 FOR 2 ) >= 96, '.
157
			'	SUBSTRING( cs_code_postal FROM 1 FOR 3 ), '.
158
			'	SUBSTRING( cs_code_postal FROM 1 FOR 2 ) ) '.
159
			'ORDER BY '.((!is_null($this->orderby)) ? $this->orderby  : 'id ASC').' ';
1693 raphael 160
 
1711 raphael 161
		// Récupération des résultats
162
		try {
163
			$donnees = $this->bdd->query($requete)->fetchAll(PDO::FETCH_ASSOC);
164
		} catch (PDOException $e) {
165
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
166
		}
1706 raphael 167
 
1711 raphael 168
		if ($donnees === false) {
169
			$this->messages[] = "La requête a retourné aucun résultat.";
170
			return array();
171
		}
1706 raphael 172
 
1711 raphael 173
		$info = array();
174
		foreach ($donnees as $donnee) {
175
			$info[$donnee['id']] = $donnee['nbre'];
176
		}
177
		return $info;
178
	}
1706 raphael 179
 
180
 
181
	static function NULLifNotNum(&$params, $keys_to_null) {
182
		foreach($keys_to_null as $v) {
1728 raphael 183
			if(! array_key_exists($v, $params)) continue;
184
			if(!is_numeric($params[$v]) && ! preg_match('/^-?\d+,\d*$/', $params[$v])) {
1706 raphael 185
				$params[$v] = NULL;
186
			}
1728 raphael 187
			else {
188
				$params[$v] = str_replace(',', '.', $params[$v]);
189
			}
190
 
1706 raphael 191
		}
192
	}
1497 jpm 193
 
194
	/**
195
	 * Méthode appelée pour ajouter un élément.
196
	 */
197
	public function createElement($params) {
198
		// Identification de l'utilisateur
199
		list($id_utilisateur, $id_session) = $this->getIdentification($params);
1648 raphael 200
 
1497 jpm 201
		// Contrôle du non détournement de l'utilisateur
1648 raphael 202
		if (!$this->etreAutorise($id_utilisateur)) {
203
			$this->envoyer();
204
			return;
205
		}
206
		try {
1709 raphael 207
			$form_needs_refresh = self::callNominatim($params, $this->bdd);
1649 raphael 208
 
1706 raphael 209
			self::NULLifNotNum($params, self::$optional_bool_fields);
1693 raphael 210
 
1706 raphael 211
			// Vérification des tables à vraiment mettre à jour en fonction des données passées.
1648 raphael 212
			$tables_a_modifier = $this->recupererTablesAModifier($params);
213
			reset($tables_a_modifier);
1649 raphael 214
 
1648 raphael 215
			$id_structure = null;
216
			while (list($table_id, $table) = each($tables_a_modifier)) {
217
				if (is_null($table['champs'])) continue;
218
				if ($this->avoirCleComplete($table)) {
219
					$this->mettreAJourAvecCle($id_utilisateur, $id_session, $table_id, $table);
220
					continue;
221
				}
222
 
223
				// Ajout des données à la table des données
224
				$id_structure = $this->ajouter($table);
225
				if ($id_structure === false) continue;
226
 
227
				$table['champs_valeurs_id']['cs_id_structure'] = $id_structure;
228
				$table['champs_valeurs_brut']['cs_id_structure'] = $id_structure;
229
				$tables_a_modifier[122]['champs_valeurs_id']['csc_id_structure'] = $id_structure;
230
				$tables_a_modifier[122]['champs_valeurs_brut']['csc_id_structure'] = $id_structure;
231
				$tables_a_modifier[122]['champs_valeurs_protege']['csc_id_structure'] = $this->bdd->quote($id_structure);
232
				$tables_a_modifier[123]['champs_valeurs_id']['csv_id_structure'] = $id_structure;
233
				$tables_a_modifier[123]['champs_valeurs_brut']['csv_id_structure'] = $id_structure;
234
				$tables_a_modifier[123]['champs_valeurs_protege']['csv_id_structure'] = $this->bdd->quote($id_structure);
1649 raphael 235
 
1648 raphael 236
				// Historisation (Ajout des méta-données)
237
				$etat = 1; // Ajout
238
				$cle = $this->recupererCle($table);
239
				$info = $this->creerXmlHisto($table['champs_valeurs_brut']);
240
				$id_meta = $this->historiser($table_id, $cle, $info, $id_utilisateur, $etat, $id_session);
1497 jpm 241
 
1648 raphael 242
				// Liaison de la table des données à ses méta-données
243
				$champ_meta = "{$table['prefixe']}_ce_meta";
244
				$table['champs_valeurs_protege'] = array($champ_meta => $id_meta);
245
				$this->modifier($table);
246
			}
247
 
248
			if(isset($params['cpr_abreviation']) && !empty($params['cpr_abreviation'])) {
1497 jpm 249
				$this->ajouterGuid($params['cpr_abreviation'], $id_structure);
250
			}
1648 raphael 251
		} catch (PDOException $e) {
252
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
253
		}
1708 raphael 254
 
255
		if($form_needs_refresh) { // coordonnées mises à jour en DB: en informer le formulaire
256
			$this->envoyer($this->getElementParDefaut(array('id_structure' => $id_structure)));
257
			exit;
258
		}
259
 
1669 raphael 260
		$this->envoyer($id_structure);
1497 jpm 261
	}
1706 raphael 262
 
1497 jpm 263
	/**
264
	 * Méthode appelée pour mettre à jour un élément
265
	 */
266
	public function updateElement($uid, $params) {
267
		// Vérification de la présence des id passés par l'url
268
		if (!isset($uid[0])) {
269
			$this->messages[] = "Identifiant de structure manquant. Vous ne devriez pas avoir accès à ce service.";
1648 raphael 270
			$this->envoyer();
271
			return;
272
		}
273
 
274
		// Identification de l'utilisateur
275
		list($id_utilisateur, $id_session) = $this->getIdentification($params);
276
		// Contrôle du non détournement de l'utilisateur
277
		if (!$this->etreAutorise($id_utilisateur)) {
278
			$this->envoyer();
279
			return;
280
		}
281
		try {
1709 raphael 282
			$form_needs_refresh = self::callNominatim($params, $this->bdd);
1651 raphael 283
 
1706 raphael 284
			self::NULLifNotNum($params, self::$optional_bool_fields);
1693 raphael 285
 
1648 raphael 286
			// Vérification des tables à vraiment mettre à jour en fonction des données passées.
287
			$tables_a_modifier = $this->recupererTablesAModifier($params);
288
			// Pour chaque table du module nous lançons si nécessaire l'historisation puis la mise à jour
289
			foreach ($tables_a_modifier as $table_id => $table) {
1670 raphael 290
				if(@$table['nom'] == 'coel_structure' && !$this->avoirCleComplete($table)) {
291
					error_log("tentative d'UPDATE sans contrainte de WHERE, \$table = " . print_r($table, TRUE));
1669 raphael 292
					continue; // ne pas mettre à jour sans contrainte de WHERE
293
				}
1648 raphael 294
				$this->mettreAJourAvecCle($id_utilisateur, $id_session, $table_id, $table);
295
			}
296
		} catch (PDOException $e) {
297
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
1497 jpm 298
		}
1651 raphael 299
 
1497 jpm 300
		// Envoie sur la sortie standard
1651 raphael 301
 
302
		if($form_needs_refresh) { // coordonnées mises à jour en DB: en informer le formulaire (si resté ouvert)
1673 raphael 303
			$this->envoyer($this->getElementParDefaut(array('id_structure' => $uid[0])));
304
			exit;
1651 raphael 305
		}
306
		$this->envoyer(); // OK par défaut
1497 jpm 307
	}
308
 
309
	/**
310
	 * Méthode appelée pour supprimer un élément
311
	 */
312
	public function deleteElement($uid) {
1669 raphael 313
		// NOTES : une structure ne peut pas être supprimée si elle possède des collections liées.
1497 jpm 314
		// Vérification de la présence des id passés par l'url
315
		if (!isset($uid[0]) || !isset($uid[1])) {
1711 raphael 316
			$this->messages[] = "Identifiant de structure ou d'utilisateur manquant. Vous ne devriez pas avoir accès à ce service.";
317
			$this->envoyer();
318
			return;
1706 raphael 319
		}
320
 
1711 raphael 321
		// Identification de l'utilisateur
322
		list($id_utilisateur, $id_session) = $this->getIdentification($uid[0]);
323
		// Contrôle du non détournement de l'utilisateur
324
		if (! $this->etreAutorise($id_utilisateur)) {
325
			$this->envoyer();
326
			return;
327
		}
1706 raphael 328
 
1711 raphael 329
		// Récupération des id passés par l'url
330
		$identifiants = explode(',', rtrim($uid[1], ','));
1706 raphael 331
 
1711 raphael 332
		if (count($identifiants) == 0) {
333
			$this->messages[] = "Aucun enregistrement n'a été supprimé.";
334
			$this->envoyer();
335
			return;
336
		}
1497 jpm 337
 
1711 raphael 338
		try {
339
			foreach ($identifiants as $id_structure) {
340
				// Vérification que la structure ne possède pas de collections liées
341
				if (self::verifierPresenceCollection($this->bdd, $id_structure)) {
342
					$this->messages[] = "La structure '$id_structure' ne peut pas être supprimée car elle possède des collections liées.";
343
					continue;
344
				}
1706 raphael 345
 
1711 raphael 346
				$params = array('cs_id_structure' => $id_structure, 'csc_id_structure' => $id_structure, 'csv_id_structure' => $id_structure);
347
				$tables_a_modifier = $this->recupererTablesAModifier($params);
1497 jpm 348
 
1711 raphael 349
				foreach ($tables_a_modifier as $table_id => $table) {
350
					if (! $this->avoirEnregistrement($table)) continue;
1497 jpm 351
 
1711 raphael 352
					if ($this->supprimer($table) === true) {
353
						// Historisation (Ajout des méta-données)
354
						$cle = $this->recupererCle($table);
355
						$this->historiser($table_id, $cle, 'NULL', $id_utilisateur, 3, $id_session);
356
					}
357
				}
358
			}
359
		} catch (PDOException $e) {
360
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
361
		}
1706 raphael 362
 
1497 jpm 363
		// Envoie sur la sortie standard
364
		$this->envoyer();
365
	}
366
 
1706 raphael 367
	static function verifierPresenceCollection($db, $id_structure) {
1497 jpm 368
		// Vérification que la structure ne possède pas de collections liées
1711 raphael 369
		return ($db->query(sprintf(
370
			'SELECT COUNT(cc_id_collection) AS nbre_collection FROM coel_collection ' .
371
			' WHERE cc_ce_structure = %d GROUP BY cc_ce_structure ',
372
			$id_structure))->fetchColumn() != 0);
1706 raphael 373
	}
374
 
1709 raphael 375
	static function callNominatim(&$params, $db = NULL) {
1711 raphael 376
		// lon/lat déjà saisies ?
1709 raphael 377
		if (@$params['cs_latitude'] && @$params['cs_longitude']) return FALSE;
378
 
1711 raphael 379
		// ni adresse, ni CP, ni ville ? rien n'est possible
380
		if (!@$params['cs_adresse_01'] && !@$params['cs_code_postal'] && !@$params['cs_ville']) return FALSE;
1709 raphael 381
 
1711 raphael 382
		$lonlat = array();
383
		if(Coel::coordGuess(Coel::addrReStruct($params, $db), $lonlat)) {
384
			$params['cs_latitude'] = $lonlat['lat'];
385
			$params['cs_longitude'] = $lonlat['lon'];
386
			return TRUE;
387
		}
1709 raphael 388
 
1711 raphael 389
		// second guess, sans code postal
390
		if(@$params['cs_code_postal']) {
391
			$params2 = $params;
392
			unset($params2['cs_code_postal']);
393
			if(Coel::coordGuess(Coel::addrReStruct($params2, $db), $lonlat)) {
394
				$params['cs_latitude'] = $lonlat['lat'];
395
				$params['cs_longitude'] = $lonlat['lon'];
396
				return TRUE;
397
			}
398
		}
1706 raphael 399
		return FALSE;
1497 jpm 400
	}
401
 
402
	private function ajouterGuid($abr_projet, $id_structure) {
403
		if ($id_structure !== false) {
1708 raphael 404
			$table_guid = $this->tables[120];
1497 jpm 405
			$table_guid['champs_valeurs_id']['cs_id_structure'] = $id_structure;
406
			$table_guid['champs_valeurs_protege']['cs_guid'] = $this->bdd->quote(sprintf($this->config['coel']['guid'], $abr_projet, 'str'.$id_structure));
407
			$this->modifier($table_guid);
408
		}
409
	}
410
}