Subversion Repositories eFlore/Applications.cel

Rev

Rev 1914 | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1914 Rev 1936
Line 36... Line 36...
36
// nombre d'INSERT à cumuler par requête SQL
36
// nombre d'INSERT à cumuler par requête SQL
37
// (= nombre de lignes XLS à bufferiser)
37
// (= nombre de lignes XLS à bufferiser)
38
//define('NB_LIRE_LIGNE_SIMUL', 30);
38
//define('NB_LIRE_LIGNE_SIMUL', 30);
39
define('NB_LIRE_LIGNE_SIMUL', 5);
39
define('NB_LIRE_LIGNE_SIMUL', 5);
Line -... Line 40...
-
 
40
 
-
 
41
// en cas d'import d'un fichier CSV, utilise fgetcsv() plutôt
-
 
42
// que PHPExcel ce qui se traduit par un gain de performances très substanciel
-
 
43
define('QUICK_CSV_IMPORT', TRUE);
40
 
44
 
41
// Numbers of days between January 1, 1900 and 1970 (including 19 leap years)
45
// Numbers of days between January 1, 1900 and 1970 (including 19 leap years)
42
// see traiterDateObs()
46
// see traiterDateObs()
Line 150... Line 154...
150
	public $id_utilisateur = NULL;
154
    public $id_utilisateur = NULL;
Line 151... Line 155...
151
 
155
 
152
	// erreurs d'import
156
    // erreurs d'import
Line -... Line 157...
-
 
157
    public $bilan = Array();
-
 
158
 
Line 153... Line 159...
153
	public $bilan = Array();
159
    // cache (pour traiterLocalisation() pour l'instant)
154
 
160
    static $cache = Array('geo' => array());
155
 
161
 
Line 202... Line 208...
202
		$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
208
	$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
203
		// TODO: check if compatible with toArray(<1>,<2>,TRUE,<4>)
209
	// TODO: check if compatible with toArray(<1>,<2>,TRUE,<4>)
204
		$objReader->setReadDataOnly(true);
210
	$objReader->setReadDataOnly(true);
Line 205... Line 211...
205
 
211
 
206
		// TODO: is_a obsolete entre 5.0 et 5.3, retirer le @ à terme
212
	// TODO: is_a obsolete entre 5.0 et 5.3, retirer le @ à terme
-
 
213
	$IS_CSV = @is_a($objReader, 'PHPExcel_Reader_CSV') && QUICK_CSV_IMPORT;
-
 
214
	// en cas d'usage de fgetcsv, testons que nous pouvons compter les lignes
-
 
215
	if($IS_CSV) $nb_lignes = intval(exec("wc -l $fichier"));
-
 
216
	// et, le cas échéant, fallback sur PHPExcel à nouveau. La raison de ce test ici est
-
 
217
	// l'instabilité du serveur (safe_mode, safe_mode_exec_dir, symlink vers binaires pour exec(), ... multiples points-of-failure)
-
 
218
	if($IS_CSV && !$nb_lignes) $IS_CSV = FALSE;
-
 
219
 
207
		if(@is_a($objReader, 'PHPExcel_Reader_CSV')) {
220
	if($IS_CSV) {
208
			$objReader->setDelimiter(',')
221
	    $objReader->setDelimiter(',')
209
				->setEnclosure('"')
222
		->setEnclosure('"')
210
				->setLineEnding("\n")
223
		->setLineEnding("\n")
211
				->setSheetIndex(0);
224
		->setSheetIndex(0);
Line 216... Line 229...
216
		$filtre->def_interval(1, 2);
229
	$filtre->def_interval(1, 2);
217
		$objReader->setReadFilter($filtre);
230
	$objReader->setReadFilter($filtre);
Line 218... Line 231...
218
 
231
 
219
		$objPHPExcel = $objReader->load($fichier);
232
	$objPHPExcel = $objReader->load($fichier);
-
 
233
	$obj_infos = $objReader->listWorksheetInfo($fichier);
-
 
234
 
-
 
235
	if($IS_CSV) {
-
 
236
	    // $nb_lignes est déjà défini ci-dessus
-
 
237
	    $csvFileHandler = fopen($fichier, 'r');
-
 
238
	    // nous utilisons la valeur de retour dans un but informatif de l'utilisateur à la
-
 
239
	    // fin de l'import, *mais aussi* dans un array_diff_key() ci-dessous car bien que dans le
-
 
240
	    // fond le "parser" fgetcsv() n'ait pas d'intérêt à connaître les colonnes à ignorer,
-
 
241
	    // il se trouve que celles-ci peuvent interférer sur des fonctions comme traiterEspece()
-
 
242
	    // cf test "ref-nom-num.test.php" pour lequel l'élément C_NOM_SEL vaudrait 3 et $ligne serait array(3 => -42)
-
 
243
	    $filtre->exclues = self::detectionEntete(fgetcsv($csvFileHandler), TRUE);
220
		$obj_infos = $objReader->listWorksheetInfo($fichier);
244
	} else {
221
		// XXX: indépendant du readFilter ?
245
	    // XXX: indépendant du readFilter ?
222
		$nb_lignes = $obj_infos[0]['totalRows'];
-
 
223
 
246
	    $nb_lignes = $obj_infos[0]['totalRows'];
224
		$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE);
247
	    $donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE);
-
 
248
	    $filtre->exclues = self::detectionEntete($donnees[1]);
Line 225... Line 249...
225
		$filtre->exclues = self::detectionEntete($donnees[1]);
249
	}
