Subversion Repositories eFlore/Projets.eflore-projets

Rev

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

Rev Author Line No. Line
6 jpm 1
<?php
966 raphael 2
 /**
3
 * Description :
4
 * Classe NomsVernaculaires.php fournit une liste de noms vernaculaires et leur liaison à la bdtfx
5
 * Le but étant de fournir un ensemble minimal d'information comprenant :
6
 * un identifiant (numérique ou alphanumérique sous forme de ChatMot si possible), un nom, une langue et
7
 * une relation avec un taxon de la bdtfx.
8
 * Si l'url finit par /noms-vernaculaires on retourne une liste de noms (seulement les 100 premières par défaut).
9
 * L'url peut contenir des paramètres optionnels passés après le ? : /observations?param1=val1&param2=val2&...
10
 *
11
 * Les paramètres de requête disponibles sont : masque, masque.code, masque.nom, masque.region , recherche,
12
 * distinct, retour.format, navigation.depart et navigation.limite.
13
 *
14
 * Encodage en entrée : utf8
15
 * Encodage en sortie : utf8
16
 * @package framework-v3
17
 * @author Delphine Cauquil <delphine@tela-botanica.org>
18
 * @author Jennifer Dhé <jennifer.dhe@tela-botanica.org>
19
 * @license GPL v3 <http://www.gnu.org/licenses/gpl.txt>
20
 * @license CECILL v2 <http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt>
21
 * @version 1.0
22
 * @copyright 1999-${year} Tela Botanica (accueil@tela-botanica.org)
23
 */
734 raphael 24
 
966 raphael 25
 // Un caractère de concaténation entre le projet et le service.
26
 // Ce caractère ne doit pas faire partie d'aucun des noms de service ou projet
27
 define('RES_VAL_SEP', '@');
28
 define('SPE_INDEX_NVJFL', '_result_ontologies' . RES_VAL_SEP . 'nvjfl');
734 raphael 29
 
966 raphael 30
 class NomsVernaculaires extends Commun {
832 raphael 31
 
966 raphael 32
     static $onto_multi_support = array('conseil_emploi', 'genre');
33
     static $champ_infos = array(
34
         'taxon' => array('service' => 'taxons', 'ressource' => 'nt:', 'projet' => 'bdtfx', 'nom' => 'nom_sci',
35
                          // utilisés par ajouterChampsOntologieLigneResultat()
36
                          'intitule' => 'taxon.code', // intitulé du champ tel qu'il sera renvoyé en JSON
37
                          'bdd_champ' => 'num_taxon'), // intitulé du champ tel qu'il est présent dans l'enregistrement MySQL
38
         'conseil_emploi' => array('service' => 'ontologies', 'ressource' => 'numStatut:', 'projet' => 'nvjfl', 'nom' => 'nom',
39
                                   'intitule' => 'conseil_emploi', 'bdd_champ' => 'num_statut'),
40
         'genre' => array('service' => 'ontologies', 'ressource' => 'genreNombre:', 'projet' => 'nvjfl', 'nom' => 'nom',
41
                          'intitule' => 'genre', 'bdd_champ' => 'num_genre'));
109 jpm 42
 
966 raphael 43
     protected $service = 'noms-vernaculaires';
109 jpm 44
 
966 raphael 45
     /**
46
      * Permet de stocker la requete formulée : /noms-vernaculaires | /noms-vernaculaires/#id |
47
      *  /noms-vernaculaires/#id/champ | /noms-vernaculaires/#id/relations
48
      * Est remplit au cours de l'analyse des ressources (traiterRessources()), par défaut, a la valeur du service.
49
      * Est utilisée principalement pr déterminer le format du tableau à retourner.	 */
50
     protected $format_reponse = 'noms-vernaculaires';
109 jpm 51
 
966 raphael 52
     /** Variables constituant les parametres de la requete SQL (champ, condition, limit) remplie
53
      * selon ressources et paramètres */
54
     protected $requete_champ = array(' * ');
55
     protected $requete_condition = '';
56
     protected $limite_requete = array(
57
         'depart' => 0,
58
         'limite' => 100
59
     );
109 jpm 60
 
1107 mathias 61
	/**
62
	 * Vrai tri SQL
63
	 */
64
	protected $tri;
65
	protected $tri_ordre = 'asc';
109 jpm 66
 
1107 mathias 67
	// wtf ? on trie après avoir exécuté la requête ?
68
    protected $champ_tri = 'code_langue';
69
    protected $direction_tri = 'asc';
70
 
966 raphael 71
     /**
72
      * Indique les champs supplémentaires à retourner
73
      *  - conseil_emploi = conseil d'emploi du nom vernaculaire
74
      *  - genre = genre et nombre du nom
75
      *  - taxon = nom retenu associé à ce nom
76
      */
77
     protected $champs_supp = array();
109 jpm 78
 
966 raphael 79
     /**
80
      * Precise la contenance plus ou moins précise du tableau à retourner :
81
      *  - min = les données présentes dans la table
82
      *  - max = les données de la table + les informations complémentaires (pour les identifiants et les codes)
83
      *  - oss = la liste des nom_sci (uniquement pour noms et taxons) */
84
     protected $retour_format = 'max';
85
     /** Valeur du paramètre de requete recherche :
86
      *  - stricte : le masque est passé tel quel à l'opérateur LIKE.
87
      *  - etendue : ajout automatique du signe % à la place des espaces et en fin de masque avec utilisation de LIKE.
88
      *  - floue : recherche tolérante vis-à-vis d'approximations ou d'erreurs (fautes d'orthographe par exemple) */
89
     protected $recherche;
109 jpm 90
 
966 raphael 91
     /** Permet de stocker le tableau de résultat (non encodé en json) */
92
     protected $table_retour = array();
93
     /** Stocke le nombre total de résultats de la requete principale. Est calculée lors de l'assemblage de la requete */
94
     protected $total_resultat;
6 jpm 95
 
1107 mathias 96
     protected $config;
109 jpm 97
 
966 raphael 98
     public function __construct($config) {
99
         $this->config = is_null($config) ? Config::get('NomsVernaculaires') : $config;
100
     }
109 jpm 101
 
966 raphael 102
     //+------------------------------------------------------------------------------------------------------+
103
     // créer une condition en fonction du paramétre
104
     public function traiterParametres() {
105
         if (isset($this->parametres) && !empty($this->parametres)) {
109 jpm 106
 
966 raphael 107
             if (isset($this->parametres['recherche']) && $this->parametres['recherche'] != '') {
108
                 $this->recherche = $this->parametres['recherche'];
109
             }
110
             foreach ($this->parametres as $param => $valeur) {
111
                 switch ($param) {
112
                     case 'masque' :
113
                         $this->ajouterFiltreMasque('nom_vernaculaire', $valeur);
114
                         break;
115
                     case 'masque.nt' :
116
                         $this->ajouterFiltreMasque('num_taxon', $valeur);
117
                         break;
118
                     case 'masque.nv' :
119
                         $this->ajouterFiltreMasque('nom_vernaculaire', $valeur);
120
                         break;
121
                     case 'masque.lg' :
122
                         $this->ajouterFiltreMasque('code_langue', $valeur);
123
                         break;
124
                     case 'masque.cce' :
125
                         $this->ajouterFiltreMasque('num_statut', $valeur);
126
                         break;
127
                     case 'retour.format' :
128
                         $this->retour_format = $valeur;
129
                         break;
1107 mathias 130
                     case 'retour.tri' :
131
                         $this->tri = $valeur;
132
                         break;
133
                     case 'retour.ordre' :
134
						 if (in_array(strtolower($valeur), aray('asc', 'desc'))) {
135
							$this->tri_ordre = $valeur;
136
						 }
137
                         break;
966 raphael 138
                     case 'navigation.depart' :
139
                         $this->limite_requete['depart'] = $valeur;
140
                         break;
141
                     case 'navigation.limite' :
142
                         $this->limite_requete['limite'] = $valeur;
143
                         break;
144
                     case 'retour.champs' :
145
                         $this->champs_supp = explode(',',$valeur);
146
                     break;
147
                     case 'recherche' :
148
                         break;
149
                     case 'version.projet' :
150
                         break;
151
                     default :
152
                         $p = 'Erreur dans les paramètres de recherche de votre requête : '.
153
                             '</br> Le paramètre " '.$param.' " n\'existe pas.';
154
                             $this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $p);
155
                 }
156
             }
157
         }
158
     }
