developpement_de_phpcompta

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
developpement_de_phpcompta [2013/03/23 15:43] – [Contrôle] danydeveloppement_de_phpcompta [2017/03/02 09:32] (Version actuelle) – [Les tests unitaires] dany
Ligne 34: Ligne 34:
  
  
-<code>+<code php>
 <?php <?php
  
Ligne 63: Ligne 63:
  
 Grâce à l'exemple vu dans Contrôle, vous avez compris ce qu'est le concept vue: c'est la présentation de votre action. Donc pour continuer l'exemple, dans le document include/auteur.inc.php, on aurait Grâce à l'exemple vu dans Contrôle, vous avez compris ce qu'est le concept vue: c'est la présentation de votre action. Donc pour continuer l'exemple, dans le document include/auteur.inc.php, on aurait
 +<code php>
 <?php <?php
  
Ligne 85: Ligne 85:
  
 ?> ?>
 +</code>
 Ici, comme dans contrôle, on vérifie qu'une action est bien demandée, si  c'est la cas, on appelle un objet et on lui demande d'afficher quelque chose. Cet objet est ce qui est dans le concept MVC, un modèle. En fait, on dirait une espèce de sous-contrôle Ici, comme dans contrôle, on vérifie qu'une action est bien demandée, si  c'est la cas, on appelle un objet et on lui demande d'afficher quelque chose. Cet objet est ce qui est dans le concept MVC, un modèle. En fait, on dirait une espèce de sous-contrôle
  
Ligne 101: Ligne 101:
 Il est vraiment mais vraiment fastidieux de construire une chaîne de caractère contenant tout le code html, surtout quand on emploie aussi du javascript et des tableaux. La solution que j'ai trouvé, je l'ai trouvé en m'inspirant de l'idée de smarty. En fait, je crée un sous-répertoire dans include que j'appelle template, et dedans je met le code HTML de ce qui doit être affiché Il est vraiment mais vraiment fastidieux de construire une chaîne de caractère contenant tout le code html, surtout quand on emploie aussi du javascript et des tableaux. La solution que j'ai trouvé, je l'ai trouvé en m'inspirant de l'idée de smarty. En fait, je crée un sous-répertoire dans include que j'appelle template, et dedans je met le code HTML de ce qui doit être affiché
  
-**Function** display_form() {+<code php> 
 +function display_form() {
  
 ob_start(); ob_start();
Ligne 116: Ligne 117:
  
 } }
 +</code>
  
 exemple  Ici on inclus le fichier, comme il est en php, il sera interprété par PHP, il contient surtout du code HTML et des balises PHP,  on peut aussi manipuler la chaîne retournée avec les fonctions de chaînes comme str_replace, strcmp,... Ce qui donne à cette méthode encore plus de souplesse. exemple  Ici on inclus le fichier, comme il est en php, il sera interprété par PHP, il contient surtout du code HTML et des balises PHP,  on peut aussi manipuler la chaîne retournée avec les fonctions de chaînes comme str_replace, strcmp,... Ce qui donne à cette méthode encore plus de souplesse.
