source: spip-zone/_plugins_/rainette/trunk/inc/charger_meteo.php @ 107848

Last change on this file since 107848 was 107848, checked in by eric@…, 3 years ago

Mise en place d'une gestion complète des erreurs tenant compte aussi des erreurs remontées par chaque service.
Pour ce faire, ajout d'une configuration pour chaque service et d'une fonction de service permettant de savoir si une erreur a été remontée.
Correction du service OWM et passage de tous ses modes en JSON.
Début de renommage de certaines fonctions internes.

  • Property svn:eol-style set to native
File size: 13.0 KB
Line 
1<?php
2/**
3 * Ce fichier contient la fonction standard de chargement et fourniture du fichier cache des données météo.
4 * Elle s'applique à tous les services et à tous les types de données.
5 *
6 * @package SPIP\RAINETTE\CACHE
7 */
8if (!defined('_ECRIRE_INC_VERSION')) {
9        return;
10}
11
12
13/**
14 * Renvoyer le nom du fichier cache des données météos correspondant au lieu et au type de données choisis après l'avoir
15 * éventuellement mis à jour.
16 *
17 * Si le fichier cache est obsolète ou absent, on le crée après avoir chargé puis phrasé le flux XML ou JSON
18 * et stocké les données collectées et transcodées dans un tableau standardisé. L'appelant doit s'assurer que la
19 * périodicité est compatible avec le service; cette fonction ne retourne donc que des erreurs de chargement.
20 *
21 * @uses service2cache()
22 * @uses service2donnees()
23 * @uses indice2risque_uv()
24 *
25 * @param string $lieu
26 *        Le lieu concerné par la méteo exprimé selon les critères requis par le service
27 * @param string $mode
28 *        Le type de données météorologiques demandé :
29 *            - `conditions`, la valeur par défaut
30 *            - `previsions`
31 *            - `conditions`
32 *            - `infos`
33 * @param int $periodicite
34 *        La périodicité horaire des prévisions :
35 *            - `24`, les prévisions de la journée
36 *            - `12`, les prévisions du jour et de la nuit
37 *            - `6`, les prévisions de la journée par période de 4h
38 *            - `3`, les prévisions de la journée par période de 3h
39 *            - `1`, les prévisions de la journée pour chaque heure
40 *            - `0`, pour les modes `conditions` et `infos`
41 * @param string $service
42 *        Le nom abrégé du service :
43 *            - `weather` pour le weather.com, la valeur par défaut car elle ne nécessite aucune inscription
44 *            - `wwo` pour World Weather Online
45 *            - `wunderground` pour Wunderground
46 *            - `owm` pour Open Weather Map
47 *            - `apixu` pour APIXU
48 *
49 * @return string
50 *        Le nom du fichier cache correspondant à la demande.
51 */
52function inc_charger_meteo_dist($lieu, $mode = 'conditions', $periodicite = 0, $service = 'weather') {
53
54        // Traitement des cas ou les arguments sont vides (ce qui est différent de non passés à l'appel)
55        // On considère à ce stade que la cohérence entre le mode, la périodicité et le service (qui selon ne supporte
56        // pas toutes les périodicités) est déjà assurée et n'est donc pas à tester.
57        if (!$mode) {
58                $mode = 'conditions';
59                $periodicite = 0;
60        }
61        if (!$service) {
62                $service = 'weather';
63        }
64
65        // En fonction du service, on inclut le fichier d'API.
66        // Le principe est que chaque service propose la même liste de fonctions d'interface dans un fichier unique.
67        include_spip("services/${service}");
68
69        // Acquérir la configuration statique du service (periode, format, données...)
70        $configurer = "${service}_service2configuration";
71        $configuration = $configurer($mode);
72
73        // Acquérir la configuration dynamique du service (celle modifiable par l'utilisateur via
74        // le formulaire et stockée en BDD dans la table spip_meta) et la merger avec la configuration statique.
75        // Cependant, celle-ci pouvant être incomplète on la complète par les valeurs par défaut quand
76        // cela est nécessaire.
77        $configuration_utilisateur = normaliser_configuration_utilisateur($service, $configuration['defauts']);
78
79        // Concaténer l'ensemble des configurations.
80        $configuration = array_merge($configuration, $configuration_utilisateur);
81
82        // Si on a demandé le mode 'previsions' sans préciser la periodicité horaire des données, il faut prendre l'intervalle
83        // par défaut configuré pour le service.
84        if (($mode == 'previsions') and !$periodicite) {
85                $periodicite = $configuration['previsions']['periodicite_defaut'];
86        }
87
88        // Construire le nom du fichier cache
89        include_spip('inc/rainette_normaliser');
90        $cache = service2cache($lieu, $mode, $periodicite, $configuration);
91
92        // Déterminer le système d'unité utilisé dans le cache et celui requis par la configuration.
93        // Si ces systèmes d'unité diffèrent il faut renouveler le cache sinon on affichera des données
94        // fausses avec une unité correcte et ce jusqu'à la prochaine échéance du cache.
95        $unite_configuree = '';
96        $unite_cache = '';
97        if (file_exists($cache) and ($mode != 'infos')) {
98                $unite_configuree = $configuration['unite']
99                        ? $configuration['unite']
100                        : $configuration['defauts']['unite'];
101
102                lire_fichier($cache, $contenu);
103                $tableau = unserialize($contenu);
104                $index = count($tableau) - 1;
105                $unite_cache = isset($tableau[$index]['config']['unite'])
106                        ? $tableau[$index]['config']['unite']
107                        : $configuration['defauts']['unite'];
108        }
109
110        // Mise à jour du cache avec les nouvelles données météo si:
111        // - le fichier cache n'existe pas
112        // - la période de validité du cache est échue
113        // - le système d'unités du cache n'est pas celui requis
114        if (!file_exists($cache)
115        or (!filemtime($cache) or (time() - filemtime($cache) > $configuration['periode_maj']))
116        or (($mode != 'infos') and ($unite_configuree != $unite_cache))) {
117                // Construire l'url de la requête
118                $urler = "${service}_service2url";
119                $url = $urler($lieu, $mode, $periodicite, $configuration);
120
121                // Acquérir le flux XML ou JSON dans un tableau et traiter les cas d'erreurs du plugin ou du service.
122                include_spip('inc/rainette_requeter');
123                $flux = requeter($url, $configuration['format_flux'], $service);
124                $tableau = array();
125                $erreur = array(
126                        'type' => '',
127                        'service' => array(
128                                'code' => '',
129                                'message' => ''
130                        )
131                );
132                if (!empty($flux['erreur'])) {
133                        // Erreur lors du traitement de la requête due à l'URL ou à la conversion en XML ou JSON.
134                        // Cette erreur n'est pas retournée par le service.
135                        $erreur['type'] = $flux['erreur'];
136                } else {
137                        // On teste une erreur d'acquisition renvoyée par le service. Pour tous les services, une cle de base
138                        // est explicitement utilisée pour distinguer les erreurs; sa présence permet d'identifier un cas d'erreur.
139                        include_spip('inc/filtres');
140                        $configuration_erreur = $configurer('erreurs');
141                        $flux_erreur = $flux;
142                        if (!empty($configuration_erreur['cle_base'])) {
143                                $flux_erreur = table_valeur($flux, implode('/', $configuration_erreur['cle_base']), null);
144                        }
145
146                        // On normalise le flux en utilisant le mode d'erreur pour vérifier si on obtient bien une erreur.
147                        $erreur_service = service2donnees($configuration_erreur,'erreurs', $flux_erreur, -1);
148                        $verifier = "${service}_erreur_verifier";
149                        if ($verifier($erreur_service)) {
150                                // Une erreur est renvoyée par le service, on formate l'erreur correctement.
151                                $erreur['type'] = 'reponse_service';
152                                $erreur['service'] = array_merge($erreur['service'], $erreur_service);
153                        } else {
154                                // On se positionne sur le niveau de base du flux des données où commence le tableau des données météorologiques.
155                                if (!empty($configuration['cle_base'])) {
156                                        $flux = table_valeur($flux, implode('/', $configuration['cle_base']), null);
157                                }
158
159                                if (empty($flux)) {
160                                        // Pas d'erreur retournée par le service mais aucune donnée fournie. Ce cas est peut-être impossible
161                                        // mais on le traite tout de même par sécurité avec un type particulier.
162                                        $erreur['type'] = 'aucune_donnee';
163                                } else {
164                                        // En mode prévisions, le niveau de base est un tableau de n éléments, chaque élément étant un tableau contenant
165                                        // les données météorologiques d'un jour à venir ([0] => jour0[], [1] => jour1[]...).
166                                        // En mode infos ou conditions, on a directement accès aux données météorologiques (jour[]).
167                                        // Pour réaliser un traitement standard, on transforme donc le jour[] en un tableau d'un seul élément ([0] => jour[])
168                                        // qui pourra être traité comme celui des prévisions.
169                                        if (($mode == 'conditions') or ($mode == 'infos')) {
170                                                $flux = array($flux);
171                                        }
172
173                                        // Convertir le flux en tableau standard pour la mise en cache. Ce traitement se déroule en
174                                        // 3 étapes :
175                                        // -1- initialisation du tableau standard à partir uniquement des données reçues du service
176                                        // -2- complément du tableau avec les données propres à chaque service
177                                        // -3- complément du tableau avec les données communes à tous les services
178                                        foreach ($flux as $_index_jour => $_flux_jour) {
179                                                // Pour les informations et les conditions les données récupérées concernent toute la même "période".
180                                                // Par contre, pour les prévisions on distingue 2 type de données :
181                                                // - celles du jour indépendamment de la période horaire
182                                                // - celles correspondant à une période horaire choisie (24, 12, 6, 3, 1)
183                                                //   Ces donnnées sont stockées à un index horaire de 0 à n qui représente la période horaire.
184                                                // Pour avoir un traitement identique pour les deux types de données on considère que l'index horaire
185                                                // des données jour est égal à -1.
186                                                // On crée donc le tableau des index correspondant au mode choisi et on boucle dessus.
187                                                $periodes_horaires = array(-1);
188                                                if ($periodicite) {
189                                                        for ($i = 0; $i <  (24 / $periodicite); $i++) {
190                                                                $periodes_horaires[] = $i;
191                                                        }
192                                                }
193
194                                                // On détermine le flux heure en fonction du service. Ce flux heure coincide avec le flux jour dans
195                                                // la majeure partie des cas
196                                                $flux_heure = $_flux_jour;
197                                                if ((count($periodes_horaires) > 1)     and !empty($configuration['cle_heure'])) {
198                                                        $flux_heure = table_valeur($_flux_jour, implode('/', $configuration['cle_heure']), null);
199                                                }
200
201                                                // On boucle sur chaque periode horaire pour remplir le tableau complet.
202                                                foreach ($periodes_horaires as $_periode) {
203                                                        // 1- Initialiser le tableau normalisé des informations à partir des données brutes
204                                                        //    fournies par le service.
205                                                        //    Suivant la période il faut prendre le flux jour ou le flux heure. On calcule donc le flux heure
206                                                        //    quand c'est nécessaire.
207                                                        $flux_a_normaliser = $_periode == -1
208                                                                ? $_flux_jour
209                                                                : ($configuration['structure_heure'] ? $flux_heure[$_periode] : $flux_heure);
210                                                        $donnees = service2donnees(
211                                                                $configuration,
212                                                                $mode,
213                                                                $flux_a_normaliser,
214                                                                $_periode);
215
216                                                        if ($donnees) {
217                                                                // 2- Compléments spécifiques au service et au mode.
218                                                                //    Si ces compléments sont inutiles, la fonction n'existe pas
219                                                                $completer = "${service}_complement2${mode}";
220                                                                if (function_exists($completer)) {
221                                                                        $donnees = $mode == 'previsions'
222                                                                                ? $completer($donnees, $configuration, $_periode)
223                                                                                : $completer($donnees, $configuration);
224                                                                }
225
226                                                                // 3- Compléments standard communs à tous les services mais fonction du mode
227                                                                if ($mode == 'conditions') {
228                                                                        // Vérifier que l'indice uv si celui-ci est fourni
229                                                                        // Calcul du risque uv à partir de l'indice uv si celui-ci est fourni
230                                                                        include_spip('inc/rainette_convertir');
231                                                                        $donnees['risque_uv'] = is_int($donnees['indice_uv'])
232                                                                                ? indice2risque_uv($donnees['indice_uv'])
233                                                                                : $donnees['indice_uv'];
234                                                                }
235
236                                                                // Ajout du bloc à l'index en cours
237                                                                if ($_periode == -1) {
238                                                                        $tableau[$_index_jour] = $donnees;
239                                                                } else {
240                                                                        $tableau[$_index_jour]['heure'][$_periode] = $donnees;
241                                                                }
242                                                        }
243                                                }
244                                        }
245                                }
246                        }
247                }
248
249                // 4- Compléments standard à tous les services et tous les modes
250                $extras = array();
251                $extras['credits'] = $configuration['credits'];
252                $extras['config'] = array_merge(
253                        $configuration_utilisateur,
254                        array('source' => normaliser_configuration_donnees($mode, $configuration['donnees']))
255                );
256                $extras['lieu'] = $lieu;
257                $extras['mode'] = $mode;
258                $extras['periodicite_cache'] = $periodicite;
259                $extras['service'] = $service;
260                $extras['erreur'] = $erreur;
261
262                // On range les données et les extras dans un tableau associatif à deux entrées ('donnees', 'extras')
263                if ($tableau) {
264                        // Pour les modes "conditions" et "infos" l'ensemble des données météo est accessible sous
265                        // l'index 'donnees'. Il faut donc supprimer l'index 0 provenant du traitement commun avec
266                        // les prévisions.
267                        // Pour les prévisions l'index 0 à n désigne le jour, il faut donc le conserver
268                        $tableau = array(
269                                'donnees' => ($mode != 'previsions' ? array_shift($tableau) : $tableau),
270                                'extras' => $extras
271                        );
272                } else {
273                        // Traitement des erreurs de flux. On positionne toujours les bloc extra contenant l'erreur,
274                        // le bloc des données qui est mis à tableau vide dans ce cas à l'index 1.
275                        $tableau = array(
276                                'donnees' => array(),
277                                'extras'  => $extras
278                        );
279                }
280
281                // Pipeline de fin de chargement des données météo. Peut-être utilisé :
282                // -- pour effectuer des traitements annexes à partir des données météo (archivage, par exemple)
283                // -- pour ajouter ou modifier des données au tableau (la modification n'est pas conseillée cependant)
284                $tableau = pipeline('post_chargement_meteo',
285                                                        array(
286                                                                'args' => array('lieu' => $lieu, 'mode' => $mode, 'service' => $service),
287                                                                'data' => $tableau
288                                                        ));
289
290                // Création du nouveau cache
291                ecrire_fichier($cache, serialize($tableau));
292        }
293
294        return $cache;
295}
Note: See TracBrowser for help on using the repository browser.