109 jpm 159
 
966 raphael 160
     public function ajouterFiltreMasque($nom_champ, $valeur) {
161
         if ($nom_champ == 'num_taxon') { // si il s'agit d'un chiffre
162
             $this->requete_condition[] = $nom_champ.' = '.$this->getBdd()->proteger($valeur);
163
         } else {
164
             if ($this->recherche == 'floue') {
165
                 $this->requete_condition[] = '(SOUNDEX('.$nom_champ.') = SOUNDEX(\''.$valeur.'\')'
166
                     .' OR SOUNDEX(REVERSE('.$nom_champ.')) = SOUNDEX(REVERSE(\''.$valeur.'\'))) ';
167
             } else {
168
                 if ($this->recherche == 'etendue') {
169
                     $valeur = '%'.str_replace(' ','% ', $valeur);
170
                     $valeur .= '%';
171
                 }
172
                 $this->requete_condition[] = $nom_champ.' LIKE '.$this->getBdd()->proteger($valeur);
173
             }
174
         }
175
     }
109 jpm 176
 
966 raphael 177
     //+------------------------------------------------------------------------------------------------------+
178
     // en fonction de la présence des ressources modifie requete_champ et requete_condition
179
     public function traiterRessources() {
180
         if (isset($this->ressources) && !empty($this->ressources)) {
181
             if (isset($this->ressources[0]) && !empty($this->ressources[0])) {
182
                 $this->traiterRessourceId(); // ajoute condition id=#valeur
183
                 if (isset($this->ressources[1]) && !empty($this->ressources[1])) {
184
                     $this->traiterRessourceChamp(); //modifie requete_champ ou requete_condition
185
                 }
186
             }
187
         } else { //rajoute distinct pour ne pas avoir plusieurs fois le même nom
188
             $this->requete_champ = array('distinct(id)', 'nom_vernaculaire ');
1107 mathias 189
			 $this->requete_champ = array_merge($this->requete_champ, $this->champs_supp);
966 raphael 190
         }
191
     }
109 jpm 192
 
966 raphael 193
     //requete : /noms-vernaculaires/#id (ex : /noms-vernaculaires/7)
194
     public function traiterRessourceId() {
195
         if (is_numeric($this->ressources[0])) {
196
             $this->requete_condition[] = ' id = '.$this->getBdd()->proteger($this->ressources[0]);
197
             $this->format_reponse .= '/id';
198
         } elseif ($this->ressources[0] == 'attributions') {
199
             $this->format_reponse .= '/attributions';
200
         } else {
201
             $r = 'Erreur dans les ressources de votre requête : </br> La ressource " '.$this->ressources[0].
202
                 ' " n\'existe pas.';
203
             $this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $r);
204
         }
205
     }
109 jpm 206
 
207
 
966 raphael 208
     public function traiterRessourceChamp() {
209
         $this->format_reponse .= '/champ';
210
         $this->analyserChamp();
211
     }
212
 
213
     public function analyserChamp() {
214
         $this->requete_champ = array();
215
         $this->recupererTableConfig('champs_possibles');// s'il y a plusieurs champs correspondant au champ demandé ils sont séparé par des |
216
         $champs = explode(' ', $this->ressources[1]);
217
         foreach ($champs as $champ) {
218
             preg_match('/^([^.]+)(\.([^.]+))?$/', $champ, $match);
219
             if (isset($this->champs_possibles[$match[1]])) {
220
                 $this->requete_champ[] = str_replace('|', ', ', $this->champs_possibles[$match[1]]);
221
             } elseif (isset($this->champs_possibles[$match[0]])) {
222
                 $this->requete_champ[] = str_replace('|', ', ', $this->champs_possibles[$match[0]]);
223
             } else {
224
                 $champs_possibles = implode('</li><li>', array_keys($this->champs_possibles));
225
                 $c = 'Erreur dans votre requête : </br> Le champ "'.$champ_possibles.'" n\'existe pas. '.
226
                     'Les champs disponibles sont : <li>'.$champs_possibles.'</li> et leurs déclinaisons (ex. ".code").';
227
                 $this->renvoyerErreur(RestServeur::HTTP_CODE_MAUVAISE_REQUETE, $c);
228
             }
229
         }
230
     }
