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\Exceptions\AbortXmlImportException;
|
||||
use App\Exceptions\InvalidXmlException;
|
||||
use ErrorException;
|
||||
use Illuminate\Contracts\Filesystem\FileNotFoundException;
|
||||
use Illuminate\Contracts\Filesystem\Filesystem;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
use RecursiveArrayIterator;
|
||||
use RecursiveIteratorIterator;
|
||||
use SimpleXMLElement;
|
||||
use Throwable;
|
||||
use TypeError;
|
||||
|
||||
abstract class XmlJobs extends XArcadiaFlux
|
||||
{
|
||||
|
||||
/**
|
||||
* invalid xml folder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $invalidFolderName = 'invalid';
|
||||
|
||||
/**
|
||||
* The columns to take from the XML
|
||||
* 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));
|
||||
|
||||
/** @var string $data */
|
||||
$data = $disk->get($filename);
|
||||
|
||||
try {
|
||||
if ($this->encapsulate) {
|
||||
$data = sprintf('<Root>%s</Root>', $data);
|
||||
/** @var SimpleXMLElement|false */
|
||||
$xmlContent = simplexml_load_string($data);
|
||||
} else {
|
||||
/** @var SimpleXMLElement|false */
|
||||
$xmlContent = simplexml_load_string($data, null, LIBXML_NOCDATA | LIBXML_PARSEHUGE);
|
||||
}
|
||||
/** @var string $data */
|
||||
$data = $disk->get($filename);
|
||||
try {
|
||||
if ($this->encapsulate) {
|
||||
$data = sprintf('<Root>%s</Root>', $data);
|
||||
/** @var SimpleXMLElement|false */
|
||||
$xmlContent = simplexml_load_string($data);
|
||||
} else {
|
||||
/** @var SimpleXMLElement|false */
|
||||
$xmlContent = simplexml_load_string($data, null, LIBXML_NOCDATA | LIBXML_PARSEHUGE);
|
||||
}
|
||||
|
||||
if ($xmlContent === false) {
|
||||
$this->log(
|
||||
sprintf('File %s could not be parsed (simplexml_load_string)', $filename),
|
||||
LogType::critical()
|
||||
);
|
||||
continue; // ignore the file
|
||||
if ($xmlContent === false) {
|
||||
throw new InvalidXmlException('XML is Invalid (simplexml_load_string returned false)');
|
||||
// $this->log(
|
||||
// sprintf('File %s could not be parsed (simplexml_load_string)', $filename),
|
||||
// LogType::critical()
|
||||
// );
|
||||
// continue; // ignore the file
|
||||
}
|
||||
} catch (ErrorException $e) {
|
||||
throw new InvalidXmlException('XML is Invalid', 0, $e);
|
||||
}
|
||||
|
||||
$data = $this->extract($xmlContent);
|
||||
|
||||
|
||||
$lines = [];
|
||||
foreach ($data[$entityName] as $traca) {
|
||||
$line = $this->processFields($traca);
|
||||
|
|
@ -102,6 +116,7 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
}
|
||||
$lines[] = $line;
|
||||
}
|
||||
|
||||
// Mise en base des données
|
||||
foreach ($lines as $line) {
|
||||
/** @var array Unique Key columns */
|
||||
|
|
@ -116,7 +131,7 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
// @todo : should we put that method in a interface ?
|
||||
$savedData->updateLocalProductInfo();
|
||||
}
|
||||
} catch (ErrorException | TypeError | QueryException $e) {
|
||||
} catch (InvalidXmlException $e) {
|
||||
$message = $e->getMessage();
|
||||
if (get_class($e) === QueryException::class) {
|
||||
$message = implode(' ', $e->errorInfo);
|
||||
|
|
@ -130,17 +145,49 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
),
|
||||
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
|
||||
} catch (AbortXmlImportException $e) {
|
||||
$this->log(
|
||||
sprintf(
|
||||
'File %s could not be parsed => %s on line %d',
|
||||
'ERROR: File %s could not be parsed => %s on line %d',
|
||||
$filename,
|
||||
$e->getMessage(),
|
||||
$e->getLine()
|
||||
),
|
||||
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
|
||||
}
|
||||
$this->moveToArchives($filename);
|
||||
|
|
@ -276,4 +323,57 @@ abstract class XmlJobs extends XArcadiaFlux
|
|||
}
|
||||
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' => [
|
||||
'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