Refactoring pour séparer les fonctions d'API et les fonctions internes.

Simplification par l'élimination de fonctions superfétatoires.
v0_spip32
Eric Lupinacci 3 years ago
parent 69613cbdf3
commit e2c8580d37

@ -12,7 +12,7 @@ if (!defined('_ECRIRE_INC_VERSION')) {
* Chargement des données : le formulaire propose les actions possibles sur les territoires,
* à savoir, charger ou vider.
*
* @uses territoire_acquerir()
* @uses territoires_acquerir()
* @uses territoire_est_peuple()
*
* @return array
@ -51,11 +51,12 @@ function formulaires_peupler_territoires_charger() {
}
// Acquérir la liste des pays dont les subdivisions sont disponibles
include_spip('inc/territoires_utils');
$options = array(
'exclure' => 'alternates,subdivisions',
'index' => 'pays'
);
$valeurs['_pays'] = territoire_acquerir('subdivision', array(), $options);
$valeurs['_pays'] = territoires_acquerir('subdivision', array(), $options);
// -- indiquer les territoires déjà chargés
foreach ($valeurs['_pays'] as $_code => $_pays) {
if (territoire_est_peuple('subdivision', $_code)) {
@ -104,7 +105,7 @@ function formulaires_peupler_territoires_verifier() {
*
* @uses territoire_peupler()
* @uses territoire_depeupler()
* @uses message_formater()
* @uses formulaires_peupler_territoires_notifier()
*
* @return array
* Tableau retourné par le formulaire contenant toujours un message de bonne exécution ou

@ -2,7 +2,7 @@
/**
* Ce fichier contient la fonction de requêtage des données du plugin Nomenclatures via son API REST.
*
* @package SPIP\TERRITOIRES\REQUETE
* @package SPIP\TERRITOIRES\API
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
@ -18,6 +18,8 @@ if (!defined('_TERRITOIRE_COEFF_MAX_DISTANT')) {
* le tableau de sortie. Le flux retourné par le service est systématiquement
* transcodé dans le charset du site avant d'être décodé.
*
* @api
*
* @uses recuperer_url()
*
* @param mixed $url_base Endpoint du serveur Nomenclatures

@ -0,0 +1,37 @@
<?php
/**
* Ce fichier contient la fonction de test d'égalité d'un sha avec celui stocké en meta.
*
* @package SPIP\TERRITOIRES\API
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Compare le sha passé en argument pour le type de territoire concerné avec le sha stocké dans la meta
* pour cette même type.
*
* @api
*
* @param string $sha SHA à comparer à celui du type de territoire.
* @param string $meta Nom de la meta de consignation
* @param string $consigne Nom de la variable de consigne fonction du type et du pays éventuellement.
*
* @return bool `true` si le sha passé en argument est identique au sha stocké pour la table choisie, `false` sinon.
*/
function inc_sha_est_identique_dist($sha, $meta, $consigne) {
$sha_identique = false;
// On récupère le sha de la table dans les metas si il existe (ie. la table a été chargée)
include_spip('inc/config');
$sha_stocke = lire_config("${meta}/${consigne}/sha", false);
if ($sha_stocke and ($sha === $sha_stocke)) {
$sha_identique = true;
}
return $sha_identique;
}

@ -12,66 +12,6 @@ if (!defined('_TERRITOIRE_URL_BASE_ISOCODE')) {
define('_TERRITOIRE_URL_BASE_ISOCODE', 'https://contrib.spip.net/http.api/ezrest');
}
$GLOBALS['territoires']['zone'] = array(
'champs' => array(
'base' => array(
'code_num' => 'iso_territoire',
'category' => 'categorie',
'parent' => 'iso_parent',
'label' => 'iso_titre',
),
'index' => 'zones',
),
);
$GLOBALS['territoires']['country'] = array(
'champs' => array(
'base' => array(
'code_alpha2' => 'iso_territoire',
'category' => 'categorie',
'code_continent' => 'iso_continent',
'label' => 'iso_titre',
),
'extras' => array(
'code' => array(
'code_alpha3' => 'code_iso3166_a3',
'code_num' => 'code_iso3166_num',
),
'info' => array(
'capital' => 'capital',
'area' => 'area',
'population' => 'population',
'tld' => 'tld',
'code_4217_3' => 'code_4217_3',
'phone_id' => 'phone_id'
),
),
'index' => 'pays',
),
);
$GLOBALS['territoires']['subdivision'] = array(
'champs' => array(
'base' => array(
'code_3166_2' => 'iso_territoire',
'type' => 'categorie',
'country' => 'iso_pays',
'parent' => 'iso_parent',
'label' => 'iso_titre',
),
'index' => 'subdivisions',
),
'extras' => array(
'code' => array(
'champs' => array(
'extra' => 'type_alter',
'valeur' => 'code_alter',
),
'index' => 'codes_alternatifs',
'cle_iso' => 'code_iso',
),
),
);
/**
* Peuple soit les régions du monde, soit les pays ou soit les subdivisions d'un pays.
@ -103,15 +43,22 @@ function territoire_peupler($type, $pays = '', $options = array()) {
// 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 : il faut préciser le pays (code ISO alpha2) pour lequel on charge toutes les subdivisions
include_spip('inc/territoires_utils');
if (type_pays_est_valide($type, $pays)) {
$erreur = true;
$type_identique = false;
$configuration = $GLOBALS['territoires'][$type];
// 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 = territoire_acquerir($type, $pays);
$collection = territoires_acquerir($type, $pays);
if (!empty($collection[$configuration['champs']['index']])) {
// On extrait que l'index correspondant au type demandé
$territoires = $collection[$configuration['champs']['index']];
@ -121,7 +68,8 @@ function territoire_peupler($type, $pays = '', $options = array()) {
// changée. Dans ce cas, aucun traitement n'a lieu.
$sha_type = sha1(json_encode($territoires));
if (
sha_est_identique($sha_type, $meta, $type, $pays)
$tester = charger_fonction('sha_est_identique', 'inc')
and $tester($sha_type, $meta, $consigne)
and empty($options['force'])
) {
$type_identique = true;
@ -129,7 +77,7 @@ function territoire_peupler($type, $pays = '', $options = array()) {
// 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 = territoire_preserver($type, $pays);
$sauvegardes = territoires_preserver($type, $pays);
// -- on vide les territoires avant de les remettre (inutile de gérer les erreurs
// car l'insertion les détectera).
@ -253,7 +201,7 @@ function territoire_peupler($type, $pays = '', $options = array()) {
'lic' => isset($collection['credits']) ? $collection['credits'] : array(),
'ext' => $meta_extras,
);
peuplement_consigner($meta, $contenu, $type, $pays);
ecrire_config("${meta}/${consigne}", $contenu);
$erreur = false;
}
spip_log("Les territoires (Type '${type}' - Pays '${pays}') ont été chargées", 'territoires' . _LOG_DEBUG);
@ -306,9 +254,13 @@ function territoire_depeupler($type, $pays = '') {
// 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 : il faut préciser le pays (code ISO alpha2) pour lequel on vide toutes les subdivisions
include_spip('inc/territoires_utils');
if (type_pays_est_valide($type, $pays)) {
// Inutile de vider une table vide
if (territoire_est_peuple($type, $pays)) {
// 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';
@ -354,7 +306,8 @@ function territoire_depeupler($type, $pays = '') {
pipeline('post_depeupler_territoire', $flux);
// Supprimer la meta propre au pays même si le vidage des liens est en erreur.
peuplement_deconsigner('territoires_peuplement', $type, $pays);
include_spip('inc/config');
effacer_config("territoires_peuplement/${consigne}");
}
// Enregistrer le succès ou pas du déchargement de la table
@ -381,146 +334,6 @@ function territoire_depeupler($type, $pays = '') {
return $retour;
}
/**
* Extrait, pour un les régions, les pays ou les subdivisions d'un pays, la liste des territoires ayant fait l'objet
* d'une modification manuelle (descriptif ou logo) et la liste associations vers ses mêmes territoires.
* Les extras ne sont pas sauvegardés car il ne sont ni modifiables ni indexés par un id mais par un code invariant.
*
* @api
*
* @param string $type Type de territoires à préserver. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays nécessaire si le type est `subdivision`.
*
* @return array
*/
function territoire_preserver($type, $pays = '') {
// Initialisation de la table et de la condition de base sur le type et éventuellement le pays.
$territoires = array();
$from = 'spip_territoires';
$where = array(
'type=' . sql_quote($type),
);
if ($type === 'subdivision') {
$where[] = 'iso_pays=' . sql_quote($pays);
}
// Extraction des liens vers les territoires du pays
$where_lien = array(
sql_in_select('id_territoire', 'id_territoire', $from, $where)
);
$territoires['liens'] = sql_allfetsel('*', 'spip_territoires_liens', $where_lien);
// Extraction des liens de logos vers les territoires du pays
$where_logo = array(
'objet=' . sql_quote('territoire'),
sql_in_select('id_objet', 'id_territoire', $from, $where)
);
$territoires['logos'] = sql_allfetsel('*', 'spip_documents_liens', $where_logo);
// Extraction de la correspondance id-iso pour les liens et les logos
$territoires['ids'] = array();
$select = array('id_territoire', 'iso_territoire');
// -- les liens
$where_ids = array(
sql_in('id_territoire', array_column($territoires['liens'], 'id_territoire'))
);
if ($ids = sql_allfetsel($select, $from, $where_ids)) {
$territoires['ids'] = array_column($ids, 'id_territoire', 'iso_territoire');
}
// -- les logos
$where_ids = array(
sql_in('id_territoire', array_column($territoires['logos'], 'id_objet'))
);
if ($ids = sql_allfetsel($select, $from, $where_ids)) {
$ids = array_column($ids, 'id_territoire', 'iso_territoire');
$territoires['ids'] = array_merge($territoires['ids'], $ids);
}
// Extraction des territoires éditées.
// -- détermination de la liste des champs éditables.
$territoires['editions'] = array();
include_spip('base/objets');
$description_table = lister_tables_objets_sql($from);
// -- pour le select, les champs éditables sont complétés par le code ISO.
$select = array_merge($description_table['champs_editables'], array('iso_territoire'));
$where[] = 'edite=' . sql_quote('oui');
if ($editions = sql_allfetsel($select, $from, $where)) {
// -- indexer le tableau par le code iso de façon à simplifier la réintégration.
$territoires['editions'] = array_column($editions, null, 'iso_territoire');
}
// Permettre à d'autres plugins de compléter la sauvegarde (principalement pour les liens).
// -- par exemple le plugin Contours sauvegarde les liens vers les contours GIS (spip_liens_gis).
$flux = array(
'args' => array(
'type' => $type,
'pays' => $pays,
),
'data' => $territoires
);
$territoires = pipeline('post_preserver_territoire', $flux);
return $territoires;
}
/**
* Acquiert les données de territoires disponibles dans Nomenclatures.
* La fonction utilise l'API fonctionnelle de Nomenclatures mais pourra ensuite utiliser directement API REST.
*
* @api
*
* @param string $type Type de territoires à acquérie. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays nécessaire si le type est `subdivision`.
* @param array $options Permet de demander l'exclusion (`exclure`) de certains index si ceux-ci sont inutilisés
* ou de ne retourner qu'un seul index (`index`).
*
* @return array
*/
function territoire_acquerir($type, $pays = '', $options = array()) {
// Initialiser les territoires à vide pour gérer une éventuelle erreur de type.
$territoires = array();
// Déterminer la collection et les conditions à appliquer.
$filtres = array();
$collection = array();
if ($type === 'zone') {
$collection = 'zones';
} elseif ($type === 'country') {
$collection = 'pays';
} elseif ($type === 'subdivision') {
$collection = 'subdivisions';
if ($pays) {
$filtres = array('pays' => $pays);
}
}
// Collectionner les territoires avec l'API REST de Nomenclatures
if ($collection) {
// Ajouter les exclusions si nécessaire
if (!empty($options['exclure'])) {
$filtres['exclure'] = $options['exclure'];
}
// Appel à l'API REST de Nomenclatures
$requeter = charger_fonction('requeter_isocode', 'inc');
if ($data = $requeter(_TERRITOIRE_URL_BASE_ISOCODE, $collection, $filtres)) {
$territoires = $data['donnees'];
}
// Si on a demandé un seul index on le renvoie seul sinon on renvoie le tableau complet.
if (
!empty($options['index'])
and isset($territoires[$options['index']])
) {
$territoires = $territoires[$options['index']];
}
}
return $territoires;
}
/**
* Renvoie la liste des pays dont les territoires ont été chargées.
* La fonction lit la meta de chargement et non la table spip_territoires.
@ -622,333 +435,3 @@ function territoire_retablir_lien($type_lien, $sauvegardes, $ids_crees, $config_
sql_insertq_multi($config_lien['table'], $liens);
}
}
/**
* Consigne le peuplement d'un type de territoire.
*
* @api
*
* @param string $meta Nom de la meta de consignation
* @param array $contenu Informations sur le peuplement à consigner dans la meta
* @param string $type Type de territoires à peupler. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
* @param string $service Identifiant du service Nomenclatures ayant permis le chargement. Est utilisé pour indexer
* la consignation dans le cas des contours uniquement. Sinon vaut chaine vide
*
* @return void
*/
function peuplement_consigner($meta, $contenu, $type, $pays = '', $service = '') {
// Définir la variable de config
$consigne = consigne_identifier($type, $pays, $service);
// Enregistrer la variable pour la meta demandée.
include_spip('inc/config');
ecrire_config("${meta}/${consigne}", $contenu);
}
/**
* Supprime la consignation du peuplement d'un type de territoire.
*
* @api
*
* @param string $meta Nom de la meta de consignation
* @param string $type Type de territoires à peupler. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
* @param string $service Identifiant du service Nomenclatures ayant permis le chargement. Est utilisé pour indexer
* la consignation dans le cas des contours uniquement. Sinon vaut chaine vide
*
* @return void
*/
function peuplement_deconsigner($meta, $type, $pays = '', $service = '') {
// Définir la variable de config
$consigne = consigne_identifier($type, $pays, $service);
// Effacer la variable de la meta demandée.
include_spip('inc/config');
effacer_config("${meta}/${consigne}");
}
// -----------------
// Services internes
// -----------------
/**
* Vérifie si le couple (type, pays) est valide, à savoir, désigne bien un sous-ensemble cohérent de territoires.
* Les sous-ensembles valides sont :
* - les régions du monde
* - les pays
* - les subdivisions d'un pays.
*
* @internal
*
* @param string $type Type de territoires. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
*
* @return bool `true` si le couple (type, pays) est valide, `false` sinon.
*/
function type_pays_est_valide($type, $pays = '') {
$est_valide = false;
// On récupère le sha de la table dans les metas si il existe (ie. la table a été chargée)
if ($type === 'subdivision') {
if (strlen($pays) === 2) {
$est_valide = true;
}
} elseif (in_array($type, array('zone', 'country'))) {
$est_valide = true;
}
return $est_valide;
}
/**
* Compare le sha passé en argument pour le type de territoire concerné avec le sha stocké dans la meta
* pour cette même type.
*
* @internal
*
* @param string $sha SHA à comparer à celui du type de territoire.
* @param string $meta Nom de la meta de consignation
* @param string $type Type de territoires à peupler. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
* @param string $service Identifiant du service Nomenclatures ayant permis le chargement. Est utilisé pour indexer
* la consignation dans le cas des contours uniquement. Sinon vaut chaine vide
*
* @return bool `true` si le sha passé en argument est identique au sha stocké pour la table choisie, `false` sinon.
*/
function sha_est_identique($sha, $meta, $type, $pays = '', $service = '') {
$sha_identique = false;
// Définir la variable de consignation
$consigne = consigne_identifier($type, $pays, $service);
// On récupère le sha de la table dans les metas si il existe (ie. la table a été chargée)
include_spip('inc/config');
$sha_stocke = lire_config("${meta}/${consigne}/sha", false);
if ($sha_stocke and ($sha === $sha_stocke)) {
$sha_identique = true;
}
return $sha_identique;
}
/**
* Fusionne les traductions d'une balise `<multi>` avec celles d'une autre balise `<multi>`.
* L'une des balise est considérée comme prioritaire ce qui permet de régler le cas où la même
* langue est présente dans les deux balises.
* Si on ne trouve pas de balise `<multi>` dans l'un ou l'autre des paramètres, on considère que
* le texte est tout même formaté de la façon suivante : texte0[langue1]texte1[langue2]texte2...
*
* @internal
*
* @param string $multi_prioritaire
* Balise multi considérée comme prioritaire en cas de conflit sur une langue.
* @param string $multi_non_prioritaire
* Balise multi considérée comme non prioritaire en cas de conflit sur une langue.
*
* @return string
* La chaine construite est toujours une balise `<multi>` complète ou une chaine vide sinon.
*/
function traduction_fusionner($multi_prioritaire, $multi_non_prioritaire) {
$multi_merge = '';
// On extrait le contenu de la balise <multi> si elle existe.
$multi_prioritaire = trim($multi_prioritaire);
$multi_non_prioritaire = trim($multi_non_prioritaire);
// Si les deux balises sont identiques ou si la balise non prioritaire est vide on sort directement
// avec le multi prioritaire ce qui améliore les performances.
if (
($multi_prioritaire == $multi_non_prioritaire)
or !$multi_non_prioritaire
) {
$multi_merge = $multi_prioritaire;
} else {
include_spip('inc/filtres');
if (preg_match(_EXTRAIRE_MULTI, $multi_prioritaire, $match)) {
$multi_prioritaire = trim($match[1]);
}
if (preg_match(_EXTRAIRE_MULTI, $multi_non_prioritaire, $match)) {
$multi_non_prioritaire = trim($match[1]);
}
if ($multi_prioritaire) {
if ($multi_non_prioritaire) {
// On extrait les traductions sous forme de tableau langue=>traduction.
$traductions_prioritaires = extraire_trads($multi_prioritaire);
$traductions_non_prioritaires = extraire_trads($multi_non_prioritaire);
// On complète les traductions prioritaires avec les traductions non prioritaires dont la langue n'est pas
// présente dans les traductions prioritaires.
foreach ($traductions_non_prioritaires as $_lang => $_traduction) {
if (!array_key_exists($_lang, $traductions_prioritaires)) {
$traductions_prioritaires[$_lang] = $_traduction;
}
}
// On construit le contenu de la balise <multi> mergé à partir des traductions prioritaires mises à jour.
// Les traductions vides sont ignorées.
ksort($traductions_prioritaires);
foreach ($traductions_prioritaires as $_lang => $_traduction) {
if ($_traduction) {
$multi_merge .= ($_lang ? '[' . $_lang . ']' : '') . trim($_traduction);
}
}
} else {
$multi_merge = $multi_prioritaire;
}
} else {
$multi_merge = $multi_non_prioritaire;
}
// Si le contenu est non vide on l'insère dans une balise <multi>
if ($multi_merge) {
$multi_merge = '<multi>' . $multi_merge . '</multi>';
}
}
return $multi_merge;
}
/**
* @param $territoire
* @param $type
* @param string $pays
*
* @return array
*/
function enregistrement_initialiser($territoire, $type, $pays = '') {
// Traduire les champs de Isocode en champs pour Territoires
$enregistrement = array();
$champs = $GLOBALS['territoires'][$type]['champs']['base'];
foreach ($champs as $_champ_api => $_champ_territoire) {
$enregistrement[$_champ_territoire] = $territoire[$_champ_api];
}
// Compléter systématiquement avec le type, le nom d'usage qui pour l'instant n'est pas fourni et le descriptif
// TODO : pour l'instant Nomenclatures ne fournit pas de nom d'usage (on duplique le nom ISO) ni de descriptif.
$enregistrement['type'] = $type;
$enregistrement['nom_usage'] = $enregistrement['iso_titre'];
$enregistrement['descriptif'] = '';
// Gestion des parentés inter-types : on remplit systématiquement le champ parent pour créer une hiérarchie complète
// inter-type et ce que le type parent soit peuplé ou pas.
// Cela revient :
// -- à ajouter le pays d'appartenance des subdivisions de plus haut niveau
if (
($type === 'subdivision')
and (!$enregistrement['iso_parent'])
) {
// Le pays d'appartenance est toujours inclus dans le champ iso_pays
$enregistrement['iso_parent'] = $enregistrement['iso_pays'];
}
// -- à ajouter la région d'appartenance des pays (pas de hiérarchie dans les pays).
if (
($type === 'country')
) {
// La région d'appartenance est toujours inclus dans le champ code_num_region fourni par Nomenclatures
$enregistrement['iso_parent'] = $territoire['code_num_region'];
}
return $enregistrement;
}
/**
* @param string $mode
* @param array $types_extras
* @param array $source
* @param array $configuration
* @param string $type
* @param string $pays
* @param array $meta_extras
*
* @return array
*/
function extra_compiler($mode, $types_extras, $source, $configuration, $type, $pays, &$meta_extras) {
$extras = array();
foreach ($types_extras as $_type_extra) {
// Vérifier qu'il existe des extras pour le type de territoire
// -- on traite les deux modes d'extraction : interne à un objet territoire ou un bloc externe
if (
(
($mode === 'interne')
and !empty($configuration['champs']['extras'][$_type_extra])
)
or (
($mode !== 'interne')
and !empty($configuration['extras'][$_type_extra])
and isset($source[$configuration['extras'][$_type_extra]['index']])
)
) {
// On initialise les données communes de chaque extra
$extra_defaut = array(
'type_extra' => $_type_extra,
'type' => $type,
'iso_pays' => $pays,
);
// Suivant le mode on enregistre chaque extra détecté:
// - mode interne : chaque champ extra du territoire devient un objet extra de la table spip_territoires_extras
// - mode externe : chaque élément du bloc idoine de la collection devient un objet extra
$source_extras = ($mode === 'interne')
? $configuration['champs']['extras'][$_type_extra]
: $source[$configuration['extras'][$_type_extra]['index']];
foreach ($source_extras as $_cle => $_valeur) {
$extra = $extra_defaut;
$extra['iso_territoire'] = ($mode === 'interne')
? $source['iso_territoire']
: $_valeur[$configuration['extras'][$_type_extra]['cle_iso']];
$extra['extra'] = ($mode === 'interne')
? $_valeur
: $_valeur[$configuration['extras'][$_type_extra]['champs']['extra']];
$extra['valeur'] = ($mode === 'interne')
? $source[$_cle]
: $_valeur[$configuration['extras'][$_type_extra]['champs']['valeur']];
$extras[] = $extra;
}
// Enregistrer le type d'extra pour la meta de consignation
if (!in_array($_type_extra, $meta_extras)) {
$meta_extras[] = $_type_extra;
}
}
}
return $extras;
}
/**
* Identifie la variable de configuration à partir du type de territoire, du pays et du service éventuellement.
*
* @api
*
* @param string $type Type de territoires à peupler. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
* @param string $service Identifiant du service Nomenclatures ayant permis le chargement. Est utilisé pour indexer
* la consignation dans le cas des contours uniquement. Sinon vaut chaine vide
*
* @return string
*/
function consigne_identifier($type, $pays = '', $service = '') {
if ($type === 'subdivision') {
$consigne = $service
? "${type}/${pays}/${service}"
: "${type}/${pays}";
} else {
$consigne = $service
? "${type}/${service}"
: "${type}";
}
return $consigne;
}

@ -0,0 +1,469 @@
<?php
/**
* Gestion du formulaire de chargement ou de vidage des territoires.
*
* @package SPIP\TERRITOIRES\API
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
if (!defined('_TERRITOIRE_URL_BASE_ISOCODE')) {
define('_TERRITOIRE_URL_BASE_ISOCODE', 'https://contrib.spip.net/http.api/ezrest');
}
/**
* Initialise la configuration des différents types de territoire, soit les régions du monde, les pays et
* les subdivisions.
* Cette configuration est stockée dans la meta `territoires` à linstallation et n'est pas modifiable.
*
* @return array
*/
function territoires_configurer() {
// Configuration statique du plugin Territoires
$configuration = array(
'zone' => array(
'champs' => array(
'base' => array(
'code_num' => 'iso_territoire',
'category' => 'categorie',
'parent' => 'iso_parent',
'label' => 'iso_titre',
),
'index' => 'zones',
),
),
'country' => array(
'champs' => array(
'base' => array(
'code_alpha2' => 'iso_territoire',
'category' => 'categorie',
'code_continent' => 'iso_continent',
'label' => 'iso_titre',
),
'extras' => array(
'code' => array(
'code_alpha3' => 'code_iso3166_a3',
'code_num' => 'code_iso3166_num',
),
'info' => array(
'capital' => 'capital',
'area' => 'area',
'population' => 'population',
'tld' => 'tld',
'code_4217_3' => 'code_4217_3',
'phone_id' => 'phone_id'
),
),
'index' => 'pays',
),
),
'subdivision' => array(
'champs' => array(
'base' => array(
'code_3166_2' => 'iso_territoire',
'type' => 'categorie',
'country' => 'iso_pays',
'parent' => 'iso_parent',
'label' => 'iso_titre',
),
'index' => 'subdivisions',
),
'extras' => array(
'code' => array(
'champs' => array(
'extra' => 'type_alter',
'valeur' => 'code_alter',
),
'index' => 'codes_alternatifs',
'cle_iso' => 'code_iso',
),
),
),
);
return $configuration;
}
/**
* Acquiert les données de territoires disponibles dans Nomenclatures.
* La fonction utilise l'API fonctionnelle de Nomenclatures mais pourra ensuite utiliser directement API REST.
*
* @api
*
* @param string $type Type de territoires à acquérie. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays nécessaire si le type est `subdivision`.
* @param array $options Permet de demander l'exclusion (`exclure`) de certains index si ceux-ci sont inutilisés
* ou de ne retourner qu'un seul index (`index`).
*
* @return array
*/
function territoires_acquerir($type, $pays = '', $options = array()) {
// Initialiser les territoires à vide pour gérer une éventuelle erreur de type.
$territoires = array();
// Déterminer la collection et les conditions à appliquer.
$filtres = array();
$collection = array();
if ($type === 'zone') {
$collection = 'zones';
} elseif ($type === 'country') {
$collection = 'pays';
} elseif ($type === 'subdivision') {
$collection = 'subdivisions';
if ($pays) {
$filtres = array('pays' => $pays);
}
}
// Collectionner les territoires avec l'API REST de Nomenclatures
if ($collection) {
// Ajouter les exclusions si nécessaire
if (!empty($options['exclure'])) {
$filtres['exclure'] = $options['exclure'];
}
// Appel à l'API REST de Nomenclatures
$requeter = charger_fonction('requeter_isocode', 'inc');
if ($data = $requeter(_TERRITOIRE_URL_BASE_ISOCODE, $collection, $filtres)) {
$territoires = $data['donnees'];
}
// Si on a demandé un seul index on le renvoie seul sinon on renvoie le tableau complet.
if (
!empty($options['index'])
and isset($territoires[$options['index']])
) {
$territoires = $territoires[$options['index']];
}
}
return $territoires;
}
/**
* Extrait, pour un les régions, les pays ou les subdivisions d'un pays, la liste des territoires ayant fait l'objet
* d'une modification manuelle (descriptif ou logo) et la liste associations vers ses mêmes territoires.
* Les extras ne sont pas sauvegardés car il ne sont ni modifiables ni indexés par un id mais par un code invariant.
*
* @api
*
* @param string $type Type de territoires à préserver. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays nécessaire si le type est `subdivision`.
*
* @return array
*/
function territoires_preserver($type, $pays = '') {
// Initialisation de la table et de la condition de base sur le type et éventuellement le pays.
$territoires = array();
$from = 'spip_territoires';
$where = array(
'type=' . sql_quote($type),
);
if ($type === 'subdivision') {
$where[] = 'iso_pays=' . sql_quote($pays);
}
// Extraction des liens vers les territoires du pays
$where_lien = array(
sql_in_select('id_territoire', 'id_territoire', $from, $where)
);
$territoires['liens'] = sql_allfetsel('*', 'spip_territoires_liens', $where_lien);
// Extraction des liens de logos vers les territoires du pays
$where_logo = array(
'objet=' . sql_quote('territoire'),
sql_in_select('id_objet', 'id_territoire', $from, $where)
);
$territoires['logos'] = sql_allfetsel('*', 'spip_documents_liens', $where_logo);
// Extraction de la correspondance id-iso pour les liens et les logos
$territoires['ids'] = array();
$select = array('id_territoire', 'iso_territoire');
// -- les liens
$where_ids = array(
sql_in('id_territoire', array_column($territoires['liens'], 'id_territoire'))
);
if ($ids = sql_allfetsel($select, $from, $where_ids)) {
$territoires['ids'] = array_column($ids, 'id_territoire', 'iso_territoire');
}
// -- les logos
$where_ids = array(
sql_in('id_territoire', array_column($territoires['logos'], 'id_objet'))
);
if ($ids = sql_allfetsel($select, $from, $where_ids)) {
$ids = array_column($ids, 'id_territoire', 'iso_territoire');
$territoires['ids'] = array_merge($territoires['ids'], $ids);
}
// Extraction des territoires éditées.
// -- détermination de la liste des champs éditables.
$territoires['editions'] = array();
include_spip('base/objets');
$description_table = lister_tables_objets_sql($from);
// -- pour le select, les champs éditables sont complétés par le code ISO.
$select = array_merge($description_table['champs_editables'], array('iso_territoire'));
$where[] = 'edite=' . sql_quote('oui');
if ($editions = sql_allfetsel($select, $from, $where)) {
// -- indexer le tableau par le code iso de façon à simplifier la réintégration.
$territoires['editions'] = array_column($editions, null, 'iso_territoire');
}
// Permettre à d'autres plugins de compléter la sauvegarde (principalement pour les liens).
// -- par exemple le plugin Contours sauvegarde les liens vers les contours GIS (spip_liens_gis).
$flux = array(
'args' => array(
'type' => $type,
'pays' => $pays,
),
'data' => $territoires
);
$territoires = pipeline('post_preserver_territoire', $flux);
return $territoires;
}
/**
* Vérifie si le couple (type, pays) est valide, à savoir, désigne bien un sous-ensemble cohérent de territoires.
* Les sous-ensembles valides sont :
* - les régions du monde
* - les pays
* - les subdivisions d'un pays.
*
* @internal
*
* @param string $type Type de territoires. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
*
* @return bool `true` si le couple (type, pays) est valide, `false` sinon.
*/
function type_pays_est_valide($type, $pays = '') {
$est_valide = false;
// On récupère le sha de la table dans les metas si il existe (ie. la table a été chargée)
if ($type === 'subdivision') {
if (strlen($pays) === 2) {
$est_valide = true;
}
} elseif (in_array($type, array('zone', 'country'))) {
$est_valide = true;
}
return $est_valide;
}
/**
* Fusionne les traductions d'une balise `<multi>` avec celles d'une autre balise `<multi>`.
* L'une des balise est considérée comme prioritaire ce qui permet de régler le cas où la même
* langue est présente dans les deux balises.
* Si on ne trouve pas de balise `<multi>` dans l'un ou l'autre des paramètres, on considère que
* le texte est tout même formaté de la façon suivante : texte0[langue1]texte1[langue2]texte2...
*
* @internal
*
* @param string $multi_prioritaire
* Balise multi considérée comme prioritaire en cas de conflit sur une langue.
* @param string $multi_non_prioritaire
* Balise multi considérée comme non prioritaire en cas de conflit sur une langue.
*
* @return string
* La chaine construite est toujours une balise `<multi>` complète ou une chaine vide sinon.
*/
function traduction_fusionner($multi_prioritaire, $multi_non_prioritaire) {
$multi_merge = '';
// On extrait le contenu de la balise <multi> si elle existe.
$multi_prioritaire = trim($multi_prioritaire);
$multi_non_prioritaire = trim($multi_non_prioritaire);
// Si les deux balises sont identiques ou si la balise non prioritaire est vide on sort directement
// avec le multi prioritaire ce qui améliore les performances.
if (
($multi_prioritaire == $multi_non_prioritaire)
or !$multi_non_prioritaire
) {
$multi_merge = $multi_prioritaire;
} else {
include_spip('inc/filtres');
if (preg_match(_EXTRAIRE_MULTI, $multi_prioritaire, $match)) {
$multi_prioritaire = trim($match[1]);
}
if (preg_match(_EXTRAIRE_MULTI, $multi_non_prioritaire, $match)) {
$multi_non_prioritaire = trim($match[1]);
}
if ($multi_prioritaire) {
if ($multi_non_prioritaire) {
// On extrait les traductions sous forme de tableau langue=>traduction.
$traductions_prioritaires = extraire_trads($multi_prioritaire);
$traductions_non_prioritaires = extraire_trads($multi_non_prioritaire);
// On complète les traductions prioritaires avec les traductions non prioritaires dont la langue n'est pas
// présente dans les traductions prioritaires.
foreach ($traductions_non_prioritaires as $_lang => $_traduction) {
if (!array_key_exists($_lang, $traductions_prioritaires)) {
$traductions_prioritaires[$_lang] = $_traduction;
}
}
// On construit le contenu de la balise <multi> mergé à partir des traductions prioritaires mises à jour.
// Les traductions vides sont ignorées.
ksort($traductions_prioritaires);
foreach ($traductions_prioritaires as $_lang => $_traduction) {
if ($_traduction) {
$multi_merge .= ($_lang ? '[' . $_lang . ']' : '') . trim($_traduction);
}
}
} else {
$multi_merge = $multi_prioritaire;
}
} else {
$multi_merge = $multi_non_prioritaire;
}
// Si le contenu est non vide on l'insère dans une balise <multi>
if ($multi_merge) {
$multi_merge = '<multi>' . $multi_merge . '</multi>';
}
}
return $multi_merge;
}
/**
* @param $territoire
* @param $type
* @param string $pays
*
* @return array
*/
function enregistrement_initialiser($territoire, $type, $pays = '') {
// Traduire les champs de Isocode en champs pour Territoires
include_spip('inc/config');
$enregistrement = array();
$champs = lire_config("territoires/${type}/champs/base");
foreach ($champs as $_champ_api => $_champ_territoire) {
$enregistrement[$_champ_territoire] = $territoire[$_champ_api];
}
// Compléter systématiquement avec le type, le nom d'usage qui pour l'instant n'est pas fourni et le descriptif
// TODO : pour l'instant Nomenclatures ne fournit pas de nom d'usage (on duplique le nom ISO) ni de descriptif.
$enregistrement['type'] = $type;
$enregistrement['nom_usage'] = $enregistrement['iso_titre'];
$enregistrement['descriptif'] = '';
// Gestion des parentés inter-types : on remplit systématiquement le champ parent pour créer une hiérarchie complète
// inter-type et ce que le type parent soit peuplé ou pas.
// Cela revient :
// -- à ajouter le pays d'appartenance des subdivisions de plus haut niveau
if (
($type === 'subdivision')
and (!$enregistrement['iso_parent'])
) {
// Le pays d'appartenance est toujours inclus dans le champ iso_pays
$enregistrement['iso_parent'] = $enregistrement['iso_pays'];
}
// -- à ajouter la région d'appartenance des pays (pas de hiérarchie dans les pays).
if (
($type === 'country')
) {
// La région d'appartenance est toujours inclus dans le champ code_num_region fourni par Nomenclatures
$enregistrement['iso_parent'] = $territoire['code_num_region'];
}
return $enregistrement;
}
/**
* @param string $mode
* @param array $types_extras
* @param array $source
* @param array $configuration
* @param string $type
* @param string $pays
* @param array $meta_extras
*
* @return array
*/
function extra_compiler($mode, $types_extras, $source, $configuration, $type, $pays, &$meta_extras) {
$extras = array();
foreach ($types_extras as $_type_extra) {
// Vérifier qu'il existe des extras pour le type de territoire
// -- on traite les deux modes d'extraction : interne à un objet territoire ou un bloc externe
if (
(
($mode === 'interne')
and !empty($configuration['champs']['extras'][$_type_extra])
)
or (
($mode !== 'interne')
and !empty($configuration['extras'][$_type_extra])
and isset($source[$configuration['extras'][$_type_extra]['index']])
)
) {
// On initialise les données communes de chaque extra
$extra_defaut = array(
'type_extra' => $_type_extra,
'type' => $type,
'iso_pays' => $pays,
);
// Suivant le mode on enregistre chaque extra détecté:
// - mode interne : chaque champ extra du territoire devient un objet extra de la table spip_territoires_extras
// - mode externe : chaque élément du bloc idoine de la collection devient un objet extra
$source_extras = ($mode === 'interne')
? $configuration['champs']['extras'][$_type_extra]
: $source[$configuration['extras'][$_type_extra]['index']];
foreach ($source_extras as $_cle => $_valeur) {
$extra = $extra_defaut;
$extra['iso_territoire'] = ($mode === 'interne')
? $source['iso_territoire']
: $_valeur[$configuration['extras'][$_type_extra]['cle_iso']];
$extra['extra'] = ($mode === 'interne')
? $_valeur
: $_valeur[$configuration['extras'][$_type_extra]['champs']['extra']];
$extra['valeur'] = ($mode === 'interne')
? $source[$_cle]
: $_valeur[$configuration['extras'][$_type_extra]['champs']['valeur']];
$extras[] = $extra;
}
// Enregistrer le type d'extra pour la meta de consignation
if (!in_array($_type_extra, $meta_extras)) {
$meta_extras[] = $_type_extra;
}
}
}
return $extras;
}
/**
* Identifie la variable de configuration à partir du type de territoire et éventuellement du pays pour les
* subdivisions.
*
* @api
*
* @param string $type Type de territoires à peupler. Prends les valeurs `zone`, `country` ou `subdivision`.
* @param string $pays Code ISO 3166-1 alpha2 du pays dont on veut peupler les subdivisions.
* N'est utilisé que si le type choisi est `subdivision`.
*
* @return string
*/
function consigne_identifier($type, $pays = '') {
$consigne = ($type === 'subdivision')
? "${type}/${pays}"
: $type;
return $consigne;
}

@ -26,10 +26,22 @@ if (!defined('_ECRIRE_INC_VERSION')) {
function territoires_upgrade($nom_meta_base_version, $version_cible) {
$maj = array();
// Initialisation de la configuration statique
include_spip('inc/territoires_utils');
$config_statique = territoires_configurer();
$config_modifiable = array(
'association_objets' => array(),
);
$maj['create'] = array(
array(
'maj_tables',
array('spip_territoires', 'spip_territoires_extras', 'spip_territoires_liens')
),
array(
'ecrire_config',
'territoires',
array_merge($config_statique, $config_modifiable)
)
);

@ -6,7 +6,7 @@
* @copyright 2020
* @author Eric Lupinacci
* @licence GNU/GPL
* @package SPIP\Territoires\Pipelines
* @package SPIP\TERRITOIRES\PIPELINES
*/
if (!defined('_ECRIRE_INC_VERSION')) {
@ -53,6 +53,7 @@ function territoires_affiche_milieu($flux) {
// Insertion du formulaire d'association
if (
($table = $exec['table_objet_sql'])
and include_spip('inc/config')
and (in_array($table, lire_config('territoires/association_objets', array())))
) {
$texte .= recuperer_fond(

Loading…
Cancel
Save