Langages et normes: Difference between revisions

Jump to navigation Jump to search
m
Tag: 2017 source edit
Tag: 2017 source edit
 
(31 intermediate revisions by the same user not shown)
Line 9: Line 9:
<!-- END interlang links -->
<!-- END interlang links -->


{{TemplateDocDev}}
{{TemplateDocDevFr}}


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 :
Line 18: Line 18:


#Tous OS (Windows, Linux, MACOS...)
#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).
#PHP {{PHPMinVersion}} (Doit fonctionner sans aucun module PHP complémentaire hors les modules d'accès base de donnée). Voir la page [[Versions|Liste des versions, journal des modifications et compatibilités]] pour les prérequis des versions plus anciennes.
#Mysql {{MySqlMinVersion}}
#Mysql {{MySqlMinVersion}}


Line 41: Line 41:
*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 $_COOKIE, $_SERVER, $_ENV. Mais pour récupérer les contenus de $_GET ou $_POST, il faut passer par la fonction dolibarr [[Fonctions utiles Dolibarr|GETPOST()]] ou [[Fonctions utiles Dolibarr|GETPOSTINT()]] .
*L'appel aux variables superglobales PHP doit passer par les opérateurs dédiés $_COOKIE, $_SERVER, $_ENV. Mais pour récupérer les contenus de $_GET ou $_POST, il faut passer par les fonctions dolibarr [[Fonctions utiles Dolibarr|GETPOST...()]] .


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.
Line 88: Line 88:
*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" ou "require_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-12 (https://www.php-fig.org/psr/psr-12/). Seules les règles "MUST" sont imposées. Notez aussi les points/exceptions suivants:
*Le style de code a utiliser est le PSR-12 (https://www.php-fig.org/psr/psr-12/). Seules les règles "MUST" sont imposées. Notez aussi les points/exceptions suivants:
Line 107: Line 107:
=Normes SQL=
=Normes SQL=


==Structure des tables et champs==
==Structure et nom 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>.
Line 257: Line 257:
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 SQL de date NOW, SYSDATE, 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 pour les raisons suivantes:
*Les fonctions SQL de date NOW, SYSDATE, DATEDIFF, DATE 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 pour les raisons suivantes:
**afin d'avoir une meilleure portabilité du code
**afin d'avoir une meilleure portabilité du code
**avoir une gestion correcte des TimeZone et ne pas dépendre du TimeZone de la base de donnée (le timezone de réference est le timezone de PHP et le timezone de la base de données peut être différent de celui-ci, aussi les conversions de date doivent se faire toute côté PHP).
**avoir une gestion correcte des TimeZone et ne pas dépendre du TimeZone de la base de donnée (le timezone de réference est le timezone de PHP et le timezone de la base de données peut être différent de celui-ci, aussi les conversions de date doivent se faire toute côté PHP).
Line 295: Line 295:


De telles instructions SQL sont interdites car elles contournent les règles métiers de l'application. Par exemple, s'il existe une cascade de suppression entre la table A et B, lorsque l'application exécutera le code pour supprimer un enregistrement dans A, les enfants de la table B seront également supprimés. S'il y a eu un trigger Dolibarr PHP (par exemple apporté par un module externe) sur la suppression de l'enregistrement de B (par exemple pour valider la suppression ou pour exécuter une action complémentaire), la DELETE CASCADE sera exécutée sans avoir le trigger Dolibarr PHP exécuté, manquant la validation ou les actions du déclencheur PHP du module. Donc toutes les règles métiers doivent être implémentées du même côté (côté serveur PHP), c'est la raison pour laquelle les règles métier implémentées sur Database ne sont pas autorisées (même situation que le point suivant sur les triggers Database)
De telles instructions SQL sont interdites car elles contournent les règles métiers de l'application. Par exemple, s'il existe une cascade de suppression entre la table A et B, lorsque l'application exécutera le code pour supprimer un enregistrement dans A, les enfants de la table B seront également supprimés. S'il y a eu un trigger Dolibarr PHP (par exemple apporté par un module externe) sur la suppression de l'enregistrement de B (par exemple pour valider la suppression ou pour exécuter une action complémentaire), la DELETE CASCADE sera exécutée sans avoir le trigger Dolibarr PHP exécuté, manquant la validation ou les actions du déclencheur PHP du module. Donc toutes les règles métiers doivent être implémentées du même côté (côté serveur PHP), c'est la raison pour laquelle les règles métier implémentées sur Database ne sont pas autorisées (même situation que le point suivant sur les triggers Database)
==Utilisation des triggers de base de données / procédures stockées==
L'utilisation des triggers de base de données n'est pas autorisée dans le code de Dolibarr. Vous ne devriez donc rencontrer aucun problème avec ces déclencheurs.
*Les triggers de base de données ne sont pas portables. La compatibilité peut être compromise lors de la mise à jour de votre base de données.
*Les triggers de base de données sont souvent oubliés dans les outils de sauvegarde.
*Les triggers de base de données nécessitent des autorisations spéciales que vous ne possédez peut-être pas (et que vous ne devriez pas posséder) sur une base de données sécurisée classique.
*L'utilisation de triggers de base de données implique également l'inclusion de certaines « règles métier » de votre application dans la base de données, alors que la plupart des autres règles sont gérées par le code lui-même (ce qui peut créer des conflits ou rendre le code impossible à déboguer pas à pas).
*Les triggers de base de données exécutent le code en utilisant le fuseau horaire et la langue par défaut de la base de données, au lieu du fuseau horaire de référence de l'application (qui peut être différent), ce qui génère un décalage dans la base de données. De plus, la langue par défaut de l'application est également déconseillée.
*Il existe de nombreuses autres raisons pour lesquelles nous déconseillons l'utilisation des triggers de base de données dans vos développements.
L'utilisation de triggers de base de données peut certes vous faire gagner du temps lors du développement, mais constitue une très mauvaise pratique lorsque la qualité, la portabilité, la sécurité et la pérennité sont primordiales. C'est pourquoi elle est interdite, car elle est incompatible avec le haut niveau de qualité de code exigé par l'équipe Dolibarr. Les modules externes utilisant des déclencheurs de base de données peuvent également être refusés sur la plateforme, car ils ne fonctionneront pas pour plus de 50 % des utilisateurs.


==Règles de migration de base==
==Règles de migration de base==
Line 397: Line 415:


==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 est une application multi-utilisateur et multi-site. Il est donc nécessaire de stocker les dates dans le format approprié. 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.
*   En mémoire, une date doit toujours être stockée 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 stockée en base de données correspond au Timestamp GMT de la date soumise dans la requête, en utilisant le fuseau horaire du serveur PHP. Cela ne s'applique pas aux dates mises à jour automatiquement par le moteur de base de données (champs `tms` en base de données).


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).
Par exemple, le 1er janvier 1970 à 3 heures à Paris (fuseau horaire +1) équivaut à 2 heures à Greenwich (fuseau horaire 0) ; la date sera stockée en mémoire sous la forme de l'entier 7200 (2 * 3600 s) et transmise à la base de données via une requête SQL sous la chaîne '19700101030000' (PHP convertit l'entier selon son fuseau horaire, et la base de données effectue la conversion inverse en utilisant également son propre fuseau horaire, identique à 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).
'''Gestion des dates incluant les heures'''


