Changes

m
Line 14: Line 14:  
=Versions=
 
=Versions=
   −
*Dolibarr must work on:
+
*Current version of Dolibarr must work on:
    
#All OS (Windows, Linux, MACOS...)
 
#All OS (Windows, Linux, MACOS...)
#PHP {{PHPMinVersion}} (Must work with no need of complementary PHP module, except module to PHP module to access database).
+
#PHP {{PHPMinVersion}} (Must work with no need of complementary PHP module, except module to PHP module to access database). See [[List of releases, change log and compatibilities]] for pre-requisites for older versions.
 
#MySQL {{MySqlMinVersion}}
 
#MySQL {{MySqlMinVersion}}
   Line 39: Line 39:  
*Dolibarr is written with PHP and supports all versions of PHP higher than {{PHPMinVersion}}. All files must end with extension .php
 
*Dolibarr is written with PHP and supports all versions of PHP higher than {{PHPMinVersion}}. All files must end with extension .php
   −
*Usage of PHP superglobals variables must use the dedicated operators $_COOKIES, $_SERVER, $_ENV but use the Dolibarr function GETPOST() to get the contents of $_GET or $_POST..
+
*Usage of PHP superglobals variables must use the dedicated operators $_COOKIE, $_SERVER, $_ENV but use the Dolibarr functions [[Fonctions utiles Dolibarr|GETPOST...()]] to get the contents of $_GET or $_POST..
    
*Other operators ($HTTP_SERVER_GET, ...) are now deprecated in PHP, so they must not be used. Code must work if option '''register_long_arrays''' is set to off. Moreover, the code must work when PHP option '''register_globals''' is off (recommended by PHP). It must also work  if the option '''register_globals''' is on (by default on a lot of installations).
 
*Other operators ($HTTP_SERVER_GET, ...) are now deprecated in PHP, so they must not be used. Code must work if option '''register_long_arrays''' is set to off. Moreover, the code must work when PHP option '''register_globals''' is off (recommended by PHP). It must also work  if the option '''register_globals''' is on (by default on a lot of installations).
Line 251: Line 251:  
''fk_facture_fourn_fk_soc''  is a foreign key in the table llx_facture_fourn for the field fk_soc in this table (that references the rowid field in another table)
 
''fk_facture_fourn_fk_soc''  is a foreign key in the table llx_facture_fourn for the field fk_soc in this table (that references the rowid field in another table)
   −
Note: If you develop your own external module, it must have no foreign keys that point to Dolibarr standard tables. This will break standard dolibarr upgrades, repair, backup and restore tools and may also break standard features.
+
Note: If you develop your own external module, it must have no hard foreign keys that point to Dolibarr standard tables. This will break standard dolibarr upgrades, repair, backup and restore tools and may also break standard features. Foreign keys must be soft foreign keys so managed by the code with no database contraints.
    
==Alternative keys==
 
==Alternative keys==
Line 281: Line 281:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
*Into SQL requests, you must quote fields except the fields that contain amounts which must be stored as double or real type. Quotes on numbers may result in saving as a different value. For example 412.62 in an insert will be saved as value 412.61999512 into database (due to implicit conversion string to numeric) if the target field has type double(24,8). Only PHP see value 412.61999512. Other tools will see 412.62 giving a sense that there is no problem. But it's PHP that has the good vision. There is really a wrong value into database. By removing quotes on numbers, no problem occurs.
+
*Into SQL requests, you must quote fields except the fields that contain amounts which must be stored as double or real type. Quotes on numbers may result in saving as a different value. For example 412.62 in an insert will be saved as value 412.61999512 into database (due to implicit conversion string to numeric) if the target field has type double(24,8). Only PHP see value 412.61999512. Other tools will see 412.62 letting think that there is no problem. But it's PHP that has the good vision. There is really a wrong value into database. By removing quotes on numbers, no problem occurs.
    
Example:
 