226
 
250
 
227
		$obs_ajouts = 0;
251
	$obs_ajouts = 0;
228
		$obs_maj = 0;
252
	$obs_maj = 0;
Line 233... Line 257...
233
		$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
257
	$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
234
		if(! $dernier_ordre) $dernier_ordre = 0;
258
	if(! $dernier_ordre) $dernier_ordre = 0;
Line 235... Line 259...
235
 
259
 
236
		// on catch to les trigger_error(E_USER_NOTICE);
260
	// on catch to les trigger_error(E_USER_NOTICE);
-
 
261
	set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
-
 
262
	$this->taxon_info_webservice = new RechercheInfosTaxonBeta($this->config, NULL);
Line 237... Line 263...
237
		set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
263
 
238
 
264
 
239
		// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
265
	// lecture par morceaux (chunks), NB_LIRE_LIGNE_SIMUL lignes à fois
-
 
266
	// pour aboutir des requêtes SQL d'insert groupés.
240
		// pour aboutir des requêtes SQL d'insert groupés.
267
	for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
241
		for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
268
	    if(!$IS_CSV) {
Line 242... Line 269...
242
			$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
269
		$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
243
			$objReader->setReadFilter($filtre);
270
		$objReader->setReadFilter($filtre);
Line 254... Line 281...
254
			// TODO: set to string type
281
		// TODO: set to string type
255
			if(C_ZONE_GEO != 'C_ZONE_GEO')
282
		if(C_ZONE_GEO != 'C_ZONE_GEO')
256
				$objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
283
		    $objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
Line 257... Line 284...
257
 
284
 
-
 
285
		$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE);
-
 
286
	    }
-
 
287
	    else {
-
 
288
		$i = NB_LIRE_LIGNE_SIMUL;
-
 
289
		$donnees = array();
-
 
290
		while($i--) {
-
 
291
		    $tab = fgetcsv($csvFileHandler);
-
 
292
		    if(!$tab) continue;
-
 
293
		    $donnees[] = array_diff_key($tab, $filtre->exclues);
Line -... Line 294...
-
 
294
		}
-
 
295
 
-
 
296
	    }
258
			$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE);
297
 
259
 
298
	    // var_dump($donnees, get_defined_constants(true)['user']);die;
Line 260... Line 299...
260
			// ici on appel la fonction qui fera effectivement l'insertion multiple
299
	    // ici on appel la fonction qui fera effectivement l'insertion multiple
261
			// à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
-
 
262
 
300
	    // à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
263
			// TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques
301
 
264
			// notamment dans RechercheInfosTaxonBeta.php
302
	    // TODO: passer $this, ne sert que pour appeler des méthodes publiques qui pourraient être statiques
Line 265... Line 303...
265
			list($enregistrements, $images, $mots_cle) =
303
	    list($enregistrements, $images, $mots_cle) =
Line 282... Line 320...
282
			Cel::db()->beginTransaction();
320
	    Cel::db()->beginTransaction();
283
			$stmt = Cel::db()->prepare($sql_pattern);
321
	    $stmt = Cel::db()->prepare($sql_pattern);
284
			$donnees = array();
322
	    $donnees = array();
285
			foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
323
	    foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