231
 
232
     //+------------------------------------------------------------------------------------------------------+
233
     public function assemblerLaRequete() {
234
         $nolimit = in_array(
235
             $this->format_reponse,
236
             array($this->service.'/id', $this->service.'/id/champs'));
237
         if(!$nolimit) {
238
             $count = $this->recupererTotalResultat();
239
             $limiteClause = self::formerRequeteLimite( // LIMIT
240
                 $this->limite_requete['depart'],
241
                 $count,
242
                 $this->limite_requete['limite']);
243
         }
1107 mathias 244
 
245
         $req = sprintf(
966 raphael 246
             'SELECT %s, IF(num_statut="",1,0) AS is_null' .
1107 mathias 247
             ' FROM %s WHERE %s ORDER BY %s is_null ASC, num_statut ASC %s -- %s:%d',
966 raphael 248
 
249
             in_array('*', $this->requete_champ) ? ' * ' : implode(', ', $this->requete_champ),
250
             $this->table,
251
             $this->requete_condition ? implode(' AND ', $this->requete_condition) : 'TRUE',
1107 mathias 252
			 $this->tri ? ($this->tri . ' ' . $this->tri_ordre . ', ') : '',
966 raphael 253
             $nolimit ? '' : $limiteClause,
254
             __FILE__, __LINE__);
1107 mathias 255
		 return $req;
966 raphael 256
     }
257
 
109 jpm 258
	//ajout d'une limite seulement pour les listes (pas plus de 100 resultats retournés pr les requetes
6 jpm 259
	// suivantes : /noms-vernaculaires et /noms-vernaculaires/#id/relations)
966 raphael 260
	static function formerRequeteLimite(&$depart, $total, $limite) {
261
        if ($depart > $total) {
262
			$depart = $total - $limite < 0 ? 0 : ($total - $limite);
263
			return ' LIMIT ' . $depart . ', ' . $limite;
264
        }
265
        return ' LIMIT ' . $depart . ', ' . $limite;
6 jpm 266
	}
109 jpm 267
 
6 jpm 268
	//on récupère le nombre total de résultats de la requete (ex : le nombre d'id contenu dans la liste /noms-vernaculaires)
269
	public function recupererTotalResultat() {
966 raphael 270
        $res = $this->getBdd()->recuperer(sprintf(
271
            'SELECT COUNT(%s) AS nombre FROM %s WHERE %s -- %s:%d',
272
 
273
            $this->format_reponse == 'noms-vernaculaires/attributions' ? 'id' : 'distinct(id)',
274
            $this->table,
275
            $this->requete_condition ? implode(' AND ', $this->requete_condition) : 'TRUE',
276
            __FILE__, __LINE__));
109 jpm 277
 
966 raphael 278
		if (! $res)
279
            throw new Exception('Données introuvables', RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE);
280
        if($res['nombre'] == 0) {
281
            print json_encode(
282
                array(
283
                    "entete" => array(
284
                        "depart" => $this->limite_requete['depart'],
285
                        "limite" => $this->limite_requete['limite'],
286
                        "masque" => $this->recupererMasque(),
287
                        "total" => 0
288
                    ),
289
                    "resultat" => array()
290
                ));
291
            die; // die() très dommage (pour phpunit), mais la stack d'imbrication ne nous permet pas de retourner proprement
292
            }
293
 
980 mathias 294
        $this->total_resultat = $res['nombre'];
966 raphael 295
        return $res['nombre'];
6 jpm 296
	}
109 jpm 297
 
298
	//+------------------------------------------------------------------------------------------------------+
299
	// determine en fct du service appelé (/noms-vernaculaires | /noms-vernaculaires/#id | /noms-vernaculaires/#id/champ |
6 jpm 300
	// /noms-vernaculaires/#id/relations) le format du tableau à retourner.
301
	public function retournerResultatFormate($resultat) {
302
		$this->recupererTableConfig('correspondance_champs');
303
		switch ($this->format_reponse) {
132 aurelien 304
			case 'noms-vernaculaires'				:
305
				$reponse = ($this->retour_format == 'oss') ? $this->formaterEnOss($resultat) : $this->formaterNomsVernaculaires($resultat);			break;
160 delphine 306
			case 'noms-vernaculaires/attributions'	: $reponse = $this->formaterNomsVernaculairesAttributions($resultat);	break;
6 jpm 307
			case 'noms-vernaculaires/id'			: $reponse = $this->formaterNomsVernaculairesId($resultat);			break;
308
			case 'noms-vernaculaires/id/champ'		: $reponse = $this->formaterNomsVernaculairesIdChamp($resultat);	break;
309
			default									:																	break;
310
		}
311
		return $reponse;
312
	}
608 mathilde 313
 
314
	public function ajouterJsonEnTeteNV() {
315
		$table_retour_json['masque'] = $this->recupererMasque();
316
		$table_retour_json['depart'] = $this->limite_requete['depart'];
317
		$table_retour_json['limite'] = $this->limite_requete['limite'];
318
		$table_retour_json['total']  = $this->total_resultat;
6 jpm 319
		$url = $this->formulerUrl($this->total_resultat, '/noms-vernaculaires');
608 mathilde 320
		if (isset($url['precedent']) && $url['precedent'] != '') {
321
			$table_retour_json['href.precedent'] = $url['precedent'];
6 jpm 322
		}
608 mathilde 323
		if (isset($url['suivant']) && $url['suivant']   != '') {
324
			$table_retour_json['href.suivant']   = $url['suivant'];
152 delphine 325
		}
608 mathilde 326
		return $table_retour_json;
327
	}
328
 
