Subversion Repositories eFlore/Applications.del

Rev

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

Rev Author Line No. Line
1375 raphael 1
<?php
2
/**
3
 * Le web service observations récupère toutes les observations et, pour chacune d'elle, les
4
 * images qui lui sont associées.
5
 * Basée sur la classe antérieure dans ListeObservations.php de
6
 * Grégoire Duché et Aurélien Peronnet
7
 * (formaterVote, formaterDeterminations, chargerNombreCommentaire, chargerVotes, chargerDeterminations)
8
 *
9
 * @category	php 5.2
10
 * @package		del
11
 * @author		Raphaël Droz <raphael@tela-botanica.org>
12
 * @copyright	Copyright (c) 2013 Tela Botanica (accueil@tela-botanica.org)
13
 * @license	http://www.cecill.info/licences/Licence_CeCILL_V2-fr.txt Licence CECILL
14
 * @license	http://www.gnu.org/licenses/gpl.html Licence GNU-GPL
15
 * @see http://www.tela-botanica.org/wikini/eflore/wakka.php?wiki=ApiIdentiplante01Observations
16
 *
17
 * TODO:
18
 * PDO::prepare()
19
 * Sphinx pour auteur, genre, ns, commune, tag et masque-général
20
 */
21
 
1490 raphael 22
require_once(dirname(__FILE__) . '/../DelTk.php');
1375 raphael 23
 
