Subversion Repositories eFlore/Applications.cel

Rev

Rev 1929 | Rev 2055 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1929 Rev 1933
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 204... Line 208...
204
	$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
208
	$objReader = PHPExcel_IOFactory::createReaderForFile($fichier);
205
	// TODO: check if compatible with toArray(<1>,<2>,TRUE,<4>)
209
	// TODO: check if compatible with toArray(<1>,<2>,TRUE,<4>)
206
	$objReader->setReadDataOnly(true);
210
	$objReader->setReadDataOnly(true);
Line 207... Line 211...
207
 
211
 
208
	// 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
 
209
	if(@is_a($objReader, 'PHPExcel_Reader_CSV')) {
220
	if($IS_CSV) {
210
	    $objReader->setDelimiter(',')
221
	    $objReader->setDelimiter(',')
211
		->setEnclosure('"')
222
		->setEnclosure('"')
212
		->setLineEnding("\n")
223
		->setLineEnding("\n")
213
		->setSheetIndex(0);
224
		->setSheetIndex(0);
Line 218... Line 229...
218
	$filtre->def_interval(1, 2);
229
	$filtre->def_interval(1, 2);
219
	$objReader->setReadFilter($filtre);
230
	$objReader->setReadFilter($filtre);
Line 220... Line 231...
220
 
231
 
221
	$objPHPExcel = $objReader->load($fichier);
232
	$objPHPExcel = $objReader->load($fichier);
222
	$obj_infos = $objReader->listWorksheetInfo($fichier);
-
 
223
	// XXX: indépendant du readFilter ?
-
 
Line -... Line 233...
-
 
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);
-
 
244
	} else {
224
	$nb_lignes = $obj_infos[0]['totalRows'];
245
	    // XXX: indépendant du readFilter ?
225
 
246
	    $nb_lignes = $obj_infos[0]['totalRows'];
-
 
247
	    $donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE);
Line 226... Line 248...
226
	$donnees = $objPHPExcel->getActiveSheet()->toArray(NULL, FALSE, TRUE, TRUE);
248
	    $filtre->exclues = self::detectionEntete($donnees[1]);
227
	$filtre->exclues = self::detectionEntete($donnees[1]);
249
	}
228
 
250
 
229
	$obs_ajouts = 0;
251
	$obs_ajouts = 0;
Line 235... Line 257...
235
	$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
257
	$dernier_ordre = intval($dernier_ordre[0]['ordre']) + 1;
236
	if(! $dernier_ordre) $dernier_ordre = 0;
258
	if(! $dernier_ordre) $dernier_ordre = 0;
Line 237... Line 259...
237
 
259
 
238
	// 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 239... Line 263...
239
	set_error_handler(array($this, 'erreurs_stock'), E_USER_NOTICE);
263
 
240
 
264
 
241
	// 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.
242
	// 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) {
243
	for($ligne = 2; $ligne < $nb_lignes + NB_LIRE_LIGNE_SIMUL; $ligne += NB_LIRE_LIGNE_SIMUL) {
268
	    if(!$IS_CSV) {
-
 
269
		$filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
-
 
270
		$objReader->setReadFilter($filtre);
-
 
271
 
-
 
272
		/* recharge avec $filtre actif (filtre sur lignes colonnes):
-
 
273
		   - exclue les colonnes inutiles/inutilisables)
-
 
274
		   - ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
-
 
275
		$objPHPExcel = $objReader->load($fichier)->getActiveSheet();
-
 
276
 
-
 
277
		// set col typing
-
 
278
		if(C_CE_ZONE_GEO != 'C_CE_ZONE_GEO')
-
 
279
		    $objPHPExcel->getStyle(C_CE_ZONE_GEO . '2:' . C_CE_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
-
 
280
 
-
 
281
		// TODO: set to string type
Line 244... Line -...
244
	    $filtre->def_interval($ligne, NB_LIRE_LIGNE_SIMUL);
-
 
245
	    $objReader->setReadFilter($filtre);
-
 
246
 
-
 
247
	    /* recharge avec $filtre actif (filtre sur lignes colonnes):
282
		if(C_ZONE_GEO != 'C_ZONE_GEO')
248
	       - exclue les colonnes inutiles/inutilisables)
283
		    $objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
249
	       - ne selectionne que les lignes dans le range [$ligne - $ligne + NB_LIRE_LIGNE_SIMUL] */
284
 
250
	    $objPHPExcel = $objReader->load($fichier)->getActiveSheet();
285
		$donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE);
251
 
286
	    }