329
	public function ajouterJsonResultatNV($resultat) {
6 jpm 330
		foreach ($resultat as $tab) {
331
			foreach ($tab as $key => $valeur) {
332
				if ($valeur != '') {
333
					switch ($key) {
334
						case 'id'				: $num = $valeur;								break;
335
						case 'nom_vernaculaire'	: $this->table_retour['nom'] = $valeur;			break;
336
						default					:												break;
337
					}
1107 mathias 338
					// champs supplémentaires
339
					if (in_array($key, $this->champs_supp)) {
340
						$this->table_retour[$key] = $valeur;
341
					}
6 jpm 342
				}
343
			}
608 mathilde 344
		    if ($this->retour_format == 'max') $this->table_retour['href'] = $this->ajouterHref('noms-vernaculaires', $num);
6 jpm 345
			$resultat_json[$num] = $this->table_retour;
346
			$this->table_retour = array();
347
		}
608 mathilde 348
		return  $resultat_json;
349
	}
109 jpm 350
 
608 mathilde 351
 
352
	public function formaterNomsVernaculaires($resultat) {
353
		$table_retour_json['entete'] = $this->ajouterJsonEnTeteNV();
354
		$resultat = $this->hierarchiserResultat($resultat);
355
		$table_retour_json['resultat'] = $this->ajouterJsonResultatNV($resultat);
6 jpm 356
		return $table_retour_json;
357
	}
132 aurelien 358
 
608 mathilde 359
	public function hierarchiserResultat($resultat) {
360
		//tri recherche floue
361
		if (isset($this->parametres['masque.nv'])) {
966 raphael 362
			return $this->trierRechercheFloue($this->parametres['masque.nv'], $resultat, 'nom_vernaculaire');
608 mathilde 363
		}
364
		if (isset($this->parametres['masque'])) {
966 raphael 365
			return $this->trierRechercheFloue($this->parametres['masque'], $resultat, 'nom_vernaculaire');
608 mathilde 366
		}
367
		return $resultat;
368
	}
369
 
160 delphine 370
	public function recupererMasque() {
371
		$tab_masque = array();
372
		foreach ($this->parametres as $param=>$valeur) {
373
			if (strstr($param, 'masque') != false) {
374
				$tab_masque[] = $param.'='.$valeur;
375
			}
376
		}
966 raphael 377
		return implode('&', $tab_masque);
160 delphine 378
	}
379
 
132 aurelien 380
	public function formaterEnOss($resultat) {
381
		$table_nom = array();
382
		$oss = '';
383
		foreach ($resultat as $tab) {
384
			if (isset($tab['nom_vernaculaire']) ) {
385
				if (!in_array($tab['nom_vernaculaire'], $table_nom)) {
386
					$table_nom[] = $tab['nom_vernaculaire'];
387
					$oss [] = $tab['nom_vernaculaire'];
388
				}
389
			}
390
		}
391
		if (isset($this->masque)) $masque = implode('&', $this->masque);
392
		else $masque = 'Pas de masque';
966 raphael 393
		return array($masque, $oss);
132 aurelien 394
	}
160 delphine 395
 
396
	public function formaterNomsVernaculairesAttributions($resultat) {
397
		//on remplie la table $table_retour_json['entete']
398
		$table_retour_json['entete']['masque'] = $this->recupererMasque();
399
		$table_retour_json['entete']['depart'] = $this->limite_requete['depart'];
400
		$table_retour_json['entete']['limite'] = $this->limite_requete['limite'];
401
		$table_retour_json['entete']['total']  = $this->total_resultat;
402
		$url = $this->formulerUrl($this->total_resultat, '/noms-vernaculaires/attributions');
729 raphael 403
		if (!empty($url['precedent'])) {
160 delphine 404
			$table_retour_json['entete']['href.precedent'] = $url['precedent'];
405
		}
729 raphael 406
		if (!empty($url['suivant'])) {
160 delphine 407
			$table_retour_json['entete']['href.suivant']   = $url['suivant'];
408
		}
888 raphael 409
		foreach ($resultat as &$tab) {
730 raphael 410
			$nnv = $tab['num_nom_vernaculaire'];
411
			$resultat_json[$nnv]['id'] = $tab['id'];
412
			$resultat_json[$nnv]['nom_vernaculaire'] = $tab['nom_vernaculaire'];
888 raphael 413
			$resultat_json[$nnv]['langue.code'] = $resultat_json[$nnv]['code_langue'] = $tab['code_langue'];
730 raphael 414
			$resultat_json[$nnv]['taxon.code'] = 'bdtfx.nt:'.$tab['num_taxon'];
160 delphine 415
			if ($this->retour_format == 'max') {
284 jpm 416
				$this->taxons[] = $tab['num_taxon']; // utilisé pour chercher les noms latins plus bas
729 raphael 417
				if($this->champs_supp) {
730 raphael 418
					//$resultat_json[$nnv] = $this->ajouterChampsOntologieLigneResultat($tab);
419
					// simple initialisation par copie de la référence de l'original
420
					$resultat_json[$nnv] = &$tab;
286 aurelien 421
				}
729 raphael 422
				else {
730 raphael 423
					$resultat_json[$nnv]['num_taxon'] = $tab['num_taxon'];
424
					$resultat_json[$nnv]['nom_retenu.code'] = $tab['num_taxon'];
425
					$resultat_json[$nnv]['taxon'] = $tab['num_taxon'];
426
					$resultat_json[$nnv]['href'] = $this->ajouterHref('noms-vernaculaires', $tab['id']);
729 raphael 427
				}
160 delphine 428
			}
280 aurelien 429
		}
730 raphael 430
 
431
		// dans ce cas (particulier?) nous n'avons pour l'heure initialisé qu'une référence
432
		// vers le tableau de valeurs original
433
		if ($this->retour_format == 'max' && $this->champs_supp) {
434
			// récupérons désormais les ontologies
435
			$this->ajouterChampsOntologieLigneTousResultats($resultat_json);
436
		}
437
 
280 aurelien 438
		if ($this->retour_format == 'max') {
284 jpm 439
			// On est obligé de faire un deuxième boucle pour demander tous les taxons présents en une
440
			// fois et les attribuer aux noms car c'est beaucoup plus rapide
441
			$noms_sci = $this->recupererNomTaxons();
286 aurelien 442
			foreach ($resultat_json as $num_nom => &$tab) {
443
				$tab = $this->ajouterTaxonsAttributionsLigneResultat($tab, $noms_sci);
627 aurelien 444
				if($tab == null) {
445
					unset($resultat_json[$num_nom]);
446
				}
284 jpm 447
			}
160 delphine 448
		}
280 aurelien 449
 
160 delphine 450
		$table_retour_json['resultat'] = $resultat_json;
451
		return $table_retour_json;
452
	}
