Langages et normes: Difference between revisions

Jump to navigation Jump to search
→‎PHP: ajout d'un lien vers fonctions utiles Dolibarr
m (Import interlang links (links to translated versions of this page in other languages) from origin English page "Language_and_development_rules".)
(→‎PHP: ajout d'un lien vers fonctions utiles Dolibarr)
Line 12: Line 12:
Voici les quelques règles sur le langage, la syntaxe et normes de développement en vigueur pour le projet Dolibarr:
Voici les quelques règles sur le langage, la syntaxe et normes de développement en vigueur pour le projet Dolibarr:


= Versions =
=Versions=


* Dolibarr doit fonctionner sur:
*Dolibarr doit fonctionner sur:
# Tous OS (Windows, Linux, MACOS...)
 
# PHP {{PHPMinVersion}} (Doit fonctionner sans aucun module PHP complémentaire hors les modules d'accès base de donnée).
#Tous OS (Windows, Linux, MACOS...)
# Mysql {{MySqlMinVersion}}
#PHP {{PHPMinVersion}} (Doit fonctionner sans aucun module PHP complémentaire hors les modules d'accès base de donnée).
#Mysql {{MySqlMinVersion}}
 
=Normes Copyright=
 
*Tout fichier PHP doit avoir un en-tête selon le masque suivant


= Normes Copyright =
* Tout fichier PHP doit avoir un en-tête selon le masque suivant
<source lang="php">
<source lang="php">
<?php
<?php
Line 31: Line 34:
Quand vous éditez un fichier existant du projet, ajouter une ligne Copyright sous celles existantes.
Quand vous éditez un fichier existant du projet, ajouter une ligne Copyright sous celles existantes.


= Normes PHP =
=Normes PHP=


== PHP ==
==PHP==
* Dolibarr est écrit en PHP et supporte toutes versions PHP supérieures à la {{PHPMinVersion}}. Les fichiers doivent tous comporter l'extension .php
 
*Dolibarr est écrit en PHP et supporte toutes versions PHP supérieures à la {{PHPMinVersion}}. Les fichiers doivent tous comporter l'extension .php
 
*L'appel aux variables superglobales PHP doit passer par les opérateurs dédiés $_COOKIES, $_SERVER, $_ENV mais par la fonction dolibarr [[Fonctions utiles Dolibarr|GETPOST()]] pour récupérer les contenus de $_GET ou $_POST.


* L'appel aux variables superglobales PHP doit passer par les opérateurs dédiés $_COOKIES, $_SERVER, $_ENV mais par la fonction dolibarr GETPOST() pour récupérer les contenus de $_GET ou $_POST.
Les autres opérateurs ($HTTP_SERVER_GET, ...) ayant été passés en deprecated au sein de PHP, ne doivent plus être utilisés. Ainsi le code doit fonctionner y compris quand l'option '''register_long_arrays''' est à off.
Les autres opérateurs ($HTTP_SERVER_GET, ...) ayant été passés en deprecated au sein de PHP, ne doivent plus être utilisés. Ainsi le code doit fonctionner y compris quand l'option '''register_long_arrays''' est à off.
De plus, le code doit fonctionner aussi bien quand l'option PHP '''register_globals''' est à off (recommandé par PHP)  que quand l'option '''register_globals''' est à on (par défaut sur de nombreuses installations).
De plus, le code doit fonctionner aussi bien quand l'option PHP '''register_globals''' est à off (recommandé par PHP)  que quand l'option '''register_globals''' est à on (par défaut sur de nombreuses installations).


* Pas d'utilisation de la variable '''PHP_SELF'''. Utiliser à la place $_SERVER["PHP_SELF"]. Notez aussi que le framework Dolibarr passe une routine pour rendre plus sûr le contenu du $_SERVER["PHP_SELF"] (dans le fichier main.inc.php, donc avant tout traitement métier)
*Pas d'utilisation de la variable '''PHP_SELF'''. Utiliser à la place $_SERVER["PHP_SELF"]. Notez aussi que le framework Dolibarr passe une routine pour rendre plus sûr le contenu du $_SERVER["PHP_SELF"] (dans le fichier main.inc.php, donc avant tout traitement métier)
 
*Quand plusieurs variables doivent être initialisées avec la même valeur, il faut utiliser plusieurs instructions:


* Quand plusieurs variables doivent être initialisées avec la même valeur, il faut utiliser plusieurs instructions:
<source lang="php">
<source lang="php">
$var1=1;$var2=1;$var3=1;
$var1=1;$var2=1;$var3=1;
Line 52: Line 58:
qui est moins performant.
qui est moins performant.


* Les chaines doivent être encadrées de simple quote et les variables sorties de la chaine.
*Les chaines doivent être encadrées de simple quote et les variables sorties de la chaine.
 
<source lang="php">
<source lang="php">
print 'Mon texte affiche ma '.$variable.' !';
print 'Mon texte affiche ma '.$variable.' !';
</source>
</source>


* Les commentaires doivent suivre la syntaxe C, ie un double antislash pour un commentaire d'une ligne et utilisation slash-étoile pour ouvrir un bloc de plusieurs lignes
*Les commentaires doivent suivre la syntaxe C, ie un double antislash pour un commentaire d'une ligne et utilisation slash-étoile pour ouvrir un bloc de plusieurs lignes
 
<source lang="php">
<source lang="php">
/* Bloc de commentaire
/* Bloc de commentaire
Line 75: Line 83:
</source>
</source>


* Les fonctions doivent retourner une valeure strictement > à 0 en cas de succès, et un nombre < à 0 en cas d'erreur.
*Les fonctions doivent retourner une valeure strictement > à 0 en cas de succès, et un nombre < à 0 en cas d'erreur.


* Pas de code mort (non utilisé) dans le code principal de Dolibarr (le code utilisé uniquement par un module externe doit être inclus dans le module externe).
*Pas de code mort (non utilisé) dans le code principal de Dolibarr (le code utilisé uniquement par un module externe doit être inclus dans le module externe).


* Utiliser "include_once" pour l'inclusion de tout fichier contenant des définitions de fonction ou de classes (donc fichiers *.class.php et *.lib.php), utiliser "include" pour tout inclusion de fichier de type template ou contenant un mixte de HTML et PHP (donc fichiers *.inc.php et *.tpl.php).
*Utiliser "include_once" pour l'inclusion de tout fichier contenant des définitions de fonction ou de classes (donc fichiers *.class.php et *.lib.php), utiliser "include" pour tout inclusion de fichier de type template ou contenant un mixte de HTML et PHP (donc fichiers *.inc.php et *.tpl.php).


* Le style de code a utiliser est le PSR-2 (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). Seules les règles "MUST" sont imposées. Notez aussi les points/excetions suivants:
*Le style de code a utiliser est le PSR-2 (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md). Seules les règles "MUST" sont imposées. Notez aussi les points/excetions suivants:
** La longueur des lignes: PSR-2 indique que la longueur des lignes a une limite "soft" à 120. Il est en effet préférable d'avoir de longues lignes de données de déclaration plutôt que de longues pages car ce code ne contient aucune logique, toutefois une limite "hard" a été instauré à '''1000''' caractères. Du code qui ira au dela provoquera des erreurs dans la plateforme d'Intégration Continue.
**La longueur des lignes: PSR-2 indique que la longueur des lignes a une limite "soft" à 120. Il est en effet préférable d'avoir de longues lignes de données de déclaration plutôt que de longues pages car ce code ne contient aucune logique, toutefois une limite "hard" a été instauré à '''1000''' caractères. Du code qui ira au dela provoquera des erreurs dans la plateforme d'Intégration Continue.
** Les tabulations sont acceptées: L'autre exception est qu'on ne remplace pas les tabulations systématiquement par des espaces. L'utilisation des tabulations simplifie la vie de certains développeurs. De plus, l'utilisation d'espaces rend certaines fonctions d'autoformatage défectueuses (comme sur certaines versions d'Eclipse, lors de copié-collé).
**Les tabulations sont acceptées: L'autre exception est qu'on ne remplace pas les tabulations systématiquement par des espaces. L'utilisation des tabulations simplifie la vie de certains développeurs. De plus, l'utilisation d'espaces rend certaines fonctions d'autoformatage défectueuses (comme sur certaines versions d'Eclipse, lors de copié-collé).
** Note 1: Les règles suivantes sont particulièrement importantes:
**Note 1: Les règles suivantes sont particulièrement importantes:
*** Les fichiers doivent être sauvés en format Unix (LF) et non Windows (CR/LF). Le format Unix étant compatible sur les OS Unix like, Windows, Mac, alors que le format fichier texte Windows pose problème sous certains PHP sous Unix.
***Les fichiers doivent être sauvés en format Unix (LF) et non Windows (CR/LF). Le format Unix étant compatible sur les OS Unix like, Windows, Mac, alors que le format fichier texte Windows pose problème sous certains PHP sous Unix.
*** Les smart tags PHP ne sont pas utilisés. Les sections de code doivent commencer par '''<?php'''
***Les smart tags PHP ne sont pas utilisés. Les sections de code doivent commencer par '''<?php'''
** Note 2: Vous pouvez utiliser le fichier '''dev/codesniffer/ruleset.xml''' comme fichier de contrôle pour vérifier votre style de code avec PHPCodeSniffer.
**Note 2: Vous pouvez utiliser le fichier '''dev/codesniffer/ruleset.xml''' comme fichier de contrôle pour vérifier votre style de code avec PHPCodeSniffer.
** Note 3: Vous remarquerez que le code actuel ne suit pas forcément tout cela. La raison est historique. La règle fut instaurée en cours de route, aussi, si vous trouvez du code non respectueux de ce standard, n'hésitez pas à le corriger.
**Note 3: Vous remarquerez que le code actuel ne suit pas forcément tout cela. La raison est historique. La règle fut instaurée en cours de route, aussi, si vous trouvez du code non respectueux de ce standard, n'hésitez pas à le corriger.


== Structures des classes et champs ==
==Structures des classes et champs==


Certaines propriétés de classes se retrouvent dans de nombreuses classes. Pour homogénéité, on utilisera les noms suivants:
Certaines propriétés de classes se retrouvent dans de nombreuses classes. Pour homogénéité, on utilisera les noms suivants:
{{TemplatePHPFields}}
{{TemplatePHPFields}}


= Normes SQL =
=Normes SQL=


== Structure des tables et champs ==
==Structure des tables et champs==
* Toutes les tables sont préfixées pour éviter les conflits de nommage. Aujourd'hui, le préfixe est modifiable au moment de l'installation. Sa valeur par défaut est <tt>llx_</tt>.
 
*Toutes les tables sont préfixées pour éviter les conflits de nommage. Aujourd'hui, le préfixe est modifiable au moment de l'installation. Sa valeur par défaut est <tt>llx_</tt>.
 
*Structure des tables.


* Structure des tables.
Lorsque vous créez une table, il est recommandé de prendre les même conventions de nommages de tables que les autres tables Dolibarr. Avec, à minima les champs suivant:
Lorsque vous créez une table, il est recommandé de prendre les même conventions de nommages de tables que les autres tables Dolibarr. Avec, à minima les champs suivant:
  - rowid INTEGER AUTO_INCREMENT PRIMARY KEY    qui est l'id technique
  - rowid INTEGER AUTO_INCREMENT PRIMARY KEY    qui est l'id technique
Line 114: Line 124:
  - fk_soc integer qui est l'id du tiers (si applicable)
  - fk_soc integer qui est l'id du tiers (si applicable)


* Type des champs
*Type des champs
 
Dans la pratique, afin d'etre compatible avec toutes les précisions des pays, syntaxes des bases, on utilisera uniquement les types suivants:
Dans la pratique, afin d'etre compatible avec toutes les précisions des pays, syntaxes des bases, on utilisera uniquement les types suivants:
  - smallint pour tout petit nombre entier
  - smallint pour tout petit nombre entier
Line 126: Line 137:
  - date pour un champ date
  - date pour un champ date


== Clé primaire ==
==Clé primaire==
La clé primaire d'une table s'appelle <tt>rowid</tt>.
La clé primaire d'une table s'appelle <tt>rowid</tt>.


Il y a quelques tables qui échappent à cette règle actuellement (ex [[Table llx_c_actioncomm]]), pour des raisons historiques. Une évolution pourra être étudiée pour une prochaine version.
Il y a quelques tables qui échappent à cette règle actuellement (ex [[Table llx_c_actioncomm]]), pour des raisons historiques. Une évolution pourra être étudiée pour une prochaine version.


== Clés étrangères ==
==Clés étrangères==
Le nom d'une clé étrangère commence par le préfixe <tt>fk_</tt> suivi du nom de la table liée (requis pour éviter doublons globales à la base, problématiques sous certains SGBD comme postgresql) puis du champ lié (pour permettre plusieurs clés étrangères différentes sur une même table).
Le nom d'une clé étrangère commence par le préfixe <tt>fk_</tt> suivi du nom de la table liée (requis pour éviter doublons globales à la base, problématiques sous certains SGBD comme postgresql) puis du champ lié (pour permettre plusieurs clés étrangères différentes sur une même table).


Line 139: Line 150:
Note: Si vous développez votre propre module externe, il ne doit pas y avoir de clé étrangère depuis vos tables qui pointent sur les tables standards de Dolibarr. Ceci casserait les fonctionnalités de mise à jour, de réparation, de sauvegardes et de restauration.
Note: Si vous développez votre propre module externe, il ne doit pas y avoir de clé étrangère depuis vos tables qui pointent sur les tables standards de Dolibarr. Ceci casserait les fonctionnalités de mise à jour, de réparation, de sauvegardes et de restauration.


== Clés alternatives ==
==Clés alternatives==
Parfois, il n'y a pas que la clé primaire qui doit être unique. On peut donc ajouter aussi un index clé alternative unique. Un tel index est nommé par un nom qui commence par le préfixe <tt>uk_</tt> suivi du nom de la table (requis pour éviter doublons d'index globals à la base, problématiques sous certains SGBD comme postgresql) puis d'un suffixe qui caractérise la clé (pour permettre plusieurs index uniques sur une même table).
Parfois, il n'y a pas que la clé primaire qui doit être unique. On peut donc ajouter aussi un index clé alternative unique. Un tel index est nommé par un nom qui commence par le préfixe <tt>uk_</tt> suivi du nom de la table (requis pour éviter doublons d'index globals à la base, problématiques sous certains SGBD comme postgresql) puis d'un suffixe qui caractérise la clé (pour permettre plusieurs index uniques sur une même table).


Line 145: Line 156:
uk_societe_code_client
uk_societe_code_client


== Index performance ==
==Index performance==
Certains champs sont souvent utilisés comme critère de recherche, de tri ou de jointure. Il convient dans ce cas, d'y mettre un index de performance. De tels indexes seront nommés avec un préfix <tt>idx_</tt> puis le nom de la table et le nom du champ sur lequel porte l'index.
Certains champs sont souvent utilisés comme critère de recherche, de tri ou de jointure. Il convient dans ce cas, d'y mettre un index de performance. De tels indexes seront nommés avec un préfix <tt>idx_</tt> puis le nom de la table et le nom du champ sur lequel porte l'index.


Line 151: Line 162:
idx_societe_user_creat
idx_societe_user_creat


== Format de fichier DDL ==
==Format de fichier DDL==
Les fichiers qui contiennent la définition de la structure de la base (DDL) doivent être au nombre de 2 par tables:
Les fichiers qui contiennent la définition de la structure de la base (DDL) doivent être au nombre de 2 par tables:
Chaque table est définie dans son propre fichier dont le nom est <tt>llx_''matable''.sql</tt>.  
Chaque table est définie dans son propre fichier dont le nom est <tt>llx_''matable''.sql</tt>.  
Line 215: Line 226:
</source>
</source>


== Règles de codage SQL ==
==Règles de codage SQL==
* Utilisation des alias/nommage de champs
 
*Utilisation des alias/nommage de champs
 
Dans le cas des select on pourra utiliser les alias pour simplifier l'écriture des requêtes:
Dans le cas des select on pourra utiliser les alias pour simplifier l'écriture des requêtes:
<source lang="sql">
<source lang="sql">
Line 223: Line 236:
Toutefois, il ne faut pas utiliser ces alias sur des requêtes update car non compatible avec mysql 3.1.
Toutefois, il ne faut pas utiliser ces alias sur des requêtes update car non compatible avec mysql 3.1.


* Les SELECT * sont interdits ! Chaque SELECT doit spécifier la liste complète des champs à récupérer. Cela permet d'éviter les confusions. Exemple:
*Les SELECT * sont interdits ! Chaque SELECT doit spécifier la liste complète des champs à récupérer. Cela permet d'éviter les confusions. Exemple:
 
<source lang="sql">
<source lang="sql">
SELECT field_a, field_b, field_c FROM table_1 WHERE field_d = '$id'
SELECT field_a, field_b, field_c FROM table_1 WHERE field_d = '$id'
</source>
</source>


* Dans les requêtes SQL, on quote les champs mais pas les numériques qui contiennent des montants destinés à être stockés dans des champs de type double ou real. Les quotes sur les numériques de type float provoquent parfois un stockage d'une valeur différente. Par exemple 412.62 dans le insert sera en fait stocké avec la valeur 412.61999512 en base (suite à des conversions chaines-numériques implicites) si le champ est de type double(24,8). Et seul le PHP voit 412.61999512. Les autres outils verront 412.62 donnant l'impression qu'il n'y a pas de problème. Et c'est le PHP qui a raison, il y a problème en base. En supprimant les quotes sur les numériques, cela va mieux.
*Dans les requêtes SQL, on quote les champs mais pas les numériques qui contiennent des montants destinés à être stockés dans des champs de type double ou real. Les quotes sur les numériques de type float provoquent parfois un stockage d'une valeur différente. Par exemple 412.62 dans le insert sera en fait stocké avec la valeur 412.61999512 en base (suite à des conversions chaines-numériques implicites) si le champ est de type double(24,8). Et seul le PHP voit 412.61999512. Les autres outils verront 412.62 donnant l'impression qu'il n'y a pas de problème. Et c'est le PHP qui a raison, il y a problème en base. En supprimant les quotes sur les numériques, cela va mieux.


Exemple:
Exemple:
Line 240: Line 254:
Voir aussi le chapitre "Les nombres réels, montants et calculs" plus bas.
Voir aussi le chapitre "Les nombres réels, montants et calculs" plus bas.


* Les fonctions NOW, SYSDATE ou DATEDIFF sont interdites au sein des ordres SQL. S'il faut saisir la date du moment dans un champ, la valeur doit venir du PHP, par exemple par la fonction dol_now(), et non du moteur de base de données. Ceci afin d'avoir une meilleure portabilité du code mais surtout d'avoir une gestion correcte des TimeZone et ne pas dépendre du TimeZone de la base de donnée.
*Les fonctions NOW, SYSDATE ou DATEDIFF sont interdites au sein des ordres SQL. S'il faut saisir la date du moment dans un champ, la valeur doit venir du PHP, par exemple par la fonction dol_now(), et non du moteur de base de données. Ceci afin d'avoir une meilleure portabilité du code mais surtout d'avoir une gestion correcte des TimeZone et ne pas dépendre du TimeZone de la base de donnée.


Par exemple, on ne fera pas:
Par exemple, on ne fera pas:
Line 262: Line 276:
Un autre avantage de cette règle est que la requête peut bénéficier de l'utilisation de l'index puisqu'on compare datefield à une valeur fixe. Dans le cas du datediff, on applique un traitement sur le champ avant comparaison, rendant impossible l'utilisation de l'index de ce champ. Les conséquences sont des performances très dégradées par rapport à la version sans datediff.
Un autre avantage de cette règle est que la requête peut bénéficier de l'utilisation de l'index puisqu'on compare datefield à une valeur fixe. Dans le cas du datediff, on applique un traitement sur le champ avant comparaison, rendant impossible l'utilisation de l'index de ce champ. Les conséquences sont des performances très dégradées par rapport à la version sans datediff.


== Règles de migration de base ==
==Règles de migration de base==
* Les scripts de migration de structure sont les fichiers de type '''install/mysql/migration/a.b.c-x.y.z.sql'''. Dans un fichier de migration de n vers n+1, on ne détruit une table (DROP TABLE) qui n'est plus utilisée en n+1 que lors de la migration de la version n+1 vers n+2. Ceci afin de toujours conserver les tables deprecated le temps d'une version pour réparer une situation en cas d'erreur de migration.
 
*Les scripts de migration de structure sont les fichiers de type '''install/mysql/migration/a.b.c-x.y.z.sql'''. Dans un fichier de migration de n vers n+1, on ne détruit une table (DROP TABLE) qui n'est plus utilisée en n+1 que lors de la migration de la version n+1 vers n+2. Ceci afin de toujours conserver les tables deprecated le temps d'une version pour réparer une situation en cas d'erreur de migration.
 
==Spécificités MySQL==
 
*Les tables doivent être au format InnoDB.


== Spécificités MySQL ==
* Les tables doivent être au format InnoDB.
En effet, ce format gère les clés étrangères, les éventuelles restrictions qui y sont attachées et la notion d'intégrité de transactions requise pour avoir des données en base cohérente entre tables.
En effet, ce format gère les clés étrangères, les éventuelles restrictions qui y sont attachées et la notion d'intégrité de transactions requise pour avoir des données en base cohérente entre tables.


* Dolibarr DOIT fonctionner même avec les options '''strict''' de Mysql active.
*Dolibarr DOIT fonctionner même avec les options '''strict''' de Mysql active.
 
Pour l'activer, ajouter la ligne suivante dans le fichier config du serveur Mysql (my.cnf ou my.ini)
Pour l'activer, ajouter la ligne suivante dans le fichier config du serveur Mysql (my.cnf ou my.ini)
<source lang="ini">
<source lang="ini">
Line 275: Line 293:
</source>
</source>


== Spécificités PostgreSQL ==
==Spécificités PostgreSQL==
Seuls les fichiers pour Mysql doivent être maintenus.
Seuls les fichiers pour Mysql doivent être maintenus.
Les fichiers pour les autres bases sont convertis "à la volée" par le driver Dolibarr de la base.
Les fichiers pour les autres bases sont convertis "à la volée" par le driver Dolibarr de la base.
Line 304: Line 322:
</source>
</source>


= Normes HTML =
=Normes HTML=
 
*Tous les attributs dans les balises HTML doivent être *en minuscule* et quotés avec des *doubles quote*.


* Tous les attributs dans les balises HTML doivent être *en minuscule* et quotés avec des *doubles quote*.
*Les liens href doivent être absolus en se basant sur la fonction dol_buildpath() pour obtenir un chemin absolu depuis un chemin relatif au répertoire htdocs. Pour les tags img, il faut faire appel à la fonction img_picto().


* Les liens href doivent être absolus en se basant sur la fonction dol_buildpath() pour obtenir un chemin absolu depuis un chemin relatif au répertoire htdocs. Pour les tags img, il faut faire appel à la fonction img_picto().
Par example:
Par example:
<source lang="php">
<source lang="php">
Line 314: Line 333:
</source>
</source>


* Les tables HTML doivent avoir des colonnes sans valeurs forcées, excepté pour les colonnes qui contiennent une information dont la longueur est non variable. Par exemple, une colonne avec un picto peut être forcée à with="20px". Dans les autres cas, il faut éviter de forcer la largeur des colonnes. La raison est que, dans la plupart des cas, le navigateur fait un meilleur travail pour définir automatiquement la bonne largeur des colonnes qu'en forçant manuellement les largeurs. Et ceci marche quelque soit la résolution de l'écran.
*Les tables HTML doivent avoir des colonnes sans valeurs forcées, excepté pour les colonnes qui contiennent une information dont la longueur est non variable. Par exemple, une colonne avec un picto peut être forcée à with="20px". Dans les autres cas, il faut éviter de forcer la largeur des colonnes. La raison est que, dans la plupart des cas, le navigateur fait un meilleur travail pour définir automatiquement la bonne largeur des colonnes qu'en forçant manuellement les largeurs. Et ceci marche quelque soit la résolution de l'écran.
 
*Le javascript/ajax et l'appel aux scripts java dans les pages php est à proscrire. Si toutefois du code javascript est inclus, il doit être conditionné par le test sur "$conf->use_javascript_ajax"


* Le javascript/ajax et l'appel aux scripts java dans les pages php est à proscrire. Si toutefois du code javascript est inclus, il doit être conditionné par le test sur "$conf->use_javascript_ajax"
<source lang="php">
<source lang="php">
if ($conf->use_javascript_ajax) {
if ($conf->use_javascript_ajax) {
Line 323: Line 343:
</source>
</source>


* Les popups windows ne doivent pas être utilisées, sauf pour des tooltips (et restent conditionnées par le point ci-dessus).
*Les popups windows ne doivent pas être utilisées, sauf pour des tooltips (et restent conditionnées par le point ci-dessus).


* Les scripts externes sont écrits en Perl s'ils ne peuvent l'être en php, l'utilisation d'un autre langage n'est pas interdit mais doit être discuté au préalable dans la mailing list des développeurs.
*Les scripts externes sont écrits en Perl s'ils ne peuvent l'être en php, l'utilisation d'un autre langage n'est pas interdit mais doit être discuté au préalable dans la mailing list des développeurs.


= Normes Dolibarr et squelettes de code =
=Normes Dolibarr et squelettes de code=


== Squelettes de code ==
==Squelettes de code==
Afin d'uniformiser le code et d'accélérer le développement de nouveaux composants dans Dolibarr, se trouvent dans le répertoire '''dev/skeletons''', 4 squelettes de code tout préparés.
Afin d'uniformiser le code et d'accélérer le développement de nouveaux composants dans Dolibarr, se trouvent dans le répertoire '''dev/skeletons''', 4 squelettes de code tout préparés.


* 1 qui sert d'exemple de descripteur de module: '''myModule.class.php'''
*1 qui sert d'exemple de descripteur de module: '''myModule.class.php'''
* 1 qui sert d'exemple de code pour faire une nouvelle classe: '''skeleton_class.class.php'''
*1 qui sert d'exemple de code pour faire une nouvelle classe: '''skeleton_class.class.php'''
* 1 qui sert d'exemple de code pour faire une nouvelle page: '''skeleton_page.php'''
*1 qui sert d'exemple de code pour faire une nouvelle page: '''skeleton_page.php'''
* 1 qui sert d'exemple de code pour faire un script à exécuter en ligne de commande: '''skeleton_script.php'''
*1 qui sert d'exemple de code pour faire un script à exécuter en ligne de commande: '''skeleton_script.php'''


Servez-vous en comme exemple.
Servez-vous en comme exemple.
Notons que ces squelettes sont aussi utilisés par le générateur de code PHP qui est décrit dans la chapitre de développement de module Dolibarr pour accélérer vos développement.
Notons que ces squelettes sont aussi utilisés par le générateur de code PHP qui est décrit dans la chapitre de développement de module Dolibarr pour accélérer vos développement.


== Les dates et TimeZone ==
==Les dates et TimeZone==
Dolibarr se veut une application multi-utilisateur et multi-localisation. Il convient donc de stocker les dates dans le bon format. Pour éviter les problèmes de conversion, les règles suivantes doivent être appliquées:
Dolibarr se veut une application multi-utilisateur et multi-localisation. Il convient donc de stocker les dates dans le bon format. Pour éviter les problèmes de conversion, les règles suivantes doivent être appliquées:
* Une date en mémoire doit être au format Timestamp GMT.
 
* Une date stockée en base de données contient le Timestamp issue de la date soumise dans la requête en heure <b>locale du serveur PHP</b>. Cela ne concerne pas les dates mises à jour automatiquement par la base (champ '''tms''' en base).
*Une date en mémoire doit être au format Timestamp GMT.
*Une date stockée en base de données contient le Timestamp issue de la date soumise dans la requête en heure <b>locale du serveur PHP</b>. Cela ne concerne pas les dates mises à jour automatiquement par la base (champ '''tms''' en base).
 
Ainsi le 1er janvier 1970, 3 heures à Paris (TZ=+1) = 1er janvier 1970, 2 heures à Greenwich (TZ=0) sera stocké en mémoire par 7200 et sera soumis à la base de données avec la chaine '19700101030000' (PHP convertit en heure de son TZ et la base déconvertit avec son TZ qui est le même que celui de PHP).
Ainsi le 1er janvier 1970, 3 heures à Paris (TZ=+1) = 1er janvier 1970, 2 heures à Greenwich (TZ=0) sera stocké en mémoire par 7200 et sera soumis à la base de données avec la chaine '19700101030000' (PHP convertit en heure de son TZ et la base déconvertit avec son TZ qui est le même que celui de PHP).


Les méthodes select doivent donc traduire les champs dates lus qui sont au format chaine TZ de la base ('19700101030000') par appel de la méthode db->jdate afin de récupérer une information en mémoire au format Timestamp GMT. Et les méthodes insert doivent lors de la génération de la requête convertir la date mémoire connue en variable, par la méthode db->idate (Voir exemples générés par le squelette).
Les méthodes select doivent donc traduire les champs dates lus qui sont au format chaine TZ de la base ('19700101030000') par appel de la méthode db->jdate afin de récupérer une information en mémoire au format Timestamp GMT. Et les méthodes insert doivent lors de la génération de la requête convertir la date mémoire connue en variable, par la méthode db->idate (Voir exemples générés par le squelette).


* Les dates mises à jour automatiquement par la base (champ '''tms''' en base) contiennent le Timestamp où la modification est faite selon le timezone de la base de donnée. Les méthodes select récupèrent cette donnée en mémoire au format Timestamp GMT en appliquant également le db->jdate. Si le timezone de la base de donnée diffère de celui du PHP (un des 2 est mal réglé), il peut donc y avoir des écarts entre date de création et modification.
*Les dates mises à jour automatiquement par la base (champ '''tms''' en base) contiennent le Timestamp où la modification est faite selon le timezone de la base de donnée. Les méthodes select récupèrent cette donnée en mémoire au format Timestamp GMT en appliquant également le db->jdate. Si le timezone de la base de donnée diffère de celui du PHP (un des 2 est mal réglé), il peut donc y avoir des écarts entre date de création et modification.


* La manipulation de dates en PHP doit être faite en utilisant les fonctions dates de Dolibarr: '''dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()'''. Vous trouverez également d'autres fonctions prêtes à l'emploi dans le fichier '''date.lib.php'''.
*La manipulation de dates en PHP doit être faite en utilisant les fonctions dates de Dolibarr: '''dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()'''. Vous trouverez également d'autres fonctions prêtes à l'emploi dans le fichier '''date.lib.php'''.


== L'encodage UTF8/ISO ==
==L'encodage UTF8/ISO==
Dolibarr stocke les informations de manière suivante:
Dolibarr stocke les informations de manière suivante:
* En base de donnée, les données sont en UTF8 ou ISO. Cela dépend du pagecode de la base, donc des options à la création de cette base. Dans tous les cas le driver d'accès base Dolibarr (dans /lib/database) s'arrange à la lecture et insertion pour convertir vers et depuis de l'UTF8.
* Les données en mémoires sont donc stockées en UTF8 (instances d'objets PHP).
* Les pages web affichées à l'écran sont au format UTF8 (avec les versions < 2.5.1, c'est le vieux paramètre $character_set du fichier conf.php qui définissait le format de sortie).


== Les nombres réels, montants et calculs ==
*En base de donnée, les données sont en UTF8 ou ISO. Cela dépend du pagecode de la base, donc des options à la création de cette base. Dans tous les cas le driver d'accès base Dolibarr (dans /lib/database) s'arrange à la lecture et insertion pour convertir vers et depuis de l'UTF8.
*Les données en mémoires sont donc stockées en UTF8 (instances d'objets PHP).
*Les pages web affichées à l'écran sont au format UTF8 (avec les versions < 2.5.1, c'est le vieux paramètre $character_set du fichier conf.php qui définissait le format de sortie).
 
==Les nombres réels, montants et calculs==
En PHP comme dans d'autres langages (Java par exemple), les données non entières (float, real, double) ne sont pas fiables.
En PHP comme dans d'autres langages (Java par exemple), les données non entières (float, real, double) ne sont pas fiables.
Essayer de faire par exemple  
Essayer de faire par exemple  
Line 371: Line 394:
S'il ne s'agit pas d'un prix sur lequel s'adapte les paramètres MU, MT ou MS, il faut utiliser la fonction '''round()'''.
S'il ne s'agit pas d'un prix sur lequel s'adapte les paramètres MU, MT ou MS, il faut utiliser la fonction '''round()'''.


== Création de tables ==
==Création de tables==
Ne pas créer de table à l'utilisation, c'est-à-dire à la '''première utilisation''' du module.
Ne pas créer de table à l'utilisation, c'est-à-dire à la '''première utilisation''' du module.
Si vous créez un module qui utilise des tables qui ne sont pas intégrées en standard dans le code de Dolibarr, veillez à suivre le didacticiel [[Développement module]] qui explique comment joindre des tables qui se créent à l'activation du module et non à son utilisation (voir plus haut).
Si vous créez un module qui utilise des tables qui ne sont pas intégrées en standard dans le code de Dolibarr, veillez à suivre le didacticiel [[Développement module]] qui explique comment joindre des tables qui se créent à l'activation du module et non à son utilisation (voir plus haut).


== Comparer la version ==
==Comparer la version==


Si votre code a besoin de faire des choses différentes selon la version de Dolibarr, vous pouvez utiliser le truc suivant pour comparer les versions
Si votre code a besoin de faire des choses différentes selon la version de Dolibarr, vous pouvez utiliser le truc suivant pour comparer les versions
Line 389: Line 412:
</source>
</source>


== Logs ==
==Logs==
Ajouter des traces dans votre code avec la fonction
Ajouter des traces dans votre code avec la fonction
<source lang="php">
<source lang="php">
Line 395: Line 418:
</source>
</source>


== Répertoires de travail ==
==Répertoires de travail==
Si vous avez besoin de créer un répertoire de travail, dans votre code, faites référence à ce répertoire par
Si vous avez besoin de créer un répertoire de travail, dans votre code, faites référence à ce répertoire par
'''DOL_DATA_ROOT.'/monmodule''''
'''DOL_DATA_ROOT.'/monmodule''''
Line 407: Line 430:
Si vous avez besoin d'un répertoire qui contiendra des données temporaires, ce répertoire doit être''' DOL_DATA_ROOT.'/monmodule/temp''''
Si vous avez besoin d'un répertoire qui contiendra des données temporaires, ce répertoire doit être''' DOL_DATA_ROOT.'/monmodule/temp''''


= Design patterns et programmation objet =
=Design patterns et programmation objet=


== Design patterns de Création (GoF) ==
==Design patterns de Création (GoF)==
Design patterns définis par le Gang Of Four (voir la wikipédia sur les [[wikipedia:Patron de conception|Design patterns]]).
Design patterns définis par le Gang Of Four (voir la wikipédia sur les [[wikipedia:Patron de conception|Design patterns]]).
Dans Dolibarr, pas de mise en oeuvre de design patterns de comportement particulier.
Dans Dolibarr, pas de mise en oeuvre de design patterns de comportement particulier.
On trouve des objets proches des Singletons et Fabriques conforme à 100% dans l'esprit mais pas dans la syntaxe, ceci afin d’être compatible avec la plus large plage possible de versions de PHP.
On trouve des objets proches des Singletons et Fabriques conforme à 100% dans l'esprit mais pas dans la syntaxe, ceci afin d’être compatible avec la plus large plage possible de versions de PHP.


== Design patterns d'entreprises (Martin Fowler) ==
==Design patterns d'entreprises (Martin Fowler)==


=== Mode d'organisation du code ===
===Mode d'organisation du code===
[[wikipedia:Martin_Fowler|Martin Fowler]] a identifié 3 méthodes d'organisation du code appelées '''patterns''' ('''motifs'''):
[[wikipedia:Martin_Fowler|Martin Fowler]] a identifié 3 méthodes d'organisation du code appelées '''patterns''' ('''motifs'''):
* Le '''Transaction Script''' (Le code est linéaire en fonction d'une action utilisateur).
 
*Le '''Transaction Script''' (Le code est linéaire en fonction d'une action utilisateur).
 
C'est le motif à l'ancienne utilisé dans les langages procéduraux.
C'est le motif à l'ancienne utilisé dans les langages procéduraux.
Inconvénient: Redondance du code. Nécessité de connaitre le modèle physique pour développer les parties métiers.
Inconvénient: Redondance du code. Nécessité de connaitre le modèle physique pour développer les parties métiers.
* Le '''Domain Model'''
 
*Le '''Domain Model'''
 
C'est un concept possible depuis les langages objets. Ce sont les procédures métiers (qui doivent être identifiés avant) qui servent de bases pour les classes objets.
C'est un concept possible depuis les langages objets. Ce sont les procédures métiers (qui doivent être identifiés avant) qui servent de bases pour les classes objets.
Inconvénient: Motif complexe à maintenir.
Inconvénient: Motif complexe à maintenir.
* Le '''Table Module'''
 
*Le '''Table Module'''
 
Un intermédiaire entre les 2 précédents où l'on a une instance unique de classe par table de la base de données.
Un intermédiaire entre les 2 précédents où l'on a une instance unique de classe par table de la base de données.


-> Comme le montre les squelettes de code (voir point précédent), Dolibarr se base sur le principe du '''Table Module'''.
-> Comme le montre les squelettes de code (voir point précédent), Dolibarr se base sur le principe du '''Table Module'''.


=== Communication Logique métier - Données (ORM) ===
===Communication Logique métier - Données (ORM)===
Il existe 3 modes de liaisons:
Il existe 3 modes de liaisons:
* Le '''Table And Row Data Gateway'''
 
*Le '''Table And Row Data Gateway'''
 
C'est le plus simple. On crée une classe par table et chaque classe est un pont avec la table correspondante et propose les méthodes CRUD sur cette table (Create, Read, Update, Delete). Une instance de classe étant alors un enregistrement de la table. La classe ne contient que du code d'accès aux lignes ou colonnes de tables. Le code métier doit alors être ajouté dans d'autres classes. Les liens entre ces classes tables et les classes métiers devant être connues ou déduite de la connaissance du développeur.
C'est le plus simple. On crée une classe par table et chaque classe est un pont avec la table correspondante et propose les méthodes CRUD sur cette table (Create, Read, Update, Delete). Une instance de classe étant alors un enregistrement de la table. La classe ne contient que du code d'accès aux lignes ou colonnes de tables. Le code métier doit alors être ajouté dans d'autres classes. Les liens entre ces classes tables et les classes métiers devant être connues ou déduite de la connaissance du développeur.


Exemple: C'est le mode mis en oeuvre quand on utilise certains Frameworks d'ORM comme '''iBatis''' (http://ibatis.apache.org/).
Exemple: C'est le mode mis en oeuvre quand on utilise certains Frameworks d'ORM comme '''iBatis''' (http://ibatis.apache.org/).


* Le '''Active Record'''
*Le '''Active Record'''
 
Identique au précédent, mais on se permet d'ajouter quelques fonctions métiers sur la classe, à conditions que ces fonctions soient bien  propres à la table ou à la notion métier porté par l'enregistrement. C'est le pattern qui offre le meilleur rapport fonctionnalité/complexité.
Identique au précédent, mais on se permet d'ajouter quelques fonctions métiers sur la classe, à conditions que ces fonctions soient bien  propres à la table ou à la notion métier porté par l'enregistrement. C'est le pattern qui offre le meilleur rapport fonctionnalité/complexité.


Exemple: C'est le mode choisi pour les développements Dolibarr et de nombreuses autres applications PHP qui ont leur propre framework et pratiques de développements.
Exemple: C'est le mode choisi pour les développements Dolibarr et de nombreuses autres applications PHP qui ont leur propre framework et pratiques de développements.


* Le '''Data Mapper'''
*Le '''Data Mapper'''
 
Les classes représentent les entités du problème et non les données. Il faut donc doubler, tripler... ces classes avec des classes Mapper pour accéder aux données.
Les classes représentent les entités du problème et non les données. Il faut donc doubler, tripler... ces classes avec des classes Mapper pour accéder aux données.
Plus "puriste" sur le papier car plus proche du métier, ce mode a aussi l'inconvénient d'être très complexe et difficile à maintenir dans la réalité (l'expérience pratique constaté ne rejoignant pas les promesses de la théorie).
Plus "puriste" sur le papier car plus proche du métier, ce mode a aussi l'inconvénient d'être très complexe et difficile à maintenir dans la réalité (l'expérience pratique constaté ne rejoignant pas les promesses de la théorie).
Line 449: Line 482:
-> Pour les développements Dolibarr, il est recommandé d'utiliser le mode de liaison '''Active Record''' qui offre les avantages d'un modèle proche du métier sans en avoir la complexité et sans trop masquer non plus la technique. C'est dans ce mode que le développement, la compréhension du code et la maintenance technique et/ou fonctionnelle semble la plus productive (ceci est toutefois un éternel débat entre les puristes et les pragmatiques, débat dans lequel personne ne peut vraiment avoir raison, car tout dépend des objectifs à atteindre).
-> Pour les développements Dolibarr, il est recommandé d'utiliser le mode de liaison '''Active Record''' qui offre les avantages d'un modèle proche du métier sans en avoir la complexité et sans trop masquer non plus la technique. C'est dans ce mode que le développement, la compréhension du code et la maintenance technique et/ou fonctionnelle semble la plus productive (ceci est toutefois un éternel débat entre les puristes et les pragmatiques, débat dans lequel personne ne peut vraiment avoir raison, car tout dépend des objectifs à atteindre).


== Design Pattern d'Interface Graphique ==
==Design Pattern d'Interface Graphique==
Il existe plusieurs design pattern pour les interfaces utilisateurs (MVC, MVP, MVVM).
Il existe plusieurs design pattern pour les interfaces utilisateurs (MVC, MVP, MVVM).
Beaucoup confonde ce design pattern avec celui consistant à utiliser un framework de templates. C'est sans rapport. Un framework de template (voir point précédent) n'est en lien qu'avec la partie "V" de ces modèles.
Beaucoup confonde ce design pattern avec celui consistant à utiliser un framework de templates. C'est sans rapport. Un framework de template (voir point précédent) n'est en lien qu'avec la partie "V" de ces modèles.
Line 469: Line 502:
Ce mode de séparation a eu un effet neutre sur les nouveaux développement mais a permis de réduire de manière si importante le temps requis pour la maintenance et correction de bugs qu'il n'est pas envisagé de basculer vers un autre type de séparation (oui les constats fait dans la vraie vie ne sont pas toujours ceux attendus par la théorie scolaire). L'important reste qu'il y ait toujours séparation entre le C et le V, peut importe comment est matérialisé cette séparation, du moment qu'elle l'est (Rappel: Ne pas confondre la notion de séparation du C et du V avec la notion de séparation du code pour alimenter la données d'une Vue et du code pour formater la Vue, ceci un principe de séparation relevant du Design Pattern de Vue, voir point suivant).
Ce mode de séparation a eu un effet neutre sur les nouveaux développement mais a permis de réduire de manière si importante le temps requis pour la maintenance et correction de bugs qu'il n'est pas envisagé de basculer vers un autre type de séparation (oui les constats fait dans la vraie vie ne sont pas toujours ceux attendus par la théorie scolaire). L'important reste qu'il y ait toujours séparation entre le C et le V, peut importe comment est matérialisé cette séparation, du moment qu'elle l'est (Rappel: Ne pas confondre la notion de séparation du C et du V avec la notion de séparation du code pour alimenter la données d'une Vue et du code pour formater la Vue, ceci un principe de séparation relevant du Design Pattern de Vue, voir point suivant).


== Design Pattern de Vue - Présentation ==
==Design Pattern de Vue - Présentation==
Il existe des frameworks spécialisés dans le Design Pattern de Vue, la partie qui consiste à formater l'écran vue par l'utilisateur.
Il existe des frameworks spécialisés dans le Design Pattern de Vue, la partie qui consiste à formater l'écran vue par l'utilisateur.
Les vieilles versions de Dolibarr utilisaient Smarty. Ce framework est une surcouche à un Framework, déjà très puissant de formatage d'écran nommé PHP. Les bénéfices étant très inférieurs aux inconvénients, il a été abandonné au profit du PHP qui reste le plus simple, le plus universel des frameworks de présentation. Son seul défaut est qu'il ne peut garantir à 100% les écarts d'un développeur qui irait intégrer dans la Vue, une logique sans rapport avec la présentation (donc autre que du code à vocation de génération, de formatage, de sortie HTML, de logique de test ou de boucle). Ce point est toutefois contrôlé par le mécanisme de validation du code des chefs de projets.
Les vieilles versions de Dolibarr utilisaient Smarty. Ce framework est une surcouche à un Framework, déjà très puissant de formatage d'écran nommé PHP. Les bénéfices étant très inférieurs aux inconvénients, il a été abandonné au profit du PHP qui reste le plus simple, le plus universel des frameworks de présentation. Son seul défaut est qu'il ne peut garantir à 100% les écarts d'un développeur qui irait intégrer dans la Vue, une logique sans rapport avec la présentation (donc autre que du code à vocation de génération, de formatage, de sortie HTML, de logique de test ou de boucle). Ce point est toutefois contrôlé par le mécanisme de validation du code des chefs de projets.
La encore, c'est l'experience et le constat d'un meilleur rendement de productivité qui a motivé l'abandon des frameworks de Présentation externes au profit du framework PHP.
La encore, c'est l'experience et le constat d'un meilleur rendement de productivité qui a motivé l'abandon des frameworks de Présentation externes au profit du framework PHP.
20

edits

Navigation menu