Subversion Repositories eFlore/Applications.coel

Rev

Rev 1733 | 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',
1733 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
1765 aurelien 48
			$p = $this->traiterParametresUrl(array('id_structure', 'recherche'), $param);
1673 raphael 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/_/_/_
1765 aurelien 68
	 * ou les _ représentent dans l'ordre : id_structure et nom
1497 jpm 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_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
1765 aurelien 141
		$p = $this->traiterParametresUrl(array('type'), $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
			'GROUP BY IF ( SUBSTRING( cs_code_postal FROM 1 FOR 2 ) >= 96, '.
156
			'	SUBSTRING( cs_code_postal FROM 1 FOR 3 ), '.
157
			'	SUBSTRING( cs_code_postal FROM 1 FOR 2 ) ) '.
158
			'ORDER BY '.((!is_null($this->orderby)) ? $this->orderby  : 'id ASC').' ';
1693 raphael 159
 
1711 raphael 160
		// Récupération des résultats
161
		try {
162
			$donnees = $this->bdd->query($requete)->fetchAll(PDO::FETCH_ASSOC);
163
		} catch (PDOException $e) {
164
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
165
		}
1706 raphael 166
 
1711 raphael 167
		if ($donnees === false) {
168
			$this->messages[] = "La requête a retourné aucun résultat.";
169
			return array();
170
		}
1706 raphael 171
 
1711 raphael 172
		$info = array();
173
		foreach ($donnees as $donnee) {
174
			$info[$donnee['id']] = $donnee['nbre'];
175
		}
176
		return $info;
177
	}
1706 raphael 178
 
179
 
180
	static function NULLifNotNum(&$params, $keys_to_null) {
181
		foreach($keys_to_null as $v) {
1728 raphael 182
			if(! array_key_exists($v, $params)) continue;
183
			if(!is_numeric($params[$v]) && ! preg_match('/^-?\d+,\d*$/', $params[$v])) {
1706 raphael 184
				$params[$v] = NULL;
185
			}
1728 raphael 186
			else {
187
				$params[$v] = str_replace(',', '.', $params[$v]);
188
			}
189
 
1706 raphael 190
		}
191
	}
1497 jpm 192
 
193
	/**
194
	 * Méthode appelée pour ajouter un élément.
195
	 */
196
	public function createElement($params) {
197
		// Identification de l'utilisateur
198
		list($id_utilisateur, $id_session) = $this->getIdentification($params);
1648 raphael 199
 
1497 jpm 200
		// Contrôle du non détournement de l'utilisateur
1648 raphael 201
		if (!$this->etreAutorise($id_utilisateur)) {
202
			$this->envoyer();
203
			return;
204
		}
205
		try {
1709 raphael 206
			$form_needs_refresh = self::callNominatim($params, $this->bdd);
1649 raphael 207
 
1706 raphael 208
			self::NULLifNotNum($params, self::$optional_bool_fields);
1693 raphael 209
 
1706 raphael 210
			// Vérification des tables à vraiment mettre à jour en fonction des données passées.
1648 raphael 211
			$tables_a_modifier = $this->recupererTablesAModifier($params);
212
			reset($tables_a_modifier);
1649 raphael 213
 
1648 raphael 214
			$id_structure = null;
215
			while (list($table_id, $table) = each($tables_a_modifier)) {
216
				if (is_null($table['champs'])) continue;
217
				if ($this->avoirCleComplete($table)) {
218
					$this->mettreAJourAvecCle($id_utilisateur, $id_session, $table_id, $table);
219
					continue;
220
				}
221
 
222
				// Ajout des données à la table des données
223
				$id_structure = $this->ajouter($table);
224
				if ($id_structure === false) continue;
225
 
226
				$table['champs_valeurs_id']['cs_id_structure'] = $id_structure;
227
				$table['champs_valeurs_brut']['cs_id_structure'] = $id_structure;
228
				$tables_a_modifier[122]['champs_valeurs_id']['csc_id_structure'] = $id_structure;
229
				$tables_a_modifier[122]['champs_valeurs_brut']['csc_id_structure'] = $id_structure;
230
				$tables_a_modifier[122]['champs_valeurs_protege']['csc_id_structure'] = $this->bdd->quote($id_structure);
231
				$tables_a_modifier[123]['champs_valeurs_id']['csv_id_structure'] = $id_structure;
232
				$tables_a_modifier[123]['champs_valeurs_brut']['csv_id_structure'] = $id_structure;
233
				$tables_a_modifier[123]['champs_valeurs_protege']['csv_id_structure'] = $this->bdd->quote($id_structure);
1649 raphael 234
 
1648 raphael 235
				// Historisation (Ajout des méta-données)
236
				$etat = 1; // Ajout
237
				$cle = $this->recupererCle($table);
238
				$info = $this->creerXmlHisto($table['champs_valeurs_brut']);
239
				$id_meta = $this->historiser($table_id, $cle, $info, $id_utilisateur, $etat, $id_session);
1497 jpm 240
 
1648 raphael 241
				// Liaison de la table des données à ses méta-données
242
				$champ_meta = "{$table['prefixe']}_ce_meta";
243
				$table['champs_valeurs_protege'] = array($champ_meta => $id_meta);
244
				$this->modifier($table);
245
			}
246
 
247
			if(isset($params['cpr_abreviation']) && !empty($params['cpr_abreviation'])) {
1497 jpm 248
				$this->ajouterGuid($params['cpr_abreviation'], $id_structure);
249
			}
1648 raphael 250
		} catch (PDOException $e) {
251
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
252
		}
1708 raphael 253
 
254
		if($form_needs_refresh) { // coordonnées mises à jour en DB: en informer le formulaire
255
			$this->envoyer($this->getElementParDefaut(array('id_structure' => $id_structure)));
256
			exit;
257
		}
258
 
1669 raphael 259
		$this->envoyer($id_structure);
1497 jpm 260
	}