453
 
286 aurelien 454
	/**
455
	 * Ajoute les champs d'ontologie supplémentaires si necéssaire
832 raphael 456
	 * en faisant appels aux web services associés.
457
	 * Les appels peuvent être fait individuellement (pour un couple <ontologie:valeur>) ou bien
458
	 * regroupés, **si le webservice correspondant le supporte**.
459
	 *
460
	 * Nous disposons à ce jour de 3 (trois) webservices d'ontologies correspondant aux noms vernaculaires (cf $champ_infos)
461
	 * Mais 2 d'entre eux sont identiques, il s'agit de /nvjfl/ontologies/. Or ce webservice supporte le multi-critère.
462
	 * Nous pouvons donc factorisé l'appel pour "conseil_emploi" et "genre", mais pas pour "taxon".
463
	 *
730 raphael 464
	 * @param array in/out $resultats: tous les résultats
465
	 */
466
	public function ajouterChampsOntologieLigneTousResultats(&$resultats) {
832 raphael 467
		$champs_sup = array_intersect($this->champs_supp, array_keys(self::$champ_infos));
730 raphael 468
 
832 raphael 469
		// La regroupement des toutes les valeurs recherchées (pour tous les
470
		// résultats), pour "les" onotologies supportant le multi-critère est effectué ci-dessous.
471
		// Dans les faits ce n'est le cas que pour nvjfl.
472
		$ontologieParamPending = self::NvjflOntologieIndex($resultats, $champs_sup);
473
		$this->NvjflOntologieExpand($ontologieParamPending);
474
		self::NvjflOntologieCombine($resultats);
730 raphael 475
 
832 raphael 476
		// pour les ontologies multi-critères, on vient de le régler ci-dessus
477
		$champs_sup = array_diff($champs_sup, self::$onto_multi_support);
478
 
479
 
480
		// ici, $champs_sup ne peut contenir, au plus, que "taxon".
481
		// code historique:
482
		foreach($champs_sup as $cle) {
483
			$champs_supplementaires = self::$champ_infos[$cle];
730 raphael 484
			// extrait, depuis un élément de $champ_infos:
485
			// $service, $ressource, $projet, $nom, $intitule, $bdd_champ
486
			extract($champs_supplementaires);
487
 
488
			foreach ($resultats as &$tab) {
489
				$valeur_recherche = $tab[$bdd_champ];
490
				if(!trim($valeur_recherche)) continue;
491
 
492
				$url = $this->ajouterHrefAutreProjet($service, $ressource, $valeur_recherche, $projet);
493
				$tab[$intitule] = $this->chercherSignificationCode($url, $nom);
494
			}
495
		}
496
	}
497
 
731 raphael 498
	/* Récupère les valeurs recherchées pour une liste de résultats, (plus ou moins)
499
	   spécifiquement au service d'Ontologies de NVJFL.
500
	   Aggrège les valeurs dans le tableau retourné.
501
	   Une référence vers l'index du tableau (NULL pour l'instant) est laissée dans
502
	   un élément du résultat. */
832 raphael 503
	static function NvjflOntologieIndex(&$resultats, $champs_sup) {
504
		// nous ne supportons le multi-critère que sur les ontologies nvjfl, et nous
505
		// avons précisé celles qui sont concernées dans self::$onto_multi_support
506
		$champs_sup = array_intersect($champs_sup, self::$onto_multi_support);
731 raphael 507
		$ontologieParamPending = Array();
508
		foreach($resultats as &$resultat) {
832 raphael 509
			foreach($champs_sup as $v) {
510
				// de cet extract() nous n'utilisons que $bdd_champ et $ressource
511
				extract(self::$champ_infos[$v]);
512
				if(!isset($resultat[$bdd_champ])) continue;
513
 
514
				$valeur_recherche = $resultat[$bdd_champ];
515
				if(!trim($valeur_recherche)) continue;
516
 
517
				// XXX: $ressource contient déjà ':' comme suffixe
518
				$critere = $ressource . $valeur_recherche;
519
				$ontologieParamPending[$critere] = NULL;
520
				// placeholder pour le résultat
521
				$resultat[SPE_INDEX_NVJFL][$v][$critere] =
522
					&$ontologieParamPending[$critere];
523
			}
731 raphael 524
		}
525
		return $ontologieParamPending;
526
	}
527
 
528
	// TODO: switch to static si il peut en être de même pour ajouterHrefAutreProjet()
529
	/* À partir d'un aggrégat des critère de requêtes d'ontologies, spécifiques à NVJFL,
530
	   créé une URL multi-critère.
531
	   Celle-ci, dans ce cas précis, n'est que la concaténation, par des virgules,
832 raphael 532
	   des couples <ressource:ValeurRecherchée>.
533
	   L'URL est appelée et la valeur correspondante est remplacée dans $criteres_requete.
731 raphael 534
 
535
	   Note: dans le cadre du tryptique index/expand/combine pour lequel cette fonction existe,
832 raphael 536
	   la valeur est référencée par un élément d'une ou plusieurs lignes de $resultat correspondantes.
731 raphael 537
	   Celle(s)-ci sera[ont] donc changée(s) dans la foulée. */
538
	public function NvjflOntologieExpand(&$criteres_requete) {
539
		// équivalent spécifique de ajouterHrefAutreProjet()
540
		$valeurs_requises = implode(',', array_keys($criteres_requete));
832 raphael 541
		// en vérité, nous ne supportons ceci ici que pour nvjfl et non n'importe quel url_service
809 raphael 542
		$url = Config::get('url_service').'/ontologies/'.$valeurs_requises;
731 raphael 543
		$val = $this->consulterHref($url);
831 raphael 544
 
545
		// TODO, le webservice d'ontologies devrait être modifié pour retourner un tableau
546
		// indexé par critère requesté à *CHAQUE* fois, y compris lorsque 1 seul critère est
547
		// demandé.
548
		if(array_key_exists('id', $val) && count($criteres_requete) == 1) {
549
			$k = key($criteres_requete);
550
			$criteres_requete[$k] = $val;
551
			return;
552
		}
553
 
832 raphael 554
		// subtilité, cette affectation modifie par conséquent les valeurs dans
555
		// $resultats[X][SPE_INDEX_NVJFL]
731 raphael 556
		// dont la référence pointe toujours sur $v
557
		foreach($val as $k => $v) $criteres_requete[$k] = $val->$k;
558
	}
