Chapitre 49. Développement d’extension (plugin)

49.1. L’API

Toute la documentation se trouve sur http://wiki.noalyss.eu/doc/; seules les classes nous intéressent. La documentation est générée à partir du code avec Doxygen. Le but de cet article n’est pas de revisiter la documentation technique mais de la mettre en oeuvre afin d’écrire une extension ou plugin.

49.2. Installation de l’extension

Les extensions se trouvent toujours dans un sous-répertoire de /noalyss/include/ext, pour notre plugin que nous appelerons DUMMY, le répertoire correspondant sera /noalyss/include/ext/dummy. La première étape est donc de décompresser le plugin dans le répertoire /noalyss/include et vérifier si on a bien /noalyss/include/ext/DUMMY ensuite l’activer.

Le plus simple est de retrouver le fichier dummy.php, si le chemin est /chemin/ext/dummy/dummy.php alors /chemin/ext est l’endroit où les plugins doivent être décompressés. Le chemin quand on ajoute le plugin dans le menu CFGMENU est donné dans le wiki , pour chaque plugin, on donne le paramètre "chemin" qui est en fait le chemin à partir de /ext/

49.3. Comment l’activer

Grâce à l’accès direct allez sur CFGMENU, puis ajoutez plugin, les champs sont les mêmes, il faut ajouter ce plugin dans le profil des utilisateurs qui doivent l’utiliser (CFGPRO)

Pour la version 6.8 et plus haut, il suffit d’aller dans CFGPLUGIN et cochez qui peut utiliser le plugin qui se trouvera dans le module "Extension". Avec CFGMENU, on peut placer l’extension dans un autre module.

49.3.1. Explication des champs

  • Label, est le nom de menu de votre extension

  • Code est utilisé pour inclure le fichier du plugin, il correspond au champs caché plugin_code

  • Fichier est le chemin complet vers l’extension

Pour notre extension, les valeurs suivantes sont données

  • Label : Mon dummy à moi

  • code : dum

  • Fichier : dummy/dummy.php

Vous sauvez, cliquer sur Extension et vous verrez apparaître un nouveau plugin appelé "Mon dummy à moi"; si vous cliquez dessus, la page ext/dummy/dummy.php sera exécutée; voyez le code du fichier noalyss/html/extension.php pour comprendre.

49.3.2. Tutoriel vidéo

49.3.3. Exemple de base

Dans les plugins de base de NOALYSS, il y a skel qui est le squelette d’un plugin. Vous pouvez l’utiliser comme base.

49.3.4. Connection à la base de données

Certaines valeurs doivent toujours être passées à chaque page, par exemple gDossier qui est l’identifiant du dossier. Pour se connecter c’est assez facile, il faut utiliser la classe Database et la classe Dossier.

Donc on écrit dans dummy.php

  echo "L' identifiant de mon dossier est ".dossier::id()."<br>";
  echo "Son nom réel est ".DOMAIN."dossier".dossier::id()."<br>";
  echo "Son nom est ".dossier::name()."<br>";
 // Je me connecte à présent à ce dossier
  $cn_db=new Database(dossier::id());
  // On peut aussi se connecter ainsi (développement plus récent)
  $cn= Dossier::connect();

Je veux afficher toutes les fiches qui concernent le matériel à amortir, donc j’ai besoin de savoir ce que vaut son FICHE_DEF_REF:FRD_ID dans constant.php; la FICHE_TYPE_XX n’existe pas, je vois dans la table fiche_def_ref qu’il s’agit de "7 Matériel à amortir"

Pour avoir toutes les fiches,

  $fiche= new Fiche($cn_db);
  $aFicheMateriel=$fiche->getByDef(7);

Pour chaque fiche, je veux afficher son nom, son prix, le nombre d’années à amortir et la date d’achat. Je peux en trouver les valeurs dans la table attr_def ou le fichier constant.php,

Donc cela devient

  for ($i=0; $i < count($aFicheMateriel);$i++) {
    echo "<ul>
     echo "<li> ";
     echo "Nom";
     echo $aFicheMateriel[$i]->strAttribut(ATTR_DEF_NAME);
     echo "</li>";
     echo "<li> ";
     echo "Prix achat";
     echo $aFicheMateriel[$i]->strAttribut(ATTR_DEF_PRIX_ACHAT);
     echo "</li>";
     echo "<li> ";
     echo "Durée amortissement";
     echo $aFicheMateriel[$i]->strAttribut(8);
     echo "</li>";
     echo "<li> ";
     echo "Date de début";
     echo $aFicheMateriel[$i]->strAttribut(10);
     echo "</li>";
     echo "</ul>
  }

49.3.5. Soumettre des requêtes

Uniquement pour l’exercice, nous allons ajouter un FORM. Les données nécessaires dans le FORM sont toujours au minimum: l’id du dossier, le code du plugin.

