You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
523 lines
19 KiB
523 lines
19 KiB
<?php |
|
/** |
|
* API de gestion des objets territoire. |
|
* |
|
* @package SPIP\TERRITOIRES\API |
|
*/ |
|
if (!defined('_ECRIRE_INC_VERSION')) { |
|
return; |
|
} |
|
|
|
if (!defined('_TERRITOIRE_ASYNCHRONE_PAR_JOB')) { |
|
/** |
|
* Mode de peuplement asynchrone: |
|
* - `job`: utilisation de job_queue_add |
|
* - `url`: utilisation d'une action. |
|
*/ |
|
define('_TERRITOIRE_ASYNCHRONE_PAR_JOB', true); |
|
} |
|
|
|
|
|
/** |
|
* Peuple soit les régions du monde, soit les pays ou soit les subdivisions d'un pays. |
|
* La fonction utilise les données fournies par Nomenclatures. |
|
* |
|
* @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($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 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; |
|
}
|
|
|