559
 
560
	/* Fonction finale du tryptique: réordonne les valeurs obtenues auprès du web-service
832 raphael 561
	   NVJFL en adéquation avec les champs attendus en sortie.
562
	   Dès l'indexation des critères, nous avons associé une (ou plusieurs) référence(s) du
563
	   tableau de résultats vers le tableau de retour des ontologies à l'aide d'un index
564
	   particulier l'index SPE_INDEX_NVJFL qui contient comme élément(s)
565
	   un ou plusieurs ontologies (les indexes de self::$champ_infos) qui elles-mêmes contiennent
566
	   une ou plusieurs valeurs représentant les valeurs recherchées appartement à cette ontologies.
567
	   Celui-ci est supprimé après avoir été correctement copié. */
568
	/**
569
	 * @param array in/out $resultats: tous les résultats
570
	 * @param array in $critere: tableau des ontologies:valeur demandées, de la forme [ numStatut:1, genreNombre:11, ... ]
571
	 */
848 raphael 572
	static function NvjflOntologieCombine(&$resultats) {
731 raphael 573
		foreach($resultats as &$resultat) {
832 raphael 574
			if(!array_key_exists(SPE_INDEX_NVJFL, $resultat)) continue;
575
 
576
			/* Note: la complétude d'un résultat peut dépendre de plusieurs ontologies différentes,
577
			   d'où cette boucle. Cependant une seule valeur sera demandé pour cette ontologie, c'est pourquoi
578
			   $resultat[SPE_INDEX_NVJFL][$onto_name], s'il existe, ne contiendra toujours qu'un seul élément.
579
			   Puisque par définition un résultat contenant des valeurs d'ontologie n'aura jamais qu'un seul et unique
580
			   attribut num_genre (ou num_statut, ou autre) */
581
			foreach(self::$onto_multi_support as $onto_name) {
848 raphael 582
				if(!array_key_exists($onto_name, $resultat[SPE_INDEX_NVJFL])) continue;
583
 
832 raphael 584
				/* $onto_name est un nom d'ontologie (l'une des clefs, parmi conseil_emploi et genre,
585
				   cf la boucle sur $champs_sup dans  NvjflOntologieIndex()
586
				   de cet extract() nous n'utilisons que $intitule et $nom */
587
				extract(self::$champ_infos[$onto_name]);
588
 
589
				// equivalent de l'affectation finale de chercherSignificationCode()
590
				// (utilisé lors de recherches d'ontologies en mono-critère)
591
				// XXX: PHP-5.3 pas de récupération d'attribut sur fonction
592
				$r = current($resultat[SPE_INDEX_NVJFL][$onto_name]);
593
				$resultat[$intitule] = $r->$nom;
594
 
595
				// XXX: certes nous pourrions nous contenter du unset() final
596
				unset($resultat[SPE_INDEX_NVJFL][$onto_name]);
597
			}
598
			unset($resultat[SPE_INDEX_NVJFL]);
731 raphael 599
		}
600
	}
601
 
730 raphael 602
	/**
603
	 * Ajoute les champs d'ontologie supplémentaires si necéssaire
604
	 * en faisant appels aux web services associés
286 aurelien 605
	 * @param array $ligne_resultat
606
	 *
607
	 * @return array la ligne modifiée
608
	 */
284 jpm 609
	public function ajouterChampsOntologieLigneResultat($ligne_resultat) {
832 raphael 610
		foreach(self::$champ_infos as $cle => $champs_supplementaires) {
729 raphael 611
			if(!in_array($cle, $this->champs_supp)) continue;
612
			// extrait, depuis un élément de $champ_infos:
613
			// $service, $ressource, $projet, $nom, $intitule, $bdd_champ
614
			extract($champs_supplementaires);
615
			$valeur_recherche = $ligne_resultat[$bdd_champ];
616
			if(!trim($valeur_recherche)) continue;
617
			$url = $this->ajouterHrefAutreProjet($service, $ressource, $valeur_recherche, $projet);
618
			$ligne_resultat[$intitule] = $this->chercherSignificationCode($url, $nom);
277 aurelien 619
		}
284 jpm 620
		return $ligne_resultat;
277 aurelien 621
	}
622
 
284 jpm 623
	/**
624
	 * Fonction qui ajoute les attributions à une ligne de résultats
625
	 *
626
	 * @param array $ligne_tableau_resultat
627
	 * @param array $nom_sci
628
	 */
629
	public function ajouterTaxonsAttributionsLigneResultat(&$ligne_tableau_resultat, &$noms_sci) {
285 aurelien 630
		if (isset($noms_sci[$ligne_tableau_resultat['num_taxon']])) {
631
			$ligne_tableau_resultat['nom_retenu.code'] = $noms_sci[$ligne_tableau_resultat['num_taxon']]['id'];
632
			$ligne_tableau_resultat['taxon'] = $noms_sci[$ligne_tableau_resultat['num_taxon']]['nom_sci'];
627 aurelien 633
		} else {
634
			$ligne_tableau_resultat = null;
284 jpm 635
		}
636
		return $ligne_tableau_resultat;
637
	}
638
 
639
	private function trierLigneTableau($a, $b) {
640
		$retour = 0;
641
 
642
		if ($a[$this->champ_tri] == $b[$this->champ_tri]) {
643
			$retour = 0;
644
		}
645
 
646
		if($this->champ_tri == 'code_langue') {
647
			if ($a[$this->champ_tri] == 'fra' && $b[$this->champ_tri] != 'fra') {
648
				$retour = ($this->direction_tri == 'asc') ? -1 : 1;
649
			} else if ($a[$this->champ_tri] != 'fra' && $b[$this->champ_tri] == 'fra') {
650
				$retour = ($this->direction_tri == 'asc') ? 1 : -1;
651
			} else {
652
				$retour = $this->comparerChaineSelonDirectionTri($a[$this->champ_tri], $b[$this->champ_tri]);
653
			}
654
		} else {
655
			$retour = $this->comparerChaineSelonDirectionTri($a[$this->champ_tri], $b[$this->champ_tri]);
656
		}
657
		return $retour;
658
	}
