Subversion Repositories eFlore/Applications.cel

Rev

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

Rev Author Line No. Line
1066 jpm 1
<?php
2
// declare(encoding='UTF-8');
3
/**
4
 * Classe mère permettant de rassembler les manipulation concernant les mots clés.
5
 * Pour l'utiliser, il suffit d'étendre votre service avec cette classe à la place de Cel.
6
 * Encodage en entrée : utf8
7
 * Encodage en sortie : utf8
8
 *
9
 * @author Jean-Pascal MILCENT <jpm@tela-botanica.org>
10
 * @author Aurélien PERONNET <aurelien@tela-botanica.org>
11
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
12
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
13
 * @version $Id$
14
 * @copyright © 2011, Tela-Botanica
15
 */
16
// TODO : compléter la classe avec des méthdodes de modification, suppression et consultation des mots-clés.
17
// TODO : ajout vérification de la non présence du caractère '|' dans les chaines utilisateurs...
18
class CelMotCle extends Cel {
19
 
20
	const OBS_RACINE_ID = 'racine_obs';
21
	const OBS_RACINE_NOM = 'Projets';
22
	const OBS_TABLE_SUFFIXE = '_obs';
23
 
24
	const IMG_RACINE_ID = 'racine';
25
	const IMG_RACINE_NOM = 'Mots clés';
26
	const IMG_TABLE_SUFFIXE = '_images';
27
 
28
	const SEPARATEUR_MOT_CLE_TEXTE = '##';
29
	const SEPARATEUR_MOT_CLE_ID = ';';
30
 
31
	/**
32
	 * @var String permet de savoir si nous avons à faire à un mot clé d'observation ou d'image.
33
	 */
34
	private $suffix = '';
35
 
36
	/**
37
	 * @var String identifiant de l'utilisateur dont nous gérons les mots-clés.
38
	 */
39
	private $utilisateur_id = '';
40
 
41
	/**
42
	 * Lie un mot-clé à une ou plusieurs observations.
43
	 *
44
	 * @param String $utilisateur_id identifiant de l'utilisateur.
45
	 * @param String $mot_cle texte du mot-clé.
46
	 * @param Array $ordres_obs un tableau d'odre d'observation (int) pour lesquels nous devons ajouter le mot-clé.
47
	 */
48
	public function lierMotCleObs($utilisateur_id, Array $mots_cles_ids, Array $ordres) {
49
		$retour = false;
50
 
51
		if ($this->verifierOrdres($ordres)) {
52
			$mots_cles_ids_concatenes = $this->concatenerMotsClesIds($mots_cles_ids);
53
			$mots_cles_ids_concatenes = $this->proteger($mots_cles_ids_concatenes);
54
			$utilisateur_id = $this->proteger($utilisateur_id);
55
 
56
			$ordres_sql_in = implode(', ', $ordres);
57
			$requete =	'UPDATE cel_inventory '.
58
						"SET mots_cles = REPLACE(CONCAT(IFNULL(mots_cles, ''), $mots_cles_ids_concatenes), 'null', '') ".
59
						"WHERE ordre IN ($ordres_sql_in) ".
60
						"	AND identifiant = $utilisateur_id ";
61
			$resultat = $this->executer($requete);
62
			if ($resultat) {
63
				$retour = true;
64
				foreach ($ordres as $ordre) {
65
					$regeneration = $this->regenererIndexTexteMotCle($ordre);
66
					if ($regeneration === false) {
67
						$retour = false;
68
					}
69
				}
70
			} else {
71
				$e = "Erreur de mise à jour des mots clés d'une obs : $requete";
72
				$this->logger('CEL_bugs', $e);
73
				$this->messages[] = $e;
74
			}
75
 
76
		} else {
77
			$this->messages[] = "Le tableau des ordres des obs ne contenait pas que des nombres entiers.";
78
		}
79
		return $retour;
80
	}
81
 
82
	private function regenererIndexTexteMotCle($ordre) {
83
		$ok = false;
84
		$mots_cles_ids = $this->obtenirIdsMotsClesConcatenes($ordre);
85
		if ($mots_cles_ids) {
86
			$mots_cles = $this->obtenirMotClesTexte($mots_cles_ids);
87
			$mots_cles_concatenes = $this->concatenerMotsCles($mots_cles);
88
			$ok = $this->mettreAJourMotsClesConcatenes($mots_cles_concatenes, $ordre);
89
		}
90
		return $ok;
91
	}
92
 
93
	private function obtenirIdsMotsClesConcatenes($ordre) {
94
		$utilisateur_id = $this->proteger($this->utilisateur_id);
95
 
96
		$requete = 	'SELECT mots_cles '.
97
					'FROM cel_inventory '.
98
					"WHERE ordre = $ordre ".
99
					"	AND identifiant = $utilisateur_id ";
100
		$resultat = $this->recupererResultat($requete);
101
 
102
		$mots_cles_ids = false;
103
		if ($resultat) {
104
			$mots_cles_ids = $resultat['mots_cles'];
105
		}
106
		return $mots_cles_ids;
107
	}
108
 
109
	private function obtenirMotClesTexte($mot_cle_ids) {
110
		$mot_cle_ids_in = $this->formaterIdsMotClePourClauseInSql($mot_cle_ids);
111
		$utilisateur_id = $this->proteger($this->utilisateur_id);
112
 
113
		$requete = 	'SELECT cmc_mot_cle '.
114
					'FROM cel_mots_cles_obs '.
115
					"WHERE cmc_id_mot_cle_utilisateur IN ($mot_cle_ids_in) ".
116
					"	AND cmc_id_proprietaire = $utilisateur_id ";
117
		$resultats = $this->recupererResultats($requete);
118
		$mots_cles = array();
119
		if ($resultats) {
120
			foreach ($resultats as $mot_cle) {
121
				$mots_cles[] = $mot_cle['cmc_mot_cle'];
122
			}
123
		}
124
		return $mots_cles;
125
	}
126
 
127
	private function formaterIdsMotClePourClauseInSql($mot_cle_ids) {
128
		$mot_cle_ids = $this->nettoyerMotsCles($mot_cle_ids);
129
		$mot_cle_ids = str_replace(self::SEPARATEUR_MOT_CLE_ID, ',', $mot_cle_ids);
130
		$mot_cle_ids = trim($mot_cle_ids, ',');
131
		$mot_cle_ids_proteges = implode(',', $this->protegerTableau(explode(',', $mot_cle_ids)));
132
		return $mot_cle_ids_proteges;
133
	}
134
 
135
	private function concatenerMotsClesIds(Array $mots_cles_ids) {
136
		$mots_cles_ids_concatenes = '';
137
		if (count($mots_cles_ids) > 0) {
138
			foreach ($mots_cles_ids as $mot_cle_id) {
139
				$mots_cles_ids_concatenes .= $this->nettoyerMotsCles($mot_cle_id).self::SEPARATEUR_MOT_CLE_ID;
140
			}
141
		}
142
		return $mots_cles_ids_concatenes;
143
	}
144
 
145
	private function concatenerMotsCles(Array $mots_cles) {
146
		$mot_cles_concatenes = '';
147
		if (count($mots_cles) > 0) {
148
			foreach ($mots_cles as $mot_cle) {
149
				$mot_cles_concatenes .= $mot_cle.self::SEPARATEUR_MOT_CLE_TEXTE;
150
			}
151
		}
152
		$mot_cles_concatenes = rtrim($mot_cles_concatenes, self::SEPARATEUR_MOT_CLE_TEXTE);
153
 
154
		return $mot_cles_concatenes;
155
	}
156
 
157
	private function mettreAJourMotsClesConcatenes($mots_cles, $ordre) {
158
		$mots_cles = $this->proteger($mots_cles);
159
		$utilisateur_id = $this->proteger($this->utilisateur_id);
160
 
161
		$requete = 	'UPDATE cel_inventory '.
162
					"SET mots_cles_texte = $mots_cles ".
163
					"WHERE ordre = $ordre ".
164
					"	AND identifiant = $utilisateur_id ";
165
		$ok = $this->executer($requete) ? true : false;
166
		return $ok;
167
	}
168
 
169
	private function verifierOrdres($ordres) {
170
		$ok = true;
171
		foreach ($ordres as $ordre) {
172
			if (! preg_match('/^[0-9]+$/', $ordre)) {
173
				$this->debug[] = "Ordre pb : $ordre";
174
				$ok = false;
175
			}
176
		}
177
		return $ok;
178
	}
179
 
180
	private function nettoyerMotsCles($chaine) {
181
		$valeur = str_replace('null', '', $chaine);
182
		$valeur = trim($valeur, ';;');
183
 
184
		return $valeur;
185
	}
186
 
187
	public function ajouterMotCleObs($utilisateur_id, $mot_cle, $mot_cle_id, $mot_cle_parent_id) {
188
		$this->suffix = self::OBS_TABLE_SUFFIXE;
189
		$this->utilisateur_id = $utilisateur_id;
190
		return $this->ajouterMotCle($mot_cle, $mot_cle_id, $mot_cle_parent_id);
191
	}
192
 
193
	public function ajouterMotCleImg($utilisateur_id, $mot_cle, $mot_cle_id, $mot_cle_parent_id) {
194
		$this->suffix = self::IMG_TABLE_SUFFIXE;
195
		$this->utilisateur_id = $utilisateur_id;
196
		return $this->ajouterMotCle($mot_cle, $mot_cle_id, $mot_cle_parent_id);
197
	}
198
 
199
	private function ajouterMotCle($mot_cle, $mot_cle_id, $mot_cle_parent_id) {
200
		$retour = true;
201
		$this->ajouterMotCleRacine();
202
		if ($this->verifierAbscence($mot_cle_id)) {
203
			$this->commencerTransaction();
204
 
205
			$bornes = $this->retrouverBornesEtNiveau($mot_cle_parent_id);
206
			$borne_pere = $bornes['cmc_bd'];
207
			$niveau = $bornes['cmc_niveau'] + 1;
208
			$bg = $bornes['cmc_bd'];
209
			$bd = $bg + 1;
210
			$mot_cle_encode = $this->encoderMotCle($mot_cle);
211
 
212
			$mot_cle = $this->proteger($mot_cle);
213
			$bg = $this->proteger($bg);
214
			$bd = $this->proteger($bd);
215
			$mot_cle_encode = $this->proteger($mot_cle_encode);
216
			$mot_cle_id = $this->proteger($mot_cle_id);
217
			$id_utilisateur = $this->proteger($this->utilisateur_id);
218
			$mot_cle_parent_id = $this->proteger($mot_cle_parent_id);
219
			$niveau = $this->proteger($niveau);
220
 
221
			$transaction_reussie_1 = $this->decalerBornesPlusDeux($borne_pere) ? true : false;
222
 
223
			$requete = 	"INSERT INTO  cel_mots_cles{$this->suffix} ".
224
						"VALUES ( $mot_cle, $bg, $bd, $mot_cle_encode, $mot_cle_id, ".
225
						"	$id_utilisateur, $mot_cle_parent_id, $niveau) ";
226
			$transaction_reussie_2 = $this->executerSQL($requete);
227
			if (!$transaction_reussie_2) {
228
				$e = "Échec d'insertion du mot-clé : $requete ";
229
				$this->messages[] = $e;
230
			}
231
 
232
			$retour = null;
233
			if ($transaction_reussie_1 && $transaction_reussie_2) {
234
				$retour = $this->completerTransaction();
235
			} else {
236
				$retour = $this->annulerTransaction();
237
			}
238
		} else {
239
			$e = "Le mot-clé '$mot_cle' ayant l'id '$mot_cle_id' existe déjà.";
240
			$this->debug[] = $e;
241
		}
242
 
243
		return $retour;
244
	}
245
 
246
	private function ajouterMotCleRacine() {
247
		$nbre_mots_cles = $this->compterMotsCles();
248
		$this->debug[] = $nbre_mots_cles;
249
		if ($nbre_mots_cles == 0) {
250
			switch ($this->suffix) {
251
				case self::OBS_TABLE_SUFFIXE :
252
					$nom_racine = self::OBS_RACINE_NOM;
253
					$id_racine = self::OBS_RACINE_ID;
254
					break;
255
				case self::IMG_TABLE_SUFFIXE :
256
					$nom_racine = self::IMG_RACINE_NOM;
257
					$id_racine = self::IMG_RACINE_ID;
258
					break;
259
				default:
260
					$nom_racine = $this->suffix;
261
					$id_racine = $this->suffix;
262
			}
263
 
264
			$nom_racine = $this->proteger($nom_racine);
265
			$id_racine = $this->proteger($id_racine);
266
			$id_utilisateur = $this->proteger($this->utilisateur_id);
267
			$requete = 	"INSERT INTO cel_mots_cles{$this->suffix} ".
268
						"VALUES ($nom_racine, 1, 2, $id_racine, $id_racine, $id_utilisateur, '', 0) ";
269
			$this->debug[] = $requete;
270
			if ($this->executerSQL($requete) === false) {
271
				$e = "La requête d'insertion du mot-clé racine a échoué.";
272
				$this->messages[] = $e;
273
			}
274
		}
275
	}
276
 
277
	private function verifierAbscence($mot_cle_id) {
278
		$absence = false;
279
		$mot_cle_id = $this->proteger($mot_cle_id);
280
		$id_utilisateur = $this->proteger($this->utilisateur_id);
281
		$requete = 	'SELECT COUNT(*) AS nbre '.
282
					"FROM cel_mots_cles{$this->suffix} ".
283
					"WHERE cmc_id_mot_cle_utilisateur = $mot_cle_id ".
284
					"	AND cmc_id_proprietaire = $id_utilisateur ";
285
		$nbre = $this->recupererValeur($requete);
286
		if ($nbre === false) {
287
			$e = "La requête de vérification d'abscence d'un mot-clé a échoué.";
288
			$this->messages[] = $e;
289
		} else if ($nbre == 0) {
290
			$absence = true;
291
		}
292
		return $absence;
293
	}
294
 
295
	private function compterMotsCles() {
296
		$nbre = 0;
297
		$id_utilisateur = $this->proteger($this->utilisateur_id);
298
		$requete = 	'SELECT COUNT(*) AS nbre '.
299
					"FROM cel_mots_cles{$this->suffix} ".
300
					"WHERE cmc_id_proprietaire = $id_utilisateur ";
301
		$nbre = $this->recupererValeur($requete);
302
		if ($nbre === false) {
303
			$e = "La requête de comptage du nombre de mots-clés a échoué.";
304
			$this->messages[] = $e;
305
		}
306
		return $nbre;
307
	}
308
 
309
	/**
310
	 * Désactive l'auto-commit puis débute la transaction
311
	 */
312
	private function commencerTransaction() {
313
		// Désactive l'autocommit le temps de la manipulation de l'arbre
314
		$requete = 'SET AUTOCOMMIT = 0 ';
315
		$reussite_autocommit = $this->executerSQL($requete);
316
 
317
		// Débute une nouvelle transaction
318
		$requete = 'BEGIN ';
319
		$reussite_begin = $this->executerSQL($requete);
320
	}
321
 
322
	/**
323
	 * Termine la transaction puis réactive l'auto-commit
324
	 */
325
	private function completerTransaction() {
326
		// Complète la transaction
327
		$requete = 'COMMIT ';
328
		$reussite_commit = $this->executerSQL($requete);
329
 
330
		// Réactive l'autocommit le temps de la manipulation de l'arbre
331
		$requete = 'SET AUTOCOMMIT = 1 ';
332
		$reussite_autocommit = $this->executerSQL($requete);
333
 
334
		return true;
335
	}
336
 
337
	/**
338
	 * Annule la transaction et réactive l'auto-commit
339
	 */
340
	private function annulerTransaction() {
341
		// Annule la transaction
342
		$requete = 'ROLLBACK ';
343
		$reussite_rollback = $this->executerSQL($requete);
344
 
345
		// Réactive l'autocommit le temps de la manipulation de l'arbre
346
		$requete = 'SET AUTOCOMMIT = 1 ';
347
		$reussite_autocommit = $this->executerSQL($requete);
348
 
349
		return false;
350
	}
351
 
352
	/**
353
	 * Renvoie les bornes d'un noeud de l'arbre des mots clés
354
	 */
355
	private function retrouverBornesEtNiveau($mot_cle_id) {
356
		$mot_cle_id = $this->proteger($mot_cle_id);
357
		$id_utilisateur = $this->proteger($this->utilisateur_id);
358
		$requete = 	'SELECT cmc_bd, cmc_bg, cmc_niveau '.
359
					"FROM cel_mots_cles{$this->suffix} ".
360
					"WHERE cmc_id_mot_cle_utilisateur = $mot_cle_id ".
361
					"	AND cmc_id_proprietaire = $id_utilisateur ";
362
		$resultat = $this->recupererResultat($requete);
363
		return $resultat;
364
	}
365
 
366
	/**
367
	 * Décale les bornes de deux pour insérer un nouvel élément
368
	 */
369
	private function decalerBornesPlusDeux($valeur) {
370
		// Décalage borne droite
371
		$valeur = $this->proteger($valeur);
372
		$id_utilisateur = $this->proteger($this->utilisateur_id);
373
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
374
					'SET cmc_bd = cmc_bd + 2 '.
375
					"WHERE cmc_bd >= $valeur ".
376
					"	AND cmc_id_proprietaire = $id_utilisateur ";
377
		$reussi_1 = $this->executerSQL($requete);
378
		if (!$reussi_1) {
379
			$e = "Échec du décalage de la borne droite de +2 : $requete ";
380
			$this->messages[] = $e;
381
		}
382
 
383
		// Décalage borne gauche
384
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
385
					'SET cmc_bg = cmc_bg + 2 '.
386
					"WHERE cmc_bg >= $valeur ".
387
					"	AND cmc_id_proprietaire = $id_utilisateur ";
388
		$reussi_2 = $this->executerSQL($requete);
389
		if (!$reussi_2) {
390
			$e = "Échec du décalage de la borne gauche de +2 : $requete";
391
			$this->messages[] = $e;
392
		}
393
 
394
		return ($reussi_1 && $reussi_2);
395
	}
396
 
397
	/**
398
	 * Décale les bornes d'un intervalle négatif donné (pour la suppression d'un sous arbre).
399
	 */
400
	private function decalerBornesMoinsIntervalle($bg, $bd) {
401
		$decalage = $bd - $bg + 1;
402
		$bg = $this->proteger($bg);
403
		$id_utilisateur = $this->proteger($this->utilisateur_id);
404
 
405
		// Décalage borne droite
406
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
407
					"SET cmc_bd = cmc_bd - $decalage ".
408
					"WHERE cmc_bd >= $bg ".
409
					"	AND cmc_id_proprietaire = $id_utilisateur ";
410
		$reussi_1 = $this->executerSQL($requete);
411
 
412
		// Décalage borne gauche
413
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
414
					"SET cmc_bg = cmc_bg - $decalage ".
415
					"WHERE cmc_bg > $bg ".
416
					"	AND cmc_id_proprietaire = $id_utilisateur ";
417
		$reussi_2 = $this->executerSQL($requete);
418
 
419
		return $reussi_1 && $reussi_2;
420
	}
421
 
422
	/**
423
	 * Décale à droite des bornes donées d'un intervalle positif donné (pour l'ajout d'un sous arbre).
424
	 */
425
	private function decalerBornesPlusIntervalle($valeur_bornes, $largeur) {
426
		$valeur_bornes = $this->proteger($valeur_bornes);
427
		$largeur = $this->proteger($largeur);
428
		$id_utilisateur = $this->proteger($this->utilisateur_id);
429
 
430
		// Décalage borne droite
431
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
432
					"SET cmc_bd = cmc_bd + $largeur ".
433
					"WHERE cmc_bd >= $valeur_bornes ".
434
					"	AND cmc_id_proprietaire = $id_utilisateur ";
435
		$reussi_1 = $this->executerSQL($requete);
436
 
437
		// Décalage borne gauche
438
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
439
					"SET cmc_bg = cmc_bg + $largeur ".
440
					"WHERE cmc_bg >= $valeur_bornes ".
441
					"	AND cmc_id_proprietaire = $id_utilisateur| ";
442
		$reussi_2 = $this->executerSQL($requete);
443
 
444
		return $reussi_1 && $reussi_2;
445
	}
446
 
447
	/**
448
	 * Inverse les bornes d'un intervalle pour l'exclure des modifications sur l'arbre sans changer la hiérarchie.
449
	 */
450
	private function exclureIntervalle($bg, $bd) {
451
		$bg = $this->proteger($bg);
452
		$bd = $this->proteger($bd);
453
		$id_utilisateur = $this->proteger($this->utilisateur_id);
454
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
455
					"SET cmc_bd = cmc_bd - $bd - 1 , ".
456
					"	cmc_bg =  cmc_bg - $bd - 1 ".
457
					"WHERE cmc_bd <= $bd ".
458
					"	AND cmc_bg >= $bg ".
459
					"	AND cmc_id_proprietaire = $id_utilisateur ";
460
		return $this->executerSQL($requete);
461
	}
462
 
463
	/**
464
	 * Recale les bornes dun intervalle pour l'inclure dans l'arbre à la bonne place.
465
	 * Décalage borne droite
466
	 */
467
	private function inclureIntervalle($bg, $bd, $largeur, $modif_niveau) {
468
		$bg = $this->proteger($bg);
469
		$bd = $this->proteger($bd);
470
		$largeur = $this->proteger($largeur);
471
		$modif_niveau = $this->proteger($modif_niveau);
472
		$id_utilisateur = $this->proteger($this->utilisateur_id);
473
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
474
					"SET cmc_bg =  cmc_bg + $largeur , ".
475
					"	cmc_bd = cmc_bd + $largeur, ".
476
					"	cmc_niveau = cmc_niveau + $modif_niveau ".
477
					"WHERE cmc_bg >=  $bg ".
478
					"	AND cmc_bd <=  $bd ".
479
					"	AND cmc_id_proprietaire = $id_utilisateur ";
480
 
481
		return $this->executerSQL($requete);
482
	}
483
 
484
	private function changerPere($mot_cle_id, $id_pere) {
485
		$mot_cle_id = $this->proteger($mot_cle_id);
486
		$id_pere = $this->proteger($id_pere);
487
		$id_utilisateur = $this->proteger($this->utilisateur_id);
488
		$requete = 	"UPDATE cel_mots_cles{$this->suffix} ".
489
					"SET cmc_id_parent = $id_pere ".
490
					"WHERE cmc_id_mot_cle_utilisateur = $mot_cle_id ".
491
					"	AND cmc_id_proprietaire = $id_utilisateur ";
492
 
493
		return $this->executerSQL($requete);
494
	}
495
 
496
	private function executerSQL($requete) {
497
		$execution = $this->executer($requete);
498
		$execution = ($execution === false) ? false : true;
499
		return $execution;
500
	}
501
 
502
	private function recupererValeur($requete) {
503
		$resultat = $this->requeter($requete, Cel::SQL_RETOUR_COLONNE);
504
		return $resultat;
505
	}
506
 
507
	private function recupererResultat($requete) {
508
		$resultat = $this->requeter($requete, Cel::SQL_RETOUR_LIGNE, Cel::SQL_MODE_ASSOC);
509
		return $resultat;
510
	}
511
 
512
	private function recupererResultats($requete) {
513
		$resultat = $this->requeter($requete, Cel::SQL_RETOUR_COMPLET, Cel::SQL_MODE_ASSOC);
514
		return $resultat;
515
	}
516
 
517
	private function verifierLignesAffectees($requete) {
518
		$execution = $this->executer($requete);
519
		return $execution;
520
	}
521
}
522
?>