developpement:developpement_de_plugin

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.

Installation de l'extension

Dans noalyss/include/ext/skel , vous trouverez des fichiers qui peuvent vous servir de base.

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>
  }

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 phpcompta/include/ext/dummy/dummy.php, on ajoutera un test pour savoir un FORM a été soumis et on affichera une boîte de dialogue.

 if (isset($_GET['year_left'])){
 
    alert('Vous avez demandé le nombre d\'années restantes');
 
 }

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=new Database(dossier::id());

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'])){
 
     $a=new Fiche($cn);
 
     $prop=$a->toArray($_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',$_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é, il n'y a peu voire aucun contrôle ni de gestion d'erreur.

 if ( isset($_POST['start_import'])){
 
     $fd_id=$_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($_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”…

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>';
}
?>

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);

….

  • developpement/developpement_de_plugin.txt
  • Dernière modification : 2021/11/23 13:16
  • de dany