659
 
660
	private function comparerChaineSelonDirectionTri($a, $b) {
661
		if($this->direction_tri == 'asc') {
662
			return ($a < $b) ? -1 : 1;
663
		} else {
664
			return ($a > $b) ? -1 : 1;
665
		}
666
	}
667
 
6 jpm 668
	// formatage de la reponse /id ss la forme
669
	// id, nom_vernaculaire, attributions
670
	// langue
671
	// num_nom (correspond à un taxon bdtfx)
672
	public function formaterNomsVernaculairesId($resultat) {
673
		foreach ($resultat as $taxon) { // pour chaque attribution à un taxon bdtfx
674
			// on crée les variables qui serviront de clés et on les enléves du tableau
675
			$num_nom = $taxon['num_nom_vernaculaire']; // unique pour un trinôme id, langue, taxon
676
			unset($taxon['num_nom_vernaculaire']);
677
			$langue = $taxon['code_langue'];
678
			unset($taxon['code_langue']);
109 jpm 679
 
6 jpm 680
			foreach ($this->correspondance_champs as $key => $correspondance) { // ordonne les infos pour affichage
681
				if (isset($taxon[$key]) && $taxon[$key] != "") {
682
					$this->afficherDonnees($correspondance, $taxon[$key], $langue, $num_nom);
683
				}
684
			}
685
			foreach ($taxon as $key => $valeur) { // rajoute les champs non prévus dans l'api
686
				if (!isset($this->correspondance_champs[$key]) && $valeur != "") {
687
					$this->afficherDonnees($key, $valeur, $langue, $num_nom);
688
				}
689
			}
690
			if ($this->retour_format == 'max') $this->chargerBiblio($num_nom, $langue);
691
		}
692
		if ($this->retour_format == 'max') $this->afficherTaxons(); // va chercher les noms de tous les taxons
693
		unset($this->table_retour['href']);
694
		return $this->table_retour;
695
	}
109 jpm 696
 
6 jpm 697
	public function afficherDonnees($champ, $valeur, $langue = '', $num_nom = '') {
698
		if ($champ == 'id' || $champ == 'nom_vernaculaire') {
699
			$this->table_retour[$champ] = $valeur;
700
		} elseif (preg_match('/^(.*)\.code$/', $champ, $match)) {
701
				switch ($match[1]) {
702
					case 'taxon'	: if ($this->retour_format == 'max') {$this->taxons[$num_nom] = $valeur;}
703
						$this->afficherPointCode($match[1], $langue, $num_nom, $valeur);	break;
109 jpm 704
					case 'langue'	: //$this->afficherPointCode($match[1], 'iso-639-3', 'langues', $valeur);
6 jpm 705
						break;
706
					case 'genre'	: $this->afficherPointCode($match[1], $langue, $num_nom, $valeur);	break;
707
					case 'conseil_emploi'	: $this->afficherPointCode($match[1], $langue, $num_nom, $valeur);	break;
708
					default : break;
709
				}
109 jpm 710
 
6 jpm 711
		} elseif ($langue != '') {
712
			$this->table_retour['attributions'][$langue][$num_nom][$champ] = $valeur;
713
		} else {
714
			$this->table_retour[$champ] = $valeur;
715
		}
716
	}
109 jpm 717
 
6 jpm 718
	public function afficherPointCode($nomChamp, $langue, $num_nom, $valeur) {
832 raphael 719
		if (isset(self::$champ_infos[$nomChamp])) {
720
			extract(self::$champ_infos[$nomChamp]);
6 jpm 721
		}
109 jpm 722
 
6 jpm 723
		if ($this->retour_format == 'max') {
724
			$url = $this->ajouterHrefAutreProjet($service, $ressource, $valeur, $projet);
725
			if ($service == 'taxons') {
726
				$code_valeur = '';
164 delphine 727
				$this->table_retour['attributions'][$langue][$num_nom]['nom_retenu.code'] = $code_valeur;
109 jpm 728
			} else {
6 jpm 729
				$code_valeur = $this->chercherSignificationCode($url, $nom);
730
			}
731
			if ($projet != '') $projet .= '.';
732
			$this->table_retour['attributions'][$langue][$num_nom][$nomChamp] = $code_valeur;
733
			$this->table_retour['attributions'][$langue][$num_nom][$nomChamp.'.code'] = $projet.$ressource.$valeur;
734
			$this->table_retour['attributions'][$langue][$num_nom][$nomChamp.'.href'] = $url;
735
		} else {
736
			if ($projet != '') $projet .= '.';
737
			$this->table_retour['attributions'][$langue][$num_nom][$nomChamp.'.code'] = $projet.$ressource.$valeur;
738
		}
739
	}
109 jpm 740
 
6 jpm 741
	public function chercherSignificationCode($url, $nom) {
742
		if (isset($this->signification_code[$url])) {
743
			$valeur = $this->signification_code[$url];
744
		} else {
745
			$res = $this->consulterHref($url);
746
			$valeur = $res->$nom;
747
			$this->signification_code[$url] = $valeur;
748
		}
749
		return $valeur;
750
	}
109 jpm 751
 
6 jpm 752
	public function afficherTaxons() {
160 delphine 753
		$resultat = $this->recupererNomTaxons();
6 jpm 754
		foreach ($this->table_retour['attributions'] as $code_langue=>$langue) {
755
			foreach ($langue as $num_nom=>$taxon) {
756
				$num_tax = ltrim($taxon['taxon.code'], 'bdtfx.nt:');
757
				if (isset($resultat[$num_tax])) {
164 delphine 758
					$this->table_retour['attributions'][$code_langue][$num_nom]['nom_retenu.code'] = $resultat[$num_tax]['id'];
759
					$this->table_retour['attributions'][$code_langue][$num_nom]['taxon'] = $resultat[$num_tax]['nom_sci'];
6 jpm 760
				}
761
			}
762
		}
763
	}
