Gestion des erreurs d'import xml pour données inconsistentes
This commit is contained in:
parent
3ef393878f
commit
0663305ea7
5 changed files with 159 additions and 21 deletions
9
app/Exceptions/InvalidXmlException.php
Normal file
9
app/Exceptions/InvalidXmlException.php
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
class InvalidXmlException extends Exception
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
@ -4,19 +4,30 @@ namespace App\Jobs;
|
||||||
|
|
||||||
use App\Enums\LogType;
|
use App\Enums\LogType;
|
||||||
use App\Exceptions\AbortXmlImportException;
|
use App\Exceptions\AbortXmlImportException;
|
||||||
|
use App\Exceptions\InvalidXmlException;
|
||||||
use ErrorException;
|
use ErrorException;
|
||||||
|
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||||
use Illuminate\Database\QueryException;
|
use Illuminate\Database\QueryException;
|
||||||
use Illuminate\Support\Facades\Log;
|
use Illuminate\Support\Facades\Log;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use RecursiveArrayIterator;
|
use RecursiveArrayIterator;
|
||||||
use RecursiveIteratorIterator;
|
use RecursiveIteratorIterator;
|
||||||
use SimpleXMLElement;
|
use SimpleXMLElement;
|
||||||
|
use Throwable;
|
||||||
use TypeError;
|
use TypeError;
|
||||||
|
|
||||||
abstract class XmlJobs extends XArcadiaFlux
|
abstract class XmlJobs extends XArcadiaFlux
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid xml folder
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $invalidFolderName = 'invalid';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The columns to take from the XML
|
* The columns to take from the XML
|
||||||
* subcolumns can be added with a dot
|
* subcolumns can be added with a dot
|
||||||
|
|
@ -70,30 +81,33 @@ abstract class XmlJobs extends XArcadiaFlux
|
||||||
|
|
||||||
$this->log(sprintf(' traitement %d sur %s ', $progress++, $total));
|
$this->log(sprintf(' traitement %d sur %s ', $progress++, $total));
|
||||||
|
|
||||||
/** @var string $data */
|
|
||||||
$data = $disk->get($filename);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($this->encapsulate) {
|
/** @var string $data */
|
||||||
$data = sprintf('<Root>%s</Root>', $data);
|
$data = $disk->get($filename);
|
||||||
/** @var SimpleXMLElement|false */
|
try {
|
||||||
$xmlContent = simplexml_load_string($data);
|
if ($this->encapsulate) {
|
||||||
} else {
|
$data = sprintf('<Root>%s</Root>', $data);
|
||||||
/** @var SimpleXMLElement|false */
|
/** @var SimpleXMLElement|false */
|
||||||
$xmlContent = simplexml_load_string($data, null, LIBXML_NOCDATA | LIBXML_PARSEHUGE);
|
$xmlContent = simplexml_load_string($data);
|
||||||
}
|
} else {
|
||||||
|
/** @var SimpleXMLElement|false */
|
||||||
|
$xmlContent = simplexml_load_string($data, null, LIBXML_NOCDATA | LIBXML_PARSEHUGE);
|
||||||
|
}
|
||||||
|
|
||||||
if ($xmlContent === false) {
|
if ($xmlContent === false) {
|
||||||
$this->log(
|
throw new InvalidXmlException('XML is Invalid (simplexml_load_string returned false)');
|
||||||
sprintf('File %s could not be parsed (simplexml_load_string)', $filename),
|
// $this->log(
|
||||||
LogType::critical()
|
// sprintf('File %s could not be parsed (simplexml_load_string)', $filename),
|
||||||
);
|
// LogType::critical()
|
||||||
continue; // ignore the file
|
// );
|
||||||
|
// continue; // ignore the file
|
||||||
|
}
|
||||||
|
} catch (ErrorException $e) {
|
||||||
|
throw new InvalidXmlException('XML is Invalid', 0, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $this->extract($xmlContent);
|
$data = $this->extract($xmlContent);
|
||||||
|
|
||||||
|
|
||||||
$lines = [];
|
$lines = [];
|
||||||
foreach ($data[$entityName] as $traca) {
|
foreach ($data[$entityName] as $traca) {
|
||||||
$line = $this->processFields($traca);
|
$line = $this->processFields($traca);
|
||||||
|
|
@ -102,6 +116,7 @@ abstract class XmlJobs extends XArcadiaFlux
|
||||||
}
|
}
|
||||||
$lines[] = $line;
|
$lines[] = $line;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mise en base des données
|
// Mise en base des données
|
||||||
foreach ($lines as $line) {
|
foreach ($lines as $line) {
|
||||||
/** @var array Unique Key columns */
|
/** @var array Unique Key columns */
|
||||||
|
|
@ -116,7 +131,7 @@ abstract class XmlJobs extends XArcadiaFlux
|
||||||
// @todo : should we put that method in a interface ?
|
// @todo : should we put that method in a interface ?
|
||||||
$savedData->updateLocalProductInfo();
|
$savedData->updateLocalProductInfo();
|
||||||
}
|
}
|
||||||
} catch (ErrorException | TypeError | QueryException $e) {
|
} catch (InvalidXmlException $e) {
|
||||||
$message = $e->getMessage();
|
$message = $e->getMessage();
|
||||||
if (get_class($e) === QueryException::class) {
|
if (get_class($e) === QueryException::class) {
|
||||||
$message = implode(' ', $e->errorInfo);
|
$message = implode(' ', $e->errorInfo);
|
||||||
|
|
@ -130,17 +145,49 @@ abstract class XmlJobs extends XArcadiaFlux
|
||||||
),
|
),
|
||||||
LogType::critical()
|
LogType::critical()
|
||||||
);
|
);
|
||||||
|
$this->sendInvalidXmlEmail($filename, $e);
|
||||||
|
$this->moveToInvalid($filename);
|
||||||
|
continue;
|
||||||
|
} catch (ErrorException | TypeError $e) {
|
||||||
|
$this->log(
|
||||||
|
sprintf(
|
||||||
|
'CRITICAL: File %s could not be parsed => %s on line %d',
|
||||||
|
$filename,
|
||||||
|
$e->getMessage(),
|
||||||
|
$e->getLine()
|
||||||
|
),
|
||||||
|
LogType::critical()
|
||||||
|
);
|
||||||
|
$this->sendErrorParseEmailToServiceWeb($e);
|
||||||
continue; // ignore the file
|
continue; // ignore the file
|
||||||
} catch (AbortXmlImportException $e) {
|
} catch (AbortXmlImportException $e) {
|
||||||
$this->log(
|
$this->log(
|
||||||
sprintf(
|
sprintf(
|
||||||
'File %s could not be parsed => %s on line %d',
|
'ERROR: File %s could not be parsed => %s on line %d',
|
||||||
$filename,
|
$filename,
|
||||||
$e->getMessage(),
|
$e->getMessage(),
|
||||||
$e->getLine()
|
$e->getLine()
|
||||||
),
|
),
|
||||||
LogType::error()
|
LogType::error()
|
||||||
);
|
);
|
||||||
|
$this->sendErrorParseEmailToServiceWeb($e);
|
||||||
|
$this->moveToInvalid($filename);
|
||||||
|
continue; // ignore the file
|
||||||
|
} catch (FileNotFoundException | QueryException $e) {
|
||||||
|
// This happens because of concurent xml jobs read
|
||||||
|
$message = $e->getMessage();
|
||||||
|
if (get_class($e) === QueryException::class) {
|
||||||
|
$message = implode(' ', $e->errorInfo);
|
||||||
|
}
|
||||||
|
$this->log(
|
||||||
|
sprintf(
|
||||||
|
'ERROR: File %s could not be read (not found) => %s on line %d',
|
||||||
|
$filename,
|
||||||
|
$message,
|
||||||
|
$e->getLine()
|
||||||
|
),
|
||||||
|
LogType::debug()
|
||||||
|
);
|
||||||
continue; // ignore the file
|
continue; // ignore the file
|
||||||
}
|
}
|
||||||
$this->moveToArchives($filename);
|
$this->moveToArchives($filename);
|
||||||
|
|
@ -276,4 +323,57 @@ abstract class XmlJobs extends XArcadiaFlux
|
||||||
}
|
}
|
||||||
return $isXml;
|
return $isXml;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function sendErrorParseEmailToServiceWeb(Throwable $e)
|
||||||
|
{
|
||||||
|
Mail::send('emails.exception', [
|
||||||
|
'exception' => $e,
|
||||||
|
'appName' => config('app.name'),
|
||||||
|
], function ($m) {
|
||||||
|
$m->to(
|
||||||
|
config('mail.contactsList.serviceweb'),
|
||||||
|
sprintf('%s Exception Handler', config('app.name'))
|
||||||
|
)->subject('Could not eat INCO, because of its toxicity !');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function sendInvalidXmlEmail(string $filename, Throwable $e)
|
||||||
|
{
|
||||||
|
$message = $e->getPrevious()->getMessage();
|
||||||
|
Mail::send('emails.invalidxml', [
|
||||||
|
'strError' => sprintf(
|
||||||
|
'File %s could not be parsed => %s on line %d',
|
||||||
|
$filename,
|
||||||
|
$message,
|
||||||
|
$e->getLine()
|
||||||
|
),
|
||||||
|
'appName' => config('app.name'),
|
||||||
|
'filename' => $filename,
|
||||||
|
'exception' => $e->getPrevious()
|
||||||
|
], function ($m) {
|
||||||
|
$m->to(
|
||||||
|
config('mail.contactsList.invalidInco'),
|
||||||
|
sprintf('%s Exception Handler', config('app.name'))
|
||||||
|
)->subject('You sent me an invalid XML file, please check its validity before resend ASAP.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the file to invalid folder
|
||||||
|
*
|
||||||
|
* @param string $filename
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function moveToInvalid(string $filename): void
|
||||||
|
{
|
||||||
|
if (!$this->getDisk()->move($filename, sprintf('%s/%s', $this->invalidFolderName, $filename))) {
|
||||||
|
$this->log(
|
||||||
|
sprintf(
|
||||||
|
'File %s could not be moved to invalid folder name',
|
||||||
|
$filename
|
||||||
|
),
|
||||||
|
LogType::warning()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,8 @@ return [
|
||||||
],
|
],
|
||||||
|
|
||||||
'contactsList' => [
|
'contactsList' => [
|
||||||
'serviceweb' => env('MAIL_LIST_SERVICEWEB', 'informatique.internet@ldc.fr')
|
'serviceweb' => explode(",", env('MAIL_LIST_SERVICEWEB', 'informatique.internet@ldc.fr')),
|
||||||
|
'invalidInco' => explode(",", env('MAIL_LIST_INVALIDINCO', 'informatique.internet@ldc.fr,vincent.pierre@ldc.fr,christelle.manceau@ldc.fr')),
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
28
resources/views/emails/invalidxml.blade.php
Normal file
28
resources/views/emails/invalidxml.blade.php
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>{{ $appName }} Exception Handler: Unvalid XML</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>{{ $appName }} à reçu un fichier xml non valide !!</h1>
|
||||||
|
<h3>{{ $strError }}</h3>
|
||||||
|
<h4>FICHIER: `{{ $filename }}`</h4>
|
||||||
|
<p>{{ $exception->getMessage() }}</p>
|
||||||
|
<p>
|
||||||
|
<b>date</b> : {{ date('Y-m-d H:i:s') }}<br>
|
||||||
|
<b>code</b> : {{$exception->getCode() }}<br>
|
||||||
|
<b>file</b> : {{$exception->getFile() }}<br>
|
||||||
|
<b>line</b> : {{$exception->getLine() }}<br>
|
||||||
|
<p>
|
||||||
|
<b>Merci de corriger le flux, puis de renvoyer le fichier en provoquant un mouvement EAI.</b><br><br>
|
||||||
|
<b>Pour rappel</b> : Il est recommandé de valider un fichier XML à l'aide d'un <b>DTD</b><br>
|
||||||
|
<a href="https://www.w3schools.com/xml/xml_dtd.asp">https://www.w3schools.com/xml/xml_dtd.asp</a><br>
|
||||||
|
ou bien <b>XSD</b> <a href="https://www.w3schools.com/xml/schema_intro.asp">https://www.w3schools.com/xml/schema_intro.asp</a><br><br>
|
||||||
|
<b>Pourquoi ?</b><br>
|
||||||
|
Pour que les concepteurs puissent identifier les types de données qui transitent (les champs et leurs caratéristiques)<br>
|
||||||
|
Mais aussi valider les fichiers reçus.
|
||||||
|
</p>
|
||||||
|
<p>En l'absence de données valides, cette fiche va être mise de coté.</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
0
storage/inco/invalid/.gitkeep
Normal file
0
storage/inco/invalid/.gitkeep
Normal file
Loading…
Add table
Reference in a new issue