Subversion Repositories eFlore/Applications.del

Rev

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