ldc-boutique-cnc/app/Jobs/XmlIncoReader.php
2022-08-25 12:26:43 +02:00

535 lines
20 KiB
PHP

<?php
namespace App\Jobs;
use App\Exceptions\AbortXmlImportException;
use App\Models\XmlInco;
use SimpleXMLElement;
class XmlIncoReader extends XmlJobs
{
protected $disk = 'inco';
protected $imagesPath = 'images';
/**
* éléments à la racine : nom du noeud
* sous éléments d'un noeud PARENT :
* d'abord:
* 'PARENT' => 'parent', // Consider this sub array
* puis:
* "PARENT.LEAF" => 'leaf', // extract this data in the line
* Note : Xmljobs iterates the PARENT with RecursiveIteratorIterator::LEAVES_ONLY
* intermediate nodes are therefore ignored
* example : nodes : <EXPLOITANT><SOCIETE><ID_SOCIETE /><NOM_SOCIETE /></SOCIETE></EXPLOITANT>
* how to extract leaves :
* 'EXPLOITANT' => 'exploitant', // Consider this sub array
* 'EXPLOITANT.ID_SOCIETE' => 'id_societe',
* 'EXPLOITANT.NOM_SOCIETE' => 'nom_societe',
*/
protected $takeColumns = [
'NO_ART' => 'id',
// primary key on model
// this wil not return anything cf doc above
'ID_SOCIETE' => 'id_societe',
'NOM_SOCIETE' => 'nom_societe',
'PROD_SAISON' => 'prod_saison',
'NOM' => 'nom',
'NUMERO' => 'numero',
'TAILLE_REF' => 'taille_ref',
// $poidsRef censé être dans INCO_COMPO (et généralement 100g)
'ALLEGATIONS' => 'allegations',
'CONSEIL_PREPA' => 'conseil_prepa',
'ASTUCES' => 'astuces',
'DESCRIPTIF' => 'descriptif',
// $descriptif
'ARG_VENTE' => 'arg_vente',
'NB_PORTION' => 'nb_portion',
'TYP_PORTION' => 'typ_portion',
'PDS_MOY_THEO' => 'pds_moy_theo',
'LIB_CONSO' => 'lib_conso',
'LST_ING' => 'lst_ing',
// $ingredients
// list alergene
'LST_ALLERGENE' => 'lst_allergene',
// Consider this sub array
'LST_ALLERGENE.LIB_ALLERGENE' => 'lib_allergene',
// Allegations
'ALLEGAT_SANTE' => 'allegat_sante',
'ALLEGAT_NUTRIT' => 'allegat_nutrit',
'ALLEGAT_AUTRE' => 'allegat_autre',
'INCO_COMPO' => 'inco_compo',
// Consider this sub array
'INCO_COMPO.NOM' => 'nom',
'INCO_COMPO.TAILLE_REF' => 'taille_ref',
'INCO_COMPO.VAL_ENERG_KJ_NUT' => 'val_energ_kj_nut',
'INCO_COMPO.VAL_ENERG_KJ_R' => 'val_energ_kj_r',
// _R apports de la taille_ref
'INCO_COMPO.VAL_ENERG_KCAL_R' => 'val_energ_kcal_r',
'INCO_COMPO.VAL_ENERG_KCAL_NUT' => 'val_energ_kcal_nut',
'INCO_COMPO.MAT_GRASS_R' => 'mat_grass_r',
'INCO_COMPO.MAT_GRASS_NUT' => 'mat_grass_nut',
'INCO_COMPO.AGS_R' => 'ags_r',
'INCO_COMPO.AGS_NUT' => 'ags_nut',
'INCO_COMPO.GLUCIDES_R' => 'glucides_r',
'INCO_COMPO.GLUCIDES_NUT' => 'glucides_nut',
'INCO_COMPO.SUCRE_NUT' => 'sucre_nut',
'INCO_COMPO.SUCRE_R' => 'sucre_r',
'INCO_COMPO.FIB_ALIM_NUT' => 'fib_alim_nut',
'INCO_COMPO.FIB_ALIM_R' => 'fib_alim_r',
'INCO_COMPO.PROTEINE_R' => 'proteine_r',
'INCO_COMPO.PROTEINE_NUT' => 'proteine_nut',
'INCO_COMPO.SEL_R' => 'sel_r',
'INCO_COMPO.SEL_NUT' => 'sel_nut',
'INCO_COMPO.SODIUM_R' => 'sodium_r',
'INCO_COMPO.ENER_E14_R' => 'ener_e14_r',
'INCO_COMPO.FRUITS_R' => 'fruits_r',
'INCO_COMPO.FRUITS_COQUE_SECH_R' => 'fruits_coque_sech_r',
'INCO_COMPO.POURCENT_APPORT_REF_E14_R' => 'pourcent_apport_ref_e14_r',
// POURCENT_*_P apports journaliers par portion
'INCO_COMPO.ENER_KJO_R' => 'ener_kjo_r',
'INCO_COMPO.POURCENT_APPORT_REF_KJO_R' => 'pourcent_apport_ref_kjo_r',
'INCO_COMPO.POURCENT_APPORT_REF_FAT_R' => 'pourcent_apport_ref_fat_r',
'INCO_COMPO.FATSAT_R' => 'fatsat_r',
'INCO_COMPO.POURCENT_APPORT_REF_FATSAT_R' => 'pourcent_apport_ref_fatsat_r',
'INCO_COMPO.CHOVAL_R' => 'choval_r',
'INCO_COMPO.POURCENT_APPORT_REF_CHOVAL_R' => 'pourcent_apport_ref_choval_r',
'INCO_COMPO.SUGAR_R' => 'sugar_r',
'INCO_COMPO.POURCENT_APPORT_REF_SUGAR_R' => 'pourcent_apport_ref_sugar_r',
'INCO_COMPO.FIBTG_R' => 'fibtg_r',
'INCO_COMPO.POURCENT_APPORT_REF_FIBTG_R' => 'pourcent_apport_ref_fibtg_r',
'INCO_COMPO.PRO_R' => 'pro_r',
'INCO_COMPO.POURCENT_APPORT_REF_PRO_R' => 'pourcent_apport_ref_pro_r',
'INCO_COMPO.SALTEQ_R' => 'salteq_r',
'INCO_COMPO.POURCENT_APPORT_REF_SALTEQ_R' => 'pourcent_apport_ref_salteq_r',
'INCO_COMPO.APPORT_REF' => 'apport_ref',
'INCO_COMPO.TAILLE_PORT' => 'taille_port',
// $poidsPortion
'INCO_COMPO.VAL_ENERG_KJ_P' => 'val_energ_kj_p',
// _P apports par portion
'INCO_COMPO.VAL_ENERG_KCAL_P' => 'val_energ_kcal_p',
'INCO_COMPO.MAT_GRASS_P' => 'mat_grass_p',
'INCO_COMPO.AGS_P' => 'ags_p',
'INCO_COMPO.GLUCIDES_P' => 'glucides_p',
'INCO_COMPO.SUCRE_P' => 'sucre_p',
'INCO_COMPO.FIB_ALIM_P' => 'fib_alim_p',
'INCO_COMPO.PROTEINE_P' => 'proteine_p',
'INCO_COMPO.SODIUM_P' => 'sodium_p',
'INCO_COMPO.FRUITS_P' => 'fruits_p',
'INCO_COMPO.SEL_P' => 'sel_p',
'INCO_COMPO.FRUITS_COQUE_SECH_P' => 'fruits_coque_sech_p',
'INCO_COMPO.ENER_E14_P' => 'ener_e14_p',
'INCO_COMPO.POURCENT_APPORT_REF_E14_P' => 'pourcent_apport_ref_e14_p',
'INCO_COMPO.ENER_KJO_P' => 'ener_kjo_p',
'INCO_COMPO.POURCENT_APPORT_REF_KJO_P' => 'pourcent_apport_ref_kjo_p',
'INCO_COMPO.FAT_P' => 'fat_p',
'INCO_COMPO.POURCENT_APPORT_REF_FAT_P' => 'pourcent_apport_ref_fat_p',
'INCO_COMPO.FATSAT_P' => 'fatsat_p',
'INCO_COMPO.POURCENT_APPORT_REF_FATSAT_P' => 'pourcent_apport_ref_fatsat_p',
'INCO_COMPO.CHOVAL_P' => 'CHOVAL_P',
'INCO_COMPO.POURCENT_APPORT_REF_CHOVAL_P' => 'pourcent_apport_ref_choval_p',
'INCO_COMPO.SUGAR_P' => 'SUGAR_P',
'INCO_COMPO.POURCENT_APPORT_REF_SUGAR_P' => 'pourcent_apport_ref_sugar_p',
'INCO_COMPO.FIBTG_P' => 'fibtg_p',
'INCO_COMPO.POURCENT_APPORT_REF_FIBTG_P' => 'pourcent_apport_ref_fibtg_p',
'INCO_COMPO.PRO_P' => 'pro_p',
'INCO_COMPO.POURCENT_APPORT_REF_PRO_P' => 'pourcent_apport_ref_pro_p',
'INCO_COMPO.SALTEQ_P' => 'salteq_p',
'INCO_COMPO.POURCENT_APPORT_REF_SALTEQ_P' => 'pourcent_apport_ref_salteq_p',
'INCO_COMPO.APPORT_PORT' => 'apport_port',
'INCO_COMPO.PART_P' => 'part_p',
'INCO_COMPO.PART_G' => 'part_g',
'INCO_COMPO.PART_L' => 'part_l',
'INCO_COMPO.P_SUR_L' => 'p_sur_l',
'INCO_COMPO.POURCENT_AGS' => 'pourcent_ags',
'INCO_COMPO.POURCENT_AGI' => 'pourcent_agi',
'INCO_COMPO.POURCENT_SS' => 'pourcent_ss',
'INCO_COMPO.POURCENT_AMIDON' => 'pourcent_amidon',
'INCO_COMPO.COMPOSANTE_N' => 'composante_n',
'INCO_COMPO.COMPOSANTE_P' => 'composante_p',
'INCO_COMPO.POURCENT_FRUITS' => 'pourcent_fruits',
'INCO_COMPO.SCORE_NUTRI' => 'score_nutri',
// du coup nutriscore ?
'INCO_COMPO.CLASSEMENT' => 'classement',
// $nutriscore mais pas censé être dans INCO_COMPO
'INCO_COMPO.MAT_GRASS_R_PREC' => 'mat_grass_r_prec',
'INCO_COMPO.AGS_R_PREC' => 'ags_r_prec',
'INCO_COMPO.GLUCIDES_R_PREC' => 'glucides_r_prec',
'INCO_COMPO.SUCRE_R_PREC' => 'sucre_r_prec',
'INCO_COMPO.FIB_ALIM_R_PREC' => 'fib_alim_r_prec',
'INCO_COMPO.PROTEINE_R_PREC' => 'proteine_r_prec',
'INCO_COMPO.SEL_R_PREC' => 'sel_r_prec',
'INCO_COMPO.SODIUM_R_PREC' => 'sodium_r_prec',
'INCO_COMPO.FRUITS_R_PREC' => 'fruits_r_prec',
'INCO_COMPO.FRUITS_COQUE_SECH_R_PREC' => 'fruits_coque_sech_r_prec',
];
protected $nullableFields = [
'taille_ref',
'conseil_prepa',
'typ_portion',
'nb_portion',
'descriptif',
'prod_saison',
'allegations',
'astuces', 'arg_vente',
'pds_moy_theo',
'lib_conso', 'lst_ing', 'lst_allergene',
'allegat_sante', 'allegat_nutrit', 'allegat_autre',
'inco_compo',
'inco_compo.nom',
'inco_compo.numero',
'inco_compo.taille',
'inco_compo.taille_ref',
'inco_compo.val_energ_kj_nut',
'inco_compo.val_energ_kj_r',
'inco_compo.val_energ_kcal_r',
'inco_compo.val_energ_kcal_nut',
'inco_compo.mat_grass_r',
'inco_compo.mat_grass_nut',
'inco_compo.ags_r',
'inco_compo.ags_nut',
'inco_compo.glucides_r',
'inco_compo.glucides_nut',
'inco_compo.sucre_nut',
'inco_compo.sucre_r',
'inco_compo.fib_alim_nut',
'inco_compo.fib_alim_r',
'inco_compo.proteine_r',
'inco_compo.proteine_nut',
'inco_compo.sel_r',
'inco_compo.sel_nut',
'inco_compo.sodium_r',
'inco_compo.ener_e14_r',
'inco_compo.fruits_r',
'inco_compo.fruits_coque_sech_r',
'inco_compo.pourcent_apport_ref_e14_r',
'inco_compo.ener_kjo_r',
'inco_compo.pourcent_apport_ref_kjo_r',
'inco_compo.pourcent_apport_ref_fat_r',
'inco_compo.fatsat_r',
'inco_compo.pourcent_apport_ref_fatsat_r',
'inco_compo.choval_r',
'inco_compo.pourcent_apport_ref_choval_r',
'inco_compo.sugar_r',
'inco_compo.pourcent_apport_ref_sugar_r',
'inco_compo.fibtg_r',
'inco_compo.pourcent_apport_ref_fibtg_r',
'inco_compo.pro_r',
'inco_compo.pourcent_apport_ref_pro_r',
'inco_compo.salteq_r',
'inco_compo.pourcent_apport_ref_salteq_r',
'inco_compo.apport_ref',
'inco_compo.taille_port',
'inco_compo.val_energ_kj_p',
'inco_compo.val_energ_kcal_p',
'inco_compo.mat_grass_p',
'inco_compo.ags_p',
'inco_compo.glucides_p',
'inco_compo.sucre_p',
'inco_compo.fib_alim_p',
'inco_compo.proteine_p',
'inco_compo.sodium_p',
'inco_compo.fruits_p',
'inco_compo.sel_p',
'inco_compo.fruits_coque_sech_p',
'inco_compo.ener_e14_p',
'inco_compo.pourcent_apport_ref_e14_p',
'inco_compo.ener_kjo_p',
'inco_compo.pourcent_apport_ref_kjo_p',
'inco_compo.fat_p',
'inco_compo.pourcent_apport_ref_fat_p',
'inco_compo.fatsat_p',
'inco_compo.pourcent_apport_ref_fatsat_p',
'inco_compo.choval_p',
'inco_compo.pourcent_apport_ref_choval_p',
'inco_compo.sugar_p',
'inco_compo.pourcent_apport_ref_sugar_p',
'inco_compo.fibtg_p',
'inco_compo.pourcent_apport_ref_fibtg_p',
'inco_compo.pro_p',
'inco_compo.pourcent_apport_ref_pro_p',
'inco_compo.salteq_p',
'inco_compo.pourcent_apport_ref_salteq_p',
'inco_compo.apport_port',
'inco_compo.part_p',
'inco_compo.part_g',
'inco_compo.part_l',
'inco_compo.p_sur_l',
'inco_compo.pourcent_ags',
'inco_compo.pourcent_agi',
'inco_compo.pourcent_ss',
'inco_compo.pourcent_amidon',
'inco_compo.composante_n',
'inco_compo.composante_p',
'inco_compo.pourcent_fruits',
'inco_compo.score_nutri',
'inco_compo.classement',
'inco_compo.mat_grass_r_prec',
'inco_compo.ags_r_prec',
'inco_compo.glucides_r_prec',
'inco_compo.sucre_r_prec',
'inco_compo.fib_alim_r_prec',
'inco_compo.proteine_r_prec',
'inco_compo.sel_r_prec',
'inco_compo.sodium_r_prec',
'inco_compo.fruits_r_prec',
'inco_compo.fruits_coque_sech_r_prec'
];
protected $uniqueKeyField = ['id'];
protected $mergeColumns = [
'allegations' => [
'allegat_sante',
'allegat_nutrit',
'allegat_autre'
],
'nutritional_values' => [
'taille_ref',
'val_energ_kj_nut',
'val_energ_kj_r',
'val_energ_kcal_r',
'val_energ_kcal_nut',
'mat_grass_r',
'mat_grass_nut',
'ags_r',
'ags_nut',
'glucides_r',
'glucides_nut',
'sucre_nut',
'sucre_r',
'fib_alim_nut',
'fib_alim_r',
'proteine_r',
'proteine_nut',
'sel_r',
'sel_nut',
'sodium_r',
'ener_e14_r',
'fruits_r',
'fruits_coque_sech_r',
'pourcent_apport_ref_e14_r',
'ener_kjo_r',
'pourcent_apport_ref_kjo_r',
'pourcent_apport_ref_fat_r',
'fatsat_r',
'pourcent_apport_ref_fatsat_r',
'choval_r',
'pourcent_apport_ref_choval_r',
'sugar_r',
'pourcent_apport_ref_sugar_r',
'fibtg_r',
'pourcent_apport_ref_fibtg_r',
'pro_r',
'pourcent_apport_ref_pro_r',
'salteq_r',
'pourcent_apport_ref_salteq_r',
'apport_ref',
'taille_port',
'val_energ_kj_p',
'val_energ_kcal_p',
'mat_grass_p',
'ags_p',
'glucides_p',
'sucre_p',
'fib_alim_p',
'proteine_p',
'sodium_p',
'fruits_p',
'sel_p',
'fruits_coque_sech_p',
'ener_e14_p',
'pourcent_apport_ref_e14_p',
'ener_kjo_p',
'pourcent_apport_ref_kjo_p',
'fat_p',
'pourcent_apport_ref_fat_p',
'fatsat_p',
'pourcent_apport_ref_fatsat_p',
'choval_p',
'pourcent_apport_ref_choval_p',
'sugar_p',
'pourcent_apport_ref_sugar_p',
'fibtg_p',
'pourcent_apport_ref_fibtg_p',
'pro_p',
'pourcent_apport_ref_pro_p',
'salteq_p',
'pourcent_apport_ref_salteq_p',
'apport_port',
'part_p',
'part_g',
'part_l',
'p_sur_l',
'pourcent_ags',
'pourcent_agi',
'pourcent_ss',
'pourcent_amidon',
'composante_n',
'composante_p',
'pourcent_fruits',
'score_nutri',
'classement',
'mat_grass_r_prec',
'ags_r_prec',
'glucides_r_prec',
'sucre_r_prec',
'fib_alim_r_prec',
'proteine_r_prec',
'sel_r_prec',
'sodium_r_prec',
'fruits_r_prec',
'fruits_coque_sech_r_prec',
]
];
public function handle()
{
$this->parseData('INCO', XmlInco::class, function (SimpleXMLElement $xmlData, array &$line) {
// merge columns
foreach ($this->mergeColumns as $key => $values) {
$line[$key] = [];
// merge columns and remove merged columns from line
array_map(function ($kValue) use (&$line, $key) {
if (array_key_exists($kValue, $line)) {
$line[$key][$kValue] = $line[$kValue];
unset($line[$kValue]);
}
}, $values);
if ($key == 'allegations') {
$line[$key] = implode(',', array_filter($line[$key]));
$line[$key] = strlen($line[$key]) ? $line[$key] : null;
}
// json column cast into array in model => no need for encode
// if ($key == 'nutritional_values') {
// $line[$key] = json_encode($line[$key], \JSON_FORCE_OBJECT);
// }
}
// Boolean cast prod_saison
$line['prod_saison'] = isset($line['prod_saison']) ?
(strtolower($line['prod_saison']) == 'non' ? false : true) : false;
$arImgPaths = $this->parseImage($xmlData);
$line['picture'] = $arImgPaths;
});
}
private function parseImage(SimpleXMLElement $xmlData)
{
$list_media = $xmlData->INCO->MEDIA_VISUEL_EAI->MEDIA_VISUEL_EAI;
$arImgPaths = array();
$index = 1;
foreach ($list_media as $media) {
$image = $media->img;
$imageData = trim((string)$image);
if (strlen($imageData)) {
$imageData = base64_decode($imageData);
$imgName = strval($xmlData->INCO->INCO_COMPO->TBL_INCO_COMPO->ID_INCO);
if (empty($imgName)) {
$imgName = strval($xmlData->INCO->NO_ART);
}
$imgName = $imgName . "_" . $index;
$imgNamePath = sprintf('%s/%s', rtrim($this->imagesPath, '/'), $imgName);
$disk = $this->getDisk();
$info = getimagesizefromstring($imageData);
if ($info !== false) {
$mime = $info['mime'];
switch ($mime) {
case 'image/jpeg':
$imgExtension = 'jpg';
break;
case 'image/png':
$imgExtension = 'png';
break;
case 'image/gif':
$imgExtension = 'gif';
break;
default:
throw new AbortXmlImportException(sprintf('Unknown image type %s', $imgName));
}
$imgNamePath = sprintf('%s.%s', $imgNamePath, $imgExtension);
if (!$disk->put($imgNamePath, $imageData)) {
throw new AbortXmlImportException(sprintf('The image %s could not be saved', $imgNamePath));
}
$arImgPaths[$index] = sprintf('%s/%s', $this->disk, $imgNamePath);
$index++;
} else {
// probably not an image could be a PDF, PPT, AI anything is possible
}//end if
}//end if
}//end foreach
return $arImgPaths;
}
/**
* Recursive extract to array
* introduce sort of Hook to transform
* <TYP_PORTION>
* <code><![CDATA[2]]></code>
* <libelle><![CDATA[Approximatif]]></libelle>
* </TYP_PORTION>
* extracted as "TYP_PORTION" => array:1 [
* 0 => array:2 [
* "code" => "2"
* "libelle" => "Approximatif"
* ]
* ]
* into this
* <TYP_PORTION><![CDATA[Approximatif]]></TYP_PORTION>
* extracted as "TYP_PORTION" => "Approximatif"
*
*
* @param \SimpleXMLElement|false $sxe
* @return array
*/
protected function extract($sxe = null): array
{
if (!$sxe instanceof SimpleXMLElement) {
return array();
}
$extract = array();
foreach ($sxe->children() as $key => $value) {
if ($value->count()) {
$extraction = $this->extract($value);
if (
count($extraction)
&& array_key_exists("code", $extraction)
&& array_key_exists("libelle", $extraction)
) {
$val = strval($extraction['libelle']);
$extract[$key] = strlen($val) ? $val : null;
continue;
}
$extract[$key][] = $extraction;
// $this->extract($value);
continue;
}
$value = strval($value);
if (array_key_exists($key, $extract) and is_array($extract[$key])) {
$extract[$key][] = strlen($value) ? $value : null;
} else {
$extract[$key] = strlen($value) ? $value : null;
}
}//end foreach
return $extract;
}
}