Dans le FORM, on demandera juste à afficher le solde de chaque élément. On aura alors le code suivant, on utilisera la technique des templates

  $year=new IText('year');

  $str_year=$year->input();

  $str_submit=HtmlInput::submit('year_left','Appliquer');

  require_once('template1.php');
template1.php
  <FORM METHOD="GET" ACTION="extension.php">

  <?=dossier::hidden()?>

  <?=HtmlInput::extension()?>

  Solde pour l'année : <?=$str_year?>

  <?=$str_submit?>

  </form>

Puis dans le début du fichier noalyss/include/ext/dummy/dummy.php, on ajoutera un test pour savoir un FORM a été soumis et on affichera une boîte de dialogue.

$http= new HttpInput();1
 if (isset($http->get('year_left','number'))){ 2

    alert('Vous avez demandé le nombre d\'années restantes');

 }

(1) permet de retrouver des variables passées par get , post ou request (voir documentation code^) (2) remplace $_GET['year_left'], HttpInput vérifie aussi le type de données et peut donner une valeur par défaut si cette donnée n’est pas dans $_GET

49.4. Plugin plus avancé

Ma première extension, intégrer un fichier de client dans une catégorie de fiche, ce fichier est en CSV. Le code est simple et compréhensible, normalement on devrait avoir une meilleure gestion des erreurs, vérifier les attaques SQL Inject,…​ Ce code n’est là QUE pour expliquer le concept. On n’a pas utilisé plusieurs pages, ni de templates

Tout d’abord, il faut se connecter à la base de données

 // se connecter au dossier courant

 $cn=Dossier::connect();

Dans extension.php on vérifie la sécurité, en ajoutez une dans l’extension n’est en général pas nécessaire mais vous pourriez avoir votre propre système de sécurité si votre extension est fort complexe

En premier lieu, il est nécessaire de choisir dans quelle catégorie de fiche je veux intégrer les enregistrements. Donc on utilise un petit form

 echo '<form METHOD="get" action="extension.php">';

 echo dossier::hidden();

 // Ceci vous permet de revenir ici (voir extension.php). Cet élément caché permet d'include cette page-ci

 // Donc si votre plugin contient plusieurs pages, vous allez devoir ajouter une seconde variable pour

 // inclure la page que vous voulez (voir méthode de développement de PhpCompta )

 echo HtmlInput::extension();


 echo "Choix de la catégorie de fiche";

 $select_cat=new ISelect('fd_id');

 $select_cat->value=$cn->make_array('select fd_id,fd_label from fiche_def where frd_id='.

     FICHE_TYPE_CLIENT);

 echo $select_cat->input();

 echo HtmlInput::submit('display_prop','Afficher les propriétés');


 echo '</FORM>';

Il faut remarquer 2 choses dans ce FORM, primo, on utilise les objets HtmlInput et ISelect, secundo on doit avoir absolument en variables cachées, le n° de dossier sur lequel on est connecté, le code de l’extension, qui permettra à extension.php d’include le bon fichier. On utilise ici le protocole GET puisqu’on interroge, le protocole POST est réservé aux sauvegardes, c’est une convention assez répandue. La différence, est que les requêtes GET se voient dans l’URL, les requêtes POST ne sont jamais dans l’url.

L’utilisateur soumet le FORM, donc la feuille se recharge et on arrive à cette partie du code