Line 286... Line 324...
286
 
324
 
Line 287... Line 325...
287
			/* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/
325
	    // echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die; // debug ici
Line 288... Line 326...
288
 
326
 
289
			$stmt->execute($donnees);
327
	    $stmt->execute($donnees);
Line 318... Line 356...
318
			   count($filtre->exclues) > 1 ? 's' : '',
356
	       count($filtre->exclues) > 1 ? 's' : '',
319
			   implode(', ', $filtre->exclues));
357
	       implode(', ', $filtre->exclues));
320
		die();
358
	die();
321
	}
359
    }
Line -... Line 360...
-
 
360
 
-
 
361
    /* detectionEntete() sert deux rôles:
-
 
362
       1) détecter le type de colonne attendu à partir des textes de la ligne d'en-tête afin de define()
-
 
363
       2) permet d'identifier les colonnes non-supportées/inutiles afin d'alléger le processus de parsing de PHPExcel
-
 
364
       grace au ReadFilter (C'est le rôle de la valeur de retour)
-
 
365
 
-
 
366
       La raison de la présence du paramètre $numeric_keys est que pour réussir à identifier les colonnes à exclure nous
-
 
367
       devons traiter un tableau représentant la ligne d'en-tête aussi bien:
-
 
368
       - sous forme associative pour PHPExcel (les clefs sont les lettres de l'alphabet)
-
 
369
       - sous forme de clefs numériques (fgetcsv())
-
 
370
       Le détecter après coup est difficile et pourtant cette distinction est importante car le comportement
322
 
371
       d'array_merge() (réordonnancement des clefs numérique) n'est pas souhaitable dans le second cas. */
