false, 'arg' => false, 'sha' => false, 'type' => $type, 'pays' => $pays, 'sync' => true ); // Le peuplement dépend du type : // - type = zone ou country : on charge l'ensemble des régions du monde ou l'ensemble des pays // - type = subdivision ou infrasubdivision : il faut préciser le pays (code ISO alpha2) pour lequel on charge toutes les subdivisions include_spip('inc/territoires_services'); include_spip('inc/territoires_utils'); if (type_pays_est_valide($type, $pays)) { $timestamp['debut'] = microtime(true); $erreur = true; $type_identique = false; // Lecture de la configuration statique du type de territoire include_spip('inc/config'); $configuration = lire_config("territoires/${type}"); // Identification de la meta et de la variable de consigne $meta = 'territoires_peuplement'; $consigne = consigne_identifier($type, $pays); // On récupère tous les index fournis par la collection et pas uniquement celui des territoires concernés. // Ainsi, les autres index éventuels restent disponibles. $collection = territoires_acquerir($type, $pays); $timestamp['acquisition'] = microtime(true); if (!empty($collection[$configuration['champs']['index']])) { // On extrait que l'index correspondant au type demandé $territoires = $collection[$configuration['champs']['index']]; // Si le type de territoire est déjà chargé il possède un sha. Si le sha des data récupérées de Nomenclatures // possèdent le même sha alors on ne fait aucun traitement et on indique que la configuration n'a pas // changée. Dans ce cas, aucun traitement n'a lieu. $sha_type = sha1(json_encode($territoires)); if ( sha_est_identique($sha_type, $meta, $consigne) and empty($options['force']) ) { $type_identique = true; } else { // Le sha a changé : il est donc licite de recharger les territoires. // -- on préserve les éditions manuelles et les liens pour les réinjecter ensuite lors du // rechargement $sauvegardes = territoires_preserver($type, $pays); $timestamp['preservation'] = microtime(true); // -- on vide les territoires avant de les remettre (inutile de gérer les erreurs // car l'insertion les détectera). // On gère aussi les infra subdivisions qui doivent être vidées au préalable si on vide // les subdivisions parents. if ( ($type === 'subdivision') and territoire_est_peuple('infrasubdivision', $pays) ) { territoire_depeupler('infrasubdivision', $pays); } territoire_depeupler($type, $pays); $timestamp['vidage'] = microtime(true); // -- on insère chaque territoire comme un objet include_spip('action/editer_objet'); $erreur_insertion = false; $ids = array(); $extras = array(); $meta_extras = array(); foreach ($territoires as $_territoire) { // On initialise le territoire avec les noms de champs de la table spip_territoires $territoire = enregistrement_initialiser($_territoire, $type, $pays); // Si le code iso_continent est rempli c'est qu'on vient de charger les pays. Comme le code // du continent est le code alpha2 on le remplace par le code M49 pour être homogène. // -- la collection pays contient pour cela un bloc 'continents'. if (!empty($territoire['iso_continent'])) { $territoire['iso_continent'] = $collection['continents'][$territoire['iso_continent']]['code_num']; } // Intégrer les éventuelles modifications sauvegardées if (isset($sauvegardes['editions'][$territoire['iso_territoire']])) { // -- descriptif en fusionnant les traductions (priorité aux sauvegardes) // -- remise à 'oui' de l'indicateur d'édition $territoire['descriptif'] = traduction_fusionner( $sauvegardes['editions'][$territoire['iso_territoire']]['descriptif'], $territoire['descriptif'] ); $territoire['edite'] = 'oui'; } if ($id = sql_insertq('spip_territoires', $territoire)) { // On consigne le couple (iso, id) pour rétablir les liens si besoin $ids[$territoire['iso_territoire']] = $id; // Si demandé et que la configuration le prévoit préparer le tableau des extras inclus dans // le bloc principal des territoires if (!empty($options['extras'])) { $source = $_territoire; $source['iso_territoire'] = $territoire['iso_territoire']; $extras = array_merge( $extras, extra_compiler( 'interne', $options['extras'], $source, $configuration, $type, $pays, $meta_extras ) ); } } else { $erreur_insertion = true; break; } } $timestamp['insertion'] = microtime(true); if (!$erreur_insertion) { // Traitements des extras if (!empty($options['extras'])) { // Si la configuration le prévoit préparer le tableau des extras inclus dans un bloc annexe if (!empty($configuration['extras'])) { $extras = array_merge( $extras, extra_compiler( 'externe', $options['extras'], $collection, $configuration, $type, $pays, $meta_extras ) ); } // Ajouter tous les extras compilés pour le type de territoire. if ($extras) { sql_insertq_multi('spip_territoires_extras', $extras); } $timestamp['extras'] = microtime(true); } // On rétablit les liens vers les territoires et les logos // -- les liens avec les autres objets $config_lien = array( 'table' => 'spip_territoires_liens', 'id_table' => 'id_territoire' ); liens_retablir('liens', $sauvegardes, $ids, $config_lien); // -- les liens avec les logos $config_lien = array( 'table' => 'spip_documents_liens', 'id_table' => 'id_objet' ); liens_retablir('logos', $sauvegardes, $ids, $config_lien); $timestamp['retablissement'] = microtime(true); // Permettre à d'autres plugins de compléter le peuplement. // -- par exemple le plugin Contours rétablit les liens vers les contours GIS (spip_liens_gis), // les objets GIS étant conservés si ils existent déjà. $flux = array( 'args' => array( 'type' => $type, 'pays' => $pays, 'sauvegardes' => $sauvegardes, 'ids_crees' => $ids, ), 'data' => array() ); pipeline('post_peupler_territoire', $flux); // On stocke les informations de chargement dans une meta. $contenu = array( 'sha' => $sha_type, 'nbr' => count($territoires), 'maj' => date('Y-m-d H:i:s'), 'lic' => isset($collection['credits']) ? $collection['credits'] : array(), 'ext' => $meta_extras, ); ecrire_config("${meta}/${consigne}", $contenu); $timestamp['fin'] = microtime(true); $erreur = false; } // Log du traitement pour debug $duree = $timestamp['fin'] - $timestamp['debut']; spip_log("Les territoires (Type '${type}' - Pays '${pays}') ont été chargées en ${duree} s", 'territoires' . _LOG_INFO_IMPORTANTE); if ( defined('_LOG_FILTRE_GRAVITE') and (_LOG_FILTRE_GRAVITE >= _LOG_DEBUG) ) { $timestamp_debut = $timestamp['debut']; foreach ($timestamp as $_periode => $_timestamp) { if ($_periode !== 'debut') { $timestamp_fin = $_timestamp; $duree = ($timestamp_fin - $timestamp_debut) * 1000; $timestamp_debut = $timestamp_fin; spip_log("Période ${_periode}: ${duree} ms", 'territoires' . _LOG_DEBUG); } } } } } else { spip_log("Aucun territoire pour (Type '${type}' - Pays '${pays}') retourné par Nomenclatures", 'territoires' . _LOG_ERREUR); } // Si le territoire est en erreur, on stocke le cas d'erreur. if ($erreur) { if ($type_identique) { $retour['sha'] = true; spip_log("Les territoires de (Type '${type}' - Pays '${pays}') sont inchangés", 'territoires' . _LOG_AVERTISSEMENT); } else { $retour['ok'] = false; } } else { $retour['ok'] = true; } } else { $retour['arg'] = true; spip_log("Le couple (Type '${type}' - Pays '${pays}') est invalide", 'territoires' . _LOG_ERREUR); } return $retour; } /** * Appelle la fonction de peuplement de territoires en asynchrone. * * @api * * @param string $type Type de territoires. Prends les valeurs `zone`, `country`, `subdivision` ou `infrasubdivision`. * @param string $pays Code ISO 3166-1 alpha2 du pays si le type est `subdivision` ou `infrasubdivision` sinon une chaine vide. * @param array $options Tableau des options de peuplement: * - `force` : si `true` force le repeuplement même si le sha est identique (`false` par défaut). * - `extras`: tableau des types d'extras à peupler soit `code` pour les codes alternatifs * et `info` pour le caractéristiques (table spip_territoires_extras) * * @return array Tableau retour de la fonction permettant de connaitre le résultat du traitement (utile pour l'affichage * du message dans le formulaire de peuplement). */ function territoire_peupler_asynchrone($type, $pays, $options = array()) { // On initialise le retour à une ok ce qui est le cas le plus fréquent car on ne fait que créer le job. $retour = array( 'ok' => true, 'arg' => false, 'sha' => false, 'type' => $type, 'pays' => $pays, 'sync' => false ); if (_TERRITOIRE_ASYNCHRONE_PAR_JOB) { // Lancement du peuplement dans un job à déclenchement immédiat et de priorité maximale pour éviter d'attendre. include_spip('inc/utils'); $arguments = array( $type, $pays, $options ); $retour['job'] = job_queue_add( 'territoire_peupler', 'Peuplement de territoires', $arguments, 'inc/territoire', true ); if (!$retour['job']) { $retour['ok'] = false; } } else { // Construction de la chaine des arguments passés à l'action. // -- type et pays sont toujours fournis même si le pays est la chaine vide. $arguments = "${type}:${pays}"; // -- ajout des éventuelles options : on passe les options par leur identifiant if (!empty($options['force'])) { $arguments .= ":force"; } if (!empty($options['extras'])) { $arguments .= ':' . implode(':', $options['extras']); } // Génération de l'URL qui lancera le peuplement en asynchrone. include_spip('inc/actions'); $url = generer_action_auteur('peupler_territoires', $arguments); // Lancement du peuplement en asynchrone. include_spip ('inc/queue'); $retour['ok'] = queue_lancer_url_http_async($url); } return $retour; } /** * Supprime de la base soit les régions du monde, soit les pays ou soit les subdivisions d'un pays. * * @api * * @param string $type Type de territoires. Prends les valeurs `zone`, `country`, `subdivision` ou `infrasubdivision`. * @param string $pays Code ISO 3166-1 alpha2 du pays si le type est `subdivision` ou `infrasubdivision` sinon une chaine vide. * @param array $options Tableau des options de dépeuplement: * - `force` : si `true` force le vidage même si la meta n'est pas présente (cas d'erreur * sur timeout par exemple). La valeur par défaut est `false`. * * @return array Tableau retour de la fonction permettant de connaitre le résultat du traitement (utile pour l'affichage * du message dans le formulaire de peuplement). */ function territoire_depeupler($type, $pays = '', $options = array()) { // On initialise le retour à une erreur nok $retour = array( 'ok' => false, 'arg' => false, 'sha' => false, 'type' => $type, 'pays' => $pays, 'sync' => true ); // Le vidage dépend du type : // - type = zone ou country : on vide l'ensemble des régions du monde ou l'ensemble des pays // - type = subdivision ou infrasubdivision : il faut préciser le pays (code ISO alpha2) pour lequel on vide toutes les subdivisions include_spip('inc/territoires_services'); include_spip('inc/territoires_utils'); if (type_pays_est_valide($type, $pays)) { // Inutile de vider une table vide sauf si l'option de forçage est activée. if ( territoire_est_peuple($type, $pays) or !empty($options['force']) ) { // Identification de la variable de consigne $consigne = consigne_identifier($type, $pays); // Avant de vider la table on réserve la liste des id de territoire qui seront supprimés // de façon à vider ensuite les liens éventuels y compris ceux des logos. $from = 'spip_territoires'; $where = array( 'type=' . sql_quote($type), ); if (type_est_subdivision($type)) { $where[] = 'iso_pays=' . sql_quote($pays); } if ($ids = sql_allfetsel('id_territoire', $from, $where)) { $ids = array_column($ids, 'id_territoire'); $sql_ok = sql_delete($from, $where); if ($sql_ok !== false) { // Vider les extras si besoin $sql_ok = sql_delete('spip_territoires_extras', $where); if ($sql_ok !== false) { // Vider les liens éventuels avec les logos (on gère pas d'erreur) $where_logo = array( sql_in('id_objet', $ids), 'objet=' . sql_quote('territoire') ); sql_delete('spip_documents_liens', $where_logo); // Vider les liens éventuels avec les autres objets (on gère pas d'erreur) $where_lien = array( sql_in('id_territoire', $ids), ); sql_delete('spip_territoires_liens', $where_lien); // Permettre à d'autres plugins de compléter le dépeuplement. // -- par exemple le plugin Contours supprime les liens vers les contours GIS (spip_liens_gis), // mais pas les objets GIS. $flux = array( 'args' => array( 'type' => $type, 'pays' => $pays, 'ids_territoire' => $ids, ), 'data' => array() ); pipeline('post_depeupler_territoire', $flux); // Supprimer la meta propre au pays même si le vidage des liens est en erreur. include_spip('inc/config'); effacer_config("territoires_peuplement/${consigne}"); } // Enregistrer le succès ou pas du déchargement de la table if ($sql_ok !== false) { // Succès complet $retour['ok'] = true; spip_log("Les territoires (Type '${type}' - Pays '${pays}') ont été vidés avec succès ainsi que les extras", 'territoires' . _LOG_DEBUG); } else { spip_log("Les territoires (Type '${type}' - Pays '${pays}') ont été vidés avec succès mais erreur lors du vidage des extras", 'territoires' . _LOG_ERREUR); } } else { spip_log("Erreur de vidage des territoires (Type '${type}' - Pays '${pays}')", 'territoires' . _LOG_ERREUR); } } } else { $retour['sha'] = true; spip_log("Aucun territoire (Type '${type}' - Pays '${pays}') à vider", 'territoires' . _LOG_AVERTISSEMENT); } } else { $retour['arg'] = true; spip_log("Le couple (Type '${type}' - Pays '${pays}') est invalide", 'territoires' . _LOG_ERREUR); } return $retour; } /** * Teste si un type de territoire est chargé en base. * La fonction lit la meta de chargement et non la table `spip_territoires`. * * @api * * @param string $type Type de territoires. Prends les valeurs `zone`, `country`, `subdivision` ou `infrasubdivision`. * @param array|string $pays Code ISO 3166-1 alpha2 du pays si le type est `subdivision` ou `infrasubdivision` sinon une chaine vide. * * @return bool `true` si le territoire est chargé, `false` sinon. */ function territoire_est_peuple($type, $pays = '') { // Initialisation de la liste $est_peuple = false; // La liste des territoires chargés est en meta. include_spip('inc/config'); $peuplement = lire_config('territoires_peuplement', array()); if ( include_spip('inc/territoires_utils') and type_est_subdivision($type) ) { // Chaque pays chargé est un index du tableau if (isset($peuplement[$type])) { $est_peuple = array_key_exists($pays, $peuplement[$type]); } } else { $est_peuple = isset($peuplement[$type]); } return $est_peuple; } /** * Teste si les codes alternatifs ou les caractéristiques additionnelles d’un type de territoire sont chargées en base. * La fonction lit la meta de chargement et non la table `spip_territoires_extras`. * * @api * * @param string $type Type de territoires. Prends les valeurs `zone`, `country`, `subdivision` ou `infrasubdivision`. * @param string $pays Code ISO 3166-1 alpha2 du pays si le type est `subdivision` ou `infrasubdivision` sinon une chaine vide. * @param string $type_extra Type d'extra. Prends les valeurs `code` ou `info`. * * @return bool `true` si le territoire est chargé, `false` sinon. */ function territoire_extra_est_peuple($type, $pays, $type_extra) { // Initialisation de la liste $est_peuple = false; // La liste des territoires chargés est en meta. include_spip('inc/config'); $peuplement = lire_config('territoires_peuplement', array()); if ( include_spip('inc/territoires_utils') and type_est_subdivision($type) ) { // Chaque pays chargé est un index du tableau if (isset($peuplement[$type][$pays]['ext'])) { $est_peuple = in_array($type_extra, $peuplement[$type][$pays]['ext']); } } else { if (isset($peuplement[$type]['ext'])) { $est_peuple = in_array($type_extra, $peuplement[$type]['ext']); } } return $est_peuple; }