Introduction
Définir des rôles sur des liaisons consiste à gérer une colonne supplémentaire sur certaines tables de liaisons spip_x_liens. La clé primaire de la table ne doit alors plus être sur le trio id_x, objet, id_objet, mais sur le quatuor id_x, objet, id_objet, colonne_role. Dit autrement, au lieu d’avoir une seule liaison possible entre X et Y, il peut y en avoir maintenant plusieurs : une par rôle.
Le jeu de ce plugin consiste donc à gérer la déclaration de ces rôles, gérer l’interface pour les saisir et enlever, gérer les traitements en base de données pour ces rôles. Techniquement parlant, cela consiste à prendre en compte des descriptions supplémentaires, concernant les rôles possibles, dans la déclaration de l’objet éditorial ; de modifier le formulaire d’édition de lien pour gérer les rôles lorsqu’il y en a et enfin de modifier l’API de liens pour prendre en compte le changement d’unicité s’il y a des rôles, et les rôles eux-mêmes.
Déclarer les rôles
Tel qu’imaginé actuellement la déclaration des rôles possibles sur la table de liaison d’un objet, se réalise dans la même déclaration que la description de l’objet, via le pipeline declarer_table_objet_sql
donc.
Elle se décompose en 3 nouveaux index dans ce tableau :
-
roles_colonne
indique la colonne utilisée pour placer les rôles -
roles_titres
indique des couples clé de rôle, clé de traduction, indiquant pour chaque type de rôle à quelle chaîne de langue il correspond -
roles_objets
est un tableau indiquant pour chaque objet vers lequel on peut se lier (l’index), la liste des rôles que l’on peut lier (choix), ainsi que le rôle utilisé par défaut lorsqu’il n’est pas précisé au moment de la création de la liaison (defaut). Chaque index est un nom d’objet tel que ’articles’, mais il accepte un index générique ’*’ indiquant quelque soit l’objet.
Voici un exemple complet de déclaration pour lier des auteurs avec des articles avec 4 rôles définis (et utilisés) :
function roles_auteurs_declarer_tables_objets_sql($tables){
array_set_merge($tables, 'spip_auteurs', array(
"roles_colonne" => "role",
"roles_titres" => array(
'redacteur' => 'info_statut_redacteur',
'traducteur' => 'roles_auteurs:traducteur',
'correcteur' => 'roles_auteurs:correcteur',
'relecteur' => 'roles_auteurs:relecteur',
),
"roles_objets" => array(
'articles' => array(
'choix' => array('redacteur', 'traducteur', 'correcteur', 'relecteur'),
'defaut' => 'redacteur'
)
#'*' => array()
)
));
return $tables;
}
Adapter la table de liens
Il y a 3 étapes : la déclaration, l’installation et la désinstallation
Il y a deux cas :
- La table de liaison n’existait pas : c’est le plus simple, par exemple pour gérer un nouvel objet éditorial et ses liaisons
- La table de liaison existe : vous voulez étendre un objet éditorial existant - du moins ses liaisons
1. Table de liaison toute neuve
La déclaration déclare tous les champs de la table, via le pipeline declarer_tables_auxiliaires
, par exemple avec :
function roses_declarer_tables_auxiliaires($tables) {
$tables['spip_roses_liens'] array(
'field' => array(
"id_rose" => "bigint(21) DEFAULT '0' NOT NULL",
"id_objet" => "bigint(21) DEFAULT '0' NOT NULL",
"objet" => "VARCHAR (25) DEFAULT '' NOT NULL",
'role' => "varchar(30) NOT NULL DEFAULT ''",
),
'key' => array(
'PRIMARY KEY' => "id_rose,id_objet,objet,role",
)
);
}
L’installation et la désinstallation ne font que créer la table de liens (et peut être d’autres tables non mentionnées ici qui serait ’spip_roses’ dans notre exemple) :
function roses_upgrade($nom_meta_base_version, $version_cible) {
$maj = array();
$maj['create'] = array(array('maj_tables', array('spip_auteurs_liens')),);
include_spip('base/upgrade');
maj_plugin($nom_meta_base_version, $version_cible, $maj);
}
function roses_vider_tables($nom_meta_base_version) {
sql_drop_table("spip_roses");
effacer_meta($nom_meta_base_version);
}
2. Table de liaison modifiée
La déclaration consiste juste à ajouter la colonne et modifier la clé primaire pour ajouter la colonne dedans. Voici un exemple :
function roles_auteurs_declarer_tables_auxiliaires($tables) {
$tables['spip_auteurs_liens']['field']['role'] = "varchar(30) NOT NULL DEFAULT ''";
$tables['spip_auteurs_liens']['key']['PRIMARY KEY'] = "id_auteur,id_objet,objet,role";
return $tables;
}
L’installation consiste à altérer la table pour modifier la clé primaire et d’ajouter les rôles par défaut aux enregistrements déjà présents.
Voici un exemple avec la liaison d’auteurs. Il faut enlever la clé primaire pour la remettre sur le quatuor de colonnes. Pour chaque liaison vers les articles, et lorsqu’aucun rôle n’est défini, on applique le rôle rédacteur.
function roles_auteurs_upgrade($nom_meta_base_version, $version_cible) {
$maj = array();
$maj['create'] = array(
// supprimer la clé primaire actuelle pour pouvoir en changer en ajoutant la colonne rôle
array('sql_alter', "TABLE spip_auteurs_liens DROP PRIMARY KEY"),
// ajout de la colonne role
array('maj_tables', array('spip_auteurs_liens')),
// la nouvelle colonne est la, mettre sa nouvelle clé primaire
array('sql_alter', "TABLE spip_auteurs_liens ADD PRIMARY KEY (id_auteur,id_objet,objet,role)"),
// on passe par défaut tous les liens auteurs/articles en rôle : redacteur
array('sql_updateq', 'spip_auteurs_liens', array('role' => 'redacteur'), array(
'role=' . sql_quote(''),
'objet=' . sql_quote('article')
))
);
include_spip('base/upgrade');
maj_plugin($nom_meta_base_version, $version_cible, $maj);
}
La désinstallation consiste à faire l’opération inverse : on enlève la clé primaire, les liaisons en doublons, puis la colonne de rôle. On remet ensuite la clé primaire sur le trio de colonne. La clé primaire ne peut pas être remise sur le trio s’il existe des doublons !
function roles_auteurs_vider_tables($nom_meta_base_version) {
// tant qu'il existe des doublons, on supprime une ligne doublonnée
// sinon on ne pourra pas modifier la cle primaire ensuite
// cet algo est certainement a optimiser
while ($doublons = sql_allfetsel(
array('id_auteur', 'id_objet', 'objet', 'role'),
array('spip_auteurs_liens'),
'', 'id_auteur,id_objet,objet', '', '', 'COUNT(*) > 1'))
{
foreach ($doublons as $d) {
$where = array();
foreach ($d as $cle=>$valeur) {
$where[] = "$cle=".sql_quote($valeur);
}
sql_delete('spip_auteurs_liens', $where);
}
}
// supprimer la clé primaire, la colonne rôle, et remettre l'ancienne clé primaire
sql_alter("TABLE spip_auteurs_liens DROP PRIMARY KEY");
sql_alter("TABLE spip_auteurs_liens DROP COLUMN role");
sql_alter("TABLE spip_auteurs_liens ADD PRIMARY KEY (id_auteur,id_objet,objet)");
effacer_meta($nom_meta_base_version);
}
Fournir des squelettes pour les liaisons avec rôles
Pour faire fonctionner un formulaire de liaison habituel, SPIP utilise deux listes par défaut,
- l’une
prive/objets/liste/{objet}_lies.html
gère l’affichage de ce qui est lié, - l’autre
prive/objets/liste/{objet}_associer.html
gère l’affichage de ce qu’on peut lier (il faut en avoir le droit évidemment).
Ces listes n’affichent pas les rôles attribués et ne permettent pas d’en saisir. Ces listes ont par contre un certain nombre d’actions possibles pour ceux qui ont des droits de modifications sur les objets en question, par exemple un bouton « ajouter cet auteur ».
Le choix pris ici a été de dire que si une liaison peut avoir des rôles (ils sont donc déclarés) alors ce n’est pas les mêmes squelettes que l’on appelle mais des nouveaux, qui listent et permettent d’attribuer des rôles. Ils sont respectivement :
-
prive/objets/liste/{objet}_roles_lies.html
et -
prive/objets/liste/{objet}_roles_associer.html
Leur code est semblable en grande partie aux squelettes d’origines, mais quelques points diffèrent :
- ils disposent d’une colonne « Rôles » listant les rôles d’une liaison ou indiquant les rôles qui seront attribués pour une liaison,
- les actions possibles sont légèrement différentes pour tenir compte des rôles.
Par ailleurs, pour obtenir une interface de saisie pratique, ce plugin ajoute 2 librairies JavaScript (et CSS) qui sont Chosen et les boutons dépliants de Bootstrap.
Enfin pour faciliter l’affichage, un filtre |role{objet}
est créé permettant de traduire une clé de rôle pour une table de liaison donnée. De même 2 inclusions permettent de ne modifier que le minimum vis à vis des squelettes de liste d’origine, extrayant ainsi 2 parties complexes et réutilisables.
Les squelettes peuvent donc déclarer la colonne rôle dans l’en-tête du tableau :
<th class='role' scope='col'><:roles:role_titre:></th>
Ils peuvent lister les rôles pour la liste des liaisons existantes. Si le visiteur a le droit d’effectuer des actions, on inclut en plus un bouton « modifier les rôles » permettant d’ajouter ou de retirer des rôles à cette liaison, et cela déjà depuis la liste des liaisons existantes. Il faut transmettre à cet inclure :
- l’environnement,
- l’id en cours de parcours,
- et la clé d’action (la même qui est présente sur l’action de suppression du lien du squelette de vue sans rôle).
<td class='role'>
[(#ENV{editable}|oui)
[(#INCLURE{fond=formulaires/inc-editer_liens_actions_roles,env,id=#ID_AUTEUR,cle=auteur-#ID_AUTEUR-#OBJET-#ID_OBJET})]
]
<BOUCLE_roles(auteurs_liens){id_auteur}{objet}{id_objet}{par role}{", "}>
[(#ROLE|role{auteurs})]</BOUCLE_roles>
</td>
Pour le squelette d’association, de la même façon, la colonne rôle effectue simplement une inclusion (seul le nom de l’inclusion change) :
<td class='role'>[(#INCLURE{fond=formulaires/inc-editer_liens_roles,env,id=#ID_AUTEUR,cle=auteur-#ID_AUTEUR-#OBJET-#ID_OBJET})]</td>
Tout ceci fait, votre plugin décrivant des rôles entre certaines liaisons est fonctionnel (lorsque ce plugin est installé).
Nous allons maintenant développer les modifications apportées à deux fichiers de SPIP pour réaliser tout cela.
Modifications du formulaires/editer_liens.php
Afin de gérer les rôles, le formulaire de liens est quelque peu modifié.
Dans le chargement du formulaire, on teste si des rôles existent pour ce lien grâce au code $roles = roles_presents($objet_source, $objet)
. Cela récupère le cas échéant un tableau de description des rôles pour ce type de liaison, qui sera envoyé dans l’environnement du formulaire. De plus, s’il y a des rôles, on change alors les squelettes de liste chargés, en ajoutant « _roles » dans leurs noms :
// on demande de nouveaux squelettes en conséquence
$skel_vue = $table_source."_roles_lies";
$skel_ajout = $table_source."_roles_associer";
Dans les traitements du formulaire, on s’adapte aussi à la présence des rôles en acceptant que les actions qui ont normalement 4 valeurs, puissent en avoir 5, la 5è concernant le rôle. On peut alors recevoir du formulaire des éléments tel que :
-
ajouter_lien[objet1-id1-objet2-id2]
ce qui est l’action de base qui existe sans cette surcharge. Cependant pour nous, lorsque des rôles sont possibles entre objet1 et objet2 et que rien n’est précisé (5e valeur ou clédefinir_roles
), cela ajoute la liaison avec le rôle par défaut déclaré. -
ajouter_lien[objet1-id1-objet2-id2-role]
Ajoute le rôle explicitement indiqué -
supprimer_lien[objet1-id1-objet2-id2]
Supprime la liaison s’il n’y a pas de rôles possibles entre les objets, sinon supprime la liaison qui a le rôle par défaut déclaré -
supprimer_lien[objet1-id1-objet2-id2-role]
Supprime la liaison qui a le rôle explicitement indiqué -
supprimer_lien[objet1-id1-objet2-id2-*]
Supprime toutes les liaisons (et tous les rôles donc) -
definir_roles[objet1-id1-objet2-id2]=array('roleA', 'roleB')
Permet d’indiquer, lorsqueajouter_lien
est présent sans 5e argument, de prendre les rôles indiqués ici au moment de l’ajout
Enfin, les appels à l’API d’édition de lien sont modifiés également pour tenir compte des rôles qui sont ajoutés ou supprimés.
Modifications de l’API dans action/editer_liens.php
Actuellement, l’ajout, la modification ou la suppression se base sur le postulat qu’il n’existe qu’un seul couple (id_xx, objet, id_objet) et il faut donc pouvoir s’en passer dans certaines situations, particulièrement pour la gestion de nos rôles.
On peut séparer en 2 les adaptations faites dans ce plugin.
Contraindre les suppressions et modifications
Il s’agit ici de pouvoir dire : je veux trouver ou supprimer tous les liens qui ont tel champ à telle valeur, ou tel rôle à telle valeur.
Pour ce faire, on ajoute un paramètre $cond
aux fonctions
-
objet_trouver_liens($objets_source, $objets_lies, $cond=null)
-
objet_dissocier($objets_source, $objets_lies, $cond=null)
- et sur des fonctions internes.
Ce paramètre permet de passer un tableau de conditions tel que :
array("vu=" . sql_quote('oui'))
Dans ce cas on ne cherche ou supprime que les éléments répondant aux critères demandés. Mais ce paramètre peut également indiquer un index ’role’ indiquant quel rôle trouver ou supprimer (indépendamment du nom réel de la colonne de rôle), tel que :
array('role' => 'correcteur')
array('role' => '*')
L’API comprend alors qu’elle doit retrouver le rôle correcteur dans la colonne définie dans la déclaration des rôles pour les objets en question.
Note : dans le cas de objet_dissocier
, si des rôles sont possibles mais qu’aucun n’est passé, seul le rôle par défaut déclaré est supprimé ! Pour supprimer tous les rôles les liaisons, il faut alors passer explicitement 'role'=>'*'
Gérer les insertions et qualifications
La signature les fonctions pour le faire ne change pas :
-
objet_associer($objets_source, $objets_lies, $qualif = null)
-
objet_qualifier_liens($objets_source, $objets_lies, $qualif)
Ce qui change est le traitement de $qualif
lorsque la liaison entre les 2 objets peut avoir des rôles (rien ne change sinon). L’API extrait alors le rôle de $qualif
s’il est présent, et en l’absence utilise alors le rôle par défaut.
Dans ce tableau $qualif
, et contrairement à la variable $cond
, c’est bien le nom véritable de la colonne qui est attendu, par exemple :
objet_associer(array('auteur'=>3), array('article'=>11), array('colonne_des_roles' => 'correcteur');
Le cas des pipelines pre_edition_lien et post_edition_lien
Les pipelines pre_edition_lien et post_edition_lien ne fonctionnent pas comme pre_edition
et post_edition
dans le sens où ils ne transmettent pas dans $flux['data']
la liste des champs impactés par l’insertion ou la suppression. De plus, il n’y a pas de pipeline sur la modification.
Bien que ce plugin pour SPIP 3 ne modifie pas leur fonctionnement, il sera bon pour les futures versions de SPIP de modifier ces pipelines pour être homogène avec leurs homologues en :
- modifiant
$flux['data']
des pipelines pour qu’ils deviennent un tableau des champs ajoutés ou modifiés (ou supprimés) (le code pour le faire est commenté dans ce plugin) - ajouter le passage de ces pipelines dans l’étape de modification d’un lien (c’est fait dans ce plugin)
Discussions par date d’activité
10 discussions
Bonjour,
Une excellente idée qui va m’être bien utile.
Juste une remarque : Dans la doc, au chapitre ’Adapter la table de liens’ cas 1, n’y a t-il pas une erreur sur la Primary Key : id_rose devrait remplacer id_auteur non ?
Bravo pour cette contrib.
Très juste. Corrigé (bien tardivement, mais corrigé !).
Répondre à ce message
Bonjour,
Merci pour ce plugin, qui répond à un besoin de longue date dans SPIP.
Question très bête : comment fait-on pour le faire fonctionner, une fois qu’il est installé. Très concrètement : où faut-il placer quel code ? J’ai tenté de mettre le premier bloc de code dans
mes_options.php
, mais semble ne rien produire comme effet.Merci
Répondre à ce message
Sur SPIP 3.0.17, la mise à jour de la version 1.5 du plugin provoque un bug chez moi.
Lorsque je clique sur le bouton Modifier, je n’ai plus ma liste de role. Elle est vide.
J’ai trouvé que le problème venait du fichier formulaires/inc-editer_liens_roles.html.
En enlevant l’underscore sur la ligne
..ça remarche. Ne comprenant pas à quoi sert l’underscore, je n’ai pas pu aller plus loin dans mes investigations
Répondre à ce message
Bonjour,
Il me semble que les rôles deviennent natifs en 3.1 (?)
J’aimerais savoir si il sera possible de customiser/étendre l’usage des rôles pour « typer » des relations ?
Un exemple avec deux nouveaux objets : VETEMENT et MATIERE
VETEMENT 1 est lié à MATIERE 1 et à MATIERE 2
VETEMENT 1 contient 50% de MATIERE 1 et 50% de MATIERE 2
En clair : Une robe est composée à 50% de coton, et 50% d’élasthane
La nouvelle API d’éditions de lien pourrait-elle permettre de réaliser cela ? À quel prix (surcharges) ?
Merci pour votre aide !
Répondre à ce message
Je pense avoir trouvé un petit bug.
Lorsqu’un auteur a été créé par défaut sur un objet éditorial et que l’on souhaite lui attribuer un rôle, le plugin crée un deuxième lien avec le rôle dans la table de liaison.
Dans la liste associée, une virgule apparaît d’ailleurs pour séparer les 2 liaisons.
Cela se passe donc dans l’action « modifier la liaison »
FDM
Répondre à ce message
Merci pour ce plugin, associé à « Rôles d’auteurs ».
Dans les sites que je fais, je suis souvent confronté à ce type de problème. Plus que correcteur ou relecteur, c’est surtout direction (« Sous la direction de ») qui est courant.
Je n’ai pas bien saisi si l’on peut modifier le type de rôle. Est-ce possible ? Via une interface, ce serait bien pratique.
Répondre à ce message
Bonjour,
J’ai 2 questions sur le fonctionnement de ce plugin.
{par role}
?Cas concret avec Rôles des auteurs :
Répondre à ce message
ça a l’air génial comme plugin... Pour le moment, je survole seulement. En ajoutant de nouveaux statuts aux auteurs, il serait possible de proposer différentes inscriptions selon les statuts, non ?
Répondre à ce message
Merci pour ce beau plugin que j’attendais depuis longtemps pour mon site de travail collaboratif.
Suggestion : Ne peut-on pas définir les objets et les rôles depuis une page de configuration, plutôt qu’en éditant un fichier php qui sera écrasé lors de la prochaine mise à jour.
Répondre à ce message
Vraiment extra.
Un beau plugin qui ouvre de belles perspectives (jusqu’alors compliquées à envisager)
J’ai créé un plugin avec la fabrique, j’ai mis des rôles sur les auteurs pour mon nouvel objet éditorial, ça marche parfaitement seulement je ne vois pas comment gérer les droits... ?
Ex : faire en sorte qu’un auteur avec rôle de ’lecteur’ ne puisse pas modifier l’article.
Bravo et merci pour ce plugin
Répondre à ce message
Ajouter un commentaire
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Suivre les commentaires : |