323
	static function detectionEntete($entete) {
372
    static function detectionEntete($entete, $numeric_keys = FALSE) {
324
		$colonnes_reconnues = Array();
373
	$colonnes_reconnues = Array();
325
		$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
374
	$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
326
		foreach($entete as $k => $v) {
375
	foreach($entete as $k => $v) {
327
			// traite les colonnes en faisant fi de la casse et des accents
376
	    // traite les colonnes en faisant fi de la casse et des accents
Line 361... Line 410...
361
 
410
 
362
		// intersect ( Array ( N => Milieu, S => Ordre ), Array ( ordre => Ordre, phenologie => Phénologie ) )
411
	// intersect ( Array ( N => Milieu, S => Ordre ), Array ( ordre => Ordre, phenologie => Phénologie ) )
363
		// ==> Array ( S => Ordre, AA => Phénologie )
412
	// ==> Array ( S => Ordre, AA => Phénologie )
Line -... Line 413...
-
 
413
	$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
-
 
414
 
-
 
415
	if($numeric_keys) {
364
		$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
416
	    return $colonnesID_non_reconnues + $colonnesID_a_exclure;
365
 
417
	}
366
		// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
418
	// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
367
		// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
419
	// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
368
		// ==> Array ( I => rien, AA => Phénologie )
420
	// ==> Array ( I => rien, AA => Phénologie )
Line 377... Line 429...
377
		$enregistrements = Array();
429
	$enregistrements = Array();
378
		$toutes_images = Array();
430
	$toutes_images = Array();
379
		$tous_mots_cle = Array();
431
	$tous_mots_cle = Array();
Line 380... Line 432...
380
 
432
 
-
 
433
	foreach($lignes as $ligne) {
-
 
434
	    // dans le cas de fgetcsv, on peut avoir des false additionnel (cf do/while l. 279)
-
 
435
	    if($ligne === false) continue;
381
		foreach($lignes as $ligne) {
436
 
382
			//$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
437
	    //$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
383
			//if(!$ligne) continue;
438
	    //if(!$ligne) continue;
384
			// on a besoin des NULL pour éviter des notice d'index indéfini
439
	    // on a besoin des NULL pour éviter des notice d'index indéfini
Line 478... Line 533...
478
		$referentiel = self::identReferentiel(trim(strtolower(@$ligne[C_NOM_REFERENTIEL])), $ligne, $ref_ligne);
533
	$referentiel = self::identReferentiel(trim(strtolower(@$ligne[C_NOM_REFERENTIEL])), $ligne, $ref_ligne);
Line 479... Line 534...
479
 
534
 
480
		// $espece est rempli de plusieurs informations
535
	// $espece est rempli de plusieurs informations
481
		$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
536
	$espece = Array(C_NOM_SEL => NULL, C_NOM_SEL_NN => NULL, C_NOM_RET => NULL,
482
						C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
537
			C_NOM_RET_NN => NULL, C_NT => NULL, C_FAMILLE => NULL);
Line 483... Line 538...
483
		self::traiterEspece($ligne, $espece, $referentiel, $cel);
538
	self::traiterEspece($ligne, $espece, $referentiel, $cel->taxon_info_webservice);
484
 
539
 
Line 485... Line 540...
485
		if(!$espece[C_NOM_SEL]) $referentiel = Cel::$fallback_referentiel;
540
	if(!$espece[C_NOM_SEL]) $referentiel = Cel::$fallback_referentiel;
Line 688... Line 743...
688
 
743
 
689
	/*
744
    /*
690
	  TODO: s'affranchir du webservice pour la détermination du nom scientifique en s'appuyant sur cel_references,
745
      TODO: s'affranchir du webservice pour la détermination du nom scientifique en s'appuyant sur cel_references,
691
	  pour des questions de performances
746
      pour des questions de performances
692
	*/
747
    */
693
	static function traiterEspece($ligne, Array &$espece, &$referentiel, $cel) {
748
    static function traiterEspece($ligne, Array &$espece, &$referentiel, $taxon_info_webservice) {
694
		if(empty($ligne[C_NOM_SEL])) {
749
	if(empty($ligne[C_NOM_SEL])) {
695
			// TODO: nous ne déclarons pas "Numéro nomenclatural" comme colonne importable
750
	    // TODO: nous ne déclarons pas "Numéro nomenclatural" comme colonne importable
696
			// Nous ne pouvons donc pas tenter d'être sympa sur la détermination par num_nom
751
	    // Nous ne pouvons donc pas tenter d'être sympa sur la détermination par num_nom
697
			/* if(!empty($ligne[C_NOM_SEL_NN]) && $referentiel != Cel::$fallback_referentiel)
752
	    /* if(!empty($ligne[C_NOM_SEL_NN]) && $referentiel != Cel::$fallback_referentiel)
Line 703... Line 758...
703
		// nom_sel reste toujours celui de l'utilisateur
758
	// nom_sel reste toujours celui de l'utilisateur
704
		$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
759
	$espece[C_NOM_SEL] = trim($ligne[C_NOM_SEL]);
Line 705... Line 760...
705
 
760
 
706
		// XXX/attention, nous ne devrions pas accepter un référentiel absent !
761
	// XXX/attention, nous ne devrions pas accepter un référentiel absent !
707
		if(!$referentiel) $referentiel = 'bdtfx';
762
	if(!$referentiel) $referentiel = 'bdtfx';
708
		$taxon_info_webservice = new RechercheInfosTaxonBeta($cel->config, $referentiel);
763
	$taxon_info_webservice->setReferentiel($referentiel);
Line 709... Line 764...
709
		$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
764
	$ascii = iconv('UTF-8', 'ASCII//TRANSLIT', $ligne[C_NOM_SEL]);
710
 
765
 
711
		// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
766
	// TODO: si empty(C_NOM_SEL) et !empty(C_NOM_SEL_NN) : recherche info à partir de C_NOM_SEL_NN
Line 809... Line 864...
809
		if(empty($ligne[C_CE_ZONE_GEO])) $ligne[C_CE_ZONE_GEO] = NULL;
864
	if(empty($ligne[C_CE_ZONE_GEO])) $ligne[C_CE_ZONE_GEO] = NULL;
Line 810... Line 865...
810
 
865
 
811
	    $identifiant_commune = trim($ligne[C_ZONE_GEO]);
866
	$identifiant_commune = trim($ligne[C_ZONE_GEO]);
812
		if(!$identifiant_commune) {
867
	if(!$identifiant_commune) {
-
 
868
	    $departement = trim($ligne[C_CE_ZONE_GEO]);
813
			$departement = trim($ligne[C_CE_ZONE_GEO]);
869
 
814
			if(strpos($departement, "INSEE-C:", 0) === 0) {
870
	    if(strpos($departement, "INSEE-C:", 0) === 0) {
-
 
871
		$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
-
 
872
		if(array_key_exists($localisation[C_CE_ZONE_GEO], self::$cache['geo'])) {
-
 
873
		    $localisation[C_ZONE_GEO] = self::$cache['geo'][$localisation[C_CE_ZONE_GEO]];
-
 
874
		}
815
				$localisation[C_CE_ZONE_GEO] = trim($ligne[C_CE_ZONE_GEO]);
875
		else {
816
				$nom = Cel::db()->requeter(sprintf("SELECT nom FROM cel_zones_geo WHERE code = %s LIMIT 1",
876
		    $nom = Cel::db()->requeter(sprintf("SELECT nom FROM cel_zones_geo WHERE code = %s LIMIT 1",
817
																		self::quoteNonNull(substr($localisation[C_CE_ZONE_GEO], strlen("INSEE-C:")))));
877
						       self::quoteNonNull(substr($localisation[C_CE_ZONE_GEO], strlen("INSEE-C:")))));
-
 
878
		    if($nom) $localisation[C_ZONE_GEO] = $nom[0]['nom'];
-
 
879
		    self::$cache['geo'][$localisation[C_CE_ZONE_GEO]] = @$nom[0]['nom'];
818
				if($nom) $localisation[C_ZONE_GEO] = $nom[0]['nom'];
880
		}
819
				return;
881
		return;
Line 820... Line 882...
820
			}
882
	    }
821
 
883
 
822
			if(!is_numeric($departement)) {
884
	    if(!is_numeric($departement)) {
823
				$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
885
		$localisation[C_CE_ZONE_GEO] = $ligne[C_CE_ZONE_GEO];
Line -... Line 886...
-
 
886
		return;
-
 
887
	    }
-
 
888
 
-
 
889
	    $cache_attempted = FALSE;
-
 
890
	    if(array_key_exists($departement, self::$cache['geo'])) {
-
 
891
		$cache_attempted = TRUE;
-
 
892
		if(self::$cache['geo'][$departement][0] && self::$cache['geo'][$departement][1]) {
-
 
893
		    $localisation[C_ZONE_GEO] = self::$cache['geo'][$departement][0];
-
 
894
		    $localisation[C_CE_ZONE_GEO] = self::$cache['geo'][$departement][1];
-
 
895
		    return;
824
				return;
896
		}
825
			}
897
	    }
826
 
898
 
827
			if( ($resultat_commune = Cel::db()->requeter(sprintf("SELECT DISTINCT nom, CONCAT('INSEE-C:', code) AS code FROM cel_zones_geo WHERE code = %s LIMIT 1",
899
	    if(! $cache_attempted && ($resultat_commune = Cel::db()->requeter(sprintf("SELECT DISTINCT nom, CONCAT('INSEE-C:', code) AS code FROM cel_zones_geo WHERE code = %s LIMIT 1",
-
 
900
										      self::quoteNonNull($departement)))) ) {
828
																 self::quoteNonNull($departement)))) ) {
901
		$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
829
				$localisation[C_ZONE_GEO] = $resultat_commune[0]['nom'];
902
		$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
830
				$localisation[C_CE_ZONE_GEO] = $resultat_commune[0]['code'];
903
		self::$cache['geo'][$departement] = array($resultat_commune[0]['nom'], $resultat_commune[0]['code']);
831
				return;
904
		return;
832
			}
905
	    }
Line 869... Line 942...
869
			// on prend le risque ici de retourner une mauvaise Commune
942
	    // on prend le risque ici de retourner une mauvaise Commune
870
			$nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
943
	    $nom_commune = str_replace(" ", "%", iconv('UTF-8', 'ASCII//TRANSLIT', $identifiant_commune));
871
	 	    $requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
944
	    $requete = sprintf("%s WHERE nom LIKE %s", $select, self::quoteNonNull($nom_commune.'%'));
872
		}
945
	}
Line -... Line 946...
-
 
946
 
-
 
947
 
-
 
948
	if(array_key_exists($identifiant_commune, self::$cache['geo'])) {
-
 
949
	    $resultat_commune = self::$cache['geo'][$identifiant_commune];
-
 
950
	}
873
	
951
	else {
-
 
952
	    $resultat_commune = Cel::db()->requeter($requete);
-
 
953
	    self::$cache['geo'][$identifiant_commune] = $resultat_commune;
874
		$resultat_commune = Cel::db()->requeter($requete);
954
	}
875
		// TODO: levenstein sort ?
955
	// TODO: levenstein sort ?
Line 876... Line 956...
876
		// TODO: count résultat !
956
	// TODO: count résultat !
877
 
957