source: spip-zone/_plugins_/n-core/trunk/ncore/ncore.php @ 113630

Last change on this file since 113630 was 113630, checked in by eric@…, 4 months ago

Par cohérence avec le fait de pouvoir compléter la description d'un type de noisette et d'une noisette, il faut proposer des services idoines pour traiter les champs textuels par typo() qui pourraient être spécifiques au plugin appelant. On crée donc type_noisette_traiter_typo() et noisette_traiter_typo().
Les API de lecture des types et noisettes sont donc maintenant finalisées.

  • Property svn:eol-style set to native
File size: 53.3 KB
Line 
1<?php
2/**
3 * Ce fichier contient les fonctions du service de stockage N-Core pour les types de noisettes et les noisettes.
4 *
5 * Chaque fonction, soit aiguille, si elle existe, vers une fonction "homonyme" propre au plugin appelant
6 * ou à un autre service de stockage, soit déroule sa propre implémentation.
7 * Ainsi, les plugins externes peuvent, si elle leur convient, utiliser l'implémentation proposée par N-Core
8 * en codant un minimum de fonctions, à savoir, `conteneur_identifier` et `conteneur_verifier`.
9 */
10if (!defined('_ECRIRE_INC_VERSION')) {
11        return;
12}
13
14
15// -----------------------------------------------------------------------
16// ------------------------- TYPES DE NOISETTE ---------------------------
17// -----------------------------------------------------------------------
18
19/**
20 * Stocke les descriptions des types de noisette en distinguant les types de noisette obsolètes, les types de
21 * noisettes modifiés et les types de noisettes nouveaux.
22 * Chaque description de type de noisette est un tableau associatif dont tous les index possibles - y compris
23 * la signature - sont initialisés quelque soit le contenu du fichier YAML.
24 *
25 * Le service N-Core stocke les descriptions dans un cache et les signatures dans un autre.
26 *
27 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
28 *
29 * @uses ncore_chercher_service()
30 * @uses cache_lire()
31 * @uses cache_ecrire()
32 *
33 * @param string $plugin
34 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
35 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
36 * @param array  $types_noisette
37 *        Tableau associatif à 3 entrées fournissant les descriptions des types de noisettes nouveaux, obsolètes
38 *        et modifiés:
39 *        `a_effacer` : liste des identifiants de type de noisette devenus obsolètes.
40 *        `a_changer` : liste des descriptions des types de noisette dont le fichier YAML a été modifié.
41 *        `a_ajouter` : liste des descriptions des nouveaux types de noisette.
42 *        Si $recharger est à `true`, seul l'index `nouvelles` est fourni dans le tableau $types_noisette.
43 * @param bool   $recharger
44 *        Indique si le chargement en cours est forcé ou pas. Cela permet à la fonction N-Core ou au service
45 *        concerné d'optimiser le traitement sachant que seules les types de noisette nouveaux sont fournis.
46 * @param string $stockage
47 *        Identifiant du service de stockage à utiliser si précisé.
48 *
49 * @return bool
50 *        `true` si le traitement s'est bien déroulé, `false` sinon.
51 */
52function ncore_type_noisette_stocker($plugin, $types_noisette, $recharger, $stockage = '') {
53
54        // On cherche le service de stockage à utiliser selon la logique suivante :
55        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
56        // - sinon, on utilise la fonction du plugin appelant si elle existe;
57        // - et sinon, on utilise la fonction de N-Core.
58        include_spip('inc/ncore_utils');
59        if ($stocker = ncore_chercher_service($plugin, 'type_noisette_stocker', $stockage)) {
60                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
61                $retour = $stocker($plugin, $types_noisette, $recharger);
62        } else {
63                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
64                // Les descriptions de types de noisette et les signatures sont stockés dans deux caches distincts.
65                // -- Les descriptions : on conserve la signature pour chaque description, le tableau est réindexé avec l'identifiant
66                //    de la noisette.
67                // -- Les signatures : on isole la liste des signatures et on indexe le tableau avec l'identifiant de la noisette.
68
69                // Initialisation de la sortie.
70                $retour = true;
71
72                include_spip('inc/ncore_cache');
73                if ($recharger) {
74                        // Si le rechargement est forcé, tous les types de noisette sont nouveaux, on peut donc écraser les caches
75                        // existants sans s'en préoccuper.
76                        $descriptions = array_column($types_noisette['a_ajouter'], null, 'type_noisette');
77                        cache_ecrire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_DESCRIPTION, $descriptions);
78
79                        $signatures = array_column($types_noisette['a_ajouter'], 'signature', 'type_noisette');
80                        cache_ecrire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_SIGNATURE, $signatures);
81                } else {
82                        // On lit les cache existants et on applique les modifications.
83                        $descriptions = cache_lire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_DESCRIPTION);
84                        $signatures = cache_lire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_SIGNATURE);
85
86                        // On supprime les noisettes obsolètes
87                        if (!empty($types_noisette['a_effacer'])) {
88                                $descriptions_obsoletes = array_column($types_noisette['a_effacer'], null, 'type_noisette');
89                                $descriptions = array_diff($descriptions, $descriptions_obsoletes);
90
91                                $signatures_obsoletes = array_column($types_noisette['a_effacer'], 'signature', 'type_noisette');
92                                $signatures = array_diff($signatures, $signatures_obsoletes);
93                        }
94
95                        // On remplace les noisettes modifiées et on ajoute les noisettes nouvelles. Cette opération peut-être
96                        // réalisée en une action avec la fonction array_merge.
97                        if (!empty($types_noisette['a_changer']) or !empty($types_noisette['a_ajouter'])) {
98                                $descriptions_modifiees = array_column($types_noisette['a_changer'], null, 'type_noisette');
99                                $descriptions_nouvelles = array_column($types_noisette['a_ajouter'], null, 'type_noisette');
100                                $descriptions = array_merge($descriptions, $descriptions_modifiees, $descriptions_nouvelles);
101
102                                $signatures_modifiees = array_column($types_noisette['a_changer'], 'signature', 'type_noisette');
103                                $signatures_nouvelles = array_column($types_noisette['a_ajouter'], 'signature', 'type_noisette');
104                                $signatures = array_merge($signatures, $signatures_modifiees, $signatures_nouvelles);
105                        }
106
107                        // On recrée les caches.
108                        cache_ecrire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_DESCRIPTION, $descriptions);
109                        cache_ecrire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_SIGNATURE, $signatures);
110                }
111        }
112
113        return $retour;
114}
115
116/**
117 * Complète la description d'un type de noisette issue de la lecture de son fichier YAML.
118 *
119 * Le plugin N-Core ne complète pas les types de noisette.
120 *
121 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
122 *
123 * @uses ncore_chercher_service()
124 *
125 * @param string $plugin
126 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
127 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
128 * @param array  $description
129 *        Description du type de noisette issue de la lecture du fichier YAML. Suivant le plugin utilisateur elle
130 *        nécessite d'être compléter avant son stockage.
131 * @param string $stockage
132 *        Identifiant du service de stockage à utiliser si précisé.
133 *
134 * @return array
135 *        Description du type de noisette éventuellement complétée par le plugin utilisateur.
136 */
137function ncore_type_noisette_completer($plugin, $description, $stockage = '') {
138
139        $description_complete = $description;
140
141        // Si le plugin utilisateur complète la description avec des champs spécifiques il doit proposer un service
142        // de complément propre.
143        include_spip('inc/ncore_utils');
144        if ($completer = ncore_chercher_service($plugin, 'type_noisette_completer', $stockage)) {
145                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
146                $description_complete = $completer($plugin, $description);
147        }
148
149        return $description_complete;
150}
151
152/**
153 * Traite les champs textuels de la description brute d'un type de noisette issue de la lecture de l'espace de stockage
154 * avec la fonction typo(). Si le plugin utilisateur complète la description du type de noisette avec de tels champs
155 * textuels il doit donc les traiter dans son service dédié.
156 *
157 * Le plugin N-Core traite toujours les champs `nom` et `description.
158 *
159 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
160 *
161 * @uses ncore_chercher_service()
162 *
163 * @param string $plugin
164 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
165 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
166 * @param array  $description
167 *        Description brute du type de noisette issue de la lecture dans l'espace de stockage du plugin utilisateur.
168 * @param string $stockage
169 *        Identifiant du service de stockage à utiliser si précisé.
170 *
171 * @return array
172 *        Description du type de noisette dont les champs textuels ont été traités avec la fonction typo().
173 */
174function ncore_type_noisette_traiter_typo($plugin, $description, $stockage = '') {
175
176        // N-Core traite toujours les champs nom et description inclus dans les YAML.
177        $description['nom'] = typo($description['nom']);
178        if ($description['description']) {
179                $description['description'] = typo($description['description']);
180        }
181
182        // Si le plugin appelant complète la description du type de noisette avec des champs textuels il doit
183        // proposer un service propre de traitement de ces champs.
184        include_spip('inc/ncore_utils');
185        if ($traiter_typo = ncore_chercher_service($plugin, 'type_noisette_traiter_typo', $stockage)) {
186                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
187                $description = $traiter_typo($plugin, $description);
188        }
189
190        return $description;
191}
192
193/**
194 * Renvoie la description brute d'un type de noisette sans traitement typo ni désérialisation des champs de type
195 * tableau sérialisé.
196 *
197 * Le service N-Core lit la description du type de noisette concerné dans le cache des descriptions.
198 *
199 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
200 *
201 * @uses ncore_chercher_service()
202 * @uses cache_lire()
203 *
204 * @param string $plugin
205 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
206 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
207 * @param string $type_noisette
208 *        Identifiant du type de noisette.
209 * @param string $stockage
210 *        Identifiant du service de stockage à utiliser si précisé.
211 *
212 * @return array
213 *        Tableau de la description du type de noisette. Les champs textuels et les champs de type tableau sérialisé
214 *        sont retournés en l'état.
215 */
216function ncore_type_noisette_decrire($plugin, $type_noisette, $stockage = '') {
217
218        // On cherche le service de stockage à utiliser selon la logique suivante :
219        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
220        // - sinon, on utilise la fonction du plugin appelant si elle existe;
221        // - et sinon, on utilise la fonction de N-Core.
222        include_spip('inc/ncore_utils');
223        if ($decrire = ncore_chercher_service($plugin, 'type_noisette_decrire', $stockage)) {
224                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
225                $description = $decrire($plugin, $type_noisette);
226        } else {
227                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
228                // -- Lecture de toute la description du type de noisette à partir du cache.
229                // -- Les données sont renvoyées brutes sans traitement sur les textes ni sur les tableaux sérialisés.
230
231                // Initialisation de la description à renvoyer.
232                $description = array();
233
234                include_spip('inc/ncore_cache');
235                $descriptions = cache_lire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_DESCRIPTION);
236                if (isset($descriptions[$type_noisette])) {
237                        $description = $descriptions[$type_noisette];
238                }
239        }
240
241        return $description;
242}
243
244/**
245 * Renvoie, pour l'ensemble des types de noisette, l'information brute demandée
246 * ou toute la description si aucune information n'est explicitement demandée.
247 *
248 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
249 *
250 * @uses ncore_chercher_service()
251 * @uses cache_lire()
252 *
253 * @param string $plugin
254 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
255 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
256 * @param string $information
257 *        Identifiant d'un champ de la description d'un type de noisette ou `signature`.
258 *        Si l'argument est vide, la fonction renvoie les descriptions complètes et si l'argument est
259 *        un champ invalide la fonction renvoie un tableau vide.
260 * @param string $stockage
261 *        Identifiant du service de stockage à utiliser si précisé.
262 *
263 * @return array
264 *        Tableau de la forme `[noisette] = information ou description complète`.
265 */
266function ncore_type_noisette_lister($plugin, $information = '', $stockage = '') {
267
268        // On cherche le service de stockage à utiliser selon la logique suivante :
269        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
270        // - sinon, on utilise la fonction du plugin appelant si elle existe;
271        // - et sinon, on utilise la fonction de N-Core.
272        include_spip('inc/ncore_utils');
273        if ($lister = ncore_chercher_service($plugin, 'type_noisette_lister', $stockage)) {
274                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
275                $types_noisettes = $lister($plugin, $information);
276        } else {
277                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
278                // -- Initialisation du tableau de sortie
279                $types_noisettes = array();
280
281                include_spip('inc/ncore_cache');
282                if ($information == 'signature') {
283                        // Les signatures md5 sont sockées dans un fichier cache séparé de celui des descriptions de noisettes.
284                        $types_noisettes = cache_lire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_SIGNATURE);
285                } elseif ($descriptions = cache_lire($plugin, _NCORE_NOMCACHE_TYPE_NOISETTE_DESCRIPTION)) {
286                        if ($information) {
287                                // Si $information n'est pas une colonne valide array_column retournera un tableau vide.
288                                $types_noisettes = array_column($descriptions, $information, 'type_noisette');
289                        } else {
290                                $types_noisettes = $descriptions;
291                        }
292                }
293        }
294
295        return $types_noisettes;
296}
297
298/**
299 * Renvoie la configuration par défaut de l'ajax à appliquer pour la compilation des noisettes.
300 * Cette information est utilisée si la description YAML d'un type noisette ne contient pas de tag ajax
301 * ou contient un tag ajax à `defaut`.
302 *
303 * Le service N-Core considère que toute noisette est par défaut insérée en ajax.
304 *
305 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
306 *
307 * @uses ncore_chercher_service()
308 *
309 * @param string $plugin
310 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
311 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
312 *
313 * @return bool
314 *              `true` si par défaut une noisette est insérée en ajax, `false` sinon.
315 */
316function ncore_type_noisette_initialiser_ajax($plugin) {
317
318        // On cherche le service de stockage à utiliser selon la logique suivante :
319        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
320        // - sinon, on utilise la fonction du plugin appelant si elle existe;
321        // - et sinon, on utilise la fonction de N-Core.
322        include_spip('inc/ncore_utils');
323        if ($configurer = ncore_chercher_service($plugin, 'type_noisette_initialiser_ajax', '')) {
324                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
325                // On autorise la fonction du plugin à retourner autre chose que true ou false si tant est que l'on puisse
326                // en déduire un booléen (par exemple, 'on' et '' comme le retourne une case à cocher du plugin Saisies).
327                $defaut_ajax = $configurer($plugin) ? true : false;
328        } else {
329                // Le service ne propose pas de fonction propre, on utilise celle de N-Core.
330                $defaut_ajax = true;
331        }
332
333        return $defaut_ajax;
334}
335
336/**
337 * Renvoie la configuration par défaut de l'inclusion dynamique à appliquer pour la compilation des noisettes.
338 * Cette information est utilisée si la description YAML d'un type noisette ne contient pas de tag inclusion
339 * ou contient un tag inclusion à `defaut`.
340 *
341 * Le service N-Core considère que toute noisette est par défaut insérée en statique.
342 *
343 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
344 *
345 * @uses ncore_chercher_service()
346 *
347 * @param string $plugin
348 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
349 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
350 *
351 * @return bool
352 *              `true` si par défaut une noisette est insérée en dynamique, `false` sinon.
353 */
354function ncore_type_noisette_initialiser_inclusion($plugin) {
355
356        // On cherche le service de stockage à utiliser selon la logique suivante :
357        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
358        // - sinon, on utilise la fonction du plugin appelant si elle existe;
359        // - et sinon, on utilise la fonction de N-Core.
360        include_spip('inc/ncore_utils');
361        if ($configurer = ncore_chercher_service($plugin, 'type_noisette_initialiser_inclusion', '')) {
362                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
363                // On autorise la fonction du plugin à retourner autre chose que true ou false si tant est que l'on puisse
364                // en déduire un booléen (par exemple, 'on' et '' comme le retourne une case à cocher du plugin Saisies).
365                $defaut_inclusion = $configurer($plugin) ? true : false;
366        } else {
367                // Le service ne propose pas de fonction propre, on utilise celle de N-Core.
368                $defaut_inclusion = false;
369        }
370
371        return $defaut_inclusion;
372}
373
374/**
375 * Renvoie la configuration par défaut du dossier relatif où trouver les types de noisettes.
376 * Cette information est utilisée a minima au chargement des types de noisettes disponibles.
377 *
378 * Le service N-Core considère que par défaut le dossier relatif des types de noisette est 'noisettes/'.
379 *
380 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
381 *
382 * @uses ncore_chercher_service()
383 *
384 * @param string $plugin
385 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
386 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
387 *
388 * @return string
389 *              Chemin relatif du dossier où chercher les types de noisette.
390 */
391function ncore_type_noisette_initialiser_dossier($plugin) {
392
393        // On cherche le service de stockage à utiliser selon la logique suivante :
394        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
395        // - sinon, on utilise la fonction du plugin appelant si elle existe;
396        // - et sinon, on utilise la fonction de N-Core.
397        include_spip('inc/ncore_utils');
398        if ($configurer = ncore_chercher_service($plugin, 'type_noisette_initialiser_dossier', '')) {
399                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
400                // On autorise la fonction du plugin à retourner autre chose que true ou false si tant est que l'on puisse
401                // en déduire un booléen (par exemple, 'on' et '' comme le retourne une case à cocher du plugin Saisies).
402                $dossier = $configurer($plugin);
403        } else {
404                // Le service ne propose pas de fonction propre, on utilise celle de N-Core.
405                $dossier = 'noisettes/';
406        }
407
408        return $dossier;
409}
410
411
412// -----------------------------------------------------------------------
413// ----------------------------- NOISETTES -------------------------------
414// -----------------------------------------------------------------------
415
416/**
417 * Stocke la description d'une nouvelle noisette et calcule son identifiant unique, ou met à jour les paramètres
418 * d'affichage d'une noisette existante.
419 *
420 * @package SPIP\NCORE\NOISETTE\SERVICE
421 *
422 * @uses ncore_chercher_service()
423 *
424 * @param string $plugin
425 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
426 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
427 * @param array  $description
428 *        Description de la noisette. Soit la description ne contient pas l'id de la noisette et c'est un ajout,
429 *        soit la description contient l'id et c'est une mise à jour.
430 * @param string $stockage
431 *        Identifiant du service de stockage à utiliser si précisé.
432 *
433 * @return int|string
434 *        Id de la noisette de type entier ou chaine.
435 *        Le stockage N-Core renvoie lui une chaine construite à partir du plugin et de la fonction uniqid()
436 *        ou chaine vide en cas d'erreur.
437 */
438function ncore_noisette_stocker($plugin, $description, $stockage = '') {
439
440        // On cherche le service de stockage à utiliser selon la logique suivante :
441        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
442        // - sinon, on utilise la fonction du plugin appelant si elle existe;
443        // - et sinon, on utilise la fonction de N-Core.
444        include_spip('inc/ncore_utils');
445        if ($stocker = ncore_chercher_service($plugin, 'noisette_stocker', $stockage)) {
446                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
447                $id_noisette = $stocker($plugin, $description);
448        } else {
449                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
450                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
451                //    [id_conteneur][rang] = description
452                //    N-Core calcule un identifiant unique pour la noisette qui sera stocké à l'index 'id_noisette' de sa
453                //    description et qui vaudra uniqid() avec comme préfixe le plugin appelant.
454
455                // Initialisation de l'id de la noisette qui sera fourni en sortie. La valeur chaine vide indique une erreur.
456                $id_noisette = '';
457
458                // On lit la meta de stockage des noisettes pour le plugin appelant.
459                include_spip('inc/config');
460                $noisettes = lire_config("${plugin}_noisettes", array());
461
462                // Détermination de l'identifiant du conteneur qui est inclus dans la description et jamais vide.
463                if (!empty($description['id_conteneur'])) {
464                        $id_conteneur = $description['id_conteneur'];
465
466                        if (empty($description['id_noisette'])) {
467                                // Ajout de la noisette :
468                                // -- la description est complète à l'exception de l'id unique qui est créé à la volée
469                                // -- et on range la noisette avec les noisettes affectées au même conteneur en fonction de son rang.
470                                $description['id_noisette'] = uniqid("${plugin}_");
471                                $noisettes[$id_conteneur][$description['rang_noisette']] = $description;
472                        } else {
473                                // Modification de la noisette :
474                                // -- les identifiants de la noisette sont toujours fournies, à savoir, l'id, le conteneur et le rang.
475                                // -- on utilise le conteneur et le rang pour se positionner sur la noisette concernée.
476                                // -- Les modifications ne concernent que les paramètres d'affichage, cette fonction n'est jamais utilisée
477                                //    pour le changement de rang.
478                                if (isset($noisettes[$id_conteneur][$description['rang_noisette']])) {
479                                        $noisettes[$id_conteneur][$description['rang_noisette']] = array_merge(
480                                                $noisettes[$id_conteneur][$description['rang_noisette']],
481                                                $description
482                                        );
483                                }
484                        }
485
486                        // On met à jour la meta
487                        ecrire_config("${plugin}_noisettes", $noisettes);
488
489                        // On renvoie l'id de la noisette ajoutée ou modifiée.
490                        $id_noisette = $description['id_noisette'];
491                }
492        }
493
494        return $id_noisette;
495}
496
497/**
498 * Transfère une noisette d'un conteneur vers un autre à un rang donné et met à jour la profondeur.
499 * Le rang destination n'est pas vérifié lors du rangement dans le conteneur destination. Il convient
500 * à l'appelant de vérifier que le rang est libre.
501 *
502 * @package SPIP\NCORE\NOISETTE\SERVICE
503 *
504 * @uses ncore_chercher_service()
505 * @uses ncore_noisette_destocker()
506 * @uses ncore_conteneur_construire()
507 *
508 * @param string $plugin
509 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
510 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
511 * @param array  $description
512 *        Description de la noisette à changer de conteneur.
513 * @param string $id_conteneur
514 *        Identifiant unique sous forme de chaine du conteneur destination.
515 * @param int    $rang
516 *        Rang où positionner la noisette dans le conteneur destination. Il faut toujours vérifier au préalable
517 *        que ce rang est libre.
518 * @param int    $profondeur
519 *        Profondeur de la noisette à sa nouvelle position.
520 * @param string $stockage
521 *        Identifiant du service de stockage à utiliser si précisé.
522 *
523 * @return array
524 */
525function ncore_noisette_changer_conteneur($plugin, $description, $id_conteneur, $rang, $profondeur, $stockage = '') {
526
527        // On cherche le service de stockage à utiliser selon la logique suivante :
528        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
529        // - sinon, on utilise la fonction du plugin appelant si elle existe;
530        // - et sinon, on utilise la fonction de N-Core.
531        include_spip('inc/ncore_utils');
532        if ($changer = ncore_chercher_service($plugin, 'noisette_changer_conteneur', $stockage)) {
533                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
534                $description = $changer($plugin, $description, $id_conteneur, $rang, $profondeur);
535        } else {
536                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
537                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
538                //    [id_conteneur][rang] = description
539
540                // On supprime la noisette de son emplacement actuel en utilisant la description.
541                ncore_noisette_destocker('ncore', $description, $stockage);
542
543                // On lit la meta de stockage des noisettes pour le plugin appelant.
544                include_spip('inc/config');
545                $noisettes = lire_config("${plugin}_noisettes", array());
546
547                // On rajoute la description à son emplacement destination en prenant soin de modifier les index id_conteneur,
548                // conteneur, rang_noisette et profondeur qui doivent représenter le conteneur destination.
549                $description['id_conteneur'] = $id_conteneur;
550                $description['conteneur'] = ncore_conteneur_construire($plugin, $id_conteneur, $stockage);
551                $description['rang_noisette'] = $rang;
552                $description['profondeur'] = $profondeur;
553                $noisettes[$id_conteneur][$rang] = $description;
554
555                // On met à jour la meta
556                ecrire_config("${plugin}_noisettes", $noisettes);
557        }
558
559        return $description;
560}
561
562/**
563 * Complète la description d'une noisette avec des champs spécifiques au plugin utilisateur si besoin.
564 *
565 * Le plugin N-Core ne complète pas les descriptions de noisette.
566 *
567 * @package SPIP\NCORE\NOISETTE\SERVICE
568 *
569 * @uses ncore_chercher_service()
570 *
571 * @param string $plugin
572 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
573 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
574 * @param array  $description
575 *        Description standard de la noisette. Suivant le plugin utilisateur elle nécessite d'être compléter
576 *        avant son stockage.
577 * @param string $stockage
578 *        Identifiant du service de stockage à utiliser si précisé.
579 *
580 * @return array
581 *        Description de la noisette éventuellement complétée par le plugin utilisateur.
582 */
583function ncore_noisette_completer($plugin, $description, $stockage = '') {
584
585        $description_complete = $description;
586
587        // On cherche le service de stockage à utiliser selon la logique suivante :
588        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
589        // - sinon, on utilise la fonction du plugin appelant si elle existe;
590        // - et sinon, on utilise la fonction de N-Core.
591        include_spip('inc/ncore_utils');
592        if ($completer = ncore_chercher_service($plugin, 'noisette_completer', $stockage)) {
593                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
594                $description_complete = $completer($plugin, $description);
595        }
596
597        return $description_complete;
598}
599
600/**
601 * Traite les champs textuels de la description brute d'une noisette issue de la lecture de l'espace de stockage
602 * avec la fonction typo(). Si le plugin utilisateur complète la description de la noisette avec de tels champs
603 * textuels il doit donc les traiter dans son service dédié.
604 *
605 * Le plugin N-Core n'a aucun champ textuel à traiter dans la description de base d'une noisette.
606 *
607 * @package SPIP\NCORE\TYPE_NOISETTE\SERVICE
608 *
609 * @uses ncore_chercher_service()
610 *
611 * @param string $plugin
612 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
613 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
614 * @param array  $description
615 *        Description brute de la noisette issue de la lecture dans l'espace de stockage du plugin utilisateur.
616 * @param string $stockage
617 *        Identifiant du service de stockage à utiliser si précisé.
618 *
619 * @return array
620 *        Description du type de noisette dont les champs textuels ont été traités avec la fonction typo().
621 */
622function ncore_noisette_traiter_typo($plugin, $description, $stockage = '') {
623
624        // N-Core n'a aucun champ textuel à traiter dans la description de base d'une noisette.
625        // Si le plugin appelant complète la description du type de noisette avec des champs textuels il doit
626        // proposer un service propre de traitement de ces champs.
627        include_spip('inc/ncore_utils');
628        if ($traiter_typo = ncore_chercher_service($plugin, 'noisette_traiter_typo', $stockage)) {
629                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
630                $description = $traiter_typo($plugin, $description);
631        }
632
633        return $description;
634}
635
636
637/**
638 * Positionne une noisette à un rang différent de celui qu'elle occupe dans le conteneur.
639 *
640 * @package SPIP\NCORE\NOISETTE\SERVICE
641 *
642 * @uses ncore_chercher_service()
643 *
644 * @param string $plugin
645 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
646 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
647 * @param array  $description
648 *        Description complète de la noisette.
649 * @param int    $rang_destination
650 *        Position à laquelle ranger la noisette au sein du conteneur.
651 * @param string $stockage
652 *        Identifiant du service de stockage à utiliser si précisé.
653 *
654 * @return bool
655 *        `true` si le traitement s'est bien déroulé, `false` sinon.
656 */
657function ncore_noisette_ranger($plugin, $description, $rang_destination, $stockage = '') {
658
659        // On cherche le service de stockage à utiliser selon la logique suivante :
660        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
661        // - sinon, on utilise la fonction du plugin appelant si elle existe;
662        // - et sinon, on utilise la fonction de N-Core.
663        include_spip('inc/ncore_utils');
664        if ($ranger = ncore_chercher_service($plugin, 'noisette_ranger', $stockage)) {
665                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
666                $retour = $ranger($plugin, $description, $rang_destination);
667        } else {
668                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
669                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
670                //    [id_conteneur][rang] = description
671
672                // Initialisation de la sortie.
673                $retour = false;
674
675                // On lit la meta de stockage des noisettes pour le plugin appelant.
676                include_spip('inc/config');
677                $noisettes = lire_config("${plugin}_noisettes", array());
678
679                if (!empty($description['id_conteneur'])) {
680                        $id_conteneur = $description['id_conteneur'];
681
682                        // On ajoute la noisette au rang choisi même si on doit écraser un index existant:
683                        // -- Il est donc nécessaire de gérer la collision en amont de cette fonction.
684                        // -- Par contre, l'ancien rang de la noisette est supprimé sauf si celui-ci est à zéro.
685                        $rang_source = $description['rang_noisette'];
686                        $description['rang_noisette'] = $rang_destination;
687                        $noisettes[$id_conteneur][$rang_destination] = $description;
688                        if ($rang_source != 0) {
689                                unset($noisettes[$id_conteneur][$rang_source]);
690                        }
691
692                        // On met à jour la meta
693                        ecrire_config("${plugin}_noisettes", $noisettes);
694                        $retour = true;
695                }
696        }
697
698        return $retour;
699}
700
701/**
702 * Retire, de l'espace de stockage, une noisette donnée de son conteneur.
703 *
704 * @package SPIP\NCORE\NOISETTE\SERVICE
705 *
706 * @uses ncore_chercher_service()
707 *
708 * @param string       $plugin
709 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
710 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
711 * @param array|string $description
712 *        Description complète de la noisette.
713 * @param string       $stockage
714 *        Identifiant du service de stockage à utiliser si précisé.
715 *
716 * @return bool
717 *        `true` si le traitement s'est bien déroulé, `false` sinon.
718 */
719function ncore_noisette_destocker($plugin, $description, $stockage = '') {
720
721        // On cherche le service de stockage à utiliser selon la logique suivante :
722        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
723        // - sinon, on utilise la fonction du plugin appelant si elle existe;
724        // - et sinon, on utilise la fonction de N-Core.
725        include_spip('inc/ncore_utils');
726        if ($destocker = ncore_chercher_service($plugin, 'noisette_destocker', $stockage)) {
727                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
728                $retour = $destocker($plugin, $description);
729        } else {
730                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
731                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
732                //    [id_conteneur][rang] = description
733                // -- $description est soit le tableau descriptif de la noisette, soit le conteneur, et dans ce cas, il faut
734                //    supprimer toutes les noisettes du conteneur.
735
736                // Initialisation de la sortie.
737                $retour = false;
738
739                include_spip('inc/config');
740                $meta_noisettes = lire_config("${plugin}_noisettes", array());
741
742                if (isset($meta_noisettes[$description['id_conteneur']][$description['rang_noisette']])) {
743                        // On supprime une noisette donnée.
744                        unset($meta_noisettes[$description['id_conteneur']][$description['rang_noisette']]);
745                        // Si c'est la dernière noisette du conteneur il faut aussi supprimer l'index correspondant au conteneur.
746                        if (!$meta_noisettes[$description['id_conteneur']]) {
747                                unset($meta_noisettes[$description['id_conteneur']]);
748                        }
749                        ecrire_config("${plugin}_noisettes", $meta_noisettes);
750                        $retour = true;
751                }
752        }
753
754        return $retour;
755}
756
757
758/**
759 * Renvoie un champ ou toute la description des noisettes d'un conteneur ou de tous les conteneurs.
760 * Le tableau retourné est indexé soit par identifiant de noisette soit par identifiant du conteneur et rang
761 * de noisette.
762 *
763 * @package SPIP\NCORE\NOISETTE\SERVICE
764 *
765 * @uses ncore_chercher_service()
766 * @uses ncore_conteneur_identifier()
767 *
768 * @param string $plugin
769 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
770 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
771 * @param array|string $conteneur
772 *        Tableau descriptif du conteneur ou identifiant du conteneur ou vide si on souhaite adresser tous les
773 *        conteneurs.
774 * @param string $information
775 *        Identifiant d'un champ de la description d'une noisette.
776 *        Si l'argument est vide, la fonction renvoie les descriptions complètes et si l'argument est
777 *        un champ invalide la fonction renvoie un tableau vide.
778 * @param string $cle
779 *        Champ de la description d'une noisette servant d'index du tableau. En général on utilisera soit `id_noisette`
780 *        soit `rang_noisette`.
781 * @param string $stockage
782 *        Identifiant du service de stockage à utiliser si précisé.
783 *
784 * @return array
785 *        Tableau de la liste des informations demandées indexé par identifiant de noisette ou par rang.
786 */
787function ncore_noisette_lister($plugin, $conteneur = array(), $information = '', $cle = 'rang_noisette', $stockage = '') {
788
789        // On cherche le service de stockage à utiliser selon la logique suivante :
790        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
791        // - sinon, on utilise la fonction du plugin appelant si elle existe;
792        // - et sinon, on utilise la fonction de N-Core.
793        include_spip('inc/ncore_utils');
794        if ($lister = ncore_chercher_service($plugin, 'noisette_lister', $stockage)) {
795                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
796                $noisettes = $lister($plugin, $conteneur, $information, $cle);
797        } else {
798                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
799                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
800                //    [id_conteneur][rang] = description
801
802                // Initialisation du tableau de sortie.
803                $noisettes = array();
804
805                include_spip('inc/config');
806                $meta_noisettes = lire_config("${plugin}_noisettes", array());
807
808                if ($conteneur) {
809                        // On détermine l'id du conteneur en fonction du mode d'identification du conteneur lors de l'appel.
810                        if (is_array($conteneur)) {
811                                $id_conteneur = ncore_conteneur_identifier($plugin, $conteneur, $stockage);
812                        } else {
813                                $id_conteneur = $conteneur;
814                        }
815                        if (!empty($meta_noisettes[$id_conteneur])) {
816                                $noisettes = $meta_noisettes[$id_conteneur];
817                                $noisettes = $information
818                                        ? array_column($noisettes, $information, $cle)
819                                        : array_column($noisettes, null, $cle);
820                        }
821                } elseif ($meta_noisettes) {
822                        if ($cle == 'rang_noisette') {
823                                $noisettes = $meta_noisettes;
824                        } else {
825                                foreach ($meta_noisettes as $_squelette => $_descriptions) {
826                                        $noisettes_squelette = $information
827                                                ? array_column($_descriptions, $information, $cle)
828                                                : array_column($_descriptions, null, $cle);
829                                        $noisettes = array_merge($noisettes, $noisettes_squelette);
830                                }
831                        }
832                }
833        }
834
835        return $noisettes;
836}
837
838
839/**
840 * Renvoie la description brute d'une noisette sans traitement typo des champs textuels ni désérialisation
841 * des champs de type tableau sérialisé.
842 *
843 * @package SPIP\NCORE\NOISETTE\SERVICE
844 *
845 * @uses ncore_chercher_service()
846 *
847 * @param string $plugin
848 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
849 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
850 * @param mixed  $noisette
851 *        Identifiant de la noisette qui peut prendre soit la forme d'un entier ou d'une chaine unique, soit la forme
852 *        d'un couple (conteneur, rang de noisette).
853 * @param string $stockage
854 *        Identifiant du service de stockage à utiliser si précisé.
855 *
856 * @return array
857 *        Tableau de la description du type de noisette. Les champs textuels et les champs de type tableau sérialisé
858 *        sont retournés en l'état.
859 */
860function ncore_noisette_decrire($plugin, $noisette, $stockage = '') {
861
862        // On cherche le service de stockage à utiliser selon la logique suivante :
863        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
864        // - sinon, on utilise la fonction du plugin appelant si elle existe;
865        // - et sinon, on utilise la fonction de N-Core.
866        include_spip('inc/ncore_utils');
867        if ($decrire = ncore_chercher_service($plugin, 'noisette_decrire', $stockage)) {
868                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
869                $description = $decrire($plugin, $noisette);
870        } else {
871                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
872                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
873                //    [id_conteneur][rang] = description
874
875                // Initialisation de la description à retourner.
876                $description = array();
877
878                include_spip('inc/config');
879                $meta_noisettes = lire_config("${plugin}_noisettes", array());
880
881                // On recherche la description dans la meta.
882                if ($meta_noisettes) {
883                        if (!is_array($noisette)) {
884                                // L'identifiant est l'id unique de la noisette. Il faut donc parcourir le tableau pour trouver la
885                                // noisette désirée
886                                // => ce n'est pas la méthode optimale pour le stockage N-Core.
887                                $noisette_trouvee = false;
888                                foreach ($meta_noisettes as $_noisettes_squelette) {
889                                        foreach ($_noisettes_squelette as $_noisette) {
890                                                if ($_noisette['id_noisette'] == $noisette) {
891                                                        $description = $_noisette;
892                                                        $noisette_trouvee = true;
893                                                        break;
894                                                }
895                                        }
896                                        if ($noisette_trouvee) {
897                                                break;
898                                        }
899                                }
900                        } else {
901                                if (isset($noisette['id_conteneur'], $noisette['rang_noisette'])) {
902                                        // Détermination de l'identifiant du conteneur.
903                                        $id_conteneur = $noisette['id_conteneur'];
904                                        if (!empty($meta_noisettes[$id_conteneur][$noisette['rang_noisette']])) {
905                                        // L'identifiant est un tableau associatif fournissant le conteneur et le rang.
906                                        // Comme la meta de N-Core est structurée ainsi c'est la méthode la plus adaptée pour adresser
907                                        // le stockage de N-Core.
908                                        $description = $meta_noisettes[$id_conteneur][$noisette['rang_noisette']];
909                                        }
910                                }
911                        }
912                }
913        }
914
915        return $description;
916}
917
918/**
919 * Renvoie la configuration par défaut de l'encapsulation d'une noisette.
920 * Cette information est utilisée si le champ `encapsulation` de la noisette vaut `defaut`.
921 *
922 * Le service N-Core positionne cette valeur à `true`.
923 *
924 * @package SPIP\NCORE\NOISETTE\SERVICE
925 *
926 * @uses ncore_chercher_service()
927 *
928 * @param string $plugin
929 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
930 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
931 *
932 * @return bool
933 *              `true` si par défaut une noisette est encapsulée, `false` sinon.
934 */
935function ncore_noisette_initialiser_encapsulation($plugin) {
936
937        // On cherche le service de stockage à utiliser selon la logique suivante :
938        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
939        // - sinon, on utilise la fonction du plugin appelant si elle existe;
940        // - et sinon, on utilise la fonction de N-Core.
941        include_spip('inc/ncore_utils');
942        if ($configurer = ncore_chercher_service($plugin, 'noisette_initialiser_encapsulation', '')) {
943                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
944                // On autorise la fonction du plugin à retourner autre chose que true ou false si tant est que l'on puisse
945                // en déduire un booléen (par exemple, 'on' et '' comme le retourne une case à cocher du plugin Saisies).
946                $defaut_capsule = $configurer($plugin) ? true : false;
947        } else {
948                // Le service ne propose pas de fonction propre, on utilise celle de N-Core.
949                $defaut_capsule = true;
950        }
951
952        return $defaut_capsule;
953}
954
955
956// -----------------------------------------------------------------------
957// ----------------------------- CONTENEURS ------------------------------
958// -----------------------------------------------------------------------
959
960/**
961 * Vérifie la conformité des index du tableau représentant le conteneur et supprime les index inutiles, si besoin.
962 * N-Core vérifie que pour les noisettes conteneur les seuls index sont le type et l'id de la noisette.
963 * Pour les autres conteneurs, c'est au plugin utilisateur de vérifier le conteneur.
964 *
965 * @package SPIP\NCORE\CONTENEUR\SERVICE
966 *
967 * @uses ncore_chercher_service()
968 *
969 * @param string $plugin
970 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
971 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
972 * @param array  $conteneur
973 *        Tableau associatif descriptif du conteneur dont les index doivent être vérifiés.
974 * @param string $stockage
975 *        Identifiant du service de stockage à utiliser si précisé.
976 *
977 * @return array
978 *        Tableau du conteneur dont tous les index sont conformes ou tableau vide si non conforme.
979 */
980function ncore_conteneur_verifier($plugin, $conteneur, $stockage = '') {
981
982        static $index_conteneur_noisette = array('type_noisette', 'id_noisette');
983
984        // N-Core ne vérifie pas les conteneurs spécifiques aux plugins utilisateur
985        // sauf pour les noisettes conteneur qui ne sont déterminées que par leur type et leur id.
986        // Il est donc indispensable que le plugin utilisateur propose toujours une fonction de vérification
987        // pour les conteneurs hors noisette conteneur.
988        $conteneur_verifie = array();
989        if ($conteneur) {
990                if (isset($conteneur['type_noisette'], $conteneur['id_noisette'])
991                and $conteneur['type_noisette']
992                and intval($conteneur['id_noisette'])) {
993                        // Le conteneur est une noisette, N-Core effectue le filtre des index.
994                        $conteneur = array_intersect_key($conteneur, array_flip($index_conteneur_noisette));
995                        if (count($conteneur) == 2) {
996                                $conteneur_verifie = $conteneur;
997                        }
998                } else {
999                        // Le conteneur est spécifique au plugin utilisateur, c'est donc au plugin faire la vérification des index.
1000                        include_spip('inc/ncore_utils');
1001                        if ($verifier = ncore_chercher_service($plugin, 'conteneur_verifier', $stockage)) {
1002                                $conteneur_verifie = $verifier($plugin, $conteneur);
1003                        }
1004                }
1005        }
1006
1007        return $conteneur_verifie;
1008}
1009
1010/**
1011 * Construit un identifiant unique pour le conteneur sous forme de chaine.
1012 * N-Core ne fournit d'identifiant que pour les noisettes conteneur.
1013 * Pour les autres conteneurs, c'est au plugin utilisateur de calculer l'identifiant.
1014 *
1015 * @package SPIP\NCORE\CONTENEUR\SERVICE
1016 *
1017 * @uses ncore_chercher_service()
1018 *
1019 * @param string $plugin
1020 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
1021 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
1022 * @param array  $conteneur
1023 *        Tableau associatif descriptif du conteneur. Les index sont spécifiques à l'utilisation qui en est faite
1024 *        par le plugin utilisateur. Néanmoins, pour une noisette conteneur, le tableau est limité aux index
1025 *        type de noisette et id de noisette.
1026 * @param string $stockage
1027 *        Identifiant du service de stockage à utiliser si précisé.
1028 *
1029 * @return string
1030 *        Identifiant du conteneur ou chaine vide en cas d'erreur.
1031 */
1032function ncore_conteneur_identifier($plugin, $conteneur, $stockage = '') {
1033
1034        // Il faut calculer l'identifiant du conteneur pour accéder à la bonne liste de noisettes.
1035        // N-Core ne propose pas de fonction par défaut pour les conteneurs spécifiques aux plugins utilisateur
1036        // sauf pour les noisettes conteneur car elles ne sont déterminées que par leur type et leur id.
1037        // Il est donc indispensable que le plugin utilisateur propose toujours une fonction de calcul de l'identifiant
1038        // pour les conteneurs hors noisette conteneur.
1039        $id_conteneur = '';
1040        if ($conteneur) {
1041                if (isset($conteneur['type_noisette'], $conteneur['id_noisette'])
1042                and $conteneur['type_noisette']
1043                and intval($conteneur['id_noisette'])) {
1044                        // Le conteneur est une noisette, N-Core effectue le calcul de l'id.
1045                        $id_conteneur = $conteneur['type_noisette'] . '|noisette|' . $conteneur['id_noisette'];
1046                } else {
1047                        // Le conteneur est spécifique au plugin utilisateur, c'est donc au plugin de le calculer.
1048                        include_spip('inc/ncore_utils');
1049                        if ($identifier = ncore_chercher_service($plugin, 'conteneur_identifier', $stockage)) {
1050                                $id_conteneur = $identifier($plugin, $conteneur);
1051                        }
1052                }
1053        }
1054
1055        return $id_conteneur;
1056}
1057
1058/**
1059 * Reconstruit le conteneur sous forme de tableau à partir de son identifiant unique (fonction inverse
1060 * de `ncore_conteneur_identifier`).
1061 * N-Core ne fournit le conteneur que pour les noisettes conteneur.
1062 * Pour les autres conteneurs, c'est au plugin utilisateur de calculer le tableau.
1063 *
1064 * @package SPIP\NCORE\CONTENEUR\SERVICE
1065 *
1066 * @uses ncore_chercher_service()
1067 *
1068 * @param string $plugin
1069 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
1070 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
1071 * @param string $id_conteneur
1072 *        Identifiant unique du conteneur. Si l'id correspond à une noisette conteneur le traitement sera fait
1073 *        par N-Core, sinon par le plugin utilisateur
1074 * @param string $stockage
1075 *        Identifiant du service de stockage à utiliser si précisé.
1076 *
1077 * @return array
1078 *        Tableau représentatif du conteneur ou tableau vide en cas d'erreur.
1079 */
1080function ncore_conteneur_construire($plugin, $id_conteneur, $stockage = '') {
1081
1082        // Il faut recomposer le tableau du conteneur à partir de son id.
1083        // N-Core ne propose pas de fonction par défaut pour les conteneurs spécifiques aux plugins utilisateur
1084        // sauf pour les noisettes conteneur.
1085        // Il est donc indispensable que le plugin utilisateur propose toujours une fonction de calcul du tableau
1086        // pour les conteneurs hors noisette conteneur.
1087        $conteneur = array();
1088        if ($id_conteneur) {
1089                $elements = explode('|', $id_conteneur);
1090                if ((count($elements) == 3) and ($elements[1] == 'noisette')) {
1091                        // C'est une noisette conteneur : les index sont le type et l'id de noisette.
1092                        $conteneur['type_noisette'] = $elements[0];
1093                        $conteneur['id_noisette'] = intval($elements[2]);
1094                } else {
1095                        // Le conteneur est spécifique au plugin utilisateur, c'est donc au plugin de le calculer.
1096                        include_spip('inc/ncore_utils');
1097                        if ($construire = ncore_chercher_service($plugin, 'conteneur_construire', $stockage)) {
1098                                $conteneur = $construire($plugin, $id_conteneur);
1099                        }
1100                }
1101        }
1102
1103        return $conteneur;
1104}
1105
1106/**
1107 * Détermine si un conteneur est une noisette ou pas. Le conteneur a été vérifié au préalable.
1108 * Ce service est le seul a ne pas être surchargeable par un plugin utilisateur car les noisettes conteneur
1109 * sont gérées entièrement par N-Core.
1110 *
1111 * @package SPIP\NCORE\CONTENEUR\SERVICE
1112 *
1113 * @param string $plugin
1114 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
1115 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
1116 * @param array $conteneur
1117 *        Identifiant du conteneur sous forme de tableau canonique.
1118 * @param string $stockage
1119 *        Identifiant du service de stockage à utiliser si précisé.
1120 *
1121 * @return bool
1122 *        `true` si le conteneur est une noisette `false` sinon.
1123 */
1124function ncore_conteneur_est_noisette($plugin, $conteneur, $stockage = '') {
1125
1126        // Initialiser la sortie
1127        $est_noisette = false;
1128
1129        // On détermine à partir du tableau si le conteneur est une noisette.
1130        if (isset($conteneur['type_noisette'], $conteneur['id_noisette'])
1131        and $conteneur['type_noisette']
1132        and intval($conteneur['id_noisette'])) {
1133                $est_noisette = true;
1134        }
1135
1136        return $est_noisette;
1137}
1138
1139/**
1140 * Retire, de l'espace de stockage, toutes les noisettes d'un conteneur et ce de façon récursive si
1141 * il existe une imbrication de conteneurs.
1142 *
1143 * @package SPIP\NCORE\CONTENEUR\SERVICE
1144 *
1145 * @uses ncore_noisette_lister()
1146 * @uses ncore_conteneur_destocker()
1147 * @uses ncore_chercher_service()
1148 * @uses ncore_conteneur_identifier()
1149 *
1150 * @param string       $plugin
1151 *        Identifiant qui permet de distinguer le module appelant qui peut-être un plugin comme le noiZetier ou
1152 *        un script. Pour un plugin, le plus pertinent est d'utiliser le préfixe.
1153 * @param array|string $conteneur
1154 *        Tableau descriptif du conteneur ou identifiant du conteneur.
1155 * @param string       $stockage
1156 *        Identifiant du service de stockage à utiliser si précisé.
1157 *
1158 * @return bool
1159 *        `true` si le traitement s'est bien déroulé, `false` sinon.
1160 */
1161function ncore_conteneur_destocker($plugin, $conteneur, $stockage = '') {
1162
1163        // Initialisation de la sortie.
1164        $retour = false;
1165
1166        // On liste les noisettes du conteneur concerné et on repère les noisettes conteneur.
1167        // Chaque conteneur imbriqué est vidé et ce de façon récursive.
1168        foreach (ncore_noisette_lister($plugin, $conteneur, '', 'rang_noisette', $stockage) as $_noisette) {
1169                if ($_noisette['est_conteneur'] == 'oui') {
1170                        // On vide récursivement les noisettes de type conteneur.
1171                        ncore_conteneur_destocker($plugin, $_noisette, $stockage);
1172                }
1173        }
1174
1175        // On cherche le service de stockage à utiliser selon la logique suivante :
1176        // - si le service de stockage est non vide on l'utilise en considérant que la fonction existe forcément;
1177        // - sinon, on utilise la fonction du plugin appelant si elle existe;
1178        // - et sinon, on utilise la fonction de N-Core.
1179        include_spip('inc/ncore_utils');
1180        if ($destocker = ncore_chercher_service($plugin, 'conteneur_destocker', $stockage)) {
1181                // On passe le plugin appelant à la fonction car cela permet ainsi de mutualiser les services de stockage.
1182                $retour = $destocker($plugin, $conteneur);
1183        } else {
1184                // Le plugin ne propose pas de fonction propre ou le stockage N-Core est explicitement demandé.
1185                // -- N-Core stocke les noisettes dans une meta propre au plugin appelant contenant un tableau au format
1186                //    [conteneur][rang] = description
1187                include_spip('inc/config');
1188                $meta_noisettes = lire_config("${plugin}_noisettes", array());
1189
1190                // On détermine l'id du conteneur en fonction du mode d'identification du conteneur lors de l'appel.
1191                if (is_array($conteneur)) {
1192                        $id_conteneur = ncore_conteneur_identifier($plugin, $conteneur, $stockage);
1193                } else {
1194                        $id_conteneur = $conteneur;
1195                }
1196
1197                if (isset($meta_noisettes[$id_conteneur])) {
1198                        // On supprime toutes les noisettes du conteneur.
1199                        unset($meta_noisettes[$id_conteneur]);
1200                        ecrire_config("${plugin}_noisettes", $meta_noisettes);
1201                        $retour = true;
1202                }
1203        }
1204
1205        return $retour;
1206}
Note: See TracBrowser for help on using the repository browser.