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 51: Line 51:  
$var2 = 1;
 
$var2 = 1;
 
$var3 = 1;
 
$var3 = 1;
</sousyntaxhighlightrce>
+
</syntaxhighlight>
 
instead of
 
instead of
 
<syntaxhighlight lang="php">
 
<syntaxhighlight lang="php">
Line 119: Line 119:  
{{TemplatePHPFields}}
 
{{TemplatePHPFields}}
   −
=SQL and database rules=
+
=SQL and Database rules=
    
==DDL file format==
 
==DDL file format==
Line 207: Line 207:  
  - import_key      varchar(32)                that will contain the import code YYYYMMDDHHMMSS if you make mass import
 
  - import_key      varchar(32)                that will contain the import code YYYYMMDDHHMMSS if you make mass import
 
  - status          smallint                    to store a status
 
  - status          smallint                    to store a status
Eventually
+
Optional
 
  - fk_user_creat or fk_user_author integer that is the id of user making creation
 
  - fk_user_creat or fk_user_author integer that is the id of user making creation
 
  - fk_user_modif integer that is the id of user making change
 
  - fk_user_modif integer that is the id of user making change
Line 215: Line 215:  
Note field:
 
Note field:
 
  - note_private text for private comment of the object
 
  - note_private text for private comment of the object
  - note_pubic text for public comment of the object
+
  - note_public text for public comment of the object
 
or  
 
or  
 
  - note text if there is no need to have private and public
 
  - note text if there is no need to have private and public
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==
Sometimes, we need another unique keys than primary key. We can add in this case an alternate unique key. When we need this, we can create an alternate unique key. Such an index is called by a name that start by prefix <tt>uk_</tt> followed by an underscore, then the the table name (this is required to avoid duplicate names of unique keys that may create problems for some DBMS like Postgresql) and then another string to define the key (this is to allow to have several unique keys on same table).
+
Sometimes, we need other unique keys than primary key. When we need this, we can create an alternate unique key. Such a key should have a name that starts with <tt>uk_</tt>, then the table name (this is required to avoid duplicate names of unique keys that may create problems for some DBMS like Postgresql) and then another string to define the key (this is to allow having several unique keys on the same table).
    
Example:
 
Example:
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)
   −
*Functions NOW, SYSDATE or DATEDIFF are forbidden inside SQL requests. 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 better portability of code and correct management of TimeZone.
+
* 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 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 performance (see example and final comment)
    
For example, don't do:
 
For example, don't do:
Line 314: Line 317:  
An other advantage of this rule, is that request benefits of index because we are making a compare of a field with a fixed value. When using datediff, you make an operation on field before comparison, this means database can't use the index on field, resulting on very bad performance compared to solution without the datediff.
 
An other advantage of this rule, is that request benefits of index because we are making a compare of a field with a fixed value. When using datediff, you make an operation on field before comparison, this means database can't use the index on field, resulting on very bad performance compared to solution without the datediff.
   −
*Use $db->ifsql for SQL IF
+
* The statement WITH ROLLUP is prohibited:
 +
 
 +
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).
 +
 
 +
* 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
    
Do not include the IF into your forged SQL request. But use instead $db->ifsql() method to you will make a SQL IF that is compatible with all SQL databases.
 
Do not include the IF into your forged SQL request. But use instead $db->ifsql() method to you will make a SQL IF that is compatible with all SQL databases.
    +
