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;
|
|
}
|