1706 raphael 261
 
1497 jpm 262
	/**
263
	 * Méthode appelée pour mettre à jour un élément
264
	 */
265
	public function updateElement($uid, $params) {
266
		// Vérification de la présence des id passés par l'url
267
		if (!isset($uid[0])) {
268
			$this->messages[] = "Identifiant de structure manquant. Vous ne devriez pas avoir accès à ce service.";
1648 raphael 269
			$this->envoyer();
270
			return;
271
		}
272
 
273
		// Identification de l'utilisateur
274
		list($id_utilisateur, $id_session) = $this->getIdentification($params);
275
		// Contrôle du non détournement de l'utilisateur
276
		if (!$this->etreAutorise($id_utilisateur)) {
277
			$this->envoyer();
278
			return;
279
		}
280
		try {
1709 raphael 281
			$form_needs_refresh = self::callNominatim($params, $this->bdd);
1651 raphael 282
 
1706 raphael 283
			self::NULLifNotNum($params, self::$optional_bool_fields);
1693 raphael 284
 
1648 raphael 285
			// Vérification des tables à vraiment mettre à jour en fonction des données passées.
286
			$tables_a_modifier = $this->recupererTablesAModifier($params);
287
			// Pour chaque table du module nous lançons si nécessaire l'historisation puis la mise à jour
288
			foreach ($tables_a_modifier as $table_id => $table) {
1670 raphael 289
				if(@$table['nom'] == 'coel_structure' && !$this->avoirCleComplete($table)) {
290
					error_log("tentative d'UPDATE sans contrainte de WHERE, \$table = " . print_r($table, TRUE));
1669 raphael 291
					continue; // ne pas mettre à jour sans contrainte de WHERE
292
				}
1648 raphael 293
				$this->mettreAJourAvecCle($id_utilisateur, $id_session, $table_id, $table);
294
			}
295
		} catch (PDOException $e) {
1765 aurelien 296
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage());
1497 jpm 297
		}
1651 raphael 298
 
1497 jpm 299
		// Envoie sur la sortie standard
1651 raphael 300
 
301
		if($form_needs_refresh) { // coordonnées mises à jour en DB: en informer le formulaire (si resté ouvert)
1673 raphael 302
			$this->envoyer($this->getElementParDefaut(array('id_structure' => $uid[0])));
303
			exit;
1651 raphael 304
		}
305
		$this->envoyer(); // OK par défaut
1497 jpm 306
	}
307
 
308
	/**
309
	 * Méthode appelée pour supprimer un élément
310
	 */