Ligne 126: Ligne 128:
 J'utilise Doxygen afin de générer le code ce sont les TAGS brief, param... Cela me permet de générer une documentation; cette documentation me permet de développer plus vite et de mieux vérifier la qualité du code. J'utilise Doxygen afin de générer le code ce sont les TAGS brief, param... Cela me permet de générer une documentation; cette documentation me permet de développer plus vite et de mieux vérifier la qualité du code.
  
 +Voir le résultat ici [[http://www.noalyss.eu/doc/]]
 ====PhpCompta==== ====PhpCompta====
  
Ligne 156: Ligne 158:
 =====La partie base de données===== =====La partie base de données=====
  
-====Ancienne méthode (non recommandée)====+[[developpement:base_de_donnée_ancienne_méthode]]
  
-On avait commencé ainsion générait le fichier php à une table grâce à un script (dans phpcompta/dev/manage-code/create-file/create-phpclass.py)+==== Les mises à jour ==== 
 +Depuis 2005dans phpcompta, il y a une table VERSION qui contient le numéro du dernier patch appliqué. Quand le fichier do.php est exécuté, il vérifie si le nombre DBVERSION contenu dans constant.php correspond à la version actuelle
  
-Les colonnes de la table sont dans un tableau et déclaré comme variable privéeCe point est important. Cela oblige à utiliser les setters/getters. Cela vous permet aussi de faire correspondre des noms parlants à des noms de colonnes parfois hmm... moins parlants. +<code php> 
- +/* Ficher do.php *
-Cependant, je préfère souvent utiliser les commandes SQL plutôt que de passer par les objets. D'abord pour des raisons de performance, d'utilisation de la mémoire... La théorie qui veut que l'application doit être indépendante de la base de données n'est pas un mauvais principe mais dans la vie réelle, il est rare que l 'on change le programme de base de données pour un autre.  +if (DBVERSION < dossier::get_version($cn))
- +
-**class** Todo_List+
 { {
 +    echo '<h2 class="error" style="font-size:12px">' .
 +     _("Attention: la version de base de donnée est supérieure à la version du programme, vous devriez
 + mettre à jour") . '</h2>';
 +}
 +if (DBVERSION > dossier::get_version($cn))
 +{
 +    echo '<h2 class="error" style="font-size:12px">' . _("Votre base de données n'est pas à jour") . '   ';
 +    $a = _("cliquez ici pour appliquer le patch");
 +    $base = dirname($_SERVER['REQUEST_URI']) . '/admin/setup.php';
 +    echo '<a hreF="' . $base . '">' . $a . '</a></h2>';
 +}
  
-  **private** static $variable=array( 
- "id"=>"tl_id", 
- "date"=>"tl_date", 
- "title"=>"tl_title", 
- "desc"=>"tl_desc", 
- "owner"=>"use_login"); 
-  **private** $cn; 
-  **private**  $tl_id,$tl_date,$tl_title,$use_login; 
-   
-  **function** %%__%%construct ($p_init) { 
-    $this->cn=$p_init; 
-    $this->tl_id=0; 
-    $this->tl_desc=""; 
-    $this->use_login=$_SESSION['g_user']; 
  
-  }+</code>
  
 +Dans le cas où DBVERSION n'est pas la valeur contenue dans la base de donnée, do.php vous propose d'appliquer le patch sur vos bases de données. Voici la fonction qui applique les patch SQL pour la base de données
 +<code php>
 +/* fichier setup.php */
 +//----------------------------------------------------------------------
 +// Upgrade the folders
 +//----------------------------------------------------------------------
  
 +for ($e=0;$e < $MaxDossier;$e++) {
 +   $db_row=Database::fetch_array($Resdossier,$e);
 +  echo "<h3>Patching ".$db_row['dos_name'].'</h3>';
  
 +  $name=$cn->format_name($db_row['dos_id'],'dos');
  
 +  if ( $cn->exist_database($name)> 0 )
 +  {
 +    $db=new Database($db_row['dos_id'],'dos');
 +    $db->apply_patch($db_row['dos_name']);
 +    Dossier::synchro_admin($db_row['dos_id']);
  
-Ici voici, des setters / getters génériques, ce qui permet de ne pas en avoir un par variable. Ce qui est bien pratique. On accède aux données avec set_parameter ('date','01.01.2009') ou avec get_parameter ('date'); +  } else 
- +  
- +      echo_warning(_("Dossier inexistant")." $name");
- +
-**public** **function** get_parameter($p_string) +
-    if array_key_exists($p_string,**self**::$variable) { +
-      $idx=**self**::$variable[$p_string]; +
-      return $this->$idx; +
-    } +
-    else  +
-      exit (**%%__%%FILE%%__%%**.":".**%%__%%LINE%%__%%**.'Erreur attribut inexistant');+
   }   }
 + }
  
-  **public** **function** set_parameter($p_string,$p_value) { +</code>
-    if ( array_key_exists($p_string,**self**::$variable) ) { +
-      $idx=**self**::$variable[$p_string]; +
-      if ($this->check($idx,$p_value) == **true** )      $this->$idx=$p_value; +
-    } +
-    else  +
-      exit (**%%__%%FILE%%__%%**.":".**%%__%%LINE%%__%%**.'Erreur attribut inexistant'); +
-        +
-  }+
  
-Ceci est la fonction qui contrôle que les données sont validesCela pourrait aussi être fait dans la base de données, soit avec des contrôles d'intégrités (foreign key, primary key) soit avec des procédures SQL embarquées de contrôle.+La fonction qui applique le patch est Database::apply_patch  voir [[http://www.phpcompta.eu/doc/classDatabase.html|la documentation en ligne]]
  
  
 +Tous les patchs pour la base de données se trouve dans phpcompta/html/admin/sql/patch et sont numérotés dans l'ordre d’exécution.
 +Chaque patch commence par 
 +<code sql>
 +begin;
 +</code>
  