160 delphine 764
 
765
	public function recupererNomTaxons() {
627 aurelien 766
		$taxons = array_unique($this->taxons);
767
		$url = Config::get('url_service_base').'bdtfx/taxons?navigation.limite=500&ns.structure=au&masque.nt='.implode(',', $taxons);
160 delphine 768
		$res = $this->consulterHref($url);
769
		foreach ($res->resultat as $id=>$taxon) {
164 delphine 770
			$resultat[$taxon->num_taxonomique]['id'] = 'bdtfx.nn:'.$id;
627 aurelien 771
			$resultat[$taxon->num_taxonomique]['nom_sci'] = $taxon->nom_sci_complet;
160 delphine 772
		}
773
		return $resultat;
774
	}
6 jpm 775
 
776
	public function formaterNomsVernaculairesIdChamp($resultat) {
109 jpm 777
		$this->table_retour['id'] = $this->ressources[0];
778
		$champs = explode(' ', $this->ressources[1]);
6 jpm 779
		if (in_array('attributions', $champs) != false) {
780
			$this->formaterNomsVernaculairesId($resultat);
781
			unset($this->table_retour['nom_vernaculaire']);
160 delphine 782
		} else {
6 jpm 783
			$champ_attributions = array('num_taxon', 'zone_usage', 'num_statut', 'num_genre', 'notes');
784
			foreach ($resultat as $taxon) {
785
				foreach ($taxon as $key=>$valeur) {
786
					if ($key == 'code_langue' && in_array('langue', $champs) != false) {
787
						$this->table_retour['attributions']['langue'][] = $valeur;
788
					} elseif (in_array($key, $champ_attributions) != false) {
789
						$this->afficherPoint($this->correspondance_champs[$key] , $valeur, $taxon['code_langue'], $taxon['num_nom_vernaculaire']);
790
					} elseif (in_array($key, $champs) != false) {
791
						$this->table_retour[$key] = $valeur;
792
					}
793
				}
794
				if (in_array('biblio', $champs) != false) $this->chargerBiblio($taxon['num_nom_vernaculaire'], $taxon['code_langue']);
795
			}
796
			if (in_array('biblio', $champs) != false && array_search('biblio.num_ref', $this->table_retour) != false) $this->table_retour['biblio'] = null;
797
		}
798
		return $this->table_retour;
799
	}
109 jpm 800
 
6 jpm 801
	public function afficherPoint($champ, $valeur, $langue, $num_nom) {
802
		preg_match('/^(.*)\.code$/', $champ, $match);
803
		$champ = $match[1];
832 raphael 804
		if (isset(self::$champ_infos[$champ])) {
805
			extract(self::$champ_infos[$champ]);
6 jpm 806
			$url = $this->ajouterHrefAutreProjet($service, $ressource, $valeur, $projet);
807
			$projet .= '.';
808
		}
109 jpm 809
 
810
		$champs = explode(' ', $this->ressources[1]);
6 jpm 811
		if (in_array($champ.'.*', $champs) !== false && isset($projet)) {
812
			$this->table_retour['attributions'][$langue][$num_nom][$champ.'.code'] = $projet.$ressource.$valeur;
813
			$this->table_retour['attributions'][$langue][$num_nom][$champ.'.href'] = $url;
109 jpm 814
		}
6 jpm 815
		if (in_array($champ.'.code', $champs) !== false && isset($projet)) {
816
			$this->table_retour['attributions'][$langue][$num_nom][$champ.'.code'] = $projet.$ressource.$valeur;
109 jpm 817
		}
6 jpm 818
		if (in_array($champ.'.href', $champs) !== false && isset($projet)) {
819
			$this->table_retour['attributions'][$langue][$num_nom][$champ.'.href'] = $url;
109 jpm 820
		}
6 jpm 821
		if (in_array($champ, $champs) !== false) {
822
			if (isset($url)) {
823
				$this->table_retour['attributions'][$langue][$num_nom][$champ] = $this->chercherSignificationCode($url, $nom);
824
			} else {
825
				$this->table_retour['attributions'][$langue][$champ] = $valeur;
826
			}
109 jpm 827
		}
6 jpm 828
	}
829
 
830
	public function afficherLangue($nomChamp, $projet, $service, $valeur, $ressource = '', $nom = 'nom') {
831
		if ($this->retour_format == 'max') {
832
				$this->table_retour['attributions'][$nomChamp] = $nom;
833
				$this->table_retour['attributions'][$nomChamp.'.code'] = $projet.$ressource.$valeur;
834
				$this->table_retour['attributions'][$nomChamp.'.href'] = $url;
835
		} else {
836
			$this->table_retour['attributions'][$nomChamp.'.code'] = $projet.$ressource.$valeur;
837
		}
838
	}
109 jpm 839
 
6 jpm 840
	public function chargerBiblio($num_nom, $langue) {
841
		list($table, $version) = explode('_v',$this->table);
842
		$requete = "SELECT b.*, lb.notes FROM nvjfl_lien_biblio_v$version lb, nvjfl_biblio_v$version b ".
843
					"WHERE b.num_ref = lb.num_ref AND lb.num_nom = '$num_nom' ;";
284 jpm 844
		$resultat = $this->getBdd()->recupererTous($requete);
109 jpm 845
 
6 jpm 846
		 if ($resultat == '') { //cas ou la requete comporte des erreurs
847
		 	$r = 'La requête SQL formée comporte une erreur !!';
848
			$this->renvoyerErreur(RestServeur::HTTP_CODE_RESSOURCE_INTROUVABLE, $r);
849
			Debug::printr($requete);
850
		 } elseif ($resultat) {
851
			foreach ($resultat as $res) {
852
			   	foreach ($res as $cle => $valeur) {
853
			   		if ($valeur !== "") {
854
			   			$this->table_retour['attributions'][$langue][$num_nom]['biblio.'.$cle] = $valeur;
855
			   		}
856
			    }
857
			}
858
		}
859
	}
109 jpm 860
 
6 jpm 861
}
862
?>