Subversion Repositories eFlore/Applications.cel

Rev

Rev 3084 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2025 aurelien 1
<?php
2462 jpm 2
// declare(encoding='UTF-8');
2025 aurelien 3
/**
2462 jpm 4
 * Classe de liaison d'images et d'observation à des mots clés en utilisant la méthode path enumeration.
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     Jean-Pascal MILCENT <jpm@tela-botanica.org>
13
 * @author     Aurelien PERONNET <aurelien@tela-botanica.org>
14
 * @license    GPL v3 <http://www.gnu.org/licenses/gpl.txt>
15
 * @license    CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
16
 * @copyright  1999-2014 Tela Botanica <accueil@tela-botanica.org>
17
 */
2025 aurelien 18
class GestionMotsClesChemin {
2101 jpm 19
 
2025 aurelien 20
	private $config;
21
	private $mode;
2101 jpm 22
 
2025 aurelien 23
	private $table_liaison;
24
	private $table_mots_cles;
2101 jpm 25
 
2032 aurelien 26
	//TODO: trigger pour les tables liaisons
2101 jpm 27
 
2026 aurelien 28
	public function GestionMotsClesChemin($config, $mode = 'obs') {
2025 aurelien 29
		$this->config = $config;
30
		//TODO: switch suivant mode
2027 aurelien 31
		$this->mode = $mode;
2101 jpm 32
 
2060 aurelien 33
		list($this->table_liaison, $this->table_mots_cles) = self::getTablesMotsClesEtLiaisons($mode);
2059 aurelien 34
	}
2101 jpm 35
 
36
	public function obtenirArbre($id_utilisateur, $chemin = '/') {
37
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
38
		$cheminP = Cel::db()->proteger($chemin.'%');
39
 
40
		$requete = 'SELECT * '.
41
			"FROM {$this->table_mots_cles} ".
42
			"WHERE id_utilisateur = $idUtilisateurP ".
43
			"AND chemin LIKE $cheminP ".
44
			'ORDER BY chemin '.
45
			' -- '.__FILE__.':'.__LINE__;
46
 
47
		$arbre = Cel::db()->requeter($requete);
2187 mathias 48
		foreach ($arbre as &$noeud) {
49
			$noeud['chemin'] = strtolower($noeud['chemin']);
50
		}
2026 aurelien 51
		usort($arbre, array('GestionMotsClesChemin', 'comparerProfNoeuds'));
2025 aurelien 52
		return $arbre;
53
	}
2101 jpm 54
 
2042 aurelien 55
	public function obtenirIdsMotsClesParIdParent($id_utilisateur, $id_mot_cle) {
2101 jpm 56
		$idMotCleP = Cel::db()->proteger($id_mot_cle);
2111 aurelien 57
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2042 aurelien 58
 
2101 jpm 59
		$sousRequete = "SELECT chemin FROM {$this->table_mots_cles} WHERE id_mot_cle = $idMotCleP ";
60
		$requete = 'SELECT id_mot_cle '.
61
			"FROM {$this->table_mots_cles} ".
62
			"WHERE chemin LIKE CONCAT(($sousRequete), '%') ".
2462 jpm 63
			"AND id_utilisateur = $idUtilisateurP ".
2101 jpm 64
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 65
		return Cel::db()->requeter($requete);
2042 aurelien 66
	}
2101 jpm 67
 
2241 mathias 68
	/**
69
	 * Retourne la liste des mots clés pour l'élément lié fourni. Ne tient pas compte de l'utilisateur
70
	 * car seul le propriétaire d'un élément lié peut y lier des mots clés
71
	 */
72
	public function obtenirIdsMotsClesParIdElementLie($id_element_lie) {
73
		$idElementLieP = Cel::db()->proteger($id_element_lie);
74
 
2462 jpm 75
		$requete = "SELECT id_mot_cle FROM {$this->table_liaison} ".
76
			"WHERE id_element_lie = $idElementLieP ".
2241 mathias 77
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 78
		return Cel::db()->requeter($requete);
2241 mathias 79
	}
80
 
2056 aurelien 81
	public function insererParCheminSiInexistant($mot_cle, $chemin_parent, $id_utilisateur) {
2199 mathias 82
		$mot_cle = self::simplifier($mot_cle);
2101 jpm 83
		$cheminMotCle = self::getCheminHarmonise($chemin_parent, $mot_cle);
84
		$cheminMotCleP = Cel::db()->proteger($cheminMotCle);
85
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2056 aurelien 86
 
2101 jpm 87
		$requete = 'SELECT id_mot_cle '.
88
			"FROM {$this->table_mots_cles} ".
89
			"WHERE chemin = $cheminMotCleP ".
90
			"AND id_utilisateur = $idUtilisateurP ".
91
			' -- '.__FILE__.':'.__LINE__;
2143 jpm 92
		$infosMotCle = Cel::db()->requeter($requete);
2101 jpm 93
 
94
		if (!empty($infosMotCle)) {
95
			$idMotCle = $infosMotCle[0]['id_mot_cle'];
2056 aurelien 96
		} else {
2101 jpm 97
			$idMotCle = $this->insererParChemin($mot_cle, $chemin_parent, $id_utilisateur);
2056 aurelien 98
		}
2101 jpm 99
		return $idMotCle;
2056 aurelien 100
	}
2101 jpm 101
 
102
	public function insererParChemin($mot_cle, $chemin_parent, $id_utilisateur) {
2199 mathias 103
		$mot_cle = self::simplifier($mot_cle);
2101 jpm 104
		$cheminMotCle = self::getCheminHarmonise($chemin_parent, $mot_cle);
105
		$cheminMotCleP = Cel::db()->proteger($cheminMotCle);
106
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
107
		$motCleP = Cel::db()->proteger($mot_cle);
108
 
109
		$requete = "INSERT INTO {$this->table_mots_cles} ".
110
			'(chemin, id_utilisateur, mot_cle) '.
111
			"VALUES ($cheminMotCleP, $idUtilisateurP, $motCleP ) ".
112
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 113
		$insertion = Cel::db()->executer($requete);
2101 jpm 114
 
2042 aurelien 115
		$resultat = false;
2101 jpm 116
		if ($insertion !== false) {
2042 aurelien 117
			$resultat = Cel::db()->obtenirDernierId();
118
		}
119
		return $resultat;
2025 aurelien 120
	}
2101 jpm 121
 
122
	public function insererParIdParent($mot_cle, $id_parent, $id_utilisateur) {
123
		$motCleSimple = self::simplifier($mot_cle);
2196 mathias 124
		$motCleSimpleP = Cel::db()->proteger(strtolower(self::supprimerAccents($mot_cle)));
2101 jpm 125
		$idParentP = Cel::db()->proteger($id_parent);
126
		$racineP = Cel::db()->proteger('/');
127
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
128
		$motCleP = Cel::db()->proteger($mot_cle);
129
 
130
		$sousRequete = $racineP;
131
		if ($id_parent != '') {
132
			$sousRequete = '(SELECT chemin '.
133
				"FROM {$this->table_mots_cles} AS ctp ".
134
				"WHERE ctp.id_mot_cle = $idParentP) ";
2042 aurelien 135
		}
2045 aurelien 136
 
2101 jpm 137
		$requete = "INSERT INTO {$this->table_mots_cles} (chemin, id_utilisateur, mot_cle) ".
138
			"VALUES (CONCAT($sousRequete, $motCleSimpleP, '/'), $idUtilisateurP, $motCleP ) ".
139
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 140
		$insertion = Cel::db()->executer($requete);
2101 jpm 141
 
142
		if ($insertion !== false) {
2042 aurelien 143
			$resultat = Cel::db()->obtenirDernierId();
144
		}
145
		return $resultat;
2025 aurelien 146
	}
2101 jpm 147
 
2032 aurelien 148
	public function lierParId($id_mot_cle, $id_element_lie) {
2101 jpm 149
		$idElementLieP = Cel::db()->proteger($id_element_lie);
150
		$idMotCleP = Cel::db()->proteger($id_mot_cle);
2143 jpm 151
 
2101 jpm 152
		$requete = "INSERT INTO {$this->table_liaison} (id_element_lie, id_mot_cle) ".
153
			"VALUES ($idElementLieP, $idMotCleP) ".
3096 killian 154
			'ON DUPLICATE KEY UPDATE `id_element_lie`=VALUES(`id_element_lie`), `id_mot_cle`=VALUES(`id_mot_cle`) '.
2101 jpm 155
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 156
		return Cel::db()->executer($requete);
2025 aurelien 157
	}
2101 jpm 158
 
2032 aurelien 159
	public function lierParChemin($chemin, $id_element_lie, $id_utilisateur) {
2101 jpm 160
		$cheminP = Cel::db()->proteger(self::harmoniserChemin($chemin));
161
		$idElementLieP = Cel::db()->proteger($id_element_lie);
162
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2143 jpm 163
 
2101 jpm 164
		$sousRequete = '(SELECT id_mot_cle '.
165
			"FROM {$this->table_mots_cles} ".
166
			"WHERE chemin = $cheminP ".
167
			"AND id_utilisateur = $idUtilisateurP ".
168
			')';
169
		$requete = "INSERT INTO {$this->table_liaison} (id_element_lie, id_mot_cle) ".
170
			"VALUES ($idElementLieP, $sousRequete) ".
3096 killian 171
			'ON DUPLICATE KEY UPDATE `id_element_lie`=VALUES(`id_element_lie`), `id_mot_cle`=VALUES(`id_mot_cle`) '.
2101 jpm 172
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 173
		return Cel::db()->executer($requete);
2025 aurelien 174
	}
2101 jpm 175
 
2241 mathias 176
	public function lierParTableaux($ids_mots_cles, $ids_elements_lies) {
2101 jpm 177
		$combinaisons = array();
178
		foreach ($ids_mots_cles as $id_mot_cle) {
179
			$idMotCleP = Cel::db()->proteger($id_mot_cle);
180
			foreach ($ids_elements_lies as $id_element_lie) {
181
				$idElementLieP = Cel::db()->proteger($id_element_lie);
182
				$combinaisons[] = "($idElementLieP, $idMotCleP)";
2042 aurelien 183
			}
2101 jpm 184
		}
185
 
186
		$valeursGroupees = implode(', ', $combinaisons);
187
		$requete = "INSERT INTO {$this->table_liaison} (id_element_lie, id_mot_cle) ".
188
			"VALUES $valeursGroupees ".
3096 killian 189
			"ON DUPLICATE KEY UPDATE `id_element_lie`=VALUES(`id_element_lie`), `id_mot_cle`=VALUES(`id_mot_cle`) ".
2101 jpm 190
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 191
		return Cel::db()->executer($requete);
2042 aurelien 192
	}
2101 jpm 193
 
2241 mathias 194
	/**
195
	 * Modifie les liaisons aux mots clés pour chaque element lié, en supprimant et ajoutant seulement les
196
	 * mots clés qui ont changé, sans toucher à ceux qui sont conservés. Ça évite de tout supprimer avant,
2314 mathias 197
	 * et ainsi de perdre la date de liaison des mots clés conservés.
198
	 * Si $supprimer est true, les mots clefs existant mais non spécifiés dans le POST seront supprimés,
199
	 * sinon ils seront laissés en l'état.
2462 jpm 200
	 */
2314 mathias 201
	public function modifierLiaisonParTableaux($ids_mots_cles, $ids_elements_lies, $supprimer) {
2241 mathias 202
		$reussi = true;
203
		foreach ($ids_elements_lies as $id_element_lie) {
204
			$idElementLieP = Cel::db()->proteger($id_element_lie);
205
			// trouver les mots clés actuels
206
			$ids_mots_cles_actuels = $this->obtenirIdsMotsClesParIdElementLie($id_element_lie);
207
			if (! is_array($ids_mots_cles_actuels)) {
208
				$ids_mots_cles_actuels = array();
209
			}
210
			// remise en forme
211
			foreach ($ids_mots_cles_actuels as $k => $v) {
212
				if (isset($v['id_mot_cle'])) { // je vois mal comment ça pourrait ne pas être set
213
					$ids_mots_cles_actuels[$k] = $v['id_mot_cle'];
214
				}
215
			}
216
 
217
			// changements
218
			$ids_mots_cles_ajoutes = array_diff($ids_mots_cles, $ids_mots_cles_actuels);
2314 mathias 219
			if ($supprimer === true) {
220
				$ids_mots_cles_supprimes = array_diff($ids_mots_cles_actuels, $ids_mots_cles);
221
			}
2241 mathias 222
 
223
			// insérer
224
			if (count($ids_mots_cles_ajoutes) > 0) {
225
				$combinaisons = array();
226
				foreach ($ids_mots_cles_ajoutes as $id_mot_cle) {
227
					$idMotCleP = Cel::db()->proteger($id_mot_cle);
228
					$combinaisons[] = "($idElementLieP, $idMotCleP)";
229
				}
230
				$valeursGroupees = implode(', ', $combinaisons);
231
				$requete = "INSERT INTO {$this->table_liaison} (id_element_lie, id_mot_cle) ".
232
						"VALUES $valeursGroupees ".
3096 killian 233
						"ON DUPLICATE KEY UPDATE `id_element_lie`=VALUES(`id_element_lie`), `id_mot_cle`=VALUES(`id_mot_cle`) ". // normalement pas nécessaire
2241 mathias 234
						' -- '.__FILE__.':'.__LINE__;
235
				$resultat = Cel::db()->executer($requete);
236
				$reussi = ($reussi && $resultat);
237
			}
238
 
239
			// supprimer
2314 mathias 240
			if ($supprimer === true && count($ids_mots_cles_supprimes) > 0) {
2241 mathias 241
				$clauses = array();
242
				foreach ($ids_mots_cles_supprimes as $id_mot_cle) {
243
					$idMotCleP = Cel::db()->proteger($id_mot_cle);
244
					$clauses[] = "(id_element_lie = $idElementLieP AND id_mot_cle = $idMotCleP)";
245
				}
246
				$clause = implode(' OR ', $clauses);
247
				$requete = "DELETE FROM {$this->table_liaison} WHERE $clause" .
248
					' -- '.__FILE__.':'.__LINE__;
249
				$resultat = Cel::db()->executer($requete);
250
				$reussi = ($reussi && $resultat);
251
			}
252
		}
253
		return $reussi;
254
	}
255
 
2042 aurelien 256
	public function supprimerLiaisonsMotsCles($ids_mots_cles, $ids_elements_lies, $id_utilisateur) {
257
		$combinaisons = array();
2101 jpm 258
		foreach ($ids_mots_cles as $id_mot_cle) {
259
			$idMotCleP = Cel::db()->proteger($id_mot_cle);
260
			foreach ($ids_elements_lies as $id_element_lie) {
261
				$idElementLieP = Cel::db()->proteger($id_element_lie);
262
				$combinaisons[] = "(id_element_lie = $idElementLieP AND id_mot_cle = $idMotCleP)";
2042 aurelien 263
			}
2101 jpm 264
		}
265
		$clauseWhere = implode(' OR ', $combinaisons);
2143 jpm 266
 
2101 jpm 267
		$requete = "DELETE FROM {$this->table_liaison} ".
268
			"WHERE $clauseWhere ".
269
			' -- '.__FILE__.':'.__LINE__;
2462 jpm 270
		return Cel::db()->executer($requete);
2042 aurelien 271
	}
2101 jpm 272
 
2058 aurelien 273
	public function supprimerToutesLiaisonsPourIdsElementsLies($ids_elements_lies) {
2143 jpm 274
		$idsElementsLiesP = Cel::db()->proteger($ids_elements_lies);
2101 jpm 275
		$listeIds = implode(',', $idsElementsLiesP);
2143 jpm 276
 
2101 jpm 277
		$requete = "DELETE FROM {$this->table_liaison} ".
278
			"WHERE id_element_lie IN ($listeIds) ".
279
			' -- '.__FILE__.':'.__LINE__;
280
 
281
		$suppression = Cel::db()->executer($requete);
282
		$suppression = ($suppression !== false) ? true : false;
2042 aurelien 283
		return $suppression;
284
	}
2101 jpm 285
 
2042 aurelien 286
	public function supprimerToutesLiaisonsIdsMotsCles($ids_mots_cles, $id_utilisateur) {
2101 jpm 287
		$suppression = true;
288
		if (!empty($ids_mots_cles)) {
2143 jpm 289
			$idsMotsClesP = Cel::db()->proteger($ids_mots_cles);
2101 jpm 290
			$listeIds = implode(',', $idsMotsClesP);
2143 jpm 291
 
2101 jpm 292
			$requete = "DELETE FROM {$this->table_liaison} ".
293
				"WHERE id_mot_cle IN ($listeIds) ".
294
				' -- '.__FILE__.':'.__LINE__;
295
 
2143 jpm 296
			$suppression = Cel::db()->executer($requete);
2101 jpm 297
			$suppression = ($suppression !== false) ? true : false;
2042 aurelien 298
		}
299
		return $suppression;
300
	}
2101 jpm 301
 
302
	/**
303
	 * Supprime toutes les laisons pour un utilisateur et un mot clé (au sens textuel) donnés.
2143 jpm 304
	 *
2101 jpm 305
	 */
2046 aurelien 306
	public function supprimerLiaisonPourMotCleEtIdElementLie($mot_cle, $id_element_lie, $id_utilisateur) {
2199 mathias 307
		$mot_cle = self::simplifier($mot_cle);
2101 jpm 308
		$idElementLieP = Cel::db()->proteger($id_element_lie);
309
		$motCleP = Cel::db()->proteger($mot_cle);
310
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2143 jpm 311
 
2101 jpm 312
		$sousRequete = "SELECT id_mot_cle FROM {$this->table_mots_cles} ".
313
			"WHERE mot_cle = $motCleP ".
314
			"AND id_utilisateur = $idUtilisateurP ";
315
		$requete = "DELETE FROM {$this->table_liaison} ".
316
			"WHERE id_element_lie = $idElementLieP ".
317
			"AND id_mot_cle IN ($sousRequete) ".
318
			' -- '.__FILE__.':'.__LINE__;
2046 aurelien 319
 
2143 jpm 320
		$suppression_liaison = Cel::db()->executer($requete);
2046 aurelien 321
		$suppression_liaison = ($suppression_liaison !== false);
322
 
323
		return $suppression_liaison;
324
	}
2101 jpm 325
 
2042 aurelien 326
	public function renommerMotCle($id_mot_cle, $nouveau_nom) {
2101 jpm 327
		$nouveauNomSimple = self::simplifier($nouveau_nom);
328
		$nouveauNomSimpleP = Cel::db()->proteger($nouveauNomSimple);
329
		$idMotCleP = Cel::db()->proteger($id_mot_cle);
330
 
331
		$requete = 'SELECT chemin, id_utilisateur '.
332
			"FROM {$this->table_mots_cles} ".
333
			"WHERE id_mot_cle = $idMotCleP ".
334
			' -- '.__FILE__.':'.__LINE__;
335
		$ancienCheminInfos = Cel::db()->requeter($requete);
336
 
337
		$ancienChemin = $ancienCheminInfos[0]['chemin'];
338
		$id_utilisateur = $ancienCheminInfos[0]['id_utilisateur'];
339
 
340
		$cheminDecompo = explode('/', $ancienChemin);
2042 aurelien 341
		// le dernier élément du tableau est vide (à cause du / terminal)
342
		// c'est également le cas pour le premier (à cause du / qui commence le chemin)
2101 jpm 343
		$cheminDecompo[count($cheminDecompo) - 2] = $nouveauNomSimple;
344
		$nouveauChemin = implode('/', $cheminDecompo);
345
 
346
		$requete = "UPDATE {$this->table_mots_cles} ".
347
			"SET mot_cle = $nouveauNomSimpleP ".
348
			"WHERE id_mot_cle = $idMotCleP ".
349
			' -- '.__FILE__.':'.__LINE__;
350
 
351
		$renommage = Cel::db()->executer($requete);
352
		$this->renommerChemin($ancienChemin, $nouveauChemin, $id_utilisateur);
353
 
354
		$idsElementsLies = $this->obtenirIdElementsLiesPourIds(array($id_mot_cle));
355
		foreach ($idsElementsLies as $idElementLie) {
356
			self::regenererIndexTexteMotCle($idElementLie['id_element_lie'], $this->mode);
2045 aurelien 357
		}
2101 jpm 358
 
2042 aurelien 359
		return $renommage;
360
	}
361
 
2143 jpm 362
	/**
2101 jpm 363
	 * Si aucun id_père n'est mentionné, c'est un déplacement vers la racine de l'arbre (qui n'existe pas).
364
	 */
365
	public function deplacerMotCle($id_mot_cle, $id_pere, $id_utilisateur) {
366
		$idMotCleP = Cel::db()->proteger($id_mot_cle);
367
		$idPereP = Cel::db()->proteger($id_pere);
368
		$cheminPere = '';
369
 
370
		if ($id_pere != '') {
371
			$requete = 'SELECT chemin '.
372
				"FROM {$this->table_mots_cles} ".
373
				"WHERE id_mot_cle = $idPereP ".
374
				' -- '.__FILE__.':'.__LINE__;
375
 
376
			$cheminPereInfos = Cel::db()->requeter($requete);
377
			if (!empty($cheminPereInfos)) {
378
				$cheminPere = $cheminPereInfos[0]['chemin'];
2061 aurelien 379
			}
380
		}
2101 jpm 381
 
382
		$requete = 'SELECT chemin, mot_cle '.
383
			"FROM {$this->table_mots_cles} ".
384
			"WHERE id_mot_cle = $idMotCleP ".
385
			' -- '.__FILE__.':'.__LINE__;
386
		$infosMotCle = Cel::db()->requeter($requete);
387
		$ancienChemin = $infosMotCle[0]['chemin'];
388
		$ancienMotCle = $infosMotCle[0]['mot_cle'];
389
 
390
		$nouveauChemin = $cheminPere.'/'.$ancienMotCle;
391
 
392
		return $this->renommerChemin($ancienChemin, $nouveauChemin, $id_utilisateur);
2042 aurelien 393
	}
2101 jpm 394
 
2025 aurelien 395
	public function renommerChemin($ancien_chemin, $nouveau_chemin, $id_utilisateur) {
2101 jpm 396
		$ancienCheminHarmonise = self::harmoniserChemin($ancien_chemin);
397
		$nouveauCheminHarmonise = self::harmoniserChemin($nouveau_chemin);
398
 
399
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
400
		$ancienCheminP = Cel::db()->proteger($ancienCheminHarmonise);
401
		$nouveauCheminP = Cel::db()->proteger($nouveauCheminHarmonise);
402
		$conditionCheminP = Cel::db()->proteger($ancienCheminHarmonise.'%');
403
 
404
		$requete = "UPDATE {$this->table_mots_cles} ".
405
			"SET chemin = REPLACE(chemin, $ancienCheminP, $nouveauCheminP) ".
406
			"WHERE chemin LIKE $conditionCheminP ".
407
			"AND id_utilisateur = $idUtilisateurP ".
408
			' -- '.__FILE__.':'.__LINE__;
409
 
410
		return Cel::db()->executer($requete);
2025 aurelien 411
	}
2101 jpm 412
 
2025 aurelien 413
	public function supprimerChemin($chemin, $id_utilisateur) {
2101 jpm 414
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
415
		$cheminP = Cel::db()->proteger($chemin.'%');
2025 aurelien 416
		// TODO : triggers pour les tables liées ?
2101 jpm 417
		$requete = "DELETE FROM {$this->$table_mots_cles} ".
418
			"WHERE chemin LIKE $cheminP ".
419
			"AND id_utilisateur = $idUtilisateurP ".
420
			' -- '.__FILE__.':'.__LINE__;
2025 aurelien 421
 
2101 jpm 422
		return Cel::db()->executer($requete);
2042 aurelien 423
	}
2101 jpm 424
 
425
	/**
426
	 * suppression des associations du mots clé aux images ou obs, mais aussi des associations de ses enfants
427
	 * (car ceux-ci seront supprimés aussi dans le processus)
428
	 * même s'il n'a pas d'enfants, le tableau contient au moins l'id du mot clé lui même
429
	 */
2043 aurelien 430
	public function supprimerMotCleParId($id_mot_cle, $id_utilisateur) {
431
		//TODO: simplifier cette fonction
432
		$ids_mot_cle_et_enfants = $this->obtenirIdsMotsClesParIdParent($id_utilisateur, $id_mot_cle);
2101 jpm 433
 
2043 aurelien 434
		// obtention des ids des éléments liés au mot clé ainsi qu'à ces enfants (afin de pouvoir
2060 aurelien 435
		// régénérer les index texte de mots clés sur les éléments liés)
2043 aurelien 436
		$ids_a_delier = array();
2101 jpm 437
		foreach ($ids_mot_cle_et_enfants as $id) {
2043 aurelien 438
			$ids_a_delier[] = $id['id_mot_cle'];
439
		}
2101 jpm 440
 
2043 aurelien 441
		$ids_elements_lies = $this->obtenirIdElementsLiesPourIds($ids_a_delier);
442
		$suppression_liaison = $this->supprimerToutesLiaisonsIdsMotsCles($ids_a_delier, $id_utilisateur);
443
 
2101 jpm 444
		foreach ($ids_elements_lies as $id_element_lie) {
2043 aurelien 445
			self::regenererIndexTexteMotCle($id_element_lie['id_element_lie'], $this->mode);
446
		}
2101 jpm 447
 
2043 aurelien 448
		// suppression du mot clé proprement dit ainsi que de ses enfants
449
		$suppression = $this->supprimerMotCleEtEnfantsParId($id_mot_cle, $id_utilisateur);
2101 jpm 450
 
2043 aurelien 451
		return $suppression && $suppression_liaison;
452
	}
2101 jpm 453
 
2042 aurelien 454
	public function supprimerMotCleEtEnfantsParId($id_mot_cle, $id_utilisateur) {
2101 jpm 455
		$idMotCleP = Cel::db()->proteger($id_mot_cle);
2116 jpm 456
		$requete = 'SELECT chemin '.
2101 jpm 457
			"FROM {$this->table_mots_cles} ".
458
			"WHERE id_mot_cle = $idMotCleP ".
459
			' -- '.__FILE__.':'.__LINE__;
2116 jpm 460
		$chemin = Cel::db()->requeter($requete);
2101 jpm 461
 
2043 aurelien 462
		$suppression = true;
2101 jpm 463
		// vérification pour empecher la suppression accidentelle de tout l'arbre,
2060 aurelien 464
		// cas qui ne devrait jamais arriver normalement
2101 jpm 465
		if (!empty($chemin) && $chemin != '/') {
466
			$chemin = $chemin[0]['chemin'];
467
			$cheminP = Cel::db()->proteger($chemin.'%');
468
			$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2143 jpm 469
 
2101 jpm 470
			$requete = "DELETE FROM {$this->table_mots_cles} ".
471
				"WHERE chemin LIKE $cheminP ".
472
				"AND id_utilisateur = $idUtilisateurP ".
473
				' -- '.__FILE__.':'.__LINE__;;
474
 
475
			$suppression = Cel::db()->executer($requete);
2043 aurelien 476
		}
2042 aurelien 477
 
2043 aurelien 478
		return ($suppression !== false);
2101 jpm 479
 
2025 aurelien 480
	}
2101 jpm 481
 
2056 aurelien 482
	public function obtenirIdsMotClesPourMotsCles($mots_cles, $id_utilisateur) {
2199 mathias 483
		$motsClesP = array();
484
		foreach ($mots_cles as $mot_cle) {
485
			$motsClesP[] = Cel::db()->proteger(self::simplifier($mot_cle));
486
		}
2101 jpm 487
		$listeMotsClesP = implode(',', $motsClesP);
488
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2056 aurelien 489
 
2101 jpm 490
		$requete = 'SELECT id_mot_cle, mot_cle '.
491
			"FROM {$this->table_mots_cles} ".
492
			"WHERE mot_cle IN ($listeMotsClesP) ".
493
			"AND id_utilisateur = $idUtilisateurP ".
494
			' -- '.__FILE__.':'.__LINE__;
2143 jpm 495
 
3084 mathias 496
		$resultat = Cel::db()->executerRequete($requete);
2101 jpm 497
		return $resultat;
2056 aurelien 498
	}
2101 jpm 499
 
2046 aurelien 500
	public function obtenirIdElementsLiesPourChemins($chemins, $id_utilisateur) {
2101 jpm 501
		foreach ($chemins as &$chemin) {
2042 aurelien 502
			$chemin = Cel::db()->proteger(self::harmoniserChemin($chemin));
503
		}
2101 jpm 504
		$listeChemins = implode(',', $chemin);
505
		$idUtilisateurP = Cel::db()->proteger($id_utilisateur);
2143 jpm 506
 
2101 jpm 507
		$requete = 'SELECT id_element_lie '.
508
			"FROM {$this->table_liaison} AS cl INNER JOIN {$this->table_mots_cles} AS cm ".
509
			"ON (".
510
				"cm.id_mot_cle = cl.id_mot_cle ".
511
				"AND chemin IN ($listeChemins) ".
512
				"AND cm.id_utilisateur = $idUtilisateurP ".
513
			") ".
514
			' -- '.__FILE__.':'.__LINE__;
515
 
516
		$idsPourChemin = Cel::db()->executer($requete);
517
 
518
		return $idsPourChemin;
2042 aurelien 519
	}
2101 jpm 520
 
2042 aurelien 521
	public function obtenirIdElementsLiesPourIds($ids_mots_cles) {
2101 jpm 522
		$idsElementsLies = array();
523
		if (!empty($ids_mots_cles)) {
2143 jpm 524
			$idsMotsClesP = Cel::db()->proteger($ids_mots_cles);
2101 jpm 525
			$listeIdsMotsCles = implode(',', $idsMotsClesP);
2143 jpm 526
 
2101 jpm 527
			$requete = 'SELECT id_element_lie '.
528
				"FROM {$this->table_liaison} ".
529
				"WHERE id_mot_cle IN ($listeIdsMotsCles) ".
530
				' -- '.__FILE__.':'.__LINE__;
531
 
2143 jpm 532
 
533
			$idsElementsLies = Cel::db()->requeter($requete);
2042 aurelien 534
		}
2101 jpm 535
		return $idsElementsLies;
536
	}
2042 aurelien 537
 
2101 jpm 538
	/**
539
	 *
2060 aurelien 540
	 * Fonctions statiques utilitaires
2101 jpm 541
	 * (Dans l'idéal toute la classe pourrait être statique car elle n'a
2060 aurelien 542
	 * pas d'état (mais il faudrait passer $mode à toutes les fonctions)
2101 jpm 543
	 *
2060 aurelien 544
	 */
545
	public static function getTablesMotsClesEtLiaisons($mode) {
2101 jpm 546
		if ($mode == 'obs') {
2060 aurelien 547
			$table_liaison = 'cel_mots_cles_obs_liaison';
548
			$table_mots_cles = 'cel_arbre_mots_cles_obs';
549
		} else {
550
			$table_liaison = 'cel_mots_cles_images_liaison';
551
			$table_mots_cles = 'cel_arbre_mots_cles_images';
552
		}
553
		return array($table_liaison, $table_mots_cles);
554
	}
2101 jpm 555
 
2486 jpm 556
	/**
557
	 * Régénère le champ "mots_cles_texte" l'entité liée (image ou obs)
558
	 * et met à jour sa date de modification
559
	 */
2043 aurelien 560
	public static function regenererIndexTexteMotCle($id_element_lie, $mode) {
2101 jpm 561
		$idElementLieP = Cel::db()->proteger($id_element_lie);
562
		$sqlTpl = self::obtenirTemplateRequeteMotsClesTexte($mode);
563
		$sousRequete = sprintf($sqlTpl, $idElementLieP);
2060 aurelien 564
 
2101 jpm 565
		list($table, $champId) = self::getNomTablesEtChampsElementsLies($mode);
566
		$requete = "UPDATE $table ".
567
			"SET mots_cles_texte = ($sousRequete) ".
2486 jpm 568
			", date_modification = NOW() ".
2101 jpm 569
			"WHERE $champId = $idElementLieP ".
570
			' -- '.__FILE__.':'.__LINE__;
571
 
572
		return Cel::db()->executer($requete);
2043 aurelien 573
	}
2101 jpm 574
 
2043 aurelien 575
	private static function getNomTablesEtChampsElementsLies($mode) {
576
		$tables = array();
2101 jpm 577
		if ($mode == 'obs') {
578
			$tables = array('cel_obs', 'id_observation');
2043 aurelien 579
		} else {
2101 jpm 580
			$tables = array('cel_images', 'id_image');
2043 aurelien 581
		}
582
		return $tables;
583
	}
2101 jpm 584
 
585
	/**
2143 jpm 586
	 * Renvoie un template de requete pour selectionner la concatenation de mots clé
2101 jpm 587
	 * pour un element donné (utilisable avec sprintf)
588
	 */
2060 aurelien 589
	public static function obtenirTemplateRequeteMotsClesTexte($mode) {
590
		list($table_liaison, $table_mots_cles) = self::getTablesMotsClesEtLiaisons($mode);
2143 jpm 591
 
2101 jpm 592
		$requeteTpl = 'SELECT GROUP_CONCAT(mot_cle) '.
593
			"FROM $table_mots_cles AS cm ".
594
			"INNER JOIN $table_liaison AS cml ON cml.id_mot_cle = cm.id_mot_cle ".
595
			'AND cml.id_element_lie = %s ';
2143 jpm 596
 
2101 jpm 597
		return $requeteTpl;
2042 aurelien 598
	}
2101 jpm 599
	/**
600
	* Renvoie un template de recherche sur les ids de mots clés utilisables avec sprintf.
601
	*/
2060 aurelien 602
	public static function obtenirTemplateRequeteMotsClesIds($mode) {
603
		list($table_liaison, $table_mots_cles) = self::getTablesMotsClesEtLiaisons($mode);
2101 jpm 604
		$requeteTpl = "SELECT id_element_lie FROM $table_liaison WHERE id_mot_cle IN (%s) ";
605
		return $requeteTpl;
2059 aurelien 606
	}
2101 jpm 607
 
2462 jpm 608
	// Méthodes utilitaires
2143 jpm 609
 
2101 jpm 610
	/**
611
	 * La profondeur d'un noeud est déterminée par le nombre de slashs
612
	 * qu'il contient (étant donné que ceux ci sont interdits dans le texte du mot clé.
613
	 */
2025 aurelien 614
	static public function comparerProfNoeuds($a, $b) {
615
		$nb_slashs_a = substr_count($a['chemin'], '/');
616
		$nb_slashs_b = substr_count($a['chemin'], '/');
617
		$cmp = 0;
2101 jpm 618
 
619
		if ($nb_slashs_a == $nb_slashs_b) {
2187 mathias 620
			$cmp = strcasecmp($a['chemin'], $b['chemin']);
2025 aurelien 621
		} else {
622
			$cmp = ($a['chemin'] > $b['chemin']) ? +1 : -1;
623
		}
624
		return $cmp;
625
	}
2101 jpm 626
 
2026 aurelien 627
	static public function getCheminHarmonise($chemin_parent, $mot_cle) {
628
		return self::harmoniserChemin($chemin_parent.'/'.self::simplifier($mot_cle).'/');
629
	}
2101 jpm 630
 
2026 aurelien 631
	static public function harmoniserChemin($chemin) {
632
		$chemin = self::startsWith($chemin,'/') ? $chemin : '/'.$chemin;
633
		$chemin = self::endsWith($chemin,'/') ? $chemin : $chemin.'/';
2101 jpm 634
		$chemin = str_replace('//', '/', $chemin);
2462 jpm 635
		// mise en minuscule du chemin afin d'éviter des cas où l'on aurait
2149 aurelien 636
		// des même mots clés avec minuscule et majuscule
637
		$chemin = strtolower($chemin);
2189 mathias 638
		$chemin = self::supprimerAccents($chemin);
2101 jpm 639
		return $chemin;
2026 aurelien 640
	}
2462 jpm 641
 
642
	static function supprimerAccents($str, $charset='utf-8') {
2189 mathias 643
		$str = htmlentities($str, ENT_NOQUOTES, $charset);
644
		$str = preg_replace('#&([A-za-z])(?:acute|cedil|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str);
645
		$str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str); // pour les ligatures e.g. '&oelig;'
646
		$str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères
647
		return $str;
648
	}
2101 jpm 649
 
2143 jpm 650
	/**
2101 jpm 651
	 * Fonction de slugification du mot clé
2143 jpm 652
	 *
2101 jpm 653
	 * Ni slashes ou antislashes ou virgules (ce qui fausserait l'arbre ou bien les mots
654
	 * clés texte dans les tables obs ou image)
655
	 */
656
	static public function simplifier($text) {
657
		$caracteresASupprimer = array('\\','/', ',');
658
		$text = str_replace($caracteresASupprimer, '', $text);
2167 aurelien 659
		$text = trim($text);
2101 jpm 660
		return $text;
2025 aurelien 661
	}
2101 jpm 662
 
2143 jpm 663
	/**
2101 jpm 664
	 * Gardée pour compatibilité ancienne version (mais devrait être supprimée
665
	 * dans le futur
666
	 */
2060 aurelien 667
	static function nettoyerMotsClesAvantSuppression($chaine) {
668
		$valeur = str_replace('null', '', $chaine);
669
		$valeur = trim($valeur, ';;');
670
		return $valeur;
671
	}
2101 jpm 672
 
2462 jpm 673
	public static function startsWith($haystack, $needle) {
2101 jpm 674
		return $needle === '' || strpos($haystack, $needle) === 0;
2026 aurelien 675
	}
2101 jpm 676
 
2462 jpm 677
	public  static function endsWith($haystack, $needle) {
2101 jpm 678
		return $needle === '' || substr($haystack, -strlen($needle)) === $needle;
2026 aurelien 679
	}
2101 jpm 680
 
2060 aurelien 681
	/**
682
	* Fonction utilisée pour importer les anciens mots clés saisis dans les widget dans un compte identifié
683
	* Dans ce cas là, le widget remplit la case id_utilisateur par le mail indiqué lors de la saisie
684
	* @param string $mail_utilisateur
685
	* @param string $id_utilisateur
686
	*/
687
	public static function migrerMotsClesMailVersId($mail_utilisateur, $infos_utilisateur) {
688
		return self::migrerLiaisonEtMotsCles($mail_utilisateur, $infos_utilisateur, 'obs') &&
689
				self::migrerLiaisonEtMotsCles($mail_utilisateur, $infos_utilisateur, 'images');
690
	}
2101 jpm 691
 
692
	/**
693
	 * ATTENTION : cette fonction suppose que l'utilisateur n'ai pas déjà de mots clés dans le CEL
694
	 * avec l'identifiant $id_utilisateur ce qui est normalement le cas
695
	 * ça devrait normalement marcher correctement même s'il en a déjà mais ça n'a pas été testé
696
	 */
697
	private static function migrerLiaisonEtMotsCles($email_utilisateur, $infos_utilisateur, $mode) {
2060 aurelien 698
		list($table_liaisons, $table_mots_cles) = self::getTablesMotsClesEtLiaisons($mode);
2101 jpm 699
		$idUtilisateurP = Cel::db()->proteger($infos_utilisateur['id_utilisateur']);
700
		$emailUtilisateurP = Cel::db()->proteger($email_utilisateur);
2143 jpm 701
 
2101 jpm 702
		$requete_migration_mc = "UPDATE {$table_mots_cles} ".
703
			"SET id_utilisateur = $idUtilisateurP ".
704
			"WHERE id_utilisateur = $emailUtilisateurP ";
705
 
2143 jpm 706
		$migration = Cel::db()->executer($requete_migration_mc);
2101 jpm 707
		$migration = ($migration !== false) ? true : false;
708
		return $migration;
2060 aurelien 709
	}
3084 mathias 710
}