1451 raphael 24
class ListeObservations {
1375 raphael 25
 
1494 raphael 26
    private $conteneur;
27
    private $gestionBdd;
28
    private $bdd;
29
    private $parametres = array();
30
    private $ressources = array();
1375 raphael 31
 
1494 raphael 32
    static $tris_possibles = array('date_observation');
33
    // paramètres autorisés
1375 raphael 34
 
1494 raphael 35
    static $sql_fields_liaisons = array(
36
	'dob' => array('id_observation', 'nom_sel AS `determination.ns`', 'nt AS `determination.nt`',
37
		       'nom_sel_nn AS `determination.nn`', 'famille AS `determination.famille`',
38
		       'nom_referentiel AS `determination.referentiel`',
39
		       'ce_zone_geo AS id_zone_geo', 'zone_geo', 'lieudit',
40
		       'station', 'milieu', 'date_observation', 'mots_cles_texte', 'date_transmission',
41
		       'ce_utilisateur AS `auteur.id`', 'prenom_utilisateur AS `auteur.prenom`',
1666 jpm 42
		       'nom_utilisateur AS `auteur.nom`', 'courriel_utilisateur AS `auteur.courriel` ',
1494 raphael 43
		       'commentaire'),
1829 mathias 44
	'di' => array('id_image', 'date_prise_de_vue AS `date`', 'hauteur'),
1494 raphael 45
	'du' => array('prenom', 'nom', 'courriel'),
46
	'dc' => array('commentaire')
47
    );
1375 raphael 48
 
49
 
1494 raphael 50
    public function __construct(Conteneur $conteneur = null) {
1618 mathias 51
		$this->conteneur = $conteneur == null ? new Conteneur() : $conteneur;
52
		$this->conteneur->chargerConfiguration('config_departements_bruts.ini');
53
		$this->conteneur->chargerConfiguration('config_observations.ini');
54
		$this->conteneur->chargerConfiguration('config_mapping_votes.ini');
55
		$this->conteneur->chargerConfiguration('config_mapping_commentaires.ini');
56
		$this->navigation = $conteneur->getNavigation();
57
		$this->masque = $conteneur->getMasque();
58
		$this->gestionBdd = $conteneur->getGestionBdd();
59
		$this->bdd = $this->gestionBdd->getBdd();
1494 raphael 60
    }
1375 raphael 61
 
1494 raphael 62
    static function reformateObservation($obs, $url_pattern = '') {
1618 mathias 63
		$obs = array_map('array_filter', $obs);
64
		$obs_merged = array();
65
		foreach($obs as $o) {
66
		    $id = $o['id_observation'];
1666 jpm 67
 
1618 mathias 68
		    // car auteur.id peut être un email, un hash, ou un annuaire_tela.U_ID
69
		    // mais dans les deux premiers cas SELECT courriel AS observateur fait déjà l'affaire
70
		    if(!isset($o['auteur.id']) || !is_numeric($o['auteur.id'])) $o['auteur.id'] = "0";
71
		    if(!isset($o['auteur.nom'])) $o['auteur.nom'] = '[inconnu]';
1666 jpm 72
 
1618 mathias 73
		    $image = array_intersect_key($o, array_flip(array('id_image', 'date', 'hauteur' , 'largeur', 'nom_original')));
74
		    $image['binaire.href'] = sprintf($url_pattern, $image['id_image']);
75
		    unset($o['id_image'], $o['date'], $o['hauteur'], $o['largeur'], $o['nom_original']);
76
		    if(!isset($obs_merged['"' . $id . '"'])) $obs_merged['"' . $id . '"'] = $o;
77
		    $obs_merged['"' . $id . '"']['images'][] = $image;
78
		}
79
		return $obs_merged;
1494 raphael 80
    }
1375 raphael 81
 
1494 raphael 82
    /**
83
     * Méthode principale de la classe.
84
     * Lance la récupération des images dans la base et les place dans un objet ResultatService
85
     * pour l'afficher.
86
     * @param array $ressources les ressources situées après l'url de base (ex : http://url/ressource1/ressource2)
87
     * @param array $parametres les paramètres situés après le ? dans l'url
1666 jpm 88
     **/
1494 raphael 89
    public function consulter($ressources, $parametres) {
1618 mathias 90
		// SELECT, à terme, pourrait affecter getInfos(), mais en aucune manière getIdObs()
91
		$req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array());
1666 jpm 92
 
1618 mathias 93
		// toujours nécessaire puisque nous tapons sur v_del_image qui INNER JOIN cel_images, or nous voulons certes
94
		// toutes les images, mais nous voulons $limite observations uniques.
95
		$req['groupby'][] = 'vdi.id_observation';
1666 jpm 96
 
1618 mathias 97
		$db = $this->bdd;
1666 jpm 98
 
1618 mathias 99
		// filtrage de l'INPUT
100
		$params = DelTk::requestFilterParams($parametres, DelTk::$parametres_autorises, $this->conteneur);
1666 jpm 101
 
1618 mathias 102
		$params['masque.tag'] = DelTk::buildTagsAST(@$parametres['masque.tag'], 'OR', ',');
1666 jpm 103
 
1618 mathias 104
		// ... et paramètres par défaut
105
		$params = array_merge(DelTk::$default_params, $params);
1666 jpm 106
 
1618 mathias 107
		// création des contraintes (masques)
108
		DelTk::sqlAddConstraint($params, $db, $req);
109
		self::sqlAddConstraint($params, $db, $req, $this->conteneur);
110
		self::sqlAddMasqueConstraint($params, $db, $req, $this->conteneur);
1666 jpm 111
 
1618 mathias 112
		// 1) grunt-work: *la* requête de récupération des id valides (+ SQL_CALC_FOUND_ROWS)
113
		$idobs_tab = self::getIdObs($params, $req, $db);
114
		// idobs est une liste (toujours ordonnée) des id d'observations recherchées
115
		$idobs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'), $idobs_tab));
1666 jpm 116
 
1618 mathias 117
		if($idobs) {
118
		    $total = $db->recuperer('SELECT FOUND_ROWS() AS c'); $total = intval($total['c']);
1666 jpm 119
 
1618 mathias 120
		    // 2) récupération des données nécessaires pour ces observations (obs + images)
121
		    // ici les champs récupérés sont issus de self::$sql_fields_liaisons mais sans préfixes
122
		    // car tout provient de v_del_image
123
		    $obs_unfmt = self::getInfos($idobs, $db);
1666 jpm 124
 
1618 mathias 125
		    // 3) suppression, merge des données en tableau assez représentatif du futur JSON en output
126
		    $observations = self::reformateObservation($obs_unfmt, $this->conteneur->getParametre('url_images'));
1666 jpm 127
 
1618 mathias 128
		    // 4) récupération des données nécessaires pour ces observations (commentaires + votes)
129
		    // modifie $observations
130
		    $this->configurer();
131
		    $this->chargerDeterminations($observations);
1666 jpm 132
 
1618 mathias 133
		    // 5) restauration de l'ordre souhaité initialement
134
		    $observations = self::sortArrayByArray($observations, $idobs);
135
		} else {
136
		    $observations = array();
137
		    $total = 0;
138
		}
1666 jpm 139
 
1618 mathias 140
		// 6) JSON output
141
		$resultat = new ResultatService();
142
		$resultat->corps = array('entete' => DelTk::makeJSONHeader($total, $params, Config::get('url_service')),
143
					 'resultats' => $observations);
1666 jpm 144
 
1618 mathias 145
		return $resultat;
1494 raphael 146
    }
