ContributionComme tout projet libre qui se respecte, les contributions à LdapSaisie sont les bienvenues. Ce chapitre explique
les possibilités de contribution.LSaddonsLes &LSaddons; sont utilisés pour implémenter dans &LdapSaisie; des fonctionnalités spécifiques tel que :
le support d'une famille d'attributs spécifiques (POSIX, Samba, SUPANN…) par le biais de
méthodes de génération de la valeur de ces attributs par exemple (paramètre
generate_function) ;des tâches communes et génériques (envoi de mails, connexion FTP/SSH…) ;l'implémentation de déclencheurs spécifiques à
votre environnement : création automatique du dossier client sur le serveur de fichiers de l'entreprise, création
de la boite mail de l'utilisateur… ;l'implémentation de vues personnalisées proposées
dans l'interfacel'implémentation d'action personnalisée sur les
objets (synchronisation, archivage…) ou sur les
résultats de recherches (export, rapport personnalisé…) ;Structure d'écritureL'écriture d'un &LSaddon; doit respecter une structure suffisamment souple afin de ne pas être un frein à vos
contributions, tout en permettant d'assurer la bonne intégration de votre contribution au projet. Le code que vous
écrirez sera réparti dans deux fichiers :conf/LSaddons/config.LSaddons.[addon name].phpCe fichier contiendra la configuration de votre &LSaddon;. On y retrouvera la déclaration de
constances et/ou variables de configuration permettant d'adapter votre &LSaddon; à une installation et à un
environnement.includes/addons/LSaddons.[addon name].phpCe fichier contiendra le code à proprement dit de votre &LSaddon;.Structure du fichier includes/addons/LSaddons.[addon name].php
*
* @retval boolean true if my addon is totaly supported, false in other cases
**/
function LSaddon_myaddon_support() {
$retval=true;
// Check/load dependencies
if ( !class_exists('mylib') ) {
if ( !LSsession::includeFile(LS_LIB_DIR . 'class.mylib.php') ) {
LSerror :: addErrorCode('MYADDON_SUPPORT_01', 'mylib');
$retval=false;
}
}
$MUST_DEFINE_CONST= array(
'LS_MYADDON_CONF_O1',
'LS_MYADDON_CONF_O2',
...
);
foreach($MUST_DEFINE_CONST as $const) {
if ( (!defined($const)) || (constant($const) == "")) {
LSerror :: addErrorCode('MYADDON_SUPPORT_02',$const);
$retval=false;
}
}
if ($retval) {
// Register LSaddon view using LSsession :: registerLSaddonView()
if (php_sapi_name() == 'cli') {
// Register LSaddon CLI command using LScli :: add_command()
}
}
return $retval;
}
/**
* My first function
*
* Description of this wonderfull function
*
* @author My Name
*
* @retval [type(s) of returned values (pipe separator)] Description of the return of this function
**/
function myaddon_first_function($arg1, $arg2) {
// Do some stuff
if (something) {
LSerror :: addErrorCode(
'MYADDON_01',
'something went wrong' // Error LSformat unique argument
);
return false;
}
if (something else) {
LSerror :: addErrorCode(
'MYADDON_02',
array( // Error LSformat arguments
'about' => 'second step',
'msg' => 'something went wrong'
)
);
return false;
}
if (still something else) {
LSerror :: addErrorCode('MYADDON_03'); // Error without argument
return false;
}
return true;
}
[...]
// Defined custom CLI commands functions only on CLI context
if (php_sapi_name() != 'cli')
return true; // Always return true to avoid some warning in log
// Defined functions handling custom CLI commands and optionnaly
// their arguments autocompleter functions.
]]>
Par convention, la structure de ce fichier est toujours à peu près la même:
On déclare tout d'abord les messages d'erreurs qui seront potentiellement émis par notre &LSaddon; en commençant par
les messages d'erreurs liés au support de cet &LSaddon;. On utilise pour cela la méthode LSerror :: defineError() qui
attends en premier argument, l'identifiant du message d'erreur et en tant que second argument, le &LSformat; du message d'erreur. Par
convention, les identifiants des messages d'erreurs seront en majuscule et préfixés du nom du &LSaddon;.On déclare ensuite une fonction LSaddon_[myaddon]_support qui sera exécutée lors du chargement de
l'addon et qui permettra de s'assurer du support de celui-ci. Cette fonction devra retourner True si c'est le cas ou
False dans le cas contraire.Cette fonction s'assura notamment :
que les librairies dont l'addon dépends sont bien chargées et fonctionnelles ;que ses variables et constantes de configuration sont bien définies ;de déclarer les vues personnalisées fournies par cet &LSaddon; ;de déclarer les commandes CLI personnalisées fournies par cet &LSaddon; ;On déclare ensuite les fonctions, classes et éléments fournis et manipulés par l'addon.Si notre addon offre des commandes CLI
personnalisées, les fonctions les implémentant ne seront définies, dans un souci de performance, que dans un contexte
ou elles seraient potentiellement appelables, c'est à dire dans un contexte d'exécution CLI. Pour cela,
nous utilisons communément la fonction php_sapi_name pour déterminer le contexte d'exécution et si celui-ci
vaut cli, nous stoppons l'exécution du reste du code du fichier via un return true.
Il est important dans ce contexte de ne jamais retourner autre chose que True pour éviter tout message
d'erreur inutile dans les logs.On déclare, pour finir, les fonctions implémentant les commandes
CLI personnalisées et leur éventuelle fonction gérant l'autocomplétion des arguments qu'elles acceptent.
Les vues personnaliséesLes &LSaddons; peuvent fournir des vues personnalisées qui seront accessibles à tout ou parties des utilisateurs de l'application.
Ce filtrage d'accès sera fait en utilisant les &LSprofiles; de l'utilisateur connecté sur la racine
courante de l'annuaire LDAP.Pour mettre en place une telle vue personnalisée, il est nécessaire de :
Déclarer cette vue dans la fonction LSaddon_[addon]_support de l'addon à l'aide de la méthode
LSsession :: registerLSaddonView ;Déclarer la fonction implémentant cette vue. Cette fonction n'acceptera aucun paramètre et ne retournera rien.
Elle devra en outre s'occuper de définir son fichier template et charger les dépendances de ce dernier (fichiers CSS
& JS, variables...).Pour implémenter une telle vue personnalisée, vous pouvez vous inspirer de l'exemple fourni ci-dessous ou encore des vues fournies
par les autres &LSaddons; (par exemple, l'addon exportSearchResultAsCSV).
Structure du fichier includes/addons/LSaddons.[addon name].php
*
* @retval void
**/
function myaddon_view() {
// Do some stuff and set some template variables
$list = array ([...]);
LStemplate :: assign('list', $list);
// Load some CSS & JS files need on this view
LStemplate :: addCssFile('LSaddon_myadon.css');
LStemplate :: addJSscript('LSaddon_myadon.js');
// Set template file of the view
LSsession :: setTemplate('LSaddon_myadon_view.tpl');
}
]]>
Les commandes CLI personnaliséesLes &LSaddons; peuvent fournir des commandes CLI personnalisées qui seront accessibles via la commande
ldapsaisie fournie avec l'application. Cela peut, par exemple, vous permettre de rendre accessible en ligne de commandes
une procédure implémentée dans le code d'LdapSaisie et vous permettre de mettre en place une tâche planifiée exécutant cette procédure
régulièrement.Pour mettre en place une telle commande CLI personnalisée, il est nécessaire de :
Déclarer cette vue dans la fonction LSaddon_[addon]_support de l'addon à l'aide de la méthode
LScli :: add_command ;Déclarer la fonction implémentant cette commande CLI personnalisée. Cette fonction acceptera,
en tant qu'unique paramètre, un tableau des arguments reçus lors de l'exécution de la commande et retournera True
ou False en cas de succès/d'erreur d'exécution de la commande. Cette valeur de retour influencera le code retourné
par la commande : 0 en cas de succès, 1 en cas d'erreur.Bien que cela ne soit pas obligatoire, il sera également possible de déclarer une fonction permettant l'autocomplétion
des arguments acceptés par la commande.Cette méthode recevra en paramètre:
$command_argsUn tableau des arguments déjà reçus par la commande.$comp_word_numUn entier indiquant le rang de l'argument que l'autocomplétion tente de compléter. Il peut s'agir du rang d'un
paramètre déjà fourni et présent dans le tableau $command_args ou bien d'un rang supérieur aux nombres
d'arguments déjà fournis à la commande et dans ce cas il s'agira d'autocompléter tous potentiels autre argument que pourrait
accepter cette commande.$comp_wordUne chaîne de caractères correspondant à ce qu'a déjà saisi l'utilisateur de l'argument que l'on tente
d'autocompléter. Cette chaîne de caractères peut être vide ou non, en fonction de s'il s'agit d'un nouvel argument à
autocompléter ou non.$optsUn tableau des potentiels arguments globaux acceptés par LScli dans le contexte actuel (par
exemple, -d ou --debug pour l'activation du mode debug). La réponse de cette fonction
devra inclure ces potentiels arguments si le contexte d'autocomplétion si prête (nouvel argument par exemple).Pour finir, cette fonction devra retourner un tableau des potentielles valeurs que pourrait prendre l'argument autocomplété. Si
une unique proposition est faite à l'utilisateur, celle-ci sera automatiquement proposée à l'utilisateur et à défaut, la liste des
valeurs possibles lui seront affichées.Pour vous aider dans l'écrire d'une telle méthode d'autocomplétion, des méthodes statiques sont fournies par la classe
LScli pour les autocomplétions les plus courantes:
LScli :: autocomplete_class_name()Autocomplétion du nom d'une classe PHP.LScli :: autocomplete_addon_name()Autocomplétion du nom d'un &LSaddon;.LScli :: autocomplete_int()Autocomplétion d'un nombre entier.LScli :: autocomplete_LSobject_types()Autocomplétion du nom d'un type d'&LSobject;.LScli :: autocomplete_LSobject_dn()Autocomplétion du DN d'un type précis d'&LSobject; de l'annuaire.Par ailleurs, la méthode LScli :: autocomplete_opts() vous facilitera la construction de la liste des valeurs
d'autocomplétion de l'argument courant en fonction de ce qui a déjà été saisi par l'utilisateur (paramètre
$comp_word). Cette méthode s'occupera en l'occurrence de filtrer parmi toutes les valeurs contextuelles possibles,
celles qui correspondent au préfixe fourni par l'utilisateur.Pour implémenter une telle commande CLI personnalisée, vous pouvez vous inspirer de l'exemple fourni ci-dessous
ou encore des commandes CLI fournies par les autres &LSaddons; ou classes PHP de l'application.Structure du fichier includes/addons/LSaddons.[addon name].php
*
* @retval boolean True on succes, false otherwise
**/
function cli_my_custom_cli_cmd($command_args) {
$objType = null;
$dn = null;
$force_mode = false;
foreach ($command_args as $arg) {
if ($arg == '-f' || $arg == '--force')
$force_mode = true;
elseif (is_null($objType)) {
$objType = $arg;
}
elseif (is_null($dn)) {
$dn = $arg;
}
else
LScli :: usage("Invalid $arg parameter.");
}
if (is_null($objType) || is_null($dn))
LScli :: usage('You must provide LSobject type and DN.');
if (!LSsession :: loadLSobject($objType))
return false;
$obj = new $objType();
if (!$obj->loadData($dn)) {
self :: log_fatal("Fail to load object $dn data from LDAP");
return false;
}
// Do some stuff on loaded object
[...]
return true;
}
/**
* Args autocompleter for CLI my_custom_cli_cmd command
*
* @param[in] $command_args array List of already typed words of the command
* @param[in] $comp_word_num int The command word number to autocomplete
* @param[in] $comp_word string The command word to autocomplete
* @param[in] $opts array List of global available options
*
* @retval array List of available options for the word to autocomplete
**/
public static function cli_my_custom_cli_cmd_autocompleter($command_args, $comp_word_num, $comp_word, $opts) {
$opts = array_merge($opts, array ('-f', '--force'));
// Handle positional args
$objType = null;
$objType_arg_num = null;
$dn = null;
$dn_arg_num = null;
for ($i=0; $i < count($command_args); $i++) {
if (!in_array($command_args[$i], $opts)) {
// If object type not defined
if (is_null($objType)) {
// Defined it
$objType = $command_args[$i];
LScli :: unquote_word($objType);
$objType_arg_num = $i;
// Check object type exists
$objTypes = LScli :: autocomplete_LSobject_types($objType);
// Load it if exist and not trying to complete it
if (in_array($objType, $objTypes) && $i != $comp_word_num) {
LSsession :: loadLSobject($objType, false);
}
}
elseif (is_null($dn)) {
$dn = $command_args[$i];
LScli :: unquote_word($dn);
$dn_arg_num = $i;
}
}
}
// If objType not already choiced (or currently autocomplete), add LSobject types to available options
if (!$objType || $objType_arg_num == $comp_word_num)
$opts = array_merge($opts, LScli :: autocomplete_LSobject_types($comp_word));
// If dn not alreay choiced (or currently autocomplete), try autocomplete it
elseif (!$dn || $dn_arg_num == $comp_word_num)
$opts = array_merge($opts, LScli :: autocomplete_LSobject_dn($objType, $comp_word));
return LScli :: autocomplete_opts($opts, $comp_word);
}
]]>
LSformElementsLes &LSformElements; sont les types de champs de formulaire supportés par l'application.Pour chaque type implémenté, on devra trouver :
Une classe PHP dérivée de la classe LSattr_html et devant s'appeler
LSattr_html_[nom du type d'attribut HTML]. Dans celle-ci, il devra être défini à minima la variable de classe
LSformElement_type permettant de référencer le type d'&LSformElement; à utiliser ;Une classe PHP dérivée de la classe LSformElement et devant s'appeler
LSformElement_[nom du type d'LSformElement]. Cette classe implémentera tout ce qui concerne l'affichage du champ
dans le formulaire et le traitement d'une valeur retournée par ce dernier. Cela concerne notamment les méthodes suivantes :
getDisplay()Retourne les informations d'affichage du champ dans un formulaire sous la forme d'un tableau (implémentation
obligatoire, pas de méthode par défaut). Il sera possible de s'appuyer sur la méthode getLabelInfos()
permettant de générer et récupérer tout ce qui concerne le label du champ du formulaire. Il faudra cependant à minima fournir
également la clé html dans le tableau retourné qui devra contenir le bout de code HTML correspondant au champ
du formulaire. Communément, ce code HTML est généré en appelant la méthode fetchTemplate().fetchTemplate()Retourne le code HTML du champ dans le formulaire. L'implémentation de cette méthode est facultative et par défaut, cette
méthode utilisera la variable de classe $template pour connaître le fichier de template à utiliser. Ce fichier
de template permettra la génération de la liste de tous les champs associés à chacune des valeurs de l'attribut. Individuellement,
le champ d'une des valeurs de l'attribut est généré à l'aide du fichier de template référencé dans la variable de class
$fieldTemplate.La variable de classe $fieldTemplate est également utilisée par la méthode
LSformElement :: getEmptyField() qui sert à générer le code HTML d'un champ du formulaire pour une nouvelle
valeur de l'attribut. Cette méthode est notamment utilisée lorsque l'on clique sur le bouton permettant d'ajouter une valeur à
un champ du formulaire.getPostData()Récupère dans les données postées par le formulaire, celle concernant ce champ. Cette méthode devra potentiellement
traiter l'ensemble des valeurs de l'attribut envoyées par le formulaire et les définir dans le tableau passé en référence en tant
que premier argument, les valeurs de l'attribut. L'implémentation de cette méthode est facultative et par défaut, un tableau de
valeurs portant le nom de l'attribut LDAP correspondant sera récupérée comme valeur de l'attribut.Pour plus d'informations sur le rôle et fonctionnement de cette méthode, référer à la méthode par défaut, définie
dans la classe PHP parente LSformElement.setValueFromPostData()Définit les valeurs de l'attribut à partir des données reçues du formulaire (et récupérées par la méthode
getPostData). L'implémentation de cette méthode est facultative et par défaut, aucune transformation ne sera
faites à cette étape sur les données récupérées depuis le formulaire. Implémenter cette méthode pourra cependant se révéler utile
en cas de champs de formulaire complexe (attribut composite par exemple).autocomplete_attr_values()Génère de la liste des valeurs possibles de l'attribut dans un contexte CLI.Pour plus d'informations sur le rôle et fonctionnement de cette méthode, référer aux commentaires de la méthode par
défaut, définie dans la classe PHP parente LSformElement. Vous pouvez également vous inspirer des exemples
d'implémentations fournies avec les autres type d'&LSformElement;.Un (ou plusieurs) fichier template pour la génération du code HTML du champ du formulaire. Communément, le fichier
LSformElement.tpl est utilisé pour générer la structure de la liste des champs correspondant aux différentes valeurs
de l'attribut. Ce template utilise une variable $fieldTemplate pour définir quel fichier template devra être utilisé
pour générer le code HTML de chaque champ associés à une valeur. C'est ce second fichier de template qui est en général à fournir à
minima avec votre &LSformElement;.Il peut être utile d'étendre un type d'&LSformElement; existant pour faciliter l'implémentation d'un nouveau type. Pour
cela, vous devez utiliser l'héritage de classe PHP en faisant dériver vos nouvelles classes des classes du &LSformElement; dont vous vous
inspirer, plutôt que les classes génériques. Vous pouvez prendre exemple sur le type d'&LSformElement; pre qui s'inspire
du type textarea, ou encore du type url dérivé du type text.LSformRulesLes &LSformRules; sont les règles syntaxiques applicables aux champs des formulaires. Ces règles serviront à s'assurer que les
valeurs des champs récupérées des formulaires sont syntaxiquement correctes. Elles seront configurables via le paramètre
check_data des attributs des &LSobjects;.Pour chaque type implémenté, on trouvera une classe PHP dérivée de la classe LSformRule et devant s'appeler
LSattr_rule_[nom du type]. Dans celle-ci, il devra être défini la méthode statique validate() qui
implémentera le contrôle syntaxique. Cette méthode prendra en paramètres :
$valueLa valeur à tester.$optionsUn tableau des options définies dans la configuration pour ce contrôle syntaxique.$formElementUne référence au champ du formulaire (objet &LSformElement;).Cette méthode devra retourner True ou False si la valeur testée est respectivement valide ou
invalide. Elle pourra également déclencher une exception LSformRuleException qui lui permettra de donner des messages
d'erreurs elle-même sur le(s) problème(s) detecté(s) durant l'analyse de la valeur passée. Le constructeur de ce type d'exception prend
en tant que premier paramètre un tableau de messages d'erreurs (ou un simple message d'erreur) qui seront retournés à l'utilisateur.Par défaut, les valeurs de l'attribut sont testées une à une via la méthode validate(). Cependant, il est
possible d'implémenter une méthode de validation pour toutes les valeurs de l'attribut en une seule fois en affectant la valeur
false à la constante de classe validate_one_by_one. Dans ce cas, l'ensemble des valeurs de l'attribut seront
passées via le paramètre $value à la méthode validate() (sous la forme d'un tableau). Cela pourra par
exemple être utile pour implémenter une validation de la cohérence des valeurs les unes vis à vis des autres (unicité, nombre maximum de
valeurs, …).