311
	public function deleteElement($uid) {
1669 raphael 312
		// NOTES : une structure ne peut pas être supprimée si elle possède des collections liées.
1497 jpm 313
		// Vérification de la présence des id passés par l'url
314
		if (!isset($uid[0]) || !isset($uid[1])) {
1711 raphael 315
			$this->messages[] = "Identifiant de structure ou d'utilisateur manquant. Vous ne devriez pas avoir accès à ce service.";
316
			$this->envoyer();
317
			return;
1706 raphael 318
		}
319
 
1711 raphael 320
		// Identification de l'utilisateur
321
		list($id_utilisateur, $id_session) = $this->getIdentification($uid[0]);
322
		// Contrôle du non détournement de l'utilisateur
323
		if (! $this->etreAutorise($id_utilisateur)) {
324
			$this->envoyer();
325
			return;
326
		}
1706 raphael 327
 
1711 raphael 328
		// Récupération des id passés par l'url
329
		$identifiants = explode(',', rtrim($uid[1], ','));
1706 raphael 330
 
1711 raphael 331
		if (count($identifiants) == 0) {
332
			$this->messages[] = "Aucun enregistrement n'a été supprimé.";
333
			$this->envoyer();
334
			return;
335
		}
1497 jpm 336
 
1711 raphael 337
		try {
338
			foreach ($identifiants as $id_structure) {
339
				// Vérification que la structure ne possède pas de collections liées
340
				if (self::verifierPresenceCollection($this->bdd, $id_structure)) {
341
					$this->messages[] = "La structure '$id_structure' ne peut pas être supprimée car elle possède des collections liées.";
342
					continue;
343
				}
1706 raphael 344
 
1711 raphael 345
				$params = array('cs_id_structure' => $id_structure, 'csc_id_structure' => $id_structure, 'csv_id_structure' => $id_structure);
346
				$tables_a_modifier = $this->recupererTablesAModifier($params);
1497 jpm 347
 
1711 raphael 348
				foreach ($tables_a_modifier as $table_id => $table) {
349
					if (! $this->avoirEnregistrement($table)) continue;
1497 jpm 350
 
1711 raphael 351
					if ($this->supprimer($table) === true) {
352
						// Historisation (Ajout des méta-données)
353
						$cle = $this->recupererCle($table);
354
						$this->historiser($table_id, $cle, 'NULL', $id_utilisateur, 3, $id_session);
355
					}
356
				}
357
			}
358
		} catch (PDOException $e) {
359
			$this->messages[] = sprintf($this->getTxt('sql_erreur'), $e->getFile(), $e->getLine(), $e->getMessage(), $requete);
360
		}
1706 raphael 361
 
1497 jpm 362
		// Envoie sur la sortie standard
363
		$this->envoyer();
364
	}
365
 
1706 raphael 366
	static function verifierPresenceCollection($db, $id_structure) {
1497 jpm 367
		// Vérification que la structure ne possède pas de collections liées
1711 raphael 368
		return ($db->query(sprintf(
369
			'SELECT COUNT(cc_id_collection) AS nbre_collection FROM coel_collection ' .
370
			' WHERE cc_ce_structure = %d GROUP BY cc_ce_structure ',
371
			$id_structure))->fetchColumn() != 0);
1706 raphael 372
	}
373
 
1709 raphael 374
	static function callNominatim(&$params, $db = NULL) {
1711 raphael 375
		// lon/lat déjà saisies ?
1709 raphael 376
		if (@$params['cs_latitude'] && @$params['cs_longitude']) return FALSE;
377
 
1711 raphael 378
		// ni adresse, ni CP, ni ville ? rien n'est possible
379
		if (!@$params['cs_adresse_01'] && !@$params['cs_code_postal'] && !@$params['cs_ville']) return FALSE;
1709 raphael 380
 
1711 raphael 381
		$lonlat = array();
382
		if(Coel::coordGuess(Coel::addrReStruct($params, $db), $lonlat)) {
383
			$params['cs_latitude'] = $lonlat['lat'];
384
			$params['cs_longitude'] = $lonlat['lon'];
385
			return TRUE;
386
		}
1709 raphael 387
 
1711 raphael 388
		// second guess, sans code postal
389
		if(@$params['cs_code_postal']) {
390
			$params2 = $params;
391
			unset($params2['cs_code_postal']);
392
			if(Coel::coordGuess(Coel::addrReStruct($params2, $db), $lonlat)) {
393
				$params['cs_latitude'] = $lonlat['lat'];
394
				$params['cs_longitude'] = $lonlat['lon'];
395
				return TRUE;
396
			}
397
		}
1706 raphael 398
		return FALSE;
1497 jpm 399
	}
400
 
1765 aurelien 401
	private function ajouterGuid($id_structure) {
1497 jpm 402
		if ($id_structure !== false) {
1708 raphael 403
			$table_guid = $this->tables[120];
1497 jpm 404
			$table_guid['champs_valeurs_id']['cs_id_structure'] = $id_structure;
1765 aurelien 405
			$table_guid['champs_valeurs_protege']['cs_guid'] = $this->bdd->quote(sprintf($this->config['coel']['guid'], 'str'.$id_structure));
1497 jpm 406
			$this->modifier($table_guid);
407
		}
408
	}
409
}