1375 raphael 147
 
1494 raphael 148
    static function sortArrayByArray($array, $orderArray) {
1618 mathias 149
		$ordered = array();
150
		foreach($orderArray as $key) {
151
		    if(array_key_exists('"' . $key . '"', $array)) {
152
			$ordered['"' . $key . '"'] = $array['"' . $key . '"'];
153
			unset($array['"' . $key . '"']);
154
		    }
155
		}
156
		return $ordered + $array;
1494 raphael 157
    }
1375 raphael 158
 
1494 raphael 159
    // SQL helpers
160
    /*
161
     * Retourne une liste ordonnée d'id d'observation correspondant aux critères
162
     * passés dans p et aux clauses where/join présentes dans le tableau $req
163
     *
164
     * @param p: $params (filtrés sauf escape-string)
165
     * @param req: le tableau représentant les composants de la requete SQL
166
     * @param db: l'instance de db
167
     */
168
    static function getIdObs($p, $req, $db) {
169
	$req_s = sprintf('SELECT SQL_CALC_FOUND_ROWS id_observation' .
170
			 ' FROM v_del_image vdi'.
171
			 ' %s' . // LEFT JOIN if any
172
			 ' WHERE %s'. // where-clause ou TRUE
173
			 ' %s'. // group-by
174
			 ' %s'. // having (si commentaires)
175
			 ' ORDER BY %s %s %s'.
176
			 ' LIMIT %d, %d -- %s',
1666 jpm 177
 
1494 raphael 178
			 $req['join'] ? implode(' ', $req['join']) : '',
179
			 $req['where'] ? implode(' AND ', $req['where']) : 'TRUE',
1375 raphael 180
 
1494 raphael 181
			 $req['groupby'] ? ('GROUP BY ' . implode(', ', array_unique($req['groupby']))) : '',
182
			 $req['having'] ? ('HAVING ' . implode(' AND ', $req['having'])) : '',
1375 raphael 183
 
1494 raphael 184
			 $p['tri'], strtoupper($p['ordre']),
185
			 // date_transmission peut-être NULL et nous voulons de la consistence
186
			 // (sauf après r1860 de Cel)
187
			 $p['tri'] == 'date_transmission' ? ', id_observation' : '',
1375 raphael 188
 
1494 raphael 189
			 $p['navigation.depart'], $p['navigation.limite'], __FILE__ . ':' . __LINE__);
1379 raphael 190
 
1494 raphael 191
	$res = $db->recupererTous($req_s);
192
	$err = mysql_error();
193
	if(!$res && $err) {
194
	    // http_response_code(400);
195
	    // if(defined('DEBUG') && DEBUG) header("X-Debug: $req_s");
196
	    throw new Exception('not found', 400);
1375 raphael 197
	}
1494 raphael 198
	// ordre préservé, à partir d'ici c'est important.
199
	return $res;
200
    }
1375 raphael 201
 
1494 raphael 202
    /*
203
      Champs récupérés:
204
      Pour del_images, la vue retourne déjà ce que nous recherchons de cel_obs et cel_images
205
      (cel_obs.* et cel_[obs_]images.{id_observation, id_image, date_prise_de_vue AS date, hauteur, largeur})
206
      Pour del_commentaires: nous voulons *
207
      Reste ensuite à formatter.
208
      Note: le préfixe de table utilisé ici (vdi) n'impacte *aucune* autre partie du code car rien
209
      n'en dépend pour l'heure. (inutilisation de $req['select'])
210
    */
211
    static function getInfos($idobs, $db) {
1829 mathias 212
 
1494 raphael 213
	$select_fields = array_merge(self::$sql_fields_liaisons['dob'],
214
				     self::$sql_fields_liaisons['di']);
215
	$req_s = sprintf('SELECT %s FROM v_del_image vdi'.
216
			 // ' LEFT JOIN del_commentaire AS dc ON di.id_observation = dc.ce_observation AND dc.nom_sel IS NOT NULL'.
217
			 ' WHERE id_observation IN (%s)',
218
			 implode(',', $select_fields),
219
			 implode(',', $idobs));
220
	return $db->recupererTous($req_s);
221
    }
