Line 11:
Line 11:
This is some rules on language, syntax and norm we use into Dolibarr project:
This is some rules on language, syntax and norm we use into Dolibarr project:
−
= Versions =
+
=Versions=
−
* Dolibarr must work on:
+
−
# All OS (Windows, Linux, MACOS...)
+
*Dolibarr must work on:
−
# PHP {{PHPMinVersion}} (Must work with no need of complementary PHP module, except module to PHP module to access database).
+
−
# Mysql {{MySqlMinVersion}}
+
#All OS (Windows, Linux, MACOS...)
+
#PHP {{PHPMinVersion}} (Must work with no need of complementary PHP module, except module to PHP module to access database).
+
#Mysql {{MySqlMinVersion}}
+
+
=Copyright Norms=
+
+
*All PHP files must start with a header that looks like
−
= Copyright Norms =
−
* All PHP files must start with a header that looks like
<source lang="php">
<source lang="php">
<?php
<?php
Line 29:
Line 33:
When you edit an existing file of project, you must add a Copyright line under others.
When you edit an existing file of project, you must add a Copyright line under others.
−
= PHP Norms =
+
=PHP Norms=
−
== PHP ==
+
==PHP==
−
* 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 $_COOKIES, $_SERVER, $_ENV but use the Dolibarr function 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.
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 the if the option '''register_globals''' is on (by default on a lot of installations).
Moreover, the code must work when PHP option '''register_globals''' is off (recommended by PHP). It must also work the if the option '''register_globals''' is on (by default on a lot of installations).
−
* Do not use '''PHP_SELF'''. Use instead $_SERVER["PHP_SELF"]. Also, Dolibarr framework sanitizes content of $_SERVER["PHP_SELF"] variable (into main.inc.php file, before any business code).
+
*Do not use '''PHP_SELF'''. Use instead $_SERVER["PHP_SELF"]. Also, Dolibarr framework sanitizes content of $_SERVER["PHP_SELF"] variable (into main.inc.php file, before any business code).
+
+
*When several variables must be initialized with the same value, you must use individual declarations (separated by ;)
−
* When several variables must be initialized with the same value, you must use individual declarations (separated by ;)
<source lang="php">
<source lang="php">
$var1=1;
$var1=1;
Line 51:
Line 58:
which is slower.
which is slower.
−
* Strings must be delimited by a single or double quote and a variable within the string must be outside of the quote.
+
*Strings must be delimited by a single or double quote and a variable within the string must be outside of the quote.
+
<source lang="php">
<source lang="php">
print 'My text show my '.$variable.' !';
print 'My text show my '.$variable.' !';
</source>
</source>
−
* Comments must use the C syntax, ie a double slash for a comment on one line and a slash-star to open a bloc for several lines
+
*Comments must use the C syntax, ie a double slash for a comment on one line and a slash-star to open a bloc for several lines
+
<source lang="php">
<source lang="php">
/* Bloc of comment
/* Bloc of comment
Line 77:
Line 86:
</source>
</source>
−
* Functions must return a value equal or higher than 0 if successful and strictly lower than 0 if error.
+
*Functions must return a value equal or higher than 0 if successful and strictly lower than 0 if error.
−
* No dead code (code never used) into Dolibarr core code (code used by external modules only must be included within the external modules).
+
*No dead code (code never used) into Dolibarr core code (code used by external modules only must be included within the external modules).
−
* Use "include_once" for anything with functions or class definitions in it (like *.class.php and *.lib.php files), use "include" for template-style php with files containing common part of HTML and PHP code (like *.inc.php and *.tpl.php files).
+
*Use "include_once" for anything with functions or class definitions in it (like *.class.php and *.lib.php files), use "include" for template-style php with files containing common part of HTML and PHP code (like *.inc.php and *.tpl.php files).
−
* Coding style to use is the '''PSR-12''' (https://www.php-fig.org/psr/psr-12/). Only rules tagged "MUST" are currently required. So note however the exceptions:
+
*Coding style to use is the '''PSR-12''' (https://www.php-fig.org/psr/psr-12/). Only rules tagged "MUST" are currently required. So note however the exceptions:
−
** Length of line: PSR-12 mention we can't go up to 120 characters on same line, this is a soft limit. It is better to have long lines instead of long page with code content that is just data declaration and does not contain any logic. However, we introduced a hard limit of '''1000''' characters (having line larger than this may return errors on Continuous Integration tests).
+
**Length of line: PSR-12 mention we can't go up to 120 characters on same line, this is a soft limit. It is better to have long lines instead of long page with code content that is just data declaration and does not contain any logic. However, we introduced a hard limit of '''1000''' characters (having line larger than this may return errors on Continuous Integration tests).
−
** Tabs are allowed: The other exception is that we don't replace systematically the tabs with spaces. Using tabs is more convenient for most editors/developers. Also using spaces breaks some auto-format features (like Eclipse autoformat feature on some Eclipse version). For the moment, the best setup is "Keep spaces/tabs as it is", however, you can activate the option "Remove spaces at end of lines".
+
**Tabs are allowed: The other exception is that we don't replace systematically the tabs with spaces. Using tabs is more convenient for most editors/developers. Also using spaces breaks some auto-format features (like Eclipse autoformat feature on some Eclipse version). For the moment, the best setup is "Keep spaces/tabs as it is", however, you can activate the option "Remove spaces at end of lines".
−
** We allow elements of an array on same line and we do not always add a new line at end of each element.
+
**We allow elements of an array on same line and we do not always add a new line at end of each element.
−
** Note 1: The following rule are very important to follow:
+
**Note 1: The following rule are very important to follow:
−
*** Files must be saved with Unix format (LF) and not Windows (CR/LF). Unix format is compatible on all OS such as Unix like, Windows, Mac, but the Windows text file format may not work on some PHP under Unix.
+
***Files must be saved with Unix format (LF) and not Windows (CR/LF). Unix format is compatible on all OS such as Unix like, Windows, Mac, but the Windows text file format may not work on some PHP under Unix.
−
*** Smart tags PHP are not used. PHP code section must start with '''<?php'''
+
***Smart tags PHP are not used. PHP code section must start with '''<?php'''
−
** Note 2: You can use the file '''dev/setup/codesniffer/ruleset.xml''' as rule file to control coding style with PHPCodeSniffer.
+
**Note 2: You can use the file '''dev/setup/codesniffer/ruleset.xml''' as rule file to control coding style with PHPCodeSniffer.
−
** Note 3: You can use the file '''dev/setup/eclipse/PSR-12 [built-in].xml''' as rule file to setup Eclipse syntax formater.
+
**Note 3: You can use the file '''dev/setup/eclipse/PSR-12 [built-in].xml''' as rule file to setup Eclipse syntax formater.
−
** Note 4: You may note that current code is not yet compliant with the PSR-12. The reason is that we must "now" follow the "MUST" rules of PSR-12, but it wasn't in the past. So feel free to change coding style to match new rules (keep in mind the 2 exceptions) if you find such cases.
+
**Note 4: You may note that current code is not yet compliant with the PSR-12. The reason is that we must "now" follow the "MUST" rules of PSR-12, but it wasn't in the past. So feel free to change coding style to match new rules (keep in mind the 2 exceptions) if you find such cases.
−
== Classes and properties structures ==
+
==Classes and properties structures==
Some properties of classes are found in different classes. To avoid having different names, we will use the following PHP properties names:
Some properties of classes are found in different classes. To avoid having different names, we will use the following PHP properties names:
Line 100:
Line 109:
{{TemplatePHPFields}}
{{TemplatePHPFields}}
−
= SQL rules =
+
=SQL rules=
−
== DDL file format ==
+
==DDL file format==
Files containing definition of the database structure (DDL files) must be '''2 per table''':
Files containing definition of the database structure (DDL files) must be '''2 per table''':
−
* The first file defines the table and its fields. The file name contains the table name, e.g. like this: <tt>llx_''mytable''.sql</tt>
+
+
*The first file defines the table and its fields. The file name contains the table name, e.g. like this: <tt>llx_''mytable''.sql</tt>
+
A comment will be added for each field to explain its usage.
A comment will be added for each field to explain its usage.
−
* The second file defines all foreign keys, performance indexes or other constraints and the file name will be like: <tt>llx_''mytable''.key.sql</tt>
+
+
*The second file defines all foreign keys, performance indexes or other constraints and the file name will be like: <tt>llx_''mytable''.key.sql</tt>
These files must be stored in the directory '''install/mysql/tables''' for all standard files or '''mymodule/tables''' for tables provided by an external module.
These files must be stored in the directory '''install/mysql/tables''' for all standard files or '''mymodule/tables''' for tables provided by an external module.
Line 173:
Line 185:
</source>
</source>
−
== Table and fields structures ==
+
==Table and fields structures==
+
+
*Structure of tables.
−
* Structure of tables.
When you create a new table, it is recommended to use the same conventions as other Dolibarr tables. This means the following fields:
When you create a new table, it is recommended to use the same conventions as other Dolibarr tables. This means the following fields:
- rowid INTEGER AUTO_INCREMENT PRIMARY KEY that is technical id of record
- rowid INTEGER AUTO_INCREMENT PRIMARY KEY that is technical id of record
Line 197:
Line 210:
−
* Type of fields:
+
*Type of fields:
+
Well, to be compatible with any accuracy required by any country on amounts, to be compatible with any database syntax and with the Dolibarr upgrade framework, we will use the following types for database fields:
Well, to be compatible with any accuracy required by any country on amounts, to be compatible with any database syntax and with the Dolibarr upgrade framework, we will use the following types for database fields:
Line 214:
Line 228:
Other type are not allowed for compatibility reasons.
Other type are not allowed for compatibility reasons.
−
* All tables has a prefix to avoid name conflicts with other projects. In current version this prefix is fixed ans can't be modified. Its value is <tt>llx_</tt>. In a future version this value should be modified during installation process.
+
*All tables has a prefix to avoid name conflicts with other projects. In current version this prefix is fixed ans can't be modified. Its value is <tt>llx_</tt>. In a future version this value should be modified during installation process.
−
== Primary keys ==
+
==Primary keys==
The primary key of a table must be called <tt>rowid</tt>.
The primary key of a table must be called <tt>rowid</tt>.
Some old tables does not use this rule and use a primary key called <tt>id</tt> (ie [[Table llx_c_actioncomm]]), but the reason is history and this should not happens anymore.
Some old tables does not use this rule and use a primary key called <tt>id</tt> (ie [[Table llx_c_actioncomm]]), but the reason is history and this should not happens anymore.
−
== Foreign keys ==
+
==Foreign keys==
Name of a foreign key must start with the prefix <tt>fk_</tt> followed by the table name (i.e. name of the referencing table) (this is required to avoid duplicate names in project that are not allowed even if in different tables by some DBMS like Postgresql) then the field name (i.e. name of the referencing field) (this is to allow to have several foreign keys in same table).
Name of a foreign key must start with the prefix <tt>fk_</tt> followed by the table name (i.e. name of the referencing table) (this is required to avoid duplicate names in project that are not allowed even if in different tables by some DBMS like Postgresql) then the field name (i.e. name of the referencing field) (this is to allow to have several foreign keys in same table).
Line 229:
Line 243:
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 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.
−
== 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 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).
Line 235:
Line 249:
''uk_societe_code_client'' is a unique key on table llx_societe on field code_client.
''uk_societe_code_client'' is a unique key on table llx_societe on field code_client.
−
== Index performance ==
+
==Index performance==
Some fields are often used as search or order criteria, or for joins. In such case, we need to set a performance index on field to increase performances. Such indexes are named with a prefix <tt>idx_</tt> then the table name and then the field name.
Some fields are often used as search or order criteria, or for joins. In such case, we need to set a performance index on field to increase performances. Such indexes are named with a prefix <tt>idx_</tt> then the table name and then the field name.
Line 241:
Line 255:
''idx_societe_user_creat'' is a performance index on table llx_societe for field user_creat
''idx_societe_user_creat'' is a performance index on table llx_societe for field user_creat
−
== SQL Coding rules ==
+
==SQL Coding rules==
−
* Alias usage/Fields naming
+
+
*Alias usage/Fields naming
+
When doing select, we can use alias to simplify writing/reading of requests:
When doing select, we can use alias to simplify writing/reading of requests:
<source lang="sql">
<source lang="sql">
Line 249:
Line 265:
However, we must not used alias for update request as they are not compatible with Mysql 3.1.
However, we must not used alias for update request as they are not compatible with Mysql 3.1.
−
* Using SELECT * is forbidden ! When using SELECT you must define complete list of fields to get. This avoids confusion. And above all, this make reengeering of code easier and make impact analysis of change on a field possible. Example:
+
*Using SELECT * is forbidden ! When using SELECT you must define complete list of fields to get. This avoids confusion. And above all, this make reengeering of code easier and make impact analysis of change on a field possible. Example:
+
<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>
−
* 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 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.
Example:
Example:
Line 265:
Line 282:
'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.
+
*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.
For example, don't do:
For example, don't do:
Line 287:
Line 304:
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
+
*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.
−
== Mysql specificities ==
+
==Mysql specificities==
−
* Tables must be declared with format InnoDB.
+
+
*Tables must be declared with format InnoDB.
+
This format supports foreign keys and their restrictions, and transactions integrity is also supported. This guarantees that Dolibarr events keep all data with correct values between tables even when transaction modify different tables.
This format supports foreign keys and their restrictions, and transactions integrity is also supported. This guarantees that Dolibarr events keep all data with correct values between tables even when transaction modify different tables.
−
* Dolibarr MUST work even if Mysql option '''strict''' is active.
+
*Dolibarr MUST work even if Mysql option '''strict''' is active.
+
To activate it (required when developing on Dolibarr), add the following line into the config file of your Mysql server (my.cnf or my.ini)
To activate it (required when developing on Dolibarr), add the following line into the config file of your Mysql server (my.cnf or my.ini)
<source lang="ini">
<source lang="ini">
Line 300:
Line 321:
</source>
</source>
−
== PostgreSQL specificities ==
+
==PostgreSQL specificities==
Only Mysql SQL files must be maintained.
Only Mysql SQL 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.
Line 330:
Line 351:
</source>
</source>
−
= HTML norms =
+
=HTML norms=
−
== Syntax rules ==
+
==Syntax rules==
−
* HTML used must be HTML compliant and not XHTML. All attributes of HTML tags must be in lower case and quoted with ".
+
+
*HTML used must be HTML compliant and not XHTML. All attributes of HTML tags must be in lower case and quoted with ".
+
+
*Links href must be absolute and use the function dol_buildpath() to get absolute path from a relative path and img tag must be build using function img_picto().
−
* Links href must be absolute and use the function dol_buildpath() to get absolute path from a relative path and img tag must be build using function img_picto().
For example:
For example:
<source lang="php">
<source lang="php">
Line 340:
Line 363:
</source>
</source>
−
* HTML tables must have columns with no forced width, except for columns that contains data we know the length. For example, a column with a picto only can be forced to with="20px".
+
*HTML tables must have columns with no forced width, except for columns that contains data we know the length. For example, a column with a picto only can be forced to with="20px".
+
Otherwise, we must avoid forcing the column width. Reason is that, in most cases, the browser make a better works to define column width automatically than forced values, and it works whatever is the resolution.
Otherwise, we must avoid forcing the column width. Reason is that, in most cases, the browser make a better works to define column width automatically than forced values, and it works whatever is the resolution.
−
* Javascript/ajax code and call to javascript files into php pages must be avoided. However, if you need to include javascript code, you must add a condition on "$conf->use_javascript_ajax"
+
*Javascript/ajax code and call to javascript files into php pages must be avoided. However, if you need to include javascript code, you must add a condition on "$conf->use_javascript_ajax"
+
<source lang="php">
<source lang="php">
if ($conf->use_javascript_ajax) {
if ($conf->use_javascript_ajax) {
Line 350:
Line 375:
</source>
</source>
−
* Popup windows must not be used, except for tooltips (and must have a condition as explained before).
+
*Popup windows must not be used, except for tooltips (and must have a condition as explained before).
−
* 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 templating 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 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.
Line 366:
Line 391:
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.
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.
−
= Dolibarr norms and code skeleton =
+
=Dolibarr norms and code skeleton=
−
== Skeleton code ==
+
==Skeleton code==
To standardize the code, and to speed up the development of new components in Dolibarr, you'll find skeletons of files fully prepared in the directory '''htdocs/modulebuilder/templates/'''.
To standardize the code, and to speed up the development of new components in Dolibarr, you'll find skeletons of files fully prepared in the directory '''htdocs/modulebuilder/templates/'''.
For example:
For example:
−
* 1 file that serves as an example of the module description: '''myModule.class.php'''
+
−
* 1 file that serves as an example of code for creating a new class: '''skeleton_class.class.php'''
+
*1 file that serves as an example of the module description: '''myModule.class.php'''
−
* 1 file that serves as an example of code for creating a new page: '''skeleton_page.php'''
+
*1 file that serves as an example of code for creating a new class: '''skeleton_class.class.php'''
−
* 1 file that serves as an example of code for creating a script for executing command lines: '''skeleton_script.php'''
+
*1 file that serves as an example of code for creating a new page: '''skeleton_page.php'''
+
*1 file that serves as an example of code for creating a script for executing command lines: '''skeleton_script.php'''
+
...
...
Line 381:
Line 408:
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.
−
== Dates and Timezones ==
+
==Dates and Timezones==
Dolibarr is an application that is multi-user and multi-location. It's therefore necessary to store dates in the right format. To avoid problems with conversions, the following rules should be applied:
Dolibarr is an application that is multi-user and multi-location. It's therefore necessary to store dates in the right format. To avoid problems with conversions, the following rules should be applied:
−
* A date into memory must always be stored with Timestamp GMT format.
+
*A date into memory must always be stored with Timestamp GMT format.
−
* A date stored into database, is the GMT Timestamp of date submitted into the request usng the <b>PHP server</b> timezone. This does not apply to date update automatically by database (fields '''tms''' into database).
+
*A date stored into database, is the GMT Timestamp of date submitted into the request usng the <b>PHP server</b> timezone. This does not apply to date update automatically by database (fields '''tms''' into database).
+
For exemple le 1st january 1970, 3 hour at Paris (TZ=+1) = 2 hour at Greenwitch (TZ=0) will be stored into memory with value 7200 and will be submitted into a SQL request to database with the string '19700101030000' (PHP convert into its TZ hour and database will unconvert it using its timezone too that is same than PHP).
For exemple le 1st january 1970, 3 hour at Paris (TZ=+1) = 2 hour at Greenwitch (TZ=0) will be stored into memory with value 7200 and will be submitted into a SQL request to database with the string '19700101030000' (PHP convert into its TZ hour and database will unconvert it using its timezone too that is same than PHP).
All select methods should translate date fields, that are with format TZ of database ('19700101030000'), into a timestamp field by calling the method db->jdate. This is to store into memory a GTM Timestamp date. All insert methods must convert, during generation of SQL request, the memory date into the string by using db->idate (you may find examples into skeleton).
All select methods should translate date fields, that are with format TZ of database ('19700101030000'), into a timestamp field by calling the method db->jdate. This is to store into memory a GTM Timestamp date. All insert methods must convert, during generation of SQL request, the memory date into the string by using db->idate (you may find examples into skeleton).
−
* Dates that are updated automatically (field '''tms''' into database) contains a GMT Timestamp GMT of date when change is done. The select will also use the db->jdate (that use PHP server TZ) to convert read data into a GMT Timestamp into memory. So if timezone of database differs from timezone of PHP server (one of them is not correctly set), you may experience differences between creation date and update date.
+
*Dates that are updated automatically (field '''tms''' into database) contains a GMT Timestamp GMT of date when change is done. The select will also use the db->jdate (that use PHP server TZ) to convert read data into a GMT Timestamp into memory. So if timezone of database differs from timezone of PHP server (one of them is not correctly set), you may experience differences between creation date and update date.
−
* Manipulation date with PHP must be done using the Dolibarr date functions: '''dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()'''. You may also find other functions available into file '''date.lib.php'''.
+
*Manipulation date with PHP must be done using the Dolibarr date functions: '''dol_now(), dol_mktime(), dol_stringtotime(), dol_getdate(), dol_time_plus_duree()'''. You may also find other functions available into file '''date.lib.php'''.
−
== UTF8/ISO encoding ==
+
==UTF8/ISO encoding==
Dolibarr stores data in the following way:
Dolibarr stores data in the following way:
−
* In database, data is stored in UTF8 or ISO. It depends on the database's pagecode therefore these options are set at creation time. In any case, Dolibarr's database driver (in lib/database) deals with it to convert from/to UTF8 at insertion and readout.
−
* Memory data is stored in UTF8 (PHP object instances).
−
* Web pages are returned and rendered into UTF8
−
== Float numbers, amount and calculation ==
+
*In database, data is stored in UTF8 or ISO. It depends on the database's pagecode therefore these options are set at creation time. In any case, Dolibarr's database driver (in lib/database) deals with it to convert from/to UTF8 at insertion and readout.
+
*Memory data is stored in UTF8 (PHP object instances).
+
*Web pages are returned and rendered into UTF8
+
+
==Float numbers, amount and calculation==
With PHP, like other languages (Java for exemple), non integer data (float, real, double) are not reliable for calculation.
With PHP, like other languages (Java for exemple), non integer data (float, real, double) are not reliable for calculation.
Try to make for example
Try to make for example
Line 413:
Line 442:
If data manipulated is not an amount, then using MU, MT, MS has no sense, and you must use the function '''round()'''.
If data manipulated is not an amount, then using MU, MT, MS has no sense, and you must use the function '''round()'''.
−
== Creation of tables ==
+
==Creation of tables==
Do not create tables, on the fly, during execution by a standard user, we mean, during current usage of software.
Do not create tables, on the fly, during execution by a standard user, we mean, during current usage of software.
If you create a module that uses its own table, not available in the default Dolibarr code, then take a look at tutorial [[Module development]]. It explains how to provide new tables with your module, so that, the tables will be created during module activation and not during module usage.
If you create a module that uses its own table, not available in the default Dolibarr code, then take a look at tutorial [[Module development]]. It explains how to provide new tables with your module, so that, the tables will be created during module activation and not during module usage.
−
== Comparing version ==
+
==Comparing version==
If your code need to make different things depending on Dolibarr version, you can use the following tip to detect and compare versions
If your code need to make different things depending on Dolibarr version, you can use the following tip to detect and compare versions
<source lang="php">
<source lang="php">
Line 429:
Line 458:
</source>
</source>
−
== Logs ==
+
==Logs==
Add logs to your code using function
Add logs to your code using function
<source lang="php">
<source lang="php">
Line 435:
Line 464:
</source>
</source>
−
== 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, into your code, refer to it with
'''DOL_DATA_ROOT.'/mymodule''''
'''DOL_DATA_ROOT.'/mymodule''''
Line 447:
Line 476:
If you need a directory to store temporary data, this directory must be '''DOL_DATA_ROOT.'/mymodule/temp''''
If you need a directory to store temporary data, this directory must be '''DOL_DATA_ROOT.'/mymodule/temp''''
−
= Design patterns and Object programming =
+
=Design patterns and Object programming=
−
== Creation design patterns (GoF) ==
+
==Creation design patterns (GoF)==
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).
No usage of such patterns is required. We found some objects next to Singletons or Factory but not completely compliant with syntax, this is to be compatible with PHP 4 that is not a pure object language.
No usage of such patterns is required. We found some objects next to Singletons or Factory but not completely compliant with syntax, this is to be compatible with PHP 4 that is not a pure object language.
−
== Structure design patterns (GoF) ==
+
==Structure design patterns (GoF)==
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).
No usage of such patterns is required.
No usage of such patterns is required.
−
== Behavior design patterns (GoF) ==
+
==Behavior design patterns (GoF)==
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).
Design patterns defined by the Gang Of Four (see wikipédia on [[w:Design patterns|Design patterns]]).
No usage of such patterns is required.
No usage of such patterns is required.
−
== Design patterns of enterprise (Martin Fowler) ==
+
==Design patterns of enterprise (Martin Fowler)==
−
=== Patterns of code organization ===
+
===Patterns of code organization===
[[w:Martin Fowler|Martin Fowler]] has identified 3 ways to organize code:
[[w:Martin Fowler|Martin Fowler]] has identified 3 ways to organize code:
−
* The '''Transaction Script''' (The source code is linear for each user action).
+
+
*The '''Transaction Script''' (The source code is linear for each user action).
+
This is the old school used by all procedural languages.
This is the old school used by all procedural languages.
Inconvenient: Redundancy of code. Need to know the physical model of data to develop.
Inconvenient: Redundancy of code. Need to know the physical model of data to develop.
−
* The '''Domain Model'''
+
+
*The '''Domain Model'''
+
This notion is available with object languages. It is business process (to identify before) that are used for objects classes.
This notion is available with object languages. It is business process (to identify before) that are used for objects classes.
Inconvenient: Model very complex to maintain.
Inconvenient: Model very complex to maintain.
−
* The '''Table Module'''
+
+
*The '''Table Module'''
+
This is a mix between 2 previous where we have only one unique class for each table of database.
This is a mix between 2 previous where we have only one unique class for each table of database.
-> As shown in code skeletons (see previous chapter), Dolibarr uses concept of '''Table Module'''.
-> As shown in code skeletons (see previous chapter), Dolibarr uses concept of '''Table Module'''.
−
=== Communication between business logic - data (ORM) ===
+
===Communication between business logic - data (ORM)===
There are 3 ways to make links:
There are 3 ways to make links:
−
* 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 (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.
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/).
−
* 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 class, if such functions are dedicated to the table or recording into this table.
Example: This mode is used for Dolibarr development and most PHP softwares that include their own framework and best practices.
Example: This mode is used for Dolibarr development and most PHP softwares that include their own framework and best practices.
−
* The '''Data Mapper'''
+
*The '''Data Mapper'''
+
Classes represent entities of the problem and not the data. So you have to double, triple ... these classes with Mapper classes to access the data.
Classes represent entities of the problem and not the data. So you have to double, triple ... these classes with Mapper classes to access the data.
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.
Line 497:
Line 535:
-> 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, 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).
+
[[Category:Development]]