[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / ecrire / inc / filtres_selecteur_generique.php
1 <?php
2
3 /**
4 * Filtres pour les sélecteurs d'objets
5 *
6 * @package SPIP\Core\Filtres\Selecteurs
7 **/
8
9 if (!defined('_ECRIRE_INC_VERSION')) {
10 return;
11 }
12
13 /**
14 * Fournit la liste des objets ayant un sélecteur
15 *
16 * Concrètement, va chercher tous les `formulaires/selecteur/hierarchie-{trucs}.html`
17 * Ensuite on ajoute les parents obligatoires éventuels
18 *
19 * @uses find_all_in_path()
20 *
21 * @param array $whitelist
22 * Liste blanche décrivant les objets à lister
23 * @param array $blacklist
24 * Liste noire décrivant les objets à ne pas lister
25 * @return array
26 * Retourne un tableau de deux entrées listant les objets à lister et les objets sélectionnables
27 * - selectionner : tableau des objets que l'on pourra sélectionner (avec un +)
28 * - afficher : tableau des objets à afficher (mais pas forcément sélectionnables)
29 */
30 function selecteur_lister_objets($whitelist = array(), $blacklist = array()) {
31 static $liste_selecteurs, $liste_parents;
32
33 if (!$liste_selecteurs) {
34 $liste_selecteurs = find_all_in_path('formulaires/selecteur/', 'hierarchie-[\w]+[.]html$');
35 }
36 $objets_selectionner = array();
37 foreach ($liste_selecteurs as $fichier => $chemin) {
38 $objets_selectionner[] = preg_replace('/^hierarchie-([\w]+)[.]html$/', '$1', $fichier);
39 }
40
41 // S'il y a une whitelist on ne garde que ce qui est dedans
42 if (!empty($whitelist)) {
43 $whitelist = array_map('table_objet', $whitelist);
44 $objets_selectionner = array_intersect($objets_selectionner, $whitelist);
45 }
46 // On supprime ce qui est dans la blacklist
47 $blacklist = array_map('table_objet', $blacklist);
48 // On enlève toujours la racine
49 $blacklist[] = 'racine';
50 $objets_selectionner = array_diff($objets_selectionner, $blacklist);
51
52 // Ensuite on cherche ce qu'on doit afficher : au moins ceux qu'on peut sélectionner
53 $objets_afficher = $objets_selectionner;
54
55 // Il faut alors chercher d'éventuels parents obligatoires en plus :
56 // lister-trucs-bidules.html => on doit afficher des "trucs" pour trouver des "bidules"
57 if (!$liste_parents) {
58 $liste_parents = find_all_in_path('formulaires/selecteur/', 'lister-[\w]+-[\w]+[.]html$');
59 }
60 foreach ($liste_parents as $fichier => $chemin) {
61 preg_match('/^lister-([\w]+)-([\w]+)[.]html$/', $fichier, $captures);
62 $parent = $captures[1];
63 $type = $captures[2];
64 // Si le type fait partie de ce qu'on doit afficher alors on ajoute aussi le parent à l'affichage
65 if (in_array($type, $objets_afficher)) {
66 $objets_afficher[] = $parent;
67 }
68 }
69
70 $objets = array(
71 'selectionner' => array_unique($objets_selectionner),
72 'afficher' => array_unique($objets_afficher),
73 );
74
75 return $objets;
76 }
77
78 /**
79 * Extrait des informations d'un tableau d'entrées `array("rubrique|9", "article|8", ...)`
80 * ou une chaine brute `rubrique|9,article|8,...`
81 *
82 * Peut retourner un tableau de couples (objet => id_objet) ou la liste
83 * des identifiants d'un objet précis si `$type` est fourni.
84 *
85 * @example
86 * `picker_selected(array('article|1', 'article|2', 'rubrique|5'))`
87 * retourne `array('article' => 1, 'article' => 2, 'rubrique' => 5)`
88 * @example
89 * `picker_selected(array('article|1', 'article|2', 'rubrique|5'), 'article')`
90 * retourne `array(1, 2)`
91 *
92 * @filtre
93 *
94 * @param array|string $selected
95 * Liste des entrées : tableau ou chaine séparée par des virgules
96 * @param string $type
97 * Type de valeur à recuperer tel que `rubrique`, `article`
98 * @return array
99 * liste des couples (objets => id_objet) ou liste des identifiants d'un type d'objet.
100 **/
101 function picker_selected($selected, $type = '') {
102 $select = array();
103 $type = preg_replace(',\W,', '', $type);
104
105 if ($selected and !is_array($selected)) {
106 $selected = explode(',', $selected);
107 }
108
109 if (is_array($selected)) {
110 foreach ($selected as $value) {
111 // Si c'est le bon format déjà
112 if (preg_match('/^([\w]+)[|]([0-9]+)$/', $value, $captures)) {
113 $objet = $captures[1];
114 $id_objet = intval($captures[2]);
115
116 // Si on cherche un type et que c'est le bon, on renvoit un tableau que d'identifiants
117 if (is_string($type) and $type == $objet and ($id_objet or in_array($objet, array('racine', 'rubrique')))) {
118 $select[] = $id_objet;
119 } elseif (!$type and ($id_objet or in_array($objet, array('racine', 'rubrique')))) {
120 $select[] = array('objet' => $objet, 'id_objet' => $id_objet);
121 }
122 }
123 }
124 }
125
126 return $select;
127 }
128
129 /**
130 * Récupère des informations sur un objet pour pouvoir l'ajouter aux éléments sélectionnés
131 *
132 * @uses typer_raccourci()
133 *
134 * @param string $ref
135 * Référence de l'objet à chercher, de la forme "type|id", par exemple "rubrique|123".
136 * @param mixed $rubriques_ou_objets
137 * Soit un booléen (pouvant être une chaîne vide aussi) indiquant que les rubriques sont sélectionnables
138 * soit un tableau complet des objets sélectionnables.
139 * @param bool $articles
140 * Booléen indiquant si les articles sont sélectionnables
141 */
142 function picker_identifie_id_rapide($ref, $rubriques_ou_objets = false, $articles = false) {
143 include_spip('inc/json');
144 include_spip('inc/lien');
145
146 // On construit un tableau des objets sélectionnables suivant les paramètres
147 $objets = array();
148 if ($rubriques_ou_objets and is_array($rubriques_ou_objets)) {
149 $objets = $rubriques_ou_objets;
150 } else {
151 if ($rubriques_ou_objets) {
152 $objets[] = 'rubriques';
153 }
154 if ($articles) {
155 $objets[] = 'articles';
156 }
157 }
158
159 // Si la référence ne correspond à rien, c'est fini
160 if (!($match = typer_raccourci($ref))) {
161 return json_export(false);
162 }
163 // Sinon on récupère les infos utiles
164 @list($type, , $id, , , , ) = $match;
165
166 // On regarde si le type trouvé fait partie des objets sélectionnables
167 if (!in_array(table_objet($type), $objets)) {
168 return json_export(false);
169 }
170
171 // Maintenant que tout est bon, on cherche les informations sur cet objet
172 include_spip('inc/filtres');
173 if (!$titre = generer_info_entite($id, $type, 'titre')) {
174 return json_export(false);
175 }
176
177 // On simplifie le texte
178 $titre = attribut_html($titre);
179
180 return json_export(array('type' => $type, 'id' => "$type|$id", 'titre' => $titre));
181 }
182
183 /**
184 * Déterminer si une rubrique a des enfants à afficher ou non
185 *
186 * On test d'abord si la rubrique a des sous rubriques, et sinon on regarde
187 * les autres types sélectionnables, puis on regarde si la rubrique contient
188 * certains de ces objets
189 *
190 * @note
191 * Pour optimiser, la fonction calcule sa valeur sur toute la fratrie d'un coup,
192 * puisqu'elle est appellée N fois pour toutes les rubriques d'un même niveau
193 *
194 * @param int $id_rubrique
195 * Identifiant de la rubrique
196 * @param array $types
197 * Liste de type d'objets. Si l'un de ces objet est présent dans la rubrique,
198 * alors cette rubrique est à afficher
199 * @return string
200 * Comme le filtre `oui` : espace (` `) si rubrique à afficher, chaîne vide sinon.
201 */
202 function test_enfants_rubrique($id_rubrique, $types = array()) {
203 static $has_child = array();
204
205 if (!isset($has_child[$id_rubrique])) {
206 $types = (is_array($types) ? array_filter($types) : array());
207
208 // recuperer tous les freres et soeurs de la rubrique visee
209 $id_parent = sql_getfetsel('id_parent', 'spip_rubriques', 'id_rubrique=' . intval($id_rubrique));
210 $fratrie = sql_allfetsel('id_rubrique', 'spip_rubriques', 'id_parent=' . intval($id_parent));
211 $fratrie = array_map('reset', $fratrie);
212 $has = sql_allfetsel('DISTINCT id_parent', 'spip_rubriques', sql_in('id_parent', $fratrie));
213 $has = array_map('reset', $has);
214 $fratrie = array_diff($fratrie, $has);
215
216 while (count($fratrie) and is_array($types) and count($types)) {
217 $type = array_shift($types);
218 $h = sql_allfetsel('DISTINCT id_rubrique', table_objet_sql($type), sql_in('id_rubrique', $fratrie));
219 $h = array_map('reset', $h);
220 $has = array_merge($has, $h);
221 $fratrie = array_diff($fratrie, $h);
222 }
223
224 if (count($has)) {
225 $has_child = $has_child + array_combine($has, array_pad(array(), count($has), true));
226 }
227 if (count($fratrie)) {
228 $has_child = $has_child + array_combine($fratrie, array_pad(array(), count($fratrie), false));
229 }
230 }
231
232 return $has_child[$id_rubrique] ? ' ' : '';
233 }