1375 raphael 222
 
223
 
1494 raphael 224
    /**
225
     * Complément à DelTk::sqlAddConstraint()
226
     *
1490 raphael 227
     * @param $p les paramètres (notamment de masque) passés par l'URL et déjà traités/filtrés (sauf quotes)
1494 raphael 228
     * @param $req le tableau, passé par référence représentant les composants de la requête à bâtir
229
     * @param $c conteneur, utilisé soit pour l'appel récursif à requestFilterParams() en cas de param "masque"
230
     *								soit pour la définition du type (qui utilise la variable nb_commentaires_discussion)
231
     */
232
    static function sqlAddConstraint($p, $db, &$req, Conteneur $c = NULL) {
233
	if(!empty($p['masque.tag'])) {
234
	    // TODO: remove LOWER() lorsqu'on est sur que les tags sont uniformés en minuscule
235
	    // i_mots_cles_texte provient de la VIEW v_del_image
236
	    if(isset($p['masque.tag']['AND'])) {
1800 mathias 237
			/* Lorsque nous interprêtons la chaîne provenant du masque général (cf: buildTagsAST($p['masque'], 'OR', ' ') dans sqlAddMasqueConstraint()),
238
			   nous sommes splittés par espace. Cependant, assurons que si une virgule à été saisie, nous n'aurons pas le motif
239
			   " AND CONCAT(mots_cles_texte, i_mots_cles_texte) REGEXP ',' " dans notre requête.
240
			   XXX: Au 12/11/2013, une recherche sur tag depuis le masque général implique un OU, donc le problème ne se pose pas ici */
241
			$subwhere = array();
242
			foreach($p['masque.tag']['AND'] as $tag) {
243
			    if(trim($tag) == ',') continue;
244
 
245
			    $subwhere[] = sprintf('CONCAT(%s) LIKE %s',
246
						  DelTk::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')),
247
						  $db->proteger("%" . strtolower($tag) . "%"));
248
			}
249
			$req['where'][] = '(' . implode(' AND ', $subwhere) . ')';
250
	    } else {
251
			$req['where'][] = sprintf('CONCAT(%s) LIKE %s',
1494 raphael 252
					  DelTk::sqlAddIfNullPourConcat(array('vdi.mots_cles_texte', 'vdi.i_mots_cles_texte')),
1804 mathias 253
					  $db->proteger("%" . strtolower(implode('|', $p['masque.tag']['OR'])) . "%"));
1494 raphael 254
	    }
1416 raphael 255
	}
1375 raphael 256
 
1494 raphael 257
	if(!empty($p['masque.type'])) {
258
	    self::addTypeConstraints($p['masque.type'], $db, $req, $c);
1375 raphael 259
	}
1494 raphael 260
    }
1375 raphael 261
 
1494 raphael 262
    /* Le masque fait une recherche générique parmi de nombreux champs ci-dessus.
263
       Nous initialisons donc ces paramètres (excepté masque biensur), et nous rappelons
264
       récursivement. À la seule différence que nous n'utiliserons que $or_req['where']
265
       imploded par des " OR ". */
