'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 : * 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', ]; /** * The columns allowed to be null * * @var array */ 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' ]; /** * Unique keys for updating rows * * @var array */ protected $uniqueKeyField = ['id']; /** * Columns to merge in * * @var array */ 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', ] ]; /** * Execute the job. * * @return void */ 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; } } // Boolean cast prod_saison. $line['prod_saison'] = isset($line['prod_saison']) ? (strtolower($line['prod_saison']) == 'non' ? false : true) : false; $arImgPaths = $this->parseImage($xmlData); $line['pictures'] = $arImgPaths; }); } /** * Extract Image form XML file * * @param \SimpleXMLElement $xmlData * @return array * @throws AbortXmlImportException When media tag does not contain an image. */ private function parseImage(\SimpleXMLElement $xmlData) { /** @var \Illuminate\Support\Collection<\SimpleXMLElement> */ $list_media = collect($xmlData->INCO->MEDIA_VISUEL_EAI->MEDIA_VISUEL_EAI); $arImgPaths = \collect(); $i = -1; $list_media->each(function ($media) use ($xmlData, $arImgPaths, &$i) { $i++; /** @var \SimpleXMLElement|null */ $image = $media->img; $imageData = trim((string)$image); if (!strlen($imageData)) { return; } $imageData = \strval(base64_decode($imageData)); $imgName = strval($xmlData->INCO->INCO_COMPO->TBL_INCO_COMPO->ID_INCO ?? $xmlData->INCO->NO_ART); $imgNamePath = "{$imgName}_" . \uniqid(); $info = getimagesizefromstring($imageData); if ($info === false) { Log::debug("Skipping file {$imgNamePath} on index {$i} as could not determine picture info."); return; } $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 = FileStorageHelper::sanitizeFileName("{$imgNamePath}-{$i}.{$imgExtension}"); if (!($file = tempnam(sys_get_temp_dir(), $imgNamePath))) { throw new \RuntimeException('Could not initiate a php temp file'); } if (!File::put($file, $imageData)) { throw new \RuntimeException('Could not write to the php temp file'); } $arImgPaths->push(FileStorageHelper::storeFile( new XmlInco(), new \SplFileInfo($file), true, $imgNamePath, true )); }); return $arImgPaths->all(); } /** * Recursive extract to array * introduce sort of Hook to transform * * * * * extracted as "TYP_PORTION" => array:1 [ * 0 => array:2 [ * "code" => "2" * "libelle" => "Approximatif" * ] * ] * into this * * 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; 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; } }