-**public** **function** check($p_idx,&$p_value) { +et termine par 
- if ( strcmp ($p_idx, 'tl_id') == 0 ) { if ( strlen($p_value) > 6 %%|%%| isNumber ($p_value) == **false**) return **false**;+<code sql> 
- if ( strcmp ($p_idx, 'tl_date') == 0 ) { if ( strlen(trim($p_value)) ==0 %%|%%|strlen($p_value) > 12 %%|%%| isDate ($p_value) == **false**) return **false**;+update version set val=13;
- if ( strcmp ($p_idx, 'tl_title') == 0 ) {  +
-   $p_value=substr($p_value,0,120) ; +
-   return **true**; +
-+
- if ( strcmp ($p_idx, 'tl_desc') == 0 ) { $p_value=substr($p_value,0,400) ; return **true**;+
- return **true**; +
-  } +
- +
-Enfin la fonction save, qui permet soit d'ajouter soit de même à jour. Évidemment on utilisera des requêtes SQL Prepare, afin d'éviter les problèmes de guillemets et donc d'injection SQL. +
- +
- +
- +
-**public** **function** save() { +
-    if (  $this->get_parameter("id") == 0 )  +
-      $this->insert(); +
-    else +
-      $this->update(); +
-  } +
- +
-  **public** **function** insert() { +
-    if ( $this->verify() != 0 ) return; +
- +
-    $sql="insert into todo_list (tl_date,tl_title,tl_desc,use_login) ". +
-      " values (to_date($1,'DD.MM.YYYY'),$2,$3,$4)  returning tl_id"; +
-    $res=ExecSqlParam($this->cn, +
- $sql, +
- array($this->tl_date, +
-        $this->tl_title, +
-        $this->tl_desc, +
-        $this->use_login) +
- ); +
-    $this->tl_id=pg_fetch_result($res,0,0); +
-     +
-  } +
- +
-  **public** **function** update() { +
-    if ( $this->verify() != 0 ) return; +
- +
-    $sql="update todo_list set tl_title=$1,tl_date=to_date($2,'DD.MM.YYYY'),tl_desc=$3 ". +
-      " where tl_id = $4"; +
-    $res=ExecSqlParam($this->cn, +
- $sql, +
- array($this->tl_title, +
-        $this->tl_date, +
-        $this->tl_desc, +
-        $this->tl_id) +
- ); +
-  +
-  } +
- +
-Comme cette partie est vraiment répétitive et change peu, j'ai mis au point un script (dev/manage-code/create-file/create_phpclass.py) pour directement générer le code sur base de la définition d'une table. Cela réduit vraiment le temps de travail. +
- +
- +
- +
-static **function** test_me() { +
-    $cn=DbConnect(dossier::id()); +
-    $r=**new** Todo_List($cn); +
-    $r->set_parameter('title','test'); +
-    $r->use_login='phpcompta'; +
-    $r->set_parameter('date','02.03.2008'); +
-    $r->save(); +
-    $r->set_parameter('id',3); +
-    $r->load(); +
-    print_r($r); +
-    $r->set_parameter('title','Test UPDATE'); +
-    $r->save(); +
-    print_r($r); +
-    $r->set_parameter('id',1); +
-    $r->delete(); +
-  } +
-    **public** **function** get_info() {     +
- +
-    return var_export(**self**::$variable,**true**);   +
- +
-+
- +
- +
- +
- +
- +
-Et finalement, les fonctions info et test_me qui sont très utiles lors des phases de déboggages. Je crée une simple page html/test.php et j'appelle la classe; dans la fonction test_me je mets tout ce que je souhaite tester. +
  
 +commit;
 +</code>
  
 +Ainsi, si le script échoue, la mise à jour s'arrête et annule toute ce qui a été fait dans le script contenant l'erreur, la base de données reste ainsi dans un état cohérent. Une fois l'erreur corrigée dans votre base de données, ce script ainsi que ceux qui suivent seront appliqués quand vous appelerez à nouveau phpcompta/admin/setup.php
  
-====Nouvelle méthode====+====Accèder aux données : DAO ====
  
  
  
-Nous avons créér une classe Phpcompta_Sql qui va nous permettre de faire la même chose en très peu de ligne de code. +Nous avons créér une classe qui va hériter de [[http://www.phpcompta.eu/doc/classPhpcompta__SQL.html|Phpcompta_Sql]] et qui va nous permettre de faire la même chose en très peu de ligne de code. 
  
  
Ligne 327: Ligne 251:
  
 Voici tout le code à taper par table, exemple pour la table stock_change Voici tout le code à taper par table, exemple pour la table stock_change
- +<code php> 
-**class** Stock_Change_Sql **extends** PhpCompta_Sql+class Stock_Change_Sql extends PhpCompta_Sql
 { {
- //%%//%% Le contructeur obligatoire + // Le contructeur obligatoire 
- //**function**// %%__%%construct//($p_id// //=// //-1)// + function __construct($p_id = -1) 
- //{+
 + // Façon dont les dates sont utilisées 
 + $this->date_format="DD.MM.YYYY"; 
 + // Nom de la table  
 + $this->table = "public.stock_change"; 
 + // nom de la clef primaire 
 + $this->primary_key = "c_id";
  
- //%%//%% Façon dont les dates sont utilisées + // Structure de la table, à gauche le nom logique utilisable 
- //$this->//date_format//="DD.MM.YYYY";+ // avec les getters/setters (setp/getp) et à droite le nom de la 
 + // colonne 
 + $this->name = array( 
 + "id" => "c_id", 
 + "c_comment" => "c_comment", 
 + "c_date" => "c_date", 
 + "tech_date"=>"tech_date", 
 + "tech_user"=>"tech_user", 
 + "r_id"=>"r_id" 
 + ); 
 + // Type de données 
 + $this->type = array( 
 + "c_id" => "numeric", 
 + "c_comment" => "text", 
 + "c_date" => "date", 
 + "tech_date"=>"date", 
 + "tech_user"=>"text", 
 + "r_id"=>"numeric" 
 + ); 
 + // Les colonnes qui ne peuvent pas être changée ni par insert ni par  
 + // update parce leurs valeurs sont données automatiquement  
 + // exemple : la clef primaire qui est un numéro de séquence  
 + //automatiquement donné 
 + $this->default array( 
 + "c_id=> "auto", 
 + "tech_date" => "auto" 
 + ); 
 + global $cn;
  
- //%%//%% Nom de la table  + parent::__construct($cn, $p_id); 
- //$this->//table //=// //"public.stock_change";+
 +
 +</code> 
 +Si on change la structure d'une table, il ne faut presque rien changer : seulement quelques lignes.  
 +===== Les tests unitaires ===== 
 +Avant on utilisait dans chaque class , une fonction nommée [[developpemement::test_me]] qui pouvait être appelée depuis le fichier test.php.
  
- //%%//%% nom de la clef primaire +A partir de NOALYSS (version 6.7.2.0)et pour les plugins nous utiliserons PHPUnit.Ces tests sont heureusement appelables directement depuis NetBeans (version 7.4 et supérieure).
- //$this->//primary_key //=// //"c_id";// +
-// +
- +
- //%%//%% Structure de la table, à gauche le nom logique utilisable +
- %%//%% avec les getters/setters (setp/getp) et à droite le nom de la +
- %%//%% colonne +
- //$this->//name //=// //array(// +
- //"id"// //=>// //"c_id",// +
- //"c_comment"// //=>// //"c_comment",// +
- //"c_date"// //=>// //"c_date",// +
- //"tech_date"=>"tech_date",// +
- //"tech_user"=>"tech_user",// +
- //"r_id"=>"r_id"// +
- //);// +
- %%//%% Type de données +
- //$this->//type //=// //array(// +
- //"c_id"// //=>// //"numeric",// +
- //"c_comment"// //=>// //"text",// +
- //"c_date"// //=>// //"date",// +
- //"tech_date"=>"date",// +
- //"tech_user"=>"text",// +
- //"r_id"=>"numeric"// +
- //);// +
- %%//%% Les colonnes qui ne peuvent pas être changée ni par insert ni par  +
-// //%%//%% update parce leurs valeurs sont données automatiquement  +
-// //%%//%% exemple : la clef primaire qui est un numéro de séquence  +
- // //%%//%%automatiquement donné +
- //$this->//default //=// //array(// +
- //"c_id"// //=>// //"auto",// +
- //"tech_date"// //=>// //"auto"// +
- //);// +
- //global// //$cn;// +
- +
- parent//:://%%__%%construct//($cn,// //$p_id);// +
- //}// +
-//} +
- +
-Si on change la structure d'une table, il ne faut presque rien changer : seulement quelques lignes+
  
 +Il faut tout d'abord un fichier bootstrap qui contient le path correct pour php ainsi que les variables comme $g_user ou $cn, l'inclusion de [[:config.inc.php]] et de constant.php
 + 
  
  • developpement_de_phpcompta.1364049794.txt.gz
  • Dernière modification : 2013/03/23 15:43
  • de dany