Example:
Line 289: Line 289:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
Note, problem of float numbers is same problem on all langauges and not only when inserting data into database. It occurs also with any language when you work on "real" numbers, so numbers must be, as soon as they are affected, cleaned with function price2num with second parameter defined to :
+
Note, the problem of float numbers is the same on all languages and not only when inserting data into database. It occurs also with any language when you work on "real" numbers, so numbers must be, as soon as they are affected into variable, cleaned with function price2num with second parameter defined to :
 
'MU' (for unit prices), 'MT' (for total prices) or 'MS' (otherwise) depending on usage of number. (see function documentation)
 
'MU' (for unit prices), 'MT' (for total prices) or 'MS' (otherwise) depending on usage of number. (see function documentation)
   −
* SQL Date functions NOW, SYSDATE or DATEDIFF are forbidden inside SQL requests. Other functions like (MONTH, YEAR) must also be avoided if possible. If you must use the current date into a field, value must come from the PHP and not from the database engine. This is for 3 reasons:
+
* SQL Date functions NOW, SYSDATE, DATEDIFF or DATE are forbidden inside SQL requests. Other functions like (MONTH, YEAR) must also be avoided if possible. If you must use the current date into a field, value must come from the PHP and not from the database engine. This is for 3 reasons:
 
** better portability of code
 
** better portability of code
 
** better management of TimeZone (reference timezone is the PHP timezone and timezone of database may differs so all dates functions must be on PHP side).
 
** better management of TimeZone (reference timezone is the PHP timezone and timezone of database may differs so all dates functions must be on PHP side).
Line 321: Line 321:  
This statement should not be used: it is not handled the same way by different databases.
 
This statement should not be used: it is not handled the same way by different databases.
 
Also, using WITH ROLLUP breaks the purity of the returned data. The intermediate subtotal generation aggregation performed by this statement can easily be done using PHP and helps keep the returned data array clean (not corrupted by artificially inserted data).
 
Also, using WITH ROLLUP breaks the purity of the returned data. The intermediate subtotal generation aggregation performed by this statement can easily be done using PHP and helps keep the returned data array clean (not corrupted by artificially inserted data).
 +
 +
* The sql function GROUP_CONCAT can't be used. It is not portable and ask the database to make subrequests for line into main table, this can be done easier by doing a subrequest inside the PHP loop when building the output of each line.
    
* Use $db->ifsql for SQL IF
 
* Use $db->ifsql for SQL IF
Line 328: Line 330:  
* No DELETE CASCADE and ON UPDATE CASCADE
 
* No DELETE CASCADE and ON UPDATE CASCADE
   −
Such SQL instructions are forbidden because they bypass the business rules of the application bringing a lot of troubles out of control of the developers. For example, if there is a delete cascade between table A and B, when the application will execute the code to remove a record in A, the children into table B will also be removed. If there was a Dolibarr PHP trigger (for example bring by an external module) on the deletion of record of B (for example to validate the deletion or to execute a complementary action), the DELETE CASCADE will be executed without having the Dolibarr PHP trigger executed, missing the validation or actions of the PHP trigger of the module. All business rules must be implemented on the same side (so the server PHP side), this is the reason why business rules implemented on Database side are not allowed (same conclusion than the next point about Database triggers).
+
Such SQL instructions are forbidden because they bypass the business rules of the application bringing a lot of troubles out of control of the developers. For example, if there is a delete cascade between table A and B, when the application will execute the code to remove a record in A, the children into table B will also be removed (this is the goal). But if there was a Dolibarr PHP trigger (for example provided by an external module) on the deletion of record of B (for example to validate the deletion or to execute a complementary action), the DELETE CASCADE will be executed without having the Dolibarr PHP trigger on B deletion executed, missing the validation or actions of the PHP trigger of the module. All business rules must be implemented on the same side (so the server PHP side), this is the reason why business rules implemented on Database side (like with delete cascade) are not allowed (same conclusion than the next point about Database triggers).
Note that external modules can use them for links between Dolibarr tables and its module tables but a better recommanded solution is to use the trigger to implement the deletion of its table when a record of a parent official table is deleted.
+
Note that an external module can use them for links between Dolibarr tables and its module tables but a better recommended solution is to use the trigger to implement the deletion of its tables when a record of a parent official table is deleted.
    