*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.
Ainsi, toutes les méthodes d'insertion ou de mise à jour doivent convertir, lors de la génération de la requête SQL, la date stockée en mémoire (sous forme d'entier) en une chaîne de caractères compatible avec la base de données, en utilisant `db->idate` (des exemples sont disponibles dans le squelette de code).


*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'''.
De même, toutes les méthodes de sélection doivent convertir les champs de date provenant de la base de données (chaînes au format du fuseau horaire du serveur, par exemple '19700101030000') en un champ timestamp (entier) en appelant la méthode `db->jdate()`. Cela permet de stocker la date en mémoire sous forme d'entier (Timestamp GMT).
 
'''Gestion des dates sans heures (jour uniquement)'''
 
Pour les insertions et mises à jour, vous devez effectuer la conversion avec `db->idate(valeur, 'gmt')` ; ainsi, pour la valeur 0, vous obtiendrez '19700101000000'.
 
Toutes les méthodes de sélection doivent convertir les champs de date provenant de la base de données (chaînes au format du fuseau horaire du serveur, par exemple '19700101000000') en utilisant `$db->jdate(..., 'gmt')`.
 
'''Autres cas'''
 
*Les dates mises à jour automatiquement (champ '''tms''' en base de données) contiennent un horodatage GMT correspondant au moment où la modification a été effectuée. La requête de sélection utilise également `db->jdate` (qui s'appuie sur le fuseau horaire du serveur PHP) pour convertir les données lues en un horodatage GMT en mémoire. Ainsi, si le fuseau horaire de la base de données diffère de celui du serveur PHP (par exemple, si l'un d'eux est mal configuré), vous pourriez constater des écarts entre la date de création et la date de mise à jour. Il est conseillé de ne pas se baser sur ce champ dans Dolibarr (ce champ à mise à jour automatique est principalement destiné au débogage).
 
*La manipulation des dates en PHP doit s'effectuer à l'aide des fonctions de date de Dolibarr : '''dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()'''. Vous trouverez également d'autres fonctions disponibles dans le fichier '''date.lib.php'''.


==L'encodage UTF8/ISO==
==L'encodage UTF8/ISO==
Line 481: Line 511:


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. C'est le modèle dit le plus "puriste".
Inconvénient : Motif complexe à maintenir.
 
Inconvénient : Motif plus complexe à maintenir.


*Le '''Table Module'''
*Le '''Table Module'''
Line 492: Line 524:
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 chapitre précédent Normes Dolibarr et squelettes de code), Dolibarr se base sur le principe du '''Table Module''', car le plus pragmatique des 3.


===Communication Logique métier - Données (ORM)===
===Communication Logique métier - Données (ORM)===
Line 505: Line 537:
*Le '''Active Record'''
*Le '''Active Record'''


Identique au précédent, mais on se permet d'ajouter quelques fonctions métiers sur la classe, à condition que ces fonctions soient bien  propres à la table ou à la notion métier portée 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, à condition que ces fonctions soient bien  propres à la table ou à la notion métier portée par l'enregistrement. Jugé plus éloigné des standards scolaires de la programmation objet, c'est toutefois 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éveloppement.
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éveloppement.
La couche ORM de Dolibarr se limite à une couche d abstraction de la base (on développe une fois et le driver de base converti le code pour l'accès base dans la syntaxe de la base de donnée: mysql vs postgresql vs ...)


*Le '''Data Mapper'''
*Le '''Data Mapper'''
Line 514: Line 548:
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ée 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ée ne rejoignant pas les promesses de la théorie).


Exemple: C'est le choix si on utilise le Framework d'ORM '''Propel''' (http://propel.phpdb.org/trac/). On le trouve donc sur des applications plus lourdes basées sur cet ORM entre autres.
Exemple: C'est le choix si on utilise des Framework d'ORM comme '''Propel''' (https://propelorm.org/). On le trouve donc sur des applications plus lourdes basées sur cet ORM entre autres.


-> 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).
Line 540: Line 574:
==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 de templates PHP (fichiers .php ou .tpl.php) qui restent le plus simple, le plus universel, le plus évolutif et le plus performant des frameworks de présentation.  
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 de templates PHP (fichiers .php ou .tpl.php) qui restent, de tous les frameworks de présentation, le plus simple, plus universel, plus évolutif, plus performant et surtout plus résilient au temps.  


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 pour le rendering écran). Ce point est toutefois contrôlé par le mécanisme de validation du code des chefs de projets.
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 pour le rendering écran). Ce point est toutefois contrôlé par le mécanisme de validation du code des chefs de projets.


La encore, c'est l'expérience et le constat "sur le terrain" 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'expérience et le constat "sur le terrain" d'un meilleur rendement de productivité, d'évolution applicative et de performance qui a motivé l'abandon des frameworks de Présentation externes au profit du framework PHP.
 
= Règles pour définir la branche cible d'une contribution =
Les règles pour décider si une contribution (Pull Request) doit être poussée dans une ancienne branche de maintenance ou dans une branche de développement ne sont pas strictes et sont souvent définies par le bon sens (pragmatisme avant tout).
Nous pouvons nous aider du diagramme de décision disponible sur cette page [[:Category:RoadMap#Merging_PR_process_.28develop_or_maintenance_.3F.29]]

Navigation menu