266
    static function sqlAddMasqueConstraint($p, $db, &$req, Conteneur $c = NULL) {
267
	if(!empty($p['masque'])) {
268
	    $or_params = array('masque.auteur' => $p['masque'],
269
			       'masque.departement' => $p['masque'],
270
			       'masque.id_zone_geo' => $p['masque'],
271
			       'masque.tag' => $p['masque'],
272
			       'masque.ns' => $p['masque'],
273
			       'masque.famille' => $p['masque'],
274
			       'masque.date' => $p['masque'],
275
			       'masque.genre' => $p['masque'],
276
			       /* milieu: TODO ? */ );
1498 raphael 277
	    /* Cependant les champs spécifiques ont priorité sur le masque général.
278
	       Pour cette raison nous supprimons la génération de SQL du masque général sur les
279
	       champ spécifiques qui feront l'objet d'un traitement avec une valeur propre. */
280
	    if(isset($p['masque.auteur'])) unset($or_params['masque.auteur']);
281
	    if(isset($p['masque.departement'])) unset($or_params['masque.departement']);
282
	    if(isset($p['masque.id_zone_geo'])) unset($or_params['masque.id_zone_geo']);
283
	    if(isset($p['masque.tag'])) unset($or_params['masque.tag']);
284
	    if(isset($p['masque.famille'])) unset($or_params['masque.famille']);
285
	    if(isset($p['masque.date'])) unset($or_params['masque.date']);
286
	    if(isset($p['masque.genre'])) unset($or_params['masque.genre']);
287
 
288
 
1494 raphael 289
	    $or_masque = DelTk::requestFilterParams($or_params, array_keys($or_params), $c);
1498 raphael 290
	    if(isset($or_params['masque.tag'])) {
291
		$or_masque['masque.tag'] = DelTk::buildTagsAST($p['masque'], 'OR', ' ');
292
	    }
293
 
1494 raphael 294
	    // $or_req = array('select' => array(), 'join' => array(), 'where' => array(), 'groupby' => array(), 'having' => array());
295
	    $or_req = array('join' => array(), 'where' => array());
296
	    DelTk::sqlAddConstraint($or_masque, $db, $or_req);
297
	    self::sqlAddConstraint($or_masque, $db, $or_req);
1375 raphael 298
 
1494 raphael 299
	    if($or_req['where']) {
300
		$req['where'][] = '(' . implode(' OR ', $or_req['where']) . ')';
301
		// utile au cas ou des jointures seraient rajoutées
302
		$req['join'] = array_unique(array_merge($req['join'], $or_req['join']));
303
	    }
1375 raphael 304
	}
1494 raphael 305
    }
1375 raphael 306
 
307
 
1494 raphael 308
    private function configurer() {
309
	$this->mappingVotes = $this->conteneur->getParametre('mapping_votes');
310
	$this->mappingCommentaire = $this->conteneur->getParametre('mapping_commentaire');
311
    }
1375 raphael 312
 
313
 
1494 raphael 314
    /*
315
     * @param $req: la représentation de la requête MySQL complète, à amender.
316
     */
317
    static function addTypeConstraints($val, $db, &$req, Conteneur $c) {
318
	if(array_key_exists('adeterminer', $val)) {
1528 mathias 319
	    // On récupère toutes les observations qui on le tag "aDeterminer" *ou* qui n'ont pas de nom d'espèce
320
	    // *ou* qui ont la "certitude" à ("aDeterminer" *ou* "douteux")
1494 raphael 321
	    $req['where'][] = '(' . implode(' OR ', array(
322
		'vdi.certitude = "aDeterminer"',
1528 mathias 323
		'vdi.certitude = "douteux"',
1494 raphael 324
		'vdi.mots_cles_texte LIKE "%aDeterminer%"',
1755 mathias 325
		'vdi.nom_sel_nn IS NULL',
326
	    'vdi.nom_sel_nn = 0', // il ne DEVRAIT pas y avoir d'entrées à 0, mais il y en a quand-même !!
1494 raphael 327
	    )) . ')';
1375 raphael 328
	}
1494 raphael 329
	if(array_key_exists('validees', $val)) {
330
	    //On récupère toutes les observations ayant un commentaire doté de proposition_retenue = 1
331
	    $req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation AND dc.proposition_retenue = 1';
332
	}
1375 raphael 333
 
1494 raphael 334
	// solution n°1: impraticable
335
	if(false && array_key_exists('endiscussion', $val)) {
336
	    //Si on veut les observations en discussion,
337
	    // on va récupérer les ids des observations dont le nombre de commentaire est supérieur à N
338
	    $req['select'][] = 'COUNT(dc.id_commentaire) AS comm_count';
339
	    $req['join'][] = 'INNER JOIN del_commentaire AS dc ON vdi.id_observation = dc.ce_observation';
340
	    $req['groupby'][] = 'vdi.id_observation';
341
	    $req['having'][] = "COUNT(id_commentaire) > " . $c->getParametre('nb_commentaires_discussion');
342
	}
1375 raphael 343
 
1494 raphael 344
	if(array_key_exists('endiscussion', $val)) {
345
	    $req['where'][] = '(SELECT COUNT(id_commentaire) FROM del_commentaire AS dc'.
346
		' WHERE ce_observation = id_observation) > ' . intval($c->getParametre('nb_commentaires_discussion'));
347
	}
348
    }