252
	    // set col typing
287
	    else {
253
	    if(C_CE_ZONE_GEO != 'C_CE_ZONE_GEO')
288
		$i = NB_LIRE_LIGNE_SIMUL;
254
		$objPHPExcel->getStyle(C_CE_ZONE_GEO . '2:' . C_CE_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
289
		$donnees = array();
255
 
290
		while($i--) {
-
 
291
		    $tab = fgetcsv($csvFileHandler);
Line 256... Line 292...
256
	    // TODO: set to string type
292
		    if(!$tab) continue;
Line -... Line 293...
-
 
293
		    $donnees[] = array_diff_key($tab, $filtre->exclues);
257
	    if(C_ZONE_GEO != 'C_ZONE_GEO')
294
		}
258
		$objPHPExcel->getStyle(C_ZONE_GEO . '2:' . C_ZONE_GEO . $objPHPExcel->getHighestRow())->getNumberFormat()->setFormatCode('00000');
295
 
Line 259... Line 296...
259
 
296
	    }
260
	    $donnees = $objPHPExcel->toArray(NULL, FALSE, TRUE, TRUE);
-
 
261
 
297
 
262
	    // ici on appel la fonction qui fera effectivement l'insertion multiple
298
	    // var_dump($donnees, get_defined_constants(true)['user']);die;
263
	    // à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
299
	    // ici on appel la fonction qui fera effectivement l'insertion multiple
Line 264... Line 300...
264
 
300
	    // à partir des (au plus) NB_LIRE_LIGNE_SIMUL lignes
Line 284... Line 320...
284
	    Cel::db()->beginTransaction();
320
	    Cel::db()->beginTransaction();
285
	    $stmt = Cel::db()->prepare($sql_pattern);
321
	    $stmt = Cel::db()->prepare($sql_pattern);
286
	    $donnees = array();
322
	    $donnees = array();
287
	    foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
323
	    foreach($enregistrements as $e) $donnees = array_merge($donnees, array_values($e));
Line 288... Line 324...
288
 
324
 
Line 289... Line 325...
289
	    /* debug ici: echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die;*/
325
	    // echo $sql_pattern . "\n"; var_dump($enregistrements, $donnees); die; // debug ici
Line 290... Line 326...
290
 
326
 
291
	    $stmt->execute($donnees);
327
	    $stmt->execute($donnees);
Line 320... Line 356...
320
	       count($filtre->exclues) > 1 ? 's' : '',
356
	       count($filtre->exclues) > 1 ? 's' : '',
321
	       implode(', ', $filtre->exclues));
357
	       implode(', ', $filtre->exclues));
322
	die();
358
	die();
323
    }
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
324
 
371
       d'array_merge() (réordonnancement des clefs numérique) n'est pas souhaitable dans le second cas. */
325
    static function detectionEntete($entete) {
372
    static function detectionEntete($entete, $numeric_keys = FALSE) {
326
	$colonnes_reconnues = Array();
373
	$colonnes_reconnues = Array();
327
	$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
374
	$cols = FormateurGroupeColonne::nomEnsembleVersListeColonnes('standard,avance');
328
	foreach($entete as $k => $v) {
375
	foreach($entete as $k => $v) {
329
	    // 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 363... Line 410...
363
 
410
 
364
	// 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 ) )
365
	// ==> 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) {
366
	$colonnesID_a_exclure = array_intersect($entete, $colonnes_automatiques);
416
	    return $colonnesID_non_reconnues + $colonnesID_a_exclure;
367
 
417
	}
368
	// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
418
	// TODO: pourquoi ne pas comparer avec les abbrevs aussi ?
369
	// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
419
	// merge ( Array( I => rien ) , Array ( S => Ordre, AA => Phénologie ) )
370
	// ==> Array ( I => rien, AA => Phénologie )
420
	// ==> Array ( I => rien, AA => Phénologie )
Line 379... Line 429...
379
	$enregistrements = Array();
429
	$enregistrements = Array();
380
	$toutes_images = Array();
430
	$toutes_images = Array();
381
	$tous_mots_cle = Array();
431
	$tous_mots_cle = Array();
Line 382... Line 432...
382
 
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;
383
	foreach($lignes as $ligne) {
436
 
384
	    //$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
437
	    //$ligne = array_filter($ligne, function($cell) { return !is_null($cell); });
385
	    //if(!$ligne) continue;
438
	    //if(!$ligne) continue;
386
	    // 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