* 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 (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 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 creating conflict or code that can't be debugged with a step by step debugger, ...
+
* 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 recommand 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 338: 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:
 
<syntaxhighlight lang="sql">
 
<syntaxhighlight lang="sql">
UPDATE table_taget as target, table_source as source SET fieldtarget=source.fieldsource
+
UPDATE table_target as target, table_source as source SET fieldtarget=source.fieldsource
 
WHERE source.rowid=target.rowid;
 
WHERE source.rowid=target.rowid;
 
</syntaxhighlight>
 
</syntaxhighlight>
Line 350: Line 369:  
PgSQL Syntax:
 
PgSQL Syntax:
 
<syntaxhighlight lang="sql">
 
<syntaxhighlight lang="sql">
UPDATE table_taget as target SET fieldtarget=source.fieldsource
+
UPDATE table_target as target SET fieldtarget=source.fieldsource
 
FROM table_source as source WHERE source.rowid=target.rowid;
 
FROM table_source as source WHERE source.rowid=target.rowid;
 
</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') {
$sql="UPDATE table_taget as target SET fieldtarget=source.fieldsource
+
$sql="UPDATE table_target as target SET fieldtarget=source.fieldsource
 
FROM table_source as source WHERE source.rowid=target.rowid";
 
FROM table_source as source WHERE source.rowid=target.rowid";
 
} else {
 
} else {
$sql= "UPDATE table_taget as target, table_source as source SET fieldtarget=source.fieldsource
+
$sql= "UPDATE table_target as target, table_source as source SET fieldtarget=source.fieldsource
 
WHERE source.rowid=target.rowid";
 
WHERE source.rowid=target.rowid";
 
}
 
}
Line 393: Line 412:  
*External scripts must be written in Perl if they can't be written in PHP. Usage of another language is not forbidden but must be argued before in the development mailing-list.
 
*External scripts must be written in Perl if they can't be written in PHP. Usage of another language is not forbidden but must be argued before in the development mailing-list.
   −
==External templating framework ?==
+
==External template framework ?==
There is ton of frameworks to provide a templating language of an HTML page. The best and faster is just called "PHP", and because Dolibarr already depends on PHP, there is no need to introduce a dependency on a third language.
+
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.
 +
 
 +
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.
   −
All templating frameworks are just preprocessor, BEFORE PHP. It can't be faster than PHP alone. When we say "speed is increased because templating 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 templating framework has an overload over PHP, the cache of the templating framework just reduces the slowing effect of using this framework", but not "the speed is increased, it is always decreased compared to pure PHP".
+
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 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.
   −
Above all, having a templating system is completely possible by doing a "'''.tpl.php'''" file that dos not contains any logic code, but only HTML and "echo". 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 automaticaly 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.
+
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.
   −
Also, keeping a 100% isolation between code and HTML output is interesting in only 1 situation: When teams building design is complety 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).
+
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).
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).
     −
There is a ton of other reasons to not use an external templating system and all arguments to use them are also the best argument to use PHP as our templating system.
+
=CSS norms=
 +
 
 +
==Syntax rules==
 +
 
 +
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.
 +
 
 +
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 421: Line 454:  
Use it as an example.
 
Use it as an example.
 
Note that the skeletons are also used by the PHP Code generator ([[Module ModuleBuilder]]), which is described in the development chapter of Dolibarr modules, to speed up your development.
 
Note that the skeletons are also used by the PHP Code generator ([[Module ModuleBuilder]]), which is described in the development chapter of Dolibarr modules, to speed up your development.
 +
 +
== Global variables==
 +
There is some information or objects that is common and fixed for all the execution of a PHP page and need to be used nearly everywhere in the code. To avoid to propagate everywhere this
 +
information or objects, they are stored into global variables that you can access everywhere. This global variables are initialized at the begin of each PHP call (into the master.inc.php or master.inc.php or in top of the page). These objects are instantiated only once. The list of available global variables is defined here:
 +
{{Template:TemplateGlobalVariables}}
 +
 +
* $conf is the object that contains the configuration (saved into database)
 +
* $user is the object of the current user
 +
* $mysoc is the object with all information about the current company
 +
* $langs is the object with the current language
 +
* $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
 +
* $extrafields is a factory class to manage extrafields
    
==Dates and Timezones==
 
==Dates and Timezones==
Line 479: 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 531: 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 537: 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 546: 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 555: 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 573: 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]].