On choisit d’afficher les propriétés avant de confirmer l’import

 if ( isset($_GET['display_prop'])){
    $http=new HttpInput();
     $a=new Fiche($cn);

     $prop=$a->toArray($http->get('fd_id'));

     foreach ($prop as $key=>$value)     echo "Index : $key valeur $value <br/>";



     echo '<form method="POST" action="extension.php"  enctype="multipart/form-data">';

     echo dossier::hidden();

     echo HtmlInput::extension();

     echo HtmlInput::hidden('fd_id',$http->get('fd_id');

     $file=new IFile('fichier_csv');

     echo $file->input();

     echo HtmlInput::submit('start_import','Démarrez importation');

     echo '</form>';

     exit;

 }

Voilà, si l’utilisateur clique sur le bouton SUBMIT, l’importation va démarrer. Dans notre exemple, on imaginera que le fichier CSV n’a que 4 champs "nom client","prenom client", "numero client","adresse client"

Le code qui suit est très simplifié.

 if ( isset($_POST['start_import'])){
$http=new HttpInput();
     $fd_id=$http->post('fd_id');

     $tmp_file=$_FILE['fichier_csv']['tmp_name'];

     if ( ! is_uploaded_file($tmp_file))

         die 'Je ne peux charger ce fichier';

     // on ouvre le fichier

     $f=fopen($tmp_file,'r');

     // On récupère les propriétés de cette catégorie de fiche

     $client=new Fiche($cn);

     // $array contient toutes les valeurs nécessaires à Fiche::insert,

     $array=$client->toArray($http->post('fd_id'));



     while ( $data=fgetcsv($f)) {

         // remarque : on a éliminé les traitements d'erreur



         // On  remet tous les attributs (propriétés) à vide

         foreach(array_keys($array) as $key) $array[$key]="";



         // Nom et prénom

         $array['av_text1']=$data[0].' '.$data[1];

         // Numéro de client

         $array['av_text30']=$data[2];

         // Adresse

         $array['av_text14']=$data[3];

         // Quickcode

         $array['av_text23']="CLI".$data[2];

         $client->insert($fd_id,$array);

     }

     exit;

 }

Voici le fichier client.txt

 "Nom client1","Prénom","C1","Rue de la boite,55"

 "Nom client2","Prénom","C2","Rue du couvercle,55"

 "Nom client3","Prénom","C3","Rue de la chaussure,55"

 "Nom client4","Prénom","C4","Rue de la couleur,55"

Si vous vérifiez dans VW_CLIENT, vous verrez que toutes vos fiches ont été ajoutées. Dans l’exemple, il fatraitement d’erreur plus élaboré; le fait que si une fiche echoue , l’opération est annulée (Database::rollback) ou alors création d’un fichier avec les enregistrements "ratés"…​

49.5. Ajax

Afin d’utiliser des fonctions avec ajax, prototype.js devrait être utilisé.Vous devez appeler le fichier ajax.php, ce fichier dans html va simplement vérfier la sécurité et appeler le fichier ajax.php du répertoire où se trouve le plugin avec tous les arguments donnés.

Exemple

dans

dummy/javascript.js, vous avez

function show_detail(pop_id){
    $('detail_invoice_content').innerHTML=loading();
    showIPopup('detail_invoice');
    try {
    var gDossier=$('gDossier').value;
    var phpsessid=$('phpsessid').value;
    var code=$('code').value;
    var obj={"op_id":pop_id,"gDossier":gDossier,"phpsessid":phpsessid,"code":code,'act':'detail_invoice'};
    var queryString=encodeJSON(obj);
    var action=new Ajax.Request ( 'ajax.php',
              {
                 method:'get',
                 parameters:queryString,
                 onFailure:show_detail_error,
                 onSuccess:show_detail_success
               }
               );
    } catch (e){alert('show_detail'+e.message);}


 }

et dans dummy/ajax.php

<?php
// Met correctement la langue

set_language();
//retrouve le dossier courant et s y connecte

$gDossier=dossier::id();
$cn=new Database($gDossier);

// action

$action=(isset($_REQUEST['act']))?$_REQUEST['act']:'sh';


// Véridfie la sécurité

require_once ('class_user.php');
$User=new User(new Database());
$User->Check();

/* Suivant l action demandé, on executera tel ou tel partie de code

/* Show the document */
if ( $action == 'sh') {
/*

* Votre code

*/}
/* remove the document */
if ( $action == 'rm' ) {
/*votre code et la réponse

*/

    header('Content-type: text/xml; charset=UTF-8');
    header ('<?xml version="1.0" encoding="UTF-8"?>');
    echo '<answer>';
    echo '<ctl>detail_invoice</ctl>';
    echo '<html>'.escape_xml($html).'</html>';
    echo '</answer>';
}
?>

49.6. Les données

Si votre extension nécessite de sauver ses propres données, il faut impérativement les mettres dans un schéma séparé. Prévoyez une table version, afin d’appliquer des mises à jour si nécessaire et un fichier install.php afin de créer les schémas nécessaire

exemple

create schema plugin_tva;

create table version (val integer);

1. Voir annexe : comment contribuer ou le wiki
1. vous pouvez aussi utiliser directement les postes comptables, certains postes sont si rarement utilisés qu’on peut décider de ne pas créer de fiche comme par exemple le capital souscrit
1. Voir annexe : comment contribuer ou le wiki
1. C’est l’accès direct AD
2. c’est le nombre avant la catégorie
1. https://wiki.noalyss.eu
1. Vérifie que vous pouvez encore déduire une facture passée pour la TVA et l’impôt
1. https://wiki.noalyss.eu
2. le 31 décembre mais cela pourrait être une date
3. Pour imprimer les bilans il y a aussi l’extension "Bilan Interne" ou un rapport avancé
1. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
2. https://wiki.noalyss.eu
3. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
1. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
2. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
3. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
1. Il existe aussi les actifs inversés, charges inversées…​
2. pour extourner il faut entrer une date valide. Une date valide est une date qui est dans une période non fermée et dans une période du dossier
3. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
4. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
1. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
1. Il faut d’abord créer la nouvelle année.
1. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
1. Plugins standards de NOALYSS, https://gitlab.com/noalyss/noalyss-plugins
1. Pour l’ajax, il existe plusieurs fichiers, ajax_misc.php est en général utilisé,ajax.php est utilisé pour les pluging