349
 
350
 
351
    /**
352
     * Récupérer toutes les déterminations et le nombre de commentaire au total
353
     * @param array $observations la liste des observations à mettre à jour
354
     * */
355
    private function chargerDeterminations(&$observations) {
356
	$idObs = array_values(array_map(create_function('$a', 'return $a["id_observation"];'),
357
					$observations));
358
	$r = sprintf('SELECT * FROM del_commentaire AS dc WHERE dc.nom_sel IS NOT NULL AND ce_observation IN (%s) -- %s',
359
		     implode(',',$idObs),
360
		     __FILE__ . ':' . __LINE__);
361
	$propositions = $this->bdd->recupererTous($r);
362
	if(!$propositions) return;
363
	foreach ($propositions as $proposition) {
364
	    $idObs = $proposition['ce_observation'];
365
	    $idComment = $proposition['id_commentaire'];
366
	    $comment = $this->formaterDetermination($idComment, $proposition);
367
	    if($comment) $observations['"' . $idObs . '"']['commentaires'][$idComment] = $comment;
1666 jpm 368
 
1375 raphael 369
	}
1494 raphael 370
    }
1375 raphael 371
 
1494 raphael 372
    private function formaterDetermination($commentId, $proposition) {
373
	if(!$proposition) return NULL;
1386 raphael 374
 
1494 raphael 375
	$proposition_formatee = array('nb_commentaires' => '0');
376
	foreach ($this->mappingCommentaire as $nomOriginal => $nomFinal) {
377
	    if (isset($proposition[$nomOriginal])) {
378
		$proposition_formatee[$nomFinal] = $proposition[$nomOriginal];
379
	    }
380
	}
1386 raphael 381
 
1494 raphael 382
	// Charger les votes sur les déterminations
383
	$resultatsVotes = $this->bdd->recupererTous(
384
	    sprintf('SELECT * FROM del_commentaire_vote WHERE ce_proposition = %d', $commentId));
1666 jpm 385
 
1494 raphael 386
	foreach ($resultatsVotes as $vote) {
387
	    $proposition_formatee['votes'][$vote['id_vote']] = $this->formaterVote($vote);
388
	}
1375 raphael 389
 
1386 raphael 390
 
1494 raphael 391
	// chargerNombreCommentaire()
392
	// Charger le nombre de commentaires (sans détermination) associé à l'observation
393
	$listeCommentaires = $this->bdd->recupererTous(sprintf(
394
	    'SELECT ce_commentaire_parent, ce_proposition, COUNT( id_commentaire ) AS nb '.
395
	    'FROM del_commentaire WHERE ce_proposition = %d GROUP BY ce_proposition -- %s',
396
	    $commentId, __FILE__ . ':' . __LINE__));
397
	foreach ($listeCommentaires as $ligneProposition) {
398
	    // ce test sert à exclure les proposition de 1er niveau qui sont elles aussi des commentaires
399
	    if($ligneProposition['ce_commentaire_parent']) {
400
		// TODO/debug: id_commentaire_parent != $commentId ??
401
		// reprendre la "logique" du code... moins de boucles, moins de requêtes, ...
402
		if($ligneProposition['ce_commentaire_parent'] != $commentId) {
403
		    // restore_error_handler();
404
		    error_log(sprintf("possible error: nb_commentaires = %s: comment = %d, parent = %d, %s",
405
				      $ligneProposition['nb'], $commentId, $ligneProposition['ce_commentaire_parent'], __FILE__));
1375 raphael 406
		}
1494 raphael 407
		$proposition_formatee['nb_commentaires'] = $ligneProposition['nb'];
408
	    } else {
409
		$proposition_formatee['observation']['nb_commentaires'] = $ligneProposition['nb'];
410
	    }
1375 raphael 411
	}
412
 
1494 raphael 413
	return $proposition_formatee;
414
    }
415
 
416
    /**
417
     *	Formater un vote en fonction du fichier de configuration config_votes.ini
418
     *	@param $votes array()
419
     * */
420
    private function formaterVote($vote) {
421
	$retour = array();
422
	foreach ($vote as $param=>$valeur) {
423
	    $retour[$this->mappingVotes[$param]] = $valeur;
1375 raphael 424
	}
1494 raphael 425
	return $retour;
426
    }
1375 raphael 427
}