Subversion Repositories eFlore/Applications.cel

Rev

Rev 2026 | Rev 2032 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2025 aurelien 1
<?php
2
/**
3
* @package   jrest
4
* @author    Aurélien Peronnet <aurelien@tela-botania.org>
5
* @copyright 2010, 2013 Tela-Botanica
6
* @license   http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
7
*
8
* Librairie de liaison d'images et d'observation à des mots clés en utilisant la méthode
9
* path enumeration
10
*/
11
 
12
class GestionMotsClesChemin {
13
 
14
	private $config;
15
	private $mode;
16
 
17
	private $table_liaison;
18
	private $table_mots_cles;
2027 aurelien 19
	private $champ_id_element_lie;
2025 aurelien 20
 
2026 aurelien 21
	public function GestionMotsClesChemin($config, $mode = 'obs') {
2025 aurelien 22
		$this->config = $config;
23
		//TODO: switch suivant mode
2027 aurelien 24
		$this->mode = $mode;
25
 
26
		if($mode == 'obs') {
27
			$this->table_liaison = 'cel_obs_tags_path_liaison';
28
			$this->table_mots_cles = 'cel_obs_tags_path';
29
			$this->champ_id_element_lie = 'id_obs';
30
		} else {
31
			$this->table_liaison = 'cel_images_tags_path_liaison';
32
			$this->table_mots_cles = 'cel_images_tags_path';
33
			$this->champ_id_element_lie = 'id_image';
34
		}
2025 aurelien 35
	}
36
 
2026 aurelien 37
	public function viderTables() {
38
		$requete = "TRUNCATE ".$this->table_mots_cles." ";
39
		$vidage = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
40
 
41
		$requete = "TRUNCATE ".$this->table_liaison." ";
42
		$vidage = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
43
 
44
		return $vidage;
45
	}
46
 
2027 aurelien 47
	public function construireRequeteOr($mots_cles) {
48
		return $this->construireRequete($mots_cles, 'OR');
49
	}
50
 
51
	public function construireRequeteCheminOr($mots_cles) {
52
		return $this->construireRequeteChemin($mots_cles, 'OR');
53
	}
54
 
55
	public function construireRequeteAnd($mots_cles) {
56
		return $this->construireRequete($mots_cles, 'AND');
57
	}
58
 
59
	public function construireRequeteCheminAnd($mots_cles) {
60
		return $this->construireRequeteChemin($mots_cles, 'AND');
61
	}
62
 
63
	public function construireRequete($mots_cles, $operateur = 'AND') {
64
		$requete = "SELECT * FROM cel_images_tags_path_liaison ";
65
		$criteres = array();
66
		$premier = array_pop($mots_cles);
67
		$requete .= 'WHERE (tag = '.Cel::db()->proteger($premier).' ';
68
 
69
		foreach ($mots_cles as $mot_cle) {
70
			$requete .= " ".$operateur." id_image IN (SELECT id_image ".
71
										"FROM cel_images_tags_path_liaison ".
72
										"WHERE tag = ".Cel::db()->proteger($mot_cle)." ".
73
										") ";
74
		}
75
		$requete .= ")";
76
		$images = Cel::db()->requeter($requete);
77
		return $images;
78
	}
79
 
80
	private function construireRequeteChemin($mots_cles, $operateur = 'AND') {
81
		$requete = "SELECT * FROM cel_images_tags_path_liaison ";
82
		$criteres = array();
83
		$premier = array_pop($mots_cles);
84
		$requete .= 'WHERE (chemin LIKE '.Cel::db()->proteger('%/'.$premier.'/%').' ';
2026 aurelien 85
 
2027 aurelien 86
		foreach ($mots_cles as $mot_cle) {
87
			$requete .= " ".$operateur." id_image IN (SELECT id_image ".
88
												"FROM cel_images_tags_path_liaison ".
89
												"WHERE chemin LIKE ".Cel::db()->proteger('%/'.$mot_cle.'/%')." ".
90
												") ";
91
		}
92
		$requete .= ")";
93
		$images = Cel::db()->requeter($requete);
94
		return $images;
95
	}
96
 
97
	private function obtenirMotsClesOriginaux($mode) {
2026 aurelien 98
 
2027 aurelien 99
		if($mode == 'obs') {
100
			$requete_arbre = "SELECT id_mot_cle_obs as id_mot_cle, ce_mot_cle_obs_parent as parent, id_utilisateur, mot_cle ".
101
							"FROM cel_mots_cles_obs_srv ORDER BY id_utilisateur, niveau";
102
		} else {
103
			$requete_arbre = "SELECT id_mot_cle_image as id_mot_cle, ce_mot_cle_image_parent as parent, id_utilisateur, mot_cle ".
104
							"FROM cel_mots_cles_images_srv ORDER BY id_utilisateur, niveau";
105
		}
106
 
2026 aurelien 107
		$mots_cles = Cel::db()->requeter($requete_arbre);
108
 
109
		$mots_cles_hierarchiques = array();
110
		$correspondances_id_mots_cles_obs = array();
111
 
2027 aurelien 112
		$rien = 0;
113
 
2026 aurelien 114
		foreach($mots_cles as &$mot) {
2027 aurelien 115
 
116
			if(!empty($mot['mot_cle'])) {
117
				$chemin = '/';
118
				$cle_parent = $mot['parent'].'-'.$mot['id_utilisateur'];
119
				if(isset($mots_cles_hierarchiques[$cle_parent])) {
120
					$chemin = $mots_cles_hierarchiques[$cle_parent]['chemin'];
121
				}
122
				$chemin .= self::simplifier($mot['mot_cle']).'/';
123
				$chemin = str_replace("//", "/", $chemin);
124
 
125
				$cle = $mot['id_mot_cle'].'-'.$mot['id_utilisateur'];
126
 
127
				$mots_cles_hierarchiques[$cle] = array(
128
								'id_utilisateur' => $mot['id_utilisateur'],
129
								'chemin' => $chemin,
130
								'tag' => $mot['mot_cle']
131
				);
2026 aurelien 132
			}
133
		}
134
 
2027 aurelien 135
		return $mots_cles_hierarchiques;
136
	}
137
 
138
	private function obtenirLiaisonsMotsClesOriginaux($mode) {
139
		if($mode == 'obs') {
140
			$requete_liaisons = "SELECT comc.id_observation as id_element_lie, comc.id_mot_cle_obs as id_mot_cle, id_utilisateur as id_utilisateur ".
141
														"FROM cel_obs_mots_cles_srv comc ";
142
														//"INNER JOIN cel_obs o ON o.id_observation = comc.id_observation ";
143
		} else {
144
			$requete_liaisons = "SELECT comc.id_image as id_element_lie, comc.id_mot_cle_image as id_mot_cle, id_utilisateur as id_utilisateur ".
145
																	"FROM cel_images_mots_cles_srv comc ";
146
																	//"INNER JOIN cel_images o ON o.id_image = comc.id_image ";
147
		}
2026 aurelien 148
 
2027 aurelien 149
		$liaisons = Cel::db()->requeter($requete_liaisons);
150
		return $liaisons;
151
	}
152
 
153
	public function convertirNestedSetVersPathEnum() {
154
 
155
		$mots_cles_hierarchiques = $this->obtenirMotsClesOriginaux($this->mode);
156
		$liaisons = $this->obtenirLiaisonsMotsClesOriginaux($this->mode);
157
 
158
		/*foreach($mots_cles_hierarchiques as $mot) {
159
			echo $mot['chemin'].'<br />';
160
		}*/
161
		//echo '<pre>'.print_r($liaisons,true).'</pre>';
162
		//exit;
163
 
164
		$time_start = microtime();
165
 
2026 aurelien 166
		$mots_cles_slice = array_chunk($mots_cles_hierarchiques, 800, true);
167
		foreach($mots_cles_slice as $mots_cles_tranche) {
168
			$requete_insertion_mots_cles = "INSERT INTO ".$this->table_mots_cles." (chemin, id_utilisateur, tag) ".
169
			                     			" VALUES ";
170
 
171
			foreach($mots_cles_tranche as $cle => $mot_cle_tranche) {
172
				$requete_insertion_mots_cles .= "(".
173
					cel::db()->proteger($mot_cle_tranche['chemin']).", ".
174
					cel::db()->proteger($mot_cle_tranche['id_utilisateur']).", ".
175
					cel::db()->proteger($mot_cle_tranche['tag'])." ".
176
				"), ";
177
			}
178
 
179
			$requete_insertion_mots_cles = rtrim($requete_insertion_mots_cles, ", ");
180
			cel::db()->executer($requete_insertion_mots_cles);
181
		}
182
 
2027 aurelien 183
		$gne = 0;
2026 aurelien 184
		$liaisons_slice = array_chunk($liaisons, 800, true);
185
		foreach($liaisons_slice as &$liaison_tranche) {
2027 aurelien 186
			$requete_insertion_liaisons = "INSERT INTO ".$this->table_liaison." (".$this->champ_id_element_lie.", chemin, tag, id_utilisateur) ".
2026 aurelien 187
									      " VALUES ";
188
			$lier = false;
189
 
190
			foreach($liaison_tranche as &$liaison_obs_mot_cle) {
2027 aurelien 191
				$cle = $liaison_obs_mot_cle['id_mot_cle'].'-'.$liaison_obs_mot_cle['id_utilisateur'];
2026 aurelien 192
				if(isset($mots_cles_hierarchiques[$cle])) {
193
					$requete_insertion_liaisons .= "(".
2027 aurelien 194
						cel::db()->proteger($liaison_obs_mot_cle['id_element_lie']).", ".
2026 aurelien 195
						cel::db()->proteger($mots_cles_hierarchiques[$cle]['chemin']).", ".
2027 aurelien 196
						cel::db()->proteger($mots_cles_hierarchiques[$cle]['tag']).", ".
2026 aurelien 197
						cel::db()->proteger($liaison_obs_mot_cle['id_utilisateur'])." ".
198
					"), ";
199
					$lier = true;
200
				}
201
			}
202
 
203
			if($lier) {
204
				$requete_insertion_liaisons = rtrim($requete_insertion_liaisons, ", ");
205
				cel::db()->executer($requete_insertion_liaisons);
206
			}
207
		}
208
 
2027 aurelien 209
		$time = microtime() - $time_start;
210
		echo "La génération d'un tableau de ".count($mots_cles_hierarchiques).' éléments et de '.count($liaisons).' liaisons a pris '.$time.' secondes';
2026 aurelien 211
		exit;
212
	}
213
 
2025 aurelien 214
	public function obtenirArbre($id_utilisateur, $chemin = "/") {
215
 
216
		$requete = "SELECT * FROM ".$this->table_mots_cles." ".
217
		"WHERE id_utilisateur = ".Cel::db()->proteger($id_utilisateur)." AND ".
2026 aurelien 218
		"chemin LIKE ".Cel::db()->proteger($chemin."%")." ".
219
		"ORDER BY chemin";
2025 aurelien 220
 
2026 aurelien 221
		$arbre = Cel::db()->requeter($requete.' -- '.__FILE__.':'.__LINE__);
222
		usort($arbre, array('GestionMotsClesChemin', 'comparerProfNoeuds'));
2025 aurelien 223
 
224
		return $arbre;
225
	}
226
 
2026 aurelien 227
	public function insererParChemin($mot_cle, $chemin_parent, $id_utilisateur) {
2025 aurelien 228
 
2026 aurelien 229
		$chemin_mot_cle = self::getCheminHarmonise($chemin_parent, $mot_cle);
2025 aurelien 230
 
231
		$requete = "INSERT INTO ".$this->table_mots_cles." (chemin, id_utilisateur, tag) ".
232
		           "VALUES (".
233
		           		Cel::db()->proteger($chemin_mot_cle).", ".
234
						Cel::db()->proteger($id_utilisateur).", ".
2026 aurelien 235
						Cel::db()->proteger($mot_cle)." ".
2025 aurelien 236
		           ")";
237
 
238
		$insertion = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
239
 
240
		return $insertion;
241
	}
242
 
243
	public function insererParIdParent($mot_cle, $id_parent, $id_utilisateur) {
244
 
245
		$mot_cle_simp = self::simplifier($mot_cle);
246
 
247
		$sous_requete_chemin = "(SELECT chemin FROM ".$this->table_mots_cles." ".
2026 aurelien 248
		                       "WHERE id_tag = ".Cel::db()->proteger($id_parent).")";
2025 aurelien 249
 
250
		$requete = "INSERT INTO ".$this->table_mots_cles."(chemin, id_utilisateur, tag) ".
251
		           "VALUES (".
2026 aurelien 252
						"CONCAT(".$sous_requete_chemin.",".Cel::db()->proteger($mot_cle_simp).",'/') ".
2025 aurelien 253
						Cel::db()->proteger($id_utilisateur).", ".
254
						Cel::db()->proteger($tag).", ".
255
		           ")";
256
 
257
		$insertion = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
258
 
259
		return $insertion;
260
	}
261
 
262
	public function lierParId($id_mot_cle, $id_observation, $id_utilisateur) {
263
 
264
		$sous_requete_chemin = "(SELECT chemin FROM ".$this->table_mots_cles." ".
265
				   		"WHERE id_tag = ".Cel::db()->proteger($id_mot_cle).") ";
266
 
2027 aurelien 267
		$requete = "INSERT INTO ".$this->table_liaison." (".$this->champ_id_element_lie.", chemin, id_utilisateur) ".
2025 aurelien 268
					"VALUES (".
269
				   		Cel::db()->proteger($id_observation).", ".
2026 aurelien 270
				   		$sous_requete_chemin.",".
2025 aurelien 271
				   		Cel::db()->proteger($id_utilisateur)." ".
272
				   	") ".
2027 aurelien 273
					"ON DUPLICATE KEY UPDATE ".$this->champ_id_element_lie." = ".$this->champ_id_element_lie." ";
2025 aurelien 274
 
275
		$liaison = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
276
 
277
		return $liaison;
278
	}
279
 
280
	public function lierParChemin($chemin, $id_observation, $id_utilisateur) {
281
 
282
		$requete = "INSERT INTO ".$this->table_liaison." (id_obs, chemin, id_utilisateur) ".
283
					"VALUES (".
284
						Cel::db()->proteger($id_observation).", ".
285
						Cel::db()->proteger($sous_requete_chemin).", ".
286
						Cel::db()->proteger($id_utilisateur)." ".
287
				   	") ".
2027 aurelien 288
					"ON DUPLICATE KEY UPDATE ".$this->champ_id_element_lie." = ".$this->champ_id_element_lie." ";
2025 aurelien 289
 
290
		$liaison = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
291
 
292
		return $liaison;
293
	}
294
 
295
	// Déplacer un mot clé et le renommer est une même opération, dans le cas du renommage,
296
	// seule la fin du chemin change
297
	public function renommerChemin($ancien_chemin, $nouveau_chemin, $id_utilisateur) {
2026 aurelien 298
 
299
		$ancien_chemin = self::harmoniserChemin($ancien_chemin);
300
		$nouveau_chemin = self::harmoniserChemin($nouveau_chemin);
301
 
302
		$ancien_chemin_p = Cel::db()->proteger($ancien_chemin);
303
		$nouveau_chemin_p = Cel::db()->proteger($nouveau_chemin);
304
 
2025 aurelien 305
		// TODO : triggers pour les tables liées ?
2026 aurelien 306
		$requete = "UPDATE ".$this->table_mots_cles." ".
307
		       	   "SET chemin = REPLACE(chemin,".$ancien_chemin_p.", ".$nouveau_chemin_p.") ".
2025 aurelien 308
				   "WHERE chemin LIKE ".Cel::db()->proteger($ancien_chemin."%")." AND ".
309
		           "id_utilisateur = ".Cel::db()->proteger($id_utilisateur)." ";
2026 aurelien 310
		echo $requete.'<br />';
311
		$deplacement = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
2025 aurelien 312
 
2026 aurelien 313
		return $deplacement;
2025 aurelien 314
	}
315
 
316
	public function supprimerChemin($chemin, $id_utilisateur) {
317
		// TODO : triggers pour les tables liées ?
318
		$requete = "DELETE FROM ".$this->$table_mots_cles." ".
319
                   	"WHERE chemin LIKE ".Cel::db()->proteger($chemin."%")." AND ".
320
                   	"id_utilisateur = ".Cel::db()->proteger($id_utilisateur)." ";
321
 
322
		$suppression = Cel::db()->executer($requete.' -- '.__FILE__.':'.__LINE__);
323
 
324
		return $suppression;
325
 
326
	}
327
 
328
	// Fonctions utilitaires
329
	static public function comparerProfNoeuds($a, $b) {
330
 
331
		$nb_slashs_a = substr_count($a['chemin'], '/');
332
		$nb_slashs_b = substr_count($a['chemin'], '/');
333
		$cmp = 0;
334
 
335
		if($nb_slashs_a == $nb_slashs_b) {
336
			$cmp = strcmp($a['chemin'], $b['chemin']);
337
		} else {
338
			$cmp = ($a['chemin'] > $b['chemin']) ? +1 : -1;
339
		}
340
 
341
		return $cmp;
342
	}
343
 
344
	/*
345
		CREATE TRIGGER maj_chemin BEFORE UPDATE
346
		ON cel_obs_tag_path FOR EACH ROW
347
		BEGIN
348
			UPDATE cel_obs_tag_path_liaison
349
			SET cel_obs_tag_path_liaison.chemin = NEW.CHEMIN
350
			WHERE cel_obs_tag_path_liaison.chemin LIKE CONCAT(OLD.chemin,'%')
351
			AND cel_obs_tag_path_liaison.id_utilisateur = OLD.id_utilisateur
352
		END;
353
 
354
		CREATE TRIGGER suppr_chemin BEFORE UPDATE
355
		ON cel_obs_tag_path FOR EACH ROW
356
		BEGIN
357
			DELETE FROM cel_obs_tag_path_liaison
358
			WHERE cel_obs_tag_path_liaison.chemin LIKE CONCAT(OLD.chemin,'%')
359
			AND cel_obs_tag_path_liaison.id_utilisateur = OLD.id_utilisateur
360
		END;
361
 
362
		CREATE TRIGGER suppr_obs BEFORE DELETE
363
		ON cel_obs FOR EACH ROW
364
		BEGIN
365
			DELETE FROM cel_obs_tag_path_liaison
366
			WHERE cel_obs_tag_path_liaison.id_obs = OLD.id_observation
367
		END;
368
	*/
369
 
2026 aurelien 370
	static public function getCheminHarmonise($chemin_parent, $mot_cle) {
371
		return self::harmoniserChemin($chemin_parent.'/'.self::simplifier($mot_cle).'/');
372
	}
373
 
374
	static public function harmoniserChemin($chemin) {
375
		$chemin = self::startsWith($chemin,'/') ? $chemin : '/'.$chemin;
376
		$chemin = self::endsWith($chemin,'/') ? $chemin : $chemin.'/';
377
		return str_replace('//', '/', $chemin);
378
	}
379
 
2025 aurelien 380
	// fonction de slugification du mot clé
381
	// http://stackoverflow.com/questions/2955251/php-function-to-make-slug-url-string
382
	static public function simplifier($text)
383
	{
2026 aurelien 384
		return trim(str_replace(array('\\','/'), '', $text));
2025 aurelien 385
		// replace non letter or digits by -
386
		$text = preg_replace('~[^\\pL\d]+~u', '-', $text);
387
 
388
		// trim
389
		$text = trim($text, '-');
390
 
391
		// transliterate
392
		$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
393
 
394
		// lowercase
395
		$text = strtolower($text);
396
 
397
		// remove unwanted characters
398
		$text = preg_replace('~[^-\w]+~', '', $text);
399
 
400
		if (empty($text))
401
		{
402
			return 'n-a';
403
		}
404
 
405
		return $text;
406
	}
2026 aurelien 407
 
408
	static public function startsWith($haystack, $needle) {
409
		return $needle === "" || strpos($haystack, $needle) === 0;
410
	}
411
 
412
	static public function endsWith($haystack, $needle) {
413
		return $needle === "" || substr($haystack, -strlen($needle)) === $needle;
414
	}
2025 aurelien 415
}
416
 
417
?>