Subversion Repositories eFlore/Applications.coel

Rev

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