==Using Database triggers==
 
==Using Database triggers==
 
Using Database triggers is not allowed into the code of Dolibarr, so you should have no troubles with Database triggers.  
 
Using Database triggers is not allowed into the code of Dolibarr, so you should have no troubles with Database triggers.  
Database triggers are not portable. Compatibility may be broken when upgrading your version of your database, database triggers are often not included into backup tools, database triggers need permissions that you may not have (and should not have) on a common secured database, database triggers means also that you include some "business rules" of your application into the database where most other rules are managed by the code itself (this can create conflict or code that can't be debugged with a step by step debugger), database triggers execute code using the timezone of the database instead of the reference timezone of application that may be different (generating offset into database) ...
+
* Database triggers are not portable. Compatibility may be broken when upgrading your version of your database
There is tons of reason why we do not recommend to use database triggers in your own development.  
+
* Database triggers are often forgotten into backup tools
Using Database triggers can save you time when you make development but is a very bad practice, so is forbidden as it is not compatible with the high level of quality of code expected by Dolibarr team. External modules that uses Database triggers may also be refused on the market place since it won't work for more than 50% of users.
+
* Database triggers need special permissions that you may not have (and should not have) on a common secured database
 +
* Database triggers means also that you include some "business rules" of your application into the database where most other rules are managed by the code itself (this can create conflict or code that can't be debugged with a step by step debugger)
 +
* Database triggers execute code using the timezone, the default language of the database instead of the reference timezone of the application that may be different (generating offset into database) and the default language setup in application ...
 +
There is tons of reasons why we do not recommend to use database triggers in your own development.
 +
 
 +
Using Database triggers can save you time when you make development but is a very bad practice when quality, portability, security and sustainability are priority, so it is forbidden as it is not compatible with the high level of quality of code expected by Dolibarr team. External modules that uses Database triggers may also be refused on the market place since it won't work for more than 50% of users.
    
==MySQL-MariaDB specificity==
 
==MySQL-MariaDB specificity==
Line 350: Line 357:  
==PostgreSQL specificities==
 
==PostgreSQL specificities==
 
Only MySQL files must be maintained.
 
Only MySQL files must be maintained.
Those files are converted "on the fly" by the database Dolibarr driver.
+
Those files are converted "on the fly" by the database Dolibarr driver into the targeted database system.
   −
There is an exception for the SQL "UPDATE FROM":  
+
There is an exception for the SQL "UPDATE FROM" of Postgres:  
    
MySQL Syntax:
 
MySQL Syntax:
Line 366: Line 373:  
</syntaxhighlight>
 
</syntaxhighlight>
   −
There is no native SQL requests "UPDATE FROM" in all Dolibarr core. But if you use one in your own code of your module, you should do :
+
There is no native SQL requests "UPDATE FROM" in all Dolibarr core (only simple "UPDATE") so this difference of syntax is not a problem. But if you need to use one in your own code of your module, you should do :
 
<syntaxhighlight lang="php">
 
<syntaxhighlight lang="php">
 
if ($this->db->type=='pgsql') {
 
if ($this->db->type=='pgsql') {
Line 406: Line 413:     
==External template framework ?==
 
==External template framework ?==
There is ton of frameworks to provide a template language of an HTML page (smarty, twig, ...). The best and faster on we know is just called "PHP", and because Dolibarr already depends on PHP, there is no need to introduce a dependency on a third language to make templates.
+
There is ton of frameworks to provide a template language of an HTML page (smarty, twig, ...). The best and faster one we know is just called "PHP", and because Dolibarr already depends on PHP, using another framework may introduce a dependency on a third language to make templates.
   −
All template frameworks are just pre-processor, BEFORE PHP. It can't be faster than PHP alone. When we say "speed is increased because template framework use a cache", you must read in fact "the overtime spent by the framework is reduced by cache, not the speed of processing PHP file". We should say "any template framework has an overload over PHP, the cache of the template framework just reduces the slowing effect of using this framework", but not "the speed is increased, it is always decreased compared to pure PHP".
+
We must remind that template frameworks are just pre-processor, BEFORE PHP. They can't be faster than PHP alone. When we say "speed is increased because template framework use a cache", you must read in fact "the overtime spent by the framework is reduced by cache, not the speed of processing a PHP template file". We should say "any template framework has an overload over PHP, the cache of the template framework just reduces the slowing effect of using this framework", but not "the speed is increased, it is always decreased compared to pure PHP".
    
Above all, having a template system is completely possible by doing a "'''.tpl.php'''" file that dos not contains any logic code, but only HTML and print of variables. We get same result (but faster and easier to develop because it does not need to do all the setXXX before calling each template). All variables (known by code that include the template) are automatically known into a PHP template page. No risk to forget a set, and a lot of line of codes reduced, a lot of time and development errors are also saved.
 
Above all, having a template system is completely possible by doing a "'''.tpl.php'''" file that dos not contains any logic code, but only HTML and print of variables. We get same result (but faster and easier to develop because it does not need to do all the setXXX before calling each template). All variables (known by code that include the template) are automatically known into a PHP template page. No risk to forget a set, and a lot of line of codes reduced, a lot of time and development errors are also saved.
   −
Also, keeping a guarantee of 100% of isolation between code and HTML output is interesting in only 1 situation: When teams building design is completely different than team building logic code, AND if you build not too sophisticated pages, AND with no need of too many Ajax features (this need to know how code works).
+
But an external template system can keep a guarantee of 100% of isolation between code and HTML output. Yes, but this is interesting in only 1 situation: When teams building design is completely different than team building logic code, AND if you build not too sophisticated pages, AND with no need of too many Ajax features (this need to know how code works).
And this situation is surely not the Dolibarr future (team will often be same, Ajax will be more and more present, event if I hope not too much, and screens are more and more dependent of dynamic or contextual events, difficult to have this with one simple template without transforming the template into a page with high level of code). Also design if more an more managed now in CSS side instead of PHP side.
+
And this situation is surely not the Dolibarr future (team are often be same, Ajax will be more and more present, even if we hope not "too much", and screens are more and more dependent of dynamic or contextual events, difficult to have this with one simple template without transforming the template into a page with high level of code). Also design is more and more managed now in CSS side instead of PHP side.
 +
 
 +
In the past, Dolibarr has experimented a template system like Smarty. If on the paper the idea was good, we quickly realized that finding a bug become a headache, coding become a treasure hunt, maintenance and development were done so slower (compared to previous situation where output templates are into the "View" section of each PHP file) that we forgot this idea. Pragmatism won.
 +
 
 +
There is a ton of other reasons to not use an external template system and all arguments to use them are also the best argument to use HTML/PHP as our template system. We just ask to keep separation between '''Controllers''' (the first section of PHP pages juste after the "/* Action" line), and the '''Views''', the second section after the "/* View" comment that is the presentation section build with PHP).
 +
 
 +
=CSS norms=
 +
 
 +
==Syntax rules==
   −
In the past, Dolibarr has experimented a template system like smarty. If on the paper the idea was good, we quickly realized that finding a bug become a headache, coding become a treasure hunt, maintenance and development were done so slower (compared to previous situation where output templates are into the "View" section of each PHP file) that we forgot this idea. Pragmatism has made the rule.  
+
There is NO syntax rules or norms for CSS. During Dolibarr Devcamp 2024/06 (Montpellier) a collective proposition was made to respect classes name from tailwindcss.
   −
There is a ton of other reasons to not use an external template system and all arguments to use them are also the best argument to use HTML/PHP as our template system. We just ask to keep separation between '''Controllers''' (the first section of PHP pages juste after the /* Action */ line), and the '''Views''', the second section after the /* View */ comment).
+
The objective is not to include tailwindcss into Dolibarr but to use syntax and classes norms issued from tailwindcss.
 +
 
 +
See [[migrating to tailwindcss css norms]]
 +
 
 +
PR: (link to PR to become)
    
=Dolibarr norms and code skeleton=
 
=Dolibarr norms and code skeleton=
Line 445: Line 464:  
* $mysoc is the object with all information about the current company
 
* $mysoc is the object with all information about the current company
 
* $langs is the object with the current language
 
* $langs is the object with the current language
* $db is the database handler of the current database connexion
+
* $db is the database handler of the current database connexion (inside classes, we should pass it in the constructor and we should get it with $this->db)
 
* $hookmanager is a factory class to manage hooks
 
* $hookmanager is a factory class to manage hooks
 
* $extrafields is a factory class to manage extrafields
 
* $extrafields is a factory class to manage extrafields
Line 506: Line 525:     
==Working directory==
 
==Working directory==
If you need to create a working directory, into your code, refer to it with  
+
If you need to create a working directory for persistent data, into your code, refer to it with  
 
'''DOL_DATA_ROOT.'/mymodule''''
 
'''DOL_DATA_ROOT.'/mymodule''''
   Line 558: Line 577:  
*The '''Table And Row Data Gateway'''
 
*The '''Table And Row Data Gateway'''
   −
This is the most simple. You have one class per table and each class is a link to the table with CRUD methods (Ceate, Read, Update, Delete). A class instance is a record in the table. The class contains only code to reach lines and fields of table.
+
This is the most simple. You have one class per table and each class is a link to the table with CRUD methods (Create, Read, Update, Delete). A class instance is a record in the table. The class contains only code to reach lines and fields of table.
    
Example: This mode is used by some ORM Frameworks, like '''iBatis''' (http://ibatis.apache.org/).
 
Example: This mode is used by some ORM Frameworks, like '''iBatis''' (http://ibatis.apache.org/).
Line 564: Line 583:  
*The '''Active Record'''
 
*The '''Active Record'''
   −
Same as previous, but we are allowed to add some business functions into the class, if such functions are dedicated to the table or recording into this table.
+
Same as previous, but we are allowed to add some business functions into the CRUD class, if such functions are dedicated to manipulate data into this table.
 +
This pattern is known to be the most productive of the 3, as it is a very good compromise between the '''Table And Row Data Gateway''' and the '''Data Mapper'''.
    
Example: This mode is used for Dolibarr development and most PHP software that includes their own framework and best practices.
 
Example: This mode is used for Dolibarr development and most PHP software that includes their own framework and best practices.
Line 573: Line 593:  
More "purist" on paper (closer of business), this method also has the disadvantage of being more complex in practice.
 
More "purist" on paper (closer of business), this method also has the disadvantage of being more complex in practice.
   −
Example: This is the choice if you use the ORM Framework '''Propel''' (http://propel.phpdb.org/trac/). We find this model in heavier applications, based on this ORM among others.
+
Example: This is the choice if you use the ORM Framework '''Propel''' (https://propelorm.org/). We find this model in heavier applications, based on this ORM among others.
   −
-> For Dolibarr development, it is recommended to use the connection mode '''Active Record''', which offers the advantages of a model close to the business without having the complexity, without obfuscating technical architecture. It is by this way that the development, understanding of code and technical maintenance and / or business behaviour seems the more productive (this is however an ongoing debate between the purists and the pragmatists, debate in which nobody can really be right, because it depends on the objectives).
+
-> For Dolibarr development, the pattern used is the connection mode '''Active Record''', which offers the advantages of a model close to the business without having the complexity, without obfuscating technical architecture. It is by this way that the development, understanding of code and technical maintenance and / or business behavior seems the more productive (this is however an ongoing debate between the purists and the pragmatists, debate in which nobody can really be right, because it depends on the objectives).
 
[[Category:Development]]
 
[[Category:Development]]
   Line 582: Line 602:  
Many confuse this design pattern with that of using a template framework. It's unrelated. A template framework (see previous point) is only linked to the "V" part of these models.
 
Many confuse this design pattern with that of using a template framework. It's unrelated. A template framework (see previous point) is only linked to the "V" part of these models.
   −
-> Dolibarr uses the '''MVC''' Design Pattern. Part M is materialized by a DAO class containing the CRUD (Create-Read-Update-Delete) methods for accessing the table.
+
-> Dolibarr uses the '''MVC''' Design Pattern (Model - View - Controller). Part M (Model) is materialized by a DAO class containing the CRUD (Create-Read-Update-Delete) methods for accessing the table.
 
Many frameworks have chosen to put the C code part (Controller) and the V code part (View) in different files, or even separate directories. The maintenance seems easier on paper, in practice, you have to juggle constantly between a ton of files when your project become larger. In Dolibarr, the separation is made by a simple comment section. The part of code C (Controller) is therefore the code that follow the tag
 
Many frameworks have chosen to put the C code part (Controller) and the V code part (View) in different files, or even separate directories. The maintenance seems easier on paper, in practice, you have to juggle constantly between a ton of files when your project become larger. In Dolibarr, the separation is made by a simple comment section. The part of code C (Controller) is therefore the code that follow the tag
 
<pre>
 
<pre>
Line 600: Line 620:  
==Design pattern for Views - Presentation==
 
==Design pattern for Views - Presentation==
 
There are frameworks that specialize in Vue Design Pattern, the part of formatting the screen seen by the user.
 
There are frameworks that specialize in Vue Design Pattern, the part of formatting the screen seen by the user.
Old versions of Dolibarr used Smarty. This framework is an overlay to an already very powerful screen formatting framework called ... PHP. The benefits being much lower than the disadvantages, it has been abandoned in favor of PHP templates (.tpl.php file) which remain the simplest, the most universal, the most scalable and the most efficient, of the presentation frameworks.  
+
Old versions of Dolibarr used Smarty. This framework is an overlay to an already very powerful screen formatting framework called ... PHP. The benefits being much lower than the disadvantages, it has been abandoned in favor of PHP templates (.php files or .tpl.php files) which remain the simplest, the most universal, the most scalable and the most efficient, of the presentation frameworks we tried to use.  
    
Its only flaw is that it cannot guarantee 100% the deviations of a developer who would integrate into the View, a logic unrelated to the presentation (therefore other than code intended for generation, formatting, HTML output , test or loop logic). This point is however controlled by the validation mechanism of the project managers' code.
 
Its only flaw is that it cannot guarantee 100% the deviations of a developer who would integrate into the View, a logic unrelated to the presentation (therefore other than code intended for generation, formatting, HTML output , test or loop logic). This point is however controlled by the validation mechanism of the project managers' code.
    
Here again, it is the experience and the observation of a better productivity performance that has motivated the abandonment of the external Presentation frameworks in favor of the PHP framework.
 
Here again, it is the experience and the observation of a better productivity performance that has motivated the abandonment of the external Presentation frameworks in favor of the PHP framework.
 +
 +
=Rules to define branch target of a contribution=
 +
The rules to decide if a contribution (Pull Request) must be pushed into an old maintenance branch or into development are not strict and are often defined by the good sense (pragmastism first). We can how
 +
be help by this [[Decision algorithm for branch choice of a PR]].