source: spip-zone/_plugins_/roles/trunk/inc/roles.php @ 64042

Last change on this file since 64042 was 64042, checked in by marcimat@…, 7 years ago

Petit oups

File size: 10.5 KB
Line 
1<?php
2
3/**
4 * Plugin Rôles
5 * (c) 2012 Marcillaud Matthieu
6 * Licence GNU/GPL
7 *
8 * Gestion des rôles
9 *
10 * Les rôles sont une qualification précise sur une liaison entre
11 * deux objets. Ils doivent être définis dans la déclaration d'un objet
12 * pour être utilisés. Ils s'appliquent sur une colonne particulière
13 * de la table de liaison, par défaut 'role'.
14 *
15 * Cette table de liaison, lorsqu'elle a des rôles n'a plus sa clé primaire
16 * sur le couple (id_x, objet, id_objet) mais sur (id_x, objet, id_objet, colonne_role)
17 * de sorte qu'il peut exister plusieurs liens entre 2 objets, mais avec
18 * des rôles différents. Chaque ligne de la table lien correspond alors à
19 * un des rôles.
20 */
21
22if (!defined('_ECRIRE_INC_VERSION')) return;
23
24
25
26/**
27 * Vérifie qu'un objet dispose de rôles fonctionnels
28 *
29 * Retourne une description des rôles si c'est le cas
30 *
31 * @param string $objet
32 *     Objet source qui possède la table de liaison
33 * @param string $objet_destination
34 *     Objet sur quoi on veut lier
35 *     Si défini, le retour ne contient que les roles possibles pour cet objet
36 *     Sinon retourne tous les roles possibles quelque soit l'objet
37 * @return bool|array
38 *     false si rôles indisponibles on non déclarés
39 *     array : description des roles applicables dans 3 index : colonne, titres, roles
40**/
41function roles_presents($objet, $objet_destination='') {
42        $desc = lister_tables_objets_sql(table_objet_sql($objet));
43
44        // pas de liste de roles, on sort
45        if (!isset($desc['roles_titres']) OR !($titres = $desc['roles_titres'])) {
46                return false;
47        }
48
49        // on vérifie que la table de liaison existe
50        include_spip('action/editer_liens');
51        if (!$lien = objet_associable($objet)) {
52                return false;
53        }
54
55        // on cherche ensuite si la colonne existe bien dans la table de liaison (par défaut 'role')
56        $colonne = isset($desc['roles_colonne']) ? $desc['roles_colonne'] : 'role';
57        $trouver_table = charger_fonction('trouver_table', 'base');
58        list(,$table_lien) = $lien;
59        $desc_lien = $trouver_table($table_lien);
60        if (!isset($desc_lien['field'][$colonne])) {
61                return false;
62        }
63
64        // sur quoi peuvent s'appliquer nos rôles
65        if (!$application = $desc['roles_objets']) {
66                return false;
67        }
68
69        // destination presente, on restreint si possible
70        if ($objet_destination) {
71                $objet_destination = table_objet($objet_destination);
72
73                // pour l'objet
74                if (isset($application[$objet_destination])) {
75                        $application = $application[$objet_destination];
76                // sinon pour tous les objets
77                } elseif (isset($application['*'])) {
78                        $application = $application['*'];
79                }
80                // sinon tant pis
81                else {
82                        return false;
83                }
84        }
85
86        // tout est ok
87        return array(
88                'titres'  => $titres,
89                'roles'   => $application,
90                'colonne' => $colonne
91        );
92}
93
94/**
95 * Retrouve la colonne de liaison d'un rôle si définie entre 2 objets
96 *
97 * @param string $objet
98 *     Objet source qui possède la table de liaison
99 * @param string $objet_destination
100 *     Objet sur quoi on veut lier
101 * @return string
102 *     Nom de la colonne, sinon vide
103**/
104function roles_colonne($objet, $objet_destination) {
105        if ($roles = roles_presents($objet, $objet_destination)) {
106                return $roles['colonne'];
107        }
108        return '';
109}
110
111
112/**
113 * Extrait le rôle et la colonne de role d'un tableau de qualification
114 *
115 * Calcule également une condition where pour ce rôle.
116 *
117 * Pour un objet pouvant recevoir des roles sur sa liaison avec un autre objet,
118 * on retrouve le rôle en question dans le tableau de qualification.
119 * Si le rôle n'est pas défini dedans, on prend le rôle par défaut
120 * déclaré.
121 * 
122 * @param string $objet               Objet source de la liaison
123 * @param string $objet_destination   Objet de destination de la liaison
124 * @param array  $qualif              tableau de qualifications array(champ => valeur)
125 * @return array
126 *     Liste (role, colonne, (array)condition) si role possible
127 *     Liste ('', '', array()) sinon.
128**/
129function roles_trouver_dans_qualif($objet, $objet_destination, $qualif = array()) {
130        // si des rôles sont possibles, on les utilise
131        $role = $colonne_role = ''; # role défini
132        // condition du where par defaut
133        $cond = array();
134        if ($roles = roles_presents($objet, $objet_destination)) {
135                $colonne_role = $roles['colonne'];
136                // qu'il n'est pas défini
137                if (!isset($qualif[$colonne_role])
138                  OR !($role = $qualif[$colonne_role])) {
139                        $role = $roles['roles']['defaut'];
140                }
141                // where
142                $cond = array("$colonne_role=" . sql_quote($role));
143        }
144
145        return array($role, $colonne_role, $cond);
146}
147
148/**
149 * Gérer l'ajout dans la condition where du rôle
150 *
151 * On ajoute la condition uniquement si la liaison entre les 2 objets a une colonne de rôle !
152 *
153 * @param string $objet_source   Objet source (qui possède la table de liens)
154 * @param string $objet          Objet de destination
155 * @param array $cond
156 *     Tableau de conditions where
157 *     qui peut avoir un index spécial 'role' définissant le role à appliquer
158 *     ou valant '*' pour tous les roles.
159 * @param bool $tous_si_absent
160 *     true pour ne pas appliquer une condition sur le rôle s'il n'est pas indiqué
161 *     dans la liste des conditions entrantes. Autrement dit, on n'applique
162 *     pas de rôle par défaut si aucun n'est défini.
163 * @return array
164 *     Liste (Tableau de conditions where complété du role, Colonne du role, role utilisé)
165**/
166function roles_creer_condition_role($objet_source, $objet, $cond, $tous_si_absent = false) {
167        // role par défaut, colonne
168        list($role_defaut, $colonne_role) = roles_trouver_dans_qualif($objet_source, $objet);
169
170        // chercher d'eventuels rôles transmis
171        $role = isset($cond['role']) ? $cond['role'] : ($tous_si_absent ? '' : $role_defaut);
172        unset($cond['role']); // cette condition est particuliere...
173
174        if ($colonne_role and $role) {
175                // on ajoute la condition du role aux autres conditions.
176                if ($role != '*') {
177                        $cond[] = "$colonne_role=" .sql_quote($role);
178                }
179        }
180        return array($cond, $colonne_role, $role);
181}
182
183/**
184 * Liste des identifiants dont on ne peut ajouter de rôle
185 *
186 * Lister les id objet_source associés à l'objet id_objet
187 * via la table de lien objet_lien, et détermine dans cette liste
188 * lesquels ont les rôles complets, c'est à dire qu'on ne peut leur
189 * affecteur d'autres rôles parmi ceux qui existe pour cette liaison.
190 *
191 * @see lister_objets_lies()
192 *
193 * @param string $objet_source Objet dont on veut récupérer la liste des identifiants
194 * @param string $objet        Objet sur lequel est liée la source
195 * @param int $id_objet        Identifiant d'objet sur lequel est liée la source
196 * @param string $objet_lien   Objet dont on utilise la table de liaison (c'est forcément soit $objet_source, soit $objet)
197 * @return array               Liste des identifiants
198 */
199function roles_complets($objet_source, $objet, $id_objet, $objet_lien) {
200
201        $presents = roles_presents_liaisons($objet_source, $objet, $id_objet, $objet_lien);
202        // pas de roles sur ces objets => la liste par defaut, comme sans role
203        if ($presents === false) {
204                return lister_objets_lies($objet_source, $objet, $id_objet, $objet_lien);
205        }
206
207        // types de roles possibles
208        $roles_possibles = $presents['roles']['roles']['choix'];
209        // couples id / roles
210        $ids = $presents['ids'];
211
212        // pour chaque groupe, on fait le diff entre tous les roles possibles
213        // et les roles attribués à l'élément : s'il en reste, c'est que l'élément
214        // n'est pas complet
215        $complets = array();
216        foreach ($ids as $id => $roles_presents) {
217                if (!array_diff($roles_possibles, $roles_presents)) {
218                        $complets[] = $id;
219                }
220        }
221
222        return $complets;
223}
224
225
226
227/**
228 * Liste les roles attribués entre 2 objets/id_objet sur une table de liaison donnée
229 *
230 * @param string $id_objet_source Identifiant de l'objet qu'on lie
231 * @param string $objet_source    Objet qu'on lie
232 * @param string $objet           Objet sur lequel est liée la source
233 * @param int $id_objet           Identifiant d'objet sur lequel est liée la source
234 * @param string $objet_lien      Objet dont on utilise la table de liaison (c'est forcément soit $objet_source, soit $objet)
235 * @return array                  Liste des roles
236 */
237function roles_presents_sur_id($id_objet_source, $objet_source, $objet, $id_objet, $objet_lien) {
238
239        $presents = roles_presents_liaisons($objet_source, $objet, $id_objet, $objet_lien);
240        // pas de roles sur ces objets => la liste par defaut, comme sans role
241        if ($presents === false) {
242                return array();
243        }
244
245        if (!isset($presents['ids'][$id_objet_source])) {
246                return array();
247        }
248
249        return $presents['ids'][$id_objet_source];
250}
251
252
253
254/**
255 * Lister des rôles présents sur une liaion, pour un objet sur un autre,
256 * classés par identifiant de l'objet
257 *
258 * Lister les id objet_source associés à l'objet id_objet
259 * via la table de lien objet_lien, et groupe cette liste
260 * par identifiant (la clé) et ses roles attribués (tableau de valeur)
261 *
262 * On retourne cette liste dans l'index 'ids' et la description des roles
263 * pour la liaison dans l'index 'roles' pour éviter le le faire recalculer
264 * aux fonctions utilisant celle ci.
265 *
266 * @param string $objet_source Objet dont on veut récupérer la liste des identifiants
267 * @param string $objet        Objet sur lequel est liée la source
268 * @param int $id_objet        Identifiant d'objet sur lequel est liée la source
269 * @param string $objet_lien   Objet dont on utilise la table de liaison (c'est forcément soit $objet_source, soit $objet)
270 * @return array|bool
271 *     - Tableau d'index
272 *       - roles : tableau de description des roles,
273 *       - ids   : tableau des identifiants / roles.
274 *     - False si pas de role déclarés
275 */
276function roles_presents_liaisons($objet_source, $objet, $id_objet, $objet_lien) {
277        static $done = array();
278
279        // stocker le résultat
280        $hash = md5($objet_source . $objet . $id_objet . $objet_lien);
281        if (isset($done[$hash])) {
282                return $done[$hash];
283        }
284
285        // pas de roles sur ces objets, on sort
286        $roles = roles_presents($objet_lien, ($objet_lien==$objet) ? $objet_source : $objet);
287        if (!$roles) {
288                return $done[$hash] = false;
289        }
290
291        // inspiré de lister_objets_lies()
292        if ($objet_lien==$objet){
293                $res = objet_trouver_liens(array($objet=>$id_objet),array($objet_source=>'*'));
294        }
295        else{
296                $res = objet_trouver_liens(array($objet_source=>'*'),array($objet=>$id_objet));
297        }
298
299        // types de roles possibles
300        $roles_possibles = $roles['roles']['choix'];
301        // colonne du role
302        $colonne = $roles['colonne'];
303
304        // on recupere par id, et role existant
305        $ids = array();
306        while ($row = array_shift($res)) {
307                $id = $row[$objet_source];
308                if (!isset($ids[$id])) {
309                        $ids[$id] = array();
310                }
311                // tableau des roles présents
312                $ids[$id][] = $row[$colonne];
313        }
314
315        return $done[$hash] = array(
316                'roles' => $roles,
317                'ids' => $ids
318        );
319}
Note: See TracBrowser for help on using the repository browser.